diff --git a/.github/labeler.yaml b/.github/labeler.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..d31a361baf2212b092bc7dca01ccf0f0e0b20ce4
--- /dev/null
+++ b/.github/labeler.yaml
@@ -0,0 +1,78 @@
+llappearance:
+  - indra/llappearance/**/*
+  
+llaudio:
+  - indra/llaudio/**/*
+
+llcharacter:
+  - indra/llcharacter/**/*
+
+llcommon:
+  - indra/llcommon/**/*
+
+llcorehttp:
+  - indra/llcorehttp/**/*
+
+llcrashlogger:
+  - indra/llcrashlogger/**/*
+
+llfilesystem:
+  - indra/llfilesystem/**/*
+
+llimage:
+  - indra/llimage/**/*
+
+llimagej2coj:
+  - indra/llimagej2coj/**/*
+
+llinventory:
+  - indra/llinventory/**/*
+
+llkdu:
+  - indra/llkdu/**/*
+
+llmath:
+  - indra/llmath/**/*
+
+llmeshoptimizer:
+  - indra/llmeshoptimizer/**/*
+
+llmessage:
+  - indra/llmessage/**/*
+
+llplugin:
+  - indra/llplugin/**/*
+
+llprimitive:
+  - indra/llprimitive/**/*
+
+llrender:
+  - indra/llrender/**/*
+
+llui:
+  - indra/llui/**/*
+
+llwindow:
+  - indra/llwindow/**/*
+
+llxml:
+  - indra/llxml/**/*
+
+cmake:
+  - '**/*.cmake'
+  - '**/*/cmake/*'
+  - '**/CMakeLists.txt'
+
+python:
+  - '**/*.py'
+
+c/cpp:
+  - '**/*.c'
+  - '**/*.cpp'
+  - '**/*.cxx'
+  - '**/*.h'
+  - '**/*.hpp'
+  - '**/*.hxx'
+  - '**/*.i'
+  - '**/*.inl'
+  - '**/*.y'
diff --git a/.github/workflows/cla.yaml b/.github/workflows/cla.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..fa180c66c9763bfcc7bec83d4c901e7526790574
--- /dev/null
+++ b/.github/workflows/cla.yaml
@@ -0,0 +1,25 @@
+name: Check CLA
+
+on:
+  issue_comment:
+    types: [created]
+  pull_request_target:
+    types: [opened, closed, synchronize]
+
+jobs:
+  cla:
+    name: Check CLA
+    runs-on: ubuntu-latest
+    steps:
+      - name: CLA Assistant
+        if: (github.event.comment.body == 'recheck' || github.event.comment.body == 'I have read the CLA Document and I hereby sign the CLA') || github.event_name == 'pull_request_target'
+        uses: secondlife-3p/contributor-assistant@v2
+        env:
+          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+          PERSONAL_ACCESS_TOKEN: ${{ secrets.SHARED_CLA_TOKEN }}
+        with:
+          branch: main
+          path-to-document: https://github.com/secondlife/cla/blob/master/CLA.md
+          path-to-signatures: signatures.json
+          remote-organization-name: secondlife
+          remote-repository-name: cla-signatures
diff --git a/.github/workflows/label.yaml b/.github/workflows/label.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..6e41d8aa2d808e5edd3e99bc67067ba5353b7b69
--- /dev/null
+++ b/.github/workflows/label.yaml
@@ -0,0 +1,15 @@
+name: Pull Request Labeler
+on:
+  - pull_request_target
+
+jobs:
+  triage:
+    permissions:
+      contents: read
+      pull-requests: write
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/labeler@v4
+        with:
+          configuration-path: .github/labeler.yaml
+          repo-token: "${{ secrets.GITHUB_TOKEN }}"
diff --git a/.gitignore b/.gitignore
index 355c39de70f86c6fa72ed2c6fc8e3787a294afd7..839d14bc0df0f4a1515480a4228836ac21a0be1e 100755
--- a/.gitignore
+++ b/.gitignore
@@ -24,6 +24,7 @@ build-vc120-32/
 build-vc120-64/
 build-vc150-32/
 build-vc150-64/
+build-vc160-64/
 indra/CMakeFiles
 indra/build-vc[0-9]*
 indra/lib/mono/1.0/*.dll
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..6d296d7a24cd416f33970eca5d76f0cdbdcf18ce
--- /dev/null
+++ b/.pre-commit-config.yaml
@@ -0,0 +1,17 @@
+repos:
+  - repo: https://bitbucket.org/lindenlab/git-hooks.git 
+    rev: v1.0.0-beta2
+    hooks:
+      - id: opensource-license
+      - id: jira-issue 
+      - id: llsd
+      - id: no-trigraphs
+      - id: copyright
+      - id: end-of-file
+        files: \.(cpp|c|h|py|glsl|cmake|txt)$
+        exclude: language.txt
+  - repo: https://github.com/pre-commit/pre-commit-hooks
+    rev: v2.5.0
+    hooks:
+      - id: check-xml
+      - id: mixed-line-ending
diff --git a/doc/LGPL-licence.txt b/LICENSE
similarity index 100%
rename from doc/LGPL-licence.txt
rename to LICENSE
diff --git a/README.md b/README.md
index 8813c2522815c116a2f14a59cb52cf52278ef2d5..c57140af9cb65f04afacdb15db3963240929c6be 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,8 @@
-![Second Life Logo](doc/sl-logo.png)
+<picture>
+  <source media="(prefers-color-scheme: dark)" srcset="doc/sl-logo-dark.png">
+  <source media="(prefers-color-scheme: light)" srcset="doc/sl-logo.png">
+  <img alt="Second Life Logo" src="doc/sl-logo.png">
+</picture>
 
 **[Second Life][] is a free 3D virtual world where users can create, connect and chat with others from around the
 world.** This repository contains the source code for the official client.
diff --git a/autobuild.xml b/autobuild.xml
index 3cdbaa280e60b3192835166099c8d0877d9eb104..25d95a68499d7dee3c9e46bf695e3530f55b2955 100644
--- a/autobuild.xml
+++ b/autobuild.xml
@@ -17,18 +17,6 @@
         <string>SDL</string>
         <key>platforms</key>
         <map>
-          <key>linux</key>
-          <map>
-            <key>archive</key>
-            <map>
-              <key>hash</key>
-              <string>459cdc8d7c19a8025f98f61db95622ff</string>
-              <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/sdl_3p-update-sdl/rev/297546/arch/Linux/installer/SDL-1.2.15-linux-297546.tar.bz2</string>
-            </map>
-            <key>name</key>
-            <string>linux</string>
-          </map>
           <key>linux64</key>
           <map>
             <key>archive</key>
@@ -59,18 +47,6 @@
         <string>apr_suite</string>
         <key>platforms</key>
         <map>
-          <key>darwin</key>
-          <map>
-            <key>archive</key>
-            <map>
-              <key>hash</key>
-              <string>0c53148aa00e51c06fa246c4130915be</string>
-              <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/apr_3p-update-apr/rev/297252/arch/Darwin/installer/apr_suite-1.4.5.297252-darwin-297252.tar.bz2</string>
-            </map>
-            <key>name</key>
-            <string>darwin</string>
-          </map>
           <key>darwin64</key>
           <map>
             <key>archive</key>
@@ -83,18 +59,6 @@
             <key>name</key>
             <string>darwin64</string>
           </map>
-          <key>linux</key>
-          <map>
-            <key>archive</key>
-            <map>
-              <key>hash</key>
-              <string>1aa2e5355bb9df09f9196d14a72b6705</string>
-              <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/p64_3p-apr/rev/314241/arch/Linux/installer/apr_suite-1.4.5.314241-linux-314241.tar.bz2</string>
-            </map>
-            <key>name</key>
-            <string>linux</string>
-          </map>
           <key>linux64</key>
           <map>
             <key>archive</key>
@@ -149,42 +113,18 @@
         <string>boost</string>
         <key>platforms</key>
         <map>
-          <key>darwin</key>
-          <map>
-            <key>archive</key>
-            <map>
-              <key>hash</key>
-              <string>c296845cad075250c1ae2620f175a957</string>
-              <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/boost_3p-update-boost/rev/297445/arch/Darwin/installer/boost-1.57-darwin-297445.tar.bz2</string>
-            </map>
-            <key>name</key>
-            <string>darwin</string>
-          </map>
           <key>darwin64</key>
           <map>
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>35cc090d942b85c9126ceac9912d52d6</string>
+              <string>fedc8d63856f534b6098102e059dc548</string>
               <key>url</key>
-              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/78585/744021/boost-1.72-darwin64-557045.tar.bz2</string>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/87776/805857/boost-1.72-darwin64-563847.tar.bz2</string>
             </map>
             <key>name</key>
             <string>darwin64</string>
           </map>
-          <key>linux</key>
-          <map>
-            <key>archive</key>
-            <map>
-              <key>hash</key>
-              <string>f1fdb548fd6c09a083c86f3a23d7f041</string>
-              <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/p64_3p-boost/rev/317807/arch/Linux/installer/boost-1.57-linux-317807.tar.bz2</string>
-            </map>
-            <key>name</key>
-            <string>linux</string>
-          </map>
           <key>linux64</key>
           <map>
             <key>archive</key>
@@ -202,9 +142,9 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>9aa4ce32df5f5e36124c990e2d77b885</string>
+              <string>6cc9fb4ca21365c4470a3e516544ba71</string>
               <key>url</key>
-              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/78586/743982/boost-1.72-windows-557045.tar.bz2</string>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/87784/805850/boost-1.72-windows-563847.tar.bz2</string>
             </map>
             <key>name</key>
             <string>windows</string>
@@ -214,9 +154,9 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>a79511c9d8b956767ebaa405155d4238</string>
+              <string>0c526efc3f8825cd25cdf635e238fab3</string>
               <key>url</key>
-              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/78584/743961/boost-1.72-windows64-557045.tar.bz2</string>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/87783/805851/boost-1.72-windows64-563847.tar.bz2</string>
             </map>
             <key>name</key>
             <string>windows64</string>
@@ -291,42 +231,18 @@
         <string>colladadom</string>
         <key>platforms</key>
         <map>
-          <key>darwin</key>
-          <map>
-            <key>archive</key>
-            <map>
-              <key>hash</key>
-              <string>726bc31e562752f081e95e8fcc70e405</string>
-              <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/colladadom_3p-update-colladadom/rev/297450/arch/Darwin/installer/colladadom-2.3.297450-darwin-297450.tar.bz2</string>
-            </map>
-            <key>name</key>
-            <string>darwin</string>
-          </map>
           <key>darwin64</key>
           <map>
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>1d063cf1783e7788f17486c234adb1db</string>
+              <string>4699b8389dfb754da0393ddb5d325722</string>
               <key>url</key>
-              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/78635/744249/colladadom-2.3.557064-darwin64-557064.tar.bz2</string>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/95882/856117/colladadom-2.3.569219-darwin64-569219.tar.bz2</string>
             </map>
             <key>name</key>
             <string>darwin64</string>
           </map>
-          <key>linux</key>
-          <map>
-            <key>archive</key>
-            <map>
-              <key>hash</key>
-              <string>78b9a6506fb7d53da166f7a65f2278f4</string>
-              <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/p64_3p-colladadom/rev/317826/arch/Linux/installer/colladadom-2.3.317826-linux-317826.tar.bz2</string>
-            </map>
-            <key>name</key>
-            <string>linux</string>
-          </map>
           <key>linux64</key>
           <map>
             <key>archive</key>
@@ -344,9 +260,9 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>e78ecf919eee01567556787c3a358d15</string>
+              <string>343e46ea49a08ad6596d3dc702d5b812</string>
               <key>url</key>
-              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/78637/744269/colladadom-2.3.557064-windows-557064.tar.bz2</string>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/95883/856128/colladadom-2.3.569219-windows-569219.tar.bz2</string>
             </map>
             <key>name</key>
             <string>windows</string>
@@ -356,16 +272,16 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>7e63a212c8909a25236138422fe01298</string>
+              <string>de5bdfb61b31db56c5fe7d0962ad11e2</string>
               <key>url</key>
-              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/78636/744273/colladadom-2.3.557064-windows64-557064.tar.bz2</string>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/95884/856129/colladadom-2.3.569219-windows64-569219.tar.bz2</string>
             </map>
             <key>name</key>
             <string>windows64</string>
           </map>
         </map>
         <key>version</key>
-        <string>2.3.557064</string>
+        <string>2.3.569219</string>
       </map>
       <key>cubemaptoequirectangular</key>
       <map>
@@ -433,42 +349,18 @@
         <string>curl</string>
         <key>platforms</key>
         <map>
-          <key>darwin</key>
-          <map>
-            <key>archive</key>
-            <map>
-              <key>hash</key>
-              <string>ad0061db7188a1b9a974eb0512eeeb8d</string>
-              <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-curl/rev/312763/arch/Darwin/installer/curl-7.47.0.312763-darwin-312763.tar.bz2</string>
-            </map>
-            <key>name</key>
-            <string>darwin</string>
-          </map>
           <key>darwin64</key>
           <map>
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>13f74f43a6363ec998569f731fd869c5</string>
+              <string>44d801e05811269d1bed7dbc75d85843</string>
               <key>url</key>
-              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/82637/774617/curl-7.54.1.560191-darwin64-560191.tar.bz2</string>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/87786/805905/curl-7.54.1.563852-darwin64-563852.tar.bz2</string>
             </map>
             <key>name</key>
             <string>darwin64</string>
           </map>
-          <key>linux</key>
-          <map>
-            <key>archive</key>
-            <map>
-              <key>hash</key>
-              <string>9430c08954c00736117099046694e1b1</string>
-              <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/p64_3p-curl/rev/314230/arch/Linux/installer/curl-7.47.0.314230-linux-314230.tar.bz2</string>
-            </map>
-            <key>name</key>
-            <string>linux</string>
-          </map>
           <key>linux64</key>
           <map>
             <key>archive</key>
@@ -486,11 +378,11 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>0df99bd685dc3561ca8ea347b2921987</string>
+              <string>676f624d4ebdc2189caa43ef6dd8266d</string>
               <key>hash_algorithm</key>
               <string>md5</string>
               <key>url</key>
-              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/82639/774610/curl-7.54.1.560191-windows-560191.tar.bz2</string>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/87790/805917/curl-7.54.1.563852-windows-563852.tar.bz2</string>
             </map>
             <key>name</key>
             <string>windows</string>
@@ -500,46 +392,16 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>50db2a9e6b74ec4b0c38b1ea8f135735</string>
+              <string>b3db5a2cdf275c1af7758fbe2d14544a</string>
               <key>url</key>
-              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/82638/774608/curl-7.54.1.560191-windows64-560191.tar.bz2</string>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/87789/805918/curl-7.54.1.563852-windows64-563852.tar.bz2</string>
             </map>
             <key>name</key>
             <string>windows64</string>
           </map>
         </map>
         <key>version</key>
-        <string>7.54.1.560191</string>
-      </map>
-      <key>db</key>
-      <map>
-        <key>copyright</key>
-        <string>Copyright (c) 1990, 2010 Oracle and/or its affiliates.  All rights reserved.</string>
-        <key>description</key>
-        <string>Berkeley DB (libdb) is a programmatic toolkit that provides embedded database support for both traditional and client/server applications.</string>
-        <key>license</key>
-        <string>bsd</string>
-        <key>license_file</key>
-        <string>LICENSES/db.txt</string>
-        <key>name</key>
-        <string>db</string>
-        <key>platforms</key>
-        <map>
-          <key>linux</key>
-          <map>
-            <key>archive</key>
-            <map>
-              <key>hash</key>
-              <string>1cc7940e500858a9754e9a3cc3ba2237</string>
-              <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/db_3p-update-db/rev/295315/arch/Linux/installer/db-5.1.25-linux-295315.tar.bz2</string>
-            </map>
-            <key>name</key>
-            <string>linux</string>
-          </map>
-        </map>
-        <key>version</key>
-        <string>5.1.25</string>
+        <string>7.54.1.563852</string>
       </map>
       <key>dbus_glib</key>
       <map>
@@ -555,18 +417,6 @@
         <string>dbus_glib</string>
         <key>platforms</key>
         <map>
-          <key>linux</key>
-          <map>
-            <key>archive</key>
-            <map>
-              <key>hash</key>
-              <string>6d676abd9ad8d2883b855dbe397d9034</string>
-              <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/p64_3p-dbus-glib/rev/314266/arch/Linux/installer/dbus_glib-0.76-linux-314266.tar.bz2</string>
-            </map>
-            <key>name</key>
-            <string>linux</string>
-          </map>
           <key>linux64</key>
           <map>
             <key>archive</key>
@@ -632,9 +482,9 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>2653c3627fd8687ff9e003425fd14834</string>
+              <string>439d92ec73f0500ba1671faad2bd8090</string>
               <key>url</key>
-              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/90199/821852/dullahan-1.12.3.202111032211_91.1.21_g9dd45fe_chromium-91.0.4472.114-darwin64-565428.tar.bz2</string>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/104637/916643/dullahan-1.12.4.202209142017_91.1.21_g9dd45fe_chromium-91.0.4472.114-darwin64-575005.tar.bz2</string>
             </map>
             <key>name</key>
             <string>darwin64</string>
@@ -644,9 +494,9 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>b4003772562a5dd40bc112eec7cba5f5</string>
+              <string>2a7c01da15de77bc1fd1863327174d5e</string>
               <key>url</key>
-              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/90201/821871/dullahan-1.12.3.202111032221_91.1.21_g9dd45fe_chromium-91.0.4472.114-windows-565428.tar.bz2</string>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/104638/916654/dullahan-1.12.4.202209142021_91.1.21_g9dd45fe_chromium-91.0.4472.114-windows-575005.tar.bz2</string>
             </map>
             <key>name</key>
             <string>windows</string>
@@ -656,40 +506,16 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>d9030d7a7390b3bda7de2adcc27e535a</string>
+              <string>d06bee9b2517fbb09ba1a65e6d675361</string>
               <key>url</key>
-              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/90200/821876/dullahan-1.12.3.202111032221_91.1.21_g9dd45fe_chromium-91.0.4472.114-windows64-565428.tar.bz2</string>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/104639/916659/dullahan-1.12.4.202209142021_91.1.21_g9dd45fe_chromium-91.0.4472.114-windows64-575005.tar.bz2</string>
             </map>
             <key>name</key>
             <string>windows64</string>
           </map>
         </map>
         <key>version</key>
-        <string>1.12.3.202111032221_91.1.21_g9dd45fe_chromium-91.0.4472.114</string>
-      </map>
-      <key>elfio</key>
-      <map>
-        <key>license</key>
-        <string>lgpl</string>
-        <key>license_file</key>
-        <string>LICENSES/elfio.txt</string>
-        <key>name</key>
-        <string>elfio</string>
-        <key>platforms</key>
-        <map>
-          <key>linux</key>
-          <map>
-            <key>archive</key>
-            <map>
-              <key>hash</key>
-              <string>031e6315a5c0829c9b9a2ec18aeb7ae3</string>
-              <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-elfio/rev/222074/arch/Linux/installer/elfio-1.0.3-linux-20110225.tar.bz2</string>
-            </map>
-            <key>name</key>
-            <string>linux</string>
-          </map>
-        </map>
+        <string>1.12.4.202209142021_91.1.21_g9dd45fe_chromium-91.0.4472.114</string>
       </map>
       <key>expat</key>
       <map>
@@ -705,18 +531,6 @@
         <string>expat</string>
         <key>platforms</key>
         <map>
-          <key>darwin</key>
-          <map>
-            <key>archive</key>
-            <map>
-              <key>hash</key>
-              <string>452d1910ef853329cd59858e6c5b2c48</string>
-              <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/expat_3p-update-expat/rev/297014/arch/Darwin/installer/expat-2.0.1.297014-darwin-297014.tar.bz2</string>
-            </map>
-            <key>name</key>
-            <string>darwin</string>
-          </map>
           <key>darwin64</key>
           <map>
             <key>archive</key>
@@ -729,18 +543,6 @@
             <key>name</key>
             <string>darwin64</string>
           </map>
-          <key>linux</key>
-          <map>
-            <key>archive</key>
-            <map>
-              <key>hash</key>
-              <string>387c90b9bb5ec412587fbe7a56261dd1</string>
-              <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/p64_3p-expat/rev/314211/arch/Linux/installer/expat-2.1.1.314211-linux-314211.tar.bz2</string>
-            </map>
-            <key>name</key>
-            <string>linux</string>
-          </map>
           <key>linux64</key>
           <map>
             <key>archive</key>
@@ -800,25 +602,13 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>c36808a58384a52672d81593de61f7ff</string>
+              <string>2c619c1bef969dc42b4f44a4651b314e</string>
               <key>url</key>
-              <string>https://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/89681/818422/fmodstudio-2.02.03.565082-darwin64-565082.tar.bz2</string>
+              <string>https://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/98369/869141/fmodstudio-2.02.06.570913-darwin64-570913.tar.bz2</string>
             </map>
             <key>name</key>
             <string>darwin64</string>
           </map>
-          <key>linux</key>
-          <map>
-            <key>archive</key>
-            <map>
-              <key>hash</key>
-              <string>24b86630ccdfb5b3221f90ca7a9704f6</string>
-              <key>url</key>
-              <string>https://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/89682/818423/fmodstudio-2.02.03.565082-linux-565082.tar.bz2</string>
-            </map>
-            <key>name</key>
-            <string>linux</string>
-          </map>
           <key>linux64</key>
           <map>
             <key>archive</key>
@@ -836,9 +626,9 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>96853d91ce4da14e14ea322122629551</string>
+              <string>875ccd8c1feec8ff03438d453371044b</string>
               <key>url</key>
-              <string>https://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/89683/818438/fmodstudio-2.02.03.565082-windows-565082.tar.bz2</string>
+              <string>https://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/98371/869153/fmodstudio-2.02.06.570913-windows-570913.tar.bz2</string>
             </map>
             <key>name</key>
             <string>windows</string>
@@ -848,16 +638,16 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>58d0cc28a1d90bacefbda48fcd8d379c</string>
+              <string>5e402f4828741bce942e2ced318cd02a</string>
               <key>url</key>
-              <string>https://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/89684/818439/fmodstudio-2.02.03.565082-windows64-565082.tar.bz2</string>
+              <string>https://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/98372/869154/fmodstudio-2.02.06.570913-windows64-570913.tar.bz2</string>
             </map>
             <key>name</key>
             <string>windows64</string>
           </map>
         </map>
         <key>version</key>
-        <string>2.02.03.565082</string>
+        <string>2.02.06.570913</string>
       </map>
       <key>fontconfig</key>
       <map>
@@ -873,18 +663,6 @@
         <string>fontconfig</string>
         <key>platforms</key>
         <map>
-          <key>linux</key>
-          <map>
-            <key>archive</key>
-            <map>
-              <key>hash</key>
-              <string>a20a3d0ab7fc3401bc2ca81e9309f630</string>
-              <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/p64_3p-fontconfig/rev/314281/arch/Linux/installer/fontconfig-2.11.0-linux-314281.tar.bz2</string>
-            </map>
-            <key>name</key>
-            <string>linux</string>
-          </map>
           <key>linux64</key>
           <map>
             <key>archive</key>
@@ -915,42 +693,18 @@
         <string>freetype</string>
         <key>platforms</key>
         <map>
-          <key>darwin</key>
-          <map>
-            <key>archive</key>
-            <map>
-              <key>hash</key>
-              <string>83618d16d974eb0af93926a10ac13297</string>
-              <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/freetype_3p-update-freetype/rev/297053/arch/Darwin/installer/freetype-2.4.4.297053-darwin-297053.tar.bz2</string>
-            </map>
-            <key>name</key>
-            <string>darwin</string>
-          </map>
           <key>darwin64</key>
           <map>
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>3a478d6c8a10d49d9161ef864394b03c</string>
+              <string>8865739d8e530199dacb3c3042c1bc01</string>
               <key>url</key>
-              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/78592/744013/freetype-2.4.4.557047-darwin64-557047.tar.bz2</string>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/87777/805782/freetype-2.4.4.563848-darwin64-563848.tar.bz2</string>
             </map>
             <key>name</key>
             <string>darwin64</string>
           </map>
-          <key>linux</key>
-          <map>
-            <key>archive</key>
-            <map>
-              <key>hash</key>
-              <string>1b401394106cedc86926bd488f5aa45e</string>
-              <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/p64_3p-freetype/rev/314215/arch/Linux/installer/freetype-2.4.4.314215-linux-314215.tar.bz2</string>
-            </map>
-            <key>name</key>
-            <string>linux</string>
-          </map>
           <key>linux64</key>
           <map>
             <key>archive</key>
@@ -968,9 +722,9 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>7ee200d6b5fa282c7f973ade5615aa86</string>
+              <string>c0b3601e997553931cadc7d7ee94168b</string>
               <key>url</key>
-              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/78594/744011/freetype-2.4.4.557047-windows-557047.tar.bz2</string>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/87779/805814/freetype-2.4.4.563848-windows-563848.tar.bz2</string>
             </map>
             <key>name</key>
             <string>windows</string>
@@ -980,16 +734,16 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>69307aaba16ac71531c9c4d930ace993</string>
+              <string>e98e1e088cdcd20442e05e9abecdadf9</string>
               <key>url</key>
-              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/78593/744010/freetype-2.4.4.557047-windows64-557047.tar.bz2</string>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/87778/805815/freetype-2.4.4.563848-windows64-563848.tar.bz2</string>
             </map>
             <key>name</key>
             <string>windows64</string>
           </map>
         </map>
         <key>version</key>
-        <string>2.4.4.557047</string>
+        <string>2.4.4.563848</string>
       </map>
       <key>glext</key>
       <map>
@@ -1017,18 +771,6 @@
             <key>name</key>
             <string>darwin64</string>
           </map>
-          <key>linux</key>
-          <map>
-            <key>archive</key>
-            <map>
-              <key>hash</key>
-              <string>baf1fd13e1fe6aef586200fc87a70f53</string>
-              <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/p64_3p-glext/rev/314200/arch/Linux/installer/glext-68-linux-314200.tar.bz2</string>
-            </map>
-            <key>name</key>
-            <string>linux</string>
-          </map>
           <key>linux64</key>
           <map>
             <key>archive</key>
@@ -1088,9 +830,9 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>650e836255b6c2ecb93d3f1f7220051c</string>
+              <string>dce3f3c01fddb400cb143c3283fe9259</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/55011/511905/glh_linear-0.0.0-common-538981.tar.bz2</string>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/82754/775367/glh_linear-0.0.0-common-560278.tar.bz2</string>
             </map>
             <key>name</key>
             <string>common</string>
@@ -1099,66 +841,40 @@
         <key>version</key>
         <string>0.0.0</string>
       </map>
-      <key>glod</key>
+      <key>googlemock</key>
       <map>
         <key>copyright</key>
-        <string>Copyright 2003 Jonathan Cohen, Nat Duca, David Luebke, Brenden Schubert - Johns Hopkins University and University of Virginia</string>
+        <string>Copyright 2008, Google Inc.</string>
+        <key>description</key>
+        <string>a library for writing and using C++ mock classes</string>
         <key>license</key>
-        <string>GLOD Open-Source License   Version 1.0</string>
+        <string>BSD</string>
         <key>license_file</key>
-        <string>LICENSES/GLOD.txt</string>
+        <string>LICENSES/gmock.txt</string>
         <key>name</key>
-        <string>glod</string>
+        <string>googlemock</string>
         <key>platforms</key>
         <map>
-          <key>darwin</key>
-          <map>
-            <key>archive</key>
-            <map>
-              <key>hash</key>
-              <string>71e678d70e276fc42a56926fc28a7abd</string>
-              <key>hash_algorithm</key>
-              <string>md5</string>
-              <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/glod_3p-update-glod/rev/296895/arch/Darwin/installer/glod-1.0pre4.296895-darwin-296895.tar.bz2</string>
-            </map>
-            <key>name</key>
-            <string>darwin</string>
-          </map>
           <key>darwin64</key>
           <map>
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>a9eaa005ff9d387f946283fbcb69b3c8</string>
+              <string>11d0794582e91a57f6524ad345f2399d</string>
               <key>url</key>
-              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/76353/727324/glod-1.0pre3.555522-darwin64-555522.tar.bz2</string>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/87791/805924/googlemock-1.7.0.563853-darwin64-563853.tar.bz2</string>
             </map>
             <key>name</key>
             <string>darwin64</string>
           </map>
-          <key>linux</key>
-          <map>
-            <key>archive</key>
-            <map>
-              <key>hash</key>
-              <string>58113bcbbacbaeb2d278f745867ae6f0</string>
-              <key>hash_algorithm</key>
-              <string>md5</string>
-              <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/p64_3p-glod/rev/314201/arch/Linux/installer/glod-1.0pre4.314201-linux-314201.tar.bz2</string>
-            </map>
-            <key>name</key>
-            <string>linux</string>
-          </map>
           <key>linux64</key>
           <map>
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>9aef5cd576ace19568da01d9bc3db29c</string>
+              <string>ff459b58695c76838782847a0b792104</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/1625/3628/glod-1.0pre3.501614-linux64-501614.tar.bz2</string>
+              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/9697/45717/googlemock-1.7.0.509686-linux64-509686.tar.bz2</string>
             </map>
             <key>name</key>
             <string>linux64</string>
@@ -1168,11 +884,9 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>e36c95b0d0fbaa3ff3392facaf5de447</string>
-              <key>hash_algorithm</key>
-              <string>md5</string>
+              <string>7d267050970ec6e28749178597bc8af0</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/55008/511893/glod-1.0pre3.538980-windows-538980.tar.bz2</string>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/87793/805930/googlemock-1.7.0.563853-windows-563853.tar.bz2</string>
             </map>
             <key>name</key>
             <string>windows</string>
@@ -1182,142 +896,40 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>6302ee1903ab419e76565d9eb6acd274</string>
+              <string>27638c692f0ec6121e54bf75f2d45e49</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/55004/511885/glod-1.0pre3.538980-windows64-538980.tar.bz2</string>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/87792/805936/googlemock-1.7.0.563853-windows64-563853.tar.bz2</string>
             </map>
             <key>name</key>
             <string>windows64</string>
           </map>
         </map>
         <key>version</key>
-        <string>1.0pre3.555522</string>
+        <string>1.7.0.563853</string>
       </map>
-      <key>googlemock</key>
+      <key>gstreamer</key>
       <map>
         <key>copyright</key>
-        <string>Copyright 2008, Google Inc.</string>
-        <key>description</key>
-        <string>a library for writing and using C++ mock classes</string>
+        <string>Copyright (C) 2007 Free Software Foundation, Inc. &lt;http://fsf.org/&gt;</string>
         <key>license</key>
-        <string>BSD</string>
+        <string>LGPL</string>
         <key>license_file</key>
-        <string>LICENSES/gmock.txt</string>
+        <string>LICENSES/gstreamer.txt</string>
         <key>name</key>
-        <string>googlemock</string>
+        <string>gstreamer</string>
         <key>platforms</key>
         <map>
-          <key>darwin</key>
+          <key>linux64</key>
           <map>
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>022649e284163b8ee23e3c9a81302fa7</string>
+              <string>7c9d7cc88add7831a6afeedc20cad2fe</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/googlemock_3p-update-googlemock/rev/297460/arch/Darwin/installer/googlemock-1.7.0.297460-darwin-297460.tar.bz2</string>
+              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/p64_3p-gstreamer/rev/314267/arch/Linux/installer/gstreamer-0.10.6.314267-linux64-314267.tar.bz2</string>
             </map>
             <key>name</key>
-            <string>darwin</string>
-          </map>
-          <key>darwin64</key>
-          <map>
-            <key>archive</key>
-            <map>
-              <key>hash</key>
-              <string>19e925604bc1a91efb4b130e1edd8bf2</string>
-              <key>url</key>
-              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/78620/744140/googlemock-1.7.0.557057-darwin64-557057.tar.bz2</string>
-            </map>
-            <key>name</key>
-            <string>darwin64</string>
-          </map>
-          <key>linux</key>
-          <map>
-            <key>archive</key>
-            <map>
-              <key>hash</key>
-              <string>ad51f68702f25ba245fff312c50c8876</string>
-              <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/p64_3p-googlemock/rev/317828/arch/Linux/installer/googlemock-1.7.0.317828-linux-317828.tar.bz2</string>
-            </map>
-            <key>name</key>
-            <string>linux</string>
-          </map>
-          <key>linux64</key>
-          <map>
-            <key>archive</key>
-            <map>
-              <key>hash</key>
-              <string>ff459b58695c76838782847a0b792104</string>
-              <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/9697/45717/googlemock-1.7.0.509686-linux64-509686.tar.bz2</string>
-            </map>
-            <key>name</key>
-            <string>linux64</string>
-          </map>
-          <key>windows</key>
-          <map>
-            <key>archive</key>
-            <map>
-              <key>hash</key>
-              <string>eed7b41d0d1f41b24f315349ef78c728</string>
-              <key>url</key>
-              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/78622/744148/googlemock-1.7.0.557057-windows-557057.tar.bz2</string>
-            </map>
-            <key>name</key>
-            <string>windows</string>
-          </map>
-          <key>windows64</key>
-          <map>
-            <key>archive</key>
-            <map>
-              <key>hash</key>
-              <string>a6ad6fe722d2fe4e8137495af3f374c9</string>
-              <key>url</key>
-              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/78621/744152/googlemock-1.7.0.557057-windows64-557057.tar.bz2</string>
-            </map>
-            <key>name</key>
-            <string>windows64</string>
-          </map>
-        </map>
-        <key>version</key>
-        <string>1.7.0.557057</string>
-      </map>
-      <key>gstreamer</key>
-      <map>
-        <key>copyright</key>
-        <string>Copyright (C) 2007 Free Software Foundation, Inc. &lt;http://fsf.org/&gt;</string>
-        <key>license</key>
-        <string>LGPL</string>
-        <key>license_file</key>
-        <string>LICENSES/gstreamer.txt</string>
-        <key>name</key>
-        <string>gstreamer</string>
-        <key>platforms</key>
-        <map>
-          <key>linux</key>
-          <map>
-            <key>archive</key>
-            <map>
-              <key>hash</key>
-              <string>5017b3e95d2c6f47bb111c3f9c075522</string>
-              <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/p64_3p-gstreamer/rev/314267/arch/Linux/installer/gstreamer-0.10.6.314267-linux-314267.tar.bz2</string>
-            </map>
-            <key>name</key>
-            <string>linux</string>
-          </map>
-          <key>linux64</key>
-          <map>
-            <key>archive</key>
-            <map>
-              <key>hash</key>
-              <string>7c9d7cc88add7831a6afeedc20cad2fe</string>
-              <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/p64_3p-gstreamer/rev/314267/arch/Linux/installer/gstreamer-0.10.6.314267-linux64-314267.tar.bz2</string>
-            </map>
-            <key>name</key>
-            <string>linux64</string>
+            <string>linux64</string>
           </map>
         </map>
         <key>version</key>
@@ -1335,18 +947,6 @@
         <string>gtk-atk-pango-glib</string>
         <key>platforms</key>
         <map>
-          <key>linux</key>
-          <map>
-            <key>archive</key>
-            <map>
-              <key>hash</key>
-              <string>a6431df705526501684d9050e04bfa5b</string>
-              <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/p64_3p-gtk-atk-pango-glib/rev/314220/arch/Linux/installer/gtk_atk_pango_glib-0.1-linux-314220.tar.bz2</string>
-            </map>
-            <key>name</key>
-            <string>linux</string>
-          </map>
           <key>linux64</key>
           <map>
             <key>archive</key>
@@ -1377,18 +977,6 @@
         <string>havok-source</string>
         <key>platforms</key>
         <map>
-          <key>darwin</key>
-          <map>
-            <key>archive</key>
-            <map>
-              <key>hash</key>
-              <string>5c5b4820999ae9e398801d6a46f45897</string>
-              <key>url</key>
-              <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/hg/repo/havok-source_3p-update-havok-source/rev/297312/arch/Darwin/installer/havok_source-2012.1-darwin-297312.tar.bz2</string>
-            </map>
-            <key>name</key>
-            <string>darwin</string>
-          </map>
           <key>darwin64</key>
           <map>
             <key>archive</key>
@@ -1401,18 +989,6 @@
             <key>name</key>
             <string>darwin64</string>
           </map>
-          <key>linux</key>
-          <map>
-            <key>archive</key>
-            <map>
-              <key>hash</key>
-              <string>03c1c5f7c3e93e905f635ca22b607494</string>
-              <key>url</key>
-              <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/hg/repo/p64_3p-havok-source/rev/314226/arch/Linux/installer/havok_source-2012.1-2-linux-314226.tar.bz2</string>
-            </map>
-            <key>name</key>
-            <string>linux</string>
-          </map>
           <key>linux64</key>
           <map>
             <key>archive</key>
@@ -1519,18 +1095,6 @@
         <string>jpeglib</string>
         <key>platforms</key>
         <map>
-          <key>darwin</key>
-          <map>
-            <key>archive</key>
-            <map>
-              <key>hash</key>
-              <string>4d7658997fd0f93a9c55e40e40b1b0e5</string>
-              <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/jpeglib_3p-update-jpeglib/rev/296854/arch/Darwin/installer/jpeglib-8c.296854-darwin-296854.tar.bz2</string>
-            </map>
-            <key>name</key>
-            <string>darwin</string>
-          </map>
           <key>darwin64</key>
           <map>
             <key>archive</key>
@@ -1543,18 +1107,6 @@
             <key>name</key>
             <string>darwin64</string>
           </map>
-          <key>linux</key>
-          <map>
-            <key>archive</key>
-            <map>
-              <key>hash</key>
-              <string>32560d3200da72fea2922371fcef25f5</string>
-              <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/p64_3p-jpeglib/rev/314202/arch/Linux/installer/jpeglib-8c.314202-linux-314202.tar.bz2</string>
-            </map>
-            <key>name</key>
-            <string>linux</string>
-          </map>
           <key>linux64</key>
           <map>
             <key>archive</key>
@@ -1609,18 +1161,6 @@
         <string>jsoncpp</string>
         <key>platforms</key>
         <map>
-          <key>darwin</key>
-          <map>
-            <key>archive</key>
-            <map>
-              <key>hash</key>
-              <string>b25a4f480e07c670ffef00c3da578f87</string>
-              <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/jsoncpp_3p-update-jsoncpp/rev/297281/arch/Darwin/installer/jsoncpp-0.5.0.297281-darwin-297281.tar.bz2</string>
-            </map>
-            <key>name</key>
-            <string>darwin</string>
-          </map>
           <key>darwin64</key>
           <map>
             <key>archive</key>
@@ -1633,18 +1173,6 @@
             <key>name</key>
             <string>darwin64</string>
           </map>
-          <key>linux</key>
-          <map>
-            <key>archive</key>
-            <map>
-              <key>hash</key>
-              <string>9d5d9fec28cbbb1651b95728173f8af7</string>
-              <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/p64_3p-jsoncpp/rev/314229/arch/Linux/installer/jsoncpp-0.5.0.314229-linux-314229.tar.bz2</string>
-            </map>
-            <key>name</key>
-            <string>linux</string>
-          </map>
           <key>linux64</key>
           <map>
             <key>archive</key>
@@ -1699,18 +1227,6 @@
         <string>kdu</string>
         <key>platforms</key>
         <map>
-          <key>darwin</key>
-          <map>
-            <key>archive</key>
-            <map>
-              <key>hash</key>
-              <string>3855bd40f950e3c22739ae8f3ee2afc9</string>
-              <key>url</key>
-              <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/15258/98444/kdu-7.10.4.513518-darwin-513518.tar.bz2</string>
-            </map>
-            <key>name</key>
-            <string>darwin</string>
-          </map>
           <key>darwin64</key>
           <map>
             <key>archive</key>
@@ -1723,18 +1239,6 @@
             <key>name</key>
             <string>darwin64</string>
           </map>
-          <key>linux</key>
-          <map>
-            <key>archive</key>
-            <map>
-              <key>hash</key>
-              <string>43d7a6a69a54534a736f132e9c81795b</string>
-              <key>url</key>
-              <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/15255/98451/kdu-7.10.4.513518-linux-513518.tar.bz2</string>
-            </map>
-            <key>name</key>
-            <string>linux</string>
-          </map>
           <key>linux64</key>
           <map>
             <key>archive</key>
@@ -1789,18 +1293,6 @@
         <string>libhunspell</string>
         <key>platforms</key>
         <map>
-          <key>darwin</key>
-          <map>
-            <key>archive</key>
-            <map>
-              <key>hash</key>
-              <string>05eda16106df26a211f8bdd874d1fca5</string>
-              <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/hunspell_3p-update-hunspell/rev/296916/arch/Darwin/installer/libhunspell-1.3.2.296916-darwin-296916.tar.bz2</string>
-            </map>
-            <key>name</key>
-            <string>darwin</string>
-          </map>
           <key>darwin64</key>
           <map>
             <key>archive</key>
@@ -1813,18 +1305,6 @@
             <key>name</key>
             <string>darwin64</string>
           </map>
-          <key>linux</key>
-          <map>
-            <key>archive</key>
-            <map>
-              <key>hash</key>
-              <string>0d8009c3b6c1eb510593476dd1d821b5</string>
-              <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/p64_3p-hunspell/rev/314217/arch/Linux/installer/libhunspell-1.3.2.314217-linux-314217.tar.bz2</string>
-            </map>
-            <key>name</key>
-            <string>linux</string>
-          </map>
           <key>linux64</key>
           <map>
             <key>archive</key>
@@ -1879,18 +1359,6 @@
         <string>libndofdev</string>
         <key>platforms</key>
         <map>
-          <key>darwin</key>
-          <map>
-            <key>archive</key>
-            <map>
-              <key>hash</key>
-              <string>a01b411433dbf8a4b481de9e76d9a652</string>
-              <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/libndofdev_3p-update-libndofdev/rev/297264/arch/Darwin/installer/libndofdev-0.1.297264-darwin-297264.tar.bz2</string>
-            </map>
-            <key>name</key>
-            <string>darwin</string>
-          </map>
           <key>darwin64</key>
           <map>
             <key>archive</key>
@@ -1945,42 +1413,18 @@
         <string>libpng</string>
         <key>platforms</key>
         <map>
-          <key>darwin</key>
-          <map>
-            <key>archive</key>
-            <map>
-              <key>hash</key>
-              <string>14cb5c8686a472e9e60179e46cd196f7</string>
-              <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/libpng_3p-update-libpng/rev/297708/arch/Darwin/installer/libpng-1.6.8.297708-darwin-297708.tar.bz2</string>
-            </map>
-            <key>name</key>
-            <string>darwin</string>
-          </map>
           <key>darwin64</key>
           <map>
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>2a41acc3116ce19a443873216cb882ad</string>
+              <string>c1c9e32e21f3c34d91ed045b2ca91f24</string>
               <key>url</key>
-              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/78587/743948/libpng-1.6.8.557046-darwin64-557046.tar.bz2</string>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/87781/805801/libpng-1.6.8.563850-darwin64-563850.tar.bz2</string>
             </map>
             <key>name</key>
             <string>darwin64</string>
           </map>
-          <key>linux</key>
-          <map>
-            <key>archive</key>
-            <map>
-              <key>hash</key>
-              <string>0758f3cb4c02ebab61854b811b0894e9</string>
-              <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/p64_3p-libpng/rev/314214/arch/Linux/installer/libpng-1.6.8.314214-linux-314214.tar.bz2</string>
-            </map>
-            <key>name</key>
-            <string>linux</string>
-          </map>
           <key>linux64</key>
           <map>
             <key>archive</key>
@@ -1998,9 +1442,9 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>b935b440947f63c69700bdcf5095a8e1</string>
+              <string>642e9cf95c8ccd0eb34f6d7a40df585a</string>
               <key>url</key>
-              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/78591/743970/libpng-1.6.8.557046-windows-557046.tar.bz2</string>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/87782/805831/libpng-1.6.8.563850-windows-563850.tar.bz2</string>
             </map>
             <key>name</key>
             <string>windows</string>
@@ -2010,16 +1454,16 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>d1cc8354ac4e877eefedf16b1be3aac6</string>
+              <string>ce46aa0f171d97626c4a3940347cecd7</string>
               <key>url</key>
-              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/78589/743991/libpng-1.6.8.557046-windows64-557046.tar.bz2</string>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/87780/805832/libpng-1.6.8.563850-windows64-563850.tar.bz2</string>
             </map>
             <key>name</key>
             <string>windows64</string>
           </map>
         </map>
         <key>version</key>
-        <string>1.6.8.557046</string>
+        <string>1.6.8.563850</string>
       </map>
       <key>libuuid</key>
       <map>
@@ -2035,18 +1479,6 @@
         <string>libuuid</string>
         <key>platforms</key>
         <map>
-          <key>linux</key>
-          <map>
-            <key>archive</key>
-            <map>
-              <key>hash</key>
-              <string>a2eaf9515cd129f3e21a08e92689006b</string>
-              <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/p64_3p-libuuid/rev/314269/arch/Linux/installer/libuuid-1.6.2-linux-314269.tar.bz2</string>
-            </map>
-            <key>name</key>
-            <string>linux</string>
-          </map>
           <key>linux64</key>
           <map>
             <key>archive</key>
@@ -2077,42 +1509,18 @@
         <string>libxml2</string>
         <key>platforms</key>
         <map>
-          <key>darwin</key>
-          <map>
-            <key>archive</key>
-            <map>
-              <key>hash</key>
-              <string>9303f0dd174129e297eca6cc2eb1ab3f</string>
-              <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/libxml_3p-update-libxml/rev/297050/arch/Darwin/installer/libxml2-2.9.1.297050-darwin-297050.tar.bz2</string>
-            </map>
-            <key>name</key>
-            <string>darwin</string>
-          </map>
           <key>darwin64</key>
           <map>
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>6677173bbbb0ea32369b5e9b6c9aa641</string>
+              <string>6f37dd6c4a5174f358b6cc5d953f121b</string>
               <key>url</key>
-              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/78631/744225/libxml2-2.9.4.557062-darwin64-557062.tar.bz2</string>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/87768/805766/libxml2-2.9.4.563845-darwin64-563845.tar.bz2</string>
             </map>
             <key>name</key>
             <string>darwin64</string>
           </map>
-          <key>linux</key>
-          <map>
-            <key>archive</key>
-            <map>
-              <key>hash</key>
-              <string>6954173a141d928f2614076577d952de</string>
-              <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/p64_3p-libxml/rev/314197/arch/Linux/installer/libxml2-2.9.1.314197-linux-314197.tar.bz2</string>
-            </map>
-            <key>name</key>
-            <string>linux</string>
-          </map>
           <key>linux64</key>
           <map>
             <key>archive</key>
@@ -2130,9 +1538,9 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>ad6a596fbf0e83a21d95762da78437bc</string>
+              <string>fd85d3aa13fbdfd1f1ace587e95ef151</string>
               <key>url</key>
-              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/78633/744239/libxml2-2.9.4.557062-windows-557062.tar.bz2</string>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/87773/805797/libxml2-2.9.4.563845-windows-563845.tar.bz2</string>
             </map>
             <key>name</key>
             <string>windows</string>
@@ -2142,16 +1550,16 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>6b5bb230684ecf28386d7c91c47bb6e1</string>
+              <string>d231d36c3b8942e0259aa2d9fcaa3b7e</string>
               <key>url</key>
-              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/78634/744240/libxml2-2.9.4.557062-windows64-557062.tar.bz2</string>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/87772/805795/libxml2-2.9.4.563845-windows64-563845.tar.bz2</string>
             </map>
             <key>name</key>
             <string>windows64</string>
           </map>
         </map>
         <key>version</key>
-        <string>2.9.4.557062</string>
+        <string>2.9.4.563845</string>
       </map>
       <key>llappearance_utility</key>
       <map>
@@ -2201,18 +1609,18 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>95cb09a712b7b61e992fe68ab7bf8c72</string>
+              <string>d6e7ab8483c348f223fd24028e27a52f</string>
               <key>hash_algorithm</key>
               <string>md5</string>
               <key>url</key>
-              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/92744/837149/llca-202201010217.567162-common-567162.tar.bz2</string>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/93933/844890/llca-202202010217.567974-common-567974.tar.bz2</string>
             </map>
             <key>name</key>
             <string>common</string>
           </map>
         </map>
         <key>version</key>
-        <string>202201010217.567162</string>
+        <string>202202010217.567974</string>
       </map>
       <key>llphysicsextensions_source</key>
       <map>
@@ -2408,19 +1816,20 @@
         <key>version</key>
         <string>7.11.1.297294</string>
       </map>
-      <key>nghttp2</key>
+      <key>meshoptimizer</key>
       <map>
+        <key>canonical_repo</key>
+        <string>https://bitbucket.org/lindenlab/3p-meshoptimizer</string>
         <key>copyright</key>
-        <string>Copyright (c) 2012, 2014, 2015, 2016 Tatsuhiro Tsujikawa
-Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
+        <string>Copyright (c) 2016-2021 Arseny Kapoulkine</string>
         <key>description</key>
-        <string>Library providing HTTP 2 support for libcurl</string>
+        <string>Meshoptimizer. Mesh optimization library.</string>
         <key>license</key>
-        <string>MIT</string>
+        <string>meshoptimizer</string>
         <key>license_file</key>
-        <string>LICENSES/nghttp2.txt</string>
+        <string>LICENSES/meshoptimizer.txt</string>
         <key>name</key>
-        <string>nghttp2</string>
+        <string>meshoptimizer</string>
         <key>platforms</key>
         <map>
           <key>darwin64</key>
@@ -2428,36 +1837,135 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>e4f784d8a035c51921a1562ca7a1bab6</string>
+              <string>30bc37db57bbd87c4b5f62634964242a</string>
               <key>url</key>
-              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/76357/727350/nghttp2-1.40.0.555524-darwin64-555524.tar.bz2</string>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/84218/784918/meshoptimizer-0.16.561408-darwin64-561408.tar.bz2</string>
             </map>
             <key>name</key>
             <string>darwin64</string>
           </map>
-          <key>linux</key>
+          <key>windows</key>
           <map>
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>079c1a1bdb3ce1cda8ce3d7f75eeced3</string>
+              <string>ca3684bcf0447746cd2844e94f6d1fc7</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/9258/41585/nghttp2-1.25.0.509246-linux-509246.tar.bz2</string>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/84219/784924/meshoptimizer-0.16.561408-windows-561408.tar.bz2</string>
             </map>
             <key>name</key>
-            <string>linux</string>
+            <string>windows</string>
           </map>
-          <key>linux64</key>
+          <key>windows64</key>
           <map>
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>c3c5ff7d2f7ac1143ef8d888192d4a53</string>
+              <string>aef28c089d20f69d13c9c3e113fb3895</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/9257/41579/nghttp2-1.25.0.509246-linux64-509246.tar.bz2</string>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/84220/784931/meshoptimizer-0.16.561408-windows64-561408.tar.bz2</string>
             </map>
             <key>name</key>
-            <string>linux64</string>
+            <string>windows64</string>
+          </map>
+        </map>
+        <key>version</key>
+        <string>0.16.561408</string>
+      </map>
+      <key>minizip-ng</key>
+      <map>
+        <key>canonical_repo</key>
+        <string>https://bitbucket.org/lindenlab/3p-minizip-ng</string>
+        <key>copyright</key>
+        <string>This project uses the zlib license. Copyright (C) 1995-2013 Jean-loup Gailly and Mark Adler</string>
+        <key>description</key>
+        <string>minizip-ng is a zip manipulation library. Based on work of Gilles Vollant.</string>
+        <key>license</key>
+        <string>minizip-ng</string>
+        <key>license_file</key>
+        <string>LICENSES/minizip-ng.txt</string>
+        <key>name</key>
+        <string>minizip-ng</string>
+        <key>platforms</key>
+        <map>
+          <key>darwin64</key>
+          <map>
+            <key>archive</key>
+            <map>
+              <key>hash</key>
+              <string>843587a078102d86d90054d03354684d</string>
+              <key>url</key>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/95876/856095/minizip_ng-3.0.2.569217-darwin64-569217.tar.bz2</string>
+            </map>
+            <key>name</key>
+            <string>darwin64</string>
+          </map>
+          <key>windows</key>
+          <map>
+            <key>archive</key>
+            <map>
+              <key>hash</key>
+              <string>26dc254f443ca9c5509547d7fbd9d8e5</string>
+              <key>url</key>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/95878/856107/minizip_ng-3.0.2.569217-windows-569217.tar.bz2</string>
+            </map>
+            <key>name</key>
+            <string>windows</string>
+          </map>
+          <key>windows64</key>
+          <map>
+            <key>archive</key>
+            <map>
+              <key>hash</key>
+              <string>e9241fa325f4014995b62193321e7a1c</string>
+              <key>url</key>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/95877/856106/minizip_ng-3.0.2.569217-windows64-569217.tar.bz2</string>
+            </map>
+            <key>name</key>
+            <string>windows64</string>
+          </map>
+        </map>
+        <key>version</key>
+        <string>3.0.2.569217</string>
+      </map>
+      <key>nghttp2</key>
+      <map>
+        <key>copyright</key>
+        <string>Copyright (c) 2012, 2014, 2015, 2016 Tatsuhiro Tsujikawa
+Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
+        <key>description</key>
+        <string>Library providing HTTP 2 support for libcurl</string>
+        <key>license</key>
+        <string>MIT</string>
+        <key>license_file</key>
+        <string>LICENSES/nghttp2.txt</string>
+        <key>name</key>
+        <string>nghttp2</string>
+        <key>platforms</key>
+        <map>
+          <key>darwin64</key>
+          <map>
+            <key>archive</key>
+            <map>
+              <key>hash</key>
+              <string>e4f784d8a035c51921a1562ca7a1bab6</string>
+              <key>url</key>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/76357/727350/nghttp2-1.40.0.555524-darwin64-555524.tar.bz2</string>
+            </map>
+            <key>name</key>
+            <string>darwin64</string>
+          </map>
+          <key>linux64</key>
+          <map>
+            <key>archive</key>
+            <map>
+              <key>hash</key>
+              <string>c3c5ff7d2f7ac1143ef8d888192d4a53</string>
+              <key>url</key>
+              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/9257/41579/nghttp2-1.25.0.509246-linux64-509246.tar.bz2</string>
+            </map>
+            <key>name</key>
+            <string>linux64</string>
           </map>
           <key>windows</key>
           <map>
@@ -2545,18 +2053,6 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
         <string>ogg_vorbis</string>
         <key>platforms</key>
         <map>
-          <key>darwin</key>
-          <map>
-            <key>archive</key>
-            <map>
-              <key>hash</key>
-              <string>07fca1531a27915f642a5c1d95008d54</string>
-              <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/oggvorbis_3p-update-oggvorbis/rev/296878/arch/Darwin/installer/ogg_vorbis-1.2.2-1.3.2.296878-darwin-296878.tar.bz2</string>
-            </map>
-            <key>name</key>
-            <string>darwin</string>
-          </map>
           <key>darwin64</key>
           <map>
             <key>archive</key>
@@ -2569,18 +2065,6 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
             <key>name</key>
             <string>darwin64</string>
           </map>
-          <key>linux</key>
-          <map>
-            <key>archive</key>
-            <map>
-              <key>hash</key>
-              <string>5c9d94dce4551b19790057766ff939ea</string>
-              <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/p64_3p-oggvorbis/rev/314224/arch/Linux/installer/ogg_vorbis-1.2.2-1.3.2.314224-linux-314224.tar.bz2</string>
-            </map>
-            <key>name</key>
-            <string>linux</string>
-          </map>
           <key>linux64</key>
           <map>
             <key>archive</key>
@@ -2633,21 +2117,6 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
         <string>LICENSES/libndofdev.txt</string>
         <key>name</key>
         <string>open-libndofdev</string>
-        <key>platforms</key>
-        <map>
-          <key>linux</key>
-          <map>
-            <key>archive</key>
-            <map>
-              <key>hash</key>
-              <string>b1245d467d5914a266efa16afeb55406</string>
-              <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/libndofdev_3p-update-libndofdev/rev/297553/arch/Linux/installer/open_libndofdev-0.3-linux-297553.tar.bz2</string>
-            </map>
-            <key>name</key>
-            <string>linux</string>
-          </map>
-        </map>
         <key>version</key>
         <string>0.3</string>
       </map>
@@ -2665,20 +2134,6 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
         <string>openal</string>
         <key>platforms</key>
         <map>
-          <key>linux</key>
-          <map>
-            <key>archive</key>
-            <map>
-              <key>hash</key>
-              <string>24b91eda3831a51c7774644016c4cb09</string>
-              <key>hash_algorithm</key>
-              <string>md5</string>
-              <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/p64_3p-openal/rev/314223/arch/Linux/installer/openal-1.12.854-1.1.0.314223-linux-314223.tar.bz2</string>
-            </map>
-            <key>name</key>
-            <string>linux</string>
-          </map>
           <key>linux64</key>
           <map>
             <key>archive</key>
@@ -2735,18 +2190,6 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
         <string>openjpeg</string>
         <key>platforms</key>
         <map>
-          <key>darwin</key>
-          <map>
-            <key>archive</key>
-            <map>
-              <key>hash</key>
-              <string>2adb5b8bd2493d576c5d02b992d8f819</string>
-              <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/openjpeg_3p-update-openjpeg/rev/297018/arch/Darwin/installer/openjpeg-1.4.297018-darwin-297018.tar.bz2</string>
-            </map>
-            <key>name</key>
-            <string>darwin</string>
-          </map>
           <key>darwin64</key>
           <map>
             <key>archive</key>
@@ -2759,18 +2202,6 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
             <key>name</key>
             <string>darwin64</string>
           </map>
-          <key>linux</key>
-          <map>
-            <key>archive</key>
-            <map>
-              <key>hash</key>
-              <string>e82317482647559d46a818ba48e9423a</string>
-              <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/p64_3p-openjpeg/rev/314205/arch/Linux/installer/openjpeg-2.0.0.314205-linux-314205.tar.bz2</string>
-            </map>
-            <key>name</key>
-            <string>linux</string>
-          </map>
           <key>linux64</key>
           <map>
             <key>archive</key>
@@ -2825,42 +2256,18 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
         <string>openssl</string>
         <key>platforms</key>
         <map>
-          <key>darwin</key>
-          <map>
-            <key>archive</key>
-            <map>
-              <key>hash</key>
-              <string>0a77d56769e6075957f614be6575423e</string>
-              <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/openssl_3p-update-openssl/rev/297168/arch/Darwin/installer/openssl-1.0.1h.297168-darwin-297168.tar.bz2</string>
-            </map>
-            <key>name</key>
-            <string>darwin</string>
-          </map>
           <key>darwin64</key>
           <map>
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>5503e4928bcdb0a29685b3242c4a409b</string>
+              <string>142d0ad85d0ee4fbb673c9f9e414fbdd</string>
               <key>url</key>
-              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/82619/774464/openssl-1.1.1l.560177-darwin64-560177.tar.bz2</string>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/87769/805772/openssl-1.1.1l.563846-darwin64-563846.tar.bz2</string>
             </map>
             <key>name</key>
             <string>darwin64</string>
           </map>
-          <key>linux</key>
-          <map>
-            <key>archive</key>
-            <map>
-              <key>hash</key>
-              <string>f46a601d60b7dbcfde32afc0cb64453e</string>
-              <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/p64_3p-openssl/rev/314227/arch/Linux/installer/openssl-1.0.1h.314227-linux-314227.tar.bz2</string>
-            </map>
-            <key>name</key>
-            <string>linux</string>
-          </map>
           <key>linux64</key>
           <map>
             <key>archive</key>
@@ -2878,9 +2285,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>d2153f20dc2d35c609b876a9f019a748</string>
+              <string>55bd833166d03f1467e2c7f24fa9143e</string>
               <key>url</key>
-              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/82623/774521/openssl-1.1.1l.560177-windows-560177.tar.bz2</string>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/87775/805841/openssl-1.1.1l.563846-windows-563846.tar.bz2</string>
             </map>
             <key>name</key>
             <string>windows</string>
@@ -2890,16 +2297,16 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>f40b8622ba38084b0962e273988d748f</string>
+              <string>6fefc60f68882fc6b246521b696497ab</string>
               <key>url</key>
-              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/82624/774520/openssl-1.1.1l.560177-windows64-560177.tar.bz2</string>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/87774/805833/openssl-1.1.1l.563846-windows64-563846.tar.bz2</string>
             </map>
             <key>name</key>
             <string>windows64</string>
           </map>
         </map>
         <key>version</key>
-        <string>1.1.1l.560177</string>
+        <string>1.1.1l.563846</string>
       </map>
       <key>pcre</key>
       <map>
@@ -2915,18 +2322,6 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
         <string>pcre</string>
         <key>platforms</key>
         <map>
-          <key>darwin</key>
-          <map>
-            <key>archive</key>
-            <map>
-              <key>hash</key>
-              <string>6d2b38897f1adf354b299345d5fc759b</string>
-              <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/pcre_3p-update-pcre/rev/297155/arch/Darwin/installer/pcre-8.35.-darwin-297155.tar.bz2</string>
-            </map>
-            <key>name</key>
-            <string>darwin</string>
-          </map>
           <key>darwin64</key>
           <map>
             <key>archive</key>
@@ -2939,18 +2334,6 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
             <key>name</key>
             <string>darwin64</string>
           </map>
-          <key>linux</key>
-          <map>
-            <key>archive</key>
-            <map>
-              <key>hash</key>
-              <string>24a119b18e63017ad932ad54df8161bc</string>
-              <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/p64_3p-pcre/rev/314136/arch/Linux/installer/pcre-8.35.314136-linux-314136.tar.bz2</string>
-            </map>
-            <key>name</key>
-            <string>linux</string>
-          </map>
           <key>linux64</key>
           <map>
             <key>archive</key>
@@ -2973,7 +2356,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
               <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/55041/512002/pcre-8.35.538986-windows-538986.tar.bz2</string>
             </map>
             <key>name</key>
-            <string>linux</string>
+            <string>windows</string>
           </map>
           <key>windows64</key>
           <map>
@@ -3005,42 +2388,18 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
         <string>slvoice</string>
         <key>platforms</key>
         <map>
-          <key>darwin</key>
-          <map>
-            <key>archive</key>
-            <map>
-              <key>hash</key>
-              <string>511a9c3fd4b6c76a8a737d06bba1c291</string>
-              <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/oz-426-slvoice/rev/330003/arch/Darwin/installer/slvoice-4.9.0002.27586.330003-darwin-330003.tar.bz2</string>
-            </map>
-            <key>name</key>
-            <string>darwin</string>
-          </map>
           <key>darwin64</key>
           <map>
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>6ce3cbaed968a69fb7a2cca80220874d</string>
+              <string>b583668b28fde0490e6953f10e93e4ab</string>
               <key>url</key>
-              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/80380/758537/slvoice-4.10.0000.32327.5fc3fe7c.558436-darwin64-558436.tar.bz2</string>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/98681/871545/slvoice-4.10.0000.32327.5fc3fe7c.571099-darwin64-571099.tar.bz2</string>
             </map>
             <key>name</key>
             <string>darwin64</string>
           </map>
-          <key>linux</key>
-          <map>
-            <key>archive</key>
-            <map>
-              <key>hash</key>
-              <string>785c86999b56e1838cefb430f674cba7</string>
-              <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/oz-426-slvoice/rev/330003/arch/Linux/installer/slvoice-3.2.0002.10426.330003-linux-330003.tar.bz2</string>
-            </map>
-            <key>name</key>
-            <string>linux</string>
-          </map>
           <key>linux64</key>
           <map>
             <key>archive</key>
@@ -3058,9 +2417,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>2eb38c5eff4d0f18fbb89d0c30c4f0a4</string>
+              <string>6e0ed41653955afe8eeb8945776cf07b</string>
               <key>url</key>
-              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/80382/758550/slvoice-4.10.0000.32327.5fc3fe7c.558436-windows-558436.tar.bz2</string>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/98683/871560/slvoice-4.10.0000.32327.5fc3fe7c.571099-windows-571099.tar.bz2</string>
             </map>
             <key>name</key>
             <string>windows</string>
@@ -3070,16 +2429,16 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>9ee8f3cbc5369c598a998c61961ed16d</string>
+              <string>c39735851fd05c194d0be09b8f9e8cb7</string>
               <key>url</key>
-              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/80381/758551/slvoice-4.10.0000.32327.5fc3fe7c.558436-windows64-558436.tar.bz2</string>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/98682/871552/slvoice-4.10.0000.32327.5fc3fe7c.571099-windows64-571099.tar.bz2</string>
             </map>
             <key>name</key>
             <string>windows64</string>
           </map>
         </map>
         <key>version</key>
-        <string>4.10.0000.32327.5fc3fe7c.558436</string>
+        <string>4.10.0000.32327.5fc3fe7c.571099</string>
       </map>
       <key>threejs</key>
       <map>
@@ -3133,6 +2492,70 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
         <key>version</key>
         <string>0.132.2</string>
       </map>
+      <key>tracy</key>
+      <map>
+        <key>canonical_repo</key>
+        <string>https://bitbucket.org/lindenlab/3p-tracy</string>
+        <key>copyright</key>
+        <string>Copyright (c) 2017-2021, Bartosz Taudul (wolf@nereid.pl)</string>
+        <key>description</key>
+        <string>Tracy Profiler Library</string>
+        <key>license</key>
+        <string>bsd</string>
+        <key>license_file</key>
+        <string>LICENSES/tracy_license.txt</string>
+        <key>name</key>
+        <string>tracy</string>
+        <key>platforms</key>
+        <map>
+          <key>darwin64</key>
+          <map>
+            <key>archive</key>
+            <map>
+              <key>hash</key>
+              <string>da7317e4a81609f624f84780f28b07de</string>
+              <key>url</key>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/86972/801630/tracy-v0.7.8.563351-darwin64-563351.tar.bz2</string>
+            </map>
+            <key>name</key>
+            <string>darwin64</string>
+          </map>
+          <key>windows</key>
+          <map>
+            <key>archive</key>
+            <map>
+              <key>hash</key>
+              <string>47c696cd2966c5cc3c8ba6115dd1f886</string>
+              <key>hash_algorithm</key>
+              <string>md5</string>
+              <key>url</key>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/86973/801641/tracy-v0.7.8.563351-windows-563351.tar.bz2</string>
+            </map>
+            <key>name</key>
+            <string>windows</string>
+          </map>
+          <key>windows64</key>
+          <map>
+            <key>archive</key>
+            <map>
+              <key>hash</key>
+              <string>b649ee6591e67d2341e886b3fc3484a7</string>
+              <key>hash_algorithm</key>
+              <string>md5</string>
+              <key>url</key>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/86974/801642/tracy-v0.7.8.563351-windows64-563351.tar.bz2</string>
+            </map>
+            <key>name</key>
+            <string>windows64</string>
+          </map>
+        </map>
+        <key>source</key>
+        <string>https://bitbucket.org/lindenlab/3p-tracy</string>
+        <key>source_type</key>
+        <string>git</string>
+        <key>version</key>
+        <string>v0.7.8.563351</string>
+      </map>
       <key>tut</key>
       <map>
         <key>copyright</key>
@@ -3177,18 +2600,6 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
         <string>uriparser</string>
         <key>platforms</key>
         <map>
-          <key>darwin</key>
-          <map>
-            <key>archive</key>
-            <map>
-              <key>hash</key>
-              <string>22608adaf54e8ddc9182a719ba6e2b32</string>
-              <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/uriparser_3p-update-uriparser/rev/299435/arch/Darwin/installer/uriparser-0.8.0.1-darwin-299435.tar.bz2</string>
-            </map>
-            <key>name</key>
-            <string>darwin</string>
-          </map>
           <key>darwin64</key>
           <map>
             <key>archive</key>
@@ -3201,18 +2612,6 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
             <key>name</key>
             <string>darwin64</string>
           </map>
-          <key>linux</key>
-          <map>
-            <key>archive</key>
-            <map>
-              <key>hash</key>
-              <string>dddfc8dea540801f93ba0382cb1e3685</string>
-              <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/uriparser_3p-update-uriparser/rev/299435/arch/Linux/installer/uriparser-0.8.0.1-linux-299435.tar.bz2</string>
-            </map>
-            <key>name</key>
-            <string>linux</string>
-          </map>
           <key>linux64</key>
           <map>
             <key>archive</key>
@@ -3272,33 +2671,21 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>33ed1bb3e24fbd3462da04fb3e917e94</string>
+              <string>1dda5fb3bb649b0ab5a93f22df7cb11e</string>
               <key>url</key>
-              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/94814/850320/viewer_manager-3.0.568552-darwin64-568552.tar.bz2</string>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/96998/862110/viewer_manager-3.0.569958-darwin64-569958.tar.bz2</string>
             </map>
             <key>name</key>
             <string>darwin64</string>
           </map>
-          <key>linux</key>
-          <map>
-            <key>archive</key>
-            <map>
-              <key>hash</key>
-              <string>8c7f32f85850248809ae811ba8e47d81</string>
-              <key>url</key>
-              <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/3428/8686/viewer_manager-1.0-linux-503417.tar.bz2</string>
-            </map>
-            <key>name</key>
-            <string>linux</string>
-          </map>
           <key>windows</key>
           <map>
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>2ad8e04965ac8bddb7d351abe09bee07</string>
+              <string>30d1386d0a6883d898fc56757a789b8b</string>
               <key>url</key>
-              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/94813/850316/viewer_manager-3.0.568552-windows-568552.tar.bz2</string>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/97002/862130/viewer_manager-3.0.569958-windows-569958.tar.bz2</string>
             </map>
             <key>name</key>
             <string>windows</string>
@@ -3309,7 +2696,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
         <key>source_type</key>
         <string>hg</string>
         <key>version</key>
-        <string>3.0.568552</string>
+        <string>3.0.569958</string>
       </map>
       <key>vlc-bin</key>
       <map>
@@ -3335,18 +2722,6 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
             <key>name</key>
             <string>darwin64</string>
           </map>
-          <key>linux</key>
-          <map>
-            <key>archive</key>
-            <map>
-              <key>hash</key>
-              <string>2f410640df3f9812d1abff02a414cfa8</string>
-              <key>url</key>
-              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-vlc-bin/rev/315283/arch/Linux/vlc_bin-2.2.3-linux-201606011750-r10.tar.bz2</string>
-            </map>
-            <key>name</key>
-            <string>linux</string>
-          </map>
           <key>windows</key>
           <map>
             <key>archive</key>
@@ -3389,18 +2764,6 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
         <string>xmlrpc-epi</string>
         <key>platforms</key>
         <map>
-          <key>darwin</key>
-          <map>
-            <key>archive</key>
-            <map>
-              <key>hash</key>
-              <string>ffd3aab8e0c0ff6dadbce49ca2809078</string>
-              <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/xmlrpc-emi_3p-update-xmlrpc-epi/rev/297075/arch/Darwin/installer/xmlrpc_epi-0.54.1.297075-darwin-297075.tar.bz2</string>
-            </map>
-            <key>name</key>
-            <string>darwin</string>
-          </map>
           <key>darwin64</key>
           <map>
             <key>archive</key>
@@ -3413,18 +2776,6 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
             <key>name</key>
             <string>darwin64</string>
           </map>
-          <key>linux</key>
-          <map>
-            <key>archive</key>
-            <map>
-              <key>hash</key>
-              <string>b63f828e798287d475991134cdcfbca3</string>
-              <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/p64_3p-xmlrpc-epi/rev/314240/arch/Linux/installer/xmlrpc_epi-0.54.1.314240-linux-314240.tar.bz2</string>
-            </map>
-            <key>name</key>
-            <string>linux</string>
-          </map>
           <key>linux64</key>
           <map>
             <key>archive</key>
@@ -3465,58 +2816,34 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
         <key>version</key>
         <string>0.54.1.555529</string>
       </map>
-      <key>zlib</key>
+      <key>zlib-ng</key>
       <map>
+        <key>canonical_repo</key>
+        <string>https://bitbucket.org/lindenlab/3p-zlib-ng</string>
         <key>copyright</key>
         <string>Copyright (C) 1995-2013 Jean-loup Gailly and Mark Adler</string>
         <key>description</key>
-        <string>Zlib Data Compression Library</string>
+        <string>zlib data compression library for the next generation systems</string>
         <key>license</key>
-        <string>zlib</string>
+        <string>zlib-ng</string>
         <key>license_file</key>
-        <string>LICENSES/zlib.txt</string>
+        <string>LICENSES/zlib-ng.txt</string>
         <key>name</key>
-        <string>zlib</string>
+        <string>zlib-ng</string>
         <key>platforms</key>
         <map>
-          <key>darwin</key>
-          <map>
-            <key>archive</key>
-            <map>
-              <key>hash</key>
-              <string>1a79eeac199c2d94e4ae4e5d0194e25f</string>
-              <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/zlib_3p-update-zlib/rev/296881/arch/Darwin/installer/zlib-1.2.8.296881-darwin-296881.tar.bz2</string>
-            </map>
-            <key>name</key>
-            <string>darwin</string>
-          </map>
           <key>darwin64</key>
           <map>
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>9181bc8229f1a8e480d2a40a2744ec28</string>
+              <string>bf306e38bf81c6095e0967bdef6a2445</string>
               <key>url</key>
-              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/78578/743913/zlib-1.2.11.557041-darwin64-557041.tar.bz2</string>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/87759/805718/zlib_ng-2.0.5.563838-darwin64-563838.tar.bz2</string>
             </map>
             <key>name</key>
             <string>darwin64</string>
           </map>
-          <key>linux</key>
-          <map>
-            <key>archive</key>
-            <map>
-              <key>hash</key>
-              <string>98a8c775c581ca80bb559e8b4e8eaae7</string>
-              <key>hash_algorithm</key>
-              <string>md5</string>
-              <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/p64_3p-zlib/rev/314131/arch/Linux/installer/zlib-1.2.8.314131-linux-314131.tar.bz2</string>
-            </map>
-            <key>name</key>
-            <string>linux</string>
-          </map>
           <key>linux64</key>
           <map>
             <key>archive</key>
@@ -3534,9 +2861,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>8308cbd2ea0fe290541698b0f63482e2</string>
+              <string>8ffce5bd00e3d5afa8cb39b855237c4a</string>
               <key>url</key>
-              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/78579/743926/zlib-1.2.11.557041-windows-557041.tar.bz2</string>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/87761/805730/zlib_ng-2.0.5.563838-windows-563838.tar.bz2</string>
             </map>
             <key>name</key>
             <string>windows</string>
@@ -3546,22 +2873,22 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>36bdc34f67d3ad3c57125dc1b16a3129</string>
+              <string>bd103a9129e57f7ea35886bc7750f8a6</string>
               <key>url</key>
-              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/78577/743920/zlib-1.2.11.557041-windows64-557041.tar.bz2</string>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/87760/805729/zlib_ng-2.0.5.563838-windows64-563838.tar.bz2</string>
             </map>
             <key>name</key>
             <string>windows64</string>
           </map>
         </map>
         <key>version</key>
-        <string>1.2.11.557041</string>
+        <string>2.0.5.563838</string>
       </map>
     </map>
     <key>package_description</key>
     <map>
       <key>canonical_repo</key>
-      <string>https://bitbucket.org/lindenlab/viewer</string>
+      <string>https://github.com/secondlife/viewer</string>
       <key>copyright</key>
       <string>Copyright (c) 2020, Linden Research, Inc.</string>
       <key>description</key>
@@ -3784,126 +3111,6 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
           <key>name</key>
           <string>darwin64</string>
         </map>
-        <key>linux</key>
-        <map>
-          <key>build_directory</key>
-          <string>build-linux-i686</string>
-          <key>configurations</key>
-          <map>
-            <key>RelWithDebInfo</key>
-            <map>
-              <key>build</key>
-              <map>
-                <key>command</key>
-                <string>make</string>
-                <key>options</key>
-                <array>
-                  <string>-j</string>
-                  <string>12</string>
-                </array>
-              </map>
-              <key>configure</key>
-              <map>
-                <key>arguments</key>
-                <array>
-                  <string>../indra</string>
-                </array>
-                <key>options</key>
-                <array>
-                  <string>-G</string>
-                  <string>Unix Makefiles</string>
-                </array>
-              </map>
-              <key>default</key>
-              <string>True</string>
-              <key>name</key>
-              <string>RelWithDebInfo</string>
-            </map>
-            <key>RelWithDebInfoOS</key>
-            <map>
-              <key>build</key>
-              <map>
-                <key>command</key>
-                <string>make</string>
-                <key>options</key>
-                <array>
-                  <string>-j</string>
-                  <string>7</string>
-                </array>
-              </map>
-              <key>configure</key>
-              <map>
-                <key>options</key>
-                <array>
-                  <string>-G</string>
-                  <string>Unix Makefiles</string>
-                </array>
-              </map>
-              <key>name</key>
-              <string>RelWithDebInfoOS</string>
-            </map>
-            <key>Release</key>
-            <map>
-              <key>build</key>
-              <map>
-                <key>command</key>
-                <string>make</string>
-                <key>options</key>
-                <array>
-                  <string>-j</string>
-                  <string>12</string>
-                </array>
-              </map>
-              <key>configure</key>
-              <map>
-                <key>arguments</key>
-                <array>
-                  <string>../indra</string>
-                </array>
-                <key>options</key>
-                <array>
-                  <string>-G</string>
-                  <string>Unix Makefiles</string>
-                </array>
-              </map>
-              <key>name</key>
-              <string>Release</string>
-            </map>
-            <key>ReleaseOS</key>
-            <map>
-              <key>build</key>
-              <map>
-                <key>command</key>
-                <string>make</string>
-                <key>options</key>
-                <array>
-                  <string>-j</string>
-                  <string>7</string>
-                </array>
-              </map>
-              <key>configure</key>
-              <map>
-                <key>options</key>
-                <array>
-                  <string>-G</string>
-                  <string>Unix Makefiles</string>
-                </array>
-              </map>
-              <key>name</key>
-              <string>ReleaseOS</string>
-            </map>
-            <key>default</key>
-            <map>
-              <key>build</key>
-              <map>
-              </map>
-              <key>name</key>
-              <string>default</string>
-            </map>
-          </map>
-          <key>name</key>
-          <string>linux</string>
-        </map>
         <key>windows</key>
         <map>
           <key>build_directory</key>
diff --git a/build.sh b/build.sh
index 1b6dd17a4a8a57fa048c5b9d00202c137adbd93b..89609a9ffd6d3b5b07fa30e6442700b2bf59ce9d 100755
--- a/build.sh
+++ b/build.sh
@@ -155,7 +155,11 @@ pre_build()
     fi
     set -x
 
-    "$autobuild" configure --quiet -c $variant -- \
+    # honor autobuild_configure_parameters same as sling-buildscripts
+    eval_autobuild_configure_parameters=$(eval $(echo echo $autobuild_configure_parameters))
+
+    "$autobuild" configure --quiet -c $variant \
+     ${eval_autobuild_configure_parameters:---} \
      -DPACKAGE:BOOL=ON \
      -DHAVOK:BOOL="$HAVOK" \
      -DRELEASE_CRASH_REPORTING:BOOL="$RELEASE_CRASH_REPORTING" \
@@ -205,7 +209,11 @@ build()
   if $build_viewer
   then
     begin_section "autobuild $variant"
-    "$autobuild" build --no-configure -c $variant || fatal "failed building $variant"
+    # honor autobuild_build_parameters same as sling-buildscripts
+    eval_autobuild_build_parameters=$(eval $(echo echo $autobuild_build_parameters))
+    "$autobuild" build --no-configure -c $variant \
+         $eval_autobuild_build_parameters \
+    || fatal "failed building $variant"
     echo true >"$build_dir"/build_ok
     end_section "autobuild $variant"
     
diff --git a/doc/LGPL-license.txt b/doc/LGPL-license.txt
new file mode 100755
index 0000000000000000000000000000000000000000..4362b49151d7b34ef83b3067a8f9c9f877d72a0e
--- /dev/null
+++ b/doc/LGPL-license.txt
@@ -0,0 +1,502 @@
+                  GNU LESSER GENERAL PUBLIC LICENSE
+                       Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL.  It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it.  You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+  When we speak of free software, we are referring to freedom of use,
+not price.  Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+  To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights.  These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  To protect each distributor, we want to make it very clear that
+there is no warranty for the free library.  Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+  Finally, software patents pose a constant threat to the existence of
+any free program.  We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder.  Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+  Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License.  This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License.  We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+  When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library.  The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom.  The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+  We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License.  It also provides other free software developers Less
+of an advantage over competing non-free programs.  These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries.  However, the Lesser license provides advantages in certain
+special circumstances.
+
+  For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard.  To achieve this, non-free programs must be
+allowed to use the library.  A more frequent case is that a free
+library does the same job as widely used non-free libraries.  In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+  In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software.  For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+  Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+                  GNU LESSER GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+  6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Use a suitable shared library mechanism for linking with the
+    Library.  A suitable mechanism is one that (1) uses at run time a
+    copy of the library already present on the user's computer system,
+    rather than copying library functions into the executable, and (2)
+    will operate properly with a modified version of the library, if
+    the user installs one, as long as the modified version is
+    interface-compatible with the version that the work was made with.
+
+    c) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    d) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    e) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+                            NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+
+           How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/doc/contributions.txt b/doc/contributions.txt
index 669a0cd671904693861788397ad5ce79efe199b2..9368781c9a6cc27e81d9a2a3b4830da743a261eb 100755
--- a/doc/contributions.txt
+++ b/doc/contributions.txt
@@ -223,6 +223,7 @@ Ansariel Hiller
 	MAINT-8723
 	SL-10385
 	SL-10891
+	SL-10675
 	SL-13364
 	SL-13858
 	SL-13697
@@ -235,6 +236,7 @@ Ansariel Hiller
 	SL-15226
 	SL-15227
 	SL-15398
+	SL-18432
 Aralara Rajal
 Arare Chantilly
 	CHUIBUG-191
@@ -278,6 +280,7 @@ Beq Janus
 	SL-14766
 	SL-14927
 	SL-11300
+	SL-15709
 	SL-16021
 Beth Walcher
 Bezilon Kasei
@@ -399,6 +402,7 @@ Cinder Roxley
     STORM-2127
     STORM-2144
     SL-3404
+    SL-17634
 Clara Young
 Coaldust Numbers
     VWR-1095
@@ -819,6 +823,7 @@ Jonathan Yap
 Kadah Coba
 	STORM-1060
     STORM-1843
+    SL-10675
 Jondan Lundquist
 Joosten Briebers
     MAINT-7074
@@ -1107,16 +1112,19 @@ Nicky Dasmijn
 	STORM-1937
 	OPEN-187
 	SL-15234
-    STORM-2010
+	STORM-2010
 	STORM-2082
 	MAINT-6665
 	SL-10291
 	SL-10293
 	SL-11061
-    SL-11072
+	SL-11072
 	SL-13141
 	SL-13642
+	SL-14541
 	SL-16438
+	SL-17218
+	SL-17585
 Nicky Perian
 	OPEN-1
 	STORM-1087
@@ -1370,7 +1378,7 @@ Sovereign Engineer
     MAINT-7343
     SL-11079
     OPEN-343
-    SL-11625
+	SL-11625
     BUG-229030
 	SL-14705
 	SL-14706
@@ -1378,6 +1386,7 @@ Sovereign Engineer
 	SL-14731
 	SL-14732
 	SL-15096
+	SL-16127
 SpacedOut Frye
 	VWR-34
 	VWR-45
diff --git a/doc/sl-logo-dark.png b/doc/sl-logo-dark.png
new file mode 100644
index 0000000000000000000000000000000000000000..fa9ef32aea03eef5d740df05964bb60ddd8b05fd
Binary files /dev/null and b/doc/sl-logo-dark.png differ
diff --git a/indra/CMakeLists.txt b/indra/CMakeLists.txt
index dc1c28ce5b5a34af46455fdcb81f3ad14fa186bf..68f6e962efed0dd73ed23706e4efe6b9ec280550 100644
--- a/indra/CMakeLists.txt
+++ b/indra/CMakeLists.txt
@@ -13,7 +13,6 @@ project(${ROOT_PROJECT_NAME})
 set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
 
 include(Variables)
-include(bugsplat)
 include(BuildVersion)
 
 set(LEGACY_STDIO_LIBS)
@@ -38,6 +37,7 @@ add_subdirectory(${LIBS_OPEN_PREFIX}llkdu)
 add_subdirectory(${LIBS_OPEN_PREFIX}llimagej2coj)
 add_subdirectory(${LIBS_OPEN_PREFIX}llinventory)
 add_subdirectory(${LIBS_OPEN_PREFIX}llmath)
+add_subdirectory(${LIBS_OPEN_PREFIX}llmeshoptimizer)
 add_subdirectory(${LIBS_OPEN_PREFIX}llmessage)
 add_subdirectory(${LIBS_OPEN_PREFIX}llprimitive)
 add_subdirectory(${LIBS_OPEN_PREFIX}llrender)
@@ -72,6 +72,12 @@ if (LINUX)
       include(LLAppearanceUtility)
       add_subdirectory(${LLAPPEARANCEUTILITY_SRC_DIR} ${LLAPPEARANCEUTILITY_BIN_DIR})
   endif (INSTALL_PROPRIETARY)
+  add_dependencies(viewer linux-crash-logger-strip-target)
+elseif (WINDOWS)
+  # cmake EXISTS requires an absolute path, see indra/cmake/Variables.cmake
+  if (EXISTS ${VIEWER_DIR}win_setup)
+    add_subdirectory(${VIEWER_DIR}win_setup)
+  endif (EXISTS ${VIEWER_DIR}win_setup)
 endif (LINUX)
 
 if (WINDOWS)
diff --git a/indra/cmake/00-Common.cmake b/indra/cmake/00-Common.cmake
index f4071793d50e31667a66c12eacabf87c3063911f..572422d080ee97c0b8da58b049a39d4066cb9bfc 100644
--- a/indra/cmake/00-Common.cmake
+++ b/indra/cmake/00-Common.cmake
@@ -42,8 +42,8 @@ if(NON_RELEASE_CRASH_REPORTING)
   set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DLL_SEND_CRASH_REPORTS=1")
 endif()  
 
-# Don't bother with a MinSizeRel build.
-set(CMAKE_CONFIGURATION_TYPES "RelWithDebInfo;Release;Debug" CACHE STRING
+# Don't bother with MinSizeRel or Debug builds.
+set(CMAKE_CONFIGURATION_TYPES "RelWithDebInfo;Release" CACHE STRING
     "Supported build types." FORCE)
 
 
@@ -66,16 +66,21 @@ if (WINDOWS)
   # CP changed to only append the flag for 32bit builds - on 64bit builds,
   # locally at least, the build output is spammed with 1000s of 'D9002'
   # warnings about this switch being ignored.
-  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP")
+  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP")  
   if( ADDRESS_SIZE EQUAL 32 )
     set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /p:PreferredToolArchitecture=x64")  
   endif()
+  # Preserve first-pass-through versions (ie no FORCE overwrite). Prevents recursive addition of /Zo (04/2021)
+  set(OG_CMAKE_CXX_FLAGS_RELEASE ${CMAKE_CXX_FLAGS_RELEASE} CACHE STRING "OG_CXX_FLAGS_RELEASE")
+  set(OG_CMAKE_CXX_FLAGS_RELWITHDEBINFO ${CMAKE_CXX_FLAGS_RELWITHDEBINFO} CACHE STRING "OG_CXX_FLAGS_RELWITHDEBINFO")
+
   set(CMAKE_CXX_FLAGS_RELWITHDEBINFO 
-      "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /Zo"
+      "${OG_CMAKE_CXX_FLAGS_RELWITHDEBINFO} /Zo"
       CACHE STRING "C++ compiler release-with-debug options" FORCE)
   set(CMAKE_CXX_FLAGS_RELEASE
-      "${CMAKE_CXX_FLAGS_RELEASE} ${LL_CXX_FLAGS} /Zo"
+      "${OG_CMAKE_CXX_FLAGS_RELEASE} ${LL_CXX_FLAGS} /Zo"
       CACHE STRING "C++ compiler release options" FORCE)
+  
   # zlib has assembly-language object files incompatible with SAFESEH
   set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /LARGEADDRESSAWARE /SAFESEH:NO /NODEFAULTLIB:LIBCMT /IGNORE:4099")
 
@@ -218,7 +223,6 @@ if (USESYSTEMLIBS)
 
 else (USESYSTEMLIBS)
   set(${ARCH}_linux_INCLUDES
-      ELFIO
       atk-1.0
       glib-2.0
       gstreamer-0.10
diff --git a/indra/cmake/APR.cmake b/indra/cmake/APR.cmake
index 1a01671002597c492ebe60a4c8640bd17921beac..9b64bc6160c6c13236e12957f10421911c055b95 100644
--- a/indra/cmake/APR.cmake
+++ b/indra/cmake/APR.cmake
@@ -1,4 +1,3 @@
-include(BerkeleyDB)
 include(Linking)
 include(Prebuilt)
 
@@ -49,7 +48,7 @@ else (USESYSTEMLIBS)
   set(APR_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include/apr-1)
 
   if (LINUX)
-      list(APPEND APRUTIL_LIBRARIES ${DB_LIBRARIES} uuid)
-    list(APPEND APRUTIL_LIBRARIES ${DB_LIBRARIES} rt)
+      list(APPEND APRUTIL_LIBRARIES uuid)
+      list(APPEND APRUTIL_LIBRARIES rt)
   endif (LINUX)
 endif (USESYSTEMLIBS)
diff --git a/indra/cmake/BerkeleyDB.cmake b/indra/cmake/BerkeleyDB.cmake
deleted file mode 100644
index ee670ac6502d0bdf1f07bf50c6d021b9f2e27732..0000000000000000000000000000000000000000
--- a/indra/cmake/BerkeleyDB.cmake
+++ /dev/null
@@ -1,17 +0,0 @@
-# -*- cmake -*-
-include(Prebuilt)
-set(DB_FIND_QUIETLY ON)
-set(DB_FIND_REQUIRED ON)
-
-if (USESYSTEMLIBS)
-  include(FindBerkeleyDB)
-else (USESYSTEMLIBS)
-  if (LINUX)
-    # Need to add dependency pthread explicitely to support ld.gold.
-    use_prebuilt_binary(db)
-    set(DB_LIBRARIES db-5.1 pthread)
-  else (LINUX)
-    set(DB_LIBRARIES db-4.2)
-  endif (LINUX)
-  set(DB_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/include)
-endif (USESYSTEMLIBS)
diff --git a/indra/cmake/Boost.cmake b/indra/cmake/Boost.cmake
index 06a7ab6d7586306e1a0d408f5ea3e24d11aa58ca..e79dc332450d13b98e422eab4273834e5af4288b 100644
--- a/indra/cmake/Boost.cmake
+++ b/indra/cmake/Boost.cmake
@@ -24,57 +24,30 @@ else (USESYSTEMLIBS)
   set(addrsfx "-x${ADDRESS_SIZE}")
 
   if (WINDOWS)
-    if(MSVC80)
-      # This should be obsolete at this point
-      set(BOOST_VERSION "1.55")
-      set(BOOST_CONTEXT_LIBRARY 
-          optimized libboost_context-vc80-mt-${BOOST_VERSION}
-          debug libboost_context-vc80-mt-gd-${BOOST_VERSION})
-      set(BOOST_FILESYSTEM_LIBRARY 
-          optimized libboost_filesystem-vc80-mt-${BOOST_VERSION}
-          debug libboost_filesystem-vc80-mt-gd-${BOOST_VERSION})
-      set(BOOST_PROGRAM_OPTIONS_LIBRARY 
-          optimized libboost_program_options-vc80-mt-${BOOST_VERSION}
-          debug libboost_program_options-vc80-mt-gd-${BOOST_VERSION})
-      set(BOOST_REGEX_LIBRARY
-          optimized libboost_regex-vc80-mt-${BOOST_VERSION}
-          debug libboost_regex-vc80-mt-gd-${BOOST_VERSION})
-      set(BOOST_SIGNALS_LIBRARY 
-          optimized libboost_signals-vc80-mt-${BOOST_VERSION}
-          debug libboost_signals-vc80-mt-gd-${BOOST_VERSION})
-      set(BOOST_SYSTEM_LIBRARY 
-          optimized libboost_system-vc80-mt-${BOOST_VERSION}
-          debug libboost_system-vc80-mt-gd-${BOOST_VERSION})
-      set(BOOST_THREAD_LIBRARY 
-          optimized libboost_thread-vc80-mt-${BOOST_VERSION}
-          debug libboost_thread-vc80-mt-gd-${BOOST_VERSION})
-    else(MSVC80)
-      # MSVC 10.0 config
-      set(BOOST_CONTEXT_LIBRARY 
-          optimized libboost_context-mt${addrsfx}
-          debug libboost_context-mt${addrsfx}-gd)
-      set(BOOST_FIBER_LIBRARY 
-          optimized libboost_fiber-mt${addrsfx}
-          debug libboost_fiber-mt${addrsfx}-gd)
-      set(BOOST_FILESYSTEM_LIBRARY 
-          optimized libboost_filesystem-mt${addrsfx}
-          debug libboost_filesystem-mt${addrsfx}-gd)
-      set(BOOST_PROGRAM_OPTIONS_LIBRARY 
-          optimized libboost_program_options-mt${addrsfx}
-          debug libboost_program_options-mt${addrsfx}-gd)
-      set(BOOST_REGEX_LIBRARY
-          optimized libboost_regex-mt${addrsfx}
-          debug libboost_regex-mt${addrsfx}-gd)
-      set(BOOST_SIGNALS_LIBRARY 
-          optimized libboost_signals-mt${addrsfx}
-          debug libboost_signals-mt${addrsfx}-gd)
-      set(BOOST_SYSTEM_LIBRARY 
-          optimized libboost_system-mt${addrsfx}
-          debug libboost_system-mt${addrsfx}-gd)
-      set(BOOST_THREAD_LIBRARY 
-          optimized libboost_thread-mt${addrsfx}
-          debug libboost_thread-mt${addrsfx}-gd)
-    endif (MSVC80)
+    set(BOOST_CONTEXT_LIBRARY
+        optimized libboost_context-mt${addrsfx}
+        debug libboost_context-mt${addrsfx}-gd)
+    set(BOOST_FIBER_LIBRARY
+        optimized libboost_fiber-mt${addrsfx}
+        debug libboost_fiber-mt${addrsfx}-gd)
+    set(BOOST_FILESYSTEM_LIBRARY
+        optimized libboost_filesystem-mt${addrsfx}
+        debug libboost_filesystem-mt${addrsfx}-gd)
+    set(BOOST_PROGRAM_OPTIONS_LIBRARY
+        optimized libboost_program_options-mt${addrsfx}
+        debug libboost_program_options-mt${addrsfx}-gd)
+    set(BOOST_REGEX_LIBRARY
+        optimized libboost_regex-mt${addrsfx}
+        debug libboost_regex-mt${addrsfx}-gd)
+    set(BOOST_SIGNALS_LIBRARY
+        optimized libboost_signals-mt${addrsfx}
+        debug libboost_signals-mt${addrsfx}-gd)
+    set(BOOST_SYSTEM_LIBRARY
+        optimized libboost_system-mt${addrsfx}
+        debug libboost_system-mt${addrsfx}-gd)
+    set(BOOST_THREAD_LIBRARY
+        optimized libboost_thread-mt${addrsfx}
+        debug libboost_thread-mt${addrsfx}-gd)
   elseif (LINUX)
     set(BOOST_CONTEXT_LIBRARY
         optimized boost_context-mt${addrsfx}
@@ -103,28 +76,28 @@ else (USESYSTEMLIBS)
   elseif (DARWIN)
     set(BOOST_CONTEXT_LIBRARY
         optimized boost_context-mt${addrsfx}
-        debug boost_context-mt${addrsfx}-d)
+        debug boost_context-mt${addrsfx})
     set(BOOST_FIBER_LIBRARY
         optimized boost_fiber-mt${addrsfx}
-        debug boost_fiber-mt${addrsfx}-d)
+        debug boost_fiber-mt${addrsfx})
     set(BOOST_FILESYSTEM_LIBRARY
         optimized boost_filesystem-mt${addrsfx}
-        debug boost_filesystem-mt${addrsfx}-d)
+        debug boost_filesystem-mt${addrsfx})
     set(BOOST_PROGRAM_OPTIONS_LIBRARY
         optimized boost_program_options-mt${addrsfx}
-        debug boost_program_options-mt${addrsfx}-d)
+        debug boost_program_options-mt${addrsfx})
     set(BOOST_REGEX_LIBRARY
         optimized boost_regex-mt${addrsfx}
-        debug boost_regex-mt${addrsfx}-d)
+        debug boost_regex-mt${addrsfx})
     set(BOOST_SIGNALS_LIBRARY
         optimized boost_signals-mt${addrsfx}
-        debug boost_signals-mt${addrsfx}-d)
+        debug boost_signals-mt${addrsfx})
     set(BOOST_SYSTEM_LIBRARY
         optimized boost_system-mt${addrsfx}
-        debug boost_system-mt${addrsfx}-d)
+        debug boost_system-mt${addrsfx})
     set(BOOST_THREAD_LIBRARY
         optimized boost_thread-mt${addrsfx}
-        debug boost_thread-mt${addrsfx}-d)
+        debug boost_thread-mt${addrsfx})
   endif (WINDOWS)
 endif (USESYSTEMLIBS)
 
diff --git a/indra/cmake/CMakeLists.txt b/indra/cmake/CMakeLists.txt
index d7725670a2e9787dfe9562b9ed8ce304aa30354e..4d700897374423bd9691afeda7b58c1e66c301c8 100644
--- a/indra/cmake/CMakeLists.txt
+++ b/indra/cmake/CMakeLists.txt
@@ -10,7 +10,6 @@ set(cmake_SOURCE_FILES
     00-Common.cmake
     APR.cmake
     Audio.cmake
-    BerkeleyDB.cmake
     Boost.cmake
     bugsplat.cmake
     BuildVersion.cmake
@@ -26,7 +25,6 @@ set(cmake_SOURCE_FILES
     EXPAT.cmake
     FindAPR.cmake
     FindAutobuild.cmake
-    FindBerkeleyDB.cmake
     FindGLH.cmake
     FindHUNSPELL.cmake
     FindJsonCpp.cmake
@@ -35,12 +33,11 @@ set(cmake_SOURCE_FILES
     FindSCP.cmake
     FindURIPARSER.cmake
     FindXmlRpcEpi.cmake
-    FindZLIB.cmake
+    FindZLIBNG.cmake
     FMODSTUDIO.cmake
     FreeType.cmake
     GLEXT.cmake
     GLH.cmake
-    GLOD.cmake
 ##  GStreamer010Plugin.cmake
     GoogleMock.cmake
     Havok.cmake
@@ -59,6 +56,7 @@ set(cmake_SOURCE_FILES
     LLKDU.cmake
     LLLogin.cmake
     LLMath.cmake
+    LLMeshOptimizer.cmake
     LLMessage.cmake
     LLPhysicsExtensions.cmake
     LLPlugin.cmake
@@ -72,6 +70,7 @@ set(cmake_SOURCE_FILES
     LLXML.cmake
     Linking.cmake
     MediaPluginBase.cmake
+    MESHOPTIMIZER.cmake
     NDOF.cmake
     OPENAL.cmake
     OpenGL.cmake
@@ -92,7 +91,7 @@ set(cmake_SOURCE_FILES
     VisualLeakDetector.cmake
     LibVLCPlugin.cmake
     XmlRpcEpi.cmake
-    ZLIB.cmake
+    ZLIBNG.cmake
     )
 
 source_group("Shared Rules" FILES ${cmake_SOURCE_FILES})
diff --git a/indra/cmake/Copy3rdPartyLibs.cmake b/indra/cmake/Copy3rdPartyLibs.cmake
index b20d23ceade2ed54197214cc4118c88df8412f13..ff705101ded51485ee120cc69017823871d68899 100644
--- a/indra/cmake/Copy3rdPartyLibs.cmake
+++ b/indra/cmake/Copy3rdPartyLibs.cmake
@@ -57,7 +57,6 @@ if(WINDOWS)
         libaprutil-1.dll
         libapriconv-1.dll
         nghttp2.dll
-        glod.dll
         libhunspell.dll
         uriparser.dll
         )
@@ -104,6 +103,8 @@ if(WINDOWS)
         set(MSVC_VER 120)
     elseif (MSVC_VERSION GREATER_EQUAL 1910 AND MSVC_VERSION LESS 1920) # Visual Studio 2017
         set(MSVC_VER 140)
+    elseif (MSVC_VERSION GREATER_EQUAL 1920 AND MSVC_VERSION LESS 1930) # Visual Studio 2019
+        set(MSVC_VER 140)
     else (MSVC80)
         MESSAGE(WARNING "New MSVC_VERSION ${MSVC_VERSION} of MSVC: adapt Copy3rdPartyLibs.cmake")
     endif (MSVC80)
@@ -128,6 +129,7 @@ if(WINDOWS)
             msvcp${MSVC_VER}.dll
             msvcr${MSVC_VER}.dll
             vcruntime${MSVC_VER}.dll
+            vcruntime${MSVC_VER}_1.dll
             )
         if(EXISTS "${registry_path}/${release_msvc_file}")
             to_staging_dirs(
@@ -166,7 +168,6 @@ elseif(DARWIN)
         libaprutil-1.0.dylib
         libaprutil-1.dylib
         ${EXPAT_COPY}
-        libGLOD.dylib
         libhunspell-1.3.0.dylib
         libndofdev.dylib
         libnghttp2.dylib
@@ -215,7 +216,6 @@ elseif(LINUX)
         ${EXPAT_COPY}
         libfreetype.so.6.6.2
         libfreetype.so.6
-        libGLOD.so
         libgmodule-2.0.so
         libgobject-2.0.so
         libhunspell-1.3.so.0.0.0
diff --git a/indra/cmake/FindBerkeleyDB.cmake b/indra/cmake/FindBerkeleyDB.cmake
deleted file mode 100644
index 2d633c74ecb3fcd693a9e4ea520eef98249868b8..0000000000000000000000000000000000000000
--- a/indra/cmake/FindBerkeleyDB.cmake
+++ /dev/null
@@ -1,50 +0,0 @@
-# -*- cmake -*-
-
-# - Find BerkeleyDB
-# Find the BerkeleyDB includes and library
-# This module defines
-#  DB_INCLUDE_DIR, where to find db.h, etc.
-#  DB_LIBRARIES, the libraries needed to use BerkeleyDB.
-#  DB_FOUND, If false, do not try to use BerkeleyDB.
-# also defined, but not for general use are
-#  DB_LIBRARY, where to find the BerkeleyDB library.
-
-FIND_PATH(DB_INCLUDE_DIR db.h
-/usr/local/include/db4
-/usr/local/include
-/usr/include/db4
-/usr/include
-)
-
-SET(DB_NAMES ${DB_NAMES} db)
-FIND_LIBRARY(DB_LIBRARY
-  NAMES ${DB_NAMES}
-  PATHS /usr/lib /usr/local/lib
-  )
-
-IF (DB_LIBRARY AND DB_INCLUDE_DIR)
-    SET(DB_LIBRARIES ${DB_LIBRARY})
-    SET(DB_FOUND "YES")
-ELSE (DB_LIBRARY AND DB_INCLUDE_DIR)
-  SET(DB_FOUND "NO")
-ENDIF (DB_LIBRARY AND DB_INCLUDE_DIR)
-
-
-IF (DB_FOUND)
-   IF (NOT DB_FIND_QUIETLY)
-      MESSAGE(STATUS "Found BerkeleyDB: ${DB_LIBRARIES}")
-   ENDIF (NOT DB_FIND_QUIETLY)
-ELSE (DB_FOUND)
-   IF (DB_FIND_REQUIRED)
-      MESSAGE(FATAL_ERROR "Could not find BerkeleyDB library")
-   ENDIF (DB_FIND_REQUIRED)
-ENDIF (DB_FOUND)
-
-# Deprecated declarations.
-SET (NATIVE_DB_INCLUDE_PATH ${DB_INCLUDE_DIR} )
-GET_FILENAME_COMPONENT (NATIVE_DB_LIB_PATH ${DB_LIBRARY} PATH)
-
-MARK_AS_ADVANCED(
-  DB_LIBRARY
-  DB_INCLUDE_DIR
-  )
diff --git a/indra/cmake/FindZLIB.cmake b/indra/cmake/FindZLIB.cmake
deleted file mode 100644
index 03a7db9d6f9c8fecdf75484fff79cc6e667e279b..0000000000000000000000000000000000000000
--- a/indra/cmake/FindZLIB.cmake
+++ /dev/null
@@ -1,46 +0,0 @@
-# -*- cmake -*-
-
-# - Find zlib
-# Find the ZLIB includes and library
-# This module defines
-#  ZLIB_INCLUDE_DIRS, where to find zlib.h, etc.
-#  ZLIB_LIBRARIES, the libraries needed to use zlib.
-#  ZLIB_FOUND, If false, do not try to use zlib.
-#
-# This FindZLIB is about 43 times as fast the one provided with cmake (2.8.x),
-# because it doesn't look up the version of zlib, resulting in a dramatic
-# speed up for configure (from 4 minutes 22 seconds to 6 seconds).
-#
-# Note: Since this file is only used for standalone, the windows
-# specific parts were left out.
-
-FIND_PATH(ZLIB_INCLUDE_DIR zlib.h
-  NO_SYSTEM_ENVIRONMENT_PATH
-  )
-
-FIND_LIBRARY(ZLIB_LIBRARY z)
-
-if (ZLIB_LIBRARY AND ZLIB_INCLUDE_DIR)
-  SET(ZLIB_INCLUDE_DIRS ${ZLIB_INCLUDE_DIR})
-  SET(ZLIB_LIBRARIES ${ZLIB_LIBRARY})
-  SET(ZLIB_FOUND "YES")
-else (ZLIB_LIBRARY AND ZLIB_INCLUDE_DIR)
-  SET(ZLIB_FOUND "NO")
-endif (ZLIB_LIBRARY AND ZLIB_INCLUDE_DIR)
-
-if (ZLIB_FOUND)
-  if (NOT ZLIB_FIND_QUIETLY)
-    message(STATUS "Found ZLIB: ${ZLIB_LIBRARIES}")
-    SET(ZLIB_FIND_QUIETLY TRUE)
-  endif (NOT ZLIB_FIND_QUIETLY)
-else (ZLIB_FOUND)
-  if (ZLIB_FIND_REQUIRED)
-    message(FATAL_ERROR "Could not find ZLIB library")
-  endif (ZLIB_FIND_REQUIRED)
-endif (ZLIB_FOUND)
-
-mark_as_advanced(
-  ZLIB_LIBRARY
-  ZLIB_INCLUDE_DIR
-  )
-
diff --git a/indra/cmake/FindZLIBNG.cmake b/indra/cmake/FindZLIBNG.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..6e3c8cdddbfe283f10da559e345655f8dafe055e
--- /dev/null
+++ b/indra/cmake/FindZLIBNG.cmake
@@ -0,0 +1,46 @@
+# -*- cmake -*-
+
+# - Find zlib-ng
+# Find the ZLIB includes and library
+# This module defines
+#  ZLIBNG_INCLUDE_DIRS, where to find zlib.h, etc.
+#  ZLIBNG_LIBRARIES, the libraries needed to use zlib.
+#  ZLIBNG_FOUND, If false, do not try to use zlib.
+#
+# This FindZLIBNG is about 43 times as fast the one provided with cmake (2.8.x),
+# because it doesn't look up the version of zlib, resulting in a dramatic
+# speed up for configure (from 4 minutes 22 seconds to 6 seconds).
+#
+# Note: Since this file is only used for standalone, the windows
+# specific parts were left out.
+
+FIND_PATH(ZLIBNG_INCLUDE_DIR zlib.h
+  NO_SYSTEM_ENVIRONMENT_PATH
+  )
+
+FIND_LIBRARY(ZLIBNG_LIBRARY z)
+
+if (ZLIBNG_LIBRARY AND ZLIBNG_INCLUDE_DIR)
+  SET(ZLIBNG_INCLUDE_DIRS ${ZLIBNG_INCLUDE_DIR})
+  SET(ZLIBNG_LIBRARIES ${ZLIBNG_LIBRARY})
+  SET(ZLIBNG_FOUND "YES")
+else (ZLIBNG_LIBRARY AND ZLIBNG_INCLUDE_DIR)
+  SET(ZLIBNG_FOUND "NO")
+endif (ZLINGB_LIBRARY AND ZLIBNG_INCLUDE_DIR)
+
+if (ZLIBNG_FOUND)
+  if (NOT ZLIBNG_FIND_QUIETLY)
+    message(STATUS "Found ZLIBNG: ${ZLIBNG_LIBRARIES}")
+    SET(ZLIBNG_FIND_QUIETLY TRUE)
+  endif (NOT ZLIBNG_FIND_QUIETLY)
+else (ZLIBNG_FOUND)
+  if (ZLIBNG_FIND_REQUIRED)
+    message(FATAL_ERROR "Could not find ZLIBNG library")
+  endif (ZLIBNG_FIND_REQUIRED)
+endif (ZLIBNG_FOUND)
+
+mark_as_advanced(
+  ZLIBNG_LIBRARY
+  ZLIBNG_INCLUDE_DIR
+  )
+
diff --git a/indra/cmake/GLOD.cmake b/indra/cmake/GLOD.cmake
deleted file mode 100644
index 6f42b44ab8f0b1c6ed9efcbdcd071d518993a8ff..0000000000000000000000000000000000000000
--- a/indra/cmake/GLOD.cmake
+++ /dev/null
@@ -1,11 +0,0 @@
-# -*- cmake -*-
-include(Prebuilt)
-
-if (NOT USESYSTEMLIBS)
-  use_prebuilt_binary(glod)
-endif (NOT USESYSTEMLIBS)
-
-set(GLODLIB ON CACHE BOOL "Using GLOD library")
-
-set(GLOD_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include)
-set(GLOD_LIBRARIES GLOD)
diff --git a/indra/cmake/LLAppearanceUtility.cmake b/indra/cmake/LLAppearanceUtility.cmake
index 28b49bf75f73c8f532b9bc4726edff3f4b31915e..0eb3c723d5df360a7a904d0a3f23c8203c8caaa2 100644
--- a/indra/cmake/LLAppearanceUtility.cmake
+++ b/indra/cmake/LLAppearanceUtility.cmake
@@ -10,5 +10,3 @@ if (INSTALL_PROPRIETARY)
         set(LLAPPEARANCEUTILITY_BIN_DIR ${CMAKE_BINARY_DIR}/llappearanceutility)
     endif (LINUX)
 endif (INSTALL_PROPRIETARY)
-
-
diff --git a/indra/cmake/LLCommon.cmake b/indra/cmake/LLCommon.cmake
index 8900419f9b3465e24935b773fc3cb7a1c2f70178..53871791fdd0e42a6519e6e6fb1c191552eeae99 100644
--- a/indra/cmake/LLCommon.cmake
+++ b/indra/cmake/LLCommon.cmake
@@ -3,12 +3,14 @@
 include(APR)
 include(Boost)
 include(EXPAT)
-include(ZLIB)
+include(Tracy)
+include(ZLIBNG)
 
 set(LLCOMMON_INCLUDE_DIRS
     ${LIBS_OPEN_DIR}/llcommon
     ${APRUTIL_INCLUDE_DIR}
     ${APR_INCLUDE_DIR}
+    ${TRACY_INCLUDE_DIR}
     )
 set(LLCOMMON_SYSTEM_INCLUDE_DIRS
     ${Boost_INCLUDE_DIRS}
@@ -30,7 +32,8 @@ else (LINUX)
         ${BOOST_FIBER_LIBRARY} 
         ${BOOST_CONTEXT_LIBRARY} 
         ${BOOST_THREAD_LIBRARY} 
-        ${BOOST_SYSTEM_LIBRARY} )
+        ${BOOST_SYSTEM_LIBRARY}
+        )
 endif (LINUX)
 
 set(LLCOMMON_LINK_SHARED OFF CACHE BOOL "Build the llcommon target as a static library.")
diff --git a/indra/cmake/LLMeshOptimizer.cmake b/indra/cmake/LLMeshOptimizer.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..b79944f61875a2cffef4f51e06a531fc5d4479c2
--- /dev/null
+++ b/indra/cmake/LLMeshOptimizer.cmake
@@ -0,0 +1,7 @@
+# -*- cmake -*-
+
+set(LLMESHOPTIMIZER_INCLUDE_DIRS
+    ${LIBS_OPEN_DIR}/llmeshoptimizer
+    )
+
+set(LLMESHOPTIMIZER_LIBRARIES llmeshoptimizer)
diff --git a/indra/cmake/LLPrimitive.cmake b/indra/cmake/LLPrimitive.cmake
index 93626f689fda6f9ed450bc65696a4d0410f663dd..4e349512156f4d90bead5bd97099ec663c3f3a83 100644
--- a/indra/cmake/LLPrimitive.cmake
+++ b/indra/cmake/LLPrimitive.cmake
@@ -5,6 +5,7 @@ include(Prebuilt)
 include(Boost)
 
 use_prebuilt_binary(colladadom)
+use_prebuilt_binary(minizip-ng) # needed for colladadom
 use_prebuilt_binary(pcre)
 use_prebuilt_binary(libxml2)
 
@@ -22,6 +23,8 @@ if (WINDOWS)
         optimized pcrecpp
         debug pcred
         optimized pcre
+        debug libminizip
+        optimized libminizip
         ${BOOST_SYSTEM_LIBRARIES}
         )
 elseif (DARWIN)
@@ -29,7 +32,7 @@ elseif (DARWIN)
         llprimitive
         debug collada14dom-d
         optimized collada14dom
-        minizip
+        minizip           # for collada libminizip.a
         xml2
         pcrecpp
         pcre
diff --git a/indra/cmake/MESHOPTIMIZER.cmake b/indra/cmake/MESHOPTIMIZER.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..1c5b47b9bddfd81c28eb840b2dae6361eed97d42
--- /dev/null
+++ b/indra/cmake/MESHOPTIMIZER.cmake
@@ -0,0 +1,16 @@
+# -*- cmake -*-
+
+include(Linking)
+include(Prebuilt)
+
+use_prebuilt_binary(meshoptimizer)
+
+if (WINDOWS)
+  set(MESHOPTIMIZER_LIBRARIES meshoptimizer.lib)
+elseif (LINUX)
+  set(MESHOPTIMIZER_LIBRARIES meshoptimizer.o)
+elseif (DARWIN)
+  set(MESHOPTIMIZER_LIBRARIES libmeshoptimizer.a)
+endif (WINDOWS)
+
+set(MESHOPTIMIZER_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/include/meshoptimizer)
diff --git a/indra/cmake/Tracy.cmake b/indra/cmake/Tracy.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..cfff956bcf82f8c64a554c570471fc7905e62506
--- /dev/null
+++ b/indra/cmake/Tracy.cmake
@@ -0,0 +1,29 @@
+# -*- cmake -*-
+include(Prebuilt)
+
+set(USE_TRACY OFF CACHE BOOL "Use Tracy profiler.")
+
+if (USE_TRACY)
+  set(TRACY_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include/tracy) 
+
+# See: indra/llcommon/llprofiler.h
+  add_definitions(-DLL_PROFILER_CONFIGURATION=3)
+  use_prebuilt_binary(tracy)
+
+  if (WINDOWS)
+    MESSAGE(STATUS "Including Tracy for Windows: '${TRACY_INCLUDE_DIR}'")
+  endif (WINDOWS)
+
+  if (DARWIN)
+    MESSAGE(STATUS "Including Tracy for Darwin: '${TRACY_INCLUDE_DIR}'")
+  endif (DARWIN)
+
+  if (LINUX)
+    MESSAGE(STATUS "Including Tracy for Linux: '${TRACY_INCLUDE_DIR}'")
+  endif (LINUX)
+else (USE_TRACY)
+  # Tracy.cmake should not set LLCOMMON_INCLUDE_DIRS, let LLCommon.cmake do that
+  set(TRACY_INCLUDE_DIR "")
+  set(TRACY_LIBRARY "")
+endif (USE_TRACY)
+
diff --git a/indra/cmake/ZLIB.cmake b/indra/cmake/ZLIBNG.cmake
similarity index 71%
rename from indra/cmake/ZLIB.cmake
rename to indra/cmake/ZLIBNG.cmake
index 6cff0753b25f5d6ea55448bd866e27ce8609a2f9..1f46a23d92c9ffc8e5081d8c82e857cb853b2d0d 100644
--- a/indra/cmake/ZLIB.cmake
+++ b/indra/cmake/ZLIBNG.cmake
@@ -1,17 +1,17 @@
 # -*- cmake -*-
 
-set(ZLIB_FIND_QUIETLY ON)
-set(ZLIB_FIND_REQUIRED ON)
+set(ZLIBNG_FIND_QUIETLY ON)
+set(ZLIBNG_FIND_REQUIRED ON)
 
 include(Prebuilt)
 
 if (USESYSTEMLIBS)
-  include(FindZLIB)
+  include(FindZLIBNG)
 else (USESYSTEMLIBS)
-  use_prebuilt_binary(zlib)
+  use_prebuilt_binary(zlib-ng)
   if (WINDOWS)
-    set(ZLIB_LIBRARIES 
-      debug zlibd
+    set(ZLIBNG_LIBRARIES 
+      debug zlib
       optimized zlib)
   elseif (LINUX)
     #
@@ -26,10 +26,10 @@ else (USESYSTEMLIBS)
     # second whole-archive load of the archive.  See viewer's
     # CMakeLists.txt for more information.
     #
-    set(ZLIB_PRELOAD_ARCHIVES -Wl,--whole-archive z -Wl,--no-whole-archive)
-    set(ZLIB_LIBRARIES z)
+    set(ZLIBNG_PRELOAD_ARCHIVES -Wl,--whole-archive z -Wl,--no-whole-archive)
+    set(ZLIBNG_LIBRARIES z)
   elseif (DARWIN)
-    set(ZLIB_LIBRARIES z)
+    set(ZLIBNG_LIBRARIES z)
   endif (WINDOWS)
-  set(ZLIB_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/include/zlib)
+  set(ZLIBNG_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/include/zlib-ng)
 endif (USESYSTEMLIBS)
diff --git a/indra/doxygen/CMakeLists.txt b/indra/doxygen/CMakeLists.txt
index 84188bd32f9592762a34fc9d9ebc23006b33eff3..616b5cd09c9b81044f03fde6e7ef7d598638b5fb 100644
--- a/indra/doxygen/CMakeLists.txt
+++ b/indra/doxygen/CMakeLists.txt
@@ -4,7 +4,7 @@
 # other commands to guarantee full compatibility
 # with the version specified
 ## prior to 2.8, the add_custom_target commands used in setting the version did not work correctly
-cmake_minimum_required(VERSION 2.8.8 FATAL_ERROR)
+cmake_minimum_required(VERSION 3.8.0 FATAL_ERROR)
 
 set(ROOT_PROJECT_NAME "SecondLife" CACHE STRING
     "The root project/makefile/solution name. Defaults to SecondLife.")
diff --git a/indra/edit-me-to-trigger-new-build.txt b/indra/edit-me-to-trigger-new-build.txt
index ade83202cf50a82a89bf0452c09a764542370560..eab7c17b71d5a7bf2c6444aa88a346d5e0c74d0d 100644
--- a/indra/edit-me-to-trigger-new-build.txt
+++ b/indra/edit-me-to-trigger-new-build.txt
@@ -1,3 +1,4 @@
 euclid 5/29/2020
 euclid 7/23/2020
 euclid 4/29/2021
+euclid 10/5/2021 DRTVWR-546
diff --git a/indra/lib/python/indra/util/llmanifest.py b/indra/lib/python/indra/util/llmanifest.py
index 30b722828911625513ae31220e8fcf9ac35e41a4..5b277846b750e79f765267217415e0f2b4fccf1e 100755
--- a/indra/lib/python/indra/util/llmanifest.py
+++ b/indra/lib/python/indra/util/llmanifest.py
@@ -83,8 +83,7 @@ def proper_windows_path(path, current_platform = sys.platform):
         return drive_letter.upper() + ':\\' + rel.replace('/', '\\')
 
 def get_default_platform(dummy):
-    return {'linux2':'linux',
-            'linux1':'linux',
+    return {'linux':'linux',
             'cygwin':'windows',
             'win32':'windows',
             'darwin':'darwin'
@@ -881,6 +880,49 @@ def try_path(src):
         # particular, let caller notice 0.
         return count
 
+    def path_optional(self, src, dst=None):
+        sys.stdout.flush()
+        if src == None:
+            raise ManifestError("No source file, dst is " + dst)
+        if dst == None:
+            dst = src
+        dst = os.path.join(self.get_dst_prefix(), dst)
+        sys.stdout.write("Processing %s => %s ... " % (src, self._relative_dst_path(dst)))
+
+        def try_path(src):
+            # expand globs
+            count = 0
+            if self.wildcard_pattern.search(src):
+                for s,d in self.expand_globs(src, dst):
+                    assert(s != d)
+                    count += self.process_file(s, d)
+            else:
+                # if we're specifying a single path (not a glob),
+                # we should error out if it doesn't exist
+                self.check_file_exists(src)
+                count += self.process_either(src, dst)
+            return count
+
+        try_prefixes = [self.get_src_prefix(), self.get_artwork_prefix(), self.get_build_prefix()]
+        for pfx in try_prefixes:
+            try:
+                count = try_path(os.path.join(pfx, src))
+            except MissingError:
+                # if we produce MissingError, just try the next prefix
+                continue
+            # If we actually found nonzero files, stop looking
+            if count:
+                break
+        else:
+            sys.stdout.write("Skipping %s\n" % (src))
+            return 0
+
+        print("%d files" % count)
+
+        # Let caller check whether we processed as many files as expected. In
+        # particular, let caller notice 0.
+        return count
+
     def do(self, *actions):
         self.actions = actions
         self.construct()
diff --git a/indra/llappearance/llavatarappearance.cpp b/indra/llappearance/llavatarappearance.cpp
index 90dfa04f2889cdd5caa00d19c2c93ac050db5a21..f0df3e147489ae16b7752ae5a6892dd3a8db2cd3 100644
--- a/indra/llappearance/llavatarappearance.cpp
+++ b/indra/llappearance/llavatarappearance.cpp
@@ -927,6 +927,9 @@ BOOL LLAvatarAppearance::loadAvatar()
 		return FALSE;
 	}
 
+	// initialize mJointAliasMap
+	getJointAliases();
+
 	// avatar_lad.xml : <skeleton>
 	if( !loadSkeletonNode() )
 	{
@@ -1047,7 +1050,6 @@ BOOL LLAvatarAppearance::loadAvatar()
 			return FALSE;
 		}
 	}
-
 	
 	return TRUE;
 }
@@ -1590,7 +1592,7 @@ BOOL LLAvatarAppearance::allocateCollisionVolumes( U32 num )
         delete_and_clear_array(mCollisionVolumes);
         mNumCollisionVolumes = 0;
 
-        mCollisionVolumes = new(std::nothrow) LLAvatarJointCollisionVolume[num];
+        mCollisionVolumes = new LLAvatarJointCollisionVolume[num];
         if (!mCollisionVolumes)
         {
             LL_WARNS() << "Failed to allocate collision volumes" << LL_ENDL;
diff --git a/indra/llappearance/lldriverparam.h b/indra/llappearance/lldriverparam.h
index f278dcc2e29b0746afa157676bcf88603f832967..a6261b507b3bf61513943a8a69882f3f21777079 100644
--- a/indra/llappearance/lldriverparam.h
+++ b/indra/llappearance/lldriverparam.h
@@ -77,73 +77,63 @@ class LLDriverParamInfo : public LLViewerVisualParamInfo
 
 //-----------------------------------------------------------------------------
 
-LL_ALIGN_PREFIX(16)
-class LLDriverParam : public LLViewerVisualParam
+class alignas(16) LLDriverParam : public LLViewerVisualParam
 {
+    LL_ALIGN_NEW
 private:
-	// Hide the default constructor.  Force construction with LLAvatarAppearance.
-	LLDriverParam() {}
+    // Hide the default constructor.  Force construction with LLAvatarAppearance.
+    LLDriverParam() {}
 public:
-	LLDriverParam(LLAvatarAppearance *appearance, LLWearable* wearable = NULL);
-	~LLDriverParam();
-
-	void* operator new(size_t size)
-	{
-		return ll_aligned_malloc_16(size);
-	}
-
-	void operator delete(void* ptr)
-	{
-		ll_aligned_free_16(ptr);
-	}
-
-	// Special: These functions are overridden by child classes
-	LLDriverParamInfo*		getInfo() const { return (LLDriverParamInfo*)mInfo; }
-	//   This sets mInfo and calls initialization functions
-	BOOL					setInfo(LLDriverParamInfo *info);
-
-	LLAvatarAppearance* getAvatarAppearance() { return mAvatarAppearance; }
-	const LLAvatarAppearance* getAvatarAppearance() const { return mAvatarAppearance; }
-
-	void					updateCrossDrivenParams(LLWearableType::EType driven_type);
-
-	/*virtual*/ LLViewerVisualParam* cloneParam(LLWearable* wearable) const;
-
-	// LLVisualParam Virtual functions
-	/*virtual*/ void				apply( ESex sex ) {} // apply is called separately for each driven param.
-	/*virtual*/ void				setWeight(F32 weight);
-	/*virtual*/ void				setAnimationTarget( F32 target_value);
-	/*virtual*/ void				stopAnimating();
-	/*virtual*/ BOOL				linkDrivenParams(visual_param_mapper mapper, BOOL only_cross_params);
-	/*virtual*/ void				resetDrivenParams();
-	
-	// LLViewerVisualParam Virtual functions
-	/*virtual*/ F32					getTotalDistortion();
-	/*virtual*/ const LLVector4a&	getAvgDistortion();
-	/*virtual*/ F32					getMaxDistortion();
-	/*virtual*/ LLVector4a			getVertexDistortion(S32 index, LLPolyMesh *poly_mesh);
-	/*virtual*/ const LLVector4a*	getFirstDistortion(U32 *index, LLPolyMesh **poly_mesh);
-	/*virtual*/ const LLVector4a*	getNextDistortion(U32 *index, LLPolyMesh **poly_mesh);
-
-	S32								getDrivenParamsCount() const;
-	const LLViewerVisualParam*		getDrivenParam(S32 index) const;
-
-	typedef std::vector<LLDrivenEntry> entry_list_t;
-    entry_list_t&                   getDrivenList() { return mDriven; }
+    LLDriverParam(LLAvatarAppearance* appearance, LLWearable* wearable = NULL);
+    ~LLDriverParam();
+
+    // Special: These functions are overridden by child classes
+    LLDriverParamInfo* getInfo() const { return (LLDriverParamInfo*)mInfo; }
+    //   This sets mInfo and calls initialization functions
+    BOOL					setInfo(LLDriverParamInfo* info);
+
+    LLAvatarAppearance* getAvatarAppearance() { return mAvatarAppearance; }
+    const LLAvatarAppearance* getAvatarAppearance() const { return mAvatarAppearance; }
+
+    void					updateCrossDrivenParams(LLWearableType::EType driven_type);
+
+    /*virtual*/ LLViewerVisualParam* cloneParam(LLWearable* wearable) const;
+
+    // LLVisualParam Virtual functions
+    /*virtual*/ void				apply(ESex sex) {} // apply is called separately for each driven param.
+    /*virtual*/ void				setWeight(F32 weight);
+    /*virtual*/ void				setAnimationTarget(F32 target_value);
+    /*virtual*/ void				stopAnimating();
+    /*virtual*/ BOOL				linkDrivenParams(visual_param_mapper mapper, BOOL only_cross_params);
+    /*virtual*/ void				resetDrivenParams();
+
+    // LLViewerVisualParam Virtual functions
+    /*virtual*/ F32					getTotalDistortion();
+    /*virtual*/ const LLVector4a& getAvgDistortion();
+    /*virtual*/ F32					getMaxDistortion();
+    /*virtual*/ LLVector4a			getVertexDistortion(S32 index, LLPolyMesh* poly_mesh);
+    /*virtual*/ const LLVector4a* getFirstDistortion(U32* index, LLPolyMesh** poly_mesh);
+    /*virtual*/ const LLVector4a* getNextDistortion(U32* index, LLPolyMesh** poly_mesh);
+
+    S32								getDrivenParamsCount() const;
+    const LLViewerVisualParam* getDrivenParam(S32 index) const;
+
+    typedef std::vector<LLDrivenEntry> entry_list_t;
+    entry_list_t& getDrivenList() { return mDriven; }
     void                            setDrivenList(entry_list_t& driven_list) { mDriven = driven_list; }
 
 protected:
-	LLDriverParam(const LLDriverParam& pOther);
-	F32 getDrivenWeight(const LLDrivenEntry* driven, F32 input_weight);
-	void setDrivenWeight(LLDrivenEntry *driven, F32 driven_weight);
-
-
-	LL_ALIGN_16(LLVector4a	mDefaultVec); // temp holder
-	entry_list_t mDriven;
-	LLViewerVisualParam* mCurrentDistortionParam;
-	// Backlink only; don't make this an LLPointer.
-	LLAvatarAppearance* mAvatarAppearance;
-	LLWearable* mWearablep;
-} LL_ALIGN_POSTFIX(16);
+    LLDriverParam(const LLDriverParam& pOther);
+    F32 getDrivenWeight(const LLDrivenEntry* driven, F32 input_weight);
+    void setDrivenWeight(LLDrivenEntry* driven, F32 driven_weight);
+
+
+    LL_ALIGN_16(LLVector4a	mDefaultVec); // temp holder
+    entry_list_t mDriven;
+    LLViewerVisualParam* mCurrentDistortionParam;
+    // Backlink only; don't make this an LLPointer.
+    LLAvatarAppearance* mAvatarAppearance;
+    LLWearable* mWearablep;
+};
 
 #endif  // LL_LLDRIVERPARAM_H
diff --git a/indra/llappearance/llpolymesh.cpp b/indra/llappearance/llpolymesh.cpp
index 0a7a8d27bbfa701e701286aa6ce62a6ebeba5ab7..3892e4ce43ee75625f1d8aa179741f59357633ed 100644
--- a/indra/llappearance/llpolymesh.cpp
+++ b/indra/llappearance/llpolymesh.cpp
@@ -612,14 +612,16 @@ BOOL LLPolyMeshSharedData::loadMesh( const std::string& fileName )
                                         // we reached the end of the morphs
                                         break;
                                 }
-                                LLPolyMorphData* morph_data = new LLPolyMorphData(std::string(morphName));
+                                std::string morph_name(morphName);
+                                LLPolyMorphData* morph_data = new LLPolyMorphData(morph_name);
 
                                 BOOL result = morph_data->loadBinary(fp, this);
 
                                 if (!result)
                                 {
-                                        delete morph_data;
-                                        continue;
+                                    LL_WARNS() << "Failure loading " << morph_name << " from " << fileName << LL_ENDL;
+                                    delete morph_data;
+                                    continue;
                                 }
 
                                 mMorphData.insert(morph_data);
diff --git a/indra/llappearance/llpolymorph.cpp b/indra/llappearance/llpolymorph.cpp
index ce7010984a0c74995873c02ce120116889c2141d..84dd6156a9424387298eb499b52e424b88d107bf 100644
--- a/indra/llappearance/llpolymorph.cpp
+++ b/indra/llappearance/llpolymorph.cpp
@@ -156,7 +156,9 @@ BOOL LLPolyMorphData::loadBinary(LLFILE *fp, LLPolyMeshSharedData *mesh)
 
 		if (mVertexIndices[v] > 10000)
 		{
-			LL_ERRS() << "Bad morph index: " << mVertexIndices[v] << LL_ENDL;
+            // Bad install? These are usually .llm files from 'character' fodler
+			LL_WARNS() << "Bad morph index " << v << ": " << mVertexIndices[v] << LL_ENDL;
+            return FALSE;
 		}
 
 
@@ -539,8 +541,6 @@ F32	LLPolyMorphTarget::getMaxDistortion()
 //-----------------------------------------------------------------------------
 // apply()
 //-----------------------------------------------------------------------------
-static LLTrace::BlockTimerStatHandle FTM_APPLY_MORPH_TARGET("Apply Morph");
-
 void LLPolyMorphTarget::apply( ESex avatar_sex )
 {
 	if (!mMorphData || mNumMorphMasksPending > 0)
@@ -548,7 +548,7 @@ void LLPolyMorphTarget::apply( ESex avatar_sex )
 		return;
 	}
 
-	LL_RECORD_BLOCK_TIME(FTM_APPLY_MORPH_TARGET);
+    LL_PROFILE_ZONE_SCOPED;
 
 	mLastSex = avatar_sex;
 
diff --git a/indra/llappearance/llpolymorph.h b/indra/llappearance/llpolymorph.h
index c6133cd83119605a7f2085db8ea9e1f37966658b..29cd373636263e14cc9a637e1c590fbcf8fdff86 100644
--- a/indra/llappearance/llpolymorph.h
+++ b/indra/llappearance/llpolymorph.h
@@ -41,24 +41,14 @@ class LLWearable;
 //-----------------------------------------------------------------------------
 // LLPolyMorphData()
 //-----------------------------------------------------------------------------
-LL_ALIGN_PREFIX(16)
-class LLPolyMorphData
+class alignas(16) LLPolyMorphData
 {
+    LL_ALIGN_NEW
 public:
 	LLPolyMorphData(const std::string& morph_name);
 	~LLPolyMorphData();
 	LLPolyMorphData(const LLPolyMorphData &rhs);
 
-	void* operator new(size_t size)
-	{
-		return ll_aligned_malloc_16(size);
-	}
-
-	void operator delete(void* ptr)
-	{
-		ll_aligned_free_16(ptr);
-	}
-
 	BOOL			loadBinary(LLFILE* fp, LLPolyMeshSharedData *mesh);
 	const std::string& getName() { return mName; }
 
@@ -76,7 +66,7 @@ class LLPolyMorphData
 
 	F32					mTotalDistortion;	// vertex distortion summed over entire morph
 	F32					mMaxDistortion;		// maximum single vertex distortion in a given morph
-	LL_ALIGN_16(LLVector4a			mAvgDistortion);		// average vertex distortion, to infer directionality of the morph
+	LLVector4a			mAvgDistortion;		// average vertex distortion, to infer directionality of the morph
 	LLPolyMeshSharedData*	mMesh;
 
 private:
@@ -154,8 +144,9 @@ class LLPolyMorphTargetInfo : public LLViewerVisualParamInfo
 // These morph targets must be topologically consistent with a given Polymesh
 // (share face sets)
 //-----------------------------------------------------------------------------
-class LLPolyMorphTarget : public LLViewerVisualParam
+class alignas(16) LLPolyMorphTarget : public LLViewerVisualParam
 {
+    LL_ALIGN_NEW
 public:
 	LLPolyMorphTarget(LLPolyMesh *poly_mesh);
 	~LLPolyMorphTarget();
@@ -184,16 +175,6 @@ class LLPolyMorphTarget : public LLViewerVisualParam
 
     void    applyVolumeChanges(F32 delta_weight); // SL-315 - for resetSkeleton()
 
-	void* operator new(size_t size)
-	{
-		return ll_aligned_malloc_16(size);
-	}
-
-	void operator delete(void* ptr)
-	{
-		ll_aligned_free_16(ptr);
-	}
-
 protected:
 	LLPolyMorphTarget(const LLPolyMorphTarget& pOther);
 
diff --git a/indra/llappearance/llpolyskeletaldistortion.cpp b/indra/llappearance/llpolyskeletaldistortion.cpp
index ae38c25dbf1f316d7fa7f44e1e0047d39e217360..360f17508fdba828c8431a7dc23789d19f95a1f7 100644
--- a/indra/llappearance/llpolyskeletaldistortion.cpp
+++ b/indra/llappearance/llpolyskeletaldistortion.cpp
@@ -188,11 +188,9 @@ BOOL LLPolySkeletalDistortion::setInfo(LLPolySkeletalDistortionInfo *info)
 //-----------------------------------------------------------------------------
 // apply()
 //-----------------------------------------------------------------------------
-static LLTrace::BlockTimerStatHandle FTM_POLYSKELETAL_DISTORTION_APPLY("Skeletal Distortion");
-
 void LLPolySkeletalDistortion::apply( ESex avatar_sex )
 {
-    LL_RECORD_BLOCK_TIME(FTM_POLYSKELETAL_DISTORTION_APPLY);
+    LL_PROFILE_ZONE_SCOPED;
 
     F32 effective_weight = ( getSex() & avatar_sex ) ? mCurWeight : getDefaultWeight();
 
diff --git a/indra/llappearance/llpolyskeletaldistortion.h b/indra/llappearance/llpolyskeletaldistortion.h
index ab1a132d1902f6de8962edddfecda97ef996651d..585d85f055e51b9043a49247b384a7927dc0b708 100644
--- a/indra/llappearance/llpolyskeletaldistortion.h
+++ b/indra/llappearance/llpolyskeletaldistortion.h
@@ -62,9 +62,9 @@ struct LLPolySkeletalBoneInfo
 	BOOL mHasPositionDeformation;
 };
 
-LL_ALIGN_PREFIX(16)
-class LLPolySkeletalDistortionInfo : public LLViewerVisualParamInfo
+class alignas(16) LLPolySkeletalDistortionInfo : public LLViewerVisualParamInfo
 {
+    LL_ALIGN_NEW
 	friend class LLPolySkeletalDistortion;
 public:
 	
@@ -73,19 +73,6 @@ class LLPolySkeletalDistortionInfo : public LLViewerVisualParamInfo
 	
 	/*virtual*/ BOOL parseXml(LLXmlTreeNode* node);
 
-
-
-	void* operator new(size_t size)
-	{
-		return ll_aligned_malloc_16(size);
-	}
-
-	void operator delete(void* ptr)
-	{
-		ll_aligned_free_16(ptr);
-	}
-
-
 protected:
 	typedef std::vector<LLPolySkeletalBoneInfo> bone_info_list_t;
 	bone_info_list_t mBoneInfoList;
@@ -95,19 +82,10 @@ class LLPolySkeletalDistortionInfo : public LLViewerVisualParamInfo
 // LLPolySkeletalDeformation
 // A set of joint scale data for deforming the avatar mesh
 //-----------------------------------------------------------------------------
-class LLPolySkeletalDistortion : public LLViewerVisualParam
+class alignas(16) LLPolySkeletalDistortion : public LLViewerVisualParam
 {
+    LL_ALIGN_NEW
 public:
-	void* operator new(size_t size)
-	{
-		return ll_aligned_malloc_16(size);
-	}
-
-	void operator delete(void* ptr)
-	{
-		ll_aligned_free_16(ptr);
-	}
-
 	LLPolySkeletalDistortion(LLAvatarAppearance *avatarp);
 	~LLPolySkeletalDistortion();
 
diff --git a/indra/llappearance/lltexlayer.cpp b/indra/llappearance/lltexlayer.cpp
index a4600069ced78f3b4651a51f1d8797628f51e897..3430a255368e7f10c4e583e5418ca578d491787b 100644
--- a/indra/llappearance/lltexlayer.cpp
+++ b/indra/llappearance/lltexlayer.cpp
@@ -142,17 +142,8 @@ BOOL LLTexLayerSetBuffer::renderTexLayerSet(LLRenderTarget* bound_target)
 
 	BOOL success = TRUE;
 	
-	bool use_shaders = LLGLSLShader::sNoFixedFunction;
-
-	if (use_shaders)
-	{
-		gAlphaMaskProgram.bind();
-		gAlphaMaskProgram.setMinimumAlpha(0.004f);
-	}
-	else
-	{
-		gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.00f);
-	}
+	gAlphaMaskProgram.bind();
+	gAlphaMaskProgram.setMinimumAlpha(0.004f);
 
 	LLVertexBuffer::unbind();
 
@@ -164,10 +155,7 @@ BOOL LLTexLayerSetBuffer::renderTexLayerSet(LLRenderTarget* bound_target)
 
 	midRenderTexLayerSet(success);
 
-	if (use_shaders)
-	{
-		gAlphaMaskProgram.unbind();
-	}
+	gAlphaMaskProgram.unbind();
 
 	LLVertexBuffer::unbind();
 	
@@ -390,8 +378,6 @@ BOOL LLTexLayerSet::render( S32 x, S32 y, S32 width, S32 height, LLRenderTarget*
 		}
 	}
 
-	bool use_shaders = LLGLSLShader::sNoFixedFunction;
-
 	LLGLSUIDefault gls_ui;
 	LLGLDepthTest gls_depth(GL_FALSE, GL_FALSE);
 	gGL.setColorMask(true, true);
@@ -400,20 +386,14 @@ BOOL LLTexLayerSet::render( S32 x, S32 y, S32 width, S32 height, LLRenderTarget*
 	{
 		gGL.flush();
 		LLGLDisable no_alpha(GL_ALPHA_TEST);
-		if (use_shaders)
-		{
-			gAlphaMaskProgram.setMinimumAlpha(0.0f);
-		}
+		gAlphaMaskProgram.setMinimumAlpha(0.0f);
 		gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 		gGL.color4f( 0.f, 0.f, 0.f, 1.f );
 
 		gl_rect_2d_simple( width, height );
 
 		gGL.flush();
-		if (use_shaders)
-		{
-			gAlphaMaskProgram.setMinimumAlpha(0.004f);
-		}
+		gAlphaMaskProgram.setMinimumAlpha(0.004f);
 	}
 
 	if (mIsVisible)
@@ -440,10 +420,7 @@ BOOL LLTexLayerSet::render( S32 x, S32 y, S32 width, S32 height, LLRenderTarget*
 
 		gGL.setSceneBlendType(LLRender::BT_REPLACE);
 		LLGLDisable no_alpha(GL_ALPHA_TEST);
-		if (use_shaders)
-		{
-			gAlphaMaskProgram.setMinimumAlpha(0.f);
-		}
+		gAlphaMaskProgram.setMinimumAlpha(0.f);
 
 		gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 		gGL.color4f( 0.f, 0.f, 0.f, 0.f );
@@ -452,10 +429,7 @@ BOOL LLTexLayerSet::render( S32 x, S32 y, S32 width, S32 height, LLRenderTarget*
 		gGL.setSceneBlendType(LLRender::BT_ALPHA);
 
 		gGL.flush();
-		if (use_shaders)
-		{
-			gAlphaMaskProgram.setMinimumAlpha(0.004f);
-		}
+		gAlphaMaskProgram.setMinimumAlpha(0.004f);
 	}
 
 	return success;
@@ -472,32 +446,6 @@ const std::string LLTexLayerSet::getBodyRegionName() const
 	return mInfo->mBodyRegion; 
 }
 
-
-// virtual
-void LLTexLayerSet::asLLSD(LLSD& sd) const
-{
-	sd["visible"] = LLSD::Boolean(isVisible());
-	LLSD layer_list_sd;
-	layer_list_t::const_iterator layer_iter = mLayerList.begin();
-	layer_list_t::const_iterator layer_end  = mLayerList.end();
-	for(; layer_iter != layer_end; ++layer_iter);
-	{
-		LLSD layer_sd;
-		//LLTexLayerInterface* layer = (*layer_iter);
-		//if (layer)
-		//{
-		//	layer->asLLSD(layer_sd);
-		//}
-		layer_list_sd.append(layer_sd);
-	}
-	LLSD mask_list_sd;
-	LLSD info_sd;
-	sd["layers"] = layer_list_sd;
-	sd["masks"] = mask_list_sd;
-	sd["info"] = info_sd;
-}
-
-
 void LLTexLayerSet::destroyComposite()
 {
 	if( mComposite )
@@ -520,10 +468,9 @@ const LLTexLayerSetBuffer* LLTexLayerSet::getComposite() const
 	return mComposite;
 }
 
-static LLTrace::BlockTimerStatHandle FTM_GATHER_MORPH_MASK_ALPHA("gatherMorphMaskAlpha");
 void LLTexLayerSet::gatherMorphMaskAlpha(U8 *data, S32 origin_x, S32 origin_y, S32 width, S32 height, LLRenderTarget* bound_target)
 {
-	LL_RECORD_BLOCK_TIME(FTM_GATHER_MORPH_MASK_ALPHA);
+    LL_PROFILE_ZONE_SCOPED;
 	memset(data, 255, width * height);
 
 	for( layer_list_t::iterator iter = mLayerList.begin(); iter != mLayerList.end(); iter++ )
@@ -536,14 +483,11 @@ void LLTexLayerSet::gatherMorphMaskAlpha(U8 *data, S32 origin_x, S32 origin_y, S
 	renderAlphaMaskTextures(origin_x, origin_y, width, height, bound_target, true);
 }
 
-static LLTrace::BlockTimerStatHandle FTM_RENDER_ALPHA_MASK_TEXTURES("renderAlphaMaskTextures");
 void LLTexLayerSet::renderAlphaMaskTextures(S32 x, S32 y, S32 width, S32 height, LLRenderTarget* bound_target, bool forceClear)
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_MASK_TEXTURES);
+    LL_PROFILE_ZONE_SCOPED;
 	const LLTexLayerSetInfo *info = getInfo();
 	
-	bool use_shaders = LLGLSLShader::sNoFixedFunction;
-
 	gGL.setColorMask(false, true);
 	gGL.setSceneBlendType(LLRender::BT_REPLACE);
 	
@@ -557,7 +501,6 @@ void LLTexLayerSet::renderAlphaMaskTextures(S32 x, S32 y, S32 width, S32 height,
 			{
 				LLGLSUIDefault gls_ui;
 				gGL.getTexUnit(0)->bind(tex);
-				gGL.getTexUnit(0)->setTextureBlendType( LLTexUnit::TB_REPLACE );
 				gl_rect_2d_simple_tex( width, height );
 			}
 		}
@@ -568,20 +511,14 @@ void LLTexLayerSet::renderAlphaMaskTextures(S32 x, S32 y, S32 width, S32 height,
 		// Set the alpha channel to one (clean up after previous blending)
 		gGL.flush();
 		LLGLDisable no_alpha(GL_ALPHA_TEST);
-		if (use_shaders)
-		{
-			gAlphaMaskProgram.setMinimumAlpha(0.f);
-		}
+		gAlphaMaskProgram.setMinimumAlpha(0.f);
 		gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 		gGL.color4f( 0.f, 0.f, 0.f, 1.f );
 		
 		gl_rect_2d_simple( width, height );
 		
 		gGL.flush();
-		if (use_shaders)
-		{
-			gAlphaMaskProgram.setMinimumAlpha(0.004f);
-		}
+		gAlphaMaskProgram.setMinimumAlpha(0.004f);
 	}
 	
 	// (Optional) Mask out part of the baked texture with alpha masks
@@ -589,7 +526,6 @@ void LLTexLayerSet::renderAlphaMaskTextures(S32 x, S32 y, S32 width, S32 height,
 	if (mMaskLayerList.size() > 0)
 	{
 		gGL.setSceneBlendType(LLRender::BT_MULT_ALPHA);
-		gGL.getTexUnit(0)->setTextureBlendType( LLTexUnit::TB_REPLACE );
 		for (layer_list_t::iterator iter = mMaskLayerList.begin(); iter != mMaskLayerList.end(); iter++)
 		{
 			LLTexLayerInterface* layer = *iter;
@@ -602,7 +538,6 @@ void LLTexLayerSet::renderAlphaMaskTextures(S32 x, S32 y, S32 width, S32 height,
 	
 	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 	
-	gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
 	gGL.setColorMask(true, true);
 	gGL.setSceneBlendType(LLRender::BT_ALPHA);
 }
@@ -1128,13 +1063,6 @@ BOOL LLTexLayer::render(S32 x, S32 y, S32 width, S32 height, LLRenderTarget* bou
 	// *TODO: Is this correct?
 	//gPipeline.disableLights();
 	stop_glerror();
-	if (!LLGLSLShader::sNoFixedFunction)
-	{
-		glDisable(GL_LIGHTING);
-	}
-	stop_glerror();
-
-	bool use_shaders = LLGLSLShader::sNoFixedFunction;
 
 	LLColor4 net_color;
 	BOOL color_specified = findNetColor(&net_color);
@@ -1221,10 +1149,7 @@ BOOL LLTexLayer::render(S32 x, S32 y, S32 width, S32 height, LLRenderTarget* bou
 					LLGLDisable alpha_test(no_alpha_test ? GL_ALPHA_TEST : 0);
 					if (no_alpha_test)
 					{
-						if (use_shaders)
-						{
-							gAlphaMaskProgram.setMinimumAlpha(0.f);
-						}
+						gAlphaMaskProgram.setMinimumAlpha(0.f);
 					}
 					
 					LLTexUnit::eTextureAddressMode old_mode = tex->getAddressMode();
@@ -1238,10 +1163,7 @@ BOOL LLTexLayer::render(S32 x, S32 y, S32 width, S32 height, LLRenderTarget* bou
 					gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 					if (no_alpha_test)
 					{
-						if (use_shaders)
-						{
-							gAlphaMaskProgram.setMinimumAlpha(0.004f);
-						}
+						gAlphaMaskProgram.setMinimumAlpha(0.004f);
 					}
 				}
 			}
@@ -1275,18 +1197,12 @@ BOOL LLTexLayer::render(S32 x, S32 y, S32 width, S32 height, LLRenderTarget* bou
 		color_specified )
 	{
 		LLGLDisable no_alpha(GL_ALPHA_TEST);
-		if (use_shaders)
-		{
-			gAlphaMaskProgram.setMinimumAlpha(0.000f);
-		}
+		gAlphaMaskProgram.setMinimumAlpha(0.000f);
 
 		gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 		gGL.color4fv( net_color.mV );
 		gl_rect_2d_simple( width, height );
-		if (use_shaders)
-		{
-			gAlphaMaskProgram.setMinimumAlpha(0.004f);
-		}
+		gAlphaMaskProgram.setMinimumAlpha(0.004f);
 	}
 
 	if( alpha_mask_specified || getInfo()->mWriteAllChannels )
@@ -1374,25 +1290,17 @@ BOOL LLTexLayer::blendAlphaTexture(S32 x, S32 y, S32 width, S32 height)
 
 	gGL.flush();
 	
-	bool use_shaders = LLGLSLShader::sNoFixedFunction;
-
 	if( !getInfo()->mStaticImageFileName.empty() )
 	{
 		LLGLTexture* tex = LLTexLayerStaticImageList::getInstance()->getTexture( getInfo()->mStaticImageFileName, getInfo()->mStaticImageIsMask );
 		if( tex )
 		{
 			LLGLSNoAlphaTest gls_no_alpha_test;
-			if (use_shaders)
-			{
-				gAlphaMaskProgram.setMinimumAlpha(0.f);
-			}
+			gAlphaMaskProgram.setMinimumAlpha(0.f);
 			gGL.getTexUnit(0)->bind(tex, TRUE);
 			gl_rect_2d_simple_tex( width, height );
 			gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
-			if (use_shaders)
-			{
-				gAlphaMaskProgram.setMinimumAlpha(0.004f);
-			}
+			gAlphaMaskProgram.setMinimumAlpha(0.004f);
 		}
 		else
 		{
@@ -1407,18 +1315,11 @@ BOOL LLTexLayer::blendAlphaTexture(S32 x, S32 y, S32 width, S32 height)
 			if (tex)
 			{
 				LLGLSNoAlphaTest gls_no_alpha_test;
-				if (use_shaders)
-				{
-					gAlphaMaskProgram.setMinimumAlpha(0.f);
-				}
+				gAlphaMaskProgram.setMinimumAlpha(0.f);
 				gGL.getTexUnit(0)->bind(tex);
 				gl_rect_2d_simple_tex( width, height );
 				gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
-				success = TRUE;
-				if (use_shaders)
-				{
-					gAlphaMaskProgram.setMinimumAlpha(0.004f);
-				}
+				gAlphaMaskProgram.setMinimumAlpha(0.004f);
 			}
 		}
 	}
@@ -1431,7 +1332,6 @@ BOOL LLTexLayer::blendAlphaTexture(S32 x, S32 y, S32 width, S32 height)
 	addAlphaMask(data, originX, originY, width, height, bound_target);
 }
 
-static LLTrace::BlockTimerStatHandle FTM_RENDER_MORPH_MASKS("renderMorphMasks");
 void LLTexLayer::renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLColor4 &layer_color, LLRenderTarget* bound_target, bool force_render)
 {
 	if (!force_render && !hasMorph())
@@ -1439,18 +1339,12 @@ void LLTexLayer::renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLC
 		LL_DEBUGS() << "skipping renderMorphMasks for " << getUUID() << LL_ENDL;
 		return;
 	}
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_MORPH_MASKS);
+    LL_PROFILE_ZONE_SCOPED;
 	BOOL success = TRUE;
 
 	llassert( !mParamAlphaList.empty() );
 
-	bool use_shaders = LLGLSLShader::sNoFixedFunction;
-
-	if (use_shaders)
-	{
-		gAlphaMaskProgram.setMinimumAlpha(0.f);
-	}
-
+	gAlphaMaskProgram.setMinimumAlpha(0.f);
 	gGL.setColorMask(false, true);
 
 	LLTexLayerParamAlpha* first_param = *mParamAlphaList.begin();
@@ -1535,10 +1429,7 @@ void LLTexLayer::renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLC
 		gl_rect_2d_simple( width, height );
 	}
 
-	if (use_shaders)
-	{
-		gAlphaMaskProgram.setMinimumAlpha(0.004f);
-	}
+	gAlphaMaskProgram.setMinimumAlpha(0.004f);
 
 	LLGLSUIDefault gls_ui;
 
@@ -1637,10 +1528,9 @@ void LLTexLayer::renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLC
 	}
 }
 
-static LLTrace::BlockTimerStatHandle FTM_ADD_ALPHA_MASK("addAlphaMask");
 void LLTexLayer::addAlphaMask(U8 *data, S32 originX, S32 originY, S32 width, S32 height, LLRenderTarget* bound_target)
 {
-	LL_RECORD_BLOCK_TIME(FTM_ADD_ALPHA_MASK);
+    LL_PROFILE_ZONE_SCOPED;
 	S32 size = width * height;
 	const U8* alphaData = getAlphaData();
 	if (!alphaData && hasAlphaParams())
@@ -1981,10 +1871,9 @@ void LLTexLayerStaticImageList::deleteCachedImages()
 
 // Returns an LLImageTGA that contains the encoded data from a tga file named file_name.
 // Caches the result to speed identical subsequent requests.
-static LLTrace::BlockTimerStatHandle FTM_LOAD_STATIC_TGA("getImageTGA");
 LLImageTGA* LLTexLayerStaticImageList::getImageTGA(const std::string& file_name)
 {
-	LL_RECORD_BLOCK_TIME(FTM_LOAD_STATIC_TGA);
+    LL_PROFILE_ZONE_SCOPED;
 	const char *namekey = mImageNames.addString(file_name);
 	image_tga_map_t::const_iterator iter = mStaticImageListTGA.find(namekey);
 	if( iter != mStaticImageListTGA.end() )
@@ -2011,10 +1900,9 @@ LLImageTGA* LLTexLayerStaticImageList::getImageTGA(const std::string& file_name)
 
 // Returns a GL Image (without a backing ImageRaw) that contains the decoded data from a tga file named file_name.
 // Caches the result to speed identical subsequent requests.
-static LLTrace::BlockTimerStatHandle FTM_LOAD_STATIC_TEXTURE("getTexture");
 LLGLTexture* LLTexLayerStaticImageList::getTexture(const std::string& file_name, BOOL is_mask)
 {
-	LL_RECORD_BLOCK_TIME(FTM_LOAD_STATIC_TEXTURE);
+    LL_PROFILE_ZONE_SCOPED;
 	LLPointer<LLGLTexture> tex;
 	const char *namekey = mImageNames.addString(file_name);
 
@@ -2061,10 +1949,9 @@ LLGLTexture* LLTexLayerStaticImageList::getTexture(const std::string& file_name,
 
 // Reads a .tga file, decodes it, and puts the decoded data in image_raw.
 // Returns TRUE if successful.
-static LLTrace::BlockTimerStatHandle FTM_LOAD_IMAGE_RAW("loadImageRaw");
 BOOL LLTexLayerStaticImageList::loadImageRaw(const std::string& file_name, LLImageRaw* image_raw)
 {
-	LL_RECORD_BLOCK_TIME(FTM_LOAD_IMAGE_RAW);
+    LL_PROFILE_ZONE_SCOPED;
 	BOOL success = FALSE;
 	std::string path;
 	path = gDirUtilp->getExpandedFilename(LL_PATH_CHARACTER,file_name);
diff --git a/indra/llappearance/lltexlayer.h b/indra/llappearance/lltexlayer.h
index 6a5040cf0ba69009a22afcbcd4541c65f65513a2..74b421d3eeda70fc1ad3818e47cd8f7a55d58670 100644
--- a/indra/llappearance/lltexlayer.h
+++ b/indra/llappearance/lltexlayer.h
@@ -220,8 +220,6 @@ class LLTexLayerSet
 
 	static BOOL					sHasCaches;
 
-	virtual void				asLLSD(LLSD& sd) const;
-
 protected:
 	typedef std::vector<LLTexLayerInterface *> layer_list_t;
 	layer_list_t				mLayerList;
diff --git a/indra/llappearance/lltexlayerparams.cpp b/indra/llappearance/lltexlayerparams.cpp
index ff682d69069ad15696e65852734dd488e227c39c..ce5c7142d5ccc9d310762105596d30993f03a0c5 100644
--- a/indra/llappearance/lltexlayerparams.cpp
+++ b/indra/llappearance/lltexlayerparams.cpp
@@ -261,10 +261,9 @@ BOOL LLTexLayerParamAlpha::getSkip() const
 }
 
 
-static LLTrace::BlockTimerStatHandle FTM_TEX_LAYER_PARAM_ALPHA("alpha render");
 BOOL LLTexLayerParamAlpha::render(S32 x, S32 y, S32 width, S32 height)
 {
-	LL_RECORD_BLOCK_TIME(FTM_TEX_LAYER_PARAM_ALPHA);
+    LL_PROFILE_ZONE_SCOPED;
 	BOOL success = TRUE;
 
 	if (!mTexLayer)
diff --git a/indra/llappearance/lltexlayerparams.h b/indra/llappearance/lltexlayerparams.h
index 0cb2dedbff869d21e70f45f16ecf166c173a799a..e2440998b34494165b9b574980be015ff9d6a16f 100644
--- a/indra/llappearance/lltexlayerparams.h
+++ b/indra/llappearance/lltexlayerparams.h
@@ -63,23 +63,14 @@ class LLTexLayerParam : public LLViewerVisualParam
 // 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 LL_ALIGN_PREFIX(16)
-class LLTexLayerParamAlpha : public LLTexLayerParam
+class alignas(16) LLTexLayerParamAlpha : public LLTexLayerParam
 {
+    LL_ALIGN_NEW
 public:
 	LLTexLayerParamAlpha( LLTexLayerInterface* layer );
 	LLTexLayerParamAlpha( LLAvatarAppearance* appearance );
 	/*virtual*/ ~LLTexLayerParamAlpha();
 
-	void* operator new(size_t size)
-	{
-		return ll_aligned_malloc_16(size);
-	}
-
-	void operator delete(void* ptr)
-	{
-		ll_aligned_free_16(ptr);
-	}
-
 	/*virtual*/ LLViewerVisualParam* cloneParam(LLWearable* wearable = NULL) const;
 
 	// LLVisualParam Virtual functions
@@ -146,9 +137,9 @@ class LLTexLayerParamAlphaInfo : public LLViewerVisualParamInfo
 //
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-LL_ALIGN_PREFIX(16)
-class LLTexLayerParamColor : public LLTexLayerParam
+class alignas(16) LLTexLayerParamColor : public LLTexLayerParam
 {
+    LL_ALIGN_NEW
 public:
 	enum EColorOperation
 	{
@@ -161,16 +152,6 @@ class LLTexLayerParamColor : public LLTexLayerParam
 	LLTexLayerParamColor( LLTexLayerInterface* layer );
 	LLTexLayerParamColor( LLAvatarAppearance* appearance );
 
-	void* operator new(size_t size)
-	{
-		return ll_aligned_malloc_16(size);
-	}
-
-	void operator delete(void* ptr)
-	{
-		ll_aligned_free_16(ptr);
-	}
-
 	/* virtual */ ~LLTexLayerParamColor();
 
 	/*virtual*/ LLViewerVisualParam* cloneParam(LLWearable* wearable = NULL) const;
@@ -198,8 +179,8 @@ class LLTexLayerParamColor : public LLTexLayerParam
 
 	virtual void onGlobalColorChanged() {}
 private:
-	LL_ALIGN_16(LLVector4a				mAvgDistortionVec);
-} LL_ALIGN_POSTFIX(16);
+	LLVector4a				mAvgDistortionVec;
+};
 
 class LLTexLayerParamColorInfo : public LLViewerVisualParamInfo
 {
diff --git a/indra/llaudio/llaudiodecodemgr.cpp b/indra/llaudio/llaudiodecodemgr.cpp
old mode 100644
new mode 100755
index ff0aa6e76ec2e45ee8a09c80baa2e49846ade6cd..38a6b41afeba8e314db1a95fe4916550fea99942
--- a/indra/llaudio/llaudiodecodemgr.cpp
+++ b/indra/llaudio/llaudiodecodemgr.cpp
@@ -35,6 +35,8 @@
 #include "llendianswizzle.h"
 #include "llassetstorage.h"
 #include "llrefcount.h"
+#include "threadpool.h"
+#include "workqueue.h"
 
 #include "llvorbisencode.h"
 
@@ -45,15 +47,13 @@
 
 extern LLAudioEngine *gAudiop;
 
-LLAudioDecodeMgr *gAudioDecodeMgrp = NULL;
-
 static const S32 WAV_HEADER_SIZE = 44;
 
 
 //////////////////////////////////////////////////////////////////////////////
 
 
-class LLVorbisDecodeState : public LLRefCount
+class LLVorbisDecodeState : public LLThreadSafeRefCount
 {
 public:
 	class WriteResponder : public LLLFSThread::Responder
@@ -532,146 +532,254 @@ void LLVorbisDecodeState::flushBadFile()
 
 class LLAudioDecodeMgr::Impl
 {
-	friend class LLAudioDecodeMgr;
-public:
-	Impl() {};
-	~Impl() {};
+    friend class LLAudioDecodeMgr;
+    Impl();
+  public:
 
-	void processQueue(const F32 num_secs = 0.005);
+    void processQueue();
 
-protected:
-	std::deque<LLUUID> mDecodeQueue;
-	LLPointer<LLVorbisDecodeState> mCurrentDecodep;
+    void startMoreDecodes();
+    void enqueueFinishAudio(const LLUUID &decode_id, LLPointer<LLVorbisDecodeState>& decode_state);
+    void checkDecodesFinished();
+
+  protected:
+    std::deque<LLUUID> mDecodeQueue;
+    std::map<LLUUID, LLPointer<LLVorbisDecodeState>> mDecodes;
 };
 
+LLAudioDecodeMgr::Impl::Impl()
+{
+}
+
+// Returns the in-progress decode_state, which may be an empty LLPointer if
+// there was an error and there is no more work to be done.
+LLPointer<LLVorbisDecodeState> beginDecodingAndWritingAudio(const LLUUID &decode_id);
 
-void LLAudioDecodeMgr::Impl::processQueue(const F32 num_secs)
+// Return true if finished
+bool tryFinishAudio(const LLUUID &decode_id, LLPointer<LLVorbisDecodeState> decode_state);
+
+void LLAudioDecodeMgr::Impl::processQueue()
 {
-	LLUUID uuid;
+    // First, check if any audio from in-progress decodes are ready to play. If
+    // so, mark them ready for playback (or errored, in case of error).
+    checkDecodesFinished();
 
-	LLTimer decode_timer;
+    // Second, start as many decodes from the queue as permitted
+    startMoreDecodes();
+}
 
-	BOOL done = FALSE;
-	while (!done)
-	{
-		if (mCurrentDecodep)
-		{
-			BOOL res;
+void LLAudioDecodeMgr::Impl::startMoreDecodes()
+{
+    llassert_always(gAudiop);
+
+    LL::WorkQueue::ptr_t main_queue = LL::WorkQueue::getInstance("mainloop");
+    // *NOTE: main_queue->postTo casts this refcounted smart pointer to a weak
+    // pointer
+    LL::WorkQueue::ptr_t general_queue = LL::WorkQueue::getInstance("General");
+    const LL::ThreadPool::ptr_t general_thread_pool = LL::ThreadPool::getInstance("General");
+    llassert_always(main_queue);
+    llassert_always(general_queue);
+    llassert_always(general_thread_pool);
+    // Set max decodes to double the thread count of the general work queue.
+    // This ensures the general work queue is full, but prevents theoretical
+    // buildup of buffers in memory due to disk writes once the
+    // LLVorbisDecodeState leaves the worker thread (see
+    // LLLFSThread::sLocal->write). This is probably as fast as we can get it
+    // without modifying/removing LLVorbisDecodeState, at which point we should
+    // consider decoding the audio during the asset download process.
+    // -Cosmic,2022-05-11
+    const size_t max_decodes = general_thread_pool->getWidth() * 2;
+
+    while (!mDecodeQueue.empty() && mDecodes.size() < max_decodes)
+    {
+        const LLUUID decode_id = mDecodeQueue.front();
+        mDecodeQueue.pop_front();
+
+        // Don't decode the same file twice
+        if (mDecodes.find(decode_id) != mDecodes.end())
+        {
+            continue;
+        }
+        if (gAudiop->hasDecodedFile(decode_id))
+        {
+            continue;
+        }
+
+        // Kick off a decode
+        mDecodes[decode_id] = LLPointer<LLVorbisDecodeState>(NULL);
+        try
+        {
+            main_queue->postTo(
+                general_queue,
+                [decode_id]() // Work done on general queue
+                {
+                    LLPointer<LLVorbisDecodeState> decode_state = beginDecodingAndWritingAudio(decode_id);
+
+                    if (!decode_state)
+                    {
+                        // Audio decode has errored
+                        return decode_state;
+                    }
+
+                    // Disk write of decoded audio is now in progress off-thread
+                    return decode_state;
+                },
+                [decode_id, this](LLPointer<LLVorbisDecodeState> decode_state) // Callback to main thread
+                mutable {
+                    if (!gAudiop)
+                    {
+                        // There is no LLAudioEngine anymore. This might happen if
+                        // an audio decode is enqueued just before shutdown.
+                        return;
+                    }
+
+                    // At this point, we can be certain that the pointer to "this"
+                    // is valid because the lifetime of "this" is dependent upon
+                    // the lifetime of gAudiop.
+
+                    enqueueFinishAudio(decode_id, decode_state);
+                });
+        }
+        catch (const LLThreadSafeQueueInterrupt&)
+        {
+            // Shutdown
+            // Consider making processQueue() do a cleanup instead
+            // of starting more decodes
+            LL_WARNS() << "Tried to start decoding on shutdown" << LL_ENDL;
+        }
+    }
+}
 
-			// Decode in a loop until we're done or have run out of time.
-			while(!(res = mCurrentDecodep->decodeSection()) && (decode_timer.getElapsedTimeF32() < num_secs))
-			{
-				// decodeSection does all of the work above
-			}
+LLPointer<LLVorbisDecodeState> beginDecodingAndWritingAudio(const LLUUID &decode_id)
+{
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_MEDIA;
+
+    LL_DEBUGS() << "Decoding " << decode_id << " from audio queue!" << LL_ENDL;
+
+    std::string                    d_path       = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, decode_id.asString()) + ".dsf";
+    LLPointer<LLVorbisDecodeState> decode_state = new LLVorbisDecodeState(decode_id, d_path);
+
+    if (!decode_state->initDecode())
+    {
+        return NULL;
+    }
+
+    // Decode in a loop until we're done
+    while (!decode_state->decodeSection())
+    {
+        // decodeSection does all of the work above
+    }
+
+    if (!decode_state->isDone())
+    {
+        // Decode stopped early, or something bad happened to the file
+        // during decoding.
+        LL_WARNS("AudioEngine") << decode_id << " has invalid vorbis data or decode has been canceled, aborting decode" << LL_ENDL;
+        decode_state->flushBadFile();
+        return NULL;
+    }
+
+    if (!decode_state->isValid())
+    {
+        // We had an error when decoding, abort.
+        LL_WARNS("AudioEngine") << decode_id << " has invalid vorbis data, aborting decode" << LL_ENDL;
+        decode_state->flushBadFile();
+        return NULL;
+    }
+
+    // Kick off the writing of the decoded audio to the disk cache.
+    // The receiving thread can then cheaply call finishDecode() again to check
+    // if writing has finished. Someone has to hold on to the refcounted
+    // decode_state to prevent it from getting destroyed during write.
+    decode_state->finishDecode();
+
+    return decode_state;
+}
 
-			if (mCurrentDecodep->isDone() && !mCurrentDecodep->isValid())
-			{
-				// We had an error when decoding, abort.
-				LL_WARNS("AudioEngine") << mCurrentDecodep->getUUID() << " has invalid vorbis data, aborting decode" << LL_ENDL;
-				mCurrentDecodep->flushBadFile();
-
-				if (gAudiop)
-				{
-					LLAudioData *adp = gAudiop->getAudioData(mCurrentDecodep->getUUID());
-					adp->setHasValidData(false);
-					adp->setHasCompletedDecode(true);
-				}
-
-				mCurrentDecodep = NULL;
-				done = TRUE;
-			}
+void LLAudioDecodeMgr::Impl::enqueueFinishAudio(const LLUUID &decode_id, LLPointer<LLVorbisDecodeState>& decode_state)
+{
+    // Assumed fast
+    if (tryFinishAudio(decode_id, decode_state))
+    {
+        // Done early!
+        auto decode_iter = mDecodes.find(decode_id);
+        llassert(decode_iter != mDecodes.end());
+        mDecodes.erase(decode_iter);
+        return;
+    }
+
+    // Not done yet... enqueue it
+    mDecodes[decode_id] = decode_state;
+}
 
-			if (!res)
-			{
-				// We've used up out time slice, bail...
-				done = TRUE;
-			}
-			else if (mCurrentDecodep)
-			{
-				if (gAudiop && mCurrentDecodep->finishDecode())
-				{
-					// We finished!
-					LLAudioData *adp = gAudiop->getAudioData(mCurrentDecodep->getUUID());
-					if (!adp)
-					{
-						LL_WARNS("AudioEngine") << "Missing LLAudioData for decode of " << mCurrentDecodep->getUUID() << LL_ENDL;
-					}
-					else if (mCurrentDecodep->isValid() && mCurrentDecodep->isDone())
-					{
-						adp->setHasCompletedDecode(true);
-						adp->setHasDecodedData(true);
-						adp->setHasValidData(true);
-
-						// At this point, we could see if anyone needs this sound immediately, but
-						// I'm not sure that there's a reason to - we need to poll all of the playing
-						// sounds anyway.
-						//LL_INFOS("AudioEngine") << "Finished the vorbis decode, now what?" << LL_ENDL;
-					}
-					else
-					{
-						adp->setHasCompletedDecode(true);
-						LL_INFOS("AudioEngine") << "Vorbis decode failed for " << mCurrentDecodep->getUUID() << LL_ENDL;
-					}
-					mCurrentDecodep = NULL;
-				}
-				done = TRUE; // done for now
-			}
-		}
+void LLAudioDecodeMgr::Impl::checkDecodesFinished()
+{
+    auto decode_iter = mDecodes.begin();
+    while (decode_iter != mDecodes.end())
+    {
+        const LLUUID& decode_id = decode_iter->first;
+        const LLPointer<LLVorbisDecodeState>& decode_state = decode_iter->second;
+        if (tryFinishAudio(decode_id, decode_state))
+        {
+            decode_iter = mDecodes.erase(decode_iter);
+        }
+        else
+        {
+            ++decode_iter;
+        }
+    }
+}
 
-		if (!done)
-		{
-			if (mDecodeQueue.empty())
-			{
-				// Nothing else on the queue.
-				done = TRUE;
-			}
-			else
-			{
-				LLUUID uuid;
-				uuid = mDecodeQueue.front();
-				mDecodeQueue.pop_front();
-				if (!gAudiop || gAudiop->hasDecodedFile(uuid))
-				{
-					// This file has already been decoded, don't decode it again.
-					continue;
-				}
-
-				LL_DEBUGS() << "Decoding " << uuid << " from audio queue!" << LL_ENDL;
-
-				std::string uuid_str;
-				std::string d_path;
-
-				LLTimer timer;
-				timer.reset();
-
-				uuid.toString(uuid_str);
-				d_path = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,uuid_str) + ".dsf";
-
-				mCurrentDecodep = new LLVorbisDecodeState(uuid, d_path);
-				if (!mCurrentDecodep->initDecode())
-				{
-					mCurrentDecodep = NULL;
-				}
-			}
-		}
-	}
+bool tryFinishAudio(const LLUUID &decode_id, LLPointer<LLVorbisDecodeState> decode_state)
+{
+    // decode_state is a file write in progress unless finished is true
+    bool finished = decode_state && decode_state->finishDecode();
+    if (!finished)
+    {
+        return false;
+    }
+
+    llassert_always(gAudiop);
+
+    LLAudioData *adp = gAudiop->getAudioData(decode_id);
+    if (!adp)
+    {
+        LL_WARNS("AudioEngine") << "Missing LLAudioData for decode of " << decode_id << LL_ENDL;
+        return true;
+    }
+
+    bool valid = decode_state && decode_state->isValid();
+    // Mark current decode finished regardless of success or failure
+    adp->setHasCompletedDecode(true);
+    // Flip flags for decoded data
+    adp->setHasDecodeFailed(!valid);
+    adp->setHasDecodedData(valid);
+    // When finished decoding, there will also be a decoded wav file cached on
+    // disk with the .dsf extension
+    if (valid)
+    {
+        adp->setHasWAVLoadFailed(false);
+    }
+
+    return true;
 }
 
 //////////////////////////////////////////////////////////////////////////////
 
 LLAudioDecodeMgr::LLAudioDecodeMgr()
 {
-	mImpl = new Impl;
+    mImpl = new Impl();
 }
 
 LLAudioDecodeMgr::~LLAudioDecodeMgr()
 {
-	delete mImpl;
+    delete mImpl;
+    mImpl = nullptr;
 }
 
-void LLAudioDecodeMgr::processQueue(const F32 num_secs)
+void LLAudioDecodeMgr::processQueue()
 {
-	mImpl->processQueue(num_secs);
+    mImpl->processQueue();
 }
 
 BOOL LLAudioDecodeMgr::addDecodeRequest(const LLUUID &uuid)
@@ -687,7 +795,7 @@ BOOL LLAudioDecodeMgr::addDecodeRequest(const LLUUID &uuid)
 	{
 		// Just put it on the decode queue.
 		LL_DEBUGS("AudioEngine") << "addDecodeRequest for " << uuid << " has local asset file already" << LL_ENDL;
-		mImpl->mDecodeQueue.push_back(uuid);
+        mImpl->mDecodeQueue.push_back(uuid);
 		return TRUE;
 	}
 
diff --git a/indra/llaudio/llaudiodecodemgr.h b/indra/llaudio/llaudiodecodemgr.h
index ceaff3f2d8254a97cf2f865a67fb2dc02cbb15c6..4c17b46156237557ae461b47b63a4e0a8dd7ca51 100644
--- a/indra/llaudio/llaudiodecodemgr.h
+++ b/indra/llaudio/llaudiodecodemgr.h
@@ -32,24 +32,23 @@
 
 #include "llassettype.h"
 #include "llframetimer.h"
+#include "llsingleton.h"
 
+template<class T> class LLPointer;
 class LLVorbisDecodeState;
 
-class LLAudioDecodeMgr
+class LLAudioDecodeMgr : public LLSingleton<LLAudioDecodeMgr>
 {
+    LLSINGLETON(LLAudioDecodeMgr);
+    ~LLAudioDecodeMgr();
 public:
-	LLAudioDecodeMgr();
-	~LLAudioDecodeMgr();
-
-	void processQueue(const F32 num_secs = 0.005);
+	void processQueue();
 	BOOL addDecodeRequest(const LLUUID &uuid);
 	void addAudioRequest(const LLUUID &uuid);
 	
 protected:
 	class Impl;
-	Impl* mImpl;
+    Impl* mImpl;
 };
 
-extern LLAudioDecodeMgr *gAudioDecodeMgrp;
-
 #endif
diff --git a/indra/llaudio/llaudioengine.cpp b/indra/llaudio/llaudioengine.cpp
index d35f2499730a14a2ed159388e697d78f9db89e62..008e1827c516f93893cb6f4a06b8590876eb1f7b 100644
--- a/indra/llaudio/llaudioengine.cpp
+++ b/indra/llaudio/llaudioengine.cpp
@@ -83,18 +83,10 @@ void LLAudioEngine::setDefaults()
 
 	mLastStatus = 0;
 
-	mNumChannels = 0;
 	mEnableWind = false;
 
-	S32 i;
-	for (i = 0; i < MAX_CHANNELS; i++)
-	{
-		mChannels[i] = NULL;
-	}
-	for (i = 0; i < MAX_BUFFERS; i++)
-	{
-		mBuffers[i] = NULL;
-	}
+	mChannels.fill(nullptr);
+	mBuffers.fill(nullptr);
 
 	mMasterGain = 1.f;
 	// Setting mInternalGain to an out of range value fixes the issue reported in STORM-830.
@@ -111,18 +103,14 @@ void LLAudioEngine::setDefaults()
 }
 
 
-bool LLAudioEngine::init(const S32 num_channels, void* userdata, const std::string &app_title)
+bool LLAudioEngine::init(void* userdata, const std::string &app_title)
 {
 	setDefaults();
 
-	mNumChannels = num_channels;
 	mUserData = userdata;
 	
 	allocateListener();
 
-	// Initialize the decode manager
-	gAudioDecodeMgrp = new LLAudioDecodeMgr;
-
 	LL_INFOS("AudioEngine") << "LLAudioEngine::init() AudioEngine successfully initialized" << LL_ENDL;
 
 	return true;
@@ -131,10 +119,6 @@ bool LLAudioEngine::init(const S32 num_channels, void* userdata, const std::stri
 
 void LLAudioEngine::shutdown()
 {
-	// Clean up decode manager
-	delete gAudioDecodeMgrp;
-	gAudioDecodeMgrp = NULL;
-
 	// Clean up wind source
 	cleanupWind();
 
@@ -156,14 +140,14 @@ void LLAudioEngine::shutdown()
 
 	// Clean up channels
 	S32 i;
-	for (i = 0; i < MAX_CHANNELS; i++)
+	for (i = 0; i < LL_MAX_AUDIO_CHANNELS; i++)
 	{
 		delete mChannels[i];
 		mChannels[i] = NULL;
 	}
 
 	// Clean up buffers
-	for (i = 0; i < MAX_BUFFERS; i++)
+	for (i = 0; i < LL_MAX_AUDIO_BUFFERS; i++)
 	{
 		delete mBuffers[i];
 		mBuffers[i] = NULL;
@@ -229,7 +213,7 @@ std::string LLAudioEngine::getInternetStreamURL()
 void LLAudioEngine::updateChannels()
 {
 	S32 i;
-	for (i = 0; i < MAX_CHANNELS; i++)
+	for (i = 0; i < LL_MAX_AUDIO_CHANNELS; i++)
 	{
 		if (mChannels[i])
 		{
@@ -240,20 +224,14 @@ void LLAudioEngine::updateChannels()
 	}
 }
 
-static const F32 default_max_decode_time = .002f; // 2 ms
-void LLAudioEngine::idle(F32 max_decode_time)
+void LLAudioEngine::idle()
 {
-	if (max_decode_time <= 0.f)
-	{
-		max_decode_time = default_max_decode_time;
-	}
-	
 	// "Update" all of our audio sources, clean up dead ones.
 	// Primarily does position updating, cleanup of unused audio sources.
 	// Also does regeneration of the current priority of each audio source.
 
 	S32 i;
-	for (i = 0; i < MAX_BUFFERS; i++)
+	for (i = 0; i < LL_MAX_AUDIO_BUFFERS; i++)
 	{
 		if (mBuffers[i])
 		{
@@ -276,7 +254,7 @@ void LLAudioEngine::idle(F32 max_decode_time)
 		{
 			// The source is done playing, clean it up.
 			delete sourcep;
-			mAllSources.erase(iter++);
+            iter = mAllSources.erase(iter);
 			continue;
 		}
 
@@ -473,7 +451,7 @@ void LLAudioEngine::idle(F32 max_decode_time)
 	commitDeferredChanges();
 	
 	// Flush unused buffers that are stale enough
-	for (i = 0; i < MAX_BUFFERS; i++)
+	for (i = 0; i < LL_MAX_AUDIO_BUFFERS; i++)
 	{
 		if (mBuffers[i])
 		{
@@ -489,7 +467,7 @@ void LLAudioEngine::idle(F32 max_decode_time)
 
 
 	// Clear all of the looped flags for the channels
-	for (i = 0; i < MAX_CHANNELS; i++)
+	for (i = 0; i < LL_MAX_AUDIO_CHANNELS; i++)
 	{
 		if (mChannels[i])
 		{
@@ -498,7 +476,7 @@ void LLAudioEngine::idle(F32 max_decode_time)
 	}
 
 	// Decode audio files
-	gAudioDecodeMgrp->processQueue(max_decode_time);
+    LLAudioDecodeMgr::getInstance()->processQueue();
 	
 	// Call this every frame, just in case we somehow
 	// missed picking it up in all the places that can add
@@ -532,7 +510,7 @@ bool LLAudioEngine::updateBufferForData(LLAudioData *adp, const LLUUID &audio_uu
 		{
 			if (audio_uuid.notNull())
 			{
-				gAudioDecodeMgrp->addDecodeRequest(audio_uuid);
+                LLAudioDecodeMgr::getInstance()->addDecodeRequest(audio_uuid);
 			}
 		}
 		else
@@ -561,7 +539,7 @@ void LLAudioEngine::enableWind(bool enable)
 LLAudioBuffer * LLAudioEngine::getFreeBuffer()
 {
 	S32 i;
-	for (i = 0; i < MAX_BUFFERS; i++)
+	for (i = 0; i < LL_MAX_AUDIO_BUFFERS; i++)
 	{
 		if (!mBuffers[i])
 		{
@@ -574,7 +552,7 @@ LLAudioBuffer * LLAudioEngine::getFreeBuffer()
 	// Grab the oldest unused buffer
 	F32 max_age = -1.f;
 	S32 buffer_id = -1;
-	for (i = 0; i < MAX_BUFFERS; i++)
+	for (i = 0; i < LL_MAX_AUDIO_BUFFERS; i++)
 	{
 		if (mBuffers[i])
 		{
@@ -605,7 +583,7 @@ LLAudioBuffer * LLAudioEngine::getFreeBuffer()
 LLAudioChannel * LLAudioEngine::getFreeChannel(const F32 priority)
 {
 	S32 i;
-	for (i = 0; i < mNumChannels; i++)
+    for (i = 0; i < LL_MAX_AUDIO_CHANNELS; i++)
 	{
 		if (!mChannels[i])
 		{
@@ -633,7 +611,7 @@ LLAudioChannel * LLAudioEngine::getFreeChannel(const F32 priority)
 	F32 min_priority = 10000.f;
 	LLAudioChannel *min_channelp = NULL;
 
-	for (i = 0; i < mNumChannels; i++)
+    for (i = 0; i < LL_MAX_AUDIO_CHANNELS; i++)
 	{
 		LLAudioChannel *channelp = mChannels[i];
 		LLAudioSource *sourcep = channelp->getSource();
@@ -660,7 +638,7 @@ LLAudioChannel * LLAudioEngine::getFreeChannel(const F32 priority)
 void LLAudioEngine::cleanupBuffer(LLAudioBuffer *bufferp)
 {
 	S32 i;
-	for (i = 0; i < MAX_BUFFERS; i++)
+	for (i = 0; i < LL_MAX_AUDIO_BUFFERS; i++)
 	{
 		if (mBuffers[i] == bufferp)
 		{
@@ -678,7 +656,7 @@ bool LLAudioEngine::preloadSound(const LLUUID &uuid)
 	getAudioData(uuid);	// We don't care about the return value, this is just to make sure
 									// that we have an entry, which will mean that the audio engine knows about this
 
-	if (gAudioDecodeMgrp->addDecodeRequest(uuid))
+    if (LLAudioDecodeMgr::getInstance()->addDecodeRequest(uuid))
 	{
 		// This means that we do have a local copy, and we're working on decoding it.
 		return true;
@@ -827,7 +805,8 @@ void LLAudioEngine::triggerSound(const LLUUID &audio_uuid, const LLUUID& owner_i
 	addAudioSource(asp);
 	if (pos_global.isExactlyZero())
 	{
-		asp->setAmbient(true);
+		// For sound preview and UI
+		asp->setForcedPriority(true);
 	}
 	else
 	{
@@ -953,6 +932,7 @@ LLAudioSource * LLAudioEngine::findAudioSource(const LLUUID &source_id)
 
 LLAudioData * LLAudioEngine::getAudioData(const LLUUID &audio_uuid)
 {
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_MEDIA;
 	data_map::iterator iter;
 	iter = mAllData.find(audio_uuid);
 	if (iter == mAllData.end())
@@ -1039,7 +1019,7 @@ void LLAudioEngine::startNextTransfer()
 
 	// Check all channels for currently playing sounds.
 	F32 max_pri = -1.f;
-	for (i = 0; i < MAX_CHANNELS; i++)
+	for (i = 0; i < LL_MAX_AUDIO_CHANNELS; i++)
 	{
 		if (!mChannels[i])
 		{
@@ -1067,7 +1047,7 @@ void LLAudioEngine::startNextTransfer()
 			continue;
 		}
 
-		if (!adp->hasLocalData() && adp->hasValidData())
+        if (!adp->hasLocalData() && !adp->hasDecodeFailed())
 		{
 			asset_id = adp->getID();
 			max_pri = asp->getPriority();
@@ -1078,7 +1058,7 @@ void LLAudioEngine::startNextTransfer()
 	if (asset_id.isNull())
 	{
 		max_pri = -1.f;
-		for (i = 0; i < MAX_CHANNELS; i++)
+		for (i = 0; i < LL_MAX_AUDIO_CHANNELS; i++)
 		{
 			if (!mChannels[i])
 			{
@@ -1103,7 +1083,7 @@ void LLAudioEngine::startNextTransfer()
 				continue;
 			}
 
-			if (!adp->hasLocalData() && adp->hasValidData())
+            if (!adp->hasLocalData() && !adp->hasDecodeFailed())
 			{
 				asset_id = adp->getID();
 				max_pri = asp->getPriority();
@@ -1115,7 +1095,7 @@ void LLAudioEngine::startNextTransfer()
 	if (asset_id.isNull())
 	{
 		max_pri = -1.f;
-		for (i = 0; i < MAX_CHANNELS; i++)
+		for (i = 0; i < LL_MAX_AUDIO_CHANNELS; i++)
 		{
 			if (!mChannels[i])
 			{
@@ -1143,7 +1123,7 @@ void LLAudioEngine::startNextTransfer()
 					continue;
 				}
 
-				if (!adp->hasLocalData() && adp->hasValidData())
+                if (!adp->hasLocalData() && !adp->hasDecodeFailed())
 				{
 					asset_id = adp->getID();
 					max_pri = asp->getPriority();
@@ -1171,7 +1151,7 @@ void LLAudioEngine::startNextTransfer()
 			}
 
 			adp = asp->getCurrentData();
-			if (adp && !adp->hasLocalData() && adp->hasValidData())
+            if (adp && !adp->hasLocalData() && !adp->hasDecodeFailed())
 			{
 				asset_id = adp->getID();
 				max_pri = asp->getPriority();
@@ -1179,7 +1159,7 @@ void LLAudioEngine::startNextTransfer()
 			}
 
 			adp = asp->getQueuedData();
-			if (adp && !adp->hasLocalData() && adp->hasValidData())
+            if (adp && !adp->hasLocalData() && !adp->hasDecodeFailed())
 			{
 				asset_id = adp->getID();
 				max_pri = asp->getPriority();
@@ -1194,7 +1174,7 @@ void LLAudioEngine::startNextTransfer()
 					continue;
 				}
 
-				if (!adp->hasLocalData() && adp->hasValidData())
+                if (!adp->hasLocalData() && !adp->hasDecodeFailed())
 				{
 					asset_id = adp->getID();
 					max_pri = asp->getPriority();
@@ -1235,7 +1215,7 @@ void LLAudioEngine::assetCallback(const LLUUID &uuid, LLAssetType::EType type, v
 		LLAudioData *adp = gAudiop->getAudioData(uuid);
 		if (adp)
         {	// Make sure everything is cleared
-			adp->setHasValidData(false);
+            adp->setHasDecodeFailed(true);
 			adp->setHasLocalData(false);
 			adp->setHasDecodedData(false);
 			adp->setHasCompletedDecode(true);
@@ -1252,9 +1232,9 @@ void LLAudioEngine::assetCallback(const LLUUID &uuid, LLAssetType::EType type, v
 		else
 		{
 			// LL_INFOS() << "Got asset callback with good audio data for " << uuid << ", making decode request" << LL_ENDL;
-			adp->setHasValidData(true);
+            adp->setHasDecodeFailed(false);
 		    adp->setHasLocalData(true);
-		    gAudioDecodeMgrp->addDecodeRequest(uuid);
+            LLAudioDecodeMgr::getInstance()->addDecodeRequest(uuid);
 		}
 	}
 	gAudiop->mCurrentTransfer = LLUUID::null;
@@ -1273,7 +1253,7 @@ LLAudioSource::LLAudioSource(const LLUUID& id, const LLUUID& owner_id, const F32
 	mPriority(0.f),
 	mGain(gain),
 	mSourceMuted(false),
-	mAmbient(false),
+	mForcedPriority(false),
 	mLoop(false),
 	mSyncMaster(false),
 	mSyncSlave(false),
@@ -1324,11 +1304,15 @@ void LLAudioSource::update()
 		{
 			// Hack - try and load the sound.  Will do this as a callback
 			// on decode later.
-			if (adp->load() && adp->getBuffer())
+            if (adp->getBuffer())
 			{
 				play(adp->getID());
 			}
-			else if (adp->hasCompletedDecode())		// Only mark corrupted after decode is done
+            else if (adp->hasDecodedData() && !adp->hasWAVLoadFailed())
+            {
+                adp->load();
+            }
+            else if (adp->hasCompletedDecode() && adp->hasDecodeFailed()) // Only mark corrupted after decode is done
 			{
 				LL_WARNS() << "Marking LLAudioSource corrupted for " << adp->getID() << LL_ENDL;
 				mCorrupted = true ;
@@ -1339,7 +1323,7 @@ void LLAudioSource::update()
 
 void LLAudioSource::updatePriority()
 {
-	if (isAmbient())
+	if (isForcedPriority())
 	{
 		mPriority = 1.f;
 	}
@@ -1402,6 +1386,15 @@ bool LLAudioSource::setupChannel()
 	return true;
 }
 
+void LLAudioSource::stop()
+{
+    play(LLUUID::null);
+    if (mCurrentDatap)
+    {
+        // always reset data if something wants us to stop
+        mCurrentDatap = nullptr;
+    }
+}
 
 bool LLAudioSource::play(const LLUUID &audio_uuid)
 {
@@ -1615,12 +1608,12 @@ bool LLAudioSource::hasPendingPreloads() const
 	{
 		LLAudioData *adp = iter->second;
 		// note: a bad UUID will forever be !hasDecodedData()
-		// but also !hasValidData(), hence the check for hasValidData()
+        // but also hasDecodeFailed(), hence the check for hasDecodeFailed()
 		if (!adp)
 		{
 			continue;
 		}
-		if (!adp->hasDecodedData() && adp->hasValidData())
+        if (!adp->hasDecodedData() && !adp->hasDecodeFailed())
 		{
 			// This source is still waiting for a preload
 			return true;
@@ -1777,7 +1770,8 @@ LLAudioData::LLAudioData(const LLUUID &uuid) :
 	mHasLocalData(false),
 	mHasDecodedData(false),
 	mHasCompletedDecode(false),
-	mHasValidData(true)
+    mHasDecodeFailed(false),
+    mHasWAVLoadFailed(false)
 {
 	if (uuid.isNull())
 	{
@@ -1812,12 +1806,14 @@ bool LLAudioData::load()
 	{
 		// We already have this sound in a buffer, don't do anything.
 		LL_INFOS() << "Already have a buffer for this sound, don't bother loading!" << LL_ENDL;
+        mHasWAVLoadFailed = false;
 		return true;
 	}
 
 	if (!gAudiop)
 	{
 		LL_WARNS("AudioEngine") << "LLAudioEngine instance doesn't exist!" << LL_ENDL;
+        mHasWAVLoadFailed = true;
 		return false;
 	}
 	
@@ -1826,6 +1822,8 @@ bool LLAudioData::load()
 	{
 		// No free buffers, abort.
 		LL_INFOS() << "Not able to allocate a new audio buffer, aborting." << LL_ENDL;
+        // *TODO: Mark this failure differently so the audio engine could retry loading this buffer in the future
+        mHasWAVLoadFailed = true;
 		return true;
 	}
 
@@ -1834,7 +1832,8 @@ bool LLAudioData::load()
 	mID.toString(uuid_str);
 	wav_path= gDirUtilp->getExpandedFilename(LL_PATH_CACHE,uuid_str) + ".dsf";
 
-	if (!mBufferp->loadWAV(wav_path))
+    mHasWAVLoadFailed = !mBufferp->loadWAV(wav_path);
+    if (mHasWAVLoadFailed)
 	{
 		// Hrm.  Right now, let's unset the buffer, since it's empty.
 		gAudiop->cleanupBuffer(mBufferp);
diff --git a/indra/llaudio/llaudioengine.h b/indra/llaudio/llaudioengine.h
old mode 100644
new mode 100755
index 577b36d667f895fe2535a6750ed46b14a31f156f..0fe8b3d75633f4622626b4c0774fdfc6e67c76e3
--- a/indra/llaudio/llaudioengine.h
+++ b/indra/llaudio/llaudioengine.h
@@ -47,8 +47,8 @@ const F32 LL_WIND_UNDERWATER_CENTER_FREQ = 20.f;
 const F32 ATTACHED_OBJECT_TIMEOUT = 5.0f;
 const F32 DEFAULT_MIN_DISTANCE = 2.0f;
 
-#define MAX_CHANNELS 30
-#define MAX_BUFFERS 40	// Some extra for preloading, maybe?
+#define LL_MAX_AUDIO_CHANNELS 30
+#define LL_MAX_AUDIO_BUFFERS 40 // Some extra for preloading, maybe?
 
 class LLAudioSource;
 class LLAudioData;
@@ -88,7 +88,7 @@ class LLAudioEngine
 	virtual ~LLAudioEngine();
 
 	// initialization/startup/shutdown
-	virtual bool init(const S32 num_channels, void *userdata, const std::string &app_title);
+	virtual bool init(void *userdata, const std::string &app_title);
 	virtual std::string getDriverName(bool verbose) = 0;
 	virtual void shutdown();
 
@@ -96,7 +96,7 @@ class LLAudioEngine
 	//virtual void processQueue(const LLUUID &sound_guid);
 	virtual void setListener(LLVector3 pos,LLVector3 vel,LLVector3 up,LLVector3 at);
 	virtual void updateWind(LLVector3 direction, F32 camera_height_above_water) = 0;
-	virtual void idle(F32 max_decode_time = 0.f);
+	virtual void idle();
 	virtual void updateChannels();
 
 	//
@@ -209,7 +209,6 @@ class LLAudioEngine
 
 	S32 mLastStatus;
 	
-	S32 mNumChannels;
 	bool mEnableWind;
 
 	LLUUID mCurrentTransfer; // Audio file currently being transferred by the system
@@ -224,11 +223,11 @@ class LLAudioEngine
 	source_map mAllSources;
 	data_map mAllData;
 
-	LLAudioChannel *mChannels[MAX_CHANNELS];
+    std::array<LLAudioChannel*, LL_MAX_AUDIO_CHANNELS> mChannels;
 
 	// Buffers needs to change into a different data structure, as the number of buffers
 	// that we have active should be limited by RAM usage, not count.
-	LLAudioBuffer *mBuffers[MAX_BUFFERS];
+    std::array<LLAudioBuffer*, LL_MAX_AUDIO_BUFFERS> mBuffers;
 	
 	F32 mMasterGain;
 	F32 mInternalGain;			// Actual gain set; either mMasterGain or 0 when mMuted is true.
@@ -266,8 +265,8 @@ class LLAudioSource
 
 	void addAudioData(LLAudioData *adp, bool set_current = TRUE);
 
-	void setAmbient(const bool ambient)						{ mAmbient = ambient; }
-	bool isAmbient() const									{ return mAmbient; }
+	void setForcedPriority(const bool ambient)						{ mForcedPriority = ambient; }
+	bool isForcedPriority() const									{ return mForcedPriority; }
 
 	void setLoop(const bool loop)							{ mLoop = loop; }
 	bool isLoop() const										{ return mLoop; }
@@ -304,7 +303,13 @@ class LLAudioSource
 	LLAudioBuffer *getCurrentBuffer();
 
 	bool setupChannel();
-	bool play(const LLUUID &audio_id);	// Start the audio source playing
+
+    // Stop the audio source, reset audio id even if muted
+    void stop();
+
+    // Start the audio source playing,
+    // takes mute into account to preserve previous id if nessesary
+    bool play(const LLUUID &audio_id);
 
 	bool hasPendingPreloads() const;	// Has preloads that haven't been done yet
 
@@ -320,7 +325,7 @@ class LLAudioSource
 	F32				mPriority;
 	F32				mGain;
 	bool			mSourceMuted;
-	bool			mAmbient;
+	bool			mForcedPriority; // ignore mute, set high priority, researved for sound preview and UI
 	bool			mLoop;
 	bool			mSyncMaster;
 	bool			mSyncSlave;
@@ -354,32 +359,36 @@ class LLAudioSource
 
 class LLAudioData
 {
-public:
-	LLAudioData(const LLUUID &uuid);
-	bool load();
-
-	LLUUID getID() const				{ return mID; }
-	LLAudioBuffer *getBuffer() const	{ return mBufferp; }
-
-	bool	hasLocalData() const		{ return mHasLocalData; }
-	bool	hasDecodedData() const		{ return mHasDecodedData; }
-	bool	hasCompletedDecode() const	{ return mHasCompletedDecode; }
-	bool	hasValidData() const		{ return mHasValidData; }
-
-	void	setHasLocalData(const bool hld)		{ mHasLocalData = hld; }
-	void	setHasDecodedData(const bool hdd)	{ mHasDecodedData = hdd; }
-	void	setHasCompletedDecode(const bool hcd)	{ mHasCompletedDecode = hcd; }
-	void	setHasValidData(const bool hvd)		{ mHasValidData = hvd; }
-
-	friend class LLAudioEngine; // Severe laziness, bad.
-
-protected:
-	LLUUID mID;
-	LLAudioBuffer *mBufferp;	// If this data is being used by the audio system, a pointer to the buffer will be set here.
-	bool mHasLocalData;			// Set true if the sound asset file is available locally
-	bool mHasDecodedData;		// Set true if the sound file has been decoded
-	bool mHasCompletedDecode;	// Set true when the sound is decoded
-	bool mHasValidData;			// Set false if decoding failed, meaning the sound asset is bad
+  public:
+    LLAudioData(const LLUUID &uuid);
+    bool load();
+
+    LLUUID         getID() const { return mID; }
+    LLAudioBuffer *getBuffer() const { return mBufferp; }
+
+    bool hasLocalData() const { return mHasLocalData; }
+    bool hasDecodedData() const { return mHasDecodedData; }
+    bool hasCompletedDecode() const { return mHasCompletedDecode; }
+    bool hasDecodeFailed() const { return mHasDecodeFailed; }
+    bool hasWAVLoadFailed() const { return mHasWAVLoadFailed; }
+
+    void setHasLocalData(const bool hld) { mHasLocalData = hld; }
+    void setHasDecodedData(const bool hdd) { mHasDecodedData = hdd; }
+    void setHasCompletedDecode(const bool hcd) { mHasCompletedDecode = hcd; }
+    void setHasDecodeFailed(const bool hdf) { mHasDecodeFailed = hdf; }
+    void setHasWAVLoadFailed(const bool hwlf) { mHasWAVLoadFailed = hwlf; }
+
+    friend class LLAudioEngine;  // Severe laziness, bad.
+
+  protected:
+    LLUUID         mID;
+    LLAudioBuffer *mBufferp;             // If this data is being used by the audio system, a pointer to the buffer will be set here.
+    bool           mHasLocalData;        // Set true if the encoded sound asset file is available locally
+    bool           mHasDecodedData;      // Set true if the decoded sound file is available on disk
+    bool           mHasCompletedDecode;  // Set true when the sound is decoded
+    bool           mHasDecodeFailed;     // Set true if decoding failed, meaning the sound asset is bad
+    bool mHasWAVLoadFailed;  // Set true if loading the decoded WAV file failed, meaning the sound asset should be decoded instead if
+                             // possible
 };
 
 
diff --git a/indra/llaudio/llaudioengine_fmodstudio.cpp b/indra/llaudio/llaudioengine_fmodstudio.cpp
index b0c87b02085b50a03bfdf61ed37b4af637483f05..ba743020b5a879ae679260c1b87a5db0ca3b62e4 100644
--- a/indra/llaudio/llaudioengine_fmodstudio.cpp
+++ b/indra/llaudio/llaudioengine_fmodstudio.cpp
@@ -74,7 +74,7 @@ static inline bool Check_FMOD_Error(FMOD_RESULT result, const char *string)
     return true;
 }
 
-bool LLAudioEngine_FMODSTUDIO::init(const S32 num_channels, void* userdata, const std::string &app_title)
+bool LLAudioEngine_FMODSTUDIO::init(void* userdata, const std::string &app_title)
 {
     U32 version;
     FMOD_RESULT result;
@@ -86,7 +86,7 @@ bool LLAudioEngine_FMODSTUDIO::init(const S32 num_channels, void* userdata, cons
         return false;
 
     //will call LLAudioEngine_FMODSTUDIO::allocateListener, which needs a valid mSystem pointer.
-    LLAudioEngine::init(num_channels, userdata, app_title);
+    LLAudioEngine::init(userdata, app_title);
 
     result = mSystem->getVersion(&version);
     Check_FMOD_Error(result, "FMOD::System::getVersion");
@@ -98,7 +98,7 @@ bool LLAudioEngine_FMODSTUDIO::init(const S32 num_channels, void* userdata, cons
     }
 
     // In this case, all sounds, PLUS wind and stream will be software.
-    result = mSystem->setSoftwareChannels(num_channels + 2);
+    result = mSystem->setSoftwareChannels(LL_MAX_AUDIO_CHANNELS + 2);
     Check_FMOD_Error(result, "FMOD::System::setSoftwareChannels");
 
     FMOD_ADVANCEDSETTINGS settings;
@@ -127,7 +127,7 @@ bool LLAudioEngine_FMODSTUDIO::init(const S32 num_channels, void* userdata, cons
         {
             LL_DEBUGS("AppInit") << "Trying PulseAudio audio output..." << LL_ENDL;
             if (mSystem->setOutput(FMOD_OUTPUTTYPE_PULSEAUDIO) == FMOD_OK &&
-                (result = mSystem->init(num_channels + 2, fmod_flags, const_cast<char*>(app_title.c_str()))) == FMOD_OK)
+                (result = mSystem->init(LL_MAX_AUDIO_CHANNELS + 2, fmod_flags, const_cast<char*>(app_title.c_str()))) == FMOD_OK)
             {
                 LL_DEBUGS("AppInit") << "PulseAudio output initialized OKAY" << LL_ENDL;
                 audio_ok = true;
@@ -149,7 +149,7 @@ bool LLAudioEngine_FMODSTUDIO::init(const S32 num_channels, void* userdata, cons
         {
             LL_DEBUGS("AppInit") << "Trying ALSA audio output..." << LL_ENDL;
             if (mSystem->setOutput(FMOD_OUTPUTTYPE_ALSA) == FMOD_OK &&
-                (result = mSystem->init(num_channels + 2, fmod_flags, 0)) == FMOD_OK)
+                (result = mSystem->init(LL_MAX_AUDIO_CHANNELS + 2, fmod_flags, 0)) == FMOD_OK)
             {
                 LL_DEBUGS("AppInit") << "ALSA audio output initialized OKAY" << LL_ENDL;
                 audio_ok = true;
@@ -190,7 +190,7 @@ bool LLAudioEngine_FMODSTUDIO::init(const S32 num_channels, void* userdata, cons
     // initialize the FMOD engine
     // number of channel in this case looks to be identiacal to number of max simultaneously
     // playing objects and we can set practically any number
-    result = mSystem->init(num_channels + 2, fmod_flags, 0);
+    result = mSystem->init(LL_MAX_AUDIO_CHANNELS + 2, fmod_flags, 0);
     if (Check_FMOD_Error(result, "Error initializing FMOD Studio with default settins, retrying with other format"))
     {
         result = mSystem->setSoftwareFormat(44100, FMOD_SPEAKERMODE_STEREO, 0/*- ignore*/);
@@ -198,7 +198,7 @@ bool LLAudioEngine_FMODSTUDIO::init(const S32 num_channels, void* userdata, cons
         {
             return false;
         }
-        result = mSystem->init(num_channels + 2, fmod_flags, 0);
+        result = mSystem->init(LL_MAX_AUDIO_CHANNELS + 2, fmod_flags, 0);
     }
     if (Check_FMOD_Error(result, "Error initializing FMOD Studio"))
     {
@@ -519,9 +519,9 @@ void LLAudioChannelFMODSTUDIO::update3DPosition()
         return;
     }
 
-    if (mCurrentSourcep->isAmbient())
+    if (mCurrentSourcep->isForcedPriority())
     {
-        // Ambient sound, don't need to do any positional updates.
+        // Prioritized UI and preview sounds don't need to do any positional updates.
         set3DMode(false);
     }
     else
diff --git a/indra/llaudio/llaudioengine_fmodstudio.h b/indra/llaudio/llaudioengine_fmodstudio.h
index f2361df1b618005d5ab9f7db595d0353e394afe5..d3d6d69685c2b4908a432de9d8c5196a36c2254d 100644
--- a/indra/llaudio/llaudioengine_fmodstudio.h
+++ b/indra/llaudio/llaudioengine_fmodstudio.h
@@ -51,7 +51,7 @@ class LLAudioEngine_FMODSTUDIO : public LLAudioEngine
 	virtual ~LLAudioEngine_FMODSTUDIO();
 
 	// initialization/startup/shutdown
-	virtual bool init(const S32 num_channels, void *user_data, const std::string &app_title);
+	virtual bool init(void *user_data, const std::string &app_title);
 	virtual std::string getDriverName(bool verbose);
 	virtual void allocateListener();
 
diff --git a/indra/llaudio/llaudioengine_openal.cpp b/indra/llaudio/llaudioengine_openal.cpp
index 3bdd0302eedf16ff02d0c00b0c0c1e490e6190c3..0a79614424b0204b769b8a1ebde8d9acc55535f8 100644
--- a/indra/llaudio/llaudioengine_openal.cpp
+++ b/indra/llaudio/llaudioengine_openal.cpp
@@ -52,10 +52,10 @@ LLAudioEngine_OpenAL::~LLAudioEngine_OpenAL()
 }
 
 // virtual
-bool LLAudioEngine_OpenAL::init(const S32 num_channels, void* userdata, const std::string &app_title)
+bool LLAudioEngine_OpenAL::init(void* userdata, const std::string &app_title)
 {
 	mWindGen = NULL;
-	LLAudioEngine::init(num_channels, userdata, app_title);
+	LLAudioEngine::init(userdata, app_title);
 
 	if(!alutInit(NULL, NULL))
 	{
@@ -297,7 +297,7 @@ void LLAudioChannelOpenAL::update3DPosition()
 	{
 		return;
 	}
-	if (mCurrentSourcep->isAmbient())
+	if (mCurrentSourcep->isForcedPriority())
 	{
 		alSource3f(mALSource, AL_POSITION, 0.0, 0.0, 0.0);
 		alSource3f(mALSource, AL_VELOCITY, 0.0, 0.0, 0.0);
diff --git a/indra/llaudio/llaudioengine_openal.h b/indra/llaudio/llaudioengine_openal.h
index 366f9259e31e825f139763ea04ff7290abe6f9a7..a3cab97cd2f4ab4663ed569150bf6d06eed18055 100644
--- a/indra/llaudio/llaudioengine_openal.h
+++ b/indra/llaudio/llaudioengine_openal.h
@@ -40,7 +40,7 @@ class LLAudioEngine_OpenAL : public LLAudioEngine
 		LLAudioEngine_OpenAL();
 		virtual ~LLAudioEngine_OpenAL();
 
-        virtual bool init(const S32 num_channels, void *user_data, const std::string &app_title);
+        virtual bool init(void *user_data, const std::string &app_title);
         virtual std::string getDriverName(bool verbose);
 		virtual void allocateListener();
 
diff --git a/indra/llaudio/llstreamingaudio_fmodstudio.cpp b/indra/llaudio/llstreamingaudio_fmodstudio.cpp
index 1ad29a3f590d8662edeebee2ff499ea2501cb18b..85577992a64fe8b95f222cc43973509bd2ae7630 100644
--- a/indra/llaudio/llstreamingaudio_fmodstudio.cpp
+++ b/indra/llaudio/llstreamingaudio_fmodstudio.cpp
@@ -70,7 +70,11 @@ mRetryCount(0)
     // Must be larger than the usual Second Life frame stutter time.
     const U32 buffer_seconds = 10;		//sec
     const U32 estimated_bitrate = 128;	//kbit/sec
-    mSystem->setStreamBufferSize(estimated_bitrate * buffer_seconds * 128/*bytes/kbit*/, FMOD_TIMEUNIT_RAWBYTES);
+    FMOD_RESULT result = mSystem->setStreamBufferSize(estimated_bitrate * buffer_seconds * 128/*bytes/kbit*/, FMOD_TIMEUNIT_RAWBYTES);
+    if (result != FMOD_OK)
+    {
+        LL_WARNS("FMOD") << "setStreamBufferSize error: " << FMOD_ErrorString(result) << LL_ENDL;
+    }
 
     // Here's where we set the size of the network buffer and some buffering 
     // parameters.  In this case we want a network buffer of 16k, we want it 
@@ -134,7 +138,7 @@ void LLStreamingAudio_FMODSTUDIO::killDeadStreams()
         {
             LL_INFOS("FMOD") << "Closed dead stream" << LL_ENDL;
             delete streamp;
-            mDeadStreams.erase(iter++);
+            iter = mDeadStreams.erase(iter);
         }
         else
         {
@@ -404,7 +408,11 @@ FMOD::Channel *LLAudioStreamManagerFMODSTUDIO::startStream()
     if (mStreamChannel)
         return mStreamChannel;	//Already have a channel for this stream.
 
-    mSystem->playSound(mInternetStream, NULL, true, &mStreamChannel);
+    FMOD_RESULT result = mSystem->playSound(mInternetStream, NULL, true, &mStreamChannel);
+    if (result != FMOD_OK)
+    {
+        LL_WARNS("FMOD") << FMOD_ErrorString(result) << LL_ENDL;
+    }
     return mStreamChannel;
 }
 
@@ -445,16 +453,29 @@ bool LLAudioStreamManagerFMODSTUDIO::stopStream()
 FMOD_OPENSTATE LLAudioStreamManagerFMODSTUDIO::getOpenState(unsigned int* percentbuffered, bool* starving, bool* diskbusy)
 {
     FMOD_OPENSTATE state;
-    mInternetStream->getOpenState(&state, percentbuffered, starving, diskbusy);
+    FMOD_RESULT result = mInternetStream->getOpenState(&state, percentbuffered, starving, diskbusy);
+    if (result != FMOD_OK)
+    {
+        LL_WARNS("FMOD") << FMOD_ErrorString(result) << LL_ENDL;
+    }
     return state;
 }
 
 void LLStreamingAudio_FMODSTUDIO::setBufferSizes(U32 streambuffertime, U32 decodebuffertime)
 {
-    mSystem->setStreamBufferSize(streambuffertime / 1000 * 128 * 128, FMOD_TIMEUNIT_RAWBYTES);
+    FMOD_RESULT result = mSystem->setStreamBufferSize(streambuffertime / 1000 * 128 * 128, FMOD_TIMEUNIT_RAWBYTES);
+    if (result != FMOD_OK)
+    {
+        LL_WARNS("FMOD") << "setStreamBufferSize error: " << FMOD_ErrorString(result) << LL_ENDL;
+        return;
+    }
     FMOD_ADVANCEDSETTINGS settings;
     memset(&settings, 0, sizeof(settings));
     settings.cbSize = sizeof(settings);
     settings.defaultDecodeBufferSize = decodebuffertime;//ms
-    mSystem->setAdvancedSettings(&settings);
+    result = mSystem->setAdvancedSettings(&settings);
+    if (result != FMOD_OK)
+    {
+        LL_WARNS("FMOD") << "setAdvancedSettings error: " << FMOD_ErrorString(result) << LL_ENDL;
+    }
 }
diff --git a/indra/llcharacter/llbvhloader.cpp b/indra/llcharacter/llbvhloader.cpp
index e906d81ce15229ae99aad55dd06c4bcecee4d5c6..c38614b0b427a2d0ad21c9e7e4d9dc9313d557b4 100644
--- a/indra/llcharacter/llbvhloader.cpp
+++ b/indra/llcharacter/llbvhloader.cpp
@@ -44,6 +44,14 @@ using namespace std;
 
 #define INCHES_TO_METERS 0.02540005f
 
+/// The .bvh does not have a formal spec, and different readers interpret things in their own way.
+/// In OUR usage, frame 0 is used in optimization and is not considered to be part of the animation.
+const S32 NUMBER_OF_IGNORED_FRAMES_AT_START = 1;
+/// In our usage, the last frame is used only to indicate what the penultimate frame should be interpolated towards.
+///  I.e., the animation only plays up to the start of the last frame. There is no hold or exptrapolation past that point..
+/// Thus there are two frame of the total that do not contribute to the total running time of the animation.
+const S32 NUMBER_OF_UNPLAYED_FRAMES = NUMBER_OF_IGNORED_FRAMES_AT_START + 1;
+
 const F32 POSITION_KEYFRAME_THRESHOLD_SQUARED = 0.03f * 0.03f;
 const F32 ROTATION_KEYFRAME_THRESHOLD = 0.01f;
 
@@ -865,7 +873,10 @@ ELoadStatus LLBVHLoader::loadBVHFile(const char *buffer, char* error_text, S32 &
 		return E_ST_NO_FRAME_TIME;
 	}
 
-	mDuration = (F32)mNumFrames * mFrameTime;
+	// If the user only supplies one animation frame (after the ignored reference frame 0), hold for mFrameTime.
+	// If the user supples exactly one total frame, it isn't clear if that is a pose or reference frame, and the
+	// behavior is not defined. In this case, retain historical undefined behavior.
+	mDuration = llmax((F32)(mNumFrames - NUMBER_OF_UNPLAYED_FRAMES), 1.0f) * mFrameTime;
 	if (!mLoop)
 	{
 		mLoopOutPoint = mDuration;
@@ -1355,12 +1366,13 @@ BOOL LLBVHLoader::serialize(LLDataPacker& dp)
 
 		LLQuaternion::Order order = bvhStringToOrder( joint->mOrder );
 		S32 outcount = 0;
-		S32 frame = 1;
+		S32 frame = 0;
 		for (	ki = joint->mKeys.begin();
 				ki != joint->mKeys.end();
 				++ki )
 		{
-			if ((frame == 1) && joint->mRelativeRotationKey)
+
+			if ((frame == 0) && joint->mRelativeRotationKey)
 			{
 				first_frame_rot = mayaQ( ki->mRot[0], ki->mRot[1], ki->mRot[2], order);
 				
@@ -1373,7 +1385,7 @@ BOOL LLBVHLoader::serialize(LLDataPacker& dp)
 				continue;
 			}
 
-			time = (F32)frame * mFrameTime;
+			time = llmax((F32)(frame - NUMBER_OF_IGNORED_FRAMES_AT_START), 0.0f) * mFrameTime; // Time elapsed before this frame starts.
 
 			if (mergeParent)
 			{
@@ -1433,12 +1445,12 @@ BOOL LLBVHLoader::serialize(LLDataPacker& dp)
 			LLVector3 relPos = joint->mRelativePosition;
 			LLVector3 relKey;
 
-			frame = 1;
+			frame = 0;
 			for (	ki = joint->mKeys.begin();
 					ki != joint->mKeys.end();
 					++ki )
 			{
-				if ((frame == 1) && joint->mRelativePositionKey)
+				if ((frame == 0) && joint->mRelativePositionKey)
 				{
 					relKey.setVec(ki->mPos);
 				}
@@ -1449,7 +1461,7 @@ BOOL LLBVHLoader::serialize(LLDataPacker& dp)
 					continue;
 				}
 
-				time = (F32)frame * mFrameTime;
+				time = llmax((F32)(frame - NUMBER_OF_IGNORED_FRAMES_AT_START), 0.0f) * mFrameTime; // Time elapsed before this frame starts.
 
 				LLVector3 inPos = (LLVector3(ki->mPos) - relKey) * ~first_frame_rot;// * fixup_rot;
 				LLVector3 outPos = inPos * frameRot * offsetRot;
diff --git a/indra/llcharacter/llcharacter.cpp b/indra/llcharacter/llcharacter.cpp
index b764ef0c7e1f206abe615efe2f17e4c7418de877..376f096642e1dbbdd566c1b3388a3494a2bde22c 100644
--- a/indra/llcharacter/llcharacter.cpp
+++ b/indra/llcharacter/llcharacter.cpp
@@ -188,20 +188,15 @@ void LLCharacter::requestStopMotion( LLMotion* motion)
 //-----------------------------------------------------------------------------
 // updateMotions()
 //-----------------------------------------------------------------------------
-static LLTrace::BlockTimerStatHandle FTM_UPDATE_ANIMATION("Update Animation");
-static LLTrace::BlockTimerStatHandle FTM_UPDATE_HIDDEN_ANIMATION("Update Hidden Anim");
-static LLTrace::BlockTimerStatHandle FTM_UPDATE_MOTIONS("Update Motions");
-
 void LLCharacter::updateMotions(e_update_t update_type)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
 	if (update_type == HIDDEN_UPDATE)
 	{
-		LL_RECORD_BLOCK_TIME(FTM_UPDATE_HIDDEN_ANIMATION);
 		mMotionController.updateMotionsMinimal();
 	}
 	else
 	{
-		LL_RECORD_BLOCK_TIME(FTM_UPDATE_ANIMATION);
 		// unpause if the number of outstanding pause requests has dropped to the initial one
 		if (mMotionController.isPaused() && mPauseRequest->getNumRefs() == 1)
 		{
@@ -209,7 +204,6 @@ void LLCharacter::updateMotions(e_update_t update_type)
 		}
 		bool force_update = (update_type == FORCE_UPDATE);
 		{
-			LL_RECORD_BLOCK_TIME(FTM_UPDATE_MOTIONS);
 			mMotionController.updateMotions(force_update);
 		}
 	}
diff --git a/indra/llcharacter/lleditingmotion.cpp b/indra/llcharacter/lleditingmotion.cpp
index ddf89f30f22bb34f35df1ed65775c0ab39dd56d1..c5757163d92bb43f297d61837c88f34e7c8fc129 100644
--- a/indra/llcharacter/lleditingmotion.cpp
+++ b/indra/llcharacter/lleditingmotion.cpp
@@ -163,6 +163,7 @@ BOOL LLEditingMotion::onActivate()
 //-----------------------------------------------------------------------------
 BOOL LLEditingMotion::onUpdate(F32 time, U8* joint_mask)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	LLVector3 focus_pt;
 	LLVector3* pointAtPt = (LLVector3*)mCharacter->getAnimationData("PointAtPoint");
 
diff --git a/indra/llcharacter/lleditingmotion.h b/indra/llcharacter/lleditingmotion.h
index 7b1c8bb0598ad3a4be255011978bd9553c532342..80c1717a707a27a4f16d18fa543a04d2cd5dc458 100644
--- a/indra/llcharacter/lleditingmotion.h
+++ b/indra/llcharacter/lleditingmotion.h
@@ -42,9 +42,11 @@
 //-----------------------------------------------------------------------------
 // class LLEditingMotion
 //-----------------------------------------------------------------------------
+LL_ALIGN_PREFIX(16)
 class LLEditingMotion :
 	public LLMotion
 {
+    LL_ALIGN_NEW
 public:
 	// Constructor
 	LLEditingMotion(const LLUUID &id);
@@ -108,6 +110,13 @@ class LLEditingMotion :
 	//-------------------------------------------------------------------------
 	// joint states to be animated
 	//-------------------------------------------------------------------------
+    LL_ALIGN_16(LLJoint				mParentJoint);
+    LL_ALIGN_16(LLJoint				mShoulderJoint);
+    LL_ALIGN_16(LLJoint				mElbowJoint);
+    LL_ALIGN_16(LLJoint				mWristJoint);
+    LL_ALIGN_16(LLJoint				mTarget);
+    LLJointSolverRP3	mIKSolver;
+
 	LLCharacter			*mCharacter;
 	LLVector3			mWristOffset;
 
@@ -117,17 +126,10 @@ class LLEditingMotion :
 	LLPointer<LLJointState> mWristState;
 	LLPointer<LLJointState> mTorsoState;
 
-	LLJoint				mParentJoint;
-	LLJoint				mShoulderJoint;
-	LLJoint				mElbowJoint;
-	LLJoint				mWristJoint;
-	LLJoint				mTarget;
-	LLJointSolverRP3	mIKSolver;
-
 	static S32			sHandPose;
 	static S32			sHandPosePriority;
 	LLVector3			mLastSelectPt;
-};
+} LL_ALIGN_POSTFIX(16);
 
 #endif // LL_LLKEYFRAMEMOTION_H
 
diff --git a/indra/llcharacter/llhandmotion.cpp b/indra/llcharacter/llhandmotion.cpp
index b3bf5a9a919d9b1ed2e835702ce5e485c5da5112..ceba956214fcbaa621bb6720068345ed5a1572f6 100644
--- a/indra/llcharacter/llhandmotion.cpp
+++ b/indra/llcharacter/llhandmotion.cpp
@@ -121,6 +121,7 @@ BOOL LLHandMotion::onActivate()
 //-----------------------------------------------------------------------------
 BOOL LLHandMotion::onUpdate(F32 time, U8* joint_mask)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	eHandPose *requestedHandPose;
 
 	F32 timeDelta = time - mLastTime;
diff --git a/indra/llcharacter/llheadrotmotion.cpp b/indra/llcharacter/llheadrotmotion.cpp
index e91de7a11d8a17a3e73942957a5ac4342f9f1b17..07a3aaebb60abc7e23a6d643b1b9190ffdbac77e 100644
--- a/indra/llcharacter/llheadrotmotion.cpp
+++ b/indra/llcharacter/llheadrotmotion.cpp
@@ -175,6 +175,7 @@ BOOL LLHeadRotMotion::onActivate()
 //-----------------------------------------------------------------------------
 BOOL LLHeadRotMotion::onUpdate(F32 time, U8* joint_mask)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
 	LLQuaternion	targetHeadRotWorld;
 	LLQuaternion	currentRootRotWorld = mRootJoint->getWorldRotation();
 	LLQuaternion	currentInvRootRotWorld = ~currentRootRotWorld;
@@ -458,6 +459,7 @@ void LLEyeMotion::adjustEyeTarget(LLVector3* targetPos, LLJointState& left_eye_s
 //-----------------------------------------------------------------------------
 BOOL LLEyeMotion::onUpdate(F32 time, U8* joint_mask)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
 	//calculate jitter
 	if (mEyeJitterTimer.getElapsedTimeF32() > mEyeJitterTime)
 	{
diff --git a/indra/llcharacter/lljoint.cpp b/indra/llcharacter/lljoint.cpp
index dee642310e0bea014d2569c5f2bf775251981d42..d72282ab4210759dc728632dc99415582bed243a 100644
--- a/indra/llcharacter/lljoint.cpp
+++ b/indra/llcharacter/lljoint.cpp
@@ -922,6 +922,13 @@ const LLMatrix4 &LLJoint::getWorldMatrix()
 	return mXform.getWorldMatrix();
 }
 
+const LLMatrix4a& LLJoint::getWorldMatrix4a()
+{
+    updateWorldMatrixParent();
+
+    return mWorldMatrix;
+}
+
 
 //--------------------------------------------------------------------
 // setWorldMatrix()
@@ -1003,6 +1010,7 @@ void LLJoint::updateWorldMatrix()
 	{
 		sNumUpdates++;
 		mXform.updateMatrix(FALSE);
+        mWorldMatrix.loadu(mXform.getWorldMatrix());
 		mDirtyFlags = 0x0;
 	}
 }
diff --git a/indra/llcharacter/lljoint.h b/indra/llcharacter/lljoint.h
index 1b646b641f4bb39696c7864e18f601fea490175e..63d99b920905017a1e4025cb08a263bf423b9088 100644
--- a/indra/llcharacter/lljoint.h
+++ b/indra/llcharacter/lljoint.h
@@ -38,6 +38,7 @@
 #include "m4math.h"
 #include "llquaternion.h"
 #include "xform.h"
+#include "llmatrix4a.h"
 
 const S32 LL_CHARACTER_MAX_JOINTS_PER_MESH = 15;
 // Need to set this to count of animate-able joints,
@@ -85,8 +86,10 @@ inline bool operator!=(const LLVector3OverrideMap& a, const LLVector3OverrideMap
 //-----------------------------------------------------------------------------
 // class LLJoint
 //-----------------------------------------------------------------------------
+LL_ALIGN_PREFIX(16)
 class LLJoint
 {
+    LL_ALIGN_NEW
 public:
 	// priority levels, from highest to lowest
 	enum JointPriority
@@ -114,16 +117,17 @@ class LLJoint
         SUPPORT_EXTENDED
     };
 protected:
-	std::string	mName;
+    // explicit transformation members
+    LL_ALIGN_16(LLMatrix4a          mWorldMatrix);
+    LLXformMatrix       mXform;
+	
+    std::string	mName;
 
 	SupportCategory mSupport;
 
 	// parent joint
 	LLJoint	*mParent;
 
-	// explicit transformation members
-	LLXformMatrix		mXform;
-
     LLVector3       mDefaultPosition;
     LLVector3       mDefaultScale;
     
@@ -259,6 +263,8 @@ class LLJoint
 	const LLMatrix4 &getWorldMatrix();
 	void setWorldMatrix( const LLMatrix4& mat );
 
+    const LLMatrix4a& getWorldMatrix4a();
+
 	void updateWorldMatrixChildren();
 	void updateWorldMatrixParent();
 
@@ -296,6 +302,6 @@ class LLJoint
     // These are used in checks of whether a pos/scale override is considered significant.
     bool aboveJointPosThreshold(const LLVector3& pos) const;
     bool aboveJointScaleThreshold(const LLVector3& scale) const;
-};
+} LL_ALIGN_POSTFIX(16);
 #endif // LL_LLJOINT_H
 
diff --git a/indra/llcharacter/lljointsolverrp3.cpp b/indra/llcharacter/lljointsolverrp3.cpp
index 69a7e3dc6e7593c314ab30a2e94960a0ef6f17cc..f3d5e2e32411fc3f149fc12f4874a53d35c7ea69 100644
--- a/indra/llcharacter/lljointsolverrp3.cpp
+++ b/indra/llcharacter/lljointsolverrp3.cpp
@@ -1,6 +1,6 @@
 /** 
  * @file lljointsolverrp3.cpp
- * @brief Implementation of LLJointSolverRP3 class.
+ * @brief Implementation of Joint Solver in 3D Real Projective space (RP3). See: https://en.wikipedia.org/wiki/Real_projective_space
  *
  * $LicenseInfo:firstyear=2001&license=viewerlgpl$
  * Second Life Viewer Source Code
@@ -35,6 +35,11 @@
 
 #define F_EPSILON 0.00001f
 
+#if LL_RELEASE
+    #define DEBUG_JOINT_SOLVER 0
+#else
+    #define DEBUG_JOINT_SOLVER 1
+#endif
 
 //-----------------------------------------------------------------------------
 // Constructor
@@ -150,6 +155,7 @@ void LLJointSolverRP3::solve()
 	LLVector3 cPos = mJointC->getWorldPosition();
 	LLVector3 gPos = mJointGoal->getWorldPosition();
 
+#if DEBUG_JOINT_SOLVER
 	LL_DEBUGS("JointSolver") << "LLJointSolverRP3::solve()" << LL_NEWLINE
 							<< "bPosLocal = " << mJointB->getPosition() << LL_NEWLINE
 							<< "cPosLocal = " << mJointC->getPosition() << LL_NEWLINE
@@ -159,6 +165,7 @@ void LLJointSolverRP3::solve()
 							<< "bPos : " << bPos << LL_NEWLINE
 							<< "cPos : " << cPos << LL_NEWLINE
 							<< "gPos : " << gPos << LL_ENDL;
+#endif
 
 	//-------------------------------------------------------------------------
 	// get the poleVector in world space
@@ -194,6 +201,7 @@ void LLJointSolverRP3::solve()
 	//-------------------------------------------------------------------------
 	LLVector3 abacCompOrthoVec = abVec - acVec * ((abVec * acVec)/(acVec * acVec));
 
+#if DEBUG_JOINT_SOLVER
 	LL_DEBUGS("JointSolver") << "abVec : " << abVec << LL_NEWLINE
 		<< "bcVec : " << bcVec << LL_NEWLINE
 		<< "acVec : " << acVec << LL_NEWLINE
@@ -202,6 +210,7 @@ void LLJointSolverRP3::solve()
 		<< "bcLen : " << bcLen << LL_NEWLINE
 		<< "agLen : " << agLen << LL_NEWLINE
 		<< "abacCompOrthoVec : " << abacCompOrthoVec << LL_ENDL;
+#endif
 
 	//-------------------------------------------------------------------------
 	// compute the normal of the original ABC plane (and store for later)
@@ -269,6 +278,7 @@ void LLJointSolverRP3::solve()
 
 	LLQuaternion bRot(theta - abbcAng, abbcOrthoVec);
 
+#if DEBUG_JOINT_SOLVER
 	LL_DEBUGS("JointSolver") << "abbcAng      : " << abbcAng << LL_NEWLINE
 							<< "abbcOrthoVec : " << abbcOrthoVec << LL_NEWLINE
 							<< "agLenSq      : " << agLenSq << LL_NEWLINE
@@ -280,6 +290,7 @@ void LLJointSolverRP3::solve()
 								<< abbcAng*180.0f/F_PI << " " 
 								<< (theta - abbcAng)*180.0f/F_PI 
 	<< LL_ENDL;
+#endif
 
 	//-------------------------------------------------------------------------
 	// compute rotation that rotates new A->C to A->G
@@ -293,9 +304,11 @@ void LLJointSolverRP3::solve()
 	LLQuaternion cgRot;
 	cgRot.shortestArc( acVec, agVec );
 
+#if DEBUG_JOINT_SOLVER
 	LL_DEBUGS("JointSolver") << "bcVec : " << bcVec << LL_NEWLINE
 							<< "acVec : " << acVec << LL_NEWLINE
 							<< "cgRot : " << cgRot << LL_ENDL;
+#endif
 
 	// update A->B and B->C with rotation from C to G
 	abVec = abVec * cgRot;
@@ -358,11 +371,13 @@ void LLJointSolverRP3::solve()
 	//-------------------------------------------------------------------------
 	LLQuaternion twistRot( mTwist, agVec );
 
+#if DEBUG_JOINT_SOLVER
 	LL_DEBUGS("JointSolver") << "abcNorm = " << abcNorm << LL_NEWLINE
 							<< "apgNorm = " << apgNorm << LL_NEWLINE
 							<< "pRot = " << pRot << LL_NEWLINE
 							<< "twist    : " << mTwist*180.0/F_PI << LL_NEWLINE
 							<< "twistRot : " << twistRot << LL_ENDL;
+#endif
 
 	//-------------------------------------------------------------------------
 	// compute rotation of A
diff --git a/indra/llcharacter/llkeyframefallmotion.cpp b/indra/llcharacter/llkeyframefallmotion.cpp
index 7842f0e5fbce9d7c75b671aa7dd123e860eba1c5..e8bb2bf95d092bec927044cada88978552f8e56b 100644
--- a/indra/llcharacter/llkeyframefallmotion.cpp
+++ b/indra/llcharacter/llkeyframefallmotion.cpp
@@ -121,6 +121,7 @@ BOOL LLKeyframeFallMotion::onActivate()
 //-----------------------------------------------------------------------------
 BOOL LLKeyframeFallMotion::onUpdate(F32 activeTime, U8* joint_mask)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
 	BOOL result = LLKeyframeMotion::onUpdate(activeTime, joint_mask);
 	F32  slerp_amt = clamp_rescale(activeTime / getDuration(), 0.5f, 0.75f, 0.f, 1.f);
 
diff --git a/indra/llcharacter/llkeyframemotion.cpp b/indra/llcharacter/llkeyframemotion.cpp
index fe9de30f0a0bbc6d968e87578ccd9318f48e0be4..ebf7454a6154cd148b8d5a0e6de1cd8ab196bb6f 100644
--- a/indra/llcharacter/llkeyframemotion.cpp
+++ b/indra/llcharacter/llkeyframemotion.cpp
@@ -677,6 +677,7 @@ BOOL LLKeyframeMotion::onActivate()
 //-----------------------------------------------------------------------------
 BOOL LLKeyframeMotion::onUpdate(F32 time, U8* joint_mask)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
 	// llassert(time >= 0.f);		// This will fire
 	time = llmax(0.f, time);
 
@@ -1221,8 +1222,11 @@ void LLKeyframeMotion::applyConstraint(JointConstraint* constraint, F32 time, U8
 
 //-----------------------------------------------------------------------------
 // deserialize()
+//
+// allow_invalid_joints should be true when handling existing content, to avoid breakage.
+// During upload, we should be more restrictive and reject such animations.
 //-----------------------------------------------------------------------------
-BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp, const LLUUID& asset_id)
+BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp, const LLUUID& asset_id, bool allow_invalid_joints)
 {
 	BOOL old_version = FALSE;
 	mJointMotionList = new LLKeyframeMotion::JointMotionList;
@@ -1343,6 +1347,15 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp, const LLUUID& asset_id)
 		return FALSE;
 	}
 
+	//SL-17206 hack to alter Female_land loop setting, while current behavior won't be changed serverside
+	LLUUID const female_land_anim("ca1baf4d-0a18-5a1f-0330-e4bd1e71f09e");
+	LLUUID const formal_female_land_anim("6a9a173b-61fa-3ad5-01fa-a851cfc5f66a");
+	if (female_land_anim == asset_id || formal_female_land_anim == asset_id)
+	{
+		LL_WARNS() << "Animation(" << asset_id << ") won't be looped." << LL_ENDL;
+		mJointMotionList->mLoop = FALSE;
+	}
+
 	//-------------------------------------------------------------------------
 	// get easeIn and easeOut
 	//-------------------------------------------------------------------------
@@ -1442,6 +1455,7 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp, const LLUUID& asset_id)
 		if (joint)
 		{
             S32 joint_num = joint->getJointNum();
+			joint_name = joint->getName(); // canonical name in case this is an alias.
 //			LL_INFOS() << "  joint: " << joint_name << LL_ENDL;
             if ((joint_num >= (S32)LL_CHARACTER_MAX_ANIMATED_JOINTS) || (joint_num < 0))
             {
@@ -1456,7 +1470,10 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp, const LLUUID& asset_id)
 		{
 			LL_WARNS() << "invalid joint name: " << joint_name
                        << " for animation " << asset_id << LL_ENDL;
-			//return FALSE;
+			if (!allow_invalid_joints)
+			{
+				return FALSE;
+			}
 		}
 
 		joint_motion->mJointName = joint_name;
@@ -2095,8 +2112,9 @@ U32	LLKeyframeMotion::getFileSize()
 //-----------------------------------------------------------------------------
 // dumpToFile()
 //-----------------------------------------------------------------------------
-void LLKeyframeMotion::dumpToFile(const std::string& name)
+bool LLKeyframeMotion::dumpToFile(const std::string& name)
 {
+	bool succ = false;
     if (isLoaded())
     {
         std::string outfile_base;
@@ -2113,10 +2131,24 @@ void LLKeyframeMotion::dumpToFile(const std::string& name)
             const LLUUID& id = getID();
             outfile_base = id.asString();
         }
-        std::string outfilename = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,outfile_base + ".anim");
+
+		if (gDirUtilp->getExtension(outfile_base).empty())
+		{
+			outfile_base += ".anim";
+		}
+		std::string outfilename;
+		if (gDirUtilp->getDirName(outfile_base).empty())
+		{
+			outfilename = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,outfile_base);
+		}
+		else
+		{
+			outfilename = outfile_base;
+		}
         if (LLFile::isfile(outfilename))
         {
-            return;
+			LL_WARNS() << outfilename << " already exists, write failed" << LL_ENDL;
+            return false;
         }
 
         S32 file_size = getFileSize();
@@ -2130,11 +2162,13 @@ void LLKeyframeMotion::dumpToFile(const std::string& name)
             outfile.open(outfilename, LL_APR_WPB);
             if (outfile.getFileHandle())
             {
-                outfile.write(buffer, file_size);
+                S32 wrote_bytes = outfile.write(buffer, file_size);
+				succ = (wrote_bytes == file_size);
             }
         }
         delete [] buffer;
     }
+	return succ;
 }
 
 //-----------------------------------------------------------------------------
diff --git a/indra/llcharacter/llkeyframemotion.h b/indra/llcharacter/llkeyframemotion.h
index 9a927ede9ae7f78cee4ae275507f047e18d9026a..96746f57c923fe55254ddc1f151f19d1b37d7eb1 100644
--- a/indra/llcharacter/llkeyframemotion.h
+++ b/indra/llcharacter/llkeyframemotion.h
@@ -156,9 +156,9 @@ class LLKeyframeMotion :
 public:
 	U32		getFileSize();
 	BOOL	serialize(LLDataPacker& dp) const;
-	BOOL	deserialize(LLDataPacker& dp, const LLUUID& asset_id);
+	BOOL	deserialize(LLDataPacker& dp, const LLUUID& asset_id, bool allow_invalid_joints = true);
 	BOOL	isLoaded() { return mJointMotionList != NULL; }
-    void	dumpToFile(const std::string& name);
+    bool	dumpToFile(const std::string& name);
 
 
 	// setters for modifying a keyframe animation
@@ -432,6 +432,9 @@ class LLKeyframeMotion :
 	F32								mLastUpdateTime;
 	F32								mLastLoopedTime;
 	AssetStatus						mAssetStatus;
+
+public:
+	void setCharacter(LLCharacter* character) { mCharacter = character; }
 };
 
 class LLKeyframeDataCache
diff --git a/indra/llcharacter/llkeyframemotionparam.cpp b/indra/llcharacter/llkeyframemotionparam.cpp
index 6ed18bc4455972d76acc18cb69236491158b6c4f..aba1c5db395c77d4fbf7726f44a8d63a1e694650 100644
--- a/indra/llcharacter/llkeyframemotionparam.cpp
+++ b/indra/llcharacter/llkeyframemotionparam.cpp
@@ -158,6 +158,7 @@ BOOL LLKeyframeMotionParam::onActivate()
 //-----------------------------------------------------------------------------
 BOOL LLKeyframeMotionParam::onUpdate(F32 time, U8* joint_mask)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	F32 weightFactor = 1.f / (F32)mParameterizedMotions.size();
 
 	// zero out all pose weights
diff --git a/indra/llcharacter/llkeyframestandmotion.h b/indra/llcharacter/llkeyframestandmotion.h
index c2634ecd6d185f452dd6f90a8a996566fd6f5874..1aa5b187ba00a5f058cb52b42e8e2de902c1c402 100644
--- a/indra/llcharacter/llkeyframestandmotion.h
+++ b/indra/llcharacter/llkeyframestandmotion.h
@@ -37,9 +37,11 @@
 //-----------------------------------------------------------------------------
 // class LLKeyframeStandMotion
 //-----------------------------------------------------------------------------
+LL_ALIGN_PREFIX(16)
 class LLKeyframeStandMotion :
 	public LLKeyframeMotion
 {
+    LL_ALIGN_NEW
 public:
 	// Constructor
 	LLKeyframeStandMotion(const LLUUID &id);
@@ -69,6 +71,18 @@ class LLKeyframeStandMotion :
 	//-------------------------------------------------------------------------
 	// Member Data
 	//-------------------------------------------------------------------------
+    LLJoint				mPelvisJoint;
+
+    LLJoint				mHipLeftJoint;
+    LLJoint				mKneeLeftJoint;
+    LLJoint				mAnkleLeftJoint;
+    LLJoint				mTargetLeft;
+
+    LLJoint				mHipRightJoint;
+    LLJoint				mKneeRightJoint;
+    LLJoint				mAnkleRightJoint;
+    LLJoint				mTargetRight;
+
 	LLCharacter	*mCharacter;
 
 	BOOL				mFlipFeet;
@@ -83,18 +97,6 @@ class LLKeyframeStandMotion :
 	LLPointer<LLJointState>	mKneeRightState;
 	LLPointer<LLJointState>	mAnkleRightState;
 
-	LLJoint				mPelvisJoint;
-
-	LLJoint				mHipLeftJoint;
-	LLJoint				mKneeLeftJoint;
-	LLJoint				mAnkleLeftJoint;
-	LLJoint				mTargetLeft;
-
-	LLJoint				mHipRightJoint;
-	LLJoint				mKneeRightJoint;
-	LLJoint				mAnkleRightJoint;
-	LLJoint				mTargetRight;
-
 	LLJointSolverRP3	mIKLeft;
 	LLJointSolverRP3	mIKRight;
 
@@ -110,7 +112,7 @@ class LLKeyframeStandMotion :
 	BOOL				mTrackAnkles;
 
 	S32					mFrameNum;
-};
+} LL_ALIGN_POSTFIX(16);
 
 #endif // LL_LLKEYFRAMESTANDMOTION_H
 
diff --git a/indra/llcharacter/llkeyframewalkmotion.cpp b/indra/llcharacter/llkeyframewalkmotion.cpp
index f180702385c6113d64cea9b2967f3d9b35caffe1..298b37e60cb19a0694a3f29d5aec386a9de23339 100644
--- a/indra/llcharacter/llkeyframewalkmotion.cpp
+++ b/indra/llcharacter/llkeyframewalkmotion.cpp
@@ -105,6 +105,7 @@ void LLKeyframeWalkMotion::onDeactivate()
 //-----------------------------------------------------------------------------
 BOOL LLKeyframeWalkMotion::onUpdate(F32 time, U8* joint_mask)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	// compute time since last update
 	F32 deltaTime = time - mRealTimeLast;
 
@@ -198,6 +199,7 @@ BOOL LLWalkAdjustMotion::onActivate()
 //-----------------------------------------------------------------------------
 BOOL LLWalkAdjustMotion::onUpdate(F32 time, U8* joint_mask)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	// delta_time is guaranteed to be non zero
 	F32 delta_time = llclamp(time - mLastTime, TIME_EPSILON, MAX_TIME_DELTA);
 	mLastTime = time;
@@ -373,6 +375,7 @@ BOOL LLFlyAdjustMotion::onActivate()
 //-----------------------------------------------------------------------------
 BOOL LLFlyAdjustMotion::onUpdate(F32 time, U8* joint_mask)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	LLVector3 ang_vel = mCharacter->getCharacterAngularVelocity() * mCharacter->getTimeDilation();
 	F32 speed = mCharacter->getCharacterVelocity().magVec();
 
diff --git a/indra/llcharacter/llmotioncontroller.cpp b/indra/llcharacter/llmotioncontroller.cpp
index c48d02b6529077473377201456e061fd60b8771c..e66714388a4105b673ec06f1936cdb5a217a06b5 100644
--- a/indra/llcharacter/llmotioncontroller.cpp
+++ b/indra/llcharacter/llmotioncontroller.cpp
@@ -503,6 +503,7 @@ void LLMotionController::resetJointSignatures()
 //-----------------------------------------------------------------------------
 void LLMotionController::updateIdleMotion(LLMotion* motionp)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
 	if (motionp->isStopped() && mAnimTime > motionp->getStopTime() + motionp->getEaseOutDuration())
 	{
 		deactivateMotionInstance(motionp);
@@ -541,6 +542,7 @@ void LLMotionController::updateIdleMotion(LLMotion* motionp)
 //-----------------------------------------------------------------------------
 void LLMotionController::updateIdleActiveMotions()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
 	for (motion_list_t::iterator iter = mActiveMotions.begin();
 		 iter != mActiveMotions.end(); )
 	{
@@ -553,10 +555,9 @@ void LLMotionController::updateIdleActiveMotions()
 //-----------------------------------------------------------------------------
 // updateMotionsByType()
 //-----------------------------------------------------------------------------
-static LLTrace::BlockTimerStatHandle FTM_MOTION_ON_UPDATE("Motion onUpdate");
-
 void LLMotionController::updateMotionsByType(LLMotion::LLMotionBlendType anim_type)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
 	BOOL update_result = TRUE;
 	U8 last_joint_signature[LL_CHARACTER_MAX_ANIMATED_JOINTS];
 
@@ -712,7 +713,6 @@ void LLMotionController::updateMotionsByType(LLMotion::LLMotionBlendType anim_ty
 
 			// perform motion update
 			{
-				LL_RECORD_BLOCK_TIME(FTM_MOTION_ON_UPDATE);
 				update_result = motionp->onUpdate(mAnimTime - motionp->mActivationTimestamp, last_joint_signature);
 			}
 		}
@@ -768,6 +768,7 @@ void LLMotionController::updateMotionsByType(LLMotion::LLMotionBlendType anim_ty
 //-----------------------------------------------------------------------------
 void LLMotionController::updateLoadingMotions()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
 	// query pending motions for completion
 	for (motion_set_t::iterator iter = mLoadingMotions.begin();
 		 iter != mLoadingMotions.end(); )
@@ -815,6 +816,7 @@ void LLMotionController::updateLoadingMotions()
 //-----------------------------------------------------------------------------
 void LLMotionController::updateMotions(bool force_update)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
     // SL-763: "Distant animated objects run at super fast speed"
     // The use_quantum optimization or possibly the associated code in setTimeStamp()
     // does not work as implemented.
@@ -907,6 +909,7 @@ void LLMotionController::updateMotions(bool force_update)
 //-----------------------------------------------------------------------------
 void LLMotionController::updateMotionsMinimal()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
 	// Always update mPrevTimerElapsed
 	mPrevTimerElapsed = mTimer.getElapsedTimeF32();
 
@@ -924,6 +927,7 @@ void LLMotionController::updateMotionsMinimal()
 //-----------------------------------------------------------------------------
 BOOL LLMotionController::activateMotionInstance(LLMotion *motion, F32 time)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
 	// It's not clear why the getWeight() line seems to be crashing this, but
 	// hopefully this fixes it.
 	if (motion == NULL || motion->getPose() == NULL)
diff --git a/indra/llcharacter/llpose.h b/indra/llcharacter/llpose.h
index c004a0f3b74388b3ceb7999eca33b2dff6a59fb9..1405f1e053a379c877a7d82502352055d42cc365 100644
--- a/indra/llcharacter/llpose.h
+++ b/indra/llcharacter/llpose.h
@@ -80,8 +80,10 @@ class LLPose
 
 const S32 JSB_NUM_JOINT_STATES = 6;
 
+LL_ALIGN_PREFIX(16)
 class LLJointStateBlender
 {
+    LL_ALIGN_NEW
 protected:
 	LLPointer<LLJointState>	mJointStates[JSB_NUM_JOINT_STATES];
 	S32				mPriorities[JSB_NUM_JOINT_STATES];
@@ -96,8 +98,8 @@ class LLJointStateBlender
 	void resetCachedJoint();
 
 public:
-	LLJoint mJointCache;
-};
+	LL_ALIGN_16(LLJoint mJointCache);
+} LL_ALIGN_POSTFIX(16);
 
 class LLMotion;
 
diff --git a/indra/llcharacter/lltargetingmotion.cpp b/indra/llcharacter/lltargetingmotion.cpp
index 69681e41970d5d18adbb8234fea78978e4f155cc..ec75212a4039975fa7c0f7b2838a5f1229506219 100644
--- a/indra/llcharacter/lltargetingmotion.cpp
+++ b/indra/llcharacter/lltargetingmotion.cpp
@@ -103,6 +103,7 @@ BOOL LLTargetingMotion::onActivate()
 //-----------------------------------------------------------------------------
 BOOL LLTargetingMotion::onUpdate(F32 time, U8* joint_mask)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	F32 slerp_amt = LLSmoothInterpolation::getInterpolant(TORSO_TARGET_HALF_LIFE);
 
 	LLVector3 target;
diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt
index 766a1849f9fdd6f634132286ed0cafa135fa3139..df65828d02ff6ffad43b8601e240f8fd6324f08f 100644
--- a/indra/llcommon/CMakeLists.txt
+++ b/indra/llcommon/CMakeLists.txt
@@ -10,15 +10,17 @@ include(Boost)
 include(LLSharedLibs)
 include(JsonCpp)
 include(Copy3rdPartyLibs)
-include(ZLIB)
+include(ZLIBNG)
 include(URIPARSER)
+include(Tracy)
 
 include_directories(
     ${EXPAT_INCLUDE_DIRS}
     ${LLCOMMON_INCLUDE_DIRS}
     ${JSONCPP_INCLUDE_DIR}
-    ${ZLIB_INCLUDE_DIRS}
+    ${ZLIBNG_INCLUDE_DIRS}
     ${URIPARSER_INCLUDE_DIRS}
+    ${TRACY_INCLUDE_DIR}
     )
 
 # add_executable(lltreeiterators lltreeiterators.cpp)
@@ -117,14 +119,17 @@ set(llcommon_SOURCE_FILES
     lluriparser.cpp
     lluuid.cpp
     llworkerthread.cpp
-    timing.cpp
     u64.cpp
+    threadpool.cpp
+    workqueue.cpp
     StackWalker.cpp
     )
     
 set(llcommon_HEADER_FILES
     CMakeLists.txt
 
+    chrono.h
+    classic_callback.h
     ctype_workaround.h
     fix_macros.h
     indra_constants.h
@@ -197,6 +202,8 @@ set(llcommon_HEADER_FILES
     llmortician.h
     llnametable.h
     llpointer.h
+    llprofiler.h
+    llprofilercategories.h
     llpounceable.h
     llpredicate.h
     llpreprocessor.h
@@ -251,10 +258,19 @@ set(llcommon_HEADER_FILES
     lockstatic.h
     stdtypes.h
     stringize.h
+    threadpool.h
+    threadsafeschedule.h
     timer.h
+    tuple.h
     u64.h
+    workqueue.h
     StackWalker.h
     )
+    
+if (DARWIN)
+  list(APPEND llcommon_HEADER_FILES llsys_objc.h)
+  list(APPEND llcommon_SOURCE_FILES llsys_objc.mm)
+endif (DARWIN)
 
 set_source_files_properties(${llcommon_HEADER_FILES}
                             PROPERTIES HEADER_FILE_ONLY TRUE)
@@ -290,7 +306,7 @@ target_link_libraries(
     ${APR_LIBRARIES}
     ${EXPAT_LIBRARIES}
     ${JSONCPP_LIBRARIES}
-    ${ZLIB_LIBRARIES}
+    ${ZLIBNG_LIBRARIES}
     ${WINDOWS_LIBRARIES}
     ${BOOST_FIBER_LIBRARY}
     ${BOOST_CONTEXT_LIBRARY}
@@ -299,14 +315,9 @@ target_link_libraries(
     ${BOOST_SYSTEM_LIBRARY}
     ${GOOGLE_PERFTOOLS_LIBRARIES}
     ${URIPARSER_LIBRARIES}
+    ${TRACY_LIBRARY}
     )
 
-if (DARWIN)
-  include(CMakeFindFrameworks)
-  find_library(CARBON_LIBRARY Carbon)
-  target_link_libraries(llcommon ${CARBON_LIBRARY})
-endif (DARWIN)
-
 add_dependencies(llcommon stage_third_party_libs)
 
 if (LL_TESTS)
@@ -325,16 +336,17 @@ if (LL_TESTS)
       ${BOOST_CONTEXT_LIBRARY} 
       ${BOOST_THREAD_LIBRARY} 
       ${BOOST_SYSTEM_LIBRARY})
-  LL_ADD_INTEGRATION_TEST(commonmisc "" "${test_libs}")
   LL_ADD_INTEGRATION_TEST(bitpack "" "${test_libs}")
+  LL_ADD_INTEGRATION_TEST(classic_callback "" "${test_libs}")
+  LL_ADD_INTEGRATION_TEST(commonmisc "" "${test_libs}")
   LL_ADD_INTEGRATION_TEST(llbase64 "" "${test_libs}")
   LL_ADD_INTEGRATION_TEST(llcond "" "${test_libs}")
   LL_ADD_INTEGRATION_TEST(lldate "" "${test_libs}")
   LL_ADD_INTEGRATION_TEST(lldeadmantimer "" "${test_libs}")
   LL_ADD_INTEGRATION_TEST(lldependencies "" "${test_libs}")
   LL_ADD_INTEGRATION_TEST(llerror "" "${test_libs}")
-  LL_ADD_INTEGRATION_TEST(lleventdispatcher "" "${test_libs}")
   LL_ADD_INTEGRATION_TEST(lleventcoro "" "${test_libs}")
+  LL_ADD_INTEGRATION_TEST(lleventdispatcher "" "${test_libs}")
   LL_ADD_INTEGRATION_TEST(lleventfilter "" "${test_libs}")
   LL_ADD_INTEGRATION_TEST(llframetimer "" "${test_libs}")
   LL_ADD_INTEGRATION_TEST(llheteromap "" "${test_libs}")
@@ -352,9 +364,12 @@ if (LL_TESTS)
   LL_ADD_INTEGRATION_TEST(llstring "" "${test_libs}")
   LL_ADD_INTEGRATION_TEST(lltrace "" "${test_libs}")
   LL_ADD_INTEGRATION_TEST(lltreeiterators "" "${test_libs}")
-  LL_ADD_INTEGRATION_TEST(lluri "" "${test_libs}")
   LL_ADD_INTEGRATION_TEST(llunits "" "${test_libs}")
+  LL_ADD_INTEGRATION_TEST(lluri "" "${test_libs}")
   LL_ADD_INTEGRATION_TEST(stringize "" "${test_libs}")
+  LL_ADD_INTEGRATION_TEST(threadsafeschedule "" "${test_libs}")
+  LL_ADD_INTEGRATION_TEST(tuple "" "${test_libs}")
+  LL_ADD_INTEGRATION_TEST(workqueue "" "${test_libs}")
 
 ## llexception_test.cpp isn't a regression test, and doesn't need to be run
 ## every build. It's to help a developer make implementation choices about
diff --git a/indra/llcommon/chrono.h b/indra/llcommon/chrono.h
new file mode 100644
index 0000000000000000000000000000000000000000..806e871892e4b38b352cb911740757aac5b986c1
--- /dev/null
+++ b/indra/llcommon/chrono.h
@@ -0,0 +1,65 @@
+/**
+ * @file   chrono.h
+ * @author Nat Goodspeed
+ * @date   2021-10-05
+ * @brief  supplement <chrono> with utility functions
+ * 
+ * $LicenseInfo:firstyear=2021&license=viewerlgpl$
+ * Copyright (c) 2021, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+#if ! defined(LL_CHRONO_H)
+#define LL_CHRONO_H
+
+#include <chrono>
+#include <type_traits>              // std::enable_if
+
+namespace LL
+{
+
+// time_point_cast() is derived from https://stackoverflow.com/a/35293183
+// without the iteration: we think errors in the ~1 microsecond range are
+// probably acceptable.
+
+// This variant is for the optimal case when the source and dest use the same
+// clock: that case is handled by std::chrono.
+template <typename DestTimePoint, typename SrcTimePoint,
+          typename std::enable_if<std::is_same<typename DestTimePoint::clock,
+                                               typename SrcTimePoint::clock>::value,
+                                  bool>::type = true>
+DestTimePoint time_point_cast(const SrcTimePoint& time)
+{
+    return std::chrono::time_point_cast<typename DestTimePoint::duration>(time);
+}
+
+// This variant is for when the source and dest use different clocks -- see
+// the linked StackOverflow answer, also Howard Hinnant's, for more context.
+template <typename DestTimePoint, typename SrcTimePoint,
+          typename std::enable_if<! std::is_same<typename DestTimePoint::clock,
+                                                 typename SrcTimePoint::clock>::value,
+                                  bool>::type = true>
+DestTimePoint time_point_cast(const SrcTimePoint& time)
+{
+    // The basic idea is that we must adjust the passed time_point by the
+    // difference between the clocks' epochs. But since time_point doesn't
+    // expose its epoch, we fall back on what each of them thinks is now().
+    // However, since we necessarily make sequential calls to those now()
+    // functions, the answers differ not only by the cycles spent executing
+    // those calls, but by potential OS interruptions between them. Try to
+    // reduce that error by capturing the source clock time both before and
+    // after the dest clock, and splitting the difference. Of course an
+    // interruption between two of these now() calls without a comparable
+    // interruption between the other two will skew the result, but better is
+    // more expensive.
+    const auto src_before = typename SrcTimePoint::clock::now();
+    const auto dest_now   = typename DestTimePoint::clock::now();
+    const auto src_after  = typename SrcTimePoint::clock::now();
+    const auto src_diff   = src_after - src_before;
+    const auto src_now    = src_before + src_diff / 2;
+    return dest_now + (time - src_now);
+}
+
+} // namespace LL
+
+#endif /* ! defined(LL_CHRONO_H) */
diff --git a/indra/llcommon/classic_callback.cpp b/indra/llcommon/classic_callback.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..5674e0a44dac169a6bca5b73f301707759a4dead
--- /dev/null
+++ b/indra/llcommon/classic_callback.cpp
@@ -0,0 +1,16 @@
+/**
+ * @file   classic_callback.cpp
+ * @author Nat Goodspeed
+ * @date   2021-09-23
+ * @brief  Implementation for classic_callback.
+ * 
+ * $LicenseInfo:firstyear=2021&license=viewerlgpl$
+ * Copyright (c) 2021, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+namespace {
+
+const char dummy[] = "cpp file required to build test program";
+
+} // anonymous namespace
diff --git a/indra/llcommon/classic_callback.h b/indra/llcommon/classic_callback.h
new file mode 100644
index 0000000000000000000000000000000000000000..1ad6dbc58fde86d77d461538297c2c9793f61dfb
--- /dev/null
+++ b/indra/llcommon/classic_callback.h
@@ -0,0 +1,292 @@
+/**
+ * @file   classic_callback.h
+ * @author Nat Goodspeed
+ * @date   2016-06-21
+ * @brief  ClassicCallback and HeapClassicCallback
+ *
+ * This header file addresses the problem of passing a method on a C++ object
+ * to an API that requires a classic-C function pointer. Typically such a
+ * callback API accepts a void* pointer along with the function pointer, and
+ * the function pointer signature accepts a void* parameter. The API passes
+ * the caller's pointer value into the callback function so it can find its
+ * data. In C++, there are a few ways to deal with this case:
+ *
+ * - Use a static method with correct signature. If you don't need access to a
+ *   specific instance, that works fine.
+ * - Store the object statically (or store a static pointer to a non-static
+ *   instance). As long as you only care about one instance, that works, but
+ *   starts to get a little icky. As soon as there's more than one pertinent
+ *   instance, fight valiantly against the temptation to stuff the instance
+ *   pointer into a static pointer variable "just for a moment."
+ * - Code a static trampoline callback function that accepts the void* user
+ *   data pointer, casts it to the appropriate class type and calls the actual
+ *   method on that class.
+ *
+ * ClassicCallback encapsulates the last. You need only construct a
+ * ClassicCallback instance somewhere that will survive until the callback is
+ * called, binding the target C++ callable. You then call its get_callback()
+ * and get_userdata() methods to pass an appropriate classic-C function
+ * pointer and void* user data pointer, respectively, to the old-style
+ * callback API. get_callback() synthesizes a static trampoline function
+ * that casts the user data pointer and calls the bound C++ callable.
+ *
+ * $LicenseInfo:firstyear=2016&license=viewerlgpl$
+ * Copyright (c) 2016, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+#if ! defined(LL_CLASSIC_CALLBACK_H)
+#define LL_CLASSIC_CALLBACK_H
+
+#include <tuple>
+#include <type_traits>              // std::is_same
+
+/*****************************************************************************
+*   Helpers
+*****************************************************************************/
+
+// find a type in a parameter pack: http://stackoverflow.com/q/17844867/5533635
+// usage: index_of<0, sought_t, PackName...>::value
+template <int idx, typename sought, typename candidate, typename ...rest>
+struct index_of
+{
+  static constexpr int const value =
+      std::is_same<sought, candidate>::value ?
+          idx : index_of<idx + 1, sought, rest...>::value;
+};
+
+// recursion tail
+template <int idx, typename sought, typename candidate>
+struct index_of<idx, sought, candidate>
+{
+  static constexpr int const value =
+      std::is_same<sought, candidate>::value ? idx : -1;
+};
+
+/*****************************************************************************
+*   ClassicCallback
+*****************************************************************************/
+/**
+ * Instantiate ClassicCallback in whatever storage will persist long enough
+ * for the callback to be called. It holds a modern C++ callable, providing a
+ * static function pointer and a USERDATA (default void*) capable of being
+ * passed through a classic-C callback API. When the static function is called
+ * with that USERDATA pointer, ClassicCallback forwards the call to the bound
+ * C++ callable.
+ *
+ * Usage:
+ * @code
+ * // callback signature required by the API of interest
+ * typedef void (*callback_t)(int, const char*, void*, double);
+ * // old-style API that accepts a classic-C callback function pointer
+ * void oldAPI(callback_t callback, void* userdata);
+ * // but I want to pass a lambda that references data local to my function!
+ * // (We don't need to name the void* parameter in the C++ callable;
+ * // ClassicCallback already used it to locate the lambda instance.)
+ * auto ccb{
+ *     makeClassicCallback<callback_t>(
+ *         [=](int n, const char* s, void*, double f){ ... }) };
+ * oldAPI(ccb.get_callback(), ccb.get_userdata());
+ * // If the passed callback is called before oldAPI() returns, we can now
+ * // safely destroy ccb. If the callback might be called later, consider
+ * // HeapClassicCallback instead.
+ * @endcode
+ *
+ * If you have a callable object in hand, and you want to pass that to
+ * ClassicCallback, you may either consume it by passing std::move(object), or
+ * explicitly specify a reference to that object type as the CALLABLE template
+ * parameter:
+ * @code
+ * CallableObject obj;
+ * ClassicCallback<callback_t, void*, CallableObject&> ccb{obj};
+ * @endcode
+ */
+// CALLABLE should either be deduced, e.g. by makeClassicCallback(), or
+// specified explicitly. Its default type is meaningless, coded only so we can
+// provide a useful default for USERDATA.
+template <typename SIGNATURE, typename USERDATA=void*, typename CALLABLE=void(*)()>
+class ClassicCallback
+{
+    typedef ClassicCallback<SIGNATURE, USERDATA, CALLABLE> self_t;
+
+public:
+    /// ClassicCallback binds any modern C++ callable.
+    ClassicCallback(CALLABLE&& callable):
+        mCallable(std::forward<CALLABLE>(callable))
+    {}
+
+    /**
+     * ClassicCallback must not itself be copied or moved! Once you've passed
+     * get_userdata() to some API, this object MUST remain at that address.
+     */
+    // However, we can't yet count on C++17 Class Template Argument Deduction,
+    // which means makeClassicCallback() is still useful, which means we MUST
+    // be able to return one to construct into caller's instance (move ctor).
+    // Possible defense: bool 'referenced' data member set by get_userdata(),
+    // with an llassert_always(! referenced) check in the move constructor.
+    ClassicCallback(ClassicCallback const&) = delete;
+    ClassicCallback(ClassicCallback&&) = default; // delete;
+    ClassicCallback& operator=(ClassicCallback const&) = delete;
+    ClassicCallback& operator=(ClassicCallback&&) = delete;
+
+    /// Call get_callback() to get the necessary function pointer.
+    SIGNATURE get_callback() const
+    {
+        // This declaration is where the compiler instantiates the correct
+        // signature for the call() function template.
+        SIGNATURE callback = call;
+        return callback;
+    }
+
+    /// Call get_userdata() to get the opaque USERDATA pointer to pass
+    /// through the classic-C callback API.
+    USERDATA get_userdata() const
+    {
+        // The USERDATA userdata is of course a pointer to this object.
+        return static_cast<USERDATA>(const_cast<self_t*>(this));
+    }
+
+protected:
+    /**
+     * This call() method accepts one or more callback arguments. It assumes
+     * the first USERDATA parameter is the userdata.
+     */
+    // Note that we're not literally using C++ perfect forwarding here -- it
+    // doesn't work to specify (Args&&... args). But that's okay because we're
+    // dealing with a classic-C callback! It's not going to pass any move-only
+    // types.
+    template <typename... Args>
+    static auto call(Args... args)
+    {
+        auto userdata = extract_userdata(std::forward<Args>(args)...);
+        // cast the userdata param to 'this' and call mCallable
+        return static_cast<self_t*>(userdata)->
+            mCallable(std::forward<Args>(args)...);
+    }
+
+    template <typename... Args>
+    static USERDATA extract_userdata(Args... args)
+    {
+        // Search for the first USERDATA parameter type, then extract that pointer.
+        // extract value from parameter pack: http://stackoverflow.com/a/24710433/5533635
+        return std::get<index_of<0, USERDATA, Args...>::value>(std::forward_as_tuple(args...));
+    }
+
+    CALLABLE mCallable;
+};
+
+/**
+ * Usage:
+ * @code
+ * auto ccb{ makeClassicCallback<classic_callback_signature>(actual_callback) };
+ * @endcode
+ */
+template <typename SIGNATURE, typename USERDATA=void*, typename CALLABLE=void(*)()>
+auto makeClassicCallback(CALLABLE&& callable)
+{
+    return std::move(ClassicCallback<SIGNATURE, USERDATA, CALLABLE>
+                     (std::forward<CALLABLE>(callable)));
+}
+
+/*****************************************************************************
+*   HeapClassicCallback
+*****************************************************************************/
+/**
+ * HeapClassicCallback is like ClassicCallback, with this exception: it MUST
+ * be allocated on the heap because, once the callback has been called, it
+ * deletes itself. This addresses the problem of a callback whose lifespan
+ * must persist beyond the scope in which the callback API is engaged -- but
+ * naturally this callback must be called exactly ONCE.
+ *
+ * Usage:
+ * @code
+ * // callback signature required by the API of interest
+ * typedef void (*callback_t)(int, const char*, void*, double);
+ * // here's the old-style API
+ * void oldAPI(callback_t callback, void* userdata);
+ * // want to call someObjPtr->method() when oldAPI() fires the callback,
+ * // sometime in the future after the enclosing function has returned
+ * auto ccb{
+ *     makeHeapClassicCallback<callback_t>(
+ *         [someObjPtr](int n, const char* s, void*, double f)
+ *         { someObjPtr->method(); }) };
+ * oldAPI(ccb.get_callback(), ccb.get_userdata());
+ * // We don't need a smart pointer for ccb, because it will be deleted once
+ * // oldAPI() calls the bound lambda. HeapClassicCallback is for when the
+ * // callback will be called exactly once. If the classic API might call the
+ * // passed callback more than once -- or might never call it at all --
+ * // manually construct a ClassicCallback on the heap and manage its lifespan
+ * // explicitly.
+ * @endcode
+ */
+template <typename SIGNATURE, typename USERDATA=void*, typename CALLABLE=void(*)()>
+class HeapClassicCallback: public ClassicCallback<SIGNATURE, USERDATA, CALLABLE>
+{
+    typedef ClassicCallback<SIGNATURE, USERDATA, CALLABLE> super;
+    typedef HeapClassicCallback<SIGNATURE, USERDATA, CALLABLE> self_t;
+
+    // This destructor is intentionally private to prevent allocation anywhere
+    // but the heap. (The Design and Evolution of C++, section 11.4.2: Control
+    // of Allocation)
+    ~HeapClassicCallback() {}
+
+public:
+    HeapClassicCallback(CALLABLE&& callable):
+        super(std::forward<CALLABLE>(callable))
+    {}
+
+    // makeHeapClassicCallback() only needs to return a pointer -- not an
+    // instance -- so we can lock down our move constructor too.
+    HeapClassicCallback(HeapClassicCallback&&) = delete;
+
+    /// Replicate get_callback() from the base class because we must
+    /// instantiate OUR call() function template.
+    SIGNATURE get_callback() const
+    {
+        // This declaration is where the compiler instantiates the correct
+        // signature for the call() function template.
+        SIGNATURE callback = call;
+        return callback;
+    }
+
+    /// Replicate get_userdata() from the base class because our call()
+    /// method must be able to reconstitute a pointer to this subclass.
+    USERDATA get_userdata() const
+    {
+        // The USERDATA userdata is of course a pointer to this object.
+        return static_cast<const USERDATA>(const_cast<self_t*>(this));
+    }
+
+private:
+    // call() uses a helper class to delete the HeapClassicCallback when done,
+    // for two reasons. Most importantly, this deletes even if the callback
+    // throws an exception. But also, call() must directly return the callback
+    // result for return-type deduction.
+    struct Destroyer
+    {
+        Destroyer(self_t* p): mPtr(p) {}
+        ~Destroyer() { delete mPtr; }
+
+        self_t* mPtr;
+    };
+
+    template <typename... Args>
+    static auto call(Args... args)
+    {
+        // extract userdata at this level too
+        USERDATA userdata = super::extract_userdata(std::forward<Args>(args)...);
+        // arrange to delete it when we leave by whatever means
+        Destroyer destroy(static_cast<self_t*>(userdata));
+
+        return super::call(std::forward<Args>(args)...);
+    }
+};
+
+template <typename SIGNATURE, typename USERDATA=void*, typename CALLABLE=void(*)()>
+auto makeHeapClassicCallback(CALLABLE&& callable)
+{
+    return new HeapClassicCallback<SIGNATURE, USERDATA, CALLABLE>
+        (std::forward<CALLABLE>(callable));
+}
+
+#endif /* ! defined(LL_CLASSIC_CALLBACK_H) */
diff --git a/indra/llcommon/linden_common.h b/indra/llcommon/linden_common.h
index e5a913a6a99c56214fc7365b2c13957aae0a810b..a228fd22be401a406931d193a3b86a5e8af526d9 100644
--- a/indra/llcommon/linden_common.h
+++ b/indra/llcommon/linden_common.h
@@ -27,6 +27,14 @@
 #ifndef LL_LINDEN_COMMON_H
 #define LL_LINDEN_COMMON_H
 
+#include "llprofiler.h"
+#if TRACY_ENABLE && !defined(LL_PROFILER_ENABLE_TRACY_OPENGL)  // hooks for memory profiling
+void *tracy_aligned_malloc(size_t size, size_t alignment);
+void  tracy_aligned_free(void *memblock);
+#define _aligned_malloc(X, Y) tracy_aligned_malloc((X), (Y))
+#define _aligned_free(X)      tracy_aligned_free((X))
+#endif
+
 // *NOTE:  Please keep includes here to a minimum!
 //
 // Files included here are included in every library .cpp file and
diff --git a/indra/llcommon/llalignedarray.h b/indra/llcommon/llalignedarray.h
index b68e9e0f82d6eae65ea84c99e53776433119d6ae..da9d98c16ce0d75d0907ae706db00073db4e8433 100644
--- a/indra/llcommon/llalignedarray.h
+++ b/indra/llcommon/llalignedarray.h
@@ -116,14 +116,20 @@ void LLAlignedArray<T, alignment>::resize(U32 size)
 template <class T, U32 alignment>
 T& LLAlignedArray<T, alignment>::operator[](int idx)
 {
-	llassert(idx < mElementCount);
+	if(idx >= mElementCount || idx < 0)
+    {
+        LL_ERRS() << "Out of bounds LLAlignedArray, requested: " << (S32)idx << " size: " << mElementCount << LL_ENDL;
+    }
 	return mArray[idx];
 }
 
 template <class T, U32 alignment>
 const T& LLAlignedArray<T, alignment>::operator[](int idx) const
 {
-	llassert(idx < mElementCount);
+    if (idx >= mElementCount || idx < 0)
+    {
+        LL_ERRS() << "Out of bounds LLAlignedArray, requested: " << (S32)idx << " size: " << mElementCount << LL_ENDL;
+    }
 	return mArray[idx];
 }
 
diff --git a/indra/llcommon/llcommon.cpp b/indra/llcommon/llcommon.cpp
index 96be913d17a07cface3713ddf5ae95ecb8557b73..d2c4e66160c83506174f8d0f1c6719c261cdf269 100644
--- a/indra/llcommon/llcommon.cpp
+++ b/indra/llcommon/llcommon.cpp
@@ -33,6 +33,66 @@
 #include "lltracethreadrecorder.h"
 #include "llcleanup.h"
 
+thread_local bool gProfilerEnabled = false;
+
+#if (TRACY_ENABLE)
+// Override new/delete for tracy memory profiling
+void *operator new(size_t size)
+{
+    void* ptr;
+    if (gProfilerEnabled)
+    {
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY;
+        ptr = (malloc)(size);
+    }
+    else
+    {
+        ptr = (malloc)(size);
+    }
+    if (!ptr)
+    {
+        throw std::bad_alloc();
+    }
+    TracyAlloc(ptr, size);
+    return ptr;
+}
+
+void operator delete(void *ptr) noexcept
+{
+    TracyFree(ptr);
+    if (gProfilerEnabled)
+    {
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY;
+        (free)(ptr);
+    }
+    else
+    {
+        (free)(ptr);
+    }
+}
+
+// C-style malloc/free can't be so easily overridden, so we define tracy versions and use
+// a pre-processor #define in linden_common.h to redirect to them. The parens around the native
+// functions below prevents recursive substitution by the preprocessor.
+//
+// Unaligned mallocs are rare in LL code but hooking them causes problems in 3p lib code (looking at
+// you, Havok), so we'll only capture the aligned version.
+
+void *tracy_aligned_malloc(size_t size, size_t alignment)
+{
+    auto ptr = ll_aligned_malloc_fallback(size, alignment);
+    if (ptr) TracyAlloc(ptr, size);
+    return ptr;
+}
+
+void tracy_aligned_free(void *memblock)
+{
+    TracyFree(memblock);
+    ll_aligned_free_fallback(memblock);
+}
+
+#endif
+
 //static
 BOOL LLCommon::sAprInitialized = FALSE;
 
diff --git a/indra/llcommon/llcond.h b/indra/llcommon/llcond.h
index e31b67d8937a495e2e4de51566ae01055a7abea3..da6e6affe1b7b17e43ea69aa58a4c051635e61c9 100644
--- a/indra/llcommon/llcond.h
+++ b/indra/llcommon/llcond.h
@@ -53,6 +53,8 @@ class LLCond
     LLCoros::Mutex mMutex;
     // Use LLCoros::ConditionVariable for the same reason.
     LLCoros::ConditionVariable mCond;
+    using LockType = LLCoros::LockType;
+    using cv_status = LLCoros::cv_status;
 
 public:
     /// LLCond can be explicitly initialized with a specific value for mData if
@@ -65,10 +67,29 @@ class LLCond
     LLCond(const LLCond&) = delete;
     LLCond& operator=(const LLCond&) = delete;
 
-    /// get() returns a const reference to the stored DATA. The only way to
-    /// get a non-const reference -- to modify the stored DATA -- is via
-    /// update_one() or update_all().
-    const value_type& get() const { return mData; }
+    /**
+     * get() returns the stored DATA by value -- so to use get(), DATA must
+     * be copyable. The only way to get a non-const reference -- to modify
+     * the stored DATA -- is via update_one() or update_all().
+     */
+    value_type get()
+    {
+        LockType lk(mMutex);
+        return mData;
+    }
+
+    /**
+     * get(functor) returns whatever the functor returns. It allows us to peek
+     * at the stored DATA without copying the whole thing. The functor must
+     * accept a const reference to DATA. If you want to modify DATA, call
+     * update_one() or update_all() instead.
+     */
+    template <typename FUNC>
+    auto get(FUNC&& func)
+    {
+        LockType lk(mMutex);
+        return std::forward<FUNC>(func)(const_data());
+    }
 
     /**
      * Pass update_one() an invocable accepting non-const (DATA&). The
@@ -80,11 +101,11 @@ class LLCond
      * update_one() when DATA is a struct or class.
      */
     template <typename MODIFY>
-    void update_one(MODIFY modify)
+    void update_one(MODIFY&& modify)
     {
         { // scope of lock can/should end before notify_one()
-            LLCoros::LockType lk(mMutex);
-            modify(mData);
+            LockType lk(mMutex);
+            std::forward<MODIFY>(modify)(mData);
         }
         mCond.notify_one();
     }
@@ -99,11 +120,11 @@ class LLCond
      * update_all() when DATA is a struct or class.
      */
     template <typename MODIFY>
-    void update_all(MODIFY modify)
+    void update_all(MODIFY&& modify)
     {
         { // scope of lock can/should end before notify_all()
-            LLCoros::LockType lk(mMutex);
-            modify(mData);
+            LockType lk(mMutex);
+            std::forward<MODIFY>(modify)(mData);
         }
         mCond.notify_all();
     }
@@ -116,9 +137,9 @@ class LLCond
      * wait() on the condition_variable.
      */
     template <typename Pred>
-    void wait(Pred pred)
+    void wait(Pred&& pred)
     {
-        LLCoros::LockType lk(mMutex);
+        LockType lk(mMutex);
         // We must iterate explicitly since the predicate accepted by
         // condition_variable::wait() requires a different signature:
         // condition_variable::wait() calls its predicate with no arguments.
@@ -127,7 +148,7 @@ class LLCond
         // But what if they instead pass a predicate accepting non-const
         // (DATA&)? Such a predicate could modify mData, which would be Bad.
         // Forbid that.
-        while (! pred(const_cast<const value_type&>(mData)))
+        while (! std::forward<Pred>(pred)(const_data()))
         {
             mCond.wait(lk);
         }
@@ -144,7 +165,7 @@ class LLCond
      * returning true.
      */
     template <typename Rep, typename Period, typename Pred>
-    bool wait_for(const std::chrono::duration<Rep, Period>& timeout_duration, Pred pred)
+    bool wait_for(const std::chrono::duration<Rep, Period>& timeout_duration, Pred&& pred)
     {
         // Instead of replicating wait_until() logic, convert duration to
         // time_point and just call wait_until().
@@ -153,7 +174,8 @@ class LLCond
         // wrong! We'd keep pushing the timeout time farther and farther into
         // the future. This way, we establish a definite timeout time and
         // stick to it.
-        return wait_until(std::chrono::steady_clock::now() + timeout_duration, pred);
+        return wait_until(std::chrono::steady_clock::now() + timeout_duration,
+                          std::forward<Pred>(pred));
     }
 
     /**
@@ -163,9 +185,9 @@ class LLCond
      * generic wait_for() method.
      */
     template <typename Pred>
-    bool wait_for(F32Milliseconds timeout_duration, Pred pred)
+    bool wait_for(F32Milliseconds timeout_duration, Pred&& pred)
     {
-        return wait_for(convert(timeout_duration), pred);
+        return wait_for(convert(timeout_duration), std::forward<Pred>(pred));
     }
 
 protected:
@@ -183,6 +205,10 @@ class LLCond
     }
 
 private:
+    // It's important to pass a const ref to certain user-specified functors
+    // that aren't supposed to be able to modify mData.
+    const value_type& const_data() const { return mData; }
+
     /**
      * Pass wait_until() a chrono::time_point, indicating the time at which we
      * should stop waiting, and a predicate accepting (const DATA&), returning
@@ -203,21 +229,21 @@ class LLCond
      * honoring a fixed timeout.
      */
     template <typename Clock, typename Duration, typename Pred>
-    bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time, Pred pred)
+    bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time, Pred&& pred)
     {
-        LLCoros::LockType lk(mMutex);
+        LockType lk(mMutex);
         // We advise the caller to pass a predicate accepting (const DATA&).
         // But what if they instead pass a predicate accepting non-const
         // (DATA&)? Such a predicate could modify mData, which would be Bad.
         // Forbid that.
-        while (! pred(const_cast<const value_type&>(mData)))
+        while (! std::forward<Pred>(pred)(const_data()))
         {
-            if (LLCoros::cv_status::timeout == mCond.wait_until(lk, timeout_time))
+            if (cv_status::timeout == mCond.wait_until(lk, timeout_time))
             {
                 // It's possible that wait_until() timed out AND the predicate
                 // became true more or less simultaneously. Even though
                 // wait_until() timed out, check the predicate one more time.
-                return pred(const_cast<const value_type&>(mData));
+                return std::forward<Pred>(pred)(const_data());
             }
         }
         return true;
diff --git a/indra/llcommon/llcoros.cpp b/indra/llcommon/llcoros.cpp
index 75fc0fec99d19942c8859130c6f29b7160d1da4e..14bfb98629d2e79bcd4b64a3ee0363489360e73d 100644
--- a/indra/llcommon/llcoros.cpp
+++ b/indra/llcommon/llcoros.cpp
@@ -35,6 +35,7 @@
 // STL headers
 // std headers
 #include <atomic>
+#include <stdexcept>
 // external library headers
 #include <boost/bind.hpp>
 #include <boost/fiber/fiber.hpp>
@@ -214,6 +215,22 @@ std::string LLCoros::logname()
     return data.mName.empty()? data.getKey() : data.mName;
 }
 
+void LLCoros::saveException(const std::string& name, std::exception_ptr exc)
+{
+    mExceptionQueue.emplace(name, exc);
+}
+
+void LLCoros::rethrow()
+{
+    if (! mExceptionQueue.empty())
+    {
+        ExceptionData front = mExceptionQueue.front();
+        mExceptionQueue.pop();
+        LL_WARNS("LLCoros") << "Rethrowing exception from coroutine " << front.name << LL_ENDL;
+        std::rethrow_exception(front.exception);
+    }
+}
+
 void LLCoros::setStackSize(S32 stacksize)
 {
     LL_DEBUGS("LLCoros") << "Setting coroutine stack size to " << stacksize << LL_ENDL;
@@ -249,14 +266,25 @@ std::string LLCoros::launch(const std::string& prefix, const callable_t& callabl
     // protected_fixedsize_stack sets a guard page past the end of the new
     // stack so that stack underflow will result in an access violation
     // instead of weird, subtle, possibly undiagnosed memory stomps.
-    boost::fibers::fiber newCoro(boost::fibers::launch::dispatch,
-                                 std::allocator_arg,
-                                 boost::fibers::protected_fixedsize_stack(mStackSize),
-                                 [this, &name, &callable](){ toplevel(name, callable); });
-    // You have two choices with a fiber instance: you can join() it or you
-    // can detach() it. If you try to destroy the instance before doing
-    // either, the program silently terminates. We don't need this handle.
-    newCoro.detach();
+
+    try
+    {
+        boost::fibers::fiber newCoro(boost::fibers::launch::dispatch,
+            std::allocator_arg,
+            boost::fibers::protected_fixedsize_stack(mStackSize),
+            [this, &name, &callable]() { toplevel(name, callable); });
+
+        // You have two choices with a fiber instance: you can join() it or you
+        // can detach() it. If you try to destroy the instance before doing
+        // either, the program silently terminates. We don't need this handle.
+        newCoro.detach();
+    }
+    catch (std::bad_alloc&)
+    {
+        // Out of memory on stack allocation?
+        LL_ERRS("LLCoros") << "Bad memory allocation in LLCoros::launch(" << prefix << ")!" << LL_ENDL;
+    }
+
     return name;
 }
 
@@ -291,11 +319,11 @@ U32 cpp_exception_filter(U32 code, struct _EXCEPTION_POINTERS *exception_infop,
     }
 }
 
-void LLCoros::winlevel(const std::string& name, const callable_t& callable)
+void LLCoros::sehHandle(const std::string& name, const LLCoros::callable_t& callable)
 {
     __try
     {
-        toplevelTryWrapper(name, callable);
+        LLCoros::toplevelTryWrapper(name, callable);
     }
     __except (cpp_exception_filter(GetExceptionCode(), GetExceptionInformation(), name))
     {
@@ -310,7 +338,6 @@ void LLCoros::winlevel(const std::string& name, const callable_t& callable)
         throw std::exception(integer_string);
     }
 }
-
 #endif
 
 void LLCoros::toplevelTryWrapper(const std::string& name, const callable_t& callable)
@@ -339,11 +366,19 @@ void LLCoros::toplevelTryWrapper(const std::string& name, const callable_t& call
     }
     catch (...)
     {
+#if LL_WINDOWS
         // Any OTHER kind of uncaught exception will cause the viewer to
-        // crash, hopefully informatively.
+        // crash, SEH handling should catch it and report to bugsplat.
         LOG_UNHANDLED_EXCEPTION(STRINGIZE("coroutine " << name));
         // to not modify callstack
         throw;
+#else
+        // Stash any OTHER kind of uncaught exception in the rethrow() queue
+        // to be rethrown by the main fiber.
+        LL_WARNS("LLCoros") << "Capturing uncaught exception in coroutine "
+                            << name << LL_ENDL;
+        LLCoros::instance().saveException(name, std::current_exception());
+#endif
     }
 }
 
@@ -353,8 +388,9 @@ void LLCoros::toplevelTryWrapper(const std::string& name, const callable_t& call
 void LLCoros::toplevel(std::string name, callable_t callable)
 {
 #if LL_WINDOWS
-    // Can not use __try in functions that require unwinding, so use one more wrapper
-    winlevel(name, callable);
+    // Because SEH can's have unwinding, need to call a wrapper
+    // 'try' is inside SEH handling to not catch LLContinue
+    sehHandle(name, callable);
 #else
     toplevelTryWrapper(name, callable);
 #endif
diff --git a/indra/llcommon/llcoros.h b/indra/llcommon/llcoros.h
index a94cfca19f88a06376ce245c63ccf6bac2b9cd91..dbff921f167eb5f69262de816911c73e7c9e3845 100644
--- a/indra/llcommon/llcoros.h
+++ b/indra/llcommon/llcoros.h
@@ -38,6 +38,8 @@
 #include "llinstancetracker.h"
 #include <boost/function.hpp>
 #include <string>
+#include <exception>
+#include <queue>
 
 // e.g. #include LLCOROS_MUTEX_HEADER
 #define LLCOROS_MUTEX_HEADER   <boost/fiber/mutex.hpp>
@@ -156,6 +158,19 @@ class LL_COMMON_API LLCoros: public LLSingleton<LLCoros>
      * LLCoros::launch()).
      */
     static std::string getName();
+    
+    /**
+     * rethrow() is called by the thread's main fiber to propagate an
+     * exception from any coroutine into the main fiber, where it can engage
+     * the normal unhandled-exception machinery, up to and including crash
+     * reporting.
+     *
+     * LLCoros maintains a queue of otherwise-uncaught exceptions from
+     * terminated coroutines. Each call to rethrow() pops the first of those
+     * and rethrows it. When the queue is empty (normal case), rethrow() is a
+     * no-op.
+     */
+    void rethrow();
 
     /**
      * This variation returns a name suitable for log messages: the explicit
@@ -292,13 +307,27 @@ class LL_COMMON_API LLCoros: public LLSingleton<LLCoros>
 
 private:
     std::string generateDistinctName(const std::string& prefix) const;
+    void toplevelTryWrapper(const std::string& name, const callable_t& callable);
 #if LL_WINDOWS
-    void winlevel(const std::string& name, const callable_t& callable);
+    void sehHandle(const std::string& name, const callable_t& callable); // calls toplevelTryWrapper
 #endif
-    void toplevelTryWrapper(const std::string& name, const callable_t& callable);
-    void toplevel(std::string name, callable_t callable);
+    void toplevel(std::string name, callable_t callable); // calls sehHandle or toplevelTryWrapper
     struct CoroData;
     static CoroData& get_CoroData(const std::string& caller);
+    void saveException(const std::string& name, std::exception_ptr exc);
+
+    struct ExceptionData
+    {
+        ExceptionData(const std::string& nm, std::exception_ptr exc):
+            name(nm),
+            exception(exc)
+        {}
+        // name of coroutine that originally threw this exception
+        std::string name;
+        // the thrown exception
+        std::exception_ptr exception;
+    };
+    std::queue<ExceptionData> mExceptionQueue;
 
     S32 mStackSize;
 
diff --git a/indra/llcommon/lldate.cpp b/indra/llcommon/lldate.cpp
index 7a2a0869f49188aed322188496952e7c494de994..2ddcf40895c6c163db2dcf1b4e393ee4758dec26 100644
--- a/indra/llcommon/lldate.cpp
+++ b/indra/llcommon/lldate.cpp
@@ -86,11 +86,9 @@ std::string LLDate::asRFC1123() const
 	return toHTTPDateString (std::string ("%A, %d %b %Y %H:%M:%S GMT"));
 }
 
-LLTrace::BlockTimerStatHandle FT_DATE_FORMAT("Date Format");
-
 std::string LLDate::toHTTPDateString (std::string fmt) const
 {
-	LL_RECORD_BLOCK_TIME(FT_DATE_FORMAT);
+    LL_PROFILE_ZONE_SCOPED;
 	
 	time_t locSeconds = (time_t) mSecondsSinceEpoch;
 	struct tm * gmt = gmtime (&locSeconds);
@@ -99,7 +97,7 @@ std::string LLDate::toHTTPDateString (std::string fmt) const
 
 std::string LLDate::toHTTPDateString (tm * gmt, std::string fmt)
 {
-	LL_RECORD_BLOCK_TIME(FT_DATE_FORMAT);
+    LL_PROFILE_ZONE_SCOPED;
 
 	// avoid calling setlocale() unnecessarily - it's expensive.
 	static std::string prev_locale = "";
diff --git a/indra/llcommon/llerror.cpp b/indra/llcommon/llerror.cpp
index 55a06f83264352df3e4ae06b2078b198d172bfe3..919d2dabc4a1d75040e72f9c504ee0dfe9f5eb44 100644
--- a/indra/llcommon/llerror.cpp
+++ b/indra/llcommon/llerror.cpp
@@ -109,6 +109,7 @@ namespace {
 		virtual void recordMessage(LLError::ELevel level,
 									const std::string& message) override
 		{
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING
 			int syslogPriority = LOG_CRIT;
 			switch (level) {
 				case LLError::LEVEL_DEBUG:	syslogPriority = LOG_DEBUG;	break;
@@ -166,6 +167,7 @@ namespace {
         virtual void recordMessage(LLError::ELevel level,
                                     const std::string& message) override
         {
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING
             if (LLError::getAlwaysFlush())
             {
                 mFile << message << std::endl;
@@ -194,7 +196,7 @@ namespace {
         {
             return LLError::getEnabledLogTypesMask() & 0x04;
         }
-
+        
         LL_FORCE_INLINE std::string createBoldANSI()
         {
             std::string ansi_code;
@@ -220,10 +222,10 @@ namespace {
         LL_FORCE_INLINE std::string createANSI(const std::string& color)
         {
             std::string ansi_code;
-            ansi_code += '\033';
-            ansi_code += "[";
+            ansi_code  += '\033';
+            ansi_code  += "[";
             ansi_code += "38;5;";
-            ansi_code += color;
+            ansi_code  += color;
             ansi_code += "m";
 
             return ansi_code;
@@ -232,6 +234,7 @@ namespace {
 		virtual void recordMessage(LLError::ELevel level,
 					   const std::string& message) override
 		{
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING
             // The default colors for error, warn and debug are now a bit more pastel
             // and easier to read on the default (black) terminal background but you 
             // now have the option to set the color of each via an environment variables:
@@ -261,6 +264,7 @@ namespace {
 			}
             else
             {
+                LL_PROFILE_ZONE_NAMED("fprintf");
                  fprintf(stderr, "%s\n", message.c_str());
             }
 		}
@@ -270,6 +274,7 @@ namespace {
 
         LL_FORCE_INLINE void writeANSI(const std::string& ansi_code, const std::string& message)
 		{
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING
             static std::string s_ansi_bold = createBoldANSI();  // bold text
             static std::string s_ansi_reset = createResetANSI();  // reset
 			// ANSI color code escape sequence, message, and reset in one fprintf call
@@ -306,6 +311,7 @@ namespace {
 		virtual void recordMessage(LLError::ELevel level,
 								   const std::string& message) override
 		{
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING
 			mBuffer->addLine(message);
 		}
 	
@@ -332,6 +338,7 @@ namespace {
 		virtual void recordMessage(LLError::ELevel level,
 								   const std::string& message) override
 		{
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING
 			debugger_print(message);
 		}
 	};
@@ -1210,6 +1217,7 @@ namespace
 
 	void writeToRecorders(const LLError::CallSite& site, const std::string& message)
 	{
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING
 		LLError::ELevel level = site.mLevel;
 		SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig();
 
@@ -1344,6 +1352,7 @@ namespace LLError
 
 	bool Log::shouldLog(CallSite& site)
 	{
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING
 		LLMutexTrylock lock(getMutex<LOG_MUTEX>(), 5);
 		if (!lock.isLocked())
 		{
@@ -1388,6 +1397,7 @@ namespace LLError
 
 	void Log::flush(const std::ostringstream& out, const CallSite& site)
 	{
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING
 		LLMutexTrylock lock(getMutex<LOG_MUTEX>(),5);
 		if (!lock.isLocked())
 		{
diff --git a/indra/llcommon/llerror.h b/indra/llcommon/llerror.h
index d439136ca8525721ee0917f388ad12053e672bd2..d06c0e21323711a6612b0a159e57d4f815b9ded8 100644
--- a/indra/llcommon/llerror.h
+++ b/indra/llcommon/llerror.h
@@ -35,7 +35,9 @@
 
 #include "stdtypes.h"
 
+#include "llprofiler.h"
 #include "llpreprocessor.h"
+
 #include <boost/static_assert.hpp>
 
 const int LL_ERR_NOERR = 0;
@@ -348,7 +350,8 @@ typedef LLError::NoClassInfo _LL_CLASS_TO_LOG;
 // if (condition) LL_INFOS() << "True" << LL_ENDL; else LL_INFOS()() << "False" << LL_ENDL;
 
 #define lllog(level, once, ...)                                         \
-	do {                                                                \
+    do {                                                                \
+        LL_PROFILE_ZONE_NAMED("lllog");                                 \
 		const char* tags[] = {"", ##__VA_ARGS__};                       \
 		static LLError::CallSite _site(lllog_site_args_(level, once, tags)); \
 		lllog_test_()
diff --git a/indra/llcommon/llerrorcontrol.h b/indra/llcommon/llerrorcontrol.h
index e87bb7bf350abf85f7c99f0008847a0ee65a7035..57f10b78950e7d7f9a8455ac180377e527241a76 100644
--- a/indra/llcommon/llerrorcontrol.h
+++ b/indra/llcommon/llerrorcontrol.h
@@ -190,6 +190,7 @@ namespace LLError
         {}
         void recordMessage(LLError::ELevel level, const std::string& message) override
         {
+            LL_PROFILE_ZONE_SCOPED
             mCallable(level, message);
         }
     private:
diff --git a/indra/llcommon/lleventcoro.cpp b/indra/llcommon/lleventcoro.cpp
index 995356dc520197e4e5d8a3fad20f13229621a42f..067b5e6fbc9737f88d655268d051cd42107d9bfa 100644
--- a/indra/llcommon/lleventcoro.cpp
+++ b/indra/llcommon/lleventcoro.cpp
@@ -101,7 +101,7 @@ void storeToLLSDPath(LLSD& dest, const LLSD& path, const LLSD& value)
     }
 
     // Drill down to where we should store 'value'.
-    llsd::drill(dest, path) = value;
+    llsd::drill_ref(dest, path) = value;
 }
 
 } // anonymous
diff --git a/indra/llcommon/lleventfilter.h b/indra/llcommon/lleventfilter.h
index 48c2570732090a0cbb6b2305259dd9214c2c1f47..7613850fb21b8305863752f12095c22d8a9337d3 100644
--- a/indra/llcommon/lleventfilter.h
+++ b/indra/llcommon/lleventfilter.h
@@ -429,6 +429,8 @@ class LLStoreListener: public LLEventFilter
     // path, then stores it to mTarget.
     virtual bool post(const LLSD& event)
     {
+        LL_PROFILE_ZONE_SCOPED
+
         // Extract the element specified by 'mPath' from 'event'. To perform a
         // generic type-appropriate store through mTarget, construct an
         // LLSDParam<T> and store that, thus engaging LLSDParam's custom
diff --git a/indra/llcommon/llexception.cpp b/indra/llcommon/llexception.cpp
index b584b0ff8b53c2a4efb58e40f4d4aef210fb1466..46560b5e4ce39ac7c12dc45b7ae1d080448090d7 100644
--- a/indra/llcommon/llexception.cpp
+++ b/indra/llcommon/llexception.cpp
@@ -97,6 +97,11 @@ static const U32 STATUS_MSC_EXCEPTION = 0xE06D7363; // compiler specific
 
 U32 msc_exception_filter(U32 code, struct _EXCEPTION_POINTERS *exception_infop)
 {
+    const auto stack = to_string(boost::stacktrace::stacktrace());
+    LL_WARNS() << "SEH Exception handled (that probably shouldn't be): Code " << code 
+        << "\n Stack trace: \n" 
+        << stack << LL_ENDL;
+
     if (code == STATUS_MSC_EXCEPTION)
     {
         // C++ exception, go on
diff --git a/indra/llcommon/llfasttimer.cpp b/indra/llcommon/llfasttimer.cpp
index 5b6a7b82f803bf35b455d4b37ffcb83b7b326b41..2612d0f07cdd7e73cc8e9ee7dddb016008329702 100644
--- a/indra/llcommon/llfasttimer.cpp
+++ b/indra/llcommon/llfasttimer.cpp
@@ -191,29 +191,30 @@ TimeBlockTreeNode& BlockTimerStatHandle::getTreeNode() const
 }
 
 
+
 void BlockTimer::bootstrapTimerTree()
 {
-	for (auto& base : BlockTimerStatHandle::instance_snapshot())
-	{
-		// because of indirect derivation from LLInstanceTracker, have to downcast
-		BlockTimerStatHandle& timer = static_cast<BlockTimerStatHandle&>(base);
-		if (&timer == &BlockTimer::getRootTimeBlock()) continue;
-
-		// bootstrap tree construction by attaching to last timer to be on stack
-		// when this timer was called
-		if (timer.getParent() == &BlockTimer::getRootTimeBlock())
-		{
-			TimeBlockAccumulator& accumulator = timer.getCurrentAccumulator();
-
-			if (accumulator.mLastCaller)
-			{
-				timer.setParent(accumulator.mLastCaller);
-				accumulator.mParent = accumulator.mLastCaller;
-			}
-			// no need to push up tree on first use, flag can be set spuriously
-			accumulator.mMoveUpTree = false;
-		}
-	}
+    for (auto& base : BlockTimerStatHandle::instance_snapshot())
+    {
+        // because of indirect derivation from LLInstanceTracker, have to downcast
+        BlockTimerStatHandle& timer = static_cast<BlockTimerStatHandle&>(base);
+        if (&timer == &BlockTimer::getRootTimeBlock()) continue;
+
+        // bootstrap tree construction by attaching to last timer to be on stack
+        // when this timer was called
+        if (timer.getParent() == &BlockTimer::getRootTimeBlock())
+        {
+            TimeBlockAccumulator& accumulator = timer.getCurrentAccumulator();
+
+            if (accumulator.mLastCaller)
+            {
+                timer.setParent(accumulator.mLastCaller);
+                accumulator.mParent = accumulator.mLastCaller;
+            }
+            // no need to push up tree on first use, flag can be set spuriously
+            accumulator.mMoveUpTree = false;
+        }
+    }
 }
 
 // bump timers up tree if they have been flagged as being in the wrong place
@@ -221,6 +222,7 @@ void BlockTimer::bootstrapTimerTree()
 // this preserves partial order derived from current frame's observations
 void BlockTimer::incrementalUpdateTimerTree()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	for(block_timer_tree_df_post_iterator_t it = begin_block_timer_tree_df_post(BlockTimer::getRootTimeBlock());
 		it != end_block_timer_tree_df_post();
 		++it)
@@ -260,7 +262,8 @@ void BlockTimer::incrementalUpdateTimerTree()
 
 
 void BlockTimer::updateTimes()
-	{
+{
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	// walk up stack of active timers and accumulate current time while leaving timing structures active
 	BlockTimerStackRecord* stack_record	= LLThreadLocalSingletonPointer<BlockTimerStackRecord>::getInstance();
 	if (!stack_record) return;
@@ -271,7 +274,7 @@ void BlockTimer::updateTimes()
 
 	while(cur_timer 
 		&& cur_timer->mParentTimerData.mActiveTimer != cur_timer) // root defined by parent pointing to self
-		{
+	{
 		U64 cumulative_time_delta = cur_time - cur_timer->mStartTime;
 		cur_timer->mStartTime = cur_time;
 
diff --git a/indra/llcommon/llfasttimer.h b/indra/llcommon/llfasttimer.h
index dfc63d08a2979203866b0cf6ff7647e66867853e..9bd93d7240bbed169a3ed45dbe03f6879afdfc06 100644
--- a/indra/llcommon/llfasttimer.h
+++ b/indra/llcommon/llfasttimer.h
@@ -38,7 +38,10 @@
 #define LL_FAST_TIMER_ON 1
 #define LL_FASTTIMER_USE_RDTSC 1
 
+// NOTE: Also see llprofiler.h
+#if !defined(LL_PROFILER_CONFIGURATION)
 #define LL_RECORD_BLOCK_TIME(timer_stat) const LLTrace::BlockTimer& LL_GLUE_TOKENS(block_time_recorder, __LINE__)(LLTrace::timeThisBlock(timer_stat)); (void)LL_GLUE_TOKENS(block_time_recorder, __LINE__);
+#endif // LL_PROFILER_CONFIGURATION
 
 namespace LLTrace
 {
diff --git a/indra/llcommon/llframetimer.cpp b/indra/llcommon/llframetimer.cpp
index 1e9920746b0191efc8ef41346bfdccdd0266ac7f..c54029e8b440b87e5944dbfbfea6f1d7bbedb4ba 100644
--- a/indra/llcommon/llframetimer.cpp
+++ b/indra/llcommon/llframetimer.cpp
@@ -29,6 +29,11 @@
 
 #include "llframetimer.h"
 
+// We don't bother building a stand alone lib; we just need to include the one source file for Tracy support
+#if LL_PROFILER_CONFIGURATION == LL_PROFILER_CONFIG_TRACY || LL_PROFILER_CONFIGURATION == LL_PROFILER_CONFIG_TRACY_FAST_TIMER
+	#include "TracyClient.cpp"
+#endif // LL_PROFILER_CONFIGURATION
+
 // Static members
 //LLTimer	LLFrameTimer::sInternalTimer;
 U64 LLFrameTimer::sStartTotalTime = totalTime();
diff --git a/indra/llcommon/llinstancetracker.h b/indra/llcommon/llinstancetracker.h
index 402333cca7d513c1c22eb3a3080a2d5f0e7fc4f1..02535a59e7e1a7c7e5efa7e6c2a6f597e2889126 100644
--- a/indra/llcommon/llinstancetracker.h
+++ b/indra/llcommon/llinstancetracker.h
@@ -83,13 +83,34 @@ class LLInstanceTracker
     typedef llthread::LockStatic<StaticData> LockStatic;
 
 public:
+    using ptr_t  = std::shared_ptr<T>;
+    using weak_t = std::weak_ptr<T>;
+
+    /**
+     * Storing a dumb T* somewhere external is a bad idea, since
+     * LLInstanceTracker subclasses are explicitly destroyed rather than
+     * managed by smart pointers. It's legal to declare stack instances of an
+     * LLInstanceTracker subclass. But it's reasonable to store a
+     * std::weak_ptr<T>, which will become invalid when the T instance is
+     * destroyed.
+     */
+    weak_t getWeak()
+    {
+        return mSelf;
+    }
+
+    static S32 instanceCount() 
+    { 
+        return LockStatic()->mMap.size(); 
+    }
+    
     // snapshot of std::pair<const KEY, std::shared_ptr<T>> pairs
     class snapshot
     {
         // It's very important that what we store in this snapshot are
         // weak_ptrs, NOT shared_ptrs. That's how we discover whether any
         // instance has been deleted during the lifespan of a snapshot.
-        typedef std::vector<std::pair<const KEY, std::weak_ptr<T>>> VectorType;
+        typedef std::vector<std::pair<const KEY, weak_t>> VectorType;
         // Dereferencing our iterator produces a std::shared_ptr for each
         // instance that still exists. Since we store weak_ptrs, that involves
         // two chained transformations:
@@ -98,7 +119,7 @@ class LLInstanceTracker
         // It is very important that we filter lazily, that is, during
         // traversal. Any one of our stored weak_ptrs might expire during
         // traversal.
-        typedef std::pair<const KEY, std::shared_ptr<T>> strong_pair;
+        typedef std::pair<const KEY, ptr_t> strong_pair;
         // Note for future reference: nat has not yet had any luck (up to
         // Boost 1.67) trying to use boost::transform_iterator with a hand-
         // coded functor, only with actual functions. In my experience, an
@@ -202,17 +223,12 @@ class LLInstanceTracker
         iterator end()   { return iterator(snapshot::end(),   key_getter); }
     };
 
-    static T* getInstance(const KEY& k)
+    static ptr_t getInstance(const KEY& k)
     {
         LockStatic lock;
         const InstanceMap& map(lock->mMap);
         typename InstanceMap::const_iterator found = map.find(k);
-        return (found == map.end()) ? NULL : found->second.get();
-    }
-
-    static S32 instanceCount() 
-    { 
-        return LockStatic()->mMap.size(); 
+        return (found == map.end()) ? NULL : found->second;
     }
 
 protected:
@@ -222,7 +238,9 @@ class LLInstanceTracker
         // shared_ptr, so give it a no-op deleter. We store shared_ptrs in our
         // InstanceMap specifically so snapshot can store weak_ptrs so we can
         // detect deletions during traversals.
-        std::shared_ptr<T> ptr(static_cast<T*>(this), [](T*){});
+        ptr_t ptr(static_cast<T*>(this), [](T*){});
+        // save corresponding weak_ptr for future reference
+        mSelf = ptr;
         LockStatic lock;
         add_(lock, key, ptr);
     }
@@ -257,7 +275,7 @@ class LLInstanceTracker
     static std::string report(const char* key) { return report(std::string(key)); }
 
     // caller must instantiate LockStatic
-    void add_(LockStatic& lock, const KEY& key, const std::shared_ptr<T>& ptr) 
+    void add_(LockStatic& lock, const KEY& key, const ptr_t& ptr) 
     { 
         mInstanceKey = key; 
         InstanceMap& map = lock->mMap;
@@ -281,7 +299,7 @@ class LLInstanceTracker
             break;
         }
     }
-    std::shared_ptr<T> remove_(LockStatic& lock)
+    ptr_t remove_(LockStatic& lock)
     {
         InstanceMap& map = lock->mMap;
         typename InstanceMap::iterator iter = map.find(mInstanceKey);
@@ -295,6 +313,9 @@ class LLInstanceTracker
     }
 
 private:
+    // Storing a weak_ptr to self is a bit like deriving from
+    // std::enable_shared_from_this(), except more explicit.
+    weak_t mSelf;
     KEY mInstanceKey;
 };
 
@@ -326,6 +347,9 @@ class LLInstanceTracker<T, void, KEY_COLLISION_BEHAVIOR>
     typedef llthread::LockStatic<StaticData> LockStatic;
 
 public:
+    using ptr_t  = std::shared_ptr<T>;
+    using weak_t = std::weak_ptr<T>;
+
     /**
      * Storing a dumb T* somewhere external is a bad idea, since
      * LLInstanceTracker subclasses are explicitly destroyed rather than
@@ -334,12 +358,15 @@ class LLInstanceTracker<T, void, KEY_COLLISION_BEHAVIOR>
      * std::weak_ptr<T>, which will become invalid when the T instance is
      * destroyed.
      */
-    std::weak_ptr<T> getWeak()
+    weak_t getWeak()
     {
         return mSelf;
     }
     
-    static S32 instanceCount() { return LockStatic()->mSet.size(); }
+    static S32 instanceCount()
+    {
+        return LockStatic()->mSet.size();
+    }
 
     // snapshot of std::shared_ptr<T> pointers
     class snapshot
@@ -347,7 +374,7 @@ class LLInstanceTracker<T, void, KEY_COLLISION_BEHAVIOR>
         // It's very important that what we store in this snapshot are
         // weak_ptrs, NOT shared_ptrs. That's how we discover whether any
         // instance has been deleted during the lifespan of a snapshot.
-        typedef std::vector<std::weak_ptr<T>> VectorType;
+        typedef std::vector<weak_t> VectorType;
         // Dereferencing our iterator produces a std::shared_ptr for each
         // instance that still exists. Since we store weak_ptrs, that involves
         // two chained transformations:
@@ -453,7 +480,7 @@ class LLInstanceTracker<T, void, KEY_COLLISION_BEHAVIOR>
 private:
     // Storing a weak_ptr to self is a bit like deriving from
     // std::enable_shared_from_this(), except more explicit.
-    std::weak_ptr<T> mSelf;
+    weak_t mSelf;
 };
 
 #endif
diff --git a/indra/llcommon/llleaplistener.cpp b/indra/llcommon/llleaplistener.cpp
index 3e6ce9092ccfa6f0e8922403e0c58de858fe0660..11bfec1b31f71ce7f0993a192a9e1e95d92dfed5 100644
--- a/indra/llcommon/llleaplistener.cpp
+++ b/indra/llcommon/llleaplistener.cpp
@@ -220,7 +220,7 @@ void LLLeapListener::getAPI(const LLSD& request) const
 {
     Response reply(LLSD(), request);
 
-    LLEventAPI* found = LLEventAPI::getInstance(request["api"]);
+    auto found = LLEventAPI::getInstance(request["api"]);
     if (found)
     {
         reply["name"] = found->getName();
diff --git a/indra/llcommon/llmemory.cpp b/indra/llcommon/llmemory.cpp
index ea84e4c1ea1baf971233db28fed511180828ca80..d6ae1284d3ded847a08e247135e89463a4f4827e 100644
--- a/indra/llcommon/llmemory.cpp
+++ b/indra/llcommon/llmemory.cpp
@@ -82,6 +82,7 @@ void LLMemory::initMaxHeapSizeGB(F32Gigabytes max_heap_size)
 //static 
 void LLMemory::updateMemoryInfo() 
 {
+	LL_PROFILE_ZONE_SCOPED
 #if LL_WINDOWS
 	PROCESS_MEMORY_COUNTERS counters;
 
@@ -145,6 +146,7 @@ void* LLMemory::tryToAlloc(void* address, U32 size)
 //static 
 void LLMemory::logMemoryInfo(BOOL update)
 {
+	LL_PROFILE_ZONE_SCOPED
 	if(update)
 	{
 		updateMemoryInfo() ;
@@ -210,11 +212,9 @@ U64 LLMemory::getCurrentRSS()
 	mach_msg_type_number_t  basicInfoCount = MACH_TASK_BASIC_INFO_COUNT;
 	if (task_info(mach_task_self(), MACH_TASK_BASIC_INFO, (task_info_t)&basicInfo, &basicInfoCount) == KERN_SUCCESS)
 	{
-//		residentSize = basicInfo.resident_size;
-		// Although this method is defined to return the "resident set size,"
-		// in fact what callers want from it is the total virtual memory
-		// consumed by the application.
-		residentSize = basicInfo.virtual_size;
+        residentSize = basicInfo.resident_size;
+        // 64-bit macos apps allocate 32 GB or more at startup, and this is reflected in virtual_size.
+        // basicInfo.virtual_size is not what we want.
 	}
 	else
 	{
diff --git a/indra/llcommon/llmemory.h b/indra/llcommon/llmemory.h
index 24f86cc11ee3a7b5c9d0b567e2907539b8fee015..ac6c969d70b2e0815d594e888221db685c93d3da 100644
--- a/indra/llcommon/llmemory.h
+++ b/indra/llcommon/llmemory.h
@@ -101,6 +101,29 @@ template <typename T> T* LL_NEXT_ALIGNED_ADDRESS_64(T* address)
 
 #define LL_ALIGN_16(var) LL_ALIGN_PREFIX(16) var LL_ALIGN_POSTFIX(16)
 
+#define LL_ALIGN_NEW                        \
+public:                                     \
+    void* operator new(size_t size)         \
+    {                                       \
+        return ll_aligned_malloc_16(size);  \
+    }                                       \
+                                            \
+    void operator delete(void* ptr)         \
+    {                                       \
+        ll_aligned_free_16(ptr);            \
+    }                                       \
+                                            \
+    void* operator new[](size_t size)       \
+    {                                       \
+        return ll_aligned_malloc_16(size);  \
+    }                                       \
+                                            \
+    void operator delete[](void* ptr)       \
+    {                                       \
+        ll_aligned_free_16(ptr);            \
+    }
+
+
 //------------------------------------------------------------------------------------------------
 //------------------------------------------------------------------------------------------------
 	// for enable buffer overrun detection predefine LL_DEBUG_BUFFER_OVERRUN in current library
@@ -113,8 +136,9 @@ template <typename T> T* LL_NEXT_ALIGNED_ADDRESS_64(T* address)
 #else
 	inline void* ll_aligned_malloc_fallback( size_t size, int align )
 	{
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY;
 	#if defined(LL_WINDOWS)
-		return _aligned_malloc(size, align);
+        void* ret = _aligned_malloc(size, align);
 	#else
         char* aligned = NULL;
 		void* mem = malloc( size + (align - 1) + sizeof(void*) );
@@ -125,12 +149,16 @@ template <typename T> T* LL_NEXT_ALIGNED_ADDRESS_64(T* address)
 
             ((void**)aligned)[-1] = mem;
         }
-		return aligned;
+		void* ret = aligned;
 	#endif
+        LL_PROFILE_ALLOC(ret, size);
+        return ret;
 	}
 
 	inline void ll_aligned_free_fallback( void* ptr )
 	{
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY;
+        LL_PROFILE_FREE(ptr);
 	#if defined(LL_WINDOWS)
 		_aligned_free(ptr);
 	#else
@@ -146,21 +174,24 @@ template <typename T> T* LL_NEXT_ALIGNED_ADDRESS_64(T* address)
 
 inline void* ll_aligned_malloc_16(size_t size) // returned hunk MUST be freed with ll_aligned_free_16().
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY;
 #if defined(LL_WINDOWS)
-	return _aligned_malloc(size, 16);
+	void* ret = _aligned_malloc(size, 16);
 #elif defined(LL_DARWIN)
-	return malloc(size); // default osx malloc is 16 byte aligned.
+	void* ret = malloc(size); // default osx malloc is 16 byte aligned.
 #else
-	void *rtn;
-	if (LL_LIKELY(0 == posix_memalign(&rtn, 16, size)))
-		return rtn;
-	else // bad alignment requested, or out of memory
-		return NULL;
+	void *ret;
+    if (0 != posix_memalign(&ret, 16, size))
+        return nullptr;
 #endif
+    LL_PROFILE_ALLOC(ret, size);
+    return ret;
 }
 
 inline void ll_aligned_free_16(void *p)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY;
+    LL_PROFILE_FREE(p);
 #if defined(LL_WINDOWS)
 	_aligned_free(p);
 #elif defined(LL_DARWIN)
@@ -172,10 +203,12 @@ inline void ll_aligned_free_16(void *p)
 
 inline void* ll_aligned_realloc_16(void* ptr, size_t size, size_t old_size) // returned hunk MUST be freed with ll_aligned_free_16().
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY;
+    LL_PROFILE_FREE(ptr);
 #if defined(LL_WINDOWS)
-	return _aligned_realloc(ptr, size, 16);
+	void* ret = _aligned_realloc(ptr, size, 16);
 #elif defined(LL_DARWIN)
-	return realloc(ptr,size); // default osx malloc is 16 byte aligned.
+	void* ret = realloc(ptr,size); // default osx malloc is 16 byte aligned.
 #else
 	//FIXME: memcpy is SLOW
 	void* ret = ll_aligned_malloc_16(size);
@@ -188,27 +221,31 @@ inline void* ll_aligned_realloc_16(void* ptr, size_t size, size_t old_size) // r
 		}
 		ll_aligned_free_16(ptr);
 	}
-	return ret;
 #endif
+    LL_PROFILE_ALLOC(ptr, size);
+    return ret;
 }
 
 inline void* ll_aligned_malloc_32(size_t size) // returned hunk MUST be freed with ll_aligned_free_32().
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY;
 #if defined(LL_WINDOWS)
-	return _aligned_malloc(size, 32);
+	void* ret = _aligned_malloc(size, 32);
 #elif defined(LL_DARWIN)
-	return ll_aligned_malloc_fallback( size, 32 );
+	void* ret = ll_aligned_malloc_fallback( size, 32 );
 #else
-	void *rtn;
-	if (LL_LIKELY(0 == posix_memalign(&rtn, 32, size)))
-		return rtn;
-	else // bad alignment requested, or out of memory
-		return NULL;
+	void *ret;
+    if (0 != posix_memalign(&ret, 32, size))
+        return nullptr;
 #endif
+    LL_PROFILE_ALLOC(ret, size);
+    return ret;
 }
 
 inline void ll_aligned_free_32(void *p)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY;
+    LL_PROFILE_FREE(p);
 #if defined(LL_WINDOWS)
 	_aligned_free(p);
 #elif defined(LL_DARWIN)
@@ -222,29 +259,35 @@ inline void ll_aligned_free_32(void *p)
 template<size_t ALIGNMENT>
 LL_FORCE_INLINE void* ll_aligned_malloc(size_t size)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY;
+    void* ret;
 	if (LL_DEFAULT_HEAP_ALIGN % ALIGNMENT == 0)
 	{
-		return malloc(size);
+		ret = malloc(size);
+        LL_PROFILE_ALLOC(ret, size);
 	}
 	else if (ALIGNMENT == 16)
 	{
-		return ll_aligned_malloc_16(size);
+		ret = ll_aligned_malloc_16(size);
 	}
 	else if (ALIGNMENT == 32)
 	{
-		return ll_aligned_malloc_32(size);
+		ret = ll_aligned_malloc_32(size);
 	}
 	else
 	{
-		return ll_aligned_malloc_fallback(size, ALIGNMENT);
+		ret = ll_aligned_malloc_fallback(size, ALIGNMENT);
 	}
+    return ret;
 }
 
 template<size_t ALIGNMENT>
 LL_FORCE_INLINE void ll_aligned_free(void* ptr)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY;
 	if (ALIGNMENT == LL_DEFAULT_HEAP_ALIGN)
 	{
+        LL_PROFILE_FREE(ptr);
 		free(ptr);
 	}
 	else if (ALIGNMENT == 16)
@@ -266,6 +309,7 @@ LL_FORCE_INLINE void ll_aligned_free(void* ptr)
 //
 inline void ll_memcpy_nonaliased_aligned_16(char* __restrict dst, const char* __restrict src, size_t bytes)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY;
 	assert(src != NULL);
 	assert(dst != NULL);
 	assert(bytes > 0);
diff --git a/indra/llcommon/llmutex.cpp b/indra/llcommon/llmutex.cpp
index 4d73c04d076ed565d55404790069653c3147c520..0273dd5970ba7300b58e14b9527f1ce1ce0761dc 100644
--- a/indra/llcommon/llmutex.cpp
+++ b/indra/llcommon/llmutex.cpp
@@ -44,6 +44,7 @@ LLMutex::~LLMutex()
 
 void LLMutex::lock()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
 	if(isSelfLocked())
 	{ //redundant lock
 		mCount++;
@@ -65,6 +66,7 @@ void LLMutex::lock()
 
 void LLMutex::unlock()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
 	if (mCount > 0)
 	{ //not the root unlock
 		mCount--;
@@ -85,6 +87,7 @@ void LLMutex::unlock()
 
 bool LLMutex::isLocked()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
 	if (!mMutex.try_lock())
 	{
 		return true;
@@ -108,6 +111,7 @@ LLThread::id_t LLMutex::lockingThread() const
 
 bool LLMutex::trylock()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
 	if(isSelfLocked())
 	{ //redundant lock
 		mCount++;
@@ -146,17 +150,20 @@ LLCondition::~LLCondition()
 
 void LLCondition::wait()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
 	std::unique_lock< std::mutex > lock(mMutex);
 	mCond.wait(lock);
 }
 
 void LLCondition::signal()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
 	mCond.notify_one();
 }
 
 void LLCondition::broadcast()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
 	mCond.notify_all();
 }
 
@@ -166,6 +173,7 @@ LLMutexTrylock::LLMutexTrylock(LLMutex* mutex)
     : mMutex(mutex),
     mLocked(false)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
     if (mMutex)
         mLocked = mMutex->trylock();
 }
@@ -174,6 +182,7 @@ LLMutexTrylock::LLMutexTrylock(LLMutex* mutex, U32 aTries, U32 delay_ms)
     : mMutex(mutex),
     mLocked(false)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
     if (!mMutex)
         return;
 
@@ -188,6 +197,7 @@ LLMutexTrylock::LLMutexTrylock(LLMutex* mutex, U32 aTries, U32 delay_ms)
 
 LLMutexTrylock::~LLMutexTrylock()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
     if (mMutex && mLocked)
         mMutex->unlock();
 }
@@ -199,6 +209,7 @@ LLMutexTrylock::~LLMutexTrylock()
 //
 LLScopedLock::LLScopedLock(std::mutex* mutex) : mMutex(mutex)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
 	if(mutex)
 	{
 		mutex->lock();
@@ -217,6 +228,7 @@ LLScopedLock::~LLScopedLock()
 
 void LLScopedLock::unlock()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
 	if(mLocked)
 	{
 		mMutex->unlock();
diff --git a/indra/llcommon/llpreprocessor.h b/indra/llcommon/llpreprocessor.h
index b17a8e761a1f5b6dd50fa9c803185c3ed15abf21..dc586b0008cac2ba8f3b1ac80494fa5b2d1c4981 100644
--- a/indra/llcommon/llpreprocessor.h
+++ b/indra/llcommon/llpreprocessor.h
@@ -171,7 +171,9 @@
 #define LL_DLLIMPORT
 #endif // LL_WINDOWS
 
-#if ! defined(LL_WINDOWS)
+#if __clang__ || ! defined(LL_WINDOWS)
+// Only on Windows, and only with the Microsoft compiler (vs. clang) is
+// wchar_t potentially not a distinct type.
 #define LL_WCHAR_T_NATIVE 1
 #else  // LL_WINDOWS
 // https://docs.microsoft.com/en-us/cpp/preprocessor/predefined-macros
diff --git a/indra/llcommon/llprocessor.cpp b/indra/llcommon/llprocessor.cpp
index 5d16a4b74d3b5ad306ec13f2a90ba57dd01de2e8..4a1a81f083875824e15358183d836321610110e1 100644
--- a/indra/llcommon/llprocessor.cpp
+++ b/indra/llcommon/llprocessor.cpp
@@ -44,20 +44,6 @@
 
 #include "llsd.h"
 
-#if LL_MSVC && _M_X64
-#      define LL_X86_64 1
-#      define LL_X86 1
-#elif LL_MSVC && _M_IX86
-#      define LL_X86 1
-#elif LL_GNUC && ( defined(__amd64__) || defined(__x86_64__) )
-#      define LL_X86_64 1
-#      define LL_X86 1
-#elif LL_GNUC && ( defined(__i386__) )
-#      define LL_X86 1
-#elif LL_GNUC && ( defined(__powerpc__) || defined(__ppc__) )
-#      define LL_PPC 1
-#endif
-
 class LLProcessorInfoImpl; // foward declaration for the mImpl;
 
 namespace 
@@ -132,7 +118,11 @@ namespace
 		eMONTIOR_MWAIT=33,
 		eCPLDebugStore=34,
 		eThermalMonitor2=35,
-		eAltivec=36
+		eAltivec=36,
+        eSSE3S_Features = 37,
+        eSSE4_1_Features = 38,
+        eSSE4_2_Features = 39,
+        eSSE4a_Features = 40,
 	};
 
 	const char* cpu_feature_names[] =
@@ -175,7 +165,11 @@ namespace
 		"CPL Qualified Debug Store",
 		"Thermal Monitor 2",
 
-		"Altivec"
+		"Altivec",
+        "SSE3S Instructions",
+        "SSE4.1 Instructions",
+        "SSE4.2 Instructions",
+        "SSE4a Instructions",
 	};
 
 	std::string intel_CPUFamilyName(int composed_family) 
@@ -264,6 +258,31 @@ class LLProcessorInfoImpl
 		return hasExtension(cpu_feature_names[eSSE2_Ext]);
 	}
 
+    bool hasSSE3() const
+    {
+        return hasExtension(cpu_feature_names[eSSE3_Features]);
+    }
+
+    bool hasSSE3S() const
+    {
+        return hasExtension(cpu_feature_names[eSSE3S_Features]);
+    }
+
+    bool hasSSE41() const
+    {
+        return hasExtension(cpu_feature_names[eSSE4_1_Features]);
+    }
+
+    bool hasSSE42() const
+    {
+        return hasExtension(cpu_feature_names[eSSE4_2_Features]);
+    }
+
+    bool hasSSE4a() const
+    {
+        return hasExtension(cpu_feature_names[eSSE4a_Features]);
+    }
+
 	bool hasAltivec() const 
 	{
 		return hasExtension("Altivec"); 
@@ -487,6 +506,12 @@ class LLProcessorInfoWindowsImpl : public LLProcessorInfoImpl
 		*((int*)(cpu_vendor+4)) = cpu_info[3];
 		*((int*)(cpu_vendor+8)) = cpu_info[2];
 		setInfo(eVendor, cpu_vendor);
+        std::string cmp_vendor(cpu_vendor);
+        bool is_amd = false;
+        if (cmp_vendor == "AuthenticAMD")
+        {
+            is_amd = true;
+        }
 
 		// Get the information associated with each valid Id
 		for(unsigned int i=0; i<=ids; ++i)
@@ -518,6 +543,7 @@ class LLProcessorInfoWindowsImpl : public LLProcessorInfoImpl
 
 				if(cpu_info[2] & 0x8)
 				{
+                    // intel specific SSE3 suplements
 					setExtension(cpu_feature_names[eMONTIOR_MWAIT]);
 				}
 				
@@ -530,7 +556,22 @@ class LLProcessorInfoWindowsImpl : public LLProcessorInfoImpl
 				{
 					setExtension(cpu_feature_names[eThermalMonitor2]);
 				}
-						
+
+                if (cpu_info[2] & 0x200)
+                {
+                    setExtension(cpu_feature_names[eSSE3S_Features]);
+                }
+
+                if (cpu_info[2] & 0x80000)
+                {
+                    setExtension(cpu_feature_names[eSSE4_1_Features]);
+                }
+
+                if (cpu_info[2] & 0x100000)
+                {
+                    setExtension(cpu_feature_names[eSSE4_2_Features]);
+                }
+
 				unsigned int feature_info = (unsigned int) cpu_info[3];
 				for(unsigned int index = 0, bit = 1; index < eSSE3_Features; ++index, bit <<= 1)
 				{
@@ -557,8 +598,17 @@ class LLProcessorInfoWindowsImpl : public LLProcessorInfoImpl
 			__cpuid(cpu_info, i);
 
 			// Interpret CPU brand string and cache information.
-			if  (i == 0x80000002)
-				memcpy(cpu_brand_string, cpu_info, sizeof(cpu_info));
+            if (i == 0x80000001)
+            {
+                if (is_amd)
+                {
+                    setExtension(cpu_feature_names[eSSE4a_Features]);
+                }
+            }
+            else if (i == 0x80000002)
+            {
+                memcpy(cpu_brand_string, cpu_info, sizeof(cpu_info));
+            }
 			else if  (i == 0x80000003)
 				memcpy(cpu_brand_string + 16, cpu_info, sizeof(cpu_info));
 			else if  (i == 0x80000004)
@@ -704,6 +754,41 @@ class LLProcessorInfoDarwinImpl : public LLProcessorInfoImpl
 		uint64_t ext_feature_info = getSysctlInt64("machdep.cpu.extfeature_bits");
 		S32 *ext_feature_infos = (S32*)(&ext_feature_info);
 		setConfig(eExtFeatureBits, ext_feature_infos[0]);
+
+
+        char cpu_features[1024];
+        len = sizeof(cpu_features);
+        memset(cpu_features, 0, len);
+        sysctlbyname("machdep.cpu.features", (void*)cpu_features, &len, NULL, 0);
+
+        std::string cpu_features_str(cpu_features);
+        cpu_features_str = " " + cpu_features_str + " ";
+
+        if (cpu_features_str.find(" SSE3 ") != std::string::npos)
+        {
+            setExtension(cpu_feature_names[eSSE3_Features]);
+        }
+
+        if (cpu_features_str.find(" SSSE3 ") != std::string::npos)
+        {
+            setExtension(cpu_feature_names[eSSE3S_Features]);
+        }
+
+        if (cpu_features_str.find(" SSE4.1 ") != std::string::npos)
+        {
+            setExtension(cpu_feature_names[eSSE4_1_Features]);
+        }
+
+        if (cpu_features_str.find(" SSE4.2 ") != std::string::npos)
+        {
+            setExtension(cpu_feature_names[eSSE4_2_Features]);
+        }
+
+        if (cpu_features_str.find(" SSE4A ") != std::string::npos)
+        {
+            // Not supposed to happen?
+            setExtension(cpu_feature_names[eSSE4a_Features]);
+        }
 	}
 };
 
@@ -814,6 +899,31 @@ class LLProcessorInfoLinuxImpl : public LLProcessorInfoImpl
 		{
 			setExtension(cpu_feature_names[eSSE2_Ext]);
 		}
+
+        if (flags.find(" pni ") != std::string::npos)
+        {
+            setExtension(cpu_feature_names[eSSE3_Features]);
+        }
+
+        if (flags.find(" ssse3 ") != std::string::npos)
+        {
+            setExtension(cpu_feature_names[eSSE3S_Features]);
+        }
+
+        if (flags.find(" sse4_1 ") != std::string::npos)
+        {
+            setExtension(cpu_feature_names[eSSE4_1_Features]);
+        }
+
+        if (flags.find(" sse4_2 ") != std::string::npos)
+        {
+            setExtension(cpu_feature_names[eSSE4_2_Features]);
+        }
+
+        if (flags.find(" sse4a ") != std::string::npos)
+        {
+            setExtension(cpu_feature_names[eSSE4a_Features]);
+        }
 	
 # endif // LL_X86
 	}
@@ -874,6 +984,11 @@ LLProcessorInfo::~LLProcessorInfo() {}
 F64MegahertzImplicit LLProcessorInfo::getCPUFrequency() const { return mImpl->getCPUFrequency(); }
 bool LLProcessorInfo::hasSSE() const { return mImpl->hasSSE(); }
 bool LLProcessorInfo::hasSSE2() const { return mImpl->hasSSE2(); }
+bool LLProcessorInfo::hasSSE3() const { return mImpl->hasSSE3(); }
+bool LLProcessorInfo::hasSSE3S() const { return mImpl->hasSSE3S(); }
+bool LLProcessorInfo::hasSSE41() const { return mImpl->hasSSE41(); }
+bool LLProcessorInfo::hasSSE42() const { return mImpl->hasSSE42(); }
+bool LLProcessorInfo::hasSSE4a() const { return mImpl->hasSSE4a(); }
 bool LLProcessorInfo::hasAltivec() const { return mImpl->hasAltivec(); }
 std::string LLProcessorInfo::getCPUFamilyName() const { return mImpl->getCPUFamilyName(); }
 std::string LLProcessorInfo::getCPUBrandName() const { return mImpl->getCPUBrandName(); }
diff --git a/indra/llcommon/llprocessor.h b/indra/llcommon/llprocessor.h
index 90e5bc59ee24638243342e814de4a761006f13c1..1a473ddc97d1eed6148c4f00fecf7fdfed473d1c 100644
--- a/indra/llcommon/llprocessor.h
+++ b/indra/llcommon/llprocessor.h
@@ -29,6 +29,20 @@
 #define LLPROCESSOR_H
 #include "llunits.h"
 
+#if LL_MSVC && _M_X64
+#      define LL_X86_64 1
+#      define LL_X86 1
+#elif LL_MSVC && _M_IX86
+#      define LL_X86 1
+#elif LL_GNUC && ( defined(__amd64__) || defined(__x86_64__) )
+#      define LL_X86_64 1
+#      define LL_X86 1
+#elif LL_GNUC && ( defined(__i386__) )
+#      define LL_X86 1
+#elif LL_GNUC && ( defined(__powerpc__) || defined(__ppc__) )
+#      define LL_PPC 1
+#endif
+
 class LLProcessorInfoImpl;
 
 class LL_COMMON_API LLProcessorInfo
@@ -40,6 +54,11 @@ class LL_COMMON_API LLProcessorInfo
 	F64MegahertzImplicit getCPUFrequency() const;
 	bool hasSSE() const;
 	bool hasSSE2() const;
+    bool hasSSE3() const;
+    bool hasSSE3S() const;
+    bool hasSSE41() const;
+    bool hasSSE42() const;
+    bool hasSSE4a() const;
 	bool hasAltivec() const;
 	std::string getCPUFamilyName() const;
 	std::string getCPUBrandName() const;
diff --git a/indra/llcommon/llprofiler.h b/indra/llcommon/llprofiler.h
new file mode 100644
index 0000000000000000000000000000000000000000..f9d7ae7ce41c74bc1e45354dbfd44700eb580a36
--- /dev/null
+++ b/indra/llcommon/llprofiler.h
@@ -0,0 +1,151 @@
+/**
+ * @file llprofiler.h
+ * @brief Wrapper for Tracy and/or other profilers
+ *
+ * $LicenseInfo:firstyear=2021&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2021, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_PROFILER_H
+#define LL_PROFILER_H
+
+// If you use the default macros LL_PROFILE_ZONE_SCOPED and LL_PROFILE_ZONE_NAMED to profile code ...
+//
+//     void foo()
+//     {
+//         LL_PROFILE_ZONE_SCOPED;
+//         :
+//
+//         {
+//             LL_PROFILE_ZONE_NAMED("widget bar");
+//             :
+//         }
+//         {
+//             LL_PROFILE_ZONE_NAMED("widget qux");
+//             :
+//         }
+//     }
+//
+// ... please be aware that ALL these will show up in a Tracy capture which can quickly exhaust memory.
+// Instead, use LL_PROFILE_ZONE_SCOPED_CATEGORY_* and LL_PROFILE_ZONE_NAMED_CATEGORY_* to profile code ...
+//
+//     void foo()
+//     {
+//         LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
+//         :
+//
+//         {
+//             LL_PROFILE_ZONE_NAMED_CATEGORY_UI("widget bar");
+//             :
+//         }
+//         {
+//             LL_PROFILE_ZONE_NAMED_CATEGORY_UI("widget qux");
+//             :
+//         }
+//     }
+//
+// ... as these can be selectively turned on/off.  This will minimize memory usage and visual clutter in a Tracy capture.
+// See llprofiler_categories.h for more details on profiling categories.
+
+#define LL_PROFILER_CONFIG_NONE             0  // No profiling
+#define LL_PROFILER_CONFIG_FAST_TIMER       1  // Profiling on: Only Fast Timers
+#define LL_PROFILER_CONFIG_TRACY            2  // Profiling on: Only Tracy
+#define LL_PROFILER_CONFIG_TRACY_FAST_TIMER 3  // Profiling on: Fast Timers + Tracy
+
+#ifndef LL_PROFILER_CONFIGURATION
+#define LL_PROFILER_CONFIGURATION           LL_PROFILER_CONFIG_FAST_TIMER
+#endif
+
+extern thread_local bool gProfilerEnabled;
+
+#if defined(LL_PROFILER_CONFIGURATION) && (LL_PROFILER_CONFIGURATION > LL_PROFILER_CONFIG_NONE)
+    #if LL_PROFILER_CONFIGURATION == LL_PROFILER_CONFIG_TRACY || LL_PROFILER_CONFIGURATION == LL_PROFILER_CONFIG_TRACY_FAST_TIMER
+        #define TRACY_ENABLE         1
+// Normally these would be enabled but we want to be able to build any viewer with Tracy enabled and run the Tracy server on another machine
+// They must be undefined in order to work across multiple machines
+//      #define TRACY_NO_BROADCAST   1
+//      #define TRACY_ONLY_LOCALHOST 1
+        #define TRACY_ONLY_IPV4      1
+        #include "Tracy.hpp"
+
+        // Mutually exclusive with detailed memory tracing
+        #define LL_PROFILER_ENABLE_TRACY_OPENGL 0
+    #endif
+
+    #if LL_PROFILER_CONFIGURATION == LL_PROFILER_CONFIG_TRACY
+        #define LL_PROFILER_FRAME_END                   FrameMark
+        #define LL_PROFILER_SET_THREAD_NAME( name )     tracy::SetThreadName( name );    gProfilerEnabled = true;
+        #define LL_RECORD_BLOCK_TIME(name)              ZoneScoped // Want descriptive names; was: ZoneNamedN( ___tracy_scoped_zone, #name, true );
+        #define LL_PROFILE_ZONE_NAMED(name)             ZoneNamedN( ___tracy_scoped_zone, name, true );
+        #define LL_PROFILE_ZONE_NAMED_COLOR(name,color) ZoneNamedNC( ___tracy_scopped_zone, name, color, true ) // RGB
+        #define LL_PROFILE_ZONE_SCOPED                  ZoneScoped
+
+        #define LL_PROFILE_ZONE_NUM( val )              ZoneValue( val )
+        #define LL_PROFILE_ZONE_TEXT( text, size )      ZoneText( text, size )
+
+        #define LL_PROFILE_ZONE_ERR(name)               LL_PROFILE_ZONE_NAMED_COLOR( name, 0XFF0000  )  // RGB yellow
+        #define LL_PROFILE_ZONE_INFO(name)              LL_PROFILE_ZONE_NAMED_COLOR( name, 0X00FFFF  )  // RGB cyan
+        #define LL_PROFILE_ZONE_WARN(name)              LL_PROFILE_ZONE_NAMED_COLOR( name, 0x0FFFF00 )  // RGB red
+        #define LL_PROFILE_ALLOC(ptr, size)             TracyAlloc(ptr, size)
+        #define LL_PROFILE_FREE(ptr)                    TracyFree(ptr)
+    #endif
+    #if LL_PROFILER_CONFIGURATION == LL_PROFILER_CONFIG_FAST_TIMER
+        #define LL_PROFILER_FRAME_END
+        #define LL_PROFILER_SET_THREAD_NAME( name )      (void)(name)
+        #define LL_RECORD_BLOCK_TIME(name)                                                                  const LLTrace::BlockTimer& LL_GLUE_TOKENS(block_time_recorder, __LINE__)(LLTrace::timeThisBlock(name)); (void)LL_GLUE_TOKENS(block_time_recorder, __LINE__);
+        #define LL_PROFILE_ZONE_NAMED(name)             // LL_PROFILE_ZONE_NAMED is a no-op when Tracy is disabled
+        #define LL_PROFILE_ZONE_SCOPED                  // LL_PROFILE_ZONE_SCOPED is a no-op when Tracy is disabled
+        #define LL_PROFILE_ZONE_COLOR(name,color)       // LL_RECORD_BLOCK_TIME(name)
+
+        #define LL_PROFILE_ZONE_NUM( val )              (void)( val );                // Not supported
+        #define LL_PROFILE_ZONE_TEXT( text, size )      (void)( text ); void( size ); // Not supported
+
+        #define LL_PROFILE_ZONE_ERR(name)               (void)(name); // Not supported
+        #define LL_PROFILE_ZONE_INFO(name)              (void)(name); // Not supported
+        #define LL_PROFILE_ZONE_WARN(name)              (void)(name); // Not supported
+        #define LL_PROFILE_ALLOC(ptr, size)             (void)(ptr); (void)(size);
+        #define LL_PROFILE_FREE(ptr)                    (void)(ptr);
+    #endif
+    #if LL_PROFILER_CONFIGURATION == LL_PROFILER_CONFIG_TRACY_FAST_TIMER
+        #define LL_PROFILER_FRAME_END                   FrameMark
+        #define LL_PROFILER_SET_THREAD_NAME( name )     tracy::SetThreadName( name );    gProfilerEnabled = true;
+        #define LL_RECORD_BLOCK_TIME(name)              ZoneNamedN(___tracy_scoped_zone, #name, true);   const LLTrace::BlockTimer& LL_GLUE_TOKENS(block_time_recorder, __LINE__)(LLTrace::timeThisBlock(name)); (void)LL_GLUE_TOKENS(block_time_recorder, __LINE__);
+        #define LL_PROFILE_ZONE_NAMED(name)             ZoneNamedN( ___tracy_scoped_zone, #name, true );
+        #define LL_PROFILE_ZONE_NAMED_COLOR(name,color) ZoneNamedNC( ___tracy_scopped_zone, name, color, true ) // RGB
+        #define LL_PROFILE_ZONE_SCOPED                  ZoneScoped
+
+        #define LL_PROFILE_ZONE_NUM( val )              ZoneValue( val )
+        #define LL_PROFILE_ZONE_TEXT( text, size )      ZoneText( text, size )
+
+        #define LL_PROFILE_ZONE_ERR(name)               LL_PROFILE_ZONE_NAMED_COLOR( name, 0XFF0000  )  // RGB yellow
+        #define LL_PROFILE_ZONE_INFO(name)              LL_PROFILE_ZONE_NAMED_COLOR( name, 0X00FFFF  )  // RGB cyan
+        #define LL_PROFILE_ZONE_WARN(name)              LL_PROFILE_ZONE_NAMED_COLOR( name, 0x0FFFF00 )  // RGB red
+        #define LL_PROFILE_ALLOC(ptr, size)             TracyAlloc(ptr, size)
+        #define LL_PROFILE_FREE(ptr)                    TracyFree(ptr)
+    #endif
+#else
+    #define LL_PROFILER_FRAME_END
+    #define LL_PROFILER_SET_THREAD_NAME( name ) (void)(name)
+#endif // LL_PROFILER
+
+#include "llprofilercategories.h"
+
+#endif // LL_PROFILER_H
diff --git a/indra/llcommon/llprofilercategories.h b/indra/llcommon/llprofilercategories.h
new file mode 100644
index 0000000000000000000000000000000000000000..8db29468cccae8370314911240047f74a1c1413f
--- /dev/null
+++ b/indra/llcommon/llprofilercategories.h
@@ -0,0 +1,280 @@
+/**
+ * @file llprofiler_ategories.h
+ * @brief Profiling categories to minimize Tracy memory usage when viewing captures.
+ *
+ * $LicenseInfo:firstyear=2022&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2022, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_PROFILER_CATEGORIES_H
+#define LL_PROFILER_CATEGORIES_H
+
+// A Tracy capture can quickly consume memory.  Use these defines to selectively turn on/off Tracy profiling for these categories.
+// The biggest memory usage ones are:
+//
+//    LL_PROFILER_CATEGORY_ENABLE_DRAWPOOL
+//    LL_PROFILER_CATEGORY_ENABLE_LLSD
+//    LL_PROFILER_CATEGORY_ENABLE_MEMORY
+//    LL_PROFILER_CATEGORY_ENABLE_SHADERS
+//
+// NOTE: You can still manually use:
+//     LL_PROFILE_ZONE_SCOPED();
+//     LL_PROFILE_ZONE_NAMED("name");
+// but just be aware that those will ALWAYS show up in a Tracy capture
+//  a) using more memory, and
+//  b) adding visual clutter.
+#define LL_PROFILER_CATEGORY_ENABLE_APP         1
+#define LL_PROFILER_CATEGORY_ENABLE_AVATAR      1
+#define LL_PROFILER_CATEGORY_ENABLE_DISPLAY     1
+#define LL_PROFILER_CATEGORY_ENABLE_DRAWABLE    1
+#define LL_PROFILER_CATEGORY_ENABLE_DRAWPOOL    1
+#define LL_PROFILER_CATEGORY_ENABLE_ENVIRONMENT 1
+#define LL_PROFILER_CATEGORY_ENABLE_FACE        1
+#define LL_PROFILER_CATEGORY_ENABLE_LLSD        1
+#define LL_PROFILER_CATEGORY_ENABLE_LOGGING     1
+#define LL_PROFILER_CATEGORY_ENABLE_MATERIAL    1
+#define LL_PROFILER_CATEGORY_ENABLE_MEDIA       1
+#define LL_PROFILER_CATEGORY_ENABLE_MEMORY      1
+#define LL_PROFILER_CATEGORY_ENABLE_NETWORK     1
+#define LL_PROFILER_CATEGORY_ENABLE_OCTREE      1
+#define LL_PROFILER_CATEGORY_ENABLE_PIPELINE    1
+#define LL_PROFILER_CATEGORY_ENABLE_SHADER      1
+#define LL_PROFILER_CATEGORY_ENABLE_SPATIAL     1
+#define LL_PROFILER_CATEGORY_ENABLE_STATS       1
+#define LL_PROFILER_CATEGORY_ENABLE_STRING      1
+#define LL_PROFILER_CATEGORY_ENABLE_TEXTURE     1
+#define LL_PROFILER_CATEGORY_ENABLE_THREAD      1
+#define LL_PROFILER_CATEGORY_ENABLE_UI          1
+#define LL_PROFILER_CATEGORY_ENABLE_VIEWER      1
+#define LL_PROFILER_CATEGORY_ENABLE_VERTEX      1
+#define LL_PROFILER_CATEGORY_ENABLE_VOLUME      1
+#define LL_PROFILER_CATEGORY_ENABLE_WIN32       1
+
+#if LL_PROFILER_CATEGORY_ENABLE_APP
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_APP  LL_PROFILE_ZONE_NAMED
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_APP LL_PROFILE_ZONE_SCOPED
+#else
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_APP(name)
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_APP
+#endif
+
+#if LL_PROFILER_CATEGORY_ENABLE_AVATAR
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_AVATAR  LL_PROFILE_ZONE_NAMED
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR LL_PROFILE_ZONE_SCOPED
+#else
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_AVATAR(name)
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR
+#endif
+
+#if LL_PROFILER_CATEGORY_ENABLE_DISPLAY
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY  LL_PROFILE_ZONE_NAMED
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_DISPLAY LL_PROFILE_ZONE_SCOPED
+#else
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY(name)
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_DISPLAY
+#endif
+
+#if LL_PROFILER_CATEGORY_ENABLE_DRAWABLE
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWABLE  LL_PROFILE_ZONE_NAMED
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE LL_PROFILE_ZONE_SCOPED
+#else
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWABLE(name)
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE
+#endif
+
+#if LL_PROFILER_CATEGORY_ENABLE_DRAWPOOL
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWPOOL  LL_PROFILE_ZONE_NAMED
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL LL_PROFILE_ZONE_SCOPED
+#else
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWPOOL(name)
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL
+#endif
+
+#if LL_PROFILER_CATEGORY_ENABLE_ENVIRONMENT
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_ENVIRONMENT  LL_PROFILE_ZONE_NAMED
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_ENVIRONMENT LL_PROFILE_ZONE_SCOPED
+#else
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_ENVIRONMENT(name)
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_ENVIRONMENT
+#endif
+
+#if LL_PROFILER_CATEGORY_ENABLE_FACE
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_FACE  LL_PROFILE_ZONE_NAMED
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_FACE LL_PROFILE_ZONE_SCOPED
+#else
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_FACE(name)
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_FACE
+#endif
+
+#if LL_PROFILER_CATEGORY_ENABLE_LLSD
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_LLSD  LL_PROFILE_ZONE_NAMED
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD LL_PROFILE_ZONE_SCOPED
+#else
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_LLSD(name)
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD
+#endif
+
+#if LL_PROFILER_CATEGORY_ENABLE_LOGGING
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_LOGGING  LL_PROFILE_ZONE_NAMED
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING LL_PROFILE_ZONE_SCOPED
+#else
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_LOGGING(name)
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING
+#endif
+
+#if LL_PROFILER_CATEGORY_ENABLE_MATERIAL
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_MATERIAL  LL_PROFILE_ZONE_NAMED
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_MATERIAL LL_PROFILE_ZONE_SCOPED
+#else
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_MATERIAL(name)
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_MATERIAL
+#endif
+
+#if LL_PROFILER_CATEGORY_ENABLE_MEDIA
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_MEDIA  LL_PROFILE_ZONE_NAMED
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_MEDIA LL_PROFILE_ZONE_SCOPED
+#else
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_MEDIA(name)
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_MEDIA
+#endif
+
+#if LL_PROFILER_CATEGORY_ENABLE_MEMORY
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_MEMORY  LL_PROFILE_ZONE_NAMED
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY LL_PROFILE_ZONE_SCOPED
+#else
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_MEMORY(name)
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY
+#endif
+
+#if LL_PROFILER_CATEGORY_ENABLE_NETWORK
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_NETWORK  LL_PROFILE_ZONE_NAMED
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK LL_PROFILE_ZONE_SCOPED
+#else
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_NETWORK(name)
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK
+#endif
+
+#if LL_PROFILER_CATEGORY_ENABLE_OCTREE
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_OCTREE  LL_PROFILE_ZONE_NAMED
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_OCTREE LL_PROFILE_ZONE_SCOPED
+#else
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_OCTREE(name)
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_OCTREE
+#endif
+
+#if LL_PROFILER_CATEGORY_ENABLE_PIPELINE
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE  LL_PROFILE_ZONE_NAMED
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE LL_PROFILE_ZONE_SCOPED
+#else
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE(name)
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE
+#endif
+
+#if LL_PROFILER_CATEGORY_ENABLE_SHADER
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_SHADER  LL_PROFILE_ZONE_NAMED
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER LL_PROFILE_ZONE_SCOPED
+#else
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_SHADER(name)
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER
+#endif
+
+#if LL_PROFILER_CATEGORY_ENABLE_SPATIAL
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_SPATIAL  LL_PROFILE_ZONE_NAMED
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_SPATIAL LL_PROFILE_ZONE_SCOPED
+#else
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_SPATIAL(name)
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_SPATIAL
+#endif
+
+#if LL_PROFILER_CATEGORY_ENABLE_STATS
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_STATS  LL_PROFILE_ZONE_NAMED
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS LL_PROFILE_ZONE_SCOPED
+#else
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_STATS(name)
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS
+#endif
+
+#if LL_PROFILER_CATEGORY_ENABLE_STRING
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_STRING  LL_PROFILE_ZONE_NAMED
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_STRING LL_PROFILE_ZONE_SCOPED
+#else
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_STRING(name)
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_STRING
+#endif
+
+#if LL_PROFILER_CATEGORY_ENABLE_TEXTURE
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE  LL_PROFILE_ZONE_NAMED
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE LL_PROFILE_ZONE_SCOPED
+#else
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE(name)
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE
+#endif
+
+#if LL_PROFILER_CATEGORY_ENABLE_THREAD
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_THREAD  LL_PROFILE_ZONE_NAMED
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD LL_PROFILE_ZONE_SCOPED
+#else
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_THREAD(name)
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
+#endif
+
+#if LL_PROFILER_CATEGORY_ENABLE_UI
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_UI  LL_PROFILE_ZONE_NAMED
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_UI LL_PROFILE_ZONE_SCOPED
+#else
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_UI(name)
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_UI
+#endif
+
+#if LL_PROFILER_CATEGORY_ENABLE_VERTEX
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX  LL_PROFILE_ZONE_NAMED
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX LL_PROFILE_ZONE_SCOPED
+#else
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX(name)
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX
+#endif
+
+#if LL_PROFILER_CATEGORY_ENABLE_VIEWER
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_VIEWER  LL_PROFILE_ZONE_NAMED
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_VIEWER LL_PROFILE_ZONE_SCOPED
+#else
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_VIEWER(name)
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_VIEWER
+#endif
+
+#if LL_PROFILER_CATEGORY_ENABLE_VOLUME
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_VOLUME  LL_PROFILE_ZONE_NAMED
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME LL_PROFILE_ZONE_SCOPED
+#else
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_VOLUME(name)
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME
+#endif
+
+#if LL_PROFILER_CATEGORY_ENABLE_WIN32
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32  LL_PROFILE_ZONE_NAMED
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_WIN32 LL_PROFILE_ZONE_SCOPED
+#else
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32(name)
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_WIN32
+#endif
+
+#endif // LL_PROFILER_CATEGORIES_H
+
diff --git a/indra/llcommon/llrefcount.cpp b/indra/llcommon/llrefcount.cpp
index 29a5ca6f245cbec59e6be9205607a415fc4e050b..6852b5536aecdfebb1627ae218cfcfed26bacc78 100644
--- a/indra/llcommon/llrefcount.cpp
+++ b/indra/llcommon/llrefcount.cpp
@@ -29,6 +29,9 @@
 
 #include "llerror.h"
 
+// maximum reference count before sounding memory leak alarm
+const S32 gMaxRefCount = S32_MAX;
+
 LLRefCount::LLRefCount(const LLRefCount& other)
 :	mRef(0)
 {
@@ -47,7 +50,7 @@ LLRefCount::LLRefCount() :
 
 LLRefCount::~LLRefCount()
 { 
-	if (mRef != 0)
+	if (mRef != LL_REFCOUNT_FREE && mRef != 0)
 	{
 		LL_ERRS() << "deleting non-zero reference" << LL_ENDL;
 	}
diff --git a/indra/llcommon/llrefcount.h b/indra/llcommon/llrefcount.h
index 7e4af6ea66a58ca9972583ff29e3060c9ce43269..2080da15653d8e9974b3d2d09aa38755aa981151 100644
--- a/indra/llcommon/llrefcount.h
+++ b/indra/llcommon/llrefcount.h
@@ -37,6 +37,10 @@ class LLMutex;
 // see llthread.h for LLThreadSafeRefCount
 //----------------------------------------------------------------------------
 
+//nonsense but recognizable value for freed LLRefCount (aids in debugging)
+#define LL_REFCOUNT_FREE 1234567890
+extern const S32 gMaxRefCount;
+
 class LL_COMMON_API LLRefCount
 {
 protected:
@@ -47,17 +51,25 @@ class LL_COMMON_API LLRefCount
 public:
 	LLRefCount();
 
+    inline void validateRefCount() const
+    {
+        llassert(mRef > 0); // ref count below 0, likely corrupted
+        llassert(mRef < gMaxRefCount); // ref count excessive, likely memory leak
+    }
+
 	inline void ref() const
 	{ 
 		mRef++; 
+        validateRefCount();
 	} 
 
 	inline S32 unref() const
 	{
-		llassert(mRef >= 1);
+        validateRefCount();
 		if (0 == --mRef)
 		{
-			delete this; 
+            mRef = LL_REFCOUNT_FREE; // set to nonsense yet recognizable value to aid in debugging
+			delete this;
 			return 0;
 		}
 		return mRef;
diff --git a/indra/llcommon/llsd.cpp b/indra/llcommon/llsd.cpp
index 57b746889d8f19ed1c2386b2f86d427c53aa9ffb..807b3d13f830f162bdd4378ceb1a2d6f8907f591 100644
--- a/indra/llcommon/llsd.cpp
+++ b/indra/llcommon/llsd.cpp
@@ -400,6 +400,7 @@ namespace
 	
 	ImplMap& ImplMap::makeMap(LLSD::Impl*& var)
 	{
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD;
 		if (shared())
 		{
 			ImplMap* i = new ImplMap(mData);
@@ -414,18 +415,21 @@ namespace
 	
 	bool ImplMap::has(const LLSD::String& k) const
 	{
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD;
 		DataMap::const_iterator i = mData.find(k);
 		return i != mData.end();
 	}
 	
 	LLSD ImplMap::get(const LLSD::String& k) const
 	{
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD;
 		DataMap::const_iterator i = mData.find(k);
 		return (i != mData.end()) ? i->second : LLSD();
 	}
 
 	LLSD ImplMap::getKeys() const
 	{ 
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD;
 		LLSD keys = LLSD::emptyArray();
 		DataMap::const_iterator iter = mData.begin();
 		while (iter != mData.end())
@@ -438,11 +442,13 @@ namespace
 
 	void ImplMap::insert(const LLSD::String& k, const LLSD& v)
 	{
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD;
 		mData.insert(DataMap::value_type(k, v));
 	}
 	
 	void ImplMap::erase(const LLSD::String& k)
 	{
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD;
 		mData.erase(k);
 	}
 	
@@ -684,6 +690,7 @@ const LLSD::Impl& LLSD::Impl::safe(const Impl* impl)
 
 ImplMap& LLSD::Impl::makeMap(Impl*& var)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD;
 	ImplMap* im = new ImplMap;
 	reset(var, im);
 	return *im;
@@ -887,11 +894,16 @@ LLSD& LLSD::with(const String& k, const LLSD& v)
 										}
 void LLSD::erase(const String& k)		{ makeMap(impl).erase(k); }
 
-LLSD&		LLSD::operator[](const String& k)
-										{ return makeMap(impl).ref(k); }
+LLSD& LLSD::operator[](const String& k)
+{ 
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD;
+    return makeMap(impl).ref(k); 
+}
 const LLSD& LLSD::operator[](const String& k) const
-										{ return safe(impl).ref(k); }
-
+{ 
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD;
+    return safe(impl).ref(k); 
+}
 
 LLSD LLSD::emptyArray()
 {
@@ -914,10 +926,16 @@ LLSD& LLSD::with(Integer i, const LLSD& v)
 LLSD& LLSD::append(const LLSD& v)		{ return makeArray(impl).append(v); }
 void LLSD::erase(Integer i)				{ makeArray(impl).erase(i); }
 
-LLSD&		LLSD::operator[](Integer i)
-										{ return makeArray(impl).ref(i); }
+LLSD& LLSD::operator[](Integer i)
+{ 
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD;
+    return makeArray(impl).ref(i); 
+}
 const LLSD& LLSD::operator[](Integer i) const
-										{ return safe(impl).ref(i); }
+{ 
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD;
+    return safe(impl).ref(i);
+}
 
 static const char *llsd_dump(const LLSD &llsd, bool useXMLFormat)
 {
diff --git a/indra/llcommon/llsd.h b/indra/llcommon/llsd.h
index 5b6d5545af11d61bfa2f9ca731e9f34c4091886d..24cb9bbce170d0f358f9e7ed3b2d5ca8eec1b38f 100644
--- a/indra/llcommon/llsd.h
+++ b/indra/llcommon/llsd.h
@@ -290,9 +290,17 @@ class LL_COMMON_API LLSD
 		LLSD& with(const String&, const LLSD&);
 		
 		LLSD& operator[](const String&);
-		LLSD& operator[](const char* c)			{ return (*this)[String(c)]; }
+		LLSD& operator[](const char* c)
+        {
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD;
+            return (*this)[String(c)];
+        }
 		const LLSD& operator[](const String&) const;
-		const LLSD& operator[](const char* c) const	{ return (*this)[String(c)]; }
+		const LLSD& operator[](const char* c) const	
+        {
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD;
+            return (*this)[String(c)];
+        }
 	//@}
 	
 	/** @name Array Values */
diff --git a/indra/llcommon/llsdparam.cpp b/indra/llcommon/llsdparam.cpp
index 2e7b46f8858694867d6e3ca0ba142a23b9b32d03..af4ccf25fd741e39e789013f1062b4c924489cae 100644
--- a/indra/llcommon/llsdparam.cpp
+++ b/indra/llcommon/llsdparam.cpp
@@ -37,8 +37,6 @@ static 	LLInitParam::Parser::parser_write_func_map_t sWriteFuncs;
 static 	LLInitParam::Parser::parser_inspect_func_map_t sInspectFuncs;
 static const LLSD NO_VALUE_MARKER;
 
-LLTrace::BlockTimerStatHandle FTM_SD_PARAM_ADAPTOR("LLSD to LLInitParam conversion");
-
 //
 // LLParamSDParser
 //
diff --git a/indra/llcommon/llsdparam.h b/indra/llcommon/llsdparam.h
index 93910b70ae98957246faaa30c4579f6666eb91d6..82a623a8a06e82ae3df78ff4dcc2e40e8ce4975a 100644
--- a/indra/llcommon/llsdparam.h
+++ b/indra/llcommon/llsdparam.h
@@ -110,7 +110,6 @@ typedef LLInitParam::Parser parser_t;
 };
 
 
-extern LL_COMMON_API LLTrace::BlockTimerStatHandle FTM_SD_PARAM_ADAPTOR;
 template<typename T>
 class LLSDParamAdapter : public T
 {
@@ -118,7 +117,7 @@ class LLSDParamAdapter : public T
 	LLSDParamAdapter() {}
 	LLSDParamAdapter(const LLSD& sd)
 	{
-		LL_RECORD_BLOCK_TIME(FTM_SD_PARAM_ADAPTOR);
+        LL_PROFILE_ZONE_SCOPED;
 		LLParamSDParser parser;
 		// don't spam for implicit parsing of LLSD, as we want to allow arbitrary freeform data and ignore most of it
 		bool parse_silently = true;
diff --git a/indra/llcommon/llsdserialize.cpp b/indra/llcommon/llsdserialize.cpp
index 022a5d4659ee99966f26231cdc6463de8c4da230..8b4a0ee6d87404f638b397019e18a03b9a47567b 100644
--- a/indra/llcommon/llsdserialize.cpp
+++ b/indra/llcommon/llsdserialize.cpp
@@ -37,7 +37,7 @@
 #ifdef LL_USESYSTEMLIBS
 # include <zlib.h>
 #else
-# include "zlib/zlib.h"  // for davep's dirty little zip functions
+# include "zlib-ng/zlib.h"  // for davep's dirty little zip functions
 #endif
 
 #if !LL_WINDOWS
diff --git a/indra/llcommon/llsdutil.cpp b/indra/llcommon/llsdutil.cpp
index eb3a96b1333d6d6902ea277b5c46ed60905f5829..8e90d1e8b89f76dafba377d1efaa9f538bc9da5c 100644
--- a/indra/llcommon/llsdutil.cpp
+++ b/indra/llcommon/llsdutil.cpp
@@ -29,6 +29,7 @@
 #include "linden_common.h"
 
 #include "llsdutil.h"
+#include <sstream>
 
 #if LL_WINDOWS
 #	define WIN32_LEAN_AND_MEAN
@@ -214,6 +215,8 @@ BOOL compare_llsd_with_template(
 	const LLSD& template_llsd,
 	LLSD& resultant_llsd)
 {
+    LL_PROFILE_ZONE_SCOPED
+
 	if (
 		llsd_to_test.isUndefined() &&
 		template_llsd.isDefined() )
@@ -335,6 +338,8 @@ bool filter_llsd_with_template(
 	const LLSD & template_llsd,
 	LLSD & resultant_llsd)
 {
+    LL_PROFILE_ZONE_SCOPED
+
 	if (llsd_to_test.isUndefined() && template_llsd.isDefined())
 	{
 		resultant_llsd = template_llsd;
@@ -529,6 +534,8 @@ class TypeLookup
 public:
     TypeLookup()
     {
+        LL_PROFILE_ZONE_SCOPED
+
         for (const Data *di(boost::begin(typedata)), *dend(boost::end(typedata)); di != dend; ++di)
         {
             mMap[di->type] = di->name;
@@ -537,6 +544,8 @@ class TypeLookup
 
     std::string lookup(LLSD::Type type) const
     {
+        LL_PROFILE_ZONE_SCOPED
+
         MapType::const_iterator found = mMap.find(type);
         if (found != mMap.end())
         {
@@ -587,6 +596,8 @@ static std::string match_types(LLSD::Type expect, // prototype.type()
                                LLSD::Type actual,        // type we're checking
                                const std::string& pfx)   // as for llsd_matches
 {
+    LL_PROFILE_ZONE_SCOPED
+
     // Trivial case: if the actual type is exactly what we expect, we're good.
     if (actual == expect)
         return "";
@@ -624,6 +635,8 @@ static std::string match_types(LLSD::Type expect, // prototype.type()
 // see docstring in .h file
 std::string llsd_matches(const LLSD& prototype, const LLSD& data, const std::string& pfx)
 {
+    LL_PROFILE_ZONE_SCOPED
+
     // An undefined prototype means that any data is valid.
     // An undefined slot in an array or map prototype means that any data
     // may fill that slot.
@@ -756,6 +769,8 @@ std::string llsd_matches(const LLSD& prototype, const LLSD& data, const std::str
 
 bool llsd_equals(const LLSD& lhs, const LLSD& rhs, int bits)
 {
+    LL_PROFILE_ZONE_SCOPED
+
     // We're comparing strict equality of LLSD representation rather than
     // performing any conversions. So if the types aren't equal, the LLSD
     // values aren't equal.
@@ -862,8 +877,10 @@ bool llsd_equals(const LLSD& lhs, const LLSD& rhs, int bits)
 namespace llsd
 {
 
-LLSD& drill(LLSD& blob, const LLSD& rawPath)
+LLSD& drill_ref(LLSD& blob, const LLSD& rawPath)
 {
+    LL_PROFILE_ZONE_SCOPED
+
     // Treat rawPath uniformly as an array. If it's not already an array,
     // store it as the only entry in one. (But let's say Undefined means an
     // empty array.)
@@ -889,6 +906,8 @@ LLSD& drill(LLSD& blob, const LLSD& rawPath)
     // path entry that's bad.
     for (LLSD::Integer i = 0; i < path.size(); ++i)
     {
+        LL_PROFILE_ZONE_NUM( i )
+
         const LLSD& key{path[i]};
         if (key.isString())
         {
@@ -917,9 +936,11 @@ LLSD& drill(LLSD& blob, const LLSD& rawPath)
 
 LLSD drill(const LLSD& blob, const LLSD& path)
 {
-    // non-const drill() does exactly what we want. Temporarily cast away
+    LL_PROFILE_ZONE_SCOPED
+
+    // drill_ref() does exactly what we want. Temporarily cast away
     // const-ness and use that.
-    return drill(const_cast<LLSD&>(blob), path);
+    return drill_ref(const_cast<LLSD&>(blob), path);
 }
 
 } // namespace llsd
@@ -929,6 +950,8 @@ LLSD drill(const LLSD& blob, const LLSD& path)
 // filter may be include to exclude/include keys in a map. 
 LLSD llsd_clone(LLSD value, LLSD filter)
 {
+    LL_PROFILE_ZONE_SCOPED
+
     LLSD clone;
     bool has_filter(filter.isMap());
 
diff --git a/indra/llcommon/llsdutil.h b/indra/llcommon/llsdutil.h
index 8678ca97f2e9ac7b75c0f468af9bf5c90b44f8cc..1321615805bfec449bedcd91b464962a67ce1fef 100644
--- a/indra/llcommon/llsdutil.h
+++ b/indra/llcommon/llsdutil.h
@@ -184,10 +184,10 @@ namespace llsd
  *   - Anything else is an error.
  *
  * By implication, if path.isUndefined() or otherwise equivalent to an empty
- * LLSD::Array, drill() returns 'blob' as is.
+ * LLSD::Array, drill[_ref]() returns 'blob' as is.
  */
 LLSD  drill(const LLSD& blob, const LLSD& path);
-LLSD& drill(      LLSD& blob, const LLSD& path);
+LLSD& drill_ref(  LLSD& blob, const LLSD& path);
 
 }
 
diff --git a/indra/llcommon/llsingleton.h b/indra/llcommon/llsingleton.h
index 7c81d65a8bb3edc613730c0130353b46f223849c..51ef514cf78785157d20fa83d8c031c274cddad4 100644
--- a/indra/llcommon/llsingleton.h
+++ b/indra/llcommon/llsingleton.h
@@ -455,6 +455,7 @@ class LLSingleton : public LLSingletonBase
 
     static DERIVED_TYPE* getInstance()
     {
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
         // We know the viewer has LLSingleton dependency circularities. If you
         // feel strongly motivated to eliminate them, cheers and good luck.
         // (At that point we could consider a much simpler locking mechanism.)
@@ -838,4 +839,36 @@ private:                                                                \
     /* LLSINGLETON() is carefully implemented to permit exactly this */ \
     LLSINGLETON_C11(DERIVED_CLASS) {}
 
+// Relatively unsafe singleton implementation that is much faster
+// and simpler than LLSingleton, but has no dependency tracking
+// or inherent thread safety and requires manual invocation of 
+// createInstance before first use.
+template<class T>
+class LLSimpleton
+{
+public:
+    template <typename... ARGS>
+    static void createInstance(ARGS&&... args)
+    {
+        llassert(sInstance == nullptr);
+        sInstance = new T(std::forward<ARGS>(args)...);
+    }
+
+    static inline T* getInstance() { return sInstance; }
+    static inline T& instance() { return *getInstance(); }
+    static inline bool instanceExists() { return sInstance != nullptr; }
+
+    static void deleteSingleton()
+    {
+        delete sInstance;
+        sInstance = nullptr;
+    }
+
+private:
+    static T* sInstance;
+};
+
+template <class T>
+T* LLSimpleton<T>::sInstance{ nullptr };
+
 #endif
diff --git a/indra/llcommon/llstring.cpp b/indra/llcommon/llstring.cpp
index 0290eea1430b89d088fcdfae45042669b0252ea9..7f501f2e776341f852461a720547ada37716cd53 100644
--- a/indra/llcommon/llstring.cpp
+++ b/indra/llcommon/llstring.cpp
@@ -37,9 +37,6 @@
 #include <winnls.h> // for WideCharToMultiByte
 #endif
 
-LLTrace::BlockTimerStatHandle FT_STRING_FORMAT("String Format");
-
-
 std::string ll_safe_string(const char* in)
 {
 	if(in) return std::string(in);
@@ -215,7 +212,7 @@ S32 utf16chars_to_wchar(const U16* inchars, llwchar* outchar)
 	return inchars - base;
 }
 
-llutf16string wstring_to_utf16str(const LLWString &utf32str, S32 len)
+llutf16string wstring_to_utf16str(const llwchar* utf32str, size_t len)
 {
 	llutf16string out;
 
@@ -237,27 +234,19 @@ llutf16string wstring_to_utf16str(const LLWString &utf32str, S32 len)
 	return out;
 }
 
-llutf16string wstring_to_utf16str(const LLWString &utf32str)
-{
-	const S32 len = (S32)utf32str.length();
-	return wstring_to_utf16str(utf32str, len);
-}
-
-llutf16string utf8str_to_utf16str ( const std::string& utf8str )
+llutf16string utf8str_to_utf16str( const char* utf8str, size_t len )
 {
-	LLWString wstr = utf8str_to_wstring ( utf8str );
+	LLWString wstr = utf8str_to_wstring ( utf8str, len );
 	return wstring_to_utf16str ( wstr );
 }
 
-
-LLWString utf16str_to_wstring(const llutf16string &utf16str, S32 len)
+LLWString utf16str_to_wstring(const U16* utf16str, size_t len)
 {
 	LLWString wout;
-	if((len <= 0) || utf16str.empty()) return wout;
+	if (len == 0) return wout;
 
 	S32 i = 0;
-	// craziness to make gcc happy (llutf16string.c_str() is tweaked on linux):
-	const U16* chars16 = &(*(utf16str.begin()));
+	const U16* chars16 = utf16str;
 	while (i < len)
 	{
 		llwchar cur_char;
@@ -267,12 +256,6 @@ LLWString utf16str_to_wstring(const llutf16string &utf16str, S32 len)
 	return wout;
 }
 
-LLWString utf16str_to_wstring(const llutf16string &utf16str)
-{
-	const S32 len = (S32)utf16str.length();
-	return utf16str_to_wstring(utf16str, len);
-}
-
 // Length in llwchar (UTF-32) of the first len units (16 bits) of the given UTF-16 string.
 S32 utf16str_wstring_length(const llutf16string &utf16str, const S32 utf16_len)
 {
@@ -392,8 +375,7 @@ S32 wstring_utf8_length(const LLWString& wstr)
 	return len;
 }
 
-
-LLWString utf8str_to_wstring(const std::string& utf8str, S32 len)
+LLWString utf8str_to_wstring(const char* utf8str, size_t len)
 {
 	LLWString wout;
 
@@ -481,13 +463,7 @@ LLWString utf8str_to_wstring(const std::string& utf8str, S32 len)
 	return wout;
 }
 
-LLWString utf8str_to_wstring(const std::string& utf8str)
-{
-	const S32 len = (S32)utf8str.length();
-	return utf8str_to_wstring(utf8str, len);
-}
-
-std::string wstring_to_utf8str(const LLWString& utf32str, S32 len)
+std::string wstring_to_utf8str(const llwchar* utf32str, size_t len)
 {
 	std::string out;
 
@@ -503,20 +479,9 @@ std::string wstring_to_utf8str(const LLWString& utf32str, S32 len)
 	return out;
 }
 
-std::string wstring_to_utf8str(const LLWString& utf32str)
-{
-	const S32 len = (S32)utf32str.length();
-	return wstring_to_utf8str(utf32str, len);
-}
-
-std::string utf16str_to_utf8str(const llutf16string& utf16str)
-{
-	return wstring_to_utf8str(utf16str_to_wstring(utf16str));
-}
-
-std::string utf16str_to_utf8str(const llutf16string& utf16str, S32 len)
+std::string utf16str_to_utf8str(const U16* utf16str, size_t len)
 {
-	return wstring_to_utf8str(utf16str_to_wstring(utf16str, len), len);
+	return wstring_to_utf8str(utf16str_to_wstring(utf16str, len));
 }
 
 std::string utf8str_trim(const std::string& utf8str)
@@ -657,17 +622,16 @@ std::string utf8str_removeCRLF(const std::string& utf8str)
 }
 
 #if LL_WINDOWS
-std::string ll_convert_wide_to_string(const wchar_t* in)
+unsigned int ll_wstring_default_code_page()
 {
-	return ll_convert_wide_to_string(in, CP_UTF8);
+    return CP_UTF8;
 }
 
-std::string ll_convert_wide_to_string(const wchar_t* in, unsigned int code_page)
+std::string ll_convert_wide_to_string(const wchar_t* in, size_t len_in, unsigned int code_page)
 {
 	std::string out;
 	if(in)
 	{
-		int len_in = wcslen(in);
 		int len_out = WideCharToMultiByte(
 			code_page,
 			0,
@@ -699,12 +663,7 @@ std::string ll_convert_wide_to_string(const wchar_t* in, unsigned int code_page)
 	return out;
 }
 
-std::wstring ll_convert_string_to_wide(const std::string& in)
-{
-	return ll_convert_string_to_wide(in, CP_UTF8);
-}
-
-std::wstring ll_convert_string_to_wide(const std::string& in, unsigned int code_page)
+std::wstring ll_convert_string_to_wide(const char* in, size_t len, unsigned int code_page)
 {
 	// From review:
 	// We can preallocate a wide char buffer that is the same length (in wchar_t elements) as the utf8 input,
@@ -716,10 +675,10 @@ std::wstring ll_convert_string_to_wide(const std::string& in, unsigned int code_
 
 	// reserve an output buffer that will be destroyed on exit, with a place
 	// to put NULL terminator
-	std::vector<wchar_t> w_out(in.length() + 1);
+	std::vector<wchar_t> w_out(len + 1);
 
 	memset(&w_out[0], 0, w_out.size());
-	int real_output_str_len = MultiByteToWideChar(code_page, 0, in.c_str(), in.length(),
+	int real_output_str_len = MultiByteToWideChar(code_page, 0, in, len,
 												  &w_out[0], w_out.size() - 1);
 
 	//looks like MultiByteToWideChar didn't add null terminator to converted string, see EXT-4858.
@@ -729,30 +688,32 @@ std::wstring ll_convert_string_to_wide(const std::string& in, unsigned int code_
 	return {&w_out[0]};
 }
 
-LLWString ll_convert_wide_to_wstring(const std::wstring& in)
+LLWString ll_convert_wide_to_wstring(const wchar_t* in, size_t len)
 {
-    // This function, like its converse, is a placeholder, encapsulating a
-    // guilty little hack: the only "official" way nat has found to convert
-    // between std::wstring (16 bits on Windows) and LLWString (UTF-32) is
-    // by using iconv, which we've avoided so far. It kinda sorta works to
-    // just copy individual characters...
-    // The point is that if/when we DO introduce some more official way to
-    // perform such conversions, we should only have to call it here.
-    return { in.begin(), in.end() };
+    // Whether or not std::wstring and llutf16string are distinct types, they
+    // both hold UTF-16LE characters. (See header file comments.) Pretend this
+    // wchar_t* sequence is really a U16* sequence and use the conversion we
+    // define above.
+    return utf16str_to_wstring(reinterpret_cast<const U16*>(in), len);
 }
 
-std::wstring ll_convert_wstring_to_wide(const LLWString& in)
+std::wstring ll_convert_wstring_to_wide(const llwchar* in, size_t len)
 {
-    // See comments in ll_convert_wide_to_wstring()
-    return { in.begin(), in.end() };
+    // first, convert to llutf16string, for which we have a real implementation
+    auto utf16str{ wstring_to_utf16str(in, len) };
+    // then, because each U16 char must be UTF-16LE encoded, pretend the U16*
+    // string pointer is a wchar_t* and instantiate a std::wstring of the same
+    // length.
+    return { reinterpret_cast<const wchar_t*>(utf16str.c_str()), utf16str.length() };
 }
 
 std::string ll_convert_string_to_utf8_string(const std::string& in)
 {
-	auto w_mesg = ll_convert_string_to_wide(in, CP_ACP);
-	std::string out_utf8(ll_convert_wide_to_string(w_mesg.c_str(), CP_UTF8));
-
-	return out_utf8;
+	// If you pass code_page, you must also pass length, otherwise the code
+	// page parameter will be mistaken for length.
+	auto w_mesg = ll_convert_string_to_wide(in, in.length(), CP_ACP);
+	// CP_UTF8 is default -- see ll_wstring_default_code_page() above.
+	return ll_convert_wide_to_string(w_mesg);
 }
 
 namespace
@@ -1356,7 +1317,7 @@ bool LLStringUtil::formatDatetime(std::string& replacement, std::string token,
 template<> 
 S32 LLStringUtil::format(std::string& s, const format_map_t& substitutions)
 {
-	LL_RECORD_BLOCK_TIME(FT_STRING_FORMAT);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STRING;
 	S32 res = 0;
 
 	std::string output;
@@ -1429,7 +1390,7 @@ S32 LLStringUtil::format(std::string& s, const format_map_t& substitutions)
 template<> 
 S32 LLStringUtil::format(std::string& s, const LLSD& substitutions)
 {
-	LL_RECORD_BLOCK_TIME(FT_STRING_FORMAT);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STRING;
 	S32 res = 0;
 
 	if (!substitutions.isMap()) 
diff --git a/indra/llcommon/llstring.h b/indra/llcommon/llstring.h
index 4263122f366f8668f5d76b460cab418292c54a4a..d94f5494808a398b36a6f7792aeecf3a462e1eb5 100644
--- a/indra/llcommon/llstring.h
+++ b/indra/llcommon/llstring.h
@@ -27,9 +27,11 @@
 #ifndef LL_LLSTRING_H
 #define LL_LLSTRING_H
 
+#include <boost/call_traits.hpp>
 #include <boost/optional/optional.hpp>
 #include <string>
 #include <cstdio>
+#include <cwchar>                   // std::wcslen()
 //#include <locale>
 #include <iomanip>
 #include <algorithm>
@@ -527,14 +529,71 @@ struct ll_convert_impl<T, T>
     T operator()(const T& in) const { return in; }
 };
 
+// simple construction from char*
+template<typename T>
+struct ll_convert_impl<T, const typename T::value_type*>
+{
+    T operator()(const typename T::value_type* in) const { return { in }; }
+};
+
 // specialize ll_convert_impl<TO, FROM> to return EXPR
 #define ll_convert_alias(TO, FROM, EXPR)                    \
 template<>                                                  \
 struct ll_convert_impl<TO, FROM>                            \
 {                                                           \
-    TO operator()(const FROM& in) const { return EXPR; }    \
+    /* param_type optimally passes both char* and string */ \
+    TO operator()(typename boost::call_traits<FROM>::param_type in) const { return EXPR; } \
+}
+
+// If all we're doing is copying characters, pass this to ll_convert_alias as
+// EXPR. Since it expands into the 'return EXPR' slot in the ll_convert_impl
+// specialization above, it implies TO{ in.begin(), in.end() }.
+#define LL_CONVERT_COPY_CHARS { in.begin(), in.end() }
+
+// Generic name for strlen() / wcslen() - the default implementation should
+// (!) work with U16 and llwchar, but we don't intend to engage it.
+template <typename CHARTYPE>
+size_t ll_convert_length(const CHARTYPE* zstr)
+{
+    const CHARTYPE* zp;
+    // classic C string scan
+    for (zp = zstr; *zp; ++zp)
+        ;
+    return (zp - zstr);
 }
 
+// specialize where we have a library function; may use intrinsic operations
+template <>
+inline size_t ll_convert_length<wchar_t>(const wchar_t* zstr) { return std::wcslen(zstr); }
+template <>
+inline size_t ll_convert_length<char>   (const char*    zstr) { return std::strlen(zstr); }
+
+// ll_convert_forms() is short for a bunch of boilerplate. It defines
+// longname(const char*, len), longname(const char*), longname(const string&)
+// and longname(const string&, len) so calls written pre-ll_convert() will
+// work. Most of these overloads will be unified once we turn on C++17 and can
+// use std::string_view.
+// It also uses aliasmacro to ensure that both ll_convert<OUTSTR>(const char*)
+// and ll_convert<OUTSTR>(const string&) will work.
+#define ll_convert_forms(aliasmacro, OUTSTR, INSTR, longname)           \
+LL_COMMON_API OUTSTR longname(const INSTR::value_type* in, size_t len); \
+inline auto longname(const INSTR& in, size_t len)                       \
+{                                                                       \
+    return longname(in.c_str(), len);                                   \
+}                                                                       \
+inline auto longname(const INSTR::value_type* in)                       \
+{                                                                       \
+    return longname(in, ll_convert_length(in));                         \
+}                                                                       \
+inline auto longname(const INSTR& in)                                   \
+{                                                                       \
+    return longname(in.c_str(), in.length());                           \
+}                                                                       \
+/* string param */                                                      \
+aliasmacro(OUTSTR, INSTR, longname(in));                                \
+/* char* param */                                                       \
+aliasmacro(OUTSTR, const INSTR::value_type*, longname(in))
+
 // Make the incoming string a utf8 string. Replaces any unknown glyph
 // with the UNKNOWN_CHARACTER. Once any unknown glyph is found, the rest
 // of the data may not be recovered.
@@ -571,63 +630,47 @@ LL_COMMON_API std::string rawstr_to_utf8(const std::string& raw);
 // LL_WCHAR_T_NATIVE.
 typedef std::basic_string<U16> llutf16string;
 
-#if ! defined(LL_WCHAR_T_NATIVE)
-// wchar_t is identical to U16, and std::wstring is identical to llutf16string.
-// Defining an ll_convert alias involving llutf16string would collide with the
-// comparable preferred alias involving std::wstring. (In this scenario, if
-// you pass llutf16string, it will engage the std::wstring specialization.)
-#define ll_convert_u16_alias(TO, FROM, EXPR) // nothing
-#else  // defined(LL_WCHAR_T_NATIVE)
-// wchar_t is a distinct native type, so llutf16string is also a distinct
-// type, and there IS a point to converting separately to/from llutf16string.
-// (But why? Windows APIs are still defined in terms of wchar_t, and
-// in this scenario llutf16string won't work for them!)
-#define ll_convert_u16_alias(TO, FROM, EXPR) ll_convert_alias(TO, FROM, EXPR)
+// Considering wchar_t, llwchar and U16, there are three relevant cases:
+#if LLWCHAR_IS_WCHAR_T         // every which way but Windows
+// llwchar is identical to wchar_t, LLWString is identical to std::wstring.
+// U16 is distinct, llutf16string is distinct (though pretty useless).
+// Given conversions to/from LLWString and to/from llutf16string, conversions
+// involving std::wstring would collide.
+#define ll_convert_wstr_alias(TO, FROM, EXPR) // nothing
+// but we can define conversions involving llutf16string without collisions
+#define  ll_convert_u16_alias(TO, FROM, EXPR) ll_convert_alias(TO, FROM, EXPR)
+
+#elif defined(LL_WCHAR_T_NATIVE)    // Windows, either clang or MS /Zc:wchar_t
+// llwchar (32-bit), wchar_t (16-bit) and U16 are all different types.
+// Conversions to/from LLWString, to/from std::wstring and to/from llutf16string
+// can all be defined.
+#define ll_convert_wstr_alias(TO, FROM, EXPR) ll_convert_alias(TO, FROM, EXPR)
+#define  ll_convert_u16_alias(TO, FROM, EXPR) ll_convert_alias(TO, FROM, EXPR)
+
+#else  // ! LL_WCHAR_T_NATIVE: Windows with MS /Zc:wchar_t-
+// wchar_t is identical to U16, std::wstring is identical to llutf16string.
+// Given conversions to/from LLWString and to/from std::wstring, conversions
+// involving llutf16string would collide.
+#define  ll_convert_u16_alias(TO, FROM, EXPR) // nothing
+// but we can define conversions involving std::wstring without collisions
+#define ll_convert_wstr_alias(TO, FROM, EXPR) ll_convert_alias(TO, FROM, EXPR)
+#endif
+
+ll_convert_forms(ll_convert_u16_alias, LLWString,     llutf16string, utf16str_to_wstring);
+ll_convert_forms(ll_convert_u16_alias, llutf16string, LLWString,     wstring_to_utf16str);
+ll_convert_forms(ll_convert_u16_alias, llutf16string, std::string,   utf8str_to_utf16str);
+ll_convert_forms(ll_convert_alias,     LLWString,     std::string,   utf8str_to_wstring);
 
-#if LL_WINDOWS
-// LL_WCHAR_T_NATIVE is defined on non-Windows systems because, in fact,
-// wchar_t is native. Everywhere but Windows, we use it for llwchar (see
-// stdtypes.h). That makes LLWString identical to std::wstring, so these
-// aliases for std::wstring would collide with those for LLWString. Only
-// define on Windows, where converting between std::wstring and llutf16string
-// means copying chars.
-ll_convert_alias(llutf16string, std::wstring, llutf16string(in.begin(), in.end()));
-ll_convert_alias(std::wstring, llutf16string,  std::wstring(in.begin(), in.end()));
-#endif // LL_WINDOWS
-#endif // defined(LL_WCHAR_T_NATIVE)
-
-LL_COMMON_API LLWString utf16str_to_wstring(const llutf16string &utf16str, S32 len);
-LL_COMMON_API LLWString utf16str_to_wstring(const llutf16string &utf16str);
-ll_convert_u16_alias(LLWString, llutf16string, utf16str_to_wstring(in));
-
-LL_COMMON_API llutf16string wstring_to_utf16str(const LLWString &utf32str, S32 len);
-LL_COMMON_API llutf16string wstring_to_utf16str(const LLWString &utf32str);
-ll_convert_u16_alias(llutf16string, LLWString, wstring_to_utf16str(in));
-
-LL_COMMON_API llutf16string utf8str_to_utf16str ( const std::string& utf8str, S32 len);
-LL_COMMON_API llutf16string utf8str_to_utf16str ( const std::string& utf8str );
-ll_convert_u16_alias(llutf16string, std::string, utf8str_to_utf16str(in));
-
-LL_COMMON_API LLWString utf8str_to_wstring(const std::string &utf8str, S32 len);
-LL_COMMON_API LLWString utf8str_to_wstring(const std::string &utf8str);
 // Same function, better name. JC
 inline LLWString utf8string_to_wstring(const std::string& utf8_string) { return utf8str_to_wstring(utf8_string); }
-// best name of all
-ll_convert_alias(LLWString, std::string, utf8string_to_wstring(in));
 
-//
 LL_COMMON_API S32 wchar_to_utf8chars(llwchar inchar, char* outchars);
 
-LL_COMMON_API std::string wstring_to_utf8str(const LLWString &utf32str, S32 len);
-LL_COMMON_API std::string wstring_to_utf8str(const LLWString &utf32str);
-ll_convert_alias(std::string, LLWString, wstring_to_utf8str(in));
-LL_COMMON_API std::string utf16str_to_utf8str(const llutf16string &utf16str, S32 len);
-LL_COMMON_API std::string utf16str_to_utf8str(const llutf16string &utf16str);
-ll_convert_u16_alias(std::string, llutf16string, utf16str_to_utf8str(in));
+ll_convert_forms(ll_convert_alias,     std::string, LLWString,     wstring_to_utf8str);
+ll_convert_forms(ll_convert_u16_alias, std::string, llutf16string, utf16str_to_utf8str);
 
-#if LL_WINDOWS
+// an older alias for utf16str_to_utf8str(llutf16string)
 inline std::string wstring_to_utf8str(const llutf16string &utf16str) { return utf16str_to_utf8str(utf16str);}
-#endif
 
 // Length of this UTF32 string in bytes when transformed to UTF8
 LL_COMMON_API S32 wstring_utf8_length(const LLWString& wstr); 
@@ -701,42 +744,48 @@ LL_COMMON_API std::string utf8str_removeCRLF(const std::string& utf8str);
 //@{
 
 /**
- * @brief Convert a wide string to std::string
+ * @brief Convert a wide string to/from std::string
+ * Convert a Windows wide string to/from our LLWString
  *
  * This replaces the unsafe W2A macro from ATL.
  */
-LL_COMMON_API std::string ll_convert_wide_to_string(const wchar_t* in, unsigned int code_page);
-LL_COMMON_API std::string ll_convert_wide_to_string(const wchar_t* in); // default CP_UTF8
-inline std::string ll_convert_wide_to_string(const std::wstring& in, unsigned int code_page)
-{
-    return ll_convert_wide_to_string(in.c_str(), code_page);
-}
-inline std::string ll_convert_wide_to_string(const std::wstring& in)
-{
-    return ll_convert_wide_to_string(in.c_str());
-}
-ll_convert_alias(std::string, std::wstring, ll_convert_wide_to_string(in));
-
-/**
- * Converts a string to wide string.
- */
-LL_COMMON_API std::wstring ll_convert_string_to_wide(const std::string& in,
-                                                     unsigned int code_page);
-LL_COMMON_API std::wstring ll_convert_string_to_wide(const std::string& in);
-                                                     // default CP_UTF8
-ll_convert_alias(std::wstring, std::string, ll_convert_string_to_wide(in));
-
-/**
- * Convert a Windows wide string to our LLWString
- */
-LL_COMMON_API LLWString ll_convert_wide_to_wstring(const std::wstring& in);
-ll_convert_alias(LLWString, std::wstring, ll_convert_wide_to_wstring(in));
-
-/**
- * Convert LLWString to Windows wide string
- */
-LL_COMMON_API std::wstring ll_convert_wstring_to_wide(const LLWString& in);
-ll_convert_alias(std::wstring, LLWString, ll_convert_wstring_to_wide(in));
+// Avoid requiring this header to #include the Windows header file declaring
+// our actual default code_page by delegating this function to our .cpp file.
+LL_COMMON_API unsigned int ll_wstring_default_code_page();
+
+// This is like ll_convert_forms(), with the added complexity of a code page
+// parameter that may or may not be passed.
+#define ll_convert_cp_forms(aliasmacro, OUTSTR, INSTR, longname)    \
+/* declare the only nontrivial implementation (in .cpp file) */     \
+LL_COMMON_API OUTSTR longname(                                      \
+    const INSTR::value_type* in,                                    \
+    size_t len,                                                     \
+    unsigned int code_page=ll_wstring_default_code_page());         \
+/* if passed only a char pointer, scan for nul terminator */        \
+inline auto longname(const INSTR::value_type* in)                   \
+{                                                                   \
+    return longname(in, ll_convert_length(in));                     \
+}                                                                   \
+/* if passed string and length, extract its char pointer */         \
+inline auto longname(                                               \
+    const INSTR& in,                                                \
+    size_t len,                                                     \
+    unsigned int code_page=ll_wstring_default_code_page())          \
+{                                                                   \
+    return longname(in.c_str(), len, code_page);                    \
+}                                                                   \
+/* if passed only a string object, no scan, pass known length */    \
+inline auto longname(const INSTR& in)                               \
+{                                                                   \
+    return longname(in.c_str(), in.length());                       \
+}                                                                   \
+aliasmacro(OUTSTR, INSTR, longname(in));                            \
+aliasmacro(OUTSTR, const INSTR::value_type*, longname(in))
+
+ll_convert_cp_forms(ll_convert_wstr_alias, std::string,  std::wstring, ll_convert_wide_to_string);
+ll_convert_cp_forms(ll_convert_wstr_alias, std::wstring, std::string,  ll_convert_string_to_wide);
+   ll_convert_forms(ll_convert_wstr_alias, LLWString,    std::wstring, ll_convert_wide_to_wstring);
+   ll_convert_forms(ll_convert_wstr_alias, std::wstring, LLWString,    ll_convert_wstring_to_wide);
 
 /**
  * Converts incoming string into utf8 string
@@ -1937,4 +1986,14 @@ void LLStringUtilBase<T>::truncate(string_type& string, size_type count)
 	string.resize(count < cur_size ? count : cur_size);
 }
 
+// The good thing about *declaration* macros, vs. usage macros, is that now
+// we're done with them: we don't need them to bleed into the consuming source
+// file.
+#undef ll_convert_alias
+#undef ll_convert_u16_alias
+#undef ll_convert_wstr_alias
+#undef LL_CONVERT_COPY_CHARS
+#undef ll_convert_forms
+#undef ll_convert_cp_forms
+
 #endif  // LL_STRING_H
diff --git a/indra/llcommon/llsys.cpp b/indra/llcommon/llsys.cpp
index 8df818559d60bace84998d88d755c3288893b066..a8b5c7b3a8a8dfd563946f1354e8331e11bae76d 100644
--- a/indra/llcommon/llsys.cpp
+++ b/indra/llcommon/llsys.cpp
@@ -36,7 +36,7 @@
 #ifdef LL_USESYSTEMLIBS
 # include <zlib.h>
 #else
-# include "zlib/zlib.h"
+# include "zlib-ng/zlib.h"
 #endif
 
 #include "llprocessor.h"
@@ -64,6 +64,7 @@ using namespace llsd;
 #   include <psapi.h>               // GetPerformanceInfo() et al.
 #	include <VersionHelpers.h>
 #elif LL_DARWIN
+#   include "llsys_objc.h"
 #	include <errno.h>
 #	include <sys/sysctl.h>
 #	include <sys/utsname.h>
@@ -74,12 +75,6 @@ using namespace llsd;
 #	include <mach/mach_host.h>
 #	include <mach/task.h>
 #	include <mach/task_info.h>
-
-// disable warnings about Gestalt calls being deprecated
-// until Apple get's on the ball and provides an alternative
-//
-#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
-
 #elif LL_LINUX
 #	include <errno.h>
 #	include <sys/utsname.h>
@@ -195,18 +190,6 @@ LLOSInfo::LLOSInfo() :
 		GetSystemInfo(&si); //if it fails get regular system info 
 	//(Warning: If GetSystemInfo it may result in incorrect information in a WOW64 machine, if the kernel fails to load)
 
-	//msdn microsoft finds 32 bit and 64 bit flavors this way..
-	//http://msdn.microsoft.com/en-us/library/ms724429(VS.85).aspx (example code that contains quite a few more flavors
-	//of windows than this code does (in case it is needed for the future)
-	if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) //check for 64 bit
-	{
-		mOSStringSimple += "64-bit ";
-	}
-	else if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL)
-	{
-		mOSStringSimple += "32-bit ";
-	}
-
 	// Try calling GetVersionEx using the OSVERSIONINFOEX structure.
 	OSVERSIONINFOEX osvi;
 	ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
@@ -253,9 +236,21 @@ LLOSInfo::LLOSInfo() :
             // Query WMI's Win32_OperatingSystem for OS string. Slow
             // and likely to return 'compatibility' string.
             // Check presence of dlls/libs or may be their version.
-            mOSStringSimple = "Microsoft Windows 10/11";
+            mOSStringSimple = "Microsoft Windows 10/11 ";
         }
-	}
+    }
+
+    //msdn microsoft finds 32 bit and 64 bit flavors this way..
+    //http://msdn.microsoft.com/en-us/library/ms724429(VS.85).aspx (example code that contains quite a few more flavors
+    //of windows than this code does (in case it is needed for the future)
+    if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) //check for 64 bit
+    {
+        mOSStringSimple += "64-bit ";
+    }
+    else if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL)
+    {
+        mOSStringSimple += "32-bit ";
+    }
 
 	mOSString = mOSStringSimple;
 	if (mBuild > 0)
@@ -278,12 +273,9 @@ LLOSInfo::LLOSInfo() :
 	{
 		const char * DARWIN_PRODUCT_NAME = "Mac OS X";
 		
-		SInt32 major_version, minor_version, bugfix_version;
-		OSErr r1 = Gestalt(gestaltSystemVersionMajor, &major_version);
-		OSErr r2 = Gestalt(gestaltSystemVersionMinor, &minor_version);
-		OSErr r3 = Gestalt(gestaltSystemVersionBugFix, &bugfix_version);
+		S32 major_version, minor_version, bugfix_version = 0;
 
-		if((r1 == noErr) && (r2 == noErr) && (r3 == noErr))
+		if (LLGetDarwinOSInfo(major_version, minor_version, bugfix_version))
 		{
 			mMajorVer = major_version;
 			mMinorVer = minor_version;
@@ -456,6 +448,8 @@ LLOSInfo::LLOSInfo() :
 	dotted_version_string << mMajorVer << "." << mMinorVer << "." << mBuild;
 	mOSVersionString.append(dotted_version_string.str());
 
+	mOSBitness = is64Bit() ? 64 : 32;
+	LL_INFOS("LLOSInfo") << "OS bitness: " << mOSBitness << LL_ENDL;
 }
 
 #ifndef LL_WINDOWS
@@ -511,6 +505,11 @@ const std::string& LLOSInfo::getOSVersionString() const
 	return mOSVersionString;
 }
 
+const S32 LLOSInfo::getOSBitness() const
+{
+	return mOSBitness;
+}
+
 //static
 U32 LLOSInfo::getProcessVirtualSizeKB()
 {
@@ -564,6 +563,25 @@ U32 LLOSInfo::getProcessResidentSizeKB()
 	return resident_size;
 }
 
+//static
+bool LLOSInfo::is64Bit()
+{
+#if LL_WINDOWS
+#if defined(_WIN64)
+    return true;
+#elif defined(_WIN32)
+    // 32-bit viewer may be run on both 32-bit and 64-bit Windows, need to elaborate
+    BOOL f64 = FALSE;
+    return IsWow64Process(GetCurrentProcess(), &f64) && f64;
+#else
+    return false;
+#endif
+#else // ! LL_WINDOWS
+    // we only build a 64-bit mac viewer and currently we don't build for linux at all
+    return true; 
+#endif
+}
+
 LLCPUInfo::LLCPUInfo()
 {
 	std::ostringstream out;
@@ -571,6 +589,11 @@ LLCPUInfo::LLCPUInfo()
 	// proc.WriteInfoTextFile("procInfo.txt");
 	mHasSSE = proc.hasSSE();
 	mHasSSE2 = proc.hasSSE2();
+    mHasSSE3 = proc.hasSSE3();
+    mHasSSE3S = proc.hasSSE3S();
+    mHasSSE41 = proc.hasSSE41();
+    mHasSSE42 = proc.hasSSE42();
+    mHasSSE4a = proc.hasSSE4a();
 	mHasAltivec = proc.hasAltivec();
 	mCPUMHz = (F64)proc.getCPUFrequency();
 	mFamily = proc.getCPUFamilyName();
@@ -583,6 +606,35 @@ LLCPUInfo::LLCPUInfo()
 	}
 	mCPUString = out.str();
 	LLStringUtil::trim(mCPUString);
+
+    if (mHasSSE)
+    {
+        mSSEVersions.append("1");
+    }
+    if (mHasSSE2)
+    {
+        mSSEVersions.append("2");
+    }
+    if (mHasSSE3)
+    {
+        mSSEVersions.append("3");
+    }
+    if (mHasSSE3S)
+    {
+        mSSEVersions.append("3S");
+    }
+    if (mHasSSE41)
+    {
+        mSSEVersions.append("4.1");
+    }
+    if (mHasSSE42)
+    {
+        mSSEVersions.append("4.2");
+    }
+    if (mHasSSE4a)
+    {
+        mSSEVersions.append("4a");
+    }
 }
 
 bool LLCPUInfo::hasAltivec() const
@@ -600,6 +652,31 @@ bool LLCPUInfo::hasSSE2() const
 	return mHasSSE2;
 }
 
+bool LLCPUInfo::hasSSE3() const
+{
+    return mHasSSE3;
+}
+
+bool LLCPUInfo::hasSSE3S() const
+{
+    return mHasSSE3S;
+}
+
+bool LLCPUInfo::hasSSE41() const
+{
+    return mHasSSE41;
+}
+
+bool LLCPUInfo::hasSSE42() const
+{
+    return mHasSSE42;
+}
+
+bool LLCPUInfo::hasSSE4a() const
+{
+    return mHasSSE4a;
+}
+
 F64 LLCPUInfo::getMHz() const
 {
 	return mCPUMHz;
@@ -610,6 +687,11 @@ std::string LLCPUInfo::getCPUString() const
 	return mCPUString;
 }
 
+const LLSD& LLCPUInfo::getSSEVersions() const
+{
+    return mSSEVersions;
+}
+
 void LLCPUInfo::stream(std::ostream& s) const
 {
 	// gather machine information.
@@ -619,6 +701,11 @@ void LLCPUInfo::stream(std::ostream& s) const
 	// CPU's attributes regardless of platform
 	s << "->mHasSSE:     " << (U32)mHasSSE << std::endl;
 	s << "->mHasSSE2:    " << (U32)mHasSSE2 << std::endl;
+    s << "->mHasSSE3:    " << (U32)mHasSSE3 << std::endl;
+    s << "->mHasSSE3S:    " << (U32)mHasSSE3S << std::endl;
+    s << "->mHasSSE41:    " << (U32)mHasSSE41 << std::endl;
+    s << "->mHasSSE42:    " << (U32)mHasSSE42 << std::endl;
+    s << "->mHasSSE4a:    " << (U32)mHasSSE4a << std::endl;
 	s << "->mHasAltivec: " << (U32)mHasAltivec << std::endl;
 	s << "->mCPUMHz:     " << mCPUMHz << std::endl;
 	s << "->mCPUString:  " << mCPUString << std::endl;
@@ -843,6 +930,7 @@ LLSD LLMemoryInfo::getStatsMap() const
 
 LLMemoryInfo& LLMemoryInfo::refresh()
 {
+	LL_PROFILE_ZONE_SCOPED
 	mStatsMap = loadStatsMap();
 
 	LL_DEBUGS("LLMemoryInfo") << "Populated mStatsMap:\n";
@@ -852,11 +940,9 @@ LLMemoryInfo& LLMemoryInfo::refresh()
 	return *this;
 }
 
-static LLTrace::BlockTimerStatHandle FTM_MEMINFO_LOAD_STATS("MemInfo Load Stats");
-
 LLSD LLMemoryInfo::loadStatsMap()
 {
-	LL_RECORD_BLOCK_TIME(FTM_MEMINFO_LOAD_STATS);
+    LL_PROFILE_ZONE_SCOPED;
 
 	// This implementation is derived from stream() code (as of 2011-06-29).
 	Stats stats;
@@ -1316,10 +1402,3 @@ BOOL gzip_file(const std::string& srcfile, const std::string& dstfile)
 	if (dst != NULL) gzclose(dst);
 	return retval;
 }
-
-#if LL_DARWIN
-// disable warnings about Gestalt calls being deprecated
-// until Apple get's on the ball and provides an alternative
-//
-#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
-#endif
diff --git a/indra/llcommon/llsys.h b/indra/llcommon/llsys.h
index 5ab97939b95f709024e59532e5cc1d37aa0ed7da..5ffbf5a732b07a2659350f92310349fd4f319a44 100644
--- a/indra/llcommon/llsys.h
+++ b/indra/llcommon/llsys.h
@@ -51,6 +51,8 @@ class LL_COMMON_API LLOSInfo : public LLSingleton<LLOSInfo>
 	const std::string& getOSStringSimple() const;
 
 	const std::string& getOSVersionString() const;
+
+	const S32 getOSBitness() const;
 	
 	S32 mMajorVer;
 	S32 mMinorVer;
@@ -59,6 +61,7 @@ class LL_COMMON_API LLOSInfo : public LLSingleton<LLOSInfo>
 #ifndef LL_WINDOWS
 	static S32 getMaxOpenFiles();
 #endif
+	static bool is64Bit();
 
 	static U32 getProcessVirtualSizeKB();
 	static U32 getProcessResidentSizeKB();
@@ -66,6 +69,7 @@ class LL_COMMON_API LLOSInfo : public LLSingleton<LLOSInfo>
 	std::string mOSString;
 	std::string mOSStringSimple;
 	std::string mOSVersionString;
+	S32 mOSBitness;
 };
 
 
@@ -76,10 +80,16 @@ class LL_COMMON_API LLCPUInfo
 	void stream(std::ostream& s) const;
 
 	std::string getCPUString() const;
+	const LLSD& getSSEVersions() const;
 
 	bool hasAltivec() const;
 	bool hasSSE() const;
 	bool hasSSE2() const;
+    bool hasSSE3() const;
+    bool hasSSE3S() const;
+    bool hasSSE41() const;
+    bool hasSSE42() const;
+    bool hasSSE4a() const;
 	F64 getMHz() const;
 
 	// Family is "AMD Duron" or "Intel Pentium Pro"
@@ -88,10 +98,16 @@ class LL_COMMON_API LLCPUInfo
 private:
 	bool mHasSSE;
 	bool mHasSSE2;
+    bool mHasSSE3;
+    bool mHasSSE3S;
+    bool mHasSSE41;
+    bool mHasSSE42;
+    bool mHasSSE4a;
 	bool mHasAltivec;
 	F64 mCPUMHz;
 	std::string mFamily;
 	std::string mCPUString;
+    LLSD mSSEVersions;
 };
 
 //=============================================================================
diff --git a/indra/llcommon/llsys_objc.h b/indra/llcommon/llsys_objc.h
new file mode 100644
index 0000000000000000000000000000000000000000..35599a574b7212c9eb00e3be9522283a0a760973
--- /dev/null
+++ b/indra/llcommon/llsys_objc.h
@@ -0,0 +1,33 @@
+/**
+ * @file llsys_objc.h
+ * @brief Header file for llsys_objc.mm
+ *
+ * $LicenseInfo:firstyear=2022&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2022, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLSYS_OBJC_H
+#define LL_LLSYS_OBJC_H
+
+bool LLGetDarwinOSInfo(int &major, int &minor, int &patch);
+
+
+#endif // LL_LLSYS_OBJC_H
diff --git a/indra/llcommon/llsys_objc.mm b/indra/llcommon/llsys_objc.mm
new file mode 100644
index 0000000000000000000000000000000000000000..cdb1e320d5c7924895c1630be6bedbf1c90352bb
--- /dev/null
+++ b/indra/llcommon/llsys_objc.mm
@@ -0,0 +1,64 @@
+/**
+ * @file llsys_objc.mm
+ * @brief obj-c implementation of the system information functions
+ *
+ * $LicenseInfo:firstyear=2022&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2022, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#import "llsys_objc.h"
+#import <AppKit/AppKit.h>
+
+static int intAtStringIndex(NSArray *array, int index)
+{
+    return [(NSString *)[array objectAtIndex:index] integerValue];
+}
+
+bool LLGetDarwinOSInfo(int &major, int &minor, int &patch)
+{
+    if (NSAppKitVersionNumber > NSAppKitVersionNumber10_8)
+    {
+        NSOperatingSystemVersion osVersion = [[NSProcessInfo processInfo] operatingSystemVersion];
+        major = osVersion.majorVersion;
+        minor = osVersion.minorVersion;
+        patch = osVersion.patchVersion;
+    }
+    else
+    {
+        NSString* versionString = [[NSDictionary dictionaryWithContentsOfFile:
+                                    @"/System/Library/CoreServices/SystemVersion.plist"] objectForKey:@"ProductVersion"];
+        NSArray* versions = [versionString componentsSeparatedByString:@"."];
+        NSUInteger count = [versions count];
+        if (count > 0)
+        {
+            major = intAtStringIndex(versions, 0);
+            if (count > 1)
+            {
+                minor = intAtStringIndex(versions, 1);
+                if (count > 2)
+                {
+                    patch = intAtStringIndex(versions, 2);
+                }
+            }
+        }
+    }
+    return true;
+}
diff --git a/indra/llcommon/llthread.cpp b/indra/llcommon/llthread.cpp
index 6d531d842d83c0e091d652112a53ca9a46a5ef21..a807acc56ed86e67451b392cad9077a7b09a6e4c 100644
--- a/indra/llcommon/llthread.cpp
+++ b/indra/llcommon/llthread.cpp
@@ -135,6 +135,8 @@ void LLThread::threadRun()
     set_thread_name(-1, mName.c_str());
 #endif
 
+    LL_PROFILER_SET_THREAD_NAME( mName.c_str() );
+
     // this is the first point at which we're actually running in the new thread
     mID = currentID();
 
@@ -331,6 +333,7 @@ bool LLThread::runCondition(void)
 // Stop thread execution if requested until unpaused.
 void LLThread::checkPause()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
     mDataLock->lock();
 
     // This is in a while loop because the pthread API allows for spurious wakeups.
@@ -362,17 +365,20 @@ void LLThread::setQuitting()
 // static
 LLThread::id_t LLThread::currentID()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
     return std::this_thread::get_id();
 }
 
 // static
 void LLThread::yield()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
     std::this_thread::yield();
 }
 
 void LLThread::wake()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
     mDataLock->lock();
     if(!shouldSleep())
     {
@@ -383,6 +389,7 @@ void LLThread::wake()
 
 void LLThread::wakeLocked()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
     if(!shouldSleep())
     {
         mRunCondition->signal();
@@ -391,11 +398,13 @@ void LLThread::wakeLocked()
 
 void LLThread::lockData()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
     mDataLock->lock();
 }
 
 void LLThread::unlockData()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
     mDataLock->unlock();
 }
 
diff --git a/indra/llcommon/llthreadsafequeue.h b/indra/llcommon/llthreadsafequeue.h
index 26e0d71d314341c4abf3b47231a12dfa3854dd96..68d79cdd12d7d565d824bdd6f981e8dbca8d0b7f 100644
--- a/indra/llcommon/llthreadsafequeue.h
+++ b/indra/llcommon/llthreadsafequeue.h
@@ -1,6 +1,6 @@
 /** 
  * @file llthreadsafequeue.h
- * @brief Base classes for thread, mutex and condition handling.
+ * @brief Queue protected with mutexes for cross-thread use
  *
  * $LicenseInfo:firstyear=2004&license=viewerlgpl$
  * Second Life Viewer Source Code
@@ -27,16 +27,19 @@
 #ifndef LL_LLTHREADSAFEQUEUE_H
 #define LL_LLTHREADSAFEQUEUE_H
 
-#include "llexception.h"
-#include <deque>
-#include <string>
-#include <chrono>
-#include "mutex.h"
 #include "llcoros.h"
 #include LLCOROS_MUTEX_HEADER
 #include <boost/fiber/timed_mutex.hpp>
 #include LLCOROS_CONDVAR_HEADER
+#include "llexception.h"
+#include "mutex.h"
+#include <chrono>
+#include <queue>
+#include <string>
 
+/*****************************************************************************
+*   LLThreadSafeQueue
+*****************************************************************************/
 //
 // A general queue exception.
 //
@@ -66,70 +69,116 @@ class LL_COMMON_API LLThreadSafeQueueInterrupt:
 	}
 };
 
-//
-// Implements a thread safe FIFO.
-//
-template<typename ElementT>
+/**
+ * Implements a thread safe FIFO.
+ */
+// Let the default std::queue default to underlying std::deque. Override if
+// desired.
+template<typename ElementT, typename QueueT=std::queue<ElementT>>
 class LLThreadSafeQueue
 {
 public:
 	typedef ElementT value_type;
-	
-	// If the pool is set to NULL one will be allocated and managed by this
-	// queue.
+
+	// Limiting the number of pending items prevents unbounded growth of the
+	// underlying queue.
 	LLThreadSafeQueue(U32 capacity = 1024);
-	
-	// Add an element to the front of queue (will block if the queue has
-	// reached capacity).
+	virtual ~LLThreadSafeQueue() {}
+
+	// Add an element to the queue (will block if the queue has reached
+	// capacity).
 	//
 	// This call will raise an interrupt error if the queue is closed while
 	// the caller is blocked.
-	void pushFront(ElementT const & element);
-	
-	// Try to add an element to the front of queue without blocking. Returns
+	template <typename T>
+	void push(T&& element);
+	// legacy name
+	void pushFront(ElementT const & element) { return push(element); }
+
+	// Add an element to the queue (will block if the queue has reached
+	// capacity). Return false if the queue is closed before push is possible.
+	template <typename T>
+	bool pushIfOpen(T&& element);
+
+	// Try to add an element to the queue without blocking. Returns
 	// true only if the element was actually added.
-	bool tryPushFront(ElementT const & element);
+	template <typename T>
+	bool tryPush(T&& element);
+	// legacy name
+	bool tryPushFront(ElementT const & element) { return tryPush(element); }
 
-	// Try to add an element to the front of queue, blocking if full but with
-	// timeout. Returns true if the element was added.
+	// Try to add an element to the queue, blocking if full but with timeout
+	// after specified duration. Returns true if the element was added.
 	// There are potentially two different timeouts involved: how long to try
 	// to lock the mutex, versus how long to wait for the queue to stop being
 	// full. Careful settings for each timeout might be orders of magnitude
 	// apart. However, this method conflates them.
+	template <typename Rep, typename Period, typename T>
+	bool tryPushFor(const std::chrono::duration<Rep, Period>& timeout,
+					T&& element);
+	// legacy name
 	template <typename Rep, typename Period>
 	bool tryPushFrontFor(const std::chrono::duration<Rep, Period>& timeout,
-						 ElementT const & element);
+						 ElementT const & element) { return tryPushFor(timeout, element); }
+
+	// Try to add an element to the queue, blocking if full but with
+	// timeout at specified time_point. Returns true if the element was added.
+	template <typename Clock, typename Duration, typename T>
+	bool tryPushUntil(const std::chrono::time_point<Clock, Duration>& until,
+					  T&& element);
+	// no legacy name because this is a newer method
 
-	// Pop the element at the end of the queue (will block if the queue is
+	// Pop the element at the head of the queue (will block if the queue is
 	// empty).
 	//
 	// This call will raise an interrupt error if the queue is closed while
 	// the caller is blocked.
-	ElementT popBack(void);
-	
-	// Pop an element from the end of the queue if there is one available.
+	ElementT pop(void);
+	// legacy name
+	ElementT popBack(void) { return pop(); }
+
+	// Pop an element from the head of the queue if there is one available.
 	// Returns true only if an element was popped.
-	bool tryPopBack(ElementT & element);
-	
+	bool tryPop(ElementT & element);
+	// legacy name
+	bool tryPopBack(ElementT & element) { return tryPop(element); }
+
+	// Pop the element at the head of the queue, blocking if empty, with
+	// timeout after specified duration. Returns true if an element was popped.
+	template <typename Rep, typename Period>
+	bool tryPopFor(const std::chrono::duration<Rep, Period>& timeout, ElementT& element);
+	// no legacy name because this is a newer method
+
+	// Pop the element at the head of the queue, blocking if empty, with
+	// timeout at specified time_point. Returns true if an element was popped.
+	template <typename Clock, typename Duration>
+	bool tryPopUntil(const std::chrono::time_point<Clock, Duration>& until,
+					 ElementT& element);
+	// no legacy name because this is a newer method
+
 	// Returns the size of the queue.
 	size_t size();
 
+    //Returns the capacity of the queue.
+    U32 capacity() { return mCapacity; }
+
 	// closes the queue:
-	// - every subsequent pushFront() call will throw LLThreadSafeQueueInterrupt
-	// - every subsequent tryPushFront() call will return false
-	// - popBack() calls will return normally until the queue is drained, then
-	//   every subsequent popBack() will throw LLThreadSafeQueueInterrupt
-	// - tryPopBack() calls will return normally until the queue is drained,
-	//   then every subsequent tryPopBack() call will return false
+	// - every subsequent push() call will throw LLThreadSafeQueueInterrupt
+	// - every subsequent tryPush() call will return false
+	// - pop() calls will return normally until the queue is drained, then
+	//   every subsequent pop() will throw LLThreadSafeQueueInterrupt
+	// - tryPop() calls will return normally until the queue is drained,
+	//   then every subsequent tryPop() call will return false
 	void close();
 
-	// detect closed state
+	// producer end: are we prevented from pushing any additional items?
 	bool isClosed();
-	// inverse of isClosed()
-	explicit operator bool();
+	// consumer end: are we done, is the queue entirely drained?
+	bool done();
 
-private:
-	std::deque< ElementT > mStorage;
+protected:
+	typedef QueueT queue_type;
+	QueueT mStorage;
 	U32 mCapacity;
 	bool mClosed;
 
@@ -137,37 +186,154 @@ class LLThreadSafeQueue
 	typedef std::unique_lock<decltype(mLock)> lock_t;
 	boost::fibers::condition_variable_any mCapacityCond;
 	boost::fibers::condition_variable_any mEmptyCond;
-};
 
-// LLThreadSafeQueue
-//-----------------------------------------------------------------------------
+	enum pop_result { EMPTY, DONE, WAITING, POPPED };
+	// implementation logic, suitable for passing to tryLockUntil()
+	template <typename Clock, typename Duration>
+	pop_result tryPopUntil_(lock_t& lock,
+							const std::chrono::time_point<Clock, Duration>& until,
+							ElementT& element);
+	// if we're able to lock immediately, do so and run the passed callable,
+	// which must accept lock_t& and return bool
+	template <typename CALLABLE>
+	bool tryLock(CALLABLE&& callable);
+	// if we're able to lock before the passed time_point, do so and run the
+	// passed callable, which must accept lock_t& and return bool
+	template <typename Clock, typename Duration, typename CALLABLE>
+	bool tryLockUntil(const std::chrono::time_point<Clock, Duration>& until,
+					  CALLABLE&& callable);
+	// while lock is locked, really push the passed element, if we can
+	template <typename T>
+	bool push_(lock_t& lock, T&& element);
+	// while lock is locked, really pop the head element, if we can
+	pop_result pop_(lock_t& lock, ElementT& element);
+	// Is the current head element ready to pop? We say yes; subclass can
+	// override as needed.
+	virtual bool canPop(const ElementT& head) const { return true; }
+};
 
-template<typename ElementT>
-LLThreadSafeQueue<ElementT>::LLThreadSafeQueue(U32 capacity) :
+/*****************************************************************************
+*   PriorityQueueAdapter
+*****************************************************************************/
+namespace LL
+{
+    /**
+     * std::priority_queue's API is almost like std::queue, intentionally of
+     * course, but you must access the element about to pop() as top() rather
+     * than as front(). Make an adapter for use with LLThreadSafeQueue.
+     */
+    template <typename T, typename Container=std::vector<T>,
+              typename Compare=std::less<typename Container::value_type>>
+    class PriorityQueueAdapter
+    {
+    public:
+        // publish all the same types
+        typedef std::priority_queue<T, Container, Compare> queue_type;
+        typedef typename queue_type::container_type  container_type;
+        typedef typename queue_type::value_compare   value_compare;
+        typedef typename queue_type::value_type      value_type;
+        typedef typename queue_type::size_type       size_type;
+        typedef typename queue_type::reference       reference;
+        typedef typename queue_type::const_reference const_reference;
+
+        // Although std::queue defines both const and non-const front()
+        // methods, std::priority_queue defines only const top().
+        const_reference front() const { return mQ.top(); }
+        // std::priority_queue has no equivalent to back(), so it's good that
+        // LLThreadSafeQueue doesn't use it.
+
+        // All the rest of these merely forward to the corresponding
+        // queue_type methods.
+        bool empty() const                 { return mQ.empty(); }
+        size_type size() const             { return mQ.size(); }
+        void push(const value_type& value) { mQ.push(value); }
+        void push(value_type&& value)      { mQ.push(std::move(value)); }
+        template <typename... Args>
+        void emplace(Args&&... args)       { mQ.emplace(std::forward<Args>(args)...); }
+        void pop()                         { mQ.pop(); }
+
+    private:
+        queue_type mQ;
+    };
+} // namespace LL
+
+
+/*****************************************************************************
+*   LLThreadSafeQueue implementation
+*****************************************************************************/
+template<typename ElementT, typename QueueT>
+LLThreadSafeQueue<ElementT, QueueT>::LLThreadSafeQueue(U32 capacity) :
     mCapacity(capacity),
     mClosed(false)
 {
 }
 
 
-template<typename ElementT>
-void LLThreadSafeQueue<ElementT>::pushFront(ElementT const & element)
+// if we're able to lock immediately, do so and run the passed callable, which
+// must accept lock_t& and return bool
+template <typename ElementT, typename QueueT>
+template <typename CALLABLE>
+bool LLThreadSafeQueue<ElementT, QueueT>::tryLock(CALLABLE&& callable)
+{
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
+    lock_t lock1(mLock, std::defer_lock);
+    if (!lock1.try_lock())
+        return false;
+
+    return std::forward<CALLABLE>(callable)(lock1);
+}
+
+
+// if we're able to lock before the passed time_point, do so and run the
+// passed callable, which must accept lock_t& and return bool
+template <typename ElementT, typename QueueT>
+template <typename Clock, typename Duration, typename CALLABLE>
+bool LLThreadSafeQueue<ElementT, QueueT>::tryLockUntil(
+    const std::chrono::time_point<Clock, Duration>& until,
+    CALLABLE&& callable)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
+    lock_t lock1(mLock, std::defer_lock);
+    if (!lock1.try_lock_until(until))
+        return false;
+
+    return std::forward<CALLABLE>(callable)(lock1);
+}
+
+
+// while lock is locked, really push the passed element, if we can
+template <typename ElementT, typename QueueT>
+template <typename T>
+bool LLThreadSafeQueue<ElementT, QueueT>::push_(lock_t& lock, T&& element)
+{
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
+    if (mStorage.size() >= mCapacity)
+        return false;
+
+    mStorage.push(std::forward<T>(element));
+    lock.unlock();
+    // now that we've pushed, if somebody's been waiting to pop, signal them
+    mEmptyCond.notify_one();
+    return true;
+}
+
+
+template <typename ElementT, typename QueueT>
+template <typename T>
+bool LLThreadSafeQueue<ElementT, QueueT>::pushIfOpen(T&& element)
+{
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
     lock_t lock1(mLock);
     while (true)
     {
+        // On the producer side, it doesn't matter whether the queue has been
+        // drained or not: the moment either end calls close(), further push()
+        // operations will fail.
         if (mClosed)
-        {
-            LLTHROW(LLThreadSafeQueueInterrupt());
-        }
+            return false;
 
-        if (mStorage.size() < mCapacity)
-        {
-            mStorage.push_front(element);
-            lock1.unlock();
-            mEmptyCond.notify_one();
-            return;
-        }
+        if (push_(lock1, std::forward<T>(element)))
+            return true;
 
         // Storage Full. Wait for signal.
         mCapacityCond.wait(lock1);
@@ -175,142 +341,250 @@ void LLThreadSafeQueue<ElementT>::pushFront(ElementT const & element)
 }
 
 
-template <typename ElementT>
-template <typename Rep, typename Period>
-bool LLThreadSafeQueue<ElementT>::tryPushFrontFor(const std::chrono::duration<Rep, Period>& timeout,
-                                                  ElementT const & element)
+template <typename ElementT, typename QueueT>
+template<typename T>
+void LLThreadSafeQueue<ElementT, QueueT>::push(T&& element)
 {
-    // Convert duration to time_point: passing the same timeout duration to
-    // each of multiple calls is wrong.
-    auto endpoint = std::chrono::steady_clock::now() + timeout;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
+    if (! pushIfOpen(std::forward<T>(element)))
+    {
+        LLTHROW(LLThreadSafeQueueInterrupt());
+    }
+}
 
-    lock_t lock1(mLock, std::defer_lock);
-    if (!lock1.try_lock_until(endpoint))
-        return false;
 
-    while (true)
-    {
-        if (mClosed)
+template<typename ElementT, typename QueueT>
+template<typename T>
+bool LLThreadSafeQueue<ElementT, QueueT>::tryPush(T&& element)
+{
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
+    return tryLock(
+        [this, element=std::move(element)](lock_t& lock)
         {
-            return false;
-        }
+            if (mClosed)
+                return false;
+            return push_(lock, std::move(element));
+        });
+}
 
-        if (mStorage.size() < mCapacity)
-        {
-            mStorage.push_front(element);
-            lock1.unlock();
-            mEmptyCond.notify_one();
-            return true;
-        }
 
-        // Storage Full. Wait for signal.
-        if (LLCoros::cv_status::timeout == mCapacityCond.wait_until(lock1, endpoint))
-        {
-            // timed out -- formally we might recheck both conditions above
-            return false;
-        }
-        // If we didn't time out, we were notified for some reason. Loop back
-        // to check.
-    }
+template <typename ElementT, typename QueueT>
+template <typename Rep, typename Period, typename T>
+bool LLThreadSafeQueue<ElementT, QueueT>::tryPushFor(
+    const std::chrono::duration<Rep, Period>& timeout,
+    T&& element)
+{
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
+    // Convert duration to time_point: passing the same timeout duration to
+    // each of multiple calls is wrong.
+    return tryPushUntil(std::chrono::steady_clock::now() + timeout,
+                        std::forward<T>(element));
 }
 
 
-template<typename ElementT>
-bool LLThreadSafeQueue<ElementT>::tryPushFront(ElementT const & element)
+template <typename ElementT, typename QueueT>
+template <typename Clock, typename Duration, typename T>
+bool LLThreadSafeQueue<ElementT, QueueT>::tryPushUntil(
+    const std::chrono::time_point<Clock, Duration>& until,
+    T&& element)
 {
-    lock_t lock1(mLock, std::defer_lock);
-    if (!lock1.try_lock())
-        return false;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
+    return tryLockUntil(
+        until,
+        [this, until, element=std::move(element)](lock_t& lock)
+        {
+            while (true)
+            {
+                if (mClosed)
+                {
+                    return false;
+                }
+
+                if (push_(lock, std::move(element)))
+                    return true;
+
+                // Storage Full. Wait for signal.
+                if (LLCoros::cv_status::timeout == mCapacityCond.wait_until(lock, until))
+                {
+                    // timed out -- formally we might recheck both conditions above
+                    return false;
+                }
+                // If we didn't time out, we were notified for some reason. Loop back
+                // to check.
+            }
+        });
+}
 
-    if (mClosed)
-        return false;
 
-    if (mStorage.size() >= mCapacity)
-        return false;
+// while lock is locked, really pop the head element, if we can
+template <typename ElementT, typename QueueT>
+typename LLThreadSafeQueue<ElementT, QueueT>::pop_result
+LLThreadSafeQueue<ElementT, QueueT>::pop_(lock_t& lock, ElementT& element)
+{
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
+    // If mStorage is empty, there's no head element.
+    if (mStorage.empty())
+        return mClosed? DONE : EMPTY;
 
-    mStorage.push_front(element);
-    lock1.unlock();
-    mEmptyCond.notify_one();
-    return true;
+    // If there's a head element, pass it to canPop() to see if it's ready to pop. 
+    if (! canPop(mStorage.front()))
+        return WAITING;
+
+    // std::queue::front() is the element about to pop()
+    element = mStorage.front();
+    mStorage.pop();
+    lock.unlock();
+    // now that we've popped, if somebody's been waiting to push, signal them
+    mCapacityCond.notify_one();
+    return POPPED;
 }
 
 
-template<typename ElementT>
-ElementT LLThreadSafeQueue<ElementT>::popBack(void)
+template<typename ElementT, typename QueueT>
+ElementT LLThreadSafeQueue<ElementT, QueueT>::pop(void)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
     lock_t lock1(mLock);
+    ElementT value;
     while (true)
     {
-        if (!mStorage.empty())
-        {
-            ElementT value = mStorage.back();
-            mStorage.pop_back();
-            lock1.unlock();
-            mCapacityCond.notify_one();
-            return value;
-        }
-
-        if (mClosed)
+        // On the consumer side, we always try to pop before checking mClosed
+        // so we can finish draining the queue.
+        pop_result popped = pop_(lock1, value);
+        if (popped == POPPED)
+            return std::move(value);
+
+        // Once the queue is DONE, there will never be any more coming.
+        if (popped == DONE)
         {
             LLTHROW(LLThreadSafeQueueInterrupt());
         }
 
-        // Storage empty. Wait for signal.
+        // If we didn't pop because WAITING, i.e. canPop() returned false,
+        // then even if the producer end has been closed, there's still at
+        // least one item to drain: wait for it. Or we might be EMPTY, with
+        // the queue still open. Either way, wait for signal.
         mEmptyCond.wait(lock1);
     }
 }
 
 
-template<typename ElementT>
-bool LLThreadSafeQueue<ElementT>::tryPopBack(ElementT & element)
+template<typename ElementT, typename QueueT>
+bool LLThreadSafeQueue<ElementT, QueueT>::tryPop(ElementT & element)
 {
-    lock_t lock1(mLock, std::defer_lock);
-    if (!lock1.try_lock())
-        return false;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
+    return tryLock(
+        [this, &element](lock_t& lock)
+        {
+            // conflate EMPTY, DONE, WAITING: tryPop() behavior when the queue
+            // is closed is implemented by simple inability to push any new
+            // elements
+            return pop_(lock, element) == POPPED;
+        });
+}
 
-    // no need to check mClosed: tryPopBack() behavior when the queue is
-    // closed is implemented by simple inability to push any new elements
-    if (mStorage.empty())
-        return false;
 
-    element = mStorage.back();
-    mStorage.pop_back();
-    lock1.unlock();
-    mCapacityCond.notify_one();
-    return true;
+template <typename ElementT, typename QueueT>
+template <typename Rep, typename Period>
+bool LLThreadSafeQueue<ElementT, QueueT>::tryPopFor(
+    const std::chrono::duration<Rep, Period>& timeout,
+    ElementT& element)
+{
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
+    // Convert duration to time_point: passing the same timeout duration to
+    // each of multiple calls is wrong.
+    return tryPopUntil(std::chrono::steady_clock::now() + timeout, element);
 }
 
 
-template<typename ElementT>
-size_t LLThreadSafeQueue<ElementT>::size(void)
+template <typename ElementT, typename QueueT>
+template <typename Clock, typename Duration>
+bool LLThreadSafeQueue<ElementT, QueueT>::tryPopUntil(
+    const std::chrono::time_point<Clock, Duration>& until,
+    ElementT& element)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
+    return tryLockUntil(
+        until,
+        [this, until, &element](lock_t& lock)
+        {
+            // conflate EMPTY, DONE, WAITING
+            return tryPopUntil_(lock, until, element) == POPPED;
+        });
+}
+
+
+// body of tryPopUntil(), called once we have the lock
+template <typename ElementT, typename QueueT>
+template <typename Clock, typename Duration>
+typename LLThreadSafeQueue<ElementT, QueueT>::pop_result
+LLThreadSafeQueue<ElementT, QueueT>::tryPopUntil_(
+    lock_t& lock,
+    const std::chrono::time_point<Clock, Duration>& until,
+    ElementT& element)
+{
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
+    while (true)
+    {
+        pop_result popped = pop_(lock, element);
+        if (popped == POPPED || popped == DONE)
+        {
+            // If we succeeded, great! If we've drained the last item, so be
+            // it. Either way, break the loop and tell caller.
+            return popped;
+        }
+
+        // EMPTY or WAITING: wait for signal.
+        if (LLCoros::cv_status::timeout == mEmptyCond.wait_until(lock, until))
+        {
+            // timed out -- formally we might recheck
+            // as it is, break loop
+            return popped;
+        }
+        // If we didn't time out, we were notified for some reason. Loop back
+        // to check.
+    }
+}
+
+
+template<typename ElementT, typename QueueT>
+size_t LLThreadSafeQueue<ElementT, QueueT>::size(void)
+{
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
     lock_t lock(mLock);
     return mStorage.size();
 }
 
-template<typename ElementT>
-void LLThreadSafeQueue<ElementT>::close()
+
+template<typename ElementT, typename QueueT>
+void LLThreadSafeQueue<ElementT, QueueT>::close()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
     lock_t lock(mLock);
     mClosed = true;
     lock.unlock();
-    // wake up any blocked popBack() calls
+    // wake up any blocked pop() calls
     mEmptyCond.notify_all();
-    // wake up any blocked pushFront() calls
+    // wake up any blocked push() calls
     mCapacityCond.notify_all();
 }
 
-template<typename ElementT>
-bool LLThreadSafeQueue<ElementT>::isClosed()
+
+template<typename ElementT, typename QueueT>
+bool LLThreadSafeQueue<ElementT, QueueT>::isClosed()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
     lock_t lock(mLock);
-    return mClosed && mStorage.size() == 0;
+    return mClosed;
 }
 
-template<typename ElementT>
-LLThreadSafeQueue<ElementT>::operator bool()
+
+template<typename ElementT, typename QueueT>
+bool LLThreadSafeQueue<ElementT, QueueT>::done()
 {
-    return ! isClosed();
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
+    lock_t lock(mLock);
+    return mClosed && mStorage.empty();
 }
 
 #endif
diff --git a/indra/llcommon/lltrace.cpp b/indra/llcommon/lltrace.cpp
index 54079a4689e34db6c5006f14f93d0b8313b0d9c8..f59b207ded2d26634f8a8b266cb4ed7fc0e14637 100644
--- a/indra/llcommon/lltrace.cpp
+++ b/indra/llcommon/lltrace.cpp
@@ -61,6 +61,7 @@ TimeBlockTreeNode::TimeBlockTreeNode()
 
 void TimeBlockTreeNode::setParent( BlockTimerStatHandle* parent )
 {
+    LL_PROFILE_ZONE_SCOPED;
 	llassert_always(parent != mBlock);
 	llassert_always(parent != NULL);
 
diff --git a/indra/llcommon/lltrace.h b/indra/llcommon/lltrace.h
index 0d0cd6f581f1d1832aaa81cd045f1c542575c25a..fcd8753f753004dfca5c7fed93a90b78544ab943 100644
--- a/indra/llcommon/lltrace.h
+++ b/indra/llcommon/lltrace.h
@@ -227,6 +227,7 @@ class MemStatHandle : public StatType<MemAccumulator>
 
 	void setName(const char* name)
 	{
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 		mName = name;
 		setKey(name);
 	}
@@ -234,12 +235,14 @@ class MemStatHandle : public StatType<MemAccumulator>
 	/*virtual*/ const char* getUnitLabel() const { return "KB"; }
 
 	StatType<MemAccumulator::AllocationFacet>& allocations() 
-	{ 
+	{
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 		return static_cast<StatType<MemAccumulator::AllocationFacet>&>(*(StatType<MemAccumulator>*)this);
 	}
 
 	StatType<MemAccumulator::DeallocationFacet>& deallocations() 
-	{ 
+	{
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 		return static_cast<StatType<MemAccumulator::DeallocationFacet>&>(*(StatType<MemAccumulator>*)this);
 	}
 };
@@ -261,6 +264,7 @@ struct MeasureMem<T, typename T::mem_trackable_tag_t, IS_BYTES>
 {
 	static size_t measureFootprint(const T& value)
 	{
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 		return sizeof(T) + value.getMemFootprint();
 	}
 };
@@ -270,6 +274,7 @@ struct MeasureMem<T, IS_MEM_TRACKABLE, typename T::is_unit_t>
 {
 	static size_t measureFootprint(const T& value)
 	{
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 		return U32Bytes(value).value();
 	}
 };
@@ -279,6 +284,7 @@ struct MeasureMem<T*, IS_MEM_TRACKABLE, IS_BYTES>
 {
 	static size_t measureFootprint(const T* value)
 	{
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 		if (!value)
 		{
 			return 0;
@@ -323,6 +329,7 @@ struct MeasureMem<std::basic_string<T>, IS_MEM_TRACKABLE, IS_BYTES>
 {
 	static size_t measureFootprint(const std::basic_string<T>& value)
 	{
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 		return value.capacity() * sizeof(T);
 	}
 };
@@ -331,6 +338,7 @@ struct MeasureMem<std::basic_string<T>, IS_MEM_TRACKABLE, IS_BYTES>
 template<typename T>
 inline void claim_alloc(MemStatHandle& measurement, const T& value)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 #if LL_TRACE_ENABLED
 	S32 size = MeasureMem<T>::measureFootprint(value);
 	if(size == 0) return;
@@ -343,6 +351,7 @@ inline void claim_alloc(MemStatHandle& measurement, const T& value)
 template<typename T>
 inline void disclaim_alloc(MemStatHandle& measurement, const T& value)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 #if LL_TRACE_ENABLED
 	S32 size = MeasureMem<T>::measureFootprint(value);
 	if(size == 0) return;
@@ -352,141 +361,6 @@ inline void disclaim_alloc(MemStatHandle& measurement, const T& value)
 #endif
 }
 
-template<typename DERIVED, size_t ALIGNMENT = LL_DEFAULT_HEAP_ALIGN>
-class MemTrackableNonVirtual
-{
-public:
-	typedef void mem_trackable_tag_t;
-
-	MemTrackableNonVirtual(const char* name)
-#if LL_TRACE_ENABLED
-	:	mMemFootprint(0)
-#endif
-	{
-#if LL_TRACE_ENABLED
-		static bool name_initialized = false;
-		if (!name_initialized)
-		{
-			name_initialized = true;
-			sMemStat.setName(name);
-		}
-#endif
-	}
-
-#if LL_TRACE_ENABLED
-	~MemTrackableNonVirtual()
-	{
-		disclaimMem(mMemFootprint);
-	}
-
-	static MemStatHandle& getMemStatHandle()
-	{
-		return sMemStat;
-	}
-
-	S32 getMemFootprint() const	{ return mMemFootprint; }
-#endif
-
-	void* operator new(size_t size) 
-	{
-#if LL_TRACE_ENABLED
-		claim_alloc(sMemStat, size);
-#endif
-		return ll_aligned_malloc<ALIGNMENT>(size);
-	}
-
-	template<int CUSTOM_ALIGNMENT>
-	static void* aligned_new(size_t size)
-	{
-#if LL_TRACE_ENABLED
-		claim_alloc(sMemStat, size);
-#endif
-		return ll_aligned_malloc<CUSTOM_ALIGNMENT>(size);
-	}
-
-	void operator delete(void* ptr, size_t size)
-	{
-#if LL_TRACE_ENABLED
-		disclaim_alloc(sMemStat, size);
-#endif
-		ll_aligned_free<ALIGNMENT>(ptr);
-	}
-
-	template<int CUSTOM_ALIGNMENT>
-	static void aligned_delete(void* ptr, size_t size)
-	{
-#if LL_TRACE_ENABLED
-		disclaim_alloc(sMemStat, size);
-#endif
-		ll_aligned_free<CUSTOM_ALIGNMENT>(ptr);
-	}
-
-	void* operator new [](size_t size)
-	{
-#if LL_TRACE_ENABLED
-		claim_alloc(sMemStat, size);
-#endif
-		return ll_aligned_malloc<ALIGNMENT>(size);
-	}
-
-	void operator delete[](void* ptr, size_t size)
-	{
-#if LL_TRACE_ENABLED
-		disclaim_alloc(sMemStat, size);
-#endif
-		ll_aligned_free<ALIGNMENT>(ptr);
-	}
-
-	// claim memory associated with other objects/data as our own, adding to our calculated footprint
-	template<typename CLAIM_T>
-	void claimMem(const CLAIM_T& value) const
-	{
-#if LL_TRACE_ENABLED
-		S32 size = MeasureMem<CLAIM_T>::measureFootprint(value);
-		claim_alloc(sMemStat, size);
-		mMemFootprint += size;
-#endif
-	}
-
-	// remove memory we had claimed from our calculated footprint
-	template<typename CLAIM_T>
-	void disclaimMem(const CLAIM_T& value) const
-	{
-#if LL_TRACE_ENABLED
-		S32 size = MeasureMem<CLAIM_T>::measureFootprint(value);
-		disclaim_alloc(sMemStat, size);
-		mMemFootprint -= size;
-#endif
-	}
-
-private:
-#if LL_TRACE_ENABLED
-	// use signed values so that we can temporarily go negative
-	// and reconcile in destructor
-	// NB: this assumes that no single class is responsible for > 2GB of allocations
-	mutable S32 mMemFootprint;
-	
-	static	MemStatHandle	sMemStat;
-#endif
-
-};
-
-#if LL_TRACE_ENABLED
-template<typename DERIVED, size_t ALIGNMENT>
-MemStatHandle MemTrackableNonVirtual<DERIVED, ALIGNMENT>::sMemStat(typeid(MemTrackableNonVirtual<DERIVED, ALIGNMENT>).name());
-#endif
-
-template<typename DERIVED, size_t ALIGNMENT = LL_DEFAULT_HEAP_ALIGN>
-class MemTrackable : public MemTrackableNonVirtual<DERIVED, ALIGNMENT>
-{
-public:
-	MemTrackable(const char* name)
-	:	MemTrackableNonVirtual<DERIVED, ALIGNMENT>(name)
-	{}
-
-	virtual ~MemTrackable()
-	{}
-};
 }
 
 #endif // LL_LLTRACE_H
diff --git a/indra/llcommon/lltraceaccumulators.cpp b/indra/llcommon/lltraceaccumulators.cpp
index b1c23c6fb7a35dfafb800f9d05b29f134ff9cfe2..34299f5a29a3f55188c5f7b465d0b1c4fdcb79db 100644
--- a/indra/llcommon/lltraceaccumulators.cpp
+++ b/indra/llcommon/lltraceaccumulators.cpp
@@ -41,6 +41,7 @@ extern MemStatHandle gTraceMemStat;
 
 AccumulatorBufferGroup::AccumulatorBufferGroup() 
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	claim_alloc(gTraceMemStat, mCounts.capacity() * sizeof(CountAccumulator));
 	claim_alloc(gTraceMemStat, mSamples.capacity() * sizeof(SampleAccumulator));
 	claim_alloc(gTraceMemStat, mEvents.capacity() * sizeof(EventAccumulator));
@@ -55,6 +56,7 @@ AccumulatorBufferGroup::AccumulatorBufferGroup(const AccumulatorBufferGroup& oth
 	mStackTimers(other.mStackTimers),
 	mMemStats(other.mMemStats)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	claim_alloc(gTraceMemStat, mCounts.capacity() * sizeof(CountAccumulator));
 	claim_alloc(gTraceMemStat, mSamples.capacity() * sizeof(SampleAccumulator));
 	claim_alloc(gTraceMemStat, mEvents.capacity() * sizeof(EventAccumulator));
@@ -64,6 +66,7 @@ AccumulatorBufferGroup::AccumulatorBufferGroup(const AccumulatorBufferGroup& oth
 
 AccumulatorBufferGroup::~AccumulatorBufferGroup()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	disclaim_alloc(gTraceMemStat, mCounts.capacity() * sizeof(CountAccumulator));
 	disclaim_alloc(gTraceMemStat, mSamples.capacity() * sizeof(SampleAccumulator));
 	disclaim_alloc(gTraceMemStat, mEvents.capacity() * sizeof(EventAccumulator));
@@ -73,6 +76,7 @@ AccumulatorBufferGroup::~AccumulatorBufferGroup()
 
 void AccumulatorBufferGroup::handOffTo(AccumulatorBufferGroup& other)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	other.mCounts.reset(&mCounts);
 	other.mSamples.reset(&mSamples);
 	other.mEvents.reset(&mEvents);
@@ -82,6 +86,7 @@ void AccumulatorBufferGroup::handOffTo(AccumulatorBufferGroup& other)
 
 void AccumulatorBufferGroup::makeCurrent()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	mCounts.makeCurrent();
 	mSamples.makeCurrent();
 	mEvents.makeCurrent();
@@ -104,6 +109,7 @@ void AccumulatorBufferGroup::makeCurrent()
 //static
 void AccumulatorBufferGroup::clearCurrent()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	AccumulatorBuffer<CountAccumulator>::clearCurrent();	
 	AccumulatorBuffer<SampleAccumulator>::clearCurrent();
 	AccumulatorBuffer<EventAccumulator>::clearCurrent();
@@ -118,6 +124,7 @@ bool AccumulatorBufferGroup::isCurrent() const
 
 void AccumulatorBufferGroup::append( const AccumulatorBufferGroup& other )
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	mCounts.addSamples(other.mCounts, SEQUENTIAL);
 	mSamples.addSamples(other.mSamples, SEQUENTIAL);
 	mEvents.addSamples(other.mEvents, SEQUENTIAL);
@@ -127,6 +134,7 @@ void AccumulatorBufferGroup::append( const AccumulatorBufferGroup& other )
 
 void AccumulatorBufferGroup::merge( const AccumulatorBufferGroup& other)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	mCounts.addSamples(other.mCounts, NON_SEQUENTIAL);
 	mSamples.addSamples(other.mSamples, NON_SEQUENTIAL);
 	mEvents.addSamples(other.mEvents, NON_SEQUENTIAL);
@@ -137,6 +145,7 @@ void AccumulatorBufferGroup::merge( const AccumulatorBufferGroup& other)
 
 void AccumulatorBufferGroup::reset(AccumulatorBufferGroup* other)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	mCounts.reset(other ? &other->mCounts : NULL);
 	mSamples.reset(other ? &other->mSamples : NULL);
 	mEvents.reset(other ? &other->mEvents : NULL);
@@ -146,6 +155,7 @@ void AccumulatorBufferGroup::reset(AccumulatorBufferGroup* other)
 
 void AccumulatorBufferGroup::sync()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	if (isCurrent())
 	{
 		F64SecondsImplicit time_stamp = LLTimer::getTotalSeconds();
@@ -190,7 +200,7 @@ F64 SampleAccumulator::mergeSumsOfSquares(const SampleAccumulator& a, const Samp
 
 void SampleAccumulator::addSamples( const SampleAccumulator& other, EBufferAppendType append_type )
 {
-	if (append_type == NON_SEQUENTIAL)
+    if (append_type == NON_SEQUENTIAL)
 	{
 		return;
 	}
@@ -289,7 +299,7 @@ void EventAccumulator::addSamples( const EventAccumulator& other, EBufferAppendT
 
 void EventAccumulator::reset( const EventAccumulator* other )
 {
-	mNumSamples = 0;
+    mNumSamples = 0;
 	mSum = 0;
 	mMin = F32(NaN);
 	mMax = F32(NaN);
diff --git a/indra/llcommon/lltraceaccumulators.h b/indra/llcommon/lltraceaccumulators.h
index 8eb5338a2a92a65d3efe9f3685e720c289f2dd30..7267a44300cd605eef702d68b2f5c04e76d718b4 100644
--- a/indra/llcommon/lltraceaccumulators.h
+++ b/indra/llcommon/lltraceaccumulators.h
@@ -66,6 +66,7 @@ namespace LLTrace
 			: mStorageSize(0),
 			mStorage(NULL)
 		{
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			const AccumulatorBuffer& other = *getDefaultBuffer();
 			resize(sNextStorageSlot);
 			for (S32 i = 0; i < sNextStorageSlot; i++)
@@ -76,6 +77,7 @@ namespace LLTrace
 
 		~AccumulatorBuffer()
 		{
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			if (isCurrent())
 			{
 				LLThreadLocalSingletonPointer<ACCUMULATOR>::setInstance(NULL);
@@ -98,6 +100,7 @@ namespace LLTrace
 			: mStorageSize(0),
 			mStorage(NULL)
 		{
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			resize(sNextStorageSlot);
 			for (S32 i = 0; i < sNextStorageSlot; i++)
 			{
@@ -107,6 +110,7 @@ namespace LLTrace
 
 		void addSamples(const AccumulatorBuffer<ACCUMULATOR>& other, EBufferAppendType append_type)
 		{
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			llassert(mStorageSize >= sNextStorageSlot && other.mStorageSize >= sNextStorageSlot);
 			for (size_t i = 0; i < sNextStorageSlot; i++)
 			{
@@ -116,6 +120,7 @@ namespace LLTrace
 
 		void copyFrom(const AccumulatorBuffer<ACCUMULATOR>& other)
 		{
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			llassert(mStorageSize >= sNextStorageSlot && other.mStorageSize >= sNextStorageSlot);
 			for (size_t i = 0; i < sNextStorageSlot; i++)
 			{
@@ -125,6 +130,7 @@ namespace LLTrace
 
 		void reset(const AccumulatorBuffer<ACCUMULATOR>* other = NULL)
 		{
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			llassert(mStorageSize >= sNextStorageSlot);
 			for (size_t i = 0; i < sNextStorageSlot; i++)
 			{
@@ -134,6 +140,7 @@ namespace LLTrace
 
 		void sync(F64SecondsImplicit time_stamp)
 		{
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			llassert(mStorageSize >= sNextStorageSlot);
 			for (size_t i = 0; i < sNextStorageSlot; i++)
 			{
@@ -153,12 +160,13 @@ namespace LLTrace
 
 		static void clearCurrent()
 		{
-			LLThreadLocalSingletonPointer<ACCUMULATOR>::setInstance(NULL);
+            LLThreadLocalSingletonPointer<ACCUMULATOR>::setInstance(NULL);
 		}
 
 		// NOTE: this is not thread-safe.  We assume that slots are reserved in the main thread before any child threads are spawned
 		size_t reserveSlot()
 		{
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			size_t next_slot = sNextStorageSlot++;
 			if (next_slot >= mStorageSize)
 			{
@@ -172,6 +180,7 @@ namespace LLTrace
 
 		void resize(size_t new_size)
 		{
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			if (new_size <= mStorageSize) return;
 
 			ACCUMULATOR* old_storage = mStorage;
@@ -212,6 +221,7 @@ namespace LLTrace
 
 		static self_t* getDefaultBuffer()
 		{
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			static bool sInitialized = false;
 			if (!sInitialized)
 			{
@@ -326,6 +336,7 @@ namespace LLTrace
 
 		void sample(F64 value)
 		{
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			F64SecondsImplicit time_stamp = LLTimer::getTotalSeconds();
 
 			// store effect of last value
@@ -444,9 +455,9 @@ namespace LLTrace
 		S32	mNumSamples;
 	};
 
-	class TimeBlockAccumulator
+	class alignas(32) TimeBlockAccumulator
 	{
-	public:
+    public:
 		typedef F64Seconds value_t;
 		static F64Seconds getDefaultValue() { return F64Seconds(0); }
 
@@ -539,6 +550,7 @@ namespace LLTrace
 
 		void addSamples(const MemAccumulator& other, EBufferAppendType append_type)
 		{
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			mAllocations.addSamples(other.mAllocations, append_type);
 			mDeallocations.addSamples(other.mDeallocations, append_type);
 
@@ -557,6 +569,7 @@ namespace LLTrace
 
 		void reset(const MemAccumulator* other)
 		{
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			mSize.reset(other ? &other->mSize : NULL);
 			mAllocations.reset(other ? &other->mAllocations : NULL);
 			mDeallocations.reset(other ? &other->mDeallocations : NULL);
diff --git a/indra/llcommon/lltracerecording.cpp b/indra/llcommon/lltracerecording.cpp
index 3094b627a2f35b7ecfa8d30661196a6fbd7b4304..1613af1dcf5900dab2f0f0517ed8be86a310a942 100644
--- a/indra/llcommon/lltracerecording.cpp
+++ b/indra/llcommon/lltracerecording.cpp
@@ -50,6 +50,7 @@ Recording::Recording(EPlayState state)
 :	mElapsedSeconds(0),
 	mActiveBuffers(NULL)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	claim_alloc(gTraceMemStat, this);
 	mBuffers = new AccumulatorBufferGroup();
 	claim_alloc(gTraceMemStat, mBuffers);
@@ -59,12 +60,14 @@ Recording::Recording(EPlayState state)
 Recording::Recording( const Recording& other )
 :	mActiveBuffers(NULL)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	claim_alloc(gTraceMemStat, this);
 	*this = other;
 }
 
 Recording& Recording::operator = (const Recording& other)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	// this will allow us to seamlessly start without affecting any data we've acquired from other
 	setPlayState(PAUSED);
 
@@ -85,6 +88,7 @@ Recording& Recording::operator = (const Recording& other)
 
 Recording::~Recording()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	disclaim_alloc(gTraceMemStat, this);
 	disclaim_alloc(gTraceMemStat, mBuffers);
 
@@ -103,6 +107,7 @@ void Recording::update()
 #if LL_TRACE_ENABLED
 	if (isStarted())
 	{
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 		mElapsedSeconds += mSamplingTimer.getElapsedTimeF64();
 
 		// must have 
@@ -123,6 +128,7 @@ void Recording::update()
 
 void Recording::handleReset()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 #if LL_TRACE_ENABLED
 	mBuffers.write()->reset();
 
@@ -133,6 +139,7 @@ void Recording::handleReset()
 
 void Recording::handleStart()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 #if LL_TRACE_ENABLED
 	mSamplingTimer.reset();
 	mBuffers.setStayUnique(true);
@@ -144,6 +151,7 @@ void Recording::handleStart()
 
 void Recording::handleStop()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 #if LL_TRACE_ENABLED
 	mElapsedSeconds += mSamplingTimer.getElapsedTimeF64();
 	// must have thread recorder running on this thread
@@ -273,7 +281,7 @@ F64Kilobytes Recording::getMean(const StatType<MemAccumulator>& stat)
 
 F64Kilobytes Recording::getMax(const StatType<MemAccumulator>& stat)
 {
-	update();
+    update();
 	const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()];
 	const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL;
 	return F64Bytes(llmax(accumulator.mSize.getMax(), active_accumulator && active_accumulator->mSize.hasValue() ? active_accumulator->mSize.getMax() : F32_MIN));
@@ -281,7 +289,7 @@ F64Kilobytes Recording::getMax(const StatType<MemAccumulator>& stat)
 
 F64Kilobytes Recording::getStandardDeviation(const StatType<MemAccumulator>& stat)
 {
-	update();
+    update();
 	const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()];
 	const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL;
 	if (active_accumulator && active_accumulator->hasValue())
@@ -297,7 +305,7 @@ F64Kilobytes Recording::getStandardDeviation(const StatType<MemAccumulator>& sta
 
 F64Kilobytes Recording::getLastValue(const StatType<MemAccumulator>& stat)
 {
-	update();
+    update();
 	const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()];
 	const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL;
 	return F64Bytes(active_accumulator ? active_accumulator->mSize.getLastValue() : accumulator.mSize.getLastValue());
@@ -305,7 +313,7 @@ F64Kilobytes Recording::getLastValue(const StatType<MemAccumulator>& stat)
 
 bool Recording::hasValue(const StatType<MemAccumulator::AllocationFacet>& stat)
 {
-	update();
+    update();
 	const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()];
 	const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL;
 	return accumulator.mAllocations.hasValue() || (active_accumulator ? active_accumulator->mAllocations.hasValue() : false);
@@ -313,7 +321,7 @@ bool Recording::hasValue(const StatType<MemAccumulator::AllocationFacet>& stat)
 
 F64Kilobytes Recording::getSum(const StatType<MemAccumulator::AllocationFacet>& stat)
 {
-	update();
+    update();
 	const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()];
 	const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL;
 	return F64Bytes(accumulator.mAllocations.getSum() + (active_accumulator ? active_accumulator->mAllocations.getSum() : 0));
@@ -321,7 +329,7 @@ F64Kilobytes Recording::getSum(const StatType<MemAccumulator::AllocationFacet>&
 
 F64Kilobytes Recording::getPerSec(const StatType<MemAccumulator::AllocationFacet>& stat)
 {
-	update();
+    update();
 	const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()];
 	const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL;
 	return F64Bytes((accumulator.mAllocations.getSum() + (active_accumulator ? active_accumulator->mAllocations.getSum() : 0)) / mElapsedSeconds.value());
@@ -329,7 +337,7 @@ F64Kilobytes Recording::getPerSec(const StatType<MemAccumulator::AllocationFacet
 
 S32 Recording::getSampleCount(const StatType<MemAccumulator::AllocationFacet>& stat)
 {
-	update();
+    update();
 	const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()];
 	const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL;
 	return accumulator.mAllocations.getSampleCount() + (active_accumulator ? active_accumulator->mAllocations.getSampleCount() : 0);
@@ -337,7 +345,7 @@ S32 Recording::getSampleCount(const StatType<MemAccumulator::AllocationFacet>& s
 
 bool Recording::hasValue(const StatType<MemAccumulator::DeallocationFacet>& stat)
 {
-	update();
+    update();
 	const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()];
 	const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL;
 	return accumulator.mDeallocations.hasValue() || (active_accumulator ? active_accumulator->mDeallocations.hasValue() : false);
@@ -346,7 +354,7 @@ bool Recording::hasValue(const StatType<MemAccumulator::DeallocationFacet>& stat
 
 F64Kilobytes Recording::getSum(const StatType<MemAccumulator::DeallocationFacet>& stat)
 {
-	update();
+    update();
 	const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()];
 	const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL;
 	return F64Bytes(accumulator.mDeallocations.getSum() + (active_accumulator ? active_accumulator->mDeallocations.getSum() : 0));
@@ -354,7 +362,7 @@ F64Kilobytes Recording::getSum(const StatType<MemAccumulator::DeallocationFacet>
 
 F64Kilobytes Recording::getPerSec(const StatType<MemAccumulator::DeallocationFacet>& stat)
 {
-	update();
+    update();
 	const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()];
 	const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL;
 	return F64Bytes((accumulator.mDeallocations.getSum() + (active_accumulator ? active_accumulator->mDeallocations.getSum() : 0)) / mElapsedSeconds.value());
@@ -362,7 +370,7 @@ F64Kilobytes Recording::getPerSec(const StatType<MemAccumulator::DeallocationFac
 
 S32 Recording::getSampleCount(const StatType<MemAccumulator::DeallocationFacet>& stat)
 {
-	update();
+    update();
 	const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()];
 	const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL;
 	return accumulator.mDeallocations.getSampleCount() + (active_accumulator ? active_accumulator->mDeallocations.getSampleCount() : 0);
@@ -370,7 +378,7 @@ S32 Recording::getSampleCount(const StatType<MemAccumulator::DeallocationFacet>&
 
 bool Recording::hasValue(const StatType<CountAccumulator>& stat)
 {
-	update();
+    update();
 	const CountAccumulator& accumulator = mBuffers->mCounts[stat.getIndex()];
 	const CountAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mCounts[stat.getIndex()] : NULL;
 	return accumulator.hasValue() || (active_accumulator ? active_accumulator->hasValue() : false);
@@ -378,7 +386,7 @@ bool Recording::hasValue(const StatType<CountAccumulator>& stat)
 
 F64 Recording::getSum(const StatType<CountAccumulator>& stat)
 {
-	update();
+    update();
 	const CountAccumulator& accumulator = mBuffers->mCounts[stat.getIndex()];
 	const CountAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mCounts[stat.getIndex()] : NULL;
 	return accumulator.getSum() + (active_accumulator ? active_accumulator->getSum() : 0);
@@ -386,7 +394,7 @@ F64 Recording::getSum(const StatType<CountAccumulator>& stat)
 
 F64 Recording::getPerSec( const StatType<CountAccumulator>& stat )
 {
-	update();
+    update();
 	const CountAccumulator& accumulator = mBuffers->mCounts[stat.getIndex()];
 	const CountAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mCounts[stat.getIndex()] : NULL;
 	F64 sum = accumulator.getSum() + (active_accumulator ? active_accumulator->getSum() : 0);
@@ -395,7 +403,7 @@ F64 Recording::getPerSec( const StatType<CountAccumulator>& stat )
 
 S32 Recording::getSampleCount( const StatType<CountAccumulator>& stat )
 {
-	update();
+    update();
 	const CountAccumulator& accumulator = mBuffers->mCounts[stat.getIndex()];
 	const CountAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mCounts[stat.getIndex()] : NULL;
 	return accumulator.getSampleCount() + (active_accumulator ? active_accumulator->getSampleCount() : 0);
@@ -403,7 +411,7 @@ S32 Recording::getSampleCount( const StatType<CountAccumulator>& stat )
 
 bool Recording::hasValue(const StatType<SampleAccumulator>& stat)
 {
-	update();
+    update();
 	const SampleAccumulator& accumulator = mBuffers->mSamples[stat.getIndex()];
 	const SampleAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mSamples[stat.getIndex()] : NULL;
 	return accumulator.hasValue() || (active_accumulator && active_accumulator->hasValue());
@@ -411,7 +419,7 @@ bool Recording::hasValue(const StatType<SampleAccumulator>& stat)
 
 F64 Recording::getMin( const StatType<SampleAccumulator>& stat )
 {
-	update();
+    update();
 	const SampleAccumulator& accumulator = mBuffers->mSamples[stat.getIndex()];
 	const SampleAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mSamples[stat.getIndex()] : NULL;
 	return llmin(accumulator.getMin(), active_accumulator && active_accumulator->hasValue() ? active_accumulator->getMin() : F32_MAX);
@@ -419,7 +427,7 @@ F64 Recording::getMin( const StatType<SampleAccumulator>& stat )
 
 F64 Recording::getMax( const StatType<SampleAccumulator>& stat )
 {
-	update();
+    update();
 	const SampleAccumulator& accumulator = mBuffers->mSamples[stat.getIndex()];
 	const SampleAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mSamples[stat.getIndex()] : NULL;
 	return llmax(accumulator.getMax(), active_accumulator && active_accumulator->hasValue() ? active_accumulator->getMax() : F32_MIN);
@@ -427,7 +435,7 @@ F64 Recording::getMax( const StatType<SampleAccumulator>& stat )
 
 F64 Recording::getMean( const StatType<SampleAccumulator>& stat )
 {
-	update();
+    update();
 	const SampleAccumulator& accumulator = mBuffers->mSamples[stat.getIndex()];
 	const SampleAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mSamples[stat.getIndex()] : NULL;
 	if (active_accumulator && active_accumulator->hasValue())
@@ -448,7 +456,7 @@ F64 Recording::getMean( const StatType<SampleAccumulator>& stat )
 
 F64 Recording::getStandardDeviation( const StatType<SampleAccumulator>& stat )
 {
-	update();
+    update();
 	const SampleAccumulator& accumulator = mBuffers->mSamples[stat.getIndex()];
 	const SampleAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mSamples[stat.getIndex()] : NULL;
 
@@ -465,7 +473,7 @@ F64 Recording::getStandardDeviation( const StatType<SampleAccumulator>& stat )
 
 F64 Recording::getLastValue( const StatType<SampleAccumulator>& stat )
 {
-	update();
+    update();
 	const SampleAccumulator& accumulator = mBuffers->mSamples[stat.getIndex()];
 	const SampleAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mSamples[stat.getIndex()] : NULL;
 	return (active_accumulator && active_accumulator->hasValue() ? active_accumulator->getLastValue() : accumulator.getLastValue());
@@ -473,7 +481,7 @@ F64 Recording::getLastValue( const StatType<SampleAccumulator>& stat )
 
 S32 Recording::getSampleCount( const StatType<SampleAccumulator>& stat )
 {
-	update();
+    update();
 	const SampleAccumulator& accumulator = mBuffers->mSamples[stat.getIndex()];
 	const SampleAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mSamples[stat.getIndex()] : NULL;
 	return accumulator.getSampleCount() + (active_accumulator && active_accumulator->hasValue() ? active_accumulator->getSampleCount() : 0);
@@ -481,7 +489,7 @@ S32 Recording::getSampleCount( const StatType<SampleAccumulator>& stat )
 
 bool Recording::hasValue(const StatType<EventAccumulator>& stat)
 {
-	update();
+    update();
 	const EventAccumulator& accumulator = mBuffers->mEvents[stat.getIndex()];
 	const EventAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mEvents[stat.getIndex()] : NULL;
 	return accumulator.hasValue() || (active_accumulator && active_accumulator->hasValue());
@@ -489,7 +497,7 @@ bool Recording::hasValue(const StatType<EventAccumulator>& stat)
 
 F64 Recording::getSum( const StatType<EventAccumulator>& stat)
 {
-	update();
+    update();
 	const EventAccumulator& accumulator = mBuffers->mEvents[stat.getIndex()];
 	const EventAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mEvents[stat.getIndex()] : NULL;
 	return (F64)(accumulator.getSum() + (active_accumulator && active_accumulator->hasValue() ? active_accumulator->getSum() : 0));
@@ -497,7 +505,7 @@ F64 Recording::getSum( const StatType<EventAccumulator>& stat)
 
 F64 Recording::getMin( const StatType<EventAccumulator>& stat )
 {
-	update();
+    update();
 	const EventAccumulator& accumulator = mBuffers->mEvents[stat.getIndex()];
 	const EventAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mEvents[stat.getIndex()] : NULL;
 	return llmin(accumulator.getMin(), active_accumulator && active_accumulator->hasValue() ? active_accumulator->getMin() : F32_MAX);
@@ -505,7 +513,7 @@ F64 Recording::getMin( const StatType<EventAccumulator>& stat )
 
 F64 Recording::getMax( const StatType<EventAccumulator>& stat )
 {
-	update();
+    update();
 	const EventAccumulator& accumulator = mBuffers->mEvents[stat.getIndex()];
 	const EventAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mEvents[stat.getIndex()] : NULL;
 	return llmax(accumulator.getMax(), active_accumulator && active_accumulator->hasValue() ? active_accumulator->getMax() : F32_MIN);
@@ -513,7 +521,7 @@ F64 Recording::getMax( const StatType<EventAccumulator>& stat )
 
 F64 Recording::getMean( const StatType<EventAccumulator>& stat )
 {
-	update();
+    update();
 	const EventAccumulator& accumulator = mBuffers->mEvents[stat.getIndex()];
 	const EventAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mEvents[stat.getIndex()] : NULL;
 	if (active_accumulator && active_accumulator->hasValue())
@@ -534,7 +542,7 @@ F64 Recording::getMean( const StatType<EventAccumulator>& stat )
 
 F64 Recording::getStandardDeviation( const StatType<EventAccumulator>& stat )
 {
-	update();
+    update();
 	const EventAccumulator& accumulator = mBuffers->mEvents[stat.getIndex()];
 	const EventAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mEvents[stat.getIndex()] : NULL;
 
@@ -551,7 +559,7 @@ F64 Recording::getStandardDeviation( const StatType<EventAccumulator>& stat )
 
 F64 Recording::getLastValue( const StatType<EventAccumulator>& stat )
 {
-	update();
+    update();
 	const EventAccumulator& accumulator = mBuffers->mEvents[stat.getIndex()];
 	const EventAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mEvents[stat.getIndex()] : NULL;
 	return active_accumulator ? active_accumulator->getLastValue() : accumulator.getLastValue();
@@ -559,7 +567,7 @@ F64 Recording::getLastValue( const StatType<EventAccumulator>& stat )
 
 S32 Recording::getSampleCount( const StatType<EventAccumulator>& stat )
 {
-	update();
+    update();
 	const EventAccumulator& accumulator = mBuffers->mEvents[stat.getIndex()];
 	const EventAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mEvents[stat.getIndex()] : NULL;
 	return accumulator.getSampleCount() + (active_accumulator ? active_accumulator->getSampleCount() : 0);
@@ -575,17 +583,20 @@ PeriodicRecording::PeriodicRecording( S32 num_periods, EPlayState state)
 	mNumRecordedPeriods(0),
 	mRecordingPeriods(num_periods ? num_periods : 1)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	setPlayState(state);
 	claim_alloc(gTraceMemStat, this);
 }
 
 PeriodicRecording::~PeriodicRecording()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	disclaim_alloc(gTraceMemStat, this);
 }
 
 void PeriodicRecording::nextPeriod()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	if (mAutoResize)
 	{
 		mRecordingPeriods.push_back(Recording());
@@ -600,6 +611,7 @@ void PeriodicRecording::nextPeriod()
 
 void PeriodicRecording::appendRecording(Recording& recording)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	getCurRecording().appendRecording(recording);
 	nextPeriod();
 }
@@ -607,6 +619,7 @@ void PeriodicRecording::appendRecording(Recording& recording)
 
 void PeriodicRecording::appendPeriodicRecording( PeriodicRecording& other )
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	if (other.mRecordingPeriods.empty()) return;
 
 	getCurRecording().update();
@@ -680,6 +693,7 @@ void PeriodicRecording::appendPeriodicRecording( PeriodicRecording& other )
 
 F64Seconds PeriodicRecording::getDuration() const
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	F64Seconds duration;
 	S32 num_periods = mRecordingPeriods.size();
 	for (S32 i = 1; i <= num_periods; i++)
@@ -693,6 +707,7 @@ F64Seconds PeriodicRecording::getDuration() const
 
 LLTrace::Recording PeriodicRecording::snapshotCurRecording() const
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	Recording recording_copy(getCurRecording());
 	recording_copy.stop();
 	return recording_copy;
@@ -735,16 +750,19 @@ const Recording& PeriodicRecording::getPrevRecording( S32 offset ) const
 
 void PeriodicRecording::handleStart()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	getCurRecording().start();
 }
 
 void PeriodicRecording::handleStop()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	getCurRecording().pause();
 }
 
 void PeriodicRecording::handleReset()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	getCurRecording().stop();
 
 	if (mAutoResize)
@@ -768,11 +786,13 @@ void PeriodicRecording::handleReset()
 
 void PeriodicRecording::handleSplitTo(PeriodicRecording& other)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	getCurRecording().splitTo(other.getCurRecording());
 }
 
 F64 PeriodicRecording::getPeriodMin( const StatType<EventAccumulator>& stat, S32 num_periods /*= S32_MAX*/ )
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	num_periods = llmin(num_periods, getNumRecordedPeriods());
 
 	bool has_value = false;
@@ -794,6 +814,7 @@ F64 PeriodicRecording::getPeriodMin( const StatType<EventAccumulator>& stat, S32
 
 F64 PeriodicRecording::getPeriodMax( const StatType<EventAccumulator>& stat, S32 num_periods /*= S32_MAX*/ )
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	num_periods = llmin(num_periods, getNumRecordedPeriods());
 
 	bool has_value = false;
@@ -816,6 +837,7 @@ F64 PeriodicRecording::getPeriodMax( const StatType<EventAccumulator>& stat, S32
 // calculates means using aggregates per period
 F64 PeriodicRecording::getPeriodMean( const StatType<EventAccumulator>& stat, S32 num_periods /*= S32_MAX*/ )
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	num_periods = llmin(num_periods, getNumRecordedPeriods());
 
 	F64 mean = 0;
@@ -836,9 +858,9 @@ F64 PeriodicRecording::getPeriodMean( const StatType<EventAccumulator>& stat, S3
 			: NaN;
 }
 
-
 F64 PeriodicRecording::getPeriodStandardDeviation( const StatType<EventAccumulator>& stat, S32 num_periods /*= S32_MAX*/ )
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	num_periods = llmin(num_periods, getNumRecordedPeriods());
 
 	F64 period_mean = getPeriodMean(stat, num_periods);
@@ -863,6 +885,7 @@ F64 PeriodicRecording::getPeriodStandardDeviation( const StatType<EventAccumulat
 
 F64 PeriodicRecording::getPeriodMin( const StatType<SampleAccumulator>& stat, S32 num_periods /*= S32_MAX*/ )
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	num_periods = llmin(num_periods, getNumRecordedPeriods());
 
 	bool has_value = false;
@@ -884,6 +907,7 @@ F64 PeriodicRecording::getPeriodMin( const StatType<SampleAccumulator>& stat, S3
 
 F64 PeriodicRecording::getPeriodMax(const StatType<SampleAccumulator>& stat, S32 num_periods /*= S32_MAX*/)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	num_periods = llmin(num_periods, getNumRecordedPeriods());
 
 	bool has_value = false;
@@ -906,6 +930,7 @@ F64 PeriodicRecording::getPeriodMax(const StatType<SampleAccumulator>& stat, S32
 
 F64 PeriodicRecording::getPeriodMean( const StatType<SampleAccumulator>& stat, S32 num_periods /*= S32_MAX*/ )
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	num_periods = llmin(num_periods, getNumRecordedPeriods());
 
 	S32 valid_period_count = 0;
@@ -926,8 +951,35 @@ F64 PeriodicRecording::getPeriodMean( const StatType<SampleAccumulator>& stat, S
 			: NaN;
 }
 
+F64 PeriodicRecording::getPeriodMedian( const StatType<SampleAccumulator>& stat, S32 num_periods /*= S32_MAX*/ )
+{
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
+	num_periods = llmin(num_periods, getNumRecordedPeriods());
+
+	std::vector<F64> buf;
+	for (S32 i = 1; i <= num_periods; i++)
+	{
+		Recording& recording = getPrevRecording(i);
+		if (recording.getDuration() > (F32Seconds)0.f)
+		{
+			if (recording.hasValue(stat))
+			{
+				buf.push_back(recording.getMean(stat));
+			}
+		}
+	}
+	if (buf.size()==0)
+	{
+		return 0.0f;
+	}
+	std::sort(buf.begin(), buf.end());
+
+	return F64((buf.size() % 2 == 0) ? (buf[buf.size() / 2 - 1] + buf[buf.size() / 2]) / 2 : buf[buf.size() / 2]);
+}
+
 F64 PeriodicRecording::getPeriodStandardDeviation( const StatType<SampleAccumulator>& stat, S32 num_periods /*= S32_MAX*/ )
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	num_periods = llmin(num_periods, getNumRecordedPeriods());
 
 	F64 period_mean = getPeriodMean(stat, num_periods);
@@ -953,6 +1005,7 @@ F64 PeriodicRecording::getPeriodStandardDeviation( const StatType<SampleAccumula
 
 F64Kilobytes PeriodicRecording::getPeriodMin( const StatType<MemAccumulator>& stat, S32 num_periods /*= S32_MAX*/ )
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	num_periods = llmin(num_periods, getNumRecordedPeriods());
 
 	F64Kilobytes min_val(std::numeric_limits<F64>::max());
@@ -972,6 +1025,7 @@ F64Kilobytes PeriodicRecording::getPeriodMin(const MemStatHandle& stat, S32 num_
 
 F64Kilobytes PeriodicRecording::getPeriodMax(const StatType<MemAccumulator>& stat, S32 num_periods /*= S32_MAX*/)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	num_periods = llmin(num_periods, getNumRecordedPeriods());
 
 	F64Kilobytes max_val(0.0);
@@ -991,6 +1045,7 @@ F64Kilobytes PeriodicRecording::getPeriodMax(const MemStatHandle& stat, S32 num_
 
 F64Kilobytes PeriodicRecording::getPeriodMean( const StatType<MemAccumulator>& stat, S32 num_periods /*= S32_MAX*/ )
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	num_periods = llmin(num_periods, getNumRecordedPeriods());
 
 	F64Kilobytes mean(0);
@@ -1011,6 +1066,7 @@ F64Kilobytes PeriodicRecording::getPeriodMean(const MemStatHandle& stat, S32 num
 
 F64Kilobytes PeriodicRecording::getPeriodStandardDeviation( const StatType<MemAccumulator>& stat, S32 num_periods /*= S32_MAX*/ )
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	num_periods = llmin(num_periods, getNumRecordedPeriods());
 
 	F64Kilobytes period_mean = getPeriodMean(stat, num_periods);
@@ -1044,6 +1100,7 @@ F64Kilobytes PeriodicRecording::getPeriodStandardDeviation(const MemStatHandle&
 
 void ExtendableRecording::extend()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	// push the data back to accepted recording
 	mAcceptedRecording.appendRecording(mPotentialRecording);
 	// flush data, so we can start from scratch
@@ -1052,22 +1109,26 @@ void ExtendableRecording::extend()
 
 void ExtendableRecording::handleStart()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	mPotentialRecording.start();
 }
 
 void ExtendableRecording::handleStop()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	mPotentialRecording.pause();
 }
 
 void ExtendableRecording::handleReset()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	mAcceptedRecording.reset();
 	mPotentialRecording.reset();
 }
 
 void ExtendableRecording::handleSplitTo(ExtendableRecording& other)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	mPotentialRecording.splitTo(other.mPotentialRecording);
 }
 
@@ -1084,6 +1145,7 @@ ExtendablePeriodicRecording::ExtendablePeriodicRecording()
 
 void ExtendablePeriodicRecording::extend()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	// push the data back to accepted recording
 	mAcceptedRecording.appendPeriodicRecording(mPotentialRecording);
 	// flush data, so we can start from scratch
@@ -1093,22 +1155,26 @@ void ExtendablePeriodicRecording::extend()
 
 void ExtendablePeriodicRecording::handleStart()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	mPotentialRecording.start();
 }
 
 void ExtendablePeriodicRecording::handleStop()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	mPotentialRecording.pause();
 }
 
 void ExtendablePeriodicRecording::handleReset()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	mAcceptedRecording.reset();
 	mPotentialRecording.reset();
 }
 
 void ExtendablePeriodicRecording::handleSplitTo(ExtendablePeriodicRecording& other)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	mPotentialRecording.splitTo(other.mPotentialRecording);
 }
 
@@ -1123,6 +1189,7 @@ PeriodicRecording& get_frame_recording()
 
 void LLStopWatchControlsMixinCommon::start()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	switch (mPlayState)
 	{
 	case STOPPED:
@@ -1144,6 +1211,7 @@ void LLStopWatchControlsMixinCommon::start()
 
 void LLStopWatchControlsMixinCommon::stop()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	switch (mPlayState)
 	{
 	case STOPPED:
@@ -1163,6 +1231,7 @@ void LLStopWatchControlsMixinCommon::stop()
 
 void LLStopWatchControlsMixinCommon::pause()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	switch (mPlayState)
 	{
 	case STOPPED:
@@ -1182,6 +1251,7 @@ void LLStopWatchControlsMixinCommon::pause()
 
 void LLStopWatchControlsMixinCommon::unpause()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	switch (mPlayState)
 	{
 	case STOPPED:
@@ -1201,6 +1271,7 @@ void LLStopWatchControlsMixinCommon::unpause()
 
 void LLStopWatchControlsMixinCommon::resume()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	switch (mPlayState)
 	{
 	case STOPPED:
@@ -1221,6 +1292,7 @@ void LLStopWatchControlsMixinCommon::resume()
 
 void LLStopWatchControlsMixinCommon::restart()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	switch (mPlayState)
 	{
 	case STOPPED:
@@ -1244,11 +1316,13 @@ void LLStopWatchControlsMixinCommon::restart()
 
 void LLStopWatchControlsMixinCommon::reset()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	handleReset();
 }
 
 void LLStopWatchControlsMixinCommon::setPlayState( EPlayState state )
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	switch(state)
 	{
 	case STOPPED:
diff --git a/indra/llcommon/lltracerecording.h b/indra/llcommon/lltracerecording.h
index d0b4a842a64aee82b234b894551b9df94ac1161e..556b7470cf56afb6e5bd94944b44bddb4bfc8e0a 100644
--- a/indra/llcommon/lltracerecording.h
+++ b/indra/llcommon/lltracerecording.h
@@ -355,6 +355,7 @@ namespace LLTrace
 		template <typename T>
 		S32 getSampleCount(const StatType<T>& stat, S32 num_periods = S32_MAX)
         {
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			num_periods = llmin(num_periods, getNumRecordedPeriods());
 
             S32 num_samples = 0;
@@ -374,6 +375,7 @@ namespace LLTrace
 		template <typename T>
 		typename T::value_t getPeriodMin(const StatType<T>& stat, S32 num_periods = S32_MAX)
 		{
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			num_periods = llmin(num_periods, getNumRecordedPeriods());
 
 			bool has_value = false;
@@ -396,6 +398,7 @@ namespace LLTrace
 		template<typename T>
 		T getPeriodMin(const CountStatHandle<T>& stat, S32 num_periods = S32_MAX)
 		{
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			return T(getPeriodMin(static_cast<const StatType<CountAccumulator>&>(stat), num_periods));
 		}
 
@@ -403,6 +406,7 @@ namespace LLTrace
 		template<typename T>
 		T getPeriodMin(const SampleStatHandle<T>& stat, S32 num_periods = S32_MAX)
 		{
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			return T(getPeriodMin(static_cast<const StatType<SampleAccumulator>&>(stat), num_periods));
 		}
 
@@ -410,6 +414,7 @@ namespace LLTrace
 		template<typename T>
 		T getPeriodMin(const EventStatHandle<T>& stat, S32 num_periods = S32_MAX)
 		{
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			return T(getPeriodMin(static_cast<const StatType<EventAccumulator>&>(stat), num_periods));
 		}
 
@@ -419,6 +424,7 @@ namespace LLTrace
 		template <typename T>
 		typename RelatedTypes<typename T::value_t>::fractional_t getPeriodMinPerSec(const StatType<T>& stat, S32 num_periods = S32_MAX)
 		{
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			num_periods = llmin(num_periods, getNumRecordedPeriods());
 
 			typename RelatedTypes<typename T::value_t>::fractional_t min_val(std::numeric_limits<F64>::max());
@@ -433,6 +439,7 @@ namespace LLTrace
 		template<typename T>
 		typename RelatedTypes<T>::fractional_t getPeriodMinPerSec(const CountStatHandle<T>& stat, S32 num_periods = S32_MAX)
 		{
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			return typename RelatedTypes<T>::fractional_t(getPeriodMinPerSec(static_cast<const StatType<CountAccumulator>&>(stat), num_periods));
 		}
 
@@ -444,6 +451,7 @@ namespace LLTrace
 		template <typename T>
 		typename T::value_t getPeriodMax(const StatType<T>& stat, S32 num_periods = S32_MAX)
 		{
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			num_periods = llmin(num_periods, getNumRecordedPeriods());
 
 			bool has_value = false;
@@ -466,6 +474,7 @@ namespace LLTrace
 		template<typename T>
 		T getPeriodMax(const CountStatHandle<T>& stat, S32 num_periods = S32_MAX)
 		{
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			return T(getPeriodMax(static_cast<const StatType<CountAccumulator>&>(stat), num_periods));
 		}
 
@@ -473,6 +482,7 @@ namespace LLTrace
 		template<typename T>
 		T getPeriodMax(const SampleStatHandle<T>& stat, S32 num_periods = S32_MAX)
 		{
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			return T(getPeriodMax(static_cast<const StatType<SampleAccumulator>&>(stat), num_periods));
 		}
 
@@ -480,6 +490,7 @@ namespace LLTrace
 		template<typename T>
 		T getPeriodMax(const EventStatHandle<T>& stat, S32 num_periods = S32_MAX)
 		{
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			return T(getPeriodMax(static_cast<const StatType<EventAccumulator>&>(stat), num_periods));
 		}
 
@@ -489,6 +500,7 @@ namespace LLTrace
 		template <typename T>
 		typename RelatedTypes<typename T::value_t>::fractional_t getPeriodMaxPerSec(const StatType<T>& stat, S32 num_periods = S32_MAX)
 		{
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			num_periods = llmin(num_periods, getNumRecordedPeriods());
 
 			F64 max_val = std::numeric_limits<F64>::min();
@@ -503,6 +515,7 @@ namespace LLTrace
 		template<typename T>
 		typename RelatedTypes<T>::fractional_t getPeriodMaxPerSec(const CountStatHandle<T>& stat, S32 num_periods = S32_MAX)
 		{
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			return typename RelatedTypes<T>::fractional_t(getPeriodMaxPerSec(static_cast<const StatType<CountAccumulator>&>(stat), num_periods));
 		}
 
@@ -514,6 +527,7 @@ namespace LLTrace
 		template <typename T>
 		typename RelatedTypes<typename T::value_t>::fractional_t getPeriodMean(const StatType<T >& stat, S32 num_periods = S32_MAX)
 		{
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			num_periods = llmin(num_periods, getNumRecordedPeriods());
 
 			typename RelatedTypes<typename T::value_t>::fractional_t mean(0);
@@ -534,12 +548,14 @@ namespace LLTrace
 		template<typename T>
 		typename RelatedTypes<T>::fractional_t getPeriodMean(const CountStatHandle<T>& stat, S32 num_periods = S32_MAX)
 		{
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			return typename RelatedTypes<T>::fractional_t(getPeriodMean(static_cast<const StatType<CountAccumulator>&>(stat), num_periods));
 		}
 		F64 getPeriodMean(const StatType<SampleAccumulator>& stat, S32 num_periods = S32_MAX);
 		template<typename T> 
 		typename RelatedTypes<T>::fractional_t getPeriodMean(const SampleStatHandle<T>& stat, S32 num_periods = S32_MAX)
 		{
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			return typename RelatedTypes<T>::fractional_t(getPeriodMean(static_cast<const StatType<SampleAccumulator>&>(stat), num_periods));
 		}
 
@@ -547,6 +563,7 @@ namespace LLTrace
 		template<typename T>
 		typename RelatedTypes<T>::fractional_t getPeriodMean(const EventStatHandle<T>& stat, S32 num_periods = S32_MAX)
 		{
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			return typename RelatedTypes<T>::fractional_t(getPeriodMean(static_cast<const StatType<EventAccumulator>&>(stat), num_periods));
 		}
 
@@ -556,6 +573,7 @@ namespace LLTrace
 		template <typename T>
 		typename RelatedTypes<typename T::value_t>::fractional_t getPeriodMeanPerSec(const StatType<T>& stat, S32 num_periods = S32_MAX)
 		{
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			num_periods = llmin(num_periods, getNumRecordedPeriods());
 
 			typename RelatedTypes<typename T::value_t>::fractional_t mean = 0;
@@ -577,9 +595,39 @@ namespace LLTrace
 		template<typename T>
 		typename RelatedTypes<T>::fractional_t getPeriodMeanPerSec(const CountStatHandle<T>& stat, S32 num_periods = S32_MAX)
 		{
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			return typename RelatedTypes<T>::fractional_t(getPeriodMeanPerSec(static_cast<const StatType<CountAccumulator>&>(stat), num_periods));
 		}
 
+        F64 getPeriodMedian( const StatType<SampleAccumulator>& stat, S32 num_periods = S32_MAX);
+
+        template <typename T>
+        typename RelatedTypes<typename T::value_t>::fractional_t getPeriodMedianPerSec(const StatType<T>& stat, S32 num_periods = S32_MAX)
+        {
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
+            num_periods = llmin(num_periods, getNumRecordedPeriods());
+
+            std::vector <typename RelatedTypes<typename T::value_t>::fractional_t> buf;
+            for (S32 i = 1; i <= num_periods; i++)
+            {
+                Recording& recording = getPrevRecording(i);
+                if (recording.getDuration() > (F32Seconds)0.f)
+                {
+                    buf.push_back(recording.getPerSec(stat));
+                }
+            }
+            std::sort(buf.begin(), buf.end());
+
+            return typename RelatedTypes<T>::fractional_t((buf.size() % 2 == 0) ? (buf[buf.size() / 2 - 1] + buf[buf.size() / 2]) / 2 : buf[buf.size() / 2]);
+        }
+
+        template<typename T>
+        typename RelatedTypes<T>::fractional_t getPeriodMedianPerSec(const CountStatHandle<T>& stat, S32 num_periods = S32_MAX)
+        {
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
+            return typename RelatedTypes<T>::fractional_t(getPeriodMedianPerSec(static_cast<const StatType<CountAccumulator>&>(stat), num_periods));
+        }
+
 		//
 		// PERIODIC STANDARD DEVIATION
 		//
@@ -589,6 +637,7 @@ namespace LLTrace
 		template<typename T> 
 		typename RelatedTypes<T>::fractional_t getPeriodStandardDeviation(const SampleStatHandle<T>& stat, S32 num_periods = S32_MAX)
 		{
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			return typename RelatedTypes<T>::fractional_t(getPeriodStandardDeviation(static_cast<const StatType<SampleAccumulator>&>(stat), num_periods));
 		}
 
@@ -596,6 +645,7 @@ namespace LLTrace
 		template<typename T>
 		typename RelatedTypes<T>::fractional_t getPeriodStandardDeviation(const EventStatHandle<T>& stat, S32 num_periods = S32_MAX)
 		{
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			return typename RelatedTypes<T>::fractional_t(getPeriodStandardDeviation(static_cast<const StatType<EventAccumulator>&>(stat), num_periods));
 		}
 
diff --git a/indra/llcommon/lltracethreadrecorder.cpp b/indra/llcommon/lltracethreadrecorder.cpp
index 025dc57044d6b8edaad0c8faf343f073a96fa0bc..090d3297a017fbeb2da4bfa91ca027dfc594c424 100644
--- a/indra/llcommon/lltracethreadrecorder.cpp
+++ b/indra/llcommon/lltracethreadrecorder.cpp
@@ -274,12 +274,10 @@ void ThreadRecorder::pushToParent()
 }
 
 
-static LLTrace::BlockTimerStatHandle FTM_PULL_TRACE_DATA_FROM_CHILDREN("Pull child thread trace data");
-
 void ThreadRecorder::pullFromChildren()
 {
 #if LL_TRACE_ENABLED
-	LL_RECORD_BLOCK_TIME(FTM_PULL_TRACE_DATA_FROM_CHILDREN);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	if (mActiveRecordings.empty()) return;
 
 	{ LLMutexLock lock(&mChildListMutex);
diff --git a/indra/llcommon/lluuid.h b/indra/llcommon/lluuid.h
index fe7482ba29f82c70598a1497da8e04f4fa1f5faa..86a396ab06f8c1f4de367116c96eba87d8635133 100644
--- a/indra/llcommon/lluuid.h
+++ b/indra/llcommon/lluuid.h
@@ -184,6 +184,17 @@ struct boost::hash<LLUUID>
     }
 };
 
+// Adapt boost hash to std hash
+namespace std
+{
+    template<> struct hash<LLUUID>
+    {
+        std::size_t operator()(LLUUID const& s) const noexcept
+        {
+            return boost::hash<LLUUID>()(s);
+        }
+    };
+}
 #endif
 
 
diff --git a/indra/llcommon/stdtypes.h b/indra/llcommon/stdtypes.h
index 887f6ab7332413fcd2a8bc043636935c516729e1..b07805b62831271404212e025f1b9151c76eb86b 100644
--- a/indra/llcommon/stdtypes.h
+++ b/indra/llcommon/stdtypes.h
@@ -42,10 +42,17 @@ typedef unsigned int			U32;
 // Windows wchar_t is 16-bit, whichever way /Zc:wchar_t is set. In effect,
 // Windows wchar_t is always a typedef, either for unsigned short or __wchar_t.
 // (__wchar_t, available either way, is Microsoft's native 2-byte wchar_t type.)
+// The version of clang available with VS 2019 also defines wchar_t as __wchar_t
+// which is also 16 bits.
 // In any case, llwchar should be a UTF-32 type.
 typedef U32				llwchar;
 #else
 typedef wchar_t				llwchar;
+// What we'd actually want is a simple module-scope 'if constexpr' to test
+// std::is_same<wchar_t, llwchar>::value and use that to define, or not
+// define, string conversion specializations. Since we don't have that, we'll
+// have to rely on #if instead. Sorry, Dr. Stroustrup.
+#define LLWCHAR_IS_WCHAR_T 1
 #endif
 
 #if LL_WINDOWS
diff --git a/indra/llcommon/stringize.h b/indra/llcommon/stringize.h
index 38dd198ad319760c3be12230b1dfe2975421a9d9..12df6939108e47b3f0e05c8ccfa40ffae7f8f5c4 100644
--- a/indra/llcommon/stringize.h
+++ b/indra/llcommon/stringize.h
@@ -31,58 +31,109 @@
 
 #include <sstream>
 #include <llstring.h>
+#include <boost/call_traits.hpp>
 
 /**
- * gstringize(item) encapsulates an idiom we use constantly, using
- * operator<<(std::ostringstream&, TYPE) followed by std::ostringstream::str()
- * or their wstring equivalents
- * to render a string expressing some item.
+ * stream_to(std::ostream&, items, ...) streams each item in the parameter list
+ * to the passed std::ostream using the insertion operator <<. This can be
+ * used, for instance, to make a simple print() function, e.g.:
+ *
+ * @code
+ * template <typename... Items>
+ * void print(Items&&... items)
+ * {
+ *     stream_to(std::cout, std::forward<Items>(items)...);
+ * }
+ * @endcode
  */
-template <typename CHARTYPE, typename T>
-std::basic_string<CHARTYPE> gstringize(const T& item)
+// recursion tail
+template <typename CHARTYPE>
+void stream_to(std::basic_ostream<CHARTYPE>& out) {}
+// stream one or more items
+template <typename CHARTYPE, typename T, typename... Items>
+void stream_to(std::basic_ostream<CHARTYPE>& out, T&& item, Items&&... items)
 {
-    std::basic_ostringstream<CHARTYPE> out;
-    out << item;
-    return out.str();
+    out << std::forward<T>(item);
+    stream_to(out, std::forward<Items>(items)...);
 }
 
+// why we use function overloads, not function template specializations:
+// http://www.gotw.ca/publications/mill17.htm
+
 /**
- *partial specialization of stringize for handling wstring
- *TODO: we should have similar specializations for wchar_t[] but not until it is needed.
+ * gstringize(item, ...) encapsulates an idiom we use constantly, using
+ * operator<<(std::ostringstream&, TYPE) followed by std::ostringstream::str()
+ * or their wstring equivalents to render a string expressing one or more items.
  */
-inline std::string stringize(const std::wstring& item)
+// two or more args - the case of a single argument is handled separately
+template <typename CHARTYPE, typename T0, typename T1, typename... Items>
+auto gstringize(T0&& item0, T1&& item1, Items&&... items)
 {
-    return wstring_to_utf8str(item);
+    std::basic_ostringstream<CHARTYPE> out;
+    stream_to(out, std::forward<T0>(item0), std::forward<T1>(item1),
+              std::forward<Items>(items)...);
+    return out.str();
 }
 
-/**
- * Specialization of gstringize for std::string return types
- */
-template <typename T>
-std::string stringize(const T& item)
+// generic single argument: stream to out, as above
+template <typename CHARTYPE, typename T>
+struct gstringize_impl
 {
-    return gstringize<char>(item);
+    auto operator()(typename boost::call_traits<T>::param_type arg)
+    {
+        std::basic_ostringstream<CHARTYPE> out;
+        out << arg;
+        return out.str();
+    }
+};
+
+// partially specialize for a single STRING argument -
+// note that ll_convert<T>(T) already handles the trivial case
+template <typename OUTCHAR, typename INCHAR>
+struct gstringize_impl<OUTCHAR, std::basic_string<INCHAR>>
+{
+    auto operator()(const std::basic_string<INCHAR>& arg)
+    {
+        return ll_convert<std::basic_string<OUTCHAR>>(arg);
+    }
+};
+
+// partially specialize for a single CHARTYPE* argument -
+// since it's not a basic_string and we do want to optimize this common case
+template <typename OUTCHAR, typename INCHAR>
+struct gstringize_impl<OUTCHAR, INCHAR*>
+{
+    auto operator()(const INCHAR* arg)
+    {
+        return ll_convert<std::basic_string<OUTCHAR>>(arg);
+    }
+};
+
+// gstringize(single argument)
+template <typename CHARTYPE, typename T>
+auto gstringize(T&& item)
+{
+    // use decay<T> so we don't require separate specializations
+    // for T, const T, T&, const T& ...
+    return gstringize_impl<CHARTYPE, std::decay_t<T>>()(std::forward<T>(item));
 }
 
 /**
- * Specialization for generating wstring from string.
- * Both a convenience function and saves a miniscule amount of overhead.
+ * Specialization of gstringize for std::string return types
  */
-inline std::wstring wstringize(const std::string& item)
+template <typename... Items>
+auto stringize(Items&&... items)
 {
-    // utf8str_to_wstring() returns LLWString, which isn't necessarily the
-    // same as std::wstring
-    LLWString s(utf8str_to_wstring(item));
-    return std::wstring(s.begin(), s.end());
+    return gstringize<char>(std::forward<Items>(items)...);
 }
 
 /**
  * Specialization of gstringize for std::wstring return types
  */
-template <typename T>
-std::wstring wstringize(const T& item)
+template <typename... Items>
+auto wstringize(Items&&... items)
 {
-    return gstringize<wchar_t>(item);
+    return gstringize<wchar_t>(std::forward<Items>(items)...);
 }
 
 /**
@@ -146,11 +197,9 @@ void destringize_f(std::basic_string<CHARTYPE> const & str, Functor const & f)
  * std::istringstream in(str);
  * in >> item1 >> item2 >> item3 ... ;
  * @endcode
- * @NOTE - once we get generic lambdas, we shouldn't need DEWSTRINGIZE() any
- * more since DESTRINGIZE() should do the right thing with a std::wstring. But
- * until then, the lambda we pass must accept the right std::basic_istream.
  */
-#define DESTRINGIZE(STR, EXPRESSION) (destringize_f((STR), [&](std::istream& in){in >> EXPRESSION;}))
-#define DEWSTRINGIZE(STR, EXPRESSION) (destringize_f((STR), [&](std::wistream& in){in >> EXPRESSION;}))
+#define DESTRINGIZE(STR, EXPRESSION) (destringize_f((STR), [&](auto& in){in >> EXPRESSION;}))
+// legacy name, just use DESTRINGIZE() going forward
+#define DEWSTRINGIZE(STR, EXPRESSION) DESTRINGIZE(STR, EXPRESSION)
 
 #endif /* ! defined(LL_STRINGIZE_H) */
diff --git a/indra/llcommon/tests/classic_callback_test.cpp b/indra/llcommon/tests/classic_callback_test.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..c060775c2418bc4ef3749288eb5ac166d5069f62
--- /dev/null
+++ b/indra/llcommon/tests/classic_callback_test.cpp
@@ -0,0 +1,144 @@
+/**
+ * @file   classic_callback_test.cpp
+ * @author Nat Goodspeed
+ * @date   2021-09-22
+ * @brief  Test ClassicCallback and HeapClassicCallback.
+ * 
+ * $LicenseInfo:firstyear=2021&license=viewerlgpl$
+ * Copyright (c) 2021, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+// Precompiled header
+#include "linden_common.h"
+// associated header
+#include "classic_callback.h"
+// STL headers
+#include <iostream>
+#include <string>
+// std headers
+// external library headers
+// other Linden headers
+#include "../test/lltut.h"
+
+/*****************************************************************************
+*   example callback
+*****************************************************************************/
+// callback_t is part of the specification of someAPI()
+typedef void (*callback_t)(const char*, void*);
+void someAPI(callback_t callback, void* userdata)
+{
+    callback("called", userdata);
+}
+
+// C++ callable I want as the actual callback
+struct MyCallback
+{
+    void operator()(const char* msg, void*)
+    {
+        mMsg = msg;
+    }
+
+    void callback_with_extra(const std::string& extra, const char* msg)
+    {
+        mMsg = extra + ' ' + msg;
+    }
+
+    std::string mMsg;
+};
+
+/*****************************************************************************
+*   example callback accepting several params, and void* userdata isn't first
+*****************************************************************************/
+typedef std::string (*complex_callback)(int, const char*, void*, double);
+std::string otherAPI(complex_callback callback, void* userdata)
+{
+    return callback(17, "hello world", userdata, 3.0);
+}
+
+// struct into which we can capture complex_callback params
+static struct Data
+{
+    void set(int i, const char* s, double f)
+    {
+        mi = i;
+        ms = s;
+        mf = f;
+    }
+
+    void clear() { set(0, "", 0.0); }
+
+    int mi;
+    std::string ms;
+    double mf;
+} sData;
+
+// C++ callable I want to pass
+struct OtherCallback
+{
+    std::string operator()(int num, const char* str, void*, double approx)
+    {
+        sData.set(num, str, approx);
+        return "hello back!";
+    }
+};
+
+/*****************************************************************************
+*   TUT
+*****************************************************************************/
+namespace tut
+{
+    struct classic_callback_data
+    {
+    };
+    typedef test_group<classic_callback_data> classic_callback_group;
+    typedef classic_callback_group::object object;
+    classic_callback_group classic_callbackgrp("classic_callback");
+
+    template<> template<>
+    void object::test<1>()
+    {
+        set_test_name("ClassicCallback");
+        // engage someAPI(MyCallback())
+        auto ccb{ makeClassicCallback<callback_t>(MyCallback()) };
+        someAPI(ccb.get_callback(), ccb.get_userdata());
+        // Unfortunately, with the side effect confined to the bound
+        // MyCallback instance, that call was invisible. Bind a reference to a
+        // named instance by specifying a ref type.
+        MyCallback mcb;
+        ClassicCallback<callback_t, void*, MyCallback&> ccb2(mcb);
+        someAPI(ccb2.get_callback(), ccb2.get_userdata());
+        ensure_equals("failed to call through ClassicCallback", mcb.mMsg, "called");
+
+        // try with HeapClassicCallback
+        mcb.mMsg.clear();
+        auto hcbp{ makeHeapClassicCallback<callback_t>(mcb) };
+        someAPI(hcbp->get_callback(), hcbp->get_userdata());
+        ensure_equals("failed to call through HeapClassicCallback", mcb.mMsg, "called");
+
+        // lambda
+        // The tricky thing here is that a lambda is an unspecified type, so
+        // you can't declare a ClassicCallback<signature, void*, that type>.
+        mcb.mMsg.clear();
+        auto xcb(
+            makeClassicCallback<callback_t>(
+                [&mcb](const char* msg, void*)
+                { mcb.callback_with_extra("extra", msg); }));
+        someAPI(xcb.get_callback(), xcb.get_userdata());
+        ensure_equals("failed to call lambda", mcb.mMsg, "extra called");
+
+        // engage otherAPI(OtherCallback())
+        OtherCallback ocb;
+        // Instead of specifying a reference type for the bound CALLBACK, as
+        // with ccb2 above, you can alternatively move the callable object
+        // into the ClassicCallback (of course AFTER any other reference).
+        // That's why OtherCallback uses external data for its observable side
+        // effect.
+        auto occb{ makeClassicCallback<complex_callback>(std::move(ocb)) };
+        std::string result{ otherAPI(occb.get_callback(), occb.get_userdata()) };
+        ensure_equals("failed to return callback result", result, "hello back!");
+        ensure_equals("failed to set int", sData.mi, 17);
+        ensure_equals("failed to set string", sData.ms, "hello world");
+        ensure_equals("failed to set double", sData.mf, 3.0);
+    }
+} // namespace tut
diff --git a/indra/llcommon/tests/llinstancetracker_test.cpp b/indra/llcommon/tests/llinstancetracker_test.cpp
index 9b8915962525d7bc4272c9c7b3cafda77c527bf7..5daa29adf44386ce3ee2ca3670e08ca012a3f37f 100644
--- a/indra/llcommon/tests/llinstancetracker_test.cpp
+++ b/indra/llcommon/tests/llinstancetracker_test.cpp
@@ -90,19 +90,19 @@ namespace tut
         {
             Keyed one("one");
             ensure_equals(Keyed::instanceCount(), 1);
-            Keyed* found = Keyed::getInstance("one");
-            ensure("couldn't find stack Keyed", found);
-            ensure_equals("found wrong Keyed instance", found, &one);
+            auto found = Keyed::getInstance("one");
+            ensure("couldn't find stack Keyed", bool(found));
+            ensure_equals("found wrong Keyed instance", found.get(), &one);
             {
                 boost::scoped_ptr<Keyed> two(new Keyed("two"));
                 ensure_equals(Keyed::instanceCount(), 2);
-                Keyed* found = Keyed::getInstance("two");
-                ensure("couldn't find heap Keyed", found);
-                ensure_equals("found wrong Keyed instance", found, two.get());
+                auto found = Keyed::getInstance("two");
+                ensure("couldn't find heap Keyed", bool(found));
+                ensure_equals("found wrong Keyed instance", found.get(), two.get());
             }
             ensure_equals(Keyed::instanceCount(), 1);
         }
-        Keyed* found = Keyed::getInstance("one");
+        auto found = Keyed::getInstance("one");
         ensure("Keyed key lives too long", ! found);
         ensure_equals(Keyed::instanceCount(), 0);
     }
diff --git a/indra/llcommon/tests/llprocess_test.cpp b/indra/llcommon/tests/llprocess_test.cpp
index e530975e86828d76a557719bb6fe8cfcae661187..999d4320798e630fd41f56fae6591e928a71d7d7 100644
--- a/indra/llcommon/tests/llprocess_test.cpp
+++ b/indra/llcommon/tests/llprocess_test.cpp
@@ -356,14 +356,15 @@ namespace tut
 
         // Create a script file in a temporary place.
         NamedTempFile script("py",
+			"from __future__ import print_function" EOL
             "import sys" EOL
             "import time" EOL
             EOL
             "time.sleep(2)" EOL
-            "print('stdout after wait', file=sys.stdout)" EOL
+            "print('stdout after wait',file=sys.stdout)" EOL
             "sys.stdout.flush()" EOL
             "time.sleep(2)" EOL
-            "print('stderr after wait', file=sys.stderr)" EOL
+            "print('stderr after wait',file=sys.stderr)" EOL
             "sys.stderr.flush()" EOL
             );
 
@@ -572,12 +573,12 @@ namespace tut
     {
         set_test_name("arguments");
         PythonProcessLauncher py(get_test_name(),
-                                 "from __future__ import with_statement\n"
+                                 "from __future__ import with_statement, print_function\n"
                                  "import sys\n"
                                  // note nonstandard output-file arg!
                                  "with open(sys.argv[3], 'w') as f:\n"
                                  "    for arg in sys.argv[1:]:\n"
-                                 "        print(arg, file=f)\n");
+                                 "        print(arg,file=f)\n");
         // We expect that PythonProcessLauncher has already appended
         // its own NamedTempFile to mParams.args (sys.argv[0]).
         py.mParams.args.add("first arg");          // sys.argv[1]
@@ -861,6 +862,7 @@ namespace tut
         set_test_name("'bogus' test");
         CaptureLog recorder;
         PythonProcessLauncher py(get_test_name(),
+                                 "from __future__ import print_function\n"
                                  "print('Hello world')\n");
         py.mParams.files.add(LLProcess::FileParam("bogus"));
         py.mPy = LLProcess::create(py.mParams);
@@ -876,6 +878,7 @@ namespace tut
         // Replace this test with one or more real 'file' tests when we
         // implement 'file' support
         PythonProcessLauncher py(get_test_name(),
+                                 "from __future__ import print_function\n"
                                  "print('Hello world')\n");
         py.mParams.files.add(LLProcess::FileParam());
         py.mParams.files.add(LLProcess::FileParam("file"));
@@ -891,6 +894,7 @@ namespace tut
         // implement 'tpipe' support
         CaptureLog recorder;
         PythonProcessLauncher py(get_test_name(),
+                                 "from __future__ import print_function\n"
                                  "print('Hello world')\n");
         py.mParams.files.add(LLProcess::FileParam());
         py.mParams.files.add(LLProcess::FileParam("tpipe"));
@@ -908,6 +912,7 @@ namespace tut
         // implement 'npipe' support
         CaptureLog recorder;
         PythonProcessLauncher py(get_test_name(),
+                                 "from __future__ import print_function\n"
                                  "print('Hello world')\n");
         py.mParams.files.add(LLProcess::FileParam());
         py.mParams.files.add(LLProcess::FileParam());
@@ -984,7 +989,8 @@ namespace tut
     {
         set_test_name("get*Pipe() validation");
         PythonProcessLauncher py(get_test_name(),
-                                 "print('this output is expected)'\n");
+                                 "from __future__ import print_function\n"
+                                 "print('this output is expected')\n");
         py.mParams.files.add(LLProcess::FileParam("pipe")); // pipe for  stdin
         py.mParams.files.add(LLProcess::FileParam());       // inherit stdout
         py.mParams.files.add(LLProcess::FileParam("pipe")); // pipe for stderr
@@ -1004,6 +1010,7 @@ namespace tut
     {
         set_test_name("talk to stdin/stdout");
         PythonProcessLauncher py(get_test_name(),
+                                 "from __future__ import print_function\n"
                                  "import sys, time\n"
                                  "print('ok')\n"
                                  "sys.stdout.flush()\n"
@@ -1122,6 +1129,7 @@ namespace tut
     {
         set_test_name("ReadPipe \"eof\" event");
         PythonProcessLauncher py(get_test_name(),
+                                 "from __future__ import print_function\n"
                                  "print('Hello from Python!')\n");
         py.mParams.files.add(LLProcess::FileParam()); // stdin
         py.mParams.files.add(LLProcess::FileParam("pipe")); // stdout
diff --git a/indra/llcommon/tests/threadsafeschedule_test.cpp b/indra/llcommon/tests/threadsafeschedule_test.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..c421cc7b1c3634ba4b81511a1097d136a50bb166
--- /dev/null
+++ b/indra/llcommon/tests/threadsafeschedule_test.cpp
@@ -0,0 +1,69 @@
+/**
+ * @file   threadsafeschedule_test.cpp
+ * @author Nat Goodspeed
+ * @date   2021-10-04
+ * @brief  Test for threadsafeschedule.
+ * 
+ * $LicenseInfo:firstyear=2021&license=viewerlgpl$
+ * Copyright (c) 2021, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+// Precompiled header
+#include "linden_common.h"
+// associated header
+#include "threadsafeschedule.h"
+// STL headers
+// std headers
+#include <chrono>
+// external library headers
+// other Linden headers
+#include "../test/lltut.h"
+
+using namespace std::literals::chrono_literals; // ms suffix
+using namespace std::literals::string_literals; // s suffix
+using Queue = LL::ThreadSafeSchedule<std::string>;
+
+/*****************************************************************************
+*   TUT
+*****************************************************************************/
+namespace tut
+{
+    struct threadsafeschedule_data
+    {
+        Queue queue;
+    };
+    typedef test_group<threadsafeschedule_data> threadsafeschedule_group;
+    typedef threadsafeschedule_group::object object;
+    threadsafeschedule_group threadsafeschedulegrp("threadsafeschedule");
+
+    template<> template<>
+    void object::test<1>()
+    {
+        set_test_name("push");
+        // Simply calling push() a few times might result in indeterminate
+        // delivery order if the resolution of steady_clock is coarser than
+        // the real time required for each push() call. Explicitly increment
+        // the timestamp for each one -- but since we're passing explicit
+        // timestamps, make the queue reorder them.
+        queue.push(Queue::TimeTuple(Queue::Clock::now() + 200ms, "ghi"));
+        // Given the various push() overloads, you have to match the type
+        // exactly: conversions are ambiguous.
+        queue.push("abc"s);
+        queue.push(Queue::Clock::now() + 100ms, "def");
+        queue.close();
+        auto entry = queue.pop();
+        ensure_equals("failed to pop first", std::get<0>(entry), "abc"s);
+        entry = queue.pop();
+        ensure_equals("failed to pop second", std::get<0>(entry), "def"s);
+        ensure("queue not closed", queue.isClosed());
+        ensure("queue prematurely done", ! queue.done());
+        std::string s;
+        bool popped = queue.tryPopFor(1s, s);
+        ensure("failed to pop third", popped);
+        ensure_equals("third is wrong", s, "ghi"s);
+        popped = queue.tryPop(s);
+        ensure("queue not empty", ! popped);
+        ensure("queue not done", queue.done());
+    }
+} // namespace tut
diff --git a/indra/llcommon/tests/tuple_test.cpp b/indra/llcommon/tests/tuple_test.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..af94e2086c12e41263431a19828b1ce10ab89b6b
--- /dev/null
+++ b/indra/llcommon/tests/tuple_test.cpp
@@ -0,0 +1,47 @@
+/**
+ * @file   tuple_test.cpp
+ * @author Nat Goodspeed
+ * @date   2021-10-04
+ * @brief  Test for tuple.
+ * 
+ * $LicenseInfo:firstyear=2021&license=viewerlgpl$
+ * Copyright (c) 2021, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+// Precompiled header
+#include "linden_common.h"
+// associated header
+#include "tuple.h"
+// STL headers
+// std headers
+// external library headers
+// other Linden headers
+#include "../test/lltut.h"
+
+/*****************************************************************************
+*   TUT
+*****************************************************************************/
+namespace tut
+{
+    struct tuple_data
+    {
+    };
+    typedef test_group<tuple_data> tuple_group;
+    typedef tuple_group::object object;
+    tuple_group tuplegrp("tuple");
+
+    template<> template<>
+    void object::test<1>()
+    {
+        set_test_name("tuple");
+        std::tuple<std::string, int> tup{ "abc", 17 };
+        std::tuple<int, std::string, int> ptup{ tuple_cons(34, tup) };
+        std::tuple<std::string, int> tup2;
+        int i;
+        std::tie(i, tup2) = tuple_split(ptup);
+        ensure_equals("tuple_car() fail", i, 34);
+        ensure_equals("tuple_cdr() (0) fail", std::get<0>(tup2), "abc");
+        ensure_equals("tuple_cdr() (1) fail", std::get<1>(tup2), 17);
+    }
+} // namespace tut
diff --git a/indra/llcommon/tests/workqueue_test.cpp b/indra/llcommon/tests/workqueue_test.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..1d73f7aa0d47f913292f9fbfd4f7c5d8bb96d666
--- /dev/null
+++ b/indra/llcommon/tests/workqueue_test.cpp
@@ -0,0 +1,235 @@
+/**
+ * @file   workqueue_test.cpp
+ * @author Nat Goodspeed
+ * @date   2021-10-07
+ * @brief  Test for workqueue.
+ * 
+ * $LicenseInfo:firstyear=2021&license=viewerlgpl$
+ * Copyright (c) 2021, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+// Precompiled header
+#include "linden_common.h"
+// associated header
+#include "workqueue.h"
+// STL headers
+// std headers
+#include <chrono>
+#include <deque>
+// external library headers
+// other Linden headers
+#include "../test/lltut.h"
+#include "../test/catch_and_store_what_in.h"
+#include "llcond.h"
+#include "llcoros.h"
+#include "lleventcoro.h"
+#include "llstring.h"
+#include "stringize.h"
+
+using namespace LL;
+using namespace std::literals::chrono_literals; // ms suffix
+using namespace std::literals::string_literals; // s suffix
+
+/*****************************************************************************
+*   TUT
+*****************************************************************************/
+namespace tut
+{
+    struct workqueue_data
+    {
+        WorkQueue queue{"queue"};
+    };
+    typedef test_group<workqueue_data> workqueue_group;
+    typedef workqueue_group::object object;
+    workqueue_group workqueuegrp("workqueue");
+
+    template<> template<>
+    void object::test<1>()
+    {
+        set_test_name("name");
+        ensure_equals("didn't capture name", queue.getKey(), "queue");
+        ensure("not findable", WorkQueue::getInstance("queue") == queue.getWeak().lock());
+        WorkQueue q2;
+        ensure("has no name", LLStringUtil::startsWith(q2.getKey(), "WorkQueue"));
+    }
+
+    template<> template<>
+    void object::test<2>()
+    {
+        set_test_name("post");
+        bool wasRun{ false };
+        // We only get away with binding a simple bool because we're running
+        // the work on the same thread.
+        queue.post([&wasRun](){ wasRun = true; });
+        queue.close();
+        ensure("ran too soon", ! wasRun);
+        queue.runUntilClose();
+        ensure("didn't run", wasRun);
+    }
+
+    template<> template<>
+    void object::test<3>()
+    {
+        set_test_name("postEvery");
+        // record of runs
+        using Shared = std::deque<WorkQueue::TimePoint>;
+        // This is an example of how to share data between the originator of
+        // postEvery(work) and the work item itself, since usually a WorkQueue
+        // is used to dispatch work to a different thread. Neither of them
+        // should call any of LLCond's wait methods: you don't want to stall
+        // either the worker thread or the originating thread (conventionally
+        // main). Use LLCond or a subclass even if all you want to do is
+        // signal the work item that it can quit; consider LLOneShotCond.
+        LLCond<Shared> data;
+        auto start = WorkQueue::TimePoint::clock::now();
+        auto interval = 100ms;
+        queue.postEvery(
+            interval,
+            [&data, count = 0]
+            () mutable
+            {
+                // record the timestamp at which this instance is running
+                data.update_one(
+                    [](Shared& data)
+                    {
+                        data.push_back(WorkQueue::TimePoint::clock::now());
+                    });
+                // by the 3rd call, return false to stop
+                return (++count < 3);
+            });
+        // no convenient way to close() our queue while we've got a
+        // postEvery() running, so run until we have exhausted the iterations
+        // or we time out waiting
+        for (auto finish = start + 10*interval;
+             WorkQueue::TimePoint::clock::now() < finish &&
+             data.get([](const Shared& data){ return data.size(); }) < 3; )
+        {
+            queue.runPending();
+            std::this_thread::sleep_for(interval/10);
+        }
+        // Take a copy of the captured deque.
+        Shared result = data.get();
+        ensure_equals("called wrong number of times", result.size(), 3);
+        // postEvery() assumes you want the first call to happen right away.
+        // Pretend our start time was (interval) earlier than that, to make
+        // our too early/too late tests uniform for all entries.
+        start -= interval;
+        for (size_t i = 0; i < result.size(); ++i)
+        {
+            auto diff = result[i] - start;
+            start += interval;
+            try
+            {
+                ensure(STRINGIZE("call " << i << " too soon"), diff >= interval);
+                ensure(STRINGIZE("call " << i << " too late"), diff < interval*1.5);
+            }
+            catch (const tut::failure&)
+            {
+                auto interval_ms = interval / 1ms;
+                auto diff_ms = diff / 1ms;
+                std::cerr << "interval " << interval_ms
+                          << "ms; diff " << diff_ms << "ms" << std::endl;
+                throw;
+            }
+        }
+    }
+
+    template<> template<>
+    void object::test<4>()
+    {
+        set_test_name("postTo");
+        WorkQueue main("main");
+        auto qptr = WorkQueue::getInstance("queue");
+        int result = 0;
+        main.postTo(
+            qptr,
+            [](){ return 17; },
+            // Note that a postTo() *callback* can safely bind a reference to
+            // a variable on the invoking thread, because the callback is run
+            // on the invoking thread. (Of course the bound variable must
+            // survive until the callback is called.)
+            [&result](int i){ result = i; });
+        // this should post the callback to main
+        qptr->runOne();
+        // this should run the callback
+        main.runOne();
+        ensure_equals("failed to run int callback", result, 17);
+
+        std::string alpha;
+        // postTo() handles arbitrary return types
+        main.postTo(
+            qptr,
+            [](){ return "abc"s; },
+            [&alpha](const std::string& s){ alpha = s; });
+        qptr->runPending();
+        main.runPending();
+        ensure_equals("failed to run string callback", alpha, "abc");
+    }
+
+    template<> template<>
+    void object::test<5>()
+    {
+        set_test_name("postTo with void return");
+        WorkQueue main("main");
+        auto qptr = WorkQueue::getInstance("queue");
+        std::string observe;
+        main.postTo(
+            qptr,
+            // The ONLY reason we can get away with binding a reference to
+            // 'observe' in our work callable is because we're directly
+            // calling qptr->runOne() on this same thread. It would be a
+            // mistake to do that if some other thread were servicing 'queue'.
+            [&observe](){ observe = "queue"; },
+            [&observe](){ observe.append(";main"); });
+        qptr->runOne();
+        main.runOne();
+        ensure_equals("failed to run both lambdas", observe, "queue;main");
+    }
+
+    template<> template<>
+    void object::test<6>()
+    {
+        set_test_name("waitForResult");
+        std::string stored;
+        // Try to call waitForResult() on this thread's main coroutine. It
+        // should throw because the main coroutine must service the queue.
+        auto what{ catch_what<WorkQueue::Error>(
+                [this, &stored](){ stored = queue.waitForResult(
+                        [](){ return "should throw"; }); }) };
+        ensure("lambda should not have run", stored.empty());
+        ensure_not("waitForResult() should have thrown", what.empty());
+        ensure(STRINGIZE("should mention waitForResult: " << what),
+               what.find("waitForResult") != std::string::npos);
+
+        // Call waitForResult() on a coroutine, with a string result.
+        LLCoros::instance().launch(
+            "waitForResult string",
+            [this, &stored]()
+            { stored = queue.waitForResult(
+                    [](){ return "string result"; }); });
+        llcoro::suspend();
+        // Nothing will have happened yet because, even if the coroutine did
+        // run immediately, all it did was to queue the inner lambda on
+        // 'queue'. Service it.
+        queue.runOne();
+        llcoro::suspend();
+        ensure_equals("bad waitForResult return", stored, "string result");
+
+        // Call waitForResult() on a coroutine, with a void callable.
+        stored.clear();
+        bool done = false;
+        LLCoros::instance().launch(
+            "waitForResult void",
+            [this, &stored, &done]()
+            {
+                queue.waitForResult([&stored](){ stored = "ran"; });
+                done = true;
+            });
+        llcoro::suspend();
+        queue.runOne();
+        llcoro::suspend();
+        ensure_equals("didn't run coroutine", stored, "ran");
+        ensure("void waitForResult() didn't return", done);
+    }
+} // namespace tut
diff --git a/indra/llcommon/threadpool.cpp b/indra/llcommon/threadpool.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..d5adf11264cfc25f8de690f545a2a80807355c50
--- /dev/null
+++ b/indra/llcommon/threadpool.cpp
@@ -0,0 +1,89 @@
+/**
+ * @file   threadpool.cpp
+ * @author Nat Goodspeed
+ * @date   2021-10-21
+ * @brief  Implementation for threadpool.
+ * 
+ * $LicenseInfo:firstyear=2021&license=viewerlgpl$
+ * Copyright (c) 2021, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+// Precompiled header
+#include "linden_common.h"
+// associated header
+#include "threadpool.h"
+// STL headers
+// std headers
+// external library headers
+// other Linden headers
+#include "llerror.h"
+#include "llevents.h"
+#include "stringize.h"
+
+LL::ThreadPool::ThreadPool(const std::string& name, size_t threads, size_t capacity):
+    super(name),
+    mQueue(name, capacity),
+    mName("ThreadPool:" + name),
+    mThreadCount(threads)
+{}
+
+void LL::ThreadPool::start()
+{
+    for (size_t i = 0; i < mThreadCount; ++i)
+    {
+        std::string tname{ stringize(mName, ':', (i+1), '/', mThreadCount) };
+        mThreads.emplace_back(tname, [this, tname]()
+            {
+                LL_PROFILER_SET_THREAD_NAME(tname.c_str());
+                run(tname);
+            });
+    }
+    // Listen on "LLApp", and when the app is shutting down, close the queue
+    // and join the workers.
+    LLEventPumps::instance().obtain("LLApp").listen(
+        mName,
+        [this](const LLSD& stat)
+        {
+            std::string status(stat["status"]);
+            if (status != "running")
+            {
+                // viewer is starting shutdown -- proclaim the end is nigh!
+                LL_DEBUGS("ThreadPool") << mName << " saw " << status << LL_ENDL;
+                close();
+            }
+            return false;
+        });
+}
+
+LL::ThreadPool::~ThreadPool()
+{
+    close();
+}
+
+void LL::ThreadPool::close()
+{
+    if (! mQueue.isClosed())
+    {
+        LL_DEBUGS("ThreadPool") << mName << " closing queue and joining threads" << LL_ENDL;
+        mQueue.close();
+        for (auto& pair: mThreads)
+        {
+            LL_DEBUGS("ThreadPool") << mName << " waiting on thread " << pair.first << LL_ENDL;
+            pair.second.join();
+        }
+        LL_DEBUGS("ThreadPool") << mName << " shutdown complete" << LL_ENDL;
+    }
+}
+
+void LL::ThreadPool::run(const std::string& name)
+{
+    LL_DEBUGS("ThreadPool") << name << " starting" << LL_ENDL;
+    run();
+    LL_DEBUGS("ThreadPool") << name << " stopping" << LL_ENDL;
+}
+
+void LL::ThreadPool::run()
+{
+    mQueue.runUntilClose();
+}
diff --git a/indra/llcommon/threadpool.h b/indra/llcommon/threadpool.h
new file mode 100644
index 0000000000000000000000000000000000000000..f8eec3b45744d8a18532811a24901fe84271f62a
--- /dev/null
+++ b/indra/llcommon/threadpool.h
@@ -0,0 +1,73 @@
+/**
+ * @file   threadpool.h
+ * @author Nat Goodspeed
+ * @date   2021-10-21
+ * @brief  ThreadPool configures a WorkQueue along with a pool of threads to
+ *         service it.
+ * 
+ * $LicenseInfo:firstyear=2021&license=viewerlgpl$
+ * Copyright (c) 2021, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+#if ! defined(LL_THREADPOOL_H)
+#define LL_THREADPOOL_H
+
+#include "workqueue.h"
+#include <string>
+#include <thread>
+#include <utility>                  // std::pair
+#include <vector>
+
+namespace LL
+{
+
+    class ThreadPool: public LLInstanceTracker<ThreadPool, std::string>
+    {
+    private:
+        using super = LLInstanceTracker<ThreadPool, std::string>;
+    public:
+        /**
+         * Pass ThreadPool a string name. This can be used to look up the
+         * relevant WorkQueue.
+         */
+        ThreadPool(const std::string& name, size_t threads=1, size_t capacity=1024);
+        virtual ~ThreadPool();
+
+        /**
+         * Launch the ThreadPool. Until this call, a constructed ThreadPool
+         * launches no threads. That permits coders to derive from ThreadPool,
+         * or store it as a member of some other class, but refrain from
+         * launching it until all other construction is complete.
+         */
+        void start();
+
+        /**
+         * ThreadPool listens for application shutdown messages on the "LLApp"
+         * LLEventPump. Call close() to shut down this ThreadPool early.
+         */
+        void close();
+
+        std::string getName() const { return mName; }
+        size_t getWidth() const { return mThreads.size(); }
+        /// obtain a non-const reference to the WorkQueue to post work to it
+        WorkQueue& getQueue() { return mQueue; }
+
+        /**
+         * Override run() if you need special processing. The default run()
+         * implementation simply calls WorkQueue::runUntilClose().
+         */
+        virtual void run();
+
+    private:
+        void run(const std::string& name);
+
+        WorkQueue mQueue;
+        std::string mName;
+        size_t mThreadCount;
+        std::vector<std::pair<std::string, std::thread>> mThreads;
+    };
+
+} // namespace LL
+
+#endif /* ! defined(LL_THREADPOOL_H) */
diff --git a/indra/llcommon/threadsafeschedule.h b/indra/llcommon/threadsafeschedule.h
new file mode 100644
index 0000000000000000000000000000000000000000..3e0da94c0278054c894f248bf613ee222f55de00
--- /dev/null
+++ b/indra/llcommon/threadsafeschedule.h
@@ -0,0 +1,399 @@
+/**
+ * @file   threadsafeschedule.h
+ * @author Nat Goodspeed
+ * @date   2021-10-02
+ * @brief  ThreadSafeSchedule is an ordered queue in which every item has an
+ *         associated timestamp.
+ * 
+ * $LicenseInfo:firstyear=2021&license=viewerlgpl$
+ * Copyright (c) 2021, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+#if ! defined(LL_THREADSAFESCHEDULE_H)
+#define LL_THREADSAFESCHEDULE_H
+
+#include "chrono.h"
+#include "llexception.h"
+#include "llthreadsafequeue.h"
+#include "tuple.h"
+#include <chrono>
+#include <tuple>  
+
+namespace LL
+{
+    namespace ThreadSafeSchedulePrivate
+    {
+        using TimePoint = std::chrono::steady_clock::time_point;
+        // Bundle consumer's data with a TimePoint to order items by timestamp.
+        template <typename... Args>
+        using TimestampedTuple = std::tuple<TimePoint, Args...>;
+
+        // comparison functor for TimedTuples -- see TimedQueue comments
+        struct ReverseTupleOrder
+        {
+            template <typename Tuple>
+            bool operator()(const Tuple& left, const Tuple& right) const
+            {
+                return std::get<0>(left) > std::get<0>(right);
+            }
+        };
+
+        template <typename... Args>
+        using TimedQueue = PriorityQueueAdapter<
+            TimestampedTuple<Args...>,
+            // std::vector is the default storage for std::priority_queue,
+            // have to restate to specify comparison template parameter
+            std::vector<TimestampedTuple<Args...>>,
+            // std::priority_queue uses a counterintuitive comparison
+            // behavior: the default std::less comparator is used to present
+            // the *highest* value as top(). So to sort by earliest timestamp,
+            // we must invert by using >.
+            ReverseTupleOrder>;
+    } // namespace ThreadSafeSchedulePrivate
+
+    /**
+     * ThreadSafeSchedule is an ordered LLThreadSafeQueue in which every item
+     * is given an associated timestamp. That is, TimePoint is implicitly
+     * prepended to the std::tuple with the specified types.
+     *
+     * Items are popped in increasing chronological order. Moreover, any item
+     * with a timestamp in the future is held back until
+     * std::chrono::steady_clock reaches that timestamp.
+     */
+    template <typename... Args>
+    class ThreadSafeSchedule:
+        public LLThreadSafeQueue<ThreadSafeSchedulePrivate::TimestampedTuple<Args...>,
+                                 ThreadSafeSchedulePrivate::TimedQueue<Args...>>
+    {
+    public:
+        using DataTuple = std::tuple<Args...>;
+        using TimeTuple = ThreadSafeSchedulePrivate::TimestampedTuple<Args...>;
+
+    private:
+        using super = LLThreadSafeQueue<TimeTuple, ThreadSafeSchedulePrivate::TimedQueue<Args...>>;
+        using lock_t = typename super::lock_t;
+        // VS 2017 needs this due to a bug:
+        // https://developercommunity.visualstudio.com/t/cannot-access-protected-enumerator-of-enclosing-cl/203430
+        enum pop_result { EMPTY=super::EMPTY, DONE=super::DONE, WAITING=super::WAITING, POPPED=super::POPPED };
+
+    public:
+        using Closed = LLThreadSafeQueueInterrupt;
+        using TimePoint = ThreadSafeSchedulePrivate::TimePoint;
+        using Clock = TimePoint::clock;
+
+        ThreadSafeSchedule(U32 capacity=1024):
+            super(capacity)
+        {}
+
+        /*----------------------------- push() -----------------------------*/
+        /// explicitly pass TimeTuple
+        using super::push;
+
+        /// pass DataTuple with implicit now
+        // This could be ambiguous for Args with a single type. Unfortunately
+        // we can't enable_if an individual method with a condition based on
+        // the *class* template arguments, only on that method's template
+        // arguments. We could specialize this class for the single-Args case;
+        // we could minimize redundancy by breaking out a common base class...
+        void push(const DataTuple& tuple)
+        {
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
+            push(tuple_cons(Clock::now(), tuple));
+        }
+
+        /// individually pass each component of the TimeTuple
+        void push(const TimePoint& time, Args&&... args)
+        {
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
+            push(TimeTuple(time, std::forward<Args>(args)...));
+        }
+
+        /// individually pass every component except the TimePoint (implies now)
+        // This could be ambiguous if the first specified template parameter
+        // type is also TimePoint. We could try to disambiguate, but a simpler
+        // approach would be for the caller to explicitly construct DataTuple
+        // and call that overload.
+        void push(Args&&... args)
+        {
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
+            push(Clock::now(), std::forward<Args>(args)...);
+        }
+
+        /*--------------------------- tryPush() ----------------------------*/
+        /// explicit TimeTuple
+        using super::tryPush;
+
+        /// DataTuple with implicit now
+        bool tryPush(const DataTuple& tuple)
+        {
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
+            return tryPush(tuple_cons(Clock::now(), tuple));
+        }
+
+        /// individually pass components
+        bool tryPush(const TimePoint& time, Args&&... args)
+        {
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
+            return tryPush(TimeTuple(time, std::forward<Args>(args)...));
+        }
+
+        /// individually pass components with implicit now
+        bool tryPush(Args&&... args)
+        {
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
+            return tryPush(Clock::now(), std::forward<Args>(args)...);
+        }
+
+        /*-------------------------- tryPushFor() --------------------------*/
+        /// explicit TimeTuple
+        using super::tryPushFor;
+
+        /// DataTuple with implicit now
+        template <typename Rep, typename Period>
+        bool tryPushFor(const std::chrono::duration<Rep, Period>& timeout,
+                        const DataTuple& tuple)
+        {
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
+            return tryPushFor(timeout, tuple_cons(Clock::now(), tuple));
+        }
+
+        /// individually pass components
+        template <typename Rep, typename Period>
+        bool tryPushFor(const std::chrono::duration<Rep, Period>& timeout,
+                        const TimePoint& time, Args&&... args)
+        {
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
+            return tryPushFor(TimeTuple(time, std::forward<Args>(args)...));
+        }
+
+        /// individually pass components with implicit now
+        template <typename Rep, typename Period>
+        bool tryPushFor(const std::chrono::duration<Rep, Period>& timeout,
+                        Args&&... args)
+        {
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
+            return tryPushFor(Clock::now(), std::forward<Args>(args)...);
+        }
+
+        /*------------------------- tryPushUntil() -------------------------*/
+        /// explicit TimeTuple
+        using super::tryPushUntil;
+
+        /// DataTuple with implicit now
+        template <typename Clock, typename Duration>
+        bool tryPushUntil(const std::chrono::time_point<Clock, Duration>& until,
+                          const DataTuple& tuple)
+        {
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
+            return tryPushUntil(until, tuple_cons(Clock::now(), tuple));
+        }
+
+        /// individually pass components
+        template <typename Clock, typename Duration>
+        bool tryPushUntil(const std::chrono::time_point<Clock, Duration>& until,
+                          const TimePoint& time, Args&&... args)
+        {
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
+            return tryPushUntil(until, TimeTuple(time, std::forward<Args>(args)...));
+        }
+
+        /// individually pass components with implicit now
+        template <typename Clock, typename Duration>
+        bool tryPushUntil(const std::chrono::time_point<Clock, Duration>& until,
+                          Args&&... args)
+        {
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
+            return tryPushUntil(until, Clock::now(), std::forward<Args>(args)...);
+        }
+
+        /*----------------------------- pop() ------------------------------*/
+        // Our consumer may or may not care about the timestamp associated
+        // with each popped item, so we allow retrieving either DataTuple or
+        // TimeTuple. One potential use would be to observe, and possibly
+        // adjust for, the time lag between the item time and the actual
+        // current time.
+
+        /// pop DataTuple by value
+        // It would be great to notice when sizeof...(Args) == 1 and directly
+        // return the first (only) value, instead of making pop()'s caller
+        // call std::get<0>(value). See push(DataTuple) remarks for why we
+        // haven't yet jumped through those hoops.
+        DataTuple pop()
+        {
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
+            return tuple_cdr(popWithTime());
+        }
+
+        /// pop TimeTuple by value
+        TimeTuple popWithTime()
+        {
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
+            lock_t lock(super::mLock);
+            // We can't just sit around waiting forever, given that there may
+            // be items in the queue that are not yet ready but will *become*
+            // ready in the near future. So in fact, with this class, every
+            // pop() becomes a tryPopUntil(), constrained to the timestamp of
+            // the head item. It almost doesn't matter what we specify for the
+            // caller's time constraint -- all we really care about is the
+            // head item's timestamp. Since pop() and popWithTime() are
+            // defined to wait until either an item becomes available or the
+            // queue is closed, loop until one of those things happens. The
+            // constraint we pass just determines how often we'll loop while
+            // waiting.
+            TimeTuple tt;
+            while (true)
+            {
+                // Pick a point suitably far into the future.
+                TimePoint until = TimePoint::clock::now() + std::chrono::hours(24);
+                pop_result popped = tryPopUntil_(lock, until, tt);
+                if (popped == POPPED)
+                    return std::move(tt);
+
+                // DONE: throw, just as super::pop() does
+                if (popped == DONE)
+                {
+                    LLTHROW(LLThreadSafeQueueInterrupt());
+                }
+                // WAITING: we've still got items to drain.
+                // EMPTY: not closed, so it's worth waiting for more items.
+                // Either way, loop back to wait.
+            }
+        }
+
+        // We can use tryPop(TimeTuple&) just as it stands; the only behavior
+        // difference is in our canPop() override method.
+        using super::tryPop;
+
+        /// tryPop(DataTuple&)
+        bool tryPop(DataTuple& tuple)
+        {
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
+            TimeTuple tt;
+            if (! super::tryPop(tt))
+                return false;
+            tuple = tuple_cdr(std::move(tt));
+            return true;
+        }
+
+        /// for when Args has exactly one type
+        bool tryPop(typename std::tuple_element<1, TimeTuple>::type& value)
+        {
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
+            TimeTuple tt;
+            if (! super::tryPop(tt))
+                return false;
+            value = std::get<1>(std::move(tt));
+            return true;
+        }
+
+        /// tryPopFor()
+        template <typename Rep, typename Period, typename Tuple>
+        bool tryPopFor(const std::chrono::duration<Rep, Period>& timeout, Tuple& tuple)
+        {
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
+            // It's important to use OUR tryPopUntil() implementation, rather
+            // than delegating immediately to our base class.
+            return tryPopUntil(Clock::now() + timeout, tuple);
+        }
+
+        /// tryPopUntil(TimeTuple&)
+        template <typename Clock, typename Duration>
+        bool tryPopUntil(const std::chrono::time_point<Clock, Duration>& until,
+                         TimeTuple& tuple)
+        {
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
+            // super::tryPopUntil() wakes up when an item becomes available or
+            // we hit 'until', whichever comes first. Thing is, the current
+            // head of the queue could become ready sooner than either of
+            // those events, and we need to deliver it as soon as it does.
+            // Don't wait past the TimePoint of the head item.
+            // Naturally, lock the queue before peeking at mStorage.
+            return super::tryLockUntil(
+                until,
+                [this, until, &tuple](lock_t& lock)
+                {
+                    // Use our time_point_cast to allow for 'until' that's a
+                    // time_point type other than TimePoint.
+                    return POPPED ==
+                        tryPopUntil_(lock, LL::time_point_cast<TimePoint>(until), tuple);
+                });
+        }
+
+        pop_result tryPopUntil_(lock_t& lock, const TimePoint& until, TimeTuple& tuple)
+        {
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
+            TimePoint adjusted = until;
+            if (! super::mStorage.empty())
+            {
+                LL_PROFILE_ZONE_NAMED("tpu - adjust");
+                // use whichever is earlier: the head item's timestamp, or
+                // the caller's limit
+                adjusted = min(std::get<0>(super::mStorage.front()), adjusted);
+            }
+            // now delegate to base-class tryPopUntil_()
+            pop_result popped;
+            {
+                LL_PROFILE_ZONE_NAMED("tpu - super");
+                while ((popped = pop_result(super::tryPopUntil_(lock, adjusted, tuple))) == WAITING)
+                {
+                    // If super::tryPopUntil_() returns WAITING, it means there's
+                    // a head item, but it's not yet time. But it's worth looping
+                    // back to recheck.
+                }
+            }
+            return popped;
+        }
+
+        /// tryPopUntil(DataTuple&)
+        template <typename Clock, typename Duration>
+        bool tryPopUntil(const std::chrono::time_point<Clock, Duration>& until,
+                         DataTuple& tuple)
+        {
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
+            TimeTuple tt;
+            if (! tryPopUntil(until, tt))
+                return false;
+            tuple = tuple_cdr(std::move(tt));
+            return true;
+        }
+
+        /// for when Args has exactly one type
+        template <typename Clock, typename Duration>
+        bool tryPopUntil(const std::chrono::time_point<Clock, Duration>& until,
+                         typename std::tuple_element<1, TimeTuple>::type& value)
+        {
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
+            TimeTuple tt;
+            if (! tryPopUntil(until, tt))
+                return false;
+            value = std::get<1>(std::move(tt));
+            return true;
+        }
+
+        /*------------------------------ etc. ------------------------------*/
+        // We can't hide items that aren't yet ready because we can't traverse
+        // the underlying priority_queue: it has no iterators, only top(). So
+        // a consumer could observe size() > 0 and yet tryPop() returns false.
+        // Shrug, in a multi-consumer scenario that would be expected behavior.
+        using super::size;
+        // open/closed state
+        using super::close;
+        using super::isClosed;
+        using super::done;
+
+    private:
+        // this method is called by base class pop_() every time we're
+        // considering whether to deliver the current head element
+        bool canPop(const TimeTuple& head) const override
+        {
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
+            // an item with a future timestamp isn't yet ready to pop
+            // (should we add some slop for overhead?)
+            return std::get<0>(head) <= Clock::now();
+        }
+    };
+
+} // namespace LL
+
+#endif /* ! defined(LL_THREADSAFESCHEDULE_H) */
diff --git a/indra/llcommon/tuple.h b/indra/llcommon/tuple.h
new file mode 100644
index 0000000000000000000000000000000000000000..bfe7e3c2bad434a3e575fd75015597486c3e3141
--- /dev/null
+++ b/indra/llcommon/tuple.h
@@ -0,0 +1,84 @@
+/**
+ * @file   tuple.h
+ * @author Nat Goodspeed
+ * @date   2021-10-04
+ * @brief  A couple tuple utilities
+ * 
+ * $LicenseInfo:firstyear=2021&license=viewerlgpl$
+ * Copyright (c) 2021, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+#if ! defined(LL_TUPLE_H)
+#define LL_TUPLE_H
+
+#include <tuple>
+#include <type_traits>              // std::remove_reference
+#include <utility>                  // std::pair
+
+/**
+ * tuple_cons() behaves like LISP cons: it uses std::tuple_cat() to prepend a
+ * new item of arbitrary type to an existing std::tuple.
+ */
+template <typename First, typename... Rest, typename Tuple_=std::tuple<Rest...>>
+auto tuple_cons(First&& first, Tuple_&& rest)
+{
+    // All we need to do is make a tuple containing 'first', and let
+    // tuple_cat() do the hard part.
+    return std::tuple_cat(std::tuple<First>(std::forward<First>(first)),
+                          std::forward<Tuple_>(rest));
+}
+
+/**
+ * tuple_car() behaves like LISP car: it extracts the first item from a
+ * std::tuple.
+ */
+template <typename... Args, typename Tuple_=std::tuple<Args...>>
+auto tuple_car(Tuple_&& tuple)
+{
+    return std::get<0>(std::forward<Tuple_>(tuple));
+}
+
+/**
+ * tuple_cdr() behaves like LISP cdr: it returns a new tuple containing
+ * everything BUT the first item.
+ */
+// derived from https://stackoverflow.com/a/24046437
+template <typename Tuple, std::size_t... Indices>
+auto tuple_cdr_(Tuple&& tuple, const std::index_sequence<Indices...>)
+{
+    // Given an index sequence from [0..N-1), extract tuple items [1..N)
+    return std::make_tuple(std::get<Indices+1u>(std::forward<Tuple>(tuple))...);
+}
+
+template <typename Tuple>
+auto tuple_cdr(Tuple&& tuple)
+{
+    return tuple_cdr_(
+        std::forward<Tuple>(tuple),
+        // Pass helper function an index sequence one item shorter than tuple
+        std::make_index_sequence<
+            std::tuple_size<
+                // tuple_size doesn't like reference types
+                typename std::remove_reference<Tuple>::type
+            >::value - 1u>
+        ());
+}
+
+/**
+ * tuple_split(), the opposite of tuple_cons(), has no direct analog in LISP.
+ * It returns a std::pair of tuple_car(), tuple_cdr(). We could call this
+ * function tuple_car_cdr(), or tuple_slice() or some such. But tuple_split()
+ * feels more descriptive.
+ */
+template <typename... Args, typename Tuple_=std::tuple<Args...>>
+auto tuple_split(Tuple_&& tuple)
+{
+    // We're not really worried about forwarding multiple times a tuple that
+    // might contain move-only items, because the implementation above only
+    // applies std::get() exactly once to each item.
+    return std::make_pair(tuple_car(std::forward<Tuple_>(tuple)),
+                          tuple_cdr(std::forward<Tuple_>(tuple)));
+}
+
+#endif /* ! defined(LL_TUPLE_H) */
diff --git a/indra/llcommon/workqueue.cpp b/indra/llcommon/workqueue.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..eb06890468b7ae73b874fe7bd6d75c57354bee53
--- /dev/null
+++ b/indra/llcommon/workqueue.cpp
@@ -0,0 +1,158 @@
+/**
+ * @file   workqueue.cpp
+ * @author Nat Goodspeed
+ * @date   2021-10-06
+ * @brief  Implementation for WorkQueue.
+ * 
+ * $LicenseInfo:firstyear=2021&license=viewerlgpl$
+ * Copyright (c) 2021, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+// Precompiled header
+#include "linden_common.h"
+// associated header
+#include "workqueue.h"
+// STL headers
+// std headers
+// external library headers
+// other Linden headers
+#include "llcoros.h"
+#include LLCOROS_MUTEX_HEADER
+#include "llerror.h"
+#include "llexception.h"
+#include "stringize.h"
+
+using Mutex = LLCoros::Mutex;
+using Lock  = LLCoros::LockType;
+
+LL::WorkQueue::WorkQueue(const std::string& name, size_t capacity):
+    super(makeName(name)),
+    mQueue(capacity)
+{
+    // TODO: register for "LLApp" events so we can implicitly close() on
+    // viewer shutdown.
+}
+
+void LL::WorkQueue::close()
+{
+    mQueue.close();
+}
+
+size_t LL::WorkQueue::size()
+{
+    return mQueue.size();
+}
+
+bool LL::WorkQueue::isClosed()
+{
+    return mQueue.isClosed();
+}
+
+bool LL::WorkQueue::done()
+{
+    return mQueue.done();
+}
+
+void LL::WorkQueue::runUntilClose()
+{
+    try
+    {
+        for (;;)
+        {
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
+            callWork(mQueue.pop());
+        }
+    }
+    catch (const Queue::Closed&)
+    {
+    }
+}
+
+bool LL::WorkQueue::runPending()
+{
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
+    for (Work work; mQueue.tryPop(work); )
+    {
+        callWork(work);
+    }
+    return ! mQueue.done();
+}
+
+bool LL::WorkQueue::runOne()
+{
+    Work work;
+    if (mQueue.tryPop(work))
+    {
+        callWork(work);
+    }
+    return ! mQueue.done();
+}
+
+bool LL::WorkQueue::runUntil(const TimePoint& until)
+{
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
+    // Should we subtract some slop to allow for typical Work execution time?
+    // How much slop?
+    // runUntil() is simply a time-bounded runPending().
+    for (Work work; TimePoint::clock::now() < until && mQueue.tryPop(work); )
+    {
+        callWork(work);
+    }
+    return ! mQueue.done();
+}
+
+std::string LL::WorkQueue::makeName(const std::string& name)
+{
+    if (! name.empty())
+        return name;
+
+    static U32 discriminator = 0;
+    static Mutex mutex;
+    U32 num;
+    {
+        // Protect discriminator from concurrent access by different threads.
+        // It can't be thread_local, else two racing threads will come up with
+        // the same name.
+        Lock lk(mutex);
+        num = discriminator++;
+    }
+    return STRINGIZE("WorkQueue" << num);
+}
+
+void LL::WorkQueue::callWork(const Queue::DataTuple& work)
+{
+    // ThreadSafeSchedule::pop() always delivers a tuple, even when
+    // there's only one data field per item, as for us.
+    callWork(std::get<0>(work));
+}
+
+void LL::WorkQueue::callWork(const Work& work)
+{
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
+    try
+    {
+        work();
+    }
+    catch (...)
+    {
+        // No matter what goes wrong with any individual work item, the worker
+        // thread must go on! Log our own instance name with the exception.
+        LOG_UNHANDLED_EXCEPTION(getKey());
+    }
+}
+
+void LL::WorkQueue::error(const std::string& msg)
+{
+    LL_ERRS("WorkQueue") << msg << LL_ENDL;
+}
+
+void LL::WorkQueue::checkCoroutine(const std::string& method)
+{
+    // By convention, the default coroutine on each thread has an empty name
+    // string. See also LLCoros::logname().
+    if (LLCoros::getName().empty())
+    {
+        LLTHROW(Error("Do not call " + method + " from a thread's default coroutine"));
+    }
+}
diff --git a/indra/llcommon/workqueue.h b/indra/llcommon/workqueue.h
new file mode 100644
index 0000000000000000000000000000000000000000..70fd65bd0cd71c1f6e5c9dd86639f45ef7c4cb5f
--- /dev/null
+++ b/indra/llcommon/workqueue.h
@@ -0,0 +1,574 @@
+/**
+ * @file   workqueue.h
+ * @author Nat Goodspeed
+ * @date   2021-09-30
+ * @brief  Queue used for inter-thread work passing.
+ * 
+ * $LicenseInfo:firstyear=2021&license=viewerlgpl$
+ * Copyright (c) 2021, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+#if ! defined(LL_WORKQUEUE_H)
+#define LL_WORKQUEUE_H
+
+#include "llcoros.h"
+#include "llexception.h"
+#include "llinstancetracker.h"
+#include "threadsafeschedule.h"
+#include <chrono>
+#include <exception>                // std::current_exception
+#include <functional>               // std::function
+#include <string>
+
+namespace LL
+{
+    /**
+     * A typical WorkQueue has a string name that can be used to find it.
+     */
+    class WorkQueue: public LLInstanceTracker<WorkQueue, std::string>
+    {
+    private:
+        using super = LLInstanceTracker<WorkQueue, std::string>;
+
+    public:
+        using Work = std::function<void()>;
+
+    private:
+        using Queue = ThreadSafeSchedule<Work>;
+        // helper for postEvery()
+        template <typename Rep, typename Period, typename CALLABLE>
+        class BackJack;
+
+    public:
+        using TimePoint = Queue::TimePoint;
+        using TimedWork = Queue::TimeTuple;
+        using Closed    = Queue::Closed;
+
+        struct Error: public LLException
+        {
+            Error(const std::string& what): LLException(what) {}
+        };
+
+        /**
+         * You may omit the WorkQueue name, in which case a unique name is
+         * synthesized; for practical purposes that makes it anonymous.
+         */
+        WorkQueue(const std::string& name = std::string(), size_t capacity=1024);
+
+        /**
+         * Since the point of WorkQueue is to pass work to some other worker
+         * thread(s) asynchronously, it's important that the WorkQueue continue
+         * to exist until the worker thread(s) have drained it. To communicate
+         * that it's time for them to quit, close() the queue.
+         */
+        void close();
+
+        /**
+         * WorkQueue supports multiple producers and multiple consumers. In
+         * the general case it's misleading to test size(), since any other
+         * thread might change it the nanosecond the lock is released. On that
+         * basis, some might argue against publishing a size() method at all.
+         *
+         * But there are two specific cases in which a test based on size()
+         * might be reasonable:
+         *
+         * * If you're the only producer, noticing that size() == 0 is
+         *   meaningful.
+         * * If you're the only consumer, noticing that size() > 0 is
+         *   meaningful.
+         */
+        size_t size();
+        /// producer end: are we prevented from pushing any additional items?
+        bool isClosed();
+        /// consumer end: are we done, is the queue entirely drained?
+        bool done();
+
+        /*---------------------- fire and forget API -----------------------*/
+
+        /// fire-and-forget, but at a particular (future?) time
+        template <typename CALLABLE>
+        void post(const TimePoint& time, CALLABLE&& callable)
+        {
+            // Defer reifying an arbitrary CALLABLE until we hit this or
+            // postIfOpen(). All other methods should accept CALLABLEs of
+            // arbitrary type to avoid multiple levels of std::function
+            // indirection.
+            mQueue.push(TimedWork(time, std::move(callable)));
+        }
+
+        /// fire-and-forget
+        template <typename CALLABLE>
+        void post(CALLABLE&& callable)
+        {
+            // We use TimePoint::clock::now() instead of TimePoint's
+            // representation of the epoch because this WorkQueue may contain
+            // a mix of past-due TimedWork items and TimedWork items scheduled
+            // for the future. Sift this new item into the correct place.
+            post(TimePoint::clock::now(), std::move(callable));
+        }
+
+        /**
+         * post work for a particular time, unless the queue is closed before
+         * we can post
+         */
+        template <typename CALLABLE>
+        bool postIfOpen(const TimePoint& time, CALLABLE&& callable)
+        {
+            // Defer reifying an arbitrary CALLABLE until we hit this or
+            // post(). All other methods should accept CALLABLEs of arbitrary
+            // type to avoid multiple levels of std::function indirection.
+            return mQueue.pushIfOpen(TimedWork(time, std::move(callable)));
+        }
+
+        /**
+         * post work, unless the queue is closed before we can post
+         */
+        template <typename CALLABLE>
+        bool postIfOpen(CALLABLE&& callable)
+        {
+            return postIfOpen(TimePoint::clock::now(), std::move(callable));
+        }
+
+        /**
+         * Post work to be run at a specified time to another WorkQueue, which
+         * may or may not still exist and be open. Return true if we were able
+         * to post.
+         */
+        template <typename CALLABLE>
+        static bool postMaybe(weak_t target, const TimePoint& time, CALLABLE&& callable);
+
+        /**
+         * Post work to another WorkQueue, which may or may not still exist
+         * and be open. Return true if we were able to post.
+         */
+        template <typename CALLABLE>
+        static bool postMaybe(weak_t target, CALLABLE&& callable)
+        {
+            return postMaybe(target, TimePoint::clock::now(),
+                             std::forward<CALLABLE>(callable));
+        }
+
+        /**
+         * Launch a callable returning bool that will trigger repeatedly at
+         * specified interval, until the callable returns false.
+         *
+         * If you need to signal that callable from outside, DO NOT bind a
+         * reference to a simple bool! That's not thread-safe. Instead, bind
+         * an LLCond variant, e.g. LLOneShotCond or LLBoolCond.
+         */
+        template <typename Rep, typename Period, typename CALLABLE>
+        void postEvery(const std::chrono::duration<Rep, Period>& interval,
+                       CALLABLE&& callable);
+
+        template <typename CALLABLE>
+        bool tryPost(CALLABLE&& callable)
+        {
+            return mQueue.tryPush(TimedWork(TimePoint::clock::now(), std::move(callable)));
+        }
+
+        /*------------------------- handshake API --------------------------*/
+
+        /**
+         * Post work to another WorkQueue to be run at a specified time,
+         * requesting a specific callback to be run on this WorkQueue on
+         * completion.
+         *
+         * Returns true if able to post, false if the other WorkQueue is
+         * inaccessible.
+         */
+        // Apparently some Microsoft header file defines a macro CALLBACK? The
+        // natural template argument name CALLBACK produces very weird Visual
+        // Studio compile errors that seem utterly unrelated to this source
+        // code.
+        template <typename CALLABLE, typename FOLLOWUP>
+        bool postTo(weak_t target,
+                    const TimePoint& time, CALLABLE&& callable, FOLLOWUP&& callback);
+
+        /**
+         * Post work to another WorkQueue, requesting a specific callback to
+         * be run on this WorkQueue on completion.
+         *
+         * Returns true if able to post, false if the other WorkQueue is
+         * inaccessible.
+         */
+        template <typename CALLABLE, typename FOLLOWUP>
+        bool postTo(weak_t target, CALLABLE&& callable, FOLLOWUP&& callback)
+        {
+            return postTo(target, TimePoint::clock::now(),
+                          std::move(callable), std::move(callback));
+        }
+
+        /**
+         * Post work to another WorkQueue to be run at a specified time,
+         * blocking the calling coroutine until then, returning the result to
+         * caller on completion.
+         *
+         * In general, we assume that each thread's default coroutine is busy
+         * servicing its WorkQueue or whatever. To try to prevent mistakes, we
+         * forbid calling waitForResult() from a thread's default coroutine.
+         */
+        template <typename CALLABLE>
+        auto waitForResult(const TimePoint& time, CALLABLE&& callable);
+
+        /**
+         * Post work to another WorkQueue, blocking the calling coroutine
+         * until then, returning the result to caller on completion.
+         *
+         * In general, we assume that each thread's default coroutine is busy
+         * servicing its WorkQueue or whatever. To try to prevent mistakes, we
+         * forbid calling waitForResult() from a thread's default coroutine.
+         */
+        template <typename CALLABLE>
+        auto waitForResult(CALLABLE&& callable)
+        {
+            return waitForResult(TimePoint::clock::now(), std::move(callable));
+        }
+
+        /*--------------------------- worker API ---------------------------*/
+
+        /**
+         * runUntilClose() pulls TimedWork items off this WorkQueue until the
+         * queue is closed, at which point it returns. This would be the
+         * typical entry point for a simple worker thread.
+         */
+        void runUntilClose();
+
+        /**
+         * runPending() runs all TimedWork items that are ready to run. It
+         * returns true if the queue remains open, false if the queue has been
+         * closed. This could be used by a thread whose primary purpose is to
+         * serve the queue, but also wants to do other things with its idle time.
+         */
+        bool runPending();
+
+        /**
+         * runOne() runs at most one ready TimedWork item -- zero if none are
+         * ready. It returns true if the queue remains open, false if the
+         * queue has been closed.
+         */
+        bool runOne();
+
+        /**
+         * runFor() runs a subset of ready TimedWork items, until the
+         * timeslice has been exceeded. It returns true if the queue remains
+         * open, false if the queue has been closed. This could be used by a
+         * busy main thread to lend a bounded few CPU cycles to this WorkQueue
+         * without risking the WorkQueue blowing out the length of any one
+         * frame.
+         */
+        template <typename Rep, typename Period>
+        bool runFor(const std::chrono::duration<Rep, Period>& timeslice)
+        {
+            LL_PROFILE_ZONE_SCOPED;
+            return runUntil(TimePoint::clock::now() + timeslice);
+        }
+
+        /**
+         * runUntil() is just like runFor(), only with a specific end time
+         * instead of a timeslice duration.
+         */
+        bool runUntil(const TimePoint& until);
+
+    private:
+        template <typename CALLABLE, typename FOLLOWUP>
+        static auto makeReplyLambda(CALLABLE&& callable, FOLLOWUP&& callback);
+        /// general case: arbitrary C++ return type
+        template <typename CALLABLE, typename FOLLOWUP, typename RETURNTYPE>
+        struct MakeReplyLambda;
+        /// specialize for CALLABLE returning void
+        template <typename CALLABLE, typename FOLLOWUP>
+        struct MakeReplyLambda<CALLABLE, FOLLOWUP, void>;
+
+        /// general case: arbitrary C++ return type
+        template <typename CALLABLE, typename RETURNTYPE>
+        struct WaitForResult;
+        /// specialize for CALLABLE returning void
+        template <typename CALLABLE>
+        struct WaitForResult<CALLABLE, void>;
+
+        static void checkCoroutine(const std::string& method);
+        static void error(const std::string& msg);
+        static std::string makeName(const std::string& name);
+        void callWork(const Queue::DataTuple& work);
+        void callWork(const Work& work);
+        Queue mQueue;
+    };
+
+    /**
+     * BackJack is, in effect, a hand-rolled lambda, binding a WorkQueue, a
+     * CALLABLE that returns bool, a TimePoint and an interval at which to
+     * relaunch it. As long as the callable continues returning true, BackJack
+     * keeps resubmitting it to the target WorkQueue.
+     */
+    // Why is BackJack a class and not a lambda? Because, unlike a lambda, a
+    // class method gets its own 'this' pointer -- which we need to resubmit
+    // the whole BackJack callable.
+    template <typename Rep, typename Period, typename CALLABLE>
+    class WorkQueue::BackJack
+    {
+    public:
+        // bind the desired data
+        BackJack(weak_t target,
+                 const TimePoint& start,
+                 const std::chrono::duration<Rep, Period>& interval,
+                 CALLABLE&& callable):
+            mTarget(target),
+            mStart(start),
+            mInterval(interval),
+            mCallable(std::move(callable))
+        {}
+
+        // Call by target WorkQueue -- note that although WE require a
+        // callable returning bool, WorkQueue wants a void callable. We
+        // consume the bool.
+        void operator()()
+        {
+            // If mCallable() throws an exception, don't catch it here: if it
+            // throws once, it's likely to throw every time, so it's a waste
+            // of time to arrange to call it again.
+            if (mCallable())
+            {
+                // Modify mStart to the new start time we desire. If we simply
+                // added mInterval to now, we'd get actual timings of
+                // (mInterval + slop), where 'slop' is the latency between the
+                // previous mStart and the WorkQueue actually calling us.
+                // Instead, add mInterval to mStart so that at least we
+                // register our intent to fire at exact mIntervals.
+                mStart += mInterval;
+
+                // We're being called at this moment by the target WorkQueue.
+                // Assume it still exists, rather than checking the result of
+                // lock().
+                // Resubmit the whole *this callable: that's why we're a class
+                // rather than a lambda. Allow moving *this so we can carry a
+                // move-only callable; but naturally this statement must be
+                // the last time we reference this instance, which may become
+                // moved-from.
+                try
+                {
+                    mTarget.lock()->post(mStart, std::move(*this));
+                }
+                catch (const Closed&)
+                {
+                    // Once this queue is closed, oh well, just stop
+                }
+            }
+        }
+
+    private:
+        weak_t mTarget;
+        TimePoint mStart;
+        std::chrono::duration<Rep, Period> mInterval;
+        CALLABLE mCallable;
+    };
+
+    template <typename Rep, typename Period, typename CALLABLE>
+    void WorkQueue::postEvery(const std::chrono::duration<Rep, Period>& interval,
+                              CALLABLE&& callable)
+    {
+        if (interval.count() <= 0)
+        {
+            // It's essential that postEvery() be called with a positive
+            // interval, since each call to BackJack posts another instance of
+            // itself at (start + interval) and we order by target time. A
+            // zero or negative interval would result in that BackJack
+            // instance going to the head of the queue every time, immediately
+            // ready to run. Effectively that would produce an infinite loop,
+            // a denial of service on this WorkQueue.
+            error("postEvery(interval) may not be 0");
+        }
+        // Instantiate and post a suitable BackJack, binding a weak_ptr to
+        // self, the current time, the desired interval and the desired
+        // callable.
+        post(
+            BackJack<Rep, Period, CALLABLE>(
+                 getWeak(), TimePoint::clock::now(), interval, std::move(callable)));
+    }
+
+    /// general case: arbitrary C++ return type
+    template <typename CALLABLE, typename FOLLOWUP, typename RETURNTYPE>
+    struct WorkQueue::MakeReplyLambda
+    {
+        auto operator()(CALLABLE&& callable, FOLLOWUP&& callback)
+        {
+            // Call the callable in any case -- but to minimize
+            // copying the result, immediately bind it into the reply
+            // lambda. The reply lambda also binds the original
+            // callback, so that when we, the originating WorkQueue,
+            // finally receive and process the reply lambda, we'll
+            // call the bound callback with the bound result -- on the
+            // same thread that originally called postTo().
+            return
+                [result = std::forward<CALLABLE>(callable)(),
+                 callback = std::move(callback)]
+                ()
+                mutable { callback(std::move(result)); };
+        }
+    };
+
+    /// specialize for CALLABLE returning void
+    template <typename CALLABLE, typename FOLLOWUP>
+    struct WorkQueue::MakeReplyLambda<CALLABLE, FOLLOWUP, void>
+    {
+        auto operator()(CALLABLE&& callable, FOLLOWUP&& callback)
+        {
+            // Call the callable, which produces no result.
+            std::forward<CALLABLE>(callable)();
+            // Our completion callback is simply the caller's callback.
+            return std::move(callback);
+        }
+    };
+
+    template <typename CALLABLE, typename FOLLOWUP>
+    auto WorkQueue::makeReplyLambda(CALLABLE&& callable, FOLLOWUP&& callback)
+    {
+        return MakeReplyLambda<CALLABLE, FOLLOWUP,
+                               decltype(std::forward<CALLABLE>(callable)())>()
+            (std::move(callable), std::move(callback));
+    }
+
+    template <typename CALLABLE, typename FOLLOWUP>
+    bool WorkQueue::postTo(weak_t target,
+                           const TimePoint& time, CALLABLE&& callable, FOLLOWUP&& callback)
+    {
+        LL_PROFILE_ZONE_SCOPED;
+        // We're being asked to post to the WorkQueue at target.
+        // target is a weak_ptr: have to lock it to check it.
+        auto tptr = target.lock();
+        if (! tptr)
+            // can't post() if the target WorkQueue has been destroyed
+            return false;
+
+        // Here we believe target WorkQueue still exists. Post to it a
+        // lambda that packages our callable, our callback and a weak_ptr
+        // to this originating WorkQueue.
+        tptr->post(
+            time,
+            [reply = super::getWeak(),
+             callable = std::move(callable),
+             callback = std::move(callback)]
+            ()
+            mutable {
+                // Use postMaybe() below in case this originating WorkQueue
+                // has been closed or destroyed. Remember, the outer lambda is
+                // now running on a thread servicing the target WorkQueue, and
+                // real time has elapsed since postTo()'s tptr->post() call.
+                try
+                {
+                    // Make a reply lambda to repost to THIS WorkQueue.
+                    // Delegate to makeReplyLambda() so we can partially
+                    // specialize on void return.
+                    postMaybe(reply, makeReplyLambda(std::move(callable), std::move(callback)));
+                }
+                catch (...)
+                {
+                    // Either variant of makeReplyLambda() is responsible for
+                    // calling the caller's callable. If that throws, return
+                    // the exception to the originating thread.
+                    postMaybe(
+                        reply,
+                        // Bind the current exception to transport back to the
+                        // originating WorkQueue. Once there, rethrow it.
+                        [exc = std::current_exception()](){ std::rethrow_exception(exc); });
+                }
+            });
+
+        // looks like we were able to post()
+        return true;
+    }
+
+    template <typename CALLABLE>
+    bool WorkQueue::postMaybe(weak_t target, const TimePoint& time, CALLABLE&& callable)
+    {
+        LL_PROFILE_ZONE_SCOPED;
+        // target is a weak_ptr: have to lock it to check it
+        auto tptr = target.lock();
+        if (tptr)
+        {
+            try
+            {
+                tptr->post(time, std::forward<CALLABLE>(callable));
+                // we were able to post()
+                return true;
+            }
+            catch (const Closed&)
+            {
+                // target WorkQueue still exists, but is Closed
+            }
+        }
+        // either target no longer exists, or its WorkQueue is Closed
+        return false;
+    }
+
+    /// general case: arbitrary C++ return type
+    template <typename CALLABLE, typename RETURNTYPE>
+    struct WorkQueue::WaitForResult
+    {
+        auto operator()(WorkQueue* self, const TimePoint& time, CALLABLE&& callable)
+        {
+            LLCoros::Promise<RETURNTYPE> promise;
+            self->post(
+                time,
+                // We dare to bind a reference to Promise because it's
+                // specifically designed for cross-thread communication.
+                [&promise, callable = std::move(callable)]()
+                mutable {
+                    try
+                    {
+                        // call the caller's callable and trigger promise with result
+                        promise.set_value(callable());
+                    }
+                    catch (...)
+                    {
+                        promise.set_exception(std::current_exception());
+                    }
+                });
+            auto future{ LLCoros::getFuture(promise) };
+            // now, on the calling thread, wait for that result
+            LLCoros::TempStatus st("waiting for WorkQueue::waitForResult()");
+            return future.get();
+        }
+    };
+
+    /// specialize for CALLABLE returning void
+    template <typename CALLABLE>
+    struct WorkQueue::WaitForResult<CALLABLE, void>
+    {
+        void operator()(WorkQueue* self, const TimePoint& time, CALLABLE&& callable)
+        {
+            LLCoros::Promise<void> promise;
+            self->post(
+                time,
+                // &promise is designed for cross-thread access
+                [&promise, callable = std::move(callable)]()
+                mutable {
+                    try
+                    {
+                        callable();
+                        promise.set_value();
+                    }
+                    catch (...)
+                    {
+                        promise.set_exception(std::current_exception());
+                    }
+                });
+            auto future{ LLCoros::getFuture(promise) };
+            // block until set_value()
+            LLCoros::TempStatus st("waiting for void WorkQueue::waitForResult()");
+            future.get();
+        }
+    };
+
+    template <typename CALLABLE>
+    auto WorkQueue::waitForResult(const TimePoint& time, CALLABLE&& callable)
+    {
+        checkCoroutine("waitForResult()");
+        // derive callable's return type so we can specialize for void
+        return WaitForResult<CALLABLE, decltype(std::forward<CALLABLE>(callable)())>()
+            (this, time, std::forward<CALLABLE>(callable));
+    }
+
+} // namespace LL
+
+#endif /* ! defined(LL_WORKQUEUE_H) */
diff --git a/indra/llcorehttp/CMakeLists.txt b/indra/llcorehttp/CMakeLists.txt
index 6a301ad50d237060c409f394321378fc3cc0e34b..c591680250b220f196e425c7977f15c499f91a0b 100644
--- a/indra/llcorehttp/CMakeLists.txt
+++ b/indra/llcorehttp/CMakeLists.txt
@@ -7,7 +7,7 @@ include(GoogleMock)
 include(CURL)
 include(OpenSSL)
 include(NGHTTP2)
-include(ZLIB)
+include(ZLIBNG)
 include(LLCoreHttp)
 include(LLAddBuildTest)
 include(LLMessage)
diff --git a/indra/llfilesystem/lldiskcache.cpp b/indra/llfilesystem/lldiskcache.cpp
index ee43a599f754705b036126e2dba3bf7839ec7f15..6de99dfbff81953bf427de9a5de847ffcb046762 100644
--- a/indra/llfilesystem/lldiskcache.cpp
+++ b/indra/llfilesystem/lldiskcache.cpp
@@ -131,28 +131,44 @@ void LLDiskCache::purge()
 
     LL_INFOS() << "Purging cache to a maximum of " << mMaxSizeBytes << " bytes" << LL_ENDL;
 
+    std::vector<bool> file_removed;
+    if (mEnableCacheDebugInfo)
+    {
+        file_removed.reserve(file_info.size());
+    }
     uintmax_t file_size_total = 0;
     for (file_info_t& entry : file_info)
     {
         file_size_total += entry.second.first;
 
-        std::string action = "";
-        if (file_size_total > mMaxSizeBytes)
+        bool should_remove = file_size_total > mMaxSizeBytes;
+        if (mEnableCacheDebugInfo)
+        {
+            file_removed.push_back(should_remove);
+        }
+        if (should_remove)
         {
-            action = "DELETE:";
             boost::filesystem::remove(entry.second.second, ec);
             if (ec.failed())
             {
                 LL_WARNS() << "Failed to delete cache file " << entry.second.second << ": " << ec.message() << LL_ENDL;
             }
         }
-        else
-        {
-            action = "  KEEP:";
-        }
+    }
 
-        if (mEnableCacheDebugInfo)
+    if (mEnableCacheDebugInfo)
+    {
+        auto end_time = std::chrono::high_resolution_clock::now();
+        auto execute_time = std::chrono::duration_cast<std::chrono::milliseconds>(end_time - start_time).count();
+
+        // Log afterward so it doesn't affect the time measurement
+        // Logging thousands of file results can take hundreds of milliseconds
+        for (size_t i = 0; i < file_info.size(); ++i)
         {
+            const file_info_t& entry = file_info[i];
+            const bool removed = file_removed[i];
+            const std::string action = removed ? "DELETE:" : "KEEP:";
+
             // have to do this because of LL_INFO/LL_END weirdness
             std::ostringstream line;
 
@@ -163,12 +179,7 @@ void LLDiskCache::purge()
             line << " (" << file_size_total << "/" << mMaxSizeBytes << ")";
             LL_INFOS() << line.str() << LL_ENDL;
         }
-    }
 
-    if (mEnableCacheDebugInfo)
-    {
-        auto end_time = std::chrono::high_resolution_clock::now();
-        auto execute_time = std::chrono::duration_cast<std::chrono::milliseconds>(end_time - start_time).count();
         LL_INFOS() << "Total dir size after purge is " << dirFileSize(mCacheDir) << LL_ENDL;
         LL_INFOS() << "Cache purge took " << execute_time << " ms to execute for " << file_info.size() << " files" << LL_ENDL;
     }
@@ -354,6 +365,38 @@ void LLDiskCache::clearCache()
     }
 }
 
+void LLDiskCache::removeOldVFSFiles()
+{
+    //VFS files won't be created, so consider removing this code later
+    static const char CACHE_FORMAT[] = "inv.llsd";
+    static const char DB_FORMAT[] = "db2.x";
+
+    boost::system::error_code ec;
+#if LL_WINDOWS
+    std::wstring cache_path(utf8str_to_utf16str(gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "")));
+#else
+    std::string cache_path(gDirUtilp->getExpandedFilename(LL_PATH_CACHE, ""));
+#endif
+    if (boost::filesystem::is_directory(cache_path, ec) && !ec.failed())
+    {
+        for (auto& entry : boost::make_iterator_range(boost::filesystem::directory_iterator(cache_path, ec), {}))
+        {
+            if (boost::filesystem::is_regular_file(entry, ec) && !ec.failed())
+            {
+                if ((entry.path().string().find(CACHE_FORMAT) != std::string::npos) ||
+                    (entry.path().string().find(DB_FORMAT) != std::string::npos))
+                {
+                    boost::filesystem::remove(entry, ec);
+                    if (ec.failed())
+                    {
+                        LL_WARNS() << "Failed to delete cache file " << entry << ": " << ec.message() << LL_ENDL;
+                    }
+                }
+            }
+        }
+    }
+}
+
 uintmax_t LLDiskCache::dirFileSize(const std::string dir)
 {
     uintmax_t total_file_size = 0;
diff --git a/indra/llfilesystem/lldiskcache.h b/indra/llfilesystem/lldiskcache.h
index 1cbd2c58aa60efc1dcd3b959bd7abe72643b1b4b..b60e74f8c9b9f7fab235e79cad5e53f6e1f17d1b 100644
--- a/indra/llfilesystem/lldiskcache.h
+++ b/indra/llfilesystem/lldiskcache.h
@@ -140,6 +140,8 @@ class LLDiskCache :
          */
         const std::string getCacheInfo();
 
+        void removeOldVFSFiles();
+
     private:
         /**
          * Utility function to gather the total size the files in a given
diff --git a/indra/llimage/CMakeLists.txt b/indra/llimage/CMakeLists.txt
index 888331775144b9ab3765a537143906bb39039c8a..436b8dd1a251a8d4fbf8021a2ed50efe8a284d25 100644
--- a/indra/llimage/CMakeLists.txt
+++ b/indra/llimage/CMakeLists.txt
@@ -9,7 +9,7 @@ include(LLMath)
 include(LLFileSystem)
 include(LLKDU)
 include(LLImageJ2COJ)
-include(ZLIB)
+include(ZLIBNG)
 include(LLAddBuildTest)
 include(bugsplat)
 include(Tut)
@@ -20,7 +20,7 @@ include_directories(
     ${LLMATH_INCLUDE_DIRS}
     ${LLFILESYSTEM_INCLUDE_DIRS}
     ${PNG_INCLUDE_DIRS}
-    ${ZLIB_INCLUDE_DIRS}
+    ${ZLIBNG_INCLUDE_DIRS}
     )
 
 set(llimage_SOURCE_FILES
@@ -74,7 +74,7 @@ target_link_libraries(llimage
     ${LLCOMMON_LIBRARIES}
     ${JPEG_LIBRARIES}
     ${PNG_LIBRARIES}
-    ${ZLIB_LIBRARIES}
+    ${ZLIBNG_LIBRARIES}
     )
 
 # Add tests
diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp
index 8922f46ffec9655e6c6c96592596071a53dbdb46..0fa027c9c30314302b82e475255e7d75949631a6 100644
--- a/indra/llimage/llimage.cpp
+++ b/indra/llimage/llimage.cpp
@@ -623,8 +623,7 @@ void LLImage::setLastError(const std::string& message)
 //---------------------------------------------------------------------------
 
 LLImageBase::LLImageBase()
-:	LLTrace::MemTrackable<LLImageBase>("LLImage"),
-	mData(NULL),
+:	mData(NULL),
 	mDataSize(0),
 	mWidth(0),
 	mHeight(0),
@@ -673,7 +672,6 @@ void LLImageBase::sanityCheck()
 void LLImageBase::deleteData()
 {
 	ll_aligned_free_16(mData);
-	disclaimMem(mDataSize);
 	mDataSize = 0;
 	mData = NULL;
 }
@@ -731,7 +729,6 @@ U8* LLImageBase::allocateData(S32 size)
 		}
 	}
 	mDataSize = size;
-	claimMem(mDataSize);
 
 	return mData;
 }
@@ -752,9 +749,7 @@ U8* LLImageBase::reallocateData(S32 size)
 		ll_aligned_free_16(mData) ;
 	}
 	mData = new_datap;
-	disclaimMem(mDataSize);
 	mDataSize = size;
-	claimMem(mDataSize);
 	mBadBufferAllocation = false;
 	return mData;
 }
@@ -865,6 +860,12 @@ U8* LLImageRaw::reallocateData(S32 size)
 	return res;
 }
 
+void LLImageRaw::releaseData()
+{
+    LLImageBase::setSize(0, 0, 0);
+    LLImageBase::setDataAndSize(nullptr, 0);
+}
+
 // virtual
 void LLImageRaw::deleteData()
 {
@@ -883,8 +884,6 @@ void LLImageRaw::setDataAndSize(U8 *data, S32 width, S32 height, S8 components)
 
 	LLImageBase::setSize(width, height, components) ;
 	LLImageBase::setDataAndSize(data, width * height * components) ;
-	
-	sGlobalRawMemory += getDataSize();
 }
 
 bool LLImageRaw::resize(U16 width, U16 height, S8 components)
@@ -2254,9 +2253,7 @@ void LLImageBase::setDataAndSize(U8 *data, S32 size)
 { 
 	ll_assert_aligned(data, 16);
 	mData = data; 
-	disclaimMem(mDataSize); 
 	mDataSize = size; 
-	claimMem(mDataSize);
 }	
 
 //static
diff --git a/indra/llimage/llimage.h b/indra/llimage/llimage.h
index f66b1666d77bc288ecbc87613ebc10d11e5989c1..7a588cfb0370347ae57e7285e31a0b64333c8af5 100644
--- a/indra/llimage/llimage.h
+++ b/indra/llimage/llimage.h
@@ -112,8 +112,7 @@ class LLImage
 // Image base class
 
 class LLImageBase 
-:	public LLThreadSafeRefCount,
-	public LLTrace::MemTrackable<LLImageBase>
+:	public LLThreadSafeRefCount
 {
 protected:
 	virtual ~LLImageBase();
@@ -192,6 +191,12 @@ class LLImageRaw : public LLImageBase
 	/*virtual*/ void deleteData();
 	/*virtual*/ U8* allocateData(S32 size = -1);
 	/*virtual*/ U8* reallocateData(S32 size);
+
+    // use in conjunction with "no_copy" constructor to release data pointer before deleting
+    // so that deletion of this LLImageRaw will not free the memory at the "data" parameter 
+    // provided to "no_copy" constructor
+    void releaseData();
+
 	
 	bool resize(U16 width, U16 height, S8 components);
 
diff --git a/indra/llimage/llimagej2c.cpp b/indra/llimage/llimagej2c.cpp
index 4bff21610fc83c861fa301f6ce189823e0d1080b..e1809dbe592a15debaaba10a2c77f543fb3e60c4 100644
--- a/indra/llimage/llimagej2c.cpp
+++ b/indra/llimage/llimagej2c.cpp
@@ -60,7 +60,6 @@ LLImageJ2C::LLImageJ2C() : 	LLImageFormatted(IMG_CODEC_J2C),
 							mAreaUsedForDataSizeCalcs(0)
 {
 	mImpl.reset(fallbackCreateLLImageJ2CImpl());
-	claimMem(mImpl);
 
 	// Clear data size table
 	for( S32 i = 0; i <= MAX_DISCARD_LEVEL; i++)
diff --git a/indra/llimage/llimagejpeg.cpp b/indra/llimage/llimagejpeg.cpp
index 62638fa16cd6de5511a812de83bb2fd6397f15ce..32a5472ec8dfadcedd4ba8b13274e97ead55305b 100644
--- a/indra/llimage/llimagejpeg.cpp
+++ b/indra/llimage/llimagejpeg.cpp
@@ -393,9 +393,7 @@ boolean LLImageJPEG::encodeEmptyOutputBuffer( j_compress_ptr cinfo )
 
   cinfo->dest->next_output_byte = self->mOutputBuffer + self->mOutputBufferSize;
   cinfo->dest->free_in_buffer = self->mOutputBufferSize;
-  self->disclaimMem(self->mOutputBufferSize);
   self->mOutputBufferSize = new_buffer_size;
-  self->claimMem(new_buffer_size);
 
   return true;
 }
@@ -501,13 +499,10 @@ bool LLImageJPEG::encode( const LLImageRaw* raw_image, F32 encode_time )
 	// Allocate a temporary buffer big enough to hold the entire compressed image (and then some)
 	// (Note: we make it bigger in emptyOutputBuffer() if we need to)
 	delete[] mOutputBuffer;
-	disclaimMem(mOutputBufferSize);
 	mOutputBufferSize = getWidth() * getHeight() * getComponents() + 1024;
-	claimMem(mOutputBufferSize);
 	mOutputBuffer = new(std::nothrow) U8[ mOutputBufferSize ];
 	if (mOutputBuffer == NULL)
 	{
-		disclaimMem(mOutputBufferSize);
 		mOutputBufferSize = 0;
 		setLastError("Failed to allocate output buffer");
 		return false;
@@ -547,7 +542,6 @@ bool LLImageJPEG::encode( const LLImageRaw* raw_image, F32 encode_time )
 		jpeg_destroy_compress(&cinfo);
 		delete[] mOutputBuffer;
 		mOutputBuffer = NULL;
-		disclaimMem(mOutputBufferSize);
 		mOutputBufferSize = 0;
 		return false;
 	}
@@ -650,7 +644,6 @@ bool LLImageJPEG::encode( const LLImageRaw* raw_image, F32 encode_time )
 		// After finish_compress, we can release the temp output buffer. 
 		delete[] mOutputBuffer;
 		mOutputBuffer = NULL;
-		disclaimMem(mOutputBufferSize);
 		mOutputBufferSize = 0;
 
 		////////////////////////////////////////
@@ -663,7 +656,6 @@ bool LLImageJPEG::encode( const LLImageRaw* raw_image, F32 encode_time )
 		jpeg_destroy_compress(&cinfo);
 		delete[] mOutputBuffer;
 		mOutputBuffer = NULL;
-		disclaimMem(mOutputBufferSize);
 		mOutputBufferSize = 0;
 		return false;
 	}
diff --git a/indra/llimage/llimageworker.cpp b/indra/llimage/llimageworker.cpp
index 5f42fba86602ecf4df3b609ebae06b4ff947495a..0dbb744bcf9985bd9f7192801356eaf7587ebbf6 100644
--- a/indra/llimage/llimageworker.cpp
+++ b/indra/llimage/llimageworker.cpp
@@ -48,6 +48,7 @@ LLImageDecodeThread::~LLImageDecodeThread()
 // virtual
 S32 LLImageDecodeThread::update(F32 max_time_ms)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	LLMutexLock lock(mCreationMutex);
 	for (creation_list_t::iterator iter = mCreationList.begin();
 		 iter != mCreationList.end(); ++iter)
@@ -71,6 +72,7 @@ S32 LLImageDecodeThread::update(F32 max_time_ms)
 LLImageDecodeThread::handle_t LLImageDecodeThread::decodeImage(LLImageFormatted* image, 
 	U32 priority, S32 discard, BOOL needs_aux, Responder* responder)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	LLMutexLock lock(mCreationMutex);
 	handle_t handle = generateHandle();
 	mCreationList.push_back(creation_info(handle, image, priority, discard, needs_aux, responder));
@@ -118,6 +120,7 @@ LLImageDecodeThread::ImageRequest::~ImageRequest()
 // Returns true when done, whether or not decode was successful.
 bool LLImageDecodeThread::ImageRequest::processRequest()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	const F32 decode_time_slice = .1f;
 	bool done = true;
 	if (!mDecodedRaw && mFormattedImage.notNull())
@@ -164,6 +167,7 @@ bool LLImageDecodeThread::ImageRequest::processRequest()
 
 void LLImageDecodeThread::ImageRequest::finishRequest(bool completed)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	if (mResponder.notNull())
 	{
 		bool success = completed && mDecodedRaw && (!mNeedsAux || mDecodedAux);
diff --git a/indra/llimage/tests/llimageworker_test.cpp b/indra/llimage/tests/llimageworker_test.cpp
index 51c5c635562c2c5b7f776245a0dc74110cf18e44..9011ac615c0fb69268d242434235c0d8c29c1b26 100644
--- a/indra/llimage/tests/llimageworker_test.cpp
+++ b/indra/llimage/tests/llimageworker_test.cpp
@@ -45,8 +45,7 @@
 // * A simulator for a class can be implemented here. Please comment and document thoroughly.
 
 LLImageBase::LLImageBase() 
-: LLTrace::MemTrackable<LLImageBase>("LLImageBase"),
-mData(NULL),
+: mData(NULL),
 mDataSize(0),
 mWidth(0),
 mHeight(0),
diff --git a/indra/llinventory/llinventory.cpp b/indra/llinventory/llinventory.cpp
index 18bc1b5a9102a715c06e913d588abac42ba4f83c..81261f0767ce959fd47619960155ee34cd85ca64 100644
--- a/indra/llinventory/llinventory.cpp
+++ b/indra/llinventory/llinventory.cpp
@@ -74,20 +74,17 @@ LLInventoryObject::LLInventoryObject(const LLUUID& uuid,
 									 const LLUUID& parent_uuid,
 									 LLAssetType::EType type,
 									 const std::string& name) 
-:	LLTrace::MemTrackable<LLInventoryObject>("LLInventoryObject"),
-	mUUID(uuid),
+:	mUUID(uuid),
 	mParentUUID(parent_uuid),
 	mType(type),
 	mName(name),
 	mCreationDate(0)
 {
-	claimMem(mName);
 	correctInventoryName(mName);
 }
 
 LLInventoryObject::LLInventoryObject() 
-:	LLTrace::MemTrackable<LLInventoryObject>("LLInventoryObject"),
-	mType(LLAssetType::AT_NONE),
+:	mType(LLAssetType::AT_NONE),
 	mCreationDate(0)
 {
 }
@@ -101,9 +98,7 @@ void LLInventoryObject::copyObject(const LLInventoryObject* other)
 	mUUID = other->mUUID;
 	mParentUUID = other->mParentUUID;
 	mType = other->mType;
-	disclaimMem(mName);
 	mName = other->mName;
-	claimMem(mName);
 }
 
 const LLUUID& LLInventoryObject::getUUID() const
@@ -156,9 +151,7 @@ void LLInventoryObject::rename(const std::string& n)
 	correctInventoryName(new_name);
 	if( !new_name.empty() && new_name != mName )
 	{
-		disclaimMem(mName);
 		mName = new_name;
-		claimMem(mName);
 	}
 }
 
@@ -311,7 +304,6 @@ LLInventoryItem::LLInventoryItem(const LLUUID& uuid,
 
 	LLStringUtil::replaceNonstandardASCII(mDescription, ' ');
 	LLStringUtil::replaceChar(mDescription, '|', ' ');
-	claimMem(mDescription);
 
 	mPermissions.initMasks(inv_type);
 }
@@ -344,9 +336,7 @@ void LLInventoryItem::copyItem(const LLInventoryItem* other)
 	copyObject(other);
 	mPermissions = other->mPermissions;
 	mAssetUUID = other->mAssetUUID;
-	disclaimMem(mDescription);
 	mDescription = other->mDescription;
-	claimMem(mDescription);
 	mSaleInfo = other->mSaleInfo;
 	mInventoryType = other->mInventoryType;
 	mFlags = other->mFlags;
@@ -426,9 +416,7 @@ void LLInventoryItem::setDescription(const std::string& d)
 	LLInventoryItem::correctInventoryDescription(new_desc);
 	if( new_desc != mDescription )
 	{
-		disclaimMem(mDescription);
 		mDescription = new_desc;
-		claimMem(mDescription);
 	}
 }
 
@@ -708,10 +696,8 @@ BOOL LLInventoryItem::importLegacyStream(std::istream& input_stream)
 				valuestr[0] = '\000';
 			}
 
-			disclaimMem(mDescription);
 			mDescription.assign(valuestr);
 			LLStringUtil::replaceNonstandardASCII(mDescription, ' ');
-			claimMem(mDescription);
 			/* TODO -- ask Ian about this code
 			const char *donkey = mDescription.c_str();
 			if (donkey[0] == '|')
@@ -840,11 +826,9 @@ void LLInventoryItem::asLLSD( LLSD& sd ) const
 	sd[INV_CREATION_DATE_LABEL] = (S32) mCreationDate;
 }
 
-LLTrace::BlockTimerStatHandle FTM_INVENTORY_SD_DESERIALIZE("Inventory SD Deserialize");
-
 bool LLInventoryItem::fromLLSD(const LLSD& sd, bool is_new)
 {
-	LL_RECORD_BLOCK_TIME(FTM_INVENTORY_SD_DESERIALIZE);
+    LL_PROFILE_ZONE_SCOPED;
 	if (is_new)
 	{
 		// If we're adding LLSD to an existing object, need avoid
@@ -961,10 +945,8 @@ bool LLInventoryItem::fromLLSD(const LLSD& sd, bool is_new)
 	w = INV_DESC_LABEL;
 	if (sd.has(w))
 	{
-		disclaimMem(mDescription);
 		mDescription = sd[w].asString();
 		LLStringUtil::replaceNonstandardASCII(mDescription, ' ');
-		claimMem(mDescription);
 	}
 	w = INV_CREATION_DATE_LABEL;
 	if (sd.has(w))
diff --git a/indra/llinventory/llinventory.h b/indra/llinventory/llinventory.h
index 0f336a072f6573f2e2a7d6bc5228a79049b1bfe7..7d9f9704f10bf9bf9e7ed4330b2df410ac9e9f5f 100644
--- a/indra/llinventory/llinventory.h
+++ b/indra/llinventory/llinventory.h
@@ -44,7 +44,7 @@ class LLMessageSystem;
 //   Base class for anything in the user's inventory.   Handles the common code 
 //   between items and categories. 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-class LLInventoryObject : public LLRefCount, public LLTrace::MemTrackable<LLInventoryObject>
+class LLInventoryObject : public LLRefCount
 {
 public:
 	typedef std::list<LLPointer<LLInventoryObject> > object_list_t;
diff --git a/indra/llinventory/llparcel.cpp b/indra/llinventory/llparcel.cpp
index e2469f3c7e651275c33b67c54138e04a0dba8526..134e7830531277e622af3c815f80631b6ccfcf87 100644
--- a/indra/llinventory/llparcel.cpp
+++ b/indra/llinventory/llparcel.cpp
@@ -234,6 +234,8 @@ void LLParcel::init(const LLUUID &owner_id,
 
     setRegionAllowEnvironmentOverride(FALSE);
     setParcelEnvironmentVersion(INVALID_PARCEL_ENVIRONMENT_VERSION);
+
+    setObscureMOAP(false);
 }
 
 void LLParcel::overrideOwner(const LLUUID& owner_id, BOOL is_group_owned)
@@ -463,13 +465,13 @@ BOOL LLParcel::importAccessEntry(std::istream& input_stream, LLAccessEntry* entr
         }
         else if ("time" == keyword)
         {
-            S32 when;
+            S32 when{};
             LLStringUtil::convertToS32(value, when);
             entry->mTime = when;
         }
         else if ("flags" == keyword)
         {
-            U32 setting;
+            U32 setting{};
             LLStringUtil::convertToU32(value, setting);
             entry->mFlags = setting;
         }
@@ -540,6 +542,7 @@ void LLParcel::packMessage(LLSD& msg)
 	msg["see_avs"] = (LLSD::Boolean) getSeeAVs();
 	msg["group_av_sounds"] = (LLSD::Boolean) getAllowGroupAVSounds();
 	msg["any_av_sounds"] = (LLSD::Boolean) getAllowAnyAVSounds();
+    msg["obscure_moap"] = (LLSD::Boolean) getObscureMOAP();
 }
 
 
diff --git a/indra/llinventory/llparcel.h b/indra/llinventory/llparcel.h
index 5d08c1f4c69a24249fbb7c20290ffe3cc820f98b..f5ee1241ab9697e7c6fab929fd7ff9c960257cd5 100644
--- a/indra/llinventory/llparcel.h
+++ b/indra/llinventory/llparcel.h
@@ -306,6 +306,7 @@ class LLParcel
 	void	setRestrictPushObject(BOOL b) { setParcelFlag(PF_RESTRICT_PUSHOBJECT, b); }
 	void	setAllowGroupAVSounds(BOOL b)	{ mAllowGroupAVSounds = b;		}
 	void	setAllowAnyAVSounds(BOOL b)		{ mAllowAnyAVSounds = b;		}
+    void    setObscureMOAP(bool b)  { mObscureMOAP = b; }
 
 	void	setDrawDistance(F32 dist)	{ mDrawDistance = dist; }
 	void	setSalePrice(S32 price)		{ mSalePrice = price; }
@@ -517,6 +518,8 @@ class LLParcel
 
 	BOOL	getAllowGroupAVSounds()	const	{ return mAllowGroupAVSounds;	} 
 	BOOL	getAllowAnyAVSounds()	const	{ return mAllowAnyAVSounds;		}
+ 
+    bool    getObscureMOAP() const { return mObscureMOAP; }
 
 	F32		getDrawDistance() const			{ return mDrawDistance; }
 	S32		getSalePrice() const			{ return mSalePrice; }
@@ -670,6 +673,7 @@ class LLParcel
     BOOL                mRegionAllowEnvironmentOverride;
 	BOOL				mAllowGroupAVSounds;
 	BOOL				mAllowAnyAVSounds;
+    bool                mObscureMOAP;
     S32                 mCurrentEnvironmentVersion;
 	
     bool                mIsDefaultDayCycle;
diff --git a/indra/llinventory/llsettingsbase.cpp b/indra/llinventory/llsettingsbase.cpp
index 8a8e2bb340949a6e86a910b48df4b5599f953c86..936b166409f921e25f502635af21b60b2ab0ac07 100644
--- a/indra/llinventory/llsettingsbase.cpp
+++ b/indra/llinventory/llsettingsbase.cpp
@@ -683,6 +683,7 @@ bool LLSettingsBase::Validator::verifyStringLength(LLSD &value, U32, S32 length)
 //=========================================================================
 void LLSettingsBlender::update(const LLSettingsBase::BlendFactor& blendf)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_ENVIRONMENT;
     F64 res = setBlendFactor(blendf);
     llassert(res >= 0.0 && res <= 1.0);
     (void)res;
@@ -713,6 +714,7 @@ F64 LLSettingsBlender::setBlendFactor(const LLSettingsBase::BlendFactor& blendf_
 
 void LLSettingsBlender::triggerComplete()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_ENVIRONMENT;
     if (mTarget)
         mTarget->replaceSettings(mFinal->getSettings());
     LLSettingsBlender::ptr_t hold = shared_from_this();   // prevents this from deleting too soon
@@ -725,11 +727,13 @@ const LLSettingsBase::BlendFactor LLSettingsBlenderTimeDelta::MIN_BLEND_DELTA(FL
 
 LLSettingsBase::BlendFactor LLSettingsBlenderTimeDelta::calculateBlend(const LLSettingsBase::TrackPosition& spanpos, const LLSettingsBase::TrackPosition& spanlen) const
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_ENVIRONMENT;
     return LLSettingsBase::BlendFactor(fmod((F64)spanpos, (F64)spanlen) / (F64)spanlen);
 }
 
 bool LLSettingsBlenderTimeDelta::applyTimeDelta(const LLSettingsBase::Seconds& timedelta)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_ENVIRONMENT;
     mTimeSpent += timedelta;
 
     if (mTimeSpent > mBlendSpan)
diff --git a/indra/llinventory/llsettingsdaycycle.cpp b/indra/llinventory/llsettingsdaycycle.cpp
index 2bb03e8391dc2920c2d822a5b2d794923bede8e5..241826604f660e5c6c1f9c0e1f6b397ab34e5907 100644
--- a/indra/llinventory/llsettingsdaycycle.cpp
+++ b/indra/llinventory/llsettingsdaycycle.cpp
@@ -41,9 +41,6 @@
 //=========================================================================
 namespace
 {
-    LLTrace::BlockTimerStatHandle FTM_BLEND_WATERVALUES("Blending Water Environment Day");
-    LLTrace::BlockTimerStatHandle FTM_UPDATE_WATERVALUES("Update Water Environment Day");
-
     template<typename T>
     inline T get_wrapping_distance(T begin, T end)
     {
diff --git a/indra/llinventory/llsettingssky.cpp b/indra/llinventory/llsettingssky.cpp
index 1470edbf385131a48d54d05a51b23ab8305ec6bd..83a92f08d0ec2e1695e0fbb424a5c8e1d1eebd0c 100644
--- a/indra/llinventory/llsettingssky.cpp
+++ b/indra/llinventory/llsettingssky.cpp
@@ -66,11 +66,6 @@ namespace {
     }
 }
 
-static LLTrace::BlockTimerStatHandle FTM_BLEND_SKYVALUES("Blending Sky Environment");
-static LLTrace::BlockTimerStatHandle FTM_RECALCULATE_SKYVALUES("Recalculate Sky");
-static LLTrace::BlockTimerStatHandle FTM_RECALCULATE_BODIES("Recalculate Heavenly Bodies");
-static LLTrace::BlockTimerStatHandle FTM_RECALCULATE_LIGHTING("Recalculate Lighting");
-
 //=========================================================================
 const std::string LLSettingsSky::SETTING_AMBIENT("ambient");
 const std::string LLSettingsSky::SETTING_BLUE_DENSITY("blue_density");
@@ -444,6 +439,7 @@ void LLSettingsSky::replaceWithSky(LLSettingsSky::ptr_t pother)
 
 void LLSettingsSky::blend(const LLSettingsBase::ptr_t &end, F64 blendf) 
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_ENVIRONMENT;
     llassert(getSettingsType() == end->getSettingsType());
 
     LLSettingsSky::ptr_t other = PTR_NAMESPACE::dynamic_pointer_cast<LLSettingsSky>(end);
@@ -939,7 +935,7 @@ LLSD LLSettingsSky::translateLegacySettings(const LLSD& legacy)
 
 void LLSettingsSky::updateSettings()
 {
-    LL_RECORD_BLOCK_TIME(FTM_RECALCULATE_SKYVALUES);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_ENVIRONMENT;
 
     // base class clears dirty flag so as to not trigger recursive update
     LLSettingsBase::updateSettings();
@@ -1022,6 +1018,7 @@ LLColor3 LLSettingsSky::getLightDiffuse() const
 
 LLColor3 LLSettingsSky::getColor(const std::string& key, const LLColor3& default_value) const
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_ENVIRONMENT;
     if (mSettings.has(SETTING_LEGACY_HAZE) && mSettings[SETTING_LEGACY_HAZE].has(key))
     {
         return LLColor3(mSettings[SETTING_LEGACY_HAZE][key]);
@@ -1035,6 +1032,7 @@ LLColor3 LLSettingsSky::getColor(const std::string& key, const LLColor3& default
 
 F32 LLSettingsSky::getFloat(const std::string& key, F32 default_value) const
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_ENVIRONMENT;
     if (mSettings.has(SETTING_LEGACY_HAZE) && mSettings[SETTING_LEGACY_HAZE].has(key))
     {
         return mSettings[SETTING_LEGACY_HAZE][key].asReal();
@@ -1206,11 +1204,19 @@ LLColor3 LLSettingsSky::getLightTransmittance(F32 distance) const
     return transmittance;
 }
 
+// SL-16127: getTotalDensity() and getDensityMultiplier() call LLSettingsSky::getColor() and LLSettingsSky::getFloat() respectively which are S-L-O-W
+LLColor3 LLSettingsSky::getLightTransmittanceFast( const LLColor3& total_density, const F32 density_multiplier, const F32 distance ) const
+{
+    // Transparency (-> density) from Beer's law
+    LLColor3 transmittance = componentExp(total_density * -(density_multiplier * distance));
+    return transmittance;
+}
+
 // performs soft scale clip and gamma correction ala the shader implementation
 // scales colors down to 0 - 1 range preserving relative ratios
-LLColor3 LLSettingsSky::gammaCorrect(const LLColor3& in) const
+LLColor3 LLSettingsSky::gammaCorrect(const LLColor3& in,const F32 &gamma) const
 {
-    F32 gamma = getGamma();
+    //F32 gamma = getGamma(); // SL-16127: Use cached gamma from atmospheric vars
 
     LLColor3 v(in);
     // scale down to 0 to 1 range preserving relative ratio (aka homegenize)
diff --git a/indra/llinventory/llsettingssky.h b/indra/llinventory/llsettingssky.h
index 412791164327d9e7c3dcebfa5fca437f9a069b6a..fa9326f0069f62b0d97a9da1568f49a2f7602656 100644
--- a/indra/llinventory/llsettingssky.h
+++ b/indra/llinventory/llsettingssky.h
@@ -252,8 +252,9 @@ class LLSettingsSky: public LLSettingsBase
 
     LLColor3 getLightAttenuation(F32 distance) const;
     LLColor3 getLightTransmittance(F32 distance) const;
+    LLColor3 getLightTransmittanceFast(const LLColor3& total_density, const F32 density_multiplier, const F32 distance) const;
     LLColor3 getTotalDensity() const;
-    LLColor3 gammaCorrect(const LLColor3& in) const;
+    LLColor3 gammaCorrect(const LLColor3& in,const F32 &gamma) const;
 
     LLColor3 getBlueDensity() const;
     LLColor3 getBlueHorizon() const;
diff --git a/indra/llinventory/llsettingswater.cpp b/indra/llinventory/llsettingswater.cpp
index 1ae8d78b22ca40ee1a7347d26b417f3d0b1e954e..90f99e81986dba3d0694d851c46bb5ead53d39d2 100644
--- a/indra/llinventory/llsettingswater.cpp
+++ b/indra/llinventory/llsettingswater.cpp
@@ -33,14 +33,6 @@
 #include "v3colorutil.h"
 #include "indra_constants.h"
 
-//=========================================================================
-namespace
-{
-     LLTrace::BlockTimerStatHandle FTM_BLEND_WATERVALUES("Blending Water Environment");
-     LLTrace::BlockTimerStatHandle FTM_UPDATE_WATERVALUES("Update Water Environment");
-}
-
-//=========================================================================
 const std::string LLSettingsWater::SETTING_BLUR_MULTIPLIER("blur_multiplier");
 const std::string LLSettingsWater::SETTING_FOG_COLOR("water_fog_color");
 const std::string LLSettingsWater::SETTING_FOG_DENSITY("water_fog_density");
diff --git a/indra/llkdu/tests/llimagej2ckdu_test.cpp b/indra/llkdu/tests/llimagej2ckdu_test.cpp
index ee7b14be853a7054ae0bb29c226053174541e12a..16213b7f45663fcd0ad64e63446e75b65f3b6777 100644
--- a/indra/llkdu/tests/llimagej2ckdu_test.cpp
+++ b/indra/llkdu/tests/llimagej2ckdu_test.cpp
@@ -63,8 +63,7 @@ U8* LLImageRaw::reallocateData(S32 ) { return NULL; }
 bool LLImageRaw::resize(U16, U16, S8) { return true; } // this method always returns true...
 
 LLImageBase::LLImageBase()
-: LLTrace::MemTrackable<LLImageBase>("LLImageBase"),
-mData(NULL),
+: mData(NULL),
 mDataSize(0),
 mWidth(0),
 mHeight(0),
diff --git a/indra/llmath/CMakeLists.txt b/indra/llmath/CMakeLists.txt
index 552e8201279564695b4cfa119f15ec6ad76897c5..4617309606dfc3c17d27015dd83b1f9875cd474b 100644
--- a/indra/llmath/CMakeLists.txt
+++ b/indra/llmath/CMakeLists.txt
@@ -4,12 +4,14 @@ project(llmath)
 
 include(00-Common)
 include(LLCommon)
+include(LLMeshOptimizer)
 include(bugsplat)
 include(Boost)
 
 include_directories(
     ${LLCOMMON_INCLUDE_DIRS}
     ${LLCOMMON_SYSTEM_INCLUDE_DIRS}
+    ${LLMESHOPTIMIZER_INCLUDE_DIRS}
     )
 
 set(llmath_SOURCE_FILES
@@ -109,6 +111,7 @@ add_library (llmath ${llmath_SOURCE_FILES})
 
 target_link_libraries(llmath
     ${LLCOMMON_LIBRARIES}
+    ${LLMESHOPTIMIZER_LIBRARIES}
     )
 
 # Add tests
diff --git a/indra/llmath/llmatrix4a.h b/indra/llmath/llmatrix4a.h
index 7ba347062f724c99b8df1589cb5bee169daa8fa1..2cf50e9cd2b1420a892f469649dd39b615d21e15 100644
--- a/indra/llmath/llmatrix4a.h
+++ b/indra/llmath/llmatrix4a.h
@@ -36,6 +36,26 @@ class LLMatrix4a
 public:
 	LL_ALIGN_16(LLVector4a mMatrix[4]);
 
+    LLMatrix4a()
+    {
+
+    }
+
+    explicit LLMatrix4a(const LLMatrix4& val)
+    {
+        loadu(val);
+    }
+
+    inline F32* getF32ptr()
+    {
+        return (F32*) &mMatrix;
+    }
+
+    inline const F32* getF32ptr() const
+    {
+        return (F32*)&mMatrix;
+    }
+
 	inline void clear()
 	{
 		mMatrix[0].clear();
@@ -44,14 +64,29 @@ class LLMatrix4a
 		mMatrix[3].clear();
 	}
 
+    inline void setIdentity()
+    {
+        mMatrix[0].set(1.f, 0.f, 0.f, 0.f);
+        mMatrix[1].set(0.f, 1.f, 0.f, 0.f);
+        mMatrix[2].set(0.f, 0.f, 1.f, 0.f);
+        mMatrix[3].set(0.f, 0.f, 0.f, 1.f);
+    }
+
 	inline void loadu(const LLMatrix4& src)
 	{
 		mMatrix[0] = _mm_loadu_ps(src.mMatrix[0]);
 		mMatrix[1] = _mm_loadu_ps(src.mMatrix[1]);
 		mMatrix[2] = _mm_loadu_ps(src.mMatrix[2]);
 		mMatrix[3] = _mm_loadu_ps(src.mMatrix[3]);
-		
 	}
+    
+    inline void loadu(const F32* src)
+    {
+        mMatrix[0] = _mm_loadu_ps(src);
+        mMatrix[1] = _mm_loadu_ps(src+4);
+        mMatrix[2] = _mm_loadu_ps(src+8);
+        mMatrix[3] = _mm_loadu_ps(src+12);
+    }
 
 	inline void loadu(const LLMatrix3& src)
 	{
@@ -105,7 +140,7 @@ class LLMatrix4a
 		mMatrix[3].setAdd(a.mMatrix[3],d3);
 	}
 
-	inline void rotate(const LLVector4a& v, LLVector4a& res)
+	inline void rotate(const LLVector4a& v, LLVector4a& res) const
 	{
 		LLVector4a y,z;
 
@@ -151,6 +186,8 @@ class LLMatrix4a
     {
         affineTransformSSE(v,res);
     }
+
+    const LLVector4a& getTranslation() const { return mMatrix[3]; }
 };
 
 inline LLVector4a rowMul(const LLVector4a &row, const LLMatrix4a &mat)
@@ -176,6 +213,15 @@ inline void matMul(const LLMatrix4a &a, const LLMatrix4a &b, LLMatrix4a &res)
     res.mMatrix[3] = row3;
 }
 
+//Faster version of matMul wehere res must not be a or b
+inline void matMulUnsafe(const LLMatrix4a &a, const LLMatrix4a &b, LLMatrix4a &res)
+{
+    res.mMatrix[0] = rowMul(a.mMatrix[0], b);
+    res.mMatrix[1] = rowMul(a.mMatrix[1], b);
+    res.mMatrix[2] = rowMul(a.mMatrix[2], b);
+    res.mMatrix[3] = rowMul(a.mMatrix[3], b);
+}
+
 inline std::ostream& operator<<(std::ostream& s, const LLMatrix4a& m)
 {
     s << "[" << m.mMatrix[0] << ", " << m.mMatrix[1] << ", " << m.mMatrix[2] << ", " << m.mMatrix[3] << "]";
diff --git a/indra/llmath/lloctree.h b/indra/llmath/lloctree.h
index 0e2f62f9db85a28a5684abee685e1f0d2be02d67..318ee65cc0fe2193fff2d18044674ab40ea838c1 100644
--- a/indra/llmath/lloctree.h
+++ b/indra/llmath/lloctree.h
@@ -34,6 +34,9 @@
 
 #define OCT_ERRS LL_WARNS("OctreeErrors")
 
+#define OCTREE_DEBUG_COLOR_REMOVE   0x0000FF // r
+#define OCTREE_DEBUG_COLOR_INSERT   0x00FF00 // g
+#define OCTREE_DEBUG_COLOR_BALANCE  0xFF0000 // b
 
 extern U32 gOctreeMaxCapacity;
 extern float gOctreeMinSize;
@@ -45,101 +48,98 @@ extern float gOctreeMinSize;
 #define LL_OCTREE_MAX_CAPACITY 128
 #endif*/
 
-template <class T> class LLOctreeNode;
+// T is the type of the element referenced by the octree node.
+// T_PTR determines how pointers to elements are stored internally.
+// LLOctreeNode<T, LLPointer<T>> assumes ownership of inserted elements and
+// deletes elements removed from the tree.
+// LLOctreeNode<T, T*> doesn't take ownership of inserted elements, so the API
+// user is responsible for managing the storage lifecycle of elements added to
+// the tree.
+template <class T, typename T_PTR> class LLOctreeNode;
 
-template <class T>
+template <class T, typename T_PTR>
 class LLOctreeListener: public LLTreeListener<T>
 {
 public:
 	typedef LLTreeListener<T> BaseType;
-	typedef LLOctreeNode<T> oct_node;
+    typedef LLOctreeNode<T, T_PTR> oct_node;
 
 	virtual void handleChildAddition(const oct_node* parent, oct_node* child) = 0;
 	virtual void handleChildRemoval(const oct_node* parent, const oct_node* child) = 0;
 };
 
-template <class T>
+template <class T, typename T_PTR>
 class LLOctreeTraveler
 {
 public:
-	virtual void traverse(const LLOctreeNode<T>* node);
-	virtual void visit(const LLOctreeNode<T>* branch) = 0;
+    virtual void traverse(const LLOctreeNode<T, T_PTR>* node);
+    virtual void visit(const LLOctreeNode<T, T_PTR>* branch) = 0;
 };
 
-template <class T>
-class LLOctreeTravelerDepthFirst : public LLOctreeTraveler<T>
+template <class T, typename T_PTR>
+class LLOctreeTravelerDepthFirst : public LLOctreeTraveler<T, T_PTR>
 {
 public:
-	virtual void traverse(const LLOctreeNode<T>* node);
+	virtual void traverse(const LLOctreeNode<T, T_PTR>* node) override;
 };
 
-template <class T>
-class LLOctreeNode : public LLTreeNode<T>
+template <class T, typename T_PTR>
+class alignas(16) LLOctreeNode : public LLTreeNode<T>
 {
+    LL_ALIGN_NEW
 public:
 
-	typedef LLOctreeTraveler<T>									oct_traveler;
-	typedef LLTreeTraveler<T>									tree_traveler;
-	typedef std::vector< LLPointer<T> >							element_list;		// note:  don't remove the whitespace between "> >"
-	typedef LLPointer<T>*										element_iter;
-	typedef const LLPointer<T>*									const_element_iter;
+    typedef LLOctreeTraveler<T, T_PTR>                          oct_traveler;
+    typedef LLTreeTraveler<T>                                   tree_traveler;
+    typedef std::vector<T_PTR>                                  element_list;
+    typedef typename element_list::iterator                     element_iter;
+    typedef typename element_list::const_iterator               const_element_iter;
 	typedef typename std::vector<LLTreeListener<T>*>::iterator	tree_listener_iter;
-	typedef LLOctreeNode<T>**									child_list;
-	typedef LLOctreeNode<T>**									child_iter;
+    typedef LLOctreeNode<T, T_PTR>**                            child_list;
+    typedef LLOctreeNode<T, T_PTR>**                            child_iter;
 
-	typedef LLTreeNode<T>		BaseType;
-	typedef LLOctreeNode<T>		oct_node;
-	typedef LLOctreeListener<T>	oct_listener;
+    typedef LLTreeNode<T>               BaseType;
+    typedef LLOctreeNode<T, T_PTR>      oct_node;
+    typedef LLOctreeListener<T, T_PTR>  oct_listener;
 
-	void* operator new(size_t size)
-	{
-		return ll_aligned_malloc_16(size);
-	}
-
-	void operator delete(void* ptr)
-	{
-		ll_aligned_free_16(ptr);
-	}
+    enum
+    {
+        NO_CHILD_NODES = 255 // Note: This is an U8 to match the max value in mChildMap[]
+    };
 
 	LLOctreeNode(	const LLVector4a& center, 
 					const LLVector4a& size, 
 					BaseType* parent, 
-					U8 octant = 255)
+					U8 octant = NO_CHILD_NODES)
 	:	mParent((oct_node*)parent), 
 		mOctant(octant) 
 	{ 
 		llassert(size[0] >= gOctreeMinSize*0.5f);
-		//always keep a NULL terminated list to avoid out of bounds exceptions in debug builds
-		mData.push_back(NULL);
-		mDataEnd = &mData[0];
 
 		mCenter = center;
 		mSize = size;
 
 		updateMinMax();
-		if ((mOctant == 255) && mParent)
+		if ((mOctant == NO_CHILD_NODES) && mParent)
 		{
 			mOctant = ((oct_node*) mParent)->getOctant(mCenter);
 		}
 
-		mElementCount = 0;
-
 		clearChildren();
 	}
 
-	virtual ~LLOctreeNode()								
+	virtual ~LLOctreeNode()
 	{ 
-		BaseType::destroyListeners(); 
+		BaseType::destroyListeners();
 		
-		for (U32 i = 0; i < mElementCount; ++i)
+        const U32 element_count = getElementCount();
+        for (U32 i = 0; i < element_count; ++i)
 		{
 			mData[i]->setBinIndex(-1);
 			mData[i] = NULL;
 		}
 
 		mData.clear();
-		mData.push_back(NULL);
-		mDataEnd = &mData[0];
 
 		for (U32 i = 0; i < getChildCount(); i++)
 		{
@@ -168,7 +168,7 @@ class LLOctreeNode : public LLTreeNode<T>
 		return rad <= mSize[0]*2.f && isInside(pos); 
 	}
 
-	inline bool isInside(T* data) const			
+	inline bool isInside(T* data) const
 	{ 
 		return isInside(data->getPositionGroup(), data->getBinRadius());
 	}
@@ -239,14 +239,12 @@ class LLOctreeNode : public LLTreeNode<T>
 	void accept(oct_traveler* visitor)				{ visitor->visit(this); }
 	virtual bool isLeaf() const						{ return mChildCount == 0; }
 	
-	U32 getElementCount() const						{ return mElementCount; }
-	bool isEmpty() const							{ return mElementCount == 0; }
-	element_list& getData()							{ return mData; }
-	const element_list& getData() const				{ return mData; }
-	element_iter getDataBegin()						{ return &mData[0]; }
-	element_iter getDataEnd()						{ return mDataEnd; }
-	const_element_iter getDataBegin() const			{ return &mData[0]; }
-	const_element_iter getDataEnd() const			{ return mDataEnd; }
+    U32 getElementCount() const                     { return (U32)mData.size(); }
+    bool isEmpty() const                            { return mData.empty(); }
+    element_iter getDataBegin()                     { return mData.begin(); }
+    element_iter getDataEnd()                       { return mData.end(); }
+    const_element_iter getDataBegin() const         { return mData.cbegin(); }
+    const_element_iter getDataEnd() const           { return mData.cend(); }
 		
 	U32 getChildCount()	const						{ return mChildCount; }
 	oct_node* getChild(U32 index)					{ return mChild[index]; }
@@ -262,9 +260,9 @@ class LLOctreeNode : public LLTreeNode<T>
 		for (U32 i = 0; i < 8; i++)
 		{
 			U8 idx = mChildMap[i];
-			if (idx != 255)
+			if (idx != NO_CHILD_NODES)
 			{
-				LLOctreeNode<T>* child = mChild[idx];
+                oct_node* child = mChild[idx];
 
 				if (child->getOctant() != i)
 				{
@@ -282,10 +280,10 @@ class LLOctreeNode : public LLTreeNode<T>
 
 	oct_node* getNodeAt(const LLVector4a& pos, const F32& rad)
 	{ 
-		LLOctreeNode<T>* node = this;
+        oct_node* node = this;
 
 		if (node->isInside(pos, rad))
-		{		
+		{
 			//do a quick search by octant
 			U8 octant = node->getOctant(pos);
 			
@@ -295,7 +293,7 @@ class LLOctreeNode : public LLTreeNode<T>
 			// the data
 			U8 next_node = node->mChildMap[octant];
 			
-			while (next_node != 255 && node->getSize()[0] >= rad)
+			while (next_node != NO_CHILD_NODES && node->getSize()[0] >= rad)
 			{	
 				node = node->getChild(next_node);
 				octant = node->getOctant(pos);
@@ -304,7 +302,7 @@ class LLOctreeNode : public LLTreeNode<T>
 		}
 		else if (!node->contains(rad) && node->getParent())
 		{ //if we got here, data does not exist in this node
-			return ((LLOctreeNode<T>*) node->getParent())->getNodeAt(pos, rad);
+            return ((oct_node*) node->getParent())->getNodeAt(pos, rad);
 		}
 
 		return node;
@@ -312,12 +310,14 @@ class LLOctreeNode : public LLTreeNode<T>
 	
 	virtual bool insert(T* data)
 	{
+        //LL_PROFILE_ZONE_NAMED_COLOR("Octree::insert()",OCTREE_DEBUG_COLOR_INSERT);
+
 		if (data == NULL || data->getBinIndex() != -1)
 		{
 			OCT_ERRS << "!!! INVALID ELEMENT ADDED TO OCTREE BRANCH !!!" << LL_ENDL;
 			return false;
 		}
-		LLOctreeNode<T>* parent = getOctParent();
+        oct_node* parent = getOctParent();
 
 		//is it here?
 		if (isInside(data->getPositionGroup()))
@@ -325,11 +325,8 @@ class LLOctreeNode : public LLTreeNode<T>
 			if ((((getElementCount() < gOctreeMaxCapacity || getSize()[0] <= gOctreeMinSize) && contains(data->getBinRadius())) ||
 				(data->getBinRadius() > getSize()[0] &&	parent && parent->getElementCount() >= gOctreeMaxCapacity))) 
 			{ //it belongs here
-				mData.push_back(NULL);
-				mData[mElementCount] = data;
-				mElementCount++;
-				mDataEnd = &mData[mElementCount];
-				data->setBinIndex(mElementCount-1);
+                mData.push_back(data);
+                data->setBinIndex(getElementCount() - 1);
 				BaseType::insert(data);
 				return true;
 			}
@@ -353,7 +350,7 @@ class LLOctreeNode : public LLTreeNode<T>
 				size.mul(0.5f);
 		        		
 				//push center in direction of data
-				LLOctreeNode<T>::pushCenter(center, size, data);
+                oct_node::pushCenter(center, size, data);
 
 				// handle case where floating point number gets too small
 				LLVector4a val;
@@ -365,11 +362,8 @@ class LLOctreeNode : public LLTreeNode<T>
 
 				if( lt == 0x7 )
 				{
-					mData.push_back(NULL);
-					mData[mElementCount] = data;
-					mElementCount++;
-					mDataEnd = &mData[mElementCount];
-					data->setBinIndex(mElementCount-1);
+                    mData.push_back(data);
+                    data->setBinIndex(getElementCount() - 1);
 					BaseType::insert(data);
 					return true;
 				}
@@ -395,7 +389,7 @@ class LLOctreeNode : public LLTreeNode<T>
 
 				llassert(size[0] >= gOctreeMinSize*0.5f);
 				//make the new kid
-				child = new LLOctreeNode<T>(center, size, this);
+                child = new oct_node(center, size, this);
 				addChild(child);
 								
 				child->insert(data);
@@ -428,28 +422,25 @@ class LLOctreeNode : public LLTreeNode<T>
 	}
 
 	void _remove(T* data, S32 i)
-	{ //precondition -- mElementCount > 0, idx is in range [0, mElementCount)
+    { //precondition -- getElementCount() > 0, idx is in range [0, getElementCount())
 
-		mElementCount--;
 		data->setBinIndex(-1); 
 		
-		if (mElementCount > 0)
+        const U32 new_element_count = getElementCount() - 1;
+		if (new_element_count > 0)
 		{
-			if (mElementCount != i)
+			if (new_element_count != i)
 			{
-				mData[i] = mData[mElementCount]; //might unref data, do not access data after this point
+				mData[i] = mData[new_element_count]; //might unref data, do not access data after this point
 				mData[i]->setBinIndex(i);
 			}
 
-			mData[mElementCount] = NULL;
+			mData[new_element_count] = NULL;
 			mData.pop_back();
-			mDataEnd = &mData[mElementCount];
 		}
 		else
 		{
 			mData.clear();
-			mData.push_back(NULL);
-			mDataEnd = &mData[0];
 		}
 
 		this->notifyRemoval(data);
@@ -458,9 +449,11 @@ class LLOctreeNode : public LLTreeNode<T>
 
 	bool remove(T* data)
 	{
+        //LL_PROFILE_ZONE_NAMED_COLOR("Octree::remove()", OCTREE_DEBUG_COLOR_REMOVE);
+
 		S32 i = data->getBinIndex();
 
-		if (i >= 0 && i < mElementCount)
+        if (i >= 0 && i < getElementCount())
 		{
 			if (mData[i] == data)
 			{ //found it
@@ -503,7 +496,8 @@ class LLOctreeNode : public LLTreeNode<T>
 
 	void removeByAddress(T* data)
 	{
-        for (U32 i = 0; i < mElementCount; ++i)
+        const U32 element_count = getElementCount();
+        for (U32 i = 0; i < element_count; ++i)
 		{
 			if (mData[i] == data)
 			{ //we have data
@@ -515,7 +509,7 @@ class LLOctreeNode : public LLTreeNode<T>
 		
 		for (U32 i = 0; i < getChildCount(); i++)
 		{	//we don't contain data, so pass this guy down
-			LLOctreeNode<T>* child = (LLOctreeNode<T>*) getChild(i);
+            oct_node* child = (oct_node*) getChild(i);
 			child->removeByAddress(data);
 		}
 	}
@@ -523,9 +517,7 @@ class LLOctreeNode : public LLTreeNode<T>
 	void clearChildren()
 	{
 		mChildCount = 0;
-
-		U32* foo = (U32*) mChildMap;
-		foo[0] = foo[1] = 0xFFFFFFFF;
+		memset(mChildMap, NO_CHILD_NODES, sizeof(mChildMap));
 	}
 
 	void validate()
@@ -616,11 +608,9 @@ class LLOctreeNode : public LLTreeNode<T>
 		--mChildCount;
 
 		mChild[index] = mChild[mChildCount];
-		
 
 		//rebuild child map
-		U32* foo = (U32*) mChildMap;
-		foo[0] = foo[1] = 0xFFFFFFFF;
+		memset(mChildMap, NO_CHILD_NODES, sizeof(mChildMap));
 
 		for (U32 i = 0; i < mChildCount; ++i)
 		{
@@ -656,7 +646,7 @@ class LLOctreeNode : public LLTreeNode<T>
 		OCT_ERRS << "Octree failed to delete requested child." << LL_ENDL;
 	}
 
-protected:	
+protected:
 	typedef enum
 	{
 		CENTER = 0,
@@ -673,23 +663,20 @@ class LLOctreeNode : public LLTreeNode<T>
 	oct_node* mParent;
 	U8 mOctant;
 
-	LLOctreeNode<T>* mChild[8];
+    oct_node* mChild[8];
 	U8 mChildMap[8];
 	U32 mChildCount;
 
 	element_list mData;
-	element_iter mDataEnd;
-	U32 mElementCount;
-		
 }; 
 
 //just like a regular node, except it might expand on insert and compress on balance
-template <class T>
-class LLOctreeRoot : public LLOctreeNode<T>
+template <class T, typename T_PTR>
+class LLOctreeRoot : public LLOctreeNode<T, T_PTR>
 {
 public:
-	typedef LLOctreeNode<T>	BaseType;
-	typedef LLOctreeNode<T>		oct_node;
+    typedef LLOctreeNode<T, T_PTR> BaseType;
+    typedef LLOctreeNode<T, T_PTR> oct_node;
 
 	LLOctreeRoot(const LLVector4a& center, 
 				 const LLVector4a& size, 
@@ -698,11 +685,13 @@ class LLOctreeRoot : public LLOctreeNode<T>
 	{
 	}
 	
-	bool balance()
+	bool balance() override
 	{	
+        //LL_PROFILE_ZONE_NAMED_COLOR("Octree::balance()",OCTREE_DEBUG_COLOR_BALANCE);
+
 		if (this->getChildCount() == 1 && 
 			!(this->mChild[0]->isLeaf()) &&
-			this->mChild[0]->getElementCount() == 0) 
+			this->mChild[0]->getElementCount() == 0)
 		{ //if we have only one child and that child is an empty branch, make that child the root
 			oct_node* child = this->mChild[0];
 					
@@ -732,7 +721,7 @@ class LLOctreeRoot : public LLOctreeNode<T>
 	}
 
 	// LLOctreeRoot::insert
-	bool insert(T* data)
+	bool insert(T* data) override
 	{
 		if (data == NULL) 
 		{
@@ -768,7 +757,7 @@ class LLOctreeRoot : public LLOctreeNode<T>
 			oct_node* node = this->getNodeAt(data);
 			if (node == this)
 			{
-				LLOctreeNode<T>::insert(data);
+                oct_node::insert(data);
 			}
 			else if (node->isInside(data->getPositionGroup()))
 			{
@@ -788,13 +777,13 @@ class LLOctreeRoot : public LLOctreeNode<T>
 				LLVector4a center, size;
 				center = this->getCenter();
 				size = this->getSize();
-				LLOctreeNode<T>::pushCenter(center, size, data);
+                oct_node::pushCenter(center, size, data);
 				this->setCenter(center);
 				size.mul(2.f);
 				this->setSize(size);
 				this->updateMinMax();
 			}
-			LLOctreeNode<T>::insert(data);
+            oct_node::insert(data);
 		}
 		else
 		{
@@ -806,7 +795,7 @@ class LLOctreeRoot : public LLOctreeNode<T>
 
 				//expand this node
 				LLVector4a newcenter(center);
-				LLOctreeNode<T>::pushCenter(newcenter, size, data);
+                oct_node::pushCenter(newcenter, size, data);
 				this->setCenter(newcenter);
 				LLVector4a size2 = size;
 				size2.mul(2.f);
@@ -816,11 +805,11 @@ class LLOctreeRoot : public LLOctreeNode<T>
 				llassert(size[0] >= gOctreeMinSize);
 
 				//copy our children to a new branch
-				LLOctreeNode<T>* newnode = new LLOctreeNode<T>(center, size, this);
+                oct_node* newnode = new oct_node(center, size, this);
 				
 				for (U32 i = 0; i < this->getChildCount(); i++)
 				{
-					LLOctreeNode<T>* child = this->getChild(i);
+                    oct_node* child = this->getChild(i);
 					newnode->addChild(child);
 				}
 
@@ -835,13 +824,19 @@ class LLOctreeRoot : public LLOctreeNode<T>
 
 		return false;
 	}
+
+    bool isLeaf() const override
+    {
+        // root can't be a leaf
+        return false;
+    }
 };
 
 //========================
 //		LLOctreeTraveler
 //========================
-template <class T>
-void LLOctreeTraveler<T>::traverse(const LLOctreeNode<T>* node)
+template <class T, typename T_PTR>
+void LLOctreeTraveler<T, T_PTR>::traverse(const LLOctreeNode<T, T_PTR>* node)
 {
 	node->accept(this);
 	for (U32 i = 0; i < node->getChildCount(); i++)
@@ -850,8 +845,8 @@ void LLOctreeTraveler<T>::traverse(const LLOctreeNode<T>* node)
 	}
 }
 
-template <class T>
-void LLOctreeTravelerDepthFirst<T>::traverse(const LLOctreeNode<T>* node)
+template <class T, typename T_PTR>
+void LLOctreeTravelerDepthFirst<T, T_PTR>::traverse(const LLOctreeNode<T, T_PTR>* node)
 {
 	for (U32 i = 0; i < node->getChildCount(); i++)
 	{
diff --git a/indra/llmath/llrigginginfo.h b/indra/llmath/llrigginginfo.h
index b3d6bc2d19ddae9c4ae9eea7de71033a8e9302c4..059c6ae082215364a840f39fc6226956e9b0c004 100644
--- a/indra/llmath/llrigginginfo.h
+++ b/indra/llmath/llrigginginfo.h
@@ -34,9 +34,9 @@
 
 // Extents are in joint space
 // isRiggedTo is based on the state of all currently associated rigged meshes
-LL_ALIGN_PREFIX(16)
-class LLJointRiggingInfo
+class alignas(16) LLJointRiggingInfo
 {
+    LL_ALIGN_NEW
 public:
     LLJointRiggingInfo();
     bool isRiggedTo() const;
@@ -45,31 +45,10 @@ class LLJointRiggingInfo
     const LLVector4a *getRiggedExtents() const;
     void merge(const LLJointRiggingInfo& other);
 
-	void* operator new(size_t size)
-	{
-		return ll_aligned_malloc_16(size);
-	}
-
-	void operator delete(void* ptr)
-	{
-		ll_aligned_free_16(ptr);
-	}
-
-	void* operator new[](size_t size)
-	{
-		return ll_aligned_malloc_16(size);
-	}
-
-	void operator delete[](void* ptr)
-	{
-		ll_aligned_free_16(ptr);
-	}
-
-
 private:
-	LL_ALIGN_16(LLVector4a mRiggedExtents[2]);
+	LLVector4a mRiggedExtents[2];
     bool mIsRiggedTo;
-} LL_ALIGN_POSTFIX(16);
+};
 
 // For storing all the rigging info associated with a given avatar or
 // object, keyed by joint_num.
diff --git a/indra/llmath/llvector4a.h b/indra/llmath/llvector4a.h
index 27abf395376b13c0f7cb84a85a27a493382c56af..53c8f604f695417d0afcfe217c44df6dfae3870d 100644
--- a/indra/llmath/llvector4a.h
+++ b/indra/llmath/llvector4a.h
@@ -46,11 +46,10 @@ class LLRotation;
 // of this writing, July 08, 2010) about getting it implemented before you resort to
 // LLVector3/LLVector4. 
 /////////////////////////////////
-struct LLVector4a;
 
-LL_ALIGN_PREFIX(16)
-struct LLVector4a
+class alignas(16) LLVector4a
 {
+    LL_ALIGN_NEW
 public:
 
 	///////////////////////////////////
@@ -138,10 +137,10 @@ struct LLVector4a
 	// BASIC GET/SET 
 	////////////////////////////////////
 	
-	// Return a "this" as an F32 pointer. Do not use unless you have a very good reason.  (Not sure? Ask Falcon)
+	// Return a "this" as an F32 pointer.
 	inline F32* getF32ptr();
 	
-	// Return a "this" as a const F32 pointer. Do not use unless you have a very good reason.  (Not sure? Ask Falcon)
+	// Return a "this" as a const F32 pointer.
 	inline const F32* const getF32ptr() const;
 	
 	// Read-only access a single float in this vector. Do not use in proximity to any function call that manipulates
@@ -324,7 +323,7 @@ struct LLVector4a
     
 private:
 	LLQuad mQ;
-} LL_ALIGN_POSTFIX(16);
+};
 
 inline void update_min_max(LLVector4a& min, LLVector4a& max, const LLVector4a& p)
 {
diff --git a/indra/llmath/llvector4a.inl b/indra/llmath/llvector4a.inl
index 69d3d01efe485d3a4c677d1c6e730f0ea573b1e8..8be1c1b11484c3161810fc1616fadfa8540ab886 100644
--- a/indra/llmath/llvector4a.inl
+++ b/indra/llmath/llvector4a.inl
@@ -58,13 +58,13 @@ inline void LLVector4a::store4a(F32* dst) const
 // BASIC GET/SET 
 ////////////////////////////////////
 
-// Return a "this" as an F32 pointer. Do not use unless you have a very good reason.  (Not sure? Ask Falcon)
+// Return a "this" as an F32 pointer.
 F32* LLVector4a::getF32ptr()
 {
 	return (F32*) &mQ;
 }
 
-// Return a "this" as a const F32 pointer. Do not use unless you have a very good reason.  (Not sure? Ask Falcon)
+// Return a "this" as a const F32 pointer.
 const F32* const LLVector4a::getF32ptr() const
 {
 	return (const F32* const) &mQ;
diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp
index 13b65dfaa04278a4633cce5fddb061fe9e2aa909..f43d07ce5e81553414d6a69f4010b3a4121def5d 100644
--- a/indra/llmath/llvolume.cpp
+++ b/indra/llmath/llvolume.cpp
@@ -49,6 +49,7 @@
 #include "llsdserialize.h"
 #include "llvector4a.h"
 #include "llmatrix4a.h"
+#include "llmeshoptimizer.h"
 #include "lltimer.h"
 
 #define DEBUG_SILHOUETTE_BINORMALS 0
@@ -88,7 +89,7 @@ const F32 SKEW_MAX	=  0.95f;
 const F32 SCULPT_MIN_AREA = 0.002f;
 const S32 SCULPT_MIN_AREA_DETAIL = 1;
 
-BOOL gDebugGL = FALSE;
+BOOL gDebugGL = FALSE; // See settings.xml "RenderDebugGL"
 
 BOOL check_same_clock_dir( const LLVector3& pt1, const LLVector3& pt2, const LLVector3& pt3, const LLVector3& norm)
 {    
@@ -370,7 +371,7 @@ BOOL LLTriangleRayIntersect(const LLVector3& vert0, const LLVector3& vert1, cons
 	}
 }
 
-class LLVolumeOctreeRebound : public LLOctreeTravelerDepthFirst<LLVolumeTriangle>
+class LLVolumeOctreeRebound : public LLOctreeTravelerDepthFirst<LLVolumeTriangle, LLVolumeTriangle*>
 {
 public:
 	const LLVolumeFace* mFace;
@@ -380,9 +381,10 @@ class LLVolumeOctreeRebound : public LLOctreeTravelerDepthFirst<LLVolumeTriangle
 		mFace = face;
 	}
 
-	virtual void visit(const LLOctreeNode<LLVolumeTriangle>* branch)
+    virtual void visit(const LLOctreeNode<LLVolumeTriangle, LLVolumeTriangle*>* branch)
 	{ //this is a depth first traversal, so it's safe to assum all children have complete
 		//bounding data
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME
 
 		LLVolumeOctreeListener* node = (LLVolumeOctreeListener*) branch->getListener(0);
 
@@ -397,8 +399,7 @@ class LLVolumeOctreeRebound : public LLOctreeTravelerDepthFirst<LLVolumeTriangle
 			min = *(tri->mV[0]);
 			max = *(tri->mV[0]);
 			
-			for (LLOctreeNode<LLVolumeTriangle>::const_element_iter iter = 
-				branch->getDataBegin(); iter != branch->getDataEnd(); ++iter)
+            for (LLOctreeNode<LLVolumeTriangle, LLVolumeTriangle*>::const_element_iter iter = branch->getDataBegin(); iter != branch->getDataEnd(); ++iter)
 			{ //for each triangle in node
 
 				//stretch by triangles in node
@@ -413,7 +414,7 @@ class LLVolumeOctreeRebound : public LLOctreeTravelerDepthFirst<LLVolumeTriangle
 				max.setMax(max, *tri->mV[2]);
 			}
 		}
-		else if (!branch->isLeaf())
+		else if (branch->getChildCount() > 0)
 		{ //no data, but child nodes exist
 			LLVolumeOctreeListener* child = (LLVolumeOctreeListener*) branch->getChild(0)->getListener(0);
 
@@ -423,7 +424,7 @@ class LLVolumeOctreeRebound : public LLOctreeTravelerDepthFirst<LLVolumeTriangle
 		}
 		else
 		{
-			LL_ERRS() << "Empty leaf" << LL_ENDL;
+            llassert(!branch->isLeaf()); // Empty leaf
 		}
 
 		for (S32 i = 0; i < branch->getChildCount(); ++i)
@@ -682,7 +683,7 @@ LLProfile::Face* LLProfile::addHole(const LLProfileParams& params, BOOL flat, F3
 
 	Face *face = addFace(mTotalOut, mTotal-mTotalOut,0,LL_FACE_INNER_SIDE, flat);
 
-	static LLAlignedArray<LLVector4a,64> pt;
+	static thread_local LLAlignedArray<LLVector4a,64> pt;
 	pt.resize(mTotal) ;
 
 	for (S32 i=mTotalOut;i<mTotal;i++)
@@ -822,6 +823,8 @@ S32 LLProfile::getNumPoints(const LLProfileParams& params, BOOL path_open,F32 de
 BOOL LLProfile::generate(const LLProfileParams& params, BOOL path_open,F32 detail, S32 split,
 						 BOOL is_sculpted, S32 sculpt_size)
 {
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME
+
 	if ((!mDirty) && (!is_sculpted))
 	{
 		return FALSE;
@@ -1302,6 +1305,8 @@ S32 LLPath::getNumNGonPoints(const LLPathParams& params, S32 sides, F32 startOff
 
 void LLPath::genNGon(const LLPathParams& params, S32 sides, F32 startOff, F32 end_scale, F32 twist_scale)
 {
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME
+
 	// Generates a circular path, starting at (1, 0, 0), counterclockwise along the xz plane.
 	static const F32 tableScale[] = { 1, 1, 1, 0.5f, 0.707107f, 0.53f, 0.525f, 0.5f };
 
@@ -1536,6 +1541,8 @@ S32 LLPath::getNumPoints(const LLPathParams& params, F32 detail)
 BOOL LLPath::generate(const LLPathParams& params, F32 detail, S32 split,
 					  BOOL is_sculpted, S32 sculpt_size)
 {
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME
+
 	if ((!mDirty) && (!is_sculpted))
 	{
 		return FALSE;
@@ -1617,9 +1624,6 @@ BOOL LLPath::generate(const LLPathParams& params, F32 detail, S32 split,
 			//genNGon(params, llfloor(MIN_DETAIL_FACES * detail), 4.f, 0.f);
 			genNGon(params, llfloor(MIN_DETAIL_FACES * detail));
 
-			F32 t     = 0.f;
-			F32 tStep = 1.0f / mPath.size();
-
 			F32 toggle = 0.5f;
 			for (S32 i=0;i<(S32)mPath.size();i++)
 			{
@@ -1628,7 +1632,6 @@ BOOL LLPath::generate(const LLPathParams& params, F32 detail, S32 split,
 					toggle = -0.5f;
 				else
 					toggle = 0.5f;
-				t += tStep;
 			}
 		}
 
@@ -2112,6 +2115,8 @@ LLVolume::~LLVolume()
 
 BOOL LLVolume::generate()
 {
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME
+
 	LL_CHECK_MEMORY
 	llassert_always(mProfilep);
 	
@@ -2370,6 +2375,8 @@ bool LLVolumeFace::VertexData::compareNormal(const LLVolumeFace::VertexData& rhs
 
 bool LLVolume::unpackVolumeFaces(std::istream& is, S32 size)
 {
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME
+
 	//input stream is now pointing at a zlib compressed block of LLSD
 	//decompress block
 	LLSD mdl;
@@ -2415,6 +2422,13 @@ bool LLVolume::unpackVolumeFaces(std::istream& is, S32 size)
 
 			//copy out indices
             S32 num_indices = idx.size() / 2;
+            const S32 indices_to_discard = num_indices % 3;
+            if (indices_to_discard > 0)
+            {
+                // Invalid number of triangle indices
+                LL_WARNS() << "Incomplete triangle discarded from face! Indices count " << num_indices << " was not divisible by 3. face index: " << i << " Total: " << face_count << LL_ENDL;
+                num_indices -= indices_to_discard;
+            }
             face.resizeIndices(num_indices);
 
             if (num_indices > 2 && !face.mIndices)
@@ -2430,8 +2444,7 @@ bool LLVolume::unpackVolumeFaces(std::istream& is, S32 size)
 			}
 
 			U16* indices = (U16*) &(idx[0]);
-			U32 count = idx.size()/2;
-			for (U32 j = 0; j < count; ++j)
+            for (U32 j = 0; j < num_indices; ++j)
 			{
 				face.mIndices[j] = indices[j];
 			}
@@ -2776,6 +2789,8 @@ S32	LLVolume::getNumFaces() const
 
 void LLVolume::createVolumeFaces()
 {
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME
+
 	if (mGenerateSingleFace)
 	{
 		// do nothing
@@ -3741,6 +3756,8 @@ void LLVolume::generateSilhouetteVertices(std::vector<LLVector3> &vertices,
 										  const LLMatrix3& norm_mat_in,
 										  S32 face_mask)
 {
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME
+
 	LLMatrix4a mat;
 	mat.loadu(mat_in);
 
@@ -3819,8 +3836,8 @@ void LLVolume::generateSilhouetteVertices(std::vector<LLVector3> &vertices,
 #if DEBUG_SILHOUETTE_EDGE_MAP
 
 			//for each triangle
-			U32 count = face.mNumIndices;
-			for (U32 j = 0; j < count/3; j++) {
+            U32 tri_count = face.mNumIndices / 3;
+            for (U32 j = 0; j < tri_count; j++) {
 				//get vertices
 				S32 v1 = face.mIndices[j*3+0];
 				S32 v2 = face.mIndices[j*3+1];
@@ -3838,7 +3855,7 @@ void LLVolume::generateSilhouetteVertices(std::vector<LLVector3> &vertices,
 						continue;
 					}
 
-					if (nIndex >= (S32) count/3) {
+                    if (nIndex >= (S32)tri_count) {
 						continue;
 					}
 					//get neighbor vertices
@@ -4130,13 +4147,13 @@ S32 LLVolume::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& en
 			}
 			else
 			{
-				if (!face.mOctree)
+                if (!face.getOctree())
 				{
 					face.createOctree();
 				}
 			
 				LLOctreeTriangleRayIntersect intersect(start, dir, &face, &closest_t, intersection, tex_coord, normal, tangent_out);
-				intersect.traverse(face.mOctree);
+                intersect.traverse(face.getOctree());
 				if (intersect.mHitFace)
 				{
 					hit_face = i;
@@ -4691,6 +4708,7 @@ LLVolumeFace::LLVolumeFace() :
 #endif
     mWeightsScrubbed(FALSE),
 	mOctree(NULL),
+    mOctreeTriangles(NULL),
 	mOptimized(FALSE)
 {
 	mExtents = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*3);
@@ -4720,8 +4738,9 @@ LLVolumeFace::LLVolumeFace(const LLVolumeFace& src)
     mJointIndices(NULL),
 #endif
     mWeightsScrubbed(FALSE),
-	mOctree(NULL)
-{ 
+    mOctree(NULL),
+    mOctreeTriangles(NULL)
+{
 	mExtents = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*3);
 	mCenter = mExtents+2;
 	*this = src;
@@ -4861,15 +4880,15 @@ void LLVolumeFace::freeData()
 	mJustWeights = NULL;
 #endif
 
-	delete mOctree;
-	mOctree = NULL;
+    destroyOctree();
 }
 
 BOOL LLVolumeFace::create(LLVolume* volume, BOOL partial_build)
 {
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME
+
 	//tree for this face is no longer valid
-	delete mOctree;
-	mOctree = NULL;
+    destroyOctree();
 
 	LL_CHECK_MEMORY
 	BOOL ret = FALSE ;
@@ -4935,6 +4954,50 @@ bool LLVolumeFace::VertexMapData::ComparePosition::operator()(const LLVector3& a
 	return a.mV[2] < b.mV[2];
 }
 
+void LLVolumeFace::remap()
+{
+    // Generate a remap buffer
+    std::vector<unsigned int> remap(mNumVertices);
+    S32 remap_vertices_count = LLMeshOptimizer::generateRemapMultiU16(&remap[0],
+        mIndices,
+        mNumIndices,
+        mPositions,
+        mNormals,
+        mTexCoords,
+        mNumVertices);
+
+    // Allocate new buffers
+    S32 size = ((mNumIndices * sizeof(U16)) + 0xF) & ~0xF;
+    U16* remap_indices = (U16*)ll_aligned_malloc_16(size);
+
+    S32 tc_bytes_size = ((remap_vertices_count * sizeof(LLVector2)) + 0xF) & ~0xF;
+    LLVector4a* remap_positions = (LLVector4a*)ll_aligned_malloc<64>(sizeof(LLVector4a) * 2 * remap_vertices_count + tc_bytes_size);
+    LLVector4a* remap_normals = remap_positions + remap_vertices_count;
+    LLVector2* remap_tex_coords = (LLVector2*)(remap_normals + remap_vertices_count);
+
+    // Fill the buffers
+    LLMeshOptimizer::remapIndexBufferU16(remap_indices, mIndices, mNumIndices, &remap[0]);
+    LLMeshOptimizer::remapPositionsBuffer(remap_positions, mPositions, mNumVertices, &remap[0]);
+    LLMeshOptimizer::remapNormalsBuffer(remap_normals, mNormals, mNumVertices, &remap[0]);
+    LLMeshOptimizer::remapUVBuffer(remap_tex_coords, mTexCoords, mNumVertices, &remap[0]);
+
+    // Free unused buffers
+    ll_aligned_free_16(mIndices);
+    ll_aligned_free<64>(mPositions);
+
+    // Tangets are now invalid
+    ll_aligned_free_16(mTangents);
+    mTangents = NULL;
+
+    // Assign new values
+    mIndices = remap_indices;
+    mPositions = remap_positions;
+    mNormals = remap_normals;
+    mTexCoords = remap_tex_coords;
+    mNumVertices = remap_vertices_count;
+    mNumAllocatedVertices = remap_vertices_count;
+}
+
 void LLVolumeFace::optimize(F32 angle_cutoff)
 {
 	LLVolumeFace new_face;
@@ -5536,21 +5599,29 @@ bool LLVolumeFace::cacheOptimize()
 
 void LLVolumeFace::createOctree(F32 scaler, const LLVector4a& center, const LLVector4a& size)
 {
-	if (mOctree)
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME
+
+    if (getOctree())
 	{
 		return;
 	}
 
-	mOctree = new LLOctreeRoot<LLVolumeTriangle>(center, size, NULL);
+    llassert(mNumIndices % 3 == 0);
+
+    mOctree = new LLOctreeRoot<LLVolumeTriangle, LLVolumeTriangle*>(center, size, NULL);
 	new LLVolumeOctreeListener(mOctree);
+    const U32 num_triangles = mNumIndices / 3;
+    // Initialize all the triangles we need
+    mOctreeTriangles = new LLVolumeTriangle[num_triangles];
 
-	for (U32 i = 0; i < mNumIndices; i+= 3)
+    for (U32 triangle_index = 0; triangle_index < num_triangles; ++triangle_index)
 	{ //for each triangle
-		LLPointer<LLVolumeTriangle> tri = new LLVolumeTriangle();
+        const U32 index = triangle_index * 3;
+        LLVolumeTriangle* tri = &mOctreeTriangles[triangle_index];
 				
-		const LLVector4a& v0 = mPositions[mIndices[i]];
-		const LLVector4a& v1 = mPositions[mIndices[i+1]];
-		const LLVector4a& v2 = mPositions[mIndices[i+2]];
+		const LLVector4a& v0 = mPositions[mIndices[index]];
+		const LLVector4a& v1 = mPositions[mIndices[index + 1]];
+		const LLVector4a& v2 = mPositions[mIndices[index + 2]];
 
 		//store pointers to vertex data
 		tri->mV[0] = &v0;
@@ -5558,9 +5629,9 @@ void LLVolumeFace::createOctree(F32 scaler, const LLVector4a& center, const LLVe
 		tri->mV[2] = &v2;
 
 		//store indices
-		tri->mIndex[0] = mIndices[i];
-		tri->mIndex[1] = mIndices[i+1];
-		tri->mIndex[2] = mIndices[i+2];
+		tri->mIndex[0] = mIndices[index];
+		tri->mIndex[1] = mIndices[index + 1];
+		tri->mIndex[2] = mIndices[index + 2];
 
 		//get minimum point
 		LLVector4a min = v0;
@@ -5603,6 +5674,19 @@ void LLVolumeFace::createOctree(F32 scaler, const LLVector4a& center, const LLVe
 	}
 }
 
+void LLVolumeFace::destroyOctree()
+{
+    delete mOctree;
+    mOctree = NULL;
+    delete[] mOctreeTriangles;
+    mOctreeTriangles = NULL;
+}
+
+const LLOctreeNode<LLVolumeTriangle, LLVolumeTriangle*>* LLVolumeFace::getOctree() const
+{
+    return mOctree;
+}
+
 
 void LLVolumeFace::swapData(LLVolumeFace& rhs)
 {
@@ -5745,7 +5829,16 @@ BOOL LLVolumeFace::createUnCutCubeCap(LLVolume* volume, BOOL partial_build)
 		resizeIndices(grid_size*grid_size*6);
 		if (!volume->isMeshAssetLoaded())
 		{
-			mEdge.resize(grid_size*grid_size * 6);
+            S32 size = grid_size * grid_size * 6;
+            try
+            {
+                mEdge.resize(size);
+            }
+            catch (std::bad_alloc&)
+            {
+                LL_WARNS("LLVOLUME") << "Resize of mEdge to " << size << " failed" << LL_ENDL;
+                return false;
+            }
 		}
 
 		U16* out = mIndices;
@@ -6309,6 +6402,8 @@ void CalculateTangentArray(U32 vertexCount, const LLVector4a *vertex, const LLVe
 
 void LLVolumeFace::createTangents()
 {
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME
+
 	if (!mTangents)
 	{
 		allocateTangents(mNumVertices);
@@ -6349,9 +6444,9 @@ void LLVolumeFace::resizeVertices(S32 num_verts)
 	if (num_verts)
 	{
 		//pad texture coordinate block end to allow for QWORD reads
-		S32 size = ((num_verts*sizeof(LLVector2)) + 0xF) & ~0xF;
+		S32 tc_size = ((num_verts*sizeof(LLVector2)) + 0xF) & ~0xF;
 
-		mPositions = (LLVector4a*) ll_aligned_malloc<64>(sizeof(LLVector4a)*2*num_verts+size);
+		mPositions = (LLVector4a*) ll_aligned_malloc<64>(sizeof(LLVector4a)*2*num_verts+tc_size);
 		mNormals = mPositions+num_verts;
 		mTexCoords = (LLVector2*) (mNormals+num_verts);
 
@@ -6463,6 +6558,7 @@ void LLVolumeFace::allocateJointIndices(S32 num_verts)
 void LLVolumeFace::resizeIndices(S32 num_indices)
 {
 	ll_aligned_free_16(mIndices);
+    llassert(num_indices % 3 == 0);
 	
 	if (num_indices)
 	{
@@ -6522,6 +6618,8 @@ void LLVolumeFace::fillFromLegacyData(std::vector<LLVolumeFace::VertexData>& v,
 
 BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build)
 {
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME
+
 	LL_CHECK_MEMORY
 	BOOL flat = mTypeMask & FLAT_MASK;
 
@@ -6554,7 +6652,15 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build)
 
 		if (!volume->isMeshAssetLoaded())
 		{
-			mEdge.resize(num_indices);
+            try
+            {
+                mEdge.resize(num_indices);
+            }
+            catch (std::bad_alloc&)
+            {
+                LL_WARNS("LLVOLUME") << "Resize of mEdge to " << num_indices << " failed" << LL_ENDL;
+                return false;
+            }
 		}
 	}
 
@@ -6589,13 +6695,19 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build)
 			else
 			{
 				// Get s value for tex-coord.
-				if (!flat)
+                S32 index = mBeginS + s;
+                if (index >= profile.size())
+                {
+                    // edge?
+                    ss = flat ? 1.f - begin_stex : 1.f;
+                }
+				else if (!flat)
 				{
-					ss = profile[mBeginS + s][2];
+					ss = profile[index][2];
 				}
 				else
 				{
-					ss = profile[mBeginS + s][2] - begin_stex;
+					ss = profile[index][2] - begin_stex;
 				}
 			}
 
@@ -6781,8 +6893,16 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build)
 
 	LLVector4a* norm = mNormals;
 
-	static LLAlignedArray<LLVector4a, 64> triangle_normals;
-	triangle_normals.resize(count);
+    static thread_local LLAlignedArray<LLVector4a, 64> triangle_normals;
+    try
+    {
+        triangle_normals.resize(count);
+    }
+    catch (std::bad_alloc&)
+    {
+        LL_WARNS("LLVOLUME") << "Resize of triangle_normals to " << count << " failed" << LL_ENDL;
+        return false;
+    }
 	LLVector4a* output = triangle_normals.mArray;
 	LLVector4a* end_output = output+count;
 
@@ -7014,6 +7134,8 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build)
 void CalculateTangentArray(U32 vertexCount, const LLVector4a *vertex, const LLVector4a *normal,
         const LLVector2 *texcoord, U32 triangleCount, const U16* index_array, LLVector4a *tangent)
 {
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME
+
     //LLVector4a *tan1 = new LLVector4a[vertexCount * 2];
 	LLVector4a* tan1 = (LLVector4a*) ll_aligned_malloc_16(vertexCount*2*sizeof(LLVector4a));
 	// new(tan1) LLVector4a;
diff --git a/indra/llmath/llvolume.h b/indra/llmath/llvolume.h
index a77e8c08c6585b1606243f514627bf7256e432ac..3ccaed47f13eabba83217368f503335157877f53 100644
--- a/indra/llmath/llvolume.h
+++ b/indra/llmath/llvolume.h
@@ -35,7 +35,8 @@ class LLVolumeParams;
 class LLProfile;
 class LLPath;
 
-template <class T> class LLOctreeNode;
+template<class T> class LLPointer;
+template <class T, typename T_PTR> class LLOctreeNode;
 
 class LLVolumeFace;
 class LLVolume;
@@ -902,10 +903,17 @@ class LLVolumeFace
 		typedef std::map<LLVector3, std::vector<VertexMapData>, VertexMapData::ComparePosition > PointMap;
 	};
 
+    // Eliminates non unique triangles, takes positions,
+    // normals and texture coordinates into account.
+    void remap();
+
 	void optimize(F32 angle_cutoff = 2.f);
 	bool cacheOptimize();
 
 	void createOctree(F32 scaler = 0.25f, const LLVector4a& center = LLVector4a(0,0,0), const LLVector4a& size = LLVector4a(0.5f,0.5f,0.5f));
+    void destroyOctree();
+    // Get a reference to the octree, which may be null
+    const LLOctreeNode<LLVolumeTriangle, LLVolumeTriangle*>* getOctree() const;
 
 	enum
 	{
@@ -936,17 +944,23 @@ class LLVolumeFace
 	LLVector4a* mCenter;
 	LLVector2   mTexCoordExtents[2]; //minimum and maximum of texture coordinates of the face.
 
-	S32 mNumVertices;
+	S32 mNumVertices; // num vertices == num normals == num texcoords
 	S32 mNumAllocatedVertices;
 	S32 mNumIndices;
 
-	LLVector4a* mPositions;
-	LLVector4a* mNormals;
+	LLVector4a* mPositions; // Contains vertices, nortmals and texcoords
+	LLVector4a* mNormals; // pointer into mPositions
 	LLVector4a* mTangents;
-	LLVector2*  mTexCoords;
+	LLVector2*  mTexCoords; // pointer into mPositions
+
+	// mIndices contains mNumIndices amount of elements.
+	// It contains triangles, each 3 indices describe one triangle.
+    // If mIndices contains {0, 2, 3, 1, 2, 4}, it means there
+    // are two triangles {0, 2, 3} and {1, 2, 4} with values being
+    // indexes for mPositions/mNormals/mTexCoords
 	U16* mIndices;
 
-	//vertex buffer filled in by LLFace to cache this volume face geometry in vram 
+	// vertex buffer filled in by LLFace to cache this volume face geometry in vram 
 	// (declared as a LLPointer to LLRefCount to avoid dependency on LLVertexBuffer)
 	mutable LLPointer<LLRefCount> mVertexBuffer; 
 
@@ -967,13 +981,14 @@ class LLVolumeFace
     // Which joints are rigged to, and the bounding box of any rigged
     // vertices per joint.
     LLJointRiggingInfoTab mJointRiggingInfoTab;
-    
-	LLOctreeNode<LLVolumeTriangle>* mOctree;
 
 	//whether or not face has been cache optimized
 	BOOL mOptimized;
 
 private:
+    LLOctreeNode<LLVolumeTriangle, LLVolumeTriangle*>* mOctree;
+    LLVolumeTriangle* mOctreeTriangles;
+
 	BOOL createUnCutCubeCap(LLVolume* volume, BOOL partial_build = FALSE);
 	BOOL createCap(LLVolume* volume, BOOL partial_build = FALSE);
 	BOOL createSide(LLVolume* volume, BOOL partial_build = FALSE);
diff --git a/indra/llmath/llvolumeoctree.cpp b/indra/llmath/llvolumeoctree.cpp
index fb232d5f6cf1f60602c3e702b4fc47203bedb981..6894d04d3ca650274c690dd1f8ca458eedb880ad 100644
--- a/indra/llmath/llvolumeoctree.cpp
+++ b/indra/llmath/llvolumeoctree.cpp
@@ -75,7 +75,7 @@ BOOL LLLineSegmentBoxIntersect(const LLVector4a& start, const LLVector4a& end, c
 }
 
 
-LLVolumeOctreeListener::LLVolumeOctreeListener(LLOctreeNode<LLVolumeTriangle>* node)
+LLVolumeOctreeListener::LLVolumeOctreeListener(LLOctreeNode<LLVolumeTriangle, LLVolumeTriangle*>* node)
 {
 	node->addListener(this);
 }
@@ -85,13 +85,12 @@ LLVolumeOctreeListener::~LLVolumeOctreeListener()
 
 }
 	
-void LLVolumeOctreeListener::handleChildAddition(const LLOctreeNode<LLVolumeTriangle>* parent, 
-	LLOctreeNode<LLVolumeTriangle>* child)
+void LLVolumeOctreeListener::handleChildAddition(const LLOctreeNode<LLVolumeTriangle, LLVolumeTriangle*>* parent, 
+    LLOctreeNode<LLVolumeTriangle, LLVolumeTriangle*>* child)
 {
 	new LLVolumeOctreeListener(child);
 }
 
-
 LLOctreeTriangleRayIntersect::LLOctreeTriangleRayIntersect(const LLVector4a& start, const LLVector4a& dir, 
 							   const LLVolumeFace* face, F32* closest_t,
 							   LLVector4a* intersection,LLVector2* tex_coord, LLVector4a* normal, LLVector4a* tangent)
@@ -108,7 +107,7 @@ LLOctreeTriangleRayIntersect::LLOctreeTriangleRayIntersect(const LLVector4a& sta
 	mEnd.setAdd(mStart, mDir);
 }
 
-void LLOctreeTriangleRayIntersect::traverse(const LLOctreeNode<LLVolumeTriangle>* node)
+void LLOctreeTriangleRayIntersect::traverse(const LLOctreeNode<LLVolumeTriangle, LLVolumeTriangle*>* node)
 {
 	LLVolumeOctreeListener* vl = (LLVolumeOctreeListener*) node->getListener(0);
 
@@ -122,9 +121,9 @@ void LLOctreeTriangleRayIntersect::traverse(const LLOctreeNode<LLVolumeTriangle>
 	}
 }
 
-void LLOctreeTriangleRayIntersect::visit(const LLOctreeNode<LLVolumeTriangle>* node)
+void LLOctreeTriangleRayIntersect::visit(const LLOctreeNode<LLVolumeTriangle, LLVolumeTriangle*>* node)
 {
-	for (LLOctreeNode<LLVolumeTriangle>::const_element_iter iter = 
+    for (typename LLOctreeNode<LLVolumeTriangle, LLVolumeTriangle*>::const_element_iter iter =
 			node->getDataBegin(); iter != node->getDataEnd(); ++iter)
 	{
 		const LLVolumeTriangle* tri = *iter;
@@ -219,7 +218,7 @@ const F32& LLVolumeTriangle::getBinRadius() const
 
 //TEST CODE
 
-void LLVolumeOctreeValidate::visit(const LLOctreeNode<LLVolumeTriangle>* branch)
+void LLVolumeOctreeValidate::visit(const LLOctreeNode<LLVolumeTriangle, LLVolumeTriangle*>* branch)
 {
 	LLVolumeOctreeListener* node = (LLVolumeOctreeListener*) branch->getListener(0);
 
@@ -256,7 +255,7 @@ void LLVolumeOctreeValidate::visit(const LLOctreeNode<LLVolumeTriangle>* branch)
 	}
 
 	//children fit, check data
-	for (LLOctreeNode<LLVolumeTriangle>::const_element_iter iter = branch->getDataBegin(); 
+    for (typename LLOctreeNode<LLVolumeTriangle, LLVolumeTriangle*>::const_element_iter iter = branch->getDataBegin();
 			iter != branch->getDataEnd(); ++iter)
 	{
 		const LLVolumeTriangle* tri = *iter;
@@ -273,4 +272,3 @@ void LLVolumeOctreeValidate::visit(const LLOctreeNode<LLVolumeTriangle>* branch)
 	}
 }
 
-
diff --git a/indra/llmath/llvolumeoctree.h b/indra/llmath/llvolumeoctree.h
index 13150028d8253b6dfc15c3e88a282018450e4b89..d65bca5e52d566599b12a1665950d03e543d6eea 100644
--- a/indra/llmath/llvolumeoctree.h
+++ b/indra/llmath/llvolumeoctree.h
@@ -34,19 +34,10 @@
 #include "llvolume.h"
 #include "llvector4a.h"
 
-class LLVolumeTriangle : public LLRefCount
+class alignas(16) LLVolumeTriangle : public LLRefCount
 {
+    LL_ALIGN_NEW
 public:
-	void* operator new(size_t size)
-	{
-		return ll_aligned_malloc_16(size);
-	}
-
-	void operator delete(void* ptr)
-	{
-		ll_aligned_free_16(ptr);
-	}
-
 	LLVolumeTriangle()
 	{
 		mBinIndex = -1;	
@@ -86,21 +77,11 @@ class LLVolumeTriangle : public LLRefCount
 
 };
 
-class LLVolumeOctreeListener : public LLOctreeListener<LLVolumeTriangle>
+class alignas(16) LLVolumeOctreeListener : public LLOctreeListener<LLVolumeTriangle, LLVolumeTriangle*>
 {
+    LL_ALIGN_NEW
 public:
-	
-	void* operator new(size_t size)
-	{
-		return ll_aligned_malloc_16(size);
-	}
-
-	void operator delete(void* ptr)
-	{
-		ll_aligned_free_16(ptr);
-	}
-
-	LLVolumeOctreeListener(LLOctreeNode<LLVolumeTriangle>* node);
+    LLVolumeOctreeListener(LLOctreeNode<LLVolumeTriangle, LLVolumeTriangle*>* node);
 	~LLVolumeOctreeListener();
 	
 	LLVolumeOctreeListener(const LLVolumeOctreeListener& rhs)
@@ -115,11 +96,9 @@ class LLVolumeOctreeListener : public LLOctreeListener<LLVolumeTriangle>
 	}
 
 	 //LISTENER FUNCTIONS
-	virtual void handleChildAddition(const LLOctreeNode<LLVolumeTriangle>* parent, 
-		LLOctreeNode<LLVolumeTriangle>* child);
+    virtual void handleChildAddition(const LLOctreeNode<LLVolumeTriangle, LLVolumeTriangle*>* parent, LLOctreeNode<LLVolumeTriangle, LLVolumeTriangle*>* child);
 	virtual void handleStateChange(const LLTreeNode<LLVolumeTriangle>* node) { }
-	virtual void handleChildRemoval(const LLOctreeNode<LLVolumeTriangle>* parent, 
-			const LLOctreeNode<LLVolumeTriangle>* child) {	}
+    virtual void handleChildRemoval(const LLOctreeNode<LLVolumeTriangle, LLVolumeTriangle*>* parent, const LLOctreeNode<LLVolumeTriangle, LLVolumeTriangle*>* child) { }
 	virtual void handleInsertion(const LLTreeNode<LLVolumeTriangle>* node, LLVolumeTriangle* tri) { }
 	virtual void handleRemoval(const LLTreeNode<LLVolumeTriangle>* node, LLVolumeTriangle* tri) { }
 	virtual void handleDestruction(const LLTreeNode<LLVolumeTriangle>* node) { }
@@ -130,7 +109,7 @@ class LLVolumeOctreeListener : public LLOctreeListener<LLVolumeTriangle>
 	LL_ALIGN_16(LLVector4a mExtents[2]); // extents (min, max) of this node and all its children
 };
 
-class LLOctreeTriangleRayIntersect : public LLOctreeTraveler<LLVolumeTriangle>
+class LLOctreeTriangleRayIntersect : public LLOctreeTraveler<LLVolumeTriangle, LLVolumeTriangle*>
 {
 public:
 	const LLVolumeFace* mFace;
@@ -148,14 +127,14 @@ class LLOctreeTriangleRayIntersect : public LLOctreeTraveler<LLVolumeTriangle>
 								   const LLVolumeFace* face, F32* closest_t,
 								   LLVector4a* intersection,LLVector2* tex_coord, LLVector4a* normal, LLVector4a* tangent);
 
-	void traverse(const LLOctreeNode<LLVolumeTriangle>* node);
+    void traverse(const LLOctreeNode<LLVolumeTriangle, LLVolumeTriangle*>* node);
 
-	virtual void visit(const LLOctreeNode<LLVolumeTriangle>* node);
+    virtual void visit(const LLOctreeNode<LLVolumeTriangle, LLVolumeTriangle*>* node);
 };
 
-class LLVolumeOctreeValidate : public LLOctreeTraveler<LLVolumeTriangle>
+class LLVolumeOctreeValidate : public LLOctreeTraveler<LLVolumeTriangle, LLVolumeTriangle*>
 {
-	virtual void visit(const LLOctreeNode<LLVolumeTriangle>* branch);
+    virtual void visit(const LLOctreeNode<LLVolumeTriangle, LLVolumeTriangle*>* branch);
 };
 
 #endif
diff --git a/indra/llmath/m4math.cpp b/indra/llmath/m4math.cpp
index 3baf1bad18bc5ac0f6450793f6353831135b6b7a..6e40dae30b7fa35d071ac5546278bd713729f797 100644
--- a/indra/llmath/m4math.cpp
+++ b/indra/llmath/m4math.cpp
@@ -32,8 +32,7 @@
 #include "m4math.h"
 #include "m3math.h"
 #include "llquaternion.h"
-
-
+#include "llmatrix4a.h"
 
 
 // LLMatrix4
@@ -115,6 +114,12 @@ LLMatrix4::LLMatrix4(const LLQuaternion &q)
 	*this = initRotation(q);
 }
 
+LLMatrix4::LLMatrix4(const LLMatrix4a& mat)
+    : LLMatrix4(mat.getF32ptr())
+{
+    
+}
+
 LLMatrix4::LLMatrix4(const LLQuaternion &q, const LLVector4 &pos)
 {
 	*this = initRotTrans(q, pos);
diff --git a/indra/llmath/m4math.h b/indra/llmath/m4math.h
index bf60adb9b6e9083a4bd684c3b8be98306144be71..b9da970cde11cb12c4236e91a7f0d3205a47137b 100644
--- a/indra/llmath/m4math.h
+++ b/indra/llmath/m4math.h
@@ -32,6 +32,7 @@
 class LLVector4;
 class LLMatrix3;
 class LLQuaternion;
+class LLMatrix4a;
 
 // NOTA BENE: Currently assuming a right-handed, x-forward, y-left, z-up universe
 
@@ -104,6 +105,7 @@ class LLMatrix4
 	explicit LLMatrix4(const F32 *mat);								// Initializes Matrix to values in mat
 	explicit LLMatrix4(const LLMatrix3 &mat);						// Initializes Matrix to values in mat and sets position to (0,0,0)
 	explicit LLMatrix4(const LLQuaternion &q);						// Initializes Matrix with rotation q and sets position to (0,0,0)
+    explicit LLMatrix4(const LLMatrix4a& mat);
 
 	LLMatrix4(const LLMatrix3 &mat, const LLVector4 &pos);	// Initializes Matrix to values in mat and pos
 
diff --git a/indra/llmath/v3math.cpp b/indra/llmath/v3math.cpp
index b04c67d92631fac6535c0f161631487c66c66e1f..93010d2250a6471d717f7a2460280a256353fec6 100644
--- a/indra/llmath/v3math.cpp
+++ b/indra/llmath/v3math.cpp
@@ -316,6 +316,12 @@ LLVector3::LLVector3(const LLVector4 &vec)
 	mV[VZ] = (F32)vec.mV[VZ];
 }
 
+LLVector3::LLVector3(const LLVector4a& vec)
+    : LLVector3(vec.getF32ptr())
+{
+
+}
+
 LLVector3::LLVector3(const LLSD& sd)
 {
 	setValue(sd);
diff --git a/indra/llmath/v3math.h b/indra/llmath/v3math.h
index 6f857d70617167ade434c4235e76860124b15465..068f489020667be2b8498e86eedc6fb35a4c5910 100644
--- a/indra/llmath/v3math.h
+++ b/indra/llmath/v3math.h
@@ -33,6 +33,7 @@
 #include "llsd.h"
 class LLVector2;
 class LLVector4;
+class LLVector4a;
 class LLMatrix3;
 class LLMatrix4;
 class LLVector3d;
@@ -62,7 +63,9 @@ class LLVector3
 		explicit LLVector3(const LLVector2 &vec);				// Initializes LLVector3 to (vec[0]. vec[1], 0)
 		explicit LLVector3(const LLVector3d &vec);				// Initializes LLVector3 to (vec[0]. vec[1], vec[2])
 		explicit LLVector3(const LLVector4 &vec);				// Initializes LLVector4 to (vec[0]. vec[1], vec[2])
-		explicit LLVector3(const LLSD& sd);
+        explicit LLVector3(const LLVector4a& vec);              // Initializes LLVector4 to (vec[0]. vec[1], vec[2])
+        explicit LLVector3(const LLSD& sd);
+        
 
 		LLSD getValue() const;
 
diff --git a/indra/llmeshoptimizer/CMakeLists.txt b/indra/llmeshoptimizer/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..016794cfad5783c23a5ae99f8958e9fd375b94cd
--- /dev/null
+++ b/indra/llmeshoptimizer/CMakeLists.txt
@@ -0,0 +1,44 @@
+# -*- cmake -*-
+
+project(llmeshoptimizer)
+
+include(MESHOPTIMIZER)
+
+include(00-Common)
+include(LLCommon)
+include(LLMath)
+
+include_directories(
+    ${LLCOMMON_INCLUDE_DIRS}
+    ${LLMATH_INCLUDE_DIRS}
+    ${LLMESHOPTIMIZER_INCLUDE_DIR}
+    ${MESHOPTIMIZER_INCLUDE_DIRS}
+    ${LIBS_PREBUILT_DIR}/include  #access to boost headers, needed for LLError
+    )
+
+set(llmeshoptimizer_SOURCE_FILES
+    llmeshoptimizer.cpp
+    )
+
+set(llmeshoptimizer_HEADER_FILES
+    CMakeLists.txt
+
+    llmeshoptimizer.h
+    )
+
+set_source_files_properties(${llmeshoptimizer_HEADER_FILES}
+                            PROPERTIES HEADER_FILE_ONLY TRUE)
+
+list(APPEND llmeshoptimizer_SOURCE_FILES ${llmeshoptimizer_HEADER_FILES})
+
+#if (USE_MESHOPT)
+  add_library (llmeshoptimizer ${llmeshoptimizer_SOURCE_FILES})
+
+  target_link_libraries(llmeshoptimizer
+    ${LLCOMMON_LIBRARIES}
+    ${LLMATH_LIBRARIES}
+    ${MESHOPTIMIZER_LIBRARIES})
+  
+  # Add tests
+
+#endif (USE_MESHOPT)
diff --git a/indra/llmeshoptimizer/llmeshoptimizer.cpp b/indra/llmeshoptimizer/llmeshoptimizer.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..c178348968c24599183bec3b560686f32afd1534
--- /dev/null
+++ b/indra/llmeshoptimizer/llmeshoptimizer.cpp
@@ -0,0 +1,339 @@
+ /** 
+* @file llmeshoptimizer.cpp
+* @brief Wrapper around meshoptimizer
+*
+* $LicenseInfo:firstyear=2021&license=viewerlgpl$
+* Second Life Viewer Source Code
+* Copyright (C) 2021, Linden Research, Inc.
+* 
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Lesser General Public
+* License as published by the Free Software Foundation;
+* version 2.1 of the License only.
+* 
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+* Lesser General Public License for more details.
+* 
+* You should have received a copy of the GNU Lesser General Public
+* License along with this library; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+* 
+* Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+* $/LicenseInfo$
+*/
+
+#include "llmeshoptimizer.h"
+
+#include "meshoptimizer.h"
+
+#include "llmath.h"
+#include "v2math.h"
+
+LLMeshOptimizer::LLMeshOptimizer()
+{
+    // Todo: Looks like for memory management, we can add allocator and deallocator callbacks
+    // Should be one time
+    // meshopt_setAllocator(allocate, deallocate);
+}
+
+LLMeshOptimizer::~LLMeshOptimizer()
+{
+}
+
+//static
+void LLMeshOptimizer::generateShadowIndexBufferU32(U32 *destination,
+    const U32 *indices,
+    U64 index_count,
+    const LLVector4a * vertex_positions,
+    const LLVector4a * normals,
+    const LLVector2 * text_coords,
+    U64 vertex_count
+)
+{
+    meshopt_Stream streams[3];
+
+    S32 index = 0;
+    if (vertex_positions)
+    {
+        streams[index].data = (const float*)vertex_positions;
+        // Despite being LLVector4a, only x, y and z are in use
+        streams[index].size = sizeof(F32) * 3;
+        streams[index].stride = sizeof(F32) * 4;
+        index++;
+    }
+    if (normals)
+    {
+        streams[index].data = (const float*)normals;
+        streams[index].size = sizeof(F32) * 3;
+        streams[index].stride = sizeof(F32) * 4;
+        index++;
+    }
+    if (text_coords)
+    {
+        streams[index].data = (const float*)text_coords;
+        streams[index].size = sizeof(F32) * 2;
+        streams[index].stride = sizeof(F32) * 2;
+        index++;
+    }
+
+    if (index == 0)
+    {
+        // invalid
+        return;
+    }
+
+    meshopt_generateShadowIndexBufferMulti<unsigned int>(destination,
+        indices,
+        index_count,
+        vertex_count,
+        streams,
+        index
+        );
+}
+
+//static
+void LLMeshOptimizer::generateShadowIndexBufferU16(U16 *destination,
+    const U16 *indices,
+    U64 index_count,
+    const LLVector4a * vertex_positions,
+    const LLVector4a * normals,
+    const LLVector2 * text_coords,
+    U64 vertex_count
+)
+{
+    meshopt_Stream streams[3];
+
+    S32 index = 0;
+    if (vertex_positions)
+    {
+        streams[index].data = (const float*)vertex_positions;
+        streams[index].size = sizeof(F32) * 3;
+        streams[index].stride = sizeof(F32) * 4;
+        index++;
+    }
+    if (normals)
+    {
+        streams[index].data = (const float*)normals;
+        streams[index].size = sizeof(F32) * 3;
+        streams[index].stride = sizeof(F32) * 4;
+        index++;
+    }
+    if (text_coords)
+    {
+        streams[index].data = (const float*)text_coords;
+        streams[index].size = sizeof(F32) * 2;
+        streams[index].stride = sizeof(F32) * 2;
+        index++;
+    }
+
+    if (index == 0)
+    {
+        // invalid
+        return;
+    }
+
+    meshopt_generateShadowIndexBufferMulti<unsigned short>(destination,
+        indices,
+        index_count,
+        vertex_count,
+        streams,
+        index);
+}
+
+void LLMeshOptimizer::optimizeVertexCacheU32(U32 * destination, const U32 * indices, U64 index_count, U64 vertex_count)
+{
+    meshopt_optimizeVertexCache<unsigned int>(destination, indices, index_count, vertex_count);
+}
+
+void LLMeshOptimizer::optimizeVertexCacheU16(U16 * destination, const U16 * indices, U64 index_count, U64 vertex_count)
+{
+    meshopt_optimizeVertexCache<unsigned short>(destination, indices, index_count, vertex_count);
+}
+
+size_t LLMeshOptimizer::generateRemapMultiU32(
+    unsigned int* remap,
+    const U32 * indices,
+    U64 index_count,
+    const LLVector4a * vertex_positions,
+    const LLVector4a * normals,
+    const LLVector2 * text_coords,
+    U64 vertex_count)
+{
+    meshopt_Stream streams[] = {
+       {(const float*)vertex_positions, sizeof(F32) * 3, sizeof(F32) * 4},
+       {(const float*)normals, sizeof(F32) * 3, sizeof(F32) * 4},
+       {(const float*)text_coords, sizeof(F32) * 2, sizeof(F32) * 2},
+    };
+
+    // Remap can function without indices,
+    // but providing indices helps with removing unused vertices
+    U64 indeces_cmp = indices ? index_count : vertex_count;
+
+    // meshopt_generateVertexRemapMulti will throw an assert if (indices[i] >= vertex_count)
+    return meshopt_generateVertexRemapMulti(&remap[0], indices, indeces_cmp, vertex_count, streams, sizeof(streams) / sizeof(streams[0]));
+}
+
+size_t LLMeshOptimizer::generateRemapMultiU16(
+    unsigned int* remap,
+    const U16 * indices,
+    U64 index_count,
+    const LLVector4a * vertex_positions,
+    const LLVector4a * normals,
+    const LLVector2 * text_coords,
+    U64 vertex_count)
+{
+    S32 out_of_range_count = 0;
+    U32* indices_u32 = NULL;
+    if (indices)
+    {
+        indices_u32 = (U32*)ll_aligned_malloc_32(index_count * sizeof(U32));
+        for (U64 i = 0; i < index_count; i++)
+        {
+            if (indices[i] < vertex_count)
+            {
+                indices_u32[i] = (U32)indices[i];
+            }
+            else
+            {
+                out_of_range_count++;
+                indices_u32[i] = 0;
+            }
+        }
+    }
+
+    if (out_of_range_count)
+    {
+        LL_WARNS() << out_of_range_count << " indices are out of range." << LL_ENDL;
+    }
+
+    size_t unique = generateRemapMultiU32(remap, indices_u32, index_count, vertex_positions, normals, text_coords, vertex_count);
+
+    ll_aligned_free_32(indices_u32);
+
+    return unique;
+}
+
+void LLMeshOptimizer::remapIndexBufferU32(U32 * destination_indices,
+    const U32 * indices,
+    U64 index_count,
+    const unsigned int* remap)
+{
+    meshopt_remapIndexBuffer<unsigned int>(destination_indices, indices, index_count, remap);
+}
+
+void LLMeshOptimizer::remapIndexBufferU16(U16 * destination_indices,
+    const U16 * indices,
+    U64 index_count,
+    const unsigned int* remap)
+{
+    meshopt_remapIndexBuffer<unsigned short>(destination_indices, indices, index_count, remap);
+}
+
+void LLMeshOptimizer::remapPositionsBuffer(LLVector4a * destination_vertices,
+    const LLVector4a * vertex_positions,
+    U64 vertex_count,
+    const unsigned int* remap)
+{
+    meshopt_remapVertexBuffer((float*)destination_vertices, (const float*)vertex_positions, vertex_count, sizeof(LLVector4a), remap);
+}
+
+void LLMeshOptimizer::remapNormalsBuffer(LLVector4a * destination_normalss,
+    const LLVector4a * normals,
+    U64 mormals_count,
+    const unsigned int* remap)
+{
+    meshopt_remapVertexBuffer((float*)destination_normalss, (const float*)normals, mormals_count, sizeof(LLVector4a), remap);
+}
+
+void LLMeshOptimizer::remapUVBuffer(LLVector2 * destination_uvs,
+    const LLVector2 * uv_positions,
+    U64 uv_count,
+    const unsigned int* remap)
+{
+    meshopt_remapVertexBuffer((float*)destination_uvs, (const float*)uv_positions, uv_count, sizeof(LLVector2), remap);
+}
+
+//static
+U64 LLMeshOptimizer::simplifyU32(U32 *destination,
+    const U32 *indices,
+    U64 index_count,
+    const LLVector4a *vertex_positions,
+    U64 vertex_count,
+    U64 vertex_positions_stride,
+    U64 target_index_count,
+    F32 target_error,
+    bool sloppy,
+    F32* result_error
+)
+{
+    if (sloppy)
+    {
+        return meshopt_simplifySloppy<unsigned int>(destination,
+            indices,
+            index_count,
+            (const float*)vertex_positions,
+            vertex_count,
+            vertex_positions_stride,
+            target_index_count,
+            target_error,
+            result_error
+            );
+    }
+    else
+    {
+        return meshopt_simplify<unsigned int>(destination,
+            indices,
+            index_count,
+            (const float*)vertex_positions,
+            vertex_count,
+            vertex_positions_stride,
+            target_index_count,
+            target_error,
+            result_error
+            );
+    }
+}
+
+//static
+U64 LLMeshOptimizer::simplify(U16 *destination,
+                              const U16 *indices,
+                              U64 index_count,
+                              const LLVector4a *vertex_positions,
+                              U64 vertex_count,
+                              U64 vertex_positions_stride,
+                              U64 target_index_count,
+                              F32 target_error,
+                              bool sloppy,
+                              F32* result_error
+    )
+{
+    if (sloppy)
+    {
+        return meshopt_simplifySloppy<unsigned short>(destination,
+            indices,
+            index_count,
+            (const float*)vertex_positions,
+            vertex_count,
+            vertex_positions_stride,
+            target_index_count,
+            target_error,
+            result_error
+            );
+    }
+    else
+    {
+        return meshopt_simplify<unsigned short>(destination,
+            indices,
+            index_count,
+            (const float*)vertex_positions,
+            vertex_count,
+            vertex_positions_stride,
+            target_index_count,
+            target_error,
+            result_error
+            );
+    }
+}
+
diff --git a/indra/llmeshoptimizer/llmeshoptimizer.h b/indra/llmeshoptimizer/llmeshoptimizer.h
new file mode 100644
index 0000000000000000000000000000000000000000..ea965d6b47c1311f9bf8e7738b83f88b7cdc4cd6
--- /dev/null
+++ b/indra/llmeshoptimizer/llmeshoptimizer.h
@@ -0,0 +1,156 @@
+/** 
+* @file llmeshoptimizer.h
+* @brief Wrapper around meshoptimizer
+*
+* $LicenseInfo:firstyear=2021&license=viewerlgpl$
+* Second Life Viewer Source Code
+* Copyright (C) 2021, Linden Research, Inc.
+* 
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Lesser General Public
+* License as published by the Free Software Foundation;
+* version 2.1 of the License only.
+* 
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+* Lesser General Public License for more details.
+* 
+* You should have received a copy of the GNU Lesser General Public
+* License along with this library; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+* 
+* Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+* $/LicenseInfo$
+*/
+#ifndef LLMESHOPTIMIZER_H
+#define LLMESHOPTIMIZER_H
+
+#include "linden_common.h"
+
+class LLVector4a;
+class LLVector2;
+
+class LLMeshOptimizer
+{
+public:
+    LLMeshOptimizer();
+    ~LLMeshOptimizer();
+
+    static void generateShadowIndexBufferU32(
+        U32 *destination,
+        const U32 *indices,
+        U64 index_count,
+        const LLVector4a * vertex_positions,
+        const LLVector4a * normals,
+        const LLVector2 * text_coords,
+        U64 vertex_count);
+
+    static void generateShadowIndexBufferU16(
+        U16 *destination,
+        const U16 *indices,
+        U64 index_count,
+        const LLVector4a * vertex_positions,
+        const LLVector4a * normals,
+        const LLVector2 * text_coords,
+        U64 vertex_count);
+
+    static void optimizeVertexCacheU32(
+        U32 *destination,
+        const U32 *indices,
+        U64 index_count,
+        U64 vertex_count);
+
+    static void optimizeVertexCacheU16(
+        U16 *destination,
+        const U16 *indices,
+        U64 index_count,
+        U64 vertex_count);
+
+    // Remap functions
+    // Welds indentical vertexes together.
+    // Removes unused vertices if indices were provided.
+
+    static size_t generateRemapMultiU32(
+        unsigned int* remap,
+        const U32 * indices,
+        U64 index_count,
+        const LLVector4a * vertex_positions,
+        const LLVector4a * normals,
+        const LLVector2 * text_coords,
+        U64 vertex_count);
+
+    static size_t generateRemapMultiU16(
+        unsigned int* remap,
+        const U16 * indices,
+        U64 index_count,
+        const LLVector4a * vertex_positions,
+        const LLVector4a * normals,
+        const LLVector2 * text_coords,
+        U64 vertex_count);
+
+    static void remapIndexBufferU32(U32 * destination_indices,
+        const U32 * indices,
+        U64 index_count,
+        const unsigned int* remap);
+
+    static void remapIndexBufferU16(U16 * destination_indices,
+        const U16 * indices,
+        U64 index_count,
+        const unsigned int* remap);
+
+
+    static void remapPositionsBuffer(LLVector4a * destination_vertices,
+        const LLVector4a * vertex_positions,
+        U64 vertex_count,
+        const unsigned int* remap);
+
+    static void remapNormalsBuffer(LLVector4a * destination_normalss,
+        const LLVector4a * normals,
+        U64 mormals_count,
+        const unsigned int* remap);
+
+    static void remapUVBuffer(LLVector2 * destination_uvs,
+        const LLVector2 * uv_positions,
+        U64 uv_count,
+        const unsigned int* remap);
+
+    // Simplification
+
+    // returns amount of indices in destiantion
+    // sloppy engages a variant of a mechanizm that does not respect topology as much
+    // but is much more efective for simpler models
+    // result_error returns how far from original the model is in % if not NULL
+    // Works with U32 indices (LLFace uses U16 indices)
+    static U64 simplifyU32(
+        U32 *destination,
+        const U32 *indices,
+        U64 index_count,
+        const LLVector4a *vertex_positions,
+        U64 vertex_count,
+        U64 vertex_positions_stride,
+        U64 target_index_count,
+        F32 target_error,
+        bool sloppy,
+        F32* result_error);
+
+    // Returns amount of indices in destiantion
+    // sloppy engages a variant of a mechanizm that does not respect topology as much
+    // but is much better for simpler models
+    // result_error returns how far from original the model is in % if not NULL
+    // Meant for U16 indices (LLFace uses U16 indices)
+    static U64 simplify(
+        U16 *destination,
+        const U16 *indices,
+        U64 index_count,
+        const LLVector4a *vertex_positions,
+        U64 vertex_count,
+        U64 vertex_positions_stride,
+        U64 target_index_count,
+        F32 target_error,
+        bool sloppy,
+        F32* result_error);
+private:
+};
+
+#endif //LLMESHOPTIMIZER_H
diff --git a/indra/llmessage/llavatarnamecache.cpp b/indra/llmessage/llavatarnamecache.cpp
index c67f59bc0c3ffafd9ac4ae64b447e4a9a0ca3701..846549b3683b517fa1c662a7fa17508ce0dc5d40 100644
--- a/indra/llmessage/llavatarnamecache.cpp
+++ b/indra/llmessage/llavatarnamecache.cpp
@@ -196,6 +196,10 @@ void LLAvatarNameCache::requestAvatarNameCache_(std::string url, std::vector<LLU
             LLAvatarNameCache::getInstance()->handleAvNameCacheSuccess(results, httpResults);
         }
     }
+    catch (const LLCoros::Stop&)
+    {
+        LL_DEBUGS("AvNameCache") << "Received a shutdown exception" << LL_ENDL;
+    }
     catch (...)
     {
         LOG_UNHANDLED_EXCEPTION(STRINGIZE("coroutine " << LLCoros::getName()
diff --git a/indra/llmessage/llcoproceduremanager.h b/indra/llmessage/llcoproceduremanager.h
index 2d460826ffb5d7894d4ad3b2f70d3427a6d20671..c5bc37dd0eab6973d1ddf871c70137d5f35ad6c3 100644
--- a/indra/llmessage/llcoproceduremanager.h
+++ b/indra/llmessage/llcoproceduremanager.h
@@ -32,7 +32,6 @@
 #include "llcoros.h"
 #include "llcorehttputil.h"
 #include "lluuid.h"
-#include <boost/smart_ptr/shared_ptr.hpp>
 
 class LLCoprocedurePool;
 
@@ -84,7 +83,7 @@ class LLCoprocedureManager : public LLSingleton < LLCoprocedureManager >
     
 private:
 
-    typedef boost::shared_ptr<LLCoprocedurePool> poolPtr_t;
+    typedef std::shared_ptr<LLCoprocedurePool> poolPtr_t;
     typedef std::map<std::string, poolPtr_t> poolMap_t;
 
     poolMap_t mPoolMap;
diff --git a/indra/llmessage/lldatapacker.cpp b/indra/llmessage/lldatapacker.cpp
index 96c1297e0d24b2090d8744a5a9c8da3898cf4c28..b6adc102d2149d788a25e57f47a1c03025a359b9 100644
--- a/indra/llmessage/lldatapacker.cpp
+++ b/indra/llmessage/lldatapacker.cpp
@@ -127,13 +127,7 @@ BOOL LLDataPacker::unpackFixed(F32 &value, const char *name,
 		total_bits++;
 	}
 
-	S32 min_val;
 	U32 max_val;
-	if (is_signed)
-	{
-		min_val = 1 << int_bits;
-		min_val *= -1;
-	}
 	max_val = 1 << int_bits;
 
 	F32 fixed_val;
diff --git a/indra/llmessage/llfiltersd2xmlrpc.cpp b/indra/llmessage/llfiltersd2xmlrpc.cpp
index d3e195789bf84222a0dc63d5f2ea13233fa53765..0abdafbdfcd73212bf3ae3d20aea4bc73e647f97 100644
--- a/indra/llmessage/llfiltersd2xmlrpc.cpp
+++ b/indra/llmessage/llfiltersd2xmlrpc.cpp
@@ -309,7 +309,6 @@ LLFilterSD2XMLRPCResponse::~LLFilterSD2XMLRPCResponse()
 }
 
 
-static LLTrace::BlockTimerStatHandle FTM_PROCESS_SD2XMLRPC_RESPONSE("SD2XMLRPC Response");
 // virtual
 LLIOPipe::EStatus LLFilterSD2XMLRPCResponse::process_impl(
 	const LLChannelDescriptors& channels,
@@ -318,7 +317,7 @@ LLIOPipe::EStatus LLFilterSD2XMLRPCResponse::process_impl(
 	LLSD& context,
 	LLPumpIO* pump)
 {
-	LL_RECORD_BLOCK_TIME(FTM_PROCESS_SD2XMLRPC_RESPONSE);
+    LL_PROFILE_ZONE_SCOPED;
 
 	PUMP_DEBUG;
 	// This pipe does not work if it does not have everyting. This
@@ -386,8 +385,6 @@ LLFilterSD2XMLRPCRequest::~LLFilterSD2XMLRPCRequest()
 {
 }
 
-static LLTrace::BlockTimerStatHandle FTM_PROCESS_SD2XMLRPC_REQUEST("S22XMLRPC Request");
-
 // virtual
 LLIOPipe::EStatus LLFilterSD2XMLRPCRequest::process_impl(
 	const LLChannelDescriptors& channels,
@@ -396,7 +393,7 @@ LLIOPipe::EStatus LLFilterSD2XMLRPCRequest::process_impl(
 	LLSD& context,
 	LLPumpIO* pump)
 {
-	LL_RECORD_BLOCK_TIME(FTM_PROCESS_SD2XMLRPC_REQUEST);
+    LL_PROFILE_ZONE_SCOPED;
 	// This pipe does not work if it does not have everyting. This
 	// could be addressed by making a stream parser for llsd which
 	// handled partial information.
@@ -593,8 +590,6 @@ LLFilterXMLRPCResponse2LLSD::~LLFilterXMLRPCResponse2LLSD()
 {
 }
 
-static LLTrace::BlockTimerStatHandle FTM_PROCESS_XMLRPC2LLSD_RESPONSE("XMLRPC2LLSD Response");
-
 LLIOPipe::EStatus LLFilterXMLRPCResponse2LLSD::process_impl(
 	const LLChannelDescriptors& channels,
 	buffer_ptr_t& buffer,
@@ -602,7 +597,7 @@ LLIOPipe::EStatus LLFilterXMLRPCResponse2LLSD::process_impl(
 	LLSD& context,
 	LLPumpIO* pump)
 {
-	LL_RECORD_BLOCK_TIME(FTM_PROCESS_XMLRPC2LLSD_RESPONSE);
+    LL_PROFILE_ZONE_SCOPED;
 
 	PUMP_DEBUG;
 	if(!eos) return STATUS_BREAK;
@@ -679,7 +674,6 @@ LLFilterXMLRPCRequest2LLSD::~LLFilterXMLRPCRequest2LLSD()
 {
 }
 
-static LLTrace::BlockTimerStatHandle FTM_PROCESS_XMLRPC2LLSD_REQUEST("XMLRPC2LLSD Request");
 LLIOPipe::EStatus LLFilterXMLRPCRequest2LLSD::process_impl(
 	const LLChannelDescriptors& channels,
 	buffer_ptr_t& buffer,
@@ -687,7 +681,7 @@ LLIOPipe::EStatus LLFilterXMLRPCRequest2LLSD::process_impl(
 	LLSD& context,
 	LLPumpIO* pump)
 {
-	LL_RECORD_BLOCK_TIME(FTM_PROCESS_XMLRPC2LLSD_REQUEST);
+    LL_PROFILE_ZONE_SCOPED;
 	PUMP_DEBUG;
 	if(!eos) return STATUS_BREAK;
 	if(!buffer) return STATUS_ERROR;
diff --git a/indra/llmessage/llhttpnode.cpp b/indra/llmessage/llhttpnode.cpp
index 6fd17c91549b59adce034624f8b9f4f25fb15c70..6e9598a0a37a226f6b40808b22aa688b7419b7b5 100644
--- a/indra/llmessage/llhttpnode.cpp
+++ b/indra/llmessage/llhttpnode.cpp
@@ -121,6 +121,7 @@ LLSD LLHTTPNode::simplePost(const LLSD& input) const
 // virtual
 void LLHTTPNode::get(LLHTTPNode::ResponsePtr response, const LLSD& context) const
 {
+    LL_PROFILE_ZONE_SCOPED;
 	try
 	{
 		response->result(simpleGet());
@@ -134,6 +135,7 @@ void LLHTTPNode::get(LLHTTPNode::ResponsePtr response, const LLSD& context) cons
 // virtual
 void LLHTTPNode::put(LLHTTPNode::ResponsePtr response, const LLSD& context, const LLSD& input) const
 {
+    LL_PROFILE_ZONE_SCOPED;
 	try
 	{
 		response->result(simplePut(input));
@@ -147,6 +149,7 @@ void LLHTTPNode::put(LLHTTPNode::ResponsePtr response, const LLSD& context, cons
 // virtual
 void LLHTTPNode::post(LLHTTPNode::ResponsePtr response, const LLSD& context, const LLSD& input) const
 {
+    LL_PROFILE_ZONE_SCOPED;
 	try
 	{
 		response->result(simplePost(input));
@@ -160,6 +163,7 @@ void LLHTTPNode::post(LLHTTPNode::ResponsePtr response, const LLSD& context, con
 // virtual
 void LLHTTPNode::del(LLHTTPNode::ResponsePtr response, const LLSD& context) const
 {
+    LL_PROFILE_ZONE_SCOPED;
     try
     {
 	response->result(simpleDel(context));
diff --git a/indra/llmessage/lliohttpserver.cpp b/indra/llmessage/lliohttpserver.cpp
index d9042fa8b0320d01a0be63eb6b8a42fc4c17e8ca..c707c7ad09a0d77ca71a5ed2d48877da5ecd175f 100644
--- a/indra/llmessage/lliohttpserver.cpp
+++ b/indra/llmessage/lliohttpserver.cpp
@@ -132,12 +132,6 @@ class LLHTTPPipe : public LLIOPipe
 	LLSD mHeaders;
 };
 
-static LLTrace::BlockTimerStatHandle FTM_PROCESS_HTTP_PIPE("HTTP Pipe");
-static LLTrace::BlockTimerStatHandle FTM_PROCESS_HTTP_GET("HTTP Get");
-static LLTrace::BlockTimerStatHandle FTM_PROCESS_HTTP_PUT("HTTP Put");
-static LLTrace::BlockTimerStatHandle FTM_PROCESS_HTTP_POST("HTTP Post");
-static LLTrace::BlockTimerStatHandle FTM_PROCESS_HTTP_DELETE("HTTP Delete");
-
 LLIOPipe::EStatus LLHTTPPipe::process_impl(
 	const LLChannelDescriptors& channels,
     buffer_ptr_t& buffer,
@@ -145,7 +139,7 @@ LLIOPipe::EStatus LLHTTPPipe::process_impl(
     LLSD& context,
     LLPumpIO* pump)
 {
-	LL_RECORD_BLOCK_TIME(FTM_PROCESS_HTTP_PIPE);
+    LL_PROFILE_ZONE_SCOPED;
 	PUMP_DEBUG;
     LL_DEBUGS() << "LLSDHTTPServer::process_impl" << LL_ENDL;
 
@@ -174,12 +168,10 @@ LLIOPipe::EStatus LLHTTPPipe::process_impl(
 		std::string verb = context[CONTEXT_REQUEST][CONTEXT_VERB];
 		if(verb == HTTP_VERB_GET)
 		{
-			LL_RECORD_BLOCK_TIME(FTM_PROCESS_HTTP_GET);
 			mNode.get(LLHTTPNode::ResponsePtr(mResponse), context);
 		}
 		else if(verb == HTTP_VERB_PUT)
 		{
-			LL_RECORD_BLOCK_TIME(FTM_PROCESS_HTTP_PUT);
 			LLSD input;
 			if (mNode.getContentType() == LLHTTPNode::CONTENT_TYPE_LLSD)
 			{
@@ -195,7 +187,6 @@ LLIOPipe::EStatus LLHTTPPipe::process_impl(
 		}
 		else if(verb == HTTP_VERB_POST)
 		{
-			LL_RECORD_BLOCK_TIME(FTM_PROCESS_HTTP_POST);
 			LLSD input;
 			if (mNode.getContentType() == LLHTTPNode::CONTENT_TYPE_LLSD)
 			{
@@ -211,7 +202,6 @@ LLIOPipe::EStatus LLHTTPPipe::process_impl(
 		}
 		else if(verb == HTTP_VERB_DELETE)
 		{
-			LL_RECORD_BLOCK_TIME(FTM_PROCESS_HTTP_DELETE);
 			mNode.del(LLHTTPNode::ResponsePtr(mResponse), context);
 		}		
 		else if(verb == HTTP_VERB_OPTIONS)
@@ -455,8 +445,6 @@ class LLHTTPResponseHeader : public LLIOPipe
  * LLHTTPResponseHeader
  */
 
-static LLTrace::BlockTimerStatHandle FTM_PROCESS_HTTP_HEADER("HTTP Header");
-
 // virtual
 LLIOPipe::EStatus LLHTTPResponseHeader::process_impl(
 	const LLChannelDescriptors& channels,
@@ -465,7 +453,7 @@ LLIOPipe::EStatus LLHTTPResponseHeader::process_impl(
 	LLSD& context,
 	LLPumpIO* pump)
 {
-	LL_RECORD_BLOCK_TIME(FTM_PROCESS_HTTP_HEADER);
+    LL_PROFILE_ZONE_SCOPED;
 	PUMP_DEBUG;
 	if(eos)
 	{
@@ -655,8 +643,6 @@ void LLHTTPResponder::markBad(
 		<< "</body>\n</html>\n";
 }
 
-static LLTrace::BlockTimerStatHandle FTM_PROCESS_HTTP_RESPONDER("HTTP Responder");
-
 // virtual
 LLIOPipe::EStatus LLHTTPResponder::process_impl(
 	const LLChannelDescriptors& channels,
@@ -665,7 +651,7 @@ LLIOPipe::EStatus LLHTTPResponder::process_impl(
 	LLSD& context,
 	LLPumpIO* pump)
 {
-	LL_RECORD_BLOCK_TIME(FTM_PROCESS_HTTP_RESPONDER);
+    LL_PROFILE_ZONE_SCOPED;
 	PUMP_DEBUG;
 	LLIOPipe::EStatus status = STATUS_OK;
 
diff --git a/indra/llmessage/lliosocket.cpp b/indra/llmessage/lliosocket.cpp
index a9cc71c36575853887dafee011c4c6ae98374e77..321d7286eb42c7e0266ce2c8d2533d9e0c5aa026 100644
--- a/indra/llmessage/lliosocket.cpp
+++ b/indra/llmessage/lliosocket.cpp
@@ -300,8 +300,6 @@ LLIOSocketReader::~LLIOSocketReader()
 	//LL_DEBUGS() << "Destroying LLIOSocketReader" << LL_ENDL;
 }
 
-static LLTrace::BlockTimerStatHandle FTM_PROCESS_SOCKET_READER("Socket Reader");
-
 // virtual
 LLIOPipe::EStatus LLIOSocketReader::process_impl(
 	const LLChannelDescriptors& channels,
@@ -310,7 +308,7 @@ LLIOPipe::EStatus LLIOSocketReader::process_impl(
 	LLSD& context,
 	LLPumpIO* pump)
 {
-	LL_RECORD_BLOCK_TIME(FTM_PROCESS_SOCKET_READER);
+    LL_PROFILE_ZONE_SCOPED;
 	PUMP_DEBUG;
 	if(!mSource) return STATUS_PRECONDITION_NOT_MET;
 	if(!mInitialized)
@@ -400,7 +398,6 @@ LLIOSocketWriter::~LLIOSocketWriter()
 	//LL_DEBUGS() << "Destroying LLIOSocketWriter" << LL_ENDL;
 }
 
-static LLTrace::BlockTimerStatHandle FTM_PROCESS_SOCKET_WRITER("Socket Writer");
 // virtual
 LLIOPipe::EStatus LLIOSocketWriter::process_impl(
 	const LLChannelDescriptors& channels,
@@ -409,7 +406,7 @@ LLIOPipe::EStatus LLIOSocketWriter::process_impl(
 	LLSD& context,
 	LLPumpIO* pump)
 {
-	LL_RECORD_BLOCK_TIME(FTM_PROCESS_SOCKET_WRITER);
+    LL_PROFILE_ZONE_SCOPED;
 	PUMP_DEBUG;
 	if(!mDestination) return STATUS_PRECONDITION_NOT_MET;
 	if(!mInitialized)
@@ -556,7 +553,6 @@ void LLIOServerSocket::setResponseTimeout(F32 timeout_secs)
 	mResponseTimeout = timeout_secs;
 }
 
-static LLTrace::BlockTimerStatHandle FTM_PROCESS_SERVER_SOCKET("Server Socket");
 // virtual
 LLIOPipe::EStatus LLIOServerSocket::process_impl(
 	const LLChannelDescriptors& channels,
@@ -565,7 +561,7 @@ LLIOPipe::EStatus LLIOServerSocket::process_impl(
 	LLSD& context,
 	LLPumpIO* pump)
 {
-	LL_RECORD_BLOCK_TIME(FTM_PROCESS_SERVER_SOCKET);
+    LL_PROFILE_ZONE_SCOPED;
 	PUMP_DEBUG;
 	if(!pump)
 	{
diff --git a/indra/llmessage/llioutil.cpp b/indra/llmessage/llioutil.cpp
index b8443c0600d8cb23dddef45c1f1f57bd6950f468..850bc2a6167c9079367c7017e02e50f71dd2b75c 100644
--- a/indra/llmessage/llioutil.cpp
+++ b/indra/llmessage/llioutil.cpp
@@ -45,7 +45,6 @@ LLIOPipe::EStatus LLIOFlush::process_impl(
 }
 
 
-static LLTrace::BlockTimerStatHandle FTM_PROCESS_SLEEP("IO Sleep");
 /** 
  * @class LLIOSleep
  */
@@ -56,7 +55,7 @@ LLIOPipe::EStatus LLIOSleep::process_impl(
 	LLSD& context,
 	LLPumpIO* pump)
 {
-	LL_RECORD_BLOCK_TIME(FTM_PROCESS_SLEEP);
+    LL_PROFILE_ZONE_SCOPED;
 	if(mSeconds > 0.0)
 	{
 		if(pump) pump->sleepChain(mSeconds);
@@ -66,7 +65,6 @@ LLIOPipe::EStatus LLIOSleep::process_impl(
 	return STATUS_DONE;
 }
 
-static LLTrace::BlockTimerStatHandle FTM_PROCESS_ADD_CHAIN("Add Chain");
 /** 
  * @class LLIOAddChain
  */
@@ -77,7 +75,7 @@ LLIOPipe::EStatus LLIOAddChain::process_impl(
 	LLSD& context,
 	LLPumpIO* pump)
 {
-	LL_RECORD_BLOCK_TIME(FTM_PROCESS_ADD_CHAIN);
+    LL_PROFILE_ZONE_SCOPED;
 	pump->addChain(mChain, mTimeout);
 	return STATUS_DONE;
 }
diff --git a/indra/llmessage/llpartdata.cpp b/indra/llmessage/llpartdata.cpp
index 53aa35c0f9ffb316015e372554ced6c3ee98143f..6664eb02dc5d25418882dbdb9a4092d1b363bbf0 100644
--- a/indra/llmessage/llpartdata.cpp
+++ b/indra/llmessage/llpartdata.cpp
@@ -311,8 +311,9 @@ BOOL LLPartSysData::unpack(LLDataPacker &dp)
 std::ostream& operator<<(std::ostream& s, const LLPartSysData &data)
 {
 	s << "Flags: " << std::hex << data.mFlags;
-	s << " Pattern: " << std::hex << (U32) data.mPattern << "\n";
-	s << "Age: [" << data.mStartAge << ", " << data.mMaxAge << "]\n";
+	s << "Pattern: " << std::hex << (U32) data.mPattern << "\n";
+	s << "Source Age: [" << data.mStartAge << ", " << data.mMaxAge << "]\n";
+    s << "Particle Age: " << data.mPartData.mMaxAge << "\n";
 	s << "Angle: [" << data.mInnerAngle << ", " << data.mOuterAngle << "]\n";
 	s << "Burst Rate: " << data.mBurstRate << "\n";
 	s << "Burst Radius: " << data.mBurstRadius << "\n";
diff --git a/indra/llmessage/llpumpio.cpp b/indra/llmessage/llpumpio.cpp
index a2524e98043f6ec2dd17f01aa767966d9ed70715..44720f00150068bfccfc3d37414d87da1d36bbc2 100644
--- a/indra/llmessage/llpumpio.cpp
+++ b/indra/llmessage/llpumpio.cpp
@@ -416,9 +416,6 @@ void LLPumpIO::pump()
 	pump(DEFAULT_POLL_TIMEOUT);
 }
 
-static LLTrace::BlockTimerStatHandle FTM_PUMP_IO("Pump IO");
-static LLTrace::BlockTimerStatHandle FTM_PUMP_POLL("Pump Poll");
-
 LLPumpIO::current_chain_t LLPumpIO::removeRunningChain(LLPumpIO::current_chain_t& run_chain) 
 {
 	std::for_each(
@@ -431,7 +428,7 @@ LLPumpIO::current_chain_t LLPumpIO::removeRunningChain(LLPumpIO::current_chain_t
 //timeout is in microseconds
 void LLPumpIO::pump(const S32& poll_timeout)
 {
-	LL_RECORD_BLOCK_TIME(FTM_PUMP_IO);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
 	//LL_INFOS() << "LLPumpIO::pump()" << LL_ENDL;
 
 	// Run any pending runners.
@@ -509,7 +506,7 @@ void LLPumpIO::pump(const S32& poll_timeout)
 		S32 count = 0;
 		S32 client_id = 0;
         {
-			LL_RECORD_BLOCK_TIME(FTM_PUMP_POLL);
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
             apr_pollset_poll(mPollset, poll_timeout, &count, &poll_fd);
         }
 		PUMP_DEBUG;
@@ -737,10 +734,9 @@ bool LLPumpIO::respond(
 	return true;
 }
 
-static LLTrace::BlockTimerStatHandle FTM_PUMP_CALLBACK_CHAIN("Chain");
-
 void LLPumpIO::callback()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
 	//LL_INFOS() << "LLPumpIO::callback()" << LL_ENDL;
 	if(true)
 	{
@@ -756,7 +752,6 @@ void LLPumpIO::callback()
 		callbacks_t::iterator end = mCallbacks.end();
 		for(; it != end; ++it)
 		{
-			LL_RECORD_BLOCK_TIME(FTM_PUMP_CALLBACK_CHAIN);
 			// it's always the first and last time for respone chains
 			(*it).mHead = (*it).mChainLinks.begin();
 			(*it).mInit = true;
diff --git a/indra/llmessage/lltemplatemessagereader.cpp b/indra/llmessage/lltemplatemessagereader.cpp
index 6d5ad0ba089a30324f517b91acfaf9c379f36752..32f79f0546e6c8326d38eb388227da56c537678f 100644
--- a/indra/llmessage/lltemplatemessagereader.cpp
+++ b/indra/llmessage/lltemplatemessagereader.cpp
@@ -533,6 +533,8 @@ static LLTrace::BlockTimerStatHandle FTM_PROCESS_MESSAGES("Process Messages");
 // decode a given message
 BOOL LLTemplateMessageReader::decodeData(const U8* buffer, const LLHost& sender )
 {
+    LL_RECORD_BLOCK_TIME(FTM_PROCESS_MESSAGES);
+
 	llassert( mReceiveSize >= 0 );
 	llassert( mCurrentRMessageTemplate);
 	llassert( !mCurrentRMessageData );
@@ -707,12 +709,9 @@ BOOL LLTemplateMessageReader::decodeData(const U8* buffer, const LLHost& sender
 			decode_timer.reset();
 		}
 
+		if( !mCurrentRMessageTemplate->callHandlerFunc(gMessageSystem) )
 		{
-			LL_RECORD_BLOCK_TIME(FTM_PROCESS_MESSAGES);
-			if( !mCurrentRMessageTemplate->callHandlerFunc(gMessageSystem) )
-			{
-				LL_WARNS() << "Message from " << sender << " with no handler function received: " << mCurrentRMessageTemplate->mName << LL_ENDL;
-			}
+			LL_WARNS() << "Message from " << sender << " with no handler function received: " << mCurrentRMessageTemplate->mName << LL_ENDL;
 		}
 
 		if(LLMessageReader::getTimeDecodes() || gMessageSystem->getTimingCallback())
diff --git a/indra/llmessage/llthrottle.cpp b/indra/llmessage/llthrottle.cpp
index 7605da4d3fa9b06c0f5700eb351bf8d1f56226be..935af2aa5a551b04c45b54cc6d8bc637c296d664 100644
--- a/indra/llmessage/llthrottle.cpp
+++ b/indra/llmessage/llthrottle.cpp
@@ -374,7 +374,6 @@ BOOL LLThrottleGroup::dynamicAdjust()
 	}
 	mDynamicAdjustTime = mt_sec;
 
-	S32 total = 0;
 	// Update historical information
 	for (i = 0; i < TC_EOF; i++)
 	{
@@ -391,7 +390,6 @@ BOOL LLThrottleGroup::dynamicAdjust()
 		}
 
 		mBitsSentThisPeriod[i] = 0;
-		total += ll_round(mBitsSentHistory[i]);
 	}
 
 	// Look for busy channels
diff --git a/indra/llmessage/message_prehash.cpp b/indra/llmessage/message_prehash.cpp
index 219b1855d213de990c4009bb0a7db5d77edc3cae..35dcbe383682fbd9c3249234a06d0689339444c2 100644
--- a/indra/llmessage/message_prehash.cpp
+++ b/indra/llmessage/message_prehash.cpp
@@ -1386,6 +1386,7 @@ char const* const _PREHASH_RegionAllowAccessBlock = LLMessageStringTable::getIns
 char const* const _PREHASH_RegionAllowAccessOverride = LLMessageStringTable::getInstance()->getString("RegionAllowAccessOverride");
 char const* const _PREHASH_ParcelEnvironmentBlock = LLMessageStringTable::getInstance()->getString("ParcelEnvironmentBlock");
 char const* const _PREHASH_ParcelEnvironmentVersion = LLMessageStringTable::getInstance()->getString("ParcelEnvironmentVersion");
+char const* const _PREHASH_ParcelExtendedFlags = LLMessageStringTable::getInstance()->getString("ParcelExtendedFlags");
 char const* const _PREHASH_RegionAllowEnvironmentOverride = LLMessageStringTable::getInstance()->getString("RegionAllowEnvironmentOverride");
 char const* const _PREHASH_UCoord = LLMessageStringTable::getInstance()->getString("UCoord");
 char const* const _PREHASH_VCoord = LLMessageStringTable::getInstance()->getString("VCoord");
diff --git a/indra/llmessage/message_prehash.h b/indra/llmessage/message_prehash.h
index 8f6ee5a32790d3b72f16d12834e7c5f40039ad10..3015f438b5e98a47e100f316b21bf9458b635051 100644
--- a/indra/llmessage/message_prehash.h
+++ b/indra/llmessage/message_prehash.h
@@ -1386,6 +1386,7 @@ extern char const* const _PREHASH_RegionAllowAccessBlock;
 extern char const* const _PREHASH_RegionAllowAccessOverride;
 extern char const* const _PREHASH_ParcelEnvironmentBlock;
 extern char const* const _PREHASH_ParcelEnvironmentVersion;
+extern char const* const _PREHASH_ParcelExtendedFlags;
 extern char const* const _PREHASH_RegionAllowEnvironmentOverride;
 extern char const* const _PREHASH_UCoord;
 extern char const* const _PREHASH_VCoord;
diff --git a/indra/llplugin/llpluginclassmedia.cpp b/indra/llplugin/llpluginclassmedia.cpp
index 6f88232c1dcdd2c8c55c65574bdf83cc7872b935..3e72710366c3f60ac36cfc6776d43c4c9f089900 100644
--- a/indra/llplugin/llpluginclassmedia.cpp
+++ b/indra/llplugin/llpluginclassmedia.cpp
@@ -1549,6 +1549,7 @@ void LLPluginClassMedia::seek(float time)
 	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "seek");
 
 	message.setValueReal("time", time);
+    mCurrentTime = time; // assume that it worked and we will receive an update later
 
 	sendMessage(message);
 }
diff --git a/indra/llplugin/llpluginclassmedia.h b/indra/llplugin/llpluginclassmedia.h
index adbb93f789a593cf17fa1847fb05cd38bd0837d2..ba76ae4e3726174cfaea4a6b03c1457f0d97c62c 100644
--- a/indra/llplugin/llpluginclassmedia.h
+++ b/indra/llplugin/llpluginclassmedia.h
@@ -335,7 +335,7 @@ class LLPluginClassMedia : public LLPluginProcessParentOwner
 	// "init_history" message 
 	void initializeUrlHistory(const LLSD& url_history);
 
-	boost::shared_ptr<LLPluginClassMedia> getSharedPrt() { return boost::dynamic_pointer_cast<LLPluginClassMedia>(shared_from_this()); } // due to enable_shared_from_this
+	boost::shared_ptr<LLPluginClassMedia> getSharedPtr() { return boost::dynamic_pointer_cast<LLPluginClassMedia>(shared_from_this()); } // due to enable_shared_from_this
 
 protected:
 
diff --git a/indra/llplugin/llpluginprocessparent.cpp b/indra/llplugin/llpluginprocessparent.cpp
index eef22156bc3c5044eb130f185677228e37a04f51..1fbbad06d478ca19d9cd7d27150bcba76bb0bf83 100644
--- a/indra/llplugin/llpluginprocessparent.cpp
+++ b/indra/llplugin/llpluginprocessparent.cpp
@@ -999,7 +999,7 @@ void LLPluginProcessParent::poll(F64 timeout)
     while (itClean != sInstances.end())
     {
         if ((*itClean).second->isDone())
-            sInstances.erase(itClean++);
+            itClean = sInstances.erase(itClean);
         else
             ++itClean;
     }
diff --git a/indra/llprimitive/lldaeloader.cpp b/indra/llprimitive/lldaeloader.cpp
index 33e90555fac466f711639d5dc5ed5b9be4105ccd..68654486a4088fa07b24d13d97434ae3c63cf942 100644
--- a/indra/llprimitive/lldaeloader.cpp
+++ b/indra/llprimitive/lldaeloader.cpp
@@ -149,7 +149,11 @@ bool get_dom_sources(const domInputLocalOffset_Array& inputs, S32& pos_offset, S
 	return true;
 }
 
-LLModel::EModelStatus load_face_from_dom_triangles(std::vector<LLVolumeFace>& face_list, std::vector<std::string>& materials, domTrianglesRef& tri)
+LLModel::EModelStatus load_face_from_dom_triangles(
+    std::vector<LLVolumeFace>& face_list,
+    std::vector<std::string>& materials,
+    domTrianglesRef& tri,
+    LLSD& log_msg)
 {
 	LLVolumeFace face;
 	std::vector<LLVolumeFace::VertexData> verts;
@@ -169,12 +173,18 @@ LLModel::EModelStatus load_face_from_dom_triangles(std::vector<LLVolumeFace>& fa
 
 	if ( !get_dom_sources(inputs, pos_offset, tc_offset, norm_offset, idx_stride, pos_source, tc_source, norm_source))
 	{
+        LLSD args;
+        args["Message"] = "ParsingErrorBadElement";
+        log_msg.append(args);
 		return LLModel::BAD_ELEMENT;
 	}
 
 	if (!pos_source || !pos_source->getFloat_array())
 	{
 		LL_WARNS() << "Unable to process mesh without position data; invalid model;  invalid model." << LL_ENDL;
+        LLSD args;
+        args["Message"] = "ParsingErrorPositionInvalidModel";
+        log_msg.append(args);
 		return LLModel::BAD_ELEMENT;
 	}
 
@@ -354,7 +364,11 @@ LLModel::EModelStatus load_face_from_dom_triangles(std::vector<LLVolumeFace>& fa
 	return LLModel::NO_ERRORS ;
 }
 
-LLModel::EModelStatus load_face_from_dom_polylist(std::vector<LLVolumeFace>& face_list, std::vector<std::string>& materials, domPolylistRef& poly, LLSD& log_msg)
+LLModel::EModelStatus load_face_from_dom_polylist(
+    std::vector<LLVolumeFace>& face_list,
+    std::vector<std::string>& materials,
+    domPolylistRef& poly,
+    LLSD& log_msg)
 {
 	domPRef p = poly->getP();
 	domListOfUInts& idx = p->getValue();
@@ -381,6 +395,10 @@ LLModel::EModelStatus load_face_from_dom_polylist(std::vector<LLVolumeFace>& fac
 
 	if (!get_dom_sources(inputs, pos_offset, tc_offset, norm_offset, idx_stride, pos_source, tc_source, norm_source))
 	{
+        LL_WARNS() << "Bad element." << LL_ENDL;
+        LLSD args;
+        args["Message"] = "ParsingErrorBadElement";
+        log_msg.append(args);
 		return LLModel::BAD_ELEMENT;
 	}
 
@@ -432,6 +450,9 @@ LLModel::EModelStatus load_face_from_dom_polylist(std::vector<LLVolumeFace>& fac
 				if (!cv.getPosition().isFinite3())
 				{
 					LL_WARNS() << "Found NaN while loading position data from DAE-Model, invalid model." << LL_ENDL;
+                    LLSD args;
+                    args["Message"] = "PositionNaN";
+                    log_msg.append(args);
 					return LLModel::BAD_ELEMENT;
 				}
 			}
@@ -464,6 +485,10 @@ LLModel::EModelStatus load_face_from_dom_polylist(std::vector<LLVolumeFace>& fac
 				if (!cv.getNormal().isFinite3())
 				{
 					LL_WARNS() << "Found NaN while loading normals from DAE-Model, invalid model." << LL_ENDL;
+                    LLSD args;
+                    args["Message"] = "NormalsNaN";
+                    log_msg.append(args);
+
 					return LLModel::BAD_ELEMENT;
 				}
 			}
@@ -781,6 +806,9 @@ LLModel::EModelStatus load_face_from_dom_polygons(std::vector<LLVolumeFace>& fac
 		}
 	}
 
+    // Viewer can only fit U16 vertices, shouldn't we do some checks here and return overflow if result has more?
+    llassert(vert_idx.size() < U16_MAX);
+
 	//build vertex array from map
 	std::vector<LLVolumeFace::VertexData> new_verts;
 	new_verts.resize(vert_idx.size());
@@ -798,7 +826,12 @@ LLModel::EModelStatus load_face_from_dom_polygons(std::vector<LLVolumeFace>& fac
 	for (U32 i = 0; i < verts.size(); ++i)
 	{
 		indices[i] = vert_idx[verts[i]];
-		llassert(!i || (indices[i-1] != indices[i]));
+        if (i % 3 != 0) // assumes GL_TRIANGLES, compare 0-1, 1-2, 3-4, 4-5 but not 2-3 or 5-6
+        {
+            // A faulty degenerate triangle detection (triangle with 0 area),
+            // probably should be a warning and not an assert
+            llassert(!i || (indices[i-1] != indices[i]));
+        }
 	}
 
 	// DEBUG just build an expanded triangle list
@@ -918,6 +951,9 @@ bool LLDAELoader::OpenFile(const std::string& filename)
 	if (!dom)
 	{
 		LL_INFOS() <<" Error with dae - traditionally indicates a corrupt file."<<LL_ENDL;
+        LLSD args;
+        args["Message"] = "ParsingErrorCorrupt";
+        mWarningsArray.append(args);
 		setLoadState( ERROR_PARSING );
 		return false;
 	}
@@ -945,6 +981,9 @@ bool LLDAELoader::OpenFile(const std::string& filename)
 	if (!doc)
 	{
 		LL_WARNS() << "can't find internal doc" << LL_ENDL;
+        LLSD args;
+        args["Message"] = "ParsingErrorNoDoc";
+        mWarningsArray.append(args);
 		return false;
 	}
 	
@@ -952,6 +991,9 @@ bool LLDAELoader::OpenFile(const std::string& filename)
 	if (!root)
 	{
 		LL_WARNS() << "document has no root" << LL_ENDL;
+        LLSD args;
+        args["Message"] = "ParsingErrorNoRoot";
+        mWarningsArray.append(args);
 		return false;
 	}
 	
@@ -967,6 +1009,9 @@ bool LLDAELoader::OpenFile(const std::string& filename)
 		if (!result)
 		{
 			LL_INFOS() << "Could not verify controller" << LL_ENDL;
+            LLSD args;
+            args["Message"] = "ParsingErrorBadElement";
+            mWarningsArray.append(args);
 			setLoadState( ERROR_PARSING );
 			return true;
 		}
@@ -1100,6 +1145,9 @@ bool LLDAELoader::OpenFile(const std::string& filename)
 	if (!scene)
 	{
 		LL_WARNS() << "document has no visual_scene" << LL_ENDL;
+        LLSD args;
+        args["Message"] = "ParsingErrorNoScene";
+        mWarningsArray.append(args);
 		setLoadState( ERROR_PARSING );
 		return true;
 	}
@@ -1108,11 +1156,14 @@ bool LLDAELoader::OpenFile(const std::string& filename)
 
 	bool badElement = false;
 	
-	processElement( scene, badElement, &dae );
+	processElement( scene, badElement, &dae);
 	
 	if ( badElement )
 	{
 		LL_INFOS()<<"Scene could not be parsed"<<LL_ENDL;
+        LLSD args;
+        args["Message"] = "ParsingErrorCantParseScene";
+        mWarningsArray.append(args);
 		setLoadState( ERROR_PARSING );
 	}
 	
@@ -1184,17 +1235,19 @@ void LLDAELoader::processDomModel(LLModel* model, DAE* dae, daeElement* root, do
 
 			LLMeshSkinInfo& skin_info = model->mSkinInfo;
 
+            LLMatrix4 mat;
 			for (int i = 0; i < 4; i++)
 			{
 				for(int j = 0; j < 4; j++)
 				{
-					skin_info.mBindShapeMatrix.mMatrix[i][j] = dom_value[i + j*4];
+                    mat.mMatrix[i][j] = dom_value[i + j*4];
 				}
 			}
 
-			LLMatrix4 trans = normalized_transformation;
-			trans *= skin_info.mBindShapeMatrix;
-			skin_info.mBindShapeMatrix = trans;							
+            skin_info.mBindShapeMatrix.loadu(mat);
+
+			LLMatrix4a trans(normalized_transformation);
+            matMul(trans, skin_info.mBindShapeMatrix, skin_info.mBindShapeMatrix);
 		}
 
 
@@ -1412,7 +1465,7 @@ void LLDAELoader::processDomModel(LLModel* model, DAE* dae, daeElement* root, do
 									mat.mMatrix[i][j] = transform[k*16 + i + j*4];
 								}
 							}
-							model->mSkinInfo.mInvBindMatrix.push_back(mat);
+							model->mSkinInfo.mInvBindMatrix.push_back(LLMatrix4a(mat));
 						}
 					}
 				}
@@ -1486,9 +1539,9 @@ void LLDAELoader::processDomModel(LLModel* model, DAE* dae, daeElement* root, do
 			if (mJointMap.find(lookingForJoint) != mJointMap.end()
 				&& model->mSkinInfo.mInvBindMatrix.size() > i)
 			{
-				LLMatrix4 newInverse = model->mSkinInfo.mInvBindMatrix[i];
+				LLMatrix4 newInverse = LLMatrix4(model->mSkinInfo.mInvBindMatrix[i].getF32ptr());
 				newInverse.setTranslation( mJointList[lookingForJoint].getTranslation() );
-				model->mSkinInfo.mAlternateBindMatrix.push_back( newInverse );
+				model->mSkinInfo.mAlternateBindMatrix.push_back( LLMatrix4a(newInverse) );
             }
 			else
 			{
@@ -1951,7 +2004,7 @@ daeElement* LLDAELoader::getChildFromElement( daeElement* pElement, std::string
     return NULL;
 }
 
-void LLDAELoader::processElement( daeElement* element, bool& badElement, DAE* dae )
+void LLDAELoader::processElement( daeElement* element, bool& badElement, DAE* dae)
 {
 	LLMatrix4 saved_transform;
 	bool pushed_mat = false;
@@ -2045,6 +2098,11 @@ void LLDAELoader::processElement( daeElement* element, bool& badElement, DAE* da
 					if (mTransform.determinant() < 0)
 					{ //negative scales are not supported
 						LL_INFOS() << "Negative scale detected, unsupported transform.  domInstance_geometry: " << getElementLabel(instance_geo) << LL_ENDL;
+                        LLSD args;
+                        args["Message"] = "NegativeScaleTrans";
+                        args["LABEL"] = getElementLabel(instance_geo);
+                        mWarningsArray.append(args);
+
 						badElement = true;
 					}
 
@@ -2068,6 +2126,10 @@ void LLDAELoader::processElement( daeElement* element, bool& badElement, DAE* da
 					if (transformation.determinant() < 0)
 					{ //negative scales are not supported
 						LL_INFOS() << "Negative scale detected, unsupported post-normalization transform.  domInstance_geometry: " << getElementLabel(instance_geo) << LL_ENDL;
+                        LLSD args;
+                        args["Message"] = "NegativeScaleNormTrans";
+                        args["LABEL"] = getElementLabel(instance_geo);
+                        mWarningsArray.append(args);
 						badElement = true;
 					}
 
@@ -2109,6 +2171,9 @@ void LLDAELoader::processElement( daeElement* element, bool& badElement, DAE* da
 		else 
 		{
 			LL_INFOS()<<"Unable to resolve geometry URL."<<LL_ENDL;
+            LLSD args;
+            args["Message"] = "CantResolveGeometryUrl";
+            mWarningsArray.append(args);
 			badElement = true;			
 		}
 
@@ -2399,7 +2464,7 @@ bool LLDAELoader::addVolumeFacesFromDomMesh(LLModel* pModel,domMesh* mesh, LLSD&
 	{
 		domTrianglesRef& tri = tris.get(i);
 
-		status = load_face_from_dom_triangles(pModel->getVolumeFaces(), pModel->getMaterialList(), tri);
+		status = load_face_from_dom_triangles(pModel->getVolumeFaces(), pModel->getMaterialList(), tri, log_msg);
 		pModel->mStatus = status;
 		if(status != LLModel::NO_ERRORS)
 		{
@@ -2426,6 +2491,7 @@ bool LLDAELoader::addVolumeFacesFromDomMesh(LLModel* pModel,domMesh* mesh, LLSD&
 	for (U32 i = 0; i < polygons.getCount(); ++i)
 	{
 		domPolygonsRef& poly = polygons.get(i);
+
 		status = load_face_from_dom_polygons(pModel->getVolumeFaces(), pModel->getMaterialList(), poly);
 
 		if(status != LLModel::NO_ERRORS)
@@ -2511,7 +2577,7 @@ bool LLDAELoader::loadModelsFromDomMesh(domMesh* mesh, std::vector<LLModel*>& mo
 
 		if (!mNoOptimize)
 		{
-			ret->optimizeVolumeFaces();
+			ret->remapVolumeFaces();
 		}
 
 		volume_faces = remainder.size();
diff --git a/indra/llprimitive/llmodel.cpp b/indra/llprimitive/llmodel.cpp
index 1b34068eced2ca0753aedeb6aaf071d94fa0ac80..805af552996e68f9418d90ab74491210378bfd1c 100644
--- a/indra/llprimitive/llmodel.cpp
+++ b/indra/llprimitive/llmodel.cpp
@@ -31,11 +31,12 @@
 #include "llconvexdecomposition.h"
 #include "llsdserialize.h"
 #include "llvector4a.h"
+#include "llmd5.h"
 
 #ifdef LL_USESYSTEMLIBS
 # include <zlib.h>
 #else
-# include "zlib/zlib.h"
+# include "zlib-ng/zlib.h"
 #endif
 
 std::string model_names[] =
@@ -106,6 +107,14 @@ void LLModel::offsetMesh( const LLVector3& pivotPoint )
 	}
 }
 
+void LLModel::remapVolumeFaces()
+{
+    for (U32 i = 0; i < getNumVolumeFaces(); ++i)
+    {
+        mVolumeFaces[i].remap();
+    }
+}
+
 void LLModel::optimizeVolumeFaces()
 {
 	for (U32 i = 0; i < getNumVolumeFaces(); ++i)
@@ -370,6 +379,8 @@ void LLModel::setVolumeFaceData(
 	U32 num_verts, 
 	U32 num_indices)
 {
+    llassert(num_indices % 3 == 0);
+
 	LLVolumeFace& face = mVolumeFaces[f];
 
 	face.resizeVertices(num_verts);
@@ -834,7 +845,7 @@ LLSD LLModel::writeModel(
 					{
 						LLVector3 pos(face.mPositions[j].getF32ptr());
 
-						weight_list& weights = high->getJointInfluences(pos);
+						weight_list& weights = model[idx]->getJointInfluences(pos);
 
 						S32 count = 0;
 						for (weight_list::iterator iter = weights.begin(); iter != weights.end(); ++iter)
@@ -880,8 +891,6 @@ LLSD LLModel::writeModel(
 
 LLSD LLModel::writeModelToStream(std::ostream& ostr, LLSD& mdl, BOOL nowrite, BOOL as_slm)
 {
-	U32 bytes = 0;
-	
 	std::string::size_type cur_offset = 0;
 
 	LLSD header;
@@ -903,7 +912,6 @@ LLSD LLModel::writeModelToStream(std::ostream& ostr, LLSD& mdl, BOOL nowrite, BO
 			header["skin"]["offset"] = (LLSD::Integer) cur_offset;
 			header["skin"]["size"] = (LLSD::Integer) size;
 			cur_offset += size;
-			bytes += size;
 		}
 	}
 
@@ -919,7 +927,6 @@ LLSD LLModel::writeModelToStream(std::ostream& ostr, LLSD& mdl, BOOL nowrite, BO
 			header["physics_convex"]["offset"] = (LLSD::Integer) cur_offset;
 			header["physics_convex"]["size"] = (LLSD::Integer) size;
 			cur_offset += size;
-			bytes += size;
 		}
 	}
 
@@ -941,7 +948,6 @@ LLSD LLModel::writeModelToStream(std::ostream& ostr, LLSD& mdl, BOOL nowrite, BO
 			header[model_names[i]]["offset"] = (LLSD::Integer) cur_offset;
 			header[model_names[i]]["size"] = (LLSD::Integer) size;
 			cur_offset += size;
-			bytes += size;
 		}
 	}
 
@@ -1404,7 +1410,7 @@ void LLMeshSkinInfo::fromLLSD(LLSD& skin)
 				}
 			}
 
-			mInvBindMatrix.push_back(mat);
+			mInvBindMatrix.push_back(LLMatrix4a(mat));
 		}
 
         if (mJointNames.size() != mInvBindMatrix.size())
@@ -1418,13 +1424,15 @@ void LLMeshSkinInfo::fromLLSD(LLSD& skin)
 
 	if (skin.has("bind_shape_matrix"))
 	{
+        LLMatrix4 mat;
 		for (U32 j = 0; j < 4; j++)
 		{
 			for (U32 k = 0; k < 4; k++)
 			{
-				mBindShapeMatrix.mMatrix[j][k] = skin["bind_shape_matrix"][j*4+k].asReal();
+				mat.mMatrix[j][k] = skin["bind_shape_matrix"][j*4+k].asReal();
 			}
 		}
+        mBindShapeMatrix.loadu(mat);
 	}
 
 	if (skin.has("alt_inverse_bind_matrix"))
@@ -1440,7 +1448,7 @@ void LLMeshSkinInfo::fromLLSD(LLSD& skin)
 				}
 			}
 			
-			mAlternateBindMatrix.push_back(mat);
+			mAlternateBindMatrix.push_back(LLMatrix4a(mat));
 		}
 	}
 
@@ -1457,6 +1465,8 @@ void LLMeshSkinInfo::fromLLSD(LLSD& skin)
 	{
 		mLockScaleIfJointPosition = false;
 	}
+
+    updateHash();
 }
 
 LLSD LLMeshSkinInfo::asLLSD(bool include_joints, bool lock_scale_if_joint_position) const
@@ -1508,6 +1518,57 @@ LLSD LLMeshSkinInfo::asLLSD(bool include_joints, bool lock_scale_if_joint_positi
 	return ret;
 }
 
+void LLMeshSkinInfo::updateHash()
+{
+    //  get hash of data relevant to render batches
+    LLMD5 hash;
+
+    //mJointNames
+    for (auto& name : mJointNames)
+    {
+        hash.update(name);
+    }
+    
+    //mJointNums 
+    hash.update((U8*)&(mJointNums[0]), sizeof(S32) * mJointNums.size());
+    
+    //mInvBindMatrix
+    F32* src = mInvBindMatrix[0].getF32ptr();
+    
+    for (int i = 0; i < mInvBindMatrix.size() * 16; ++i)
+    {
+        S32 t = llround(src[i] * 10000.f);
+        hash.update((U8*)&t, sizeof(S32));
+    }
+    //hash.update((U8*)&(mInvBindMatrix[0]), sizeof(LLMatrix4a) * mInvBindMatrix.size());
+
+    hash.finalize();
+
+    U64 digest[2];
+    hash.raw_digest((U8*) digest);
+
+    mHash = digest[0];
+}
+
+U32 LLMeshSkinInfo::sizeBytes() const
+{
+    U32 res = sizeof(LLUUID); // mMeshID
+
+    res += sizeof(std::vector<std::string>) + sizeof(std::string) * mJointNames.size();
+    for (U32 i = 0; i < mJointNames.size(); ++i)
+    {
+        res += mJointNames[i].size(); // actual size, not capacity
+    }
+
+    res += sizeof(std::vector<S32>) + sizeof(S32) * mJointNums.size();
+    res += sizeof(std::vector<LLMatrix4>) + 16 * sizeof(float) * mInvBindMatrix.size();
+    res += sizeof(std::vector<LLMatrix4>) + 16 * sizeof(float) * mAlternateBindMatrix.size();
+    res += 16 * sizeof(float); //mBindShapeMatrix
+    res += sizeof(float) + 3 * sizeof(bool);
+
+    return res;
+}
+
 LLModel::Decomposition::Decomposition(LLSD& data)
 {
 	fromLLSD(data);
@@ -1614,6 +1675,30 @@ void LLModel::Decomposition::fromLLSD(LLSD& decomp)
 	}
 }
 
+U32 LLModel::Decomposition::sizeBytes() const
+{
+    U32 res = sizeof(LLUUID); // mMeshID
+
+    res += sizeof(LLModel::convex_hull_decomposition) + sizeof(std::vector<LLVector3>) * mHull.size();
+    for (U32 i = 0; i < mHull.size(); ++i)
+    {
+        res += mHull[i].size() * sizeof(LLVector3);
+    }
+
+    res += sizeof(LLModel::hull) + sizeof(LLVector3) * mBaseHull.size();
+
+    res += sizeof(std::vector<LLModel::PhysicsMesh>) + sizeof(std::vector<LLModel::PhysicsMesh>) * mMesh.size();
+    for (U32 i = 0; i < mMesh.size(); ++i)
+    {
+        res += mMesh[i].sizeBytes();
+    }
+
+    res += sizeof(std::vector<LLModel::PhysicsMesh>) * 2;
+    res += mBaseHullMesh.sizeBytes() + mPhysicsShapeMesh.sizeBytes();
+
+    return res;
+}
+
 bool LLModel::Decomposition::hasHullList() const
 {
 	return !mHull.empty() ;
diff --git a/indra/llprimitive/llmodel.h b/indra/llprimitive/llmodel.h
index 51fa2f8079cfef5f9182df9a68e24280dce4f88b..a6ab96ab18400dcfd57c02064a1bc1eb6bbbdcdf 100644
--- a/indra/llprimitive/llmodel.h
+++ b/indra/llprimitive/llmodel.h
@@ -33,34 +33,45 @@
 #include "m4math.h"
 #include <queue>
 
+#include <boost/align/aligned_allocator.hpp>
+
 class daeElement;
 class domMesh;
 
 #define MAX_MODEL_FACES 8
 
+LL_ALIGN_PREFIX(16)
 class LLMeshSkinInfo 
 {
+    LL_ALIGN_NEW
 public:
 	LLMeshSkinInfo();
 	LLMeshSkinInfo(LLSD& data);
 	void fromLLSD(LLSD& data);
 	LLSD asLLSD(bool include_joints, bool lock_scale_if_joint_position) const;
+    void updateHash();
+    U32 sizeBytes() const;
 
 	LLUUID mMeshID;
 	std::vector<std::string> mJointNames;
     mutable std::vector<S32> mJointNums;
-	std::vector<LLMatrix4> mInvBindMatrix;
-	std::vector<LLMatrix4> mAlternateBindMatrix;
+    typedef std::vector<LLMatrix4a, boost::alignment::aligned_allocator<LLMatrix4a, 16>> matrix_list_t;
+	matrix_list_t mInvBindMatrix;
+	matrix_list_t mAlternateBindMatrix;
+
+	LL_ALIGN_16(LLMatrix4a mBindShapeMatrix);
 
-	LLMatrix4 mBindShapeMatrix;
 	float mPelvisOffset;
     bool mLockScaleIfJointPosition;
     bool mInvalidJointsScrubbed;
     bool mJointNumsInitialized;
-};
+    U64 mHash = 0;
+} LL_ALIGN_POSTFIX(16);
 
+LL_ALIGN_PREFIX(16)
 class LLModel : public LLVolume
 {
+    LL_ALIGN_NEW
 public:
 
 	enum
@@ -102,6 +113,14 @@ class LLModel : public LLVolume
 		{
 			return mPositions.empty();
 		}
+
+        U32 sizeBytes() const
+        {
+            U32 res = sizeof(std::vector<LLVector3>) * 2;
+            res += sizeof(LLVector3) * mPositions.size();
+            res += sizeof(LLVector3) * mNormals.size();
+            return res;
+        }
 	};
 
 	class Decomposition
@@ -112,6 +131,7 @@ class LLModel : public LLVolume
 		void fromLLSD(LLSD& data);
 		LLSD asLLSD() const;
 		bool hasHullList() const;
+        U32 sizeBytes() const;
 
 		void merge(const Decomposition* rhs);
 
@@ -174,6 +194,7 @@ class LLModel : public LLVolume
 	void sortVolumeFacesByMaterialName();
 	void normalizeVolumeFaces();
 	void trimVolumeFacesToSize(U32 new_count = LL_SCULPT_MESH_MAX_FACES, LLVolume::face_list_t* remainder = NULL);
+    void remapVolumeFaces();
 	void optimizeVolumeFaces();
 	void offsetMesh( const LLVector3& pivotPoint );
 	void getNormalizedScaleTranslation(LLVector3& scale_out, LLVector3& translation_out);
@@ -281,8 +302,10 @@ class LLModel : public LLVolume
 
 	EModelStatus mStatus ;
 
+    // A model/object can only have 8 faces, spillover faces will
+    // be moved to new model/object and assigned a submodel id.
 	int mSubmodelID;
-};
+} LL_ALIGN_POSTFIX(16);
 
 typedef std::vector<LLPointer<LLModel> >	model_list;
 typedef std::queue<LLPointer<LLModel> >	model_queue;
diff --git a/indra/llrender/llcubemap.cpp b/indra/llrender/llcubemap.cpp
index 5947bca670094cec0f160c7fb767c60fbdbe268f..834084674e0de815c7f544553b94965ea208eb2e 100644
--- a/indra/llrender/llcubemap.cpp
+++ b/indra/llrender/llcubemap.cpp
@@ -47,7 +47,6 @@ bool LLCubeMap::sUseCubeMaps = true;
 
 LLCubeMap::LLCubeMap(bool init_as_srgb)
 	: mTextureStage(0),
-	  mTextureCoordStage(0),
 	  mMatrixStage(0),
 	  mIssRGB(init_as_srgb)
 {
@@ -150,6 +149,7 @@ void LLCubeMap::initRawData(const std::vector<LLPointer<LLImageRaw> >& rawimages
 
 void LLCubeMap::initGLData()
 {
+    LL_PROFILE_ZONE_SCOPED;
 	for (int i = 0; i < 6; i++)
 	{
 		mImages[i]->setSubImage(mRawImages[i], 0, 0, RESOLUTION, RESOLUTION);
@@ -179,7 +179,6 @@ void LLCubeMap::bind()
 void LLCubeMap::enable(S32 stage)
 {
 	enableTexture(stage);
-	enableTextureCoords(stage);
 }
 
 void LLCubeMap::enableTexture(S32 stage)
@@ -191,35 +190,9 @@ void LLCubeMap::enableTexture(S32 stage)
 	}
 }
 
-void LLCubeMap::enableTextureCoords(S32 stage)
-{
-	mTextureCoordStage = stage;
-	if (!LLGLSLShader::sNoFixedFunction && gGLManager.mHasCubeMap && stage >= 0 && LLCubeMap::sUseCubeMaps)
-	{
-		if (stage > 0)
-		{
-			gGL.getTexUnit(stage)->activate();
-		}
-		
-		glEnable(GL_TEXTURE_GEN_R);
-		glEnable(GL_TEXTURE_GEN_S);
-		glEnable(GL_TEXTURE_GEN_T);
-
-		glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP);
-		glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP);
-		glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP);
-		
-		if (stage > 0)
-		{
-			gGL.getTexUnit(0)->activate();
-		}
-	}
-}
-
 void LLCubeMap::disable(void)
 {
 	disableTexture();
-	disableTextureCoords();
 }
 
 void LLCubeMap::disableTexture(void)
@@ -234,24 +207,6 @@ void LLCubeMap::disableTexture(void)
 	}
 }
 
-void LLCubeMap::disableTextureCoords(void)
-{
-	if (!LLGLSLShader::sNoFixedFunction && gGLManager.mHasCubeMap && mTextureCoordStage >= 0 && LLCubeMap::sUseCubeMaps)
-	{
-		if (mTextureCoordStage > 0)
-		{
-			gGL.getTexUnit(mTextureCoordStage)->activate();
-		}
-		glDisable(GL_TEXTURE_GEN_S);
-		glDisable(GL_TEXTURE_GEN_T);
-		glDisable(GL_TEXTURE_GEN_R);
-		if (mTextureCoordStage > 0)
-		{
-			gGL.getTexUnit(0)->activate();
-		}
-	}
-}
-
 void LLCubeMap::setMatrix(S32 stage)
 {
 	mMatrixStage = stage;
@@ -453,6 +408,7 @@ BOOL LLCubeMap::project(F32& v_min, F32& v_max, F32& h_min, F32& h_max,
 
 void LLCubeMap::paintIn(LLVector3 dir[4], const LLColor4U& col)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	F32 v_min, v_max, h_min, h_max;
 	LLVector3 center = dir[0] + dir[1] + dir[2] + dir[3];
 	center.normVec();
diff --git a/indra/llrender/llcubemap.h b/indra/llrender/llcubemap.h
index 95b6d1209913d04b3353c10c8fd6f312e9dbeabf..a01636d8d41f348afb5fdc1d89cc5ee2f9d04c65 100644
--- a/indra/llrender/llcubemap.h
+++ b/indra/llrender/llcubemap.h
@@ -48,12 +48,10 @@ class LLCubeMap : public LLRefCount
 	void enable(S32 stage);
 	
 	void enableTexture(S32 stage);
-	void enableTextureCoords(S32 stage);
 	S32	 getStage(void) { return mTextureStage; }
 	
 	void disable(void);
 	void disableTexture(void);
-	void disableTextureCoords(void);
 	void setMatrix(S32 stage);
 	void restoreMatrix();
 	void setReflection (void);
@@ -80,7 +78,6 @@ class LLCubeMap : public LLRefCount
 	LLPointer<LLImageGL> mImages[6];
 	LLPointer<LLImageRaw> mRawImages[6];
 	S32 mTextureStage;
-	S32 mTextureCoordStage;
 	S32 mMatrixStage;
 };
 
diff --git a/indra/llrender/llfontbitmapcache.cpp b/indra/llrender/llfontbitmapcache.cpp
index f128636ab29b33b142dd1bf6d880c780da67c801..c71e24c83a172e4685710dadb289b442a99c3cd9 100644
--- a/indra/llrender/llfontbitmapcache.cpp
+++ b/indra/llrender/llfontbitmapcache.cpp
@@ -30,8 +30,7 @@
 #include "llfontbitmapcache.h"
 
 LLFontBitmapCache::LLFontBitmapCache()
-:	LLTrace::MemTrackable<LLFontBitmapCache>("LLFontBitmapCache"),
-	mNumComponents(0),
+:	mNumComponents(0),
 	mBitmapWidth(0),
 	mBitmapHeight(0),
 	mBitmapNum(-1),
@@ -124,9 +123,6 @@ BOOL LLFontBitmapCache::nextOpenPos(S32 width, S32 &pos_x, S32 &pos_y, S32& bitm
 			image_gl->createGLTexture(0, image_raw);
 			gGL.getTexUnit(0)->bind(image_gl);
 			image_gl->setFilteringOption(LLTexUnit::TFO_POINT); // was setMipFilterNearest(TRUE, TRUE);
-
-			claimMem(image_raw);
-			claimMem(image_gl);
 		}
 		else
 		{
@@ -156,20 +152,8 @@ void LLFontBitmapCache::destroyGL()
 
 void LLFontBitmapCache::reset()
 {
-	for (std::vector<LLPointer<LLImageRaw> >::iterator it = mImageRawVec.begin(), end_it = mImageRawVec.end();
-		it != end_it;
-		++it)
-	{
-		disclaimMem(**it);
-	}
 	mImageRawVec.clear();
 
-	for (std::vector<LLPointer<LLImageGL> >::iterator it = mImageGLVec.begin(), end_it = mImageGLVec.end();
-		it != end_it;
-		++it)
-	{
-		disclaimMem(**it);
-	}
 	mImageGLVec.clear();
 	
 	mBitmapWidth = 0;
diff --git a/indra/llrender/llfontbitmapcache.h b/indra/llrender/llfontbitmapcache.h
index 75df3a94a796fab48d4f7c63c3f03c95beef44c5..7de3a6b56f06ebcd5e2a8e1852042a200da62d13 100644
--- a/indra/llrender/llfontbitmapcache.h
+++ b/indra/llrender/llfontbitmapcache.h
@@ -32,7 +32,7 @@
 
 // Maintain a collection of bitmaps containing rendered glyphs.
 // Generalizes the single-bitmap logic from LLFontFreetype and LLFontGL.
-class LLFontBitmapCache : public LLTrace::MemTrackable<LLFontBitmapCache>
+class LLFontBitmapCache
 {
 public:
 	LLFontBitmapCache();
diff --git a/indra/llrender/llfontfreetype.cpp b/indra/llrender/llfontfreetype.cpp
index c41730ebaaacea9d369885fd04380f3821224f93..e964d1586faa1657e8efa609cbc6c8e9c25d7f2d 100644
--- a/indra/llrender/llfontfreetype.cpp
+++ b/indra/llrender/llfontfreetype.cpp
@@ -104,8 +104,7 @@ LLFontGlyphInfo::LLFontGlyphInfo(U32 index)
 }
 
 LLFontFreetype::LLFontFreetype()
-:	LLTrace::MemTrackable<LLFontFreetype>("LLFontFreetype"),
-	mFontBitmapCachep(new LLFontBitmapCache),
+:	mFontBitmapCachep(new LLFontBitmapCache),
 	mAscender(0.f),
 	mDescender(0.f),
 	mLineHeight(0.f),
@@ -222,8 +221,6 @@ BOOL LLFontFreetype::loadFace(const std::string& filename, F32 point_size, F32 v
 	S32 max_char_height = ll_round(0.5f + (y_max - y_min));
 
 	mFontBitmapCachep->init(components, max_char_width, max_char_height);
-	claimMem(mFontBitmapCachep);
-
 
 	if (!mFTFace->charmap)
 	{
@@ -238,7 +235,6 @@ BOOL LLFontFreetype::loadFace(const std::string& filename, F32 point_size, F32 v
 	}
 
 	mName = filename;
-	claimMem(mName);
 	mPointSize = point_size;
 
 	mStyle = LLFontGL::NORMAL;
@@ -460,6 +456,7 @@ LLFontGlyphInfo* LLFontFreetype::addGlyph(llwchar wch) const
 
 LLFontGlyphInfo* LLFontFreetype::addGlyphFromFont(const LLFontFreetype *fontp, llwchar wch, U32 glyph_index) const
 {
+    LL_PROFILE_ZONE_SCOPED;
 	if (mFTFace == NULL)
 		return NULL;
 
@@ -585,7 +582,6 @@ void LLFontFreetype::insertGlyphInfo(llwchar wch, LLFontGlyphInfo* gi) const
 	}
 	else
 	{
-		claimMem(gi);
 		mCharGlyphInfoMap[wch] = gi;
 	}
 }
@@ -631,11 +627,9 @@ void LLFontFreetype::resetBitmapCache()
 		it != end_it;
 		++it)
 	{
-		disclaimMem(it->second);
 		delete it->second;
 	}
 	mCharGlyphInfoMap.clear();
-	disclaimMem(mFontBitmapCachep);
 	mFontBitmapCachep->reset();
 
 	// Adding default glyph is skipped for fallback fonts here as well as in loadFace(). 
diff --git a/indra/llrender/llfontfreetype.h b/indra/llrender/llfontfreetype.h
index 1afe84e770f6c289708cc6bbff9d007971cf9da1..f61f169987b2a980ed99f2d39c2e7ab63aaa9a4c 100644
--- a/indra/llrender/llfontfreetype.h
+++ b/indra/llrender/llfontfreetype.h
@@ -76,7 +76,7 @@ struct LLFontGlyphInfo
 
 extern LLFontManager *gFontManagerp;
 
-class LLFontFreetype : public LLRefCount, public LLTrace::MemTrackable<LLFontFreetype>
+class LLFontFreetype : public LLRefCount
 {
 public:
 	LLFontFreetype();
diff --git a/indra/llrender/llfontgl.cpp b/indra/llrender/llfontgl.cpp
index 86a4c35e6dec1ef309c370bdc2b0a40fb7dff272..1bf061bc8d0b16386c6c584f356de4a2e272a21a 100644
--- a/indra/llrender/llfontgl.cpp
+++ b/indra/llrender/llfontgl.cpp
@@ -109,8 +109,6 @@ S32 LLFontGL::getNumFaces(const std::string& filename)
 	return mFontFreetype->getNumFaces(filename);
 }
 
-static LLTrace::BlockTimerStatHandle FTM_RENDER_FONTS("Fonts");
-
 S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, const LLRect& rect, const LLColor4 &color, HAlign halign, VAlign valign, U8 style,
     ShadowType shadow, S32 max_chars, F32* right_x, BOOL use_ellipses) const
 {
@@ -147,7 +145,7 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, const LLRectf& rec
 S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, const LLColor4 &color, HAlign halign, VAlign valign, U8 style, 
 					 ShadowType shadow, S32 max_chars, S32 max_pixels, F32* right_x, BOOL use_ellipses) const
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_FONTS);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
 
 	if(!sDisplayFont) //do not display texts
 	{
@@ -547,9 +545,19 @@ F32 LLFontGL::getWidthF32(const llwchar* wchars, S32 begin_offset, S32 max_chars
 	return cur_x / sScaleX;
 }
 
+void LLFontGL::generateASCIIglyphs()
+{
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_UI
+    for (U32 i = 32; (i < 127); i++)
+    {
+        mFontFreetype->getGlyphInfo(i);
+    }
+}
+
 // Returns the max number of complete characters from text (up to max_chars) that can be drawn in max_pixels
 S32 LLFontGL::maxDrawableChars(const llwchar* wchars, F32 max_pixels, S32 max_chars, EWordWrapStyle end_on_word_boundary) const
 {
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_UI
 	if (!wchars || !wchars[0] || max_chars == 0)
 	{
 		return 0;
@@ -829,6 +837,8 @@ void LLFontGL::initClass(F32 screen_dpi, F32 x_scale, F32 y_scale, const std::st
 	{
 		sFontRegistry->reset();
 	}
+
+	LLFontGL::loadDefaultFonts();
 }
 
 // Force standard fonts to get generated up front.
@@ -838,6 +848,7 @@ void LLFontGL::initClass(F32 screen_dpi, F32 x_scale, F32 y_scale, const std::st
 // static
 bool LLFontGL::loadDefaultFonts()
 {
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_UI
 	bool succ = true;
 	succ &= (NULL != getFontSansSerifSmall());
 	succ &= (NULL != getFontSansSerif());
@@ -845,10 +856,18 @@ bool LLFontGL::loadDefaultFonts()
 	succ &= (NULL != getFontSansSerifHuge());
 	succ &= (NULL != getFontSansSerifBold());
 	succ &= (NULL != getFontMonospace());
-	succ &= (NULL != getFontExtChar());
 	return succ;
 }
 
+void LLFontGL::loadCommonFonts()
+{
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_UI
+    getFont(LLFontDescriptor("SansSerif", "Small", BOLD));
+    getFont(LLFontDescriptor("SansSerif", "Large", BOLD));
+    getFont(LLFontDescriptor("SansSerif", "Huge", BOLD));
+    getFont(LLFontDescriptor("Monospace", "Medium", 0));
+}
+
 // static
 void LLFontGL::destroyDefaultFonts()
 {
@@ -1015,7 +1034,7 @@ LLFontGL* LLFontGL::getFontSansSerifBig()
 //static 
 LLFontGL* LLFontGL::getFontSansSerifHuge()
 {
-	static LLFontGL* fontp = getFont(LLFontDescriptor("SansSerif","Large",0));
+	static LLFontGL* fontp = getFont(LLFontDescriptor("SansSerif","Huge",0));
 	return fontp;
 }
 
@@ -1026,12 +1045,6 @@ LLFontGL* LLFontGL::getFontSansSerifBold()
 	return fontp;
 }
 
-//static
-LLFontGL* LLFontGL::getFontExtChar()
-{
-	return getFontSansSerif();
-}
-
 //static 
 LLFontGL* LLFontGL::getFont(const LLFontDescriptor& desc)
 {
diff --git a/indra/llrender/llfontgl.h b/indra/llrender/llfontgl.h
index 10891faed9c1318b918b1beb6bb6d2c64f741c8f..3b58a37d33fe15f63831824f8f5fcaf66a3b8ede 100644
--- a/indra/llrender/llfontgl.h
+++ b/indra/llrender/llfontgl.h
@@ -160,12 +160,15 @@ class LLFontGL
 
 	const LLFontDescriptor& getFontDesc() const;
 
+	void generateASCIIglyphs();
+
 
 	static void initClass(F32 screen_dpi, F32 x_scale, F32 y_scale, const std::string& app_dir, bool create_gl_textures = true);
 
 	// Load sans-serif, sans-serif-small, etc.
 	// Slow, requires multiple seconds to load fonts.
 	static bool loadDefaultFonts();
+    static void loadCommonFonts();
 	static void	destroyDefaultFonts();
 	static void destroyAllGL();
 
@@ -190,7 +193,6 @@ class LLFontGL
 	static LLFontGL* getFontSansSerifBig();
 	static LLFontGL* getFontSansSerifHuge();
 	static LLFontGL* getFontSansSerifBold();
-	static LLFontGL* getFontExtChar();
 	static LLFontGL* getFont(const LLFontDescriptor& desc);
 	// Use with legacy names like "SANSSERIF_SMALL" or "OCRA"
 	static LLFontGL* getFontByName(const std::string& name);
diff --git a/indra/llrender/llfontregistry.cpp b/indra/llrender/llfontregistry.cpp
index 33a33af160d2e086061ac4ac1f54cac25b1af404..bc1a2f888709813f5b31dccb90aa57c4f5112525 100644
--- a/indra/llrender/llfontregistry.cpp
+++ b/indra/llrender/llfontregistry.cpp
@@ -597,6 +597,11 @@ LLFontGL *LLFontRegistry::getFont(const LLFontDescriptor& desc)
 					<<" style=[" << ((S32) desc.getStyle()) << "]"
 					<< " size=[" << desc.getSize() << "]" << LL_ENDL;
 		}
+		else
+		{
+			//generate glyphs for ASCII chars to avoid stalls later
+			fontp->generateASCIIglyphs();
+		}
 		return fontp;
 	}
 }
diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp
index 43fedeca64053ddc78a3d202c0170baec33b35c8..193cfa64b805034c665a036cbf27d60e2544ac72 100644
--- a/indra/llrender/llgl.cpp
+++ b/indra/llrender/llgl.cpp
@@ -60,10 +60,11 @@
 
 
 BOOL gDebugSession = FALSE;
+BOOL gDebugGLSession = FALSE;
 BOOL gClothRipple = FALSE;
 BOOL gHeadlessClient = FALSE;
+BOOL gNonInteractive = FALSE;
 BOOL gGLActive = FALSE;
-BOOL gGLDebugLoggingEnabled = TRUE;
 
 static const std::string HEADLESS_VENDOR_STRING("Linden Lab");
 static const std::string HEADLESS_RENDERER_STRING("Headless");
@@ -85,8 +86,13 @@ void APIENTRY gl_debug_callback(GLenum source,
                                 const GLchar* message,
                                 GLvoid* userParam)
 {
-	if (gGLDebugLoggingEnabled)
-	{
+    if (severity != GL_DEBUG_SEVERITY_HIGH_ARB &&
+        severity != GL_DEBUG_SEVERITY_MEDIUM_ARB &&
+        severity != GL_DEBUG_SEVERITY_LOW_ARB)
+    { //suppress out-of-spec messages sent by nvidia driver (mostly vertexbuffer hints)
+        return;
+    }
+
 	if (severity == GL_DEBUG_SEVERITY_HIGH_ARB)
 	{
 		LL_WARNS() << "----- GL ERROR --------" << LL_ENDL;
@@ -105,7 +111,6 @@ void APIENTRY gl_debug_callback(GLenum source,
 		LL_ERRS() << "Halting on GL Error" << LL_ENDL;
 	}
 }
-}
 #endif
 
 void parse_glsl_version(S32& major, S32& minor);
@@ -152,7 +157,6 @@ LLMatrix4 gGLObliqueProjectionInverse;
 std::list<LLGLUpdate*> LLGLUpdate::sGLQ;
 
 #if (LL_WINDOWS || LL_LINUX)  && !LL_MESA_HEADLESS
-// ATI prototypes
 
 #if LL_WINDOWS
 PFNGLGETSTRINGIPROC glGetStringi = NULL;
@@ -199,21 +203,6 @@ PFNGLGETSYNCIVPROC				glGetSynciv = NULL;
 PFNGLBUFFERPARAMETERIAPPLEPROC	glBufferParameteriAPPLE = NULL;
 PFNGLFLUSHMAPPEDBUFFERRANGEAPPLEPROC glFlushMappedBufferRangeAPPLE = NULL;
 
-// vertex object prototypes
-PFNGLNEWOBJECTBUFFERATIPROC			glNewObjectBufferATI = NULL;
-PFNGLISOBJECTBUFFERATIPROC			glIsObjectBufferATI = NULL;
-PFNGLUPDATEOBJECTBUFFERATIPROC		glUpdateObjectBufferATI = NULL;
-PFNGLGETOBJECTBUFFERFVATIPROC		glGetObjectBufferfvATI = NULL;
-PFNGLGETOBJECTBUFFERIVATIPROC		glGetObjectBufferivATI = NULL;
-PFNGLFREEOBJECTBUFFERATIPROC		glFreeObjectBufferATI = NULL;
-PFNGLARRAYOBJECTATIPROC				glArrayObjectATI = NULL;
-PFNGLVERTEXATTRIBARRAYOBJECTATIPROC	glVertexAttribArrayObjectATI = NULL;
-PFNGLGETARRAYOBJECTFVATIPROC		glGetArrayObjectfvATI = NULL;
-PFNGLGETARRAYOBJECTIVATIPROC		glGetArrayObjectivATI = NULL;
-PFNGLVARIANTARRAYOBJECTATIPROC		glVariantObjectArrayATI = NULL;
-PFNGLGETVARIANTARRAYOBJECTFVATIPROC	glGetVariantArrayObjectfvATI = NULL;
-PFNGLGETVARIANTARRAYOBJECTIVATIPROC	glGetVariantArrayObjectivATI = NULL;
-
 // GL_ARB_occlusion_query
 PFNGLGENQUERIESARBPROC glGenQueriesARB = NULL;
 PFNGLDELETEQUERIESARBPROC glDeleteQueriesARB = NULL;
@@ -434,9 +423,6 @@ LLGLManager::LLGLManager() :
 	mHasMapBufferRange(FALSE),
 	mHasFlushBufferRange(FALSE),
 	mHasPBuffer(FALSE),
-	mHasShaderObjects(FALSE),
-	mHasVertexShader(FALSE),
-	mHasFragmentShader(FALSE),
 	mNumTextureImageUnits(0),
 	mHasOcclusionQuery(FALSE),
 	mHasTimerQuery(FALSE),
@@ -456,14 +442,9 @@ LLGLManager::LLGLManager() :
 	mHasCubeMap(FALSE),
 	mHasDebugOutput(FALSE),
 
-	mIsATI(FALSE),
+	mIsAMD(FALSE),
 	mIsNVIDIA(FALSE),
 	mIsIntel(FALSE),
-	mIsGF2or4MX(FALSE),
-	mIsGF3(FALSE),
-	mIsGFFX(FALSE),
-	mATIOffsetVerticalLines(FALSE),
-	mATIOldDriver(FALSE),
 #if LL_DARWIN
 	mIsMobileGF(FALSE),
 #endif
@@ -559,7 +540,7 @@ bool LLGLManager::initGL()
 		glGetIntegerv(GL_NUM_EXTENSIONS, &count);
 		for (GLint i = 0; i < count; ++i)
 		{
-			std::string ext((const char*) glGetStringi(GL_EXTENSIONS, i));
+			std::string ext = ll_safe_string((const char*) glGetStringi(GL_EXTENSIONS, i));
 			str << ext << " ";
 			LL_DEBUGS("GLExtensions") << ext << LL_ENDL;
 		}
@@ -622,59 +603,17 @@ bool LLGLManager::initGL()
 	
 	// Trailing space necessary to keep "nVidia Corpor_ati_on" cards
 	// from being recognized as ATI.
+    // NOTE: AMD has been pretty good about not breaking this check, do not rename without good reason
 	if (mGLVendor.substr(0,4) == "ATI ")
 	{
-		mGLVendorShort = "ATI";
+		mGLVendorShort = "AMD";
 		// *TODO: Fix this?
-		mIsATI = TRUE;
-
-#if LL_WINDOWS && !LL_MESA_HEADLESS
-		if (mDriverVersionRelease < 3842)
-		{
-			mATIOffsetVerticalLines = TRUE;
-		}
-#endif // LL_WINDOWS
-
-#if (LL_WINDOWS || LL_LINUX) && !LL_MESA_HEADLESS
-		// count any pre OpenGL 3.0 implementation as an old driver
-		if (mGLVersion < 3.f) 
-		{
-			mATIOldDriver = TRUE;
-		}
-#endif // (LL_WINDOWS || LL_LINUX) && !LL_MESA_HEADLESS
+		mIsAMD = TRUE;
 	}
 	else if (mGLVendor.find("NVIDIA ") != std::string::npos)
 	{
 		mGLVendorShort = "NVIDIA";
 		mIsNVIDIA = TRUE;
-		if (   mGLRenderer.find("GEFORCE4 MX") != std::string::npos
-			|| mGLRenderer.find("GEFORCE2") != std::string::npos
-			|| mGLRenderer.find("GEFORCE 2") != std::string::npos
-			|| mGLRenderer.find("GEFORCE4 460 GO") != std::string::npos
-			|| mGLRenderer.find("GEFORCE4 440 GO") != std::string::npos
-			|| mGLRenderer.find("GEFORCE4 420 GO") != std::string::npos)
-		{
-			mIsGF2or4MX = TRUE;
-		}
-		else if (mGLRenderer.find("GEFORCE FX") != std::string::npos
-				 || mGLRenderer.find("QUADRO FX") != std::string::npos
-				 || mGLRenderer.find("NV34") != std::string::npos)
-		{
-			mIsGFFX = TRUE;
-		}
-		else if(mGLRenderer.find("GEFORCE3") != std::string::npos)
-		{
-			mIsGF3 = TRUE;
-		}
-#if LL_DARWIN
-		else if ((mGLRenderer.find("9400M") != std::string::npos)
-			  || (mGLRenderer.find("9600M") != std::string::npos)
-			  || (mGLRenderer.find("9800M") != std::string::npos))
-		{
-			mIsMobileGF = TRUE;
-		}
-#endif
-
 	}
 	else if (mGLVendor.find("INTEL") != std::string::npos
 #if LL_LINUX
@@ -775,29 +714,27 @@ bool LLGLManager::initGL()
 
 	stop_glerror();
 
-	stop_glerror();
-
-	if (mHasFragmentShader)
-	{
-		GLint num_tex_image_units;
-		glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS_ARB, &num_tex_image_units);
-		mNumTextureImageUnits = llmin(num_tex_image_units, 32);
-	}
+	GLint num_tex_image_units;
+	glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS_ARB, &num_tex_image_units);
+	mNumTextureImageUnits = llmin(num_tex_image_units, 32);
 
-	if (LLRender::sGLCoreProfile)
-	{
-		mNumTextureUnits = llmin(mNumTextureImageUnits, MAX_GL_TEXTURE_UNITS);
-	}
-	else if (mHasMultitexture)
-	{
-		GLint num_tex_units;		
-		glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, &num_tex_units);
-		mNumTextureUnits = llmin(num_tex_units, (GLint)MAX_GL_TEXTURE_UNITS);
-		if (mIsIntel)
-		{
-			mNumTextureUnits = llmin(mNumTextureUnits, 2);
-		}
-	}
+    if (mHasMultitexture)
+    {
+        if (LLRender::sGLCoreProfile)
+        {
+            mNumTextureUnits = llmin(mNumTextureImageUnits, MAX_GL_TEXTURE_UNITS);
+        }
+        else
+        {
+            GLint num_tex_units;
+            glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, &num_tex_units);
+            mNumTextureUnits = llmin(num_tex_units, (GLint)MAX_GL_TEXTURE_UNITS);
+            if (mIsIntel)
+            {
+                mNumTextureUnits = llmin(mNumTextureUnits, 2);
+            }
+        }
+    }
 	else
 	{
 		mHasRequirements = FALSE;
@@ -806,6 +743,14 @@ bool LLGLManager::initGL()
 		LL_WARNS("RenderInit") << "GL Drivers do not support GL_ARB_multitexture" << LL_ENDL;
 		return false;
 	}
+
+    if (!mHasFramebufferObject)
+    {
+        mHasRequirements = FALSE;
+
+        LL_WARNS("RenderInit") << "GL Drivers do not support GL_ARB_framebuffer_object" << LL_ENDL;
+        return false;
+    }
 	
 	stop_glerror();
 
@@ -819,31 +764,8 @@ bool LLGLManager::initGL()
 
 	stop_glerror();
 
-#if LL_WINDOWS
-	if (mHasDebugOutput && gDebugGL)
-	{ //setup debug output callback
-		//glDebugMessageControlARB(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_LOW_ARB, 0, NULL, GL_TRUE);
-		glDebugMessageCallbackARB((GLDEBUGPROCARB) gl_debug_callback, NULL);
-		glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB);
-	}
-#endif
-
-	stop_glerror();
-
 	//HACK always disable texture multisample, use FXAA instead
 	mHasTextureMultisample = FALSE;
-#if LL_WINDOWS
-	if (mIsATI)
-	{ //using multisample textures on ATI results in black screen for some reason
-		mHasTextureMultisample = FALSE;
-	}
-
-
-	if (mIsIntel && mGLVersion <= 3.f)
-	{ //never try to use framebuffer objects on older intel drivers (crashy)
-		mHasFramebufferObject = FALSE;
-	}
-#endif
 
 	if (mHasFramebufferObject)
 	{
@@ -975,9 +897,9 @@ void LLGLManager::asLLSD(LLSD& info)
 	info["has_map_buffer_range"] = mHasMapBufferRange;
 	info["has_flush_buffer_range"] = mHasFlushBufferRange;
 	info["has_pbuffer"] = mHasPBuffer;
-	info["has_shader_objects"] = mHasShaderObjects;
-	info["has_vertex_shader"] = mHasVertexShader;
-	info["has_fragment_shader"] = mHasFragmentShader;
+    info["has_shader_objects"] = std::string("Assumed TRUE");   // was mHasShaderObjects;
+	info["has_vertex_shader"] = std::string("Assumed TRUE");    // was mHasVertexShader;
+	info["has_fragment_shader"] = std::string("Assumed TRUE");  // was mHasFragmentShader;
 	info["num_texture_image_units"] =  mNumTextureImageUnits;
 	info["has_occlusion_query"] = mHasOcclusionQuery;
 	info["has_timer_query"] = mHasTimerQuery;
@@ -1003,14 +925,9 @@ void LLGLManager::asLLSD(LLSD& info)
     info["has_texture_srgb_decode"] = mHasTexturesRGBDecode;
 
 	// Vendor-specific extensions
-	info["is_ati"] = mIsATI;
+	info["is_ati"] = mIsAMD;  // note, do not rename is_ati to is_amd without coordinating with DW
 	info["is_nvidia"] = mIsNVIDIA;
 	info["is_intel"] = mIsIntel;
-	info["is_gf2or4mx"] = mIsGF2or4MX;
-	info["is_gf3"] = mIsGF3;
-	info["is_gf_gfx"] = mIsGFFX;
-	info["ati_offset_vertical_lines"] = mATIOffsetVerticalLines;
-	info["ati_old_driver"] = mATIOldDriver;
 
 	// Other fields
 	info["has_requirements"] = mHasRequirements;
@@ -1083,9 +1000,6 @@ void LLGLManager::initExtensions()
 	mHasCubeMap = FALSE;
 	mHasOcclusionQuery = FALSE;
 	mHasPointParameters = FALSE;
-	mHasShaderObjects = FALSE;
-	mHasVertexShader = FALSE;
-	mHasFragmentShader = FALSE;
 	mHasTextureRectangle = FALSE;
 #else // LL_MESA_HEADLESS //important, gGLHExts.mSysExts is uninitialized until after glh_init_extensions is called
 	mHasMultitexture = glh_init_extensions("GL_ARB_multitexture");
@@ -1105,8 +1019,9 @@ void LLGLManager::initExtensions()
 	mHasSync = ExtensionExists("GL_ARB_sync", gGLHExts.mSysExts);
 	mHasMapBufferRange = ExtensionExists("GL_ARB_map_buffer_range", gGLHExts.mSysExts);
 	mHasFlushBufferRange = ExtensionExists("GL_APPLE_flush_buffer_range", gGLHExts.mSysExts);
-	//mHasDepthClamp = ExtensionExists("GL_ARB_depth_clamp", gGLHExts.mSysExts) || ExtensionExists("GL_NV_depth_clamp", gGLHExts.mSysExts);
-	mHasDepthClamp = FALSE;
+    // NOTE: Using extensions breaks reflections when Shadows are set to projector.  See: SL-16727
+    //mHasDepthClamp = ExtensionExists("GL_ARB_depth_clamp", gGLHExts.mSysExts) || ExtensionExists("GL_NV_depth_clamp", gGLHExts.mSysExts);
+    mHasDepthClamp = FALSE;
 	// mask out FBO support when packed_depth_stencil isn't there 'cause we need it for LLRenderTarget -Brad
 #ifdef GL_ARB_framebuffer_object
 	mHasFramebufferObject = ExtensionExists("GL_ARB_framebuffer_object", gGLHExts.mSysExts);
@@ -1141,12 +1056,8 @@ void LLGLManager::initExtensions()
 	mHasDebugOutput = ExtensionExists("GL_ARB_debug_output", gGLHExts.mSysExts);
 	mHasTransformFeedback = mGLVersion >= 4.f ? TRUE : FALSE;
 #if !LL_DARWIN
-	mHasPointParameters = !mIsATI && ExtensionExists("GL_ARB_point_parameters", gGLHExts.mSysExts);
+	mHasPointParameters = ExtensionExists("GL_ARB_point_parameters", gGLHExts.mSysExts);
 #endif
-	mHasShaderObjects = ExtensionExists("GL_ARB_shader_objects", gGLHExts.mSysExts) && (LLRender::sGLCoreProfile || ExtensionExists("GL_ARB_shading_language_100", gGLHExts.mSysExts));
-	mHasVertexShader = ExtensionExists("GL_ARB_vertex_program", gGLHExts.mSysExts) && ExtensionExists("GL_ARB_vertex_shader", gGLHExts.mSysExts)
-		&& (LLRender::sGLCoreProfile || ExtensionExists("GL_ARB_shading_language_100", gGLHExts.mSysExts));
-	mHasFragmentShader = ExtensionExists("GL_ARB_fragment_shader", gGLHExts.mSysExts) && (LLRender::sGLCoreProfile || ExtensionExists("GL_ARB_shading_language_100", gGLHExts.mSysExts));
 #endif
 
 #if LL_LINUX
@@ -1169,9 +1080,6 @@ void LLGLManager::initExtensions()
 		mHasCubeMap = FALSE;
 		mHasOcclusionQuery = FALSE;
 		mHasPointParameters = FALSE;
-		mHasShaderObjects = FALSE;
-		mHasVertexShader = FALSE;
-		mHasFragmentShader = FALSE;
 		LL_WARNS("RenderInit") << "GL extension support DISABLED via LL_GL_NOEXT" << LL_ENDL;
 	}
 	else if (getenv("LL_GL_BASICEXT"))	/* Flawfinder: ignore */
@@ -1184,9 +1092,6 @@ void LLGLManager::initExtensions()
 		mHasAnisotropic = FALSE;
 		//mHasCubeMap = FALSE; // apparently fatal on Intel 915 & similar
 		//mHasOcclusionQuery = FALSE; // source of many ATI system hangs
-		mHasShaderObjects = FALSE;
-		mHasVertexShader = FALSE;
-		mHasFragmentShader = FALSE;
 		mHasBlendFuncSeparate = FALSE;
 		LL_WARNS("RenderInit") << "GL extension support forced to SIMPLE level via LL_GL_BASICEXT" << LL_ENDL;
 	}
@@ -1208,9 +1113,6 @@ void LLGLManager::initExtensions()
 		if (strchr(blacklist,'j')) mHasCubeMap = FALSE;//S
 // 		if (strchr(blacklist,'k')) mHasATIVAO = FALSE;//S
 		if (strchr(blacklist,'l')) mHasOcclusionQuery = FALSE;
-		if (strchr(blacklist,'m')) mHasShaderObjects = FALSE;//S
-		if (strchr(blacklist,'n')) mHasVertexShader = FALSE;//S
-		if (strchr(blacklist,'o')) mHasFragmentShader = FALSE;//S
 		if (strchr(blacklist,'p')) mHasPointParameters = FALSE;//S
 		if (strchr(blacklist,'q')) mHasFramebufferObject = FALSE;//S
 		if (strchr(blacklist,'r')) mHasDrawBuffers = FALSE;//S
@@ -1257,18 +1159,6 @@ void LLGLManager::initExtensions()
 	{
 		LL_INFOS("RenderInit") << "Couldn't initialize GL_ARB_point_parameters" << LL_ENDL;
 	}
-	if (!mHasShaderObjects)
-	{
-		LL_INFOS("RenderInit") << "Couldn't initialize GL_ARB_shader_objects" << LL_ENDL;
-	}
-	if (!mHasVertexShader)
-	{
-		LL_INFOS("RenderInit") << "Couldn't initialize GL_ARB_vertex_shader" << LL_ENDL;
-	}
-	if (!mHasFragmentShader)
-	{
-		LL_INFOS("RenderInit") << "Couldn't initialize GL_ARB_fragment_shader" << LL_ENDL;
-	}
 	if (!mHasBlendFuncSeparate)
 	{
 		LL_INFOS("RenderInit") << "Couldn't initialize GL_EXT_blend_func_separate" << LL_ENDL;
@@ -1284,14 +1174,7 @@ void LLGLManager::initExtensions()
 		LL_INFOS("RenderInit") << "Disabling mip-map generation for Intel GPUs" << LL_ENDL;
 		mHasMipMapGeneration = FALSE;
 	}
-#if !LL_DARWIN
-	if (mIsATI && mHasMipMapGeneration)
-	{
-		LL_INFOS("RenderInit") << "Disabling mip-map generation for ATI GPUs (performance opt)" << LL_ENDL;
-		mHasMipMapGeneration = FALSE;
-	}
-#endif
-	
+
 	// Misc
 	glGetIntegerv(GL_MAX_ELEMENTS_VERTICES, (GLint*) &mGLMaxVertexRange);
 	glGetIntegerv(GL_MAX_ELEMENTS_INDICES, (GLint*) &mGLMaxIndexRange);
@@ -1436,134 +1319,132 @@ void LLGLManager::initExtensions()
 		glPointParameterfARB = (PFNGLPOINTPARAMETERFARBPROC)GLH_EXT_GET_PROC_ADDRESS("glPointParameterfARB");
 		glPointParameterfvARB = (PFNGLPOINTPARAMETERFVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glPointParameterfvARB");
 	}
-	if (mHasShaderObjects)
-	{
-		glDeleteObjectARB = (PFNGLDELETEOBJECTARBPROC) GLH_EXT_GET_PROC_ADDRESS("glDeleteObjectARB");
-		glGetHandleARB = (PFNGLGETHANDLEARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetHandleARB");
-		glDetachObjectARB = (PFNGLDETACHOBJECTARBPROC) GLH_EXT_GET_PROC_ADDRESS("glDetachObjectARB");
-		glCreateShaderObjectARB = (PFNGLCREATESHADEROBJECTARBPROC) GLH_EXT_GET_PROC_ADDRESS("glCreateShaderObjectARB");
-		glShaderSourceARB = (PFNGLSHADERSOURCEARBPROC) GLH_EXT_GET_PROC_ADDRESS("glShaderSourceARB");
-		glCompileShaderARB = (PFNGLCOMPILESHADERARBPROC) GLH_EXT_GET_PROC_ADDRESS("glCompileShaderARB");
-		glCreateProgramObjectARB = (PFNGLCREATEPROGRAMOBJECTARBPROC) GLH_EXT_GET_PROC_ADDRESS("glCreateProgramObjectARB");
-		glAttachObjectARB = (PFNGLATTACHOBJECTARBPROC) GLH_EXT_GET_PROC_ADDRESS("glAttachObjectARB");
-		glLinkProgramARB = (PFNGLLINKPROGRAMARBPROC) GLH_EXT_GET_PROC_ADDRESS("glLinkProgramARB");
-		glUseProgramObjectARB = (PFNGLUSEPROGRAMOBJECTARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUseProgramObjectARB");
-		glValidateProgramARB = (PFNGLVALIDATEPROGRAMARBPROC) GLH_EXT_GET_PROC_ADDRESS("glValidateProgramARB");
-		glUniform1fARB = (PFNGLUNIFORM1FARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform1fARB");
-		glUniform2fARB = (PFNGLUNIFORM2FARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform2fARB");
-		glUniform3fARB = (PFNGLUNIFORM3FARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform3fARB");
-		glUniform4fARB = (PFNGLUNIFORM4FARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform4fARB");
-		glUniform1iARB = (PFNGLUNIFORM1IARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform1iARB");
-		glUniform2iARB = (PFNGLUNIFORM2IARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform2iARB");
-		glUniform3iARB = (PFNGLUNIFORM3IARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform3iARB");
-		glUniform4iARB = (PFNGLUNIFORM4IARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform4iARB");
-		glUniform1fvARB = (PFNGLUNIFORM1FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform1fvARB");
-		glUniform2fvARB = (PFNGLUNIFORM2FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform2fvARB");
-		glUniform3fvARB = (PFNGLUNIFORM3FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform3fvARB");
-		glUniform4fvARB = (PFNGLUNIFORM4FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform4fvARB");
-		glUniform1ivARB = (PFNGLUNIFORM1IVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform1ivARB");
-		glUniform2ivARB = (PFNGLUNIFORM2IVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform2ivARB");
-		glUniform3ivARB = (PFNGLUNIFORM3IVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform3ivARB");
-		glUniform4ivARB = (PFNGLUNIFORM4IVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform4ivARB");
-		glUniformMatrix2fvARB = (PFNGLUNIFORMMATRIX2FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniformMatrix2fvARB");
-		glUniformMatrix3fvARB = (PFNGLUNIFORMMATRIX3FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniformMatrix3fvARB");
-		glUniformMatrix3x4fv = (PFNGLUNIFORMMATRIX3X4FVPROC) GLH_EXT_GET_PROC_ADDRESS("glUniformMatrix3x4fv");
-		glUniformMatrix4fvARB = (PFNGLUNIFORMMATRIX4FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniformMatrix4fvARB");
-		glGetObjectParameterfvARB = (PFNGLGETOBJECTPARAMETERFVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetObjectParameterfvARB");
-		glGetObjectParameterivARB = (PFNGLGETOBJECTPARAMETERIVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetObjectParameterivARB");
-		glGetInfoLogARB = (PFNGLGETINFOLOGARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetInfoLogARB");
-		glGetAttachedObjectsARB = (PFNGLGETATTACHEDOBJECTSARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetAttachedObjectsARB");
-		glGetUniformLocationARB = (PFNGLGETUNIFORMLOCATIONARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetUniformLocationARB");
-		glGetActiveUniformARB = (PFNGLGETACTIVEUNIFORMARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetActiveUniformARB");
-		glGetUniformfvARB = (PFNGLGETUNIFORMFVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetUniformfvARB");
-		glGetUniformivARB = (PFNGLGETUNIFORMIVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetUniformivARB");
-		glGetShaderSourceARB = (PFNGLGETSHADERSOURCEARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetShaderSourceARB");
-	}
-	if (mHasVertexShader)
-	{
-		LL_INFOS() << "initExtensions() VertexShader-related procs..." << LL_ENDL;
-
-        // nSight doesn't support use of ARB funcs that have been normalized in the API
-        if (!LLRender::sNsightDebugSupport)
-        {
-		glGetAttribLocationARB = (PFNGLGETATTRIBLOCATIONARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetAttribLocationARB");
-		glBindAttribLocationARB = (PFNGLBINDATTRIBLOCATIONARBPROC) GLH_EXT_GET_PROC_ADDRESS("glBindAttribLocationARB");
-        }
-        else
-        {
-            glGetAttribLocationARB = (PFNGLGETATTRIBLOCATIONARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGetAttribLocation");
-            glBindAttribLocationARB = (PFNGLBINDATTRIBLOCATIONARBPROC)GLH_EXT_GET_PROC_ADDRESS("glBindAttribLocation");
-        }
 
-		glGetActiveAttribARB = (PFNGLGETACTIVEATTRIBARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetActiveAttribARB");
-		glVertexAttrib1dARB = (PFNGLVERTEXATTRIB1DARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1dARB");
-		glVertexAttrib1dvARB = (PFNGLVERTEXATTRIB1DVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1dvARB");
-		glVertexAttrib1fARB = (PFNGLVERTEXATTRIB1FARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1fARB");
-		glVertexAttrib1fvARB = (PFNGLVERTEXATTRIB1FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1fvARB");
-		glVertexAttrib1sARB = (PFNGLVERTEXATTRIB1SARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1sARB");
-		glVertexAttrib1svARB = (PFNGLVERTEXATTRIB1SVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1svARB");
-		glVertexAttrib2dARB = (PFNGLVERTEXATTRIB2DARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2dARB");
-		glVertexAttrib2dvARB = (PFNGLVERTEXATTRIB2DVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2dvARB");
-		glVertexAttrib2fARB = (PFNGLVERTEXATTRIB2FARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2fARB");
-		glVertexAttrib2fvARB = (PFNGLVERTEXATTRIB2FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2fvARB");
-		glVertexAttrib2sARB = (PFNGLVERTEXATTRIB2SARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2sARB");
-		glVertexAttrib2svARB = (PFNGLVERTEXATTRIB2SVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2svARB");
-		glVertexAttrib3dARB = (PFNGLVERTEXATTRIB3DARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3dARB");
-		glVertexAttrib3dvARB = (PFNGLVERTEXATTRIB3DVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3dvARB");
-		glVertexAttrib3fARB = (PFNGLVERTEXATTRIB3FARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3fARB");
-		glVertexAttrib3fvARB = (PFNGLVERTEXATTRIB3FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3fvARB");
-		glVertexAttrib3sARB = (PFNGLVERTEXATTRIB3SARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3sARB");
-		glVertexAttrib3svARB = (PFNGLVERTEXATTRIB3SVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3svARB");
-		glVertexAttrib4nbvARB = (PFNGLVERTEXATTRIB4NBVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4nbvARB");
-		glVertexAttrib4nivARB = (PFNGLVERTEXATTRIB4NIVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4nivARB");
-		glVertexAttrib4nsvARB = (PFNGLVERTEXATTRIB4NSVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4nsvARB");
-		glVertexAttrib4nubARB = (PFNGLVERTEXATTRIB4NUBARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4nubARB");
-		glVertexAttrib4nubvARB = (PFNGLVERTEXATTRIB4NUBVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4nubvARB");
-		glVertexAttrib4nuivARB = (PFNGLVERTEXATTRIB4NUIVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4nuivARB");
-		glVertexAttrib4nusvARB = (PFNGLVERTEXATTRIB4NUSVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4nusvARB");
-		glVertexAttrib4bvARB = (PFNGLVERTEXATTRIB4BVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4bvARB");
-		glVertexAttrib4dARB = (PFNGLVERTEXATTRIB4DARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4dARB");
-		glVertexAttrib4dvARB = (PFNGLVERTEXATTRIB4DVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4dvARB");
-		glVertexAttrib4fARB = (PFNGLVERTEXATTRIB4FARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4fARB");
-		glVertexAttrib4fvARB = (PFNGLVERTEXATTRIB4FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4fvARB");
-		glVertexAttrib4ivARB = (PFNGLVERTEXATTRIB4IVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4ivARB");
-		glVertexAttrib4sARB = (PFNGLVERTEXATTRIB4SARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4sARB");
-		glVertexAttrib4svARB = (PFNGLVERTEXATTRIB4SVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4svARB");
-		glVertexAttrib4ubvARB = (PFNGLVERTEXATTRIB4UBVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4ubvARB");
-		glVertexAttrib4uivARB = (PFNGLVERTEXATTRIB4UIVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4uivARB");
-		glVertexAttrib4usvARB = (PFNGLVERTEXATTRIB4USVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4usvARB");
-		glVertexAttribPointerARB = (PFNGLVERTEXATTRIBPOINTERARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttribPointerARB");
-		glVertexAttribIPointer = (PFNGLVERTEXATTRIBIPOINTERPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttribIPointer");
-		glEnableVertexAttribArrayARB = (PFNGLENABLEVERTEXATTRIBARRAYARBPROC) GLH_EXT_GET_PROC_ADDRESS("glEnableVertexAttribArrayARB");
-		glDisableVertexAttribArrayARB = (PFNGLDISABLEVERTEXATTRIBARRAYARBPROC) GLH_EXT_GET_PROC_ADDRESS("glDisableVertexAttribArrayARB");
-		glProgramStringARB = (PFNGLPROGRAMSTRINGARBPROC) GLH_EXT_GET_PROC_ADDRESS("glProgramStringARB");
-		glBindProgramARB = (PFNGLBINDPROGRAMARBPROC) GLH_EXT_GET_PROC_ADDRESS("glBindProgramARB");
-		glDeleteProgramsARB = (PFNGLDELETEPROGRAMSARBPROC) GLH_EXT_GET_PROC_ADDRESS("glDeleteProgramsARB");
-		glGenProgramsARB = (PFNGLGENPROGRAMSARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGenProgramsARB");
-		glProgramEnvParameter4dARB = (PFNGLPROGRAMENVPARAMETER4DARBPROC) GLH_EXT_GET_PROC_ADDRESS("glProgramEnvParameter4dARB");
-		glProgramEnvParameter4dvARB = (PFNGLPROGRAMENVPARAMETER4DVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glProgramEnvParameter4dvARB");
-		glProgramEnvParameter4fARB = (PFNGLPROGRAMENVPARAMETER4FARBPROC) GLH_EXT_GET_PROC_ADDRESS("glProgramEnvParameter4fARB");
-		glProgramEnvParameter4fvARB = (PFNGLPROGRAMENVPARAMETER4FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glProgramEnvParameter4fvARB");
-		glProgramLocalParameter4dARB = (PFNGLPROGRAMLOCALPARAMETER4DARBPROC) GLH_EXT_GET_PROC_ADDRESS("glProgramLocalParameter4dARB");
-		glProgramLocalParameter4dvARB = (PFNGLPROGRAMLOCALPARAMETER4DVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glProgramLocalParameter4dvARB");
-		glProgramLocalParameter4fARB = (PFNGLPROGRAMLOCALPARAMETER4FARBPROC) GLH_EXT_GET_PROC_ADDRESS("glProgramLocalParameter4fARB");
-		glProgramLocalParameter4fvARB = (PFNGLPROGRAMLOCALPARAMETER4FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glProgramLocalParameter4fvARB");
-		glGetProgramEnvParameterdvARB = (PFNGLGETPROGRAMENVPARAMETERDVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetProgramEnvParameterdvARB");
-		glGetProgramEnvParameterfvARB = (PFNGLGETPROGRAMENVPARAMETERFVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetProgramEnvParameterfvARB");
-		glGetProgramLocalParameterdvARB = (PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetProgramLocalParameterdvARB");
-		glGetProgramLocalParameterfvARB = (PFNGLGETPROGRAMLOCALPARAMETERFVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetProgramLocalParameterfvARB");
-		glGetProgramivARB = (PFNGLGETPROGRAMIVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetProgramivARB");
-		glGetProgramStringARB = (PFNGLGETPROGRAMSTRINGARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetProgramStringARB");
-		glGetVertexAttribdvARB = (PFNGLGETVERTEXATTRIBDVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetVertexAttribdvARB");
-		glGetVertexAttribfvARB = (PFNGLGETVERTEXATTRIBFVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetVertexAttribfvARB");
-		glGetVertexAttribivARB = (PFNGLGETVERTEXATTRIBIVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetVertexAttribivARB");
-		glGetVertexAttribPointervARB = (PFNGLGETVERTEXATTRIBPOINTERVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glgetVertexAttribPointervARB");
-		glIsProgramARB = (PFNGLISPROGRAMARBPROC) GLH_EXT_GET_PROC_ADDRESS("glIsProgramARB");
-	}
-	LL_DEBUGS("RenderInit") << "GL Probe: Got symbols" << LL_ENDL;
+    // Assume shader capabilities
+    glDeleteObjectARB         = (PFNGLDELETEOBJECTARBPROC) GLH_EXT_GET_PROC_ADDRESS("glDeleteObjectARB");
+    glGetHandleARB            = (PFNGLGETHANDLEARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetHandleARB");
+    glDetachObjectARB         = (PFNGLDETACHOBJECTARBPROC) GLH_EXT_GET_PROC_ADDRESS("glDetachObjectARB");
+    glCreateShaderObjectARB   = (PFNGLCREATESHADEROBJECTARBPROC) GLH_EXT_GET_PROC_ADDRESS("glCreateShaderObjectARB");
+    glShaderSourceARB         = (PFNGLSHADERSOURCEARBPROC) GLH_EXT_GET_PROC_ADDRESS("glShaderSourceARB");
+    glCompileShaderARB        = (PFNGLCOMPILESHADERARBPROC) GLH_EXT_GET_PROC_ADDRESS("glCompileShaderARB");
+    glCreateProgramObjectARB  = (PFNGLCREATEPROGRAMOBJECTARBPROC) GLH_EXT_GET_PROC_ADDRESS("glCreateProgramObjectARB");
+    glAttachObjectARB         = (PFNGLATTACHOBJECTARBPROC) GLH_EXT_GET_PROC_ADDRESS("glAttachObjectARB");
+    glLinkProgramARB          = (PFNGLLINKPROGRAMARBPROC) GLH_EXT_GET_PROC_ADDRESS("glLinkProgramARB");
+    glUseProgramObjectARB     = (PFNGLUSEPROGRAMOBJECTARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUseProgramObjectARB");
+    glValidateProgramARB      = (PFNGLVALIDATEPROGRAMARBPROC) GLH_EXT_GET_PROC_ADDRESS("glValidateProgramARB");
+    glUniform1fARB            = (PFNGLUNIFORM1FARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform1fARB");
+    glUniform2fARB            = (PFNGLUNIFORM2FARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform2fARB");
+    glUniform3fARB            = (PFNGLUNIFORM3FARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform3fARB");
+    glUniform4fARB            = (PFNGLUNIFORM4FARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform4fARB");
+    glUniform1iARB            = (PFNGLUNIFORM1IARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform1iARB");
+    glUniform2iARB            = (PFNGLUNIFORM2IARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform2iARB");
+    glUniform3iARB            = (PFNGLUNIFORM3IARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform3iARB");
+    glUniform4iARB            = (PFNGLUNIFORM4IARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform4iARB");
+    glUniform1fvARB           = (PFNGLUNIFORM1FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform1fvARB");
+    glUniform2fvARB           = (PFNGLUNIFORM2FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform2fvARB");
+    glUniform3fvARB           = (PFNGLUNIFORM3FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform3fvARB");
+    glUniform4fvARB           = (PFNGLUNIFORM4FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform4fvARB");
+    glUniform1ivARB           = (PFNGLUNIFORM1IVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform1ivARB");
+    glUniform2ivARB           = (PFNGLUNIFORM2IVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform2ivARB");
+    glUniform3ivARB           = (PFNGLUNIFORM3IVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform3ivARB");
+    glUniform4ivARB           = (PFNGLUNIFORM4IVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform4ivARB");
+    glUniformMatrix2fvARB     = (PFNGLUNIFORMMATRIX2FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniformMatrix2fvARB");
+    glUniformMatrix3fvARB     = (PFNGLUNIFORMMATRIX3FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniformMatrix3fvARB");
+    glUniformMatrix3x4fv      = (PFNGLUNIFORMMATRIX3X4FVPROC) GLH_EXT_GET_PROC_ADDRESS("glUniformMatrix3x4fv");
+    glUniformMatrix4fvARB     = (PFNGLUNIFORMMATRIX4FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniformMatrix4fvARB");
+    glGetObjectParameterfvARB = (PFNGLGETOBJECTPARAMETERFVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetObjectParameterfvARB");
+    glGetObjectParameterivARB = (PFNGLGETOBJECTPARAMETERIVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetObjectParameterivARB");
+    glGetInfoLogARB           = (PFNGLGETINFOLOGARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetInfoLogARB");
+    glGetAttachedObjectsARB   = (PFNGLGETATTACHEDOBJECTSARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetAttachedObjectsARB");
+    glGetUniformLocationARB   = (PFNGLGETUNIFORMLOCATIONARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetUniformLocationARB");
+    glGetActiveUniformARB     = (PFNGLGETACTIVEUNIFORMARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetActiveUniformARB");
+    glGetUniformfvARB         = (PFNGLGETUNIFORMFVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetUniformfvARB");
+    glGetUniformivARB         = (PFNGLGETUNIFORMIVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetUniformivARB");
+    glGetShaderSourceARB      = (PFNGLGETSHADERSOURCEARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetShaderSourceARB");
+
+    LL_INFOS() << "initExtensions() VertexShader-related procs..." << LL_ENDL;
+
+    // nSight doesn't support use of ARB funcs that have been normalized in the API
+    if (!LLRender::sNsightDebugSupport)
+    {
+        glGetAttribLocationARB  = (PFNGLGETATTRIBLOCATIONARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetAttribLocationARB");
+        glBindAttribLocationARB = (PFNGLBINDATTRIBLOCATIONARBPROC) GLH_EXT_GET_PROC_ADDRESS("glBindAttribLocationARB");
+    }
+    else
+    {
+        glGetAttribLocationARB  = (PFNGLGETATTRIBLOCATIONARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetAttribLocation");
+        glBindAttribLocationARB = (PFNGLBINDATTRIBLOCATIONARBPROC) GLH_EXT_GET_PROC_ADDRESS("glBindAttribLocation");
+    }
+
+    glGetActiveAttribARB            = (PFNGLGETACTIVEATTRIBARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetActiveAttribARB");
+    glVertexAttrib1dARB             = (PFNGLVERTEXATTRIB1DARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1dARB");
+    glVertexAttrib1dvARB            = (PFNGLVERTEXATTRIB1DVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1dvARB");
+    glVertexAttrib1fARB             = (PFNGLVERTEXATTRIB1FARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1fARB");
+    glVertexAttrib1fvARB            = (PFNGLVERTEXATTRIB1FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1fvARB");
+    glVertexAttrib1sARB             = (PFNGLVERTEXATTRIB1SARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1sARB");
+    glVertexAttrib1svARB            = (PFNGLVERTEXATTRIB1SVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1svARB");
+    glVertexAttrib2dARB             = (PFNGLVERTEXATTRIB2DARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2dARB");
+    glVertexAttrib2dvARB            = (PFNGLVERTEXATTRIB2DVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2dvARB");
+    glVertexAttrib2fARB             = (PFNGLVERTEXATTRIB2FARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2fARB");
+    glVertexAttrib2fvARB            = (PFNGLVERTEXATTRIB2FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2fvARB");
+    glVertexAttrib2sARB             = (PFNGLVERTEXATTRIB2SARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2sARB");
+    glVertexAttrib2svARB            = (PFNGLVERTEXATTRIB2SVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2svARB");
+    glVertexAttrib3dARB             = (PFNGLVERTEXATTRIB3DARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3dARB");
+    glVertexAttrib3dvARB            = (PFNGLVERTEXATTRIB3DVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3dvARB");
+    glVertexAttrib3fARB             = (PFNGLVERTEXATTRIB3FARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3fARB");
+    glVertexAttrib3fvARB            = (PFNGLVERTEXATTRIB3FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3fvARB");
+    glVertexAttrib3sARB             = (PFNGLVERTEXATTRIB3SARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3sARB");
+    glVertexAttrib3svARB            = (PFNGLVERTEXATTRIB3SVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3svARB");
+    glVertexAttrib4nbvARB           = (PFNGLVERTEXATTRIB4NBVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4nbvARB");
+    glVertexAttrib4nivARB           = (PFNGLVERTEXATTRIB4NIVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4nivARB");
+    glVertexAttrib4nsvARB           = (PFNGLVERTEXATTRIB4NSVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4nsvARB");
+    glVertexAttrib4nubARB           = (PFNGLVERTEXATTRIB4NUBARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4nubARB");
+    glVertexAttrib4nubvARB          = (PFNGLVERTEXATTRIB4NUBVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4nubvARB");
+    glVertexAttrib4nuivARB          = (PFNGLVERTEXATTRIB4NUIVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4nuivARB");
+    glVertexAttrib4nusvARB          = (PFNGLVERTEXATTRIB4NUSVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4nusvARB");
+    glVertexAttrib4bvARB            = (PFNGLVERTEXATTRIB4BVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4bvARB");
+    glVertexAttrib4dARB             = (PFNGLVERTEXATTRIB4DARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4dARB");
+    glVertexAttrib4dvARB            = (PFNGLVERTEXATTRIB4DVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4dvARB");
+    glVertexAttrib4fARB             = (PFNGLVERTEXATTRIB4FARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4fARB");
+    glVertexAttrib4fvARB            = (PFNGLVERTEXATTRIB4FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4fvARB");
+    glVertexAttrib4ivARB            = (PFNGLVERTEXATTRIB4IVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4ivARB");
+    glVertexAttrib4sARB             = (PFNGLVERTEXATTRIB4SARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4sARB");
+    glVertexAttrib4svARB            = (PFNGLVERTEXATTRIB4SVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4svARB");
+    glVertexAttrib4ubvARB           = (PFNGLVERTEXATTRIB4UBVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4ubvARB");
+    glVertexAttrib4uivARB           = (PFNGLVERTEXATTRIB4UIVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4uivARB");
+    glVertexAttrib4usvARB           = (PFNGLVERTEXATTRIB4USVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4usvARB");
+    glVertexAttribPointerARB        = (PFNGLVERTEXATTRIBPOINTERARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttribPointerARB");
+    glVertexAttribIPointer          = (PFNGLVERTEXATTRIBIPOINTERPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttribIPointer");
+    glEnableVertexAttribArrayARB    = (PFNGLENABLEVERTEXATTRIBARRAYARBPROC) GLH_EXT_GET_PROC_ADDRESS("glEnableVertexAttribArrayARB");
+    glDisableVertexAttribArrayARB   = (PFNGLDISABLEVERTEXATTRIBARRAYARBPROC) GLH_EXT_GET_PROC_ADDRESS("glDisableVertexAttribArrayARB");
+    glProgramStringARB              = (PFNGLPROGRAMSTRINGARBPROC) GLH_EXT_GET_PROC_ADDRESS("glProgramStringARB");
+    glBindProgramARB                = (PFNGLBINDPROGRAMARBPROC) GLH_EXT_GET_PROC_ADDRESS("glBindProgramARB");
+    glDeleteProgramsARB             = (PFNGLDELETEPROGRAMSARBPROC) GLH_EXT_GET_PROC_ADDRESS("glDeleteProgramsARB");
+    glGenProgramsARB                = (PFNGLGENPROGRAMSARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGenProgramsARB");
+    glProgramEnvParameter4dARB      = (PFNGLPROGRAMENVPARAMETER4DARBPROC) GLH_EXT_GET_PROC_ADDRESS("glProgramEnvParameter4dARB");
+    glProgramEnvParameter4dvARB     = (PFNGLPROGRAMENVPARAMETER4DVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glProgramEnvParameter4dvARB");
+    glProgramEnvParameter4fARB      = (PFNGLPROGRAMENVPARAMETER4FARBPROC) GLH_EXT_GET_PROC_ADDRESS("glProgramEnvParameter4fARB");
+    glProgramEnvParameter4fvARB     = (PFNGLPROGRAMENVPARAMETER4FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glProgramEnvParameter4fvARB");
+    glProgramLocalParameter4dARB    = (PFNGLPROGRAMLOCALPARAMETER4DARBPROC) GLH_EXT_GET_PROC_ADDRESS("glProgramLocalParameter4dARB");
+    glProgramLocalParameter4dvARB   = (PFNGLPROGRAMLOCALPARAMETER4DVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glProgramLocalParameter4dvARB");
+    glProgramLocalParameter4fARB    = (PFNGLPROGRAMLOCALPARAMETER4FARBPROC) GLH_EXT_GET_PROC_ADDRESS("glProgramLocalParameter4fARB");
+    glProgramLocalParameter4fvARB   = (PFNGLPROGRAMLOCALPARAMETER4FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glProgramLocalParameter4fvARB");
+    glGetProgramEnvParameterdvARB   = (PFNGLGETPROGRAMENVPARAMETERDVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetProgramEnvParameterdvARB");
+    glGetProgramEnvParameterfvARB   = (PFNGLGETPROGRAMENVPARAMETERFVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetProgramEnvParameterfvARB");
+    glGetProgramLocalParameterdvARB = (PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetProgramLocalParameterdvARB");
+    glGetProgramLocalParameterfvARB = (PFNGLGETPROGRAMLOCALPARAMETERFVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetProgramLocalParameterfvARB");
+    glGetProgramivARB               = (PFNGLGETPROGRAMIVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetProgramivARB");
+    glGetProgramStringARB           = (PFNGLGETPROGRAMSTRINGARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetProgramStringARB");
+    glGetVertexAttribdvARB          = (PFNGLGETVERTEXATTRIBDVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetVertexAttribdvARB");
+    glGetVertexAttribfvARB          = (PFNGLGETVERTEXATTRIBFVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetVertexAttribfvARB");
+    glGetVertexAttribivARB          = (PFNGLGETVERTEXATTRIBIVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetVertexAttribivARB");
+    glGetVertexAttribPointervARB    = (PFNGLGETVERTEXATTRIBPOINTERVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glgetVertexAttribPointervARB");
+    glIsProgramARB                  = (PFNGLISPROGRAMARBPROC) GLH_EXT_GET_PROC_ADDRESS("glIsProgramARB");
+
+    LL_DEBUGS("RenderInit") << "GL Probe: Got symbols" << LL_ENDL;
 #endif
 
-	mInited = TRUE;
+    mInited = TRUE;
 }
 
 void rotate_quat(LLQuaternion& rotation)
@@ -1974,206 +1855,30 @@ void LLGLState::checkTextureChannels(const std::string& msg)
 #endif
 }
 
-void LLGLState::checkClientArrays(const std::string& msg, U32 data_mask)
-{
-	if (!gDebugGL || LLGLSLShader::sNoFixedFunction)
-	{
-		return;
-	}
-
-	stop_glerror();
-	BOOL error = FALSE;
-
-	GLint active_texture;
-	glGetIntegerv(GL_CLIENT_ACTIVE_TEXTURE_ARB, &active_texture);
-
-	if (active_texture != GL_TEXTURE0_ARB)
-	{
-		LL_WARNS() << "Client active texture corrupted: " << active_texture << LL_ENDL;
-		if (gDebugSession)
-		{
-			gFailLog << "Client active texture corrupted: " << active_texture << std::endl;
-		}
-		error = TRUE;
-	}
-
-	/*glGetIntegerv(GL_ACTIVE_TEXTURE_ARB, &active_texture);
-	if (active_texture != GL_TEXTURE0_ARB)
-	{
-		LL_WARNS() << "Active texture corrupted: " << active_texture << LL_ENDL;
-		if (gDebugSession)
-		{
-			gFailLog << "Active texture corrupted: " << active_texture << std::endl;
-		}
-		error = TRUE;
-	}*/
-
-	static const char* label[] =
-	{
-		"GL_VERTEX_ARRAY",
-		"GL_NORMAL_ARRAY",
-		"GL_COLOR_ARRAY",
-		"GL_TEXTURE_COORD_ARRAY"
-	};
-
-	static GLint value[] =
-	{
-		GL_VERTEX_ARRAY,
-		GL_NORMAL_ARRAY,
-		GL_COLOR_ARRAY,
-		GL_TEXTURE_COORD_ARRAY
-	};
-
-	static const U32 mask[] = 
-	{ //copied from llvertexbuffer.h
-		0x0001, //MAP_VERTEX,
-		0x0002, //MAP_NORMAL,
-		0x0010, //MAP_COLOR,
-		0x0004, //MAP_TEXCOORD
-	};
-
-
-	for (S32 j = 1; j < 4; j++)
-	{
-		if (glIsEnabled(value[j]))
-		{
-			if (!(mask[j] & data_mask))
-			{
-				error = TRUE;
-				LL_WARNS("RenderState") << "GL still has " << label[j] << " enabled." << LL_ENDL;
-				if (gDebugSession)
-				{
-					gFailLog << "GL still has " << label[j] << " enabled." << std::endl;
-				}
-			}
-		}
-		else
-		{
-			if (mask[j] & data_mask)
-			{
-				error = TRUE;
-				LL_WARNS("RenderState") << "GL does not have " << label[j] << " enabled." << LL_ENDL;
-				if (gDebugSession)
-				{
-					gFailLog << "GL does not have " << label[j] << " enabled." << std::endl;
-				}
-			}
-		}
-	}
-
-	glClientActiveTextureARB(GL_TEXTURE1_ARB);
-	gGL.getTexUnit(1)->activate();
-	if (glIsEnabled(GL_TEXTURE_COORD_ARRAY))
-	{
-		if (!(data_mask & 0x0008))
-		{
-			error = TRUE;
-			LL_WARNS("RenderState") << "GL still has GL_TEXTURE_COORD_ARRAY enabled on channel 1." << LL_ENDL;
-			if (gDebugSession)
-			{
-				gFailLog << "GL still has GL_TEXTURE_COORD_ARRAY enabled on channel 1." << std::endl;
-			}
-		}
-	}
-	else
-	{
-		if (data_mask & 0x0008)
-		{
-			error = TRUE;
-			LL_WARNS("RenderState") << "GL does not have GL_TEXTURE_COORD_ARRAY enabled on channel 1." << LL_ENDL;
-			if (gDebugSession)
-			{
-				gFailLog << "GL does not have GL_TEXTURE_COORD_ARRAY enabled on channel 1." << std::endl;
-			}
-		}
-	}
-
-	/*if (glIsEnabled(GL_TEXTURE_2D))
-	{
-		if (!(data_mask & 0x0008))
-		{
-			error = TRUE;
-			LL_WARNS("RenderState") << "GL still has GL_TEXTURE_2D enabled on channel 1." << LL_ENDL;
-			if (gDebugSession)
-			{
-				gFailLog << "GL still has GL_TEXTURE_2D enabled on channel 1." << std::endl;
-			}
-		}
-	}
-	else
-	{
-		if (data_mask & 0x0008)
-		{
-			error = TRUE;
-			LL_WARNS("RenderState") << "GL does not have GL_TEXTURE_2D enabled on channel 1." << LL_ENDL;
-			if (gDebugSession)
-			{
-				gFailLog << "GL does not have GL_TEXTURE_2D enabled on channel 1." << std::endl;
-			}
-		}
-	}*/
-
-	glClientActiveTextureARB(GL_TEXTURE0_ARB);
-	gGL.getTexUnit(0)->activate();
-
-	if (gGLManager.mHasVertexShader && LLGLSLShader::sNoFixedFunction)
-	{	//make sure vertex attribs are all disabled
-		GLint count;
-		glGetIntegerv(GL_MAX_VERTEX_ATTRIBS_ARB, &count);
-		for (GLint i = 0; i < count; i++)
-		{
-			GLint enabled;
-			glGetVertexAttribivARB((GLuint) i, GL_VERTEX_ATTRIB_ARRAY_ENABLED_ARB, &enabled);
-			if (enabled)
-			{
-				error = TRUE;
-				LL_WARNS("RenderState") << "GL still has vertex attrib array " << i << " enabled." << LL_ENDL;
-				if (gDebugSession)
-				{
-					gFailLog <<  "GL still has vertex attrib array " << i << " enabled." << std::endl;
-				}
-			}
-		}
-	}
-
-	if (error)
-	{
-		if (gDebugSession)
-		{
-			ll_fail("LLGLState::checkClientArrays failed.");
-		}
-		else
-		{
-			LL_GL_ERRS << "GL client array corruption detected.  " << msg << LL_ENDL;
-		}
-	}
-}
-
 ///////////////////////////////////////////////////////////////////////
 
 LLGLState::LLGLState(LLGLenum state, S32 enabled) :
 	mState(state), mWasEnabled(FALSE), mIsEnabled(FALSE)
 {
-	if (LLGLSLShader::sNoFixedFunction)
-	{ //always ignore state that's deprecated post GL 3.0
-		switch (state)
-		{
-			case GL_ALPHA_TEST:
-			case GL_NORMALIZE:
-			case GL_TEXTURE_GEN_R:
-			case GL_TEXTURE_GEN_S:
-			case GL_TEXTURE_GEN_T:
-			case GL_TEXTURE_GEN_Q:
-			case GL_LIGHTING:
-			case GL_COLOR_MATERIAL:
-			case GL_FOG:
-			case GL_LINE_STIPPLE:
-			case GL_POLYGON_STIPPLE:
-				mState = 0;
-				break;
-		}
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
+	switch (state)
+	{
+		case GL_ALPHA_TEST:
+		case GL_NORMALIZE:
+		case GL_TEXTURE_GEN_R:
+		case GL_TEXTURE_GEN_S:
+		case GL_TEXTURE_GEN_T:
+		case GL_TEXTURE_GEN_Q:
+		case GL_LIGHTING:
+		case GL_COLOR_MATERIAL:
+		case GL_FOG:
+		case GL_LINE_STIPPLE:
+		case GL_POLYGON_STIPPLE:
+			mState = 0;
+			break;
 	}
 
+
 	stop_glerror();
 	if (mState)
 	{
@@ -2212,6 +1917,7 @@ void LLGLState::setEnabled(S32 enabled)
 
 LLGLState::~LLGLState() 
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
 	stop_glerror();
 	if (mState)
 	{
@@ -2398,7 +2104,8 @@ LLGLUserClipPlane::LLGLUserClipPlane(const LLPlane& p, const glh::matrix4f& mode
 		mModelview = modelview;
 		mProjection = projection;
 
-		setPlane(p[0], p[1], p[2], p[3]);
+        //flip incoming LLPlane to get consistent behavior compared to frustum culling
+		setPlane(-p[0], -p[1], -p[2], -p[3]);
 	}
 }
 
@@ -2444,94 +2151,6 @@ LLGLUserClipPlane::~LLGLUserClipPlane()
 	disable();
 }
 
-LLGLNamePool::LLGLNamePool()
-{
-}
-
-LLGLNamePool::~LLGLNamePool()
-{
-}
-
-void LLGLNamePool::upkeep()
-{
-	std::sort(mNameList.begin(), mNameList.end(), CompareUsed());
-}
-
-void LLGLNamePool::cleanup()
-{
-	for (name_list_t::iterator iter = mNameList.begin(); iter != mNameList.end(); ++iter)
-	{
-		releaseName(iter->name);
-	}
-
-	mNameList.clear();
-}
-
-GLuint LLGLNamePool::allocate()
-{
-#if LL_GL_NAME_POOLING
-	for (name_list_t::iterator iter = mNameList.begin(); iter != mNameList.end(); ++iter)
-	{
-		if (!iter->used)
-		{
-			iter->used = TRUE;
-			return iter->name;
-		}
-	}
-
-	NameEntry entry;
-	entry.name = allocateName();
-	entry.used = TRUE;
-	mNameList.push_back(entry);
-
-	return entry.name;
-#else
-	return allocateName();
-#endif
-}
-
-void LLGLNamePool::release(GLuint name)
-{
-#if LL_GL_NAME_POOLING
-	for (name_list_t::iterator iter = mNameList.begin(); iter != mNameList.end(); ++iter)
-	{
-		if (iter->name == name)
-		{
-			if (iter->used)
-			{
-				iter->used = FALSE;
-				return;
-			}
-			else
-			{
-				LL_ERRS() << "Attempted to release a pooled name that is not in use!" << LL_ENDL;
-			}
-		}
-	}
-	LL_ERRS() << "Attempted to release a non pooled name!" << LL_ENDL;
-#else
-	releaseName(name);
-#endif
-}
-
-//static
-void LLGLNamePool::upkeepPools()
-{
-	for (auto& pool : instance_snapshot())
-	{
-		pool.upkeep();
-	}
-}
-
-//static
-void LLGLNamePool::cleanupPools()
-{
-	for (auto& pool : instance_snapshot())
-	{
-		pool.cleanup();
-	}
-}
-
 LLGLDepthTest::LLGLDepthTest(GLboolean depth_enabled, GLboolean write_enabled, GLenum depth_func)
 : mPrevDepthEnabled(sDepthEnabled), mPrevDepthFunc(sDepthFunc), mPrevWriteEnabled(sWriteEnabled)
 {
@@ -2723,22 +2342,10 @@ LLGLSPipelineSkyBox::LLGLSPipelineSkyBox()
 , mCullFace(GL_CULL_FACE)
 , mSquashClip()
 { 
-    if (!LLGLSLShader::sNoFixedFunction)
-    {
-        glDisable(GL_LIGHTING);
-        glDisable(GL_FOG);
-        glDisable(GL_CLIP_PLANE0);
-    }
 }
 
 LLGLSPipelineSkyBox::~LLGLSPipelineSkyBox()
 {
-    if (!LLGLSLShader::sNoFixedFunction)
-    {
-        glEnable(GL_LIGHTING);
-        glEnable(GL_FOG);
-        glEnable(GL_CLIP_PLANE0);
-    }
 }
 
 LLGLSPipelineDepthTestSkyBox::LLGLSPipelineDepthTestSkyBox(bool depth_test, bool depth_write)
@@ -2765,3 +2372,4 @@ extern "C"
 }
 #endif
 
+
diff --git a/indra/llrender/llgl.h b/indra/llrender/llgl.h
index a07e2d9bb02871a8a724fa00c0d46ebd00fb1335..33cb0706c45dfd489d31d4d38d8a34828073a407 100644
--- a/indra/llrender/llgl.h
+++ b/indra/llrender/llgl.h
@@ -47,6 +47,7 @@
 
 extern BOOL gDebugGL;
 extern BOOL gDebugSession;
+extern BOOL gDebugGLSession;
 extern llofstream gFailLog;
 
 #define LL_GL_ERRS LL_ERRS("RenderState")
@@ -94,9 +95,6 @@ class LLGLManager
 	BOOL mHasMapBufferRange;
 	BOOL mHasFlushBufferRange;
 	BOOL mHasPBuffer;
-	BOOL mHasShaderObjects;
-	BOOL mHasVertexShader;
-	BOOL mHasFragmentShader;
 	S32  mNumTextureImageUnits;
 	BOOL mHasOcclusionQuery;
 	BOOL mHasTimerQuery;
@@ -122,14 +120,9 @@ class LLGLManager
     BOOL mHasTexturesRGBDecode;
 
 	// Vendor-specific extensions
-	BOOL mIsATI;
+	BOOL mIsAMD;
 	BOOL mIsNVIDIA;
 	BOOL mIsIntel;
-	BOOL mIsGF2or4MX;
-	BOOL mIsGF3;
-	BOOL mIsGFFX;
-	BOOL mATIOffsetVerticalLines;
-	BOOL mATIOldDriver;
 
 #if LL_DARWIN
 	// Needed to distinguish problem cards on older Macs that break with Materials
@@ -269,7 +262,6 @@ class LLGLState
 	static void dumpStates();
 	static void checkStates(const std::string& msg = "");
 	static void checkTextureChannels(const std::string& msg = "");
-	static void checkClientArrays(const std::string& msg = "", U32 data_mask = 0);
 	
 protected:
 	static boost::unordered_map<LLGLenum, LLGLboolean> sStateMap;
@@ -375,51 +367,6 @@ class LLGLSquashToFarClip
 	~LLGLSquashToFarClip();
 };
 
-/*
-	Generic pooling scheme for things which use GL names (used for occlusion queries and vertex buffer objects).
-	Prevents thrashing of GL name caches by avoiding calls to glGenFoo and glDeleteFoo.
-*/
-class LLGLNamePool : public LLInstanceTracker<LLGLNamePool>
-{
-public:
-	typedef LLInstanceTracker<LLGLNamePool> tracker_t;
-
-	struct NameEntry
-	{
-		GLuint name;
-		BOOL used;
-	};
-
-	struct CompareUsed
-	{
-		bool operator()(const NameEntry& lhs, const NameEntry& rhs)
-		{
-			return lhs.used < rhs.used;  //FALSE entries first
-		}
-	};
-
-	typedef std::vector<NameEntry> name_list_t;
-	name_list_t mNameList;
-
-	LLGLNamePool();
-	virtual ~LLGLNamePool();
-	
-	void upkeep();
-	void cleanup();
-	
-	GLuint allocate();
-	void release(GLuint name);
-	
-	static void upkeepPools();
-	static void cleanupPools();
-
-protected:
-	typedef std::vector<LLGLNamePool*> pool_list_t;
-	
-	virtual GLuint allocateName() = 0;
-	virtual void releaseName(GLuint name) = 0;
-};
-
 /*
 	Interface for objects that need periodic GL updates applied to them.
 	Used to synchronize GL updates with GL thread.
@@ -488,6 +435,7 @@ void parse_gl_version( S32* major, S32* minor, S32* release, std::string* vendor
 
 extern BOOL gClothRipple;
 extern BOOL gHeadlessClient;
+extern BOOL gNonInteractive;
 extern BOOL gGLActive;
 
 // Deal with changing glext.h definitions for newer SDK versions, specifically
diff --git a/indra/llrender/llglheaders.h b/indra/llrender/llglheaders.h
index 6bca3623e09c101b01656bd505355062a6acbff2..3d93cc076274147609a287f7ddc731036c0a1671 100644
--- a/indra/llrender/llglheaders.h
+++ b/indra/llrender/llglheaders.h
@@ -812,4 +812,23 @@ extern void glGetBufferPointervARB (GLenum, GLenum, GLvoid* *);
 #define GL_RENDERBUFFER_FREE_MEMORY_ATI            0x87FD
 #endif
 
+#if defined(TRACY_ENABLE) && LL_PROFILER_ENABLE_TRACY_OPENGL
+    // Tracy uses the following:
+    //    glGenQueries
+    //    glGetQueryiv
+    //    glGetQueryObjectiv
+    #define glGenQueries        glGenQueriesARB
+    #define glGetQueryiv        glGetQueryivARB
+    #define glGetQueryObjectiv  glGetQueryObjectivARB
+    #include <tracy/TracyOpenGL.hpp>
+
+    #define LL_PROFILER_GPU_ZONEC(name,color) TracyGpuZoneC(name,color);
+    #define LL_PROFILER_GPU_COLLECT           TracyGpuCollect
+    #define LL_PROFILER_GPU_CONTEXT           TracyGpuContext
+#else
+    #define LL_PROFILER_GPU_ZONEC(name,color) (void)name;(void)color;
+    #define LL_PROFILER_GPU_COLLECT
+    #define LL_PROFILER_GPU_CONTEXT
+#endif
+
 #endif // LL_LLGLHEADERS_H
diff --git a/indra/llrender/llglslshader.cpp b/indra/llrender/llglslshader.cpp
index 4351f6e2c86cdde783f128c835c95f4f6f4e4604..185c1450c879879b6d2bd27cd5629fddd990f39e 100644
--- a/indra/llrender/llglslshader.cpp
+++ b/indra/llrender/llglslshader.cpp
@@ -50,7 +50,6 @@ using std::string;
 GLhandleARB LLGLSLShader::sCurBoundShader = 0;
 LLGLSLShader* LLGLSLShader::sCurBoundShaderPtr = NULL;
 S32 LLGLSLShader::sIndexedTextureChannels = 0;
-bool LLGLSLShader::sNoFixedFunction = false;
 bool LLGLSLShader::sProfileEnabled = false;
 std::set<LLGLSLShader*> LLGLSLShader::sInstances;
 U64 LLGLSLShader::sTotalTimeElapsed = 0;
@@ -208,6 +207,7 @@ void LLGLSLShader::dumpStats()
 //static
 void LLGLSLShader::startProfile()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
     if (sProfileEnabled && sCurBoundShaderPtr)
     {
         sCurBoundShaderPtr->placeProfileQuery();
@@ -218,6 +218,7 @@ void LLGLSLShader::startProfile()
 //static
 void LLGLSLShader::stopProfile(U32 count, U32 mode)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
     if (sProfileEnabled && sCurBoundShaderPtr)
     {
         sCurBoundShaderPtr->readProfileQuery(count, mode);
@@ -384,6 +385,8 @@ BOOL LLGLSLShader::createShader(std::vector<LLStaticHashedString> * attributes,
                                 U32 varying_count,
                                 const char** varyings)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
+
     unloadInternal();
 
     sInstances.insert(this);
@@ -588,6 +591,8 @@ void LLGLSLShader::attachObjects(GLhandleARB* objects, S32 count)
 
 BOOL LLGLSLShader::mapAttributes(const std::vector<LLStaticHashedString> * attributes)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
+
     //before linking, make sure reserved attributes always have consistent locations
     for (U32 i = 0; i < LLShaderMgr::instance()->mReservedAttribs.size(); i++)
     {
@@ -649,6 +654,8 @@ BOOL LLGLSLShader::mapAttributes(const std::vector<LLStaticHashedString> * attri
 
 void LLGLSLShader::mapUniform(GLint index, const vector<LLStaticHashedString> * uniforms)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
+
     if (index == -1)
     {
         return;
@@ -770,6 +777,8 @@ void LLGLSLShader::removePermutation(std::string name)
 
 GLint LLGLSLShader::mapUniformTextureChannel(GLint location, GLenum type)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
+
     if ((type >= GL_SAMPLER_1D_ARB && type <= GL_SAMPLER_2D_RECT_SHADOW_ARB) ||
         type == GL_SAMPLER_2D_MULTISAMPLE)
     {   //this here is a texture
@@ -782,7 +791,9 @@ GLint LLGLSLShader::mapUniformTextureChannel(GLint location, GLenum type)
 
 BOOL LLGLSLShader::mapUniforms(const vector<LLStaticHashedString> * uniforms)
 {
-	BOOL res = TRUE;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
+
+    BOOL res = TRUE;
 
 	mTotalUniformSize = 0;
 	mActiveTextureChannels = 0;
@@ -925,6 +936,8 @@ BOOL LLGLSLShader::mapUniforms(const vector<LLStaticHashedString> * uniforms)
 
 BOOL LLGLSLShader::link(BOOL suppress_errors)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
+
     BOOL success = LLShaderMgr::instance()->linkProgramObject(mProgramObject, suppress_errors);
 
     if (!success && !suppress_errors)
@@ -937,56 +950,65 @@ BOOL LLGLSLShader::link(BOOL suppress_errors)
 
 void LLGLSLShader::bind()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
+
     gGL.flush();
-    if (gGLManager.mHasShaderObjects)
+
+    if (sCurBoundShader != mProgramObject)  // Don't re-bind current shader
     {
         LLVertexBuffer::unbind();
         glUseProgramObjectARB(mProgramObject);
         sCurBoundShader = mProgramObject;
         sCurBoundShaderPtr = this;
-        if (mUniformsDirty)
-        {
-            LLShaderMgr::instance()->updateShaderUniforms(this);
-            mUniformsDirty = FALSE;
-        }
+    }
+
+    if (mUniformsDirty)
+    {
+        LLShaderMgr::instance()->updateShaderUniforms(this);
+        mUniformsDirty = FALSE;
     }
 }
 
-void LLGLSLShader::unbind()
+void LLGLSLShader::bind(bool rigged)
 {
-    gGL.flush();
-    if (gGLManager.mHasShaderObjects)
+    if (rigged)
     {
-        stop_glerror();
-        if (gGLManager.mIsNVIDIA)
-        {
-            for (U32 i = 0; i < mAttribute.size(); ++i)
-            {
-                vertexAttrib4f(i, 0,0,0,1);
-                stop_glerror();
-            }
-        }
-        LLVertexBuffer::unbind();
-        glUseProgramObjectARB(0);
-        sCurBoundShader = 0;
-        sCurBoundShaderPtr = NULL;
-        stop_glerror();
+        llassert(mRiggedVariant);
+        mRiggedVariant->bind();
+    }
+    else
+    {
+        bind();
     }
 }
 
+void LLGLSLShader::unbind()
+{
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
+
+    gGL.flush();
+    stop_glerror();
+    LLVertexBuffer::unbind();
+    glUseProgramObjectARB(0);
+    sCurBoundShader = 0;
+    sCurBoundShaderPtr = NULL;
+    stop_glerror();
+}
+
 void LLGLSLShader::bindNoShader(void)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
+
     LLVertexBuffer::unbind();
-    if (gGLManager.mHasShaderObjects)
-    {
-        glUseProgramObjectARB(0);
-        sCurBoundShader = 0;
-        sCurBoundShaderPtr = NULL;
-    }
+    glUseProgramObjectARB(0);
+    sCurBoundShader = 0;
+    sCurBoundShaderPtr = NULL;
 }
 
 S32 LLGLSLShader::bindTexture(const std::string &uniform, LLTexture *texture, LLTexUnit::eTextureType mode, LLTexUnit::eTextureColorSpace colorspace)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
+
     S32 channel = 0;
     channel = getUniformLocation(uniform);
     
@@ -995,6 +1017,8 @@ S32 LLGLSLShader::bindTexture(const std::string &uniform, LLTexture *texture, LL
 
 S32 LLGLSLShader::bindTexture(S32 uniform, LLTexture *texture, LLTexUnit::eTextureType mode, LLTexUnit::eTextureColorSpace colorspace)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
+
     if (uniform < 0 || uniform >= (S32)mTexture.size())
     {
         LL_SHADER_UNIFORM_ERRS() << "Uniform out of range: " << uniform << LL_ENDL;
@@ -1005,7 +1029,7 @@ S32 LLGLSLShader::bindTexture(S32 uniform, LLTexture *texture, LLTexUnit::eTextu
     
     if (uniform > -1)
     {
-        gGL.getTexUnit(uniform)->bind(texture, mode);
+        gGL.getTexUnit(uniform)->bindFast(texture);
         gGL.getTexUnit(uniform)->setTextureColorSpace(colorspace);
     }
     
@@ -1014,6 +1038,8 @@ S32 LLGLSLShader::bindTexture(S32 uniform, LLTexture *texture, LLTexUnit::eTextu
 
 S32 LLGLSLShader::unbindTexture(const std::string &uniform, LLTexUnit::eTextureType mode)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
+
     S32 channel = 0;
     channel = getUniformLocation(uniform);
     
@@ -1022,6 +1048,8 @@ S32 LLGLSLShader::unbindTexture(const std::string &uniform, LLTexUnit::eTextureT
 
 S32 LLGLSLShader::unbindTexture(S32 uniform, LLTexUnit::eTextureType mode)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
+
     if (uniform < 0 || uniform >= (S32)mTexture.size())
     {
         LL_SHADER_UNIFORM_ERRS() << "Uniform out of range: " << uniform << LL_ENDL;
@@ -1032,7 +1060,7 @@ S32 LLGLSLShader::unbindTexture(S32 uniform, LLTexUnit::eTextureType mode)
     
     if (uniform > -1)
     {
-        gGL.getTexUnit(uniform)->unbind(mode);
+        gGL.getTexUnit(uniform)->unbindFast(mode);
     }
     
     return uniform;
@@ -1040,6 +1068,8 @@ S32 LLGLSLShader::unbindTexture(S32 uniform, LLTexUnit::eTextureType mode)
 
 S32 LLGLSLShader::enableTexture(S32 uniform, LLTexUnit::eTextureType mode, LLTexUnit::eTextureColorSpace space)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
+
     if (uniform < 0 || uniform >= (S32)mTexture.size())
     {
         LL_SHADER_UNIFORM_ERRS() << "Uniform out of range: " << uniform << LL_ENDL;
@@ -1057,6 +1087,8 @@ S32 LLGLSLShader::enableTexture(S32 uniform, LLTexUnit::eTextureType mode, LLTex
 
 S32 LLGLSLShader::disableTexture(S32 uniform, LLTexUnit::eTextureType mode, LLTexUnit::eTextureColorSpace space)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
+
     if (uniform < 0 || uniform >= (S32)mTexture.size())
     {
         LL_SHADER_UNIFORM_ERRS() << "Uniform out of range: " << uniform << LL_ENDL;
@@ -1084,6 +1116,7 @@ S32 LLGLSLShader::disableTexture(S32 uniform, LLTexUnit::eTextureType mode, LLTe
 
 void LLGLSLShader::uniform1i(U32 index, GLint x)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER
     if (mProgramObject)
     {   
         if (mUniform.size() <= index)
@@ -1094,7 +1127,7 @@ void LLGLSLShader::uniform1i(U32 index, GLint x)
 
         if (mUniform[index] >= 0)
         {
-            std::map<GLint, LLVector4>::iterator iter = mValue.find(mUniform[index]);
+            const auto& iter = mValue.find(mUniform[index]);
             if (iter == mValue.end() || iter->second.mV[0] != x)
             {
                 glUniform1iARB(mUniform[index], x);
@@ -1106,6 +1139,7 @@ void LLGLSLShader::uniform1i(U32 index, GLint x)
 
 void LLGLSLShader::uniform1f(U32 index, GLfloat x)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER
     if (mProgramObject)
     {   
         if (mUniform.size() <= index)
@@ -1116,7 +1150,7 @@ void LLGLSLShader::uniform1f(U32 index, GLfloat x)
 
         if (mUniform[index] >= 0)
         {
-            std::map<GLint, LLVector4>::iterator iter = mValue.find(mUniform[index]);
+            const auto& iter = mValue.find(mUniform[index]);
             if (iter == mValue.end() || iter->second.mV[0] != x)
             {
                 glUniform1fARB(mUniform[index], x);
@@ -1138,7 +1172,7 @@ void LLGLSLShader::uniform2f(U32 index, GLfloat x, GLfloat y)
 
         if (mUniform[index] >= 0)
         {
-            std::map<GLint, LLVector4>::iterator iter = mValue.find(mUniform[index]);
+            const auto& iter = mValue.find(mUniform[index]);
             LLVector4 vec(x,y,0.f,0.f);
             if (iter == mValue.end() || shouldChange(iter->second,vec))
             {
@@ -1161,7 +1195,7 @@ void LLGLSLShader::uniform3f(U32 index, GLfloat x, GLfloat y, GLfloat z)
 
         if (mUniform[index] >= 0)
         {
-            std::map<GLint, LLVector4>::iterator iter = mValue.find(mUniform[index]);
+            const auto& iter = mValue.find(mUniform[index]);
             LLVector4 vec(x,y,z,0.f);
             if (iter == mValue.end() || shouldChange(iter->second,vec))
             {
@@ -1184,7 +1218,7 @@ void LLGLSLShader::uniform4f(U32 index, GLfloat x, GLfloat y, GLfloat z, GLfloat
 
         if (mUniform[index] >= 0)
         {
-            std::map<GLint, LLVector4>::iterator iter = mValue.find(mUniform[index]);
+            const auto& iter = mValue.find(mUniform[index]);
             LLVector4 vec(x,y,z,w);
             if (iter == mValue.end() || shouldChange(iter->second,vec))
             {
@@ -1207,7 +1241,7 @@ void LLGLSLShader::uniform1iv(U32 index, U32 count, const GLint* v)
 
         if (mUniform[index] >= 0)
         {
-            std::map<GLint, LLVector4>::iterator iter = mValue.find(mUniform[index]);
+            const auto& iter = mValue.find(mUniform[index]);
             LLVector4 vec(v[0],0.f,0.f,0.f);
             if (iter == mValue.end() || shouldChange(iter->second,vec) || count != 1)
             {
@@ -1230,7 +1264,7 @@ void LLGLSLShader::uniform1fv(U32 index, U32 count, const GLfloat* v)
 
         if (mUniform[index] >= 0)
         {
-            std::map<GLint, LLVector4>::iterator iter = mValue.find(mUniform[index]);
+            const auto& iter = mValue.find(mUniform[index]);
             LLVector4 vec(v[0],0.f,0.f,0.f);
             if (iter == mValue.end() || shouldChange(iter->second,vec) || count != 1)
             {
@@ -1253,7 +1287,7 @@ void LLGLSLShader::uniform2fv(U32 index, U32 count, const GLfloat* v)
 
         if (mUniform[index] >= 0)
         {
-            std::map<GLint, LLVector4>::iterator iter = mValue.find(mUniform[index]);
+            const auto& iter = mValue.find(mUniform[index]);
             LLVector4 vec(v[0],v[1],0.f,0.f);
             if (iter == mValue.end() || shouldChange(iter->second,vec) || count != 1)
             {
@@ -1276,7 +1310,7 @@ void LLGLSLShader::uniform3fv(U32 index, U32 count, const GLfloat* v)
 
         if (mUniform[index] >= 0)
         {
-            std::map<GLint, LLVector4>::iterator iter = mValue.find(mUniform[index]);
+            const auto& iter = mValue.find(mUniform[index]);
             LLVector4 vec(v[0],v[1],v[2],0.f);
             if (iter == mValue.end() || shouldChange(iter->second,vec) || count != 1)
             {
@@ -1299,10 +1333,11 @@ void LLGLSLShader::uniform4fv(U32 index, U32 count, const GLfloat* v)
 
         if (mUniform[index] >= 0)
         {
-            std::map<GLint, LLVector4>::iterator iter = mValue.find(mUniform[index]);
+            const auto& iter = mValue.find(mUniform[index]);
             LLVector4 vec(v[0],v[1],v[2],v[3]);
             if (iter == mValue.end() || shouldChange(iter->second,vec) || count != 1)
             {
+                LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
                 glUniform4fvARB(mUniform[index], count, v);
                 mValue[mUniform[index]] = vec;
             }
@@ -1346,6 +1381,8 @@ void LLGLSLShader::uniformMatrix3fv(U32 index, U32 count, GLboolean transpose, c
 
 void LLGLSLShader::uniformMatrix3x4fv(U32 index, U32 count, GLboolean transpose, const GLfloat *v)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
+
 	if (mProgramObject)
 	{	
 		if (mUniform.size() <= index)
@@ -1380,6 +1417,8 @@ void LLGLSLShader::uniformMatrix4fv(U32 index, U32 count, GLboolean transpose, c
 
 GLint LLGLSLShader::getUniformLocation(const LLStaticHashedString& uniform)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
+
     GLint ret = -1;
     if (mProgramObject)
     {
@@ -1404,10 +1443,16 @@ GLint LLGLSLShader::getUniformLocation(const LLStaticHashedString& uniform)
 
 GLint LLGLSLShader::getUniformLocation(U32 index)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
+
     GLint ret = -1;
     if (mProgramObject)
     {
-        llassert(index < mUniform.size());
+        if (index >= mUniform.size())
+        {
+            LL_WARNS_ONCE("Shader") << "Uniform index " << index << " out of bounds " << (S32)mUniform.size() << LL_ENDL;
+            return ret;
+        }
         return mUniform[index];
     }
 
@@ -1416,6 +1461,8 @@ GLint LLGLSLShader::getUniformLocation(U32 index)
 
 GLint LLGLSLShader::getAttribLocation(U32 attrib)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
+
     if (attrib < mAttribute.size())
     {
         return mAttribute[attrib];
@@ -1432,7 +1479,7 @@ void LLGLSLShader::uniform1i(const LLStaticHashedString& uniform, GLint v)
                 
     if (location >= 0)
     {
-        std::map<GLint, LLVector4>::iterator iter = mValue.find(location);
+        const auto& iter = mValue.find(location);
         LLVector4 vec(v,0.f,0.f,0.f);
         if (iter == mValue.end() || shouldChange(iter->second,vec))
         {
@@ -1448,7 +1495,7 @@ void LLGLSLShader::uniform2i(const LLStaticHashedString& uniform, GLint i, GLint
                 
     if (location >= 0)
     {
-        std::map<GLint, LLVector4>::iterator iter = mValue.find(location);
+        const auto& iter = mValue.find(location);
         LLVector4 vec(i,j,0.f,0.f);
         if (iter == mValue.end() || shouldChange(iter->second,vec))
         {
@@ -1465,7 +1512,7 @@ void LLGLSLShader::uniform1f(const LLStaticHashedString& uniform, GLfloat v)
                 
     if (location >= 0)
     {
-        std::map<GLint, LLVector4>::iterator iter = mValue.find(location);
+        const auto& iter = mValue.find(location);
         LLVector4 vec(v,0.f,0.f,0.f);
         if (iter == mValue.end() || shouldChange(iter->second,vec))
         {
@@ -1481,7 +1528,7 @@ void LLGLSLShader::uniform2f(const LLStaticHashedString& uniform, GLfloat x, GLf
                 
     if (location >= 0)
     {
-        std::map<GLint, LLVector4>::iterator iter = mValue.find(location);
+        const auto& iter = mValue.find(location);
         LLVector4 vec(x,y,0.f,0.f);
         if (iter == mValue.end() || shouldChange(iter->second,vec))
         {
@@ -1498,7 +1545,7 @@ void LLGLSLShader::uniform3f(const LLStaticHashedString& uniform, GLfloat x, GLf
                 
     if (location >= 0)
     {
-        std::map<GLint, LLVector4>::iterator iter = mValue.find(location);
+        const auto& iter = mValue.find(location);
         LLVector4 vec(x,y,z,0.f);
         if (iter == mValue.end() || shouldChange(iter->second,vec))
         {
@@ -1514,7 +1561,7 @@ void LLGLSLShader::uniform1fv(const LLStaticHashedString& uniform, U32 count, co
 
     if (location >= 0)
     {
-        std::map<GLint, LLVector4>::iterator iter = mValue.find(location);
+        const auto& iter = mValue.find(location);
         LLVector4 vec(v[0],0.f,0.f,0.f);
         if (iter == mValue.end() || shouldChange(iter->second,vec) || count != 1)
         {
@@ -1530,7 +1577,7 @@ void LLGLSLShader::uniform2fv(const LLStaticHashedString& uniform, U32 count, co
                 
     if (location >= 0)
     {
-        std::map<GLint, LLVector4>::iterator iter = mValue.find(location);
+        const auto& iter = mValue.find(location);
         LLVector4 vec(v[0],v[1],0.f,0.f);
         if (iter == mValue.end() || shouldChange(iter->second,vec) || count != 1)
         {
@@ -1546,7 +1593,7 @@ void LLGLSLShader::uniform3fv(const LLStaticHashedString& uniform, U32 count, co
                 
     if (location >= 0)
     {
-        std::map<GLint, LLVector4>::iterator iter = mValue.find(location);
+        const auto& iter = mValue.find(location);
         LLVector4 vec(v[0],v[1],v[2],0.f);
         if (iter == mValue.end() || shouldChange(iter->second,vec) || count != 1)
         {
@@ -1563,12 +1610,11 @@ void LLGLSLShader::uniform4fv(const LLStaticHashedString& uniform, U32 count, co
     if (location >= 0)
     {
         LLVector4 vec(v);
-        std::map<GLint, LLVector4>::iterator iter = mValue.find(location);
+        const auto& iter = mValue.find(location);
         if (iter == mValue.end() || shouldChange(iter->second,vec) || count != 1)
         {
-            stop_glerror();
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
             glUniform4fvARB(location, count, v);
-            stop_glerror();
             mValue[location] = vec;
         }
     }
@@ -1608,3 +1654,27 @@ void LLGLSLShader::setMinimumAlpha(F32 minimum)
     gGL.flush();
     uniform1f(LLShaderMgr::MINIMUM_ALPHA, minimum);
 }
+
+void LLShaderUniforms::apply(LLGLSLShader* shader)
+{
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
+    for (auto& uniform : mIntegers)
+    {
+        shader->uniform1i(uniform.mUniform, uniform.mValue);
+    }
+
+    for (auto& uniform : mFloats)
+    {
+        shader->uniform1f(uniform.mUniform, uniform.mValue);
+    }
+
+    for (auto& uniform : mVectors)
+    {
+        shader->uniform4fv(uniform.mUniform, 1, uniform.mValue.mV);
+    }
+
+    for (auto& uniform : mVector3s)
+    {
+        shader->uniform3fv(uniform.mUniform, 1, uniform.mValue.mV);
+    }
+}
diff --git a/indra/llrender/llglslshader.h b/indra/llrender/llglslshader.h
index 7cf6d3c941f294da9fadfbd014f8f3e04f890ef8..85e83dbcb997e02666efc5cad50b36257d4cc943 100644
--- a/indra/llrender/llglslshader.h
+++ b/indra/llrender/llglslshader.h
@@ -30,6 +30,7 @@
 #include "llgl.h"
 #include "llrender.h"
 #include "llstaticstringtable.h"
+#include <unordered_map>
 
 class LLShaderFeatures
 {
@@ -64,16 +65,79 @@ class LLShaderFeatures
 	LLShaderFeatures();
 };
 
+// ============= Structure for caching shader uniforms ===============
+class LLGLSLShader;
+
+class LLShaderUniforms
+{
+public:
+
+    template<typename T>
+    struct UniformSetting
+    {
+        S32 mUniform;
+        T mValue;
+    };
+
+    typedef UniformSetting<S32> IntSetting;
+    typedef UniformSetting<F32> FloatSetting;
+    typedef UniformSetting<LLVector4> VectorSetting;
+    typedef UniformSetting<LLVector3> Vector3Setting;
+
+    void clear()
+    {
+        mIntegers.resize(0);
+        mFloats.resize(0);
+        mVectors.resize(0);
+        mVector3s.resize(0);
+    }
+
+    void uniform1i(S32 index, S32 value)
+    {
+        mIntegers.push_back({ index, value });
+    }
+
+    void uniform1f(S32 index, F32 value)
+    {
+        mFloats.push_back({ index, value });
+    }
+
+    void uniform4fv(S32 index, const LLVector4& value)
+    {
+        mVectors.push_back({ index, value });
+    }
+    
+    void uniform4fv(S32 index, const F32* value)
+    {
+        mVectors.push_back({ index, LLVector4(value) });
+    }
+
+    void uniform3fv(S32 index, const LLVector3& value)
+    {
+        mVector3s.push_back({ index, value });
+    }
+
+    void apply(LLGLSLShader* shader);
+   
+
+    std::vector<IntSetting> mIntegers;
+    std::vector<FloatSetting> mFloats;
+    std::vector<VectorSetting> mVectors;
+    std::vector<Vector3Setting> mVector3s;
+};
 class LLGLSLShader
 {
 public:
 
-	enum 
+    // enum primarily used to control application sky settings uniforms
+	typedef enum 
 	{
-		SG_DEFAULT = 0,
-		SG_SKY,
-		SG_WATER
-	};
+		SG_DEFAULT = 0,  // not sky or water specific
+		SG_SKY,  //
+		SG_WATER,
+        SG_ANY,
+        SG_COUNT
+	} eGroup;
 	
 	static std::set<LLGLSLShader*> sInstances;
 	static bool sProfileEnabled;
@@ -84,7 +148,6 @@ class LLGLSLShader
 	static GLhandleARB sCurBoundShader;
 	static LLGLSLShader* sCurBoundShaderPtr;
 	static S32 sIndexedTextureChannels;
-	static bool sNoFixedFunction;
 
 	static void initProfile();
 	static void finishProfile(bool emit_report = true);
@@ -166,6 +229,8 @@ class LLGLSLShader
 	
     BOOL link(BOOL suppress_errors = FALSE);
 	void bind();
+    //helper to conditionally bind mRiggedVariant instead of this
+    void bind(bool rigged);
 	void unbind();
 
 	// Unbinds any previously bound shader by explicitly binding no shader.
@@ -190,18 +255,21 @@ class LLGLSLShader
 	U32 mAttributeMask;  //mask of which reserved attributes are set (lines up with LLVertexBuffer::getTypeMask())
 	std::vector<GLint> mUniform;   //lookup table of uniform enum to uniform location
 	LLStaticStringTable<GLint> mUniformMap; //lookup map of uniform name to uniform location
-	std::map<GLint, std::string> mUniformNameMap; //lookup map of uniform location to uniform name
-	std::map<GLint, LLVector4> mValue; //lookup map of uniform location to last known value
+    typedef std::unordered_map<GLint, std::string> uniform_name_map_t;
+    typedef std::unordered_map<GLint, LLVector4> uniform_value_map_t;
+    uniform_name_map_t mUniformNameMap; //lookup map of uniform location to uniform name
+	uniform_value_map_t mValue; //lookup map of uniform location to last known value
 	std::vector<GLint> mTexture;
 	S32 mTotalUniformSize;
 	S32 mActiveTextureChannels;
 	S32 mShaderLevel;
-	S32 mShaderGroup;
+	S32 mShaderGroup; // see LLGLSLShader::eGroup
 	BOOL mUniformsDirty;
 	LLShaderFeatures mFeatures;
 	std::vector< std::pair< std::string, GLenum > > mShaderFiles;
 	std::string mName;
-	boost::unordered_map<std::string, std::string> mDefines;
+    typedef std::unordered_map<std::string, std::string> defines_map_t;
+	defines_map_t mDefines;
 
 	//statistcis for profiling shader performance
 	U32 mTimerQuery;
@@ -219,6 +287,9 @@ class LLGLSLShader
 	std::vector<U32> mTextureMagFilter;
 	std::vector<U32> mTextureMinFilter;
 
+    // this pointer should be set to whichever shader represents this shader's rigged variant
+    LLGLSLShader* mRiggedVariant = nullptr;
+
 private:
 	void unloadInternal();
 };
diff --git a/indra/llrender/llgltexture.cpp b/indra/llrender/llgltexture.cpp
index ad501687ed54fe91f4528a00ab5d41a5ecbbff78..e012eb9a62f4a4e758e6c2beefe4ae968135b1ab 100644
--- a/indra/llrender/llgltexture.cpp
+++ b/indra/llrender/llgltexture.cpp
@@ -164,11 +164,11 @@ BOOL LLGLTexture::createGLTexture()
 	return mGLTexturep->createGLTexture() ;
 }
 
-BOOL LLGLTexture::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename, BOOL to_create, S32 category)
+BOOL LLGLTexture::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename, BOOL to_create, S32 category, bool defer_copy, LLGLuint* tex_name)
 {
-	llassert(mGLTexturep.notNull()) ;	
+	llassert(mGLTexturep.notNull());
 
-	BOOL ret = mGLTexturep->createGLTexture(discard_level, imageraw, usename, to_create, category) ;
+	BOOL ret = mGLTexturep->createGLTexture(discard_level, imageraw, usename, to_create, category, defer_copy, tex_name) ;
 
 	if(ret)
 	{
@@ -260,18 +260,20 @@ LLTexUnit::eTextureType LLGLTexture::getTarget(void) const
 	return mGLTexturep->getTarget() ;
 }
 
-BOOL LLGLTexture::setSubImage(const LLImageRaw* imageraw, S32 x_pos, S32 y_pos, S32 width, S32 height)
+BOOL LLGLTexture::setSubImage(const LLImageRaw* imageraw, S32 x_pos, S32 y_pos, S32 width, S32 height, LLGLuint use_name)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	llassert(mGLTexturep.notNull()) ;
 
-	return mGLTexturep->setSubImage(imageraw, x_pos, y_pos, width, height) ;
+	return mGLTexturep->setSubImage(imageraw, x_pos, y_pos, width, height, 0, use_name) ;
 }
 
-BOOL LLGLTexture::setSubImage(const U8* datap, S32 data_width, S32 data_height, S32 x_pos, S32 y_pos, S32 width, S32 height)
+BOOL LLGLTexture::setSubImage(const U8* datap, S32 data_width, S32 data_height, S32 x_pos, S32 y_pos, S32 width, S32 height, LLGLuint use_name)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	llassert(mGLTexturep.notNull()) ;
 
-	return mGLTexturep->setSubImage(datap, data_width, data_height, x_pos, y_pos, width, height) ;
+	return mGLTexturep->setSubImage(datap, data_width, data_height, x_pos, y_pos, width, height, 0, use_name) ;
 }
 
 void LLGLTexture::setGLTextureCreated (bool initialized)
diff --git a/indra/llrender/llgltexture.h b/indra/llrender/llgltexture.h
index 071912c2c23231080315806313c1586b95ab6fdc..8cfe7b62de4f6e35bcb4db87f876a693fe5d7312 100644
--- a/indra/llrender/llgltexture.h
+++ b/indra/llrender/llgltexture.h
@@ -124,13 +124,22 @@ class LLGLTexture : public LLTexture
 	BOOL       hasGLTexture() const ;
 	LLGLuint   getTexName() const ;		
 	BOOL       createGLTexture() ;
-	BOOL       createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename = 0, BOOL to_create = TRUE, S32 category = LLGLTexture::OTHER);
+	
+    // Create a GL Texture from an image raw
+    // discard_level - mip level, 0 for highest resultion mip
+    // imageraw - the image to copy from
+    // usename - explicit GL name override
+    // to_create - set to FALSE to force gl texture to not be created
+    // category - LLGLTexture category for this LLGLTexture
+    // defer_copy - set to true to allocate GL texture but NOT initialize with imageraw data
+    // tex_name - if not null, will be set to the GL name of the texture created
+    BOOL       createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename = 0, BOOL to_create = TRUE, S32 category = LLGLTexture::OTHER, bool defer_copy = false, LLGLuint* tex_name = nullptr);
 
 	void       setFilteringOption(LLTexUnit::eTextureFilterOptions option);
 	void       setExplicitFormat(LLGLint internal_format, LLGLenum primary_format, LLGLenum type_format = 0, BOOL swap_bytes = FALSE);
 	void       setAddressMode(LLTexUnit::eTextureAddressMode mode);
-	BOOL       setSubImage(const LLImageRaw* imageraw, S32 x_pos, S32 y_pos, S32 width, S32 height);
-	BOOL       setSubImage(const U8* datap, S32 data_width, S32 data_height, S32 x_pos, S32 y_pos, S32 width, S32 height);
+	BOOL       setSubImage(const LLImageRaw* imageraw, S32 x_pos, S32 y_pos, S32 width, S32 height, LLGLuint use_name = 0);
+	BOOL       setSubImage(const U8* datap, S32 data_width, S32 data_height, S32 x_pos, S32 y_pos, S32 width, S32 height, LLGLuint use_name = 0);
 	void       setGLTextureCreated (bool initialized);
 	void       setCategory(S32 category) ;
     void       setTexName(LLGLuint); // for forcing w/ externally created textures only
@@ -176,7 +185,7 @@ class LLGLTexture : public LLTexture
 protected:
 	void setTexelsPerImage();
 
-	//note: do not make this function public.
+public:
 	/*virtual*/ LLImageGL* getGLTexture() const ;
 
 protected:
diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp
index 0151d20128eb315fab2450ce7d2ff55f1dfac3df..9dc140b5b98bfe42e1035e1b6d8234f4f0bf743b 100644
--- a/indra/llrender/llimagegl.cpp
+++ b/indra/llrender/llimagegl.cpp
@@ -39,6 +39,12 @@
 #include "llgl.h"
 #include "llglslshader.h"
 #include "llrender.h"
+#include "llwindow.h"
+#include "llframetimer.h"
+
+#if !LL_IMAGEGL_THREAD_CHECK
+#define checkActiveThread()
+#endif
 
 //----------------------------------------------------------------------------
 const F32 MIN_TEXTURE_LIFETIME = 10.f;
@@ -61,9 +67,11 @@ F32 LLImageGL::sLastFrameTime			= 0.f;
 BOOL LLImageGL::sAllowReadBackRaw       = FALSE ;
 LLImageGL* LLImageGL::sDefaultGLTexture = NULL ;
 bool LLImageGL::sCompressTextures = false;
-
 std::set<LLImageGL*> LLImageGL::sImageList;
 
+
+bool LLImageGLThread::sEnabled = false;
+
 //****************************************************************************************************
 //The below for texture auditing use only
 //****************************************************************************************************
@@ -170,15 +178,24 @@ BOOL is_little_endian()
     
 	return (*c == 0x78) ;
 }
+
 //static 
-void LLImageGL::initClass(S32 num_catagories, BOOL skip_analyze_alpha /* = false */)
+void LLImageGL::initClass(LLWindow* window, S32 num_catagories, BOOL skip_analyze_alpha /* = false */, bool multi_threaded /* = false */)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	sSkipAnalyzeAlpha = skip_analyze_alpha;
+
+    if (multi_threaded)
+    {
+        LLImageGLThread::createInstance(window);
+    }
 }
 
 //static 
 void LLImageGL::cleanupClass() 
-{	
+{
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
+    LLImageGLThread::deleteSingleton();
 }
 
 //static
@@ -194,6 +211,7 @@ S32 LLImageGL::dataFormatBits(S32 dataformat)
     case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT:    return 8;
     case GL_LUMINANCE:						        return 8;
     case GL_ALPHA:							        return 8;
+    case GL_RED:                                    return 8;
     case GL_COLOR_INDEX:						    return 8;
     case GL_LUMINANCE_ALPHA:					    return 16;
     case GL_RGB:								    return 24;
@@ -243,6 +261,7 @@ S32 LLImageGL::dataFormatComponents(S32 dataformat)
 	  case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT: return 4;
 	  case GL_LUMINANCE:						return 1;
 	  case GL_ALPHA:							return 1;
+      case GL_RED:                              return 1;
 	  case GL_COLOR_INDEX:						return 1;
 	  case GL_LUMINANCE_ALPHA:					return 2;
 	  case GL_RGB:								return 3;
@@ -258,11 +277,10 @@ S32 LLImageGL::dataFormatComponents(S32 dataformat)
 
 //----------------------------------------------------------------------------
 
-static LLTrace::BlockTimerStatHandle FTM_IMAGE_UPDATE_STATS("Image Stats");
 // static
 void LLImageGL::updateStats(F32 current_time)
 {
-	LL_RECORD_BLOCK_TIME(FTM_IMAGE_UPDATE_STATS);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	sLastFrameTime = current_time;
 	sBoundTextureMemory = sCurBoundTextureMemory;
 	sCurBoundTextureMemory = S32Bytes(0);
@@ -295,10 +313,8 @@ void LLImageGL::destroyGL(BOOL save_state)
 			if (save_state && glimage->isGLTextureCreated() && glimage->mComponents)
 			{
 				glimage->mSaveData = new LLImageRaw;
-				glimage->claimMem(glimage->mSaveData);
 				if(!glimage->readBackRaw(glimage->mCurrentDiscardLevel, glimage->mSaveData, false)) //necessary, keep it.
 				{
-					glimage->disclaimMem(glimage->mSaveData);
 					glimage->mSaveData = NULL ;
 				}
 			}
@@ -372,8 +388,7 @@ BOOL LLImageGL::create(LLPointer<LLImageGL>& dest, const LLImageRaw* imageraw, B
 //----------------------------------------------------------------------------
 
 LLImageGL::LLImageGL(BOOL usemipmaps)
-:	LLTrace::MemTrackable<LLImageGL>("LLImageGL"),
-    mSaveData(0), mExternalTexture(FALSE)
+:	mSaveData(0), mExternalTexture(FALSE)
 {
 	init(usemipmaps);
 	setSize(0, 0, 0);
@@ -382,8 +397,7 @@ LLImageGL::LLImageGL(BOOL usemipmaps)
 }
 
 LLImageGL::LLImageGL(U32 width, U32 height, U8 components, BOOL usemipmaps)
-:	LLTrace::MemTrackable<LLImageGL>("LLImageGL"),
-    mSaveData(0), mExternalTexture(FALSE)
+:	mSaveData(0), mExternalTexture(FALSE)
 {
 	llassert( components <= 4 );
 	init(usemipmaps);
@@ -393,8 +407,7 @@ LLImageGL::LLImageGL(U32 width, U32 height, U8 components, BOOL usemipmaps)
 }
 
 LLImageGL::LLImageGL(const LLImageRaw* imageraw, BOOL usemipmaps)
-:	LLTrace::MemTrackable<LLImageGL>("LLImageGL"),
-    mSaveData(0), mExternalTexture(FALSE)
+:	mSaveData(0), mExternalTexture(FALSE)
 {
 	init(usemipmaps);
 	setSize(0, 0, 0);
@@ -412,7 +425,6 @@ LLImageGL::LLImageGL(
     LLGLenum formatPrimary,
     LLGLenum formatType,
     LLTexUnit::eTextureAddressMode addressMode)
-    : LLTrace::MemTrackable<LLImageGL>("LLImageGL"), mSaveData(0), mExternalTexture(TRUE)
 {
     init(false);
     mTexName = texName;
@@ -427,7 +439,7 @@ LLImageGL::LLImageGL(
 
 LLImageGL::~LLImageGL()
 {
-    if (!mExternalTexture)
+    if (!mExternalTexture && gGLManager.mInited)
     {
 	    LLImageGL::cleanup();
 	    sImageList.erase(this);
@@ -438,6 +450,10 @@ LLImageGL::~LLImageGL()
 
 void LLImageGL::init(BOOL usemipmaps)
 {
+#if LL_IMAGEGL_THREAD_CHECK
+    mActiveThread = LLThread::currentID();
+#endif
+
 	// keep these members in the same order as declared in llimagehl.h
 	// so that it is obvious by visual inspection if we forgot to
 	// init a field.
@@ -493,6 +509,9 @@ void LLImageGL::init(BOOL usemipmaps)
 #endif
 
 	mCategory = -1;
+
+	// Sometimes we have to post work for the main thread.
+	mMainQueue = LL::WorkQueue::getInstance("mainloop");
 }
 
 void LLImageGL::cleanup()
@@ -534,18 +553,12 @@ bool LLImageGL::setSize(S32 width, S32 height, S32 ncomponents, S32 discard_leve
 	if (width != mWidth || height != mHeight || ncomponents != mComponents)
 	{
 		// Check if dimensions are a power of two!
-		if (!checkSize(width,height))
+		if (!checkSize(width, height))
 		{
 			LL_WARNS() << llformat("Texture has non power of two dimension: %dx%d",width,height) << LL_ENDL;
 			return false;
 		}
 		
-		if (mTexName)
-		{
-// 			LL_WARNS() << "Setting Size of LLImageGL with existing mTexName = " << mTexName << LL_ENDL;
-			destroyGLTexture();
-		}
-
 		// pickmask validity depends on old image size, delete it
 		freePickMask();
 
@@ -656,6 +669,7 @@ void LLImageGL::setExplicitFormat( LLGLint internal_format, LLGLenum primary_for
 
 void LLImageGL::setImage(const LLImageRaw* imageraw)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	llassert((imageraw->getWidth() == getWidth(mCurrentDiscardLevel)) &&
 			 (imageraw->getHeight() == getHeight(mCurrentDiscardLevel)) &&
 			 (imageraw->getComponents() == getComponents()));
@@ -663,10 +677,9 @@ void LLImageGL::setImage(const LLImageRaw* imageraw)
 	setImage(rawdata, FALSE);
 }
 
-static LLTrace::BlockTimerStatHandle FTM_SET_IMAGE("setImage");
-BOOL LLImageGL::setImage(const U8* data_in, BOOL data_hasmips)
+BOOL LLImageGL::setImage(const U8* data_in, BOOL data_hasmips /* = FALSE */, S32 usename /* = 0 */)
 {
-	LL_RECORD_BLOCK_TIME(FTM_SET_IMAGE);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	bool is_compressed = false;
 
     switch (mFormatPrimary)
@@ -683,12 +696,11 @@ BOOL LLImageGL::setImage(const U8* data_in, BOOL data_hasmips)
         break;
     }
 	
-	
-	
 	if (mUseMipMaps)
 	{
 		//set has mip maps to true before binding image so tex parameters get set properly
-		gGL.getTexUnit(0)->unbind(mBindTarget);
+        gGL.getTexUnit(0)->unbind(mBindTarget);
+        
 		mHasMipMaps = true;
 		mTexOptionsDirty = true;
 		setFilteringOption(LLTexUnit::TFO_ANISOTROPIC);
@@ -698,10 +710,16 @@ BOOL LLImageGL::setImage(const U8* data_in, BOOL data_hasmips)
 		mHasMipMaps = false;
 	}
 	
-	llverify(gGL.getTexUnit(0)->bind(this));
-	
-	
-	if (mUseMipMaps)
+    gGL.getTexUnit(0)->bind(this, false, false, usename);
+
+    if (data_in == nullptr)
+    {
+        S32 w = getWidth();
+        S32 h = getHeight();
+        LLImageGL::setManualImage(mTarget, 0, mFormatInternal, w, h,
+            mFormatPrimary, mFormatType, (GLvoid*)data_in, mAllowCompression);
+    }
+    else if (mUseMipMaps)
 	{
 		if (data_hasmips)
 		{
@@ -728,8 +746,6 @@ BOOL LLImageGL::setImage(const U8* data_in, BOOL data_hasmips)
 				}
 				else
 				{
-// 					LL_RECORD_BLOCK_TIME(FTM_TEMP4);
-
 					if(mFormatSwapBytes)
 					{
 						glPixelStorei(GL_UNPACK_SWAP_BYTES, 1);
@@ -760,8 +776,6 @@ BOOL LLImageGL::setImage(const U8* data_in, BOOL data_hasmips)
 			{
 				stop_glerror();
 				{
-// 					LL_RECORD_BLOCK_TIME(FTM_TEMP4);
-
 					if(mFormatSwapBytes)
 					{
 						glPixelStorei(GL_UNPACK_SWAP_BYTES, 1);
@@ -781,7 +795,7 @@ BOOL LLImageGL::setImage(const U8* data_in, BOOL data_hasmips)
 						glTexParameteri(mTarget, GL_GENERATE_MIPMAP, GL_TRUE);
 					}
 
-					LLImageGL::setManualImage(mTarget, 0, mFormatInternal,
+                    LLImageGL::setManualImage(mTarget, 0, mFormatInternal,
 								 w, h, 
 								 mFormatPrimary, mFormatType,
 								 data_in, mAllowCompression);
@@ -871,14 +885,13 @@ BOOL LLImageGL::setImage(const U8* data_in, BOOL data_hasmips)
 					llassert(w > 0 && h > 0 && cur_mip_data);
 					(void)cur_mip_data;
 					{
-// 						LL_RECORD_BLOCK_TIME(FTM_TEMP4);
 						if(mFormatSwapBytes)
 						{
 							glPixelStorei(GL_UNPACK_SWAP_BYTES, 1);
 							stop_glerror();
 						}
 
-						LLImageGL::setManualImage(mTarget, m, mFormatInternal, w, h, mFormatPrimary, mFormatType, cur_mip_data, mAllowCompression);
+                        LLImageGL::setManualImage(mTarget, m, mFormatInternal, w, h, mFormatPrimary, mFormatType, cur_mip_data, mAllowCompression);
 						if (m == 0)
 						{
 							analyzeAlpha(data_in, w, h);
@@ -1065,13 +1078,15 @@ void LLImageGL::postAddToAtlas()
 	stop_glerror();	
 }
 
-BOOL LLImageGL::setSubImage(const U8* datap, S32 data_width, S32 data_height, S32 x_pos, S32 y_pos, S32 width, S32 height, BOOL force_fast_update)
+BOOL LLImageGL::setSubImage(const U8* datap, S32 data_width, S32 data_height, S32 x_pos, S32 y_pos, S32 width, S32 height, BOOL force_fast_update /* = FALSE */, LLGLuint use_name)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	if (!width || !height)
 	{
 		return TRUE;
 	}
-	if (mTexName == 0)
+    LLGLuint tex_name = use_name != 0 ? use_name : mTexName;
+	if (0 == tex_name)
 	{
 		// *TODO: Re-enable warning?  Ran into thread locking issues? DK 2011-02-18
 		//LL_WARNS() << "Setting subimage on image without GL texture" << LL_ENDL;
@@ -1087,7 +1102,7 @@ BOOL LLImageGL::setSubImage(const U8* datap, S32 data_width, S32 data_height, S3
 	// HACK: allow the caller to explicitly force the fast path (i.e. using glTexSubImage2D here instead of calling setImage) even when updating the full texture.
 	if (!force_fast_update && x_pos == 0 && y_pos == 0 && width == getWidth() && height == getHeight() && data_width == width && data_height == height)
 	{
-		setImage(datap, FALSE);
+		setImage(datap, FALSE, tex_name);
 	}
 	else
 	{
@@ -1139,12 +1154,11 @@ BOOL LLImageGL::setSubImage(const U8* datap, S32 data_width, S32 data_height, S3
 
 		datap += (y_pos * data_width + x_pos) * getComponents();
 		// Update the GL texture
-		BOOL res = gGL.getTexUnit(0)->bindManual(mBindTarget, mTexName);
+		BOOL res = gGL.getTexUnit(0)->bindManual(mBindTarget, tex_name);
 		if (!res) LL_ERRS() << "LLImageGL::setSubImage(): bindTexture failed" << LL_ENDL;
 		stop_glerror();
 
-		glTexSubImage2D(mTarget, 0, x_pos, y_pos, 
-						width, height, mFormatPrimary, mFormatType, datap);
+		glTexSubImage2D(mTarget, 0, x_pos, y_pos, width, height, mFormatPrimary, mFormatType, datap);
 		gGL.getTexUnit(0)->disable();
 		stop_glerror();
 
@@ -1161,9 +1175,10 @@ BOOL LLImageGL::setSubImage(const U8* datap, S32 data_width, S32 data_height, S3
 	return TRUE;
 }
 
-BOOL LLImageGL::setSubImage(const LLImageRaw* imageraw, S32 x_pos, S32 y_pos, S32 width, S32 height, BOOL force_fast_update)
+BOOL LLImageGL::setSubImage(const LLImageRaw* imageraw, S32 x_pos, S32 y_pos, S32 width, S32 height, BOOL force_fast_update /* = FALSE */, LLGLuint use_name)
 {
-	return setSubImage(imageraw->getData(), imageraw->getWidth(), imageraw->getHeight(), x_pos, y_pos, width, height, force_fast_update);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
+	return setSubImage(imageraw->getData(), imageraw->getWidth(), imageraw->getHeight(), x_pos, y_pos, width, height, force_fast_update, use_name);
 }
 
 // Copy sub image from frame buffer
@@ -1183,15 +1198,36 @@ BOOL LLImageGL::setSubImageFromFrameBuffer(S32 fb_x, S32 fb_y, S32 x_pos, S32 y_
 }
 
 // static
-static LLTrace::BlockTimerStatHandle FTM_GENERATE_TEXTURES("generate textures");
 void LLImageGL::generateTextures(S32 numTextures, U32 *textures)
 {
-	LL_RECORD_BLOCK_TIME(FTM_GENERATE_TEXTURES);
-	glGenTextures(numTextures, textures);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
+    static constexpr U32 pool_size = 1024;
+    static thread_local U32 name_pool[pool_size]; // pool of texture names
+    static thread_local U32 name_count = 0; // number of available names in the pool
+
+    if (name_count == 0)
+    {
+        LL_PROFILE_ZONE_NAMED("iglgt - reup pool");
+        // pool is emtpy, refill it
+        glGenTextures(pool_size, name_pool);
+        name_count = pool_size;
+    }
+
+    if (numTextures <= name_count)
+    {
+        //copy teture names off the end of the pool
+        memcpy(textures, name_pool + name_count - numTextures, sizeof(U32) * numTextures);
+        name_count -= numTextures;
+    }
+    else
+    {
+        LL_PROFILE_ZONE_NAMED("iglgt - pool miss");
+        glGenTextures(numTextures, textures);
+    }
 }
 
 // static
-void LLImageGL::deleteTextures(S32 numTextures, U32 *textures)
+void LLImageGL::deleteTextures(S32 numTextures, const U32 *textures)
 {
 	if (gGLManager.mInited)
 	{
@@ -1200,125 +1236,155 @@ void LLImageGL::deleteTextures(S32 numTextures, U32 *textures)
 }
 
 // static
-static LLTrace::BlockTimerStatHandle FTM_SET_MANUAL_IMAGE("setManualImage");
-void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 width, S32 height, U32 pixformat, U32 pixtype, const void *pixels, bool allow_compression)
+void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 width, S32 height, U32 pixformat, U32 pixtype, const void* pixels, bool allow_compression)
 {
-	LL_RECORD_BLOCK_TIME(FTM_SET_MANUAL_IMAGE);
-	bool use_scratch = false;
-	U32* scratch = NULL;
-	if (LLRender::sGLCoreProfile)
-	{
-		if (pixformat == GL_ALPHA && pixtype == GL_UNSIGNED_BYTE) 
-		{ //GL_ALPHA is deprecated, convert to RGBA
-			use_scratch = true;
-			scratch = new U32[width*height];
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
+    bool use_scratch = false;
+    U32* scratch = NULL;
+    if (LLRender::sGLCoreProfile)
+    {
+        if (pixformat == GL_ALPHA && pixtype == GL_UNSIGNED_BYTE)
+        { //GL_ALPHA is deprecated, convert to RGBA
+            if (pixels != nullptr)
+            {
+                use_scratch = true;
+                scratch = new(std::nothrow) U32[width * height];
+                if (!scratch)
+                {
+                    LL_ERRS() << "Failed to allocate " << (U32)(width * height * sizeof(U32))
+                              << " bytes for a manual image W" << width << " H" << height << LL_ENDL;
+                }
 
-			U32 pixel_count = (U32) (width*height);
-			for (U32 i = 0; i < pixel_count; i++)
-			{
-				U8* pix = (U8*) &scratch[i];
-				pix[0] = pix[1] = pix[2] = 0;
-				pix[3] = ((U8*) pixels)[i];
-			}				
-			
-			pixformat = GL_RGBA;
-			intformat = GL_RGBA8;
-		}
+                U32 pixel_count = (U32)(width * height);
+                for (U32 i = 0; i < pixel_count; i++)
+                {
+                    U8* pix = (U8*)&scratch[i];
+                    pix[0] = pix[1] = pix[2] = 0;
+                    pix[3] = ((U8*)pixels)[i];
+                }
+            }
 
-		if (pixformat == GL_LUMINANCE_ALPHA && pixtype == GL_UNSIGNED_BYTE) 
-		{ //GL_LUMINANCE_ALPHA is deprecated, convert to RGBA
-			use_scratch = true;
-			scratch = new U32[width*height];
+            pixformat = GL_RGBA;
+            intformat = GL_RGBA8;
+        }
 
-			U32 pixel_count = (U32) (width*height);
-			for (U32 i = 0; i < pixel_count; i++)
-			{
-				U8 lum = ((U8*) pixels)[i*2+0];
-				U8 alpha = ((U8*) pixels)[i*2+1];
+        if (pixformat == GL_LUMINANCE_ALPHA && pixtype == GL_UNSIGNED_BYTE)
+        { //GL_LUMINANCE_ALPHA is deprecated, convert to RGBA
+            if (pixels != nullptr)
+            {
+                use_scratch = true;
+                scratch = new(std::nothrow) U32[width * height];
+                if (!scratch)
+                {
+                    LL_ERRS() << "Failed to allocate " << (U32)(width * height * sizeof(U32))
+                        << " bytes for a manual image W" << width << " H" << height << LL_ENDL;
+                }
 
-				U8* pix = (U8*) &scratch[i];
-				pix[0] = pix[1] = pix[2] = lum;
-				pix[3] = alpha;
-			}				
-			
-			pixformat = GL_RGBA;
-			intformat = GL_RGBA8;
-		}
+                U32 pixel_count = (U32)(width * height);
+                for (U32 i = 0; i < pixel_count; i++)
+                {
+                    U8 lum = ((U8*)pixels)[i * 2 + 0];
+                    U8 alpha = ((U8*)pixels)[i * 2 + 1];
 
-		if (pixformat == GL_LUMINANCE && pixtype == GL_UNSIGNED_BYTE) 
-		{ //GL_LUMINANCE_ALPHA is deprecated, convert to RGB
-			use_scratch = true;
-			scratch = new U32[width*height];
+                    U8* pix = (U8*)&scratch[i];
+                    pix[0] = pix[1] = pix[2] = lum;
+                    pix[3] = alpha;
+                }
+            }
 
-			U32 pixel_count = (U32) (width*height);
-			for (U32 i = 0; i < pixel_count; i++)
-			{
-				U8 lum = ((U8*) pixels)[i];
-				
-				U8* pix = (U8*) &scratch[i];
-				pix[0] = pix[1] = pix[2] = lum;
-				pix[3] = 255;
-			}				
-			
-			pixformat = GL_RGBA;
-			intformat = GL_RGB8;
-		}
-	}
+            pixformat = GL_RGBA;
+            intformat = GL_RGBA8;
+        }
 
-	if (LLImageGL::sCompressTextures && allow_compression)
-	{
-		switch (intformat)
-		{
-			case GL_RGB: 
-			case GL_RGB8:
-				intformat = GL_COMPRESSED_RGB; 
-				break;
-            case GL_SRGB:
-            case GL_SRGB8:
-                intformat = GL_COMPRESSED_SRGB;
-                break;
-			case GL_RGBA:
-			case GL_RGBA8:
-				intformat = GL_COMPRESSED_RGBA; 
-				break;
-            case GL_SRGB_ALPHA:
-            case GL_SRGB8_ALPHA8:
-                intformat = GL_COMPRESSED_SRGB_ALPHA;
-                break;
-			case GL_LUMINANCE:
-			case GL_LUMINANCE8:
-				intformat = GL_COMPRESSED_LUMINANCE;
-				break;
-			case GL_LUMINANCE_ALPHA:
-			case GL_LUMINANCE8_ALPHA8:
-				intformat = GL_COMPRESSED_LUMINANCE_ALPHA;
-				break;
-			case GL_ALPHA:
-			case GL_ALPHA8:
-				intformat = GL_COMPRESSED_ALPHA;
-				break;
-			default:
-				LL_WARNS() << "Could not compress format: " << std::hex << intformat << LL_ENDL;
-				break;
-		}
-	}
+        if (pixformat == GL_LUMINANCE && pixtype == GL_UNSIGNED_BYTE)
+        { //GL_LUMINANCE_ALPHA is deprecated, convert to RGB
+            if (pixels != nullptr)
+            {
+                use_scratch = true;
+                scratch = new(std::nothrow) U32[width * height];
+                if (!scratch)
+                {
+                    LL_ERRS() << "Failed to allocate " << (U32)(width * height * sizeof(U32))
+                        << " bytes for a manual image W" << width << " H" << height << LL_ENDL;
+                }
 
-	stop_glerror();
-	glTexImage2D(target, miplevel, intformat, width, height, 0, pixformat, pixtype, use_scratch ? scratch : pixels);
-	stop_glerror();
+                U32 pixel_count = (U32)(width * height);
+                for (U32 i = 0; i < pixel_count; i++)
+                {
+                    U8 lum = ((U8*)pixels)[i];
 
-	if (use_scratch)
-	{
-		delete [] scratch;
-	}
+                    U8* pix = (U8*)&scratch[i];
+                    pix[0] = pix[1] = pix[2] = lum;
+                    pix[3] = 255;
+                }
+            }
+            pixformat = GL_RGBA;
+            intformat = GL_RGB8;
+        }
+    }
+
+    if (LLImageGL::sCompressTextures && allow_compression)
+    {
+        switch (intformat)
+        {
+        case GL_RGB:
+        case GL_RGB8:
+            intformat = GL_COMPRESSED_RGB;
+            break;
+        case GL_SRGB:
+        case GL_SRGB8:
+            intformat = GL_COMPRESSED_SRGB;
+            break;
+        case GL_RGBA:
+        case GL_RGBA8:
+            intformat = GL_COMPRESSED_RGBA;
+            break;
+        case GL_SRGB_ALPHA:
+        case GL_SRGB8_ALPHA8:
+            intformat = GL_COMPRESSED_SRGB_ALPHA;
+            break;
+        case GL_LUMINANCE:
+        case GL_LUMINANCE8:
+            intformat = GL_COMPRESSED_LUMINANCE;
+            break;
+        case GL_LUMINANCE_ALPHA:
+        case GL_LUMINANCE8_ALPHA8:
+            intformat = GL_COMPRESSED_LUMINANCE_ALPHA;
+            break;
+        case GL_ALPHA:
+        case GL_ALPHA8:
+            intformat = GL_COMPRESSED_ALPHA;
+            break;
+        case GL_RED:
+        case GL_R8:
+            intformat = GL_COMPRESSED_RED;
+            break;
+        default:
+            LL_WARNS() << "Could not compress format: " << std::hex << intformat << LL_ENDL;
+            break;
+        }
+    }
+
+    stop_glerror();
+    {
+        LL_PROFILE_ZONE_NAMED("glTexImage2D");
+        glTexImage2D(target, miplevel, intformat, width, height, 0, pixformat, pixtype, use_scratch ? scratch : pixels);
+    }
+    stop_glerror();
+
+    if (use_scratch)
+    {
+        delete[] scratch;
+    }
 }
 
 //create an empty GL texture: just create a texture name
 //the texture is assiciate with some image by calling glTexImage outside LLImageGL
-static LLTrace::BlockTimerStatHandle FTM_CREATE_GL_TEXTURE1("createGLTexture()");
 BOOL LLImageGL::createGLTexture()
 {
-	LL_RECORD_BLOCK_TIME(FTM_CREATE_GL_TEXTURE1);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
+    checkActiveThread();
+
 	if (gGLManager.mIsDisabled)
 	{
 		LL_WARNS() << "Trying to create a texture while GL is disabled!" << LL_ENDL;
@@ -1333,6 +1399,7 @@ BOOL LLImageGL::createGLTexture()
 	if(mTexName)
 	{
 		LLImageGL::deleteTextures(1, (reinterpret_cast<GLuint*>(&mTexName))) ;
+        mTexName = 0;
 	}
 	
 
@@ -1347,23 +1414,24 @@ BOOL LLImageGL::createGLTexture()
 	return TRUE ;
 }
 
-static LLTrace::BlockTimerStatHandle FTM_CREATE_GL_TEXTURE2("createGLTexture(raw)");
-BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename/*=0*/, BOOL to_create, S32 category)
+BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename/*=0*/, BOOL to_create, S32 category, bool defer_copy, LLGLuint* tex_name)
 {
-	LL_RECORD_BLOCK_TIME(FTM_CREATE_GL_TEXTURE2);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
+    checkActiveThread();
+
 	if (gGLManager.mIsDisabled)
 	{
 		LL_WARNS() << "Trying to create a texture while GL is disabled!" << LL_ENDL;
 		return FALSE;
 	}
 
-	mGLTextureCreated = false ;
 	llassert(gGLManager.mInited);
 	stop_glerror();
 
 	if (!imageraw || imageraw->isBufferInvalid())
 	{
 		LL_WARNS() << "Trying to create a texture from invalid image data" << LL_ENDL;
+        mGLTextureCreated = false;
 		return FALSE;
 	}
 
@@ -1376,6 +1444,7 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S
 	// Actual image width/height = raw image width/height * 2^discard_level
 	S32 raw_w = imageraw->getWidth() ;
 	S32 raw_h = imageraw->getHeight() ;
+
 	S32 w = raw_w << discard_level;
 	S32 h = raw_h << discard_level;
 
@@ -1383,6 +1452,7 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S
 	if (!setSize(w, h, imageraw->getComponents(), discard_level))
 	{
 		LL_WARNS() << "Trying to create a texture with incorrect dimensions!" << LL_ENDL;
+        mGLTextureCreated = false;
 		return FALSE;
 	}
 
@@ -1451,115 +1521,236 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S
 		destroyGLTexture();
 		mCurrentDiscardLevel = discard_level;	
 		mLastBindTime = sLastFrameTime;
+        mGLTextureCreated = false;
 		return TRUE ;
 	}
 
 	setCategory(category);
  	const U8* rawdata = imageraw->getData();
-	return createGLTexture(discard_level, rawdata, FALSE, usename);
+	return createGLTexture(discard_level, rawdata, FALSE, usename, defer_copy, tex_name);
 }
 
-static LLTrace::BlockTimerStatHandle FTM_CREATE_GL_TEXTURE3("createGLTexture3(data)");
-BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_hasmips, S32 usename)
+BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_hasmips, S32 usename, bool defer_copy, LLGLuint* tex_name)
+// Call with void data, vmem is allocated but unitialized
 {
-	LL_RECORD_BLOCK_TIME(FTM_CREATE_GL_TEXTURE3);
-	llassert(data_in);
-	stop_glerror();
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
+    checkActiveThread();
 
-	if (discard_level < 0)
-	{
-		llassert(mCurrentDiscardLevel >= 0);
-		discard_level = mCurrentDiscardLevel;
-	}
-	discard_level = llclamp(discard_level, 0, (S32)mMaxDiscardLevel);
+    bool main_thread = on_main_thread();
 
-	if (mTexName != 0 && discard_level == mCurrentDiscardLevel)
-	{
-		// This will only be true if the size has not changed
-		return setImage(data_in, data_hasmips);
-	}
-	
-	U32 old_name = mTexName;
-// 	S32 old_discard = mCurrentDiscardLevel;
-	
-	if (usename != 0)
-	{
-		mTexName = usename;
-	}
-	else
-	{
-		LLImageGL::generateTextures(1, &mTexName);
-		stop_glerror();
-		{
-			llverify(gGL.getTexUnit(0)->bind(this));
-			stop_glerror();
-			glTexParameteri(LLTexUnit::getInternalType(mBindTarget), GL_TEXTURE_BASE_LEVEL, 0);
-			stop_glerror();
-			glTexParameteri(LLTexUnit::getInternalType(mBindTarget), GL_TEXTURE_MAX_LEVEL,  mMaxDiscardLevel-discard_level);
-			stop_glerror();
-		}
-	}
-	if (!mTexName)
-	{
-		if (old_name)
-		{
-			sGlobalTextureMemory -= mTextureMemory;
-			LLImageGL::deleteTextures(1, &old_name);
-			disclaimMem(mTextureMemory);
-			stop_glerror();
-		}
+    if (defer_copy)
+    {
+        data_in = nullptr;
+    }
+    else
+    {
+        llassert(data_in);
+    }
 
-		LL_WARNS() << "LLImageGL::createGLTexture failed to make texture" << LL_ENDL;
-		return FALSE;
-	}
+    stop_glerror();
 
-	if (mUseMipMaps)
-	{
-		mAutoGenMips = gGLManager.mHasMipMapGeneration;
-#if LL_DARWIN
-		// On the Mac GF2 and GF4MX drivers, auto mipmap generation doesn't work right with alpha-only textures.
-		if(gGLManager.mIsGF2or4MX && (mFormatInternal == GL_ALPHA8) && (mFormatPrimary == GL_ALPHA))
-		{
-			mAutoGenMips = FALSE;
-		}
-#endif
-	}
+    if (discard_level < 0)
+    {
+        llassert(mCurrentDiscardLevel >= 0);
+        discard_level = mCurrentDiscardLevel;
+    }
+    discard_level = llclamp(discard_level, 0, (S32)mMaxDiscardLevel);
 
-	mCurrentDiscardLevel = discard_level;	
+    if (main_thread // <--- always force creation of new_texname when not on main thread ...
+        && !defer_copy // <--- ... or defer copy is set
+        && mTexName != 0 && discard_level == mCurrentDiscardLevel)
+    {
+        LL_PROFILE_ZONE_NAMED("cglt - early setImage");
+        // This will only be true if the size has not changed
+        if (tex_name != nullptr)
+        {
+            *tex_name = mTexName;
+        }
+        return setImage(data_in, data_hasmips);
+    }
 
-	if (!setImage(data_in, data_hasmips))
-	{
-		stop_glerror();
-		return FALSE;
-	}
+    GLuint old_texname = mTexName;
+    GLuint new_texname = 0;
+    if (usename != 0)
+    {
+        llassert(main_thread);
+        new_texname = usename;
+    }
+    else
+    {
+        LLImageGL::generateTextures(1, &new_texname);
+        {
+            gGL.getTexUnit(0)->bind(this, false, false, new_texname);
+            glTexParameteri(LLTexUnit::getInternalType(mBindTarget), GL_TEXTURE_BASE_LEVEL, 0);
+            glTexParameteri(LLTexUnit::getInternalType(mBindTarget), GL_TEXTURE_MAX_LEVEL, mMaxDiscardLevel - discard_level);
+        }
+    }
 
-	// Set texture options to our defaults.
-	gGL.getTexUnit(0)->setHasMipMaps(mHasMipMaps);
-	gGL.getTexUnit(0)->setTextureAddressMode(mAddressMode);
-	gGL.getTexUnit(0)->setTextureFilteringOption(mFilterOption);
+    if (tex_name != nullptr)
+    {
+        *tex_name = new_texname;
+    }
 
-	// things will break if we don't unbind after creation
-	gGL.getTexUnit(0)->unbind(mBindTarget);
-	stop_glerror();
+    if (mUseMipMaps)
+    {
+        mAutoGenMips = gGLManager.mHasMipMapGeneration;
+    }
 
-	if (old_name != 0)
-	{
-		sGlobalTextureMemory -= mTextureMemory;
+    mCurrentDiscardLevel = discard_level;
 
-		LLImageGL::deleteTextures(1, &old_name);
+    {
+        LL_PROFILE_ZONE_NAMED("cglt - late setImage");
+        if (!setImage(data_in, data_hasmips, new_texname))
+        {
+            return FALSE;
+        }
+    }
 
-		stop_glerror();
-	}
+    // Set texture options to our defaults.
+    gGL.getTexUnit(0)->setHasMipMaps(mHasMipMaps);
+    gGL.getTexUnit(0)->setTextureAddressMode(mAddressMode);
+    gGL.getTexUnit(0)->setTextureFilteringOption(mFilterOption);
 
-	disclaimMem(mTextureMemory);
-	mTextureMemory = (S32Bytes)getMipBytes(discard_level);
-	claimMem(mTextureMemory);
-	sGlobalTextureMemory += mTextureMemory;
-	mTexelsInGLTexture = getWidth() * getHeight() ;
+    // things will break if we don't unbind after creation
+    gGL.getTexUnit(0)->unbind(mBindTarget);
 
-	// mark this as bound at this point, so we don't throw it out immediately
-	mLastBindTime = sLastFrameTime;
-	return TRUE;
+    if (old_texname != 0)
+    {
+        sGlobalTextureMemory -= mTextureMemory;
+    }
+
+    //if we're on the image loading thread, be sure to delete old_texname and update mTexName on the main thread
+    if (!defer_copy)
+    {
+        if (!main_thread)
+        {
+            syncToMainThread(new_texname);
+        }
+        else
+        {
+            //not on background thread, immediately set mTexName
+            if (old_texname != 0 && old_texname != new_texname)
+            {
+                LLImageGL::deleteTextures(1, &old_texname);
+            }
+            mTexName = new_texname;
+        }
+    }
+
+    
+    mTextureMemory = (S32Bytes)getMipBytes(mCurrentDiscardLevel);
+    sGlobalTextureMemory += mTextureMemory;
+    mTexelsInGLTexture = getWidth() * getHeight();
+
+    // mark this as bound at this point, so we don't throw it out immediately
+    mLastBindTime = sLastFrameTime;
+
+    checkActiveThread();
+    return TRUE;
+}
+
+void LLImageGLThread::updateClass()
+{
+    LL_PROFILE_ZONE_SCOPED;
+
+    // update available vram one per second
+    static LLFrameTimer sTimer;
+
+    if (sTimer.getElapsedSeconds() < 1.f)
+    {
+        return;
+    }
+    
+    sTimer.reset();
+
+    auto func = []()
+    {
+        if (gGLManager.mHasATIMemInfo)
+        {
+            S32 meminfo[4];
+            glGetIntegerv(GL_TEXTURE_FREE_MEMORY_ATI, meminfo);
+            LLImageGLThread::sFreeVRAMMegabytes = meminfo[0];
+
+        }
+        else if (gGLManager.mHasNVXMemInfo)
+        {
+            S32 free_memory;
+            glGetIntegerv(GL_GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX, &free_memory);
+            LLImageGLThread::sFreeVRAMMegabytes = free_memory / 1024;
+        }
+    };
+
+    
+    // post update to background thread if available, otherwise execute immediately
+    auto queue = LL::WorkQueue::getInstance("LLImageGL");
+    if (sEnabled)
+    {
+        queue->post(func);
+    }
+    else
+    {
+        llassert(queue == nullptr);
+        func();
+    }
+}
+
+void LLImageGL::syncToMainThread(LLGLuint new_tex_name)
+{
+    LL_PROFILE_ZONE_SCOPED;
+    llassert(!on_main_thread());
+
+    {
+        LL_PROFILE_ZONE_NAMED("cglt - sync");
+        if (gGLManager.mHasSync)
+        {
+            // post a sync to the main thread (will execute before tex name swap lambda below)
+            // glFlush calls here are partly superstitious and partly backed by observation
+            // on AMD hardware
+            glFlush();
+            auto sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
+            glFlush();
+            LL::WorkQueue::postMaybe(
+                mMainQueue,
+                [=]()
+                {
+                    LL_PROFILE_ZONE_NAMED("cglt - wait sync");
+                    {
+                        LL_PROFILE_ZONE_NAMED("glWaitSync");
+                        glWaitSync(sync, 0, GL_TIMEOUT_IGNORED);
+                    }
+                    {
+                        LL_PROFILE_ZONE_NAMED("glDeleteSync");
+                        glDeleteSync(sync);
+                    }
+                });
+        }
+        else
+        {
+            glFinish();
+        }
+    }
+
+    ref();
+    LL::WorkQueue::postMaybe(
+        mMainQueue,
+        [=]()
+        {
+            LL_PROFILE_ZONE_NAMED("cglt - delete callback");
+            syncTexName(new_tex_name);
+            unref();
+        });
+}
+
+void LLImageGL::syncTexName(LLGLuint texname)
+{
+    if (texname != 0)
+    {
+        if (mTexName != 0 && mTexName != texname)
+        {
+            LLImageGL::deleteTextures(1, &mTexName);
+        }
+        mTexName = texname;
+    }
 }
 
 BOOL LLImageGL::readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool compressed_ok) const
@@ -1673,37 +1864,29 @@ BOOL LLImageGL::readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool compre
 	return TRUE ;
 }
 
-void LLImageGL::deleteDeadTextures()
-{
-	bool reset = false;
-
-	if (reset)
-	{
-		gGL.getTexUnit(0)->activate();
-	}
-}
-		
 void LLImageGL::destroyGLTexture()
 {
+    checkActiveThread();
+
 	if (mTexName != 0)
 	{
 		if(mTextureMemory != S32Bytes(0))
 		{
 			sGlobalTextureMemory -= mTextureMemory;
-			disclaimMem(mTextureMemory);
 			mTextureMemory = (S32Bytes)0;
 		}
 		
-		LLImageGL::deleteTextures(1, &mTexName);			
+		LLImageGL::deleteTextures(1, &mTexName);
 		mCurrentDiscardLevel = -1 ; //invalidate mCurrentDiscardLevel.
 		mTexName = 0;		
 		mGLTextureCreated = FALSE ;
-	}	
+	}
 }
 
 //force to invalidate the gl texture, most likely a sculpty texture
 void LLImageGL::forceToInvalidateGLTexture()
 {
+    checkActiveThread();
 	if (mTexName != 0)
 	{
 		destroyGLTexture();
@@ -1878,6 +2061,7 @@ void LLImageGL::calcAlphaChannelOffsetAndStride()
     case GL_LUMINANCE_ALPHA:
         mAlphaStride = 2;
         break;
+    case GL_RED:
     case GL_RGB:
     case GL_SRGB:
         mNeedsAlphaAndPickMask = FALSE;
@@ -2043,7 +2227,6 @@ U32 LLImageGL::createPickMask(S32 pWidth, S32 pHeight)
 	U32 size = pick_width * pick_height;
 	size = (size + 7) / 8; // pixelcount-to-bits
 	mPickMask = new U8[size];
-	claimMem(size);
 	mPickMaskWidth = pick_width - 1;
 	mPickMaskHeight = pick_height - 1;
 
@@ -2058,7 +2241,6 @@ void LLImageGL::freePickMask()
 	// pickmask validity depends on old image size, delete it
 	if (mPickMask != NULL)
 	{
-		disclaimMem((mPickMaskWidth * mPickMaskHeight + 7) / 8);
 		delete [] mPickMask;
 	}
 	mPickMask = NULL;
@@ -2182,6 +2364,12 @@ void LLImageGL::resetCurTexSizebar()
 	sCurTexPickSize = -1 ;
 }
 //----------------------------------------------------------------------------
+#if LL_IMAGEGL_THREAD_CHECK
+void LLImageGL::checkActiveThread()
+{
+    llassert(mActiveThread == LLThread::currentID());
+}
+#endif
 
 //----------------------------------------------------------------------------
 
@@ -2235,3 +2423,38 @@ void LLImageGL::resetCurTexSizebar()
 		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
 		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL,  nummips);
 */  
+
+std::atomic<S32> LLImageGLThread::sFreeVRAMMegabytes(4096); //if free vram is unknown, default to 4GB
+
+LLImageGLThread::LLImageGLThread(LLWindow* window)
+    // We want exactly one thread, but a very large capacity: we never want
+    // anyone, especially inner-loop render code, to have to block on post()
+    // because we're full.
+    : ThreadPool("LLImageGL", 1, 1024*1024)
+    , mWindow(window)
+{
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
+    sEnabled = true;
+    mFinished = false;
+
+    mContext = mWindow->createSharedContext();
+    ThreadPool::start();
+}
+
+void LLImageGLThread::run()
+{
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
+    // We must perform setup on this thread before actually servicing our
+    // WorkQueue, likewise cleanup afterwards.
+    mWindow->makeContextCurrent(mContext);
+    gGL.init(false);
+    ThreadPool::run();
+    gGL.shutdown();
+    mWindow->destroySharedContext(mContext);
+}
+
+S32 LLImageGLThread::getFreeVRAMMegabytes()
+{
+    return sFreeVRAMMegabytes;
+}
+
diff --git a/indra/llrender/llimagegl.h b/indra/llrender/llimagegl.h
index 61ddc8d59b7e9e63bdc0b0340f6ce68f4f4335be..4d5b60d6bc7c8db350aa7b9db4748a9306bbc00a 100644
--- a/indra/llrender/llimagegl.h
+++ b/indra/llrender/llimagegl.h
@@ -35,21 +35,26 @@
 #include "llrefcount.h"
 #include "v2math.h"
 #include "llunits.h"
-
+#include "llthreadsafequeue.h"
 #include "llrender.h"
-class LLTextureAtlas ;
+#include "threadpool.h"
+#include "workqueue.h"
+
+#define LL_IMAGEGL_THREAD_CHECK 0 //set to 1 to enable thread debugging for ImageGL
+
+class LLWindow;
+
 #define BYTES_TO_MEGA_BYTES(x) ((x) >> 20)
 #define MEGA_BYTES_TO_BYTES(x) ((x) << 20)
 
 //============================================================================
-class LLImageGL : public LLRefCount, public LLTrace::MemTrackable<LLImageGL>
+class LLImageGL : public LLRefCount
 {
 	friend class LLTexUnit;
 public:
 	// These 2 functions replace glGenTextures() and glDeleteTextures()
 	static void generateTextures(S32 numTextures, U32 *textures);
-	static void deleteTextures(S32 numTextures, U32 *textures);
-	static void deleteDeadTextures();
+	static void deleteTextures(S32 numTextures, const U32 *textures);
 
 	// Size calculation
 	static S32 dataFormatBits(S32 dataformat);
@@ -102,17 +107,21 @@ class LLImageGL : public LLRefCount, public LLTrace::MemTrackable<LLImageGL>
 	void setAllowCompression(bool allow) { mAllowCompression = allow; }
 
 	static void setManualImage(U32 target, S32 miplevel, S32 intformat, S32 width, S32 height, U32 pixformat, U32 pixtype, const void *pixels, bool allow_compression = true);
-
+    
 	BOOL createGLTexture() ;
 	BOOL createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename = 0, BOOL to_create = TRUE,
-		S32 category = sMaxCategories-1);
-	BOOL createGLTexture(S32 discard_level, const U8* data, BOOL data_hasmips = FALSE, S32 usename = 0);
+		S32 category = sMaxCategories-1, bool defer_copy = false, LLGLuint* tex_name = nullptr);
+	BOOL createGLTexture(S32 discard_level, const U8* data, BOOL data_hasmips = FALSE, S32 usename = 0, bool defer_copy = false, LLGLuint* tex_name = nullptr);
 	void setImage(const LLImageRaw* imageraw);
-	BOOL setImage(const U8* data_in, BOOL data_hasmips = FALSE);
-	BOOL setSubImage(const LLImageRaw* imageraw, S32 x_pos, S32 y_pos, S32 width, S32 height, BOOL force_fast_update = FALSE);
-	BOOL setSubImage(const U8* datap, S32 data_width, S32 data_height, S32 x_pos, S32 y_pos, S32 width, S32 height, BOOL force_fast_update = FALSE);
+	BOOL setImage(const U8* data_in, BOOL data_hasmips = FALSE, S32 usename = 0);
+	BOOL setSubImage(const LLImageRaw* imageraw, S32 x_pos, S32 y_pos, S32 width, S32 height, BOOL force_fast_update = FALSE, LLGLuint use_name = 0);
+	BOOL setSubImage(const U8* datap, S32 data_width, S32 data_height, S32 x_pos, S32 y_pos, S32 width, S32 height, BOOL force_fast_update = FALSE, LLGLuint use_name = 0);
 	BOOL setSubImageFromFrameBuffer(S32 fb_x, S32 fb_y, S32 x_pos, S32 y_pos, S32 width, S32 height);
-	
+
+    // wait for gl commands to finish on current thread and push
+    // a lambda to main thread to swap mNewTexName and mTexName
+    void syncToMainThread(LLGLuint new_tex_name);
+
 	// Read back a raw image for this discard level, if it exists
 	BOOL readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool compressed_ok) const;
 	void destroyGLTexture();
@@ -184,6 +193,12 @@ class LLImageGL : public LLRefCount, public LLTrace::MemTrackable<LLImageGL>
 	BOOL preAddToAtlas(S32 discard_level, const LLImageRaw* raw_image);
 	void postAddToAtlas() ;	
 
+#if LL_IMAGEGL_THREAD_CHECK
+    // thread debugging
+    std::thread::id mActiveThread;
+    void checkActiveThread();
+#endif
+
 public:
 	// Various GL/Rendering options
 	S32Bytes mTextureMemory;
@@ -194,6 +209,7 @@ class LLImageGL : public LLRefCount, public LLTrace::MemTrackable<LLImageGL>
 	void freePickMask();
 
 	LLPointer<LLImageRaw> mSaveData; // used for destroyGL/restoreGL
+	LL::WorkQueue::weak_t mMainQueue;
 	U8* mPickMask;  //downsampled bitmap approximation of alpha channel.  NULL if no alpha channel
 	U16 mPickMaskWidth;
 	U16 mPickMaskHeight;
@@ -208,8 +224,9 @@ class LLImageGL : public LLRefCount, public LLTrace::MemTrackable<LLImageGL>
 
 	bool     mGLTextureCreated ;
 	LLGLuint mTexName;
+    //LLGLuint mNewTexName = 0; // tex name set by background thread to be applied in main thread
 	U16      mWidth;
-	U16      mHeight;	
+	U16      mHeight;
 	S8       mCurrentDiscardLevel;
 	
 	S8       mDiscardLevelInAtlas;
@@ -265,7 +282,7 @@ class LLImageGL : public LLRefCount, public LLTrace::MemTrackable<LLImageGL>
 #endif
 
 public:
-	static void initClass(S32 num_catagories, BOOL skip_analyze_alpha = false); 
+	static void initClass(LLWindow* window, S32 num_catagories, BOOL skip_analyze_alpha = false, bool multi_threaded = false); 
 	static void cleanupClass() ;
 
 private:
@@ -287,6 +304,9 @@ class LLImageGL : public LLRefCount, public LLTrace::MemTrackable<LLImageGL>
 	
     void setTexName(GLuint texName) { mTexName = texName; }
 
+    //similar to setTexName, but will call deleteTextures on mTexName if mTexName is not 0 or texname
+    void syncTexName(LLGLuint texname);
+
 	//for debug use: show texture size distribution 
 	//----------------------------------------
 	static S32 sCurTexSizeBar ;
@@ -301,4 +321,36 @@ class LLImageGL : public LLRefCount, public LLTrace::MemTrackable<LLImageGL>
 
 };
 
+class LLImageGLThread : public LLSimpleton<LLImageGLThread>, LL::ThreadPool
+{
+public:
+    // follows gSavedSettings "RenderGLMultiThreaded"
+    static bool sEnabled;
+    
+    // app should call this function periodically
+    static void updateClass();
+
+    // free video memory in megabytes
+    static std::atomic<S32> sFreeVRAMMegabytes;
+
+    LLImageGLThread(LLWindow* window);
+
+    // post a function to be executed on the LLImageGL background thread
+    template <typename CALLABLE>
+    bool post(CALLABLE&& func)
+    {
+        return getQueue().postIfOpen(std::forward<CALLABLE>(func));
+    }
+
+    void run() override;
+
+    static S32 getFreeVRAMMegabytes();
+
+private:
+    LLWindow* mWindow;
+    void* mContext = nullptr;
+    LLAtomicBool mFinished;
+};
+
+
 #endif // LL_LLIMAGEGL_H
diff --git a/indra/llrender/llrender.cpp b/indra/llrender/llrender.cpp
index 03b6aac20c3d2883a4be39ef86e10549e69f68f7..72cca1f2a29bdb61317b10950fd26a1684f07d5c 100644
--- a/indra/llrender/llrender.cpp
+++ b/indra/llrender/llrender.cpp
@@ -36,7 +36,18 @@
 #include "lltexture.h"
 #include "llshadermgr.h"
 
-LLRender gGL;
+#if LL_WINDOWS
+extern void APIENTRY gl_debug_callback(GLenum source,
+                                GLenum type,
+                                GLuint id,
+                                GLenum severity,
+                                GLsizei length,
+                                const GLchar* message,
+                                GLvoid* userParam)
+;
+#endif
+
+thread_local LLRender gGL;
 
 // Handy copies of last good GL matrices
 F32	gGLModelView[16];
@@ -71,18 +82,6 @@ static const GLint sGLAddressMode[] =
 	GL_CLAMP_TO_EDGE
 };
 
-static const GLenum sGLCompareFunc[] =
-{
-	GL_NEVER,
-	GL_ALWAYS,
-	GL_LESS,
-	GL_LEQUAL,
-	GL_EQUAL,
-	GL_NOTEQUAL,
-	GL_GEQUAL,
-	GL_GREATER
-};
-
 const U32 immediate_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_COLOR | LLVertexBuffer::MAP_TEXCOORD0;
 
 static const GLenum sGLBlendFactor[] =
@@ -102,10 +101,7 @@ static const GLenum sGLBlendFactor[] =
 };
 
 LLTexUnit::LLTexUnit(S32 index)
-	: mCurrTexType(TT_NONE), mCurrBlendType(TB_MULT), 
-	mCurrColorOp(TBO_MULT), mCurrAlphaOp(TBO_MULT),
-	mCurrColorSrc1(TBS_TEX_COLOR), mCurrColorSrc2(TBS_PREV_COLOR),
-	mCurrAlphaSrc1(TBS_TEX_ALPHA), mCurrAlphaSrc2(TBS_PREV_ALPHA),
+	: mCurrTexType(TT_NONE),
     mCurrColorScale(1), mCurrAlphaScale(1), mCurrTexture(0), mTexColorSpace(TCS_LINEAR),
 	mHasMipMaps(false),
 	mIndex(index)
@@ -128,42 +124,15 @@ void LLTexUnit::refreshState(void)
 	
 	glActiveTextureARB(GL_TEXTURE0_ARB + mIndex);
 
-	//
-	// Per apple spec, don't call glEnable/glDisable when index exceeds max texture units
-	// http://www.mailinglistarchive.com/html/mac-opengl@lists.apple.com/2008-07/msg00653.html
-	//
-	bool enableDisable = !LLGLSLShader::sNoFixedFunction && 
-		(mIndex < gGLManager.mNumTextureUnits) && mCurrTexType != LLTexUnit::TT_MULTISAMPLE_TEXTURE;
-		
 	if (mCurrTexType != TT_NONE)
 	{
-		if (enableDisable)
-		{
-			glEnable(sGLTextureType[mCurrTexType]);
-		}
-		
 		glBindTexture(sGLTextureType[mCurrTexType], mCurrTexture);
 	}
 	else
 	{
-		if (enableDisable)
-		{
-			glDisable(GL_TEXTURE_2D);
-		}
-		
 		glBindTexture(GL_TEXTURE_2D, 0);	
 	}
 
-	if (mCurrBlendType != TB_COMBINE)
-	{
-		setTextureBlendType(mCurrBlendType);
-	}
-	else
-	{
-		setTextureCombiner(mCurrColorOp, mCurrColorSrc1, mCurrColorSrc2, false);
-		setTextureCombiner(mCurrAlphaOp, mCurrAlphaSrc1, mCurrAlphaSrc2, true);
-	}
-
     setTextureColorSpace(mTexColorSpace);
 }
 
@@ -196,14 +165,6 @@ void LLTexUnit::enable(eTextureType type)
 		mCurrTexType = type;
 
 		gGL.flush();
-		if (!LLGLSLShader::sNoFixedFunction && 
-			type != LLTexUnit::TT_MULTISAMPLE_TEXTURE &&
-			mIndex < gGLManager.mNumTextureUnits)
-		{
-			stop_glerror();
-			glEnable(sGLTextureType[type]);
-			stop_glerror();
-		}
 	}
 }
 
@@ -216,21 +177,34 @@ void LLTexUnit::disable(void)
 		activate();
 		unbind(mCurrTexType);
 		gGL.flush();
-		if (!LLGLSLShader::sNoFixedFunction &&
-			mCurrTexType != LLTexUnit::TT_MULTISAMPLE_TEXTURE &&
-			mIndex < gGLManager.mNumTextureUnits)
-		{
-			glDisable(sGLTextureType[mCurrTexType]);
-		}
-
         setTextureColorSpace(TCS_LINEAR);
 		
 		mCurrTexType = TT_NONE;
 	}
 }
 
+void LLTexUnit::bindFast(LLTexture* texture)
+{
+    LLImageGL* gl_tex = texture->getGLTexture();
+
+    glActiveTextureARB(GL_TEXTURE0_ARB + mIndex);
+    gGL.mCurrTextureUnitIndex = mIndex;
+    mCurrTexture = gl_tex->getTexName();
+    if (!mCurrTexture)
+    {
+        LL_PROFILE_ZONE_NAMED("MISSING TEXTURE");
+        //if deleted, will re-generate it immediately
+        texture->forceImmediateUpdate();
+        gl_tex->forceUpdateBindStats();
+        texture->bindDefaultImage(mIndex);
+    }
+    glBindTexture(sGLTextureType[gl_tex->getTarget()], mCurrTexture);
+    mHasMipMaps = gl_tex->mHasMipMaps;
+}
+
 bool LLTexUnit::bind(LLTexture* texture, bool for_rendering, bool forceBind)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
 	stop_glerror();
 	if (mIndex >= 0)
 	{
@@ -294,18 +268,20 @@ bool LLTexUnit::bind(LLTexture* texture, bool for_rendering, bool forceBind)
 	return true;
 }
 
-bool LLTexUnit::bind(LLImageGL* texture, bool for_rendering, bool forceBind)
+bool LLTexUnit::bind(LLImageGL* texture, bool for_rendering, bool forceBind, S32 usename)
 {
 	stop_glerror();
 	if (mIndex < 0) return false;
 
+    U32 texname = usename ? usename : texture->getTexName();
+
 	if(!texture)
 	{
 		LL_DEBUGS() << "NULL LLTexUnit::bind texture" << LL_ENDL;
 		return false;
 	}
 
-	if(!texture->getTexName())
+	if(!texname)
 	{
 		if(LLImageGL::sDefaultGLTexture && LLImageGL::sDefaultGLTexture->getTexName())
 		{
@@ -315,7 +291,7 @@ bool LLTexUnit::bind(LLImageGL* texture, bool for_rendering, bool forceBind)
 		return false ;
 	}
 
-	if ((mCurrTexture != texture->getTexName()) || forceBind)
+	if ((mCurrTexture != texname) || forceBind)
 	{
 		gGL.flush();
 		stop_glerror();
@@ -323,7 +299,7 @@ bool LLTexUnit::bind(LLImageGL* texture, bool for_rendering, bool forceBind)
 		stop_glerror();
 		enable(texture->getTarget());
 		stop_glerror();
-		mCurrTexture = texture->getTexName();
+		mCurrTexture = texname;
 		glBindTexture(sGLTextureType[texture->getTarget()], mCurrTexture);
 		stop_glerror();
 		texture->updateBindStats(texture->mTextureMemory);		
@@ -447,7 +423,7 @@ void LLTexUnit::unbind(eTextureType type)
 
         // Always make sure our texture color space is reset to linear.  SRGB sampling should be opt-in in the vast majority of cases.  Also prevents color space "popping".
         mTexColorSpace = TCS_LINEAR;
-		if (LLGLSLShader::sNoFixedFunction && type == LLTexUnit::TT_TEXTURE)
+		if (type == LLTexUnit::TT_TEXTURE)
 		{
 			glBindTexture(sGLTextureType[type], sWhiteTexture);
 		}
@@ -459,6 +435,28 @@ void LLTexUnit::unbind(eTextureType type)
 	}
 }
 
+void LLTexUnit::unbindFast(eTextureType type)
+{
+    activate();
+
+    // Disabled caching of binding state.
+    if (mCurrTexType == type)
+    {
+        mCurrTexture = 0;
+
+        // Always make sure our texture color space is reset to linear.  SRGB sampling should be opt-in in the vast majority of cases.  Also prevents color space "popping".
+        mTexColorSpace = TCS_LINEAR;
+        if (type == LLTexUnit::TT_TEXTURE)
+        {
+            glBindTexture(sGLTextureType[type], sWhiteTexture);
+        }
+        else
+        {
+            glBindTexture(sGLTextureType[type], 0);
+        }
+    }
+}
+
 void LLTexUnit::setTextureAddressMode(eTextureAddressMode mode)
 {
 	if (mIndex < 0 || mCurrTexture == 0) return;
@@ -537,55 +535,6 @@ void LLTexUnit::setTextureFilteringOption(LLTexUnit::eTextureFilterOptions optio
 	}
 }
 
-void LLTexUnit::setTextureBlendType(eTextureBlendType type)
-{
-	if (LLGLSLShader::sNoFixedFunction)
-	{ //texture blend type means nothing when using shaders
-		return;
-	}
-
-	if (mIndex < 0) return;
-
-	// Do nothing if it's already correctly set.
-	if (mCurrBlendType == type && !gGL.mDirty)
-	{
-		return;
-	}
-
-	gGL.flush();
-
-	activate();
-	mCurrBlendType = type;
-	S32 scale_amount = 1;
-	switch (type) 
-	{
-		case TB_REPLACE:
-			glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
-			break;
-		case TB_ADD:
-			glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_ADD);
-			break;
-		case TB_MULT:
-			glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
-			break;
-		case TB_MULT_X2:
-			glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
-			scale_amount = 2;
-			break;
-		case TB_ALPHA_BLEND:
-			glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
-			break;
-		case TB_COMBINE:
-			glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);
-			break;
-		default:
-			LL_ERRS() << "Unknown Texture Blend Type: " << type << LL_ENDL;
-			break;
-	}
-	setColorScale(scale_amount);
-	setAlphaScale(1);
-}
-
 GLint LLTexUnit::getTextureSource(eTextureBlendSrc src)
 {
 	switch(src)
@@ -662,159 +611,6 @@ GLint LLTexUnit::getTextureSourceType(eTextureBlendSrc src, bool isAlpha)
 	}
 }
 
-void LLTexUnit::setTextureCombiner(eTextureBlendOp op, eTextureBlendSrc src1, eTextureBlendSrc src2, bool isAlpha)
-{
-	if (LLGLSLShader::sNoFixedFunction)
-	{ //register combiners do nothing when not using fixed function
-		return;
-	}	
-
-	if (mIndex < 0) return;
-
-	activate();
-	if (mCurrBlendType != TB_COMBINE || gGL.mDirty)
-	{
-		mCurrBlendType = TB_COMBINE;
-		gGL.flush();
-		glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);
-	}
-	
-	// We want an early out, because this function does a LOT of stuff.
-	if ( ( (isAlpha && (mCurrAlphaOp == op) && (mCurrAlphaSrc1 == src1) && (mCurrAlphaSrc2 == src2))
-			|| (!isAlpha && (mCurrColorOp == op) && (mCurrColorSrc1 == src1) && (mCurrColorSrc2 == src2)) ) && !gGL.mDirty)
-	{
-		return;
-	}
-
-	gGL.flush();
-
-	// Get the gl source enums according to the eTextureBlendSrc sources passed in
-	GLint source1 = getTextureSource(src1);
-	GLint source2 = getTextureSource(src2);
-	// Get the gl operand enums according to the eTextureBlendSrc sources passed in
-	GLint operand1 = getTextureSourceType(src1, isAlpha);
-	GLint operand2 = getTextureSourceType(src2, isAlpha);
-	// Default the scale amount to 1
-	S32 scale_amount = 1;
-	GLenum comb_enum, src0_enum, src1_enum, src2_enum, operand0_enum, operand1_enum, operand2_enum;
-	
-	if (isAlpha)
-	{
-		// Set enums to ALPHA ones
-		comb_enum = GL_COMBINE_ALPHA_ARB;
-		src0_enum = GL_SOURCE0_ALPHA_ARB;
-		src1_enum = GL_SOURCE1_ALPHA_ARB;
-		src2_enum = GL_SOURCE2_ALPHA_ARB;
-		operand0_enum = GL_OPERAND0_ALPHA_ARB;
-		operand1_enum = GL_OPERAND1_ALPHA_ARB;
-		operand2_enum = GL_OPERAND2_ALPHA_ARB;
-
-		// cache current combiner
-		mCurrAlphaOp = op;
-		mCurrAlphaSrc1 = src1;
-		mCurrAlphaSrc2 = src2;
-	}
-	else 
-	{
-		// Set enums to RGB ones
-		comb_enum = GL_COMBINE_RGB_ARB;
-		src0_enum = GL_SOURCE0_RGB_ARB;
-		src1_enum = GL_SOURCE1_RGB_ARB;
-		src2_enum = GL_SOURCE2_RGB_ARB;
-		operand0_enum = GL_OPERAND0_RGB_ARB;
-		operand1_enum = GL_OPERAND1_RGB_ARB;
-		operand2_enum = GL_OPERAND2_RGB_ARB;
-
-		// cache current combiner
-		mCurrColorOp = op;
-		mCurrColorSrc1 = src1;
-		mCurrColorSrc2 = src2;
-	}
-
-	switch(op)
-	{
-		case TBO_REPLACE:
-			// Slightly special syntax (no second sources), just set all and return.
-			glTexEnvi(GL_TEXTURE_ENV, comb_enum, GL_REPLACE);
-			glTexEnvi(GL_TEXTURE_ENV, src0_enum, source1);
-			glTexEnvi(GL_TEXTURE_ENV, operand0_enum, operand1);
-			(isAlpha) ? setAlphaScale(1) : setColorScale(1);
-			return;
-
-		case TBO_MULT:
-			glTexEnvi(GL_TEXTURE_ENV, comb_enum, GL_MODULATE);
-			break;
-
-		case TBO_MULT_X2:
-			glTexEnvi(GL_TEXTURE_ENV, comb_enum, GL_MODULATE);
-			scale_amount = 2;
-			break;
-
-		case TBO_MULT_X4:
-			glTexEnvi(GL_TEXTURE_ENV, comb_enum, GL_MODULATE);
-			scale_amount = 4;
-			break;
-
-		case TBO_ADD:
-			glTexEnvi(GL_TEXTURE_ENV, comb_enum, GL_ADD);
-			break;
-
-		case TBO_ADD_SIGNED:
-			glTexEnvi(GL_TEXTURE_ENV, comb_enum, GL_ADD_SIGNED_ARB);
-			break;
-
-		case TBO_SUBTRACT:
-			glTexEnvi(GL_TEXTURE_ENV, comb_enum, GL_SUBTRACT_ARB);
-			break;
-
-		case TBO_LERP_VERT_ALPHA:
-			glTexEnvi(GL_TEXTURE_ENV, comb_enum, GL_INTERPOLATE);
-			glTexEnvi(GL_TEXTURE_ENV, src2_enum, GL_PRIMARY_COLOR_ARB);
-			glTexEnvi(GL_TEXTURE_ENV, operand2_enum, GL_SRC_ALPHA);
-			break;
-
-		case TBO_LERP_TEX_ALPHA:
-			glTexEnvi(GL_TEXTURE_ENV, comb_enum, GL_INTERPOLATE);
-			glTexEnvi(GL_TEXTURE_ENV, src2_enum, GL_TEXTURE);
-			glTexEnvi(GL_TEXTURE_ENV, operand2_enum, GL_SRC_ALPHA);
-			break;
-
-		case TBO_LERP_PREV_ALPHA:
-			glTexEnvi(GL_TEXTURE_ENV, comb_enum, GL_INTERPOLATE);
-			glTexEnvi(GL_TEXTURE_ENV, src2_enum, GL_PREVIOUS_ARB);
-			glTexEnvi(GL_TEXTURE_ENV, operand2_enum, GL_SRC_ALPHA);
-			break;
-
-		case TBO_LERP_CONST_ALPHA:
-			glTexEnvi(GL_TEXTURE_ENV, comb_enum, GL_INTERPOLATE);
-			glTexEnvi(GL_TEXTURE_ENV, src2_enum, GL_CONSTANT_ARB);
-			glTexEnvi(GL_TEXTURE_ENV, operand2_enum, GL_SRC_ALPHA);
-			break;
-
-		case TBO_LERP_VERT_COLOR:
-			glTexEnvi(GL_TEXTURE_ENV, comb_enum, GL_INTERPOLATE);
-			glTexEnvi(GL_TEXTURE_ENV, src2_enum, GL_PRIMARY_COLOR_ARB);
-			glTexEnvi(GL_TEXTURE_ENV, operand2_enum, (isAlpha) ? GL_SRC_ALPHA : GL_SRC_COLOR);
-			break;
-
-		default:
-			LL_WARNS() << "Unknown eTextureBlendOp: " << op << ".  Setting op to replace." << LL_ENDL;
-			// Slightly special syntax (no second sources), just set all and return.
-			glTexEnvi(GL_TEXTURE_ENV, comb_enum, GL_REPLACE);
-			glTexEnvi(GL_TEXTURE_ENV, src0_enum, source1);
-			glTexEnvi(GL_TEXTURE_ENV, operand0_enum, operand1);
-			(isAlpha) ? setAlphaScale(1) : setColorScale(1);
-			return;
-	}
-
-	// Set sources, operands, and scale accordingly
-	glTexEnvi(GL_TEXTURE_ENV, src0_enum, source1);
-	glTexEnvi(GL_TEXTURE_ENV, operand0_enum, operand1);
-	glTexEnvi(GL_TEXTURE_ENV, src1_enum, source2);
-	glTexEnvi(GL_TEXTURE_ENV, operand1_enum, operand2);
-	(isAlpha) ? setAlphaScale(scale_amount) : setColorScale(scale_amount);
-}
-
 void LLTexUnit::setColorScale(S32 scale)
 {
 	if (mCurrColorScale != scale || gGL.mDirty)
@@ -903,26 +699,12 @@ LLLightState::LLLightState(S32 index)
 
 void LLLightState::enable()
 {
-	if (!mEnabled)
-	{
-		if (!LLGLSLShader::sNoFixedFunction)
-		{
-			glEnable(GL_LIGHT0+mIndex);
-		}
-		mEnabled = true;
-	}
+	mEnabled = true;
 }
 
 void LLLightState::disable()
 {
-	if (mEnabled)
-	{
-		if (!LLGLSLShader::sNoFixedFunction)
-		{
-			glDisable(GL_LIGHT0+mIndex);
-		}
-		mEnabled = false;
-	}
+	mEnabled = false;
 }
 
 void LLLightState::setDiffuse(const LLColor4& diffuse)
@@ -931,10 +713,6 @@ void LLLightState::setDiffuse(const LLColor4& diffuse)
 	{
 		++gGL.mLightHash;
 		mDiffuse = diffuse;
-		if (!LLGLSLShader::sNoFixedFunction)
-		{
-			glLightfv(GL_LIGHT0+mIndex, GL_DIFFUSE, mDiffuse.mV);
-		}
 	}
 }
 
@@ -962,10 +740,6 @@ void LLLightState::setAmbient(const LLColor4& ambient)
 	{
 		++gGL.mLightHash;
 		mAmbient = ambient;
-		if (!LLGLSLShader::sNoFixedFunction)
-		{
-			glLightfv(GL_LIGHT0+mIndex, GL_AMBIENT, mAmbient.mV);
-		}
 	}
 }
 
@@ -975,10 +749,6 @@ void LLLightState::setSpecular(const LLColor4& specular)
 	{
 		++gGL.mLightHash;
 		mSpecular = specular;
-		if (!LLGLSLShader::sNoFixedFunction)
-		{
-			glLightfv(GL_LIGHT0+mIndex, GL_SPECULAR, mSpecular.mV);
-		}
 	}
 }
 
@@ -987,20 +757,11 @@ void LLLightState::setPosition(const LLVector4& position)
 	//always set position because modelview matrix may have changed
 	++gGL.mLightHash;
 	mPosition = position;
-	if (!LLGLSLShader::sNoFixedFunction)
-	{
-		glLightfv(GL_LIGHT0+mIndex, GL_POSITION, mPosition.mV);
-	}
-	else
-	{ //transform position by current modelview matrix
-		glh::vec4f pos(position.mV);
-
-		const glh::matrix4f& mat = gGL.getModelviewMatrix();
-		mat.mult_matrix_vec(pos);
-
-		mPosition.set(pos.v);
-	}
-
+	//transform position by current modelview matrix
+	glh::vec4f pos(position.mV);
+	const glh::matrix4f& mat = gGL.getModelviewMatrix();
+	mat.mult_matrix_vec(pos);
+	mPosition.set(pos.v);
 }
 
 void LLLightState::setConstantAttenuation(const F32& atten)
@@ -1009,10 +770,6 @@ void LLLightState::setConstantAttenuation(const F32& atten)
 	{
 		mConstantAtten = atten;
 		++gGL.mLightHash;
-		if (!LLGLSLShader::sNoFixedFunction)
-		{
-			glLightf(GL_LIGHT0+mIndex, GL_CONSTANT_ATTENUATION, atten);
-		}
 	}
 }
 
@@ -1022,10 +779,6 @@ void LLLightState::setLinearAttenuation(const F32& atten)
 	{
 		++gGL.mLightHash;
 		mLinearAtten = atten;
-		if (!LLGLSLShader::sNoFixedFunction)
-		{
-			glLightf(GL_LIGHT0+mIndex, GL_LINEAR_ATTENUATION, atten);
-		}
 	}
 }
 
@@ -1035,10 +788,6 @@ void LLLightState::setQuadraticAttenuation(const F32& atten)
 	{
 		++gGL.mLightHash;
 		mQuadraticAtten = atten;
-		if (!LLGLSLShader::sNoFixedFunction)
-		{
-			glLightf(GL_LIGHT0+mIndex, GL_QUADRATIC_ATTENUATION, atten);
-		}
 	}
 }
 
@@ -1048,10 +797,6 @@ void LLLightState::setSpotExponent(const F32& exponent)
 	{
 		++gGL.mLightHash;
 		mSpotExponent = exponent;
-		if (!LLGLSLShader::sNoFixedFunction)
-		{
-			glLightf(GL_LIGHT0+mIndex, GL_SPOT_EXPONENT, exponent);
-		}
 	}
 }
 
@@ -1061,10 +806,6 @@ void LLLightState::setSpotCutoff(const F32& cutoff)
 	{
 		++gGL.mLightHash;
 		mSpotCutoff = cutoff;
-		if (!LLGLSLShader::sNoFixedFunction)
-		{
-			glLightf(GL_LIGHT0+mIndex, GL_SPOT_CUTOFF, cutoff);
-		}
 	}
 }
 
@@ -1073,19 +814,12 @@ void LLLightState::setSpotDirection(const LLVector3& direction)
 	//always set direction because modelview matrix may have changed
 	++gGL.mLightHash;
 	mSpotDirection = direction;
-	if (!LLGLSLShader::sNoFixedFunction)
-	{
-		glLightfv(GL_LIGHT0+mIndex, GL_SPOT_DIRECTION, direction.mV);
-	}
-	else
-	{ //transform direction by current modelview matrix
-		glh::vec3f dir(direction.mV);
+	//transform direction by current modelview matrix
+	glh::vec3f dir(direction.mV);
+	const glh::matrix4f& mat = gGL.getModelviewMatrix();
+	mat.mult_matrix_dir(dir);
 
-		const glh::matrix4f& mat = gGL.getModelviewMatrix();
-		mat.mult_matrix_dir(dir);
-
-		mSpotDirection.set(dir.v);
-	}
+	mSpotDirection.set(dir.v);
 }
 
 LLRender::LLRender()
@@ -1113,8 +847,6 @@ LLRender::LLRender()
 		mCurrColorMask[i] = true;
 	}
 
-	mCurrAlphaFunc = CF_DEFAULT;
-	mCurrAlphaFuncVal = 0.01f;
 	mCurrBlendColorSFactor = BF_UNDEF;
 	mCurrBlendAlphaSFactor = BF_UNDEF;
 	mCurrBlendColorDFactor = BF_UNDEF;
@@ -1137,8 +869,25 @@ LLRender::~LLRender()
 	shutdown();
 }
 
-void LLRender::init()
+void LLRender::init(bool needs_vertex_buffer)
 {
+#if LL_WINDOWS
+    if (gGLManager.mHasDebugOutput && gDebugGL)
+    { //setup debug output callback
+        //glDebugMessageControlARB(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_LOW_ARB, 0, NULL, GL_TRUE);
+        glDebugMessageCallbackARB((GLDEBUGPROCARB) gl_debug_callback, NULL);
+        glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB);
+    }
+#endif
+
+    glPixelStorei(GL_PACK_ALIGNMENT, 1);
+    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+
+    gGL.setSceneBlendType(LLRender::BT_ALPHA);
+    gGL.setAmbientLightColor(LLColor4::black);
+
+    glCullFace(GL_BACK);
+
 	if (sGLCoreProfile && !LLVertexBuffer::sUseVAO)
 	{ //bind a dummy vertex array object so we're core profile compliant
 #ifdef GL_ARB_vertex_array_object
@@ -1148,15 +897,27 @@ void LLRender::init()
 #endif
 	}
 
+    if (needs_vertex_buffer)
+    {
+        initVertexBuffer();
+    }
+}
 
-	llassert_always(mBuffer.isNull()) ;
-	stop_glerror();
-	mBuffer = new LLVertexBuffer(immediate_mask, 0);
-	mBuffer->allocateBuffer(4096, 0, TRUE);
-	mBuffer->getVertexStrider(mVerticesp);
-	mBuffer->getTexCoord0Strider(mTexcoordsp);
-	mBuffer->getColorStrider(mColorsp);
-	stop_glerror();
+void LLRender::initVertexBuffer()
+{
+    llassert_always(mBuffer.isNull());
+    stop_glerror();
+    mBuffer = new LLVertexBuffer(immediate_mask, 0);
+    mBuffer->allocateBuffer(4096, 0, TRUE);
+    mBuffer->getVertexStrider(mVerticesp);
+    mBuffer->getTexCoord0Strider(mTexcoordsp);
+    mBuffer->getColorStrider(mColorsp);
+    stop_glerror();
+}
+
+void LLRender::resetVertexBuffer()
+{
+    mBuffer = NULL;
 }
 
 void LLRender::shutdown()
@@ -1174,7 +935,7 @@ void LLRender::shutdown()
 		delete mLightState[i];
 	}
 	mLightState.clear();
-	mBuffer = NULL ;
+    resetVertexBuffer();
 }
 
 void LLRender::refreshState(void)
@@ -1192,7 +953,7 @@ void LLRender::refreshState(void)
 
 	setColorMask(mCurrColorMask[0], mCurrColorMask[1], mCurrColorMask[2], mCurrColorMask[3]);
 	
-	setAlphaRejectSettings(mCurrAlphaFunc, mCurrAlphaFuncVal);
+    flush();
 
 	mDirty = false;
 }
@@ -1243,9 +1004,7 @@ void LLRender::syncLightState()
 
 void LLRender::syncMatrices()
 {
-	stop_glerror();
-
-	static const U32 name[] = 
+    static const U32 name[] = 
 	{
 		LLShaderMgr::MODELVIEW_MATRIX,
 		LLShaderMgr::PROJECTION_MATRIX,
@@ -1382,41 +1141,6 @@ void LLRender::syncMatrices()
 			syncLightState();
 		}
 	}
-	else if (!LLGLSLShader::sNoFixedFunction)
-	{
-		static const GLenum mode[] = 
-		{
-			GL_MODELVIEW,
-			GL_PROJECTION,
-			GL_TEXTURE,
-			GL_TEXTURE,
-			GL_TEXTURE,
-			GL_TEXTURE,
-		};
-
-		for (U32 i = 0; i < MM_TEXTURE0; ++i)
-		{
-			if (mMatHash[i] != mCurMatHash[i])
-			{
-				glMatrixMode(mode[i]);
-				glLoadMatrixf(mMatrix[i][mMatIdx[i]].m);
-				mCurMatHash[i] = mMatHash[i];
-			}
-		}
-
-		for (U32 i = MM_TEXTURE0; i < NUM_MATRIX_MODES; ++i)
-		{
-			if (mMatHash[i] != mCurMatHash[i])
-			{
-				gGL.getTexUnit(i-MM_TEXTURE0)->activate();
-				glMatrixMode(mode[i]);
-				glLoadMatrixf(mMatrix[i][mMatIdx[i]].m);
-				mCurMatHash[i] = mMatHash[i];
-			}
-		}
-	}
-
-	stop_glerror();
 }
 
 void LLRender::translatef(const GLfloat& x, const GLfloat& y, const GLfloat& z)
@@ -1732,55 +1456,6 @@ void LLRender::setSceneBlendType(eBlendType type)
 	}
 }
 
-void LLRender::setAlphaRejectSettings(eCompareFunc func, F32 value)
-{
-	flush();
-
-	if (LLGLSLShader::sNoFixedFunction)
-	{ //glAlphaFunc is deprecated in OpenGL 3.3
-		return;
-	}
-
-	if (mCurrAlphaFunc != func ||
-		mCurrAlphaFuncVal != value)
-	{
-		mCurrAlphaFunc = func;
-		mCurrAlphaFuncVal = value;
-		if (func == CF_DEFAULT)
-		{
-			glAlphaFunc(GL_GREATER, 0.01f);
-		} 
-		else
-		{
-			glAlphaFunc(sGLCompareFunc[func], value);
-		}
-	}
-
-	if (gDebugGL)
-	{ //make sure cached state is correct
-		GLint cur_func = 0;
-		glGetIntegerv(GL_ALPHA_TEST_FUNC, &cur_func);
-
-		if (func == CF_DEFAULT)
-		{
-			func = CF_GREATER;
-		}
-
-		if (cur_func != sGLCompareFunc[func])
-		{
-			LL_ERRS() << "Alpha test function corrupted!" << LL_ENDL;
-		}
-
-		F32 ref = 0.f;
-		glGetFloatv(GL_ALPHA_TEST_REF, &ref);
-
-		if (ref != value)
-		{
-			LL_ERRS() << "Alpha test value corrupted!" << LL_ENDL;
-		}
-	}
-}
-
 void LLRender::blendFunc(eBlendFactor sfactor, eBlendFactor dfactor)
 {
 	llassert(sfactor < BF_UNDEF);
@@ -1848,14 +1523,11 @@ LLLightState* LLRender::getLight(U32 index)
 
 void LLRender::setAmbientLightColor(const LLColor4& color)
 {
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE
 	if (color != mAmbientLightColor)
 	{
 		++mLightHash;
 		mAmbientLightColor = color;
-		if (!LLGLSLShader::sNoFixedFunction)
-		{
-			glLightModelfv(GL_LIGHT_MODEL_AMBIENT, color.mV);
-		}
 	}
 }
 
@@ -1926,6 +1598,7 @@ void LLRender::flush()
 {
 	if (mCount > 0)
 	{
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
 		if (!mUIOffset.empty())
 		{
 			sUICalls++;
@@ -1964,25 +1637,34 @@ void LLRender::flush()
 
 		mCount = 0;
 
-		if (mBuffer->useVBOs() && !mBuffer->isLocked())
-		{ //hack to only flush the part of the buffer that was updated (relies on stream draw using buffersubdata)
-			mBuffer->getVertexStrider(mVerticesp, 0, count);
-			mBuffer->getTexCoord0Strider(mTexcoordsp, 0, count);
-			mBuffer->getColorStrider(mColorsp, 0, count);
-		}
-		
-		mBuffer->flush();
-		mBuffer->setBuffer(immediate_mask);
+        if (mBuffer)
+        {
+            if (mBuffer->useVBOs() && !mBuffer->isLocked())
+            { //hack to only flush the part of the buffer that was updated (relies on stream draw using buffersubdata)
+                mBuffer->getVertexStrider(mVerticesp, 0, count);
+                mBuffer->getTexCoord0Strider(mTexcoordsp, 0, count);
+                mBuffer->getColorStrider(mColorsp, 0, count);
+            }
+
+            mBuffer->flush();
+            mBuffer->setBuffer(immediate_mask);
+
+            if (mMode == LLRender::QUADS && sGLCoreProfile)
+            {
+                mBuffer->drawArrays(LLRender::TRIANGLES, 0, count);
+                mQuadCycle = 1;
+            }
+            else
+            {
+                mBuffer->drawArrays(mMode, 0, count);
+            }
+        }
+        else
+        {
+            // mBuffer is present in main thread and not present in an image thread
+            LL_ERRS() << "A flush call from outside main rendering thread" << LL_ENDL;
+        }
 
-		if (mMode == LLRender::QUADS && sGLCoreProfile)
-		{
-			mBuffer->drawArrays(LLRender::TRIANGLES, 0, count);
-			mQuadCycle = 1;
-		}
-		else
-		{
-			mBuffer->drawArrays(mMode, 0, count);
-		}
 		
 		mVerticesp[0] = mVerticesp[count];
 		mTexcoordsp[0] = mTexcoordsp[count];
@@ -2307,7 +1989,7 @@ void LLRender::color3fv(const GLfloat* c)
 void LLRender::diffuseColor3f(F32 r, F32 g, F32 b)
 {
 	LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
-	llassert(!LLGLSLShader::sNoFixedFunction || shader != NULL);
+	llassert(shader != NULL);
 
 	if (shader)
 	{
@@ -2322,7 +2004,7 @@ void LLRender::diffuseColor3f(F32 r, F32 g, F32 b)
 void LLRender::diffuseColor3fv(const F32* c)
 {
 	LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
-	llassert(!LLGLSLShader::sNoFixedFunction || shader != NULL);
+	llassert(shader != NULL);
 
 	if (shader)
 	{
@@ -2337,7 +2019,7 @@ void LLRender::diffuseColor3fv(const F32* c)
 void LLRender::diffuseColor4f(F32 r, F32 g, F32 b, F32 a)
 {
 	LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
-	llassert(!LLGLSLShader::sNoFixedFunction || shader != NULL);
+	llassert(shader != NULL);
 
 	if (shader)
 	{
@@ -2352,7 +2034,7 @@ void LLRender::diffuseColor4f(F32 r, F32 g, F32 b, F32 a)
 void LLRender::diffuseColor4fv(const F32* c)
 {
 	LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
-	llassert(!LLGLSLShader::sNoFixedFunction || shader != NULL);
+	llassert(shader != NULL);
 
 	if (shader)
 	{
@@ -2367,7 +2049,7 @@ void LLRender::diffuseColor4fv(const F32* c)
 void LLRender::diffuseColor4ubv(const U8* c)
 {
 	LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
-	llassert(!LLGLSLShader::sNoFixedFunction || shader != NULL);
+	llassert(shader != NULL);
 
 	if (shader)
 	{
@@ -2382,7 +2064,7 @@ void LLRender::diffuseColor4ubv(const U8* c)
 void LLRender::diffuseColor4ub(U8 r, U8 g, U8 b, U8 a)
 {
 	LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
-	llassert(!LLGLSLShader::sNoFixedFunction || shader != NULL);
+	llassert(shader != NULL);
 
 	if (shader)
 	{
diff --git a/indra/llrender/llrender.h b/indra/llrender/llrender.h
index af8568f8a3438b45c075b4390f46d05b96dd3201..9c36c230fb531b1bfa9cb49102cd4d3009a1e5f8 100644
--- a/indra/llrender/llrender.h
+++ b/indra/llrender/llrender.h
@@ -105,10 +105,7 @@ class LLTexUnit
 		TBO_LERP_VERT_ALPHA,		// Interpolate based on Vertex Alpha (VA): ( Source1 * VA + Source2 * (1-VA) )
 		TBO_LERP_TEX_ALPHA,			// Interpolate based on Texture Alpha (TA): ( Source1 * TA + Source2 * (1-TA) )
 		TBO_LERP_PREV_ALPHA,		// Interpolate based on Previous Alpha (PA): ( Source1 * PA + Source2 * (1-PA) )
-		TBO_LERP_CONST_ALPHA,		// Interpolate based on Const Alpha (CA): ( Source1 * CA + Source2 * (1-CA) )
-		TBO_LERP_VERT_COLOR			// Interpolate based on Vertex Col (VC): ( Source1 * VC + Source2 * (1-VC) )
-										// *Note* TBO_LERP_VERTEX_COLOR only works with setTextureColorBlend(),
-										// and falls back to TBO_LERP_VERTEX_ALPHA for setTextureAlphaBlend().
+		TBO_LERP_CONST_ALPHA		// Interpolate based on Const Alpha (CA): ( Source1 * CA + Source2 * (1-CA) )
 	} eTextureBlendOp;
 
 	typedef enum 
@@ -158,9 +155,20 @@ class LLTexUnit
 	
 	// Binds the LLImageGL to this texture unit 
 	// (automatically enables the unit for the LLImageGL's texture type)
-	bool bind(LLImageGL* texture, bool for_rendering = false, bool forceBind = false);
+	bool bind(LLImageGL* texture, bool for_rendering = false, bool forceBind = false, S32 usename = 0);
     bool bind(LLTexture* texture, bool for_rendering = false, bool forceBind = false);
 
+    // bind implementation for inner loops
+    // makes the following assumptions:
+    //  - No need for gGL.flush() 
+    //  - texture is not null
+    //  - gl_tex->getTexName() is not zero
+    //  - This texture is not being bound redundantly
+    //  - USE_SRGB_DECODE is disabled
+    //  - mTexOptionsDirty is false
+    //  - 
+    void bindFast(LLTexture* texture);
+
 	// Binds a cubemap to this texture unit 
 	// (automatically enables the texture unit for cubemaps)
 	bool bind(LLCubeMap* cubeMap);
@@ -177,6 +185,9 @@ class LLTexUnit
 	// (only if there's a texture of the given type currently bound)
 	void unbind(eTextureType type);
 
+    // Fast but unsafe version of unbind
+    void unbindFast(eTextureType type);
+
 	// Sets the addressing mode used to sample the texture
 	// Warning: this stays set for the bound texture forever, 
 	// make sure you want to permanently change the address mode  for the bound texture.
@@ -187,15 +198,6 @@ class LLTexUnit
 	// make sure you want to permanently change the filtering for the bound texture.
 	void setTextureFilteringOption(LLTexUnit::eTextureFilterOptions option);
 
-	void setTextureBlendType(eTextureBlendType type);
-
-	inline void setTextureColorBlend(eTextureBlendOp op, eTextureBlendSrc src1, eTextureBlendSrc src2 = TBS_PREV_COLOR)
-	{ setTextureCombiner(op, src1, src2, false); }
-
-	// NOTE: If *_COLOR enums are passed to src1 or src2, the corresponding *_ALPHA enum will be used instead.
-	inline void setTextureAlphaBlend(eTextureBlendOp op, eTextureBlendSrc src1, eTextureBlendSrc src2 = TBS_PREV_ALPHA)
-	{ setTextureCombiner(op, src1, src2, true); }
-
 	static U32 getInternalType(eTextureType type);
 
 	U32 getCurrTexture(void) { return mCurrTexture; }
@@ -212,13 +214,6 @@ class LLTexUnit
 	const S32			mIndex;
 	U32					mCurrTexture;
 	eTextureType		mCurrTexType;
-	eTextureBlendType	mCurrBlendType;
-	eTextureBlendOp		mCurrColorOp;
-	eTextureBlendSrc	mCurrColorSrc1;
-	eTextureBlendSrc	mCurrColorSrc2;
-	eTextureBlendOp		mCurrAlphaOp;
-	eTextureBlendSrc	mCurrAlphaSrc1;
-	eTextureBlendSrc	mCurrAlphaSrc2;
     eTextureColorSpace  mTexColorSpace;
 	S32					mCurrColorScale;
 	S32					mCurrAlphaScale;
@@ -229,7 +224,6 @@ class LLTexUnit
 	void setAlphaScale(S32 scale);
 	GLint getTextureSource(eTextureBlendSrc src);
 	GLint getTextureSourceType(eTextureBlendSrc src, bool isAlpha = false);
-	void setTextureCombiner(eTextureBlendOp op, eTextureBlendSrc src1, eTextureBlendSrc src2, bool isAlpha = false);
 };
 
 class LLLightState
@@ -360,7 +354,9 @@ class LLRender
 
 	LLRender();
 	~LLRender();
-	void init() ;
+    void init(bool needs_vertex_buffer);
+    void initVertexBuffer();
+    void resetVertexBuffer();
 	void shutdown();
 	
 	// Refreshes renderer state to the cached values
@@ -430,8 +426,6 @@ class LLRender
 	void setColorMask(bool writeColorR, bool writeColorG, bool writeColorB, bool writeAlpha);
 	void setSceneBlendType(eBlendType type);
 
-	void setAlphaRejectSettings(eCompareFunc func, F32 value = 0.01f);
-
 	// applies blend func to both color and alpha
 	void blendFunc(eBlendFactor sfactor, eBlendFactor dfactor);
 	// applies separate blend functions to color and alpha
@@ -482,8 +476,6 @@ class LLRender
 	U32				mMode;
 	U32				mCurrTextureUnitIndex;
 	bool				mCurrColorMask[4];
-	eCompareFunc			mCurrAlphaFunc;
-	F32				mCurrAlphaFuncVal;
 
 	LLPointer<LLVertexBuffer>	mBuffer;
 	LLStrider<LLVector3>		mVerticesp;
@@ -511,7 +503,7 @@ extern F32 gGLLastProjection[16];
 extern F32 gGLProjection[16];
 extern S32 gGLViewport[4];
 
-extern LLRender gGL;
+extern thread_local LLRender gGL;
 
 // This rotation matrix moves the default OpenGL reference frame 
 // (-Z at, Y up) to Cory's favorite reference frame (X at, Z up)
diff --git a/indra/llrender/llrender2dutils.cpp b/indra/llrender/llrender2dutils.cpp
index dd34f3e383d60ada7c0567f778f18078a775b2ee..5cb1dc6b25db6633dc8e6ddc9d52b50033a7dcf3 100644
--- a/indra/llrender/llrender2dutils.cpp
+++ b/indra/llrender/llrender2dutils.cpp
@@ -132,40 +132,15 @@ void gl_rect_2d(S32 left, S32 top, S32 right, S32 bottom, BOOL filled )
 	}
 	else
 	{
-		if( gGLManager.mATIOffsetVerticalLines )
-		{
-			// Work around bug in ATI driver: vertical lines are offset by (-1,-1)
-			gGL.begin( LLRender::LINES );
-
-				// Verticals 
-				gGL.vertex2i(left + 1, top);
-				gGL.vertex2i(left + 1, bottom);
-
-				gGL.vertex2i(right, bottom);
-				gGL.vertex2i(right, top);
-
-				// Horizontals
-				top--;
-				right--;
-				gGL.vertex2i(left, bottom);
-				gGL.vertex2i(right, bottom);
-
-				gGL.vertex2i(left, top);
-				gGL.vertex2i(right, top);
-			gGL.end();
-		}
-		else
-		{
-			top--;
-			right--;
-			gGL.begin( LLRender::LINE_STRIP );
-				gGL.vertex2i(left, top);
-				gGL.vertex2i(left, bottom);
-				gGL.vertex2i(right, bottom);
-				gGL.vertex2i(right, top);
-				gGL.vertex2i(left, top);
-			gGL.end();
-		}
+		top--;
+		right--;
+		gGL.begin( LLRender::LINE_STRIP );
+			gGL.vertex2i(left, top);
+			gGL.vertex2i(left, bottom);
+			gGL.vertex2i(right, bottom);
+			gGL.vertex2i(right, top);
+			gGL.vertex2i(left, top);
+		gGL.end();
 	}
 	stop_glerror();
 }
@@ -250,15 +225,6 @@ void gl_drop_shadow(S32 left, S32 top, S32 right, S32 bottom, const LLColor4 &st
 
 void gl_line_2d(S32 x1, S32 y1, S32 x2, S32 y2 )
 {
-	// Work around bug in ATI driver: vertical lines are offset by (-1,-1)
-	if( (x1 == x2) && gGLManager.mATIOffsetVerticalLines )
-	{
-		x1++;
-		x2++;
-		y1++;
-		y2++;
-	}
-
 	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 	
 	gGL.begin(LLRender::LINES);
@@ -269,15 +235,6 @@ void gl_line_2d(S32 x1, S32 y1, S32 x2, S32 y2 )
 
 void gl_line_2d(S32 x1, S32 y1, S32 x2, S32 y2, const LLColor4 &color )
 {
-	// Work around bug in ATI driver: vertical lines are offset by (-1,-1)
-	if( (x1 == x2) && gGLManager.mATIOffsetVerticalLines )
-	{
-		x1++;
-		x2++;
-		y1++;
-		y2++;
-	}
-
 	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 
 	gGL.color4fv( color.mV );
@@ -395,15 +352,7 @@ void gl_draw_scaled_image_with_border(S32 x, S32 y, S32 width, S32 height, LLTex
 
 	if (solid_color)
 	{
-		if (LLGLSLShader::sNoFixedFunction)
-		{
-			gSolidColorProgram.bind();
-		}
-		else
-		{
-			gGL.getTexUnit(0)->setTextureColorBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_PREV_COLOR);
-			gGL.getTexUnit(0)->setTextureAlphaBlend(LLTexUnit::TBO_MULT, LLTexUnit::TBS_TEX_ALPHA, LLTexUnit::TBS_VERT_ALPHA);
-		}
+		gSolidColorProgram.bind();
 	}
 
 	if (center_rect.mLeft == 0.f
@@ -650,14 +599,7 @@ void gl_draw_scaled_image_with_border(S32 x, S32 y, S32 width, S32 height, LLTex
 
 	if (solid_color)
 	{
-		if (LLGLSLShader::sNoFixedFunction)
-		{
-			gUIProgram.bind();
-		}
-		else
-		{
-			gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
-		}
+		gUIProgram.bind();
 	}
 }
 
@@ -774,10 +716,6 @@ void gl_draw_scaled_rotated_image(S32 x, S32 y, S32 width, S32 height, F32 degre
 
 void gl_stippled_line_3d( const LLVector3& start, const LLVector3& end, const LLColor4& color, F32 phase )
 {
-	phase = fmod(phase, 1.f);
-
-	S32 shift = S32(phase * 4.f) % 4;
-
 	// Stippled line
 	LLGLEnable stipple(GL_LINE_STIPPLE);
 	
@@ -786,11 +724,6 @@ void gl_stippled_line_3d( const LLVector3& start, const LLVector3& end, const LL
 	gGL.flush();
 	glLineWidth(2.5f);
 
-	if (!LLGLSLShader::sNoFixedFunction)
-	{
-		glLineStipple(2, 0x3333 << shift);
-	}
-
 	gGL.begin(LLRender::LINES);
 	{
 		gGL.vertex3fv( start.mV );
@@ -930,52 +863,16 @@ void gl_ring( F32 radius, F32 width, const LLColor4& center_color, const LLColor
 // Draw gray and white checkerboard with black border
 void gl_rect_2d_checkerboard(const LLRect& rect, GLfloat alpha)
 {
-	if (!LLGLSLShader::sNoFixedFunction)
-	{ 
-	// Initialize the first time this is called.
-	const S32 PIXELS = 32;
-	static GLubyte checkerboard[PIXELS * PIXELS];
-	static BOOL first = TRUE;
-	if( first )
-	{
-		for( S32 i = 0; i < PIXELS; i++ )
-		{
-			for( S32 j = 0; j < PIXELS; j++ )
-			{
-				checkerboard[i * PIXELS + j] = ((i & 1) ^ (j & 1)) * 0xFF;
-			}
-		}
-		first = FALSE;
-	}
-	
-	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
-
-	// ...white squares
-	gGL.color4f( 1.f, 1.f, 1.f, alpha );
-	gl_rect_2d(rect);
-
-	// ...gray squares
-	gGL.color4f( .7f, .7f, .7f, alpha );
-	gGL.flush();
+	//polygon stipple is deprecated, use "Checker" texture
+	LLPointer<LLUIImage> img = LLRender2D::getInstance()->getUIImage("Checker");
+	gGL.getTexUnit(0)->bind(img->getImage());
+	gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_WRAP);
+	gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
 
-		glPolygonStipple( checkerboard );
+	LLColor4 color(1.f, 1.f, 1.f, alpha);
+	LLRectf uv_rect(0, 0, rect.getWidth()/32.f, rect.getHeight()/32.f);
 
-		LLGLEnable polygon_stipple(GL_POLYGON_STIPPLE);
-		gl_rect_2d(rect);
-	}
-	else
-	{ //polygon stipple is deprecated, use "Checker" texture
-		LLPointer<LLUIImage> img = LLRender2D::getInstance()->getUIImage("Checker");
-		gGL.getTexUnit(0)->bind(img->getImage());
-		gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_WRAP);
-		gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
-
-		LLColor4 color(1.f, 1.f, 1.f, alpha);
-		LLRectf uv_rect(0, 0, rect.getWidth()/32.f, rect.getHeight()/32.f);
-
-		gl_draw_scaled_image(rect.mLeft, rect.mBottom, rect.getWidth(), rect.getHeight(),
-			img->getImage(), color, uv_rect);
-	}
+	gl_draw_scaled_image(rect.mLeft, rect.mBottom, rect.getWidth(), rect.getHeight(), img->getImage(), color, uv_rect);
 	
 	gGL.flush();
 }
@@ -1083,8 +980,6 @@ void gl_rect_2d_simple( S32 width, S32 height )
 	gGL.end();
 }
 
-static LLTrace::BlockTimerStatHandle FTM_RENDER_SEGMENTED_RECT ("Render segmented rectangle");
-
 void gl_segmented_rect_2d_tex(const S32 left, 
 							  const S32 top, 
 							  const S32 right, 
@@ -1094,7 +989,7 @@ void gl_segmented_rect_2d_tex(const S32 left,
 							  const S32 border_size, 
 							  const U32 edges)
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_SEGMENTED_RECT);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
 
 	S32 width = llabs(right - left);
 	S32 height = llabs(top - bottom);
@@ -1253,7 +1148,7 @@ void gl_segmented_rect_2d_fragment_tex(const LLRect& rect,
 	const F32 end_fragment, 
 	const U32 edges)
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_SEGMENTED_RECT);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
 	const S32 left = rect.mLeft;
 	const S32 right = rect.mRight;
 	const S32 top = rect.mTop;
@@ -1440,7 +1335,7 @@ void gl_segmented_rect_2d_fragment_tex(const LLRect& rect,
 void gl_segmented_rect_3d_tex(const LLRectf& clip_rect, const LLRectf& center_uv_rect, const LLRectf& center_draw_rect, 
 							 const LLVector3& width_vec, const LLVector3& height_vec)
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_SEGMENTED_RECT);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
 
 	gGL.begin(LLRender::QUADS);
 	{
diff --git a/indra/llrender/llrendertarget.cpp b/indra/llrender/llrendertarget.cpp
index e3c0255290fde73daac8dc5ff82493f47a4e186a..fffc15efc3354d32f0c2b4e6dc2cf9c2df67fb60 100644
--- a/indra/llrender/llrendertarget.cpp
+++ b/indra/llrender/llrendertarget.cpp
@@ -133,7 +133,7 @@ bool LLRenderTarget::allocate(U32 resx, U32 resy, U32 color_fmt, bool depth, boo
 	mUsage = usage;
 	mUseDepth = depth;
 
-	if ((sUseFBO || use_fbo) && gGLManager.mHasFramebufferObject)
+	if (sUseFBO || use_fbo)
 	{
 		if (depth)
 		{
@@ -170,6 +170,53 @@ bool LLRenderTarget::allocate(U32 resx, U32 resy, U32 color_fmt, bool depth, boo
 	return addColorAttachment(color_fmt);
 }
 
+void LLRenderTarget::setColorAttachment(LLImageGL* img, LLGLuint use_name)
+{
+    LL_PROFILE_ZONE_SCOPED;
+    llassert(img != nullptr); // img must not be null
+    llassert(sUseFBO); // FBO support must be enabled
+    llassert(mDepth == 0); // depth buffers not supported with this mode
+    llassert(mTex.empty()); // mTex must be empty with this mode (binding target should be done via LLImageGL)
+
+    if (mFBO == 0)
+    {
+        glGenFramebuffers(1, (GLuint*)&mFBO);
+    }
+
+    mResX = img->getWidth();
+    mResY = img->getHeight();
+    mUsage = img->getTarget();
+
+    if (use_name == 0)
+    {
+        use_name = img->getTexName();
+    }
+
+    mTex.push_back(use_name);
+
+    glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
+    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+            LLTexUnit::getInternalType(mUsage), use_name, 0);
+        stop_glerror();
+
+    check_framebuffer_status();
+
+    glBindFramebuffer(GL_FRAMEBUFFER, sCurFBO);
+}
+
+void LLRenderTarget::releaseColorAttachment()
+{
+    LL_PROFILE_ZONE_SCOPED;
+    llassert(mTex.size() == 1); //cannot use releaseColorAttachment with LLRenderTarget managed color targets
+    llassert(mFBO != 0);  // mFBO must be valid
+    
+    glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
+    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, LLTexUnit::getInternalType(mUsage), 0, 0);
+    glBindFramebuffer(GL_FRAMEBUFFER, sCurFBO);
+
+    mTex.clear();
+}
+
 bool LLRenderTarget::addColorAttachment(U32 color_fmt)
 {
 	if (color_fmt == 0)
@@ -437,11 +484,13 @@ void LLRenderTarget::bindTarget()
 									GL_COLOR_ATTACHMENT1,
 									GL_COLOR_ATTACHMENT2,
 									GL_COLOR_ATTACHMENT3};
+			LL_PROFILER_GPU_ZONEC( "gl.DrawBuffersARB", 0x4000FF )
 			glDrawBuffersARB(mTex.size(), drawbuffers);
 		}
 			
 		if (mTex.empty())
 		{ //no color buffer to draw to
+			LL_PROFILER_GPU_ZONEC( "gl.DrawBuffer", 0x0000FF )
 			glDrawBuffer(GL_NONE);
 			glReadBuffer(GL_NONE);
 		}
diff --git a/indra/llrender/llrendertarget.h b/indra/llrender/llrendertarget.h
index 6c07ac5b1c7c8645af7e04c45fc731bdc97f3dc7..584f224dcaccc3893e1fb15954cfd171fce19a4f 100644
--- a/indra/llrender/llrendertarget.h
+++ b/indra/llrender/llrendertarget.h
@@ -81,6 +81,24 @@ class LLRenderTarget
 	// DO use for render targets that resize often and aren't likely to ruin someone's day if they break
 	void resize(U32 resx, U32 resy);
 
+    //point this render target at a particular LLImageGL
+    //   Intended usage:
+    //      LLRenderTarget target;
+    //      target.addColorAttachment(image);
+    //      target.bindTarget();
+    //      < issue GL calls>
+    //      target.flush();
+    //      target.releaseColorAttachment();
+    // 
+    // attachment -- LLImageGL to render into
+    // use_name -- optional texture name to target instead of attachment->getTexName()
+    // NOTE: setColorAttachment and releaseColorAttachment cannot be used in conjuction with
+    // addColorAttachment, allocateDepth, resize, etc.
+    void setColorAttachment(LLImageGL* attachment, LLGLuint use_name = 0);
+
+    // detach from current color attachment
+    void releaseColorAttachment();
+
 	//add color buffer attachment
 	//limit of 4 color attachments per render target
 	bool addColorAttachment(U32 color_fmt);
diff --git a/indra/llrender/llshadermgr.cpp b/indra/llrender/llshadermgr.cpp
index e8c62959303e9be71b878021cb70fe5662ea8c8c..c64f46f38ad847bbcac30d50d490229eb51d3d49 100644
--- a/indra/llrender/llshadermgr.cpp
+++ b/indra/llrender/llshadermgr.cpp
@@ -165,6 +165,7 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader)
 
 	if (features->hasObjectSkinning)
 	{
+        shader->mRiggedVariant = shader;
         if (!shader->attachVertexObject("avatar/objectSkinV.glsl"))
 		{
 			return FALSE;
@@ -599,7 +600,7 @@ void LLShaderMgr::dumpObjectLog(GLhandleARB ret, BOOL warns, const std::string&
 	}
  }
 
-GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shader_level, GLenum type, boost::unordered_map<std::string, std::string>* defines, S32 texture_index_channels)
+GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shader_level, GLenum type, std::unordered_map<std::string, std::string>* defines, S32 texture_index_channels)
 {
 
 // endsure work-around for missing GLSL funcs gets propogated to feature shader files (e.g. srgbF.glsl)
@@ -664,7 +665,7 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade
 	
 	if (file == NULL)
 	{
-		LL_SHADER_LOADING_WARNS() << "GLSL Shader file not found: " << open_file_name << LL_ENDL;
+		LL_WARNS("ShaderLoading") << "GLSL Shader file not found: " << open_file_name << LL_ENDL;
 		return 0;
 	}
 
@@ -774,14 +775,14 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade
 	
 	if (defines)
 	{
-		for (boost::unordered_map<std::string,std::string>::iterator iter = defines->begin(); iter != defines->end(); ++iter)
+		for (std::unordered_map<std::string,std::string>::iterator iter = defines->begin(); iter != defines->end(); ++iter)
 		{
 			std::string define = "#define " + iter->first + " " + iter->second + "\n";
 			extra_code_text[extra_code_count++] = (GLcharARB *) strdup(define.c_str());
 		}
 	}
 
-	if( gGLManager.mIsATI )
+	if( gGLManager.mIsAMD )
 	{
 		extra_code_text[extra_code_count++] = strdup( "#define IS_AMD_CARD 1\n" );
 	}
@@ -1053,43 +1054,6 @@ BOOL LLShaderMgr::linkProgramObject(GLhandleARB obj, BOOL suppress_errors)
 		LL_SHADER_LOADING_WARNS() << "GLSL Linker Error:" << LL_ENDL;
 	}
 
-#if LL_DARWIN
-
-	// For some reason this absolutely kills the frame rate when VBO's are enabled
-	if (0)
-	{
-		// Force an evaluation of the gl state so the driver can tell if the shader will run in hardware or software
-		// per Apple's suggestion
-		LLGLSLShader::sNoFixedFunction = false;
-		
-		glUseProgramObjectARB(obj);
-
-		gGL.begin(LLRender::TRIANGLES);
-		gGL.vertex3f(0.0f, 0.0f, 0.0f);
-		gGL.vertex3f(0.0f, 0.0f, 0.0f);
-		gGL.vertex3f(0.0f, 0.0f, 0.0f);
-		gGL.end();
-		gGL.flush();
-		
-		glUseProgramObjectARB(0);
-		
-		LLGLSLShader::sNoFixedFunction = true;
-
-		// Query whether the shader can or cannot run in hardware
-		// http://developer.apple.com/qa/qa2007/qa1502.html
-		GLint vertexGPUProcessing, fragmentGPUProcessing;
-		CGLContextObj ctx = CGLGetCurrentContext();
-		CGLGetParameter(ctx, kCGLCPGPUVertexProcessing, &vertexGPUProcessing);	
-		CGLGetParameter(ctx, kCGLCPGPUFragmentProcessing, &fragmentGPUProcessing);
-		if (!fragmentGPUProcessing || !vertexGPUProcessing)
-		{
-			LL_SHADER_LOADING_WARNS() << "GLSL Linker: Running in Software:" << LL_ENDL;
-			success = GL_FALSE;
-			suppress_errors = FALSE;		
-		}
-	}
-
-#else
 	std::string log = get_object_log(obj);
 	LLStringUtil::toLower(log);
 	if (log.find("software") != std::string::npos)
@@ -1098,7 +1062,6 @@ BOOL LLShaderMgr::linkProgramObject(GLhandleARB obj, BOOL suppress_errors)
 		success = GL_FALSE;
 		suppress_errors = FALSE;
 	}
-#endif
 	return success;
 }
 
diff --git a/indra/llrender/llshadermgr.h b/indra/llrender/llshadermgr.h
index 3908efd4ec723e492f92ebd63fe94dfd7bea62c2..67c0d6ab10b74506f81667f77738abead5e370a8 100644
--- a/indra/llrender/llshadermgr.h
+++ b/indra/llrender/llshadermgr.h
@@ -264,7 +264,7 @@ class LLShaderMgr
     void dumpShaderSource(U32 shader_code_count, GLcharARB** shader_code_text);
 	BOOL	linkProgramObject(GLhandleARB obj, BOOL suppress_errors = FALSE);
 	BOOL	validateProgramObject(GLhandleARB obj);
-	GLhandleARB loadShaderFile(const std::string& filename, S32 & shader_level, GLenum type, boost::unordered_map<std::string, std::string>* defines = NULL, S32 texture_index_channels = -1);
+	GLhandleARB loadShaderFile(const std::string& filename, S32 & shader_level, GLenum type, std::unordered_map<std::string, std::string>* defines = NULL, S32 texture_index_channels = -1);
 
 	// Implemented in the application to actually point to the shader directory.
 	virtual std::string getShaderDirPrefix(void) = 0; // Pure Virtual
diff --git a/indra/llrender/lltexture.h b/indra/llrender/lltexture.h
index 41481fb8a722d23fd06e999ee9a9c7493ea02e59..e890a5a30b46d9365cdceee1a71cfc5cf8dae949 100644
--- a/indra/llrender/lltexture.h
+++ b/indra/llrender/lltexture.h
@@ -42,7 +42,7 @@ class LLFontGL ;
 //
 //this is an abstract class as the parent for the class LLGLTexture
 //
-class LLTexture : public virtual LLRefCount, public LLTrace::MemTrackable<LLTexture>
+class LLTexture : public virtual LLRefCount
 {
 	friend class LLTexUnit ;
 	friend class LLFontGL ;
@@ -52,7 +52,6 @@ class LLTexture : public virtual LLRefCount, public LLTrace::MemTrackable<LLText
 
 public:
 	LLTexture()
-	:	LLTrace::MemTrackable<LLTexture>("LLTexture")
 	{}
 
 	//
@@ -67,11 +66,9 @@ class LLTexture : public virtual LLRefCount, public LLTrace::MemTrackable<LLText
 	virtual S32	       getWidth(S32 discard_level = -1) const;
 	virtual S32	       getHeight(S32 discard_level = -1) const;
 	virtual bool       isActiveFetching();
+    virtual LLImageGL* getGLTexture() const;
 
 private:
-	//note: do not make this function public.
-	virtual LLImageGL* getGLTexture() const;
-
 	virtual void updateBindStatsForTester();
 };
 #endif
diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp
index 7d2b09ca4a742d469b4d809dec531c1d62ea34de..be3e6ddff08813fa7212822ba423b8cd6b8b0c43 100644
--- a/indra/llrender/llvertexbuffer.cpp
+++ b/indra/llrender/llvertexbuffer.cpp
@@ -91,6 +91,8 @@ LLVBOPool LLVertexBuffer::sDynamicIBOPool(GL_DYNAMIC_DRAW_ARB, GL_ELEMENT_ARRAY_
 
 U32 LLVBOPool::sBytesPooled = 0;
 U32 LLVBOPool::sIndexBytesPooled = 0;
+U32 LLVBOPool::sNameIdx = 0;
+U32 LLVBOPool::sNamePool[1024];
 
 std::list<U32> LLVertexBuffer::sAvailableVAOName;
 U32 LLVertexBuffer::sCurVAOName = 1;
@@ -121,15 +123,20 @@ bool LLVertexBuffer::sPreferStreamDraw = false;
 
 U32 LLVBOPool::genBuffer()
 {
-	U32 ret = 0;
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX
 
-	glGenBuffersARB(1, &ret);
-	
-	return ret;
+	if (sNameIdx == 0)
+	{
+		glGenBuffersARB(1024, sNamePool);
+		sNameIdx = 1024;
+	}
+
+	return sNamePool[--sNameIdx];
 }
 
 void LLVBOPool::deleteBuffer(U32 name)
 {
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX
 	if (gGLManager.mInited)
 	{
 		LLVertexBuffer::unbind();
@@ -150,11 +157,12 @@ LLVBOPool::LLVBOPool(U32 vboUsage, U32 vboType)
 	std::fill(mMissCount.begin(), mMissCount.end(), 0);
 }
 
-volatile U8* LLVBOPool::allocate(U32& name, U32 size, bool for_seed)
+U8* LLVBOPool::allocate(U32& name, U32 size, bool for_seed)
 {
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX
 	llassert(vbo_block_size(size) == size);
 	
-	volatile U8* ret = NULL;
+	U8* ret = NULL;
 
 	U32 i = vbo_block_index(size);
 
@@ -248,7 +256,7 @@ volatile U8* LLVBOPool::allocate(U32& name, U32 size, bool for_seed)
 	return ret;
 }
 
-void LLVBOPool::release(U32 name, volatile U8* buffer, U32 size)
+void LLVBOPool::release(U32 name, U8* buffer, U32 size)
 {
 	llassert(vbo_block_size(size) == size);
 
@@ -267,10 +275,12 @@ void LLVBOPool::release(U32 name, volatile U8* buffer, U32 size)
 
 void LLVBOPool::seedPool()
 {
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX
 	U32 dummy_name = 0;
 
 	if (mFreeList.size() < LL_VBO_POOL_SEED_COUNT)
 	{
+		LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("VBOPool Resize");
 		mFreeList.resize(LL_VBO_POOL_SEED_COUNT);
 	}
 
@@ -411,6 +421,7 @@ void LLVertexBuffer::releaseVAOName(U32 name)
 //static
 void LLVertexBuffer::seedPools()
 {
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX
 	sStreamVBOPool.seedPool();
 	sDynamicVBOPool.seedPool();
 	sDynamicCopyVBOPool.seedPool();
@@ -430,135 +441,26 @@ void LLVertexBuffer::setupClientArrays(U32 data_mask)
 			data_mask = data_mask & ~MAP_TEXTURE_INDEX;
 		}
 
-		if (LLGLSLShader::sNoFixedFunction)
+		for (U32 i = 0; i < TYPE_MAX; ++i)
 		{
-			for (U32 i = 0; i < TYPE_MAX; ++i)
-			{
-				S32 loc = i;
+			S32 loc = i;
 										
-				U32 mask = 1 << i;
-
-				if (sLastMask & (1 << i))
-				{ //was enabled
-					if (!(data_mask & mask))
-					{ //needs to be disabled
-						glDisableVertexAttribArrayARB(loc);
-					}
-				}
-				else 
-				{	//was disabled
-					if (data_mask & mask)
-					{ //needs to be enabled
-						glEnableVertexAttribArrayARB(loc);
-					}
-				}
-			}
-		}
-		else
-		{
-
-			static const GLenum array[] =
-			{
-				GL_VERTEX_ARRAY,
-				GL_NORMAL_ARRAY,
-				GL_TEXTURE_COORD_ARRAY,
-				GL_COLOR_ARRAY,
-			};
-
-			static const GLenum mask[] = 
-			{
-				MAP_VERTEX,
-				MAP_NORMAL,
-				MAP_TEXCOORD0,
-				MAP_COLOR
-			};
-
-
-
-			for (U32 i = 0; i < 4; ++i)
-			{
-				if (sLastMask & mask[i])
-				{ //was enabled
-					if (!(data_mask & mask[i]))
-					{ //needs to be disabled
-						glDisableClientState(array[i]);
-					}
-					else if (gDebugGL)
-					{ //needs to be enabled, make sure it was (DEBUG)
-						if (!glIsEnabled(array[i]))
-						{
-							if (gDebugSession)
-							{
-								gFailLog << "Bad client state! " << array[i] << " disabled." << std::endl;
-							}
-							else
-							{
-								LL_ERRS() << "Bad client state! " << array[i] << " disabled." << LL_ENDL;
-							}
-						}
-					}
-				}
-				else 
-				{	//was disabled
-					if (data_mask & mask[i])
-					{ //needs to be enabled
-						glEnableClientState(array[i]);
-					}
-					else if (gDebugGL && glIsEnabled(array[i]))
-					{ //needs to be disabled, make sure it was (DEBUG TEMPORARY)
-						if (gDebugSession)
-						{
-							gFailLog << "Bad client state! " << array[i] << " enabled." << std::endl;
-						}
-						else
-						{
-							LL_ERRS() << "Bad client state! " << array[i] << " enabled." << LL_ENDL;
-						}
-					}
-				}
-			}
-		
-			static const U32 map_tc[] = 
-			{
-				MAP_TEXCOORD1,
-				MAP_TEXCOORD2,
-				MAP_TEXCOORD3
-			};
+			U32 mask = 1 << i;
 
-			for (U32 i = 0; i < 3; i++)
-			{
-				if (sLastMask & map_tc[i])
-				{
-					if (!(data_mask & map_tc[i]))
-					{ //disable
-						glClientActiveTextureARB(GL_TEXTURE1_ARB+i);
-						glDisableClientState(GL_TEXTURE_COORD_ARRAY);
-						glClientActiveTextureARB(GL_TEXTURE0_ARB);
-					}
-				}
-				else if (data_mask & map_tc[i])
-				{
-					glClientActiveTextureARB(GL_TEXTURE1_ARB+i);
-					glEnableClientState(GL_TEXTURE_COORD_ARRAY);
-					glClientActiveTextureARB(GL_TEXTURE0_ARB);
+			if (sLastMask & (1 << i))
+			{ //was enabled
+				if (!(data_mask & mask))
+				{ //needs to be disabled
+					glDisableVertexAttribArrayARB(loc);
 				}
 			}
-
-			if (sLastMask & MAP_TANGENT)
-			{
-				if (!(data_mask & MAP_TANGENT))
-				{
-					glClientActiveTextureARB(GL_TEXTURE2_ARB);
-					glDisableClientState(GL_TEXTURE_COORD_ARRAY);
-					glClientActiveTextureARB(GL_TEXTURE0_ARB);
+			else 
+			{	//was disabled
+				if (data_mask & mask)
+				{ //needs to be enabled
+					glEnableVertexAttribArrayARB(loc);
 				}
 			}
-			else if (data_mask & MAP_TANGENT)
-			{
-				glClientActiveTextureARB(GL_TEXTURE2_ARB);
-				glEnableClientState(GL_TEXTURE_COORD_ARRAY);
-				glClientActiveTextureARB(GL_TEXTURE0_ARB);
-			}
 		}
 				
 		sLastMask = data_mask;
@@ -566,63 +468,23 @@ void LLVertexBuffer::setupClientArrays(U32 data_mask)
 }
 
 //static
-static LLTrace::BlockTimerStatHandle FTM_VB_DRAW_ARRAYS("drawArrays");
-void LLVertexBuffer::drawArrays(U32 mode, const std::vector<LLVector3>& pos, const std::vector<LLVector3>& norm)
+void LLVertexBuffer::drawArrays(U32 mode, const std::vector<LLVector3>& pos)
 {
-	LL_RECORD_BLOCK_TIME(FTM_VB_DRAW_ARRAYS);
-	llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShaderPtr != NULL);
-	gGL.syncMatrices();
-
-	U32 count = pos.size();
-	
-	llassert(norm.size() >= pos.size());
-	llassert(count > 0);
-
-	if( count == 0 )
-	{
-		LL_WARNS() << "Called drawArrays with 0 vertices" << LL_ENDL;
-		return;
-	}
-
-	if( norm.size() < pos.size() )
-	{
-		LL_WARNS() << "Called drawArrays with #" << norm.size() << " normals and #" << pos.size() << " vertices" << LL_ENDL;
-		return;
-	}
-
-	unbind();
-	
-	setupClientArrays(MAP_VERTEX | MAP_NORMAL);
-
-	LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
-
-	if (shader)
-	{
-		S32 loc = LLVertexBuffer::TYPE_VERTEX;
-		if (loc > -1)
-		{
-			glVertexAttribPointerARB(loc, 3, GL_FLOAT, GL_FALSE, 0, pos[0].mV);
-		}
-		loc = LLVertexBuffer::TYPE_NORMAL;
-		if (loc > -1)
-		{
-			glVertexAttribPointerARB(loc, 3, GL_FLOAT, GL_FALSE, 0, norm[0].mV);
-		}
-	}
-	else
-	{
-		glVertexPointer(3, GL_FLOAT, 0, pos[0].mV);
-		glNormalPointer(GL_FLOAT, 0, norm[0].mV);
-	}
-	LLGLSLShader::startProfile();
-	glDrawArrays(sGLMode[mode], 0, count);
-	LLGLSLShader::stopProfile(count, mode);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX;
+    gGL.begin(mode);
+    for (auto& v : pos)
+    {
+        gGL.vertex3fv(v.mV);
+    }
+    gGL.end();
+    gGL.flush();
 }
 
 //static
 void LLVertexBuffer::drawElements(U32 mode, const LLVector4a* pos, const LLVector2* tc, S32 num_indices, const U16* indicesp)
 {
-	llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShaderPtr != NULL);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX;
+	llassert(LLGLSLShader::sCurBoundShaderPtr != NULL);
 
 	gGL.syncMatrices();
 
@@ -634,28 +496,27 @@ void LLVertexBuffer::drawElements(U32 mode, const LLVector4a* pos, const LLVecto
 
 	unbind();
 	
-	setupClientArrays(mask);
-
-	if (LLGLSLShader::sNoFixedFunction)
-	{
-		S32 loc = LLVertexBuffer::TYPE_VERTEX;
-		glVertexAttribPointerARB(loc, 3, GL_FLOAT, GL_FALSE, 16, pos);
-
-		if (tc)
-		{
-			loc = LLVertexBuffer::TYPE_TEXCOORD0;
-			glVertexAttribPointerARB(loc, 2, GL_FLOAT, GL_FALSE, 0, tc);
-		}
-	}
-	else
-	{
-		glTexCoordPointer(2, GL_FLOAT, 0, tc);
-		glVertexPointer(3, GL_FLOAT, 16, pos);
-	}
-
-	LLGLSLShader::startProfile();
-	glDrawElements(sGLMode[mode], num_indices, GL_UNSIGNED_SHORT, indicesp);
-	LLGLSLShader::stopProfile(num_indices, mode);
+    gGL.begin(mode);
+
+    if (tc != nullptr)
+    {
+        for (int i = 0; i < num_indices; ++i)
+        {
+            U16 idx = indicesp[i];
+            gGL.texCoord2fv(tc[idx].mV);
+            gGL.vertex3fv(pos[idx].getF32ptr());
+        }
+    }
+    else
+    {
+        for (int i = 0; i < num_indices; ++i)
+        {
+            U16 idx = indicesp[i];
+            gGL.vertex3fv(pos[idx].getF32ptr());
+        }
+    }
+    gGL.end();
+    gGL.flush();
 }
 
 void LLVertexBuffer::validateRange(U32 start, U32 end, U32 count, U32 indices_offset) const
@@ -720,7 +581,7 @@ void LLVertexBuffer::drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indi
 	gGL.syncMatrices();
 
 	llassert(mNumVerts >= 0);
-	llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShaderPtr != NULL);
+	llassert(LLGLSLShader::sCurBoundShaderPtr != NULL);
 
 	if (mGLArray)
 	{
@@ -763,6 +624,7 @@ void LLVertexBuffer::drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indi
 
 	stop_glerror();
 	LLGLSLShader::startProfile();
+    LL_PROFILER_GPU_ZONEC( "gl.DrawRangeElements", 0xFFFF00 )
 	glDrawRangeElements(sGLMode[mode], start, end, count, GL_UNSIGNED_SHORT, 
 		idx);
 	LLGLSLShader::stopProfile(count, mode);
@@ -773,9 +635,21 @@ void LLVertexBuffer::drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indi
 	placeFence();
 }
 
+void LLVertexBuffer::drawRangeFast(U32 mode, U32 start, U32 end, U32 count, U32 indices_offset) const
+{
+    mMappable = false;
+    gGL.syncMatrices();
+
+    U16* idx = ((U16*)getIndicesPointer()) + indices_offset;
+
+    LL_PROFILER_GPU_ZONEC("gl.DrawRangeElements", 0xFFFF00)
+        glDrawRangeElements(sGLMode[mode], start, end, count, GL_UNSIGNED_SHORT,
+            idx);
+}
+
 void LLVertexBuffer::draw(U32 mode, U32 count, U32 indices_offset) const
 {
-	llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShaderPtr != NULL);
+	llassert(LLGLSLShader::sCurBoundShaderPtr != NULL);
 	mMappable = false;
 	gGL.syncMatrices();
 
@@ -814,6 +688,7 @@ void LLVertexBuffer::draw(U32 mode, U32 count, U32 indices_offset) const
 
 	stop_glerror();
 	LLGLSLShader::startProfile();
+    LL_PROFILER_GPU_ZONEC( "gl.DrawElements", 0xA0FFA0 )
 	glDrawElements(sGLMode[mode], count, GL_UNSIGNED_SHORT,
 		((U16*) getIndicesPointer()) + indices_offset);
 	LLGLSLShader::stopProfile(count, mode);
@@ -821,53 +696,53 @@ void LLVertexBuffer::draw(U32 mode, U32 count, U32 indices_offset) const
 	placeFence();
 }
 
-static LLTrace::BlockTimerStatHandle FTM_GL_DRAW_ARRAYS("GL draw arrays");
+
 void LLVertexBuffer::drawArrays(U32 mode, U32 first, U32 count) const
 {
-	llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShaderPtr != NULL);
-	mMappable = false;
-	gGL.syncMatrices();
-	
-	llassert(mNumVerts >= 0);
-	if (first >= (U32) mNumVerts ||
-	    first + count > (U32) mNumVerts)
-	{
-		LL_ERRS() << "Bad vertex buffer draw range: [" << first << ", " << first+count << "]" << LL_ENDL;
-	}
-
-	if (mGLArray)
-	{
-		if (mGLArray != sGLRenderArray)
-		{
-			LL_ERRS() << "Wrong vertex array bound." << LL_ENDL;
-		}
-	}
-	else
-	{
-		if (mGLBuffer != sGLRenderBuffer || useVBOs() != sVBOActive)
-		{
-			LL_ERRS() << "Wrong vertex buffer bound." << LL_ENDL;
-		}
-	}
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX;
+    llassert(LLGLSLShader::sCurBoundShaderPtr != NULL);
+    mMappable = false;
+    gGL.syncMatrices();
+
+#ifndef LL_RELEASE_FOR_DOWNLOAD
+    llassert(mNumVerts >= 0);
+    if (first >= (U32)mNumVerts ||
+        first + count > (U32)mNumVerts)
+    {
+        LL_ERRS() << "Bad vertex buffer draw range: [" << first << ", " << first + count << "]" << LL_ENDL;
+    }
+
+    if (mGLArray)
+    {
+        if (mGLArray != sGLRenderArray)
+        {
+            LL_ERRS() << "Wrong vertex array bound." << LL_ENDL;
+        }
+    }
+    else
+    {
+        if (mGLBuffer != sGLRenderBuffer || useVBOs() != sVBOActive)
+        {
+            LL_ERRS() << "Wrong vertex buffer bound." << LL_ENDL;
+        }
+    }
+
+    if (mode >= LLRender::NUM_MODES)
+    {
+        LL_ERRS() << "Invalid draw mode: " << mode << LL_ENDL;
+        return;
+    }
+#endif
 
-	if (mode >= LLRender::NUM_MODES)
-	{
-		LL_ERRS() << "Invalid draw mode: " << mode << LL_ENDL;
-		return;
-	}
+    LLGLSLShader::startProfile();
+    {
+        LL_PROFILER_GPU_ZONEC("gl.DrawArrays", 0xFF4040)
+            glDrawArrays(sGLMode[mode], first, count);
+    }
+    LLGLSLShader::stopProfile(count, mode);
 
-	{
-		LL_RECORD_BLOCK_TIME(FTM_GL_DRAW_ARRAYS);
-		stop_glerror();
-		LLGLSLShader::startProfile();
-		stop_glerror();
-		glDrawArrays(sGLMode[mode], first, count);
-		stop_glerror();
-		LLGLSLShader::stopProfile(count, mode);
-	}
-
-	stop_glerror();
-	placeFence();
+    stop_glerror();
+    placeFence();
 }
 
 //static
@@ -964,8 +839,7 @@ S32 LLVertexBuffer::determineUsage(S32 usage)
 }
 
 LLVertexBuffer::LLVertexBuffer(U32 typemask, S32 usage) 
-:	LLTrace::MemTrackable<LLVertexBuffer>("LLVertexBuffer"),
-	LLRefCount(),
+:	LLRefCount(),
 
 	mNumVerts(0),
 	mNumIndices(0),
@@ -1110,9 +984,7 @@ void LLVertexBuffer::waitFence() const
 
 void LLVertexBuffer::genBuffer(U32 size)
 {
-	disclaimMem(mSize);
 	mSize = vbo_block_size(size);
-	claimMem(mSize);
 
 	if (mUsage == GL_STREAM_DRAW_ARB)
 	{
@@ -1183,7 +1055,7 @@ void LLVertexBuffer::releaseIndices()
 
 bool LLVertexBuffer::createGLBuffer(U32 size)
 {
-	if (mGLBuffer)
+	if (mGLBuffer || mMappedData)
 	{
 		destroyGLBuffer();
 	}
@@ -1208,9 +1080,7 @@ bool LLVertexBuffer::createGLBuffer(U32 size)
 		static int gl_buffer_idx = 0;
 		mGLBuffer = ++gl_buffer_idx;
 		mMappedData = (U8*)ll_aligned_malloc_16(size);
-		disclaimMem(mSize);
 		mSize = size;
-		claimMem(mSize);
 	}
 
 	if (!mMappedData)
@@ -1380,8 +1250,6 @@ bool LLVertexBuffer::allocateBuffer(S32 nverts, S32 nindices, bool create)
 	return success;
 }
 
-static LLTrace::BlockTimerStatHandle FTM_SETUP_VERTEX_ARRAY("Setup VAO");
-
 void LLVertexBuffer::setupVertexArray()
 {
 	if (!mGLArray)
@@ -1389,7 +1257,7 @@ void LLVertexBuffer::setupVertexArray()
 		return;
 	}
 
-	LL_RECORD_BLOCK_TIME(FTM_SETUP_VERTEX_ARRAY);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX;
 #if GL_ARB_vertex_array_object
 	glBindVertexArray(mGLArray);
 #endif
@@ -1562,12 +1430,11 @@ bool expand_region(LLVertexBuffer::MappedRegion& region, S32 index, S32 count)
 	return true;
 }
 
-static LLTrace::BlockTimerStatHandle FTM_VBO_MAP_BUFFER_RANGE("VBO Map Range");
-static LLTrace::BlockTimerStatHandle FTM_VBO_MAP_BUFFER("VBO Map");
 
 // Map for data access
-volatile U8* LLVertexBuffer::mapVertexBuffer(S32 type, S32 index, S32 count, bool map_range)
+U8* LLVertexBuffer::mapVertexBuffer(S32 type, S32 index, S32 count, bool map_range)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX;
 	bindGLBuffer(true);
 	if (mFinal)
 	{
@@ -1627,14 +1494,13 @@ volatile U8* LLVertexBuffer::mapVertexBuffer(S32 type, S32 index, S32 count, boo
 			}
 			else
 			{
-				volatile U8* src = NULL;
+				U8* src = NULL;
 				waitFence();
 				if (gGLManager.mHasMapBufferRange)
 				{
 					if (map_range)
 					{
 #ifdef GL_ARB_map_buffer_range
-						LL_RECORD_BLOCK_TIME(FTM_VBO_MAP_BUFFER_RANGE);
 						S32 offset = mOffsets[type] + sTypeSize[type]*index;
 						S32 length = (sTypeSize[type]*count+0xF) & ~0xF;
 						src = (U8*) glMapBufferRange(GL_ARRAY_BUFFER_ARB, offset, length, 
@@ -1658,7 +1524,6 @@ volatile U8* LLVertexBuffer::mapVertexBuffer(S32 type, S32 index, S32 count, boo
 							}
 						}
 
-						LL_RECORD_BLOCK_TIME(FTM_VBO_MAP_BUFFER);
 						src = (U8*) glMapBufferRange(GL_ARRAY_BUFFER_ARB, 0, mSize, 
 							GL_MAP_WRITE_BIT | 
 							GL_MAP_FLUSH_EXPLICIT_BIT);
@@ -1688,7 +1553,7 @@ volatile U8* LLVertexBuffer::mapVertexBuffer(S32 type, S32 index, S32 count, boo
 
 				llassert(src != NULL);
 
-				mMappedData = LL_NEXT_ALIGNED_ADDRESS<volatile U8>(src);
+				mMappedData = LL_NEXT_ALIGNED_ADDRESS<U8>(src);
 				mAlignedOffset = mMappedData - src;
 			
 				stop_glerror();
@@ -1744,11 +1609,9 @@ volatile U8* LLVertexBuffer::mapVertexBuffer(S32 type, S32 index, S32 count, boo
 }
 
 
-static LLTrace::BlockTimerStatHandle FTM_VBO_MAP_INDEX_RANGE("IBO Map Range");
-static LLTrace::BlockTimerStatHandle FTM_VBO_MAP_INDEX("IBO Map");
-
-volatile U8* LLVertexBuffer::mapIndexBuffer(S32 index, S32 count, bool map_range)
+U8* LLVertexBuffer::mapIndexBuffer(S32 index, S32 count, bool map_range)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX;
 	bindGLIndices(true);
 	if (mFinal)
 	{
@@ -1816,14 +1679,13 @@ volatile U8* LLVertexBuffer::mapIndexBuffer(S32 index, S32 count, bool map_range
 			}
 			else
 			{
-				volatile U8* src = NULL;
+				U8* src = NULL;
 				waitFence();
 				if (gGLManager.mHasMapBufferRange)
 				{
 					if (map_range)
 					{
 #ifdef GL_ARB_map_buffer_range
-						LL_RECORD_BLOCK_TIME(FTM_VBO_MAP_INDEX_RANGE);
 						S32 offset = sizeof(U16)*index;
 						S32 length = sizeof(U16)*count;
 						src = (U8*) glMapBufferRange(GL_ELEMENT_ARRAY_BUFFER_ARB, offset, length, 
@@ -1835,7 +1697,6 @@ volatile U8* LLVertexBuffer::mapIndexBuffer(S32 index, S32 count, bool map_range
 					else
 					{
 #ifdef GL_ARB_map_buffer_range
-						LL_RECORD_BLOCK_TIME(FTM_VBO_MAP_INDEX);
 						src = (U8*) glMapBufferRange(GL_ELEMENT_ARRAY_BUFFER_ARB, 0, sizeof(U16)*mNumIndices, 
 							GL_MAP_WRITE_BIT | 
 							GL_MAP_FLUSH_EXPLICIT_BIT);
@@ -1859,7 +1720,6 @@ volatile U8* LLVertexBuffer::mapIndexBuffer(S32 index, S32 count, bool map_range
 				}
 				else
 				{
-					LL_RECORD_BLOCK_TIME(FTM_VBO_MAP_INDEX);
 					map_range = false;
 					src = (U8*) glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
 				}
@@ -1910,13 +1770,6 @@ volatile U8* LLVertexBuffer::mapIndexBuffer(S32 index, S32 count, bool map_range
 	}
 }
 
-static LLTrace::BlockTimerStatHandle FTM_VBO_UNMAP("VBO Unmap");
-static LLTrace::BlockTimerStatHandle FTM_VBO_FLUSH_RANGE("Flush VBO Range");
-
-
-static LLTrace::BlockTimerStatHandle FTM_IBO_UNMAP("IBO Unmap");
-static LLTrace::BlockTimerStatHandle FTM_IBO_FLUSH_RANGE("Flush IBO Range");
-
 void LLVertexBuffer::unmapBuffer()
 {
 	if (!useVBOs())
@@ -1925,10 +1778,10 @@ void LLVertexBuffer::unmapBuffer()
 	}
 
 	bool updated_all = false;
-
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX;
 	if (mMappedData && mVertexLocked)
 	{
-		LL_RECORD_BLOCK_TIME(FTM_VBO_UNMAP);
+        LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("unmapBuffer - vertex");
 		bindGLBuffer(true);
 		updated_all = mIndexLocked; //both vertex and index buffers done updating
 
@@ -1975,7 +1828,7 @@ void LLVertexBuffer::unmapBuffer()
 			{
 				if (!mMappedVertexRegions.empty())
 				{
-					stop_glerror();
+                    LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("unmapBuffer - flush vertex");
 					for (U32 i = 0; i < mMappedVertexRegions.size(); ++i)
 					{
 						const MappedRegion& region = mMappedVertexRegions[i];
@@ -1983,18 +1836,16 @@ void LLVertexBuffer::unmapBuffer()
 						S32 length = sTypeSize[region.mType]*region.mCount;
 						if (gGLManager.mHasMapBufferRange)
 						{
-							LL_RECORD_BLOCK_TIME(FTM_VBO_FLUSH_RANGE);
 #ifdef GL_ARB_map_buffer_range
 							glFlushMappedBufferRange(GL_ARRAY_BUFFER_ARB, offset, length);
 #endif
 						}
 						else if (gGLManager.mHasFlushBufferRange)
-						{
+                        {
 #ifndef LL_MESA_HEADLESS
 							glFlushMappedBufferRangeAPPLE(GL_ARRAY_BUFFER_ARB, offset, length);
 #endif
 						}
-						stop_glerror();
 					}
 
 					mMappedVertexRegions.clear();
@@ -2013,7 +1864,7 @@ void LLVertexBuffer::unmapBuffer()
 	
 	if (mMappedIndexData && mIndexLocked)
 	{
-		LL_RECORD_BLOCK_TIME(FTM_IBO_UNMAP);
+        LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("unmapBuffer - index");
 		bindGLIndices();
 		if(!mMappable)
 		{
@@ -2059,12 +1910,12 @@ void LLVertexBuffer::unmapBuffer()
 				{
 					for (U32 i = 0; i < mMappedIndexRegions.size(); ++i)
 					{
+                        LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("unmapBuffer - flush index");
 						const MappedRegion& region = mMappedIndexRegions[i];
 						S32 offset = region.mIndex >= 0 ? sizeof(U16)*region.mIndex : 0;
 						S32 length = sizeof(U16)*region.mCount;
 						if (gGLManager.mHasMapBufferRange)
 						{
-							LL_RECORD_BLOCK_TIME(FTM_IBO_FLUSH_RANGE);
 #ifdef GL_ARB_map_buffer_range
 							glFlushMappedBufferRange(GL_ELEMENT_ARRAY_BUFFER_ARB, offset, length);
 #endif
@@ -2083,9 +1934,8 @@ void LLVertexBuffer::unmapBuffer()
 					mMappedIndexRegions.clear();
 				}
 			}
-			stop_glerror();
-			glUnmapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB);
-			stop_glerror();
+			
+            glUnmapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB);
 
 			mMappedIndexData = NULL;
 		}
@@ -2111,7 +1961,7 @@ template <class T,S32 type> struct VertexBufferStrider
 	{
 		if (type == LLVertexBuffer::TYPE_INDEX)
 		{
-			volatile U8* ptr = vbo.mapIndexBuffer(index, count, map_range);
+			U8* ptr = vbo.mapIndexBuffer(index, count, map_range);
 
 			if (ptr == NULL)
 			{
@@ -2127,7 +1977,7 @@ template <class T,S32 type> struct VertexBufferStrider
 		{
 			S32 stride = LLVertexBuffer::sTypeSize[type];
 
-			volatile U8* ptr = vbo.mapVertexBuffer(type, index, count, map_range);
+			U8* ptr = vbo.mapVertexBuffer(type, index, count, map_range);
 
 			if (ptr == NULL)
 			{
@@ -2208,13 +2058,12 @@ bool LLVertexBuffer::getClothWeightStrider(LLStrider<LLVector4>& strider, S32 in
 
 //----------------------------------------------------------------------------
 
-static LLTrace::BlockTimerStatHandle FTM_BIND_GL_ARRAY("Bind Array");
 bool LLVertexBuffer::bindGLArray()
 {
 	if (mGLArray && sGLRenderArray != mGLArray)
 	{
 		{
-			LL_RECORD_BLOCK_TIME(FTM_BIND_GL_ARRAY);
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX;
 #if GL_ARB_vertex_array_object
 			glBindVertexArray(mGLArray);
 #endif
@@ -2231,8 +2080,6 @@ bool LLVertexBuffer::bindGLArray()
 	return false;
 }
 
-static LLTrace::BlockTimerStatHandle FTM_BIND_GL_BUFFER("Bind Buffer");
-
 bool LLVertexBuffer::bindGLBuffer(bool force_bind)
 {
 	bindGLArray();
@@ -2241,8 +2088,7 @@ bool LLVertexBuffer::bindGLBuffer(bool force_bind)
 
 	if (useVBOs() && (force_bind || (mGLBuffer && (mGLBuffer != sGLRenderBuffer || !sVBOActive))))
 	{
-		//LL_RECORD_BLOCK_TIME(FTM_BIND_GL_BUFFER);
-		
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX;
 		glBindBufferARB(GL_ARRAY_BUFFER_ARB, mGLBuffer);
 		sGLRenderBuffer = mGLBuffer;
 		sBindCount++;
@@ -2256,16 +2102,29 @@ bool LLVertexBuffer::bindGLBuffer(bool force_bind)
 	return ret;
 }
 
-static LLTrace::BlockTimerStatHandle FTM_BIND_GL_INDICES("Bind Indices");
+bool LLVertexBuffer::bindGLBufferFast()
+{
+    if (mGLBuffer != sGLRenderBuffer || !sVBOActive)
+    {
+        glBindBufferARB(GL_ARRAY_BUFFER_ARB, mGLBuffer);
+        sGLRenderBuffer = mGLBuffer;
+        sBindCount++;
+        sVBOActive = true;
+
+        return true;
+    }
+
+    return false;
+}
 
 bool LLVertexBuffer::bindGLIndices(bool force_bind)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX;
 	bindGLArray();
 
 	bool ret = false;
 	if (useVBOs() && (force_bind || (mGLIndices && (mGLIndices != sGLRenderIndices || !sIBOActive))))
 	{
-		LL_RECORD_BLOCK_TIME(FTM_BIND_GL_INDICES);
 		/*if (sMapped)
 		{
 			LL_ERRS() << "VBO bound while another VBO mapped!" << LL_ENDL;
@@ -2281,6 +2140,21 @@ bool LLVertexBuffer::bindGLIndices(bool force_bind)
 	return ret;
 }
 
+bool LLVertexBuffer::bindGLIndicesFast()
+{
+    if (mGLIndices != sGLRenderIndices || !sIBOActive)
+    {
+        glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, mGLIndices);
+        sGLRenderIndices = mGLIndices;
+        sBindCount++;
+        sIBOActive = true;
+        
+        return true;
+    }
+
+    return false;
+}
+
 void LLVertexBuffer::flush()
 {
 	if (useVBOs())
@@ -2471,11 +2345,39 @@ void LLVertexBuffer::setBuffer(U32 data_mask)
 	}
 }
 
+void LLVertexBuffer::setBufferFast(U32 data_mask)
+{
+    if (useVBOs())
+    {
+        //set up pointers if the data mask is different ...
+        bool setup = (sLastMask != data_mask);
+
+        const bool bindBuffer = bindGLBufferFast();
+        const bool bindIndices = bindGLIndicesFast();
+
+        setup = setup || bindBuffer || bindIndices;
+        
+        setupClientArrays(data_mask);
+
+        if (data_mask && setup)
+        {
+            setupVertexBufferFast(data_mask);
+            sSetCount++;
+        }
+    }
+    else
+    {
+        //fallback to slow path when not using VBOs
+        setBuffer(data_mask);
+    }
+}
+
+
 // virtual (default)
 void LLVertexBuffer::setupVertexBuffer(U32 data_mask)
 {
 	stop_glerror();
-	volatile U8* base = useVBOs() ? (U8*) mAlignedOffset : mMappedData;
+	U8* base = useVBOs() ? (U8*) mAlignedOffset : mMappedData;
 
 	if (gDebugGL && ((data_mask & mTypeMask) != data_mask))
 	{
@@ -2490,144 +2392,191 @@ void LLVertexBuffer::setupVertexBuffer(U32 data_mask)
 		LL_ERRS() << "LLVertexBuffer::setupVertexBuffer missing required components for supplied data mask." << LL_ENDL;
 	}
 
-	if (LLGLSLShader::sNoFixedFunction)
+	if (data_mask & MAP_NORMAL)
 	{
-		if (data_mask & MAP_NORMAL)
-		{
-			S32 loc = TYPE_NORMAL;
-			void* ptr = (void*)(base + mOffsets[TYPE_NORMAL]);
-			glVertexAttribPointerARB(loc, 3, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_NORMAL], ptr);
-		}
-		if (data_mask & MAP_TEXCOORD3)
-		{
-			S32 loc = TYPE_TEXCOORD3;
-			void* ptr = (void*)(base + mOffsets[TYPE_TEXCOORD3]);
-			glVertexAttribPointerARB(loc,2,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD3], ptr);
-		}
-		if (data_mask & MAP_TEXCOORD2)
-		{
-			S32 loc = TYPE_TEXCOORD2;
-			void* ptr = (void*)(base + mOffsets[TYPE_TEXCOORD2]);
-			glVertexAttribPointerARB(loc,2,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD2], ptr);
-		}
-		if (data_mask & MAP_TEXCOORD1)
-		{
-			S32 loc = TYPE_TEXCOORD1;
-			void* ptr = (void*)(base + mOffsets[TYPE_TEXCOORD1]);
-			glVertexAttribPointerARB(loc,2,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD1], ptr);
-		}
-		if (data_mask & MAP_TANGENT)
-		{
-			S32 loc = TYPE_TANGENT;
-			void* ptr = (void*)(base + mOffsets[TYPE_TANGENT]);
-			glVertexAttribPointerARB(loc, 4,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TANGENT], ptr);
-		}
-		if (data_mask & MAP_TEXCOORD0)
-		{
-			S32 loc = TYPE_TEXCOORD0;
-			void* ptr = (void*)(base + mOffsets[TYPE_TEXCOORD0]);
-			glVertexAttribPointerARB(loc,2,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD0], ptr);
-		}
-		if (data_mask & MAP_COLOR)
-		{
-			S32 loc = TYPE_COLOR;
-			//bind emissive instead of color pointer if emissive is present
-			void* ptr = (data_mask & MAP_EMISSIVE) ? (void*)(base + mOffsets[TYPE_EMISSIVE]) : (void*)(base + mOffsets[TYPE_COLOR]);
-			glVertexAttribPointerARB(loc, 4, GL_UNSIGNED_BYTE, GL_TRUE, LLVertexBuffer::sTypeSize[TYPE_COLOR], ptr);
-		}
-		if (data_mask & MAP_EMISSIVE)
-		{
-			S32 loc = TYPE_EMISSIVE;
-			void* ptr = (void*)(base + mOffsets[TYPE_EMISSIVE]);
-			glVertexAttribPointerARB(loc, 4, GL_UNSIGNED_BYTE, GL_TRUE, LLVertexBuffer::sTypeSize[TYPE_EMISSIVE], ptr);
+		S32 loc = TYPE_NORMAL;
+		void* ptr = (void*)(base + mOffsets[TYPE_NORMAL]);
+		glVertexAttribPointerARB(loc, 3, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_NORMAL], ptr);
+	}
+	if (data_mask & MAP_TEXCOORD3)
+	{
+		S32 loc = TYPE_TEXCOORD3;
+		void* ptr = (void*)(base + mOffsets[TYPE_TEXCOORD3]);
+		glVertexAttribPointerARB(loc,2,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD3], ptr);
+	}
+	if (data_mask & MAP_TEXCOORD2)
+	{
+		S32 loc = TYPE_TEXCOORD2;
+		void* ptr = (void*)(base + mOffsets[TYPE_TEXCOORD2]);
+		glVertexAttribPointerARB(loc,2,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD2], ptr);
+	}
+	if (data_mask & MAP_TEXCOORD1)
+	{
+		S32 loc = TYPE_TEXCOORD1;
+		void* ptr = (void*)(base + mOffsets[TYPE_TEXCOORD1]);
+		glVertexAttribPointerARB(loc,2,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD1], ptr);
+	}
+	if (data_mask & MAP_TANGENT)
+	{
+		S32 loc = TYPE_TANGENT;
+		void* ptr = (void*)(base + mOffsets[TYPE_TANGENT]);
+		glVertexAttribPointerARB(loc, 4,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TANGENT], ptr);
+	}
+	if (data_mask & MAP_TEXCOORD0)
+	{
+		S32 loc = TYPE_TEXCOORD0;
+		void* ptr = (void*)(base + mOffsets[TYPE_TEXCOORD0]);
+		glVertexAttribPointerARB(loc,2,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD0], ptr);
+	}
+	if (data_mask & MAP_COLOR)
+	{
+		S32 loc = TYPE_COLOR;
+		//bind emissive instead of color pointer if emissive is present
+		void* ptr = (data_mask & MAP_EMISSIVE) ? (void*)(base + mOffsets[TYPE_EMISSIVE]) : (void*)(base + mOffsets[TYPE_COLOR]);
+		glVertexAttribPointerARB(loc, 4, GL_UNSIGNED_BYTE, GL_TRUE, LLVertexBuffer::sTypeSize[TYPE_COLOR], ptr);
+	}
+	if (data_mask & MAP_EMISSIVE)
+	{
+		S32 loc = TYPE_EMISSIVE;
+		void* ptr = (void*)(base + mOffsets[TYPE_EMISSIVE]);
+		glVertexAttribPointerARB(loc, 4, GL_UNSIGNED_BYTE, GL_TRUE, LLVertexBuffer::sTypeSize[TYPE_EMISSIVE], ptr);
 
-			if (!(data_mask & MAP_COLOR))
-			{ //map emissive to color channel when color is not also being bound to avoid unnecessary shader swaps
-				loc = TYPE_COLOR;
-				glVertexAttribPointerARB(loc, 4, GL_UNSIGNED_BYTE, GL_TRUE, LLVertexBuffer::sTypeSize[TYPE_EMISSIVE], ptr);
-			}
-		}
-		if (data_mask & MAP_WEIGHT)
-		{
-			S32 loc = TYPE_WEIGHT;
-			void* ptr = (void*)(base + mOffsets[TYPE_WEIGHT]);
-			glVertexAttribPointerARB(loc, 1, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_WEIGHT], ptr);
-		}
-		if (data_mask & MAP_WEIGHT4)
-		{
-			S32 loc = TYPE_WEIGHT4;
-			void* ptr = (void*)(base+mOffsets[TYPE_WEIGHT4]);
-			glVertexAttribPointerARB(loc, 4, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_WEIGHT4], ptr);
-		}
-		if (data_mask & MAP_CLOTHWEIGHT)
-		{
-			S32 loc = TYPE_CLOTHWEIGHT;
-			void* ptr = (void*)(base + mOffsets[TYPE_CLOTHWEIGHT]);
-			glVertexAttribPointerARB(loc, 4, GL_FLOAT, GL_TRUE,  LLVertexBuffer::sTypeSize[TYPE_CLOTHWEIGHT], ptr);
+		if (!(data_mask & MAP_COLOR))
+		{ //map emissive to color channel when color is not also being bound to avoid unnecessary shader swaps
+			loc = TYPE_COLOR;
+			glVertexAttribPointerARB(loc, 4, GL_UNSIGNED_BYTE, GL_TRUE, LLVertexBuffer::sTypeSize[TYPE_EMISSIVE], ptr);
 		}
-		if (data_mask & MAP_TEXTURE_INDEX && 
-				(gGLManager.mGLSLVersionMajor >= 2 || gGLManager.mGLSLVersionMinor >= 30)) //indexed texture rendering requires GLSL 1.30 or later
-		{
+	}
+	if (data_mask & MAP_WEIGHT)
+	{
+		S32 loc = TYPE_WEIGHT;
+		void* ptr = (void*)(base + mOffsets[TYPE_WEIGHT]);
+		glVertexAttribPointerARB(loc, 1, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_WEIGHT], ptr);
+	}
+	if (data_mask & MAP_WEIGHT4)
+	{
+		S32 loc = TYPE_WEIGHT4;
+		void* ptr = (void*)(base+mOffsets[TYPE_WEIGHT4]);
+		glVertexAttribPointerARB(loc, 4, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_WEIGHT4], ptr);
+	}
+	if (data_mask & MAP_CLOTHWEIGHT)
+	{
+		S32 loc = TYPE_CLOTHWEIGHT;
+		void* ptr = (void*)(base + mOffsets[TYPE_CLOTHWEIGHT]);
+		glVertexAttribPointerARB(loc, 4, GL_FLOAT, GL_TRUE,  LLVertexBuffer::sTypeSize[TYPE_CLOTHWEIGHT], ptr);
+	}
+	if (data_mask & MAP_TEXTURE_INDEX && 
+			(gGLManager.mGLSLVersionMajor >= 2 || gGLManager.mGLSLVersionMinor >= 30)) //indexed texture rendering requires GLSL 1.30 or later
+	{
 #if !LL_DARWIN
-			S32 loc = TYPE_TEXTURE_INDEX;
-			void *ptr = (void*) (base + mOffsets[TYPE_VERTEX] + 12);
-			glVertexAttribIPointer(loc, 1, GL_UNSIGNED_INT, LLVertexBuffer::sTypeSize[TYPE_VERTEX], ptr);
+		S32 loc = TYPE_TEXTURE_INDEX;
+		void *ptr = (void*) (base + mOffsets[TYPE_VERTEX] + 12);
+		glVertexAttribIPointer(loc, 1, GL_UNSIGNED_INT, LLVertexBuffer::sTypeSize[TYPE_VERTEX], ptr);
 #endif
-		}
-		if (data_mask & MAP_VERTEX)
-		{
-			S32 loc = TYPE_VERTEX;
-			void* ptr = (void*)(base + mOffsets[TYPE_VERTEX]);
-			glVertexAttribPointerARB(loc, 3,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_VERTEX], ptr);
-		}	
-	}	
-	else
-	{
-		if (data_mask & MAP_NORMAL)
-		{
-			glNormalPointer(GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_NORMAL], (void*)(base + mOffsets[TYPE_NORMAL]));
-		}
-		if (data_mask & MAP_TEXCOORD3)
-		{
-			glClientActiveTextureARB(GL_TEXTURE3_ARB);
-			glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD3], (void*)(base + mOffsets[TYPE_TEXCOORD3]));
-			glClientActiveTextureARB(GL_TEXTURE0_ARB);
-		}
-		if (data_mask & MAP_TEXCOORD2)
-		{
-			glClientActiveTextureARB(GL_TEXTURE2_ARB);
-			glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD2], (void*)(base + mOffsets[TYPE_TEXCOORD2]));
-			glClientActiveTextureARB(GL_TEXTURE0_ARB);
-		}
-		if (data_mask & MAP_TEXCOORD1)
-		{
-			glClientActiveTextureARB(GL_TEXTURE1_ARB);
-			glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD1], (void*)(base + mOffsets[TYPE_TEXCOORD1]));
-			glClientActiveTextureARB(GL_TEXTURE0_ARB);
-		}
-		if (data_mask & MAP_TANGENT)
-		{
-			glClientActiveTextureARB(GL_TEXTURE2_ARB);
-			glTexCoordPointer(4,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TANGENT], (void*)(base + mOffsets[TYPE_TANGENT]));
-			glClientActiveTextureARB(GL_TEXTURE0_ARB);
-		}
-		if (data_mask & MAP_TEXCOORD0)
-		{
-			glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD0], (void*)(base + mOffsets[TYPE_TEXCOORD0]));
-		}
-		if (data_mask & MAP_COLOR)
-		{
-			glColorPointer(4, GL_UNSIGNED_BYTE, LLVertexBuffer::sTypeSize[TYPE_COLOR], (void*)(base + mOffsets[TYPE_COLOR]));
-		}
-		if (data_mask & MAP_VERTEX)
-		{
-			glVertexPointer(3,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_VERTEX], (void*)(base + 0));
-		}	
 	}
+	if (data_mask & MAP_VERTEX)
+	{
+		S32 loc = TYPE_VERTEX;
+		void* ptr = (void*)(base + mOffsets[TYPE_VERTEX]);
+		glVertexAttribPointerARB(loc, 3,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_VERTEX], ptr);
+	}	
 
 	llglassertok();
 }
 
+void LLVertexBuffer::setupVertexBufferFast(U32 data_mask)
+{
+    U8* base = (U8*)mAlignedOffset;
+
+    if (data_mask & MAP_NORMAL)
+    {
+        S32 loc = TYPE_NORMAL;
+        void* ptr = (void*)(base + mOffsets[TYPE_NORMAL]);
+        glVertexAttribPointerARB(loc, 3, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_NORMAL], ptr);
+    }
+    if (data_mask & MAP_TEXCOORD3)
+    {
+        S32 loc = TYPE_TEXCOORD3;
+        void* ptr = (void*)(base + mOffsets[TYPE_TEXCOORD3]);
+        glVertexAttribPointerARB(loc, 2, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD3], ptr);
+    }
+    if (data_mask & MAP_TEXCOORD2)
+    {
+        S32 loc = TYPE_TEXCOORD2;
+        void* ptr = (void*)(base + mOffsets[TYPE_TEXCOORD2]);
+        glVertexAttribPointerARB(loc, 2, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD2], ptr);
+    }
+    if (data_mask & MAP_TEXCOORD1)
+    {
+        S32 loc = TYPE_TEXCOORD1;
+        void* ptr = (void*)(base + mOffsets[TYPE_TEXCOORD1]);
+        glVertexAttribPointerARB(loc, 2, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD1], ptr);
+    }
+    if (data_mask & MAP_TANGENT)
+    {
+        S32 loc = TYPE_TANGENT;
+        void* ptr = (void*)(base + mOffsets[TYPE_TANGENT]);
+        glVertexAttribPointerARB(loc, 4, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TANGENT], ptr);
+    }
+    if (data_mask & MAP_TEXCOORD0)
+    {
+        S32 loc = TYPE_TEXCOORD0;
+        void* ptr = (void*)(base + mOffsets[TYPE_TEXCOORD0]);
+        glVertexAttribPointerARB(loc, 2, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD0], ptr);
+    }
+    if (data_mask & MAP_COLOR)
+    {
+        S32 loc = TYPE_COLOR;
+        //bind emissive instead of color pointer if emissive is present
+        void* ptr = (data_mask & MAP_EMISSIVE) ? (void*)(base + mOffsets[TYPE_EMISSIVE]) : (void*)(base + mOffsets[TYPE_COLOR]);
+        glVertexAttribPointerARB(loc, 4, GL_UNSIGNED_BYTE, GL_TRUE, LLVertexBuffer::sTypeSize[TYPE_COLOR], ptr);
+    }
+    if (data_mask & MAP_EMISSIVE)
+    {
+        S32 loc = TYPE_EMISSIVE;
+        void* ptr = (void*)(base + mOffsets[TYPE_EMISSIVE]);
+        glVertexAttribPointerARB(loc, 4, GL_UNSIGNED_BYTE, GL_TRUE, LLVertexBuffer::sTypeSize[TYPE_EMISSIVE], ptr);
+
+        if (!(data_mask & MAP_COLOR))
+        { //map emissive to color channel when color is not also being bound to avoid unnecessary shader swaps
+            loc = TYPE_COLOR;
+            glVertexAttribPointerARB(loc, 4, GL_UNSIGNED_BYTE, GL_TRUE, LLVertexBuffer::sTypeSize[TYPE_EMISSIVE], ptr);
+        }
+    }
+    if (data_mask & MAP_WEIGHT)
+    {
+        S32 loc = TYPE_WEIGHT;
+        void* ptr = (void*)(base + mOffsets[TYPE_WEIGHT]);
+        glVertexAttribPointerARB(loc, 1, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_WEIGHT], ptr);
+    }
+    if (data_mask & MAP_WEIGHT4)
+    {
+        S32 loc = TYPE_WEIGHT4;
+        void* ptr = (void*)(base + mOffsets[TYPE_WEIGHT4]);
+        glVertexAttribPointerARB(loc, 4, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_WEIGHT4], ptr);
+    }
+    if (data_mask & MAP_CLOTHWEIGHT)
+    {
+        S32 loc = TYPE_CLOTHWEIGHT;
+        void* ptr = (void*)(base + mOffsets[TYPE_CLOTHWEIGHT]);
+        glVertexAttribPointerARB(loc, 4, GL_FLOAT, GL_TRUE, LLVertexBuffer::sTypeSize[TYPE_CLOTHWEIGHT], ptr);
+    }
+    if (data_mask & MAP_TEXTURE_INDEX)
+    {
+#if !LL_DARWIN
+        S32 loc = TYPE_TEXTURE_INDEX;
+        void* ptr = (void*)(base + mOffsets[TYPE_VERTEX] + 12);
+        glVertexAttribIPointer(loc, 1, GL_UNSIGNED_INT, LLVertexBuffer::sTypeSize[TYPE_VERTEX], ptr);
+#endif
+    }
+    if (data_mask & MAP_VERTEX)
+    {
+        S32 loc = TYPE_VERTEX;
+        void* ptr = (void*)(base + mOffsets[TYPE_VERTEX]);
+        glVertexAttribPointerARB(loc, 3, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_VERTEX], ptr);
+    }
+}
+
 LLVertexBuffer::MappedRegion::MappedRegion(S32 type, S32 index, S32 count)
 : mType(type), mIndex(index), mCount(count)
 { 
diff --git a/indra/llrender/llvertexbuffer.h b/indra/llrender/llvertexbuffer.h
index dbe1a3687f12c06056d901ba01c1ca455f5252ec..3b3fe4498436f14af4557650d51175a7f62344a8 100644
--- a/indra/llrender/llvertexbuffer.h
+++ b/indra/llrender/llvertexbuffer.h
@@ -64,10 +64,10 @@ class LLVBOPool
 	const U32 mType;
 
 	//size MUST be a power of 2
-	volatile U8* allocate(U32& name, U32 size, bool for_seed = false);
+	U8* allocate(U32& name, U32 size, bool for_seed = false);
 	
 	//size MUST be the size provided to allocate that returned the given name
-	void release(U32 name, volatile U8* buffer, U32 size);
+	void release(U32 name, U8* buffer, U32 size);
 	
 	//batch allocate buffers to be provided to the application on demand
 	void seedPool();
@@ -82,20 +82,23 @@ class LLVBOPool
 	{
 	public:
 		U32 mGLName;
-		volatile U8* mClientData;
+		U8* mClientData;
 	};
 
 	typedef std::list<Record> record_list_t;
 	std::vector<record_list_t> mFreeList;
 	std::vector<U32> mMissCount;
 
+	//used to avoid calling glGenBuffers for every VBO creation
+	static U32 sNamePool[1024];
+	static U32 sNameIdx;
 };
 
 
 //============================================================================
 // base class 
 class LLPrivateMemoryPool;
-class LLVertexBuffer : public LLRefCount, public LLTrace::MemTrackable<LLVertexBuffer>
+class LLVertexBuffer : public LLRefCount
 {
 public:
 	class MappedRegion
@@ -110,8 +113,7 @@ class LLVertexBuffer : public LLRefCount, public LLTrace::MemTrackable<LLVertexB
 	};
 
 	LLVertexBuffer(const LLVertexBuffer& rhs)
-	:	LLTrace::MemTrackable<LLVertexBuffer>("LLVertexBuffer"),
-		mUsage(rhs.mUsage)
+	:	mUsage(rhs.mUsage)
 	{
 		*this = rhs;
 	}
@@ -127,7 +129,7 @@ class LLVertexBuffer : public LLRefCount, public LLTrace::MemTrackable<LLVertexB
 	static LLVBOPool sDynamicCopyVBOPool;
 	static LLVBOPool sStreamIBOPool;
 	static LLVBOPool sDynamicIBOPool;
-	
+
 	static std::list<U32> sAvailableVAOName;
 	static U32 sCurVAOName;
 
@@ -143,8 +145,7 @@ class LLVertexBuffer : public LLRefCount, public LLTrace::MemTrackable<LLVertexB
 	static void initClass(bool use_vbo, bool no_vbo_mapping);
 	static void cleanupClass();
 	static void setupClientArrays(U32 data_mask);
-	static void pushPositions(U32 mode, const LLVector4a* pos, U32 count);
-	static void drawArrays(U32 mode, const std::vector<LLVector3>& pos, const std::vector<LLVector3>& norm);
+	static void drawArrays(U32 mode, const std::vector<LLVector3>& pos);
 	static void drawElements(U32 mode, const LLVector4a* pos, const LLVector2* tc, S32 num_indices, const U16* indicesp);
 
  	static void unbind(); //unbind any bound vertex buffer
@@ -207,13 +208,17 @@ class LLVertexBuffer : public LLRefCount, public LLTrace::MemTrackable<LLVertexB
 
 	virtual ~LLVertexBuffer(); // use unref()
 
-	virtual void setupVertexBuffer(U32 data_mask); // pure virtual, called from mapBuffer()
+	virtual void setupVertexBuffer(U32 data_mask);
+    void setupVertexBufferFast(U32 data_mask);
+
 	void setupVertexArray();
 	
 	void	genBuffer(U32 size);
 	void	genIndices(U32 size);
 	bool	bindGLBuffer(bool force_bind = false);
+    bool	bindGLBufferFast();
 	bool	bindGLIndices(bool force_bind = false);
+    bool    bindGLIndicesFast();
 	bool	bindGLArray();
 	void	releaseBuffer();
 	void	releaseIndices();
@@ -229,13 +234,15 @@ class LLVertexBuffer : public LLRefCount, public LLTrace::MemTrackable<LLVertexB
 	LLVertexBuffer(U32 typemask, S32 usage);
 	
 	// map for data access
-	volatile U8*		mapVertexBuffer(S32 type, S32 index, S32 count, bool map_range);
-	volatile U8*		mapIndexBuffer(S32 index, S32 count, bool map_range);
+	U8*		mapVertexBuffer(S32 type, S32 index, S32 count, bool map_range);
+	U8*		mapIndexBuffer(S32 index, S32 count, bool map_range);
 
 	void bindForFeedback(U32 channel, U32 type, U32 index, U32 count);
 
 	// set for rendering
 	virtual void	setBuffer(U32 data_mask); 	// calls  setupVertexBuffer() if data_mask is not 0
+    void	setBufferFast(U32 data_mask); 	// calls setupVertexBufferFast(), assumes data_mask is not 0 among other assumptions
+
 	void flush(); //flush pending data to GL memory
 	// allocate buffer
 	bool	allocateBuffer(S32 nverts, S32 nindices, bool create);
@@ -258,7 +265,6 @@ class LLVertexBuffer : public LLRefCount, public LLTrace::MemTrackable<LLVertexB
 	bool getTangentStrider(LLStrider<LLVector3>& strider, S32 index=0, S32 count = -1, bool map_range = false);
 	bool getTangentStrider(LLStrider<LLVector4a>& strider, S32 index=0, S32 count = -1, bool map_range = false);
 	bool getColorStrider(LLStrider<LLColor4U>& strider, S32 index=0, S32 count = -1, bool map_range = false);
-	bool getTextureIndexStrider(LLStrider<LLColor4U>& strider, S32 index=0, S32 count = -1, bool map_range = false);
 	bool getEmissiveStrider(LLStrider<LLColor4U>& strider, S32 index=0, S32 count = -1, bool map_range = false);
 	bool getWeightStrider(LLStrider<F32>& strider, S32 index=0, S32 count = -1, bool map_range = false);
 	bool getWeight4Strider(LLStrider<LLVector4>& strider, S32 index=0, S32 count = -1, bool map_range = false);
@@ -271,14 +277,14 @@ class LLVertexBuffer : public LLRefCount, public LLTrace::MemTrackable<LLVertexB
 	S32 getNumVerts() const					{ return mNumVerts; }
 	S32 getNumIndices() const				{ return mNumIndices; }
 	
-	volatile U8* getIndicesPointer() const			{ return useVBOs() ? (U8*) mAlignedIndexOffset : mMappedIndexData; }
-	volatile U8* getVerticesPointer() const			{ return useVBOs() ? (U8*) mAlignedOffset : mMappedData; }
+	U8* getIndicesPointer() const			{ return useVBOs() ? (U8*) mAlignedIndexOffset : mMappedIndexData; }
+	U8* getVerticesPointer() const			{ return useVBOs() ? (U8*) mAlignedOffset : mMappedData; }
 	U32 getTypeMask() const					{ return mTypeMask; }
 	bool hasDataType(S32 type) const		{ return ((1 << type) & getTypeMask()); }
 	S32 getSize() const;
 	S32 getIndicesSize() const				{ return mIndicesSize; }
-	volatile U8* getMappedData() const				{ return mMappedData; }
-	volatile U8* getMappedIndices() const			{ return mMappedIndexData; }
+	U8* getMappedData() const				{ return mMappedData; }
+	U8* getMappedIndices() const			{ return mMappedIndexData; }
 	S32 getOffset(S32 type) const			{ return mOffsets[type]; }
 	S32 getUsage() const					{ return mUsage; }
 	bool isWriteable() const				{ return (mMappable || mUsage == GL_STREAM_DRAW_ARB) ? true : false; }
@@ -287,6 +293,9 @@ class LLVertexBuffer : public LLRefCount, public LLTrace::MemTrackable<LLVertexB
 	void drawArrays(U32 mode, U32 offset, U32 count) const;
 	void drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indices_offset) const;
 
+    //implementation for inner loops that does no safety checking
+    void drawRangeFast(U32 mode, U32 start, U32 end, U32 count, U32 indices_offset) const;
+
 	//for debugging, validate data in given range is valid
 	void validateRange(U32 start, U32 end, U32 count, U32 offset) const;
 
@@ -308,8 +317,8 @@ class LLVertexBuffer : public LLRefCount, public LLTrace::MemTrackable<LLVertexB
 	U32		mGLIndices;		// GL IBO handle
 	U32		mGLArray;		// GL VAO handle
 	
-	volatile U8* mMappedData;	// pointer to currently mapped data (NULL if unmapped)
-	volatile U8* mMappedIndexData;	// pointer to currently mapped indices (NULL if unmapped)
+	U8* mMappedData;	// pointer to currently mapped data (NULL if unmapped)
+	U8* mMappedIndexData;	// pointer to currently mapped indices (NULL if unmapped)
 
 	U32		mMappedDataUsingVBOs : 1;
 	U32		mMappedIndexDataUsingVBOs : 1;
diff --git a/indra/llui/CMakeLists.txt b/indra/llui/CMakeLists.txt
index d96824bbf8b5c672e128c27cb36a8457cf624a06..e0579352d3b55d082a0f8e3a039255011f2d443c 100644
--- a/indra/llui/CMakeLists.txt
+++ b/indra/llui/CMakeLists.txt
@@ -308,6 +308,10 @@ if(LL_TESTS)
       ${BOOST_FIBER_LIBRARY} ${BOOST_CONTEXT_LIBRARY} ${BOOST_SYSTEM_LIBRARY}
       ${WINDOWS_LIBRARIES})
   if(NOT LINUX)
-    LL_ADD_INTEGRATION_TEST(llurlentry llurlentry.cpp "${test_libs}")
+    if(WINDOWS)
+      LL_ADD_INTEGRATION_TEST(llurlentry llurlentry.cpp "imm32;${test_libs}")
+    else(WINDOWS)
+      LL_ADD_INTEGRATION_TEST(llurlentry llurlentry.cpp "${test_libs}")
+    endif(WINDOWS)
   endif(NOT LINUX)
 endif(LL_TESTS)
diff --git a/indra/llui/llbutton.cpp b/indra/llui/llbutton.cpp
index 0e59fdf51936e4c302cbcb66a8e2c5684ebf818e..8028f397f3ebf99bc2c52d25888ab68c8d350bbf 100644
--- a/indra/llui/llbutton.cpp
+++ b/indra/llui/llbutton.cpp
@@ -102,6 +102,7 @@ LLButton::Params::Params()
 	scale_image("scale_image", true),
 	hover_glow_amount("hover_glow_amount"),
 	commit_on_return("commit_on_return", true),
+    commit_on_capture_lost("commit_on_capture_lost", false),
 	display_pressed_state("display_pressed_state", true),
 	use_draw_context_alpha("use_draw_context_alpha", true),
 	badge("badge"),
@@ -165,6 +166,7 @@ LLButton::LLButton(const LLButton::Params& p)
 	mBottomVPad(p.pad_bottom),
 	mHoverGlowStrength(p.hover_glow_amount),
 	mCommitOnReturn(p.commit_on_return),
+    mCommitOnCaptureLost(p.commit_on_capture_lost),
 	mFadeWhenDisabled(FALSE),
 	mForcePressedState(false),
 	mDisplayPressedState(p.display_pressed_state),
@@ -475,6 +477,10 @@ BOOL LLButton::handleMouseUp(S32 x, S32 y, MASK mask)
 	// We only handle the click if the click both started and ended within us
 	if( hasMouseCapture() )
 	{
+        // reset timers before focus change, to not cause
+        // additional commits if mCommitOnCaptureLost.
+        resetMouseDownTimer();
+
 		// Always release the mouse
 		gFocusMgr.setMouseCapture( NULL );
 
@@ -489,8 +495,6 @@ BOOL LLButton::handleMouseUp(S32 x, S32 y, MASK mask)
 		// Regardless of where mouseup occurs, handle callback
 		if(mMouseUpSignal) (*mMouseUpSignal)(this, LLSD());
 
-		resetMouseDownTimer();
-
 		// DO THIS AT THE VERY END to allow the button to be destroyed as a result of being clicked.
 		// If mouseup in the widget, it's been clicked
 		if (pointInView(x, y))
@@ -1195,6 +1199,18 @@ void LLButton::setImageOverlay(const LLUUID& image_id, LLFontGL::HAlign alignmen
 
 void LLButton::onMouseCaptureLost()
 {
+    if (mCommitOnCaptureLost
+        && mMouseDownTimer.getStarted())
+    {
+        if (mMouseUpSignal) (*mMouseUpSignal)(this, LLSD());
+
+        if (mIsToggle)
+        {
+            toggleState();
+        }
+
+        LLUICtrl::onCommit();
+    }
 	resetMouseDownTimer();
 }
 
diff --git a/indra/llui/llbutton.h b/indra/llui/llbutton.h
index 572d36996c47e64cbf9f622823a86340de66eef8..ccd31e90c0309ecbd4b83915d2d4fc88dc3996da 100644
--- a/indra/llui/llbutton.h
+++ b/indra/llui/llbutton.h
@@ -124,6 +124,7 @@ class LLButton
 		Optional<bool>			is_toggle,
 								scale_image,
 								commit_on_return,
+								commit_on_capture_lost,
 								display_pressed_state;
 		
 		Optional<F32>				hover_glow_amount;
@@ -374,6 +375,7 @@ class LLButton
 	F32							mCurGlowStrength;
 
 	bool						mCommitOnReturn;
+    bool						mCommitOnCaptureLost;
 	bool						mFadeWhenDisabled;
 	bool						mForcePressedState;
 	bool						mDisplayPressedState;
diff --git a/indra/llui/llcombobox.cpp b/indra/llui/llcombobox.cpp
index bcc653a6021073e6487cbbafa2d682731267704e..9ca05a16f374a0f7fc15bbd4756ebe400377f212 100644
--- a/indra/llui/llcombobox.cpp
+++ b/indra/llui/llcombobox.cpp
@@ -113,6 +113,10 @@ LLComboBox::LLComboBox(const LLComboBox::Params& p)
 	}
 
 	mArrowImage = button_params.image_unselected;
+    if (mArrowImage.notNull())
+    {
+        mImageLoadedConnection = mArrowImage->addLoadedCallback(boost::bind(&LLComboBox::imageLoaded, this));
+    }
 
 	mButton = LLUICtrlFactory::create<LLButton>(button_params);
 
@@ -183,6 +187,7 @@ LLComboBox::~LLComboBox()
 
 	// explicitly disconect this signal, since base class destructor might fire top lost
 	mTopLostSignalConnection.disconnect();
+    mImageLoadedConnection.disconnect();
 }
 
 
@@ -1074,6 +1079,30 @@ void LLComboBox::onSetHighlight() const
     }
 }
 
+void LLComboBox::imageLoaded()
+{
+    static LLUICachedControl<S32> drop_shadow_button("DropShadowButton", 0);
+
+    if (mAllowTextEntry)
+    {
+        LLRect rect = getLocalRect();
+        S32 arrow_width = mArrowImage ? mArrowImage->getWidth() : 0;
+        S32 shadow_size = drop_shadow_button;
+        mButton->setRect(LLRect(getRect().getWidth() - llmax(8, arrow_width) - 2 * shadow_size,
+            rect.mTop, rect.mRight, rect.mBottom));
+        if (mButton->getVisible())
+        {
+            // recalculate field size
+            if (mTextEntry)
+            {
+                LLRect text_entry_rect(0, getRect().getHeight(), getRect().getWidth(), 0);
+                text_entry_rect.mRight -= llmax(8, arrow_width) + 2 * drop_shadow_button;
+                mTextEntry->reshape(text_entry_rect.getWidth(), text_entry_rect.getHeight(), TRUE);
+            }
+        }
+    }
+}
+
 //============================================================================
 // LLCtrlListInterface functions
 
diff --git a/indra/llui/llcombobox.h b/indra/llui/llcombobox.h
index e17d6cdfb41b1fa4f958f4e88c095fea4db8094f..cac8850a25e77b55b5dedca7bf9304b5b1836124 100644
--- a/indra/llui/llcombobox.h
+++ b/indra/llui/llcombobox.h
@@ -105,6 +105,8 @@ class LLComboBox
     virtual std::string _getSearchText() const;
     virtual void onSetHighlight() const;
 
+    void imageLoaded();
+
 public:
 	// LLView interface
 	virtual void	onFocusLost();
@@ -244,6 +246,7 @@ class LLComboBox
 	commit_callback_t	mTextChangedCallback;
 	commit_callback_t	mSelectionCallback;
 	boost::signals2::connection mTopLostSignalConnection;
+    boost::signals2::connection mImageLoadedConnection;
 	commit_signal_t		mOnReturnSignal;
 	S32                 mLastSelectedIndex;
 };
diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp
index 0e429225430c19323eb1fc49e9fb233d071c5716..d413fab2700206e3a24c6f36f7bcfee1c30c9bae 100644
--- a/indra/llui/llfloater.cpp
+++ b/indra/llui/llfloater.cpp
@@ -259,6 +259,7 @@ LLFloater::LLFloater(const LLSD& key, const LLFloater::Params& p)
 	mMinHeight(p.min_height),
 	mHeaderHeight(p.header_height),
 	mLegacyHeaderHeight(p.legacy_header_height),
+	mDefaultRectForGroup(true),
 	mMinimized(FALSE),
 	mForeground(FALSE),
 	mFirstLook(TRUE),
@@ -761,17 +762,13 @@ void LLFloater::closeFloater(bool app_quitting)
 		for(handle_set_iter_t dependent_it = mDependents.begin();
 			dependent_it != mDependents.end(); )
 		{
-			
 			LLFloater* floaterp = dependent_it->get();
-			if (floaterp)
-			{
-				++dependent_it;
-				floaterp->closeFloater(app_quitting);
-			}
-			else
-			{
-				mDependents.erase(dependent_it++);
-			}
+            dependent_it = mDependents.erase(dependent_it);
+            if (floaterp)
+            {
+                floaterp->mDependeeHandle = LLHandle<LLFloater>();
+                floaterp->closeFloater(app_quitting);
+            }
 		}
 		
 		cleanupHandles();
@@ -906,7 +903,10 @@ bool LLFloater::applyRectControl()
 	if (last_in_group && last_in_group != this)
 	{
 		// other floaters in our group, position ourselves relative to them and don't save the rect
-		mRectControl.clear();
+		if (mDefaultRectForGroup)
+		{
+			mRectControl.clear();
+		}
 		mPositioning = LLFloaterEnums::POSITIONING_CASCADE_GROUP;
 	}
 	else
@@ -1439,7 +1439,7 @@ void LLFloater::cleanupHandles()
 		LLFloater* floaterp = dependent_it->get();
 		if (!floaterp)
 		{
-			mDependents.erase(dependent_it++);
+            dependent_it = mDependents.erase(dependent_it);
 		}
 		else
 		{
@@ -3268,11 +3268,9 @@ boost::signals2::connection LLFloater::setCloseCallback( const commit_signal_t::
 	return mCloseSignal.connect(cb);
 }
 
-LLTrace::BlockTimerStatHandle POST_BUILD("Floater Post Build");
-static LLTrace::BlockTimerStatHandle FTM_EXTERNAL_FLOATER_LOAD("Load Extern Floater Reference");
-
 bool LLFloater::initFloaterXML(LLXMLNodePtr node, LLView *parent, const std::string& filename, LLXMLNodePtr output_node)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	Params default_params(LLUICtrlFactory::getDefaultParams<LLFloater>());
 	Params params(default_params);
 
@@ -3299,7 +3297,6 @@ bool LLFloater::initFloaterXML(LLXMLNodePtr node, LLView *parent, const std::str
 
 		LLUICtrlFactory::instance().pushFileName(xml_filename);
 
-		LL_RECORD_BLOCK_TIME(FTM_EXTERNAL_FLOATER_LOAD);
 		if (!LLUICtrlFactory::getLayeredXMLNode(xml_filename, referenced_xml))
 		{
 			LL_WARNS() << "Couldn't parse panel from: " << xml_filename << LL_ENDL;
@@ -3375,12 +3372,8 @@ bool LLFloater::initFloaterXML(LLXMLNodePtr node, LLView *parent, const std::str
 	}
 
 	BOOL result;
-	{
-		LL_RECORD_BLOCK_TIME(POST_BUILD);
-
-		result = postBuild();
-	}
-
+	result = postBuild();
+	
 	if (!result)
 	{
 		LL_ERRS() << "Failed to construct floater " << getName() << LL_ENDL;
@@ -3424,11 +3417,9 @@ bool LLFloater::isVisible(const LLFloater* floater)
     return floater && floater->getVisible();
 }
 
-static LLTrace::BlockTimerStatHandle FTM_BUILD_FLOATERS("Build Floaters");
-
 bool LLFloater::buildFromFile(const std::string& filename)
 {
-	LL_RECORD_BLOCK_TIME(FTM_BUILD_FLOATERS);
+    LL_PROFILE_ZONE_SCOPED;
 	LLXMLNodePtr root;
 
 	if (!LLUICtrlFactory::getLayeredXMLNode(filename, root))
@@ -3490,8 +3481,15 @@ void LLFloater::stackWith(LLFloater& other)
 	}
 	next_rect.translate(floater_offset, -floater_offset);
 
-	next_rect.setLeftTopAndSize(next_rect.mLeft, next_rect.mTop, getRect().getWidth(), getRect().getHeight());
-	
+	const LLRect& rect = getControlGroup()->getRect(mRectControl);
+	if (rect.notEmpty() && !mDefaultRectForGroup && mResizable)
+	{
+		next_rect.setLeftTopAndSize(next_rect.mLeft, next_rect.mTop, llmax(mMinWidth, rect.getWidth()), llmax(mMinHeight, rect.getHeight()));
+	}
+	else
+	{
+		next_rect.setLeftTopAndSize(next_rect.mLeft, next_rect.mTop, getRect().getWidth(), getRect().getHeight());
+	}
 	setShape(next_rect);
 
 	if (!other.getHost())
diff --git a/indra/llui/llfloater.h b/indra/llui/llfloater.h
index 2672d600c6236f828fbc3b822962b6f94b485279..668cd208a906c149e2908b1a09531b8768d99f66 100644
--- a/indra/llui/llfloater.h
+++ b/indra/llui/llfloater.h
@@ -346,6 +346,8 @@ class LLFloater : public LLPanel, public LLInstanceTracker<LLFloater>
 	// handle refocusing.
 	static void		closeFrontmostFloater();
 
+    static bool     isQuitRequested() { return sQuitting; }
+
 //	LLNotification::Params contextualNotification(const std::string& name) 
 //	{ 
 //	    return LLNotification::Params(name).context(mNotificationContext); 
@@ -452,6 +454,7 @@ class LLFloater : public LLPanel, public LLInstanceTracker<LLFloater>
 
 protected:
 	bool			mSaveRect;
+	bool			mDefaultRectForGroup;
 	std::string		mRectControl;
 	std::string		mPosXControl;
 	std::string		mPosYControl;
diff --git a/indra/llui/llfolderview.cpp b/indra/llui/llfolderview.cpp
index cdab95b3ad7508ffca8248a2b4d0626ef4be006b..a6d4a2ae529a913508f2481e5747029663d07745 100644
--- a/indra/llui/llfolderview.cpp
+++ b/indra/llui/llfolderview.cpp
@@ -189,7 +189,6 @@ LLFolderView::LLFolderView(const Params& p)
 	mViewModel(p.view_model),
     mGroupedItemModel(p.grouped_item_model)
 {
-	claimMem(mViewModel);
     LLPanel* panel = p.parent_panel;
     mParentPanel = panel->getHandle();
 	mViewModel->setFolderView(this);
@@ -339,11 +338,9 @@ S32 LLFolderView::arrange( S32* unused_width, S32* unused_height )
 	return ll_round(mTargetHeight);
 }
 
-static LLTrace::BlockTimerStatHandle FTM_FILTER("Filter Folder View");
-
 void LLFolderView::filter( LLFolderViewFilter& filter )
 {
-	LL_RECORD_BLOCK_TIME(FTM_FILTER);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
     static LLCachedControl<S32> time_visible(*LLUI::getInstance()->mSettingGroups["config"], "FilterItemsMaxTimePerFrameVisible", 10);
     static LLCachedControl<S32> time_invisible(*LLUI::getInstance()->mSettingGroups["config"], "FilterItemsMaxTimePerFrameUnvisible", 1);
     filter.resetTime(llclamp((mParentPanel.get()->getVisible() ? time_visible() : time_invisible()), 1, 100));
@@ -505,10 +502,9 @@ BOOL LLFolderView::changeSelection(LLFolderViewItem* selection, BOOL selected)
 	return rv;
 }
 
-static LLTrace::BlockTimerStatHandle FTM_SANITIZE_SELECTION("Sanitize Selection");
 void LLFolderView::sanitizeSelection()
 {
-	LL_RECORD_BLOCK_TIME(FTM_SANITIZE_SELECTION);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
 	// store off current item in case it is automatically deselected
 	// and we want to preserve context
 	LLFolderViewItem* original_selected_item = getCurSelectedItem();
@@ -1639,7 +1635,6 @@ void LLFolderView::setShowSingleSelection(bool show)
 	}
 }
 
-static LLTrace::BlockTimerStatHandle FTM_AUTO_SELECT("Open and Select");
 static LLTrace::BlockTimerStatHandle FTM_INVENTORY("Inventory");
 
 // Main idle routine
@@ -1647,7 +1642,7 @@ void LLFolderView::update()
 {
 	// If this is associated with the user's inventory, don't do anything
 	// until that inventory is loaded up.
-	LL_RECORD_BLOCK_TIME(FTM_INVENTORY);
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; //LL_RECORD_BLOCK_TIME(FTM_INVENTORY);
     
     // If there's no model, the view is in suspended state (being deleted) and shouldn't be updated
     if (getFolderViewModel() == NULL)
@@ -1675,7 +1670,6 @@ void LLFolderView::update()
 	// automatically show matching items, and select first one if we had a selection
 	if (mNeedsAutoSelect)
 	{
-		LL_RECORD_BLOCK_TIME(FTM_AUTO_SELECT);
 		// select new item only if a filtered item not currently selected and there was a selection
 		LLFolderViewItem* selected_itemp = mSelectedItems.empty() ? NULL : mSelectedItems.back();
 		if (!mAutoSelectOverride && selected_itemp && !selected_itemp->getViewModelItem()->potentiallyVisible())
diff --git a/indra/llui/llfolderviewmodel.h b/indra/llui/llfolderviewmodel.h
index e62b2779ddbb34c724f71f00dfaedcaa4d9ca024..093e213be35038cb4850d7723a0c1d1112d60851 100644
--- a/indra/llui/llfolderviewmodel.h
+++ b/indra/llui/llfolderviewmodel.h
@@ -108,11 +108,10 @@ class LLFolderViewFilter
 	virtual S32 				getFirstRequiredGeneration() const = 0;
 };
 
-class LLFolderViewModelInterface : public LLTrace::MemTrackable<LLFolderViewModelInterface>
+class LLFolderViewModelInterface
 {
 public:
 	LLFolderViewModelInterface() 
-	:	LLTrace::MemTrackable<LLFolderViewModelInterface>("LLFolderViewModelInterface") 
 	{}
 
 	virtual ~LLFolderViewModelInterface() {}
@@ -133,11 +132,10 @@ class LLFolderViewModelInterface : public LLTrace::MemTrackable<LLFolderViewMode
 
 // This is an abstract base class that users of the folderview classes
 // would use to bridge the folder view with the underlying data
-class LLFolderViewModelItem : public LLRefCount, public LLTrace::MemTrackable<LLFolderViewModelItem>
+class LLFolderViewModelItem : public LLRefCount
 {
 public:
 	LLFolderViewModelItem() 
-	:	LLTrace::MemTrackable<LLFolderViewModelItem>("LLFolderViewModelItem") 
 	{}
 
 	virtual ~LLFolderViewModelItem() { }
diff --git a/indra/llui/lliconctrl.cpp b/indra/llui/lliconctrl.cpp
index 82b01e705dce945f4d7d366b463c4a03daa5b4a5..e01aba402e50ccb7a8f73679cc59fce1ded48094 100644
--- a/indra/llui/lliconctrl.cpp
+++ b/indra/llui/lliconctrl.cpp
@@ -35,6 +35,7 @@
 #include "llui.h"
 #include "lluictrlfactory.h"
 #include "lluiimage.h"
+#include "llwindow.h"
 
 static LLDefaultChildRegistry::Register<LLIconCtrl> r("icon");
 
@@ -42,6 +43,7 @@ LLIconCtrl::Params::Params()
 :	image("image_name"),
 	color("color"),
 	use_draw_context_alpha("use_draw_context_alpha", true),
+    interactable("interactable", false),
 	scale_image("scale_image"),
 	min_width("min_width", 0),
 	min_height("min_height", 0)
@@ -52,6 +54,7 @@ LLIconCtrl::LLIconCtrl(const LLIconCtrl::Params& p)
 	mColor(p.color()),
 	mImagep(p.image),
 	mUseDrawContextAlpha(p.use_draw_context_alpha),
+    mInteractable(p.interactable),
 	mPriority(0),
 	mMinWidth(p.min_width),
 	mMinHeight(p.min_height),
@@ -81,6 +84,16 @@ void LLIconCtrl::draw()
 	LLUICtrl::draw();
 }
 
+BOOL LLIconCtrl::handleHover(S32 x, S32 y, MASK mask)
+{
+    if (mInteractable && getEnabled())
+    {
+        getWindow()->setCursor(UI_CURSOR_HAND);
+        return TRUE;
+    }
+    return LLUICtrl::handleHover(x, y, mask);
+}
+
 // virtual
 // value might be a string or a UUID
 void LLIconCtrl::setValue(const LLSD& value)
diff --git a/indra/llui/lliconctrl.h b/indra/llui/lliconctrl.h
index dd83e78fd33e3cf413c4939fb0665f226357794f..9c3b517bca8d4451f1d7d4ae16345026282ca1fe 100644
--- a/indra/llui/lliconctrl.h
+++ b/indra/llui/lliconctrl.h
@@ -48,7 +48,8 @@ class LLIconCtrl
 	{
 		Optional<LLUIImage*>	image;
 		Optional<LLUIColor>		color;
-		Optional<bool>			use_draw_context_alpha;
+		Optional<bool>			use_draw_context_alpha,
+                                interactable;
 		Optional<S32>			min_width,
 								min_height;
 		Ignored					scale_image;
@@ -67,6 +68,9 @@ class LLIconCtrl
 	// llview overrides
 	virtual void	draw();
 
+    // llview overrides
+    virtual BOOL handleHover(S32 x, S32 y, MASK mask);
+
 	// lluictrl overrides
 	virtual void	setValue(const LLSD& value );
 
@@ -88,6 +92,7 @@ class LLIconCtrl
 	// If set to true (default), use the draw context transparency.
 	// If false, will use transparency returned by getCurrentTransparency(). See STORM-698.
 	bool mUseDrawContextAlpha;
+    bool mInteractable;
 
 private:
 	LLUIColor mColor;
diff --git a/indra/llui/lllayoutstack.cpp b/indra/llui/lllayoutstack.cpp
index 29a156e93300951c62e4f457a8b8dc7d8b26ac6c..77938edf274290caba9553ed744f05edf1d141b6 100644
--- a/indra/llui/lllayoutstack.cpp
+++ b/indra/llui/lllayoutstack.cpp
@@ -340,8 +340,6 @@ void LLLayoutStack::collapsePanel(LLPanel* panel, BOOL collapsed)
 	mNeedsLayout = true;
 }
 
-static LLTrace::BlockTimerStatHandle FTM_UPDATE_LAYOUT("Update LayoutStacks");
-
 class LLImagePanel : public LLPanel
 {
 public:
@@ -369,7 +367,7 @@ class LLImagePanel : public LLPanel
 
 void LLLayoutStack::updateLayout()
 {	
-	LL_RECORD_BLOCK_TIME(FTM_UPDATE_LAYOUT);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
 
 	if (!mNeedsLayout) return;
 
@@ -397,7 +395,6 @@ void LLLayoutStack::updateLayout()
 	space_to_distribute += panelp ? ll_round((F32)mPanelSpacing * panelp->getVisibleAmount()) : 0;
 
 	S32 remaining_space = space_to_distribute;
-	F32 fraction_distributed = 0.f;
 	if (space_to_distribute > 0 && total_visible_fraction > 0.f)
 	{	// give space proportionally to visible auto resize panels
 		BOOST_FOREACH(LLLayoutPanel* panelp, mPanels)
@@ -406,7 +403,6 @@ void LLLayoutStack::updateLayout()
 			{
 				F32 fraction_to_distribute = (panelp->mFractionalSize * panelp->getAutoResizeFactor()) / (total_visible_fraction);
 				S32 delta = ll_round((F32)space_to_distribute * fraction_to_distribute);
-				fraction_distributed += fraction_to_distribute;
 				panelp->mTargetDim += delta;
 				remaining_space -= delta;
 			}
diff --git a/indra/llui/lllineeditor.cpp b/indra/llui/lllineeditor.cpp
index 1badd54fca5df6af7b8ab85b69abb5b9b81884ae..33037b500176e2eddb5bdbe8d8bb6439f586085a 100644
--- a/indra/llui/lllineeditor.cpp
+++ b/indra/llui/lllineeditor.cpp
@@ -175,6 +175,14 @@ LLLineEditor::LLLineEditor(const LLLineEditor::Params& p)
 	mTripleClickTimer.reset();
 	setText(p.default_text());
 
+    if (p.initial_value.isProvided()
+        && !p.control_name.isProvided())
+    {
+        // Initial value often is descriptive, like "Type some ID here"
+        // and can be longer than size limitation, ignore size
+        setText(p.initial_value.getValue().asString(), false);
+    }
+
 	// Initialize current history line iterator
 	mCurrentHistoryLine = mLineHistory.begin();
 
@@ -389,6 +397,11 @@ void LLLineEditor::updateTextPadding()
 
 
 void LLLineEditor::setText(const LLStringExplicit &new_text)
+{
+    setText(new_text, true);
+}
+
+void LLLineEditor::setText(const LLStringExplicit &new_text, bool use_size_limit)
 {
 	// If new text is identical, don't copy and don't move insertion point
 	if (mText.getString() == new_text)
@@ -407,13 +420,13 @@ void LLLineEditor::setText(const LLStringExplicit &new_text)
 	all_selected = all_selected || (len == 0 && hasFocus() && mSelectAllonFocusReceived);
 
 	std::string truncated_utf8 = new_text;
-	if (truncated_utf8.size() > (U32)mMaxLengthBytes)
+	if (use_size_limit && truncated_utf8.size() > (U32)mMaxLengthBytes)
 	{	
 		truncated_utf8 = utf8str_truncate(new_text, mMaxLengthBytes);
 	}
 	mText.assign(truncated_utf8);
 
-	if (mMaxLengthChars)
+	if (use_size_limit && mMaxLengthChars)
 	{
 		mText.assign(utf8str_symbol_truncate(truncated_utf8, mMaxLengthChars));
 	}
diff --git a/indra/llui/lllineeditor.h b/indra/llui/lllineeditor.h
index f84625bea7a680467dbe2cce4e0d2f86499221bf..ae4e05c065f7430e651ab88c60080661c0bfb9bc 100644
--- a/indra/llui/lllineeditor.h
+++ b/indra/llui/lllineeditor.h
@@ -320,6 +320,8 @@ class LLLineEditor
 	virtual S32		getPreeditFontSize() const;
 	virtual LLWString getPreeditString() const { return getWText(); }
 
+    void			setText(const LLStringExplicit &new_text, bool use_size_limit);
+
 	void			setContextMenu(LLContextMenu* new_context_menu);
 
 protected:
diff --git a/indra/llui/llmenubutton.cpp b/indra/llui/llmenubutton.cpp
index 303afcda15154d000fe36a35c92c2463902f9c6c..583704418bc15ab83953d93c23da3dca2cd4d9f4 100644
--- a/indra/llui/llmenubutton.cpp
+++ b/indra/llui/llmenubutton.cpp
@@ -40,6 +40,7 @@ void LLMenuButton::MenuPositions::declareValues()
 	declare("topleft", MP_TOP_LEFT);
 	declare("topright", MP_TOP_RIGHT);
 	declare("bottomleft", MP_BOTTOM_LEFT);
+	declare("bottomright", MP_BOTTOM_RIGHT);
 }
 
 LLMenuButton::Params::Params()
@@ -212,6 +213,13 @@ void LLMenuButton::updateMenuOrigin()
 			mY = rect.mBottom;
 			break;
 		}
+		case MP_BOTTOM_RIGHT:
+		{
+			const LLRect& menu_rect = menu->getRect();
+			mX = rect.mRight - menu_rect.getWidth();
+			mY = rect.mBottom;
+			break;
+		}
 	}
 }
 
diff --git a/indra/llui/llmenubutton.h b/indra/llui/llmenubutton.h
index 67ec1983b3f1e0478a9febf4a5f94a8d79a24406..e42f8f53bd6f80cdf72ca864db22c09c8467ded3 100644
--- a/indra/llui/llmenubutton.h
+++ b/indra/llui/llmenubutton.h
@@ -41,7 +41,8 @@ class LLMenuButton
 	{
 		MP_TOP_LEFT,
 		MP_TOP_RIGHT,
-		MP_BOTTOM_LEFT
+		MP_BOTTOM_LEFT,
+		MP_BOTTOM_RIGHT
 	} EMenuPosition;
 
 	struct MenuPositions
diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp
index cdaf03ebde411a0d48bd896f4368bb36dfa7b65b..4264028338d6d40c3c17feceef38ecf5e016a7aa 100644
--- a/indra/llui/llmenugl.cpp
+++ b/indra/llui/llmenugl.cpp
@@ -1363,6 +1363,9 @@ class LLMenuItemBranchDownGL : public LLMenuItemBranchGL
 	virtual BOOL handleKeyHere(KEY key, MASK mask);
 	
 	virtual BOOL handleAcceleratorKey(KEY key, MASK mask);
+    
+    virtual void onFocusLost();
+    virtual void setFocus(BOOL b);
 };
 
 LLMenuItemBranchDownGL::LLMenuItemBranchDownGL( const Params& p) :
@@ -1517,6 +1520,21 @@ BOOL LLMenuItemBranchDownGL::handleAcceleratorKey(KEY key, MASK mask)
 
 	return handled;
 }
+void LLMenuItemBranchDownGL::onFocusLost()
+{
+    // needed for tab-based selection
+    LLMenuItemBranchGL::onFocusLost();
+    LLMenuGL::setKeyboardMode(FALSE);
+    setHighlight(FALSE);
+}
+
+void LLMenuItemBranchDownGL::setFocus(BOOL b)
+{
+    // needed for tab-based selection
+    LLMenuItemBranchGL::setFocus(b);
+    LLMenuGL::setKeyboardMode(b);
+    setHighlight(b);
+}
 
 BOOL LLMenuItemBranchDownGL::handleKeyHere(KEY key, MASK mask)
 {
@@ -2362,6 +2380,16 @@ void LLMenuGL::arrange( void )
 				(*item_iter)->setRect( rect );
 			}
 		}
+
+
+        if (getTornOff())
+        {
+            LLTearOffMenu * torn_off_menu = dynamic_cast<LLTearOffMenu*>(getParent());
+            if (torn_off_menu)
+            {
+                torn_off_menu->updateSize();
+            }
+        }
 	}
 	if (mKeepFixedSize)
 	{
@@ -3879,7 +3907,8 @@ void LLMenuHolderGL::setActivatedItem(LLMenuItemGL* item)
 /// Class LLTearOffMenu
 ///============================================================================
 LLTearOffMenu::LLTearOffMenu(LLMenuGL* menup) : 
-	LLFloater(LLSD())
+	LLFloater(LLSD()),
+    mQuitRequested(false)
 {
 	S32 floater_header_size = getHeaderHeight();
 
@@ -3894,7 +3923,7 @@ LLTearOffMenu::LLTearOffMenu(LLMenuGL* menup) :
 	LLRect rect;
 	menup->localRectToOtherView(LLRect(-1, menup->getRect().getHeight(), menup->getRect().getWidth() + 3, 0), &rect, gFloaterView);
 	// make sure this floater is big enough for menu
-	mTargetHeight = (F32)(rect.getHeight() + floater_header_size);
+	mTargetHeight = rect.getHeight() + floater_header_size;
 	reshape(rect.getWidth(), rect.getHeight());
 	setRect(rect);
 
@@ -3926,19 +3955,24 @@ LLTearOffMenu::~LLTearOffMenu()
 void LLTearOffMenu::draw()
 {
 	mMenu->setBackgroundVisible(isBackgroundOpaque());
-	mMenu->needsArrange();
 
 	if (getRect().getHeight() != mTargetHeight)
 	{
 		// animate towards target height
-		reshape(getRect().getWidth(), llceil(lerp((F32)getRect().getHeight(), mTargetHeight, LLSmoothInterpolation::getInterpolant(0.05f))));
+        reshape(getRect().getWidth(), llceil(lerp((F32)getRect().getHeight(), (F32)mTargetHeight, LLSmoothInterpolation::getInterpolant(0.05f))));
 	}
+	mMenu->needsArrange();
 	LLFloater::draw();
 }
 
 void LLTearOffMenu::onFocusReceived()
 {
-	// if nothing is highlighted, just highlight first item
+    if (mQuitRequested)
+    {
+        return;
+    }
+ 
+    // if nothing is highlighted, just highlight first item
 	if (!mMenu->getHighlightedItem())
 	{
 		mMenu->highlightNextItem(NULL);
@@ -4014,6 +4048,31 @@ LLTearOffMenu* LLTearOffMenu::create(LLMenuGL* menup)
 	return tearoffp;
 }
 
+void LLTearOffMenu::updateSize()
+{
+    if (mMenu)
+    {
+        S32 floater_header_size = getHeaderHeight();
+        const LLRect &floater_rect = getRect();
+        LLRect new_rect;
+        mMenu->localRectToOtherView(LLRect(-1, mMenu->getRect().getHeight() + floater_header_size, mMenu->getRect().getWidth() + 3, 0), &new_rect, gFloaterView);
+
+        if (floater_rect.getWidth() != new_rect.getWidth()
+            || mTargetHeight != new_rect.getHeight())
+        {
+            // make sure this floater is big enough for menu
+            mTargetHeight = new_rect.getHeight();
+            reshape(new_rect.getWidth(), mTargetHeight);
+
+            // Restore menu position
+            LLRect menu_rect = mMenu->getRect();
+            menu_rect.setOriginAndSize(1, 1,
+                menu_rect.getWidth(), menu_rect.getHeight());
+            mMenu->setRect(menu_rect);
+        }
+    }
+}
+
 void LLTearOffMenu::closeTearOff()
 {
 	removeChild(mMenu);
@@ -4024,6 +4083,7 @@ void LLTearOffMenu::closeTearOff()
 	mMenu->setVisible(FALSE);
 	mMenu->setTornOff(FALSE);
 	mMenu->setDropShadowed(TRUE);
+    mQuitRequested = true;
 }
 
 LLContextMenuBranch::LLContextMenuBranch(const LLContextMenuBranch::Params& p) 
diff --git a/indra/llui/llmenugl.h b/indra/llui/llmenugl.h
index 273bd789c44796b1a76740b2a5c6b002ffb7e0b1..abbfd9a24a36c0597045f3f0b12584a68b6931a5 100644
--- a/indra/llui/llmenugl.h
+++ b/indra/llui/llmenugl.h
@@ -873,6 +873,8 @@ class LLTearOffMenu : public LLFloater
 	virtual BOOL handleKeyHere(KEY key, MASK mask);
 	virtual void translate(S32 x, S32 y);
 
+	void updateSize();
+
 private:
 	LLTearOffMenu(LLMenuGL* menup);
 	
@@ -880,7 +882,8 @@ class LLTearOffMenu : public LLFloater
 	
 	LLView*		mOldParent;
 	LLMenuGL*	mMenu;
-	F32			mTargetHeight;
+	S32			mTargetHeight;
+    bool        mQuitRequested;
 };
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/indra/llui/llmodaldialog.cpp b/indra/llui/llmodaldialog.cpp
index 5cfa8ea9738cbe7ac36678a57fd8edbca6946685..3e5978eb592cc4d67f03432bde3a5d51625b8cc4 100644
--- a/indra/llui/llmodaldialog.cpp
+++ b/indra/llui/llmodaldialog.cpp
@@ -100,7 +100,10 @@ void LLModalDialog::onOpen(const LLSD& key)
 		if (!sModalStack.empty())
 		{
 			LLModalDialog* front = sModalStack.front();
-			front->setVisible(FALSE);
+            if (front != this)
+            {
+                front->setVisible(FALSE);
+            }
 		}
 	
 		// This is a modal dialog.  It sucks up all mouse and keyboard operations.
@@ -108,7 +111,14 @@ void LLModalDialog::onOpen(const LLSD& key)
 		LLUI::getInstance()->addPopup(this);
 		setFocus(TRUE);
 
-		sModalStack.push_front( this );
+        std::list<LLModalDialog*>::iterator iter = std::find(sModalStack.begin(), sModalStack.end(), this);
+        if (iter != sModalStack.end())
+        {
+            // if already present, we want to move it to front.
+            sModalStack.erase(iter);
+        }
+
+        sModalStack.push_front(this);
 	}
 }
 
diff --git a/indra/llui/llnotifications.cpp b/indra/llui/llnotifications.cpp
index a1f0e78bf3763d2b14f29fec452e63f101b9c974..7c381161c92bac5bc7a4f2a617657c1196ac9984 100644
--- a/indra/llui/llnotifications.cpp
+++ b/indra/llui/llnotifications.cpp
@@ -1387,7 +1387,7 @@ bool LLNotifications::failedUniquenessTest(const LLSD& payload)
 
 LLNotificationChannelPtr LLNotifications::getChannel(const std::string& channelName)
 {
-	return LLNotificationChannelPtr(LLNotificationChannel::getInstance(channelName));
+	return LLNotificationChannelPtr(LLNotificationChannel::getInstance(channelName).get());
 }
 
 
diff --git a/indra/llui/llpanel.cpp b/indra/llui/llpanel.cpp
index 00da0f5fec5075786163aecff9bffa7b0066fdbc..f770920c4ab8d4ea5cc0ffbee6034143de80b34c 100644
--- a/indra/llui/llpanel.cpp
+++ b/indra/llui/llpanel.cpp
@@ -800,14 +800,12 @@ boost::signals2::connection LLPanel::setVisibleCallback( const commit_signal_t::
 	return mVisibleSignal->connect(cb);
 }
 
-static LLTrace::BlockTimerStatHandle FTM_BUILD_PANELS("Build Panels");
-
 //-----------------------------------------------------------------------------
 // buildPanel()
 //-----------------------------------------------------------------------------
 BOOL LLPanel::buildFromFile(const std::string& filename, const LLPanel::Params& default_params)
 {
-	LL_RECORD_BLOCK_TIME(FTM_BUILD_PANELS);
+    LL_PROFILE_ZONE_SCOPED;
 	BOOL didPost = FALSE;
 	LLXMLNodePtr root;
 
diff --git a/indra/llui/llprogressbar.cpp b/indra/llui/llprogressbar.cpp
index 209796565c7410cc197cfdcef40e2e632ea4513c..cf57b1fe76e0030277690bfd88228af162f2afda 100644
--- a/indra/llui/llprogressbar.cpp
+++ b/indra/llui/llprogressbar.cpp
@@ -69,16 +69,22 @@ void LLProgressBar::draw()
 	static LLTimer timer;
 	F32 alpha = getDrawContext().mAlpha;
 	
-	LLColor4 image_bar_color = mColorBackground.get();
-	image_bar_color.setAlpha(alpha);
-	mImageBar->draw(getLocalRect(), image_bar_color);
+    if (mImageBar) // optional according to parameters
+    {
+        LLColor4 image_bar_color = mColorBackground.get();
+        image_bar_color.setAlpha(alpha);
+        mImageBar->draw(getLocalRect(), image_bar_color);
+    }
 
-	alpha *= 0.5f + 0.5f*0.5f*(1.f + (F32)sin(3.f*timer.getElapsedTimeF32()));
-	LLColor4 bar_color = mColorBar.get();
-	bar_color.mV[VALPHA] *= alpha; // modulate alpha
-	LLRect progress_rect = getLocalRect();
-	progress_rect.mRight = ll_round(getRect().getWidth() * (mPercentDone / 100.f));
-	mImageFill->draw(progress_rect, bar_color);
+    if (mImageFill)
+    {
+        alpha *= 0.5f + 0.5f*0.5f*(1.f + (F32)sin(3.f*timer.getElapsedTimeF32()));
+        LLColor4 bar_color = mColorBar.get();
+        bar_color.mV[VALPHA] *= alpha; // modulate alpha
+        LLRect progress_rect = getLocalRect();
+        progress_rect.mRight = ll_round(getRect().getWidth() * (mPercentDone / 100.f));
+        mImageFill->draw(progress_rect, bar_color);
+    }
 }
 
 void LLProgressBar::setValue(const LLSD& value)
diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp
index cd87c44dc24f37133e2aa24cf8de2357fdb83ae4..65c7b420ce725871710844a681ee63ebc8e4c19f 100644
--- a/indra/llui/llscrolllistctrl.cpp
+++ b/indra/llui/llscrolllistctrl.cpp
@@ -1388,6 +1388,84 @@ BOOL LLScrollListCtrl::selectItemByPrefix(const LLWString& target, BOOL case_sen
 	return found;
 }
 
+U32 LLScrollListCtrl::searchItems(const std::string& substring, bool case_sensitive, bool focus)
+{
+    return searchItems(utf8str_to_wstring(substring), case_sensitive, focus);
+}
+
+U32 LLScrollListCtrl::searchItems(const LLWString& substring, bool case_sensitive, bool focus)
+{
+    U32 found = 0;
+
+    LLWString substring_trimmed(substring);
+    S32 len = substring_trimmed.size();
+
+    if (0 == len)
+    {
+        // at the moment search for empty element is not supported
+        return 0;
+    }
+    else
+    {
+        deselectAllItems(TRUE);
+        if (!case_sensitive)
+        {
+            // do comparisons in lower case
+            LLWStringUtil::toLower(substring_trimmed);
+        }
+
+        for (item_list::iterator iter = mItemList.begin(); iter != mItemList.end(); iter++)
+        {
+            LLScrollListItem* item = *iter;
+            // Only select enabled items with matching names
+            if (!item->getEnabled())
+            {
+                continue;
+            }
+            LLScrollListCell* cellp = item->getColumn(getSearchColumn());
+            if (!cellp)
+            {
+                continue;
+            }
+            LLWString item_label = utf8str_to_wstring(cellp->getValue().asString());
+            if (!case_sensitive)
+            {
+                LLWStringUtil::toLower(item_label);
+            }
+            // remove extraneous whitespace from searchable label
+            LLWStringUtil::trim(item_label);
+
+            size_t found_iter = item_label.find(substring_trimmed);
+
+            if (found_iter != std::string::npos)
+            {
+                // find offset of matching text
+                cellp->highlightText(found_iter, substring_trimmed.size());
+                selectItem(item, -1, FALSE);
+
+                found++;
+
+                if (!mAllowMultipleSelection)
+                {
+                    break;
+                }
+            }
+        }
+    }
+
+    if (focus && found != 0)
+    {
+        mNeedsScroll = true;
+    }
+
+    if (mCommitOnSelectionChange)
+    {
+        commitIfChanged();
+    }
+
+    return found;
+}
+
 const std::string LLScrollListCtrl::getSelectedItemLabel(S32 column) const
 {
 	LLScrollListItem* item;
@@ -1912,6 +1990,7 @@ BOOL LLScrollListCtrl::handleRightMouseDown(S32 x, S32 y, MASK mask)
 			registrar.add("Url.SendIM", boost::bind(&LLScrollListCtrl::sendIM, id));
 			registrar.add("Url.AddFriend", boost::bind(&LLScrollListCtrl::addFriend, id));
 			registrar.add("Url.RemoveFriend", boost::bind(&LLScrollListCtrl::removeFriend, id));
+            registrar.add("Url.ReportAbuse", boost::bind(&LLScrollListCtrl::reportAbuse, id, is_group));
 			registrar.add("Url.Execute", boost::bind(&LLScrollListCtrl::showNameDetails, id, is_group));
 			registrar.add("Url.CopyLabel", boost::bind(&LLScrollListCtrl::copyNameToClipboard, id, is_group));
 			registrar.add("Url.CopyUrl", boost::bind(&LLScrollListCtrl::copySLURLToClipboard, id, is_group));
@@ -1975,6 +2054,15 @@ void LLScrollListCtrl::removeFriend(std::string id)
 	LLUrlAction::removeFriend(slurl);
 }
 
+void LLScrollListCtrl::reportAbuse(std::string id, bool is_group)
+{
+    if (!is_group)
+    {
+        std::string slurl = "secondlife:///app/agent/" + id + "/about";
+        LLUrlAction::reportAbuse(slurl);
+    }
+}
+
 void LLScrollListCtrl::showNameDetails(std::string id, bool is_group)
 {
 	// open the resident's details or the group details
@@ -3056,10 +3144,9 @@ LLScrollListColumn* LLScrollListCtrl::getColumn(const std::string& name)
 	return NULL;
 }
 
-LLTrace::BlockTimerStatHandle FTM_ADD_SCROLLLIST_ELEMENT("Add Scroll List Item");
 LLScrollListItem* LLScrollListCtrl::addElement(const LLSD& element, EAddPosition pos, void* userdata)
 {
-	LL_RECORD_BLOCK_TIME(FTM_ADD_SCROLLLIST_ELEMENT);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
 	LLScrollListItem::Params item_params;
 	LLParamSDParser parser;
 	parser.readSD(element, item_params);
@@ -3069,14 +3156,14 @@ LLScrollListItem* LLScrollListCtrl::addElement(const LLSD& element, EAddPosition
 
 LLScrollListItem* LLScrollListCtrl::addRow(const LLScrollListItem::Params& item_p, EAddPosition pos)
 {
-	LL_RECORD_BLOCK_TIME(FTM_ADD_SCROLLLIST_ELEMENT);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
 	LLScrollListItem *new_item = new LLScrollListItem(item_p);
 	return addRow(new_item, item_p, pos);
 }
 
 LLScrollListItem* LLScrollListCtrl::addRow(LLScrollListItem *new_item, const LLScrollListItem::Params& item_p, EAddPosition pos)
 {
-	LL_RECORD_BLOCK_TIME(FTM_ADD_SCROLLLIST_ELEMENT);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
 	if (!item_p.validateBlock() || !new_item) return NULL;
 	new_item->setNumColumns(mColumns.size());
 
diff --git a/indra/llui/llscrolllistctrl.h b/indra/llui/llscrolllistctrl.h
index 08134bbfc83afc69538aeb339be8596b2a9d9d7c..77d10fdec7239b2ee3299642cec3f5f3cc176cb4 100644
--- a/indra/llui/llscrolllistctrl.h
+++ b/indra/llui/llscrolllistctrl.h
@@ -267,6 +267,14 @@ class LLScrollListCtrl : public LLUICtrl, public LLEditMenuHandler,
 	const std::string	getSelectedItemLabel(S32 column = 0) const;
 	LLSD			getSelectedValue();
 
+    // If multi select is on, select all element that include substring,
+    // otherwise select first match only.
+    // If focus is true will scroll to selection.
+    // Returns number of results.
+    // Note: at the moment search happens in one go and is expensive
+    U32			searchItems(const std::string& substring, bool case_sensitive = false, bool focus = true);
+    U32			searchItems(const LLWString& substring, bool case_sensitive = false, bool focus = true);
+
 	// DEPRECATED: Use LLSD versions of setCommentText() and getSelectedValue().
 	// "StringUUID" interface: use this when you're creating a list that contains non-unique strings each of which
 	// has an associated, unique UUID, and only one of which can be selected at a time.
@@ -325,6 +333,7 @@ class LLScrollListCtrl : public LLUICtrl, public LLEditMenuHandler,
 	// support right-click context menus for avatar/group lists
 	enum ContextMenuType { MENU_NONE, MENU_AVATAR, MENU_GROUP };
 	void setContextMenu(const ContextMenuType &menu) { mContextMenuType = menu; }
+    ContextMenuType getContextMenuType() { return mContextMenuType; }
 
 	// Overridden from LLView
 	/*virtual*/ void    draw();
@@ -460,6 +469,7 @@ class LLScrollListCtrl : public LLUICtrl, public LLEditMenuHandler,
 	static void		sendIM(std::string id);
 	static void		addFriend(std::string id);
 	static void		removeFriend(std::string id);
+    static void		reportAbuse(std::string id, bool is_group);
 	static void		showNameDetails(std::string id, bool is_group);
 	static void		copyNameToClipboard(std::string id, bool is_group);
 	static void		copySLURLToClipboard(std::string id, bool is_group);
diff --git a/indra/llui/llspinctrl.cpp b/indra/llui/llspinctrl.cpp
index ee78b824295ce7d01ce2ca8b59e165a2d2d6e60e..ef7c8ec0129fc4ba40cddc8a9d778055e81cc0de 100644
--- a/indra/llui/llspinctrl.cpp
+++ b/indra/llui/llspinctrl.cpp
@@ -103,6 +103,7 @@ LLSpinCtrl::LLSpinCtrl(const LLSpinCtrl::Params& p)
 	up_button_params.rect = LLRect(btn_left, getRect().getHeight(), btn_right, getRect().getHeight() - spinctrl_btn_height);
 	up_button_params.click_callback.function(boost::bind(&LLSpinCtrl::onUpBtn, this, _2));
 	up_button_params.mouse_held_callback.function(boost::bind(&LLSpinCtrl::onUpBtn, this, _2));
+    up_button_params.commit_on_capture_lost = true;
 
 	mUpBtn = LLUICtrlFactory::create<LLButton>(up_button_params);
 	addChild(mUpBtn);
@@ -111,6 +112,7 @@ LLSpinCtrl::LLSpinCtrl(const LLSpinCtrl::Params& p)
 	down_button_params.rect = LLRect(btn_left, getRect().getHeight() - spinctrl_btn_height, btn_right, getRect().getHeight() - 2 * spinctrl_btn_height);
 	down_button_params.click_callback.function(boost::bind(&LLSpinCtrl::onDownBtn, this, _2));
 	down_button_params.mouse_held_callback.function(boost::bind(&LLSpinCtrl::onDownBtn, this, _2));
+    down_button_params.commit_on_capture_lost = true;
 	mDownBtn = LLUICtrlFactory::create<LLButton>(down_button_params);
 	addChild(mDownBtn);
 
diff --git a/indra/llui/llstatbar.cpp b/indra/llui/llstatbar.cpp
index 6c8e63442badf14ca6498a37bad9057d2ddaadcd..244910095205b9f6092d71e1ce313302206ebd4a 100644
--- a/indra/llui/llstatbar.cpp
+++ b/indra/llui/llstatbar.cpp
@@ -160,6 +160,7 @@ LLStatBar::Params::Params()
 	tick_spacing("tick_spacing", 0.f),
 	decimal_digits("decimal_digits", 3),
 	show_bar("show_bar", false),
+	show_median("show_median", false),
 	show_history("show_history", false),
 	scale_range("scale_range", true),
 	num_frames("num_frames", 200),
@@ -186,6 +187,7 @@ LLStatBar::LLStatBar(const Params& p)
 	mNumShortHistoryFrames(p.num_frames_short),
 	mMaxHeight(p.max_height),
 	mDisplayBar(p.show_bar),
+	mShowMedian(p.show_median),
 	mDisplayHistory(p.show_history),
 	mOrientation(p.orientation),
 	mAutoScaleMax(!p.bar_max.isProvided()),
@@ -318,7 +320,14 @@ void LLStatBar::draw()
 			min           = frame_recording.getPeriodMinPerSec(count_stat, num_frames);
 			max           = frame_recording.getPeriodMaxPerSec(count_stat, num_frames);
 			mean          = frame_recording.getPeriodMeanPerSec(count_stat, num_frames);
-			display_value = mean;
+			if (mShowMedian)
+			{
+				display_value = frame_recording.getPeriodMedianPerSec(count_stat, num_frames);
+			}
+			else
+			{
+				display_value = mean;
+			}
 		}
 		break;
 	case STAT_EVENT:
@@ -344,7 +353,11 @@ void LLStatBar::draw()
 			mean              = frame_recording.getPeriodMean(sample_stat, num_frames);
 			num_rapid_changes = calc_num_rapid_changes(frame_recording, sample_stat, RAPID_CHANGE_WINDOW);
 
-			if (num_rapid_changes / RAPID_CHANGE_WINDOW.value() > MAX_RAPID_CHANGES_PER_SEC)
+			if (mShowMedian)
+			{
+				display_value = frame_recording.getPeriodMedian(sample_stat, num_frames);
+			}
+			else if (num_rapid_changes / RAPID_CHANGE_WINDOW.value() > MAX_RAPID_CHANGES_PER_SEC)
 			{
 				display_value = mean;
 			}
@@ -554,29 +567,25 @@ void LLStatBar::draw()
 void LLStatBar::setStat(const std::string& stat_name)
 {
 	using namespace LLTrace;
-	const StatType<CountAccumulator>*	count_stat;
-	const StatType<EventAccumulator>*	event_stat;
-	const StatType<SampleAccumulator>*	sample_stat;
-	const StatType<MemAccumulator>*		mem_stat;
 
-	if ((count_stat = StatType<CountAccumulator>::getInstance(stat_name)))
+	if (auto count_stat = StatType<CountAccumulator>::getInstance(stat_name))
 	{
-		mStat.countStatp = count_stat;
+		mStat.countStatp = count_stat.get();
 		mStatType = STAT_COUNT;
 	}
-	else if ((event_stat = StatType<EventAccumulator>::getInstance(stat_name)))
+	else if (auto event_stat = StatType<EventAccumulator>::getInstance(stat_name))
 	{
-		mStat.eventStatp = event_stat;
+		mStat.eventStatp = event_stat.get();
 		mStatType = STAT_EVENT;
 	}
-	else if ((sample_stat = StatType<SampleAccumulator>::getInstance(stat_name)))
+	else if (auto sample_stat = StatType<SampleAccumulator>::getInstance(stat_name))
 	{
-		mStat.sampleStatp = sample_stat;
+		mStat.sampleStatp = sample_stat.get();
 		mStatType = STAT_SAMPLE;
 	}
-	else if ((mem_stat = StatType<MemAccumulator>::getInstance(stat_name)))
+	else if (auto mem_stat = StatType<MemAccumulator>::getInstance(stat_name))
 	{
-		mStat.memStatp = mem_stat;
+		mStat.memStatp = mem_stat.get();
 		mStatType = STAT_MEM;
 	}
 }
diff --git a/indra/llui/llstatbar.h b/indra/llui/llstatbar.h
index 1ff4c67fc5100b82a157b7e4b5e50e00d9753fb8..6b481ca68f78d2d1b1e8bd8de0dc95b7de35acff 100644
--- a/indra/llui/llstatbar.h
+++ b/indra/llui/llstatbar.h
@@ -44,9 +44,10 @@ class LLStatBar : public LLView
 								bar_max,
 								tick_spacing;
 
-		Optional<bool>			show_bar,
+		Optional<bool> 			show_bar,
 								show_history,
-								scale_range;
+								scale_range,
+								show_median; // default is mean
 
 		Optional<S32>			decimal_digits,
 								num_frames,
@@ -112,6 +113,7 @@ class LLStatBar : public LLView
 
 	bool         mDisplayBar,			// Display the bar graph.
 				 mDisplayHistory,
+				 mShowMedian,
 				 mAutoScaleMax,
 				 mAutoScaleMin;
 };
diff --git a/indra/llui/lltabcontainer.cpp b/indra/llui/lltabcontainer.cpp
index 459fdcf2aec61d0dd82630fc3159708641761641..0aa7a2d2178fef7d56f48a74e36fc6ec364f7980 100644
--- a/indra/llui/lltabcontainer.cpp
+++ b/indra/llui/lltabcontainer.cpp
@@ -402,9 +402,13 @@ void LLTabContainer::draw()
 	S32 cur_scroll_pos = getScrollPos();
 	if (cur_scroll_pos > 0)
 	{
-		S32 available_width_with_arrows = getRect().getWidth() - mRightTabBtnOffset - 2 * (LLPANEL_BORDER_WIDTH + tabcntr_arrow_btn_size  + tabcntr_arrow_btn_size + 1);
-		if (!mIsVertical)
+		if (mIsVertical)
 		{
+			target_pixel_scroll = cur_scroll_pos * (BTN_HEIGHT + tabcntrv_pad);
+		}
+		else
+		{
+			S32 available_width_with_arrows = getRect().getWidth() - mRightTabBtnOffset - 2 * (LLPANEL_BORDER_WIDTH + tabcntr_arrow_btn_size  + tabcntr_arrow_btn_size + 1);
 			for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter)
 			{
 				if (cur_scroll_pos == 0)
@@ -1189,13 +1193,15 @@ void LLTabContainer::addTabPanel(const TabPanelParams& panel)
 	sendChildToFront(mNextArrowBtn);
 	sendChildToFront(mJumpPrevArrowBtn);
 	sendChildToFront(mJumpNextArrowBtn);
-	
+
+	updateMaxScrollPos();
+
 	if( select )
 	{
 		selectLastTab();
+		mScrollPos = mMaxScrollPos;
 	}
 
-	updateMaxScrollPos();
 }
 
 void LLTabContainer::addPlaceholder(LLPanel* child, const std::string& label)
@@ -2079,9 +2085,9 @@ void LLTabContainer::updateMaxScrollPos()
 		if( tab_total_height > available_height )
 		{
 			static LLUICachedControl<S32> tabcntrv_arrow_btn_size ("UITabCntrvArrowBtnSize", 0);
-			S32 available_height_with_arrows = getRect().getHeight() - 2*(tabcntrv_arrow_btn_size + 3*tabcntrv_pad);
+			S32 available_height_with_arrows = getRect().getHeight() - 2*(tabcntrv_arrow_btn_size + 3*tabcntrv_pad) - mNextArrowBtn->getRect().mBottom;
 			S32 additional_needed = tab_total_height - available_height_with_arrows;
-			setMaxScrollPos((S32) ceil(additional_needed / float(BTN_HEIGHT) ) );
+			setMaxScrollPos((S32) ceil(additional_needed / float(BTN_HEIGHT + tabcntrv_pad) ) );
 			no_scroll = FALSE;
 		}
 	}
diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp
index 0532750dce801e6659d1cf29311b8103970ef4e5..7e4aaa53bff730fa595b1a6f49ec3e93e61b2532 100644
--- a/indra/llui/lltextbase.cpp
+++ b/indra/llui/lltextbase.cpp
@@ -163,6 +163,7 @@ LLTextBase::Params::Params()
 	font_shadow("font_shadow"),
 	wrap("wrap"),
 	trusted_content("trusted_content", true),
+	always_show_icons("always_show_icons", false),
 	use_ellipses("use_ellipses", false),
 	parse_urls("parse_urls", false),
 	force_urls_external("force_urls_external", false),
@@ -212,6 +213,7 @@ LLTextBase::LLTextBase(const LLTextBase::Params &p)
 	mClip(p.clip),
 	mClipPartial(p.clip_partial && !p.allow_scroll),
 	mTrustedContent(p.trusted_content),
+	mAlwaysShowIcons(p.always_show_icons),
 	mTrackEnd( p.track_end ),
 	mScrollIndex(-1),
 	mSelectionStart( 0 ),
@@ -448,8 +450,48 @@ void LLTextBase::drawSelectionBackground()
 			++rect_it)
 		{
 			LLRect selection_rect = *rect_it;
-			selection_rect = *rect_it;
-			selection_rect.translate(mVisibleTextRect.mLeft - content_display_rect.mLeft, mVisibleTextRect.mBottom - content_display_rect.mBottom);
+            if (mScroller)
+            {
+                // If scroller is On content_display_rect has correct rect and safe to use as is
+                // Note: we might need to account for border
+                selection_rect.translate(mVisibleTextRect.mLeft - content_display_rect.mLeft, mVisibleTextRect.mBottom - content_display_rect.mBottom);
+            }
+            else
+            {
+                // If scroller is Off content_display_rect will have rect from document, adjusted to text width, heigh and position
+                // and we have to acount for offset depending on position
+                S32 v_delta = 0;
+                S32 h_delta = 0;
+                switch (mVAlign)
+                {
+                case LLFontGL::TOP:
+                    v_delta = mVisibleTextRect.mTop - content_display_rect.mTop - mVPad;
+                    break;
+                case LLFontGL::VCENTER:
+                    v_delta = (llmax(mVisibleTextRect.getHeight() - content_display_rect.mTop, -content_display_rect.mBottom) + (mVisibleTextRect.mBottom - content_display_rect.mBottom)) / 2;
+                    break;
+                case LLFontGL::BOTTOM:
+                    v_delta = mVisibleTextRect.mBottom - content_display_rect.mBottom;
+                    break;
+                default:
+                    break;
+                }
+                switch (mHAlign)
+                {
+                case LLFontGL::LEFT:
+                    h_delta = mVisibleTextRect.mLeft - content_display_rect.mLeft + mHPad;
+                    break;
+                case LLFontGL::HCENTER:
+                    h_delta = (llmax(mVisibleTextRect.getWidth() - content_display_rect.mLeft, -content_display_rect.mRight) + (mVisibleTextRect.mRight - content_display_rect.mRight)) / 2;
+                    break;
+                case LLFontGL::RIGHT:
+                    h_delta = mVisibleTextRect.mRight - content_display_rect.mRight;
+                    break;
+                default:
+                    break;
+                }
+                selection_rect.translate(h_delta, v_delta);
+            }
 			gl_rect_2d(selection_rect, selection_color);
 		}
 	}
@@ -1490,11 +1532,9 @@ S32 LLTextBase::getLeftOffset(S32 width)
 	}
 }
 
-
-static LLTrace::BlockTimerStatHandle FTM_TEXT_REFLOW ("Text Reflow");
 void LLTextBase::reflow()
 {
-	LL_RECORD_BLOCK_TIME(FTM_TEXT_REFLOW);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
 
 	updateSegments();
 
@@ -1842,10 +1882,9 @@ void LLTextBase::removeDocumentChild(LLView* view)
 }
 
 
-static LLTrace::BlockTimerStatHandle FTM_UPDATE_TEXT_SEGMENTS("Update Text Segments");
 void LLTextBase::updateSegments()
 {
-	LL_RECORD_BLOCK_TIME(FTM_UPDATE_TEXT_SEGMENTS);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
 	createDefaultSegment();
 }
 
@@ -2010,6 +2049,7 @@ void LLTextBase::createUrlContextMenu(S32 x, S32 y, const std::string &in_url)
 	registrar.add("Url.ShowProfile", boost::bind(&LLUrlAction::showProfile, url));
 	registrar.add("Url.AddFriend", boost::bind(&LLUrlAction::addFriend, url));
 	registrar.add("Url.RemoveFriend", boost::bind(&LLUrlAction::removeFriend, url));
+    registrar.add("Url.ReportAbuse", boost::bind(&LLUrlAction::reportAbuse, url));
 	registrar.add("Url.SendIM", boost::bind(&LLUrlAction::sendIM, url));
 	registrar.add("Url.ShowOnMap", boost::bind(&LLUrlAction::showLocationOnMap, url));
 	registrar.add("Url.CopyLabel", boost::bind(&LLUrlAction::copyLabelToClipboard, url));
@@ -2105,24 +2145,21 @@ static LLUIImagePtr image_from_icon_name(const std::string& icon_name)
 	}
 }
 
-static LLTrace::BlockTimerStatHandle FTM_PARSE_HTML("Parse HTML");
-
-
 
 void LLTextBase::appendTextImpl(const std::string &new_text, const LLStyle::Params& input_params)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
 	LLStyle::Params style_params(input_params);
 	style_params.fillFrom(getStyleParams());
 
 	S32 part = (S32)LLTextParser::WHOLE;
 	if (mParseHTML && !style_params.is_link) // Don't search for URLs inside a link segment (STORM-358).
 	{
-		LL_RECORD_BLOCK_TIME(FTM_PARSE_HTML);
 		S32 start=0,end=0;
 		LLUrlMatch match;
 		std::string text = new_text;
 		while ( LLUrlRegistry::instance().findUrl(text, match,
-				boost::bind(&LLTextBase::replaceUrl, this, _1, _2, _3),isContentTrusted()))
+				boost::bind(&LLTextBase::replaceUrl, this, _1, _2, _3),isContentTrusted() || mAlwaysShowIcons))
 		{
 			start = match.getStart();
 			end = match.getEnd()+1;
@@ -2147,7 +2184,7 @@ void LLTextBase::appendTextImpl(const std::string &new_text, const LLStyle::Para
 			}
 
 			// add icon before url if need
-			LLTextUtil::processUrlMatch(&match, this, isContentTrusted() || match.isTrusted());
+			LLTextUtil::processUrlMatch(&match, this, isContentTrusted() || match.isTrusted() || mAlwaysShowIcons);
 			if ((isContentTrusted() || match.isTrusted()) && !match.getIcon().empty() )
 			{
 				setLastSegmentToolTip(LLTrans::getString("TooltipSLIcon"));
@@ -2211,11 +2248,9 @@ void LLTextBase::setLastSegmentToolTip(const std::string &tooltip)
 	}
 }
 
-static LLTrace::BlockTimerStatHandle FTM_APPEND_TEXT("Append Text");
-
 void LLTextBase::appendText(const std::string &new_text, bool prepend_newline, const LLStyle::Params& input_params)
 {
-	LL_RECORD_BLOCK_TIME(FTM_APPEND_TEXT);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
 	if (new_text.empty()) 
 		return;
 
diff --git a/indra/llui/lltextbase.h b/indra/llui/lltextbase.h
index 2e2e1b9833b3d5b8abcc123446e1b0b675bfd35c..25f8fa1c2bb7c770dfbeaf31778ce381df35f8bb 100644
--- a/indra/llui/lltextbase.h
+++ b/indra/llui/lltextbase.h
@@ -321,7 +321,8 @@ class LLTextBase
 								parse_highlights,
 								clip,
 								clip_partial,
-								trusted_content;
+								trusted_content,
+								always_show_icons;
 								
 		Optional<S32>			v_pad,
 								h_pad;
@@ -369,6 +370,8 @@ class LLTextBase
 	virtual void	onFocusReceived();
 	virtual void	onFocusLost();
 
+    void        setParseHTML(bool parse_html) { mParseHTML = parse_html; }
+
 	// LLSpellCheckMenuHandler overrides
 	/*virtual*/ bool		getSpellCheck() const;
 
@@ -457,6 +460,8 @@ class LLTextBase
 	void					setSkipLinkUnderline(bool skip_link_underline) { mSkipLinkUnderline = skip_link_underline; }
 	bool					getSkipLinkUnderline() { return mSkipLinkUnderline;  }
 
+    void					setParseURLs(bool parse_urls) { mParseHTML = parse_urls; }
+
 	void					setPlainText(bool value) { mPlainText = value;}
 	bool					getPlainText() const { return mPlainText; }
 
@@ -700,6 +705,8 @@ class LLTextBase
 	bool						mAutoIndent;
 	S32							mMaxTextByteLength;	// Maximum length mText is allowed to be in bytes
 	bool						mSkipTripleClick;
+	bool						mAlwaysShowIcons;
+
 	bool						mSkipLinkUnderline;
 
 	// support widgets
diff --git a/indra/llui/lltexteditor.h b/indra/llui/lltexteditor.h
index 26702b2412b8fdf4b2d81b01bb40f2f618b9b814..1a10d2fd1ee206167f843651b4c3e657a5206451 100644
--- a/indra/llui/lltexteditor.h
+++ b/indra/llui/lltexteditor.h
@@ -196,6 +196,7 @@ class LLTextEditor :
 	const LLUUID&	getSourceID() const						{ return mSourceID; }
 
 	const LLTextSegmentPtr	getPreviousSegment() const;
+    const LLTextSegmentPtr	getLastSegment() const;
 	void			getSelectedSegments(segment_vec_t& segments) const;
 
 	void			setShowContextMenu(bool show) { mShowContextMenu = show; }
diff --git a/indra/llui/lltextutil.cpp b/indra/llui/lltextutil.cpp
index 538508b856d98dcd29c7b8288d83f9935a117665..78049319bc2df252e96db2ac5ac7538100a28edf 100644
--- a/indra/llui/lltextutil.cpp
+++ b/indra/llui/lltextutil.cpp
@@ -76,22 +76,6 @@ void LLTextUtil::textboxSetGreyedVal(LLTextBox *txtbox, const LLStyle::Params& n
     txtbox->appendText(text.substr(greyed_begin + greyed_len),  false, normal_style);
 }
 
-const std::string& LLTextUtil::formatPhoneNumber(const std::string& phone_str)
-{
-	static const std::string PHONE_SEPARATOR = LLUI::getInstance()->mSettingGroups["config"]->getString("AvalinePhoneSeparator");
-	static const S32 PHONE_PART_LEN = 2;
-
-	static std::string formatted_phone_str;
-	formatted_phone_str = phone_str;
-	S32 separator_pos = (S32)(formatted_phone_str.size()) - PHONE_PART_LEN;
-	for (; separator_pos >= PHONE_PART_LEN; separator_pos -= PHONE_PART_LEN)
-	{
-		formatted_phone_str.insert(separator_pos, PHONE_SEPARATOR);
-	}
-
-	return formatted_phone_str;
-}
-
 bool LLTextUtil::processUrlMatch(LLUrlMatch* match,LLTextBase* text_base, bool is_content_trusted)
 {
 	if (match == 0 || text_base == 0)
diff --git a/indra/llui/lltextutil.h b/indra/llui/lltextutil.h
index a9c143e4450d51d979fe2863994a399911c387c5..1adc3516f7685a45021fc5bebed9abf8600d45f3 100644
--- a/indra/llui/lltextutil.h
+++ b/indra/llui/lltextutil.h
@@ -58,18 +58,6 @@ namespace LLTextUtil
 	        const std::string& text,
 	        const std::string& greyed);
 
-	/**
-	 * Formats passed phone number to be more human readable.
-	 *
-	 * It just divides the number on parts by two digits from right to left. The first left part
-	 * can have 2 or 3 digits, i.e. +44-33-33-44-55-66 or 12-34-56-78-90. Separator is set in
-	 * application settings (AvalinePhoneSeparator)
-	 *
-	 * @param[in] phone_str string with original phone number
-	 * @return reference to string with formatted phone number
-	 */
-	const std::string& formatPhoneNumber(const std::string& phone_str);
-
 	/**
 	 * Adds icon before url if need.
 	 *
diff --git a/indra/llui/lltrans.cpp b/indra/llui/lltrans.cpp
index a1a8feedaa937608dcb95bf3448f4cf98c320735..a1ef34159d9adc0b1195892c8cb86db3bc589f67 100644
--- a/indra/llui/lltrans.cpp
+++ b/indra/llui/lltrans.cpp
@@ -147,7 +147,7 @@ std::string LLTrans::getString(const std::string &xml_desc, const LLStringUtil::
 {
 	// Don't care about time as much as call count.  Make sure we're not
 	// calling LLTrans::getString() in an inner loop. JC
-	LL_RECORD_BLOCK_TIME(FTM_GET_TRANS);
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
 	
 	if (def_string)
 	{
@@ -196,7 +196,7 @@ std::string LLTrans::getString(const std::string &xml_desc, const LLSD& msg_args
 {
 	// Don't care about time as much as call count.  Make sure we're not
 	// calling LLTrans::getString() in an inner loop. JC
-	LL_RECORD_BLOCK_TIME(FTM_GET_TRANS);
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
 
 	if (def_string)
 	{
@@ -237,7 +237,7 @@ std::string LLTrans::getDefString(const std::string &xml_desc, const LLSD& msg_a
 //static 
 bool LLTrans::findString(std::string &result, const std::string &xml_desc, const LLStringUtil::format_map_t& msg_args)
 {
-	LL_RECORD_BLOCK_TIME(FTM_GET_TRANS);
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
 	
 	template_map_t::iterator iter = sStringTemplates.find(xml_desc);
 	if (iter != sStringTemplates.end())
@@ -259,7 +259,7 @@ bool LLTrans::findString(std::string &result, const std::string &xml_desc, const
 //static
 bool LLTrans::findString(std::string &result, const std::string &xml_desc, const LLSD& msg_args)
 {
-	LL_RECORD_BLOCK_TIME(FTM_GET_TRANS);
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
 
 	template_map_t::iterator iter = sStringTemplates.find(xml_desc);
 	if (iter != sStringTemplates.end())
diff --git a/indra/llui/lluictrl.cpp b/indra/llui/lluictrl.cpp
index 5924542a19e34f00fca1dcf90e7f29736f3fe873..2196ba201bbf0f9be79e9e6118e7e3e4e038e120 100644
--- a/indra/llui/lluictrl.cpp
+++ b/indra/llui/lluictrl.cpp
@@ -121,7 +121,6 @@ LLUICtrl::LLUICtrl(const LLUICtrl::Params& p, const LLViewModelPtr& viewmodel)
 	mDoubleClickSignal(NULL),
 	mTransparencyType(TT_DEFAULT)
 {
-	claimMem(viewmodel.get());
 }
 
 void LLUICtrl::initFromParams(const Params& p)
@@ -476,6 +475,7 @@ LLViewModel* LLUICtrl::getViewModel() const
 //virtual
 BOOL LLUICtrl::postBuild()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
 	//
 	// Find all of the children that want to be in front and move them to the front
 	//
@@ -781,12 +781,9 @@ BOOL LLUICtrl::getIsChrome() const
 }
 
 
-
-LLTrace::BlockTimerStatHandle FTM_FOCUS_FIRST_ITEM("Focus First Item");
-
 BOOL LLUICtrl::focusFirstItem(BOOL prefer_text_fields, BOOL focus_flash)
 {
-	LL_RECORD_BLOCK_TIME(FTM_FOCUS_FIRST_ITEM);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
 	// try to select default tab group child
 	LLViewQuery query = getTabOrderQuery();
 	child_list_t result = query(this);
@@ -1005,7 +1002,6 @@ boost::signals2::connection LLUICtrl::setCommitCallback( boost::function<void (L
 boost::signals2::connection LLUICtrl::setValidateBeforeCommit( boost::function<bool (const LLSD& data)> cb )
 {
 	if (!mValidateSignal) mValidateSignal = new enable_signal_t();
-	claimMem(mValidateSignal);
 
 	return mValidateSignal->connect(boost::bind(cb, _2));
 }
@@ -1070,7 +1066,6 @@ boost::signals2::connection LLUICtrl::setValidateCallback(const EnableCallbackPa
 boost::signals2::connection LLUICtrl::setCommitCallback( const commit_signal_t::slot_type& cb ) 
 { 
 	if (!mCommitSignal) mCommitSignal = new commit_signal_t();
-	claimMem(mCommitSignal);
 
 	return mCommitSignal->connect(cb); 
 }
@@ -1078,7 +1073,6 @@ boost::signals2::connection LLUICtrl::setCommitCallback( const commit_signal_t::
 boost::signals2::connection LLUICtrl::setValidateCallback( const enable_signal_t::slot_type& cb ) 
 { 
 	if (!mValidateSignal) mValidateSignal = new enable_signal_t();
-	claimMem(mValidateSignal);
 
 	return mValidateSignal->connect(cb); 
 }
@@ -1086,7 +1080,6 @@ boost::signals2::connection LLUICtrl::setValidateCallback( const enable_signal_t
 boost::signals2::connection LLUICtrl::setMouseEnterCallback( const commit_signal_t::slot_type& cb ) 
 { 
 	if (!mMouseEnterSignal) mMouseEnterSignal = new commit_signal_t();
-	claimMem(mMouseEnterSignal);
 
 	return mMouseEnterSignal->connect(cb); 
 }
@@ -1094,7 +1087,6 @@ boost::signals2::connection LLUICtrl::setMouseEnterCallback( const commit_signal
 boost::signals2::connection LLUICtrl::setMouseLeaveCallback( const commit_signal_t::slot_type& cb ) 
 { 
 	if (!mMouseLeaveSignal) mMouseLeaveSignal = new commit_signal_t();
-	claimMem(mMouseLeaveSignal);
 
 	return mMouseLeaveSignal->connect(cb); 
 }
@@ -1102,7 +1094,6 @@ boost::signals2::connection LLUICtrl::setMouseLeaveCallback( const commit_signal
 boost::signals2::connection LLUICtrl::setMouseDownCallback( const mouse_signal_t::slot_type& cb ) 
 { 
 	if (!mMouseDownSignal) mMouseDownSignal = new mouse_signal_t();
-	claimMem(mMouseDownSignal);
 
 	return mMouseDownSignal->connect(cb); 
 }
@@ -1110,7 +1101,6 @@ boost::signals2::connection LLUICtrl::setMouseDownCallback( const mouse_signal_t
 boost::signals2::connection LLUICtrl::setMouseUpCallback( const mouse_signal_t::slot_type& cb ) 
 { 
 	if (!mMouseUpSignal) mMouseUpSignal = new mouse_signal_t();
-	claimMem(mMouseUpSignal);
 
 	return mMouseUpSignal->connect(cb); 
 }
@@ -1118,7 +1108,6 @@ boost::signals2::connection LLUICtrl::setMouseUpCallback( const mouse_signal_t::
 boost::signals2::connection LLUICtrl::setRightMouseDownCallback( const mouse_signal_t::slot_type& cb ) 
 { 
 	if (!mRightMouseDownSignal) mRightMouseDownSignal = new mouse_signal_t();
-	claimMem(mRightMouseDownSignal);
 
 	return mRightMouseDownSignal->connect(cb); 
 }
@@ -1126,7 +1115,6 @@ boost::signals2::connection LLUICtrl::setRightMouseDownCallback( const mouse_sig
 boost::signals2::connection LLUICtrl::setRightMouseUpCallback( const mouse_signal_t::slot_type& cb ) 
 { 
 	if (!mRightMouseUpSignal) mRightMouseUpSignal = new mouse_signal_t();
-	claimMem(mRightMouseUpSignal);
 
 	return mRightMouseUpSignal->connect(cb); 
 }
@@ -1134,7 +1122,6 @@ boost::signals2::connection LLUICtrl::setRightMouseUpCallback( const mouse_signa
 boost::signals2::connection LLUICtrl::setDoubleClickCallback( const mouse_signal_t::slot_type& cb ) 
 { 
 	if (!mDoubleClickSignal) mDoubleClickSignal = new mouse_signal_t();
-	claimMem(mDoubleClickSignal);
 
 	return mDoubleClickSignal->connect(cb); 
 }
diff --git a/indra/llui/lluictrlfactory.cpp b/indra/llui/lluictrlfactory.cpp
index fdefae01b172e72627c08c2e8d64bdfed7ff10b6..a85db17c7ff02d77b8fc311610e6e2276e1eda6d 100644
--- a/indra/llui/lluictrlfactory.cpp
+++ b/indra/llui/lluictrlfactory.cpp
@@ -44,10 +44,6 @@
 // this library includes
 #include "llpanel.h"
 
-LLTrace::BlockTimerStatHandle FTM_WIDGET_CONSTRUCTION("Widget Construction");
-LLTrace::BlockTimerStatHandle FTM_INIT_FROM_PARAMS("Widget InitFromParams");
-LLTrace::BlockTimerStatHandle FTM_WIDGET_SETUP("Widget Setup");
-
 //-----------------------------------------------------------------------------
 
 // UI Ctrl class for padding
@@ -117,12 +113,10 @@ void LLUICtrlFactory::loadWidgetTemplate(const std::string& widget_tag, LLInitPa
 	}
 }
 
-static LLTrace::BlockTimerStatHandle FTM_CREATE_CHILDREN("Create XUI Children");
-
 //static 
 void LLUICtrlFactory::createChildren(LLView* viewp, LLXMLNodePtr node, const widget_registry_t& registry, LLXMLNodePtr output_node)
 {
-	LL_RECORD_BLOCK_TIME(FTM_CREATE_CHILDREN);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
 	if (node.isNull()) return;
 
 	for (LLXMLNodePtr child_node = node->getFirstChild(); child_node.notNull(); child_node = child_node->getNextSibling())
@@ -159,14 +153,13 @@ void LLUICtrlFactory::createChildren(LLView* viewp, LLXMLNodePtr node, const wid
 
 }
 
-static LLTrace::BlockTimerStatHandle FTM_XML_PARSE("XML Reading/Parsing");
 //-----------------------------------------------------------------------------
 // getLayeredXMLNode()
 //-----------------------------------------------------------------------------
 bool LLUICtrlFactory::getLayeredXMLNode(const std::string &xui_filename, LLXMLNodePtr& root,
                                         LLDir::ESkinConstraint constraint)
 {
-	LL_RECORD_BLOCK_TIME(FTM_XML_PARSE);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
 	std::vector<std::string> paths =
 		gDirUtilp->findSkinnedFilenames(LLDir::XUI, xui_filename, constraint);
 
@@ -191,11 +184,9 @@ S32 LLUICtrlFactory::saveToXML(LLView* viewp, const std::string& filename)
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
 
-static LLTrace::BlockTimerStatHandle FTM_CREATE_FROM_XML("Create child widget");
-
 LLView *LLUICtrlFactory::createFromXML(LLXMLNodePtr node, LLView* parent, const std::string& filename, const widget_registry_t& registry, LLXMLNodePtr output_node)
 {
-	LL_RECORD_BLOCK_TIME(FTM_CREATE_FROM_XML);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
 	std::string ctrl_type = node->getName()->mString;
 	LLStringUtil::toLower(ctrl_type);
 
diff --git a/indra/llui/lluictrlfactory.h b/indra/llui/lluictrlfactory.h
index 135ed57a4fba36249863421e70f464bdd38789b3..6e585abfc03a267e231857120230729a6494dafe 100644
--- a/indra/llui/lluictrlfactory.h
+++ b/indra/llui/lluictrlfactory.h
@@ -79,10 +79,6 @@ class LLWidgetNameRegistry
 //	LLSINGLETON(LLDefaultParamBlockRegistry);
 //};
 
-extern LLTrace::BlockTimerStatHandle FTM_WIDGET_SETUP;
-extern LLTrace::BlockTimerStatHandle FTM_WIDGET_CONSTRUCTION;
-extern LLTrace::BlockTimerStatHandle FTM_INIT_FROM_PARAMS;
-
 // Build time optimization, generate this once in .cpp file
 #ifndef LLUICTRLFACTORY_CPP
 extern template class LLUICtrlFactory* LLSingleton<class LLUICtrlFactory>::getInstance();
@@ -213,6 +209,7 @@ class LLUICtrlFactory : public LLSingleton<LLUICtrlFactory>
 	template<typename T>
 	static T* createWidgetImpl(const typename T::Params& params, LLView* parent = NULL)
 	{
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
 		T* widget = NULL;
 
 		if (!params.validateBlock())
@@ -221,12 +218,9 @@ class LLUICtrlFactory : public LLSingleton<LLUICtrlFactory>
 			//return NULL;
 		}
 
-		{ LL_RECORD_BLOCK_TIME(FTM_WIDGET_CONSTRUCTION);
-			widget = new T(params);	
-		}
-		{ LL_RECORD_BLOCK_TIME(FTM_INIT_FROM_PARAMS);
-			widget->initFromParams(params);
-		}
+		widget = new T(params);	
+		
+		widget->initFromParams(params);
 
 		if (parent)
 		{
@@ -239,7 +233,7 @@ class LLUICtrlFactory : public LLSingleton<LLUICtrlFactory>
 	template<typename T>
 	static T* defaultBuilder(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr output_node)
 	{
-		LL_RECORD_BLOCK_TIME(FTM_WIDGET_SETUP);
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
 
 		typename T::Params params(getDefaultParams<T>());
 
diff --git a/indra/llui/llurlaction.cpp b/indra/llui/llurlaction.cpp
index 84ea770a8d80457ccd0c6fcc7dd7516a77869d18..8216046174668d162ca1b415e26cd29a3fa19e96 100644
--- a/indra/llui/llurlaction.cpp
+++ b/indra/llui/llurlaction.cpp
@@ -222,6 +222,15 @@ void LLUrlAction::removeFriend(std::string url)
 	}
 }
 
+void LLUrlAction::reportAbuse(std::string url)
+{
+    std::string id_str = getUserID(url);
+    if (LLUUID::validate(id_str))
+    {
+        executeSLURL("secondlife:///app/agent/" + id_str + "/reportAbuse");
+    }
+}
+
 void LLUrlAction::blockObject(std::string url)
 {
 	std::string object_id = getObjectId(url);
diff --git a/indra/llui/llurlaction.h b/indra/llui/llurlaction.h
index 2d2a8dfef19835b75ffacedebe9bcc3890d454f2..c2c576254dc638055e43a0ab4216bc06a80aa958 100644
--- a/indra/llui/llurlaction.h
+++ b/indra/llui/llurlaction.h
@@ -82,6 +82,7 @@ class LLUrlAction
 	static void sendIM(std::string url);
 	static void addFriend(std::string url);
 	static void removeFriend(std::string url);
+    static void reportAbuse(std::string url);
 	static void blockObject(std::string url);
 	static void unblockObject(std::string url);
 
diff --git a/indra/llui/llurlentry.cpp b/indra/llui/llurlentry.cpp
index 38495e1e0b023fbfa5df2c1df942e6c4a0df229d..1547a4ba5c89aa0c0df716e48720989f5e08451f 100644
--- a/indra/llui/llurlentry.cpp
+++ b/indra/llui/llurlentry.cpp
@@ -1017,6 +1017,24 @@ std::string LLUrlEntryObjectIM::getLocation(const std::string &url) const
 	return LLUrlEntryBase::getLocation(url);
 }
 
+//
+// LLUrlEntryChat Describes a Second Life chat Url, e.g.,
+// secondlife:///app/chat/42/This%20Is%20a%20test
+//
+
+LLUrlEntryChat::LLUrlEntryChat()
+{
+    mPattern = boost::regex("secondlife:///app/chat/\\d+/\\S+",
+        boost::regex::perl|boost::regex::icase);
+    mMenuName = "menu_url_slapp.xml";
+    mTooltip = LLTrans::getString("TooltipSLAPP");
+}
+
+std::string LLUrlEntryChat::getLabel(const std::string &url, const LLUrlLabelCallback &cb)
+{
+    return unescapeUrl(url);
+}
+
 // LLUrlEntryParcel statics.
 LLUUID	LLUrlEntryParcel::sAgentID(LLUUID::null);
 LLUUID	LLUrlEntryParcel::sSessionID(LLUUID::null);
diff --git a/indra/llui/llurlentry.h b/indra/llui/llurlentry.h
index 102e0a4fd98d7e2537ab2df0cd6f0f427fb49552..63a1506731f73100f97fda9fa27b105e8ebaa175 100644
--- a/indra/llui/llurlentry.h
+++ b/indra/llui/llurlentry.h
@@ -370,6 +370,17 @@ class LLUrlEntryObjectIM : public LLUrlEntryBase
 private:
 };
 
+//
+// LLUrlEntryChat Describes a Second Life chat Url, e.g.,
+// secondlife:///app/chat/42/This%20Is%20a%20test
+//
+class LLUrlEntryChat : public LLUrlEntryBase
+{
+public:
+    LLUrlEntryChat();
+    /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb);
+};
+
 ///
 /// LLUrlEntryParcel Describes a Second Life parcel Url, e.g.,
 /// secondlife:///app/parcel/0000060e-4b39-e00b-d0c3-d98b1934e3a8/about
diff --git a/indra/llui/llurlregistry.cpp b/indra/llui/llurlregistry.cpp
index bfcd970529454c89aa2f09d981f38008144b02b7..c9d7013a11ac5dba1887d0d66cbc9f64c17ca1e4 100644
--- a/indra/llui/llurlregistry.cpp
+++ b/indra/llui/llurlregistry.cpp
@@ -63,6 +63,7 @@ LLUrlRegistry::LLUrlRegistry()
 	// LLUrlEntryAgent*Name must appear before LLUrlEntryAgent since 
 	// LLUrlEntryAgent is a less specific (catchall for agent urls)
 	registerUrl(new LLUrlEntryAgent());
+    registerUrl(new LLUrlEntryChat());
 	registerUrl(new LLUrlEntryGroup());
 	registerUrl(new LLUrlEntryParcel());
 	registerUrl(new LLUrlEntryTeleport());
@@ -71,7 +72,6 @@ LLUrlRegistry::LLUrlRegistry()
 	registerUrl(new LLUrlEntryObjectIM());
 	registerUrl(new LLUrlEntryPlace());
 	registerUrl(new LLUrlEntryInventory());
-	registerUrl(new LLUrlEntryObjectIM());
     registerUrl(new LLUrlEntryExperienceProfile());
 	//LLUrlEntrySL and LLUrlEntrySLLabel have more common pattern, 
 	//so it should be registered in the end of list
diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp
index b942be2a4a833def1e7ac628d19cc902c0b5315d..9ba71913d0863148a13aea2332687528dc5d6773 100644
--- a/indra/llui/llview.cpp
+++ b/indra/llui/llview.cpp
@@ -140,8 +140,7 @@ LLView::Params::Params()
 }
 
 LLView::LLView(const LLView::Params& p)
-:	LLTrace::MemTrackable<LLView>("LLView"),
-	mVisible(p.visible),
+:	mVisible(p.visible),
 	mInDraw(false),
 	mName(p.name),
 	mParentView(NULL),
@@ -1597,15 +1596,11 @@ LLView* LLView::getChildView(const std::string& name, BOOL recurse) const
 	return getChild<LLView>(name, recurse);
 }
 
-static LLTrace::BlockTimerStatHandle FTM_FIND_VIEWS("Find Widgets");
-
 LLView* LLView::findChildView(const std::string& name, BOOL recurse) const
 {
-	LL_RECORD_BLOCK_TIME(FTM_FIND_VIEWS);
-	//richard: should we allow empty names?
-	//if(name.empty())
-	//	return NULL;
-	// Look for direct children *first*
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
+	
+    // Look for direct children *first*
 	BOOST_FOREACH(LLView* childp, mChildList)
 	{
 		llassert(childp);
diff --git a/indra/llui/llview.h b/indra/llui/llview.h
index c60dcf3344f204e442c10bb7e42310fda2375a45..bec45df78a9db2589984d300713df9b611084913 100644
--- a/indra/llui/llview.h
+++ b/indra/llui/llview.h
@@ -100,8 +100,7 @@ class LLView
 :	public LLMouseHandler,			// handles mouse events
 	public LLFocusableElement,		// handles keyboard events
 	public LLMortician,				// lazy deletion
-	public LLHandleProvider<LLView>,     // passes out weak references to self
-	public LLTrace::MemTrackable<LLView> // track memory usage
+	public LLHandleProvider<LLView>     // passes out weak references to self
 {
 public:
 
diff --git a/indra/llui/llviewereventrecorder.h b/indra/llui/llviewereventrecorder.h
index 94e66f5dc4ed3d1e8501bd38ea83b4c92205402f..6170005b2b2fc218e92b2216cf9d7fe935a47a41 100644
--- a/indra/llui/llviewereventrecorder.h
+++ b/indra/llui/llviewereventrecorder.h
@@ -41,12 +41,12 @@
 
 #include "llsingleton.h" // includes llerror which we need here so we can skip the include here
 
-class LLViewerEventRecorder : public LLSingleton<LLViewerEventRecorder>
+class LLViewerEventRecorder : public LLSimpleton<LLViewerEventRecorder>
 {
-  LLSINGLETON(LLViewerEventRecorder);
-  ~LLViewerEventRecorder();
-
- public:
+public:
+    LLViewerEventRecorder();
+    ~LLViewerEventRecorder();
+   
   void updateMouseEventInfo(S32 local_x,S32 local_y, S32 global_x, S32 global_y,  std::string mName);
   void setMouseLocalCoords(S32 x,S32 y);
   void setMouseGlobalCoords(S32 x,S32 y);
diff --git a/indra/llui/llviewmodel.cpp b/indra/llui/llviewmodel.cpp
index 282addf6925d089043c8e953d8c3c54ab7b6a8bf..a400eb70c07b1aaf1ceb6b3af14ee1cbf5b0f80f 100644
--- a/indra/llui/llviewmodel.cpp
+++ b/indra/llui/llviewmodel.cpp
@@ -37,15 +37,13 @@
 
 ///
 LLViewModel::LLViewModel()
-:	LLTrace::MemTrackable<LLViewModel>("LLViewModel"),
-	mDirty(false)
+:	mDirty(false)
 {
 }
 
 /// Instantiate an LLViewModel with an existing data value
 LLViewModel::LLViewModel(const LLSD& value)
-:	LLTrace::MemTrackable<LLViewModel>("LLViewModel"),
-	mDirty(false)
+:	mDirty(false)
 {
     setValue(value);
 }
@@ -82,15 +80,9 @@ LLTextViewModel::LLTextViewModel(const LLSD& value)
 void LLTextViewModel::setValue(const LLSD& value)
 {
 	// approximate LLSD storage usage
-	disclaimMem(mDisplay.size());
 	LLViewModel::setValue(value);
-	disclaimMem(mDisplay);
     mDisplay = utf8str_to_wstring(value.asString());
 
-	claimMem(mDisplay);
-	// approximate LLSD storage usage
-	claimMem(mDisplay.size());
-
     // mDisplay and mValue agree
     mUpdateFromDisplay = false;
 }
@@ -101,12 +93,8 @@ void LLTextViewModel::setDisplay(const LLWString& value)
     // and do the utf8str_to_wstring() to get the corresponding mDisplay
     // value. But a text editor might want to edit the display string
     // directly, then convert back to UTF8 on commit.
-	disclaimMem(mDisplay.size());
-	disclaimMem(mDisplay);
-    mDisplay = value;
-	claimMem(mDisplay);
-	claimMem(mDisplay.size());
-    mDirty = true;
+	mDisplay = value;
+	mDirty = true;
     // Don't immediately convert to UTF8 -- do it lazily -- we expect many
     // more setDisplay() calls than getValue() calls. Just flag that it needs
     // doing.
diff --git a/indra/llui/llviewmodel.h b/indra/llui/llviewmodel.h
index 49d7c322a3d5f99f420a7856ab0e87acbefb1823..e7dceb6c315029e0947645dc4a80a7b30fe00f1d 100644
--- a/indra/llui/llviewmodel.h
+++ b/indra/llui/llviewmodel.h
@@ -62,8 +62,7 @@ typedef LLPointer<LLListViewModel> LLListViewModelPtr;
  * last referencing widget is destroyed.
  */
 class LLViewModel 
-:	public LLRefCount,
-	public LLTrace::MemTrackable<LLViewModel>
+:	public LLRefCount
 {
 public:
     LLViewModel();
diff --git a/indra/llwindow/CMakeLists.txt b/indra/llwindow/CMakeLists.txt
index 70eb99c86c41ccf78839d63cbaef1fdfb8334512..55befaef513c6abc5d4ddc23d8ab71e7474b4fa8 100644
--- a/indra/llwindow/CMakeLists.txt
+++ b/indra/llwindow/CMakeLists.txt
@@ -197,4 +197,10 @@ if (SDL_FOUND)
 endif (SDL_FOUND)
 
   target_link_libraries (llwindow ${llwindow_LINK_LIBRARIES})
+  
+if (DARWIN)
+  include(CMakeFindFrameworks)
+  find_library(CARBON_LIBRARY Carbon)
+  target_link_libraries(llwindow ${CARBON_LIBRARY})
+endif (DARWIN)
 
diff --git a/indra/llwindow/GL/glh_extensions.h b/indra/llwindow/GL/glh_extensions.h
deleted file mode 100644
index 554cb1731f27e20a4a1e4fbdc6d1e3971398f9e2..0000000000000000000000000000000000000000
--- a/indra/llwindow/GL/glh_extensions.h
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
- *  glh_extensions.h
- * $LicenseInfo:firstyear=2006&license=mit$ (mit used here to satisfy validity checker)
- * Copyright (C) 2006, NVIDIA
- *  From nVidia Corporation, downloaded 2006-12-18 from:
- *  http://developer.nvidia.com/attach/8196
- *  ("NVParse Library with Source (.zip) (2390 KB)")
- *
- *  License (quoted from license_info.txt in aforementioned file):
- *  "The files bison.exe, bison.simple, and flex.exe are covered by
- *  the GPL.  All other files in this distribution can be used however
- *  you want."
- * $/LicenseInfo$
-
- */
-
-#ifndef GLH_EXTENSIONS
-#define GLH_EXTENSIONS
-
-#include <string.h>
-#include <stdio.h>
-
-#ifdef _WIN32
-# include <windows.h>
-#endif
-
-#ifndef __APPLE__
-#include <GL/gl.h>
-#endif
-
-#ifdef _WIN32
-# include "GL/wglext.h"
-#endif
-
-#define CHECK_MEMORY(ptr) \
-    if (NULL == ptr) { \
-		printf("Error allocating memory in file %s, line %d\n", __FILE__, __LINE__); \
-		exit(-1); \
-	}
-
-#ifdef GLH_EXT_SINGLE_FILE
-#  define GLH_EXTENSIONS_SINGLE_FILE  // have to do this because glh_genext.h unsets GLH_EXT_SINGLE_FILE
-#endif
-
-#include "glh_genext.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifdef GLH_EXTENSIONS_SINGLE_FILE
-
-class GLHExts
-{
-public:
-	GLHExts()
-	{
-		mSysExts = NULL;
-//		mUnsupportedExts = NULL;
-	}
-	~GLHExts()
-	{
-		if (mSysExts)
-		{
-			free(mSysExts);
-		}
-//		if (mUnsupportedExts)
-//		{
-//			free(mUnsupportedExts);
-//		}
-	}
-	char *mSysExts;
-//	char *mUnsupportedExts;
-};
-
-GLHExts gGLHExts;
-
-static int ExtensionExists(const char* extName, const char* sysExts)
-{
-    char *padExtName = (char*)malloc(strlen(extName) + 2);
-    strcat(strcpy(padExtName, extName), " ");
-
-	if (0 == strcmp(extName, "GL_VERSION_1_2")) {
-		const char *version = (const char*)glGetString(GL_VERSION);
-		if (strstr(version, "1.0") == version || strstr(version, "1.1") == version) {
-			return FALSE;
-		} else {
-			return TRUE;
-		}
-	}
-    if (strstr(sysExts, padExtName)) {
-		free(padExtName);
-        return TRUE;
-    } else {
-		free(padExtName);
-        return FALSE;
-    }
-}
-
-static const char* EatWhiteSpace(const char *str)
-{
-	for (; *str && (' ' == *str || '\t' == *str || '\n' == *str); str++);
-	return str;
-}
-
-static const char* EatNonWhiteSpace(const char *str)
-{
-	for (; *str && (' ' != *str && '\t' != *str && '\n' != *str); str++);
-	return str;
-}
-
-
-int glh_init_extensions(const char *origReqExts)
-{
-	// Length of requested extensions string
-	//unsigned reqExtsLen;
-	char *reqExts;
-	// Ptr for individual extensions within reqExts
-	char *reqExt;
-	int success = TRUE;
-
-	// build space-padded extension string
-	if (NULL == gGLHExts.mSysExts) {
-		const char *extensions = (const char*)glGetString(GL_EXTENSIONS);
-		int sysExtsLen = (int)strlen(extensions);
-		const char *winsys_extensions = 0;		
-		int winsysExtsLen = 0;
-#ifdef _WIN32
-		{
-			PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetExtensionsStringARB = 0;
-			wglGetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC)wglGetProcAddress("wglGetExtensionsStringARB");
-			if(wglGetExtensionsStringARB)
-			{
-				winsys_extensions = wglGetExtensionsStringARB(wglGetCurrentDC());
-				winsysExtsLen = (S32)strlen(winsys_extensions);
-			}
-		}
-#endif
-		// Add 2 bytes, one for padding space, one for terminating NULL
-		gGLHExts.mSysExts = (char*)malloc(sysExtsLen + winsysExtsLen + 3);
-		CHECK_MEMORY(gGLHExts.mSysExts);
-		strcpy(gGLHExts.mSysExts, extensions);
-		gGLHExts.mSysExts[sysExtsLen] = ' ';
-		gGLHExts.mSysExts[sysExtsLen + 1] = 0;
-		if (winsysExtsLen)
-		{
-			strcat(gGLHExts.mSysExts, winsys_extensions);
-		}
-		gGLHExts.mSysExts[sysExtsLen + 1 + winsysExtsLen] = ' ';
-		gGLHExts.mSysExts[sysExtsLen + 1 + winsysExtsLen + 1] = 0;
-	}
-
-	if (NULL == origReqExts)
-	{
-		return TRUE;
-	}
-	reqExts = strdup(origReqExts);
-	/*
-	reqExtsLen = (S32)strlen(reqExts);
-	if (NULL == gGLHExts.mUnsupportedExts)
-	{
-		gGLHExts.mUnsupportedExts = (char*)malloc(reqExtsLen + 1);
-	}
-	else if (reqExtsLen > strlen(gGLHExts.mUnsupportedExts))
-	{
-		gGLHExts.mUnsupportedExts = (char*)realloc(gGLHExts.mUnsupportedExts, reqExtsLen + 1);
-	}
-	CHECK_MEMORY(gGLHExts.mUnsupportedExts);
-	*gGLHExts.mUnsupportedExts = 0;
-	*/
-
-	// Parse requested extension list
-	for (reqExt = reqExts;
-		(reqExt = (char*)EatWhiteSpace(reqExt)) && *reqExt;
-		reqExt = (char*)EatNonWhiteSpace(reqExt))
-	{
-		char *extEnd = (char*)EatNonWhiteSpace(reqExt);
-		char saveChar = *extEnd;
-		*extEnd = (char)0;
-		
-		if (!ExtensionExists(reqExt, gGLHExts.mSysExts) ||
-			!glh_init_extension(reqExt)) {
-			/*
-			// add reqExt to end of unsupportedExts
-			strcat(gGLHExts.mUnsupportedExts, reqExt);
-			strcat(gGLHExts.mUnsupportedExts, " ");
-			*/
-			success = FALSE;
-		}
-		*extEnd = saveChar;
-	}
-	free(reqExts);
-	return success;
-}
-
-const char* glh_get_unsupported_extensions()
-{
-	return "";
-//	return (const char*)gGLHExts.mUnsupportedExts;
-}
-
-#else
-int glh_init_extensions(const char *origReqExts);
-const char* glh_get_unsupported_extensions();
-#endif /* GLH_EXT_SINGLE_FILE */
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* GLH_EXTENSIONS */
diff --git a/indra/llwindow/GL/glh_genext.h b/indra/llwindow/GL/glh_genext.h
deleted file mode 100644
index cd5d1604a8dd217c196e44d0c40404b0db0d25c3..0000000000000000000000000000000000000000
--- a/indra/llwindow/GL/glh_genext.h
+++ /dev/null
@@ -1,1674 +0,0 @@
-/*
- *  glh_genext.h
- * $LicenseInfo:firstyear=2008&license=mit$ (mit used here to satisfy validity checker)
- * Copyright (C) 2008, NVIDIA
- *  From nVidia Corporation, downloaded 2006-12-18 from:
- *  http://developer.nvidia.com/attach/8196
- *  ("NVParse Library with Source (.zip) (2390 KB)")
- *
- *  License (quoted from license_info.txt in aforementioned file):
- *  "The files bison.exe, bison.simple, and flex.exe are covered by
- *  the GPL.  All other files in this distribution can be used however
- *  you want."
- * $/LicenseInfo$
- */
-
-/* File generated by extgen.cpp -- do not modify */
-#ifndef GLH_GENEXT_H
-#define GLH_GENEXT_H
-
-// MBW -- None of this is necessary on Mac OS.
-#ifndef __APPLE__
-
-#include <GL/gl.h>
-#include <GL/glext.h>
-
-#ifdef _WIN32 /* supports windows, x -- need to generalize */
-#  include <GL/wglext.h>
-#  define GLH_EXT_GET_PROC_ADDRESS(p)   wglGetProcAddress(p) 
-#else if GLX_VERSION_1_3
-#  include <GL/glxext.h>
-#  define GLH_EXT_GET_PROC_ADDRESS(p)   glXGetProcAddressARB(p) 
-#endif
-
-#ifdef GLH_EXT_SINGLE_FILE
-	#define GLH_EXTERN
- #define GLH_INITIALIZER = 0
-#else
-	#define GLH_EXTERN extern
- #define GLH_INITIALIZER
-#endif
-
-#define GLH__PREPROCESSOR_GYMNASTICS2(a,b) a##b
-#define GLH__PREPROCESSOR_GYMNASTICS(a,b) GLH__PREPROCESSOR_GYMNASTICS2(a,b)
-
-#ifndef GLH_EXT_PREFIX
-# define GLH_EXT_NAME(a) a
-#else
-# define GLH_EXT_NAME(a) GLH__PREPROCESSOR_GYMNASTICS(GLH_EXT_PREFIX,a)
-#endif
-
-#ifndef _WIN32
-# ifndef GLH_CORE_1_2_PREFIX
-#  define GLH_CORE_1_2_PREFIX _
-# endif
-#endif
-
-#ifndef GLH_CORE_1_2_PREFIX
-# define GLH_CORE_1_2_NAME(a) a
-#else
-# define GLH_CORE_1_2_NAME(a) GLH__PREPROCESSOR_GYMNASTICS(GLH_CORE_1_2_PREFIX,a)
-#endif
-
-#ifdef GL_ARB_multitexture
-    GLH_EXTERN PFNGLMULTITEXCOORD1DARBPROC GLH_EXT_NAME(glMultiTexCoord1dARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMULTITEXCOORD1DVARBPROC GLH_EXT_NAME(glMultiTexCoord1dvARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMULTITEXCOORD1FARBPROC GLH_EXT_NAME(glMultiTexCoord1fARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMULTITEXCOORD1FVARBPROC GLH_EXT_NAME(glMultiTexCoord1fvARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMULTITEXCOORD1IARBPROC GLH_EXT_NAME(glMultiTexCoord1iARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMULTITEXCOORD1IVARBPROC GLH_EXT_NAME(glMultiTexCoord1ivARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMULTITEXCOORD1SARBPROC GLH_EXT_NAME(glMultiTexCoord1sARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMULTITEXCOORD1SVARBPROC GLH_EXT_NAME(glMultiTexCoord1svARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMULTITEXCOORD2DARBPROC GLH_EXT_NAME(glMultiTexCoord2dARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMULTITEXCOORD2DVARBPROC GLH_EXT_NAME(glMultiTexCoord2dvARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMULTITEXCOORD2FARBPROC GLH_EXT_NAME(glMultiTexCoord2fARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMULTITEXCOORD2FVARBPROC GLH_EXT_NAME(glMultiTexCoord2fvARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMULTITEXCOORD2IARBPROC GLH_EXT_NAME(glMultiTexCoord2iARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMULTITEXCOORD2IVARBPROC GLH_EXT_NAME(glMultiTexCoord2ivARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMULTITEXCOORD2SARBPROC GLH_EXT_NAME(glMultiTexCoord2sARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMULTITEXCOORD2SVARBPROC GLH_EXT_NAME(glMultiTexCoord2svARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMULTITEXCOORD3DARBPROC GLH_EXT_NAME(glMultiTexCoord3dARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMULTITEXCOORD3DVARBPROC GLH_EXT_NAME(glMultiTexCoord3dvARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMULTITEXCOORD3FARBPROC GLH_EXT_NAME(glMultiTexCoord3fARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMULTITEXCOORD3FVARBPROC GLH_EXT_NAME(glMultiTexCoord3fvARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMULTITEXCOORD3IARBPROC GLH_EXT_NAME(glMultiTexCoord3iARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMULTITEXCOORD3IVARBPROC GLH_EXT_NAME(glMultiTexCoord3ivARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMULTITEXCOORD3SARBPROC GLH_EXT_NAME(glMultiTexCoord3sARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMULTITEXCOORD3SVARBPROC GLH_EXT_NAME(glMultiTexCoord3svARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMULTITEXCOORD4DARBPROC GLH_EXT_NAME(glMultiTexCoord4dARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMULTITEXCOORD4DVARBPROC GLH_EXT_NAME(glMultiTexCoord4dvARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMULTITEXCOORD4FARBPROC GLH_EXT_NAME(glMultiTexCoord4fARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMULTITEXCOORD4FVARBPROC GLH_EXT_NAME(glMultiTexCoord4fvARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMULTITEXCOORD4IARBPROC GLH_EXT_NAME(glMultiTexCoord4iARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMULTITEXCOORD4IVARBPROC GLH_EXT_NAME(glMultiTexCoord4ivARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMULTITEXCOORD4SARBPROC GLH_EXT_NAME(glMultiTexCoord4sARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMULTITEXCOORD4SVARBPROC GLH_EXT_NAME(glMultiTexCoord4svARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLACTIVETEXTUREARBPROC GLH_EXT_NAME(glActiveTextureARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLCLIENTACTIVETEXTUREARBPROC GLH_EXT_NAME(glClientActiveTextureARB) GLH_INITIALIZER;
-#endif
-
-#ifdef GL_ARB_texture_border_clamp
-#endif
-
-#ifdef GL_ARB_texture_compression
-    GLH_EXTERN PFNGLCOMPRESSEDTEXIMAGE3DARBPROC GLH_EXT_NAME(glCompressedTexImage3DARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLCOMPRESSEDTEXIMAGE2DARBPROC GLH_EXT_NAME(glCompressedTexImage2DARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLCOMPRESSEDTEXIMAGE1DARBPROC GLH_EXT_NAME(glCompressedTexImage1DARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLCOMPRESSEDTEXSUBIMAGE3DARBPROC GLH_EXT_NAME(glCompressedTexSubImage3DARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLCOMPRESSEDTEXSUBIMAGE2DARBPROC GLH_EXT_NAME(glCompressedTexSubImage2DARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLCOMPRESSEDTEXSUBIMAGE1DARBPROC GLH_EXT_NAME(glCompressedTexSubImage1DARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETCOMPRESSEDTEXIMAGEARBPROC GLH_EXT_NAME(glGetCompressedTexImageARB) GLH_INITIALIZER;
-#endif
-
-#ifdef GL_ARB_texture_cube_map
-#endif
-
-#ifdef GL_ARB_transpose_matrix
-    GLH_EXTERN PFNGLLOADTRANSPOSEMATRIXFARBPROC GLH_EXT_NAME(glLoadTransposeMatrixfARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLLOADTRANSPOSEMATRIXDARBPROC GLH_EXT_NAME(glLoadTransposeMatrixdARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMULTTRANSPOSEMATRIXFARBPROC GLH_EXT_NAME(glMultTransposeMatrixfARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMULTTRANSPOSEMATRIXDARBPROC GLH_EXT_NAME(glMultTransposeMatrixdARB) GLH_INITIALIZER;
-#endif
-
-#ifdef GL_ARB_vertex_program
-    GLH_EXTERN PFNGLVERTEXATTRIB1SARBPROC GLH_EXT_NAME(glVertexAttrib1sARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB1FARBPROC GLH_EXT_NAME(glVertexAttrib1fARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB1DARBPROC GLH_EXT_NAME(glVertexAttrib1dARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB2SARBPROC GLH_EXT_NAME(glVertexAttrib2sARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB2FARBPROC GLH_EXT_NAME(glVertexAttrib2fARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB2DARBPROC GLH_EXT_NAME(glVertexAttrib2dARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB3SARBPROC GLH_EXT_NAME(glVertexAttrib3sARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB3FARBPROC GLH_EXT_NAME(glVertexAttrib3fARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB3DARBPROC GLH_EXT_NAME(glVertexAttrib3dARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB4SARBPROC GLH_EXT_NAME(glVertexAttrib4sARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB4FARBPROC GLH_EXT_NAME(glVertexAttrib4fARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB4DARBPROC GLH_EXT_NAME(glVertexAttrib4dARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB4NUBARBPROC GLH_EXT_NAME(glVertexAttrib4NubARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB1SVARBPROC GLH_EXT_NAME(glVertexAttrib1svARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB1FVARBPROC GLH_EXT_NAME(glVertexAttrib1fvARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB1DVARBPROC GLH_EXT_NAME(glVertexAttrib1dvARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB2SVARBPROC GLH_EXT_NAME(glVertexAttrib2svARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB2FVARBPROC GLH_EXT_NAME(glVertexAttrib2fvARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB2DVARBPROC GLH_EXT_NAME(glVertexAttrib2dvARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB3SVARBPROC GLH_EXT_NAME(glVertexAttrib3svARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB3FVARBPROC GLH_EXT_NAME(glVertexAttrib3fvARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB3DVARBPROC GLH_EXT_NAME(glVertexAttrib3dvARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB4BVARBPROC GLH_EXT_NAME(glVertexAttrib4bvARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB4SVARBPROC GLH_EXT_NAME(glVertexAttrib4svARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB4IVARBPROC GLH_EXT_NAME(glVertexAttrib4ivARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB4UBVARBPROC GLH_EXT_NAME(glVertexAttrib4ubvARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB4USVARBPROC GLH_EXT_NAME(glVertexAttrib4usvARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB4UIVARBPROC GLH_EXT_NAME(glVertexAttrib4uivARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB4FVARBPROC GLH_EXT_NAME(glVertexAttrib4fvARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB4DVARBPROC GLH_EXT_NAME(glVertexAttrib4dvARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB4NBVARBPROC GLH_EXT_NAME(glVertexAttrib4NbvARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB4NSVARBPROC GLH_EXT_NAME(glVertexAttrib4NsvARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB4NIVARBPROC GLH_EXT_NAME(glVertexAttrib4NivARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB4NUBVARBPROC GLH_EXT_NAME(glVertexAttrib4NubvARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB4NUSVARBPROC GLH_EXT_NAME(glVertexAttrib4NusvARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB4NUIVARBPROC GLH_EXT_NAME(glVertexAttrib4NuivARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIBPOINTERARBPROC GLH_EXT_NAME(glVertexAttribPointerARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLENABLEVERTEXATTRIBARRAYARBPROC GLH_EXT_NAME(glEnableVertexAttribArrayARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLDISABLEVERTEXATTRIBARRAYARBPROC GLH_EXT_NAME(glDisableVertexAttribArrayARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLPROGRAMSTRINGARBPROC GLH_EXT_NAME(glProgramStringARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLBINDPROGRAMARBPROC GLH_EXT_NAME(glBindProgramARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLDELETEPROGRAMSARBPROC GLH_EXT_NAME(glDeleteProgramsARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGENPROGRAMSARBPROC GLH_EXT_NAME(glGenProgramsARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLPROGRAMENVPARAMETER4DARBPROC GLH_EXT_NAME(glProgramEnvParameter4dARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLPROGRAMENVPARAMETER4DVARBPROC GLH_EXT_NAME(glProgramEnvParameter4dvARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLPROGRAMENVPARAMETER4FARBPROC GLH_EXT_NAME(glProgramEnvParameter4fARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLPROGRAMENVPARAMETER4FVARBPROC GLH_EXT_NAME(glProgramEnvParameter4fvARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLPROGRAMLOCALPARAMETER4DARBPROC GLH_EXT_NAME(glProgramLocalParameter4dARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLPROGRAMLOCALPARAMETER4DVARBPROC GLH_EXT_NAME(glProgramLocalParameter4dvARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLPROGRAMLOCALPARAMETER4FARBPROC GLH_EXT_NAME(glProgramLocalParameter4fARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLPROGRAMLOCALPARAMETER4FVARBPROC GLH_EXT_NAME(glProgramLocalParameter4fvARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETPROGRAMENVPARAMETERDVARBPROC GLH_EXT_NAME(glGetProgramEnvParameterdvARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETPROGRAMENVPARAMETERFVARBPROC GLH_EXT_NAME(glGetProgramEnvParameterfvARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC GLH_EXT_NAME(glGetProgramLocalParameterdvARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETPROGRAMLOCALPARAMETERFVARBPROC GLH_EXT_NAME(glGetProgramLocalParameterfvARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETPROGRAMIVARBPROC GLH_EXT_NAME(glGetProgramivARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETPROGRAMSTRINGARBPROC GLH_EXT_NAME(glGetProgramStringARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETVERTEXATTRIBDVARBPROC GLH_EXT_NAME(glGetVertexAttribdvARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETVERTEXATTRIBFVARBPROC GLH_EXT_NAME(glGetVertexAttribfvARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETVERTEXATTRIBIVARBPROC GLH_EXT_NAME(glGetVertexAttribivARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETVERTEXATTRIBPOINTERVARBPROC GLH_EXT_NAME(glGetVertexAttribPointervARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLISPROGRAMARBPROC GLH_EXT_NAME(glIsProgramARB) GLH_INITIALIZER;
-#endif
-
-#ifdef GL_EXT_abgr
-#endif
-
-#ifdef GL_EXT_bgra
-#endif
-
-#ifdef GL_EXT_blend_color
-    GLH_EXTERN PFNGLBLENDCOLOREXTPROC GLH_EXT_NAME(glBlendColorEXT) GLH_INITIALIZER;
-#endif
-
-#ifdef GL_EXT_blend_minmax
-    GLH_EXTERN PFNGLBLENDEQUATIONEXTPROC GLH_EXT_NAME(glBlendEquationEXT) GLH_INITIALIZER;
-#endif
-
-#ifdef GL_EXT_blend_subtract
-#endif
-
-#ifdef GL_EXT_compiled_vertex_array
-    GLH_EXTERN PFNGLLOCKARRAYSEXTPROC GLH_EXT_NAME(glLockArraysEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLUNLOCKARRAYSEXTPROC GLH_EXT_NAME(glUnlockArraysEXT) GLH_INITIALIZER;
-#endif
-
-#ifdef GL_EXT_fog_coord
-    GLH_EXTERN PFNGLFOGCOORDDEXTPROC GLH_EXT_NAME(glFogCoorddEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLFOGCOORDDVEXTPROC GLH_EXT_NAME(glFogCoorddvEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLFOGCOORDFEXTPROC GLH_EXT_NAME(glFogCoordfEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLFOGCOORDFVEXTPROC GLH_EXT_NAME(glFogCoordfvEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLFOGCOORDPOINTEREXTPROC GLH_EXT_NAME(glFogCoordPointerEXT) GLH_INITIALIZER;
-#endif
-
-#ifdef GL_EXT_light_max_exponent
-#endif
-
-#ifdef GL_EXT_packed_pixels
-#endif
-
-#ifdef GL_EXT_paletted_texture
-    GLH_EXTERN PFNGLCOLORSUBTABLEEXTPROC GLH_EXT_NAME(glColorSubTableEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLCOLORTABLEEXTPROC GLH_EXT_NAME(glColorTableEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETCOLORTABLEEXTPROC GLH_EXT_NAME(glGetColorTableEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETCOLORTABLEPARAMETERFVEXTPROC GLH_EXT_NAME(glGetColorTableParameterfvEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETCOLORTABLEPARAMETERIVEXTPROC GLH_EXT_NAME(glGetColorTableParameterivEXT) GLH_INITIALIZER;
-#endif
-
-#ifdef GL_EXT_point_parameters
-    GLH_EXTERN PFNGLPOINTPARAMETERFEXTPROC GLH_EXT_NAME(glPointParameterfEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLPOINTPARAMETERFVEXTPROC GLH_EXT_NAME(glPointParameterfvEXT) GLH_INITIALIZER;
-#endif
-
-#ifdef GL_EXT_rescale_normal
-#endif
-
-#ifdef GL_EXT_secondary_color
-    GLH_EXTERN PFNGLSECONDARYCOLOR3BEXTPROC GLH_EXT_NAME(glSecondaryColor3bEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLSECONDARYCOLOR3BVEXTPROC GLH_EXT_NAME(glSecondaryColor3bvEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLSECONDARYCOLOR3DEXTPROC GLH_EXT_NAME(glSecondaryColor3dEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLSECONDARYCOLOR3DVEXTPROC GLH_EXT_NAME(glSecondaryColor3dvEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLSECONDARYCOLOR3FEXTPROC GLH_EXT_NAME(glSecondaryColor3fEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLSECONDARYCOLOR3FVEXTPROC GLH_EXT_NAME(glSecondaryColor3fvEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLSECONDARYCOLOR3IEXTPROC GLH_EXT_NAME(glSecondaryColor3iEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLSECONDARYCOLOR3IVEXTPROC GLH_EXT_NAME(glSecondaryColor3ivEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLSECONDARYCOLOR3SEXTPROC GLH_EXT_NAME(glSecondaryColor3sEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLSECONDARYCOLOR3SVEXTPROC GLH_EXT_NAME(glSecondaryColor3svEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLSECONDARYCOLOR3UBEXTPROC GLH_EXT_NAME(glSecondaryColor3ubEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLSECONDARYCOLOR3UBVEXTPROC GLH_EXT_NAME(glSecondaryColor3ubvEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLSECONDARYCOLOR3UIEXTPROC GLH_EXT_NAME(glSecondaryColor3uiEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLSECONDARYCOLOR3UIVEXTPROC GLH_EXT_NAME(glSecondaryColor3uivEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLSECONDARYCOLOR3USEXTPROC GLH_EXT_NAME(glSecondaryColor3usEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLSECONDARYCOLOR3USVEXTPROC GLH_EXT_NAME(glSecondaryColor3usvEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLSECONDARYCOLORPOINTEREXTPROC GLH_EXT_NAME(glSecondaryColorPointerEXT) GLH_INITIALIZER;
-#endif
-
-#ifdef GL_EXT_separate_specular_color
-#endif
-
-#ifdef GL_EXT_shared_texture_palette
-#endif
-
-#ifdef GL_EXT_stencil_wrap
-#endif
-
-#ifdef GL_EXT_texture_compression_s3tc
-#endif
-
-#ifdef GL_EXT_texture_cube_map
-#endif
-
-#ifdef GL_EXT_texture_edge_clamp
-#endif
-
-#ifdef GL_EXT_texture_env_add
-#endif
-
-#ifdef GL_EXT_texture_env_combine
-#endif
-
-#ifdef GL_EXT_texture_filter_anisotropic
-#endif
-
-#ifdef GL_EXT_texture_lod_bias
-#endif
-
-#ifdef GL_EXT_texture_object
-    GLH_EXTERN PFNGLARETEXTURESRESIDENTEXTPROC GLH_EXT_NAME(glAreTexturesResidentEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLBINDTEXTUREEXTPROC GLH_EXT_NAME(glBindTextureEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLDELETETEXTURESEXTPROC GLH_EXT_NAME(glDeleteTexturesEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGENTEXTURESEXTPROC GLH_EXT_NAME(glGenTexturesEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLISTEXTUREEXTPROC GLH_EXT_NAME(glIsTextureEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLPRIORITIZETEXTURESEXTPROC GLH_EXT_NAME(glPrioritizeTexturesEXT) GLH_INITIALIZER;
-#endif
-
-#ifdef GL_EXT_texture3D
-    GLH_EXTERN PFNGLTEXIMAGE3DEXTPROC GLH_EXT_NAME(glTexImage3DEXT) GLH_INITIALIZER;
-#endif
-
-#ifdef GL_EXT_vertex_array
-    GLH_EXTERN PFNGLARRAYELEMENTEXTPROC GLH_EXT_NAME(glArrayElementEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLCOLORPOINTEREXTPROC GLH_EXT_NAME(glColorPointerEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLEDGEFLAGPOINTEREXTPROC GLH_EXT_NAME(glEdgeFlagPointerEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETPOINTERVEXTPROC GLH_EXT_NAME(glGetPointervEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLINDEXPOINTEREXTPROC GLH_EXT_NAME(glIndexPointerEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLNORMALPOINTEREXTPROC GLH_EXT_NAME(glNormalPointerEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLTEXCOORDPOINTEREXTPROC GLH_EXT_NAME(glTexCoordPointerEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXPOINTEREXTPROC GLH_EXT_NAME(glVertexPointerEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLDRAWARRAYSEXTPROC GLH_EXT_NAME(glDrawArraysEXT) GLH_INITIALIZER;
-#endif
-
-#ifdef GL_EXT_vertex_weighting
-    GLH_EXTERN PFNGLVERTEXWEIGHTFEXTPROC GLH_EXT_NAME(glVertexWeightfEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXWEIGHTFVEXTPROC GLH_EXT_NAME(glVertexWeightfvEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXWEIGHTPOINTEREXTPROC GLH_EXT_NAME(glVertexWeightPointerEXT) GLH_INITIALIZER;
-#endif
-
-#ifdef GL_NV_blend_square
-#endif
-
-#ifdef GL_NV_evaluators
-    GLH_EXTERN PFNGLMAPCONTROLPOINTSNVPROC GLH_EXT_NAME(glMapControlPointsNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMAPPARAMETERIVNVPROC GLH_EXT_NAME(glMapParameterivNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMAPPARAMETERFVNVPROC GLH_EXT_NAME(glMapParameterfvNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETMAPCONTROLPOINTSNVPROC GLH_EXT_NAME(glGetMapControlPointsNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETMAPPARAMETERIVNVPROC GLH_EXT_NAME(glGetMapParameterivNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETMAPPARAMETERFVNVPROC GLH_EXT_NAME(glGetMapParameterfvNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETMAPATTRIBPARAMETERIVNVPROC GLH_EXT_NAME(glGetMapAttribParameterivNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETMAPATTRIBPARAMETERFVNVPROC GLH_EXT_NAME(glGetMapAttribParameterfvNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLEVALMAPSNVPROC GLH_EXT_NAME(glEvalMapsNV) GLH_INITIALIZER;
-#endif
-
-#ifdef GL_NV_fence
-    GLH_EXTERN PFNGLGENFENCESNVPROC GLH_EXT_NAME(glGenFencesNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLDELETEFENCESNVPROC GLH_EXT_NAME(glDeleteFencesNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLSETFENCENVPROC GLH_EXT_NAME(glSetFenceNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLTESTFENCENVPROC GLH_EXT_NAME(glTestFenceNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLFINISHFENCENVPROC GLH_EXT_NAME(glFinishFenceNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLISFENCENVPROC GLH_EXT_NAME(glIsFenceNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETFENCEIVNVPROC GLH_EXT_NAME(glGetFenceivNV) GLH_INITIALIZER;
-#endif
-
-#ifdef GL_NV_fog_distance
-#endif
-
-#ifdef GL_NV_packed_depth_stencil
-#endif
-
-#ifdef GL_NV_register_combiners
-    GLH_EXTERN PFNGLCOMBINERPARAMETERFVNVPROC GLH_EXT_NAME(glCombinerParameterfvNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLCOMBINERPARAMETERFNVPROC GLH_EXT_NAME(glCombinerParameterfNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLCOMBINERPARAMETERIVNVPROC GLH_EXT_NAME(glCombinerParameterivNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLCOMBINERPARAMETERINVPROC GLH_EXT_NAME(glCombinerParameteriNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLCOMBINERINPUTNVPROC GLH_EXT_NAME(glCombinerInputNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLCOMBINEROUTPUTNVPROC GLH_EXT_NAME(glCombinerOutputNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLFINALCOMBINERINPUTNVPROC GLH_EXT_NAME(glFinalCombinerInputNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETCOMBINERINPUTPARAMETERFVNVPROC GLH_EXT_NAME(glGetCombinerInputParameterfvNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETCOMBINERINPUTPARAMETERIVNVPROC GLH_EXT_NAME(glGetCombinerInputParameterivNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETCOMBINEROUTPUTPARAMETERFVNVPROC GLH_EXT_NAME(glGetCombinerOutputParameterfvNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETCOMBINEROUTPUTPARAMETERIVNVPROC GLH_EXT_NAME(glGetCombinerOutputParameterivNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETFINALCOMBINERINPUTPARAMETERFVNVPROC GLH_EXT_NAME(glGetFinalCombinerInputParameterfvNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETFINALCOMBINERINPUTPARAMETERIVNVPROC GLH_EXT_NAME(glGetFinalCombinerInputParameterivNV) GLH_INITIALIZER;
-#endif
-
-#ifdef GL_NV_register_combiners2
-    GLH_EXTERN PFNGLCOMBINERSTAGEPARAMETERFVNVPROC GLH_EXT_NAME(glCombinerStageParameterfvNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETCOMBINERSTAGEPARAMETERFVNVPROC GLH_EXT_NAME(glGetCombinerStageParameterfvNV) GLH_INITIALIZER;
-#endif
-
-#ifdef GL_NV_texgen_reflection
-#endif
-
-#ifdef GL_NV_texture_env_combine4
-#endif
-
-#ifdef GL_NV_texture_rectangle
-#endif
-
-#ifdef GL_NV_texture_shader
-#endif
-
-#ifdef GL_NV_vertex_array_range
-    GLH_EXTERN PFNGLFLUSHVERTEXARRAYRANGENVPROC GLH_EXT_NAME(glFlushVertexArrayRangeNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXARRAYRANGENVPROC GLH_EXT_NAME(glVertexArrayRangeNV) GLH_INITIALIZER;
-# ifdef _WIN32
-    GLH_EXTERN PFNWGLALLOCATEMEMORYNVPROC GLH_EXT_NAME(wglAllocateMemoryNV) GLH_INITIALIZER;
-# endif
-# ifdef GLX_VERSION_1_3
-    GLH_EXTERN PFNGLXALLOCATEMEMORYNVPROC GLH_EXT_NAME(glXAllocateMemoryNV) GLH_INITIALIZER;
-# endif
-# ifdef _WIN32
-    GLH_EXTERN PFNWGLFREEMEMORYNVPROC GLH_EXT_NAME(wglFreeMemoryNV) GLH_INITIALIZER;
-# endif
-# ifdef GLX_VERSION_1_3
-    GLH_EXTERN PFNGLXFREEMEMORYNVPROC GLH_EXT_NAME(glXFreeMemoryNV) GLH_INITIALIZER;
-# endif
-#endif
-
-#ifdef GL_NV_vertex_program
-    GLH_EXTERN PFNGLAREPROGRAMSRESIDENTNVPROC GLH_EXT_NAME(glAreProgramsResidentNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLBINDPROGRAMNVPROC GLH_EXT_NAME(glBindProgramNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLDELETEPROGRAMSNVPROC GLH_EXT_NAME(glDeleteProgramsNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLEXECUTEPROGRAMNVPROC GLH_EXT_NAME(glExecuteProgramNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGENPROGRAMSNVPROC GLH_EXT_NAME(glGenProgramsNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETPROGRAMPARAMETERDVNVPROC GLH_EXT_NAME(glGetProgramParameterdvNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETPROGRAMPARAMETERFVNVPROC GLH_EXT_NAME(glGetProgramParameterfvNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETPROGRAMIVNVPROC GLH_EXT_NAME(glGetProgramivNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETPROGRAMSTRINGNVPROC GLH_EXT_NAME(glGetProgramStringNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETTRACKMATRIXIVNVPROC GLH_EXT_NAME(glGetTrackMatrixivNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETVERTEXATTRIBDVNVPROC GLH_EXT_NAME(glGetVertexAttribdvNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETVERTEXATTRIBFVNVPROC GLH_EXT_NAME(glGetVertexAttribfvNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETVERTEXATTRIBIVNVPROC GLH_EXT_NAME(glGetVertexAttribivNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETVERTEXATTRIBPOINTERVNVPROC GLH_EXT_NAME(glGetVertexAttribPointervNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLISPROGRAMNVPROC GLH_EXT_NAME(glIsProgramNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLLOADPROGRAMNVPROC GLH_EXT_NAME(glLoadProgramNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLPROGRAMPARAMETER4DNVPROC GLH_EXT_NAME(glProgramParameter4dNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLPROGRAMPARAMETER4DVNVPROC GLH_EXT_NAME(glProgramParameter4dvNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLPROGRAMPARAMETER4FNVPROC GLH_EXT_NAME(glProgramParameter4fNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLPROGRAMPARAMETER4FVNVPROC GLH_EXT_NAME(glProgramParameter4fvNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLPROGRAMPARAMETERS4DVNVPROC GLH_EXT_NAME(glProgramParameters4dvNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLPROGRAMPARAMETERS4FVNVPROC GLH_EXT_NAME(glProgramParameters4fvNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLREQUESTRESIDENTPROGRAMSNVPROC GLH_EXT_NAME(glRequestResidentProgramsNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLTRACKMATRIXNVPROC GLH_EXT_NAME(glTrackMatrixNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIBPOINTERNVPROC GLH_EXT_NAME(glVertexAttribPointerNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB1DNVPROC GLH_EXT_NAME(glVertexAttrib1dNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB1DVNVPROC GLH_EXT_NAME(glVertexAttrib1dvNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB1FNVPROC GLH_EXT_NAME(glVertexAttrib1fNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB1FVNVPROC GLH_EXT_NAME(glVertexAttrib1fvNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB1SNVPROC GLH_EXT_NAME(glVertexAttrib1sNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB1SVNVPROC GLH_EXT_NAME(glVertexAttrib1svNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB2DNVPROC GLH_EXT_NAME(glVertexAttrib2dNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB2DVNVPROC GLH_EXT_NAME(glVertexAttrib2dvNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB2FNVPROC GLH_EXT_NAME(glVertexAttrib2fNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB2FVNVPROC GLH_EXT_NAME(glVertexAttrib2fvNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB2SNVPROC GLH_EXT_NAME(glVertexAttrib2sNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB2SVNVPROC GLH_EXT_NAME(glVertexAttrib2svNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB3DNVPROC GLH_EXT_NAME(glVertexAttrib3dNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB3DVNVPROC GLH_EXT_NAME(glVertexAttrib3dvNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB3FNVPROC GLH_EXT_NAME(glVertexAttrib3fNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB3FVNVPROC GLH_EXT_NAME(glVertexAttrib3fvNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB3SNVPROC GLH_EXT_NAME(glVertexAttrib3sNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB3SVNVPROC GLH_EXT_NAME(glVertexAttrib3svNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB4DNVPROC GLH_EXT_NAME(glVertexAttrib4dNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB4DVNVPROC GLH_EXT_NAME(glVertexAttrib4dvNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB4FNVPROC GLH_EXT_NAME(glVertexAttrib4fNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB4FVNVPROC GLH_EXT_NAME(glVertexAttrib4fvNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB4SNVPROC GLH_EXT_NAME(glVertexAttrib4sNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB4SVNVPROC GLH_EXT_NAME(glVertexAttrib4svNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB4UBVNVPROC GLH_EXT_NAME(glVertexAttrib4ubvNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIBS1DVNVPROC GLH_EXT_NAME(glVertexAttribs1dvNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIBS1FVNVPROC GLH_EXT_NAME(glVertexAttribs1fvNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIBS1SVNVPROC GLH_EXT_NAME(glVertexAttribs1svNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIBS2DVNVPROC GLH_EXT_NAME(glVertexAttribs2dvNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIBS2FVNVPROC GLH_EXT_NAME(glVertexAttribs2fvNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIBS2SVNVPROC GLH_EXT_NAME(glVertexAttribs2svNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIBS3DVNVPROC GLH_EXT_NAME(glVertexAttribs3dvNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIBS3FVNVPROC GLH_EXT_NAME(glVertexAttribs3fvNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIBS3SVNVPROC GLH_EXT_NAME(glVertexAttribs3svNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIBS4DVNVPROC GLH_EXT_NAME(glVertexAttribs4dvNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIBS4FVNVPROC GLH_EXT_NAME(glVertexAttribs4fvNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIBS4SVNVPROC GLH_EXT_NAME(glVertexAttribs4svNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIBS4UBVNVPROC GLH_EXT_NAME(glVertexAttribs4ubvNV) GLH_INITIALIZER;
-#endif
-
-#ifdef GL_SGIS_generate_mipmap
-#endif
-
-#ifdef GL_SGIS_texture_lod
-#endif
-
-#ifdef GL_SGIX_depth_texture
-#endif
-
-#ifdef GL_SGIX_shadow
-#endif
-
-#ifdef GL_VERSION_1_2
-    /* These routines are prefixed by the preprocessor constant
-       GLH_CORE_1_2_PREFIX to avoid colliding with the OpenGL 1.2 namespace. */
-    GLH_EXTERN PFNGLBLENDCOLORPROC GLH_CORE_1_2_NAME(glBlendColor) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLBLENDEQUATIONPROC GLH_CORE_1_2_NAME(glBlendEquation) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLDRAWRANGEELEMENTSPROC GLH_CORE_1_2_NAME(glDrawRangeElements) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLCOLORTABLEPROC GLH_CORE_1_2_NAME(glColorTable) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLCOLORTABLEPARAMETERFVPROC GLH_CORE_1_2_NAME(glColorTableParameterfv) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLCOLORTABLEPARAMETERIVPROC GLH_CORE_1_2_NAME(glColorTableParameteriv) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLCOPYCOLORTABLEPROC GLH_CORE_1_2_NAME(glCopyColorTable) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETCOLORTABLEPROC GLH_CORE_1_2_NAME(glGetColorTable) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETCOLORTABLEPARAMETERFVPROC GLH_CORE_1_2_NAME(glGetColorTableParameterfv) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETCOLORTABLEPARAMETERIVPROC GLH_CORE_1_2_NAME(glGetColorTableParameteriv) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLTEXIMAGE3DPROC GLH_CORE_1_2_NAME(glTexImage3D) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLTEXSUBIMAGE3DPROC GLH_CORE_1_2_NAME(glTexSubImage3D) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLCOPYTEXSUBIMAGE3DPROC GLH_CORE_1_2_NAME(glCopyTexSubImage3D) GLH_INITIALIZER;
-#endif
-
-#ifdef GL_WIN_swap_hint
-    GLH_EXTERN PFNGLADDSWAPHINTRECTWINPROC GLH_EXT_NAME(glAddSwapHintRectWIN) GLH_INITIALIZER;
-#endif
-
-#ifdef WGL_ARB_pbuffer
-# ifdef _WIN32
-    GLH_EXTERN PFNWGLCREATEPBUFFERARBPROC GLH_EXT_NAME(wglCreatePbufferARB) GLH_INITIALIZER;
-# endif
-# ifdef _WIN32
-    GLH_EXTERN PFNWGLGETPBUFFERDCARBPROC GLH_EXT_NAME(wglGetPbufferDCARB) GLH_INITIALIZER;
-# endif
-# ifdef _WIN32
-    GLH_EXTERN PFNWGLRELEASEPBUFFERDCARBPROC GLH_EXT_NAME(wglReleasePbufferDCARB) GLH_INITIALIZER;
-# endif
-# ifdef _WIN32
-    GLH_EXTERN PFNWGLDESTROYPBUFFERARBPROC GLH_EXT_NAME(wglDestroyPbufferARB) GLH_INITIALIZER;
-# endif
-# ifdef _WIN32
-    GLH_EXTERN PFNWGLQUERYPBUFFERARBPROC GLH_EXT_NAME(wglQueryPbufferARB) GLH_INITIALIZER;
-# endif
-#endif
-
-#ifdef WGL_ARB_render_texture
-# ifdef _WIN32
-    GLH_EXTERN PFNWGLBINDTEXIMAGEARBPROC GLH_EXT_NAME(wglBindTexImageARB) GLH_INITIALIZER;
-# endif
-# ifdef _WIN32
-    GLH_EXTERN PFNWGLRELEASETEXIMAGEARBPROC GLH_EXT_NAME(wglReleaseTexImageARB) GLH_INITIALIZER;
-# endif
-# ifdef _WIN32
-    GLH_EXTERN PFNWGLSETPBUFFERATTRIBARBPROC GLH_EXT_NAME(wglSetPbufferAttribARB) GLH_INITIALIZER;
-# endif
-#endif
-
-#ifdef WGL_ARB_pixel_format
-# ifdef _WIN32
-    GLH_EXTERN PFNWGLGETPIXELFORMATATTRIBIVARBPROC GLH_EXT_NAME(wglGetPixelFormatAttribivARB) GLH_INITIALIZER;
-# endif
-# ifdef _WIN32
-    GLH_EXTERN PFNWGLGETPIXELFORMATATTRIBFVARBPROC GLH_EXT_NAME(wglGetPixelFormatAttribfvARB) GLH_INITIALIZER;
-# endif
-# ifdef _WIN32
-    GLH_EXTERN PFNWGLCHOOSEPIXELFORMATARBPROC GLH_EXT_NAME(wglChoosePixelFormatARB) GLH_INITIALIZER;
-# endif
-#endif
-
-
-#ifdef GLH_EXT_SINGLE_FILE
-
-int glh_init_extension(const char* extension)
-{
-    if (NULL == extension) {
-        return FALSE;
-#ifdef GL_ARB_multitexture
-    } else if (0 == strcmp(extension, "GL_ARB_multitexture")) {
-        GLH_EXT_NAME(glMultiTexCoord1dARB) = (PFNGLMULTITEXCOORD1DARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord1dARB");
-        if (NULL == GLH_EXT_NAME(glMultiTexCoord1dARB))
-            return FALSE;
-        GLH_EXT_NAME(glMultiTexCoord1dvARB) = (PFNGLMULTITEXCOORD1DVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord1dvARB");
-        if (NULL == GLH_EXT_NAME(glMultiTexCoord1dvARB))
-            return FALSE;
-        GLH_EXT_NAME(glMultiTexCoord1fARB) = (PFNGLMULTITEXCOORD1FARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord1fARB");
-        if (NULL == GLH_EXT_NAME(glMultiTexCoord1fARB))
-            return FALSE;
-        GLH_EXT_NAME(glMultiTexCoord1fvARB) = (PFNGLMULTITEXCOORD1FVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord1fvARB");
-        if (NULL == GLH_EXT_NAME(glMultiTexCoord1fvARB))
-            return FALSE;
-        GLH_EXT_NAME(glMultiTexCoord1iARB) = (PFNGLMULTITEXCOORD1IARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord1iARB");
-        if (NULL == GLH_EXT_NAME(glMultiTexCoord1iARB))
-            return FALSE;
-        GLH_EXT_NAME(glMultiTexCoord1ivARB) = (PFNGLMULTITEXCOORD1IVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord1ivARB");
-        if (NULL == GLH_EXT_NAME(glMultiTexCoord1ivARB))
-            return FALSE;
-        GLH_EXT_NAME(glMultiTexCoord1sARB) = (PFNGLMULTITEXCOORD1SARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord1sARB");
-        if (NULL == GLH_EXT_NAME(glMultiTexCoord1sARB))
-            return FALSE;
-        GLH_EXT_NAME(glMultiTexCoord1svARB) = (PFNGLMULTITEXCOORD1SVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord1svARB");
-        if (NULL == GLH_EXT_NAME(glMultiTexCoord1svARB))
-            return FALSE;
-        GLH_EXT_NAME(glMultiTexCoord2dARB) = (PFNGLMULTITEXCOORD2DARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord2dARB");
-        if (NULL == GLH_EXT_NAME(glMultiTexCoord2dARB))
-            return FALSE;
-        GLH_EXT_NAME(glMultiTexCoord2dvARB) = (PFNGLMULTITEXCOORD2DVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord2dvARB");
-        if (NULL == GLH_EXT_NAME(glMultiTexCoord2dvARB))
-            return FALSE;
-        GLH_EXT_NAME(glMultiTexCoord2fARB) = (PFNGLMULTITEXCOORD2FARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord2fARB");
-        if (NULL == GLH_EXT_NAME(glMultiTexCoord2fARB))
-            return FALSE;
-        GLH_EXT_NAME(glMultiTexCoord2fvARB) = (PFNGLMULTITEXCOORD2FVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord2fvARB");
-        if (NULL == GLH_EXT_NAME(glMultiTexCoord2fvARB))
-            return FALSE;
-        GLH_EXT_NAME(glMultiTexCoord2iARB) = (PFNGLMULTITEXCOORD2IARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord2iARB");
-        if (NULL == GLH_EXT_NAME(glMultiTexCoord2iARB))
-            return FALSE;
-        GLH_EXT_NAME(glMultiTexCoord2ivARB) = (PFNGLMULTITEXCOORD2IVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord2ivARB");
-        if (NULL == GLH_EXT_NAME(glMultiTexCoord2ivARB))
-            return FALSE;
-        GLH_EXT_NAME(glMultiTexCoord2sARB) = (PFNGLMULTITEXCOORD2SARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord2sARB");
-        if (NULL == GLH_EXT_NAME(glMultiTexCoord2sARB))
-            return FALSE;
-        GLH_EXT_NAME(glMultiTexCoord2svARB) = (PFNGLMULTITEXCOORD2SVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord2svARB");
-        if (NULL == GLH_EXT_NAME(glMultiTexCoord2svARB))
-            return FALSE;
-        GLH_EXT_NAME(glMultiTexCoord3dARB) = (PFNGLMULTITEXCOORD3DARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord3dARB");
-        if (NULL == GLH_EXT_NAME(glMultiTexCoord3dARB))
-            return FALSE;
-        GLH_EXT_NAME(glMultiTexCoord3dvARB) = (PFNGLMULTITEXCOORD3DVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord3dvARB");
-        if (NULL == GLH_EXT_NAME(glMultiTexCoord3dvARB))
-            return FALSE;
-        GLH_EXT_NAME(glMultiTexCoord3fARB) = (PFNGLMULTITEXCOORD3FARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord3fARB");
-        if (NULL == GLH_EXT_NAME(glMultiTexCoord3fARB))
-            return FALSE;
-        GLH_EXT_NAME(glMultiTexCoord3fvARB) = (PFNGLMULTITEXCOORD3FVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord3fvARB");
-        if (NULL == GLH_EXT_NAME(glMultiTexCoord3fvARB))
-            return FALSE;
-        GLH_EXT_NAME(glMultiTexCoord3iARB) = (PFNGLMULTITEXCOORD3IARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord3iARB");
-        if (NULL == GLH_EXT_NAME(glMultiTexCoord3iARB))
-            return FALSE;
-        GLH_EXT_NAME(glMultiTexCoord3ivARB) = (PFNGLMULTITEXCOORD3IVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord3ivARB");
-        if (NULL == GLH_EXT_NAME(glMultiTexCoord3ivARB))
-            return FALSE;
-        GLH_EXT_NAME(glMultiTexCoord3sARB) = (PFNGLMULTITEXCOORD3SARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord3sARB");
-        if (NULL == GLH_EXT_NAME(glMultiTexCoord3sARB))
-            return FALSE;
-        GLH_EXT_NAME(glMultiTexCoord3svARB) = (PFNGLMULTITEXCOORD3SVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord3svARB");
-        if (NULL == GLH_EXT_NAME(glMultiTexCoord3svARB))
-            return FALSE;
-        GLH_EXT_NAME(glMultiTexCoord4dARB) = (PFNGLMULTITEXCOORD4DARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord4dARB");
-        if (NULL == GLH_EXT_NAME(glMultiTexCoord4dARB))
-            return FALSE;
-        GLH_EXT_NAME(glMultiTexCoord4dvARB) = (PFNGLMULTITEXCOORD4DVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord4dvARB");
-        if (NULL == GLH_EXT_NAME(glMultiTexCoord4dvARB))
-            return FALSE;
-        GLH_EXT_NAME(glMultiTexCoord4fARB) = (PFNGLMULTITEXCOORD4FARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord4fARB");
-        if (NULL == GLH_EXT_NAME(glMultiTexCoord4fARB))
-            return FALSE;
-        GLH_EXT_NAME(glMultiTexCoord4fvARB) = (PFNGLMULTITEXCOORD4FVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord4fvARB");
-        if (NULL == GLH_EXT_NAME(glMultiTexCoord4fvARB))
-            return FALSE;
-        GLH_EXT_NAME(glMultiTexCoord4iARB) = (PFNGLMULTITEXCOORD4IARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord4iARB");
-        if (NULL == GLH_EXT_NAME(glMultiTexCoord4iARB))
-            return FALSE;
-        GLH_EXT_NAME(glMultiTexCoord4ivARB) = (PFNGLMULTITEXCOORD4IVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord4ivARB");
-        if (NULL == GLH_EXT_NAME(glMultiTexCoord4ivARB))
-            return FALSE;
-        GLH_EXT_NAME(glMultiTexCoord4sARB) = (PFNGLMULTITEXCOORD4SARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord4sARB");
-        if (NULL == GLH_EXT_NAME(glMultiTexCoord4sARB))
-            return FALSE;
-        GLH_EXT_NAME(glMultiTexCoord4svARB) = (PFNGLMULTITEXCOORD4SVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord4svARB");
-        if (NULL == GLH_EXT_NAME(glMultiTexCoord4svARB))
-            return FALSE;
-        GLH_EXT_NAME(glActiveTextureARB) = (PFNGLACTIVETEXTUREARBPROC)GLH_EXT_GET_PROC_ADDRESS("glActiveTextureARB");
-        if (NULL == GLH_EXT_NAME(glActiveTextureARB))
-            return FALSE;
-        GLH_EXT_NAME(glClientActiveTextureARB) = (PFNGLCLIENTACTIVETEXTUREARBPROC)GLH_EXT_GET_PROC_ADDRESS("glClientActiveTextureARB");
-        if (NULL == GLH_EXT_NAME(glClientActiveTextureARB))
-            return FALSE;
-#endif
-
-#ifdef GL_ARB_texture_border_clamp
-    } else if (0 == strcmp(extension, "GL_ARB_texture_border_clamp")) {
-#endif
-
-#ifdef GL_ARB_texture_compression
-    } else if (0 == strcmp(extension, "GL_ARB_texture_compression")) {
-        GLH_EXT_NAME(glCompressedTexImage3DARB) = (PFNGLCOMPRESSEDTEXIMAGE3DARBPROC)GLH_EXT_GET_PROC_ADDRESS("glCompressedTexImage3DARB");
-        if (NULL == GLH_EXT_NAME(glCompressedTexImage3DARB))
-            return FALSE;
-        GLH_EXT_NAME(glCompressedTexImage2DARB) = (PFNGLCOMPRESSEDTEXIMAGE2DARBPROC)GLH_EXT_GET_PROC_ADDRESS("glCompressedTexImage2DARB");
-        if (NULL == GLH_EXT_NAME(glCompressedTexImage2DARB))
-            return FALSE;
-        GLH_EXT_NAME(glCompressedTexImage1DARB) = (PFNGLCOMPRESSEDTEXIMAGE1DARBPROC)GLH_EXT_GET_PROC_ADDRESS("glCompressedTexImage1DARB");
-        if (NULL == GLH_EXT_NAME(glCompressedTexImage1DARB))
-            return FALSE;
-        GLH_EXT_NAME(glCompressedTexSubImage3DARB) = (PFNGLCOMPRESSEDTEXSUBIMAGE3DARBPROC)GLH_EXT_GET_PROC_ADDRESS("glCompressedTexSubImage3DARB");
-        if (NULL == GLH_EXT_NAME(glCompressedTexSubImage3DARB))
-            return FALSE;
-        GLH_EXT_NAME(glCompressedTexSubImage2DARB) = (PFNGLCOMPRESSEDTEXSUBIMAGE2DARBPROC)GLH_EXT_GET_PROC_ADDRESS("glCompressedTexSubImage2DARB");
-        if (NULL == GLH_EXT_NAME(glCompressedTexSubImage2DARB))
-            return FALSE;
-        GLH_EXT_NAME(glCompressedTexSubImage1DARB) = (PFNGLCOMPRESSEDTEXSUBIMAGE1DARBPROC)GLH_EXT_GET_PROC_ADDRESS("glCompressedTexSubImage1DARB");
-        if (NULL == GLH_EXT_NAME(glCompressedTexSubImage1DARB))
-            return FALSE;
-        GLH_EXT_NAME(glGetCompressedTexImageARB) = (PFNGLGETCOMPRESSEDTEXIMAGEARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGetCompressedTexImageARB");
-        if (NULL == GLH_EXT_NAME(glGetCompressedTexImageARB))
-            return FALSE;
-#endif
-
-#ifdef GL_ARB_texture_cube_map
-    } else if (0 == strcmp(extension, "GL_ARB_texture_cube_map")) {
-#endif
-
-#ifdef GL_ARB_transpose_matrix
-    } else if (0 == strcmp(extension, "GL_ARB_transpose_matrix")) {
-        GLH_EXT_NAME(glLoadTransposeMatrixfARB) = (PFNGLLOADTRANSPOSEMATRIXFARBPROC)GLH_EXT_GET_PROC_ADDRESS("glLoadTransposeMatrixfARB");
-        if (NULL == GLH_EXT_NAME(glLoadTransposeMatrixfARB))
-            return FALSE;
-        GLH_EXT_NAME(glLoadTransposeMatrixdARB) = (PFNGLLOADTRANSPOSEMATRIXDARBPROC)GLH_EXT_GET_PROC_ADDRESS("glLoadTransposeMatrixdARB");
-        if (NULL == GLH_EXT_NAME(glLoadTransposeMatrixdARB))
-            return FALSE;
-        GLH_EXT_NAME(glMultTransposeMatrixfARB) = (PFNGLMULTTRANSPOSEMATRIXFARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultTransposeMatrixfARB");
-        if (NULL == GLH_EXT_NAME(glMultTransposeMatrixfARB))
-            return FALSE;
-        GLH_EXT_NAME(glMultTransposeMatrixdARB) = (PFNGLMULTTRANSPOSEMATRIXDARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultTransposeMatrixdARB");
-        if (NULL == GLH_EXT_NAME(glMultTransposeMatrixdARB))
-            return FALSE;
-#endif
-
-#ifdef GL_ARB_vertex_program
-    } else if (0 == strcmp(extension, "GL_ARB_vertex_program")) {
-        GLH_EXT_NAME(glVertexAttrib1sARB) = (PFNGLVERTEXATTRIB1SARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1sARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib1sARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib1fARB) = (PFNGLVERTEXATTRIB1FARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1fARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib1fARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib1dARB) = (PFNGLVERTEXATTRIB1DARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1dARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib1dARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib2sARB) = (PFNGLVERTEXATTRIB2SARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2sARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib2sARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib2fARB) = (PFNGLVERTEXATTRIB2FARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2fARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib2fARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib2dARB) = (PFNGLVERTEXATTRIB2DARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2dARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib2dARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib3sARB) = (PFNGLVERTEXATTRIB3SARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3sARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib3sARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib3fARB) = (PFNGLVERTEXATTRIB3FARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3fARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib3fARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib3dARB) = (PFNGLVERTEXATTRIB3DARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3dARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib3dARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib4sARB) = (PFNGLVERTEXATTRIB4SARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4sARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib4sARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib4fARB) = (PFNGLVERTEXATTRIB4FARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4fARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib4fARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib4dARB) = (PFNGLVERTEXATTRIB4DARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4dARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib4dARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib4NubARB) = (PFNGLVERTEXATTRIB4NUBARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4NubARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib4NubARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib1svARB) = (PFNGLVERTEXATTRIB1SVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1svARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib1svARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib1fvARB) = (PFNGLVERTEXATTRIB1FVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1fvARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib1fvARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib1dvARB) = (PFNGLVERTEXATTRIB1DVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1dvARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib1dvARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib2svARB) = (PFNGLVERTEXATTRIB2SVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2svARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib2svARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib2fvARB) = (PFNGLVERTEXATTRIB2FVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2fvARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib2fvARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib2dvARB) = (PFNGLVERTEXATTRIB2DVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2dvARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib2dvARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib3svARB) = (PFNGLVERTEXATTRIB3SVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3svARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib3svARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib3fvARB) = (PFNGLVERTEXATTRIB3FVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3fvARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib3fvARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib3dvARB) = (PFNGLVERTEXATTRIB3DVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3dvARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib3dvARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib4bvARB) = (PFNGLVERTEXATTRIB4BVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4bvARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib4bvARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib4svARB) = (PFNGLVERTEXATTRIB4SVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4svARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib4svARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib4ivARB) = (PFNGLVERTEXATTRIB4IVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4ivARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib4ivARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib4ubvARB) = (PFNGLVERTEXATTRIB4UBVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4ubvARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib4ubvARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib4usvARB) = (PFNGLVERTEXATTRIB4USVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4usvARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib4usvARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib4uivARB) = (PFNGLVERTEXATTRIB4UIVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4uivARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib4uivARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib4fvARB) = (PFNGLVERTEXATTRIB4FVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4fvARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib4fvARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib4dvARB) = (PFNGLVERTEXATTRIB4DVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4dvARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib4dvARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib4NbvARB) = (PFNGLVERTEXATTRIB4NBVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4NbvARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib4NbvARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib4NsvARB) = (PFNGLVERTEXATTRIB4NSVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4NsvARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib4NsvARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib4NivARB) = (PFNGLVERTEXATTRIB4NIVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4NivARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib4NivARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib4NubvARB) = (PFNGLVERTEXATTRIB4NUBVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4NubvARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib4NubvARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib4NusvARB) = (PFNGLVERTEXATTRIB4NUSVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4NusvARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib4NusvARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib4NuivARB) = (PFNGLVERTEXATTRIB4NUIVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4NuivARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib4NuivARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttribPointerARB) = (PFNGLVERTEXATTRIBPOINTERARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttribPointerARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttribPointerARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glEnableVertexAttribArrayARB) = (PFNGLENABLEVERTEXATTRIBARRAYARBPROC)GLH_EXT_GET_PROC_ADDRESS("glEnableVertexAttribArrayARB");
-        if (NULL == GLH_EXT_NAME(glEnableVertexAttribArrayARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glDisableVertexAttribArrayARB) = (PFNGLDISABLEVERTEXATTRIBARRAYARBPROC)GLH_EXT_GET_PROC_ADDRESS("glDisableVertexAttribArrayARB");
-        if (NULL == GLH_EXT_NAME(glDisableVertexAttribArrayARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glProgramStringARB) = (PFNGLPROGRAMSTRINGARBPROC)GLH_EXT_GET_PROC_ADDRESS("glProgramStringARB");
-        if (NULL == GLH_EXT_NAME(glProgramStringARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glBindProgramARB) = (PFNGLBINDPROGRAMARBPROC)GLH_EXT_GET_PROC_ADDRESS("glBindProgramARB");
-        if (NULL == GLH_EXT_NAME(glBindProgramARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glDeleteProgramsARB) = (PFNGLDELETEPROGRAMSARBPROC)GLH_EXT_GET_PROC_ADDRESS("glDeleteProgramsARB");
-        if (NULL == GLH_EXT_NAME(glDeleteProgramsARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glGenProgramsARB) = (PFNGLGENPROGRAMSARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGenProgramsARB");
-        if (NULL == GLH_EXT_NAME(glGenProgramsARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glProgramEnvParameter4dARB) = (PFNGLPROGRAMENVPARAMETER4DARBPROC)GLH_EXT_GET_PROC_ADDRESS("glProgramEnvParameter4dARB");
-        if (NULL == GLH_EXT_NAME(glProgramEnvParameter4dARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glProgramEnvParameter4dvARB) = (PFNGLPROGRAMENVPARAMETER4DVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glProgramEnvParameter4dvARB");
-        if (NULL == GLH_EXT_NAME(glProgramEnvParameter4dvARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glProgramEnvParameter4fARB) = (PFNGLPROGRAMENVPARAMETER4FARBPROC)GLH_EXT_GET_PROC_ADDRESS("glProgramEnvParameter4fARB");
-        if (NULL == GLH_EXT_NAME(glProgramEnvParameter4fARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glProgramEnvParameter4fvARB) = (PFNGLPROGRAMENVPARAMETER4FVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glProgramEnvParameter4fvARB");
-        if (NULL == GLH_EXT_NAME(glProgramEnvParameter4fvARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glProgramLocalParameter4dARB) = (PFNGLPROGRAMLOCALPARAMETER4DARBPROC)GLH_EXT_GET_PROC_ADDRESS("glProgramLocalParameter4dARB");
-        if (NULL == GLH_EXT_NAME(glProgramLocalParameter4dARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glProgramLocalParameter4dvARB) = (PFNGLPROGRAMLOCALPARAMETER4DVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glProgramLocalParameter4dvARB");
-        if (NULL == GLH_EXT_NAME(glProgramLocalParameter4dvARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glProgramLocalParameter4fARB) = (PFNGLPROGRAMLOCALPARAMETER4FARBPROC)GLH_EXT_GET_PROC_ADDRESS("glProgramLocalParameter4fARB");
-        if (NULL == GLH_EXT_NAME(glProgramLocalParameter4fARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glProgramLocalParameter4fvARB) = (PFNGLPROGRAMLOCALPARAMETER4FVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glProgramLocalParameter4fvARB");
-        if (NULL == GLH_EXT_NAME(glProgramLocalParameter4fvARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glGetProgramEnvParameterdvARB) = (PFNGLGETPROGRAMENVPARAMETERDVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGetProgramEnvParameterdvARB");
-        if (NULL == GLH_EXT_NAME(glGetProgramEnvParameterdvARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glGetProgramEnvParameterfvARB) = (PFNGLGETPROGRAMENVPARAMETERFVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGetProgramEnvParameterfvARB");
-        if (NULL == GLH_EXT_NAME(glGetProgramEnvParameterfvARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glGetProgramLocalParameterdvARB) = (PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGetProgramLocalParameterdvARB");
-        if (NULL == GLH_EXT_NAME(glGetProgramLocalParameterdvARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glGetProgramLocalParameterfvARB) = (PFNGLGETPROGRAMLOCALPARAMETERFVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGetProgramLocalParameterfvARB");
-        if (NULL == GLH_EXT_NAME(glGetProgramLocalParameterfvARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glGetProgramivARB) = (PFNGLGETPROGRAMIVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGetProgramivARB");
-        if (NULL == GLH_EXT_NAME(glGetProgramivARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glGetProgramStringARB) = (PFNGLGETPROGRAMSTRINGARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGetProgramStringARB");
-        if (NULL == GLH_EXT_NAME(glGetProgramStringARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glGetVertexAttribdvARB) = (PFNGLGETVERTEXATTRIBDVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGetVertexAttribdvARB");
-        if (NULL == GLH_EXT_NAME(glGetVertexAttribdvARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glGetVertexAttribfvARB) = (PFNGLGETVERTEXATTRIBFVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGetVertexAttribfvARB");
-        if (NULL == GLH_EXT_NAME(glGetVertexAttribfvARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glGetVertexAttribivARB) = (PFNGLGETVERTEXATTRIBIVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGetVertexAttribivARB");
-        if (NULL == GLH_EXT_NAME(glGetVertexAttribivARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glGetVertexAttribPointervARB) = (PFNGLGETVERTEXATTRIBPOINTERVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGetVertexAttribPointervARB");
-        if (NULL == GLH_EXT_NAME(glGetVertexAttribPointervARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glIsProgramARB) = (PFNGLISPROGRAMARBPROC)GLH_EXT_GET_PROC_ADDRESS("glIsProgramARB");
-        if (NULL == GLH_EXT_NAME(glIsProgramARB))
-            return GL_FALSE;
-#endif
-
-#ifdef GL_EXT_abgr
-    } else if (0 == strcmp(extension, "GL_EXT_abgr")) {
-#endif
-
-#ifdef GL_EXT_bgra
-    } else if (0 == strcmp(extension, "GL_EXT_bgra")) {
-#endif
-
-#ifdef GL_EXT_blend_color
-    } else if (0 == strcmp(extension, "GL_EXT_blend_color")) {
-        GLH_EXT_NAME(glBlendColorEXT) = (PFNGLBLENDCOLOREXTPROC)GLH_EXT_GET_PROC_ADDRESS("glBlendColorEXT");
-        if (NULL == GLH_EXT_NAME(glBlendColorEXT))
-            return FALSE;
-#endif
-
-#ifdef GL_EXT_blend_minmax
-    } else if (0 == strcmp(extension, "GL_EXT_blend_minmax")) {
-        GLH_EXT_NAME(glBlendEquationEXT) = (PFNGLBLENDEQUATIONEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glBlendEquationEXT");
-        if (NULL == GLH_EXT_NAME(glBlendEquationEXT))
-            return FALSE;
-#endif
-
-#ifdef GL_EXT_blend_subtract
-    } else if (0 == strcmp(extension, "GL_EXT_blend_subtract")) {
-#endif
-
-#ifdef GL_EXT_compiled_vertex_array
-    } else if (0 == strcmp(extension, "GL_EXT_compiled_vertex_array")) {
-        GLH_EXT_NAME(glLockArraysEXT) = (PFNGLLOCKARRAYSEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glLockArraysEXT");
-        if (NULL == GLH_EXT_NAME(glLockArraysEXT))
-            return FALSE;
-        GLH_EXT_NAME(glUnlockArraysEXT) = (PFNGLUNLOCKARRAYSEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glUnlockArraysEXT");
-        if (NULL == GLH_EXT_NAME(glUnlockArraysEXT))
-            return FALSE;
-#endif
-
-#ifdef GL_EXT_fog_coord
-    } else if (0 == strcmp(extension, "GL_EXT_fog_coord")) {
-        GLH_EXT_NAME(glFogCoorddEXT) = (PFNGLFOGCOORDDEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glFogCoorddEXT");
-        if (NULL == GLH_EXT_NAME(glFogCoorddEXT))
-            return FALSE;
-        GLH_EXT_NAME(glFogCoorddvEXT) = (PFNGLFOGCOORDDVEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glFogCoorddvEXT");
-        if (NULL == GLH_EXT_NAME(glFogCoorddvEXT))
-            return FALSE;
-        GLH_EXT_NAME(glFogCoordfEXT) = (PFNGLFOGCOORDFEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glFogCoordfEXT");
-        if (NULL == GLH_EXT_NAME(glFogCoordfEXT))
-            return FALSE;
-        GLH_EXT_NAME(glFogCoordfvEXT) = (PFNGLFOGCOORDFVEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glFogCoordfvEXT");
-        if (NULL == GLH_EXT_NAME(glFogCoordfvEXT))
-            return FALSE;
-        GLH_EXT_NAME(glFogCoordPointerEXT) = (PFNGLFOGCOORDPOINTEREXTPROC)GLH_EXT_GET_PROC_ADDRESS("glFogCoordPointerEXT");
-        if (NULL == GLH_EXT_NAME(glFogCoordPointerEXT))
-            return FALSE;
-#endif
-
-#ifdef GL_EXT_light_max_exponent
-    } else if (0 == strcmp(extension, "GL_EXT_light_max_exponent")) {
-#endif
-
-#ifdef GL_EXT_packed_pixels
-    } else if (0 == strcmp(extension, "GL_EXT_packed_pixels")) {
-#endif
-
-#ifdef GL_EXT_paletted_texture
-    } else if (0 == strcmp(extension, "GL_EXT_paletted_texture")) {
-        GLH_EXT_NAME(glColorSubTableEXT) = (PFNGLCOLORSUBTABLEEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glColorSubTableEXT");
-        if (NULL == GLH_EXT_NAME(glColorSubTableEXT))
-            return FALSE;
-        GLH_EXT_NAME(glColorTableEXT) = (PFNGLCOLORTABLEEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glColorTableEXT");
-        if (NULL == GLH_EXT_NAME(glColorTableEXT))
-            return FALSE;
-        GLH_EXT_NAME(glGetColorTableEXT) = (PFNGLGETCOLORTABLEEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glGetColorTableEXT");
-        if (NULL == GLH_EXT_NAME(glGetColorTableEXT))
-            return FALSE;
-        GLH_EXT_NAME(glGetColorTableParameterfvEXT) = (PFNGLGETCOLORTABLEPARAMETERFVEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glGetColorTableParameterfvEXT");
-        if (NULL == GLH_EXT_NAME(glGetColorTableParameterfvEXT))
-            return FALSE;
-        GLH_EXT_NAME(glGetColorTableParameterivEXT) = (PFNGLGETCOLORTABLEPARAMETERIVEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glGetColorTableParameterivEXT");
-        if (NULL == GLH_EXT_NAME(glGetColorTableParameterivEXT))
-            return FALSE;
-#endif
-
-#ifdef GL_EXT_point_parameters
-    } else if (0 == strcmp(extension, "GL_EXT_point_parameters")) {
-        GLH_EXT_NAME(glPointParameterfEXT) = (PFNGLPOINTPARAMETERFEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glPointParameterfEXT");
-        if (NULL == GLH_EXT_NAME(glPointParameterfEXT))
-            return FALSE;
-        GLH_EXT_NAME(glPointParameterfvEXT) = (PFNGLPOINTPARAMETERFVEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glPointParameterfvEXT");
-        if (NULL == GLH_EXT_NAME(glPointParameterfvEXT))
-            return FALSE;
-#endif
-
-#ifdef GL_EXT_rescale_normal
-    } else if (0 == strcmp(extension, "GL_EXT_rescale_normal")) {
-#endif
-
-#ifdef GL_EXT_secondary_color
-    } else if (0 == strcmp(extension, "GL_EXT_secondary_color")) {
-        GLH_EXT_NAME(glSecondaryColor3bEXT) = (PFNGLSECONDARYCOLOR3BEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glSecondaryColor3bEXT");
-        if (NULL == GLH_EXT_NAME(glSecondaryColor3bEXT))
-            return FALSE;
-        GLH_EXT_NAME(glSecondaryColor3bvEXT) = (PFNGLSECONDARYCOLOR3BVEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glSecondaryColor3bvEXT");
-        if (NULL == GLH_EXT_NAME(glSecondaryColor3bvEXT))
-            return FALSE;
-        GLH_EXT_NAME(glSecondaryColor3dEXT) = (PFNGLSECONDARYCOLOR3DEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glSecondaryColor3dEXT");
-        if (NULL == GLH_EXT_NAME(glSecondaryColor3dEXT))
-            return FALSE;
-        GLH_EXT_NAME(glSecondaryColor3dvEXT) = (PFNGLSECONDARYCOLOR3DVEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glSecondaryColor3dvEXT");
-        if (NULL == GLH_EXT_NAME(glSecondaryColor3dvEXT))
-            return FALSE;
-        GLH_EXT_NAME(glSecondaryColor3fEXT) = (PFNGLSECONDARYCOLOR3FEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glSecondaryColor3fEXT");
-        if (NULL == GLH_EXT_NAME(glSecondaryColor3fEXT))
-            return FALSE;
-        GLH_EXT_NAME(glSecondaryColor3fvEXT) = (PFNGLSECONDARYCOLOR3FVEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glSecondaryColor3fvEXT");
-        if (NULL == GLH_EXT_NAME(glSecondaryColor3fvEXT))
-            return FALSE;
-        GLH_EXT_NAME(glSecondaryColor3iEXT) = (PFNGLSECONDARYCOLOR3IEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glSecondaryColor3iEXT");
-        if (NULL == GLH_EXT_NAME(glSecondaryColor3iEXT))
-            return FALSE;
-        GLH_EXT_NAME(glSecondaryColor3ivEXT) = (PFNGLSECONDARYCOLOR3IVEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glSecondaryColor3ivEXT");
-        if (NULL == GLH_EXT_NAME(glSecondaryColor3ivEXT))
-            return FALSE;
-        GLH_EXT_NAME(glSecondaryColor3sEXT) = (PFNGLSECONDARYCOLOR3SEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glSecondaryColor3sEXT");
-        if (NULL == GLH_EXT_NAME(glSecondaryColor3sEXT))
-            return FALSE;
-        GLH_EXT_NAME(glSecondaryColor3svEXT) = (PFNGLSECONDARYCOLOR3SVEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glSecondaryColor3svEXT");
-        if (NULL == GLH_EXT_NAME(glSecondaryColor3svEXT))
-            return FALSE;
-        GLH_EXT_NAME(glSecondaryColor3ubEXT) = (PFNGLSECONDARYCOLOR3UBEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glSecondaryColor3ubEXT");
-        if (NULL == GLH_EXT_NAME(glSecondaryColor3ubEXT))
-            return FALSE;
-        GLH_EXT_NAME(glSecondaryColor3ubvEXT) = (PFNGLSECONDARYCOLOR3UBVEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glSecondaryColor3ubvEXT");
-        if (NULL == GLH_EXT_NAME(glSecondaryColor3ubvEXT))
-            return FALSE;
-        GLH_EXT_NAME(glSecondaryColor3uiEXT) = (PFNGLSECONDARYCOLOR3UIEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glSecondaryColor3uiEXT");
-        if (NULL == GLH_EXT_NAME(glSecondaryColor3uiEXT))
-            return FALSE;
-        GLH_EXT_NAME(glSecondaryColor3uivEXT) = (PFNGLSECONDARYCOLOR3UIVEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glSecondaryColor3uivEXT");
-        if (NULL == GLH_EXT_NAME(glSecondaryColor3uivEXT))
-            return FALSE;
-        GLH_EXT_NAME(glSecondaryColor3usEXT) = (PFNGLSECONDARYCOLOR3USEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glSecondaryColor3usEXT");
-        if (NULL == GLH_EXT_NAME(glSecondaryColor3usEXT))
-            return FALSE;
-        GLH_EXT_NAME(glSecondaryColor3usvEXT) = (PFNGLSECONDARYCOLOR3USVEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glSecondaryColor3usvEXT");
-        if (NULL == GLH_EXT_NAME(glSecondaryColor3usvEXT))
-            return FALSE;
-        GLH_EXT_NAME(glSecondaryColorPointerEXT) = (PFNGLSECONDARYCOLORPOINTEREXTPROC)GLH_EXT_GET_PROC_ADDRESS("glSecondaryColorPointerEXT");
-        if (NULL == GLH_EXT_NAME(glSecondaryColorPointerEXT))
-            return FALSE;
-#endif
-
-#ifdef GL_EXT_separate_specular_color
-    } else if (0 == strcmp(extension, "GL_EXT_separate_specular_color")) {
-#endif
-
-#ifdef GL_EXT_shared_texture_palette
-    } else if (0 == strcmp(extension, "GL_EXT_shared_texture_palette")) {
-#endif
-
-#ifdef GL_EXT_stencil_wrap
-    } else if (0 == strcmp(extension, "GL_EXT_stencil_wrap")) {
-#endif
-
-#ifdef GL_EXT_texture_compression_s3tc
-    } else if (0 == strcmp(extension, "GL_EXT_texture_compression_s3tc")) {
-#endif
-
-#ifdef GL_EXT_texture_cube_map
-    } else if (0 == strcmp(extension, "GL_EXT_texture_cube_map")) {
-#endif
-
-#ifdef GL_EXT_texture_edge_clamp
-    } else if (0 == strcmp(extension, "GL_EXT_texture_edge_clamp")) {
-#endif
-
-#ifdef GL_EXT_texture_env_add
-    } else if (0 == strcmp(extension, "GL_EXT_texture_env_add")) {
-#endif
-
-#ifdef GL_EXT_texture_env_combine
-    } else if (0 == strcmp(extension, "GL_EXT_texture_env_combine")) {
-#endif
-
-#ifdef GL_EXT_texture_filter_anisotropic
-    } else if (0 == strcmp(extension, "GL_EXT_texture_filter_anisotropic")) {
-#endif
-
-#ifdef GL_EXT_texture_lod_bias
-    } else if (0 == strcmp(extension, "GL_EXT_texture_lod_bias")) {
-#endif
-
-#ifdef GL_EXT_texture_object
-    } else if (0 == strcmp(extension, "GL_EXT_texture_object")) {
-        GLH_EXT_NAME(glAreTexturesResidentEXT) = (PFNGLARETEXTURESRESIDENTEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glAreTexturesResidentEXT");
-        if (NULL == GLH_EXT_NAME(glAreTexturesResidentEXT))
-            return FALSE;
-        GLH_EXT_NAME(glBindTextureEXT) = (PFNGLBINDTEXTUREEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glBindTextureEXT");
-        if (NULL == GLH_EXT_NAME(glBindTextureEXT))
-            return FALSE;
-        GLH_EXT_NAME(glDeleteTexturesEXT) = (PFNGLDELETETEXTURESEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glDeleteTexturesEXT");
-        if (NULL == GLH_EXT_NAME(glDeleteTexturesEXT))
-            return FALSE;
-        GLH_EXT_NAME(glGenTexturesEXT) = (PFNGLGENTEXTURESEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glGenTexturesEXT");
-        if (NULL == GLH_EXT_NAME(glGenTexturesEXT))
-            return FALSE;
-        GLH_EXT_NAME(glIsTextureEXT) = (PFNGLISTEXTUREEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glIsTextureEXT");
-        if (NULL == GLH_EXT_NAME(glIsTextureEXT))
-            return FALSE;
-        GLH_EXT_NAME(glPrioritizeTexturesEXT) = (PFNGLPRIORITIZETEXTURESEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glPrioritizeTexturesEXT");
-        if (NULL == GLH_EXT_NAME(glPrioritizeTexturesEXT))
-            return FALSE;
-#endif
-
-#ifdef GL_EXT_texture3D
-    } else if (0 == strcmp(extension, "GL_EXT_texture3D")) {
-        GLH_EXT_NAME(glTexImage3DEXT) = (PFNGLTEXIMAGE3DEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glTexImage3DEXT");
-        if (NULL == GLH_EXT_NAME(glTexImage3DEXT))
-            return FALSE;
-#endif
-
-#ifdef GL_EXT_vertex_array
-    } else if (0 == strcmp(extension, "GL_EXT_vertex_array")) {
-        GLH_EXT_NAME(glArrayElementEXT) = (PFNGLARRAYELEMENTEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glArrayElementEXT");
-        if (NULL == GLH_EXT_NAME(glArrayElementEXT))
-            return FALSE;
-        GLH_EXT_NAME(glColorPointerEXT) = (PFNGLCOLORPOINTEREXTPROC)GLH_EXT_GET_PROC_ADDRESS("glColorPointerEXT");
-        if (NULL == GLH_EXT_NAME(glColorPointerEXT))
-            return FALSE;
-        GLH_EXT_NAME(glEdgeFlagPointerEXT) = (PFNGLEDGEFLAGPOINTEREXTPROC)GLH_EXT_GET_PROC_ADDRESS("glEdgeFlagPointerEXT");
-        if (NULL == GLH_EXT_NAME(glEdgeFlagPointerEXT))
-            return FALSE;
-        GLH_EXT_NAME(glGetPointervEXT) = (PFNGLGETPOINTERVEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glGetPointervEXT");
-        if (NULL == GLH_EXT_NAME(glGetPointervEXT))
-            return FALSE;
-        GLH_EXT_NAME(glIndexPointerEXT) = (PFNGLINDEXPOINTEREXTPROC)GLH_EXT_GET_PROC_ADDRESS("glIndexPointerEXT");
-        if (NULL == GLH_EXT_NAME(glIndexPointerEXT))
-            return FALSE;
-        GLH_EXT_NAME(glNormalPointerEXT) = (PFNGLNORMALPOINTEREXTPROC)GLH_EXT_GET_PROC_ADDRESS("glNormalPointerEXT");
-        if (NULL == GLH_EXT_NAME(glNormalPointerEXT))
-            return FALSE;
-        GLH_EXT_NAME(glTexCoordPointerEXT) = (PFNGLTEXCOORDPOINTEREXTPROC)GLH_EXT_GET_PROC_ADDRESS("glTexCoordPointerEXT");
-        if (NULL == GLH_EXT_NAME(glTexCoordPointerEXT))
-            return FALSE;
-        GLH_EXT_NAME(glVertexPointerEXT) = (PFNGLVERTEXPOINTEREXTPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexPointerEXT");
-        if (NULL == GLH_EXT_NAME(glVertexPointerEXT))
-            return FALSE;
-        GLH_EXT_NAME(glDrawArraysEXT) = (PFNGLDRAWARRAYSEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glDrawArraysEXT");
-        if (NULL == GLH_EXT_NAME(glDrawArraysEXT))
-            return FALSE;
-#endif
-
-#ifdef GL_EXT_vertex_weighting
-    } else if (0 == strcmp(extension, "GL_EXT_vertex_weighting")) {
-        GLH_EXT_NAME(glVertexWeightfEXT) = (PFNGLVERTEXWEIGHTFEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexWeightfEXT");
-        if (NULL == GLH_EXT_NAME(glVertexWeightfEXT))
-            return FALSE;
-        GLH_EXT_NAME(glVertexWeightfvEXT) = (PFNGLVERTEXWEIGHTFVEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexWeightfvEXT");
-        if (NULL == GLH_EXT_NAME(glVertexWeightfvEXT))
-            return FALSE;
-        GLH_EXT_NAME(glVertexWeightPointerEXT) = (PFNGLVERTEXWEIGHTPOINTEREXTPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexWeightPointerEXT");
-        if (NULL == GLH_EXT_NAME(glVertexWeightPointerEXT))
-            return FALSE;
-#endif
-
-#ifdef GL_NV_blend_square
-    } else if (0 == strcmp(extension, "GL_NV_blend_square")) {
-#endif
-
-#ifdef GL_NV_evaluators
-    } else if (0 == strcmp(extension, "GL_NV_evaluators")) {
-        GLH_EXT_NAME(glMapControlPointsNV) = (PFNGLMAPCONTROLPOINTSNVPROC)GLH_EXT_GET_PROC_ADDRESS("glMapControlPointsNV");
-        if (NULL == GLH_EXT_NAME(glMapControlPointsNV))
-            return FALSE;
-        GLH_EXT_NAME(glMapParameterivNV) = (PFNGLMAPPARAMETERIVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glMapParameterivNV");
-        if (NULL == GLH_EXT_NAME(glMapParameterivNV))
-            return FALSE;
-        GLH_EXT_NAME(glMapParameterfvNV) = (PFNGLMAPPARAMETERFVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glMapParameterfvNV");
-        if (NULL == GLH_EXT_NAME(glMapParameterfvNV))
-            return FALSE;
-        GLH_EXT_NAME(glGetMapControlPointsNV) = (PFNGLGETMAPCONTROLPOINTSNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetMapControlPointsNV");
-        if (NULL == GLH_EXT_NAME(glGetMapControlPointsNV))
-            return FALSE;
-        GLH_EXT_NAME(glGetMapParameterivNV) = (PFNGLGETMAPPARAMETERIVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetMapParameterivNV");
-        if (NULL == GLH_EXT_NAME(glGetMapParameterivNV))
-            return FALSE;
-        GLH_EXT_NAME(glGetMapParameterfvNV) = (PFNGLGETMAPPARAMETERFVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetMapParameterfvNV");
-        if (NULL == GLH_EXT_NAME(glGetMapParameterfvNV))
-            return FALSE;
-        GLH_EXT_NAME(glGetMapAttribParameterivNV) = (PFNGLGETMAPATTRIBPARAMETERIVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetMapAttribParameterivNV");
-        if (NULL == GLH_EXT_NAME(glGetMapAttribParameterivNV))
-            return FALSE;
-        GLH_EXT_NAME(glGetMapAttribParameterfvNV) = (PFNGLGETMAPATTRIBPARAMETERFVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetMapAttribParameterfvNV");
-        if (NULL == GLH_EXT_NAME(glGetMapAttribParameterfvNV))
-            return FALSE;
-        GLH_EXT_NAME(glEvalMapsNV) = (PFNGLEVALMAPSNVPROC)GLH_EXT_GET_PROC_ADDRESS("glEvalMapsNV");
-        if (NULL == GLH_EXT_NAME(glEvalMapsNV))
-            return FALSE;
-#endif
-
-#ifdef GL_NV_fence
-    } else if (0 == strcmp(extension, "GL_NV_fence")) {
-        GLH_EXT_NAME(glGenFencesNV) = (PFNGLGENFENCESNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGenFencesNV");
-        if (NULL == GLH_EXT_NAME(glGenFencesNV))
-            return FALSE;
-        GLH_EXT_NAME(glDeleteFencesNV) = (PFNGLDELETEFENCESNVPROC)GLH_EXT_GET_PROC_ADDRESS("glDeleteFencesNV");
-        if (NULL == GLH_EXT_NAME(glDeleteFencesNV))
-            return FALSE;
-        GLH_EXT_NAME(glSetFenceNV) = (PFNGLSETFENCENVPROC)GLH_EXT_GET_PROC_ADDRESS("glSetFenceNV");
-        if (NULL == GLH_EXT_NAME(glSetFenceNV))
-            return FALSE;
-        GLH_EXT_NAME(glTestFenceNV) = (PFNGLTESTFENCENVPROC)GLH_EXT_GET_PROC_ADDRESS("glTestFenceNV");
-        if (NULL == GLH_EXT_NAME(glTestFenceNV))
-            return FALSE;
-        GLH_EXT_NAME(glFinishFenceNV) = (PFNGLFINISHFENCENVPROC)GLH_EXT_GET_PROC_ADDRESS("glFinishFenceNV");
-        if (NULL == GLH_EXT_NAME(glFinishFenceNV))
-            return FALSE;
-        GLH_EXT_NAME(glIsFenceNV) = (PFNGLISFENCENVPROC)GLH_EXT_GET_PROC_ADDRESS("glIsFenceNV");
-        if (NULL == GLH_EXT_NAME(glIsFenceNV))
-            return FALSE;
-        GLH_EXT_NAME(glGetFenceivNV) = (PFNGLGETFENCEIVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetFenceivNV");
-        if (NULL == GLH_EXT_NAME(glGetFenceivNV))
-            return FALSE;
-#endif
-
-#ifdef GL_NV_fog_distance
-    } else if (0 == strcmp(extension, "GL_NV_fog_distance")) {
-#endif
-
-#ifdef GL_NV_packed_depth_stencil
-    } else if (0 == strcmp(extension, "GL_NV_packed_depth_stencil")) {
-#endif
-
-#ifdef GL_NV_register_combiners
-    } else if (0 == strcmp(extension, "GL_NV_register_combiners")) {
-        GLH_EXT_NAME(glCombinerParameterfvNV) = (PFNGLCOMBINERPARAMETERFVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glCombinerParameterfvNV");
-        if (NULL == GLH_EXT_NAME(glCombinerParameterfvNV))
-            return FALSE;
-        GLH_EXT_NAME(glCombinerParameterfNV) = (PFNGLCOMBINERPARAMETERFNVPROC)GLH_EXT_GET_PROC_ADDRESS("glCombinerParameterfNV");
-        if (NULL == GLH_EXT_NAME(glCombinerParameterfNV))
-            return FALSE;
-        GLH_EXT_NAME(glCombinerParameterivNV) = (PFNGLCOMBINERPARAMETERIVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glCombinerParameterivNV");
-        if (NULL == GLH_EXT_NAME(glCombinerParameterivNV))
-            return FALSE;
-        GLH_EXT_NAME(glCombinerParameteriNV) = (PFNGLCOMBINERPARAMETERINVPROC)GLH_EXT_GET_PROC_ADDRESS("glCombinerParameteriNV");
-        if (NULL == GLH_EXT_NAME(glCombinerParameteriNV))
-            return FALSE;
-        GLH_EXT_NAME(glCombinerInputNV) = (PFNGLCOMBINERINPUTNVPROC)GLH_EXT_GET_PROC_ADDRESS("glCombinerInputNV");
-        if (NULL == GLH_EXT_NAME(glCombinerInputNV))
-            return FALSE;
-        GLH_EXT_NAME(glCombinerOutputNV) = (PFNGLCOMBINEROUTPUTNVPROC)GLH_EXT_GET_PROC_ADDRESS("glCombinerOutputNV");
-        if (NULL == GLH_EXT_NAME(glCombinerOutputNV))
-            return FALSE;
-        GLH_EXT_NAME(glFinalCombinerInputNV) = (PFNGLFINALCOMBINERINPUTNVPROC)GLH_EXT_GET_PROC_ADDRESS("glFinalCombinerInputNV");
-        if (NULL == GLH_EXT_NAME(glFinalCombinerInputNV))
-            return FALSE;
-        GLH_EXT_NAME(glGetCombinerInputParameterfvNV) = (PFNGLGETCOMBINERINPUTPARAMETERFVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetCombinerInputParameterfvNV");
-        if (NULL == GLH_EXT_NAME(glGetCombinerInputParameterfvNV))
-            return FALSE;
-        GLH_EXT_NAME(glGetCombinerInputParameterivNV) = (PFNGLGETCOMBINERINPUTPARAMETERIVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetCombinerInputParameterivNV");
-        if (NULL == GLH_EXT_NAME(glGetCombinerInputParameterivNV))
-            return FALSE;
-        GLH_EXT_NAME(glGetCombinerOutputParameterfvNV) = (PFNGLGETCOMBINEROUTPUTPARAMETERFVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetCombinerOutputParameterfvNV");
-        if (NULL == GLH_EXT_NAME(glGetCombinerOutputParameterfvNV))
-            return FALSE;
-        GLH_EXT_NAME(glGetCombinerOutputParameterivNV) = (PFNGLGETCOMBINEROUTPUTPARAMETERIVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetCombinerOutputParameterivNV");
-        if (NULL == GLH_EXT_NAME(glGetCombinerOutputParameterivNV))
-            return FALSE;
-        GLH_EXT_NAME(glGetFinalCombinerInputParameterfvNV) = (PFNGLGETFINALCOMBINERINPUTPARAMETERFVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetFinalCombinerInputParameterfvNV");
-        if (NULL == GLH_EXT_NAME(glGetFinalCombinerInputParameterfvNV))
-            return FALSE;
-        GLH_EXT_NAME(glGetFinalCombinerInputParameterivNV) = (PFNGLGETFINALCOMBINERINPUTPARAMETERIVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetFinalCombinerInputParameterivNV");
-        if (NULL == GLH_EXT_NAME(glGetFinalCombinerInputParameterivNV))
-            return FALSE;
-#endif
-
-#ifdef GL_NV_register_combiners2
-    } else if (0 == strcmp(extension, "GL_NV_register_combiners2")) {
-        GLH_EXT_NAME(glCombinerStageParameterfvNV) = (PFNGLCOMBINERSTAGEPARAMETERFVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glCombinerStageParameterfvNV");
-        if (NULL == GLH_EXT_NAME(glCombinerStageParameterfvNV))
-            return FALSE;
-        GLH_EXT_NAME(glGetCombinerStageParameterfvNV) = (PFNGLGETCOMBINERSTAGEPARAMETERFVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetCombinerStageParameterfvNV");
-        if (NULL == GLH_EXT_NAME(glGetCombinerStageParameterfvNV))
-            return FALSE;
-#endif
-
-#ifdef GL_NV_texgen_reflection
-    } else if (0 == strcmp(extension, "GL_NV_texgen_reflection")) {
-#endif
-
-#ifdef GL_NV_texture_env_combine4
-    } else if (0 == strcmp(extension, "GL_NV_texture_env_combine4")) {
-#endif
-
-#ifdef GL_NV_texture_rectangle
-    } else if (0 == strcmp(extension, "GL_NV_texture_rectangle")) {
-#endif
-
-#ifdef GL_NV_texture_shader
-    } else if (0 == strcmp(extension, "GL_NV_texture_shader")) {
-#endif
-
-#ifdef GL_NV_vertex_array_range
-    } else if (0 == strcmp(extension, "GL_NV_vertex_array_range")) {
-        GLH_EXT_NAME(glFlushVertexArrayRangeNV) = (PFNGLFLUSHVERTEXARRAYRANGENVPROC)GLH_EXT_GET_PROC_ADDRESS("glFlushVertexArrayRangeNV");
-        if (NULL == GLH_EXT_NAME(glFlushVertexArrayRangeNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexArrayRangeNV) = (PFNGLVERTEXARRAYRANGENVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexArrayRangeNV");
-        if (NULL == GLH_EXT_NAME(glVertexArrayRangeNV))
-            return FALSE;
-# ifdef _WIN32
-        GLH_EXT_NAME(wglAllocateMemoryNV) = (PFNWGLALLOCATEMEMORYNVPROC)GLH_EXT_GET_PROC_ADDRESS("wglAllocateMemoryNV");
-        if (NULL == GLH_EXT_NAME(wglAllocateMemoryNV))
-            return FALSE;
-# endif
-# ifdef GLX_VERSION_1_3
-        GLH_EXT_NAME(glXAllocateMemoryNV) = (PFNGLXALLOCATEMEMORYNVPROC)GLH_EXT_GET_PROC_ADDRESS("glXAllocateMemoryNV");
-        if (NULL == GLH_EXT_NAME(glXAllocateMemoryNV))
-            return FALSE;
-# endif
-# ifdef _WIN32
-        GLH_EXT_NAME(wglFreeMemoryNV) = (PFNWGLFREEMEMORYNVPROC)GLH_EXT_GET_PROC_ADDRESS("wglFreeMemoryNV");
-        if (NULL == GLH_EXT_NAME(wglFreeMemoryNV))
-            return FALSE;
-# endif
-# ifdef GLX_VERSION_1_3
-        GLH_EXT_NAME(glXFreeMemoryNV) = (PFNGLXFREEMEMORYNVPROC)GLH_EXT_GET_PROC_ADDRESS("glXFreeMemoryNV");
-        if (NULL == GLH_EXT_NAME(glXFreeMemoryNV))
-            return FALSE;
-# endif
-#endif
-
-#ifdef GL_NV_vertex_program
-    } else if (0 == strcmp(extension, "GL_NV_vertex_program")) {
-        GLH_EXT_NAME(glAreProgramsResidentNV) = (PFNGLAREPROGRAMSRESIDENTNVPROC)GLH_EXT_GET_PROC_ADDRESS("glAreProgramsResidentNV");
-        if (NULL == GLH_EXT_NAME(glAreProgramsResidentNV))
-            return FALSE;
-        GLH_EXT_NAME(glBindProgramNV) = (PFNGLBINDPROGRAMNVPROC)GLH_EXT_GET_PROC_ADDRESS("glBindProgramNV");
-        if (NULL == GLH_EXT_NAME(glBindProgramNV))
-            return FALSE;
-        GLH_EXT_NAME(glDeleteProgramsNV) = (PFNGLDELETEPROGRAMSNVPROC)GLH_EXT_GET_PROC_ADDRESS("glDeleteProgramsNV");
-        if (NULL == GLH_EXT_NAME(glDeleteProgramsNV))
-            return FALSE;
-        GLH_EXT_NAME(glExecuteProgramNV) = (PFNGLEXECUTEPROGRAMNVPROC)GLH_EXT_GET_PROC_ADDRESS("glExecuteProgramNV");
-        if (NULL == GLH_EXT_NAME(glExecuteProgramNV))
-            return FALSE;
-        GLH_EXT_NAME(glGenProgramsNV) = (PFNGLGENPROGRAMSNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGenProgramsNV");
-        if (NULL == GLH_EXT_NAME(glGenProgramsNV))
-            return FALSE;
-        GLH_EXT_NAME(glGetProgramParameterdvNV) = (PFNGLGETPROGRAMPARAMETERDVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetProgramParameterdvNV");
-        if (NULL == GLH_EXT_NAME(glGetProgramParameterdvNV))
-            return FALSE;
-        GLH_EXT_NAME(glGetProgramParameterfvNV) = (PFNGLGETPROGRAMPARAMETERFVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetProgramParameterfvNV");
-        if (NULL == GLH_EXT_NAME(glGetProgramParameterfvNV))
-            return FALSE;
-        GLH_EXT_NAME(glGetProgramivNV) = (PFNGLGETPROGRAMIVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetProgramivNV");
-        if (NULL == GLH_EXT_NAME(glGetProgramivNV))
-            return FALSE;
-        GLH_EXT_NAME(glGetProgramStringNV) = (PFNGLGETPROGRAMSTRINGNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetProgramStringNV");
-        if (NULL == GLH_EXT_NAME(glGetProgramStringNV))
-            return FALSE;
-        GLH_EXT_NAME(glGetTrackMatrixivNV) = (PFNGLGETTRACKMATRIXIVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetTrackMatrixivNV");
-        if (NULL == GLH_EXT_NAME(glGetTrackMatrixivNV))
-            return FALSE;
-        GLH_EXT_NAME(glGetVertexAttribdvNV) = (PFNGLGETVERTEXATTRIBDVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetVertexAttribdvNV");
-        if (NULL == GLH_EXT_NAME(glGetVertexAttribdvNV))
-            return FALSE;
-        GLH_EXT_NAME(glGetVertexAttribfvNV) = (PFNGLGETVERTEXATTRIBFVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetVertexAttribfvNV");
-        if (NULL == GLH_EXT_NAME(glGetVertexAttribfvNV))
-            return FALSE;
-        GLH_EXT_NAME(glGetVertexAttribivNV) = (PFNGLGETVERTEXATTRIBIVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetVertexAttribivNV");
-        if (NULL == GLH_EXT_NAME(glGetVertexAttribivNV))
-            return FALSE;
-        GLH_EXT_NAME(glGetVertexAttribPointervNV) = (PFNGLGETVERTEXATTRIBPOINTERVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetVertexAttribPointervNV");
-        if (NULL == GLH_EXT_NAME(glGetVertexAttribPointervNV))
-            return FALSE;
-        GLH_EXT_NAME(glIsProgramNV) = (PFNGLISPROGRAMNVPROC)GLH_EXT_GET_PROC_ADDRESS("glIsProgramNV");
-        if (NULL == GLH_EXT_NAME(glIsProgramNV))
-            return FALSE;
-        GLH_EXT_NAME(glLoadProgramNV) = (PFNGLLOADPROGRAMNVPROC)GLH_EXT_GET_PROC_ADDRESS("glLoadProgramNV");
-        if (NULL == GLH_EXT_NAME(glLoadProgramNV))
-            return FALSE;
-        GLH_EXT_NAME(glProgramParameter4dNV) = (PFNGLPROGRAMPARAMETER4DNVPROC)GLH_EXT_GET_PROC_ADDRESS("glProgramParameter4dNV");
-        if (NULL == GLH_EXT_NAME(glProgramParameter4dNV))
-            return FALSE;
-        GLH_EXT_NAME(glProgramParameter4dvNV) = (PFNGLPROGRAMPARAMETER4DVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glProgramParameter4dvNV");
-        if (NULL == GLH_EXT_NAME(glProgramParameter4dvNV))
-            return FALSE;
-        GLH_EXT_NAME(glProgramParameter4fNV) = (PFNGLPROGRAMPARAMETER4FNVPROC)GLH_EXT_GET_PROC_ADDRESS("glProgramParameter4fNV");
-        if (NULL == GLH_EXT_NAME(glProgramParameter4fNV))
-            return FALSE;
-        GLH_EXT_NAME(glProgramParameter4fvNV) = (PFNGLPROGRAMPARAMETER4FVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glProgramParameter4fvNV");
-        if (NULL == GLH_EXT_NAME(glProgramParameter4fvNV))
-            return FALSE;
-        GLH_EXT_NAME(glProgramParameters4dvNV) = (PFNGLPROGRAMPARAMETERS4DVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glProgramParameters4dvNV");
-        if (NULL == GLH_EXT_NAME(glProgramParameters4dvNV))
-            return FALSE;
-        GLH_EXT_NAME(glProgramParameters4fvNV) = (PFNGLPROGRAMPARAMETERS4FVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glProgramParameters4fvNV");
-        if (NULL == GLH_EXT_NAME(glProgramParameters4fvNV))
-            return FALSE;
-        GLH_EXT_NAME(glRequestResidentProgramsNV) = (PFNGLREQUESTRESIDENTPROGRAMSNVPROC)GLH_EXT_GET_PROC_ADDRESS("glRequestResidentProgramsNV");
-        if (NULL == GLH_EXT_NAME(glRequestResidentProgramsNV))
-            return FALSE;
-        GLH_EXT_NAME(glTrackMatrixNV) = (PFNGLTRACKMATRIXNVPROC)GLH_EXT_GET_PROC_ADDRESS("glTrackMatrixNV");
-        if (NULL == GLH_EXT_NAME(glTrackMatrixNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttribPointerNV) = (PFNGLVERTEXATTRIBPOINTERNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttribPointerNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttribPointerNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttrib1dNV) = (PFNGLVERTEXATTRIB1DNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1dNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib1dNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttrib1dvNV) = (PFNGLVERTEXATTRIB1DVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1dvNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib1dvNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttrib1fNV) = (PFNGLVERTEXATTRIB1FNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1fNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib1fNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttrib1fvNV) = (PFNGLVERTEXATTRIB1FVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1fvNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib1fvNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttrib1sNV) = (PFNGLVERTEXATTRIB1SNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1sNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib1sNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttrib1svNV) = (PFNGLVERTEXATTRIB1SVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1svNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib1svNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttrib2dNV) = (PFNGLVERTEXATTRIB2DNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2dNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib2dNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttrib2dvNV) = (PFNGLVERTEXATTRIB2DVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2dvNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib2dvNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttrib2fNV) = (PFNGLVERTEXATTRIB2FNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2fNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib2fNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttrib2fvNV) = (PFNGLVERTEXATTRIB2FVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2fvNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib2fvNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttrib2sNV) = (PFNGLVERTEXATTRIB2SNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2sNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib2sNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttrib2svNV) = (PFNGLVERTEXATTRIB2SVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2svNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib2svNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttrib3dNV) = (PFNGLVERTEXATTRIB3DNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3dNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib3dNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttrib3dvNV) = (PFNGLVERTEXATTRIB3DVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3dvNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib3dvNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttrib3fNV) = (PFNGLVERTEXATTRIB3FNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3fNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib3fNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttrib3fvNV) = (PFNGLVERTEXATTRIB3FVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3fvNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib3fvNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttrib3sNV) = (PFNGLVERTEXATTRIB3SNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3sNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib3sNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttrib3svNV) = (PFNGLVERTEXATTRIB3SVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3svNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib3svNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttrib4dNV) = (PFNGLVERTEXATTRIB4DNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4dNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib4dNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttrib4dvNV) = (PFNGLVERTEXATTRIB4DVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4dvNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib4dvNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttrib4fNV) = (PFNGLVERTEXATTRIB4FNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4fNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib4fNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttrib4fvNV) = (PFNGLVERTEXATTRIB4FVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4fvNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib4fvNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttrib4sNV) = (PFNGLVERTEXATTRIB4SNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4sNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib4sNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttrib4svNV) = (PFNGLVERTEXATTRIB4SVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4svNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib4svNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttrib4ubvNV) = (PFNGLVERTEXATTRIB4UBVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4ubvNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib4ubvNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttribs1dvNV) = (PFNGLVERTEXATTRIBS1DVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttribs1dvNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttribs1dvNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttribs1fvNV) = (PFNGLVERTEXATTRIBS1FVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttribs1fvNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttribs1fvNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttribs1svNV) = (PFNGLVERTEXATTRIBS1SVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttribs1svNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttribs1svNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttribs2dvNV) = (PFNGLVERTEXATTRIBS2DVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttribs2dvNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttribs2dvNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttribs2fvNV) = (PFNGLVERTEXATTRIBS2FVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttribs2fvNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttribs2fvNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttribs2svNV) = (PFNGLVERTEXATTRIBS2SVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttribs2svNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttribs2svNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttribs3dvNV) = (PFNGLVERTEXATTRIBS3DVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttribs3dvNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttribs3dvNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttribs3fvNV) = (PFNGLVERTEXATTRIBS3FVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttribs3fvNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttribs3fvNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttribs3svNV) = (PFNGLVERTEXATTRIBS3SVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttribs3svNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttribs3svNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttribs4dvNV) = (PFNGLVERTEXATTRIBS4DVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttribs4dvNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttribs4dvNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttribs4fvNV) = (PFNGLVERTEXATTRIBS4FVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttribs4fvNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttribs4fvNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttribs4svNV) = (PFNGLVERTEXATTRIBS4SVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttribs4svNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttribs4svNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttribs4ubvNV) = (PFNGLVERTEXATTRIBS4UBVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttribs4ubvNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttribs4ubvNV))
-            return FALSE;
-#endif
-
-#ifdef GL_SGIS_generate_mipmap
-    } else if (0 == strcmp(extension, "GL_SGIS_generate_mipmap")) {
-#endif
-
-#ifdef GL_SGIS_texture_lod
-    } else if (0 == strcmp(extension, "GL_SGIS_texture_lod")) {
-#endif
-
-#ifdef GL_SGIX_depth_texture
-    } else if (0 == strcmp(extension, "GL_SGIX_depth_texture")) {
-#endif
-
-#ifdef GL_SGIX_shadow
-    } else if (0 == strcmp(extension, "GL_SGIX_shadow")) {
-#endif
-
-#ifdef GL_VERSION_1_2
-    } else if (0 == strcmp(extension, "GL_VERSION_1_2")) {
-        GLH_CORE_1_2_NAME(glBlendColor) = (PFNGLBLENDCOLORPROC)GLH_EXT_GET_PROC_ADDRESS("glBlendColor");
-        if (NULL == GLH_CORE_1_2_NAME(glBlendColor))
-            return FALSE;
-        GLH_CORE_1_2_NAME(glBlendEquation) = (PFNGLBLENDEQUATIONPROC)GLH_EXT_GET_PROC_ADDRESS("glBlendEquation");
-        if (NULL == GLH_CORE_1_2_NAME(glBlendEquation))
-            return FALSE;
-        GLH_CORE_1_2_NAME(glDrawRangeElements) = (PFNGLDRAWRANGEELEMENTSPROC)GLH_EXT_GET_PROC_ADDRESS("glDrawRangeElements");
-        if (NULL == GLH_CORE_1_2_NAME(glDrawRangeElements))
-            return FALSE;
-        GLH_CORE_1_2_NAME(glColorTable) = (PFNGLCOLORTABLEPROC)GLH_EXT_GET_PROC_ADDRESS("glColorTable");
-        if (NULL == GLH_CORE_1_2_NAME(glColorTable))
-            return FALSE;
-        GLH_CORE_1_2_NAME(glColorTableParameterfv) = (PFNGLCOLORTABLEPARAMETERFVPROC)GLH_EXT_GET_PROC_ADDRESS("glColorTableParameterfv");
-        if (NULL == GLH_CORE_1_2_NAME(glColorTableParameterfv))
-            return FALSE;
-        GLH_CORE_1_2_NAME(glColorTableParameteriv) = (PFNGLCOLORTABLEPARAMETERIVPROC)GLH_EXT_GET_PROC_ADDRESS("glColorTableParameteriv");
-        if (NULL == GLH_CORE_1_2_NAME(glColorTableParameteriv))
-            return FALSE;
-        GLH_CORE_1_2_NAME(glCopyColorTable) = (PFNGLCOPYCOLORTABLEPROC)GLH_EXT_GET_PROC_ADDRESS("glCopyColorTable");
-        if (NULL == GLH_CORE_1_2_NAME(glCopyColorTable))
-            return FALSE;
-        GLH_CORE_1_2_NAME(glGetColorTable) = (PFNGLGETCOLORTABLEPROC)GLH_EXT_GET_PROC_ADDRESS("glGetColorTable");
-        if (NULL == GLH_CORE_1_2_NAME(glGetColorTable))
-            return FALSE;
-        GLH_CORE_1_2_NAME(glGetColorTableParameterfv) = (PFNGLGETCOLORTABLEPARAMETERFVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetColorTableParameterfv");
-        if (NULL == GLH_CORE_1_2_NAME(glGetColorTableParameterfv))
-            return FALSE;
-        GLH_CORE_1_2_NAME(glGetColorTableParameteriv) = (PFNGLGETCOLORTABLEPARAMETERIVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetColorTableParameteriv");
-        if (NULL == GLH_CORE_1_2_NAME(glGetColorTableParameteriv))
-            return FALSE;
-        GLH_CORE_1_2_NAME(glTexImage3D) = (PFNGLTEXIMAGE3DPROC)GLH_EXT_GET_PROC_ADDRESS("glTexImage3D");
-        if (NULL == GLH_CORE_1_2_NAME(glTexImage3D))
-            return FALSE;
-        GLH_CORE_1_2_NAME(glTexSubImage3D) = (PFNGLTEXSUBIMAGE3DPROC)GLH_EXT_GET_PROC_ADDRESS("glTexSubImage3D");
-        if (NULL == GLH_CORE_1_2_NAME(glTexSubImage3D))
-            return FALSE;
-        GLH_CORE_1_2_NAME(glCopyTexSubImage3D) = (PFNGLCOPYTEXSUBIMAGE3DPROC)GLH_EXT_GET_PROC_ADDRESS("glCopyTexSubImage3D");
-        if (NULL == GLH_CORE_1_2_NAME(glCopyTexSubImage3D))
-            return FALSE;
-#endif
-
-#ifdef GL_WIN_swap_hint
-    } else if (0 == strcmp(extension, "GL_WIN_swap_hint")) {
-        GLH_EXT_NAME(glAddSwapHintRectWIN) = (PFNGLADDSWAPHINTRECTWINPROC)GLH_EXT_GET_PROC_ADDRESS("glAddSwapHintRectWIN");
-        if (NULL == GLH_EXT_NAME(glAddSwapHintRectWIN))
-            return FALSE;
-#endif
-
-#ifdef WGL_ARB_pbuffer
-    } else if (0 == strcmp(extension, "WGL_ARB_pbuffer")) {
-# ifdef _WIN32
-        GLH_EXT_NAME(wglCreatePbufferARB) = (PFNWGLCREATEPBUFFERARBPROC)GLH_EXT_GET_PROC_ADDRESS("wglCreatePbufferARB");
-        if (NULL == GLH_EXT_NAME(wglCreatePbufferARB))
-            return FALSE;
-# endif
-# ifdef _WIN32
-        GLH_EXT_NAME(wglGetPbufferDCARB) = (PFNWGLGETPBUFFERDCARBPROC)GLH_EXT_GET_PROC_ADDRESS("wglGetPbufferDCARB");
-        if (NULL == GLH_EXT_NAME(wglGetPbufferDCARB))
-            return FALSE;
-# endif
-# ifdef _WIN32
-        GLH_EXT_NAME(wglReleasePbufferDCARB) = (PFNWGLRELEASEPBUFFERDCARBPROC)GLH_EXT_GET_PROC_ADDRESS("wglReleasePbufferDCARB");
-        if (NULL == GLH_EXT_NAME(wglReleasePbufferDCARB))
-            return FALSE;
-# endif
-# ifdef _WIN32
-        GLH_EXT_NAME(wglDestroyPbufferARB) = (PFNWGLDESTROYPBUFFERARBPROC)GLH_EXT_GET_PROC_ADDRESS("wglDestroyPbufferARB");
-        if (NULL == GLH_EXT_NAME(wglDestroyPbufferARB))
-            return FALSE;
-# endif
-# ifdef _WIN32
-        GLH_EXT_NAME(wglQueryPbufferARB) = (PFNWGLQUERYPBUFFERARBPROC)GLH_EXT_GET_PROC_ADDRESS("wglQueryPbufferARB");
-        if (NULL == GLH_EXT_NAME(wglQueryPbufferARB))
-            return FALSE;
-# endif
-#endif
-
-#ifdef WGL_ARB_render_texture
-# ifdef _WIN32
-		GLH_EXT_NAME(wglBindTexImageARB) = (PFNWGLBINDTEXIMAGEARBPROC)GLH_EXT_GET_PROC_ADDRESS("wglBindTexImageARB");
-		if (NULL == GLH_EXT_NAME(wglBindTexImageARB))
-			return FALSE;
-# endif
-# ifdef _WIN32
-		GLH_EXT_NAME(wglReleaseTexImageARB) = (PFNWGLRELEASETEXIMAGEARBPROC)GLH_EXT_GET_PROC_ADDRESS("wglReleaseTexImageARB");
-		if (NULL == GLH_EXT_NAME(wglReleaseTexImageARB))
-			return FALSE;
-# endif
-# ifdef _WIN32
-		GLH_EXT_NAME(wglSetPbufferAttribARB) = (PFNWGLSETPBUFFERATTRIBARBPROC)GLH_EXT_GET_PROC_ADDRESS("wglSetPbufferAttribARB");
-		if (NULL == GLH_EXT_NAME(wglSetPbufferAttribARB))
-			return FALSE;
-# endif
-#endif
-
-#ifdef WGL_ARB_pixel_format
-    } else if (0 == strcmp(extension, "WGL_ARB_pixel_format")) {
-# ifdef _WIN32
-        GLH_EXT_NAME(wglGetPixelFormatAttribivARB) = (PFNWGLGETPIXELFORMATATTRIBIVARBPROC)GLH_EXT_GET_PROC_ADDRESS("wglGetPixelFormatAttribivARB");
-        if (NULL == GLH_EXT_NAME(wglGetPixelFormatAttribivARB))
-            return FALSE;
-# endif
-# ifdef _WIN32
-        GLH_EXT_NAME(wglGetPixelFormatAttribfvARB) = (PFNWGLGETPIXELFORMATATTRIBFVARBPROC)GLH_EXT_GET_PROC_ADDRESS("wglGetPixelFormatAttribfvARB");
-        if (NULL == GLH_EXT_NAME(wglGetPixelFormatAttribfvARB))
-            return FALSE;
-# endif
-# ifdef _WIN32
-        GLH_EXT_NAME(wglChoosePixelFormatARB) = (PFNWGLCHOOSEPIXELFORMATARBPROC)GLH_EXT_GET_PROC_ADDRESS("wglChoosePixelFormatARB");
-        if (NULL == GLH_EXT_NAME(wglChoosePixelFormatARB))
-            return FALSE;
-# endif
-#endif
-
-    } else {
-        return FALSE;
-    }
-    return TRUE;
-}
-#endif
-
-#else // defined(__APPLE__)
-
-#ifdef GLH_EXT_SINGLE_FILE
-
-int glh_init_extension(const char* extension)
-{
-	// MBW -- XXX -- Should this check for extension availability?
-	return TRUE;
-}
-#endif // GLH_EXT_SINGLE_FILE
-
-#endif // defined(__APPLE__)
-
-#undef GLH_EXT_SINGLE_FILE
-
-#endif /* GLH_GENEXT_H */
diff --git a/indra/llwindow/lldxhardware.cpp b/indra/llwindow/lldxhardware.cpp
index 12a6baa3e694d57c41075d1588970768322dbbe7..81e938edbe787300138628382f4daf78e6d9cd48 100644
--- a/indra/llwindow/lldxhardware.cpp
+++ b/indra/llwindow/lldxhardware.cpp
@@ -229,7 +229,7 @@ S32 LLDXHardware::getMBVideoMemoryViaWMI()
 }
 
 //Getting the version of graphics controller driver via WMI
-std::string LLDXHardware::getDriverVersionWMI()
+std::string LLDXHardware::getDriverVersionWMI(EGPUVendor vendor)
 {
 	std::string mDriverVersion;
 	HRESULT hrCoInitialize = S_OK;
@@ -325,15 +325,68 @@ std::string LLDXHardware::getDriverVersionWMI()
 		{
 			break;               // If quantity less then 1.
 		}
+        
+        if (vendor != GPU_ANY)
+        {
+            VARIANT vtCaptionProp;
+            // Might be preferable to check "AdapterCompatibility" here instead of caption.
+            hr = pclsObj->Get(L"Caption", 0, &vtCaptionProp, 0, 0);
+
+            if (FAILED(hr))
+            {
+                LL_WARNS("AppInit") << "Query for Caption property failed." << " Error code = 0x" << hr << LL_ENDL;
+                pSvc->Release();
+                pLoc->Release();
+                CoUninitialize();
+                return std::string();               // Program has failed.
+            }
+
+            // use characters in the returned driver version
+            BSTR caption(vtCaptionProp.bstrVal);
+
+            //convert BSTR to std::string
+            std::wstring ws(caption, SysStringLen(caption));
+            std::string caption_str(ws.begin(), ws.end());
+            LLStringUtil::toLower(caption_str);
+
+            bool found = false;
+            switch (vendor)
+            {
+            case GPU_INTEL:
+                found = caption_str.find("intel") != std::string::npos;
+                break;
+            case GPU_NVIDIA:
+                found = caption_str.find("nvidia") != std::string::npos;
+                break;
+            case GPU_AMD:
+                found = caption_str.find("amd") != std::string::npos
+                        || caption_str.find("ati ") != std::string::npos
+                        || caption_str.find("radeon") != std::string::npos;
+                break;
+            default:
+                break;
+            }
 
-		VARIANT vtProp;
+            if (found)
+            {
+                VariantClear(&vtCaptionProp);
+            }
+            else
+            {
+                VariantClear(&vtCaptionProp);
+                pclsObj->Release();
+                continue;
+            }
+        }
 
-		// Get the value of the Name property
-		hr = pclsObj->Get(L"DriverVersion", 0, &vtProp, 0, 0);
+        VARIANT vtVersionProp;
+
+		// Get the value of the DriverVersion property
+		hr = pclsObj->Get(L"DriverVersion", 0, &vtVersionProp, 0, 0);
 
 		if (FAILED(hr))
 		{
-			LL_WARNS("AppInit") << "Query for name property failed." << " Error code = 0x" << hr << LL_ENDL;
+			LL_WARNS("AppInit") << "Query for DriverVersion property failed." << " Error code = 0x" << hr << LL_ENDL;
 			pSvc->Release();
 			pLoc->Release();
 			CoUninitialize();
@@ -341,7 +394,7 @@ std::string LLDXHardware::getDriverVersionWMI()
 		}
 
 		// use characters in the returned driver version
-		BSTR driverVersion(vtProp.bstrVal);
+		BSTR driverVersion(vtVersionProp.bstrVal);
 
 		//convert BSTR to std::string
 		std::wstring ws(driverVersion, SysStringLen(driverVersion));
@@ -354,10 +407,19 @@ std::string LLDXHardware::getDriverVersionWMI()
 		}
 		else if (mDriverVersion != str)
 		{
-			LL_WARNS("DriverVersion") << "Different versions of drivers. Version of second driver : " << str << LL_ENDL;
+            if (vendor == GPU_ANY)
+            {
+                // Expected from systems with gpus from different vendors
+                LL_INFOS("DriverVersion") << "Multiple video drivers detected. Version of second driver: " << str << LL_ENDL;
+            }
+            else
+            {
+                // Not Expected!
+                LL_WARNS("DriverVersion") << "Multiple video drivers detected from same vendor. Version of second driver : " << str << LL_ENDL;
+            }
 		}
 
-		VariantClear(&vtProp);
+		VariantClear(&vtVersionProp);
 		pclsObj->Release();
 	}
 
diff --git a/indra/llwindow/lldxhardware.h b/indra/llwindow/lldxhardware.h
index 1cb687e3b6d5794f71c13d088eb336649688b92b..9cec3e2f1bf1e3a76e3c5a8c52c87e85577699f0 100644
--- a/indra/llwindow/lldxhardware.h
+++ b/indra/llwindow/lldxhardware.h
@@ -88,7 +88,15 @@ class LLDXHardware
 	// vram_only TRUE does a "light" probe.
 	BOOL getInfo(BOOL vram_only);
 
-	std::string getDriverVersionWMI();
+    // WMI can return multiple GPU drivers
+    // specify which one to output
+    typedef enum {
+        GPU_INTEL,
+        GPU_NVIDIA,
+        GPU_AMD,
+        GPU_ANY
+    } EGPUVendor;
+	std::string getDriverVersionWMI(EGPUVendor vendor);
 
 	S32 getVRAM() const { return mVRAM; }
 
diff --git a/indra/llwindow/llkeyboard.cpp b/indra/llwindow/llkeyboard.cpp
index 5404ac50e5c5baefe53ec7e2f65bf6b5d0604388..e65cc7563e6a7010e1ffe54a0c5ab82342dd77a5 100644
--- a/indra/llwindow/llkeyboard.cpp
+++ b/indra/llwindow/llkeyboard.cpp
@@ -148,6 +148,22 @@ void LLKeyboard::addKeyName(KEY key, const std::string& name)
 	sNamesToKeys[nameuc] = key;
 }
 
+void LLKeyboard::resetKeyDownAndHandle()
+{
+    MASK mask = currentMask(FALSE);
+    for (S32 i = 0; i < KEY_COUNT; i++)
+    {
+        if (mKeyLevel[i])
+        {
+            mKeyDown[i] = FALSE;
+            mKeyLevel[i] = FALSE;
+            mKeyUp[i] = TRUE;
+            mCurTranslatedKey = (KEY)i;
+            mCallbacks->handleTranslatedKeyUp(i, mask);
+        }
+    }
+}
+
 // BUG this has to be called when an OS dialog is shown, otherwise modifier key state
 // is wrong because the keyup event is never received by the main window. JC
 void LLKeyboard::resetKeys()
diff --git a/indra/llwindow/llkeyboard.h b/indra/llwindow/llkeyboard.h
index 36bd8bcbed54784c4721f793f8e05dc19aeb2313..fb1ae10f50b6b21ff66a452f3c10d0dbacec23ce 100644
--- a/indra/llwindow/llkeyboard.h
+++ b/indra/llwindow/llkeyboard.h
@@ -58,7 +58,8 @@ class LLKeyboard
 	LLKeyboard();
 	virtual ~LLKeyboard();
 
-	void			resetKeys();
+    void			resetKeyDownAndHandle();
+    void			resetKeys();
 
 
 	F32				getCurKeyElapsedTime()	{ return getKeyDown(mCurScanKey) ? getKeyElapsedTime( mCurScanKey ) : 0.f; }
diff --git a/indra/llwindow/llopenglview-objc.mm b/indra/llwindow/llopenglview-objc.mm
index f9b387b00ba6b19c5d797dc91382d734d7444de4..049226db65b3ee64088b28a7e3207e10a49179ba 100644
--- a/indra/llwindow/llopenglview-objc.mm
+++ b/indra/llwindow/llopenglview-objc.mm
@@ -288,7 +288,8 @@ attributedStringInfo getSegments(NSAttributedString *str)
 	
 	if (vsync)
 	{
-		[glContext setValues:(const GLint*)1 forParameter:NSOpenGLCPSwapInterval];
+		GLint value = 1;
+		[glContext setValues:&value forParameter:NSOpenGLCPSwapInterval];
 	} else {
 		// supress this error after move to Xcode 7:
 		// error: null passed to a callee that requires a non-null argument [-Werror,-Wnonnull]
@@ -494,14 +495,14 @@ attributedStringInfo getSegments(NSAttributedString *str)
     // e.g. OS Window for upload something or Input Window...
     // mModifiers instance variable is for insertText: or insertText:replacementRange:  (by Pell Smit)
 	mModifiers = [theEvent modifierFlags];
+    unichar ch = [[theEvent charactersIgnoringModifiers] characterAtIndex:0];
+    bool acceptsText = mHasMarkedText ? false : callKeyDown(&eventData, keycode, mModifiers, ch);
 
-    bool acceptsText = mHasMarkedText ? false : callKeyDown(&eventData, keycode, mModifiers, [[theEvent characters] characterAtIndex:0]);
-    unichar ch;
     if (acceptsText &&
         !mMarkedTextAllowed &&
         !(mModifiers & (NSControlKeyMask | NSCommandKeyMask)) &&  // commands don't invoke InputWindow
         ![(LLAppDelegate*)[NSApp delegate] romanScript] &&
-        (ch = [[theEvent charactersIgnoringModifiers] characterAtIndex:0]) > ' ' &&
+        ch > ' ' &&
         ch != NSDeleteCharacter &&
         (ch < 0xF700 || ch > 0xF8FF))  // 0xF700-0xF8FF: reserved for function keys on the keyboard(from NSEvent.h)
     {
diff --git a/indra/llwindow/llwindow.cpp b/indra/llwindow/llwindow.cpp
index 30bc743e72fbf31b5efb889dd4995beaeecea8e0..f4678a70c5b407fbcc75b39a38c203312a2aad6c 100644
--- a/indra/llwindow/llwindow.cpp
+++ b/indra/llwindow/llwindow.cpp
@@ -137,6 +137,12 @@ BOOL LLWindow::canDelete()
 	return TRUE;
 }
 
+//virtual
+void LLWindow::setTitle(const std::string title)
+{
+    // the action happens in the platform specific impl
+}
+
 // virtual
 void LLWindow::incBusyCount()
 {
@@ -397,7 +403,7 @@ LLWindow* LLWindowManager::createWindow(
 	const std::string& title, const std::string& name, S32 x, S32 y, S32 width, S32 height, U32 flags,
 	BOOL fullscreen, 
 	BOOL clearBg,
-	BOOL disable_vsync,
+	BOOL enable_vsync,
 	BOOL use_gl,
 	BOOL ignore_pixel_depth,
 	U32 fsaa_samples)
@@ -409,26 +415,26 @@ LLWindow* LLWindowManager::createWindow(
 #if LL_MESA_HEADLESS
 		new_window = new LLWindowMesaHeadless(callbacks,
 			title, name, x, y, width, height, flags, 
-			fullscreen, clearBg, disable_vsync, use_gl, ignore_pixel_depth);
+			fullscreen, clearBg, enable_vsync, use_gl, ignore_pixel_depth);
 #elif LL_SDL
 		new_window = new LLWindowSDL(callbacks,
 			title, x, y, width, height, flags, 
-			fullscreen, clearBg, disable_vsync, use_gl, ignore_pixel_depth, fsaa_samples);
+			fullscreen, clearBg, enable_vsync, use_gl, ignore_pixel_depth, fsaa_samples);
 #elif LL_WINDOWS
 		new_window = new LLWindowWin32(callbacks,
 			title, name, x, y, width, height, flags, 
-			fullscreen, clearBg, disable_vsync, use_gl, ignore_pixel_depth, fsaa_samples);
+			fullscreen, clearBg, enable_vsync, use_gl, ignore_pixel_depth, fsaa_samples);
 #elif LL_DARWIN
 		new_window = new LLWindowMacOSX(callbacks,
 			title, name, x, y, width, height, flags, 
-			fullscreen, clearBg, disable_vsync, use_gl, ignore_pixel_depth, fsaa_samples);
+			fullscreen, clearBg, enable_vsync, use_gl, ignore_pixel_depth, fsaa_samples);
 #endif
 	}
 	else
 	{
 		new_window = new LLWindowHeadless(callbacks,
 			title, name, x, y, width, height, flags, 
-			fullscreen, clearBg, disable_vsync, use_gl, ignore_pixel_depth);
+			fullscreen, clearBg, enable_vsync, use_gl, ignore_pixel_depth);
 	}
 
 	if (FALSE == new_window->isValid())
diff --git a/indra/llwindow/llwindow.h b/indra/llwindow/llwindow.h
index d4d5b769376d1e4ae70e9333c0ee86adfcadf992..0edf39f6ef53353d03ca75c2f66dc35f88c933f6 100644
--- a/indra/llwindow/llwindow.h
+++ b/indra/llwindow/llwindow.h
@@ -77,15 +77,37 @@ class LLWindow : public LLInstanceTracker<LLWindow>
 	BOOL setSize(LLCoordScreen size);
 	BOOL setSize(LLCoordWindow size);
 	virtual void setMinSize(U32 min_width, U32 min_height, bool enforce_immediately = true);
-	virtual BOOL switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL disable_vsync, const LLCoordScreen * const posp = NULL) = 0;
-	virtual BOOL setCursorPosition(LLCoordWindow position) = 0;
+	virtual BOOL switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL enable_vsync, const LLCoordScreen * const posp = NULL) = 0;
+
+    //create a new GL context that shares a namespace with this Window's main GL context and make it current on the current thread
+    // returns a pointer to be handed back to destroySharedConext/makeContextCurrent
+    virtual void* createSharedContext() = 0;
+    //make the given context current on the current thread
+    virtual void makeContextCurrent(void* context) = 0;
+    //destroy the given context that was retrieved by createSharedContext()
+    //Must be called on the same thread that called createSharedContext()
+    virtual void destroySharedContext(void* context) = 0;
+
+    virtual void toggleVSync(bool enable_vsync) = 0;
+
+    virtual BOOL setCursorPosition(LLCoordWindow position) = 0;
 	virtual BOOL getCursorPosition(LLCoordWindow *position) = 0;
+#if LL_WINDOWS
+    virtual BOOL getCursorDelta(LLCoordCommon* delta) = 0;
+#endif
 	virtual void showCursor() = 0;
 	virtual void hideCursor() = 0;
 	virtual BOOL isCursorHidden() = 0;
 	virtual void showCursorFromMouseMove() = 0;
 	virtual void hideCursorUntilMouseMove() = 0;
 
+    // Provide a way to set the Viewer window title after the
+    // windows has been created. The initial use case for this
+    // is described in SL-16102 (update window title with agent 
+    // name, location etc. for non-interactive viewer) but it
+    // may also be useful in other cases.
+    virtual void setTitle(const std::string title);
+
 	// These two functions create a way to make a busy cursor instead
 	// of an arrow when someone's busy doing something. Draw an
 	// arrow/hour if busycount > 0.
@@ -274,7 +296,7 @@ class LLWindowManager
 		U32 flags = 0,
 		BOOL fullscreen = FALSE,
 		BOOL clearBg = FALSE,
-		BOOL disable_vsync = TRUE,
+		BOOL enable_vsync = FALSE,
 		BOOL use_gl = TRUE,
 		BOOL ignore_pixel_depth = FALSE,
 		U32 fsaa_samples = 0);
diff --git a/indra/llwindow/llwindowheadless.cpp b/indra/llwindow/llwindowheadless.cpp
index 70f473281b6170f1c16ebb0bdbd66874952be003..c3738af6ca4cd5303a600796eba0c1da375b0429 100644
--- a/indra/llwindow/llwindowheadless.cpp
+++ b/indra/llwindow/llwindowheadless.cpp
@@ -35,7 +35,7 @@
 //
 LLWindowHeadless::LLWindowHeadless(LLWindowCallbacks* callbacks, const std::string& title, const std::string& name, S32 x, S32 y, S32 width, S32 height,
 							 U32 flags,  BOOL fullscreen, BOOL clear_background,
-							 BOOL disable_vsync, BOOL use_gl, BOOL ignore_pixel_depth)
+							 BOOL enable_vsync, BOOL use_gl, BOOL ignore_pixel_depth)
 	: LLWindow(callbacks, fullscreen, flags)
 {
 	// Initialize a headless keyboard.
diff --git a/indra/llwindow/llwindowheadless.h b/indra/llwindow/llwindowheadless.h
index c692666df140d2203d35c2f2fe8c38b028efda79..410da79623872d20ffe393c8d95491fce7dcf4cc 100644
--- a/indra/llwindow/llwindowheadless.h
+++ b/indra/llwindow/llwindowheadless.h
@@ -48,9 +48,16 @@ class LLWindowHeadless : public LLWindow
 	/*virtual*/ BOOL setPosition(LLCoordScreen position) {return FALSE;};
 	/*virtual*/ BOOL setSizeImpl(LLCoordScreen size) {return FALSE;};
 	/*virtual*/ BOOL setSizeImpl(LLCoordWindow size) {return FALSE;};
-	/*virtual*/ BOOL switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL disable_vsync, const LLCoordScreen * const posp = NULL) {return FALSE;};
-	/*virtual*/ BOOL setCursorPosition(LLCoordWindow position) {return FALSE;};
-	/*virtual*/ BOOL getCursorPosition(LLCoordWindow *position) {return FALSE;};
+	/*virtual*/ BOOL switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL enable_vsync, const LLCoordScreen * const posp = NULL) {return FALSE;};
+    void* createSharedContext()  { return nullptr; }
+    void makeContextCurrent(void*)  {}
+    void destroySharedContext(void*)  {}
+    /*virtual*/ void toggleVSync(bool enable_vsync) { }
+    /*virtual*/ BOOL setCursorPosition(LLCoordWindow position) {return FALSE;};
+    /*virtual*/ BOOL getCursorPosition(LLCoordWindow *position) {return FALSE;};
+#if LL_WINDOWS
+    /*virtual*/ BOOL getCursorDelta(LLCoordCommon* delta) { return FALSE; }
+#endif
 	/*virtual*/ void showCursor() {};
 	/*virtual*/ void hideCursor() {};
 	/*virtual*/ void showCursorFromMouseMove() {};
@@ -97,7 +104,7 @@ class LLWindowHeadless : public LLWindow
 		S32 x, S32 y, 
 		S32 width, S32 height,
 		U32 flags,  BOOL fullscreen, BOOL clear_background,
-		BOOL disable_vsync, BOOL use_gl, BOOL ignore_pixel_depth);
+		BOOL enable_vsync, BOOL use_gl, BOOL ignore_pixel_depth);
 	virtual ~LLWindowHeadless();
 
 private:
diff --git a/indra/llwindow/llwindowmacosx-objc.mm b/indra/llwindow/llwindowmacosx-objc.mm
index f895c1764396b862aa4adf246c3f22e9b7816559..5ec9b017cf1db4144a3f370658e9cde0af271f00 100644
--- a/indra/llwindow/llwindowmacosx-objc.mm
+++ b/indra/llwindow/llwindowmacosx-objc.mm
@@ -100,13 +100,13 @@ const unsigned short *copyFromPBoard()
 CursorRef createImageCursor(const char *fullpath, int hotspotX, int hotspotY)
 {
 	NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
-	
+
 	// extra retain on the NSCursor since we want it to live for the lifetime of the app.
 	NSCursor *cursor =
 	[[[NSCursor alloc]
 	  initWithImage:
 	  [[[NSImage alloc] initWithContentsOfFile:
-		[NSString stringWithFormat:@"%s", fullpath]
+		[NSString stringWithUTF8String:fullpath]
 		]autorelease]
 	  hotSpot:NSMakePoint(hotspotX, hotspotY)
 	  ]retain];
diff --git a/indra/llwindow/llwindowmacosx.cpp b/indra/llwindow/llwindowmacosx.cpp
index 24ce5131d557cc61ab662da318f4264398093946..c29131d60bc2566835e7680d59cc70ba48c65a6e 100644
--- a/indra/llwindow/llwindowmacosx.cpp
+++ b/indra/llwindow/llwindowmacosx.cpp
@@ -111,7 +111,7 @@ LLWindowMacOSX::LLWindowMacOSX(LLWindowCallbacks* callbacks,
 							   const std::string& title, const std::string& name, S32 x, S32 y, S32 width,
 							   S32 height, U32 flags,
 							   BOOL fullscreen, BOOL clearBg,
-							   BOOL disable_vsync, BOOL use_gl,
+							   BOOL enable_vsync, BOOL use_gl,
 							   BOOL ignore_pixel_depth,
 							   U32 fsaa_samples)
 	: LLWindow(NULL, fullscreen, flags)
@@ -165,7 +165,7 @@ LLWindowMacOSX::LLWindowMacOSX(LLWindowCallbacks* callbacks,
 	// Stash an object pointer for OSMessageBox()
 	gWindowImplementation = this;
 	// Create the GL context and set it up for windowed or fullscreen, as appropriate.
-	if(createContext(x, y, width, height, 32, fullscreen, disable_vsync))
+	if(createContext(x, y, width, height, 32, fullscreen, enable_vsync))
 	{
 		if(mWindow != NULL)
 		{
@@ -619,10 +619,8 @@ void LLWindowMacOSX::getMouseDeltas(float* delta)
 	delta[1] = mCursorLastEventDeltaY;
 }
 
-BOOL LLWindowMacOSX::createContext(int x, int y, int width, int height, int bits, BOOL fullscreen, BOOL disable_vsync)
+BOOL LLWindowMacOSX::createContext(int x, int y, int width, int height, int bits, BOOL fullscreen, BOOL enable_vsync)
 {
-	BOOL			glNeedsInit = FALSE;
-
 	mFullscreen = fullscreen;
 	
 	if (mWindow == NULL)
@@ -634,12 +632,9 @@ BOOL LLWindowMacOSX::createContext(int x, int y, int width, int height, int bits
 	{
 		// Our OpenGL view is already defined within SecondLife.xib.
 		// Get the view instead.
-		mGLView = createOpenGLView(mWindow, mFSAASamples, !disable_vsync);
+		mGLView = createOpenGLView(mWindow, mFSAASamples, enable_vsync);
 		mContext = getCGLContextObj(mGLView);
 		
-		// Since we just created the context, it needs to be set up.
-		glNeedsInit = TRUE;
-		
 		gGLManager.mVRAM = getVramSize(mGLView);
 	}
 	
@@ -661,17 +656,7 @@ BOOL LLWindowMacOSX::createContext(int x, int y, int width, int height, int bits
 	}
 
 	// Disable vertical sync for swap
-	GLint frames_per_swap = 0;
-	if (disable_vsync)
-	{
-		frames_per_swap = 0;
-	}
-	else
-	{
-		frames_per_swap = 1;
-	}
-	
-	CGLSetParameter(mContext, kCGLCPSwapInterval, &frames_per_swap);
+    toggleVSync(enable_vsync);
 
 	//enable multi-threaded OpenGL
 	if (sUseMultGL)
@@ -698,7 +683,7 @@ BOOL LLWindowMacOSX::createContext(int x, int y, int width, int height, int bits
 
 // We only support OS X 10.7's fullscreen app mode which is literally a full screen window that fills a virtual desktop.
 // This makes this method obsolete.
-BOOL LLWindowMacOSX::switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL disable_vsync, const LLCoordScreen * const posp)
+BOOL LLWindowMacOSX::switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL enable_vsync, const LLCoordScreen * const posp)
 {
 	return FALSE;
 }
@@ -1676,7 +1661,7 @@ void LLWindowMacOSX::hideCursor()
 
 void LLWindowMacOSX::showCursor()
 {
-	if(mCursorHidden)
+	if(mCursorHidden || !isCGCursorVisible())
 	{
 		//		LL_INFOS() << "showCursor: showing" << LL_ENDL;
 		mCursorHidden = FALSE;
@@ -1731,9 +1716,7 @@ void LLSplashScreenMacOSX::updateImpl(const std::string& mesg)
 {
 	if(mWindow != NULL)
 	{
-		CFStringRef string = NULL;
-
-		string = CFStringCreateWithCString(NULL, mesg.c_str(), kCFStringEncodingUTF8);
+		CFStringCreateWithCString(NULL, mesg.c_str(), kCFStringEncodingUTF8);
 	}
 }
 
@@ -1920,6 +1903,49 @@ void LLWindowMacOSX::allowLanguageTextInput(LLPreeditor *preeditor, BOOL b)
     allowDirectMarkedTextInput(b, mGLView); // mLanguageTextInputAllowed and mMarkedTextAllowed should be updated at once (by Pell Smit
 }
 
+class sharedContext 
+{
+public:
+    CGLContextObj mContext;
+};
+
+void* LLWindowMacOSX::createSharedContext()
+{
+    sharedContext* sc = new sharedContext();
+    CGLCreateContext(mPixelFormat, mContext, &(sc->mContext));
+
+    return (void *)sc;
+}
+
+void LLWindowMacOSX::makeContextCurrent(void* context)
+{
+    CGLSetCurrentContext(((sharedContext*)context)->mContext);
+}
+
+void LLWindowMacOSX::destroySharedContext(void* context)
+{
+    sharedContext* sc = (sharedContext*)context;
+
+    CGLDestroyContext(sc->mContext);
+
+    delete sc;
+}
+
+void LLWindowMacOSX::toggleVSync(bool enable_vsync)
+{
+    GLint frames_per_swap = 0;
+    if (!enable_vsync)
+    {
+        frames_per_swap = 0;
+    }
+    else
+    {
+        frames_per_swap = 1;
+    }
+    
+    CGLSetParameter(mContext, kCGLCPSwapInterval, &frames_per_swap);
+}
+
 void LLWindowMacOSX::interruptLanguageTextInput()
 {
 	commitCurrentPreedit(mGLView);
diff --git a/indra/llwindow/llwindowmacosx.h b/indra/llwindow/llwindowmacosx.h
index bf45238c8d91bd1150108ee16e88d86faefd0506..b0f339e1db8282bef2feb84883b4d10018cb080e 100644
--- a/indra/llwindow/llwindowmacosx.h
+++ b/indra/llwindow/llwindowmacosx.h
@@ -41,85 +41,84 @@
 #undef verify
 #undef require
 
-
 class LLWindowMacOSX : public LLWindow
 {
 public:
-	/*virtual*/ void show();
-	/*virtual*/ void hide();
-	/*virtual*/ void close();
-	/*virtual*/ BOOL getVisible();
-	/*virtual*/ BOOL getMinimized();
-	/*virtual*/ BOOL getMaximized();
-	/*virtual*/ BOOL maximize();
-	/*virtual*/ void minimize();
-	/*virtual*/ void restore();
-	/*virtual*/ BOOL getFullscreen();
-	/*virtual*/ BOOL getPosition(LLCoordScreen *position);
-	/*virtual*/ BOOL getSize(LLCoordScreen *size);
-	/*virtual*/ BOOL getSize(LLCoordWindow *size);
-	/*virtual*/ BOOL setPosition(LLCoordScreen position);
-	/*virtual*/ BOOL setSizeImpl(LLCoordScreen size);
-	/*virtual*/ BOOL setSizeImpl(LLCoordWindow size);
-	/*virtual*/ BOOL switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL disable_vsync, const LLCoordScreen * const posp = NULL);
-	/*virtual*/ BOOL setCursorPosition(LLCoordWindow position);
-	/*virtual*/ BOOL getCursorPosition(LLCoordWindow *position);
-	/*virtual*/ void showCursor();
-	/*virtual*/ void hideCursor();
-	/*virtual*/ void showCursorFromMouseMove();
-	/*virtual*/ void hideCursorUntilMouseMove();
-	/*virtual*/ BOOL isCursorHidden();
-	/*virtual*/ void updateCursor();
-	/*virtual*/ ECursorType getCursor() const;
-	/*virtual*/ void captureMouse();
-	/*virtual*/ void releaseMouse();
-	/*virtual*/ void setMouseClipping( BOOL b );
-	/*virtual*/ BOOL isClipboardTextAvailable();
-	/*virtual*/ BOOL pasteTextFromClipboard(LLWString &dst);
-	/*virtual*/ BOOL copyTextToClipboard(const LLWString & src);
-	/*virtual*/ void flashIcon(F32 seconds);
-	/*virtual*/ F32 getGamma();
-	/*virtual*/ BOOL setGamma(const F32 gamma); // Set the gamma
-	/*virtual*/ U32 getFSAASamples();
-	/*virtual*/ void setFSAASamples(const U32 fsaa_samples);
-	/*virtual*/ BOOL restoreGamma();			// Restore original gamma table (before updating gamma)
-	/*virtual*/ ESwapMethod getSwapMethod() { return mSwapMethod; }
-	/*virtual*/ void gatherInput();
-	/*virtual*/ void delayInputProcessing() {};
-	/*virtual*/ void swapBuffers();
+	void show() override;
+	void hide() override;
+	void close() override;
+	BOOL getVisible() override;
+	BOOL getMinimized() override;
+	BOOL getMaximized() override;
+	BOOL maximize() override;
+	void minimize() override;
+	void restore() override;
+	BOOL getFullscreen();
+	BOOL getPosition(LLCoordScreen *position) override;
+	BOOL getSize(LLCoordScreen *size) override;
+	BOOL getSize(LLCoordWindow *size) override;
+	BOOL setPosition(LLCoordScreen position) override;
+	BOOL setSizeImpl(LLCoordScreen size) override;
+	BOOL setSizeImpl(LLCoordWindow size) override;
+	BOOL switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL enable_vsync, const LLCoordScreen * const posp = NULL) override;
+	BOOL setCursorPosition(LLCoordWindow position) override;
+	BOOL getCursorPosition(LLCoordWindow *position) override;
+	void showCursor() override;
+	void hideCursor() override;
+	void showCursorFromMouseMove() override;
+	void hideCursorUntilMouseMove() override;
+	BOOL isCursorHidden() override;
+	void updateCursor() override;
+	ECursorType getCursor() const override;
+	void captureMouse() override;
+	void releaseMouse() override;
+	void setMouseClipping( BOOL b ) override;
+	BOOL isClipboardTextAvailable() override;
+	BOOL pasteTextFromClipboard(LLWString &dst) override;
+	BOOL copyTextToClipboard(const LLWString & src) override;
+	void flashIcon(F32 seconds) override;
+	F32 getGamma() override;
+	BOOL setGamma(const F32 gamma) override; // Set the gamma
+	U32 getFSAASamples() override;
+	void setFSAASamples(const U32 fsaa_samples) override;
+	BOOL restoreGamma() override;			// Restore original gamma table (before updating gamma)
+	ESwapMethod getSwapMethod() override { return mSwapMethod; }
+	void gatherInput() override;
+	void delayInputProcessing() override {};
+	void swapBuffers() override;
 	
 	// handy coordinate space conversion routines
-	/*virtual*/ BOOL convertCoords(LLCoordScreen from, LLCoordWindow *to);
-	/*virtual*/ BOOL convertCoords(LLCoordWindow from, LLCoordScreen *to);
-	/*virtual*/ BOOL convertCoords(LLCoordWindow from, LLCoordGL *to);
-	/*virtual*/ BOOL convertCoords(LLCoordGL from, LLCoordWindow *to);
-	/*virtual*/ BOOL convertCoords(LLCoordScreen from, LLCoordGL *to);
-	/*virtual*/ BOOL convertCoords(LLCoordGL from, LLCoordScreen *to);
+	BOOL convertCoords(LLCoordScreen from, LLCoordWindow *to) override;
+	BOOL convertCoords(LLCoordWindow from, LLCoordScreen *to) override;
+	BOOL convertCoords(LLCoordWindow from, LLCoordGL *to) override;
+	BOOL convertCoords(LLCoordGL from, LLCoordWindow *to) override;
+	BOOL convertCoords(LLCoordScreen from, LLCoordGL *to) override;
+	BOOL convertCoords(LLCoordGL from, LLCoordScreen *to) override;
 
-	/*virtual*/ LLWindowResolution* getSupportedResolutions(S32 &num_resolutions);
-	/*virtual*/ F32	getNativeAspectRatio();
-	/*virtual*/ F32 getPixelAspectRatio();
-	/*virtual*/ void setNativeAspectRatio(F32 ratio) { mOverrideAspectRatio = ratio; }
+	LLWindowResolution* getSupportedResolutions(S32 &num_resolutions) override;
+	F32	getNativeAspectRatio() override;
+	F32 getPixelAspectRatio() override;
+	void setNativeAspectRatio(F32 ratio) override { mOverrideAspectRatio = ratio; }
 
-	/*virtual*/ void beforeDialog();
-	/*virtual*/ void afterDialog();
+	void beforeDialog() override;
+	void afterDialog() override;
 
-	/*virtual*/ BOOL dialogColorPicker(F32 *r, F32 *g, F32 *b);
+	BOOL dialogColorPicker(F32 *r, F32 *g, F32 *b) override;
 
-	/*virtual*/ void *getPlatformWindow();
-	/*virtual*/ void bringToFront() {};
+	void *getPlatformWindow() override;
+	void bringToFront() override {};
 	
-	/*virtual*/ void allowLanguageTextInput(LLPreeditor *preeditor, BOOL b);
-	/*virtual*/ void interruptLanguageTextInput();
-	/*virtual*/ void spawnWebBrowser(const std::string& escaped_url, bool async);
-	/*virtual*/ F32 getSystemUISize();
+	void allowLanguageTextInput(LLPreeditor *preeditor, BOOL b) override;
+	void interruptLanguageTextInput() override;
+	void spawnWebBrowser(const std::string& escaped_url, bool async) override;
+	F32 getSystemUISize() override;
 
 	static std::vector<std::string> getDisplaysResolutionList();
 
 	static std::vector<std::string> getDynamicFallbackFontList();
 
 	// Provide native key event data
-	/*virtual*/ LLSD getNativeKeyData();
+	LLSD getNativeKeyData() override;
 	
 	void* getWindow() { return mWindow; }
 	LLWindowCallbacks* getCallbacks() { return mCallbacks; }
@@ -132,16 +131,27 @@ class LLWindowMacOSX : public LLWindow
     
     bool allowsLanguageInput() { return mLanguageTextInputAllowed; }
 
+    //create a new GL context that shares a namespace with this Window's main GL context and make it current on the current thread
+    // returns a pointer to be handed back to destroySharedConext/makeContextCurrent
+    void* createSharedContext() override;
+    //make the given context current on the current thread
+    void makeContextCurrent(void* context) override;
+    //destroy the given context that was retrieved by createSharedContext()
+    //Must be called on the same thread that called createSharedContext()
+    void destroySharedContext(void* context) override;
+
+    void toggleVSync(bool enable_vsync) override;
+
 protected:
 	LLWindowMacOSX(LLWindowCallbacks* callbacks,
 		const std::string& title, const std::string& name, int x, int y, int width, int height, U32 flags,
-		BOOL fullscreen, BOOL clearBg, BOOL disable_vsync, BOOL use_gl,
+		BOOL fullscreen, BOOL clearBg, BOOL enable_vsync, BOOL use_gl,
 		BOOL ignore_pixel_depth,
 		U32 fsaa_samples);
 		~LLWindowMacOSX();
 
 	void	initCursors();
-	BOOL	isValid();
+	BOOL	isValid() override;
 	void	moveWindow(const LLCoordScreen& position,const LLCoordScreen& size);
 
 
@@ -157,7 +167,7 @@ class LLWindowMacOSX : public LLWindow
 	BOOL	shouldPostQuit() { return mPostQuit; }
     
     //Satisfy MAINT-3135 and MAINT-3288 with a flag.
-    /*virtual */ void setOldResize(bool oldresize) {setResizeMode(oldresize, mGLView); }
+    /*virtual */ void setOldResize(bool oldresize) override {setResizeMode(oldresize, mGLView); }
 
 private:
     void restoreGLContext();
@@ -168,7 +178,7 @@ class LLWindowMacOSX : public LLWindow
 	//
 
 	// create or re-create the GL context/window.  Called from the constructor and switchContext().
-	BOOL createContext(int x, int y, int width, int height, int bits, BOOL fullscreen, BOOL disable_vsync);
+	BOOL createContext(int x, int y, int width, int height, int bits, BOOL fullscreen, BOOL enable_vsync);
 	void destroyContext();
 	void setupFailure(const std::string& text, const std::string& caption, U32 type);
 	void adjustCursorDecouple(bool warpingMouse = false);
@@ -231,9 +241,9 @@ class LLSplashScreenMacOSX : public LLSplashScreen
 	LLSplashScreenMacOSX();
 	virtual ~LLSplashScreenMacOSX();
 
-	/*virtual*/ void showImpl();
-	/*virtual*/ void updateImpl(const std::string& mesg);
-	/*virtual*/ void hideImpl();
+	void showImpl();
+	void updateImpl(const std::string& mesg);
+	void hideImpl();
 
 private:
 	WindowRef   mWindow;
diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp
index f303d1bb210fda1a31d8639bd785e42e090352c7..c487877cafdff183543c43af6dd9a8ad1d6ef6ac 100644
--- a/indra/llwindow/llwindowwin32.cpp
+++ b/indra/llwindow/llwindowwin32.cpp
@@ -45,6 +45,8 @@
 #include "lldir.h"
 #include "llsdutil.h"
 #include "llglslshader.h"
+#include "llthreadsafequeue.h"
+#include "stringize.h"
 
 // System includes
 #include <commdlg.h>
@@ -54,6 +56,10 @@
 #include <shellapi.h>
 #include <fstream>
 #include <Imm.h>
+#include <iomanip>
+#include <future>
+#include <sstream>
+#include <utility>                  // std::pair
 
 // Require DirectInput version 8
 #define DIRECTINPUT_VERSION 0x0800
@@ -77,8 +83,24 @@ const F32	ICON_FLASH_TIME = 0.5f;
 #define USER_DEFAULT_SCREEN_DPI 96 // Win7
 #endif
 
+// Claim a couple unused GetMessage() message IDs
+const UINT WM_DUMMY_(WM_USER + 0x0017);
+const UINT WM_POST_FUNCTION_(WM_USER + 0x0018);
+
 extern BOOL gDebugWindowProc;
 
+static std::thread::id sWindowThreadId;
+static std::thread::id sMainThreadId;
+
+#if 1 // flip to zero to enable assertions for functions being called from wrong thread
+#define ASSERT_MAIN_THREAD()
+#define ASSERT_WINDOW_THREAD()
+#else
+#define ASSERT_MAIN_THREAD() llassert(LLThread::currentID() == sMainThreadId)
+#define ASSERT_WINDOW_THREAD() llassert(LLThread::currentID() == sWindowThreadId)
+#endif
+
+
 LPWSTR gIconResource = IDI_APPLICATION;
 LPDIRECTINPUT8 gDirectInput8;
 
@@ -161,23 +183,19 @@ DWORD	LLWindowWin32::sWinIMESentenceMode = IME_SMODE_AUTOMATIC;
 LLCoordWindow LLWindowWin32::sWinIMEWindowPosition(-1,-1);
 
 // The following class LLWinImm delegates Windows IMM APIs.
-// We need this because some language versions of Windows,
-// e.g., US version of Windows XP, doesn't install IMM32.DLL
-// as a default, and we can't link against imm32.lib statically.
-// I believe DLL loading of this type is best suited to do
-// in a static initialization of a class.  What I'm not sure is
-// whether it follows the Linden Conding Standard... 
-// See http://wiki.secondlife.com/wiki/Coding_standards#Static_Members
+// It was originally introduced to support US Windows XP, on which we needed
+// to dynamically load IMM32.DLL and use GetProcAddress to resolve its entry
+// points. Now that that's moot, we retain this wrapper only for hooks for
+// metrics.
 
 class LLWinImm
 {
 public:
-	static bool		isAvailable() { return sTheInstance.mHImmDll != NULL; }
+	static bool		isAvailable() { return true; }
 
 public:
 	// Wrappers for IMM API.
 	static BOOL		isIME(HKL hkl);															
-	static HWND		getDefaultIMEWnd(HWND hwnd);
 	static HIMC		getContext(HWND hwnd);													
 	static BOOL		releaseContext(HWND hwnd, HIMC himc);
 	static BOOL		getOpenStatus(HIMC himc);												
@@ -191,236 +209,96 @@ class LLWinImm
 	static BOOL		setCompositionFont(HIMC himc, LPLOGFONTW logfont);
 	static BOOL		setCandidateWindow(HIMC himc, LPCANDIDATEFORM candidate_form);
 	static BOOL		notifyIME(HIMC himc, DWORD action, DWORD index, DWORD value);
-
-private:
-	LLWinImm();
-	~LLWinImm();
-
-private:
-	// Pointers to IMM API.
-	BOOL	 	(WINAPI *mImmIsIME)(HKL);
-	HWND		(WINAPI *mImmGetDefaultIMEWnd)(HWND);
-	HIMC		(WINAPI *mImmGetContext)(HWND);
-	BOOL		(WINAPI *mImmReleaseContext)(HWND, HIMC);
-	BOOL		(WINAPI *mImmGetOpenStatus)(HIMC);
-	BOOL		(WINAPI *mImmSetOpenStatus)(HIMC, BOOL);
-	BOOL		(WINAPI *mImmGetConversionStatus)(HIMC, LPDWORD, LPDWORD);
-	BOOL		(WINAPI *mImmSetConversionStatus)(HIMC, DWORD, DWORD);
-	BOOL		(WINAPI *mImmGetCompostitionWindow)(HIMC, LPCOMPOSITIONFORM);
-	BOOL		(WINAPI *mImmSetCompostitionWindow)(HIMC, LPCOMPOSITIONFORM);
-	LONG		(WINAPI *mImmGetCompositionString)(HIMC, DWORD, LPVOID, DWORD);
-	BOOL		(WINAPI *mImmSetCompositionString)(HIMC, DWORD, LPVOID, DWORD, LPVOID, DWORD);
-	BOOL		(WINAPI *mImmSetCompositionFont)(HIMC, LPLOGFONTW);
-	BOOL		(WINAPI *mImmSetCandidateWindow)(HIMC, LPCANDIDATEFORM);
-	BOOL		(WINAPI *mImmNotifyIME)(HIMC, DWORD, DWORD, DWORD);
-
-private:
-	HMODULE		mHImmDll;
-	static LLWinImm sTheInstance;
 };
 
-LLWinImm LLWinImm::sTheInstance;
-
-LLWinImm::LLWinImm() : mHImmDll(NULL)
-{
-	// Check system metrics 
-	if ( !GetSystemMetrics( SM_IMMENABLED ) )
-		return;
-
-	mHImmDll = LoadLibraryA("Imm32");
-	if (mHImmDll != NULL)
-	{
-		mImmIsIME               = (BOOL (WINAPI *)(HKL))                    GetProcAddress(mHImmDll, "ImmIsIME");
-		mImmGetDefaultIMEWnd	= (HWND (WINAPI *)(HWND))					GetProcAddress(mHImmDll, "ImmGetDefaultIMEWnd");
-		mImmGetContext          = (HIMC (WINAPI *)(HWND))                   GetProcAddress(mHImmDll, "ImmGetContext");
-		mImmReleaseContext      = (BOOL (WINAPI *)(HWND, HIMC))             GetProcAddress(mHImmDll, "ImmReleaseContext");
-		mImmGetOpenStatus       = (BOOL (WINAPI *)(HIMC))                   GetProcAddress(mHImmDll, "ImmGetOpenStatus");
-		mImmSetOpenStatus       = (BOOL (WINAPI *)(HIMC, BOOL))             GetProcAddress(mHImmDll, "ImmSetOpenStatus");
-		mImmGetConversionStatus = (BOOL (WINAPI *)(HIMC, LPDWORD, LPDWORD)) GetProcAddress(mHImmDll, "ImmGetConversionStatus");
-		mImmSetConversionStatus = (BOOL (WINAPI *)(HIMC, DWORD, DWORD))     GetProcAddress(mHImmDll, "ImmSetConversionStatus");
-		mImmGetCompostitionWindow = (BOOL (WINAPI *)(HIMC, LPCOMPOSITIONFORM))   GetProcAddress(mHImmDll, "ImmGetCompositionWindow");
-		mImmSetCompostitionWindow = (BOOL (WINAPI *)(HIMC, LPCOMPOSITIONFORM))   GetProcAddress(mHImmDll, "ImmSetCompositionWindow");
-		mImmGetCompositionString= (LONG (WINAPI *)(HIMC, DWORD, LPVOID, DWORD))					GetProcAddress(mHImmDll, "ImmGetCompositionStringW");
-		mImmSetCompositionString= (BOOL (WINAPI *)(HIMC, DWORD, LPVOID, DWORD, LPVOID, DWORD))	GetProcAddress(mHImmDll, "ImmSetCompositionStringW");
-		mImmSetCompositionFont  = (BOOL (WINAPI *)(HIMC, LPLOGFONTW))		GetProcAddress(mHImmDll, "ImmSetCompositionFontW");
-		mImmSetCandidateWindow  = (BOOL (WINAPI *)(HIMC, LPCANDIDATEFORM))  GetProcAddress(mHImmDll, "ImmSetCandidateWindow");
-		mImmNotifyIME			= (BOOL (WINAPI *)(HIMC, DWORD, DWORD, DWORD))	GetProcAddress(mHImmDll, "ImmNotifyIME");
-
-		if (mImmIsIME == NULL ||
-			mImmGetDefaultIMEWnd == NULL ||
-			mImmGetContext == NULL ||
-			mImmReleaseContext == NULL ||
-			mImmGetOpenStatus == NULL ||
-			mImmSetOpenStatus == NULL ||
-			mImmGetConversionStatus == NULL ||
-			mImmSetConversionStatus == NULL ||
-			mImmGetCompostitionWindow == NULL ||
-			mImmSetCompostitionWindow == NULL ||
-			mImmGetCompositionString == NULL ||
-			mImmSetCompositionString == NULL ||
-			mImmSetCompositionFont == NULL ||
-			mImmSetCandidateWindow == NULL ||
-			mImmNotifyIME == NULL)
-		{
-			// If any of the above API entires are not found, we can't use IMM API.  
-			// So, turn off the IMM support.  We should log some warning message in 
-			// the case, since it is very unusual; these APIs are available from 
-			// the beginning, and all versions of IMM32.DLL should have them all.  
-			// Unfortunately, this code may be executed before initialization of 
-			// the logging channel (LL_WARNS()), and we can't do it here...  Yes, this 
-			// is one of disadvantages to use static constraction to DLL loading. 
-			FreeLibrary(mHImmDll);
-			mHImmDll = NULL;
-
-			// If we unload the library, make sure all the function pointers are cleared
-			mImmIsIME = NULL;
-			mImmGetDefaultIMEWnd = NULL;
-			mImmGetContext = NULL;
-			mImmReleaseContext = NULL;
-			mImmGetOpenStatus = NULL;
-			mImmSetOpenStatus = NULL;
-			mImmGetConversionStatus = NULL;
-			mImmSetConversionStatus = NULL;
-			mImmGetCompostitionWindow = NULL;
-			mImmSetCompostitionWindow = NULL;
-			mImmGetCompositionString = NULL;
-			mImmSetCompositionString = NULL;
-			mImmSetCompositionFont = NULL;
-			mImmSetCandidateWindow = NULL;
-			mImmNotifyIME = NULL;
-		}
-	}
-}
-
-
 // static 
-BOOL	LLWinImm::isIME(HKL hkl)															
+BOOL	LLWinImm::isIME(HKL hkl)
 { 
-	if ( sTheInstance.mImmIsIME )
-		return sTheInstance.mImmIsIME(hkl); 
-	return FALSE;
+	return ImmIsIME(hkl);
 }
 
 // static 
 HIMC		LLWinImm::getContext(HWND hwnd)
 {
-	if ( sTheInstance.mImmGetContext )
-		return sTheInstance.mImmGetContext(hwnd); 
-	return 0;
+	return ImmGetContext(hwnd);
 }
 
 //static 
 BOOL		LLWinImm::releaseContext(HWND hwnd, HIMC himc)
 { 
-	if ( sTheInstance.mImmIsIME )
-		return sTheInstance.mImmReleaseContext(hwnd, himc); 
-	return FALSE;
+	return ImmReleaseContext(hwnd, himc);
 }
 
 // static 
 BOOL		LLWinImm::getOpenStatus(HIMC himc)
 { 
-	if ( sTheInstance.mImmGetOpenStatus )
-		return sTheInstance.mImmGetOpenStatus(himc); 
-	return FALSE;
+	return ImmGetOpenStatus(himc);
 }
 
 // static 
-BOOL		LLWinImm::setOpenStatus(HIMC himc, BOOL status)									
+BOOL		LLWinImm::setOpenStatus(HIMC himc, BOOL status)
 { 
-	if ( sTheInstance.mImmSetOpenStatus )
-		return sTheInstance.mImmSetOpenStatus(himc, status); 
-	return FALSE;
+	return ImmSetOpenStatus(himc, status);
 }
 
 // static 
 BOOL		LLWinImm::getConversionStatus(HIMC himc, LPDWORD conversion, LPDWORD sentence)	
 { 
-	if ( sTheInstance.mImmGetConversionStatus )
-		return sTheInstance.mImmGetConversionStatus(himc, conversion, sentence); 
-	return FALSE;
+	return ImmGetConversionStatus(himc, conversion, sentence);
 }
 
 // static 
 BOOL		LLWinImm::setConversionStatus(HIMC himc, DWORD conversion, DWORD sentence)		
 { 
-	if ( sTheInstance.mImmSetConversionStatus )
-		return sTheInstance.mImmSetConversionStatus(himc, conversion, sentence); 
-	return FALSE;
+	return ImmSetConversionStatus(himc, conversion, sentence);
 }
 
 // static 
 BOOL		LLWinImm::getCompositionWindow(HIMC himc, LPCOMPOSITIONFORM form)					
 { 
-	if ( sTheInstance.mImmGetCompostitionWindow )
-		return sTheInstance.mImmGetCompostitionWindow(himc, form);	
-	return FALSE;
+	return ImmGetCompositionWindow(himc, form);
 }
 
 // static 
 BOOL		LLWinImm::setCompositionWindow(HIMC himc, LPCOMPOSITIONFORM form)					
 { 
-	if ( sTheInstance.mImmSetCompostitionWindow )
-		return sTheInstance.mImmSetCompostitionWindow(himc, form);	
-	return FALSE;
+	return ImmSetCompositionWindow(himc, form);
 }
 
 
 // static 
 LONG		LLWinImm::getCompositionString(HIMC himc, DWORD index, LPVOID data, DWORD length)					
 { 
-	if ( sTheInstance.mImmGetCompositionString )
-		return sTheInstance.mImmGetCompositionString(himc, index, data, length);	
-	return FALSE;
+	return ImmGetCompositionString(himc, index, data, length);
 }
 
 
 // static 
 BOOL		LLWinImm::setCompositionString(HIMC himc, DWORD index, LPVOID pComp, DWORD compLength, LPVOID pRead, DWORD readLength)					
 { 
-	if ( sTheInstance.mImmSetCompositionString )
-		return sTheInstance.mImmSetCompositionString(himc, index, pComp, compLength, pRead, readLength);	
-	return FALSE;
+	return ImmSetCompositionString(himc, index, pComp, compLength, pRead, readLength);
 }
 
 // static 
 BOOL		LLWinImm::setCompositionFont(HIMC himc, LPLOGFONTW pFont)					
 { 
-	if ( sTheInstance.mImmSetCompositionFont )
-		return sTheInstance.mImmSetCompositionFont(himc, pFont);	
-	return FALSE;
+	return ImmSetCompositionFont(himc, pFont);
 }
 
 // static 
 BOOL		LLWinImm::setCandidateWindow(HIMC himc, LPCANDIDATEFORM form)					
 { 
-	if ( sTheInstance.mImmSetCandidateWindow )
-		return sTheInstance.mImmSetCandidateWindow(himc, form);	
-	return FALSE;
+	return ImmSetCandidateWindow(himc, form);
 }
 
 // static 
 BOOL		LLWinImm::notifyIME(HIMC himc, DWORD action, DWORD index, DWORD value)					
 { 
-	if ( sTheInstance.mImmNotifyIME )
-		return sTheInstance.mImmNotifyIME(himc, action, index, value);	
-	return FALSE;
+	return ImmNotifyIME(himc, action, index, value);
 }
 
 
 
-
-// ----------------------------------------------------------------------------------------
-LLWinImm::~LLWinImm()
-{
-	if (mHImmDll != NULL)
-	{
-		FreeLibrary(mHImmDll);
-		mHImmDll = NULL;
-	}
-}
-
-
 class LLMonitorInfo
 {
 public:
@@ -454,16 +332,83 @@ class LLMonitorInfo
 
 static LLMonitorInfo sMonitorInfo;
 
+
+// Thread that owns the Window Handle
+// This whole struct is private to LLWindowWin32, which needs to mess with its
+// members, which is why it's a struct rather than a class. In effect, we make
+// the containing class a friend.
+struct LLWindowWin32::LLWindowWin32Thread : public LL::ThreadPool
+{
+    static const int MAX_QUEUE_SIZE = 2048;
+
+    LLThreadSafeQueue<MSG> mMessageQueue;
+
+    LLWindowWin32Thread();
+
+    void run() override;
+
+    /// called by main thread to post work to this window thread
+    template <typename CALLABLE>
+    void post(CALLABLE&& func)
+    {
+        try
+        {
+            getQueue().post(std::forward<CALLABLE>(func));
+        }
+        catch (const LLThreadSafeQueueInterrupt&)
+        {
+            // Shutdown timing is tricky. The main thread can end up trying
+            // to post a cursor position after having closed the WorkQueue.
+        }
+    }
+
+    /**
+     * Like post(), Post() is a way of conveying a single work item to this
+     * thread. Its virtue is that it will definitely be executed "soon" rather
+     * than potentially waiting for the next frame: it uses PostMessage() to
+     * break us out of the window thread's blocked GetMessage() call. It's
+     * more expensive, though, not only from the Windows API latency of
+     * PostMessage() and GetMessage(), but also because it involves heap
+     * allocation and release.
+     *
+     * Require HWND from caller, even though we store an HWND locally.
+     * Otherwise, if our mWindowHandle was accessed from both threads, we'd
+     * have to protect it with a mutex.
+     */
+    template <typename CALLABLE>
+    void Post(HWND windowHandle, CALLABLE&& func)
+    {
+        // Move func to the heap. If we knew FuncType could fit into LPARAM,
+        // we could simply instantiate FuncType and pass it by value. But
+        // since we don't, we must put that on the heap as well as the
+        // internal heap allocation it likely requires to store func.
+        auto ptr = new FuncType(std::move(func));
+        WPARAM wparam{ 0xF1C };
+        LL_DEBUGS("Window") << "PostMessage(" << std::hex << windowHandle
+                            << ", " << WM_POST_FUNCTION_
+                            << ", " << wparam << std::dec << LL_ENDL;
+        PostMessage(windowHandle, WM_POST_FUNCTION_, wparam, LPARAM(ptr));
+    }
+
+    using FuncType = std::function<void()>;
+    // call GetMessage() and pull enqueue messages for later processing
+    void gatherInput();
+    HWND mWindowHandle = NULL;
+    HDC mhDC = 0;
+};
+
+
 LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks,
 							 const std::string& title, const std::string& name, S32 x, S32 y, S32 width,
 							 S32 height, U32 flags, 
 							 BOOL fullscreen, BOOL clearBg,
-							 BOOL disable_vsync, BOOL use_gl,
+							 BOOL enable_vsync, BOOL use_gl,
 							 BOOL ignore_pixel_depth,
 							 U32 fsaa_samples)
 	: LLWindow(callbacks, fullscreen, flags)
 {
-	
+    sMainThreadId = LLThread::currentID();
+    mWindowThread = new LLWindowWin32Thread();
 	//MAINT-516 -- force a load of opengl32.dll just in case windows went sideways 
 	LoadLibrary(L"opengl32.dll");
 
@@ -471,7 +416,6 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks,
 	mIconResource = gIconResource;
 	mOverrideAspectRatio = 0.f;
 	mNativeAspectRatio = 0.f;
-	mMousePositionModified = FALSE;
 	mInputProcessingPaused = FALSE;
 	mPreeditor = NULL;
 	mKeyCharCode = 0;
@@ -483,6 +427,9 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks,
 	memset(mPrevGammaRamp, 0, sizeof(mPrevGammaRamp));
 	mCustomGammaSet = FALSE;
 	mWindowHandle = NULL;
+
+    mRect = {0, 0, 0, 0};
+    mClientRect = {0, 0, 0, 0};
 	
 	if (!SystemParametersInfo(SPI_GETMOUSEVANISH, 0, &mMouseVanish, 0))
 	{
@@ -535,7 +482,6 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks,
 
 	// Make an instance of our window then define the window class
 	mhInstance = GetModuleHandle(NULL);
-	mWndProc = NULL;
 
     // Init Direct Input - needed for joystick / Spacemouse
 
@@ -784,7 +730,7 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks,
 	LLCoordScreen windowPos(x,y);
 	LLCoordScreen windowSize(window_rect.right - window_rect.left,
 							 window_rect.bottom - window_rect.top);
-	if (!switchContext(mFullscreen, windowSize, TRUE, &windowPos))
+	if (!switchContext(mFullscreen, windowSize, enable_vsync, &windowPos))
 	{
 		return;
 	}
@@ -793,6 +739,13 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks,
 	initCursors();
 	setCursor( UI_CURSOR_ARROW );
 
+    mRawMouse.usUsagePage = 0x01;          // HID_USAGE_PAGE_GENERIC
+    mRawMouse.usUsage = 0x02;              // HID_USAGE_GENERIC_MOUSE
+    mRawMouse.dwFlags = 0;    // adds mouse and also ignores legacy mouse messages
+    mRawMouse.hwndTarget = 0;
+
+    RegisterRawInputDevices(&mRawMouse, 1, sizeof(mRawMouse));
+
 	// Initialize (boot strap) the Language text input management,
 	// based on the system's (or user's) default settings.
 	allowLanguageTextInput(NULL, FALSE);
@@ -811,6 +764,8 @@ LLWindowWin32::~LLWindowWin32()
 
 	delete [] mWindowClassName;
 	mWindowClassName = NULL;
+    
+    delete mWindowThread;
 }
 
 void LLWindowWin32::show()
@@ -850,7 +805,7 @@ void LLWindowWin32::restore()
 // I'm turning off optimizations for this part to be sure code executes as intended
 // (it is a straw, but I have no idea why else __try can get overruled)
 #pragma optimize("", off)
-bool destroy_window_handler(HWND &hWnd)
+bool destroy_window_handler(HWND hWnd)
 {
     bool res;
     __try
@@ -919,37 +874,48 @@ void LLWindowWin32::close()
 	// Restore gamma to the system values.
 	restoreGamma();
 
-	if (mhDC)
-	{
-		if (!ReleaseDC(mWindowHandle, mhDC))
-		{
-			LL_WARNS("Window") << "Release of ghDC failed" << LL_ENDL;
-		}
-		mhDC = NULL;
-	}
-
 	LL_DEBUGS("Window") << "Destroying Window" << LL_ENDL;
 
-    if (IsWindow(mWindowHandle))
-    {
-        // Make sure we don't leave a blank toolbar button.
-        ShowWindow(mWindowHandle, SW_HIDE);
-
-        // This causes WM_DESTROY to be sent *immediately*
-        if (!destroy_window_handler(mWindowHandle))
+    mWindowThread->post([=]()
         {
-            OSMessageBox(mCallbacks->translateString("MBDestroyWinFailed"),
-                mCallbacks->translateString("MBShutdownErr"),
-                OSMB_OK);
-        }
-    }
-    else
-    {
-        // Something killed the window while we were busy destroying gl or handle somehow got broken
-        LL_WARNS("Window") << "Failed to destroy Window, invalid handle!" << LL_ENDL;
-    }
+            if (IsWindow(mWindowHandle))
+            {
+                if (mhDC)
+                {
+                    if (!ReleaseDC(mWindowHandle, mhDC))
+                    {
+                        LL_WARNS("Window") << "Release of ghDC failed!" << LL_ENDL;
+                    }
+                }
+
+                // Make sure we don't leave a blank toolbar button.
+                ShowWindow(mWindowHandle, SW_HIDE);
+
+                // This causes WM_DESTROY to be sent *immediately*
+                if (!destroy_window_handler(mWindowHandle))
+                {
+                    OSMessageBox(mCallbacks->translateString("MBDestroyWinFailed"),
+                        mCallbacks->translateString("MBShutdownErr"),
+                        OSMB_OK);
+                }
+            }
+            else
+            {
+                // Something killed the window while we were busy destroying gl or handle somehow got broken
+                LL_WARNS("Window") << "Failed to destroy Window, invalid handle!" << LL_ENDL;
+            }
 
-	mWindowHandle = NULL;
+        });
+    // Window thread might be waiting for a getMessage(), give it
+    // a push to enshure it will process destroy_window_handler
+    kickWindowThread();
+
+    // Even though the above lambda might not yet have run, we've already
+    // bound mWindowHandle into it by value, which should suffice for the
+    // operations we're asking. That's the last time WE should touch it.
+    mhDC = NULL;
+    mWindowHandle = NULL;
+    mWindowThread->close();
 }
 
 BOOL LLWindowWin32::isValid()
@@ -996,49 +962,22 @@ BOOL LLWindowWin32::getFullscreen()
 
 BOOL LLWindowWin32::getPosition(LLCoordScreen *position)
 {
-	RECT window_rect;
-
-	if (!mWindowHandle ||
-		!GetWindowRect(mWindowHandle, &window_rect) ||
-		NULL == position)
-	{
-		return FALSE;
-	}
-
-	position->mX = window_rect.left;
-	position->mY = window_rect.top;
+    position->mX = mRect.left;
+	position->mY = mRect.top;
 	return TRUE;
 }
 
 BOOL LLWindowWin32::getSize(LLCoordScreen *size)
 {
-	RECT window_rect;
-
-	if (!mWindowHandle ||
-		!GetWindowRect(mWindowHandle, &window_rect) ||
-		NULL == size)
-	{
-		return FALSE;
-	}
-
-	size->mX = window_rect.right - window_rect.left;
-	size->mY = window_rect.bottom - window_rect.top;
+	size->mX = mRect.right - mRect.left;
+	size->mY = mRect.bottom - mRect.top;
 	return TRUE;
 }
 
 BOOL LLWindowWin32::getSize(LLCoordWindow *size)
 {
-	RECT client_rect;
-
-	if (!mWindowHandle ||
-		!GetClientRect(mWindowHandle, &client_rect) ||
-		NULL == size)
-	{
-		return FALSE;
-	}
-
-	size->mX = client_rect.right - client_rect.left;
-	size->mY = client_rect.bottom - client_rect.top;
+	size->mX = mClientRect.right - mClientRect.left;
+	size->mY = mClientRect.bottom - mClientRect.top;
 	return TRUE;
 }
 
@@ -1065,14 +1004,17 @@ BOOL LLWindowWin32::setSizeImpl(const LLCoordScreen size)
 		return FALSE;
 	}
 
-	WINDOWPLACEMENT placement;
-	placement.length = sizeof(WINDOWPLACEMENT);
-
-	if (!GetWindowPlacement(mWindowHandle, &placement)) return FALSE;
-
-	placement.showCmd = SW_RESTORE;
+    mWindowThread->post([=]()
+        {
+            WINDOWPLACEMENT placement;
+            placement.length = sizeof(WINDOWPLACEMENT);
 
-	if (!SetWindowPlacement(mWindowHandle, &placement)) return FALSE;
+            if (GetWindowPlacement(mWindowHandle, &placement))
+            {
+                placement.showCmd = SW_RESTORE;
+                SetWindowPlacement(mWindowHandle, &placement);
+            }
+        });
 
 	moveWindow(position, size);
 	return TRUE;
@@ -1084,177 +1026,165 @@ BOOL LLWindowWin32::setSizeImpl(const LLCoordWindow size)
 	DWORD dw_ex_style = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
 	DWORD dw_style = WS_OVERLAPPEDWINDOW;
 
-	AdjustWindowRectEx(&window_rect, dw_style, FALSE, dw_ex_style);
+    AdjustWindowRectEx(&window_rect, dw_style, FALSE, dw_ex_style);
 
 	return setSizeImpl(LLCoordScreen(window_rect.right - window_rect.left, window_rect.bottom - window_rect.top));
 }
 
 // changing fullscreen resolution
-BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL disable_vsync, const LLCoordScreen * const posp)
+BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen& size, BOOL enable_vsync, const LLCoordScreen* const posp)
 {
-	GLuint	pixel_format;
-	DEVMODE dev_mode;
-	::ZeroMemory(&dev_mode, sizeof(DEVMODE));
-	dev_mode.dmSize = sizeof(DEVMODE);
-	DWORD	current_refresh;
-	DWORD	dw_ex_style;
-	DWORD	dw_style;
-	RECT	window_rect = {0, 0, 0, 0};
-	S32 width = size.mX;
-	S32 height = size.mY;
-	BOOL auto_show = FALSE;
-
-	if (mhRC)	
-	{
-		auto_show = TRUE;
-		resetDisplayResolution();
-	}
-
-	if (EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dev_mode))
-	{
-		current_refresh = dev_mode.dmDisplayFrequency;
-	}
-	else
-	{
-		current_refresh = 60;
-	}
-
-	gGLManager.shutdownGL();
-	//destroy gl context
-	if (mhRC)
-	{
-		if (!wglMakeCurrent(NULL, NULL))
-		{
-			LL_WARNS("Window") << "Release of DC and RC failed" << LL_ENDL;
-		}
+    //called from main thread
+    GLuint	pixel_format;
+    DEVMODE dev_mode;
+    ::ZeroMemory(&dev_mode, sizeof(DEVMODE));
+    dev_mode.dmSize = sizeof(DEVMODE);
+    DWORD	current_refresh;
+    DWORD	dw_ex_style;
+    DWORD	dw_style;
+    RECT	window_rect = { 0, 0, 0, 0 };
+    S32 width = size.mX;
+    S32 height = size.mY;
+    BOOL auto_show = FALSE;
+
+    if (mhRC)
+    {
+        auto_show = TRUE;
+        resetDisplayResolution();
+    }
 
-		if (!wglDeleteContext(mhRC))
-		{
-			LL_WARNS("Window") << "Release of rendering context failed" << LL_ENDL;
-		}
+    if (EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dev_mode))
+    {
+        current_refresh = dev_mode.dmDisplayFrequency;
+    }
+    else
+    {
+        current_refresh = 60;
+    }
 
-		mhRC = NULL;
-	}
+    gGLManager.shutdownGL();
+    //destroy gl context
+    if (mhRC)
+    {
+        if (!wglMakeCurrent(NULL, NULL))
+        {
+            LL_WARNS("Window") << "Release of DC and RC failed" << LL_ENDL;
+        }
 
-	if (fullscreen)
-	{
-		mFullscreen = TRUE;
-		BOOL success = FALSE;
-		DWORD closest_refresh = 0;
+        if (!wglDeleteContext(mhRC))
+        {
+            LL_WARNS("Window") << "Release of rendering context failed" << LL_ENDL;
+        }
 
-		for (S32 mode_num = 0;; mode_num++)
-		{
-			if (!EnumDisplaySettings(NULL, mode_num, &dev_mode))
-			{
-				break;
-			}
+        mhRC = NULL;
+    }
 
-			if (dev_mode.dmPelsWidth == width &&
-				dev_mode.dmPelsHeight == height &&
-				dev_mode.dmBitsPerPel == BITS_PER_PIXEL)
-			{
-				success = TRUE;
-				if ((dev_mode.dmDisplayFrequency - current_refresh)
-					< (closest_refresh - current_refresh))
-				{
-					closest_refresh = dev_mode.dmDisplayFrequency;
-				}
-			}
-		}
+    if (fullscreen)
+    {
+        mFullscreen = TRUE;
+        BOOL success = FALSE;
+        DWORD closest_refresh = 0;
 
-		if (closest_refresh == 0)
-		{
-			LL_WARNS("Window") << "Couldn't find display mode " << width << " by " << height << " at " << BITS_PER_PIXEL << " bits per pixel" << LL_ENDL;
-			return FALSE;
-		}
+        for (S32 mode_num = 0;; mode_num++)
+        {
+            if (!EnumDisplaySettings(NULL, mode_num, &dev_mode))
+            {
+                break;
+            }
 
-		// If we found a good resolution, use it.
-		if (success)
-		{
-			success = setDisplayResolution(width, height, BITS_PER_PIXEL, closest_refresh);
-		}
+            if (dev_mode.dmPelsWidth == width &&
+                dev_mode.dmPelsHeight == height &&
+                dev_mode.dmBitsPerPel == BITS_PER_PIXEL)
+            {
+                success = TRUE;
+                if ((dev_mode.dmDisplayFrequency - current_refresh)
+                    < (closest_refresh - current_refresh))
+                {
+                    closest_refresh = dev_mode.dmDisplayFrequency;
+                }
+            }
+        }
 
-		// Keep a copy of the actual current device mode in case we minimize 
-		// and change the screen resolution.   JC
-		EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dev_mode);
+        if (closest_refresh == 0)
+        {
+            LL_WARNS("Window") << "Couldn't find display mode " << width << " by " << height << " at " << BITS_PER_PIXEL << " bits per pixel" << LL_ENDL;
+            return FALSE;
+        }
 
-		if (success)
-		{
-			mFullscreen = TRUE;
-			mFullscreenWidth   = dev_mode.dmPelsWidth;
-			mFullscreenHeight  = dev_mode.dmPelsHeight;
-			mFullscreenBits    = dev_mode.dmBitsPerPel;
-			mFullscreenRefresh = dev_mode.dmDisplayFrequency;
+        // If we found a good resolution, use it.
+        if (success)
+        {
+            success = setDisplayResolution(width, height, BITS_PER_PIXEL, closest_refresh);
+        }
 
-			LL_INFOS("Window") << "Running at " << dev_mode.dmPelsWidth
-				<< "x"   << dev_mode.dmPelsHeight
-				<< "x"   << dev_mode.dmBitsPerPel
-				<< " @ " << dev_mode.dmDisplayFrequency
-				<< LL_ENDL;
+        // Keep a copy of the actual current device mode in case we minimize 
+        // and change the screen resolution.   JC
+        EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dev_mode);
 
-			window_rect.left = (long) 0;
-			window_rect.right = (long) width;			// Windows GDI rects don't include rightmost pixel
-			window_rect.top = (long) 0;
-			window_rect.bottom = (long) height;
-			dw_ex_style = WS_EX_APPWINDOW;
-			dw_style = WS_POPUP;
+        if (success)
+        {
+            mFullscreen = TRUE;
+            mFullscreenWidth = dev_mode.dmPelsWidth;
+            mFullscreenHeight = dev_mode.dmPelsHeight;
+            mFullscreenBits = dev_mode.dmBitsPerPel;
+            mFullscreenRefresh = dev_mode.dmDisplayFrequency;
+
+            LL_INFOS("Window") << "Running at " << dev_mode.dmPelsWidth
+                << "x" << dev_mode.dmPelsHeight
+                << "x" << dev_mode.dmBitsPerPel
+                << " @ " << dev_mode.dmDisplayFrequency
+                << LL_ENDL;
+
+            window_rect.left = (long)0;
+            window_rect.right = (long)width;			// Windows GDI rects don't include rightmost pixel
+            window_rect.top = (long)0;
+            window_rect.bottom = (long)height;
+            dw_ex_style = WS_EX_APPWINDOW;
+            dw_style = WS_POPUP;
+
+            // Move window borders out not to cover window contents.
+            // This converts client rect to window rect, i.e. expands it by the window border size.
+            AdjustWindowRectEx(&window_rect, dw_style, FALSE, dw_ex_style);
+        }
+        // If it failed, we don't want to run fullscreen
+        else
+        {
+            mFullscreen = FALSE;
+            mFullscreenWidth = -1;
+            mFullscreenHeight = -1;
+            mFullscreenBits = -1;
+            mFullscreenRefresh = -1;
 
-			// Move window borders out not to cover window contents.
-			// This converts client rect to window rect, i.e. expands it by the window border size.
-			AdjustWindowRectEx(&window_rect, dw_style, FALSE, dw_ex_style);
-		}
-		// If it failed, we don't want to run fullscreen
-		else
-		{
-			mFullscreen = FALSE;
-			mFullscreenWidth   = -1;
-			mFullscreenHeight  = -1;
-			mFullscreenBits    = -1;
-			mFullscreenRefresh = -1;
+            LL_INFOS("Window") << "Unable to run fullscreen at " << width << "x" << height << LL_ENDL;
+            return FALSE;
+        }
+    }
+    else
+    {
+        mFullscreen = FALSE;
+        window_rect.left = (long)(posp ? posp->mX : 0);
+        window_rect.right = (long)width + window_rect.left;			// Windows GDI rects don't include rightmost pixel
+        window_rect.top = (long)(posp ? posp->mY : 0);
+        window_rect.bottom = (long)height + window_rect.top;
+        // Window with an edge
+        dw_ex_style = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
+        dw_style = WS_OVERLAPPEDWINDOW;
+    }
 
-			LL_INFOS("Window") << "Unable to run fullscreen at " << width << "x" << height << LL_ENDL;
-			return FALSE;
-		}
-	}
-	else
-	{
-		mFullscreen = FALSE;
-		window_rect.left = (long) (posp ? posp->mX : 0);
-		window_rect.right = (long) width + window_rect.left;			// Windows GDI rects don't include rightmost pixel
-		window_rect.top = (long) (posp ? posp->mY : 0);
-		window_rect.bottom = (long) height + window_rect.top;
-		// Window with an edge
-		dw_ex_style = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
-		dw_style = WS_OVERLAPPEDWINDOW;
-	}
 
+    // don't post quit messages when destroying old windows
+    mPostQuit = FALSE;
 
-	// don't post quit messages when destroying old windows
-	mPostQuit = FALSE;
 
-	// create window
+    // create window
     LL_DEBUGS("Window") << "Creating window with X: " << window_rect.left
         << " Y: " << window_rect.top
         << " Width: " << (window_rect.right - window_rect.left)
         << " Height: " << (window_rect.bottom - window_rect.top)
         << " Fullscreen: " << mFullscreen
         << LL_ENDL;
-    if (mWindowHandle && !destroy_window_handler(mWindowHandle))
-    {
-        LL_WARNS("Window") << "Failed to properly close window before recreating it!" << LL_ENDL;
-    }	
-	mWindowHandle = CreateWindowEx(dw_ex_style,
-		mWindowClassName,
-		mWindowTitle,
-		WS_CLIPSIBLINGS | WS_CLIPCHILDREN | dw_style,
-		window_rect.left,								// x pos
-		window_rect.top,								// y pos
-		window_rect.right - window_rect.left,			// width
-		window_rect.bottom - window_rect.top,			// height
-		NULL,
-		NULL,
-		mhInstance,
-		NULL);
+
+	recreateWindow(window_rect, dw_ex_style, dw_style);
 
 	if (mWindowHandle)
 	{
@@ -1288,7 +1218,7 @@ BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen &size, BO
 			0, 0, 0
 	};
 
-	if (!(mhDC = GetDC(mWindowHandle)))
+	if (!mhDC)
 	{
 		close();
 		OSMessageBox(mCallbacks->translateString("MBDevContextErr"),
@@ -1325,9 +1255,9 @@ BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen &size, BO
 	if (!DescribePixelFormat(mhDC, pixel_format, sizeof(PIXELFORMATDESCRIPTOR),
 		&pfd))
 	{
-		close();
 		OSMessageBox(mCallbacks->translateString("MBPixelFmtDescErr"),
 			mCallbacks->translateString("MBError"), OSMB_OK);
+        close();
 		return FALSE;
 	}
 
@@ -1364,42 +1294,42 @@ BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen &size, BO
 
 	if (pfd.cColorBits < 32)
 	{
-		close();
 		OSMessageBox(mCallbacks->translateString("MBTrueColorWindow"),
 			mCallbacks->translateString("MBError"), OSMB_OK);
+        close();
 		return FALSE;
 	}
 
 	if (pfd.cAlphaBits < 8)
 	{
-		close();
 		OSMessageBox(mCallbacks->translateString("MBAlpha"),
 			mCallbacks->translateString("MBError"), OSMB_OK);
+        close();
 		return FALSE;
 	}
 
 	if (!SetPixelFormat(mhDC, pixel_format, &pfd))
 	{
-		close();
 		OSMessageBox(mCallbacks->translateString("MBPixelFmtSetErr"),
 			mCallbacks->translateString("MBError"), OSMB_OK);
+        close();
 		return FALSE;
 	}
 
 
 	if (!(mhRC = SafeCreateContext(mhDC)))
 	{
-		close();
 		OSMessageBox(mCallbacks->translateString("MBGLContextErr"),
 			mCallbacks->translateString("MBError"), OSMB_OK);
+        close();
 		return FALSE;
 	}
 		
 	if (!wglMakeCurrent(mhDC, mhRC))
 	{
-		close();
 		OSMessageBox(mCallbacks->translateString("MBGLContextActErr"),
 			mCallbacks->translateString("MBError"), OSMB_OK);
+        close();
 		return FALSE;
 	}
 
@@ -1576,31 +1506,21 @@ const	S32   max_format  = (S32)num_formats - 1;
 			{
 				wglDeleteContext (mhRC);							// Release The Rendering Context
 				mhRC = 0;										// Zero The Rendering Context
-
 			}
-			ReleaseDC (mWindowHandle, mhDC);						// Release The Device Context
-			mhDC = 0;											// Zero The Device Context
 		}
 
-        // Destroy The Window
-        if (mWindowHandle && !destroy_window_handler(mWindowHandle))
+        // will release and recreate mhDC, mWindowHandle
+		recreateWindow(window_rect, dw_ex_style, dw_style);
+        
+        RECT rect;
+        RECT client_rect;
+        //initialize immediately on main thread
+        if (GetWindowRect(mWindowHandle, &rect) &&
+            GetClientRect(mWindowHandle, &client_rect))
         {
-            LL_WARNS("Window") << "Failed to properly close window!" << LL_ENDL;
-        }		
-
-		mWindowHandle = CreateWindowEx(dw_ex_style,
-			mWindowClassName,
-			mWindowTitle,
-			WS_CLIPSIBLINGS | WS_CLIPCHILDREN | dw_style,
-			window_rect.left,								// x pos
-			window_rect.top,								// y pos
-			window_rect.right - window_rect.left,			// width
-			window_rect.bottom - window_rect.top,			// height
-			NULL,
-			NULL,
-			mhInstance,
-			NULL);
-
+            mRect = rect;
+            mClientRect = client_rect;
+        };
 
 		if (mWindowHandle)
 		{
@@ -1612,18 +1532,18 @@ const	S32   max_format  = (S32)num_formats - 1;
 			LL_WARNS("Window") << "Window recreation failed, code: " << GetLastError() << LL_ENDL;
 		}
 
-		if (!(mhDC = GetDC(mWindowHandle)))
+		if (!mhDC)
 		{
-			close();
 			OSMessageBox(mCallbacks->translateString("MBDevContextErr"), mCallbacks->translateString("MBError"), OSMB_OK);
+			close();
 			return FALSE;
 		}
 
 		if (!SetPixelFormat(mhDC, pixel_format, &pfd))
 		{
-			close();
 			OSMessageBox(mCallbacks->translateString("MBPixelFmtSetErr"),
 				mCallbacks->translateString("MBError"), OSMB_OK);
+			close();
 			return FALSE;
 		}
 
@@ -1659,8 +1579,8 @@ const	S32   max_format  = (S32)num_formats - 1;
 	if (!DescribePixelFormat(mhDC, pixel_format, sizeof(PIXELFORMATDESCRIPTOR),
 		&pfd))
 	{
-		close();
 		OSMessageBox(mCallbacks->translateString("MBPixelFmtDescErr"), mCallbacks->translateString("MBError"), OSMB_OK);
+		close();
 		return FALSE;
 	}
 
@@ -1672,99 +1592,46 @@ const	S32   max_format  = (S32)num_formats - 1;
 	// make sure we have 32 bits per pixel
 	if (pfd.cColorBits < 32 || GetDeviceCaps(mhDC, BITSPIXEL) < 32)
 	{
-		close();
 		OSMessageBox(mCallbacks->translateString("MBTrueColorWindow"), mCallbacks->translateString("MBError"), OSMB_OK);
+		close();
 		return FALSE;
 	}
 
 	if (pfd.cAlphaBits < 8)
 	{
-		close();
 		OSMessageBox(mCallbacks->translateString("MBAlpha"), mCallbacks->translateString("MBError"), OSMB_OK);
+		close();
 		return FALSE;
 	}
 
 	mhRC = 0;
 	if (wglCreateContextAttribsARB)
 	{ //attempt to create a specific versioned context
-		S32 attribs[] = 
-		{ //start at 4.2
-			WGL_CONTEXT_MAJOR_VERSION_ARB, 4,
-			WGL_CONTEXT_MINOR_VERSION_ARB, 2,
-			WGL_CONTEXT_PROFILE_MASK_ARB,  LLRender::sGLCoreProfile ? WGL_CONTEXT_CORE_PROFILE_BIT_ARB : WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB,
-			WGL_CONTEXT_FLAGS_ARB, gDebugGL ? WGL_CONTEXT_DEBUG_BIT_ARB : 0,
-			0
-		};
-
-		bool done = false;
-		while (!done)
-		{
-			mhRC = wglCreateContextAttribsARB(mhDC, mhRC, attribs);
-
-			if (!mhRC)
-			{
-				if (attribs[3] > 0)
-				{ //decrement minor version
-					attribs[3]--;
-				}
-				else if (attribs[1] > 3)
-				{ //decrement major version and start minor version over at 3
-					attribs[1]--;
-					attribs[3] = 3;
-				}
-				else
-				{ //we reached 3.0 and still failed, bail out
-					done = true;
-				}
-			}
-			else
-			{
-				LL_INFOS() << "Created OpenGL " << llformat("%d.%d", attribs[1], attribs[3]) << 
-					(LLRender::sGLCoreProfile ? " core" : " compatibility") << " context." << LL_ENDL;
-				done = true;
-
-			// force sNoFixedFunction iff we're trying to use nsight debugging which does not support many legacy API uses
-
-				// nSight doesn't support use of legacy API funcs in the fixed function pipe
-				if (LLRender::sGLCoreProfile || LLRender::sNsightDebugSupport)
-				{
-					LLGLSLShader::sNoFixedFunction = true;
-				}
-			}
-		}
-	}
-
-	if (!mhRC && !(mhRC = wglCreateContext(mhDC)))
-	{
-		close();
-		OSMessageBox(mCallbacks->translateString("MBGLContextErr"), mCallbacks->translateString("MBError"), OSMB_OK);
-		return FALSE;
+        mhRC = (HGLRC) createSharedContext();
+        if (!mhRC)
+        {
+            return FALSE;
+        }
 	}
 
 	if (!wglMakeCurrent(mhDC, mhRC))
 	{
-		close();
 		OSMessageBox(mCallbacks->translateString("MBGLContextActErr"), mCallbacks->translateString("MBError"), OSMB_OK);
+        close();
 		return FALSE;
 	}
 
+	LL_PROFILER_GPU_CONTEXT
+
 	if (!gGLManager.initGL())
 	{
-		close();
 		OSMessageBox(mCallbacks->translateString("MBVideoDrvErr"), mCallbacks->translateString("MBError"), OSMB_OK);
+        close();
 		return FALSE;
 	}
 	
 	// Disable vertical sync for swap
-	if (disable_vsync && wglSwapIntervalEXT)
-	{
-		LL_DEBUGS("Window") << "Disabling vertical sync" << LL_ENDL;
-		wglSwapIntervalEXT(0);
-	}
-	else
-	{
-		LL_DEBUGS("Window") << "Keeping vertical sync" << LL_ENDL;
-	}
+    toggleVSync(enable_vsync);
 
 	SetWindowLongPtr(mWindowHandle, GWLP_USERDATA, (LONG_PTR)this);
 
@@ -1790,6 +1657,188 @@ const	S32   max_format  = (S32)num_formats - 1;
 	return TRUE;
 }
 
+void LLWindowWin32::recreateWindow(RECT window_rect, DWORD dw_ex_style, DWORD dw_style)
+{
+    auto oldWindowHandle = mWindowHandle;
+    auto oldDCHandle = mhDC;
+
+    // zero out mWindowHandle and mhDC before destroying window so window
+    // thread falls back to peekmessage
+    mWindowHandle = 0;
+    mhDC = 0;
+
+    std::promise<std::pair<HWND, HDC>> promise;
+    // What follows must be done on the window thread.
+    auto window_work =
+        [this,
+         self=mWindowThread,
+         oldWindowHandle,
+         oldDCHandle,
+         // bind CreateWindowEx() parameters by value instead of
+         // back-referencing LLWindowWin32 members
+         windowClassName=mWindowClassName,
+         windowTitle=mWindowTitle,
+         hInstance=mhInstance,
+         window_rect,
+         dw_ex_style,
+         dw_style,
+         &promise]
+        ()
+        {
+            LL_DEBUGS("Window") << "recreateWindow(): window_work entry" << LL_ENDL;
+            self->mWindowHandle = 0;
+            self->mhDC = 0;
+
+            if (oldWindowHandle)
+            {
+                if (oldDCHandle && !ReleaseDC(oldWindowHandle, oldDCHandle))
+                {
+                    LL_WARNS("Window") << "Failed to ReleaseDC" << LL_ENDL;
+                }
+
+                // important to call DestroyWindow() from the window thread
+                if (!destroy_window_handler(oldWindowHandle))
+                {
+
+                    LL_WARNS("Window") << "Failed to properly close window before recreating it!"
+                        << LL_ENDL;
+                }
+            }
+
+            auto handle = CreateWindowEx(dw_ex_style,
+                windowClassName,
+                windowTitle,
+                WS_CLIPSIBLINGS | WS_CLIPCHILDREN | dw_style,
+                window_rect.left,								// x pos
+                window_rect.top,								// y pos
+                window_rect.right - window_rect.left,			// width
+                window_rect.bottom - window_rect.top,			// height
+                NULL,
+                NULL,
+                hInstance,
+                NULL);
+
+            if (! handle)
+            {
+                // Failed to create window: clear the variables. This
+                // assignment is valid because we're running on mWindowThread.
+                self->mWindowHandle = NULL;
+                self->mhDC = 0;
+            }
+            else
+            {
+                // Update mWindowThread's own mWindowHandle and mhDC.
+                self->mWindowHandle = handle;
+                self->mhDC = GetDC(handle);
+            }
+            
+            updateWindowRect();
+
+            // It's important to wake up the future either way.
+            promise.set_value(std::make_pair(self->mWindowHandle, self->mhDC));
+            LL_DEBUGS("Window") << "recreateWindow(): window_work done" << LL_ENDL;
+        };
+    // But how we pass window_work to the window thread depends on whether we
+    // already have a window handle.
+    if (!oldWindowHandle)
+    {
+        // Pass window_work using the WorkQueue: without an existing window
+        // handle, the window thread can't call GetMessage().
+        LL_DEBUGS("Window") << "posting window_work to WorkQueue" << LL_ENDL;
+        mWindowThread->post(window_work);
+    }
+    else
+    {
+        // Pass window_work using PostMessage(). We can still
+        // PostMessage(oldHandle) because oldHandle won't be destroyed until
+        // the window thread has retrieved and executed window_work.
+        LL_DEBUGS("Window") << "posting window_work to message queue" << LL_ENDL;
+        mWindowThread->Post(oldWindowHandle, window_work);
+    }
+
+    auto future = promise.get_future();
+    // This blocks until mWindowThread processes CreateWindowEx() and calls
+    // promise.set_value().
+    auto pair = future.get();
+    mWindowHandle = pair.first;
+    mhDC = pair.second;
+}
+
+void* LLWindowWin32::createSharedContext()
+{
+    S32 attribs[] =
+    {
+        WGL_CONTEXT_MAJOR_VERSION_ARB, 4,
+        WGL_CONTEXT_MINOR_VERSION_ARB, 6,
+        WGL_CONTEXT_PROFILE_MASK_ARB,  LLRender::sGLCoreProfile ? WGL_CONTEXT_CORE_PROFILE_BIT_ARB : WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB,
+        WGL_CONTEXT_FLAGS_ARB, gDebugGL ? WGL_CONTEXT_DEBUG_BIT_ARB : 0,
+        0
+    };
+
+    HGLRC rc = 0;
+
+    bool done = false;
+    while (!done)
+    {
+        rc = wglCreateContextAttribsARB(mhDC, mhRC, attribs);
+
+        if (!rc)
+        {
+            if (attribs[3] > 0)
+            { //decrement minor version
+                attribs[3]--;
+            }
+            else if (attribs[1] > 3)
+            { //decrement major version and start minor version over at 3
+                attribs[1]--;
+                attribs[3] = 3;
+            }
+            else
+            { //we reached 3.0 and still failed, bail out
+                done = true;
+            }
+        }
+        else
+        {
+            LL_INFOS() << "Created OpenGL " << llformat("%d.%d", attribs[1], attribs[3]) <<
+                (LLRender::sGLCoreProfile ? " core" : " compatibility") << " context." << LL_ENDL;
+            done = true;
+        }
+    }
+
+    if (!rc && !(rc = wglCreateContext(mhDC)))
+    {
+        close();
+        OSMessageBox(mCallbacks->translateString("MBGLContextErr"), mCallbacks->translateString("MBError"), OSMB_OK);
+    }
+
+    return rc;
+}
+
+void LLWindowWin32::makeContextCurrent(void* contextPtr)
+{
+    wglMakeCurrent(mhDC, (HGLRC) contextPtr);
+}
+
+void LLWindowWin32::destroySharedContext(void* contextPtr)
+{
+    wglDeleteContext((HGLRC)contextPtr);
+}
+
+void LLWindowWin32::toggleVSync(bool enable_vsync)
+{
+    if (!enable_vsync && wglSwapIntervalEXT)
+    {
+        LL_INFOS("Window") << "Disabling vertical sync" << LL_ENDL;
+        wglSwapIntervalEXT(0);
+    }
+    else
+    {
+        LL_INFOS("Window") << "Enabling vertical sync" << LL_ENDL;
+        wglSwapIntervalEXT(1);
+    }
+}
+
 void LLWindowWin32::moveWindow( const LLCoordScreen& position, const LLCoordScreen& size )
 {
 	if( mIsMouseClipping )
@@ -1808,66 +1857,106 @@ void LLWindowWin32::moveWindow( const LLCoordScreen& position, const LLCoordScre
 	// THIS CAUSES DEV-15484 and DEV-15949 
 	//ShowWindow(mWindowHandle, SW_RESTORE);
 	// NOW we can call MoveWindow
-	MoveWindow(mWindowHandle, position.mX, position.mY, size.mX, size.mY, TRUE);
+    mWindowThread->post([=]()
+        {
+            MoveWindow(mWindowHandle, position.mX, position.mY, size.mX, size.mY, TRUE);
+        });
+}
+
+void LLWindowWin32::setTitle(const std::string title)
+{
+    // TODO: Do we need to use the wide string version of this call
+    // to support non-ascii usernames (and region names?)
+    mWindowThread->post([=]()
+        {
+            SetWindowTextA(mWindowHandle, title.c_str());
+        });
 }
 
 BOOL LLWindowWin32::setCursorPosition(const LLCoordWindow position)
 {
-	mMousePositionModified = TRUE;
-	if (!mWindowHandle)
-	{
-		return FALSE;
-	}
+    ASSERT_MAIN_THREAD();
 
+    if (!mWindowHandle)
+    {
+        return FALSE;
+    }
 
-	// Inform the application of the new mouse position (needed for per-frame
-	// hover/picking to function).
-	mCallbacks->handleMouseMove(this, position.convert(), (MASK)0);
-	
-	// DEV-18951 VWR-8524 Camera moves wildly when alt-clicking.
-	// Because we have preemptively notified the application of the new
-	// mouse position via handleMouseMove() above, we need to clear out
-	// any stale mouse move events.  RN/JC
-	MSG msg;
-	while (PeekMessage(&msg, NULL, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_REMOVE))
-	{ }
-
-	LLCoordScreen screen_pos(position.convert());
-	return ::SetCursorPos(screen_pos.mX, screen_pos.mY);
+    LLCoordScreen screen_pos(position.convert());
+
+    // instantly set the cursor position from the app's point of view
+    mCursorPosition = position;
+    mLastCursorPosition = position;
+
+    // Inform the application of the new mouse position (needed for per-frame
+    // hover/picking to function).
+    mCallbacks->handleMouseMove(this, position.convert(), (MASK)0);
+
+    // actually set the cursor position on the window thread
+    mWindowThread->post([=]()
+        {
+            // actually set the OS cursor position
+            SetCursorPos(screen_pos.mX, screen_pos.mY);
+        });
+
+    return TRUE;
 }
 
 BOOL LLWindowWin32::getCursorPosition(LLCoordWindow *position)
 {
-	POINT cursor_point;
-
-	if (!mWindowHandle 
-		|| !GetCursorPos(&cursor_point)
-		|| !position)
-	{
-		return FALSE;
-	}
+    ASSERT_MAIN_THREAD();
+    if (!position)
+    {
+        return FALSE;
+    }
 
-	*position = LLCoordScreen(cursor_point.x, cursor_point.y).convert();
+    *position = mCursorPosition;
 	return TRUE;
 }
 
+BOOL LLWindowWin32::getCursorDelta(LLCoordCommon* delta)
+{
+    if (delta == nullptr)
+    {
+        return FALSE;
+    }
+
+    *delta = mMouseFrameDelta;
+
+    return TRUE;
+}
+
 void LLWindowWin32::hideCursor()
 {
-	while (ShowCursor(FALSE) >= 0)
-	{
-		// nothing, wait for cursor to push down
-	}
+    ASSERT_MAIN_THREAD();
+
+    mWindowThread->post([=]()
+        {
+            while (ShowCursor(FALSE) >= 0)
+            {
+                // nothing, wait for cursor to push down
+            }
+        });
+
 	mCursorHidden = TRUE;
 	mHideCursorPermanent = TRUE;
 }
 
 void LLWindowWin32::showCursor()
 {
-	// makes sure the cursor shows up
-	while (ShowCursor(TRUE) < 0)
-	{
-		// do nothing, wait for cursor to pop out
-	}
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_WIN32;
+
+    ASSERT_MAIN_THREAD();
+	
+    mWindowThread->post([=]()
+        {
+            // makes sure the cursor shows up
+            while (ShowCursor(TRUE) < 0)
+            {
+                // do nothing, wait for cursor to pop out
+            }
+        });
+
 	mCursorHidden = FALSE;
 	mHideCursorPermanent = FALSE;
 }
@@ -1971,6 +2060,8 @@ void LLWindowWin32::initCursors()
 
 void LLWindowWin32::updateCursor()
 {
+    ASSERT_MAIN_THREAD();
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_WIN32
 	if (mNextCursor == UI_CURSOR_ARROW
 		&& mBusyCount > 0)
 	{
@@ -1980,7 +2071,11 @@ void LLWindowWin32::updateCursor()
 	if( mCurrentCursor != mNextCursor )
 	{
 		mCurrentCursor = mNextCursor;
-		SetCursor( mCursor[mNextCursor] );
+        auto nextCursor = mCursor[mNextCursor];
+        mWindowThread->post([=]()
+            {
+                SetCursor(nextCursor);
+            });
 	}
 }
 
@@ -1996,13 +2091,8 @@ void LLWindowWin32::captureMouse()
 
 void LLWindowWin32::releaseMouse()
 {
-	// *NOTE:Mani ReleaseCapture will spawn new windows messages...
-	// which will in turn call our MainWindowProc. It therefore requires
-	// pausing *and more importantly resumption* of the mainlooptimeout...
-	// just like DispatchMessage below.
-	mCallbacks->handlePauseWatchdog(this);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_WIN32;
 	ReleaseCapture();
-	mCallbacks->handleResumeWatchdog(this);
 }
 
 
@@ -2011,1003 +2101,1022 @@ void LLWindowWin32::delayInputProcessing()
 	mInputProcessingPaused = TRUE;
 }
 
+
 void LLWindowWin32::gatherInput()
 {
-	MSG		msg;
-	int		msg_count = 0;
+    ASSERT_MAIN_THREAD();
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_WIN32
+    MSG msg;
 
-	while ((msg_count < MAX_MESSAGE_PER_UPDATE) && PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
-	{
-		mCallbacks->handlePingWatchdog(this, "Main:TranslateGatherInput");
-		TranslateMessage(&msg);
+    {
+        LLMutexLock lock(&mRawMouseMutex);
+        mMouseFrameDelta = mRawMouseDelta;
 
-		// turn watchdog off in here to not fail if windows is doing something wacky
-		mCallbacks->handlePauseWatchdog(this);
-		DispatchMessage(&msg);
-		mCallbacks->handleResumeWatchdog(this);
-		msg_count++;
+        mRawMouseDelta.mX = 0;
+        mRawMouseDelta.mY = 0;
+    }
 
-		if ( mInputProcessingPaused )
-		{
-			break;
-		}
-		/* Attempted workaround for problem where typing fast and hitting
-		   return would result in only part of the text being sent. JC
 
-		BOOL key_posted = TranslateMessage(&msg);
-		DispatchMessage(&msg);
-		msg_count++;
+    if (mWindowThread->getQueue().size())
+    {
+        LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("gi - PostMessage");
+        kickWindowThread();
+    }
+        
+    while (mWindowThread->mMessageQueue.tryPopBack(msg))
+    {
+        LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("gi - message queue");
+        if (mInputProcessingPaused)
+        {
+            continue;
+        }
 
-		// If a key was translated, a WM_CHAR might have been posted to the end
-		// of the event queue.  We need it immediately.
-		if (key_posted && msg.message == WM_KEYDOWN)
-		{
-			if (PeekMessage(&msg, NULL, WM_CHAR, WM_CHAR, PM_REMOVE))
-			{
-				TranslateMessage(&msg);
-				DispatchMessage(&msg);
-				msg_count++;
-			}
-		}
-		*/
-		mCallbacks->handlePingWatchdog(this, "Main:AsyncCallbackGatherInput");
-		// For async host by name support.  Really hacky.
-		if (gAsyncMsgCallback && (LL_WM_HOST_RESOLVED == msg.message))
-		{
-			gAsyncMsgCallback(msg);
-		}
-	}
+        // For async host by name support.  Really hacky.
+        if (gAsyncMsgCallback && (LL_WM_HOST_RESOLVED == msg.message))
+        {
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("gi - callback");
+            gAsyncMsgCallback(msg);
+        }
+    }
+
+    {
+        LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("gi - PeekMessage");
+        S32 msg_count = 0;
+        while ((msg_count < MAX_MESSAGE_PER_UPDATE) && PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_REMOVE))
+        {
+            TranslateMessage(&msg);
+            DispatchMessage(&msg);
+            msg_count++;
+        }
+    }
+
+    {
+        LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("gi - function queue");
+        //process any pending functions
+        std::function<void()> curFunc;
+        while (mFunctionQueue.tryPopBack(curFunc))
+        {
+            curFunc();
+        }
+    }
+
+    // send one and only one mouse move event per frame BEFORE handling mouse button presses
+    if (mLastCursorPosition != mCursorPosition)
+    {
+        LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("gi - mouse move");
+        mCallbacks->handleMouseMove(this, mCursorPosition.convert(), mMouseMask);
+    }
+    
+    mLastCursorPosition = mCursorPosition;
+
+    {
+        LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("gi - mouse queue");
+        // handle mouse button presses AFTER updating mouse cursor position
+        std::function<void()> curFunc;
+        while (mMouseQueue.tryPopBack(curFunc))
+        {
+            curFunc();
+        }
+    }
 
 	mInputProcessingPaused = FALSE;
 
 	updateCursor();
-
-	// clear this once we've processed all mouse messages that might have occurred after
-	// we slammed the mouse position
-	mMousePositionModified = FALSE;
 }
 
 static LLTrace::BlockTimerStatHandle FTM_KEYHANDLER("Handle Keyboard");
 static LLTrace::BlockTimerStatHandle FTM_MOUSEHANDLER("Handle Mouse");
 
+#define WINDOW_IMP_POST(x) window_imp->post([=]() { x; })
+
 LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_param, LPARAM l_param)
 {
-	// Ignore clicks not originated in the client area, i.e. mouse-up events not preceded with a WM_LBUTTONDOWN.
-	// This helps prevent avatar walking after maximizing the window by double-clicking the title bar.
-	static bool sHandleLeftMouseUp = true;
-
-	// Ignore the double click received right after activating app.
-	// This is to avoid triggering double click teleport after returning focus (see MAINT-3786).
-	static bool sHandleDoubleClick = true;
-
-	LLWindowWin32 *window_imp = (LLWindowWin32 *)GetWindowLongPtr( h_wnd, GWLP_USERDATA );
-
-	bool debug_window_proc = gDebugWindowProc || debugLoggingEnabled("Window");
-
-
-	if (NULL != window_imp)
-	{
-		window_imp->mCallbacks->handleResumeWatchdog(window_imp);
-		window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:StartWndProc");
-		// Has user provided their own window callback?
-		if (NULL != window_imp->mWndProc)
-		{
-			if (!window_imp->mWndProc(h_wnd, u_msg, w_param, l_param))
-			{
-				// user has handled window message
-				return 0;
-			}
-		}
-
-		window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:PreSwitchWndProc");
-		
-		// Juggle to make sure we can get negative positions for when
-		// mouse is outside window.
-		LLCoordWindow window_coord((S32)(S16)LOWORD(l_param), (S32)(S16)HIWORD(l_param));
-
-		// This doesn't work, as LOWORD returns unsigned short.
-		//LLCoordWindow window_coord(LOWORD(l_param), HIWORD(l_param));
-		LLCoordGL gl_coord;
-
-		// pass along extended flag in mask
-		MASK mask = (l_param>>16 & KF_EXTENDED) ? MASK_EXTENDED : 0x0;
-		BOOL eat_keystroke = TRUE;
-
-		switch(u_msg)
-		{
-			RECT	update_rect;
-			S32		update_width;
-			S32		update_height;
-
-		case WM_TIMER:
-			window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_TIMER");
-			window_imp->mCallbacks->handleTimerEvent(window_imp);
-			break;
-
-		case WM_DEVICECHANGE:
-			window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_DEVICECHANGE");
-			if (debug_window_proc)
-			{
-				LL_INFOS("Window") << "  WM_DEVICECHANGE: wParam=" << w_param 
-						<< "; lParam=" << l_param << LL_ENDL;
-			}
-			if (w_param == DBT_DEVNODES_CHANGED || w_param == DBT_DEVICEARRIVAL)
-			{
-				if (window_imp->mCallbacks->handleDeviceChange(window_imp))
-				{
-					return 0;
-				}
-			}
-			break;
-
-		case WM_PAINT:
-			window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_PAINT");
-			GetUpdateRect(window_imp->mWindowHandle, &update_rect, FALSE);
-			update_width = update_rect.right - update_rect.left + 1;
-			update_height = update_rect.bottom - update_rect.top + 1;
-			window_imp->mCallbacks->handlePaint(window_imp, update_rect.left, update_rect.top,
-				update_width, update_height);
-			break;
-		case WM_PARENTNOTIFY:
-			window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_PARENTNOTIFY");
-			u_msg = u_msg;
-			break;
-
-		case WM_SETCURSOR:
-			// This message is sent whenever the cursor is moved in a window.
-			// You need to set the appropriate cursor appearance.
-
-			// Only take control of cursor over client region of window
-			// This allows Windows(tm) to handle resize cursors, etc.
-			window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_SETCURSOR");
-			if (LOWORD(l_param) == HTCLIENT)
-			{
-				SetCursor(window_imp->mCursor[ window_imp->mCurrentCursor] );
-				return 0;
-			}
-			break;
+    ASSERT_WINDOW_THREAD();
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_WIN32;
 
-		case WM_ENTERMENULOOP:
-			window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_ENTERMENULOOP");
-			window_imp->mCallbacks->handleWindowBlock(window_imp);
-			break;
-
-		case WM_EXITMENULOOP:
-			window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_EXITMENULOOP");
-			window_imp->mCallbacks->handleWindowUnblock(window_imp);
-			break;
-
-		case WM_ACTIVATEAPP:
-			window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_ACTIVATEAPP");
-			{
-				// This message should be sent whenever the app gains or loses focus.
-				BOOL activating = (BOOL) w_param;
-				BOOL minimized = window_imp->getMinimized();
-
-				if (debug_window_proc)
-				{
-					LL_INFOS("Window") << "WINDOWPROC ActivateApp "
-						<< " activating " << S32(activating)
-						<< " minimized " << S32(minimized)
-						<< " fullscreen " << S32(window_imp->mFullscreen)
-						<< LL_ENDL;
-				}
-
-				if (window_imp->mFullscreen)
-				{
-					// When we run fullscreen, restoring or minimizing the app needs 
-					// to switch the screen resolution
-					if (activating)
-					{
-						window_imp->setFullscreenResolution();
-						window_imp->restore();
-					}
-					else
-					{
-						window_imp->minimize();
-						window_imp->resetDisplayResolution();
-					}
-				}
-
-				if (!activating)
-				{
-					sHandleDoubleClick = false;
-				}
-
-				window_imp->mCallbacks->handleActivateApp(window_imp, activating);
-
-				break;
-			}
+    LL_DEBUGS("Window") << "mainWindowProc(" << std::hex << h_wnd
+                        << ", " << u_msg
+                        << ", " << w_param << ")" << std::dec << LL_ENDL;
 
-		case WM_ACTIVATE:
-			window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_ACTIVATE");
-			{
-				// Can be one of WA_ACTIVE, WA_CLICKACTIVE, or WA_INACTIVE
-				BOOL activating = (LOWORD(w_param) != WA_INACTIVE);
-
-				BOOL minimized = BOOL(HIWORD(w_param));
-
-				if (!activating && LLWinImm::isAvailable() && window_imp->mPreeditor)
-				{
-					window_imp->interruptLanguageTextInput();
-				}
-
-				// JC - I'm not sure why, but if we don't report that we handled the 
-				// WM_ACTIVATE message, the WM_ACTIVATEAPP messages don't work 
-				// properly when we run fullscreen.
-				if (debug_window_proc)
-				{
-					LL_INFOS("Window") << "WINDOWPROC Activate "
-						<< " activating " << S32(activating) 
-						<< " minimized " << S32(minimized)
-						<< LL_ENDL;
-				}
-
-				// Don't handle this.
-				break;
-			}
-
-		case WM_QUERYOPEN:
-			// TODO: use this to return a nice icon
-			break;
-
-		case WM_SYSCOMMAND:
-			window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_SYSCOMMAND");
-			switch(w_param)
-			{
-			case SC_KEYMENU: 
-				// Disallow the ALT key from triggering the default system menu.
-				return 0;		
-
-			case SC_SCREENSAVE:
-			case SC_MONITORPOWER:
-				// eat screen save messages and prevent them!
-				return 0;
-			}
-			break;
-
-		case WM_CLOSE:
-			window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_CLOSE");
-			// Will the app allow the window to close?
-			if (window_imp->mCallbacks->handleCloseRequest(window_imp))
-			{
-				// Get the app to initiate cleanup.
-				window_imp->mCallbacks->handleQuit(window_imp);
-				// The app is responsible for calling destroyWindow when done with GL
-			}
-			return 0;
-
-		case WM_DESTROY:
-			window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_DESTROY");
-			if (window_imp->shouldPostQuit())
-			{
-				PostQuitMessage(0);  // Posts WM_QUIT with an exit code of 0
-			}
-			return 0;
-
-		case WM_COMMAND:
-			window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_COMMAND");
-			if (!HIWORD(w_param)) // this message is from a menu
-			{
-				window_imp->mCallbacks->handleMenuSelect(window_imp, LOWORD(w_param));
-			}
-			break;
-
-		case WM_SYSKEYDOWN:
-			window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_SYSKEYDOWN");
-			// allow system keys, such as ALT-F4 to be processed by Windows
-			eat_keystroke = FALSE;
-		case WM_KEYDOWN:
-			window_imp->mKeyCharCode = 0; // don't know until wm_char comes in next
-			window_imp->mKeyScanCode = ( l_param >> 16 ) & 0xff;
-			window_imp->mKeyVirtualKey = w_param;
-			window_imp->mRawMsg = u_msg;
-			window_imp->mRawWParam = w_param;
-			window_imp->mRawLParam = l_param;
-
-			window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_KEYDOWN");
-			{
-				if (debug_window_proc)
-				{
-					LL_INFOS("Window") << "Debug WindowProc WM_KEYDOWN "
-						<< " key " << S32(w_param) 
-						<< LL_ENDL;
-				}
-				if(gKeyboard->handleKeyDown(w_param, mask) && eat_keystroke)
-				{
-					return 0;
-				}
-				// pass on to windows if we didn't handle it
-				break;
-			}
-		case WM_SYSKEYUP:
-			eat_keystroke = FALSE;
-		case WM_KEYUP:
-		{
-			window_imp->mKeyScanCode = ( l_param >> 16 ) & 0xff;
-			window_imp->mKeyVirtualKey = w_param;
-			window_imp->mRawMsg = u_msg;
-			window_imp->mRawWParam = w_param;
-			window_imp->mRawLParam = l_param;
+    if (u_msg == WM_POST_FUNCTION_)
+    {
+        LL_DEBUGS("Window") << "WM_POST_FUNCTION_" << LL_ENDL;
+        // from LLWindowWin32Thread::Post()
+        // Cast l_param back to the pointer to the heap FuncType
+        // allocated by Post(). Capture in unique_ptr so we'll delete
+        // once we're done with it.
+        std::unique_ptr<LLWindowWin32Thread::FuncType>
+            ptr(reinterpret_cast<LLWindowWin32Thread::FuncType*>(l_param));
+        (*ptr)();
+        return 0;
+    }
 
-			window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_KEYUP");
-			LL_RECORD_BLOCK_TIME(FTM_KEYHANDLER);
+    // Ignore clicks not originated in the client area, i.e. mouse-up events not preceded with a WM_LBUTTONDOWN.
+    // This helps prevent avatar walking after maximizing the window by double-clicking the title bar.
+    static bool sHandleLeftMouseUp = true;
 
-			if (debug_window_proc)
-			{
-				LL_INFOS("Window") << "Debug WindowProc WM_KEYUP "
-					<< " key " << S32(w_param) 
-					<< LL_ENDL;
-			}
-			if (gKeyboard->handleKeyUp(w_param, mask) && eat_keystroke)
-			{
-				return 0;
-			}
+    // Ignore the double click received right after activating app.
+    // This is to avoid triggering double click teleport after returning focus (see MAINT-3786).
+    static bool sHandleDoubleClick = true;
 
-			// pass on to windows
-			break;
-		}
-		case WM_IME_SETCONTEXT:
-			window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_IME_SETCONTEXT");
-			if (debug_window_proc)
-			{
-				LL_INFOS("Window") << "WM_IME_SETCONTEXT" << LL_ENDL;
-			}
-			if (LLWinImm::isAvailable() && window_imp->mPreeditor)
-			{
-				l_param &= ~ISC_SHOWUICOMPOSITIONWINDOW;
-				// Invoke DefWinProc with the modified LPARAM.
-			}
-			break;
+    LLWindowWin32* window_imp = (LLWindowWin32*)GetWindowLongPtr(h_wnd, GWLP_USERDATA);
 
-		case WM_IME_STARTCOMPOSITION:
-			window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_IME_STARTCOMPOSITION");
-			if (debug_window_proc)
-			{
-				LL_INFOS() << "WM_IME_STARTCOMPOSITION" << LL_ENDL;
-			}
-			if (LLWinImm::isAvailable() && window_imp->mPreeditor)
-			{
-				window_imp->handleStartCompositionMessage();
-				return 0;
-			}
-			break;
+    bool debug_window_proc = false; // gDebugWindowProc || debugLoggingEnabled("Window");
 
-		case WM_IME_ENDCOMPOSITION:
-			window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_IME_ENDCOMPOSITION");
-			if (debug_window_proc)
-			{
-				LL_INFOS() << "WM_IME_ENDCOMPOSITION" << LL_ENDL;
-			}
-			if (LLWinImm::isAvailable() && window_imp->mPreeditor)
-			{
-				return 0;
-			}
-			break;
-
-		case WM_IME_COMPOSITION:
-			window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_IME_COMPOSITION");
-			if (debug_window_proc)
-			{
-				LL_INFOS() << "WM_IME_COMPOSITION" << LL_ENDL;
-			}
-			if (LLWinImm::isAvailable() && window_imp->mPreeditor)
-			{
-				window_imp->handleCompositionMessage(l_param);
-				return 0;
-			}
-			break;
-
-		case WM_IME_REQUEST:
-			window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_IME_REQUEST");
-			if (debug_window_proc)
-			{
-				LL_INFOS() << "WM_IME_REQUEST" << LL_ENDL;
-			}
-			if (LLWinImm::isAvailable() && window_imp->mPreeditor)
-			{
-				LRESULT result = 0;
-				if (window_imp->handleImeRequests(w_param, l_param, &result))
-				{
-					return result;
-				}
-			}
-			break;
-
-		case WM_CHAR:
-			window_imp->mKeyCharCode = w_param;
-			window_imp->mRawMsg = u_msg;
-			window_imp->mRawWParam = w_param;
-			window_imp->mRawLParam = l_param;
-
-			// Should really use WM_UNICHAR eventually, but it requires a specific Windows version and I need
-			// to figure out how that works. - Doug
-			//
-			// ... Well, I don't think so.
-			// How it works is explained in Win32 API document, but WM_UNICHAR didn't work
-			// as specified at least on Windows XP SP1 Japanese version.  I have never used
-			// it since then, and I'm not sure whether it has been fixed now, but I don't think
-			// it is worth trying.  The good old WM_CHAR works just fine even for supplementary
-			// characters.  We just need to take care of surrogate pairs sent as two WM_CHAR's
-			// by ourselves.  It is not that tough.  -- Alissa Sabre @ SL
-			window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_CHAR");
-			if (debug_window_proc)
-			{
-				LL_INFOS("Window") << "Debug WindowProc WM_CHAR "
-					<< " key " << S32(w_param) 
-					<< LL_ENDL;
-			}
-			// Even if LLWindowCallbacks::handleUnicodeChar(llwchar, BOOL) returned FALSE,
-			// we *did* processed the event, so I believe we should not pass it to DefWindowProc...
-			window_imp->handleUnicodeUTF16((U16)w_param, gKeyboard->currentMask(FALSE));
-			return 0;
+    if (NULL != window_imp)
+    {
+        // Juggle to make sure we can get negative positions for when
+        // mouse is outside window.
+        LLCoordWindow window_coord((S32)(S16)LOWORD(l_param), (S32)(S16)HIWORD(l_param));
 
-		case WM_NCLBUTTONDOWN:
-			{
-				window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_NCLBUTTONDOWN");
-				// A click in a non-client area, e.g. title bar or window border.
-				sHandleLeftMouseUp = false;
-				sHandleDoubleClick = true;
-			}
-			break;
+        // pass along extended flag in mask
+        MASK mask = (l_param >> 16 & KF_EXTENDED) ? MASK_EXTENDED : 0x0;
+        BOOL eat_keystroke = TRUE;
 
-		case WM_LBUTTONDOWN:
-			{
-				window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_LBUTTONDOWN");
-				LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER);
-				sHandleLeftMouseUp = true;
+        switch (u_msg)
+        {
+            RECT	update_rect;
+            S32		update_width;
+            S32		update_height;
 
-				if (LLWinImm::isAvailable() && window_imp->mPreeditor)
-				{
-					window_imp->interruptLanguageTextInput();
-				}
+        case WM_TIMER:
+        {
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_TIMER");
+            WINDOW_IMP_POST(window_imp->mCallbacks->handleTimerEvent(window_imp));
+            break;
+        }
 
-				// Because we move the cursor position in the app, we need to query
-				// to find out where the cursor at the time the event is handled.
-				// If we don't do this, many clicks could get buffered up, and if the
-				// first click changes the cursor position, all subsequent clicks
-				// will occur at the wrong location.  JC
-				if (window_imp->mMousePositionModified)
-				{
-					LLCoordWindow cursor_coord_window;
-					window_imp->getCursorPosition(&cursor_coord_window);
-					gl_coord = cursor_coord_window.convert();
-				}
-				else
-				{
-					gl_coord = window_coord.convert();
-				}
-				MASK mask = gKeyboard->currentMask(TRUE);
-				// generate move event to update mouse coordinates
-				window_imp->mCallbacks->handleMouseMove(window_imp, gl_coord, mask);
-				if (window_imp->mCallbacks->handleMouseDown(window_imp, gl_coord, mask))
-				{
-					return 0;
-				}
-			}
-			break;
+        case WM_DEVICECHANGE:
+        {
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_DEVICECHANGE");
+            if (debug_window_proc)
+            {
+                LL_INFOS("Window") << "  WM_DEVICECHANGE: wParam=" << w_param
+                    << "; lParam=" << l_param << LL_ENDL;
+            }
+            if (w_param == DBT_DEVNODES_CHANGED || w_param == DBT_DEVICEARRIVAL)
+            {
+                WINDOW_IMP_POST(window_imp->mCallbacks->handleDeviceChange(window_imp));
+                
+                return TRUE;
+            }
+            break;
+        }
 
-		case WM_LBUTTONDBLCLK:
-		//RN: ignore right button double clicks for now
-		//case WM_RBUTTONDBLCLK:
-			{
-				window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_LBUTTONDBLCLK");
+        case WM_PAINT:
+        {
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_PAINT");
+            GetUpdateRect(window_imp->mWindowHandle, &update_rect, FALSE);
+            update_width = update_rect.right - update_rect.left + 1;
+            update_height = update_rect.bottom - update_rect.top + 1;
+
+            WINDOW_IMP_POST(window_imp->mCallbacks->handlePaint(window_imp, update_rect.left, update_rect.top,
+                update_width, update_height));
+            break;
+        }
+        case WM_PARENTNOTIFY:
+        {
+            break;
+        }
 
-				if (!sHandleDoubleClick)
-				{
-					sHandleDoubleClick = true;
-					break;
-				}
+        case WM_SETCURSOR:
+        {
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_SETCURSOR");
+            // This message is sent whenever the cursor is moved in a window.
+            // You need to set the appropriate cursor appearance.
 
-				// Because we move the cursor position in the app, we need to query
-				// to find out where the cursor at the time the event is handled.
-				// If we don't do this, many clicks could get buffered up, and if the
-				// first click changes the cursor position, all subsequent clicks
-				// will occur at the wrong location.  JC
-				if (window_imp->mMousePositionModified)
-				{
-					LLCoordWindow cursor_coord_window;
-					window_imp->getCursorPosition(&cursor_coord_window);
-					gl_coord = cursor_coord_window.convert();
-				}
-				else
-				{
-					gl_coord = window_coord.convert();
-				}
-				MASK mask = gKeyboard->currentMask(TRUE);
-				// generate move event to update mouse coordinates
-				window_imp->mCallbacks->handleMouseMove(window_imp, gl_coord, mask);
-				if (window_imp->mCallbacks->handleDoubleClick(window_imp, gl_coord, mask) )
-				{
-					return 0;
-				}
-			}
-			break;
+            // Only take control of cursor over client region of window
+            // This allows Windows(tm) to handle resize cursors, etc.
+            if (LOWORD(l_param) == HTCLIENT)
+            {
+                SetCursor(window_imp->mCursor[window_imp->mCurrentCursor]);
+                return 0;
+            }
+            break;
+        }
+        case WM_ENTERMENULOOP:
+        {
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_ENTERMENULOOP");
+            WINDOW_IMP_POST(window_imp->mCallbacks->handleWindowBlock(window_imp));
+            break;
+        }
 
-		case WM_LBUTTONUP:
-			{
-				window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_LBUTTONUP");
-				LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER);
+        case WM_EXITMENULOOP:
+        {
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_EXITMENULOOP");
+            WINDOW_IMP_POST(window_imp->mCallbacks->handleWindowUnblock(window_imp));
+            break;
+        }
 
-				if (!sHandleLeftMouseUp)
-				{
-					sHandleLeftMouseUp = true;
-					break;
-				}
-				sHandleDoubleClick = true;
-
-				//if (gDebugClicks)
-				//{
-				//	LL_INFOS("Window") << "WndProc left button up" << LL_ENDL;
-				//}
-				// Because we move the cursor position in the app, we need to query
-				// to find out where the cursor at the time the event is handled.
-				// If we don't do this, many clicks could get buffered up, and if the
-				// first click changes the cursor position, all subsequent clicks
-				// will occur at the wrong location.  JC
-				if (window_imp->mMousePositionModified)
-				{
-					LLCoordWindow cursor_coord_window;
-					window_imp->getCursorPosition(&cursor_coord_window);
-					gl_coord = cursor_coord_window.convert();
-				}
-				else
-				{
-					gl_coord = window_coord.convert();
-				}
-				MASK mask = gKeyboard->currentMask(TRUE);
-				// generate move event to update mouse coordinates
-				window_imp->mCallbacks->handleMouseMove(window_imp, gl_coord, mask);
-				if (window_imp->mCallbacks->handleMouseUp(window_imp, gl_coord, mask))
-				{
-					return 0;
-				}
-			}
-			break;
+        case WM_ACTIVATEAPP:
+        {
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_ACTIVATEAPP");
+            window_imp->post([=]()
+                {
+                    // This message should be sent whenever the app gains or loses focus.
+                    BOOL activating = (BOOL)w_param;
+                    BOOL minimized = window_imp->getMinimized();
+
+                    if (debug_window_proc)
+                    {
+                        LL_INFOS("Window") << "WINDOWPROC ActivateApp "
+                            << " activating " << S32(activating)
+                            << " minimized " << S32(minimized)
+                            << " fullscreen " << S32(window_imp->mFullscreen)
+                            << LL_ENDL;
+                    }
+
+                    if (window_imp->mFullscreen)
+                    {
+                        // When we run fullscreen, restoring or minimizing the app needs 
+                        // to switch the screen resolution
+                        if (activating)
+                        {
+                            window_imp->setFullscreenResolution();
+                            window_imp->restore();
+                        }
+                        else
+                        {
+                            window_imp->minimize();
+                            window_imp->resetDisplayResolution();
+                        }
+                    }
+
+                    if (!activating)
+                    {
+                        sHandleDoubleClick = false;
+                    }
+
+                    window_imp->mCallbacks->handleActivateApp(window_imp, activating);
+                });
+            break;
+        }
+        case WM_ACTIVATE:
+        {
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_ACTIVATE");
+            window_imp->post([=]()
+                {
+                    // Can be one of WA_ACTIVE, WA_CLICKACTIVE, or WA_INACTIVE
+                    BOOL activating = (LOWORD(w_param) != WA_INACTIVE);
+
+                    BOOL minimized = BOOL(HIWORD(w_param));
+
+                    if (!activating && LLWinImm::isAvailable() && window_imp->mPreeditor)
+                    {
+                        window_imp->interruptLanguageTextInput();
+                    }
+
+                    // JC - I'm not sure why, but if we don't report that we handled the 
+                    // WM_ACTIVATE message, the WM_ACTIVATEAPP messages don't work 
+                    // properly when we run fullscreen.
+                    if (debug_window_proc)
+                    {
+                        LL_INFOS("Window") << "WINDOWPROC Activate "
+                            << " activating " << S32(activating)
+                            << " minimized " << S32(minimized)
+                            << LL_ENDL;
+                    }
+                });
+            
+            break;
+        }
 
-		case WM_RBUTTONDBLCLK:
-		case WM_RBUTTONDOWN:
-			{
-				window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_RBUTTONDOWN");
-				LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER);
-				if (LLWinImm::isAvailable() && window_imp->mPreeditor)
-				{
-					window_imp->interruptLanguageTextInput();
-				}
+        case WM_QUERYOPEN:
+            // TODO: use this to return a nice icon
+            break;
 
-				// Because we move the cursor position in the llviewerapp, we need to query
-				// to find out where the cursor at the time the event is handled.
-				// If we don't do this, many clicks could get buffered up, and if the
-				// first click changes the cursor position, all subsequent clicks
-				// will occur at the wrong location.  JC
-				if (window_imp->mMousePositionModified)
-				{
-					LLCoordWindow cursor_coord_window;
-					window_imp->getCursorPosition(&cursor_coord_window);
-					gl_coord = cursor_coord_window.convert();
-				}
-				else
-				{
-					gl_coord = window_coord.convert();
-				}
-				MASK mask = gKeyboard->currentMask(TRUE);
-				// generate move event to update mouse coordinates
-				window_imp->mCallbacks->handleMouseMove(window_imp, gl_coord, mask);
-				if (window_imp->mCallbacks->handleRightMouseDown(window_imp, gl_coord, mask))
-				{
-					return 0;
-				}
-			}
-			break;
+        case WM_SYSCOMMAND:
+        {
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_SYSCOMMAND");
+            switch (w_param)
+            {
+            case SC_KEYMENU:
+                // Disallow the ALT key from triggering the default system menu.
+                return 0;
+
+            case SC_SCREENSAVE:
+            case SC_MONITORPOWER:
+                // eat screen save messages and prevent them!
+                return 0;
+            }
+            break;
+        }
+        case WM_CLOSE:
+        {
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_CLOSE");
+            window_imp->post([=]()
+                {
+                    // Will the app allow the window to close?
+                    if (window_imp->mCallbacks->handleCloseRequest(window_imp))
+                    {
+                        // Get the app to initiate cleanup.
+                        window_imp->mCallbacks->handleQuit(window_imp);
+                        // The app is responsible for calling destroyWindow when done with GL
+                    }
+                });
+            return 0;
+        }
+        case WM_DESTROY:
+        {
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_DESTROY");
+            if (window_imp->shouldPostQuit())
+            {
+                PostQuitMessage(0);  // Posts WM_QUIT with an exit code of 0
+            }
+            return 0;
+        }
+        case WM_COMMAND:
+        {
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_COMMAND");
+            if (!HIWORD(w_param)) // this message is from a menu
+            {
+                WINDOW_IMP_POST(window_imp->mCallbacks->handleMenuSelect(window_imp, LOWORD(w_param)));
+            }
+            break;
+        }
+        case WM_SYSKEYDOWN:
+        {
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_SYSKEYDOWN");
+            // allow system keys, such as ALT-F4 to be processed by Windows
+            eat_keystroke = FALSE;
+            // intentional fall-through here
+        }
+        case WM_KEYDOWN:
+        {
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_KEYDOWN");
+            window_imp->post([=]()
+                {
+                    window_imp->mKeyCharCode = 0; // don't know until wm_char comes in next
+                    window_imp->mKeyScanCode = (l_param >> 16) & 0xff;
+                    window_imp->mKeyVirtualKey = w_param;
+                    window_imp->mRawMsg = u_msg;
+                    window_imp->mRawWParam = w_param;
+                    window_imp->mRawLParam = l_param;
+
+                    {
+                        if (debug_window_proc)
+                        {
+                            LL_INFOS("Window") << "Debug WindowProc WM_KEYDOWN "
+                                << " key " << S32(w_param)
+                                << LL_ENDL;
+                        }
+                        
+                        gKeyboard->handleKeyDown(w_param, mask);
+                    }
+                });
+            if (eat_keystroke) return 0;    // skip DefWindowProc() handling if we're consuming the keypress 
+            break;
+        }
+        case WM_SYSKEYUP:
+            eat_keystroke = FALSE;
+            // intentional fall-through here
+        case WM_KEYUP:
+        {
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_KEYUP");
+            window_imp->post([=]()
+            {
+                window_imp->mKeyScanCode = (l_param >> 16) & 0xff;
+                window_imp->mKeyVirtualKey = w_param;
+                window_imp->mRawMsg = u_msg;
+                window_imp->mRawWParam = w_param;
+                window_imp->mRawLParam = l_param;
+
+                {
+                    LL_RECORD_BLOCK_TIME(FTM_KEYHANDLER);
+
+                    if (debug_window_proc)
+                    {
+                        LL_INFOS("Window") << "Debug WindowProc WM_KEYUP "
+                            << " key " << S32(w_param)
+                            << LL_ENDL;
+                    }
+                    gKeyboard->handleKeyUp(w_param, mask);
+                }
+            });
+            if (eat_keystroke) return 0;    // skip DefWindowProc() handling if we're consuming the keypress 
+            break;
+        }
+        case WM_IME_SETCONTEXT:
+        {
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_IME_SETCONTEXT");
+            if (debug_window_proc)
+            {
+                LL_INFOS("Window") << "WM_IME_SETCONTEXT" << LL_ENDL;
+            }
+            if (LLWinImm::isAvailable() && window_imp->mPreeditor)
+            {
+                l_param &= ~ISC_SHOWUICOMPOSITIONWINDOW;
+                // Invoke DefWinProc with the modified LPARAM.
+            }
+            break;
+        }
+        case WM_IME_STARTCOMPOSITION:
+        {
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_IME_STARTCOMPOSITION");
+            if (debug_window_proc)
+            {
+                LL_INFOS() << "WM_IME_STARTCOMPOSITION" << LL_ENDL;
+            }
+            if (LLWinImm::isAvailable() && window_imp->mPreeditor)
+            {
+                WINDOW_IMP_POST(window_imp->handleStartCompositionMessage());
+                return 0;
+            }
+            break;
+        }
+        case WM_IME_ENDCOMPOSITION:
+        {
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_IME_ENDCOMPOSITION");
+            if (debug_window_proc)
+            {
+                LL_INFOS() << "WM_IME_ENDCOMPOSITION" << LL_ENDL;
+            }
+            if (LLWinImm::isAvailable() && window_imp->mPreeditor)
+            {
+                return 0;
+            }
+            break;
+        }
+        case WM_IME_COMPOSITION:
+        {
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_IME_COMPOSITION");
+            if (debug_window_proc)
+            {
+                LL_INFOS() << "WM_IME_COMPOSITION" << LL_ENDL;
+            }
+            if (LLWinImm::isAvailable() && window_imp->mPreeditor)
+            {
+                WINDOW_IMP_POST(window_imp->handleCompositionMessage(l_param));
+                return 0;
+            }
+            break;
+        }
+        case WM_IME_REQUEST:
+        {
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_IME_REQUEST");
+            if (debug_window_proc)
+            {
+                LL_INFOS() << "WM_IME_REQUEST" << LL_ENDL;
+            }
+            if (LLWinImm::isAvailable() && window_imp->mPreeditor)
+            {
+                LRESULT result;
+                window_imp->handleImeRequests(w_param, l_param, &result);
+                return result;
+            }
+            break;
+        }
+        case WM_CHAR:
+        {
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_CHAR");
+            window_imp->post([=]()
+                {
+                    window_imp->mKeyCharCode = w_param;
+                    window_imp->mRawMsg = u_msg;
+                    window_imp->mRawWParam = w_param;
+                    window_imp->mRawLParam = l_param;
+
+                    // Should really use WM_UNICHAR eventually, but it requires a specific Windows version and I need
+                    // to figure out how that works. - Doug
+                    //
+                    // ... Well, I don't think so.
+                    // How it works is explained in Win32 API document, but WM_UNICHAR didn't work
+                    // as specified at least on Windows XP SP1 Japanese version.  I have never used
+                    // it since then, and I'm not sure whether it has been fixed now, but I don't think
+                    // it is worth trying.  The good old WM_CHAR works just fine even for supplementary
+                    // characters.  We just need to take care of surrogate pairs sent as two WM_CHAR's
+                    // by ourselves.  It is not that tough.  -- Alissa Sabre @ SL
+                    if (debug_window_proc)
+                    {
+                        LL_INFOS("Window") << "Debug WindowProc WM_CHAR "
+                            << " key " << S32(w_param)
+                            << LL_ENDL;
+                    }
+                    // Even if LLWindowCallbacks::handleUnicodeChar(llwchar, BOOL) returned FALSE,
+                    // we *did* processed the event, so I believe we should not pass it to DefWindowProc...
+                    window_imp->handleUnicodeUTF16((U16)w_param, gKeyboard->currentMask(FALSE));
+                });
+            return 0;
+        }
+        case WM_NCLBUTTONDOWN:
+        {
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_NCLBUTTONDOWN");
+            {
+                // A click in a non-client area, e.g. title bar or window border.
+                window_imp->post([=]()
+                    {
+                        sHandleLeftMouseUp = false;
+                        sHandleDoubleClick = true;
+                    });
+            }
+            break;
+        }
+        case WM_LBUTTONDOWN:
+        {
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_LBUTTONDOWN");
+            {
+                LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER);
+                window_imp->postMouseButtonEvent([=]()
+                    {
+                        sHandleLeftMouseUp = true;
+                        
+                        if (LLWinImm::isAvailable() && window_imp->mPreeditor)
+                        {
+                            window_imp->interruptLanguageTextInput();
+                        }
+                        
+                        MASK mask = gKeyboard->currentMask(TRUE);
+                        auto gl_coord = window_imp->mCursorPosition.convert();
+                        window_imp->mCallbacks->handleMouseMove(window_imp, gl_coord, mask);
+                        window_imp->mCallbacks->handleMouseDown(window_imp, gl_coord, mask);
+                    });
+
+                return 0;
+            }
+            break;
+        }
 
-		case WM_RBUTTONUP:
-			{
-				window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_RBUTTONUP");
-				LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER);
-				// Because we move the cursor position in the app, we need to query
-				// to find out where the cursor at the time the event is handled.
-				// If we don't do this, many clicks could get buffered up, and if the
-				// first click changes the cursor position, all subsequent clicks
-				// will occur at the wrong location.  JC
-				if (window_imp->mMousePositionModified)
-				{
-					LLCoordWindow cursor_coord_window;
-					window_imp->getCursorPosition(&cursor_coord_window);
-					gl_coord = cursor_coord_window.convert();
-				}
-				else
-				{
-					gl_coord = window_coord.convert();
-				}
-				MASK mask = gKeyboard->currentMask(TRUE);
-				// generate move event to update mouse coordinates
-				window_imp->mCallbacks->handleMouseMove(window_imp, gl_coord, mask);
-				if (window_imp->mCallbacks->handleRightMouseUp(window_imp, gl_coord, mask))
-				{
-					return 0;
-				}
-			}
-			break;
+        case WM_LBUTTONDBLCLK:
+        {
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_LBUTTONDBLCLK");
+            window_imp->postMouseButtonEvent([=]()
+                {
+                    //RN: ignore right button double clicks for now
+                    //case WM_RBUTTONDBLCLK:
+                    if (!sHandleDoubleClick)
+                    {
+                        sHandleDoubleClick = true;
+                        return;
+                    }
+                    MASK mask = gKeyboard->currentMask(TRUE);
+
+                    // generate move event to update mouse coordinates
+                    window_imp->mCursorPosition = window_coord;
+                    window_imp->mCallbacks->handleDoubleClick(window_imp, window_imp->mCursorPosition.convert(), mask);
+                });
+
+            return 0;
+        }
+        case WM_LBUTTONUP:
+        {
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_LBUTTONUP");
+            {
+                window_imp->postMouseButtonEvent([=]()
+                    {
+                        LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER);
+                        if (!sHandleLeftMouseUp)
+                        {
+                            sHandleLeftMouseUp = true;
+                            return;
+                        }
+                        sHandleDoubleClick = true;
+
+                        
+                        MASK mask = gKeyboard->currentMask(TRUE);
+                        // generate move event to update mouse coordinates
+                        window_imp->mCursorPosition = window_coord;
+                        window_imp->mCallbacks->handleMouseUp(window_imp, window_imp->mCursorPosition.convert(), mask);
+                    });
+            }
+            return 0;
+        }
+        case WM_RBUTTONDBLCLK:
+        case WM_RBUTTONDOWN:
+        {
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_RBUTTONDOWN");
+            {
+                LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER);
+                window_imp->post([=]()
+                    {
+                        if (LLWinImm::isAvailable() && window_imp->mPreeditor)
+                        {
+                            WINDOW_IMP_POST(window_imp->interruptLanguageTextInput());
+                        }
+
+                        MASK mask = gKeyboard->currentMask(TRUE);
+                        // generate move event to update mouse coordinates
+                        auto gl_coord = window_imp->mCursorPosition.convert();
+                        window_imp->mCallbacks->handleMouseMove(window_imp, gl_coord, mask);
+                        window_imp->mCallbacks->handleRightMouseDown(window_imp, gl_coord, mask);
+                    });
+            }
+            return 0;
+        }
+        break;
 
-		case WM_MBUTTONDOWN:
-//		case WM_MBUTTONDBLCLK:
-			{
-				window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_MBUTTONDOWN");
-				LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER);
-				if (LLWinImm::isAvailable() && window_imp->mPreeditor)
-				{
-					window_imp->interruptLanguageTextInput();
-				}
+        case WM_RBUTTONUP:
+        {
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_RBUTTONUP");
+            {
+                LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER);
+                window_imp->postMouseButtonEvent([=]()
+                    {
+                        MASK mask = gKeyboard->currentMask(TRUE);
+                        window_imp->mCallbacks->handleRightMouseUp(window_imp, window_imp->mCursorPosition.convert(), mask);
+                    });
+            }
+        }
+        break;
 
-				// Because we move the cursor position in tllviewerhe app, we need to query
-				// to find out where the cursor at the time the event is handled.
-				// If we don't do this, many clicks could get buffered up, and if the
-				// first click changes the cursor position, all subsequent clicks
-				// will occur at the wrong location.  JC
-				if (window_imp->mMousePositionModified)
-				{
-					LLCoordWindow cursor_coord_window;
-					window_imp->getCursorPosition(&cursor_coord_window);
-					gl_coord = cursor_coord_window.convert();
-				}
-				else
-				{
-					gl_coord = window_coord.convert();
-				}
-				MASK mask = gKeyboard->currentMask(TRUE);
-				// generate move event to update mouse coordinates
-				window_imp->mCallbacks->handleMouseMove(window_imp, gl_coord, mask);
-				if (window_imp->mCallbacks->handleMiddleMouseDown(window_imp, gl_coord, mask))
-				{
-					return 0;
-				}
-			}
-			break;
+        case WM_MBUTTONDOWN:
+            //		case WM_MBUTTONDBLCLK:
+        {
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_MBUTTONDOWN");
+            {
+                LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER);
+                window_imp->postMouseButtonEvent([=]()
+                    {
+                        if (LLWinImm::isAvailable() && window_imp->mPreeditor)
+                        {
+                            window_imp->interruptLanguageTextInput();
+                        }
+
+                        MASK mask = gKeyboard->currentMask(TRUE);
+                        window_imp->mCallbacks->handleMiddleMouseDown(window_imp, window_imp->mCursorPosition.convert(), mask);
+                    });
+            }
+        }
+        break;
 
-		case WM_MBUTTONUP:
-			{
-				window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_MBUTTONUP");
-				LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER);
-				// Because we move the cursor position in the llviewer app, we need to query
-				// to find out where the cursor at the time the event is handled.
-				// If we don't do this, many clicks could get buffered up, and if the
-				// first click changes the cursor position, all subsequent clicks
-				// will occur at the wrong location.  JC
-				if (window_imp->mMousePositionModified)
-				{
-					LLCoordWindow cursor_coord_window;
-					window_imp->getCursorPosition(&cursor_coord_window);
-					gl_coord = cursor_coord_window.convert();
-				}
-				else
-				{
-					gl_coord = window_coord.convert();
-				}
-				MASK mask = gKeyboard->currentMask(TRUE);
-				// generate move event to update mouse coordinates
-				window_imp->mCallbacks->handleMouseMove(window_imp, gl_coord, mask);
-				if (window_imp->mCallbacks->handleMiddleMouseUp(window_imp, gl_coord, mask))
-				{
-					return 0;
-				}
-			}
-			break;
-		case WM_XBUTTONDOWN:
-			{
-				window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_MBUTTONDOWN");
-				LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER);
-				S32 button = GET_XBUTTON_WPARAM(w_param);
-				if (LLWinImm::isAvailable() && window_imp->mPreeditor)
-				{
-					window_imp->interruptLanguageTextInput();
-				}
+        case WM_MBUTTONUP:
+        {
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_MBUTTONUP");
+            {
+                LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER);
+                window_imp->postMouseButtonEvent([=]()
+                    {
+                        MASK mask = gKeyboard->currentMask(TRUE);
+                        window_imp->mCallbacks->handleMiddleMouseUp(window_imp, window_imp->mCursorPosition.convert(), mask);
+                    });
+            }
+        }
+        break;
+        case WM_XBUTTONDOWN:
+        {
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_XBUTTONDOWN");
+            window_imp->postMouseButtonEvent([=]()
+                {
+                    LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER);
+                    S32 button = GET_XBUTTON_WPARAM(w_param);
+                    if (LLWinImm::isAvailable() && window_imp->mPreeditor)
+                    {
+                        window_imp->interruptLanguageTextInput();
+                    }
+
+                    MASK mask = gKeyboard->currentMask(TRUE);
+                    // Windows uses numbers 1 and 2 for buttons, remap to 4, 5
+                    window_imp->mCallbacks->handleOtherMouseDown(window_imp, window_imp->mCursorPosition.convert(), mask, button + 3);
+                });
+            
+        }
+        break;
 
-				// Because we move the cursor position in tllviewerhe app, we need to query
-				// to find out where the cursor at the time the event is handled.
-				// If we don't do this, many clicks could get buffered up, and if the
-				// first click changes the cursor position, all subsequent clicks
-				// will occur at the wrong location.  JC
-				if (window_imp->mMousePositionModified)
-				{
-					LLCoordWindow cursor_coord_window;
-					window_imp->getCursorPosition(&cursor_coord_window);
-					gl_coord = cursor_coord_window.convert();
-				}
-				else
-				{
-					gl_coord = window_coord.convert();
-				}
-				MASK mask = gKeyboard->currentMask(TRUE);
-				// generate move event to update mouse coordinates
-				window_imp->mCallbacks->handleMouseMove(window_imp, gl_coord, mask);
-				// Windows uses numbers 1 and 2 for buttons, remap to 4, 5
-				if (window_imp->mCallbacks->handleOtherMouseDown(window_imp, gl_coord, mask, button + 3))
-				{
-					return 0;
-				}
-			}
-			break;
+        case WM_XBUTTONUP:
+        {
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_XBUTTONUP");
+            window_imp->postMouseButtonEvent([=]()
+                {
 
-		case WM_XBUTTONUP:
-			{
-				window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_MBUTTONUP");
-				LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER);
-				S32 button = GET_XBUTTON_WPARAM(w_param);
-				// Because we move the cursor position in the llviewer app, we need to query
-				// to find out where the cursor at the time the event is handled.
-				// If we don't do this, many clicks could get buffered up, and if the
-				// first click changes the cursor position, all subsequent clicks
-				// will occur at the wrong location.  JC
-				if (window_imp->mMousePositionModified)
-				{
-					LLCoordWindow cursor_coord_window;
-					window_imp->getCursorPosition(&cursor_coord_window);
-					gl_coord = cursor_coord_window.convert();
-				}
-				else
-				{
-					gl_coord = window_coord.convert();
-				}
-				MASK mask = gKeyboard->currentMask(TRUE);
-				// generate move event to update mouse coordinates
-				window_imp->mCallbacks->handleMouseMove(window_imp, gl_coord, mask);
-				// Windows uses numbers 1 and 2 for buttons, remap to 4, 5
-				if (window_imp->mCallbacks->handleOtherMouseUp(window_imp, gl_coord, mask, button + 3))
-				{
-					return 0;
-				}
-			}
-			break;
+                    LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER);
 
-		case WM_MOUSEWHEEL:
-			{
-				window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_MOUSEWHEEL");
-				static short z_delta = 0;
+                    S32 button = GET_XBUTTON_WPARAM(w_param);
+                    MASK mask = gKeyboard->currentMask(TRUE);
+                    // Windows uses numbers 1 and 2 for buttons, remap to 4, 5
+                    window_imp->mCallbacks->handleOtherMouseUp(window_imp, window_imp->mCursorPosition.convert(), mask, button + 3);
+                });
+        }
+        break;
 
-				RECT	client_rect;
+        case WM_MOUSEWHEEL:
+        {
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_MOUSEWHEEL");
+            static short z_delta = 0;
 
-				// eat scroll events that occur outside our window, since we use mouse position to direct scroll
-				// instead of keyboard focus
-				// NOTE: mouse_coord is in *window* coordinates for scroll events
-				POINT mouse_coord = {(S32)(S16)LOWORD(l_param), (S32)(S16)HIWORD(l_param)};
+            RECT	client_rect;
 
-				if (ScreenToClient(window_imp->mWindowHandle, &mouse_coord)
-					&& GetClientRect(window_imp->mWindowHandle, &client_rect))
-				{
-					// we have a valid mouse point and client rect
-					if (mouse_coord.x < client_rect.left || client_rect.right < mouse_coord.x
-						|| mouse_coord.y < client_rect.top || client_rect.bottom < mouse_coord.y)
-					{
-						// mouse is outside of client rect, so don't do anything
-						return 0;
-					}
-				}
+            // eat scroll events that occur outside our window, since we use mouse position to direct scroll
+            // instead of keyboard focus
+            // NOTE: mouse_coord is in *window* coordinates for scroll events
+            POINT mouse_coord = { (S32)(S16)LOWORD(l_param), (S32)(S16)HIWORD(l_param) };
 
-				S16 incoming_z_delta = HIWORD(w_param);
-				z_delta += incoming_z_delta;
-				// cout << "z_delta " << z_delta << endl;
-
-				// current mouse wheels report changes in increments of zDelta (+120, -120)
-				// Future, higher resolution mouse wheels may report smaller deltas.
-				// So we sum the deltas and only act when we've exceeded WHEEL_DELTA
-				//
-				// If the user rapidly spins the wheel, we can get messages with
-				// large deltas, like 480 or so.  Thus we need to scroll more quickly.
-				if (z_delta <= -WHEEL_DELTA || WHEEL_DELTA <= z_delta)
-				{
-					window_imp->mCallbacks->handleScrollWheel(window_imp, -z_delta / WHEEL_DELTA);
-					z_delta = 0;
-				}
-				return 0;
-			}
-			/*
-			// TODO: add this after resolving _WIN32_WINNT issue
-			case WM_MOUSELEAVE:
-			{
-			window_imp->mCallbacks->handleMouseLeave(window_imp);
-
-			//				TRACKMOUSEEVENT track_mouse_event;
-			//				track_mouse_event.cbSize = sizeof( TRACKMOUSEEVENT );
-			//				track_mouse_event.dwFlags = TME_LEAVE;
-			//				track_mouse_event.hwndTrack = h_wnd;
-			//				track_mouse_event.dwHoverTime = HOVER_DEFAULT;
-			//				TrackMouseEvent( &track_mouse_event ); 
-			return 0;
-			}
-			*/
-		case WM_MOUSEHWHEEL:
-			{
-				window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_MOUSEHWHEEL");
-				static short h_delta = 0;
+            if (ScreenToClient(window_imp->mWindowHandle, &mouse_coord)
+                && GetClientRect(window_imp->mWindowHandle, &client_rect))
+            {
+                // we have a valid mouse point and client rect
+                if (mouse_coord.x < client_rect.left || client_rect.right < mouse_coord.x
+                    || mouse_coord.y < client_rect.top || client_rect.bottom < mouse_coord.y)
+                {
+                    // mouse is outside of client rect, so don't do anything
+                    return 0;
+                }
+            }
 
-				RECT	client_rect;
+            S16 incoming_z_delta = HIWORD(w_param);
+            z_delta += incoming_z_delta;
+            // cout << "z_delta " << z_delta << endl;
+
+            // current mouse wheels report changes in increments of zDelta (+120, -120)
+            // Future, higher resolution mouse wheels may report smaller deltas.
+            // So we sum the deltas and only act when we've exceeded WHEEL_DELTA
+            //
+            // If the user rapidly spins the wheel, we can get messages with
+            // large deltas, like 480 or so.  Thus we need to scroll more quickly.
+            if (z_delta <= -WHEEL_DELTA || WHEEL_DELTA <= z_delta)
+            {
+                short clicks = -z_delta / WHEEL_DELTA;
+                WINDOW_IMP_POST(window_imp->mCallbacks->handleScrollWheel(window_imp, clicks));
+                z_delta = 0;
+            }
+            return 0;
+        }
+        /*
+        // TODO: add this after resolving _WIN32_WINNT issue
+        case WM_MOUSELEAVE:
+        {
+        window_imp->mCallbacks->handleMouseLeave(window_imp);
+
+        //				TRACKMOUSEEVENT track_mouse_event;
+        //				track_mouse_event.cbSize = sizeof( TRACKMOUSEEVENT );
+        //				track_mouse_event.dwFlags = TME_LEAVE;
+        //				track_mouse_event.hwndTrack = h_wnd;
+        //				track_mouse_event.dwHoverTime = HOVER_DEFAULT;
+        //				TrackMouseEvent( &track_mouse_event );
+        return 0;
+        }
+        */
+        case WM_MOUSEHWHEEL:
+        {
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_MOUSEHWHEEL");
+            static short h_delta = 0;
 
-				// eat scroll events that occur outside our window, since we use mouse position to direct scroll
-				// instead of keyboard focus
-				// NOTE: mouse_coord is in *window* coordinates for scroll events
-				POINT mouse_coord = {(S32)(S16)LOWORD(l_param), (S32)(S16)HIWORD(l_param)};
+            RECT	client_rect;
 
-				if (ScreenToClient(window_imp->mWindowHandle, &mouse_coord)
-					&& GetClientRect(window_imp->mWindowHandle, &client_rect))
-				{
-					// we have a valid mouse point and client rect
-					if (mouse_coord.x < client_rect.left || client_rect.right < mouse_coord.x
-						|| mouse_coord.y < client_rect.top || client_rect.bottom < mouse_coord.y)
-					{
-						// mouse is outside of client rect, so don't do anything
-						return 0;
-					}
-				}
+            // eat scroll events that occur outside our window, since we use mouse position to direct scroll
+            // instead of keyboard focus
+            // NOTE: mouse_coord is in *window* coordinates for scroll events
+            POINT mouse_coord = { (S32)(S16)LOWORD(l_param), (S32)(S16)HIWORD(l_param) };
 
-				S16 incoming_h_delta = HIWORD(w_param);
-				h_delta += incoming_h_delta;
+            if (ScreenToClient(window_imp->mWindowHandle, &mouse_coord)
+                && GetClientRect(window_imp->mWindowHandle, &client_rect))
+            {
+                // we have a valid mouse point and client rect
+                if (mouse_coord.x < client_rect.left || client_rect.right < mouse_coord.x
+                    || mouse_coord.y < client_rect.top || client_rect.bottom < mouse_coord.y)
+                {
+                    // mouse is outside of client rect, so don't do anything
+                    return 0;
+                }
+            }
 
-				// If the user rapidly spins the wheel, we can get messages with
-				// large deltas, like 480 or so.  Thus we need to scroll more quickly.
-				if (h_delta <= -WHEEL_DELTA || WHEEL_DELTA <= h_delta)
-				{
-					window_imp->mCallbacks->handleScrollHWheel(window_imp, h_delta / WHEEL_DELTA);
-					h_delta = 0;
-				}
-				return 0;
-			}
-			// Handle mouse movement within the window
-		case WM_MOUSEMOVE:
-			{
-				window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_MOUSEMOVE");
-				MASK mask = gKeyboard->currentMask(TRUE);
-				window_imp->mCallbacks->handleMouseMove(window_imp, window_coord.convert(), mask);
-				return 0;
-			}
+            S16 incoming_h_delta = HIWORD(w_param);
+            h_delta += incoming_h_delta;
 
-		case WM_GETMINMAXINFO:
-			{
-				LPMINMAXINFO min_max = (LPMINMAXINFO)l_param;
-				min_max->ptMinTrackSize.x = window_imp->mMinWindowWidth;
-				min_max->ptMinTrackSize.y = window_imp->mMinWindowHeight;
-				return 0;
-			}
+            // If the user rapidly spins the wheel, we can get messages with
+            // large deltas, like 480 or so.  Thus we need to scroll more quickly.
+            if (h_delta <= -WHEEL_DELTA || WHEEL_DELTA <= h_delta)
+            {
+                WINDOW_IMP_POST(window_imp->mCallbacks->handleScrollHWheel(window_imp, h_delta / WHEEL_DELTA));
+                h_delta = 0;
+            }
+            return 0;
+        }
+        // Handle mouse movement within the window
+        case WM_MOUSEMOVE:
+        {
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_MOUSEMOVE");
+            // DO NOT use mouse event queue for move events to ensure cursor position is updated 
+            // when button events are handled
+            WINDOW_IMP_POST(
+                {
+                    LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_MOUSEMOVE lambda");
+
+                    MASK mask = gKeyboard->currentMask(TRUE);
+                    window_imp->mMouseMask = mask;
+                    window_imp->mCursorPosition = window_coord;
+                });
+            return 0;
+        }
 
-		case WM_SIZE:
-			{
-				window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_SIZE");
-				S32 width = S32( LOWORD(l_param) );
-				S32 height = S32( HIWORD(l_param) );
+        case WM_GETMINMAXINFO:
+        {
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_GETMINMAXINFO");
+            LPMINMAXINFO min_max = (LPMINMAXINFO)l_param;
+            min_max->ptMinTrackSize.x = window_imp->mMinWindowWidth;
+            min_max->ptMinTrackSize.y = window_imp->mMinWindowHeight;
+            return 0;
+        }
 
-				if (debug_window_proc)
-				{
-					BOOL maximized = ( w_param == SIZE_MAXIMIZED );
-					BOOL restored  = ( w_param == SIZE_RESTORED );
-					BOOL minimized = ( w_param == SIZE_MINIMIZED );
-
-					LL_INFOS("Window") << "WINDOWPROC Size "
-						<< width << "x" << height
-						<< " max " << S32(maximized)
-						<< " min " << S32(minimized)
-						<< " rest " << S32(restored)
-						<< LL_ENDL;
-				}
+        case WM_MOVE:
+        {
+            window_imp->updateWindowRect();
+            return 0;
+        }
+        case WM_SIZE:
+        {
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_SIZE");
+            window_imp->updateWindowRect();
+            S32 width = S32(LOWORD(l_param));
+            S32 height = S32(HIWORD(l_param));
 
-				// There's an odd behavior with WM_SIZE that I would call a bug. If 
-				// the window is maximized, and you call MoveWindow() with a size smaller
-				// than a maximized window, it ends up sending WM_SIZE with w_param set 
-				// to SIZE_MAXIMIZED -- which isn't true. So the logic below doesn't work.
-				// (SL-44655). Fixed it by calling ShowWindow(SW_RESTORE) first (see 
-				// LLWindowWin32::moveWindow in this file). 
+            
+            if (debug_window_proc)
+            {
+                BOOL maximized = (w_param == SIZE_MAXIMIZED);
+                BOOL restored = (w_param == SIZE_RESTORED);
+                BOOL minimized = (w_param == SIZE_MINIMIZED);
+
+                LL_INFOS("Window") << "WINDOWPROC Size "
+                    << width << "x" << height
+                    << " max " << S32(maximized)
+                    << " min " << S32(minimized)
+                    << " rest " << S32(restored)
+                    << LL_ENDL;
+            }
 
-				// If we are now restored, but we weren't before, this
-				// means that the window was un-minimized.
-				if (w_param == SIZE_RESTORED && window_imp->mLastSizeWParam != SIZE_RESTORED)
-				{
-					window_imp->mCallbacks->handleActivate(window_imp, TRUE);
-				}
+            // There's an odd behavior with WM_SIZE that I would call a bug. If 
+            // the window is maximized, and you call MoveWindow() with a size smaller
+            // than a maximized window, it ends up sending WM_SIZE with w_param set 
+            // to SIZE_MAXIMIZED -- which isn't true. So the logic below doesn't work.
+            // (SL-44655). Fixed it by calling ShowWindow(SW_RESTORE) first (see 
+            // LLWindowWin32::moveWindow in this file). 
 
-				// handle case of window being maximized from fully minimized state
-				if (w_param == SIZE_MAXIMIZED && window_imp->mLastSizeWParam != SIZE_MAXIMIZED)
-				{
-					window_imp->mCallbacks->handleActivate(window_imp, TRUE);
-				}
+            // If we are now restored, but we weren't before, this
+            // means that the window was un-minimized.
+            if (w_param == SIZE_RESTORED && window_imp->mLastSizeWParam != SIZE_RESTORED)
+            {
+                WINDOW_IMP_POST(window_imp->mCallbacks->handleActivate(window_imp, TRUE));
+            }
 
-				// Also handle the minimization case
-				if (w_param == SIZE_MINIMIZED && window_imp->mLastSizeWParam != SIZE_MINIMIZED)
-				{
-					window_imp->mCallbacks->handleActivate(window_imp, FALSE);
-				}
+            // handle case of window being maximized from fully minimized state
+            if (w_param == SIZE_MAXIMIZED && window_imp->mLastSizeWParam != SIZE_MAXIMIZED)
+            {
+                WINDOW_IMP_POST(window_imp->mCallbacks->handleActivate(window_imp, TRUE));
+            }
 
-				// Actually resize all of our views
-				if (w_param != SIZE_MINIMIZED)
-				{
-					// Ignore updates for minimizing and minimized "windows"
-					window_imp->mCallbacks->handleResize(	window_imp, 
-						LOWORD(l_param), 
-						HIWORD(l_param) );
-				}
+            // Also handle the minimization case
+            if (w_param == SIZE_MINIMIZED && window_imp->mLastSizeWParam != SIZE_MINIMIZED)
+            {
+                WINDOW_IMP_POST(window_imp->mCallbacks->handleActivate(window_imp, FALSE));
+            }
 
-				window_imp->mLastSizeWParam = w_param;
+            // Actually resize all of our views
+            if (w_param != SIZE_MINIMIZED)
+            {
+                // Ignore updates for minimizing and minimized "windows"
+                WINDOW_IMP_POST(window_imp->mCallbacks->handleResize(window_imp,
+                    LOWORD(l_param),
+                    HIWORD(l_param)));
+            }
 
-				return 0;
-			}
-        
-		case WM_DPICHANGED:
-			{
-				LPRECT lprc_new_scale;
-				F32 new_scale = F32(LOWORD(w_param)) / F32(USER_DEFAULT_SCREEN_DPI);
-				lprc_new_scale = (LPRECT)l_param;
-				S32 new_width = lprc_new_scale->right - lprc_new_scale->left;
-				S32 new_height = lprc_new_scale->bottom - lprc_new_scale->top;
-				if (window_imp->mCallbacks->handleDPIChanged(window_imp, new_scale, new_width, new_height))
-				{
-					SetWindowPos(h_wnd,
-						HWND_TOP,
-						lprc_new_scale->left,
-						lprc_new_scale->top,
-						new_width,
-						new_height,
-						SWP_NOZORDER | SWP_NOACTIVATE);
-				}
-				return 0;
-			}
+            window_imp->mLastSizeWParam = w_param;
 
-		case WM_SETFOCUS:
-			if (debug_window_proc)
-			{
-				LL_INFOS("Window") << "WINDOWPROC SetFocus" << LL_ENDL;
-			}
-			window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_SETFOCUS");
-			window_imp->mCallbacks->handleFocus(window_imp);
-			return 0;
+            return 0;
+        }
 
-		case WM_KILLFOCUS:
-			if (debug_window_proc)
-			{
-				LL_INFOS("Window") << "WINDOWPROC KillFocus" << LL_ENDL;
-			}
-			window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_KILLFOCUS");
-			window_imp->mCallbacks->handleFocusLost(window_imp);
-			return 0;
+        case WM_DPICHANGED:
+        {
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_DPICHANGED");
+            LPRECT lprc_new_scale;
+            F32 new_scale = F32(LOWORD(w_param)) / F32(USER_DEFAULT_SCREEN_DPI);
+            lprc_new_scale = (LPRECT)l_param;
+            S32 new_width = lprc_new_scale->right - lprc_new_scale->left;
+            S32 new_height = lprc_new_scale->bottom - lprc_new_scale->top;
+            WINDOW_IMP_POST(window_imp->mCallbacks->handleDPIChanged(window_imp, new_scale, new_width, new_height));
+            
+            SetWindowPos(h_wnd,
+                HWND_TOP,
+                lprc_new_scale->left,
+                lprc_new_scale->top,
+                new_width,
+                new_height,
+                SWP_NOZORDER | SWP_NOACTIVATE);
+           
+            return 0;
+        }
 
-		case WM_COPYDATA:
-			{
-				window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_COPYDATA");
-				// received a URL
-				PCOPYDATASTRUCT myCDS = (PCOPYDATASTRUCT) l_param;
-				window_imp->mCallbacks->handleDataCopy(window_imp, myCDS->dwData, myCDS->lpData);
-			};
-			return 0;			
+        case WM_SETFOCUS:
+        {
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_SETFOCUS");
+            if (debug_window_proc)
+            {
+                LL_INFOS("Window") << "WINDOWPROC SetFocus" << LL_ENDL;
+            }
+            WINDOW_IMP_POST(window_imp->mCallbacks->handleFocus(window_imp));
+            return 0;
+        }
 
-			break;
+        case WM_KILLFOCUS:
+        {
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_KILLFOCUS");
+            if (debug_window_proc)
+            {
+                LL_INFOS("Window") << "WINDOWPROC KillFocus" << LL_ENDL;
+            }
+            WINDOW_IMP_POST(window_imp->mCallbacks->handleFocusLost(window_imp));
+            return 0;
+        }
 
-		case WM_SETTINGCHANGE:
-			{
-				if (w_param == SPI_SETMOUSEVANISH)
-				{
-					if (!SystemParametersInfo(SPI_GETMOUSEVANISH, 0, &window_imp->mMouseVanish, 0))
-					{
-						window_imp->mMouseVanish = TRUE;
-					}
-				}
-			}
-			break;
-		default:
-			{
-				if (debug_window_proc)
-				{
-					LL_INFOS("Window") << "Unhandled windows message code: " << U32(u_msg) << LL_ENDL;
-				}
-			}
-			break;
-		}
+        case WM_COPYDATA:
+        {
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_COPYDATA");
+            {
+                // received a URL
+                PCOPYDATASTRUCT myCDS = (PCOPYDATASTRUCT)l_param;
+                void* data = new U8[myCDS->cbData];
+                memcpy(data, myCDS->lpData, myCDS->cbData);
+                auto myType = myCDS->dwData;
+
+                window_imp->post([=]()
+                    {
+                       window_imp->mCallbacks->handleDataCopy(window_imp, myType, data);
+                       delete[] data;
+                    });
+            };
+            return 0;
+
+            break;
+        }
+        case WM_SETTINGCHANGE:
+        {
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_SETTINGCHANGE");
+            if (w_param == SPI_SETMOUSEVANISH)
+            {
+                if (!SystemParametersInfo(SPI_GETMOUSEVANISH, 0, &window_imp->mMouseVanish, 0))
+                {
+                    WINDOW_IMP_POST(window_imp->mMouseVanish = TRUE);
+                }
+            }
+        }
+        break;
+        
+        case WM_INPUT:
+        {
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("MWP - WM_INPUT");
+            
+            UINT dwSize = 0;
+            GetRawInputData((HRAWINPUT)l_param, RID_INPUT, NULL, &dwSize, sizeof(RAWINPUTHEADER));
+            llassert(dwSize < 1024);
+
+            U8 lpb[1024];
+            
+            if (GetRawInputData((HRAWINPUT)l_param, RID_INPUT, (void*)lpb, &dwSize, sizeof(RAWINPUTHEADER)) == dwSize)
+            {
+                RAWINPUT* raw = (RAWINPUT*)lpb;
+
+                if (raw->header.dwType == RIM_TYPEMOUSE)
+                {
+                    LLMutexLock lock(&window_imp->mRawMouseMutex);
+
+                    S32 speed;
+                    const S32 DEFAULT_SPEED(10);
+                    SystemParametersInfo(SPI_GETMOUSESPEED, 0, &speed, 0);
+                    if (speed == DEFAULT_SPEED)
+                    {
+                        window_imp->mRawMouseDelta.mX += raw->data.mouse.lLastX;
+                        window_imp->mRawMouseDelta.mY -= raw->data.mouse.lLastY;
+                    }
+                    else
+                    {
+                        window_imp->mRawMouseDelta.mX += round((F32)raw->data.mouse.lLastX * (F32)speed / DEFAULT_SPEED);
+                        window_imp->mRawMouseDelta.mY -= round((F32)raw->data.mouse.lLastY * (F32)speed / DEFAULT_SPEED);
+                    }
+                }
+            }
+        }
 
-	window_imp->mCallbacks->handlePauseWatchdog(window_imp);	
-	}
+        //list of messages we get often that we don't care to log about
+        case WM_NCHITTEST:
+        case WM_NCMOUSEMOVE:
+        case WM_NCMOUSELEAVE:
+        case WM_MOVING:
+        case WM_WINDOWPOSCHANGING:
+        case WM_WINDOWPOSCHANGED:
+        break;
+
+        default:
+        {
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - default");
+            if (debug_window_proc)
+            {
+                LL_INFOS("Window") << "Unhandled windows message code: 0x" << std::hex << U32(u_msg) << LL_ENDL;
+            }
+        }
+        break;
+        }
+    }
     else
     {
         // (NULL == window_imp)
         LL_DEBUGS("Window") << "No window implementation to handle message with, message code: " << U32(u_msg) << LL_ENDL;
     }
 
-	// pass unhandled messages down to Windows
-	return DefWindowProc(h_wnd, u_msg, w_param, l_param);
+    // pass unhandled messages down to Windows
+    LRESULT ret;
+    {
+        LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - DefWindowProc");
+        ret = DefWindowProc(h_wnd, u_msg, w_param, l_param);
+    }
+    return ret;
 }
 
 BOOL LLWindowWin32::convertCoords(LLCoordGL from, LLCoordWindow *to)
@@ -3186,6 +3295,8 @@ BOOL LLWindowWin32::copyTextToClipboard(const LLWString& wstr)
 // Constrains the mouse to the window.
 void LLWindowWin32::setMouseClipping( BOOL b )
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_WIN32;
+    ASSERT_MAIN_THREAD();
 	if( b != mIsMouseClipping )
 	{
 		BOOL success = FALSE;
@@ -3216,43 +3327,46 @@ void LLWindowWin32::setMouseClipping( BOOL b )
 
 BOOL LLWindowWin32::getClientRectInScreenSpace( RECT* rectp )
 {
-	BOOL success = FALSE;
+    BOOL success = FALSE;
 
-	RECT client_rect;
-	if( mWindowHandle && GetClientRect(mWindowHandle, &client_rect) )
-	{
-		POINT top_left;
-		top_left.x = client_rect.left;
-		top_left.y = client_rect.top;
-		ClientToScreen(mWindowHandle, &top_left); 
-
-		POINT bottom_right;
-		bottom_right.x = client_rect.right;
-		bottom_right.y = client_rect.bottom;
-		ClientToScreen(mWindowHandle, &bottom_right); 
-
-		SetRect( rectp,
-			top_left.x,
-			top_left.y,
-			bottom_right.x,
-			bottom_right.y );
-
-		success = TRUE;
-	}
+    RECT client_rect;
+    if (mWindowHandle && GetClientRect(mWindowHandle, &client_rect))
+    {
+        POINT top_left;
+        top_left.x = client_rect.left;
+        top_left.y = client_rect.top;
+        ClientToScreen(mWindowHandle, &top_left);
+
+        POINT bottom_right;
+        bottom_right.x = client_rect.right;
+        bottom_right.y = client_rect.bottom;
+        ClientToScreen(mWindowHandle, &bottom_right);
+
+        SetRect(rectp,
+            top_left.x,
+            top_left.y,
+            bottom_right.x,
+            bottom_right.y);
+
+        success = TRUE;
+    }
 
-	return success;
+    return success;
 }
 
 void LLWindowWin32::flashIcon(F32 seconds)
 {
-	FLASHWINFO flash_info;
-
-	flash_info.cbSize = sizeof(FLASHWINFO);
-	flash_info.hwnd = mWindowHandle;
-	flash_info.dwFlags = FLASHW_TRAY;
-	flash_info.uCount = UINT(seconds / ICON_FLASH_TIME);
-	flash_info.dwTimeout = DWORD(1000.f * ICON_FLASH_TIME); // milliseconds
-	FlashWindowEx(&flash_info);
+    mWindowThread->post([=]()
+        {
+            FLASHWINFO flash_info;
+
+            flash_info.cbSize = sizeof(FLASHWINFO);
+            flash_info.hwnd = mWindowHandle;
+            flash_info.dwFlags = FLASHW_TRAY;
+            flash_info.uCount = UINT(seconds / ICON_FLASH_TIME);
+            flash_info.dwTimeout = DWORD(1000.f * ICON_FLASH_TIME); // milliseconds
+            FlashWindowEx(&flash_info);
+        });
 }
 
 F32 LLWindowWin32::getGamma()
@@ -3262,6 +3376,7 @@ F32 LLWindowWin32::getGamma()
 
 BOOL LLWindowWin32::restoreGamma()
 {
+    ASSERT_MAIN_THREAD();
 	if (mCustomGammaSet != FALSE)
 	{
         LL_DEBUGS("Window") << "Restoring gamma" << LL_ENDL;
@@ -3273,6 +3388,7 @@ BOOL LLWindowWin32::restoreGamma()
 
 BOOL LLWindowWin32::setGamma(const F32 gamma)
 {
+    ASSERT_MAIN_THREAD();
 	mCurrentGamma = gamma;
 
 	//Get the previous gamma ramp to restore later.
@@ -3311,6 +3427,7 @@ BOOL LLWindowWin32::setGamma(const F32 gamma)
 
 void LLWindowWin32::setFSAASamples(const U32 fsaa_samples)
 {
+    ASSERT_MAIN_THREAD();
 	mFSAASamples = fsaa_samples;
 }
 
@@ -3321,6 +3438,7 @@ U32 LLWindowWin32::getFSAASamples()
 
 LLWindow::LLWindowResolution* LLWindowWin32::getSupportedResolutions(S32 &num_resolutions)
 {
+    ASSERT_MAIN_THREAD();
 	if (!mSupportedResolutions)
 	{
 		mSupportedResolutions = new LLWindowResolution[MAX_NUM_RESOLUTIONS];
@@ -3475,7 +3593,12 @@ BOOL LLWindowWin32::resetDisplayResolution()
 
 void LLWindowWin32::swapBuffers()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_WIN32;
+    ASSERT_MAIN_THREAD();
+    glFlush(); //superstitious flush for maybe frame stall removal?
 	SwapBuffers(mhDC);
+
+    LL_PROFILER_GPU_COLLECT
 }
 
 
@@ -3700,13 +3823,19 @@ void *LLWindowWin32::getPlatformWindow()
 
 void LLWindowWin32::bringToFront()
 {
-	BringWindowToTop(mWindowHandle);
+    mWindowThread->post([=]()
+        {
+            BringWindowToTop(mWindowHandle);
+        });
 }
 
 // set (OS) window focus back to the client
 void LLWindowWin32::focusClient()
 {
-	SetFocus ( mWindowHandle );
+    mWindowThread->post([=]()
+        {
+            SetFocus(mWindowHandle);
+        });
 }
 
 void LLWindowWin32::allowLanguageTextInput(LLPreeditor *preeditor, BOOL b)
@@ -3948,6 +4077,7 @@ void LLWindowWin32::updateLanguageTextInputArea()
 
 void LLWindowWin32::interruptLanguageTextInput()
 {
+    ASSERT_MAIN_THREAD();
 	if (mPreeditor && LLWinImm::isAvailable())
 	{
 		HIMC himc = LLWinImm::getContext(mWindowHandle);
@@ -4150,6 +4280,7 @@ static LLWString find_context(const LLWString & wtext, S32 focus, S32 focus_leng
 // for files and via IDropTarget interface requests.
 LLWindowCallbacks::DragNDropResult LLWindowWin32::completeDragNDropRequest( const LLCoordGL gl_coord, const MASK mask, LLWindowCallbacks::DragNDropAction action, const std::string url )
 {
+    ASSERT_MAIN_THREAD();
 	return mCallbacks->handleDragNDrop( this, gl_coord, mask, action, url );
 }
 
@@ -4198,6 +4329,7 @@ BOOL LLWindowWin32::handleImeRequests(WPARAM request, LPARAM param, LRESULT *res
 					LL_WARNS("Window") << "*** IMR_QUERYCHARPOSITON called but getPreeditLocation failed." << LL_ENDL;
 					return FALSE;
 				}
+
 				fillCharPosition(caret_coord, preedit_bounds, text_control, char_position);
 
 				*result = 1;
@@ -4262,7 +4394,8 @@ BOOL LLWindowWin32::handleImeRequests(WPARAM request, LPARAM param, LRESULT *res
 				S32 context_offset;
 				LLWString context = find_context(wtext, preedit, preedit_length, &context_offset);
 				preedit -= context_offset;
-				if (preedit_length)
+				preedit_length = llmin(preedit_length, (S32)context.length() - preedit);
+				if (preedit_length && preedit >= 0)
 				{
 					// IMR_DOCUMENTFEED may be called when we have an active preedit.
 					// We should pass the context string *excluding* the preedit string.
@@ -4405,3 +4538,153 @@ std::vector<std::string> LLWindowWin32::getDynamicFallbackFontList()
 
 
 #endif // LL_WINDOWS
+
+inline LLWindowWin32::LLWindowWin32Thread::LLWindowWin32Thread()
+    : ThreadPool("Window Thread", 1, MAX_QUEUE_SIZE)
+{
+    ThreadPool::start();
+}
+
+/**
+ * LogChange is to log changes in status while trying to avoid spamming the
+ * log with repeated messages, especially in a tight loop. It refuses to log
+ * a continuous run of identical messages, but logs every time the message
+ * changes. (It will happily spam when messages quickly bounce back and
+ * forth.)
+ */
+class LogChange
+{
+public:
+    LogChange(const std::string& tag):
+        mTag(tag)
+    {}
+
+    template <typename... Items>
+    void always(Items&&... items)
+    {
+        // This odd construct ensures that the stringize() call is only
+        // executed if DEBUG logging is enabled for the passed tag.
+        LL_DEBUGS(mTag.c_str());
+        log(LL_CONT, stringize(std::forward<Items>(items)...));
+        LL_ENDL;
+    }
+
+    template <typename... Items>
+    void onChange(Items&&... items)
+    {
+        LL_DEBUGS(mTag.c_str());
+        auto str = stringize(std::forward<Items>(items)...);
+        if (str != mPrev)
+        {
+            log(LL_CONT, str);
+        }
+        LL_ENDL;
+    }
+
+private:
+    void log(std::ostream& out, const std::string& message)
+    {
+        mPrev = message;
+        out << message;
+    }
+    std::string mTag;
+    std::string mPrev;
+};
+
+void LLWindowWin32::LLWindowWin32Thread::run()
+{
+    sWindowThreadId = std::this_thread::get_id();
+    LogChange logger("Window");
+
+    while (! getQueue().done())
+    {
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_WIN32;
+
+        if (mWindowHandle != 0)
+        {
+            MSG msg;
+            BOOL status;
+            if (mhDC == 0)
+            {
+                LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("w32t - PeekMessage");
+                logger.onChange("PeekMessage(", std::hex, mWindowHandle, ")");
+                status = PeekMessage(&msg, mWindowHandle, 0, 0, PM_REMOVE);
+            }
+            else
+            {
+                LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("w32t - GetMessage");
+                logger.always("GetMessage(", std::hex, mWindowHandle, ")");
+                status = GetMessage(&msg, NULL, 0, 0);
+            }
+            if (status > 0)
+            {
+                logger.always("got MSG (", std::hex, msg.hwnd, ", ", msg.message,
+                              ", ", msg.wParam, ")");
+                TranslateMessage(&msg);
+                DispatchMessage(&msg);
+
+                mMessageQueue.pushFront(msg);
+            }
+        }
+
+        {
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("w32t - Function Queue");
+            logger.onChange("runPending()");
+            //process any pending functions
+            getQueue().runPending();
+        }
+        
+#if 0
+        {
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("w32t - Sleep");
+            logger.always("sleep(1)");
+            std::this_thread::sleep_for(std::chrono::milliseconds(1));
+        }
+#endif
+    }
+}
+
+void LLWindowWin32::post(const std::function<void()>& func)
+{
+    mFunctionQueue.pushFront(func);
+}
+
+void LLWindowWin32::postMouseButtonEvent(const std::function<void()>& func)
+{
+    mMouseQueue.pushFront(func);
+}
+
+void LLWindowWin32::kickWindowThread(HWND windowHandle)
+{
+    if (! windowHandle)
+        windowHandle = mWindowHandle;
+    if (windowHandle)
+    {
+        // post a nonsense user message to wake up the Window Thread in
+        // case any functions are pending and no windows events came
+        // through this frame
+        WPARAM wparam{ 0xB0B0 };
+        LL_DEBUGS("Window") << "PostMessage(" << std::hex << windowHandle
+                            << ", " << WM_DUMMY_
+                            << ", " << wparam << ")" << std::dec << LL_ENDL;
+        PostMessage(windowHandle, WM_DUMMY_, wparam, 0x1337);
+    }
+}
+
+void LLWindowWin32::updateWindowRect()
+{
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_WIN32;
+    //called from window thread
+    RECT rect;
+    RECT client_rect;
+    
+    if (GetWindowRect(mWindowHandle, &rect) &&
+        GetClientRect(mWindowHandle, &client_rect))
+    {
+        post([=] 
+            {
+                mRect = rect;
+                mClientRect = client_rect;
+            });
+    }
+}
diff --git a/indra/llwindow/llwindowwin32.h b/indra/llwindow/llwindowwin32.h
index e33330c1bb9f7ffe86f0fcb6cdcc9df63c6acf83..b391acc12d390b8484f0d0d62f418571ac3b3d9c 100644
--- a/indra/llwindow/llwindowwin32.h
+++ b/indra/llwindow/llwindowwin32.h
@@ -33,6 +33,10 @@
 #include "llwindow.h"
 #include "llwindowcallbacks.h"
 #include "lldragdropwin32.h"
+#include "llthread.h"
+#include "llthreadsafequeue.h"
+#include "llmutex.h"
+#include "workqueue.h"
 
 // Hack for async host by name
 #define LL_WM_HOST_RESOLVED      (WM_APP + 1)
@@ -57,9 +61,15 @@ class LLWindowWin32 : public LLWindow
 	/*virtual*/ BOOL setPosition(LLCoordScreen position);
 	/*virtual*/ BOOL setSizeImpl(LLCoordScreen size);
 	/*virtual*/ BOOL setSizeImpl(LLCoordWindow size);
-	/*virtual*/ BOOL switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL disable_vsync, const LLCoordScreen * const posp = NULL);
+	/*virtual*/ BOOL switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL enable_vsync, const LLCoordScreen * const posp = NULL);
+    /*virtual*/ void setTitle(const std::string title);
+    void* createSharedContext() override;
+    void makeContextCurrent(void* context) override;
+    void destroySharedContext(void* context) override;
+    /*virtual*/ void toggleVSync(bool enable_vsync);
 	/*virtual*/ BOOL setCursorPosition(LLCoordWindow position);
 	/*virtual*/ BOOL getCursorPosition(LLCoordWindow *position);
+    /*virtual*/ BOOL getCursorDelta(LLCoordCommon* delta);
 	/*virtual*/ void showCursor();
 	/*virtual*/ void hideCursor();
 	/*virtual*/ void showCursorFromMouseMove();
@@ -126,7 +136,7 @@ class LLWindowWin32 : public LLWindow
 protected:
 	LLWindowWin32(LLWindowCallbacks* callbacks,
 		const std::string& title, const std::string& name, int x, int y, int width, int height, U32 flags, 
-		BOOL fullscreen, BOOL clearBg, BOOL disable_vsync, BOOL use_gl,
+		BOOL fullscreen, BOOL clearBg, BOOL enable_vsync, BOOL use_gl,
 		BOOL ignore_pixel_depth, U32 fsaa_samples);
 	~LLWindowWin32();
 
@@ -175,17 +185,24 @@ class LLWindowWin32 : public LLWindow
 	WCHAR		*mWindowTitle;
 	WCHAR		*mWindowClassName;
 
-	HWND		mWindowHandle;	// window handle
-	HGLRC		mhRC;			// OpenGL rendering context
-	HDC			mhDC;			// Windows Device context handle
+	HWND	    mWindowHandle = 0;	// window handle
+	HGLRC		mhRC = 0;			// OpenGL rendering context
+	HDC			mhDC = 0;			// Windows Device context handle
 	HINSTANCE	mhInstance;		// handle to application instance
-	WNDPROC		mWndProc;		// user-installable window proc
 	RECT		mOldMouseClip;  // Screen rect to which the mouse cursor was globally constrained before we changed it in clipMouse()
 	WPARAM		mLastSizeWParam;
 	F32			mOverrideAspectRatio;
 	F32			mNativeAspectRatio;
 
 	HCURSOR		mCursor[ UI_CURSOR_COUNT ];  // Array of all mouse cursors
+    LLCoordWindow mCursorPosition;  // mouse cursor position, should only be mutated on main thread
+    LLMutex mRawMouseMutex;
+    RAWINPUTDEVICE mRawMouse;
+    LLCoordWindow mLastCursorPosition; // mouse cursor position from previous frame
+    LLCoordCommon mRawMouseDelta; // raw mouse delta according to window thread
+    LLCoordCommon mMouseFrameDelta; // how much the mouse moved between the last two calls to gatherInput
+
+    MASK        mMouseMask;
 
 	static BOOL sIsClassRegistered; // has the window class been registered?
 
@@ -196,7 +213,6 @@ class LLWindowWin32 : public LLWindow
 	BOOL		mCustomGammaSet;
 
 	LPWSTR		mIconResource;
-	BOOL		mMousePositionModified;
 	BOOL		mInputProcessingPaused;
 
 	// The following variables are for Language Text Input control.
@@ -224,6 +240,20 @@ class LLWindowWin32 : public LLWindow
 
 	BOOL			mMouseVanish;
 
+    // Cached values of GetWindowRect and GetClientRect to be used by app thread
+    void updateWindowRect();
+    RECT mRect; 
+    RECT mClientRect;
+
+	struct LLWindowWin32Thread;
+	LLWindowWin32Thread* mWindowThread = nullptr;
+	LLThreadSafeQueue<std::function<void()>> mFunctionQueue;
+	LLThreadSafeQueue<std::function<void()>> mMouseQueue;
+	void post(const std::function<void()>& func);
+	void postMouseButtonEvent(const std::function<void()>& func);
+	void recreateWindow(RECT window_rect, DWORD dw_ex_style, DWORD dw_style);
+	void kickWindowThread(HWND windowHandle=0);
+
 	friend class LLWindowManager;
 };
 
diff --git a/indra/llxml/llcontrol.h b/indra/llxml/llcontrol.h
index 19508becc30b4392bcdd38c5ca94d8e24e697ae7..0839c02c50853390dda3469ece98794b38ba8335 100644
--- a/indra/llxml/llcontrol.h
+++ b/indra/llxml/llcontrol.h
@@ -247,6 +247,7 @@ class LLControlGroup : public LLInstanceTracker<LLControlGroup, std::string>
 	// generic getter
 	template<typename T> T get(const std::string& name)
 	{
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD;
 		LLControlVariable* control = getControl(name);
 		LLSD value;
 		eControlType type = TYPE_COUNT;
@@ -405,8 +406,8 @@ class LLCachedControl
 					const T& default_value, 
 					const std::string& comment = "Declared In Code")
 	{
-		mCachedControlPtr = LLControlCache<T>::getInstance(name);
-		if (mCachedControlPtr.isNull())
+		mCachedControlPtr = LLControlCache<T>::getInstance(name).get();
+		if (! mCachedControlPtr)
 		{
 			mCachedControlPtr = new LLControlCache<T>(group, name, default_value, comment);
 		}
@@ -415,8 +416,8 @@ class LLCachedControl
 	LLCachedControl(LLControlGroup& group,
 					const std::string& name)
 	{
-		mCachedControlPtr = LLControlCache<T>::getInstance(name);
-		if (mCachedControlPtr.isNull())
+		mCachedControlPtr = LLControlCache<T>::getInstance(name).get();
+		if (! mCachedControlPtr)
 		{
 			mCachedControlPtr = new LLControlCache<T>(group, name);
 		}
diff --git a/indra/mac_crash_logger/README.txt b/indra/mac_crash_logger/README.txt
deleted file mode 100644
index 6932a8d9c3172993246b786c17fcda455a1626c9..0000000000000000000000000000000000000000
--- a/indra/mac_crash_logger/README.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-This component is no longer used in Linden Lab builds.
-Change requests to support continued use by open source
-builds are welcome.
diff --git a/indra/media_plugins/cef/CMakeLists.txt b/indra/media_plugins/cef/CMakeLists.txt
index 854ba5573125174381194d9336ca4bec19cdaf03..2acce03d08cf02051bd4a9babc0431154aa856a1 100644
--- a/indra/media_plugins/cef/CMakeLists.txt
+++ b/indra/media_plugins/cef/CMakeLists.txt
@@ -108,9 +108,6 @@ if (DARWIN)
     LINK_FLAGS "-exported_symbols_list ${CMAKE_CURRENT_SOURCE_DIR}/../base/media_plugin_base.exp"
   )
 
-  ## turns on C++11 using Cmake
-  target_compile_features(media_plugin_cef PRIVATE cxx_range_for)
-
   add_custom_command(TARGET media_plugin_cef
     POST_BUILD COMMAND ${CMAKE_INSTALL_NAME_TOOL} -change "@executable_path/Chromium Embedded Framework"
         "@executable_path/../../../../Frameworks/Chromium Embedded Framework.framework/Chromium Embedded Framework"
diff --git a/indra/media_plugins/cef/media_plugin_cef.cpp b/indra/media_plugins/cef/media_plugin_cef.cpp
index ea70e214145fe06ecc10087789561d69198984b9..43d3a32e6464bab8b88bf2c2a075a5f2f93cd0ef 100644
--- a/indra/media_plugins/cef/media_plugin_cef.cpp
+++ b/indra/media_plugins/cef/media_plugin_cef.cpp
@@ -34,6 +34,7 @@
 #include "llplugininstance.h"
 #include "llpluginmessage.h"
 #include "llpluginmessageclasses.h"
+#include "llstring.h"
 #include "volume_catcher.h"
 #include "media_plugin_base.h"
 
@@ -55,7 +56,7 @@ class MediaPluginCEF :
 	bool init();
 
 	void onPageChangedCallback(const unsigned char* pixels, int x, int y, const int width, const int height);
-	void onCustomSchemeURLCallback(std::string url);
+	void onCustomSchemeURLCallback(std::string url, bool user_gesture, bool is_redirect);
 	void onConsoleMessageCallback(std::string message, std::string source, int line);
 	void onStatusMessageCallback(std::string value);
 	void onTitleChangeCallback(std::string title);
@@ -299,11 +300,18 @@ void MediaPluginCEF::onOpenPopupCallback(std::string url, std::string target)
 
 ////////////////////////////////////////////////////////////////////////////////
 //
-void MediaPluginCEF::onCustomSchemeURLCallback(std::string url)
+void MediaPluginCEF::onCustomSchemeURLCallback(std::string url, bool user_gesture, bool is_redirect)
 {
 	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "click_nofollow");
-	message.setValue("uri", url);
-	message.setValue("nav_type", "clicked");	// TODO: differentiate between click and navigate to
+    message.setValue("uri", url);
+
+    // indicate if this interaction was from a user click (okay on a SLAPP) or 
+    // via a navigation (e.g. a data URL - see SL-18151) (not okay on a SLAPP)
+    const std::string nav_type = user_gesture ? "clicked" : "navigated";
+
+	message.setValue("nav_type", nav_type);
+    message.setValueBoolean("is_redirect", is_redirect);
+
 	sendMessage(message);
 }
 
@@ -592,7 +600,7 @@ void MediaPluginCEF::receiveMessage(const char* message_string)
             {
                 // event callbacks from Dullahan
                 mCEFLib->setOnPageChangedCallback(std::bind(&MediaPluginCEF::onPageChangedCallback, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5));
-                mCEFLib->setOnCustomSchemeURLCallback(std::bind(&MediaPluginCEF::onCustomSchemeURLCallback, this, std::placeholders::_1));
+                mCEFLib->setOnCustomSchemeURLCallback(std::bind(&MediaPluginCEF::onCustomSchemeURLCallback, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
                 mCEFLib->setOnConsoleMessageCallback(std::bind(&MediaPluginCEF::onConsoleMessageCallback, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
                 mCEFLib->setOnStatusMessageCallback(std::bind(&MediaPluginCEF::onStatusMessageCallback, this, std::placeholders::_1));
                 mCEFLib->setOnTitleChangeCallback(std::bind(&MediaPluginCEF::onTitleChangeCallback, this, std::placeholders::_1));
@@ -616,9 +624,9 @@ void MediaPluginCEF::receiveMessage(const char* message_string)
                 // dir as the executable that loaded it (SLPlugin.exe). The code in 
                 // Dullahan that tried to figure out the location automatically uses 
                 // the location of the exe which isn't helpful so we tell it explicitly.
-                char cur_dir_str[MAX_PATH];
-                GetCurrentDirectoryA(MAX_PATH, cur_dir_str);
-                settings.host_process_path = std::string(cur_dir_str);
+                std::vector<wchar_t> buffer(MAX_PATH + 1);
+                GetCurrentDirectoryW(MAX_PATH, &buffer[0]);
+                settings.host_process_path = ll_convert_wide_to_string(&buffer[0]);
 #endif
                 settings.accept_language_list = mHostLanguage;
 
diff --git a/indra/media_plugins/libvlc/media_plugin_libvlc.cpp b/indra/media_plugins/libvlc/media_plugin_libvlc.cpp
index 1afe25e9a162a24d04270e041b8fda4eea3ab2a2..89144922cca113bd03bc61b1519854e6961b10b6 100644
--- a/indra/media_plugins/libvlc/media_plugin_libvlc.cpp
+++ b/indra/media_plugins/libvlc/media_plugin_libvlc.cpp
@@ -73,6 +73,7 @@ class MediaPluginLibVLC :
 	static void display(void* data, void* id);
 
 	/*virtual*/ void setDirty(int left, int top, int right, int bottom) /* override, but that is not supported in gcc 4.6 */;
+    void setDurationDirty();
 
 	static void eventCallbacks(const libvlc_event_t* event, void* ptr);
 
@@ -93,8 +94,8 @@ class MediaPluginLibVLC :
 
 	bool mIsLooping;
 
-	float mCurTime;
-	float mDuration;
+	F64 mCurTime;
+	F64 mDuration;
 	EStatus mVlcStatus;
 };
 
@@ -213,6 +214,19 @@ void MediaPluginLibVLC::setDirty(int left, int top, int right, int bottom)
 	sendMessage(message);
 }
 
+////////////////////////////////////////////////////////////////////////////////
+// *virtual*
+void MediaPluginLibVLC::setDurationDirty()
+{
+    LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "updated");
+
+    message.setValueReal("current_time", mCurTime);
+    message.setValueReal("duration", mDuration);
+    message.setValueReal("current_rate", 1.0f);
+
+    sendMessage(message);
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 //
 void MediaPluginLibVLC::eventCallbacks(const libvlc_event_t* event, void* ptr)
@@ -233,6 +247,7 @@ void MediaPluginLibVLC::eventCallbacks(const libvlc_event_t* event, void* ptr)
 		parent->mDuration = (float)(libvlc_media_get_duration(parent->mLibVLCMedia)) / 1000.0f;
 		parent->mVlcStatus = STATUS_PLAYING;
 		parent->setVolumeVLC();
+        parent->setDurationDirty();
 		break;
 
 	case libvlc_MediaPlayerPaused:
@@ -245,6 +260,8 @@ void MediaPluginLibVLC::eventCallbacks(const libvlc_event_t* event, void* ptr)
 
 	case libvlc_MediaPlayerEndReached:
 		parent->mVlcStatus = STATUS_DONE;
+        parent->mCurTime = parent->mDuration;
+        parent->setDurationDirty();
 		break;
 
 	case libvlc_MediaPlayerEncounteredError:
@@ -253,6 +270,11 @@ void MediaPluginLibVLC::eventCallbacks(const libvlc_event_t* event, void* ptr)
 
 	case libvlc_MediaPlayerTimeChanged:
 		parent->mCurTime = (float)libvlc_media_player_get_time(parent->mLibVLCMediaPlayer) / 1000.0f;
+        if (parent->mVlcStatus == STATUS_DONE && libvlc_media_player_is_playing(parent->mLibVLCMediaPlayer))
+        {
+            parent->mVlcStatus = STATUS_PLAYING;
+        }
+        parent->setDurationDirty();
 		break;
 
 	case libvlc_MediaPlayerPositionChanged:
@@ -260,6 +282,7 @@ void MediaPluginLibVLC::eventCallbacks(const libvlc_event_t* event, void* ptr)
 
 	case libvlc_MediaPlayerLengthChanged:
 		parent->mDuration = (float)libvlc_media_get_duration(parent->mLibVLCMedia) / 1000.0f;
+        parent->setDurationDirty();
 		break;
 
 	case libvlc_MediaPlayerTitleChanged:
@@ -562,7 +585,24 @@ void MediaPluginLibVLC::receiveMessage(const char* message_string)
 						mTextureWidth = texture_width;
 						mTextureHeight = texture_height;
 
+                        libvlc_time_t time = 1000.0 * mCurTime;
+
 						playMedia();
+
+                        if (mLibVLCMediaPlayer)
+                        {
+                            libvlc_media_player_set_time(mLibVLCMediaPlayer, time);
+                            time = libvlc_media_player_get_time(mLibVLCMediaPlayer);
+                            if (time < 0)
+                            {
+                                // -1 if there is no media
+                                mCurTime = 0;
+                            }
+                            else
+                            {
+                                mCurTime = (F64)time / 1000.0;
+                            }
+                        }
 					};
 				};
 
@@ -594,6 +634,13 @@ void MediaPluginLibVLC::receiveMessage(const char* message_string)
 				{
 					if (mLibVLCMediaPlayer)
 					{
+                        if (mVlcStatus == STATUS_DONE && !libvlc_media_player_is_playing(mLibVLCMediaPlayer))
+                        {
+                            // stop or vlc will ignore 'play', it will just
+                            // make an MediaPlayerEndReached event even if
+                            // seek was used
+                            libvlc_media_player_stop(mLibVLCMediaPlayer);
+                        }
 						libvlc_media_player_play(mLibVLCMediaPlayer);
 					}
 				}
@@ -606,15 +653,32 @@ void MediaPluginLibVLC::receiveMessage(const char* message_string)
 				}
 				else if (message_name == "seek")
 				{
-					if (mDuration > 0)
-					{
-						F64 normalized_offset = message_in.getValueReal("time") / mDuration;
-						libvlc_media_player_set_position(mLibVLCMediaPlayer, normalized_offset);
-					}
+                    if (mLibVLCMediaPlayer)
+                    {
+                        libvlc_time_t time = 1000.0 * message_in.getValueReal("time");
+                        libvlc_media_player_set_time(mLibVLCMediaPlayer, time);
+                        time = libvlc_media_player_get_time(mLibVLCMediaPlayer);
+                        if (time < 0)
+                        {
+                            // -1 if there is no media
+                            mCurTime = 0;
+                        }
+                        else
+                        {
+                            mCurTime = (F64)time / 1000.0;
+                        }
+
+                        if (!libvlc_media_player_is_playing(mLibVLCMediaPlayer))
+                        {
+                            // if paused, won't trigger update, update now
+                            setDurationDirty();
+                        }
+                    }
 				}
 				else if (message_name == "set_loop")
 				{
-					mIsLooping = true;
+					bool loop = message_in.getValueBoolean("loop");
+					mIsLooping = loop;
 				}
 				else if (message_name == "set_volume")
 				{
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 83e80aa105bc4443c963aa81d384f1aa03ebf1a5..d42216a8c7876f1be286d19b38f897c49f766d6c 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -17,7 +17,6 @@ include(DBusGlib)
 include(DragDrop)
 include(EXPAT)
 include(FMODSTUDIO)
-include(GLOD)
 include(Hunspell)
 include(JPEGEncoderBasic)
 include(JsonCpp)
@@ -33,6 +32,7 @@ include(LLInventory)
 include(LLKDU)
 include(LLLogin)
 include(LLMath)
+include(LLMeshOptimizer)
 include(LLMessage)
 include(LLPhysicsExtensions)
 include(LLPlugin)
@@ -50,12 +50,13 @@ include(OpenSSL)
 include(PNG)
 include(TemplateCheck)
 include(ThreeJS)
+include(Tracy)
 include(UI)
 include(UnixInstall)
 include(ViewerMiscLibs)
 include(ViewerManager)
 include(VisualLeakDetector)
-include(ZLIB)
+include(ZLIBNG)
 include(URIPARSER)
 
 if (NOT HAVOK_TPV)
@@ -70,7 +71,6 @@ endif(FMODSTUDIO)
 include_directories(
     ${DBUSGLIB_INCLUDE_DIRS}
     ${JSONCPP_INCLUDE_DIR}
-    ${GLOD_INCLUDE_DIR}
     ${LLAUDIO_INCLUDE_DIRS}
     ${LLCHARACTER_INCLUDE_DIRS}
     ${LLCOMMON_INCLUDE_DIRS}
@@ -80,6 +80,7 @@ include_directories(
     ${LLKDU_INCLUDE_DIRS}
     ${LLINVENTORY_INCLUDE_DIRS}
     ${LLMATH_INCLUDE_DIRS}
+    ${LLMESHOPTIMIZER_INCLUDE_DIRS}
     ${LLMESSAGE_INCLUDE_DIRS}
     ${LLPLUGIN_INCLUDE_DIRS}
     ${LLPRIMITIVE_INCLUDE_DIRS}
@@ -95,6 +96,7 @@ include_directories(
     ${LIBS_PREBUILT_DIR}/include/collada/1.4
     ${LLAPPEARANCE_INCLUDE_DIRS}
     ${CMAKE_CURRENT_SOURCE_DIR}
+    ${TRACY_INCLUDE_DIR}
     )
 
 include_directories(SYSTEM
@@ -232,12 +234,14 @@ set(viewer_SOURCE_FILES
     llfloatercamera.cpp
     llfloatercamerapresets.cpp
     llfloaterchatvoicevolume.cpp
+    llfloaterclassified.cpp
     llfloatercolorpicker.cpp
     llfloaterconversationlog.cpp
     llfloaterconversationpreview.cpp
     llfloatercreatelandmark.cpp
     llfloaterdeleteprefpreset.cpp
     llfloaterdestinations.cpp
+    llfloaterdisplayname.cpp
     llfloatereditenvironmentbase.cpp
     llfloatereditextdaycycle.cpp
     llfloaterenvironmentadjust.cpp
@@ -282,7 +286,7 @@ set(viewer_SOURCE_FILES
     llfloaternamedesc.cpp
     llfloaternotificationsconsole.cpp
     llfloaternotificationstabbed.cpp
-    llfloateroutfitphotopreview.cpp
+    llfloateroutfitphotopreview.cpp 
     llfloateroutfitsnapshot.cpp
     llfloaterobjectweights.cpp
     llfloateropenobject.cpp
@@ -293,9 +297,11 @@ set(viewer_SOURCE_FILES
     llfloaterpay.cpp
     llfloaterperms.cpp
     llfloaterpostprocess.cpp
+    llfloaterprofile.cpp
     llfloaterpreference.cpp
     llfloaterpreferenceviewadvanced.cpp
     llfloaterpreviewtrash.cpp
+    llfloaterprofiletexture.cpp
     llfloaterproperties.cpp
     llfloaterregiondebugconsole.cpp
     llfloaterregioninfo.cpp
@@ -328,7 +334,6 @@ set(viewer_SOURCE_FILES
     llfloatervoiceeffect.cpp
     llfloatervoicevolume.cpp
     llfloaterwebcontent.cpp
-    llfloaterwebprofile.cpp
     llfloaterwhitelistentry.cpp
     llfloaterwindowsize.cpp
     llfloaterworldmap.cpp
@@ -396,7 +401,6 @@ set(viewer_SOURCE_FILES
     llloginhandler.cpp
     lllogininstance.cpp
     llmachineid.cpp
-    llmainlooprepeater.cpp
     llmanip.cpp
     llmaniprotate.cpp
     llmanipscale.cpp
@@ -476,7 +480,6 @@ set(viewer_SOURCE_FILES
     llpanelmediasettingsgeneral.cpp
     llpanelmediasettingspermissions.cpp
     llpanelmediasettingssecurity.cpp
-    llpanelme.cpp
     llpanelnearbymedia.cpp
     llpanelobject.cpp
     llpanelobjectinventory.cpp
@@ -486,8 +489,6 @@ set(viewer_SOURCE_FILES
     llpanelpeople.cpp
     llpanelpeoplemenus.cpp
     llpanelpermissions.cpp
-    llpanelpick.cpp
-    llpanelpicks.cpp
     llpanelplaceinfo.cpp
     llpanelplaceprofile.cpp
     llpanelplaces.cpp
@@ -496,6 +497,8 @@ set(viewer_SOURCE_FILES
     llpanelpresetspulldown.cpp
     llpanelprimmediacontrols.cpp
     llpanelprofile.cpp
+    llpanelprofileclassifieds.cpp
+    llpanelprofilepicks.cpp
     llpanelsnapshot.cpp
     llpanelsnapshotinventory.cpp
     llpanelsnapshotlocal.cpp
@@ -592,11 +595,8 @@ set(viewer_SOURCE_FILES
     llsyntaxid.cpp
     llsyswellitem.cpp
     llsyswellwindow.cpp
-    lltelemetry.cpp
     llteleporthistory.cpp
     llteleporthistorystorage.cpp
-    lltextureatlas.cpp
-    lltextureatlasmanager.cpp
     lltexturecache.cpp
     lltexturectrl.cpp
     lltexturefetch.cpp
@@ -660,6 +660,7 @@ set(viewer_SOURCE_FILES
     llviewercontrol.cpp
     llviewercontrollistener.cpp
     llviewerdisplay.cpp
+    llviewerdisplayname.cpp
     llviewerfloaterreg.cpp
     llviewerfoldertype.cpp
     llviewergenericmessage.cpp
@@ -873,12 +874,14 @@ set(viewer_HEADER_FILES
     llfloatercamerapresets.h
     llfloatercamera.h
     llfloaterchatvoicevolume.h
+    llfloaterclassified.h
     llfloatercolorpicker.h
     llfloaterconversationlog.h
     llfloaterconversationpreview.h
     llfloatercreatelandmark.h
     llfloaterdeleteprefpreset.h
     llfloaterdestinations.h
+    llfloaterdisplayname.h
     llfloatereditenvironmentbase.h
     llfloatereditextdaycycle.h
     llfloaterenvironmentadjust.h
@@ -937,9 +940,11 @@ set(viewer_HEADER_FILES
     llfloaterpay.h
     llfloaterperms.h
     llfloaterpostprocess.h
+    llfloaterprofile.h
     llfloaterpreference.h
     llfloaterpreferenceviewadvanced.h
     llfloaterpreviewtrash.h
+    llfloaterprofiletexture.h
     llfloaterproperties.h
     llfloaterregiondebugconsole.h
     llfloaterregioninfo.h
@@ -972,7 +977,6 @@ set(viewer_HEADER_FILES
     llfloatervoiceeffect.h
     llfloatervoicevolume.h
     llfloaterwebcontent.h
-    llfloaterwebprofile.h
     llfloaterwhitelistentry.h
     llfloaterwindowsize.h
     llfloaterworldmap.h
@@ -1038,7 +1042,6 @@ set(viewer_HEADER_FILES
     llloginhandler.h
     lllogininstance.h
     llmachineid.h
-    llmainlooprepeater.h
     llmanip.h
     llmaniprotate.h
     llmanipscale.h
@@ -1110,7 +1113,6 @@ set(viewer_HEADER_FILES
     llpanelmediasettingsgeneral.h
     llpanelmediasettingspermissions.h
     llpanelmediasettingssecurity.h
-    llpanelme.h
     llpanelnearbymedia.h
     llpanelobject.h
     llpanelobjectinventory.h
@@ -1120,8 +1122,6 @@ set(viewer_HEADER_FILES
     llpanelpeople.h
     llpanelpeoplemenus.h
     llpanelpermissions.h
-    llpanelpick.h
-    llpanelpicks.h
     llpanelplaceinfo.h
     llpanelplaceprofile.h
     llpanelplaces.h
@@ -1130,6 +1130,8 @@ set(viewer_HEADER_FILES
     llpanelpresetspulldown.h
     llpanelprimmediacontrols.h
     llpanelprofile.h
+    llpanelprofileclassifieds.h
+    llpanelprofilepicks.h
     llpanelsnapshot.h
     llpanelteleporthistory.h
     llpaneltiptoast.h
@@ -1227,8 +1229,6 @@ set(viewer_HEADER_FILES
     lltable.h
     llteleporthistory.h
     llteleporthistorystorage.h
-    lltextureatlas.h
-    lltextureatlasmanager.h
     lltexturecache.h
     lltexturectrl.h
     lltexturefetch.h
@@ -1294,6 +1294,7 @@ set(viewer_HEADER_FILES
     llviewercontrol.h
     llviewercontrollistener.h
     llviewerdisplay.h
+    llviewerdisplayname.h
     llviewerfloaterreg.h
     llviewerfoldertype.h
     llviewergenericmessage.h
@@ -1388,7 +1389,7 @@ file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/viewer_version.txt"
            "${VIEWER_SHORT_VERSION}.${VIEWER_VERSION_REVISION}\n")
 
 set_source_files_properties(
-   llversioninfo.cpp tests/llversioninfo_test.cpp
+   llversioninfo.cpp tests/llversioninfo_test.cpp 
    PROPERTIES
    COMPILE_DEFINITIONS "${VIEWER_CHANNEL_VERSION_DEFINES}" # see BuildVersion.cmake
    )
@@ -1610,6 +1611,7 @@ if (WINDOWS)
         ${WINDOWS_LIBRARIES}
         comdlg32
         dxguid
+        imm32
         kernel32
         odbc32
         odbccp32
@@ -1699,6 +1701,8 @@ set(viewer_APPSETTINGS_FILES
     ${CMAKE_SOURCE_DIR}/../etc/message.xml
     ${CMAKE_SOURCE_DIR}/../scripts/messages/message_template.msg
     packages-info.txt
+    featuretable.txt
+    featuretable_mac.txt
     )
 
 source_group("App Settings" FILES ${viewer_APPSETTINGS_FILES})
@@ -1753,10 +1757,6 @@ endif (HAVOK OR HAVOK_TPV)
 # progress view disables/enables icons based on available packages
 set_source_files_properties(llprogressview.cpp PROPERTIES COMPILE_FLAGS "${LLSTARTUP_COMPILE_FLAGS}")
 
-if (GLODLIB)
-  set_source_files_properties(llfloatermodelpreview.cpp PROPERTIES COMPILE_FLAGS "-DLL_GLOD")
-endif (GLODLIB)
-
 list(APPEND viewer_SOURCE_FILES ${viewer_HEADER_FILES})
 
 set_source_files_properties(${viewer_HEADER_FILES}
@@ -1824,9 +1824,6 @@ if (WINDOWS)
       ${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/libapr-1.dll
       ${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/libaprutil-1.dll
       ${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/libapriconv-1.dll
-      ${SHARED_LIB_STAGING_DIR}/Release/glod.dll
-      ${SHARED_LIB_STAGING_DIR}/RelWithDebInfo/glod.dll
-      ${SHARED_LIB_STAGING_DIR}/Debug/glod.dll
       ${SHARED_LIB_STAGING_DIR}/Release/libcollada14dom22.dll
       ${SHARED_LIB_STAGING_DIR}/RelWithDebInfo/libcollada14dom22.dll
       ${SHARED_LIB_STAGING_DIR}/Debug/libcollada14dom22-d.dll
@@ -1854,10 +1851,6 @@ if (WINDOWS)
       winmm_shim
       )
 
-    if (NOT USE_BUGSPLAT)
-        LIST(APPEND COPY_INPUT_DEPENDENCIES windows-crash-logger)
-    endif (NOT USE_BUGSPLAT)
-
     if (ADDRESS_SIZE EQUAL 64)
         list(APPEND COPY_INPUT_DEPENDENCIES
             ${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/vivoxsdk_x64.dll
@@ -1924,9 +1917,7 @@ if (WINDOWS)
       add_dependencies(${VIEWER_BINARY_NAME} copy_win_scripts)
     endif (EXISTS ${CMAKE_SOURCE_DIR}/copy_win_scripts)
 
-    add_dependencies(${VIEWER_BINARY_NAME}
-      SLPlugin
-    )
+    add_dependencies(${VIEWER_BINARY_NAME} SLPlugin)
 
     # sets the 'working directory' for debugging from visual studio.
     # Condition for version can be moved to requirements once build agents will be updated (see TOOL-3865)
@@ -2013,7 +2004,7 @@ endif (WINDOWS)
 # one of these being libz where you can find four or more versions in play
 # at once.  On Linux, libz can be found at link and run time via a number
 # of paths:
-#
+#     
 #      => -lfreetype
 #        => libz.so.1 (on install machine, not build)
 #      => -lSDL
@@ -2024,20 +2015,21 @@ endif (WINDOWS)
 #
 # We generally want the newest version of the library to provide all symbol
 # resolution.  To that end, when using static archives, the *_PRELOAD_ARCHIVES
-# variables, PNG_PRELOAD_ARCHIVES and ZLIB_PRELOAD_ARCHIVES, get the archives
+# variables, PNG_PRELOAD_ARCHIVES and ZLIBNG_PRELOAD_ARCHIVES, get the archives
 # dumped into the target binary and runtime lookup will find the most
 # modern version.
 
 target_link_libraries(${VIEWER_BINARY_NAME}
     ${LEGACY_STDIO_LIBS}
     ${PNG_PRELOAD_ARCHIVES}
-    ${ZLIB_PRELOAD_ARCHIVES}
+    ${ZLIBNG_PRELOAD_ARCHIVES}
     ${URIPARSER_PRELOAD_ARCHIVES}
     ${GOOGLE_PERFTOOLS_LIBRARIES}
     ${LLAUDIO_LIBRARIES}
     ${LLCHARACTER_LIBRARIES}
     ${LLIMAGE_LIBRARIES}
     ${LLINVENTORY_LIBRARIES}
+    ${LLMESHOPTIMIZER_LIBRARIES}
     ${LLMESSAGE_LIBRARIES}
     ${LLPLUGIN_LIBRARIES}
     ${LLPRIMITIVE_LIBRARIES}
@@ -2061,7 +2053,6 @@ target_link_libraries(${VIEWER_BINARY_NAME}
     ${DBUSGLIB_LIBRARIES}
     ${OPENGL_LIBRARIES}
     ${FMODWRAPPER_LIBRARY} # must come after LLAudio
-    ${GLOD_LIBRARIES}
     ${OPENGL_LIBRARIES}
     ${JSONCPP_LIBRARIES}
     ${SDL_LIBRARY}
@@ -2076,6 +2067,7 @@ target_link_libraries(${VIEWER_BINARY_NAME}
     ${LLPHYSICS_LIBRARIES}
     ${LLPHYSICSEXTENSIONS_LIBRARIES}
     ${LLAPPEARANCE_LIBRARIES}
+    ${TRACY_LIBRARY}
     )
 
 if (USE_BUGSPLAT)
@@ -2184,7 +2176,7 @@ if (DARWIN)
 
   # https://blog.kitware.com/upcoming-in-cmake-2-8-12-osx-rpath-support/
   set(CMAKE_MACOSX_RPATH 1)
-
+  
   set_target_properties(
     ${VIEWER_BINARY_NAME}
     PROPERTIES
@@ -2276,7 +2268,7 @@ endif (INSTALL)
 
 # Note that the conventional VIEWER_SYMBOL_FILE is set by ../../build.sh
 if (PACKAGE AND (RELEASE_CRASH_REPORTING OR NON_RELEASE_CRASH_REPORTING) AND VIEWER_SYMBOL_FILE)
-  if (BUGSPLAT_DB)
+  if (USE_BUGSPLAT)
     # BugSplat symbol-file generation
     if (WINDOWS)
       # Just pack up a tarball containing only the .pdb file for the
@@ -2360,7 +2352,7 @@ if (PACKAGE AND (RELEASE_CRASH_REPORTING OR NON_RELEASE_CRASH_REPORTING) AND VIE
     if (LINUX)
       # TBD
     endif (LINUX)
-  endif (BUGSPLAT_DB)
+  endif (USE_BUGSPLAT)
 
   # for both Bugsplat and Breakpad
   add_dependencies(llpackage generate_symbols)
@@ -2386,7 +2378,7 @@ if (LL_TESTS)
     llworldmap.cpp
     llworldmipmap.cpp
     PROPERTIES
-    LL_TEST_ADDITIONAL_SOURCE_FILES
+    LL_TEST_ADDITIONAL_SOURCE_FILES 
     tests/llviewertexture_stub.cpp
     #llviewertexturelist.cpp
   )
@@ -2420,7 +2412,7 @@ if (LL_TESTS)
     llworldmap.cpp
     llworldmipmap.cpp
     PROPERTIES
-    LL_TEST_ADDITIONAL_SOURCE_FILES
+    LL_TEST_ADDITIONAL_SOURCE_FILES 
     tests/llviewertexture_stub.cpp
     #llviewertexturelist.cpp
     LL_TEST_ADDITIONAL_LIBRARIES "${BOOST_SYSTEM_LIBRARY}"
diff --git a/indra/newview/VIEWER_VERSION.txt b/indra/newview/VIEWER_VERSION.txt
index db0785f27378c9cecd2e9f5a6f78fa49a198a660..4aa5a3a58e8c27e16189402e6ab0e13712de35f8 100644
--- a/indra/newview/VIEWER_VERSION.txt
+++ b/indra/newview/VIEWER_VERSION.txt
@@ -1 +1 @@
-6.5.3
+6.6.8
diff --git a/indra/newview/app_settings/cmd_line.xml b/indra/newview/app_settings/cmd_line.xml
index 4e186292f77d6e4c3f99f035e75f3b80141c2179..e16a5c7e76014ece4bdc11a137a51c10aa9803e8 100644
--- a/indra/newview/app_settings/cmd_line.xml
+++ b/indra/newview/app_settings/cmd_line.xml
@@ -55,7 +55,7 @@
     <key>debugsession</key>
     <map>
       <key>desc</key>
-      <string>Run as if RenderDebugGL is TRUE, but log errors until end of session.</string>
+      <string>Run as if RenderDebugGLSession is TRUE, but log errors until end of session.</string>
       <key>map-to</key>
       <string>DebugSession</string>
     </map>
@@ -207,14 +207,14 @@
     <map>
       <key>map-to</key>
       <string>NoAudio</string>
-    </map>    
+    </map>
 
-    <key>noinvlib</key>
+    <key>noninteractive</key>
     <map>
       <key>desc</key>
-      <string>Do not request the inventory library.</string>
+      <string>Run in semi-headless mode where only login and logout need to work.</string>
       <key>map-to</key>
-      <string>NoInventoryLibrary</string>
+      <string>NonInteractive</string>
     </map>
 
     <key>nonotifications</key>
diff --git a/indra/newview/app_settings/commands.xml b/indra/newview/app_settings/commands.xml
index 3dfe3f6634a9ca5043d3f1eeaa4bcaad4ccd015b..2644f5f449c74813797aa06d771ae67254aeeb12 100644
--- a/indra/newview/app_settings/commands.xml
+++ b/indra/newview/app_settings/commands.xml
@@ -167,10 +167,8 @@
            icon="Command_Picks_Icon"
            label_ref="Command_Picks_Label"
            tooltip_ref="Command_Picks_Tooltip"
-           execute_function="Floater.ToggleOrBringToFront"
-           execute_parameters="picks"
-           is_running_function="Floater.IsOpen"
-           is_running_parameters="picks"
+           execute_function="Avatar.TogglePicks"
+           is_running_function="Avatar.IsPicksTabOpen"
            />
   <command name="places"
            available_in_toybox="true"
diff --git a/indra/newview/app_settings/high_graphics.xml b/indra/newview/app_settings/high_graphics.xml
index 662f7e39dd1739742cb25140eee1f3e5fac53210..f64937f4437388bd470e1431aa7f079d7b0af4a6 100644
--- a/indra/newview/app_settings/high_graphics.xml
+++ b/indra/newview/app_settings/high_graphics.xml
@@ -6,8 +6,6 @@
 	<RenderAvatarLODFactor value="1.0"/>
 	<!--Default for now-->
 	<RenderAvatarPhysicsLODFactor value="0.9"/>
-	<!--NO SHADERS-->
-	<RenderAvatarVP value="TRUE"/>
 	<!--Short Range-->
 	<RenderFarClip value="128"/>
 	<!--Default for now-->
diff --git a/indra/newview/app_settings/key_bindings.xml b/indra/newview/app_settings/key_bindings.xml
index 1a5157838cd7a2f0d5858e5b6ce59af32853091b..8d5349550f976f9339e477fcbcee462cbbf0bd22 100644
--- a/indra/newview/app_settings/key_bindings.xml
+++ b/indra/newview/app_settings/key_bindings.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8" standalone="yes" ?>
-<keys>
+<keys xml_version="1">
   <first_person>
     <binding key="A" mask="NONE" command="slide_left"/>
     <binding key="D" mask="NONE" command="slide_right"/>
@@ -17,22 +17,13 @@
     <binding key="PGDN" mask="NONE" command="push_down"/>
     <binding key="HOME" mask="NONE" command="toggle_fly"/>
 
-    <binding key="PAD_LEFT" mask="NONE" command="slide_left"/>
-    <binding key="PAD_RIGHT" mask="NONE" command="slide_right"/>
-    <binding key="PAD_UP" mask="NONE" command="push_forward"/>
-    <binding key="PAD_DOWN" mask="NONE" command="push_backward"/>
-    <binding key="PAD_PGUP" mask="NONE" command="jump"/>
-    <binding key="PAD_PGDN" mask="NONE" command="push_down"/>
-    <binding key="PAD_HOME" mask="NONE" command="toggle_fly"/>
-    <binding key="PAD_CENTER" mask="NONE" command="stop_moving"/>
-    <binding key="PAD_ENTER" mask="NONE" command="start_chat"/>
-    <binding key="PAD_DIVIDE" mask="NONE" command="start_gesture"/>
-
     <binding key="SPACE" mask="NONE" command="stop_moving"/>
     <binding key="ENTER" mask="NONE" command="start_chat"/>
     <binding key="DIVIDE" mask="NONE" command="start_gesture"/>
 
     <binding key="" mask="NONE" mouse="MMB" command="toggle_voice"/>
+
+    <binding key="" mask="NONE" mouse="LMB" command="script_trigger_lbutton"/>
   </first_person>
   <third_person>
     <binding key="A" mask="NONE" command="turn_left"/>
@@ -60,19 +51,6 @@
     <binding key="PGDN" mask="NONE" command="push_down"/>
     <binding key="HOME" mask="NONE" command="toggle_fly"/>
 
-    <binding key="PAD_LEFT" mask="NONE" command="turn_left"/>
-    <binding key="PAD_LEFT" mask="SHIFT" command="slide_left"/>
-    <binding key="PAD_RIGHT" mask="NONE" command="turn_right"/>
-    <binding key="PAD_RIGHT" mask="SHIFT" command="slide_right"/>
-    <binding key="PAD_UP" mask="NONE" command="push_forward"/>
-    <binding key="PAD_DOWN" mask="NONE" command="push_backward"/>
-    <binding key="PAD_PGUP" mask="NONE" command="jump"/>
-    <binding key="PAD_PGDN" mask="NONE" command="push_down"/>
-    <binding key="PAD_HOME" mask="NONE" command="toggle_fly"/>
-    <binding key="PAD_CENTER" mask="NONE" command="stop_moving"/>
-    <binding key="PAD_ENTER" mask="NONE" command="start_chat"/>
-    <binding key="PAD_DIVIDE" mask="NONE" command="start_gesture"/>
-
     <!--Camera controls in third person on Alt-->
     <binding key="LEFT" mask="ALT" command="spin_around_cw"/>
     <binding key="RIGHT" mask="ALT" command="spin_around_ccw"/>
@@ -88,15 +66,6 @@
     <binding key="E" mask="ALT" command="spin_over"/>
     <binding key="C" mask="ALT" command="spin_under"/>
 
-    <binding key="PAD_LEFT" mask="ALT" command="spin_around_cw"/>
-    <binding key="PAD_RIGHT" mask="ALT" command="spin_around_ccw"/>
-    <binding key="PAD_UP" mask="ALT" command="move_forward"/>
-    <binding key="PAD_DOWN" mask="ALT" command="move_backward"/>
-    <binding key="PAD_PGUP" mask="ALT" command="spin_over"/>
-    <binding key="PAD_PGDN" mask="ALT" command="spin_under"/>
-    <binding key="PAD_ENTER" mask="ALT" command="start_chat"/>
-    <binding key="PAD_DIVIDE" mask="ALT" command="start_gesture"/>
-
     <!--mimic alt zoom behavior with keyboard only-->
     <binding key="W" mask="CTL_ALT" command="spin_over"/>
     <binding key="S" mask="CTL_ALT" command="spin_under"/>
@@ -104,9 +73,6 @@
     <binding key="UP" mask="CTL_ALT" command="spin_over"/>
     <binding key="DOWN" mask="CTL_ALT" command="spin_under"/>
 
-    <binding key="PAD_UP" mask="CTL_ALT" command="spin_over"/>
-    <binding key="PAD_DOWN" mask="CTL_ALT" command="spin_under"/>
-
     <!--Therefore pan on Alt-Shift-->
     <binding key="A" mask="CTL_ALT_SHIFT" command="pan_left"/>
     <binding key="D" mask="CTL_ALT_SHIFT" command="pan_right"/>
@@ -118,14 +84,9 @@
     <binding key="UP" mask="CTL_ALT_SHIFT" command="pan_up"/>
     <binding key="DOWN" mask="CTL_ALT_SHIFT" command="pan_down"/>
 
-    <binding key="PAD_LEFT" mask="CTL_ALT_SHIFT" command="pan_left"/>
-    <binding key="PAD_RIGHT" mask="CTL_ALT_SHIFT" command="pan_right"/>
-    <binding key="PAD_UP" mask="CTL_ALT_SHIFT" command="pan_up"/>
-    <binding key="PAD_DOWN" mask="CTL_ALT_SHIFT" command="pan_down"/>
-    <binding key="PAD_ENTER" mask="CTL_ALT_SHIFT" command="start_chat"/>
-    <binding key="PAD_DIVIDE" mask="CTL_ALT_SHIFT" command="start_gesture"/>
-
     <binding key="" mask="NONE" mouse="MMB" command="toggle_voice"/>
+
+    <binding key="" mask="NONE" mouse="LMB" command="script_trigger_lbutton"/>
   </third_person>
   <sitting>
     <binding key="A" mask="ALT" command="spin_around_cw"/>
@@ -167,16 +128,6 @@
     <binding key="PGUP" mask="NONE" command="spin_over_sitting"/>
     <binding key="PGDN" mask="NONE" command="spin_under_sitting"/>
 
-    <binding key="PAD_LEFT" mask="NONE" command="spin_around_cw_sitting"/>
-    <binding key="PAD_RIGHT" mask="NONE" command="spin_around_ccw_sitting"/>
-    <binding key="PAD_UP" mask="NONE" command="move_forward_sitting"/>
-    <binding key="PAD_DOWN" mask="NONE" command="move_backward_sitting"/>
-    <binding key="PAD_PGUP" mask="NONE" command="spin_over_sitting"/>
-    <binding key="PAD_PGDN" mask="NONE" command="spin_under_sitting"/>
-    <binding key="PAD_CENTER" mask="NONE" command="stop_moving"/>
-    <binding key="PAD_ENTER" mask="NONE" command="start_chat"/>
-    <binding key="PAD_DIVIDE" mask="NONE" command="start_gesture"/>
-
     <!--these are for passing controls when sitting on vehicles-->
     <binding key="A" mask="SHIFT" command="slide_left"/>
     <binding key="D" mask="SHIFT" command="slide_right"/>
@@ -192,15 +143,6 @@
     <binding key="PGUP" mask="SHIFT" command="spin_over_sitting"/>
     <binding key="PGDN" mask="SHIFT" command="spin_under_sitting"/>
 
-    <binding key="PAD_LEFT" mask="SHIFT" command="slide_left"/>
-    <binding key="PAD_RIGHT" mask="SHIFT" command="slide_right"/>
-    <binding key="PAD_UP" mask="SHIFT" command="move_forward_sitting"/>
-    <binding key="PAD_DOWN" mask="SHIFT" command="move_backward_sitting"/>
-    <binding key="PAD_PGUP" mask="SHIFT" command="spin_over_sitting"/>
-    <binding key="PAD_PGDN" mask="SHIFT" command="spin_under_sitting"/> 
-    <binding key="PAD_ENTER" mask="SHIFT" command="start_chat"/>
-    <binding key="PAD_DIVIDE" mask="SHIFT" command="start_gesture"/>
-
     <!--pan on Alt-Shift-->
     <binding key="A" mask="CTL_ALT_SHIFT" command="pan_left"/>
     <binding key="D" mask="CTL_ALT_SHIFT" command="pan_right"/>
@@ -212,17 +154,12 @@
     <binding key="UP" mask="CTL_ALT_SHIFT" command="pan_up"/>
     <binding key="DOWN" mask="CTL_ALT_SHIFT" command="pan_down"/>
 
-    <binding key="PAD_LEFT" mask="CTL_ALT_SHIFT" command="pan_left"/>
-    <binding key="PAD_RIGHT" mask="CTL_ALT_SHIFT" command="pan_right"/>
-    <binding key="PAD_UP" mask="CTL_ALT_SHIFT" command="pan_up"/>
-    <binding key="PAD_DOWN" mask="CTL_ALT_SHIFT" command="pan_down"/>
-    <binding key="PAD_ENTER" mask="CTL_ALT_SHIFT" command="start_chat"/>
-    <binding key="PAD_DIVIDE" mask="CTL_ALT_SHIFT" command="start_gesture"/>
-
     <binding key="ENTER" mask="NONE" command="start_chat"/>
     <binding key="DIVIDE" mask="NONE" command="start_gesture"/>
 
     <binding key="" mask="NONE" mouse="MMB" command="toggle_voice"/>
+
+    <binding key="" mask="NONE" mouse="LMB" command="script_trigger_lbutton"/>
   </sitting>
   <edit_avatar>
     <!--Avatar editing camera controls-->
@@ -240,15 +177,9 @@
     <binding key="PGDN" mask="NONE" command="edit_avatar_spin_under"/>
     <binding key="ENTER" mask="NONE" command="start_chat"/>
     <binding key="DIVIDE" mask="NONE" command="start_gesture"/>
-    <binding key="PAD_LEFT" mask="NONE" command="edit_avatar_spin_cw"/>
-    <binding key="PAD_RIGHT" mask="NONE" command="edit_avatar_spin_ccw"/>
-    <binding key="PAD_UP" mask="NONE" command="edit_avatar_move_forward"/>
-    <binding key="PAD_DOWN" mask="NONE" command="edit_avatar_move_backward"/>
-    <binding key="PAD_PGUP" mask="NONE" command="edit_avatar_spin_over"/>
-    <binding key="PAD_PGDN" mask="NONE" command="edit_avatar_spin_under"/>
-    <binding key="PAD_ENTER" mask="NONE" command="start_chat"/>
-    <binding key="PAD_DIVIDE" mask="NONE" command="start_gesture"/>
 
     <binding key="" mask="NONE" mouse="MMB" command="toggle_voice"/>
+
+    <binding key="" mask="NONE" mouse="LMB" command="script_trigger_lbutton"/>
   </edit_avatar>
 </keys>
diff --git a/indra/newview/app_settings/low_graphics.xml b/indra/newview/app_settings/low_graphics.xml
index 0ee8e7a05988a3ed78101e7f064c27b1253c1a53..b31a040d67e9e0b6be2a12d78955600451d03ffb 100644
--- a/indra/newview/app_settings/low_graphics.xml
+++ b/indra/newview/app_settings/low_graphics.xml
@@ -6,8 +6,6 @@
 	<RenderAvatarLODFactor value="0.5"/>
 	<!--Default for now-->
 	<RenderAvatarPhysicsLODFactor value="0.0"/>
-	<!--NO SHADERS-->
-	<RenderAvatarVP value="FALSE"/>
 	<!--Short Range-->
 	<RenderFarClip value="64"/>
 	<!--Default for now-->
diff --git a/indra/newview/app_settings/mid_graphics.xml b/indra/newview/app_settings/mid_graphics.xml
index c89e060307a72a0777b8a863fd5f3ac1570d374f..9c2c17fc6081ddf36a0cc9c4c9e3e17ebececf05 100644
--- a/indra/newview/app_settings/mid_graphics.xml
+++ b/indra/newview/app_settings/mid_graphics.xml
@@ -6,8 +6,6 @@
 	<RenderAvatarLODFactor value="0.5"/>
 	<!--Default for now-->
 	<RenderAvatarPhysicsLODFactor value="0.75"/>
-	<!--NO SHADERS-->
-	<RenderAvatarVP value="TRUE"/>
 	<!--Short Range-->
 	<RenderFarClip value="96"/>
 	<!--Default for now-->
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 6c36fa6f090f3c7abd9f14f054454f76ff6f2938..6861153d43798aca1899f5fa697942ce0be5e031 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -544,17 +544,6 @@
       <key>Value</key>
       <integer>1</integer>
     </map>
-    <key>AvalinePhoneSeparator</key>
-    <map>
-      <key>Comment</key>
-      <string>Separator of phone parts to have Avaline numbers human readable in Voice Control Panel</string>
-      <key>Persist</key>
-      <integer>1</integer>
-      <key>Type</key>
-      <string>String</string>
-      <key>Value</key>
-      <string>-</string>
-    </map>
     <key>AvatarAxisDeadZone0</key>
     <map>
       <key>Comment</key>
@@ -812,17 +801,6 @@
       <key>Value</key>
       <integer>0</integer>
     </map>
-    <key>FramePerSecondLimit</key>
-    <map>
-      <key>Comment</key>
-      <string>Controls upper limit of frames per second</string>
-      <key>Persist</key>
-      <integer>1</integer>
-      <key>Type</key>
-      <string>U32</string>
-      <key>Value</key>
-      <integer>120</integer>
-    </map>
     <key>BackgroundYieldTime</key>
     <map>
       <key>Comment</key>
@@ -1382,7 +1360,7 @@
       <key>Type</key>
       <string>F32</string>
       <key>Value</key>
-      <real>20.0</real>
+      <real>40.0</real>
     </map>
     <key>DiskCacheDirName</key>
     <map>
@@ -3409,10 +3387,10 @@
       <key>Value</key>
       <integer>0</integer>
     </map>
-    <key>DisableVerticalSync</key>
+    <key>RenderVSyncEnable</key>
     <map>
       <key>Comment</key>
-      <string>Update frames as fast as possible (FALSE = update frames between display scans)</string>
+      <string>Update frames between display scans (FALSE = Update frames as fast as possible).</string>
       <key>Persist</key>
       <integer>1</integer>
       <key>Type</key>
@@ -3585,7 +3563,7 @@
       <key>Value</key>
       <integer>0</integer>
     </map>
-    <key>DoubleClickTeleport</key>
+    <key>DoubleClickTeleport</key> 
     <map>
       <key>Comment</key>
       <string>Enable double-click to teleport where allowed (afects minimap and people panel)</string>
@@ -3858,7 +3836,7 @@
       <key>Type</key>
       <string>String</string>
       <key>Value</key>
-      <string>http://events.secondlife.com/viewer/embed/event/</string>
+      <string>http://events.[GRID]/viewer/embed/event/[EVENT_ID]</string>
     </map>
     <key>FastCacheFetchEnabled</key>
     <map>
@@ -3915,6 +3893,17 @@
         <key>Value</key>
         <integer>1</integer>
     </map>
+    <key>MainWorkTime</key>
+    <map>
+        <key>Comment</key>
+        <string>Max time per frame devoted to mainloop work queue (in milliseconds)</string>
+        <key>Persist</key>
+        <integer>1</integer>
+        <key>Type</key>
+        <string>F32</string>
+        <key>Value</key>
+        <real>0.1</real>
+    </map>
     <key>QueueInventoryFetchTimeout</key>
     <map>
         <key>Comment</key>
@@ -4758,7 +4747,7 @@
       <key>Type</key>
       <string>String</string>
       <key>Value</key>
-      <string>https://search.[GRID]/viewer/[CATEGORY]/?q=[QUERY]&amp;p=[AUTH_TOKEN]&amp;r=[MATURITY]&amp;lang=[LANGUAGE]&amp;g=[GODLIKE]&amp;sid=[SESSION_ID]&amp;rid=[REGION_ID]&amp;pid=[PARCEL_ID]&amp;channel=[CHANNEL]&amp;version=[VERSION]&amp;major=[VERSION_MAJOR]&amp;minor=[VERSION_MINOR]&amp;patch=[VERSION_PATCH]&amp;build=[VERSION_BUILD]</string>
+      <string>https://search.[GRID]/?query_term=[QUERY]&amp;search_type=[TYPE][COLLECTION]&amp;maturity=[MATURITY]&amp;lang=[LANGUAGE]&amp;g=[GODLIKE]&amp;sid=[SESSION_ID]&amp;rid=[REGION_ID]&amp;pid=[PARCEL_ID]&amp;channel=[CHANNEL]&amp;version=[VERSION]&amp;major=[VERSION_MAJOR]&amp;minor=[VERSION_MINOR]&amp;patch=[VERSION_PATCH]&amp;build=[VERSION_BUILD]</string>
     </map>
     <key>GuidebookURL</key>
     <map>
@@ -5806,6 +5795,17 @@
       <key>Value</key>
       <integer>0</integer>
     </map>
+    <key>DiskCacheVersion</key>
+    <map>
+      <key>Comment</key>
+      <string>Version number of disk cache</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>S32</string>
+      <key>Value</key>
+      <integer>0</integer>
+    </map>
     <key>LocalFileSystemBrowsingEnabled</key>
     <map>
       <key>Comment</key>
@@ -5895,17 +5895,6 @@
       <key>Value</key>
       <integer>0</integer>
     </map>
-    <key>LoginAsGod</key>
-    <map>
-      <key>Comment</key>
-      <string>Attempt to login with god powers (Linden accounts only)</string>
-      <key>Persist</key>
-      <integer>1</integer>
-      <key>Type</key>
-      <string>Boolean</string>
-      <key>Value</key>
-      <integer>0</integer>
-    </map>
     <key>LoginLocation</key>
     <map>
       <key>Comment</key>
@@ -6481,7 +6470,7 @@
     <key>MaxHeapSize</key>
     <map>
       <key>Comment</key>
-      <string>Maximum heap size (GB)</string>
+      <string>Maximum heap size on 32-bit builds (GB)</string>
       <key>Persist</key>
       <integer>1</integer>
       <key>Type</key>
@@ -6489,6 +6478,17 @@
       <key>Value</key>
       <real>1.6</real>
     </map>
+    <key>MaxHeapSize64</key>
+    <map>
+      <key>Comment</key>
+      <string>Maximum heap size on 64-bit builds (GB)</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>F32</string>
+      <key>Value</key>
+      <real>16.0</real>
+    </map>
     <key>MaxPersistentNotifications</key>
     <map>
       <key>Comment</key>
@@ -6808,6 +6808,9 @@
       <key>Type</key>
       <string>Boolean</string>
       <key>Value</key>
+      <!-- *HACK: On first run, set this to 0 for new users,
+           otherwise the default is 1 to maintain consistent experience
+           for existing users. Hardcoded in llnetmap.cpp -->
       <integer>1</integer>
     </map>
     <key>MiniMapScale</key>
@@ -6821,6 +6824,17 @@
       <key>Value</key>
       <real>128.0</real>
     </map>
+    <key>MiniMapShowPropertyLines</key>
+    <map>
+      <key>Comment</key>
+      <string>Whether or not to show parcel borders on the MiniMap.</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>Boolean</string>
+      <key>Value</key>
+      <real>1</real>
+    </map>
     <key>MouseSensitivity</key>
     <map>
       <key>Comment</key>
@@ -6964,6 +6978,17 @@
       <key>Value</key>
       <integer>1000</integer>
     </map>
+	<key>FakeInitialOutfitName</key>
+	<map>
+		<key>Comment</key>
+		<string>Pretend that this is first time login and specified name was chosen</string>
+		<key>Persist</key>
+		<integer>1</integer>
+		<key>Type</key>
+        <string>String</string>
+        <key>Value</key>
+        <string />
+	</map>
 	<key>MyOutfitsAutofill</key>
 	<map>
 		<key>Comment</key>
@@ -7066,7 +7091,7 @@
     <key>NoInventoryLibrary</key>
     <map>
       <key>Comment</key>
-      <string>Do not request inventory library.</string>
+      <string>(Deprecated) Do not request inventory library.</string>
       <key>Persist</key>
       <integer>1</integer>
       <key>Type</key>
@@ -7074,16 +7099,27 @@
       <key>Value</key>
       <integer>0</integer>
     </map>
+    <key>NonInteractive</key>
+    <map>
+      <key>Comment</key>
+      <string>Run in a semi-headless mode where only logging in and logging out needs to work.</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>Boolean</string>
+      <key>Value</key>
+	  <integer>0</integer>
+    </map>
     <key>NonvisibleObjectsInMemoryTime</key>
     <map>
       <key>Comment</key>
-      <string>Number of frames non-visible objects stay in memory before being removed. 0 means never to remove.</string>
+      <string>Number of frames non-visible objects stay in memory before being removed. 0 means max.</string>
       <key>Persist</key>
       <integer>1</integer>
       <key>Type</key>
       <string>U32</string>
       <key>Value</key>
-			<integer>300</integer>
+			<integer>64</integer>
     </map>
     <key>NoPreload</key>
     <map>
@@ -8088,9 +8124,9 @@
     <string>Color4</string>
     <key>Value</key>
     <array>
-      <real>1.0</real>
-      <real>1.0</real>
-      <real>1.0</real>
+      <real>0.33</real>
+      <real>0.33</real>
+      <real>0.33</real>
       <real>1.0</real>
     </array>
   </map>
@@ -8613,6 +8649,17 @@
       <key>Value</key>
       <integer>1</integer>
     </map>
+    <key>UpdateRememberPasswordSetting</key>
+    <map>
+      <key>Comment</key>
+      <string>Save 'rememeber password' setting for current user.</string>
+      <key>Persist</key>
+      <integer>0</integer>
+      <key>Type</key>
+      <string>Boolean</string>
+      <key>Value</key>
+      <integer>0</integer>
+    </map>
   <key>OctreeMaxNodeCapacity</key>
   <map>
     <key>Comment</key>
@@ -8693,28 +8740,6 @@
     </array>
   </map>
 
-    <key>RenderAlphaBatchFullbrights</key>
-    <map>
-      <key>Comment</key>
-      <string>Render fullbright alpha content more efficiently, but with possible visual differences from prev viewers.</string>
-      <key>Persist</key>
-      <integer>1</integer>
-      <key>Type</key>
-      <string>Boolean</string>
-      <key>Value</key>
-      <integer>0</integer>
-    </map>
-    <key>RenderAlphaBatchEmissives</key>
-    <map>
-      <key>Comment</key>
-      <string>Render emissive alpha content more efficiently, but with possible visual differences from prev viewers.</string>
-      <key>Persist</key>
-      <integer>1</integer>
-      <key>Type</key>
-      <string>Boolean</string>
-      <key>Value</key>
-      <integer>1</integer>
-    </map>
     <key>RenderAnisotropic</key>
     <map>
       <key>Comment</key>
@@ -8895,17 +8920,6 @@
       <key>Value</key>
       <real>1.0</real>
     </map>
-    <key>RenderAvatarVP</key>
-    <map>
-      <key>Comment</key>
-      <string>Use vertex programs to perform hardware skinning of avatar</string>
-      <key>Persist</key>
-      <integer>1</integer>
-      <key>Type</key>
-      <string>Boolean</string>
-      <key>Value</key>
-      <integer>1</integer>
-    </map>
   <key>RenderCompressTextures</key>
   <map>
     <key>Comment</key>
@@ -8917,7 +8931,7 @@
     <key>Value</key>
     <integer>0</integer>
   </map>
-    <key>RenderHiDPI</key>
+   <key>RenderHiDPI</key>
   <map>
     <key>Comment</key>
     <string>Enable support for HiDPI displays, like Retina (MacOS X ONLY, requires restart)</string>
@@ -9152,10 +9166,10 @@
       <key>Value</key>
       <real>0.5</real>
     </map>
-    <key>RenderDebugGL</key>
+    <key>RenderDebugGLSession</key>
     <map>
       <key>Comment</key>
-      <string>Enable strict GL debugging.</string>
+      <string>Enable strict GL debugging on the start of next session.</string>
       <key>Persist</key>
       <integer>1</integer>
       <key>Type</key>
@@ -9875,7 +9889,7 @@
     <key>Value</key>
     <real>2.2</real>
   </map>
-    <key>RenderGLCoreProfile</key>
+    <key>RenderGLContextCoreProfile</key>
     <map>
       <key>Comment</key>
       <string>Don't use a compatibility profile OpenGL context.  Requires restart.  Basic shaders MUST be enabled.</string>
@@ -9886,6 +9900,17 @@
       <key>Value</key>
       <integer>0</integer>
     </map>
+    <key>RenderGLMultiThreaded</key>
+    <map>
+      <key>Comment</key>
+      <string>Allow OpenGL to use multiple render contexts (reduces frame stutters from loading textures, doesn't play nice with Intel drivers).</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>Boolean</string>
+      <key>Value</key>
+      <integer>0</integer>
+    </map>
     <key>RenderGlow</key>
     <map>
       <key>Comment</key>
@@ -10189,7 +10214,7 @@
       <key>Type</key>
       <string>S32</string>
       <key>Value</key>
-      <integer>512</integer>
+      <integer>4096</integer>
     </map>
     <key>RenderNameFadeDuration</key>
     <map>
@@ -11011,7 +11036,7 @@
       <key>Type</key>
       <string>U32</string>
       <key>Value</key>
-      <integer>1024</integer>
+      <integer>2048</integer>
     </map>
     <key>SceneLoadLowMemoryBound</key>
     <map>
@@ -11639,7 +11664,7 @@
             <string>Boolean</string>
         <key>Value</key>
             <integer>0</integer>
-    </map>
+    </map> 
     <key>NearbyListShowMap</key>
     <map>
       <key>Comment</key>
@@ -12755,6 +12780,20 @@
       <key>Value</key>
       <string />
     </map>
+    <key>ThreadPoolSizes</key>
+    <map>
+      <key>Comment</key>
+      <string>Map of size overrides for specific thread pools.</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>LLSD</string>
+      <key>Value</key>
+      <map>
+        <key>General</key>
+        <integer>4</integer>
+      </map>
+    </map>
     <key>ThrottleBandwidthKBPS</key>
     <map>
       <key>Comment</key>
@@ -14196,17 +14235,6 @@
     <string>Boolean</string>
     <key>Value</key>
     <integer>1</integer>
-  </map>
-  <key>RenderSynchronousOcclusion</key>
-  <map>
-    <key>Comment</key>
-    <string>Don't let occlusion queries get more than one frame behind (block until they complete).</string>
-    <key>Persist</key>
-    <integer>1</integer>
-    <key>Type</key>
-    <string>Boolean</string>
-    <key>Value</key>
-    <integer>1</integer>
   </map>
     <key>RenderDelayVBUpdate</key>
     <map>
@@ -15722,6 +15750,17 @@
       <string>Boolean</string>
       <key>Value</key>
       <integer>1</integer>
+    </map>
+    <key>AllowSelectAvatar</key>
+    <map>
+      <key>Comment</key>
+      <string>Allows user to select and move avatars, move is viewer sided, does not propagate to server, also supresses avatar position updates while avatars are selected</string>
+      <key>Persist</key>
+      <integer>0</integer>
+      <key>Type</key>
+      <string>Boolean</string>
+      <key>Value</key>
+      <integer>0</integer>
     </map>
      <key>WebProfileFloaterRect</key>
     <map>
@@ -16725,8 +16764,8 @@
       <key>Type</key>
       <string>Boolean</string>
       <key>Value</key>
-      <integer>1</integer>
-  </map>
+      <integer>1</integer>        
+    </map>
   <key>360CaptureUseInterestListCap</key>
   <map>
     <key>Comment</key>
@@ -16806,14 +16845,36 @@
   </map>
   <key>ResetUIScaleOnFirstRun</key>
   <map>
-  <key>Comment</key>
-  <string>Resets the UI scale factor on first run due to changed display scaling behavior</string>
-  <key>Persist</key>
-  <integer>1</integer>
-  <key>Type</key>
-  <string>Boolean</string>
-  <key>Value</key>
-  <integer>1</integer>
+    <key>Comment</key>
+    <string>Resets the UI scale factor on first run due to changed display scaling behavior</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>Boolean</string>
+    <key>Value</key>
+    <integer>1</integer>        
+  </map>
+  <key>UpdateAppWindowTitleBar</key>
+  <map>
+    <key>Comment</key>
+    <string>Updates the application window title bar with brief information about user/location</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>Boolean</string>
+    <key>Value</key>
+    <integer>0</integer>
+  </map>
+  <key>MFAHash</key>
+  <map>
+    <key>Comment</key>
+    <string>Override MFA state hash for authentication</string>
+    <key>Persist</key>
+    <integer>0</integer>
+    <key>Type</key>
+    <string>String</string>
+    <key>Value</key>
+    <string></string>
   </map>
 </map>
 </llsd>
diff --git a/indra/newview/app_settings/shaders/class1/deferred/alphaF.glsl b/indra/newview/app_settings/shaders/class1/deferred/alphaF.glsl
index dc484317e9ecc8afd2f461a5cd03d53869dd7ec1..02b2daf0ac547622b27a56aa97e6c2f98328e1f9 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/alphaF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/alphaF.glsl
@@ -56,6 +56,10 @@ VARYING vec3 vary_norm;
 VARYING vec4 vertex_color; //vertex color should be treated as sRGB
 #endif
 
+#ifdef HAS_ALPHA_MASK
+uniform float minimum_alpha;
+#endif
+
 uniform mat4 proj_mat;
 uniform mat4 inv_proj;
 uniform vec2 screen_res;
@@ -86,6 +90,14 @@ float getAmbientClamp();
 
 vec3 calcPointLightOrSpotLight(vec3 light_col, vec3 diffuse, vec3 v, vec3 n, vec4 lp, vec3 ln, float la, float fa, float is_pointlight, float ambiance)
 {
+    // SL-14895 inverted attenuation work-around
+    // This routine is tweaked to match deferred lighting, but previously used an inverted la value. To reconstruct
+    // that previous value now that the inversion is corrected, we reverse the calculations in LLPipeline::setupHWLights()
+    // to recover the `adjusted_radius` value previously being sent as la.
+    float falloff_factor = (12.0 * fa) - 9.0;
+    float inverted_la = falloff_factor / la;
+    // Yes, it makes me want to cry as well. DJH
+    
     vec3 col = vec3(0);
 
 	//get light vector
@@ -95,7 +107,7 @@ vec3 calcPointLightOrSpotLight(vec3 light_col, vec3 diffuse, vec3 v, vec3 n, vec
 	float dist = length(lv);
 	float da = 1.0;
 
-    /*if (dist > la)
+    /*if (dist > inverted_la)
     {
         return col;
     }
@@ -113,9 +125,9 @@ vec3 calcPointLightOrSpotLight(vec3 light_col, vec3 diffuse, vec3 v, vec3 n, vec
         return col;
     }*/
 
-	if (dist > 0.0 && la > 0.0)
+	if (dist > 0.0 && inverted_la > 0.0)
 	{
-        dist /= la;
+        dist /= inverted_la;
 
 		//normalize light vector
 		lv = normalize(lv);
@@ -183,7 +195,6 @@ void main()
 #endif
 
     vec4 diffuse_srgb = diffuse_tap;
-    vec4 diffuse_linear = vec4(srgb_to_linear(diffuse_srgb.rgb), diffuse_srgb.a);
 
 #ifdef FOR_IMPOSTOR
     vec4 color;
@@ -192,25 +203,37 @@ void main()
 
     float final_alpha = diffuse_srgb.a * vertex_color.a;
     diffuse_srgb.rgb *= vertex_color.rgb;
-    diffuse_linear.rgb = srgb_to_linear(diffuse_srgb.rgb); 
     
     // Insure we don't pollute depth with invis pixels in impostor rendering
     //
-    if (final_alpha < 0.01)
+    if (final_alpha < minimum_alpha)
     {
         discard;
     }
-#else
-    
+
+    color.rgb = diffuse_srgb.rgb;
+    color.a = final_alpha;
+
+#else // FOR_IMPOSTOR
+
+    vec4 diffuse_linear = vec4(srgb_to_linear(diffuse_srgb.rgb), diffuse_srgb.a);
+
     vec3 light_dir = (sun_up_factor == 1) ? sun_dir: moon_dir;
 
     float final_alpha = diffuse_linear.a;
 
 #ifdef USE_VERTEX_COLOR
     final_alpha *= vertex_color.a;
+
+    if (final_alpha < minimum_alpha)
+    { // TODO: figure out how to get invisible faces out of 
+        // render batches without breaking glow
+        discard;
+    }
+
     diffuse_srgb.rgb *= vertex_color.rgb;
     diffuse_linear.rgb = srgb_to_linear(diffuse_srgb.rgb);
-#endif
+#endif // USE_VERTEX_COLOR
 
     vec3 sunlit;
     vec3 amblit;
@@ -242,13 +265,13 @@ void main()
 #if !defined(AMBIENT_KILL)
     color.rgb = amblit;
     color.rgb *= ambient;
-#endif
+#endif // !defined(AMBIENT_KILL)
 
 vec3 post_ambient = color.rgb;
 
 #if !defined(SUNLIGHT_KILL)
     color.rgb += sun_contrib;
-#endif
+#endif // !defined(SUNLIGHT_KILL)
 
 vec3 post_sunlight = color.rgb;
 
@@ -280,7 +303,7 @@ vec3 post_atmo = color.rgb;
     // sum local light contrib in linear colorspace
 #if !defined(LOCAL_LIGHT_KILL)
     color.rgb += light.rgb;
-#endif
+#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);
 
@@ -299,8 +322,8 @@ vec3 post_atmo = color.rgb;
     color = applyWaterFogView(pos.xyz, color);
 #endif // WATER_FOG
 
-#endif
-    
+#endif // #else // FOR_IMPOSTOR
+
     frag_color = color;
 }
 
diff --git a/indra/newview/app_settings/shaders/class1/deferred/alphaV.glsl b/indra/newview/app_settings/shaders/class1/deferred/alphaV.glsl
index 506118d381deb83ef7db62fc92acf6586016c751..6a93bc2fd2577cddc3cb02e5b6624a4718b7f514 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/alphaV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/alphaV.glsl
@@ -105,9 +105,9 @@ void main()
 	vec4 vert = vec4(position.xyz, 1.0);
 	pos = (modelview_matrix * vert);
 	gl_Position = modelview_projection_matrix*vec4(position.xyz, 1.0);
-#endif
+#endif //IS_AVATAR_SKIN
 	
-#endif
+#endif // HAS_SKIN
 
 #ifdef USE_INDEXED_TEX
 	passTextureIndex();
diff --git a/indra/newview/app_settings/shaders/class1/deferred/avatarAlphaShadowF.glsl b/indra/newview/app_settings/shaders/class1/deferred/avatarAlphaShadowF.glsl
index ef49b6f4e826bafdd0daf3a14bf8655ec62ec19d..1b16e4eb09e9d3a930aa7218d41f10e4bc135e04 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/avatarAlphaShadowF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/avatarAlphaShadowF.glsl
@@ -40,11 +40,11 @@ VARYING vec4 post_pos;
 VARYING float pos_w;
 VARYING float target_pos_x;
 VARYING vec2 vary_texcoord0;
-VARYING vec4 vertex_color;
+uniform vec4 color;
 
 void main() 
 {
-	float alpha = texture2D(diffuseMap, vary_texcoord0.xy).a * vertex_color.a;
+	float alpha = texture2D(diffuseMap, vary_texcoord0.xy).a * color.a;
 
 	if (alpha < 0.05) // treat as totally transparent
 	{
diff --git a/indra/newview/app_settings/shaders/class1/deferred/avatarAlphaShadowV.glsl b/indra/newview/app_settings/shaders/class1/deferred/avatarAlphaShadowV.glsl
index d1d7ece6febb89a622fabc6845eae0c067bbe862..1c5b142ebd10b30f72e52c54c0ccc8cff5b503d1 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/avatarAlphaShadowV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/avatarAlphaShadowV.glsl
@@ -30,7 +30,6 @@ uniform float shadow_target_width;
 mat4 getSkinnedTransform();
 void passTextureIndex();
 
-ATTRIBUTE vec4 diffuse_color;
 ATTRIBUTE vec3 position;
 ATTRIBUTE vec3 normal;
 ATTRIBUTE vec2 texcoord0;
@@ -41,7 +40,6 @@ VARYING vec4 post_pos;
 VARYING float pos_w;
 VARYING float target_pos_x;
 VARYING vec2 vary_texcoord0;
-VARYING vec4 vertex_color;
 
 void main()
 {
@@ -68,7 +66,6 @@ void main()
 
 	vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy;
 
-	vertex_color = diffuse_color;
 #if !DEPTH_CLAMP
 	post_pos = pos;
 
diff --git a/indra/newview/app_settings/shaders/class1/deferred/bumpSkinnedV.glsl b/indra/newview/app_settings/shaders/class1/deferred/bumpSkinnedV.glsl
deleted file mode 100644
index 10144f3e1612621f2f56f4d6fc3dab5f7853d501..0000000000000000000000000000000000000000
--- a/indra/newview/app_settings/shaders/class1/deferred/bumpSkinnedV.glsl
+++ /dev/null
@@ -1,64 +0,0 @@
-/** 
- * @file bumpV.glsl
- * $LicenseInfo:firstyear=2007&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2007, Linden Research, Inc.
- * 
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- * 
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
- * $/LicenseInfo$
- */
-
-uniform mat4 projection_matrix;
-uniform mat4 texture_matrix0;
-uniform mat4 modelview_matrix;
-
-ATTRIBUTE vec3 position;
-ATTRIBUTE vec4 diffuse_color;
-ATTRIBUTE vec3 normal;
-ATTRIBUTE vec2 texcoord0;
-ATTRIBUTE vec4 tangent;
-
-VARYING vec3 vary_mat0;
-VARYING vec3 vary_mat1;
-VARYING vec3 vary_mat2;
-VARYING vec4 vertex_color;
-VARYING vec2 vary_texcoord0;
-
-mat4 getObjectSkinnedTransform();
-
-void main()
-{
-	vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy;
-	
-	mat4 mat = getObjectSkinnedTransform();
-	
-	mat = modelview_matrix * mat;
-	
-	vec3 pos = (mat*vec4(position.xyz, 1.0)).xyz;
-	
-	
-	vec3 n = normalize((mat * vec4(normal.xyz+position.xyz, 1.0)).xyz-pos.xyz);
-	vec3 t = normalize((mat * vec4(tangent.xyz+position.xyz, 1.0)).xyz-pos.xyz);
-	vec3 b = cross(n, t) * tangent.w;
-	
-	vary_mat0 = vec3(t.x, b.x, n.x);
-	vary_mat1 = vec3(t.y, b.y, n.y);
-	vary_mat2 = vec3(t.z, b.z, n.z);
-	
-	gl_Position = projection_matrix*vec4(pos, 1.0);
-	vertex_color = diffuse_color;
-}
diff --git a/indra/newview/app_settings/shaders/class1/deferred/bumpV.glsl b/indra/newview/app_settings/shaders/class1/deferred/bumpV.glsl
index 9f9749394e023beaf336ff30a9bcf93b9c2203bb..d90891aa208dfbbad9ad59eb177487cacc3de316 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/bumpV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/bumpV.glsl
@@ -39,16 +39,32 @@ VARYING vec3 vary_mat2;
 VARYING vec4 vertex_color;
 VARYING vec2 vary_texcoord0;
 
+#ifdef HAS_SKIN
+mat4 getObjectSkinnedTransform();
+uniform mat4 projection_matrix;
+uniform mat4 modelview_matrix;
+#endif
+
 void main()
 {
 	//transform vertex
+#ifdef HAS_SKIN
+    mat4 mat = getObjectSkinnedTransform();
+	mat = modelview_matrix * mat;
+	vec3 pos = (mat*vec4(position.xyz, 1.0)).xyz;
+	gl_Position = projection_matrix*vec4(pos, 1.0);
+
+	vec3 n = normalize((mat * vec4(normal.xyz+position.xyz, 1.0)).xyz-pos.xyz);
+	vec3 t = normalize((mat * vec4(tangent.xyz+position.xyz, 1.0)).xyz-pos.xyz);
+#else
 	gl_Position = modelview_projection_matrix * vec4(position.xyz, 1.0); 
-	vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy;
-	
 	vec3 n = normalize(normal_matrix * normal);
 	vec3 t = normalize(normal_matrix * tangent.xyz);
+#endif
+
 	vec3 b = cross(n, t) * tangent.w;
-	
+	vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy;
+
 	vary_mat0 = vec3(t.x, b.x, n.x);
 	vary_mat1 = vec3(t.y, b.y, n.y);
 	vary_mat2 = vec3(t.z, b.z, n.z);
diff --git a/indra/newview/app_settings/shaders/class1/deferred/diffuseV.glsl b/indra/newview/app_settings/shaders/class1/deferred/diffuseV.glsl
index 3c026796c8b3a7fdd9e8df4076dfbc3561c12218..d64bcefade713da5d18cab55311371f346afea88 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/diffuseV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/diffuseV.glsl
@@ -39,14 +39,28 @@ VARYING vec2 vary_texcoord0;
 
 void passTextureIndex();
 
+#ifdef HAS_SKIN
+mat4 getObjectSkinnedTransform();
+uniform mat4 projection_matrix;
+uniform mat4 modelview_matrix;
+#endif
+
 void main()
 {
-	//transform vertex
+#ifdef HAS_SKIN
+    mat4 mat = getObjectSkinnedTransform();
+    mat = modelview_matrix * mat;
+    vec4 pos = mat * vec4(position.xyz, 1.0);
+    gl_Position = projection_matrix * pos;
+    vary_normal = normalize((mat*vec4(normal.xyz+position.xyz,1.0)).xyz-pos.xyz);
+#else
 	gl_Position = modelview_projection_matrix * vec4(position.xyz, 1.0); 
+    vary_normal = normalize(normal_matrix * normal);
+#endif
+	
 	vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy;
 	
 	passTextureIndex();
-	vary_normal = normalize(normal_matrix * normal);
-	
+
 	vertex_color = diffuse_color;
 }
diff --git a/indra/newview/app_settings/shaders/class1/deferred/emissiveV.glsl b/indra/newview/app_settings/shaders/class1/deferred/emissiveV.glsl
index 5e4f08b0174b4e3b7aa650f7e2a4a1c693e5dfc0..08b1147ab0b1a63f19dfdeacdbb96b7023b99889 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/emissiveV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/emissiveV.glsl
@@ -40,15 +40,26 @@ vec3 atmosAffectDirectionalLight(float lightIntensity);
 VARYING vec4 vertex_color;
 VARYING vec2 vary_texcoord0;
 
+#ifdef HAS_SKIN
+mat4 getObjectSkinnedTransform();
+uniform mat4 projection_matrix;
+#endif
 
 void main()
 {
 	//transform vertex
-	vec4 vert = vec4(position.xyz, 1.0);
-	vec4 pos = (modelview_matrix * vert);
 	passTextureIndex();
 
-	gl_Position = modelview_projection_matrix*vec4(position.xyz, 1.0);
+#ifdef HAS_SKIN
+    mat4 mat = getObjectSkinnedTransform();
+    mat = modelview_matrix * mat;
+
+    vec4 pos = mat * vec4(position.xyz, 1.0);
+    gl_Position = projection_matrix * pos;
+#else
+	gl_Position = modelview_projection_matrix * vec4(position.xyz, 1.0);
+    vec4 pos = (modelview_matrix * vec4(position.xyz, 1.0));
+#endif
 	
 	vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy;
 	
diff --git a/indra/newview/app_settings/shaders/class1/deferred/fullbrightShinyV.glsl b/indra/newview/app_settings/shaders/class1/deferred/fullbrightShinyV.glsl
index 8f6eb7966821415448a1968d6d5605c7b4e05b75..3bd6b693fa29366e3669769282a95c1a5ada0feb 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/fullbrightShinyV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/fullbrightShinyV.glsl
@@ -47,19 +47,32 @@ VARYING vec2 vary_texcoord0;
 VARYING vec3 vary_texcoord1;
 VARYING vec4 vary_position;
 
+#ifdef HAS_SKIN
+mat4 getObjectSkinnedTransform();
+uniform mat4 projection_matrix;
+#endif
+
 void main()
 {
 	//transform vertex
 	vec4 vert = vec4(position.xyz,1.0);
 	passTextureIndex();
+
+#ifdef HAS_SKIN
+    mat4 mat = getObjectSkinnedTransform();
+    mat = modelview_matrix * mat;
+    vec4 pos = mat * vert;
+    vary_position = gl_Position = projection_matrix * pos;
+	vec3 norm = normalize((mat*vec4(normal.xyz+position.xyz,1.0)).xyz-pos.xyz);
+#else
 	vec4 pos = (modelview_matrix * vert);
 	vary_position = gl_Position = modelview_projection_matrix*vec4(position.xyz, 1.0);
-	
 	vec3 norm = normalize(normal_matrix * normal);
+#endif
 	vec3 ref = reflect(pos.xyz, -norm);
 
 	vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy;
-	vary_texcoord1 = (texture_matrix1*vec4(ref,1.0)).xyz;
+	vary_texcoord1 = (texture_matrix1 * vec4(ref,1.0)).xyz;
 
 	calcAtmospherics(pos.xyz);
 
diff --git a/indra/newview/app_settings/shaders/class1/deferred/fullbrightV.glsl b/indra/newview/app_settings/shaders/class1/deferred/fullbrightV.glsl
index bdf3546aa5f7b5c052af16032593115f56ce6cba..e71636f2c9ec444b0772b903222e94f9dc6615eb 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/fullbrightV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/fullbrightV.glsl
@@ -45,15 +45,26 @@ VARYING vec3 vary_position;
 VARYING vec4 vertex_color;
 VARYING vec2 vary_texcoord0;
 
+#ifdef HAS_SKIN
+mat4 getObjectSkinnedTransform();
+uniform mat4 projection_matrix;
+#endif
 
 void main()
 {
 	//transform vertex
 	vec4 vert = vec4(position.xyz, 1.0);
-	vec4 pos = (modelview_matrix * vert);
 	passTextureIndex();
 
+#ifdef HAS_SKIN
+    mat4 mat = getObjectSkinnedTransform();
+    mat = modelview_matrix * mat;
+    vec4 pos = mat * vert;
+    gl_Position = projection_matrix * pos;
+#else
+	vec4 pos = (modelview_matrix * vert);
 	gl_Position = modelview_projection_matrix*vec4(position.xyz, 1.0);
+#endif
 
 #ifdef WATER_FOG
 	vary_position = pos.xyz;
diff --git a/indra/newview/app_settings/shaders/class1/deferred/impostorF.glsl b/indra/newview/app_settings/shaders/class1/deferred/impostorF.glsl
index eb6e56e718cf3da79584bcc5792b972e25f2e2e8..a58cc3d12df4213d1d65976df3811a4f7c8bb1d6 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/impostorF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/impostorF.glsl
@@ -54,8 +54,7 @@ void main()
 	vec4 norm = texture2D(normalMap,   vary_texcoord0.xy);
 	vec4 spec = texture2D(specularMap, vary_texcoord0.xy);
 
-	col.rgb = linear_to_srgb(col.rgb);
 	frag_data[0] = vec4(col.rgb, 0.0);
 	frag_data[1] = spec;
-	frag_data[2] = vec4(norm.xy,0,0);
+	frag_data[2] = norm;
 }
diff --git a/indra/newview/app_settings/shaders/class1/deferred/materialF.glsl b/indra/newview/app_settings/shaders/class1/deferred/materialF.glsl
index e1f7031af6ad587650665da70158588d8cf16da0..b26194f278823da1da30ec16972e52f09e3ee60c 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/materialF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/materialF.glsl
@@ -91,6 +91,14 @@ float getAmbientClamp();
 
 vec3 calcPointLightOrSpotLight(vec3 light_col, vec3 npos, vec3 diffuse, vec4 spec, vec3 v, vec3 n, vec4 lp, vec3 ln, float la, float fa, float is_pointlight, inout float glare, float ambiance)
 {
+    // SL-14895 inverted attenuation work-around
+    // This routine is tweaked to match deferred lighting, but previously used an inverted la value. To reconstruct
+    // that previous value now that the inversion is corrected, we reverse the calculations in LLPipeline::setupHWLights()
+    // to recover the `adjusted_radius` value previously being sent as la.
+    float falloff_factor = (12.0 * fa) - 9.0;
+    float inverted_la = falloff_factor / la;
+    // Yes, it makes me want to cry as well. DJH
+    
     vec3 col = vec3(0);
 
     //get light vector
@@ -100,9 +108,9 @@ vec3 calcPointLightOrSpotLight(vec3 light_col, vec3 npos, vec3 diffuse, vec4 spe
     float dist = length(lv);
     float da = 1.0;
 
-    dist /= la;
+    dist /= inverted_la;
 
-    if (dist > 0.0 && la > 0.0)
+    if (dist > 0.0 && inverted_la > 0.0)
     {
         //normalize light vector
         lv = normalize(lv);
@@ -194,7 +202,7 @@ VARYING vec2 vary_texcoord2;
 uniform float env_intensity;
 uniform vec4 specular_color;  // specular color RGB and specular exponent (glossiness) in alpha
 
-#if (DIFFUSE_ALPHA_MODE == DIFFUSE_ALPHA_MODE_MASK)
+#ifdef HAS_ALPHA_MASK
 uniform float minimum_alpha;
 #endif
 
@@ -219,11 +227,12 @@ void main()
     vec4 diffcol = texture2D(diffuseMap, vary_texcoord0.xy);
 	diffcol.rgb *= vertex_color.rgb;
 
-#if (DIFFUSE_ALPHA_MODE == DIFFUSE_ALPHA_MODE_MASK)
-
-    // Comparing floats cast from 8-bit values, produces acne right at the 8-bit transition points
-    float bias = 0.001953125; // 1/512, or half an 8-bit quantization
-    if (diffcol.a < minimum_alpha-bias)
+#ifdef HAS_ALPHA_MASK
+#if DIFFUSE_ALPHA_MODE == DIFFUSE_ALPHA_MODE_BLEND
+    if (diffcol.a*vertex_color.a < minimum_alpha)
+#else
+    if (diffcol.a < minimum_alpha)
+#endif
     {
         discard;
     }
diff --git a/indra/newview/app_settings/shaders/class1/deferred/normgenF.glsl b/indra/newview/app_settings/shaders/class1/deferred/normgenF.glsl
index d0c06cd51f6e7a9341742e346ccb341afa7a239d..7a941674b87363f6ceeb7dc635cab45e55b37aa7 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/normgenF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/normgenF.glsl
@@ -43,18 +43,18 @@ uniform float norm_scale;
 
 void main()
 {
-	float alpha = texture2D(alphaMap, vary_texcoord0).a;
+	float c = texture2D(alphaMap, vary_texcoord0).r;
 
-	vec3 right = vec3(norm_scale, 0, (texture2D(alphaMap, vary_texcoord0+vec2(stepX, 0)).a-alpha)*255);
-	vec3 left = vec3(-norm_scale, 0, (texture2D(alphaMap, vary_texcoord0-vec2(stepX, 0)).a-alpha)*255);
-	vec3 up = vec3(0, -norm_scale, (texture2D(alphaMap, vary_texcoord0-vec2(0, stepY)).a-alpha)*255);
-	vec3 down = vec3(0, norm_scale, (texture2D(alphaMap, vary_texcoord0+vec2(0, stepY)).a-alpha)*255);
+	vec3 right = vec3(norm_scale, 0, (texture2D(alphaMap, vary_texcoord0+vec2(stepX, 0)).r-c)*255);
+	vec3 left = vec3(-norm_scale, 0, (texture2D(alphaMap, vary_texcoord0-vec2(stepX, 0)).r-c)*255);
+	vec3 up = vec3(0, -norm_scale, (texture2D(alphaMap, vary_texcoord0-vec2(0, stepY)).r-c)*255);
+	vec3 down = vec3(0, norm_scale, (texture2D(alphaMap, vary_texcoord0+vec2(0, stepY)).r-c)*255);
 	
 	vec3 norm = cross(right, down) + cross(down, left) + cross(left,up) + cross(up, right);
 	
 	norm = normalize(norm);
 	norm *= 0.5;
 	norm += 0.5;	
-	
-	frag_color = vec4(norm, alpha);
+
+	frag_color = vec4(norm, c);
 }
diff --git a/indra/newview/app_settings/shaders/class1/deferred/diffuseSkinnedV.glsl b/indra/newview/app_settings/shaders/class1/deferred/shadowAlphaMaskSkinnedV.glsl
similarity index 69%
rename from indra/newview/app_settings/shaders/class1/deferred/diffuseSkinnedV.glsl
rename to indra/newview/app_settings/shaders/class1/deferred/shadowAlphaMaskSkinnedV.glsl
index 24871106242a9e334dfc470a4968e9ca21fe857e..2b17aea75a80f338b10400a42f3b553f14e1e7a7 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/diffuseSkinnedV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/shadowAlphaMaskSkinnedV.glsl
@@ -1,8 +1,9 @@
 /** 
- * @file diffuseSkinnedV.glsl
- * $LicenseInfo:firstyear=2007&license=viewerlgpl$
+ * @file shadowAlphaMaskSkinnedV.glsl
+ *
+ * $LicenseInfo:firstyear=2021&license=viewerlgpl$
  * Second Life Viewer Source Code
- * Copyright (C) 2007, Linden Research, Inc.
+ * Copyright (C) 2011, Linden Research, Inc.
  * 
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -22,38 +23,48 @@
  * $/LicenseInfo$
  */
 
-uniform mat4 projection_matrix;
 uniform mat4 texture_matrix0;
 uniform mat4 modelview_matrix;
+uniform mat4 projection_matrix;
+uniform float shadow_target_width;
 
 ATTRIBUTE vec3 position;
 ATTRIBUTE vec4 diffuse_color;
-ATTRIBUTE vec3 normal;
 ATTRIBUTE vec2 texcoord0;
 
-VARYING vec3 vary_normal;
+VARYING vec4 post_pos;
+VARYING float target_pos_x;
 VARYING vec4 vertex_color;
 VARYING vec2 vary_texcoord0;
 
+void passTextureIndex();
+
 mat4 getObjectSkinnedTransform();
 
 void main()
 {
-	vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy;
-		
+	//transform vertex
+	vec4 pre_pos = vec4(position.xyz, 1.0);
+
 	mat4 mat = getObjectSkinnedTransform();
 	
 	mat = modelview_matrix * mat;
-	vec3 pos = (mat*vec4(position.xyz, 1.0)).xyz;
 	
-	vec4 norm = vec4(position.xyz, 1.0);
-	norm.xyz += normal.xyz;
-	norm.xyz = (mat*norm).xyz;
-	norm.xyz = normalize(norm.xyz-pos.xyz);
+	vec4 pos = mat * pre_pos;
+	pos = projection_matrix * pos;
 
-	vary_normal = norm.xyz;
-			
-	vertex_color = diffuse_color;
+	target_pos_x = 0.5 * (shadow_target_width - 1.0) * pos.x;
+
+	post_pos = pos;
+
+#if !defined(DEPTH_CLAMP)
+	gl_Position = vec4(pos.x, pos.y, pos.w*0.5, pos.w);
+#else
+	gl_Position = pos;
+#endif
 	
-	gl_Position = projection_matrix*vec4(pos, 1.0);
+	passTextureIndex();
+
+	vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy;
+	vertex_color = diffuse_color;
 }
diff --git a/indra/newview/app_settings/shaders/class1/objects/simpleSkinnedV.glsl b/indra/newview/app_settings/shaders/class1/deferred/shadowSkinnedV.glsl
similarity index 59%
rename from indra/newview/app_settings/shaders/class1/objects/simpleSkinnedV.glsl
rename to indra/newview/app_settings/shaders/class1/deferred/shadowSkinnedV.glsl
index df31b5a79f149f344d3cd4ef80bcc540576fd57f..bdf8e0854d08c2055a1953497c44c4107721b0de 100644
--- a/indra/newview/app_settings/shaders/class1/objects/simpleSkinnedV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/shadowSkinnedV.glsl
@@ -1,6 +1,7 @@
 /** 
- * @file simpleSkinnedV.glsl
- * $LicenseInfo:firstyear=2007&license=viewerlgpl$
+ * @file shadowSkinnedV.glsl
+ *
+ * $LicenseInfo:firstyear=2021&license=viewerlgpl$
  * Second Life Viewer Source Code
  * Copyright (C) 2007, Linden Research, Inc.
  * 
@@ -22,44 +23,30 @@
  * $/LicenseInfo$
  */
 
-uniform mat4 texture_matrix0;
 uniform mat4 modelview_matrix;
 uniform mat4 projection_matrix;
 
 ATTRIBUTE vec3 position;
-ATTRIBUTE vec3 normal;
-ATTRIBUTE vec4 diffuse_color;
-ATTRIBUTE vec2 texcoord0;
 
-VARYING vec4 vertex_color;
-VARYING vec2 vary_texcoord0;
+VARYING vec4 post_pos;
 
-
-vec4 calcLighting(vec3 pos, vec3 norm, vec4 color);
-void calcAtmospherics(vec3 inPositionEye);
 mat4 getObjectSkinnedTransform();
 
 void main()
 {
 	//transform vertex
-	vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy;
-	
 	mat4 mat = getObjectSkinnedTransform();
 	
 	mat = modelview_matrix * mat;
-	vec3 pos = (mat*vec4(position.xyz, 1.0)).xyz;
-	
-	vec4 norm = vec4(position.xyz, 1.0);
-	norm.xyz += normal.xyz;
-	norm.xyz = (mat*norm).xyz;
-	norm.xyz = normalize(norm.xyz-pos.xyz);
-		
-	calcAtmospherics(pos.xyz);
+	vec4 pos = (mat*vec4(position.xyz, 1.0));
+	pos = projection_matrix*pos;
+
+	post_pos = pos;
+
+#if !defined(DEPTH_CLAMP)
+	gl_Position = vec4(pos.x, pos.y, pos.w*0.5, pos.w);
+#else
+	gl_Position = pos;
+#endif
 
-	vec4 color = calcLighting(pos.xyz, norm.xyz, diffuse_color);
-	vertex_color = color;
-	
-	gl_Position = projection_matrix*vec4(pos, 1.0);
-	
-	
 }
diff --git a/indra/newview/app_settings/shaders/class1/objects/emissiveSkinnedV.glsl b/indra/newview/app_settings/shaders/class1/deferred/treeShadowSkinnedV.glsl
similarity index 76%
rename from indra/newview/app_settings/shaders/class1/objects/emissiveSkinnedV.glsl
rename to indra/newview/app_settings/shaders/class1/deferred/treeShadowSkinnedV.glsl
index 90649041917c1ffdc64a441ae9dc30fb9c2e2197..d9ca6d3a46378e3537dbdd7d15b953eca7227e56 100644
--- a/indra/newview/app_settings/shaders/class1/objects/emissiveSkinnedV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/treeShadowSkinnedV.glsl
@@ -1,7 +1,7 @@
 /** 
- * @file emissiveSkinnedV.glsl
+ * @file treeShadowV.glsl
  *
- * $LicenseInfo:firstyear=2007&license=viewerlgpl$
+  * $LicenseInfo:firstyear=2007&license=viewerlgpl$
  * Second Life Viewer Source Code
  * Copyright (C) 2007, Linden Research, Inc.
  * 
@@ -23,34 +23,31 @@
  * $/LicenseInfo$
  */
 
-uniform mat4 projection_matrix;
 uniform mat4 texture_matrix0;
 uniform mat4 modelview_matrix;
-
+uniform mat4 projection_matrix;
+ 
 ATTRIBUTE vec3 position;
-ATTRIBUTE vec4 emissive;
 ATTRIBUTE vec2 texcoord0;
 
-VARYING vec4 vertex_color;
+VARYING vec4 post_pos;
 VARYING vec2 vary_texcoord0;
 
-
-void calcAtmospherics(vec3 inPositionEye);
 mat4 getObjectSkinnedTransform();
 
 void main()
 {
 	//transform vertex
-	vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy;
-	
-	mat4 mat = getObjectSkinnedTransform();
+    mat4 mat = getObjectSkinnedTransform();
 	
 	mat = modelview_matrix * mat;
-	vec3 pos = (mat*vec4(position.xyz, 1.0)).xyz;
 	
-	vertex_color = emissive;
-
-	calcAtmospherics(pos.xyz);
-
-	gl_Position = projection_matrix*vec4(pos, 1.0);
+	vec4 pos = mat * vec4(position.xyz, 1.0);
+    pos = projection_matrix * pos;
+	
+	post_pos = pos;
+	
+	gl_Position = vec4(pos.x, pos.y, pos.w*0.5, pos.w);
+	
+	vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy;
 }
diff --git a/indra/newview/app_settings/shaders/class1/interface/debugV.glsl b/indra/newview/app_settings/shaders/class1/interface/debugV.glsl
index f4d704577ad5e6f83bfb83971895255c2258397d..153998f1d5d745baae4c6f17270f9d4f0a53b0b8 100644
--- a/indra/newview/app_settings/shaders/class1/interface/debugV.glsl
+++ b/indra/newview/app_settings/shaders/class1/interface/debugV.glsl
@@ -27,8 +27,21 @@ uniform mat4 modelview_projection_matrix;
 
 ATTRIBUTE vec3 position;
 
+#ifdef HAS_SKIN
+mat4 getObjectSkinnedTransform();
+uniform mat4 projection_matrix;
+uniform mat4 modelview_matrix;
+#endif
+
 void main()
 {
+#ifdef HAS_SKIN
+    mat4 mat = getObjectSkinnedTransform();
+    mat = modelview_matrix * mat;
+    vec4 pos = mat * vec4(position.xyz,1.0);
+    gl_Position = projection_matrix * pos;
+#else
 	gl_Position = modelview_projection_matrix * vec4(position.xyz, 1.0);
+#endif
 }
 
diff --git a/indra/newview/app_settings/shaders/class1/interface/highlightV.glsl b/indra/newview/app_settings/shaders/class1/interface/highlightV.glsl
index 9bf7b60eb76a709653d9a379a1d3392ca9aa79b0..0b362cf46c4e6c3ccae1789b0586a136a9448a41 100644
--- a/indra/newview/app_settings/shaders/class1/interface/highlightV.glsl
+++ b/indra/newview/app_settings/shaders/class1/interface/highlightV.glsl
@@ -31,10 +31,23 @@ ATTRIBUTE vec2 texcoord0;
 
 VARYING vec2 vary_texcoord0;
 
+#ifdef HAS_SKIN
+mat4 getObjectSkinnedTransform();
+uniform mat4 projection_matrix;
+uniform mat4 modelview_matrix;
+#endif
+
 void main()
 {
 	//transform vertex
+#ifdef HAS_SKIN
+    mat4 mat = getObjectSkinnedTransform();
+    mat = modelview_matrix * mat;
+    vec4 pos = mat * vec4(position.xyz,1.0);
+    gl_Position = projection_matrix * pos;
+#else
 	gl_Position = modelview_projection_matrix * vec4(position.xyz, 1.0);
+#endif
 	vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy;
 }
 
diff --git a/indra/newview/app_settings/shaders/class1/objects/fullbrightSkinnedV.glsl b/indra/newview/app_settings/shaders/class1/interface/occlusionSkinnedV.glsl
similarity index 73%
rename from indra/newview/app_settings/shaders/class1/objects/fullbrightSkinnedV.glsl
rename to indra/newview/app_settings/shaders/class1/interface/occlusionSkinnedV.glsl
index eff75435a9459409ffa579611fca663c6c942fbb..7305065a057e6bd1ef66352d0563f578ef65f323 100644
--- a/indra/newview/app_settings/shaders/class1/objects/fullbrightSkinnedV.glsl
+++ b/indra/newview/app_settings/shaders/class1/interface/occlusionSkinnedV.glsl
@@ -1,6 +1,7 @@
 /** 
- * @file fullbrightSkinnedV.glsl
- * $LicenseInfo:firstyear=2007&license=viewerlgpl$
+ * @file occlusionSkinnedV.glsl
+ *
+ * $LicenseInfo:firstyear=2021&license=viewerlgpl$
  * Second Life Viewer Source Code
  * Copyright (C) 2007, Linden Research, Inc.
  * 
@@ -23,35 +24,17 @@
  */
 
 uniform mat4 projection_matrix;
-uniform mat4 texture_matrix0;
 uniform mat4 modelview_matrix;
 
 ATTRIBUTE vec3 position;
-ATTRIBUTE vec4 diffuse_color;
-ATTRIBUTE vec2 texcoord0;
 
-void calcAtmospherics(vec3 inPositionEye);
 mat4 getObjectSkinnedTransform();
 
-VARYING vec4 vertex_color;
-VARYING vec2 vary_texcoord0;
-
-
 void main()
 {
-	//transform vertex
-	vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy;
-	
 	mat4 mat = getObjectSkinnedTransform();
-	
 	mat = modelview_matrix * mat;
 	vec3 pos = (mat*vec4(position.xyz, 1.0)).xyz;
-	
-	calcAtmospherics(pos.xyz);
-
-	vertex_color = diffuse_color;
-	
 	gl_Position = projection_matrix*vec4(pos, 1.0);
-		
-	
 }
+
diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightAlphaMaskF.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightAlphaMaskF.glsl
index 1855cfceeb8c4b277e3fe3142d9a98791c4ecb3a..ad2170bbd3aa3f98f0032c221fd1f1be4cb77078 100644
--- a/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightAlphaMaskF.glsl
+++ b/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightAlphaMaskF.glsl
@@ -50,7 +50,7 @@ void fullbright_lighting()
 		discard;
 	}
 
-	color.rgb *= vertex_color.rgb;
+	color *= vertex_color;
 
 	color.rgb = pow(color.rgb, vec3(texture_gamma));
 
diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightF.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightF.glsl
index 5fcdf3107c63954568173fa3f64013e34af75428..89be8195f0f3d7fcabfd8e2986fd6e544e9d6999 100644
--- a/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightF.glsl
+++ b/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightF.glsl
@@ -56,5 +56,6 @@ void fullbright_lighting()
 	color.rgb = pow(color.rgb, vec3(1.0/texture_gamma));
 
 	frag_color = color;
+
 }
 
diff --git a/indra/newview/app_settings/shaders/class1/objects/bumpV.glsl b/indra/newview/app_settings/shaders/class1/objects/bumpV.glsl
index a7738087dcc940f41229140b89a9fa54502d85fc..ee9970bc70ae6e04fafd25cb448224e9280fa175 100644
--- a/indra/newview/app_settings/shaders/class1/objects/bumpV.glsl
+++ b/indra/newview/app_settings/shaders/class1/objects/bumpV.glsl
@@ -33,10 +33,23 @@ ATTRIBUTE vec2 texcoord1;
 VARYING vec2 vary_texcoord0;
 VARYING vec2 vary_texcoord1;
 
+#ifdef HAS_SKIN
+mat4 getObjectSkinnedTransform();
+uniform mat4 projection_matrix;
+uniform mat4 modelview_matrix;
+#endif
+
 void main()
 {
 	//transform vertex
+#ifdef HAS_SKIN
+    mat4 mat = getObjectSkinnedTransform();
+    mat = modelview_matrix * mat;
+    vec4 pos = mat * vec4(position.xyz, 1.0);
+    gl_Position = projection_matrix * pos;
+#else
 	gl_Position = modelview_projection_matrix*vec4(position.xyz, 1.0);
+#endif
 	vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy;
 	vary_texcoord1 = (texture_matrix0 * vec4(texcoord1,0,1)).xy;
 }
diff --git a/indra/newview/app_settings/shaders/class1/objects/emissiveV.glsl b/indra/newview/app_settings/shaders/class1/objects/emissiveV.glsl
index e984deb0c89c10a12ce0547ce4596dce9cad820d..d762239e5116d101d38993ba4a70c30b21a4642c 100644
--- a/indra/newview/app_settings/shaders/class1/objects/emissiveV.glsl
+++ b/indra/newview/app_settings/shaders/class1/objects/emissiveV.glsl
@@ -37,20 +37,30 @@ VARYING vec2 vary_texcoord0;
 
 void calcAtmospherics(vec3 inPositionEye);
 
-
-
+#ifdef HAS_SKIN
+mat4 getObjectSkinnedTransform();
+uniform mat4 projection_matrix;
+#endif
 
 void main()
 {
 	//transform vertex
 	passTextureIndex();
+
+#ifdef HAS_SKIN
+    mat4 mat = getObjectSkinnedTransform();
+    mat = modelview_matrix * mat;
+
+    vec4 pos = mat * vec4(position.xyz, 1.0);
+    gl_Position = projection_matrix * pos;
+#else
 	gl_Position = modelview_projection_matrix * vec4(position.xyz, 1.0);
+    vec4 pos = (modelview_matrix * vec4(position.xyz, 1.0));
+#endif
 	vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy;
 	
-	vec4 pos = (modelview_matrix * vec4(position.xyz, 1.0));
+	
 	calcAtmospherics(pos.xyz);
 
 	vertex_color = emissive;
-
-	
 }
diff --git a/indra/newview/app_settings/shaders/class1/objects/fullbrightShinySkinnedV.glsl b/indra/newview/app_settings/shaders/class1/objects/fullbrightShinySkinnedV.glsl
deleted file mode 100644
index 1e244d9dfdae3d0e1ef7920ba3ff2b58c0e75431..0000000000000000000000000000000000000000
--- a/indra/newview/app_settings/shaders/class1/objects/fullbrightShinySkinnedV.glsl
+++ /dev/null
@@ -1,71 +0,0 @@
-/** 
- * @file shinySimpleSkinnedV.glsl
- * $LicenseInfo:firstyear=2007&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2007, Linden Research, Inc.
- * 
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- * 
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
- * $/LicenseInfo$
- */
-
-uniform mat4 texture_matrix0;
-uniform mat4 texture_matrix1;
-uniform mat4 modelview_matrix;
-uniform mat4 projection_matrix;
-
-ATTRIBUTE vec3 position;
-ATTRIBUTE vec3 normal;
-ATTRIBUTE vec4 diffuse_color;
-ATTRIBUTE vec2 texcoord0;
-
-VARYING vec4 vertex_color;
-VARYING vec2 vary_texcoord0;
-VARYING vec3 vary_texcoord1;
-VARYING vec4 vary_position;
-
-
-void calcAtmospherics(vec3 inPositionEye);
-mat4 getObjectSkinnedTransform();
-
-void main()
-{
-	mat4 mat = getObjectSkinnedTransform();
-	
-	mat = modelview_matrix * mat;
-	vec3 pos = (mat*vec4(position.xyz, 1.0)).xyz;
-
-    mat4 mvp = modelview_matrix * projection_matrix;
-    vary_position = mvp * vec4(position, 1.0);
-	
-	vec4 norm = vec4(position.xyz, 1.0);
-	norm.xyz += normal.xyz;
-	norm.xyz = (mat*norm).xyz;
-	norm.xyz = normalize(norm.xyz-pos.xyz);
-		
-	vec3 ref = reflect(pos.xyz, -norm.xyz);
-
-	vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy;
-	vary_texcoord1 = (texture_matrix1*vec4(ref,1.0)).xyz;
-
-	calcAtmospherics(pos.xyz);
-
-	vertex_color = diffuse_color;
-	
-	gl_Position = projection_matrix*vec4(pos, 1.0);
-	
-	
-}
diff --git a/indra/newview/app_settings/shaders/class1/objects/fullbrightShinyV.glsl b/indra/newview/app_settings/shaders/class1/objects/fullbrightShinyV.glsl
index 34bd8d445a0eb532d77e10ea45897715bc369c65..891515ab1e2d39537a99161a2f2df8fd50f84439 100644
--- a/indra/newview/app_settings/shaders/class1/objects/fullbrightShinyV.glsl
+++ b/indra/newview/app_settings/shaders/class1/objects/fullbrightShinyV.glsl
@@ -46,20 +46,32 @@ VARYING vec4 vertex_color;
 VARYING vec2 vary_texcoord0;
 VARYING vec3 vary_texcoord1;
 
+#ifdef HAS_SKIN
+mat4 getObjectSkinnedTransform();
+uniform mat4 projection_matrix;
+#endif
 
 void main()
 {
 	//transform vertex
 	vec4 vert = vec4(position.xyz,1.0);
 	passTextureIndex();
+
+#ifdef HAS_SKIN
+    mat4 mat = getObjectSkinnedTransform();
+    mat = modelview_matrix * mat;
+    vec4 pos = mat * vert;
+    gl_Position = projection_matrix * pos;
+	vec3 norm = normalize((mat*vec4(normal.xyz+position.xyz,1.0)).xyz-pos.xyz);
+#else
 	vec4 pos = (modelview_matrix * vert);
 	gl_Position = modelview_projection_matrix*vec4(position.xyz, 1.0);
-	
 	vec3 norm = normalize(normal_matrix * normal);
+#endif
 	vec3 ref = reflect(pos.xyz, -norm);
 
 	vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy;
-	vary_texcoord1 = (texture_matrix1*vec4(ref,1.0)).xyz;
+	vary_texcoord1 = (texture_matrix1 * vec4(ref,1.0)).xyz;
 
 	calcAtmospherics(pos.xyz);
 
diff --git a/indra/newview/app_settings/shaders/class1/objects/fullbrightV.glsl b/indra/newview/app_settings/shaders/class1/objects/fullbrightV.glsl
index fc20d3270e2a349931b972de5e8a1117b9d0597c..5af42f1fcf99600e4d773aabfea17b4c95cb1032 100644
--- a/indra/newview/app_settings/shaders/class1/objects/fullbrightV.glsl
+++ b/indra/newview/app_settings/shaders/class1/objects/fullbrightV.glsl
@@ -33,26 +33,33 @@ ATTRIBUTE vec2 texcoord0;
 ATTRIBUTE vec3 normal;
 ATTRIBUTE vec4 diffuse_color;
 
-
 void calcAtmospherics(vec3 inPositionEye);
 
-
 VARYING vec4 vertex_color;
 VARYING vec2 vary_texcoord0;
 
+#ifdef HAS_SKIN
+mat4 getObjectSkinnedTransform();
+uniform mat4 projection_matrix;
+#endif
 
 void main()
 {
 	//transform vertex
 	vec4 vert = vec4(position.xyz,1.0);
 	passTextureIndex();
-	vec4 pos = (modelview_matrix * vert);
+#ifdef HAS_SKIN
+    mat4 mat = getObjectSkinnedTransform();
+    mat = modelview_matrix * mat;
+    vec4 pos = mat * vert;
+    gl_Position = projection_matrix * pos;
+#else
+    vec4 pos = (modelview_matrix * vert);
 	gl_Position = modelview_projection_matrix*vec4(position.xyz, 1.0);
+#endif
 	vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy;
 	
 	calcAtmospherics(pos.xyz);
 
 	vertex_color = diffuse_color;
-
-	
 }
diff --git a/indra/newview/llpanelme.h b/indra/newview/app_settings/shaders/class1/objects/previewPhysicsF.glsl
similarity index 59%
rename from indra/newview/llpanelme.h
rename to indra/newview/app_settings/shaders/class1/objects/previewPhysicsF.glsl
index 60e9d4317d8ee741993093ab6bf436c0177d1e54..3a5e6fdf7c440e14e541af9553c1824b502ec1b6 100644
--- a/indra/newview/llpanelme.h
+++ b/indra/newview/app_settings/shaders/class1/objects/previewPhysicsF.glsl
@@ -1,10 +1,9 @@
 /** 
- * @file llpanelme.h
- * @brief Side tray "Me" (My Profile) panel
+ * @file previewPhysicsF.glsl
  *
- * $LicenseInfo:firstyear=2009&license=viewerlgpl$
+ * $LicenseInfo:firstyear=2022&license=viewerlgpl$
  * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
+ * Copyright (C) 2022, Linden Research, Inc.
  * 
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -24,27 +23,20 @@
  * $/LicenseInfo$
  */
 
-#ifndef LL_LLPANELMEPROFILE_H
-#define LL_LLPANELMEPROFILE_H
+#ifdef DEFINE_GL_FRAGCOLOR
+out vec4 frag_color;
+#else
+#define frag_color gl_FragColor
+#endif
 
-#include "llpanel.h"
-#include "llpanelprofile.h"
+uniform sampler2D diffuseMap;
+uniform vec4 color;
 
-/**
-* Panel for displaying Agent's Picks and Classifieds panel.
-* LLPanelMe allows user to edit his picks and classifieds.
-*/
-class LLPanelMe : public LLPanelProfile
-{
-	LOG_CLASS(LLPanelMe);
-
-public:
-
-	LLPanelMe();
+VARYING vec2 vary_texcoord0;
 
-	/*virtual*/ void onOpen(const LLSD& key);
+//====================================================================================================
 
-	/*virtual*/ BOOL postBuild();
-};
-
-#endif // LL_LLPANELMEPROFILE_H
+void main()
+{
+    frag_color = texture2D(diffuseMap,vary_texcoord0.xy) * color;
+}
diff --git a/indra/newview/app_settings/shaders/class1/objects/previewPhysicsV.glsl b/indra/newview/app_settings/shaders/class1/objects/previewPhysicsV.glsl
new file mode 100644
index 0000000000000000000000000000000000000000..913dec83bd711f9419cb77369df3865a69a308bd
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/objects/previewPhysicsV.glsl
@@ -0,0 +1,42 @@
+/** 
+ * @file previewPhysicsV.glsl
+ *
+ * $LicenseInfo:firstyear=2022&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2022, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+uniform mat4 texture_matrix0;
+uniform mat4 modelview_matrix;
+uniform mat4 modelview_projection_matrix;
+
+ATTRIBUTE vec3 position;
+ATTRIBUTE vec2 texcoord0;
+
+VARYING vec2 vary_texcoord0;
+
+//====================================================================================================
+
+void main()
+{
+	//transform vertex
+	gl_Position = modelview_projection_matrix * vec4(position.xyz, 1.0);
+	vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy;
+}
diff --git a/indra/newview/app_settings/shaders/class1/objects/previewV.glsl b/indra/newview/app_settings/shaders/class1/objects/previewV.glsl
index 4bb588335ad9809773dd08cf7d2f062a8cfe0adb..5886f47cbce323205f8e6725cc8e317f6d3762c4 100644
--- a/indra/newview/app_settings/shaders/class1/objects/previewV.glsl
+++ b/indra/newview/app_settings/shaders/class1/objects/previewV.glsl
@@ -51,30 +51,6 @@ float calcDirectionalLight(vec3 n, vec3 l)
 	return a;
 }
 
-
-float calcLocalLight(vec3 v, vec3 n, vec4 lp, vec3 ln, float la, float is_pointlight)
-{
-	//get light vector
-	vec3 lv = lp.xyz-v;
-	
-	//get distance
-	float d = length(lv);
-	
-	//normalize light vector
-	lv *= 1.0/d;
-	
-	//distance attenuation
-	float da = clamp(1.0/(la * d), 0.0, 1.0);
-	
-	// spotlight coefficient.
-	float spot = max(dot(-ln, lv), is_pointlight);
-	da *= spot*spot; // GL_SPOT_EXPONENT=2
-
-	//angular attenuation
-	da *= calcDirectionalLight(n, lv);
-
-	return da;	
-}
 //====================================================================================================
 
 
@@ -91,7 +67,8 @@ void main()
 
 	// Collect normal lights (need to be divided by two, as we later multiply by 2)
 	col.rgb += light_diffuse[1].rgb * calcDirectionalLight(norm, light_position[1].xyz);
-	col.rgb += light_diffuse[2].rgb*calcLocalLight(pos.xyz, norm, light_position[2], light_direction[2], light_attenuation[2].x, light_attenuation[2].z);
-	col.rgb += light_diffuse[3].rgb*calcLocalLight(pos.xyz, norm, light_position[3], light_direction[3], light_attenuation[3].x, light_attenuation[3].z);
+    col.rgb += light_diffuse[2].rgb * calcDirectionalLight(norm, light_position[2].xyz);
+    col.rgb += light_diffuse[3].rgb * calcDirectionalLight(norm, light_position[3].xyz);
+
 	vertex_color = col*color;
 }
diff --git a/indra/newview/app_settings/shaders/class1/objects/shinySimpleSkinnedV.glsl b/indra/newview/app_settings/shaders/class1/objects/shinySimpleSkinnedV.glsl
deleted file mode 100644
index 727bae19c06f70d3050afce866eb15cc6b0718f4..0000000000000000000000000000000000000000
--- a/indra/newview/app_settings/shaders/class1/objects/shinySimpleSkinnedV.glsl
+++ /dev/null
@@ -1,66 +0,0 @@
-/** 
- * @file shinySimpleSkinnedV.glsl
- * $LicenseInfo:firstyear=2007&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2007, Linden Research, Inc.
- * 
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- * 
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
- * $/LicenseInfo$
- */
-
-uniform mat4 projection_matrix;
-uniform mat4 texture_matrix0;
-uniform mat4 texture_matrix1;
-uniform mat4 modelview_matrix;
-
-ATTRIBUTE vec3 position;
-ATTRIBUTE vec3 normal;
-ATTRIBUTE vec4 diffuse_color;
-ATTRIBUTE vec2 texcoord0;
-
-VARYING vec4 vertex_color;
-VARYING vec2 vary_texcoord0;
-VARYING vec3 vary_texcoord1;
-
-vec4 calcLighting(vec3 pos, vec3 norm, vec4 color);
-void calcAtmospherics(vec3 inPositionEye);
-mat4 getObjectSkinnedTransform();
-
-void main()
-{
-	mat4 mat = getObjectSkinnedTransform();
-	
-	mat = modelview_matrix * mat;
-	vec3 pos = (mat*vec4(position.xyz, 1.0)).xyz;
-	
-	vec4 norm = vec4(position.xyz, 1.0);
-	norm.xyz += normal.xyz;
-	norm.xyz = (mat*norm).xyz;
-	norm.xyz = normalize(norm.xyz-pos.xyz);
-		
-	vec3 ref = reflect(pos.xyz, -norm.xyz);
-
-	vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy;
-	vary_texcoord1 = (texture_matrix1*vec4(ref,1.0)).xyz;
-
-	calcAtmospherics(pos.xyz);
-
-	vec4 color = calcLighting(pos.xyz, norm.xyz, diffuse_color);
-	vertex_color = color;
-	
-	gl_Position = projection_matrix*vec4(pos, 1.0);
-}
diff --git a/indra/newview/app_settings/shaders/class1/objects/shinyV.glsl b/indra/newview/app_settings/shaders/class1/objects/shinyV.glsl
index 4ba8194d0384571a09e3597b137994f205149592..3ad7bcaa50f7bb14f0ccf8cee61ece51c7e53f4b 100644
--- a/indra/newview/app_settings/shaders/class1/objects/shinyV.glsl
+++ b/indra/newview/app_settings/shaders/class1/objects/shinyV.glsl
@@ -45,19 +45,32 @@ void calcAtmospherics(vec3 inPositionEye);
 
 uniform vec4 origin;
 
+#ifdef HAS_SKIN
+mat4 getObjectSkinnedTransform();
+uniform mat4 projection_matrix;
+#endif
+
 void main()
 {
 	//transform vertex
 	vec4 vert = vec4(position.xyz,1.0);
 	passTextureIndex();
+
+#ifdef HAS_SKIN
+    mat4 mat = getObjectSkinnedTransform();
+    mat = modelview_matrix * mat;
+    vec4 pos = mat * vert;
+    gl_Position = projection_matrix * pos;
+	vec3 norm = normalize((mat*vec4(normal.xyz+position.xyz,1.0)).xyz-pos.xyz);
+#else
 	vec4 pos = (modelview_matrix * vert);
 	gl_Position = modelview_projection_matrix*vec4(position.xyz, 1.0);
-		
 	vec3 norm = normalize(normal_matrix * normal);
+#endif
 	vec3 ref = reflect(pos.xyz, -norm);
 
-	vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy;
-	vary_texcoord1 = (texture_matrix1*vec4(ref,1.0)).xyz;
+	vary_texcoord0 = (texture_matrix0*vec4(texcoord0,0,1)).xy;
+	vary_texcoord1 = (texture_matrix1 * vec4(ref,1.0)).xyz;
 
 	calcAtmospherics(pos.xyz);
 
diff --git a/indra/newview/app_settings/shaders/class1/objects/simpleV.glsl b/indra/newview/app_settings/shaders/class1/objects/simpleV.glsl
index 9ef7704b7038ad6ae074a8d3b5011c3fce7b48b7..2025174f7decf7d25318022ee702a3867ef58c95 100644
--- a/indra/newview/app_settings/shaders/class1/objects/simpleV.glsl
+++ b/indra/newview/app_settings/shaders/class1/objects/simpleV.glsl
@@ -44,12 +44,16 @@ void calcAtmospherics(vec3 inPositionEye);
 VARYING vec4 vertex_color;
 VARYING vec2 vary_texcoord0;
 
+#ifdef HAS_SKIN
+mat4 getObjectSkinnedTransform();
+uniform mat4 projection_matrix;
+#endif
+
 
 void main()
 {
 	//transform vertex
 	vec4 vert = vec4(position.xyz,1.0);
-	gl_Position = modelview_projection_matrix*vec4(position.xyz, 1.0);
 
 	passTextureIndex();
 	vary_texcoord0 = (texture_matrix0 * vec4(texcoord0, 0, 1)).xy;
@@ -58,11 +62,23 @@ void main()
 	if (no_atmo == 1)
 	{
 		vertex_color = diffuse_color;
+        gl_Position = modelview_projection_matrix*vec4(position.xyz, 1.0);
 	}
 	else
 	{
+#ifdef HAS_SKIN
+        mat4 mat = getObjectSkinnedTransform();
+        mat = modelview_matrix * mat;
+
+        vec4 pos = mat * vert;
+        vec3 norm = normalize((mat*vec4(normal.xyz+vert.xyz,1.0)).xyz-pos.xyz);
+
+        gl_Position = projection_matrix * pos;
+#else
 		vec4 pos = (modelview_matrix * vert);
 		vec3 norm = normalize(normal_matrix * normal);
+        gl_Position = modelview_projection_matrix*vec4(position.xyz, 1.0);
+#endif
 
 		calcAtmospherics(pos.xyz);
 
diff --git a/indra/newview/app_settings/ultra_graphics.xml b/indra/newview/app_settings/ultra_graphics.xml
index eb2cd356d94e8fcff1c394b4e1ad25dc6136a99a..8462df207bc7219fae550d307f4cfc7eb1159584 100644
--- a/indra/newview/app_settings/ultra_graphics.xml
+++ b/indra/newview/app_settings/ultra_graphics.xml
@@ -6,8 +6,6 @@
 	<RenderAvatarLODFactor value="1.0"/>
 	<!--Default for now-->
 	<RenderAvatarPhysicsLODFactor value="1.0"/>
-	<!--NO SHADERS-->
-	<RenderAvatarVP value="TRUE"/>
 	<!--Short Range-->
 	<RenderFarClip value="256"/>
 	<!--Default for now-->
diff --git a/indra/newview/character/avatar_skeleton.xml b/indra/newview/character/avatar_skeleton.xml
index 2241a12545ffd942b86c3ed87422cdceb0ac0798..6cfc0b0be284682bd42dc83bcee42acc60c74cf5 100644
--- a/indra/newview/character/avatar_skeleton.xml
+++ b/indra/newview/character/avatar_skeleton.xml
@@ -2,15 +2,15 @@
    <bone aliases="hip avatar_mPelvis" connected="false" end="0.000 0.000 0.084" group="Torso" name="mPelvis" pivot="0.000000 0.000000 1.067015" pos="0.000 0.000 1.067" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base">
       <collision_volume end="0.030 0.000 0.095" group="Collision" name="PELVIS" pos="-0.01 0 -0.02" rot="0.000000 8.00000 0.000000" scale="0.12 0.16 0.17" support="base"/>
       <collision_volume end="-0.100 0.000 0.000" group="Collision" name="BUTT" pos="-0.06 0 -0.1" rot="0.000000 0.00000 0.000000" scale="0.1 0.1 0.1" support="base"/>
-      <bone connected="true" end="0.000 0.000 -0.084" group="Spine" name="mSpine1" pivot="0.000000 0.000000 0.084073" pos="0.000 0.000 0.084" rot="0.000000 0.000000 0.000000" scale="1.00 1.00 1.00" support="extended">
-         <bone connected="true" end="0.000 0.000 0.084" group="Spine" name="mSpine2" pivot="0.000000 0.000000 -0.084073" pos="0.000 0.000 -0.084" rot="0.000000 0.000000 0.000000" scale="1.00 1.00 1.00" support="extended">
+      <bone aliases="avatar_mSpine1" connected="true" end="0.000 0.000 -0.084" group="Spine" name="mSpine1" pivot="0.000000 0.000000 0.084073" pos="0.000 0.000 0.084" rot="0.000000 0.000000 0.000000" scale="1.00 1.00 1.00" support="extended">
+         <bone aliases="avatar_mSpine2" connected="true" end="0.000 0.000 0.084" group="Spine" name="mSpine2" pivot="0.000000 0.000000 -0.084073" pos="0.000 0.000 -0.084" rot="0.000000 0.000000 0.000000" scale="1.00 1.00 1.00" support="extended">
             <bone aliases="abdomen avatar_mTorso" connected="true" end="-0.015 0.000 0.205" group="Torso" name="mTorso" pivot="0.000000 0.000000 0.084073" pos="0.000 0.000 0.084" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base">
                <collision_volume end="0.028 0.000 0.094" group="Collision" name="BELLY" pos="0.028 0 0.04" rot="0.000000 8.00000 0.000000" scale="0.09 0.13 0.15" support="base"/>
                <collision_volume end="0.000 0.100 0.000" group="Collision" name="LEFT_HANDLE" pos="0.0 0.10 0.058" rot="0.000000 0.00000 0.000000" scale="0.05 0.05 0.05" support="base"/>
                <collision_volume end="0.000 -0.100 0.000" group="Collision" name="RIGHT_HANDLE" pos="0.0 -0.10 0.058" rot="0.000000 0.00000 0.000000" scale="0.05 0.05 0.05" support="base"/>
                <collision_volume end="-0.100 0.000 0.000" group="Collision" name="LOWER_BACK" pos="0.0 0.0 0.023" rot="0.000000 0.00000 0.000000" scale="0.09 0.13 0.15" support="base"/>
-               <bone connected="true" end="0.015 0.000 -0.205" group="Spine" name="mSpine3" pivot="-0.015368 0.000000 0.204877" pos="-0.015 0.000 0.205" rot="0.000000 0.000000 0.000000" scale="1.00 1.00 1.00" support="extended">
-                  <bone connected="true" end="-0.015 0.000 0.205" group="Spine" name="mSpine4" pivot="0.015368 0.000000 -0.204877" pos="0.015 0.000 -0.205" rot="0.000000 0.000000 0.000000" scale="1.00 1.00 1.00" support="extended">
+               <bone aliases="avatar_mSpine3" connected="true" end="0.015 0.000 -0.205" group="Spine" name="mSpine3" pivot="-0.015368 0.000000 0.204877" pos="-0.015 0.000 0.205" rot="0.000000 0.000000 0.000000" scale="1.00 1.00 1.00" support="extended">
+                  <bone aliases="avatar_mSpine4" connected="true" end="-0.015 0.000 0.205" group="Spine" name="mSpine4" pivot="0.015368 0.000000 -0.204877" pos="0.015 0.000 -0.205" rot="0.000000 0.000000 0.000000" scale="1.00 1.00 1.00" support="extended">
                      <bone aliases="chest avatar_mChest" connected="true" end="-0.010 0.000 0.250" group="Torso" name="mChest" pivot="-0.015368 0.000000 0.204877" pos="-0.015 0.000 0.205" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base">
                         <collision_volume end="-0.096 0.000 0.152" group="Collision" name="CHEST" pos="0.028 0 0.07" rot="0.000000 -10.00000 0.000000" scale="0.11 0.15 0.2" support="base"/>
                         <collision_volume end="0.080 0.000 -0.006" group="Collision" name="LEFT_PEC" pos="0.119 0.082 0.042" rot="0.000000 4.29000 0.000000" scale="0.05 0.05 0.05" support="base"/>
@@ -23,58 +23,58 @@
                               <bone aliases="figureHair avatar_mSkull" connected="false" end="0.000 0.000 0.033" group="Extra" name="mSkull" pivot="0.000000 0.000000 0.079000" pos="0.000 0.000 0.079" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base"/>
                               <bone aliases="avatar_mEyeRight" connected="false" end="0.025 0.000 0.000" group="Extra" name="mEyeRight" pivot="0.098466 -0.036000 0.079000" pos="0.098 -0.036 0.079" rot="0.000000 0.000000 -0.000000" scale="1.000 1.000 1.000" support="base"/>
                               <bone aliases="avatar_mEyeLeft" connected="false" end="0.025 0.000 0.000" group="Extra" name="mEyeLeft" pivot="0.098461 0.036000 0.079000" pos="0.098 0.036 0.079" rot="0.000000 -0.000000 0.000000" scale="1.000 1.000 1.000" support="base"/>
-                              <bone connected="false" end="0.020 0.000 0.000" group="Face" name="mFaceRoot" pivot="0.025000 0.000000 0.045000" pos="0.025 0.000 0.045" rot="0.000000 0.000000 0.000000" scale="1.00 1.00 1.00" support="extended">
-                                 <bone connected="false" end="0.025 0.000 0.000" group="Face" name="mFaceEyeAltRight" pivot="0.073466 -0.036000 0.0339300" pos="0.073 -0.036 0.034" rot="0.000000 0.000000 0.000000" scale="1.00 1.00 1.00" support="extended"/>
-                                 <bone connected="false" end="0.025 0.000 0.000" group="Face" name="mFaceEyeAltLeft" pivot="0.073461 0.036000 0.0339300" pos="0.073 0.036 0.034" rot="0.000000 0.000000 0.000000" scale="1.00 1.00 1.00" support="extended"/>
-                                 <bone connected="false" end="0.024 0.004 0.018" group="Face" name="mFaceForeheadLeft" pivot="0.061 0.035 0.083" pos="0.061 0.035 0.083" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
-                                 <bone connected="false" end="0.024 -0.004 0.018" group="Face" name="mFaceForeheadRight" pivot="0.061 -0.035 0.083" pos="0.061 -0.035 0.083" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
-                                 <bone connected="false" end="0.023 0.013 0.000" group="Eyes" name="mFaceEyebrowOuterLeft" pivot="0.064 0.051 0.048" pos="0.064 0.051 0.048" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
-                                 <bone connected="false" end="0.027 0.000 0.000" group="Eyes" name="mFaceEyebrowCenterLeft" pivot="0.070 0.043 0.056" pos="0.070 0.043 0.056" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
-                                 <bone connected="false" end="0.026 0.000 0.000" group="Eyes" name="mFaceEyebrowInnerLeft" pivot="0.075 0.022 0.051" pos="0.075 0.022 0.051" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
-                                 <bone connected="false" end="0.023 -0.013 0.000" group="Eyes" name="mFaceEyebrowOuterRight" pivot="0.064 -0.051 0.048" pos="0.064 -0.051 0.048" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
-                                 <bone connected="false" end="0.027 0.000 0.000" group="Eyes" name="mFaceEyebrowCenterRight" pivot="0.070 -0.043 0.056" pos="0.070 -0.043 0.056" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
-                                 <bone connected="false" end="0.026 0.000 0.000" group="Eyes" name="mFaceEyebrowInnerRight" pivot="0.075 -0.022 0.051" pos="0.075 -0.022 0.051" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
-                                 <bone connected="false" end="0.027 0.000 0.005" group="Eyes" name="mFaceEyeLidUpperLeft" pivot="0.073 0.036 0.034" pos="0.073 0.036 0.034" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
-                                 <bone connected="false" end="0.024 0.000 -0.007" group="Eyes" name="mFaceEyeLidLowerLeft" pivot="0.073 0.036 0.034" pos="0.073 0.036 0.034" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
-                                 <bone connected="false" end="0.027 0.000 0.005" group="Eyes" name="mFaceEyeLidUpperRight" pivot="0.073 -0.036 0.034" pos="0.073 -0.036 0.034" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
-                                 <bone connected="false" end="0.024 0.000 -0.007" group="Eyes" name="mFaceEyeLidLowerRight" pivot="0.073 -0.036 0.034" pos="0.073 -0.036 0.034" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
-                                 <bone connected="false" end="-0.019 0.018 0.025" group="Ears" name="mFaceEar1Left" pivot="0.000 0.080 0.002" pos="0.000 0.080 0.002" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
-                                    <bone connected="true" end="0.000 0.000 0.033" group="Ears" name="mFaceEar2Left" pivot="-0.019 0.018 0.025" pos="-0.019 0.018 0.025" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
+                              <bone aliases="avatar_mFaceRoot" connected="false" end="0.020 0.000 0.000" group="Face" name="mFaceRoot" pivot="0.025000 0.000000 0.045000" pos="0.025 0.000 0.045" rot="0.000000 0.000000 0.000000" scale="1.00 1.00 1.00" support="extended">
+                                 <bone aliases="avatar_mFaceEyeAltRight" connected="false" end="0.025 0.000 0.000" group="Face" name="mFaceEyeAltRight" pivot="0.073466 -0.036000 0.0339300" pos="0.073 -0.036 0.034" rot="0.000000 0.000000 0.000000" scale="1.00 1.00 1.00" support="extended"/>
+                                 <bone aliases="avatar_mFaceEyeAltLeft" connected="false" end="0.025 0.000 0.000" group="Face" name="mFaceEyeAltLeft" pivot="0.073461 0.036000 0.0339300" pos="0.073 0.036 0.034" rot="0.000000 0.000000 0.000000" scale="1.00 1.00 1.00" support="extended"/>
+                                 <bone aliases="avatar_mFaceForeheadLeft" connected="false" end="0.024 0.004 0.018" group="Face" name="mFaceForeheadLeft" pivot="0.061 0.035 0.083" pos="0.061 0.035 0.083" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
+                                 <bone aliases="avatar_mFaceForeheadRight" connected="false" end="0.024 -0.004 0.018" group="Face" name="mFaceForeheadRight" pivot="0.061 -0.035 0.083" pos="0.061 -0.035 0.083" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
+                                 <bone aliases="avatar_mFaceEyebrowOuterLeft" connected="false" end="0.023 0.013 0.000" group="Eyes" name="mFaceEyebrowOuterLeft" pivot="0.064 0.051 0.048" pos="0.064 0.051 0.048" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
+                                 <bone aliases="avatar_mFaceEyebrowCenterLeft" connected="false" end="0.027 0.000 0.000" group="Eyes" name="mFaceEyebrowCenterLeft" pivot="0.070 0.043 0.056" pos="0.070 0.043 0.056" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
+                                 <bone aliases="avatar_mFaceEyebrowInnerLeft" connected="false" end="0.026 0.000 0.000" group="Eyes" name="mFaceEyebrowInnerLeft" pivot="0.075 0.022 0.051" pos="0.075 0.022 0.051" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
+                                 <bone aliases="avatar_mFaceEyebrowOuterRight" connected="false" end="0.023 -0.013 0.000" group="Eyes" name="mFaceEyebrowOuterRight" pivot="0.064 -0.051 0.048" pos="0.064 -0.051 0.048" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
+                                 <bone aliases="avatar_mFaceEyebrowCenterRight" connected="false" end="0.027 0.000 0.000" group="Eyes" name="mFaceEyebrowCenterRight" pivot="0.070 -0.043 0.056" pos="0.070 -0.043 0.056" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
+                                 <bone aliases="avatar_mFaceEyebrowInnerRight" connected="false" end="0.026 0.000 0.000" group="Eyes" name="mFaceEyebrowInnerRight" pivot="0.075 -0.022 0.051" pos="0.075 -0.022 0.051" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
+                                 <bone aliases="avatar_mFaceEyeLidUpperLeft" connected="false" end="0.027 0.000 0.005" group="Eyes" name="mFaceEyeLidUpperLeft" pivot="0.073 0.036 0.034" pos="0.073 0.036 0.034" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
+                                 <bone aliases="avatar_mFaceEyeLidLowerLeft" connected="false" end="0.024 0.000 -0.007" group="Eyes" name="mFaceEyeLidLowerLeft" pivot="0.073 0.036 0.034" pos="0.073 0.036 0.034" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
+                                 <bone aliases="avatar_mFaceEyeLidUpperRight" connected="false" end="0.027 0.000 0.005" group="Eyes" name="mFaceEyeLidUpperRight" pivot="0.073 -0.036 0.034" pos="0.073 -0.036 0.034" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
+                                 <bone aliases="avatar_mFaceEyeLidLowerRight" connected="false" end="0.024 0.000 -0.007" group="Eyes" name="mFaceEyeLidLowerRight" pivot="0.073 -0.036 0.034" pos="0.073 -0.036 0.034" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
+                                 <bone aliases="avatar_mFaceEar1Left" connected="false" end="-0.019 0.018 0.025" group="Ears" name="mFaceEar1Left" pivot="0.000 0.080 0.002" pos="0.000 0.080 0.002" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
+                                    <bone aliases="avatar_mFaceEar2Left" connected="true" end="0.000 0.000 0.033" group="Ears" name="mFaceEar2Left" pivot="-0.019 0.018 0.025" pos="-0.019 0.018 0.025" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
                                  </bone>
-                                 <bone connected="false" end="-0.019 -0.018 0.025" group="Ears" name="mFaceEar1Right" pivot="0.000 -0.080 0.002" pos="0.000 -0.080 0.002" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
-                                    <bone connected="true" end="0.000 0.000 0.033" group="Ears" name="mFaceEar2Right" pivot="-0.019 -0.018 0.025" pos="-0.019 -0.018 0.025" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
+                                 <bone aliases="avatar_mFaceEar1Right" connected="false" end="-0.019 -0.018 0.025" group="Ears" name="mFaceEar1Right" pivot="0.000 -0.080 0.002" pos="0.000 -0.080 0.002" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
+                                    <bone aliases="avatar_mFaceEar2Right" connected="true" end="0.000 0.000 0.033" group="Ears" name="mFaceEar2Right" pivot="-0.019 -0.018 0.025" pos="-0.019 -0.018 0.025" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
                                  </bone>
-                                 <bone connected="false" end="0.015 0.004 0.000" group="Face" name="mFaceNoseLeft" pivot="0.086 0.015 -0.004" pos="0.086 0.015 -0.004" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
-                                 <bone connected="false" end="0.025 0.000 0.000" group="Face" name="mFaceNoseCenter" pivot="0.102 0.000 0.000" pos="0.102 0.000 0.000" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
-                                 <bone connected="false" end="0.015 -0.004 0.000" group="Face" name="mFaceNoseRight" pivot="0.086 -0.015 -0.004" pos="0.086 -0.015 -0.004" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
-                                 <bone connected="false" end="0.013 0.030 0.000" group="Face" name="mFaceCheekLowerLeft" pivot="0.050 0.034 -0.031" pos="0.050 0.034 -0.031" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
-                                 <bone connected="false" end="0.022 0.015 0.000" group="Face" name="mFaceCheekUpperLeft" pivot="0.070 0.034 -0.005" pos="0.070 0.034 -0.005" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
-                                 <bone connected="false" end="0.013 -0.030 0.000" group="Face" name="mFaceCheekLowerRight" pivot="0.050 -0.034 -0.031" pos="0.050 -0.034 -0.031" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
-                                 <bone connected="false" end="0.022 -0.015 0.000" group="Face" name="mFaceCheekUpperRight" pivot="0.070 -0.034 -0.005" pos="0.070 -0.034 -0.005" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
-                                 <bone connected="false" end="0.059 0.000 -0.039" group="Mouth" name="mFaceJaw" pivot="-0.001 0.000 -0.015" pos="-0.001 0.000 -0.015" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
-                                    <bone connected="false" end="0.021 0.000 -0.018" group="Mouth" name="mFaceChin" pivot="0.074 0.000 -0.054" pos="0.074 0.000 -0.054" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
-                                    <bone connected="false" end="0.035 0.000 0.000" group="Mouth" name="mFaceTeethLower" pivot="0.021 0.000 -0.039" pos="0.021 0.000 -0.039" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
-                                       <bone connected="false" end="0.034 0.017 0.005" group="Lips" name="mFaceLipLowerLeft" pivot="0.045 0.000 0.000" pos="0.045 0.000 0.000" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
-                                       <bone connected="false" end="0.034 -0.017 0.005" group="Lips" name="mFaceLipLowerRight" pivot="0.045 0.000 0.000" pos="0.045 0.000 0.000" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
-                                       <bone connected="false" end="0.040 0.000 0.002" group="Lips" name="mFaceLipLowerCenter" pivot="0.045 0.000 0.000" pos="0.045 0.000 0.000" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
-                                       <bone connected="false" end="0.022 0.000 0.007" group="Mouth" name="mFaceTongueBase" pivot="0.039 0.000 0.005" pos="0.039 0.000 0.005" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
-                                          <bone connected="true" end="0.010 0.000 0.000" group="Mouth" name="mFaceTongueTip" pivot="0.022 0.000 0.007" pos="0.022 0.000 0.007" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
+                                 <bone aliases="avatar_mFaceNoseLeft" connected="false" end="0.015 0.004 0.000" group="Face" name="mFaceNoseLeft" pivot="0.086 0.015 -0.004" pos="0.086 0.015 -0.004" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
+                                 <bone aliases="avatar_mFaceNoseCenter" connected="false" end="0.025 0.000 0.000" group="Face" name="mFaceNoseCenter" pivot="0.102 0.000 0.000" pos="0.102 0.000 0.000" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
+                                 <bone aliases="avatar_mFaceNoseRight" connected="false" end="0.015 -0.004 0.000" group="Face" name="mFaceNoseRight" pivot="0.086 -0.015 -0.004" pos="0.086 -0.015 -0.004" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
+                                 <bone aliases="avatar_mFaceCheekLowerLeft" connected="false" end="0.013 0.030 0.000" group="Face" name="mFaceCheekLowerLeft" pivot="0.050 0.034 -0.031" pos="0.050 0.034 -0.031" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
+                                 <bone aliases="avatar_mFaceCheekUpperLeft" connected="false" end="0.022 0.015 0.000" group="Face" name="mFaceCheekUpperLeft" pivot="0.070 0.034 -0.005" pos="0.070 0.034 -0.005" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
+                                 <bone aliases="avatar_mFaceCheekLowerRight" connected="false" end="0.013 -0.030 0.000" group="Face" name="mFaceCheekLowerRight" pivot="0.050 -0.034 -0.031" pos="0.050 -0.034 -0.031" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
+                                 <bone aliases="avatar_mFaceCheekUpperRight" connected="false" end="0.022 -0.015 0.000" group="Face" name="mFaceCheekUpperRight" pivot="0.070 -0.034 -0.005" pos="0.070 -0.034 -0.005" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
+                                 <bone aliases="avatar_mFaceJaw" connected="false" end="0.059 0.000 -0.039" group="Mouth" name="mFaceJaw" pivot="-0.001 0.000 -0.015" pos="-0.001 0.000 -0.015" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
+                                    <bone aliases="avatar_mFaceChin" connected="false" end="0.021 0.000 -0.018" group="Mouth" name="mFaceChin" pivot="0.074 0.000 -0.054" pos="0.074 0.000 -0.054" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
+                                    <bone aliases="avatar_mFaceTeethLower" connected="false" end="0.035 0.000 0.000" group="Mouth" name="mFaceTeethLower" pivot="0.021 0.000 -0.039" pos="0.021 0.000 -0.039" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
+                                       <bone aliases="avatar_mFaceLipLowerLeft" connected="false" end="0.034 0.017 0.005" group="Lips" name="mFaceLipLowerLeft" pivot="0.045 0.000 0.000" pos="0.045 0.000 0.000" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
+                                       <bone aliases="avatar_mFaceLipLowerRight" connected="false" end="0.034 -0.017 0.005" group="Lips" name="mFaceLipLowerRight" pivot="0.045 0.000 0.000" pos="0.045 0.000 0.000" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
+                                       <bone aliases="avatar_mFaceLipLowerCenter" connected="false" end="0.040 0.000 0.002" group="Lips" name="mFaceLipLowerCenter" pivot="0.045 0.000 0.000" pos="0.045 0.000 0.000" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
+                                       <bone aliases="avatar_mFaceTongueBase" connected="false" end="0.022 0.000 0.007" group="Mouth" name="mFaceTongueBase" pivot="0.039 0.000 0.005" pos="0.039 0.000 0.005" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
+                                          <bone aliases="avatar_mFaceTongueTip" connected="true" end="0.010 0.000 0.000" group="Mouth" name="mFaceTongueTip" pivot="0.022 0.000 0.007" pos="0.022 0.000 0.007" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
                                        </bone>
                                     </bone>
                                  </bone>
-                                 <bone connected="false" end="-0.017 0.000 0.000" group="Face" name="mFaceJawShaper" pivot="0.000 0.000 0.000" pos="0.000 0.000 0.000" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
-                                 <bone connected="false" end="0.036 0.000 0.000" group="Face" name="mFaceForeheadCenter" pivot="0.069 0.000 0.065" pos="0.069 0.000 0.065" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
-                                 <bone connected="false" end="0.014 0.000 0.000" group="Nose" name="mFaceNoseBase" pivot="0.094 0.000 -0.016" pos="0.094 0.000 -0.016" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
-                                 <bone connected="false" end="0.035 0.000 0.000" group="Mouth" name="mFaceTeethUpper" pivot="0.020 0.000 -0.030" pos="0.020 0.000 -0.030" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
-                                    <bone connected="false" end="0.041 0.015 0.000" group="Lips" name="mFaceLipUpperLeft" pivot="0.045 0.000 -0.003" pos="0.045 0.000 -0.003" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
-                                    <bone connected="false" end="0.041 -0.015 0.000" group="Lips" name="mFaceLipUpperRight" pivot="0.045 0.000 -0.003" pos="0.045 0.000 -0.003" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
-                                    <bone connected="false" end="0.045 0.051 0.000" group="Lips" name="mFaceLipCornerLeft" pivot="0.028 -0.019 -0.010" pos="0.028 -0.019 -0.010" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
-                                    <bone connected="false" end="0.045 -0.051 0.000" group="Lips" name="mFaceLipCornerRight" pivot="0.028 0.019 -0.010" pos="0.028 0.019 -0.010" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
-                                    <bone connected="false" end="0.043 0.000 0.002" group="Lips" name="mFaceLipUpperCenter" pivot="0.045 0.000 -0.003" pos="0.045 0.000 -0.003" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
+                                 <bone aliases="avatar_mFaceJawShaper" connected="false" end="-0.017 0.000 0.000" group="Face" name="mFaceJawShaper" pivot="0.000 0.000 0.000" pos="0.000 0.000 0.000" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
+                                 <bone aliases="avatar_mFaceForeheadCenter" connected="false" end="0.036 0.000 0.000" group="Face" name="mFaceForeheadCenter" pivot="0.069 0.000 0.065" pos="0.069 0.000 0.065" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
+                                 <bone aliases="avatar_mFaceNoseBase" connected="false" end="0.014 0.000 0.000" group="Nose" name="mFaceNoseBase" pivot="0.094 0.000 -0.016" pos="0.094 0.000 -0.016" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
+                                 <bone aliases="avatar_mFaceTeethUpper" connected="false" end="0.035 0.000 0.000" group="Mouth" name="mFaceTeethUpper" pivot="0.020 0.000 -0.030" pos="0.020 0.000 -0.030" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
+                                    <bone aliases="avatar_mFaceLipUpperLeft" connected="false" end="0.041 0.015 0.000" group="Lips" name="mFaceLipUpperLeft" pivot="0.045 0.000 -0.003" pos="0.045 0.000 -0.003" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
+                                    <bone aliases="avatar_mFaceLipUpperRight" connected="false" end="0.041 -0.015 0.000" group="Lips" name="mFaceLipUpperRight" pivot="0.045 0.000 -0.003" pos="0.045 0.000 -0.003" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
+                                    <bone aliases="avatar_mFaceLipCornerLeft" connected="false" end="0.045 0.051 0.000" group="Lips" name="mFaceLipCornerLeft" pivot="0.028 -0.019 -0.010" pos="0.028 -0.019 -0.010" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
+                                    <bone aliases="avatar_mFaceLipCornerRight" connected="false" end="0.045 -0.051 0.000" group="Lips" name="mFaceLipCornerRight" pivot="0.028 0.019 -0.010" pos="0.028 0.019 -0.010" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
+                                    <bone aliases="avatar_mFaceLipUpperCenter" connected="false" end="0.043 0.000 0.002" group="Lips" name="mFaceLipUpperCenter" pivot="0.045 0.000 -0.003" pos="0.045 0.000 -0.003" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
                                  </bone>
-                                 <bone connected="false" end="0.016 0.000 0.000" group="Face" name="mFaceEyecornerInnerLeft" pivot="0.075 0.017 0.032" pos="0.075 0.017 0.032" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
-                                 <bone connected="false" end="0.016 0.000 0.000" group="Face" name="mFaceEyecornerInnerRight" pivot="0.075 -0.017 0.032" pos="0.075 -0.017 0.032" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
-                                 <bone connected="false" end="0.015 0.000 0.008" group="Nose" name="mFaceNoseBridge" pivot="0.091 0.000 0.020" pos="0.091 0.000 0.020" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
+                                 <bone aliases="avatar_mFaceEyecornerInnerLeft" connected="false" end="0.016 0.000 0.000" group="Face" name="mFaceEyecornerInnerLeft" pivot="0.075 0.017 0.032" pos="0.075 0.017 0.032" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
+                                 <bone aliases="avatar_mFaceEyecornerInnerRight" connected="false" end="0.016 0.000 0.000" group="Face" name="mFaceEyecornerInnerRight" pivot="0.075 -0.017 0.032" pos="0.075 -0.017 0.032" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
+                                 <bone aliases="avatar_mFaceNoseBridge" connected="false" end="0.015 0.000 0.008" group="Nose" name="mFaceNoseBridge" pivot="0.091 0.000 0.020" pos="0.091 0.000 0.020" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
                               </bone>
                            </bone>
                         </bone>
@@ -86,29 +86,29 @@
                                  <collision_volume end="0.000 0.100 -0.001" group="Collision" name="L_LOWER_ARM" pos="0.0 0.1 0.0" rot="-3.000000 0.00000 0.000000" scale="0.04 0.14 0.04" support="base"/>
                                  <bone aliases="lHand avatar_mWristLeft" connected="true" end="0.000 0.060 0.000" group="Arms" name="mWristLeft" pivot="-0.000000 0.204846 0.000000" pos="-0.000 0.205 0.000" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base">
                                     <collision_volume end="0.005 0.049 -0.001" group="Collision" name="L_HAND" pos="0.01 0.05 0.0" rot="-3.000000 0.00000 -10.000000" scale="0.05 0.08 0.03" support="base"/>
-                                    <bone connected="false" end="-0.001 0.040 -0.006" group="Hand" name="mHandMiddle1Left" pivot="0.013 0.101 0.015" pos="0.013 0.101 0.015" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
-                                       <bone connected="true" end="-0.001 0.049 -0.008" group="Hand" name="mHandMiddle2Left" pivot="-0.001 0.040 -0.006" pos="-0.001 0.040 -0.006" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
-                                          <bone connected="true" end="-0.002 0.033 -0.006" group="Hand" name="mHandMiddle3Left" pivot="-0.001 0.049 -0.008" pos="-0.001 0.049 -0.008" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
+                                    <bone aliases="avatar_mHandMiddle1Left" connected="false" end="-0.001 0.040 -0.006" group="Hand" name="mHandMiddle1Left" pivot="0.013 0.101 0.015" pos="0.013 0.101 0.015" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
+                                       <bone aliases="avatar_mHandMiddle2Left" connected="true" end="-0.001 0.049 -0.008" group="Hand" name="mHandMiddle2Left" pivot="-0.001 0.040 -0.006" pos="-0.001 0.040 -0.006" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
+                                          <bone aliases="avatar_mHandMiddle3Left" connected="true" end="-0.002 0.033 -0.006" group="Hand" name="mHandMiddle3Left" pivot="-0.001 0.049 -0.008" pos="-0.001 0.049 -0.008" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
                                        </bone>
                                     </bone>
-                                    <bone connected="false" end="0.017 0.036 -0.006" group="Hand" name="mHandIndex1Left" pivot="0.038 0.097 0.015" pos="0.038 0.097 0.015" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
-                                       <bone connected="true" end="0.014 0.032 -0.006" group="Hand" name="mHandIndex2Left" pivot="0.017 0.036 -0.006" pos="0.017 0.036 -0.006" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
-                                          <bone connected="true" end="0.011 0.025 -0.004" group="Hand" name="mHandIndex3Left" pivot="0.014 0.032 -0.006" pos="0.014 0.032 -0.006" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
+                                    <bone aliases="avatar_mHandIndex1Left" connected="false" end="0.017 0.036 -0.006" group="Hand" name="mHandIndex1Left" pivot="0.038 0.097 0.015" pos="0.038 0.097 0.015" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
+                                       <bone aliases="avatar_mHandIndex2Left" connected="true" end="0.014 0.032 -0.006" group="Hand" name="mHandIndex2Left" pivot="0.017 0.036 -0.006" pos="0.017 0.036 -0.006" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
+                                          <bone aliases="avatar_mHandIndex3Left" connected="true" end="0.011 0.025 -0.004" group="Hand" name="mHandIndex3Left" pivot="0.014 0.032 -0.006" pos="0.014 0.032 -0.006" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
                                        </bone>
                                     </bone>
-                                    <bone connected="false" end="-0.013 0.038 -0.008" group="Hand" name="mHandRing1Left" pivot="-0.010 0.099 0.009" pos="-0.010 0.099 0.009" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
-                                       <bone connected="true" end="-0.013 0.040 -0.009" group="Hand" name="mHandRing2Left" pivot="-0.013 0.038 -0.008" pos="-0.013 0.038 -0.008" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
-                                          <bone connected="true" end="-0.010 0.028 -0.006" group="Hand" name="mHandRing3Left" pivot="-0.013 0.040 -0.009" pos="-0.013 0.040 -0.009" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
+                                    <bone aliases="avatar_mHandRing1Left" connected="false" end="-0.013 0.038 -0.008" group="Hand" name="mHandRing1Left" pivot="-0.010 0.099 0.009" pos="-0.010 0.099 0.009" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
+                                       <bone aliases="avatar_mHandRing2Left" connected="true" end="-0.013 0.040 -0.009" group="Hand" name="mHandRing2Left" pivot="-0.013 0.038 -0.008" pos="-0.013 0.038 -0.008" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
+                                          <bone aliases="avatar_mHandRing3Left" connected="true" end="-0.010 0.028 -0.006" group="Hand" name="mHandRing3Left" pivot="-0.013 0.040 -0.009" pos="-0.013 0.040 -0.009" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
                                        </bone>
                                     </bone>
-                                    <bone connected="false" end="-0.024 0.025 -0.006" group="Hand" name="mHandPinky1Left" pivot="-0.031 0.095 0.003" pos="-0.031 0.095 0.003" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
-                                       <bone connected="true" end="-0.015 0.018 -0.004" group="Hand" name="mHandPinky2Left" pivot="-0.024 0.025 -0.006" pos="-0.024 0.025 -0.006" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
-                                          <bone connected="true" end="-0.013 0.016 -0.004" group="Hand" name="mHandPinky3Left" pivot="-0.015 0.018 -0.004" pos="-0.015 0.018 -0.004" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
+                                    <bone aliases="avatar_mHandPinky1Left" connected="false" end="-0.024 0.025 -0.006" group="Hand" name="mHandPinky1Left" pivot="-0.031 0.095 0.003" pos="-0.031 0.095 0.003" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
+                                       <bone aliases="avatar_mHandPinky2Left" connected="true" end="-0.015 0.018 -0.004" group="Hand" name="mHandPinky2Left" pivot="-0.024 0.025 -0.006" pos="-0.024 0.025 -0.006" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
+                                          <bone aliases="avatar_mHandPinky3Left" connected="true" end="-0.013 0.016 -0.004" group="Hand" name="mHandPinky3Left" pivot="-0.015 0.018 -0.004" pos="-0.015 0.018 -0.004" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
                                        </bone>
                                     </bone>
-                                    <bone connected="false" end="0.028 0.032 0.000" group="Hand" name="mHandThumb1Left" pivot="0.031 0.026 0.004" pos="0.031 0.026 0.004" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
-                                       <bone connected="true" end="0.023 0.031 0.000" group="Hand" name="mHandThumb2Left" pivot="0.028 0.032 -0.001" pos="0.028 0.032 -0.001" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
-                                          <bone connected="true" end="0.015 0.025 0.000" group="Hand" name="mHandThumb3Left" pivot="0.023 0.031 -0.001" pos="0.023 0.031 -0.001" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
+                                    <bone aliases="avatar_mHandThumb1Left" connected="false" end="0.028 0.032 0.000" group="Hand" name="mHandThumb1Left" pivot="0.031 0.026 0.004" pos="0.031 0.026 0.004" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
+                                       <bone aliases="avatar_mHandThumb2Left" connected="true" end="0.023 0.031 0.000" group="Hand" name="mHandThumb2Left" pivot="0.028 0.032 -0.001" pos="0.028 0.032 -0.001" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
+                                          <bone aliases="avatar_mHandThumb3Left" connected="true" end="0.015 0.025 0.000" group="Hand" name="mHandThumb3Left" pivot="0.023 0.031 -0.001" pos="0.023 0.031 -0.001" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
                                        </bone>
                                     </bone>
                                  </bone>
@@ -123,49 +123,49 @@
                                  <collision_volume end="0.000 -0.100 -0.001" group="Collision" name="R_LOWER_ARM" pos="0.0 -0.1 0.0" rot="3.000000 0.00000 0.000000" scale="0.04 0.14 0.04" support="base"/>
                                  <bone aliases="rHand avatar_mWristRight" connected="true" end="0.000 -0.060 0.000" group="Arms" name="mWristRight" pivot="-0.000000 -0.205000 -0.000000" pos="0.000 -0.205 -0.000" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base">
                                     <collision_volume end="0.005 -0.049 -0.001" group="Collision" name="R_HAND" pos="0.01 -0.05 0.0" rot="3.000000 0.00000 10.000000" scale="0.05 0.08 0.03" support="base"/>
-                                    <bone connected="false" end="-0.001 -0.040 -0.006" group="Hand" name="mHandMiddle1Right" pivot="0.013 -0.101 0.015" pos="0.013 -0.101 0.015" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
-                                       <bone connected="true" end="-0.001 -0.049 -0.008" group="Hand" name="mHandMiddle2Right" pivot="-0.001 -0.040 -0.006" pos="-0.001 -0.040 -0.006" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
-                                          <bone connected="true" end="-0.002 -0.033 -0.006" group="Hand" name="mHandMiddle3Right" pivot="-0.001 -0.049 -0.008" pos="-0.001 -0.049 -0.008" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
+                                    <bone aliases="avatar_mHandMiddle1Right" connected="false" end="-0.001 -0.040 -0.006" group="Hand" name="mHandMiddle1Right" pivot="0.013 -0.101 0.015" pos="0.013 -0.101 0.015" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
+                                       <bone aliases="avatar_mHandMiddle2Right" connected="true" end="-0.001 -0.049 -0.008" group="Hand" name="mHandMiddle2Right" pivot="-0.001 -0.040 -0.006" pos="-0.001 -0.040 -0.006" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
+                                          <bone aliases="avatar_mHandMiddle3Right" connected="true" end="-0.002 -0.033 -0.006" group="Hand" name="mHandMiddle3Right" pivot="-0.001 -0.049 -0.008" pos="-0.001 -0.049 -0.008" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
                                        </bone>
                                     </bone>
-                                    <bone connected="false" end="0.017 -0.036 -0.006" group="Hand" name="mHandIndex1Right" pivot="0.038 -0.097 0.015" pos="0.038 -0.097 0.015" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
-                                       <bone connected="true" end="0.014 -0.032 -0.006" group="Hand" name="mHandIndex2Right" pivot="0.017 -0.036 -0.006" pos="0.017 -0.036 -0.006" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
-                                          <bone connected="true" end="0.011 -0.025 -0.004" group="Hand" name="mHandIndex3Right" pivot="0.014 -0.032 -0.006" pos="0.014 -0.032 -0.006" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
+                                    <bone aliases="avatar_mHandIndex1Right" connected="false" end="0.017 -0.036 -0.006" group="Hand" name="mHandIndex1Right" pivot="0.038 -0.097 0.015" pos="0.038 -0.097 0.015" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
+                                       <bone aliases="avatar_mHandIndex2Right" connected="true" end="0.014 -0.032 -0.006" group="Hand" name="mHandIndex2Right" pivot="0.017 -0.036 -0.006" pos="0.017 -0.036 -0.006" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
+                                          <bone aliases="avatar_mHandIndex3Right" connected="true" end="0.011 -0.025 -0.004" group="Hand" name="mHandIndex3Right" pivot="0.014 -0.032 -0.006" pos="0.014 -0.032 -0.006" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
                                        </bone>
                                     </bone>
-                                    <bone connected="false" end="-0.013 -0.038 -0.008" group="Hand" name="mHandRing1Right" pivot="-0.010 -0.099 0.009" pos="-0.010 -0.099 0.009" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
-                                       <bone connected="true" end="-0.013 -0.040 -0.009" group="Hand" name="mHandRing2Right" pivot="-0.013 -0.038 -0.008" pos="-0.013 -0.038 -0.008" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
-                                          <bone connected="true" end="-0.010 -0.028 -0.006" group="Hand" name="mHandRing3Right" pivot="-0.013 -0.040 -0.009" pos="-0.013 -0.040 -0.009" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
+                                    <bone aliases="avatar_mHandRing1Right" connected="false" end="-0.013 -0.038 -0.008" group="Hand" name="mHandRing1Right" pivot="-0.010 -0.099 0.009" pos="-0.010 -0.099 0.009" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
+                                       <bone aliases="avatar_mHandRing2Right" connected="true" end="-0.013 -0.040 -0.009" group="Hand" name="mHandRing2Right" pivot="-0.013 -0.038 -0.008" pos="-0.013 -0.038 -0.008" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
+                                          <bone aliases="avatar_mHandRing3Right" connected="true" end="-0.010 -0.028 -0.006" group="Hand" name="mHandRing3Right" pivot="-0.013 -0.040 -0.009" pos="-0.013 -0.040 -0.009" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
                                        </bone>
                                     </bone>
-                                    <bone connected="false" end="-0.024 -0.025 -0.006" group="Hand" name="mHandPinky1Right" pivot="-0.031 -0.095 0.003" pos="-0.031 -0.095 0.003" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
-                                       <bone connected="true" end="-0.015 -0.018 -0.004" group="Hand" name="mHandPinky2Right" pivot="-0.024 -0.025 -0.006" pos="-0.024 -0.025 -0.006" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
-                                          <bone connected="true" end="-0.013 -0.016 -0.004" group="Hand" name="mHandPinky3Right" pivot="-0.015 -0.018 -0.004" pos="-0.015 -0.018 -0.004" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
+                                    <bone aliases="avatar_mHandPinky1Right" connected="false" end="-0.024 -0.025 -0.006" group="Hand" name="mHandPinky1Right" pivot="-0.031 -0.095 0.003" pos="-0.031 -0.095 0.003" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
+                                       <bone aliases="avatar_mHandPinky2Right" connected="true" end="-0.015 -0.018 -0.004" group="Hand" name="mHandPinky2Right" pivot="-0.024 -0.025 -0.006" pos="-0.024 -0.025 -0.006" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
+                                          <bone aliases="avatar_mHandPinky3Right" connected="true" end="-0.013 -0.016 -0.004" group="Hand" name="mHandPinky3Right" pivot="-0.015 -0.018 -0.004" pos="-0.015 -0.018 -0.004" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
                                        </bone>
                                     </bone>
-                                    <bone connected="false" end="0.028 -0.032 0.000" group="Hand" name="mHandThumb1Right" pivot="0.031 -0.026 0.004" pos="0.031 -0.026 0.004" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
-                                       <bone connected="true" end="0.023 -0.031 0.000" group="Hand" name="mHandThumb2Right" pivot="0.028 -0.032 -0.001" pos="0.028 -0.032 -0.001" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
-                                          <bone connected="true" end="0.015 -0.025 0.000" group="Hand" name="mHandThumb3Right" pivot="0.023 -0.031 -0.001" pos="0.023 -0.031 -0.001" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
+                                    <bone aliases="avatar_mHandThumb1Right" connected="false" end="0.028 -0.032 0.000" group="Hand" name="mHandThumb1Right" pivot="0.031 -0.026 0.004" pos="0.031 -0.026 0.004" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
+                                       <bone aliases="avatar_mHandThumb2Right" connected="true" end="0.023 -0.031 0.000" group="Hand" name="mHandThumb2Right" pivot="0.028 -0.032 -0.001" pos="0.028 -0.032 -0.001" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
+                                          <bone aliases="avatar_mHandThumb3Right" connected="true" end="0.015 -0.025 0.000" group="Hand" name="mHandThumb3Right" pivot="0.023 -0.031 -0.001" pos="0.023 -0.031 -0.001" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
                                        </bone>
                                     </bone>
                                  </bone>
                               </bone>
                            </bone>
                         </bone>
-                        <bone connected="false" end="-0.061 0.000 0.000" group="Wing" name="mWingsRoot" pivot="-0.014 0.000 0.000" pos="-0.014 0.000 0.000" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
-                           <bone connected="false" end="-0.168 0.169 0.067" group="Wing" name="mWing1Left" pivot="-0.099 0.105 0.181" pos="-0.099 0.105 0.181" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
-                              <bone connected="true" end="-0.181 0.183 0.000" group="Wing" name="mWing2Left" pivot="-0.168 0.169 0.067" pos="-0.168 0.169 0.067" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
-                                 <bone connected="true" end="-0.171 0.173 0.000" group="Wing" name="mWing3Left" pivot="-0.181 0.183 0.000" pos="-0.181 0.183 0.000" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
-                                    <bone connected="true" end="-0.146 0.132 0.000" group="Wing" name="mWing4Left" pivot="-0.171 0.173 0.000" pos="-0.171 0.173 0.000" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
-                                    <bone connected="true" end="-0.068 0.062 -0.159" group="Wing" name="mWing4FanLeft" pivot="-0.171 0.173 0.000" pos="-0.171 0.173 0.000" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
+                        <bone aliases="avatar_mWingsRoot" connected="false" end="-0.061 0.000 0.000" group="Wing" name="mWingsRoot" pivot="-0.014 0.000 0.000" pos="-0.014 0.000 0.000" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
+                           <bone aliases="avatar_mWing1Left" connected="false" end="-0.168 0.169 0.067" group="Wing" name="mWing1Left" pivot="-0.099 0.105 0.181" pos="-0.099 0.105 0.181" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
+                              <bone aliases="avatar_mWing2Left" connected="true" end="-0.181 0.183 0.000" group="Wing" name="mWing2Left" pivot="-0.168 0.169 0.067" pos="-0.168 0.169 0.067" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
+                                 <bone aliases="avatar_mWing3Left" connected="true" end="-0.171 0.173 0.000" group="Wing" name="mWing3Left" pivot="-0.181 0.183 0.000" pos="-0.181 0.183 0.000" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
+                                    <bone aliases="avatar_mWing4Left" connected="true" end="-0.146 0.132 0.000" group="Wing" name="mWing4Left" pivot="-0.171 0.173 0.000" pos="-0.171 0.173 0.000" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
+                                    <bone aliases="avatar_mWing4FanLeft" connected="true" end="-0.068 0.062 -0.159" group="Wing" name="mWing4FanLeft" pivot="-0.171 0.173 0.000" pos="-0.171 0.173 0.000" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
                                  </bone>
                               </bone>
                            </bone>
-                           <bone connected="false" end="-0.168 -0.169 0.067" group="Wing" name="mWing1Right" pivot="-0.099 -0.105 0.181" pos="-0.099 -0.105 0.181" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
-                              <bone connected="true" end="-0.181 -0.183 0.000" group="Wing" name="mWing2Right" pivot="-0.168 -0.169 0.067" pos="-0.168 -0.169 0.067" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
-                                 <bone connected="true" end="-0.171 -0.173 0.000" group="Wing" name="mWing3Right" pivot="-0.181 -0.183 0.000" pos="-0.181 -0.183 0.000" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
-                                    <bone connected="true" end="-0.146 -0.132 0.000" group="Wing" name="mWing4Right" pivot="-0.171 -0.173 0.000" pos="-0.171 -0.173 0.000" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
-                                    <bone connected="true" end="-0.068 -0.062 -0.159" group="Wing" name="mWing4FanRight" pivot="-0.171 -0.173 0.000" pos="-0.171 -0.173 0.000" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
+                           <bone aliases="avatar_mWing1Right" connected="false" end="-0.168 -0.169 0.067" group="Wing" name="mWing1Right" pivot="-0.099 -0.105 0.181" pos="-0.099 -0.105 0.181" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
+                              <bone aliases="avatar_mWing2Right" connected="true" end="-0.181 -0.183 0.000" group="Wing" name="mWing2Right" pivot="-0.168 -0.169 0.067" pos="-0.168 -0.169 0.067" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
+                                 <bone aliases="avatar_mWing3Right" connected="true" end="-0.171 -0.173 0.000" group="Wing" name="mWing3Right" pivot="-0.181 -0.183 0.000" pos="-0.181 -0.183 0.000" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
+                                    <bone aliases="avatar_mWing4Right" connected="true" end="-0.146 -0.132 0.000" group="Wing" name="mWing4Right" pivot="-0.171 -0.173 0.000" pos="-0.171 -0.173 0.000" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
+                                    <bone aliases="avatar_mWing4FanRight" connected="true" end="-0.068 -0.062 -0.159" group="Wing" name="mWing4FanRight" pivot="-0.171 -0.173 0.000" pos="-0.171 -0.173 0.000" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
                                  </bone>
                               </bone>
                            </bone>
@@ -200,30 +200,30 @@
             </bone>
          </bone>
       </bone>
-      <bone connected="false" end="-0.197 0.000 0.000" group="Tail" name="mTail1" pivot="-0.116 0.000 0.047" pos="-0.116 0.000 0.047" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
-         <bone connected="true" end="-0.168 0.000 0.000" group="Tail" name="mTail2" pivot="-0.197 0.000 0.000" pos="-0.197 0.000 0.000" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
-            <bone connected="true" end="-0.142 0.000 0.000" group="Tail" name="mTail3" pivot="-0.168 0.000 0.000" pos="-0.168 0.000 0.000" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
-               <bone connected="true" end="-0.112 0.000 0.000" group="Tail" name="mTail4" pivot="-0.142 0.000 0.000" pos="-0.142 0.000 0.000" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
-                  <bone connected="true" end="-0.094 0.000 0.000" group="Tail" name="mTail5" pivot="-0.112 0.000 0.000" pos="-0.112 0.000 0.000" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
-                     <bone connected="true" end="-0.089 0.000 0.000" group="Tail" name="mTail6" pivot="-0.094 0.000 0.000" pos="-0.094 0.000 0.000" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
+      <bone aliases="avatar_mTail1" connected="false" end="-0.197 0.000 0.000" group="Tail" name="mTail1" pivot="-0.116 0.000 0.047" pos="-0.116 0.000 0.047" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
+         <bone aliases="avatar_mTail2" connected="true" end="-0.168 0.000 0.000" group="Tail" name="mTail2" pivot="-0.197 0.000 0.000" pos="-0.197 0.000 0.000" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
+            <bone aliases="avatar_mTail3" connected="true" end="-0.142 0.000 0.000" group="Tail" name="mTail3" pivot="-0.168 0.000 0.000" pos="-0.168 0.000 0.000" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
+               <bone aliases="avatar_mTail4" connected="true" end="-0.112 0.000 0.000" group="Tail" name="mTail4" pivot="-0.142 0.000 0.000" pos="-0.142 0.000 0.000" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
+                  <bone aliases="avatar_mTail5" connected="true" end="-0.094 0.000 0.000" group="Tail" name="mTail5" pivot="-0.112 0.000 0.000" pos="-0.112 0.000 0.000" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
+                     <bone aliases="avatar_mTail6" connected="true" end="-0.089 0.000 0.000" group="Tail" name="mTail6" pivot="-0.094 0.000 0.000" pos="-0.094 0.000 0.000" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
                   </bone>
                </bone>
             </bone>
          </bone>
       </bone>
-      <bone connected="false" end="0.004 0.000 -0.066" group="Groin" name="mGroin" pivot="0.064 0.000 -0.097" pos="0.064 0.000 -0.097" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
-      <bone connected="false" end="-0.204 0.000 0.000" group="Limb" name="mHindLimbsRoot" pivot="-0.200 0.000 0.084" pos="-0.200 0.000 0.084" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
-         <bone connected="false" end="0.002 -0.046 -0.491" group="Limb" name="mHindLimb1Left" pivot="-0.204 0.129 -0.125" pos="-0.204 0.129 -0.125" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
-            <bone connected="true" end="-0.030 -0.003 -0.468" group="Limb" name="mHindLimb2Left" pivot="0.002 -0.046 -0.491" pos="0.002 -0.046 -0.491" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
-               <bone connected="true" end="0.112 0.000 -0.061" group="Limb" name="mHindLimb3Left" pivot="-0.030 -0.003 -0.468" pos="-0.030 -0.003 -0.468" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
-                  <bone connected="true" end="0.105 0.008 0.000" group="Limb" name="mHindLimb4Left" pivot="0.112 0.000 -0.061" pos="0.112 0.000 -0.061" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
+      <bone aliases="avatar_mGroin" connected="false" end="0.004 0.000 -0.066" group="Groin" name="mGroin" pivot="0.064 0.000 -0.097" pos="0.064 0.000 -0.097" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
+      <bone aliases="avatar_mHindLimbsRoot" connected="false" end="-0.204 0.000 0.000" group="Limb" name="mHindLimbsRoot" pivot="-0.200 0.000 0.084" pos="-0.200 0.000 0.084" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
+         <bone aliases="avatar_mHindLimb1Left" connected="false" end="0.002 -0.046 -0.491" group="Limb" name="mHindLimb1Left" pivot="-0.204 0.129 -0.125" pos="-0.204 0.129 -0.125" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
+            <bone aliases="avatar_mHindLimb2Left" connected="true" end="-0.030 -0.003 -0.468" group="Limb" name="mHindLimb2Left" pivot="0.002 -0.046 -0.491" pos="0.002 -0.046 -0.491" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
+               <bone aliases="avatar_mHindLimb3Left" connected="true" end="0.112 0.000 -0.061" group="Limb" name="mHindLimb3Left" pivot="-0.030 -0.003 -0.468" pos="-0.030 -0.003 -0.468" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
+                  <bone aliases="avatar_mHindLimb4Left" connected="true" end="0.105 0.008 0.000" group="Limb" name="mHindLimb4Left" pivot="0.112 0.000 -0.061" pos="0.112 0.000 -0.061" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
                </bone>
             </bone>
          </bone>
-         <bone connected="false" end="0.002 0.046 -0.491" group="Limb" name="mHindLimb1Right" pivot="-0.204 -0.129 -0.125" pos="-0.204 -0.129 -0.125" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
-            <bone connected="true" end="-0.030 0.003 -0.468" group="Limb" name="mHindLimb2Right" pivot="0.002 0.046 -0.491" pos="0.002 0.046 -0.491" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
-               <bone connected="true" end="0.112 0.000 -0.061" group="Limb" name="mHindLimb3Right" pivot="-0.030 0.003 -0.468" pos="-0.030 0.003 -0.468" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
-                  <bone connected="true" end="0.105 -0.008 0.000" group="Limb" name="mHindLimb4Right" pivot="0.112 0.000 -0.061" pos="0.112 0.000 -0.061" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
+         <bone aliases="avatar_mHindLimb1Right" connected="false" end="0.002 0.046 -0.491" group="Limb" name="mHindLimb1Right" pivot="-0.204 -0.129 -0.125" pos="-0.204 -0.129 -0.125" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
+            <bone aliases="avatar_mHindLimb2Right" connected="true" end="-0.030 0.003 -0.468" group="Limb" name="mHindLimb2Right" pivot="0.002 0.046 -0.491" pos="0.002 0.046 -0.491" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
+               <bone aliases="avatar_mHindLimb3Right" connected="true" end="0.112 0.000 -0.061" group="Limb" name="mHindLimb3Right" pivot="-0.030 0.003 -0.468" pos="-0.030 0.003 -0.468" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
+                  <bone aliases="avatar_mHindLimb4Right" connected="true" end="0.105 -0.008 0.000" group="Limb" name="mHindLimb4Right" pivot="0.112 0.000 -0.061" pos="0.112 0.000 -0.061" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
                </bone>
             </bone>
          </bone>
diff --git a/indra/newview/cube.dae b/indra/newview/cube.dae
new file mode 100644
index 0000000000000000000000000000000000000000..085b2c73099e6bce7e46de084b04fa5666ff3784
--- /dev/null
+++ b/indra/newview/cube.dae
@@ -0,0 +1,103 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<COLLADA xmlns="http://www.collada.org/2005/11/COLLADASchema" version="1.4.1">
+ <asset>
+  <contributor>
+   modified from https://gist.github.com/wtsnz/bfa11c40e04594b260255b5dc7956f26
+  </contributor>
+  <created>2018-10-25T16:29:03Z</created>
+  <modified>2022-02-18T00:00:00Z</modified>
+  <unit meter="1.000000"/>
+  <up_axis>Y_UP</up_axis>
+ </asset>
+
+ <library_materials>
+  <material id="Blue" name="Blue">
+   <instance_effect url="#effect_Blue"/>
+  </material>
+ </library_materials>
+
+
+ <library_effects>
+  <effect id="effect_Blue">
+   <profile_COMMON>
+    <technique sid="common">
+     <phong>
+      <ambient>
+       <color>0 0 0 1</color>
+      </ambient>
+      <diffuse>
+       <color>0.137255 0.403922 0.870588 1</color>
+      </diffuse>
+      <specular>
+       <color>0.5 0.5 0.5 1</color>
+      </specular>
+      <shininess>
+       <float>16</float>
+      </shininess>
+      <transparent opaque="A_ONE">
+       <color>0 0 0 1</color>
+      </transparent>
+      <transparency>
+       <float>1</float>
+      </transparency>
+      <index_of_refraction>
+       <float>1</float>
+      </index_of_refraction>
+     </phong>
+    </technique>
+   </profile_COMMON>
+  </effect>
+ </library_effects>
+
+
+ <library_geometries>
+  <geometry id="F1" name="default_physics_shape">
+   <mesh>
+
+    <source id="cube-vertex-positions">
+     <float_array id="ID2-array" count="72">-0.5 0.5 0.5 -0.5 -0.5 0.5 0.5 -0.5 0.5 0.5 0.5 0.5 -0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 -0.5 -0.5 0.5 -0.5 -0.5 -0.5 -0.5 0.5 -0.5 -0.5 0.5 -0.5 0.5 -0.5 -0.5 0.5 -0.5 0.5 0.5 -0.5 0.5 -0.5 -0.5 -0.5 -0.5 -0.5 -0.5 0.5 0.5 -0.5 0.5 0.5 -0.5 -0.5 0.5 0.5 -0.5 0.5 0.5 0.5 0.5 0.5 -0.5 0.5 -0.5 -0.5 -0.5 -0.5 -0.5 -0.5 0.5 -0.5 </float_array>
+     <technique_common>
+      <accessor source="#ID2-array" count="24" stride="3">
+       <param name="X" type="float"/>
+       <param name="Y" type="float"/>
+       <param name="Z" type="float"/>
+      </accessor>
+     </technique_common>
+    </source>
+
+    <vertices id="cube-vertices">
+     <input semantic="POSITION" source="#cube-vertex-positions"/>
+    </vertices>
+
+    <triangles count="12" material="geometryElement5">
+     <input semantic="VERTEX" offset="0" source="#cube-vertices"/>
+     <p>0 1 2 0 2 3 4 5 6 4 6 7 8 9 10 8 10 11 12 13 14 12 14 15 16 17 18 16 18 19 20 21 22 20 22 23 </p>
+    </triangles>
+    
+   </mesh>
+  </geometry>
+ </library_geometries>
+ <library_visual_scenes>
+
+
+  <visual_scene id="reportScene">
+  <!-- No Spaces allowed in Name -->
+   <node id="F1" name="Face1">
+    <instance_geometry url="#F1">
+     <bind_material>
+      <technique_common>
+       <instance_material symbol="geometryElement5" target="#Blue"/>
+      </technique_common>
+     </bind_material>
+    </instance_geometry>
+   </node>
+  </visual_scene>
+ </library_visual_scenes>
+
+
+ <scene>
+  <instance_visual_scene url="#reportScene"/>
+ </scene>
+
+
+</COLLADA>
diff --git a/indra/newview/featuretable.txt b/indra/newview/featuretable.txt
index f1bf8d76c2aa55f5cdbb434448f5689fdcb2c984..1ccde98283751309899d1b0241854ae8196ded7f 100644
--- a/indra/newview/featuretable.txt
+++ b/indra/newview/featuretable.txt
@@ -1,4 +1,4 @@
-version 33
+version 34
 // The version number above should be incremented IF AND ONLY IF some
 // change has been made that is sufficiently important to justify
 // resetting the graphics preferences of all users to the recommended
@@ -70,37 +70,9 @@ RenderShadowDetail			1	2
 RenderUseStreamVBO			1	1
 RenderFSAASamples			1	16
 RenderMaxTextureIndex		1	16
+RenderGLContextCoreProfile         1   1
+RenderGLMultiThreaded       1   1
 
-//
-// Low Graphics Settings (fixed function)
-//
-list LowFixedFunction
-RenderAnisotropic			1	0
-RenderAvatarCloth			1	0
-RenderAvatarLODFactor		1	0
-RenderAvatarPhysicsLODFactor 1	0
-RenderAvatarMaxNonImpostors 1   3
-RenderAvatarMaxComplexity          1	25000
-RenderAvatarVP				1	0
-RenderFarClip				1	64
-RenderFlexTimeFactor		1	0
-RenderGlowResolutionPow		1	8
-RenderLocalLights			1	0
-RenderMaxPartCount			1	0
-RenderObjectBump			1	0
-RenderReflectionDetail		1	0
-RenderTerrainDetail			1	0
-RenderTerrainLODFactor		1	1
-RenderTransparentWater		1	0
-RenderTreeLODFactor			1	0
-RenderVolumeLODFactor		1	1.125
-WindLightUseAtmosShaders	1	0
-RenderDeferred				1	0
-RenderDeferredSSAO			1	0
-RenderUseAdvancedAtmospherics 1 0
-RenderShadowDetail			1	0
-WLSkyDetail					1	48
-RenderFSAASamples			1	0
 
 //
 // Low Graphics Settings
@@ -112,7 +84,6 @@ RenderAvatarLODFactor		1	0
 RenderAvatarPhysicsLODFactor 1	0
 RenderAvatarMaxNonImpostors 1   3
 RenderAvatarMaxComplexity          1	35000
-RenderAvatarVP				1	0
 RenderFarClip				1	64
 RenderFlexTimeFactor		1	0
 RenderGlowResolutionPow		1	8
@@ -142,7 +113,6 @@ RenderAvatarCloth			1	0
 RenderAvatarLODFactor		1	0.5
 RenderAvatarMaxComplexity   1	100000
 RenderAvatarPhysicsLODFactor 1	0.75
-RenderAvatarVP				1	1
 RenderFarClip				1	96
 RenderFlexTimeFactor		1	1.0
 RenderGlowResolutionPow		1	8
@@ -172,7 +142,6 @@ RenderAvatarCloth			1	0
 RenderAvatarLODFactor		1	1.0
 RenderAvatarMaxComplexity   1	200000
 RenderAvatarPhysicsLODFactor 1	1.0
-RenderAvatarVP				1	1
 RenderFarClip				1	128
 RenderFlexTimeFactor		1	1.0
 RenderGlowResolutionPow		1	9
@@ -202,7 +171,6 @@ RenderAvatarCloth			1	0
 RenderAvatarLODFactor		1	1.0
 RenderAvatarMaxComplexity   1	250000
 RenderAvatarPhysicsLODFactor 1	1.0
-RenderAvatarVP				1	1
 RenderFarClip				1	128
 RenderFlexTimeFactor		1	1.0
 RenderGlowResolutionPow		1	9
@@ -232,7 +200,6 @@ RenderAvatarCloth			1	0
 RenderAvatarLODFactor		1	1.0
 RenderAvatarMaxComplexity   1	300000
 RenderAvatarPhysicsLODFactor 1	1.0
-RenderAvatarVP				1	1
 RenderFarClip				1	128
 RenderFlexTimeFactor		1	1.0
 RenderGlowResolutionPow		1	9
@@ -262,7 +229,6 @@ RenderAvatarCloth			1	0
 RenderAvatarLODFactor		1	1.0
 RenderAvatarMaxComplexity   1	350000
 RenderAvatarPhysicsLODFactor 1	1.0
-RenderAvatarVP				1	1
 RenderFarClip				1	128
 RenderFlexTimeFactor		1	1.0
 RenderGlowResolutionPow		1	9
@@ -291,7 +257,6 @@ RenderAnisotropic			1	1
 RenderAvatarCloth			1	1
 RenderAvatarLODFactor		1	1.0
 RenderAvatarPhysicsLODFactor 1	1.0
-RenderAvatarVP				1	1
 RenderFarClip				1	256
 RenderFlexTimeFactor		1	1.0
 RenderGlowResolutionPow		1	9
@@ -316,414 +281,45 @@ RenderFSAASamples			1	2
 // Class Unknown Hardware (unknown)
 //
 list Unknown
-RenderVBOEnable				1	0
 RenderShadowDetail			1	0
 RenderDeferred				1	0
 RenderDeferredSSAO			1	0
 RenderUseAdvancedAtmospherics 1 0
 
-//
-// Class 0 Hardware (just old)
-//
-list Class0
-RenderVBOEnable				1	1
-
-//
-// Class 1 Hardware
-//
-list Class1
-RenderVBOEnable				1	1
-
-//
-// Class 2 Hardware
-//
-list Class2
-RenderVBOEnable				1	1
-
-//
-// Class 3 Hardware
-//
-list Class3
-RenderVBOEnable				1	1
-
-//
-// Class 4 Hardware
-//
-list Class4
-RenderVBOEnable				1	1
-
-//
-// Class 5 Hardware
-//
-list Class5
-RenderVBOEnable				1	1
-
 //
 // VRAM > 512MB
 //
 list VRAMGT512
 RenderCompressTextures		1	0
 
-//
-// No Pixel Shaders available
-//
-list NoPixelShaders
-RenderAvatarVP				0	0
-RenderAvatarCloth			0	0
-RenderReflectionDetail		0	0
-WindLightUseAtmosShaders	0	0
-RenderDeferred				0	0
-RenderDeferredSSAO			0	0
-RenderShadowDetail			0	0
-RenderUseAdvancedAtmospherics 0 0
-
-//
-// No Vertex Shaders available
-//
-list NoVertexShaders
-RenderAvatarVP				0	0
-RenderAvatarCloth			0	0
-RenderReflectionDetail		0	0
-WindLightUseAtmosShaders	0	0
-RenderDeferred				0	0
-RenderDeferredSSAO			0	0
-RenderShadowDetail			0	0
-RenderUseAdvancedAtmospherics 0 0
-
-//
-// GL_ARB_map_buffer_range exists
-//
-list MapBufferRange
-RenderVBOMappingDisable		1	1
-
-
 //
 // "Default" setups for safe, low, medium, high
 //
 list safe
 RenderAnisotropic			1	0
 RenderAvatarCloth			0	0
-RenderAvatarVP				0	0
 RenderAvatarMaxNonImpostors 1	16
 RenderAvatarMaxComplexity          1	80000
 RenderObjectBump			0	0
 RenderLocalLights			1	0
 RenderMaxPartCount			1	1024
 RenderTerrainDetail 		1	0
-RenderVBOEnable				1	0
 RenderReflectionDetail		0	0
 WindLightUseAtmosShaders	0	0
 RenderDeferred				0	0
 RenderDeferredSSAO			0	0
 RenderShadowDetail			0	0
 
-//
-// CPU based feature masks
-//
-
-// 1Ghz or less (equiv)
-list CPUSlow
-RenderMaxPartCount			1	1024
-
-//
-// RAM based feature masks
-//
-list RAM256MB
-RenderObjectBump			0	0
-
-//
-// Graphics card based feature masks
-//
-list OpenGLPre15
-RenderVBOEnable				1	0
-
-list OpenGLPre30
-RenderDeferred				0	0
-RenderMaxTextureIndex		1	1
-
 list Intel
 RenderAnisotropic			1	0
-RenderVBOEnable				1	0
 RenderFSAASamples			1	0
+RenderGLMultiThreaded       1   0
+RenderGLContextCoreProfile         1   0
 
-list GeForce2
-RenderAnisotropic			1	0
-RenderMaxPartCount			1	2048
-RenderTerrainDetail			1	0
-RenderVBOEnable				1	1
-
-list SiS
-UseOcclusion				0	0
-
-
-list Intel_830M
-RenderTerrainDetail			1	0
-RenderVBOEnable				1	0
-
-list Intel_845G					
-RenderTerrainDetail			1	0
-RenderVBOEnable				1	0
-
-list Intel_855GM				
-RenderTerrainDetail			1	0
-RenderVBOEnable				1	0
-
-list Intel_865G			
-RenderTerrainDetail			1	0
-RenderVBOEnable				1	0
-
-list Intel_900		
-RenderTerrainDetail			1	0
-RenderVBOEnable				1	0
-
-list Intel_915GM	
-RenderTerrainDetail			1	0
-RenderVBOEnable				1	0
-
-list Intel_915G					
-RenderTerrainDetail			1	0
-RenderVBOEnable				1	0
-
-list Intel_945GM			
-RenderTerrainDetail			1	0
-RenderVBOEnable				1	0
-
-list Intel_945G
-RenderTerrainDetail			1	0
-RenderVBOEnable				1	0
-
-list Intel_950
-RenderTerrainDetail			1	0
-RenderVBOEnable				1	0
-
-list Intel_965
-RenderTerrainDetail			1	0
-RenderVBOEnable				1	0
-UseOcclusion				0	0
-
-list Intel_G33
-RenderTerrainDetail			1	0
-RenderVBOEnable				1	0
-
-list Intel_G45
-WindLightUseAtmosShaders		0	0
-
-list Intel_Bear_Lake	
-RenderTerrainDetail			1	0
-RenderVBOEnable				1	0
-
-list Intel_Broadwater 
-RenderTerrainDetail			1	0
-RenderVBOEnable				1	0
-
-list Intel_Brookdale	
-RenderTerrainDetail			1	0
-RenderVBOEnable				1	0
-
-list Intel_Eaglelake
-WindLightUseAtmosShaders	0	0
-
-list Intel_Montara
-RenderTerrainDetail			1	0
-RenderVBOEnable				1	0
-
-list Intel_Springdale
-RenderTerrainDetail			1	0
-RenderVBOEnable				1	0
-
-
-list ATI_FireGL_5200
-RenderVBOEnable				1	0
-WindLightUseAtmosShaders	0	0
-
-
-list ATI_Mobility_Radeon_7xxx
-RenderVBOEnable				0	0
-
-list ATI_Radeon_7xxx
-RenderVBOEnable				0	0
-
-list ATI_All-in-Wonder_Radeon
-RenderVBOEnable				0	0
-
-list ATI_All-in-Wonder_7500
-RenderVBOEnable				0	0
-
-list ATI_Mobility_Radeon_9600
-Disregard96DefaultDrawDistance	1	0
-
-
-/// tweaked ATI to 96 Draw distance
-
-list ATI_Radeon_9000
-Disregard96DefaultDrawDistance	1	0
-list ATI_Radeon_9200
-Disregard96DefaultDrawDistance	1	0
-list ATI_Radeon_9500
-Disregard96DefaultDrawDistance	1	0
-list ATI_Radeon_9600
-Disregard96DefaultDrawDistance	1	0
-
-/// tweaked ATI to 128 draw distance
-
-list ATI_Radeon_X300 
-Disregard128DefaultDrawDistance	1	0
-RenderVBOEnable				1	0
-list ATI_Radeon_X400 
-Disregard128DefaultDrawDistance	1	0
-RenderVBOEnable				1	0
-list ATI_Radeon_X500 
-Disregard128DefaultDrawDistance	1	0
-RenderVBOEnable				1	0
-list ATI_Radeon_X600 
-Disregard128DefaultDrawDistance	1	0
-RenderVBOEnable				1	0
-list ATI_Radeon_X700 
-Disregard128DefaultDrawDistance	1	0
-RenderVBOEnable				1	0
-list ATI_Radeon_X1300 
-Disregard128DefaultDrawDistance	1	0
-RenderVBOEnable				1	0
-UseStartScreen					0	0
-list ATI_Radeon_X1400 
-Disregard128DefaultDrawDistance	1	0
-RenderVBOEnable				1	0
-list ATI_Radeon_X1500 
-Disregard128DefaultDrawDistance	1	0
-RenderVBOEnable				1	0
-UseStartScreen					0	0
-list ATI_Radeon_X1600 
-Disregard128DefaultDrawDistance	1	0
-RenderVBOEnable				1	0
-list ATI_Radeon_X1700 
-Disregard128DefaultDrawDistance	1	0
-RenderVBOEnable				1	0
-list ATI_Mobility_Radeon_X1xxx
-Disregard128DefaultDrawDistance	1	0
-RenderVBOEnable				1	0
-
-list ATI_Radeon_HD_2300
-Disregard128DefaultDrawDistance	1	0
-list ATI_Radeon_HD_2400
-Disregard128DefaultDrawDistance	1	0
-list ATI_ASUS_AH24xx
-Disregard128DefaultDrawDistance	1	0
-
-
-// Avatar hardware skinning causes invisible avatars
-// on various ATI chipsets on drivers before 8.2
-
-list ATIOldDriver
-RenderAvatarVP				0	0
-RenderAvatarCloth			0	0
-RenderVBOEnable				1	0
-
-// ATI cards generally perform better when not using VBOs for streaming data
-
-list ATI
+// AMD cards generally perform better when not using VBOs for streaming data
+// AMD cards also prefer an OpenGL Compatibility Profile Context
+list AMD
 RenderUseStreamVBO			1	0
+RenderGLContextCoreProfile         1   0
 
-// Disable vertex buffer objects by default for ATI cards with little video memory
-list ATIVramLT256
-RenderVBOEnable				1	0
-
-/// Tweaked NVIDIA
-
-list NVIDIA_GeForce_FX_5100
-Disregard96DefaultDrawDistance	1	0
-list NVIDIA_GeForce_FX_5200
-Disregard96DefaultDrawDistance	1	0
-list NVIDIA_GeForce_FX_5500
-Disregard96DefaultDrawDistance	1	0
-list NVIDIA_GeForce_FX_5600
-Disregard96DefaultDrawDistance	1	0
-
-list NVIDIA_GeForce_FX_Go5100
-Disregard96DefaultDrawDistance	1	0
-list NVIDIA_GeForce_FX_Go5200
-Disregard96DefaultDrawDistance	1	0
-list NVIDIA_GeForce_FX_Go5300
-Disregard96DefaultDrawDistance	1	0
-list NVIDIA_GeForce_FX_Go5500
-Disregard96DefaultDrawDistance	1	0
-list NVIDIA_GeForce_FX_Go5600
-Disregard96DefaultDrawDistance	1	0
-
-list NVIDIA_GeForce_6100
-Disregard128DefaultDrawDistance	1	0
-list NVIDIA_GeForce_6200
-Disregard128DefaultDrawDistance	1	0
-list NVIDIA_GeForce_6500
-Disregard128DefaultDrawDistance	1	0
-list NVIDIA_GeForce_6600
-Disregard128DefaultDrawDistance	1	0
-
-list NVIDIA_G73
-Disregard128DefaultDrawDistance	1	0
-
-list NVIDIA_GeForce_Go_6100
-RenderVBOEnable				1	0
-Disregard128DefaultDrawDistance	1	0
-list NVIDIA_GeForce_Go_6200
-RenderVBOEnable				1	0
-Disregard128DefaultDrawDistance	1	0
-list NVIDIA_GeForce_Go_6500
-RenderVBOEnable				1	0
-Disregard128DefaultDrawDistance	1	0
-list NVIDIA_GeForce_Go_6600
-RenderVBOEnable				1	0
-Disregard128DefaultDrawDistance	1	0
-list NVIDIA_GeForce_Go_6700
-RenderVBOEnable				1	0
-Disregard128DefaultDrawDistance	1	0
-list NVIDIA_GeForce_Go_6800
-RenderVBOEnable				1	0
-Disregard128DefaultDrawDistance	1	0
-list NVIDIA_GeForce_Go_6
-RenderVBOEnable				1	0
-Disregard128DefaultDrawDistance	1	0
-
-list NVIDIA_GeForce_7000
-RenderShaderLightingMaxLevel	1	2
-list NVIDIA_GeForce_7100
-RenderShaderLightingMaxLevel	1	2
-list NVIDIA_GeForce_7200
-Disregard128DefaultDrawDistance	1	0
-RenderShaderLightingMaxLevel	1	2
-list NVIDIA_GeForce_7300
-Disregard128DefaultDrawDistance	1	0
-RenderShaderLightingMaxLevel	1	2
-list NVIDIA_GeForce_7400
-Disregard128DefaultDrawDistance	1	0
-RenderShaderLightingMaxLevel	1	2
-list NVIDIA_GeForce_7500
-RenderShaderLightingMaxLevel	1	2
-list NVIDIA_GeForce_7600
-RenderShaderLightingMaxLevel	1	2
-list NVIDIA_GeForce_7700
-RenderShaderLightingMaxLevel	1	2
-list NVIDIA_GeForce_7800
-RenderShaderLightingMaxLevel	1	2
-list NVIDIA_GeForce_7900
-RenderShaderLightingMaxLevel	1	2
-
-list NVIDIA_GeForce_Go_7200
-Disregard128DefaultDrawDistance	1	0
-RenderShaderLightingMaxLevel	1	2
-list NVIDIA_GeForce_Go_7300
-Disregard128DefaultDrawDistance	1	0
-RenderShaderLightingMaxLevel	1	2
-list NVIDIA_GeForce_Go_7300_LE
-RenderShaderLightingMaxLevel	1	2
-list NVIDIA_GeForce_Go_7400
-Disregard128DefaultDrawDistance	1	0
-RenderShaderLightingMaxLevel	1	2
-list NVIDIA_GeForce_Go_7600
-RenderShaderLightingMaxLevel	1	2
-list NVIDIA_GeForce_Go_7700
-RenderShaderLightingMaxLevel	1	2
-list NVIDIA_GeForce_Go_7800
-RenderShaderLightingMaxLevel	1	2
-list NVIDIA_GeForce_Go_7900
-RenderShaderLightingMaxLevel	1	2
 
diff --git a/indra/newview/featuretable_mac.txt b/indra/newview/featuretable_mac.txt
index bac6fd5708218a627bffcbd2a1b0a4656786b17e..c9efd89cc87d7dc6802e35ea52ea0fdf19c9224b 100644
--- a/indra/newview/featuretable_mac.txt
+++ b/indra/newview/featuretable_mac.txt
@@ -1,4 +1,4 @@
-version 37
+version 38
 // The version number above should be incremented IF AND ONLY IF some
 // change has been made that is sufficiently important to justify
 // resetting the graphics preferences of all users to the recommended
@@ -70,37 +70,8 @@ RenderShadowDetail			1	2
 RenderUseStreamVBO			1	1
 RenderFSAASamples			1	16
 RenderMaxTextureIndex		1	16
-
-//
-// Low Graphics Settings (fixed function)
-//
-list LowFixedFunction
-RenderAnisotropic			1	0
-RenderAvatarCloth			1	0
-RenderAvatarLODFactor		1	0
-RenderAvatarPhysicsLODFactor 1	0
-RenderAvatarMaxNonImpostors 1   3
-RenderAvatarMaxComplexity          1	25000
-RenderAvatarVP				1	0
-RenderFarClip				1	64
-RenderFlexTimeFactor		1	0
-RenderGlowResolutionPow		1	8
-RenderLocalLights			1	0
-RenderMaxPartCount			1	0
-RenderObjectBump			1	0
-RenderReflectionDetail		1	0
-RenderTerrainDetail			1	0
-RenderTerrainLODFactor		1	1
-RenderTransparentWater		1	0
-RenderTreeLODFactor			1	0
-RenderVolumeLODFactor		1	0.5
-WindLightUseAtmosShaders	1	0
-RenderDeferred				1	0
-RenderDeferredSSAO			1	0
-RenderUseAdvancedAtmospherics 1 0
-RenderShadowDetail			1	0
-WLSkyDetail					1	48
-RenderFSAASamples			1	0
+RenderGLContextCoreProfile         1   0
+RenderGLMultiThreaded       1   0
 
 //
 // Low Graphics Settings
@@ -112,7 +83,6 @@ RenderAvatarLODFactor		1	0
 RenderAvatarPhysicsLODFactor 1	0
 RenderAvatarMaxNonImpostors 1   3
 RenderAvatarMaxComplexity          1	35000
-RenderAvatarVP				1	0
 RenderFarClip				1	64
 RenderFlexTimeFactor		1	0
 RenderGlowResolutionPow		1	8
@@ -142,7 +112,6 @@ RenderAvatarCloth			1	0
 RenderAvatarLODFactor		1	0.5
 RenderAvatarMaxComplexity   1	100000
 RenderAvatarPhysicsLODFactor 1	0.75
-RenderAvatarVP				1	1
 RenderFarClip				1	96
 RenderFlexTimeFactor		1	1.0
 RenderGlowResolutionPow		1	8
@@ -172,7 +141,6 @@ RenderAvatarCloth			1	0
 RenderAvatarLODFactor		1	1.0
 RenderAvatarMaxComplexity   1	200000
 RenderAvatarPhysicsLODFactor 1	1.0
-RenderAvatarVP				1	1
 RenderFarClip				1	128
 RenderFlexTimeFactor		1	1.0
 RenderGlowResolutionPow		1	9
@@ -202,7 +170,6 @@ RenderAvatarCloth			1	0
 RenderAvatarLODFactor		1	1.0
 RenderAvatarMaxComplexity   1	250000
 RenderAvatarPhysicsLODFactor 1	1.0
-RenderAvatarVP				1	1
 RenderFarClip				1	128
 RenderFlexTimeFactor		1	1.0
 RenderGlowResolutionPow		1	9
@@ -232,7 +199,6 @@ RenderAvatarCloth			1	0
 RenderAvatarLODFactor		1	1.0
 RenderAvatarMaxComplexity   1	300000
 RenderAvatarPhysicsLODFactor 1	1.0
-RenderAvatarVP				1	1
 RenderFarClip				1	128
 RenderFlexTimeFactor		1	1.0
 RenderGlowResolutionPow		1	9
@@ -262,7 +228,6 @@ RenderAvatarCloth			1	0
 RenderAvatarLODFactor		1	1.0
 RenderAvatarMaxComplexity   1	350000
 RenderAvatarPhysicsLODFactor 1	1.0
-RenderAvatarVP				1	1
 RenderFarClip				1	128
 RenderFlexTimeFactor		1	1.0
 RenderGlowResolutionPow		1	9
@@ -291,7 +256,6 @@ RenderAnisotropic			1	1
 RenderAvatarCloth			1	1
 RenderAvatarLODFactor		1	1.0
 RenderAvatarPhysicsLODFactor 1	1.0
-RenderAvatarVP				1	1
 RenderFarClip				1	256
 RenderFlexTimeFactor		1	1.0
 RenderGlowResolutionPow		1	9
@@ -316,73 +280,11 @@ RenderFSAASamples			1	2
 // Class Unknown Hardware (unknown)
 //
 list Unknown
-RenderVBOEnable				1	0
 RenderShadowDetail			1	0
 RenderDeferred				1	0
 RenderDeferredSSAO			1	0
 RenderUseAdvancedAtmospherics 1 0
 
-//
-// Class 0 Hardware (just old)
-//
-list Class0
-RenderVBOEnable				1	1
-
-//
-// Class 1 Hardware
-//
-list Class1
-RenderVBOEnable				1	1
-
-//
-// Class 2 Hardware
-//
-list Class2
-RenderVBOEnable				1	1
-
-//
-// Class 3 Hardware
-//
-list Class3
-RenderVBOEnable				1	1
-
-//
-// Class 4 Hardware
-//
-list Class4
-RenderVBOEnable				1	1
-
-//
-// Class 5 Hardware
-//
-list Class5
-RenderVBOEnable				1	1
-
-//
-// No Pixel Shaders available
-//
-list NoPixelShaders
-RenderAvatarVP				0	0
-RenderAvatarCloth			0	0
-RenderReflectionDetail		0	0
-WindLightUseAtmosShaders	0	0
-RenderDeferred				0	0
-RenderDeferredSSAO			0	0
-RenderUseAdvancedAtmospherics 0 0
-RenderShadowDetail			0	0
-
-//
-// No Vertex Shaders available
-//
-list NoVertexShaders
-RenderAvatarVP				0	0
-RenderAvatarCloth			0	0
-RenderReflectionDetail		0	0
-WindLightUseAtmosShaders	0	0
-RenderDeferred				0	0
-RenderDeferredSSAO			0	0
-RenderUseAdvancedAtmospherics 0 0
-RenderShadowDetail			0	0
 
 //
 // VRAM > 512MB
@@ -396,14 +298,12 @@ RenderCompressTextures		1	0
 list safe
 RenderAnisotropic			1	0
 RenderAvatarCloth			0	0
-RenderAvatarVP				0	0
 RenderAvatarMaxNonImpostors 1	16
 RenderAvatarMaxComplexity          1	80000
 RenderObjectBump			0	0
 RenderLocalLights			1	0
 RenderMaxPartCount			1	1024
 RenderTerrainDetail 		1	0
-RenderVBOEnable				1	0
 RenderReflectionDetail		0	0
 WindLightUseAtmosShaders	0	0
 RenderDeferred				0	0
@@ -411,31 +311,10 @@ RenderDeferredSSAO			0	0
 RenderUseAdvancedAtmospherics 0 0
 RenderShadowDetail			0	0
 
-//
-// CPU based feature masks
-//
-
-// 1Ghz or less (equiv)
-list CPUSlow
-RenderMaxPartCount			1	1024
-
-//
-// RAM based feature masks
-//
-list RAM256MB
-RenderObjectBump			0	0
-
-//
-// Graphics card based feature masks
-//
-list OpenGLPre15
-RenderVBOEnable				1	0
-
-
 list TexUnit8orLess
 RenderDeferredSSAO			0	0
 
-list ATI
+list AMD
 RenderDeferredSSAO			1	0
 
 list Intel
@@ -443,195 +322,6 @@ RenderAnisotropic			1	0
 RenderLocalLights			1	0
 RenderFSAASamples			1	0
 
-list GeForce2
-RenderAnisotropic			1	0
-RenderLocalLights			1	0
-RenderMaxPartCount			1	2048
-RenderTerrainDetail			1	0
-RenderVBOEnable				1	1
-
-list Intel_830M
-RenderTerrainDetail			1	0
-RenderVBOEnable				1	0
-
-list Intel_845G					
-RenderTerrainDetail			1	0
-RenderVBOEnable				1	0
-
-list Intel_855GM				
-RenderTerrainDetail			1	0
-RenderVBOEnable				1	0
-
-list Intel_865G			
-RenderTerrainDetail			1	0
-RenderVBOEnable				1	0
-
-list Intel_900		
-RenderTerrainDetail			1	0
-RenderVBOEnable				1	0
-
-list Intel_915GM	
-RenderTerrainDetail			1	0
-RenderVBOEnable				1	0
-
-list Intel_915G					
-RenderTerrainDetail			1	0
-RenderVBOEnable				1	0
-
-list Intel_945GM			
-RenderTerrainDetail			1	0
-RenderVBOEnable				1	0
-
-list Intel_945G
-RenderTerrainDetail			1	0
-RenderVBOEnable				1	0
-
-list Intel_950
-RenderTerrainDetail			1	0
-RenderVBOEnable				1	0
-RenderGround				1	0
-
-list Intel_965
-RenderTerrainDetail			1	0
-RenderVBOEnable				1	0
-UseOcclusion				0	0
-
-list Intel_G33
-RenderTerrainDetail			1	0
-RenderVBOEnable				1	0
-
-list Intel_Bear_Lake	
-RenderTerrainDetail			1	0
-RenderVBOEnable				1	0
-
-list Intel_Broadwater 
-RenderTerrainDetail			1	0
-RenderVBOEnable				1	0
-
-list Intel_Brookdale	
-RenderTerrainDetail			1	0
-RenderVBOEnable				1	0
-
-list Intel_X3100
-WindLightUseAtmosShaders	0	0
-
-list Intel_Montara
-RenderTerrainDetail			1	0
-RenderVBOEnable				1	0
-
-list Intel_Springdale
-RenderTerrainDetail			1	0
-RenderVBOEnable				1	0
-
-list ATI_Mobility_Radeon_9600
-Disregard96DefaultDrawDistance	1	0
-
-list NVIDIA_GeForce_8600
-RenderTextureMemoryMultiple			1	1	
-UseOcclusion				0	0
-
-/// tweaked ATI to 96 Draw distance
-
-list ATI_Radeon_9000
-Disregard96DefaultDrawDistance	1	0
-list ATI_Radeon_9200
-Disregard96DefaultDrawDistance	1	0
-list ATI_Radeon_9500
-Disregard96DefaultDrawDistance	1	0
-list ATI_Radeon_9600
-Disregard96DefaultDrawDistance	1	0
-
-/// tweaked ATI to 128 draw distance
-
-list ATI_Radeon_X300 
-Disregard128DefaultDrawDistance	1	0
-list ATI_Radeon_X400 
-Disregard128DefaultDrawDistance	1	0
-list ATI_Radeon_X500 
-Disregard128DefaultDrawDistance	1	0
-list ATI_Radeon_X600 
-Disregard128DefaultDrawDistance	1	0
-list ATI_Radeon_X700 
-Disregard128DefaultDrawDistance	1	0
-list ATI_Radeon_X1300 
-Disregard128DefaultDrawDistance	1	0
-list ATI_Radeon_X1400 
-Disregard128DefaultDrawDistance	1	0
-list ATI_Radeon_X1500 
-Disregard128DefaultDrawDistance	1	0
-list ATI_Radeon_X1600 
-Disregard128DefaultDrawDistance	1	0
-list ATI_Radeon_X1700 
-Disregard128DefaultDrawDistance	1	0
-list ATI_Mobility_Radeon_X1xxx
-Disregard128DefaultDrawDistance	1	0
-
-/// Tweaked NVIDIA
-
-list NVIDIA_GeForce_FX_5100
-Disregard96DefaultDrawDistance	1	0
-list NVIDIA_GeForce_FX_5200
-Disregard96DefaultDrawDistance	1	0
-list NVIDIA_GeForce_FX_5500
-Disregard96DefaultDrawDistance	1	0
-
-list NVIDIA_GeForce_FX_Go5100
-Disregard96DefaultDrawDistance	1	0
-list NVIDIA_GeForce_FX_Go5200
-Disregard96DefaultDrawDistance	1	0
-list NVIDIA_GeForce_FX_Go5300
-Disregard96DefaultDrawDistance	1	0
-list NVIDIA_GeForce_FX_Go5500
-Disregard96DefaultDrawDistance	1	0
-list NVIDIA_GeForce_FX_Go5600
-Disregard96DefaultDrawDistance	1	0
-
-list NVIDIA_GeForce_6100
-Disregard128DefaultDrawDistance	1	0
-list NVIDIA_GeForce_6200
-Disregard128DefaultDrawDistance	1	0
-list NVIDIA_GeForce_6500
-Disregard128DefaultDrawDistance	1	0
-list NVIDIA_GeForce_6600
-Disregard128DefaultDrawDistance	1	0
-
-
-list NVIDIA_GeForce_Go_6100
-RenderVBOEnable				1	0
-Disregard128DefaultDrawDistance	1	0
-list NVIDIA_GeForce_Go_6200
-RenderVBOEnable				1	0
-Disregard128DefaultDrawDistance	1	0
-list NVIDIA_GeForce_Go_6500
-RenderVBOEnable				1	0
-Disregard128DefaultDrawDistance	1	0
-list NVIDIA_GeForce_Go_6600
-RenderVBOEnable				1	0
-Disregard128DefaultDrawDistance	1	0
-list NVIDIA_GeForce_Go_6700
-RenderVBOEnable				1	0
-Disregard128DefaultDrawDistance	1	0
-list NVIDIA_GeForce_Go_6800
-RenderVBOEnable				1	0
-Disregard128DefaultDrawDistance	1	0
-list NVIDIA_GeForce_Go_6
-RenderVBOEnable				1	0
-Disregard128DefaultDrawDistance	1	0
-
-list NVIDIA_GeForce_7200
-Disregard128DefaultDrawDistance	1	0
-list NVIDIA_GeForce_7300
-Disregard128DefaultDrawDistance	1	0
-list NVIDIA_GeForce_7400
-Disregard128DefaultDrawDistance	1	0
-
-list NVIDIA_GeForce_Go_7200
-Disregard128DefaultDrawDistance	1	0
-list NVIDIA_GeForce_Go_7300
-Disregard128DefaultDrawDistance	1	0
-list NVIDIA_GeForce_Go_7400
-Disregard128DefaultDrawDistance	1	0
-
 list OSX_10_6_8
 RenderDeferred 0 0
 
diff --git a/indra/newview/installers/windows/installer_template.nsi b/indra/newview/installers/windows/installer_template.nsi
index 7513908cb4f022094c802ebe716d89f49effb7f2..60e26274cbe87226f2d041e62d32304f18840f0d 100644
--- a/indra/newview/installers/windows/installer_template.nsi
+++ b/indra/newview/installers/windows/installer_template.nsi
@@ -351,11 +351,29 @@ DeleteRegValue HKEY_CLASSES_ROOT "Applications\$VIEWER_EXE" "IsHostApp"
 DeleteRegValue HKEY_CLASSES_ROOT "Applications\$VIEWER_EXE" "NoStartPage"
 ClearErrors
 
+INSTALL_FILES_START:
+
 Call RemoveProgFilesOnInst		# Remove existing files to prevent certain errors when running the new version of the viewer
 
 # This placeholder is replaced by the complete list of all the files in the installer, by viewer_manifest.py
 %%INSTALL_FILES%%
 
+IfErrors 0 INSTALL_FILES_DONE
+  StrCmp $SKIP_DIALOGS "true" INSTALL_FILES_DONE
+	MessageBox MB_ABORTRETRYIGNORE $(ErrorSecondLifeInstallRetry) IDABORT INSTALL_FILES_CANCEL IDRETRY INSTALL_FILES_START
+    # MB_ABORTRETRYIGNORE does not accept IDIGNORE
+    Goto INSTALL_FILES_DONE
+
+INSTALL_FILES_CANCEL:
+  # We are quiting, cleanup.
+  # Silence warnings from RemoveProgFilesOnInst.
+  StrCpy $SKIP_DIALOGS "true"
+  Call RemoveProgFilesOnInst
+  MessageBox MB_OK $(ErrorSecondLifeInstallSupport)
+  Quit
+
+INSTALL_FILES_DONE:
+
 # Pass the installer's language to the client to use as a default
 StrCpy $SHORTCUT_LANG_PARAM "--set InstallLanguage $(LanguageCode)"
 
@@ -622,7 +640,9 @@ Function RemoveProgFilesOnInst
 Push $0
 StrCpy $0 0
 
-PREINSTALLREMOVE:
+ClearErrors
+
+PREINSTALL_REMOVE:
 
 # Remove old SecondLife.exe to invalidate any old shortcuts to it that may be in non-standard locations. See MAINT-3575
 Delete "$INSTDIR\$INSTEXE"
@@ -642,17 +662,17 @@ RMDir /r "$INSTDIR\llplugin"
 
 IntOp $0 $0 + 1
 
-IfErrors 0 PREINSTALLDONE
-  IntCmp $0 1 PREINSTALLREMOVE #try again once
-    StrCmp $SKIP_DIALOGS "true" PREINSTALLDONE
-      MessageBox MB_ABORTRETRYIGNORE $(CloseSecondLifeInstRM) IDABORT PREINSTALLFAIL IDRETRY PREINSTALLREMOVE
+IfErrors 0 PREINSTALL_DONE
+  IntCmp $0 1 PREINSTALL_REMOVE #try again once
+    StrCmp $SKIP_DIALOGS "true" PREINSTALL_DONE
+      MessageBox MB_ABORTRETRYIGNORE $(CloseSecondLifeInstRM) IDABORT PREINSTALL_FAIL IDRETRY PREINSTALL_REMOVE
       # MB_ABORTRETRYIGNORE does not accept IDIGNORE
-      Goto PREINSTALLDONE
+      Goto PREINSTALL_DONE
 
-PREINSTALLFAIL:
+PREINSTALL_FAIL:
     Quit
 
-PREINSTALLDONE:
+PREINSTALL_DONE:
 
 # We are no longer including release notes with the viewer, so remove them.
 Delete "$SMPROGRAMS\$INSTSHORTCUT\SL Release Notes.lnk"
diff --git a/indra/newview/installers/windows/lang_da.nsi b/indra/newview/installers/windows/lang_da.nsi
index 648ddbfb8502e1bee254d26c8c01ce8e40d1026c..73f23086be22efa016f61757a0246ad56a929a6c 100644
Binary files a/indra/newview/installers/windows/lang_da.nsi and b/indra/newview/installers/windows/lang_da.nsi differ
diff --git a/indra/newview/installers/windows/lang_de.nsi b/indra/newview/installers/windows/lang_de.nsi
index 188c30197a4e7dc7dd6b0e2e96d37986b8cf8d36..7cc70e4c76cb2ad43058358ba5f000654ba1184a 100755
--- a/indra/newview/installers/windows/lang_de.nsi
+++ b/indra/newview/installers/windows/lang_de.nsi
@@ -73,6 +73,10 @@ LangString CloseSecondLifeUnInstMB ${LANG_GERMAN} "Second Life kann nicht entfer
 ; CheckNetworkConnection
 LangString CheckNetworkConnectionDP ${LANG_GERMAN} "Prüfe Netzwerkverbindung..."
 
+; error during installation
+LangString ErrorSecondLifeInstallRetry ${LANG_GERMAN} "Second Life konnte nicht korrekt installiert werden, einige Dateien wurden eventuell nicht korrekt von der Installationroutine kopiert."
+LangString ErrorSecondLifeInstallSupport ${LANG_GERMAN} "Bitte laden Sie den Viewer erneut von https://secondlife.com/support/downloads/ und versuchen Sie die Installation erneut. Sollte das Problem weiterhin bestehen, dann kontaktieren Sie unseren Support unter https://support.secondlife.com."
+
 ; ask to remove user's data files
 LangString RemoveDataFilesMB ${LANG_GERMAN} "Möchten Sie alle anderen zu Second Life gehörigen Dateien ebenfalls ENTFERNEN?$\n$\nWir empfehlen, die Einstellungen und Cache-Dateien zu behalten, wenn Sie andere Versionen von Second Life installiert haben oder eine Deinstallation durchführen, um Second Life auf eine neuere Version zu aktualisieren."
 
diff --git a/indra/newview/installers/windows/lang_en-us.nsi b/indra/newview/installers/windows/lang_en-us.nsi
index 0639d51e10fc489a37312db071c7177bf4c151c6..2eaf97d0238769ce2f41e23543dc1a6ce037ca32 100644
Binary files a/indra/newview/installers/windows/lang_en-us.nsi and b/indra/newview/installers/windows/lang_en-us.nsi differ
diff --git a/indra/newview/installers/windows/lang_es.nsi b/indra/newview/installers/windows/lang_es.nsi
index ee30651a38983aec3b199fb9f7c27adf122d595d..364cc9f67e2f9aa7b05498d848d38b56ab22e429 100755
Binary files a/indra/newview/installers/windows/lang_es.nsi and b/indra/newview/installers/windows/lang_es.nsi differ
diff --git a/indra/newview/installers/windows/lang_fr.nsi b/indra/newview/installers/windows/lang_fr.nsi
index 7cd90ec3148fdd30e01e9c2aee2408511618eb67..2f34c0c87a1552dd0632baf63dd53cc9bf1edf7b 100755
Binary files a/indra/newview/installers/windows/lang_fr.nsi and b/indra/newview/installers/windows/lang_fr.nsi differ
diff --git a/indra/newview/installers/windows/lang_it.nsi b/indra/newview/installers/windows/lang_it.nsi
index 194062da9a8ea42fb5bb5265b974764fdb9d263e..51214d3a9ce88d5a594a6ab02ea3b8f4b09af8e2 100755
Binary files a/indra/newview/installers/windows/lang_it.nsi and b/indra/newview/installers/windows/lang_it.nsi differ
diff --git a/indra/newview/installers/windows/lang_ja.nsi b/indra/newview/installers/windows/lang_ja.nsi
index a54005ba1466c4e82247fa46d144ad9037b00262..296703d1a3e94080fe18709d1e5ac3031887cde7 100755
Binary files a/indra/newview/installers/windows/lang_ja.nsi and b/indra/newview/installers/windows/lang_ja.nsi differ
diff --git a/indra/newview/installers/windows/lang_pl.nsi b/indra/newview/installers/windows/lang_pl.nsi
index 355d806866959266519b0c3069ac600ff23a0c29..299645bbb78010298d43366cfa5dd3299081a096 100644
Binary files a/indra/newview/installers/windows/lang_pl.nsi and b/indra/newview/installers/windows/lang_pl.nsi differ
diff --git a/indra/newview/installers/windows/lang_pt-br.nsi b/indra/newview/installers/windows/lang_pt-br.nsi
index 97f5d2b44a946ea8d58ae8eec42a1a966d4d30a3..542c8654b5bffbe4d6f57a90c878c329ce7eb997 100755
Binary files a/indra/newview/installers/windows/lang_pt-br.nsi and b/indra/newview/installers/windows/lang_pt-br.nsi differ
diff --git a/indra/newview/installers/windows/lang_ru.nsi b/indra/newview/installers/windows/lang_ru.nsi
index 65a9f4846d42a2331b25181fe99750e6e7e7682c..4e53a4957d49d2cf9b11df0b1ac0849a3101dfaa 100755
Binary files a/indra/newview/installers/windows/lang_ru.nsi and b/indra/newview/installers/windows/lang_ru.nsi differ
diff --git a/indra/newview/installers/windows/lang_tr.nsi b/indra/newview/installers/windows/lang_tr.nsi
index e71886cc6609f89a090c31a2c5d9c6cb714dc907..bae5029ad1ce56a2fd347c95de656848400c052e 100755
Binary files a/indra/newview/installers/windows/lang_tr.nsi and b/indra/newview/installers/windows/lang_tr.nsi differ
diff --git a/indra/newview/installers/windows/lang_zh.nsi b/indra/newview/installers/windows/lang_zh.nsi
index f5f0c6cbdf6539d8683151de663a23a58ede11c1..7922d9df5228d652bf08955f00c0eb62b6794965 100755
Binary files a/indra/newview/installers/windows/lang_zh.nsi and b/indra/newview/installers/windows/lang_zh.nsi differ
diff --git a/indra/newview/licenses-mac.txt b/indra/newview/licenses-mac.txt
index d0747ccd0309c4221c900836f299879e9af6e08b..fba6a55da345572ae009a227a711e1832a22d7df 100644
--- a/indra/newview/licenses-mac.txt
+++ b/indra/newview/licenses-mac.txt
@@ -693,3 +693,29 @@ From Vivox:
      Attn: customer support 
      40 Speen Street Suite 402 
      Framingham, MA 01701 
+
+
+=============
+meshoptimizer
+=============
+MIT License
+
+Copyright (c) 2016-2021 Arseny Kapoulkine
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/indra/newview/licenses-win32.txt b/indra/newview/licenses-win32.txt
index 98edd35beaaf6b09f0a01c6f95428b4b2c6a001e..837d92139d5c9a5f48aff4d423b0aa854e5702b9 100644
--- a/indra/newview/licenses-win32.txt
+++ b/indra/newview/licenses-win32.txt
@@ -770,71 +770,29 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-
 =============
-GLOD license
+meshoptimizer
 =============
-The GLOD Open-Source License   Version 1.0                June 16, 2004
+MIT License
 
-Copyright (C) 2003-04 Jonathan Cohen, Nat Duca, Chris Niski, Johns 
-Hopkins University and David Luebke, Brenden Schubert, University of 
-Virginia. All rights reserved.
+Copyright (c) 2016-2021 Arseny Kapoulkine
 
-Redistribution and use in source and binary forms, with or without
-modification, is permitted provided that the following conditions are
-met:
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
 
-1. Redistributions of source code must retain the above copyright
-   notice, this list of conditions and the following disclaimer and
-   request.
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
 
-2. Redistributions in binary form must reproduce the above copyright
-   notice, this list of conditions and the following disclaimer and
-   request in the documentation and/or other materials provided with
-   the distribution.
-
-3. The name "GLOD" must not be used to endorse or promote products
-   derived from this software without prior written permission.
-
-4. Redistributions of any modified version of this source, whether in
-   source or binary form , must include a form of the following
-   acknowledgment: "This product is derived from the GLOD library,
-   which is available from http://www.cs.jhu.edu/~graphics/GLOD."
-
-5. Redistributions of any modified version of this source in binary
-   form must provide, free of charge, access to the modified version
-   of the code.
-
-6. This license shall be governed by and construed and enforced in
-   accordance with the laws of the State of Maryland, without
-   reference to its conflicts of law provisions. The exclusive
-   jurisdiction and venue for all legal actions relating to this
-   license shall be in courts of competent subject matter jurisdiction
-   located in the State of Maryland.
-
-TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, GLOD IS PROVIDED
-UNDER THIS LICENSE ON AN AS IS BASIS, WITHOUT WARRANTY OF ANY KIND,
-EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES
-THAT GLOD IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR
-PURPOSE OR NON-INFRINGING. ALL WARRANTIES ARE DISCLAIMED AND THE
-ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE CODE IS WITH
-YOU. SHOULD ANY CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT THE
-COPYRIGHT HOLDER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY
-NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY
-CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF ANY CODE IS
-AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER.
-
-TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, IN NO EVENT SHALL
-THE COPYRIGHT HOLDER OR ANY OTHER CONTRIBUTOR BE LIABLE FOR ANY
-SPECIAL, INCIDENTAL, INDIRECT, OR CONSEQUENTIAL DAMAGES FOR LOSS OF
-PROFITS, REVENUE, OR FOR LOSS OF INFORMATION OR ANY OTHER LOSS.
-
-YOU EXPRESSLY AGREE TO FOREVER INDEMNIFY, DEFEND AND HOLD HARMLESS THE
-COPYRIGHT HOLDERS AND CONTRIBUTORS OF GLOD AGAINST ALL CLAIMS,
-DEMANDS, SUITS OR OTHER ACTIONS ARISING DIRECTLY OR INDIRECTLY FROM
-YOUR ACCEPTANCE AND USE OF GLOD.
-
-Although NOT REQUIRED, we would appreciate it if active users of GLOD
-put a link on their web site to the GLOD web site when possible.
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
 
 
diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp
index 9cae1dd930f5cf4c765c0778833857fb33eec6f2..5250369813de200833d39a9d3b9b7dfb7ca20b05 100644
--- a/indra/newview/llagent.cpp
+++ b/indra/newview/llagent.cpp
@@ -96,6 +96,7 @@
 #include "stringize.h"
 #include "boost/foreach.hpp"
 #include "llcorehttputil.h"
+#include "lluiusage.h"
 
 using namespace LLAvatarAppearanceDefines;
 
@@ -574,6 +575,8 @@ void LLAgent::ageChat()
 //-----------------------------------------------------------------------------
 void LLAgent::moveAt(S32 direction, bool reset)
 {
+	LLUIUsage::instance().logCommand("Agent.MoveAt");
+	
 	mMoveTimer.reset();
 	LLFirstUse::notMoving(false);
 
@@ -713,6 +716,15 @@ void LLAgent::moveYaw(F32 mag, bool reset_view)
 		setControlFlags(AGENT_CONTROL_YAW_NEG);
 	}
 
+    U32 mask = AGENT_CONTROL_YAW_POS | AGENT_CONTROL_YAW_NEG;
+    if ((getControlFlags() & mask) == mask)
+    {
+        // Rotation into both directions should cancel out
+        // But keep sending controls to simulator,
+        // it's needed for script based controls
+        gAgentCamera.setYawKey(0);
+    }
+
     if (reset_view)
 	{
         gAgentCamera.resetView();
@@ -1481,7 +1493,7 @@ void LLAgent::resetControlFlags()
 //-----------------------------------------------------------------------------
 void LLAgent::setAFK()
 {
-	if (!gAgent.getRegion())
+	if (gNonInteractive || !gAgent.getRegion())
 	{
 		// Don't set AFK if we're not talking to a region yet.
 		return;
@@ -1988,7 +2000,8 @@ void LLAgent::propagate(const F32 dt)
 //-----------------------------------------------------------------------------
 void LLAgent::updateAgentPosition(const F32 dt, const F32 yaw_radians, const S32 mouse_x, const S32 mouse_y)
 {
-	if (mMoveTimer.getStarted() && mMoveTimer.getElapsedTimeF32() > gSavedSettings.getF32("NotMovingHintTimeout"))
+    static LLCachedControl<F32> hint_timeout(gSavedSettings, "NotMovingHintTimeout");
+	if (mMoveTimer.getStarted() && mMoveTimer.getElapsedTimeF32() > hint_timeout)
 	{
 		LLFirstUse::notMoving();
 	}
@@ -2004,6 +2017,27 @@ void LLAgent::updateAgentPosition(const F32 dt, const F32 yaw_radians, const S32
 	//
 
 	gAgentCamera.updateLookAt(mouse_x, mouse_y);
+
+    // When agent has no parents, position updates come from setPositionAgent()
+    // But when agent has a parent (ex: is seated), position remains unchanged
+    // relative to parent and no parent's position update trigger
+    // setPositionAgent().
+    // But EEP's sky track selection still needs an update if agent has a parent
+    // and parent moves (ex: vehicles).
+    if (isAgentAvatarValid()
+        && gAgentAvatarp->getParent()
+        && !mOnPositionChanged.empty()
+        )
+    {
+        LLVector3d new_position = getPositionGlobal();
+        if ((mLastTestGlobal - new_position).lengthSquared() > 1.0)
+        {
+            // If the position has changed by more than 1 meter since the last time we triggered.
+            // filters out some noise. 
+            mLastTestGlobal = new_position;
+            mOnPositionChanged(mFrameAgent.getOrigin(), new_position);
+        }
+    }
 }
 
 // friends and operators
@@ -2159,7 +2193,8 @@ void LLAgent::endAnimationUpdateUI()
 		LLNavigationBar::getInstance()->setVisible(TRUE && gSavedSettings.getBOOL("ShowNavbarNavigationPanel"));
 		gStatusBar->setVisibleForMouselook(true);
 
-		if (gSavedSettings.getBOOL("ShowMiniLocationPanel"))
+        static LLCachedControl<bool> show_mini_location_panel(gSavedSettings, "ShowMiniLocationPanel");
+		if (show_mini_location_panel)
 		{
 			LLPanelTopInfoBar::getInstance()->setVisible(TRUE);
 		}
@@ -3901,10 +3936,6 @@ bool LLAgent::teleportCore(bool is_local)
 	// yet if the teleport will succeed.  Look in 
 	// process_teleport_location_reply
 
-	// close the map panel so we can see our destination.
-	// we don't close search floater, see EXT-5840.
-	LLFloaterReg::hideInstance("world_map");
-
 	// hide land floater too - it'll be out of date
 	LLFloaterReg::hideInstance("about_land");
 
@@ -3998,6 +4029,7 @@ void LLAgent::startTeleportRequest()
     }
 	if (hasPendingTeleportRequest())
 	{
+		LLUIUsage::instance().logCommand("Agent.StartTeleportRequest");
         mTeleportCanceled.reset();
 		if  (!isMaturityPreferenceSyncedWithServer())
 		{
diff --git a/indra/newview/llagentcamera.cpp b/indra/newview/llagentcamera.cpp
index ed6c3c307fcc2712f09be591415350ecdca21283..8d2e3905d1f50fcb2e5a7d027ad7251f0937e49a 100644
--- a/indra/newview/llagentcamera.cpp
+++ b/indra/newview/llagentcamera.cpp
@@ -210,9 +210,6 @@ void LLAgentCamera::init()
 	
 	mCameraPreset = (ECameraPreset) gSavedSettings.getU32("CameraPresetType");
 
-	mCameraOffsetInitial = gSavedSettings.getControl("CameraOffsetRearView");
-	mFocusOffsetInitial = gSavedSettings.getControl("FocusOffsetRearView");
-
 	mCameraCollidePlane.clearVec();
 	mCurrentCameraDistance = getCameraOffsetInitial().magVec() * gSavedSettings.getF32("CameraOffsetScale");
 	mTargetCameraDistance = mCurrentCameraDistance;
@@ -404,10 +401,9 @@ LLVector3 LLAgentCamera::calcFocusOffset(LLViewerObject *object, LLVector3 origi
 	LLQuaternion obj_rot = object->getRenderRotation();
 	LLVector3 obj_pos = object->getRenderPosition();
 
-	BOOL is_avatar = object->isAvatar();
 	// if is avatar - don't do any funk heuristics to position the focal point
 	// see DEV-30589
-	if (is_avatar)
+	if (object->isAvatar() || (object->isAnimatedObject() && object->getControlAvatar()))
 	{
 		return original_focus_point - obj_pos;
 	}
@@ -532,7 +528,6 @@ LLVector3 LLAgentCamera::calcFocusOffset(LLViewerObject *object, LLVector3 origi
 	// or keep the focus point in the object middle when (relatively) far
 	// NOTE: leave focus point in middle of avatars, since the behavior you want when alt-zooming on avatars
 	// is almost always "tumble about middle" and not "spin around surface point"
-	if (!is_avatar) 
 	{
 		LLVector3 obj_rel = original_focus_point - object->getRenderPosition();
 		
@@ -1420,7 +1415,7 @@ void LLAgentCamera::updateCamera()
 			
 			F32 smoothing = LLSmoothInterpolation::getInterpolant(gSavedSettings.getF32("CameraPositionSmoothing") * SMOOTHING_HALF_LIFE, FALSE);
 					
-			if (!mFocusObject)  // we differentiate on avatar mode 
+			if (mFocusOnAvatar && !mFocusObject) // we differentiate on avatar mode 
 			{
 				// for avatar-relative focus, we smooth in avatar space -
 				// the avatar moves too jerkily w/r/t global space to smooth there.
@@ -1672,8 +1667,8 @@ LLVector3d LLAgentCamera::calcThirdPersonFocusOffset()
 		agent_rot *= ((LLViewerObject*)(gAgentAvatarp->getParent()))->getRenderRotation();
 	}
 
-	focus_offset = convert_from_llsd<LLVector3d>(mFocusOffsetInitial->get(), TYPE_VEC3D, "");
-	return focus_offset * agent_rot;
+    static LLCachedControl<LLVector3d> focus_offset_initial(gSavedSettings, "FocusOffsetRearView", LLVector3d());
+	return focus_offset_initial * agent_rot;
 }
 
 void LLAgentCamera::setupSitCamera()
@@ -1810,8 +1805,9 @@ LLVector3d LLAgentCamera::calcCameraPositionTargetGlobal(BOOL *hit_limit)
 		}
 		else
 		{
-			local_camera_offset = mCameraZoomFraction * getCameraOffsetInitial() * gSavedSettings.getF32("CameraOffsetScale");
-			
+            static LLCachedControl<F32> camera_offset_scale(gSavedSettings, "CameraOffsetScale");
+            local_camera_offset = mCameraZoomFraction * getCameraOffsetInitial() * camera_offset_scale;
+
 			// are we sitting down?
 			if (isAgentAvatarValid() && gAgentAvatarp->getParent())
 			{
@@ -2028,12 +2024,15 @@ bool LLAgentCamera::isJoystickCameraUsed()
 
 LLVector3 LLAgentCamera::getCameraOffsetInitial()
 {
-	return convert_from_llsd<LLVector3>(mCameraOffsetInitial->get(), TYPE_VEC3, "");
+    // getCameraOffsetInitial and getFocusOffsetInitial can be called on update from idle before init()
+    static LLCachedControl<LLVector3> camera_offset_initial (gSavedSettings, "CameraOffsetRearView", LLVector3());
+	return camera_offset_initial;
 }
 
 LLVector3d LLAgentCamera::getFocusOffsetInitial()
 {
-	return convert_from_llsd<LLVector3d>(mFocusOffsetInitial->get(), TYPE_VEC3D, "");
+    static LLCachedControl<LLVector3d> focus_offset_initial(gSavedSettings, "FocusOffsetRearView", LLVector3d());
+	return focus_offset_initial;
 }
 
 F32 LLAgentCamera::getCameraMaxZoomDistance()
diff --git a/indra/newview/llagentcamera.h b/indra/newview/llagentcamera.h
index ec1ed433d7cd9b26564b7c719041db24c7ffa3ee..89680f95dc28982ffadcb0c26fcf05b54e1886a1 100644
--- a/indra/newview/llagentcamera.h
+++ b/indra/newview/llagentcamera.h
@@ -131,12 +131,6 @@ class LLAgentCamera
 	/** Camera preset in Third Person Mode */
 	ECameraPreset mCameraPreset; 
 
-	/** Initial camera offset */
-	LLPointer<LLControlVariable> mCameraOffsetInitial;
-
-	/** Initial focus offset */
-	LLPointer<LLControlVariable> mFocusOffsetInitial;
-
 	LLQuaternion mInitSitRot;
 
 	//--------------------------------------------------------------------
diff --git a/indra/newview/llagentpicksinfo.h b/indra/newview/llagentpicksinfo.h
index f981e08ff7715c6b7d60e602a9a2873d6b7db27f..21df036cb7ecf02fa377c9d4f5105eb4d30c6f88 100644
--- a/indra/newview/llagentpicksinfo.h
+++ b/indra/newview/llagentpicksinfo.h
@@ -74,10 +74,10 @@ class LLAgentPicksInfo : public LLSingleton<LLAgentPicksInfo>
 
 	void decrementNumberOfPicks() { --mNumberOfPicks; }
 
-private:
-
 	void onServerRespond(LLAvatarPicks* picks);
 
+private:
+
 	/**
 	* Sets number of Picks.
 	*/
diff --git a/indra/newview/llagentwearables.cpp b/indra/newview/llagentwearables.cpp
index be168ff5ddbd02467c8c0740056a94381586eb14..2e769dc737993c22810a01213d10f03b9c9f6416 100644
--- a/indra/newview/llagentwearables.cpp
+++ b/indra/newview/llagentwearables.cpp
@@ -37,6 +37,7 @@
 #include "llgesturemgr.h"
 #include "llinventorybridge.h"
 #include "llinventoryfunctions.h"
+#include "llinventorymodelbackgroundfetch.h"
 #include "llinventoryobserver.h"
 #include "llinventorypanel.h"
 #include "lllocaltextureobject.h"
@@ -1582,6 +1583,14 @@ void LLAgentWearables::editWearable(const LLUUID& item_id)
 		return;
 	}
 
+    if (!item->isFinished())
+    {
+        LL_WARNS() << "Tried to edit wearable that isn't loaded" << LL_ENDL;
+        // Restart fetch or put item to the front
+        LLInventoryModelBackgroundFetch::instance().start(item->getUUID(), false);
+        return;
+    }
+
 	LLViewerWearable* wearable = gAgentWearables.getWearableFromItemID(item_id);
 	if (!wearable)
 	{
@@ -1595,6 +1604,18 @@ void LLAgentWearables::editWearable(const LLUUID& item_id)
 		return;
 	}
 
+    S32 shape_count = gAgentWearables.getWearableCount(LLWearableType::WT_SHAPE);
+    S32 hair_count = gAgentWearables.getWearableCount(LLWearableType::WT_HAIR);
+    S32 eye_count = gAgentWearables.getWearableCount(LLWearableType::WT_EYES);
+    S32 skin_count = gAgentWearables.getWearableCount(LLWearableType::WT_SKIN);
+    if (!shape_count || !hair_count || !eye_count || !skin_count)
+    {
+        // Don't let user edit wearables if avatar is cloud due to missing parts.
+        // Let user edit wearables if avatar is cloud due to missing textures.
+        LL_WARNS() << "Cannot modify wearable. Avatar is cloud and missing parts." << LL_ENDL;
+        return;
+    }
+
 	const BOOL disable_camera_switch = LLWearableType::getInstance()->getDisableCameraSwitch(wearable->getType());
 	LLPanel* panel = LLFloaterSidePanelContainer::getPanel("appearance");
 	LLSidepanelAppearance::editWearable(wearable, panel, disable_camera_switch);
diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp
index 39c9fa1bca4ab4d240743fd258ddfcfc7a5b7694..909f32cd21a637de4e8564aa471f7dad2c40bdbe 100644
--- a/indra/newview/llappearancemgr.cpp
+++ b/indra/newview/llappearancemgr.cpp
@@ -60,6 +60,7 @@
 #include "llappviewer.h"
 #include "llcoros.h"
 #include "lleventcoro.h"
+#include "lluiusage.h"
 
 #include "llavatarpropertiesprocessor.h"
 
@@ -1426,6 +1427,9 @@ void LLAppearanceMgr::wearItemsOnAvatar(const uuid_vec_t& item_ids_to_wear,
                                         bool replace,
                                         LLPointer<LLInventoryCallback> cb)
 {
+	LL_DEBUGS("UIUsage") << "wearItemsOnAvatar" << LL_ENDL;
+	LLUIUsage::instance().logCommand("Avatar.WearItem");
+
     bool first = true;
 
     LLInventoryObject::const_object_list_t items_to_link;
@@ -2761,6 +2765,7 @@ void LLAppearanceMgr::wearInventoryCategoryOnAvatar( LLInventoryCategory* catego
 
 	LL_INFOS("Avatar") << self_av_string() << "wearInventoryCategoryOnAvatar '" << category->getName()
 			 << "'" << LL_ENDL;
+	LLUIUsage::instance().logCommand("Avatar.WearCategory");
 			 	
 	if (gAgentCamera.cameraCustomizeAvatar())
 	{
@@ -3968,6 +3973,8 @@ void LLAppearanceMgr::makeNewOutfitLinks(const std::string& new_folder_name, boo
 {
 	if (!isAgentAvatarValid()) return;
 
+	LLUIUsage::instance().logCommand("Avatar.CreateNewOutfit");
+
 	LL_DEBUGS("Avatar") << "creating new outfit" << LL_ENDL;
 
 	gAgentWearables.notifyLoadingStarted();
@@ -4006,6 +4013,9 @@ void LLAppearanceMgr::wearBaseOutfit()
 
 void LLAppearanceMgr::removeItemsFromAvatar(const uuid_vec_t& ids_to_remove)
 {
+	LL_DEBUGS("UIUsage") << "removeItemsFromAvatar" << LL_ENDL;
+	LLUIUsage::instance().logCommand("Avatar.RemoveItem");
+
 	if (ids_to_remove.empty())
 	{
 		LL_WARNS() << "called with empty list, nothing to do" << LL_ENDL;
@@ -4485,6 +4495,8 @@ class LLWearFolderHandler : public LLCommandHandler
 																			  "Quick Appearance");
 			if ( gInventory.getCategory( folder_uuid ) != NULL )
 			{
+				// Assume this is coming from the predefined avatars web floater
+				LLUIUsage::instance().logCommand("Avatar.WearPredefinedAppearance");
 				LLAppearanceMgr::getInstance()->wearInventoryCategory(category, true, false);
 				
 				// *TODOw: This may not be necessary if initial outfit is chosen already -- josh
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 254bf05d0558eec592a770c86d8c31c79431970d..4f3e0b08e490fb083af241d4571381ebe38fa55b 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -91,7 +91,6 @@
 #include "llsdutil_math.h"
 #include "lllocationhistory.h"
 #include "llfasttimerview.h"
-#include "lltelemetry.h"
 #include "llvector4a.h"
 #include "llviewermenufile.h"
 #include "llvoicechannel.h"
@@ -233,11 +232,12 @@
 #include "llavatariconctrl.h"
 #include "llgroupiconctrl.h"
 #include "llviewerassetstats.h"
+#include "workqueue.h"
+using namespace LL;
 
 // Include for security api initialization
 #include "llsecapi.h"
 #include "llmachineid.h"
-#include "llmainlooprepeater.h"
 #include "llcleanup.h"
 
 #include "llcoproceduremanager.h"
@@ -363,6 +363,10 @@ BOOL gLogoutInProgress = FALSE;
 
 BOOL gSimulateMemLeak = FALSE;
 
+// We don't want anyone, especially threads working on the graphics pipeline,
+// to have to block due to this WorkQueue being full.
+WorkQueue gMainloopWork("mainloop", 1024*1024);
+
 ////////////////////////////////////////////////////////////
 // Internal globals... that should be removed.
 static std::string gArgs;
@@ -378,42 +382,6 @@ static std::string gLaunchFileOnQuit;
 // Used on Win32 for other apps to identify our window (eg, win_setup)
 const char* const VIEWER_WINDOW_CLASSNAME = "Second Life";
 
-//-- LLDeferredTaskList ------------------------------------------------------
-
-/**
- * A list of deferred tasks.
- *
- * We sometimes need to defer execution of some code until the viewer gets idle,
- * e.g. removing an inventory item from within notifyObservers() may not work out.
- *
- * Tasks added to this list will be executed in the next LLAppViewer::idle() iteration.
- * All tasks are executed only once.
- */
-class LLDeferredTaskList: public LLSingleton<LLDeferredTaskList>
-{
-	LLSINGLETON_EMPTY_CTOR(LLDeferredTaskList);
-	LOG_CLASS(LLDeferredTaskList);
-
-	friend class LLAppViewer;
-	typedef boost::signals2::signal<void()> signal_t;
-
-	void addTask(const signal_t::slot_type& cb)
-	{
-		mSignal.connect(cb);
-	}
-
-	void run()
-	{
-		if (!mSignal.empty())
-		{
-			mSignal();
-			mSignal.disconnect_all_slots();
-		}
-	}
-
-	signal_t mSignal;
-};
-
 //----------------------------------------------------------------------------
 
 // List of entries from strings.xml to always replace
@@ -564,7 +532,7 @@ static void settings_to_globals()
 
 	LLSurface::setTextureSize(gSavedSettings.getU32("RegionTextureSize"));
 
-	LLRender::sGLCoreProfile = gSavedSettings.getBOOL("RenderGLCoreProfile");
+	LLRender::sGLCoreProfile = gSavedSettings.getBOOL("RenderGLContextCoreProfile");
 	LLRender::sNsightDebugSupport = gSavedSettings.getBOOL("RenderNsightDebugSupport");
 	LLVertexBuffer::sUseVAO = gSavedSettings.getBOOL("RenderUseVAO");
 	LLImageGL::sGlobalUseAnisotropic	= gSavedSettings.getBOOL("RenderAnisotropic");
@@ -589,7 +557,7 @@ static void settings_to_globals()
 
 	gDebugWindowProc = gSavedSettings.getBOOL("DebugWindowProc");
 	gShowObjectUpdates = gSavedSettings.getBOOL("ShowObjectUpdates");
-	LLWorldMapView::sMapScale = gSavedSettings.getF32("MapScale");
+    LLWorldMapView::setScaleSetting(gSavedSettings.getF32("MapScale"));
 	
 #if LL_DARWIN
 	gHiDPISupport = gSavedSettings.getBOOL("RenderHiDPI");
@@ -598,14 +566,14 @@ static void settings_to_globals()
 
 static void settings_modify()
 {
-	LLPipeline::sRenderTransparentWater	= gSavedSettings.getBOOL("RenderTransparentWater");
-	LLPipeline::sRenderBump				= gSavedSettings.getBOOL("RenderObjectBump");
-	LLPipeline::sRenderDeferred = LLPipeline::sRenderTransparentWater && LLPipeline::sRenderBump && gSavedSettings.getBOOL("RenderDeferred");
-    LLRenderTarget::sUseFBO = LLPipeline::sRenderDeferred && gSavedSettings.getBOOL("RenderAvatarVP");
-	LLVOSurfacePatch::sLODFactor		= gSavedSettings.getF32("RenderTerrainLODFactor");
-	LLVOSurfacePatch::sLODFactor *= LLVOSurfacePatch::sLODFactor; //square lod factor to get exponential range of [1,4]
-	gDebugGL = gSavedSettings.getBOOL("RenderDebugGL") || gDebugSession;
-	gDebugPipeline = gSavedSettings.getBOOL("RenderDebugPipeline");
+    LLPipeline::sRenderTransparentWater = gSavedSettings.getBOOL("RenderTransparentWater");
+    LLPipeline::sRenderBump             = gSavedSettings.getBOOL("RenderObjectBump");
+    LLPipeline::sRenderDeferred         = LLPipeline::sRenderBump && gSavedSettings.getBOOL("RenderDeferred");
+    LLRenderTarget::sUseFBO             = LLPipeline::sRenderDeferred;
+    LLVOSurfacePatch::sLODFactor        = gSavedSettings.getF32("RenderTerrainLODFactor");
+    LLVOSurfacePatch::sLODFactor *= LLVOSurfacePatch::sLODFactor;  // square lod factor to get exponential range of [1,4]
+    gDebugGL       = gDebugGLSession || gDebugSession;
+    gDebugPipeline = gSavedSettings.getBOOL("RenderDebugPipeline");
 }
 
 class LLFastTimerLogThread : public LLThread
@@ -669,6 +637,7 @@ LLAppViewer::LLAppViewer()
 	mLogoutMarkerFile(),
 	mReportedCrash(false),
 	mNumSessions(0),
+    mGeneralThreadPool(nullptr),
 	mPurgeCache(false),
 	mPurgeCacheOnExit(false),
 	mPurgeUserDataOnExit(false),
@@ -686,8 +655,7 @@ LLAppViewer::LLAppViewer()
 	mPeriodicSlowFrame(LLCachedControl<bool>(gSavedSettings,"Periodic Slow Frame", FALSE)),
 	mFastTimerLogThread(NULL),
 	mSettingsLocationList(NULL),
-	mIsFirstRun(false),
-	mMinMicroSecPerFrame(0.f)
+	mIsFirstRun(false)
 {
 	if(NULL != sInstance)
 	{
@@ -856,8 +824,6 @@ bool LLAppViewer::init()
 	LLNotifications::instance();
 	LL_INFOS("InitInfo") << "Notifications initialized." << LL_ENDL ;
 
-    writeSystemInfo();
-
 	//////////////////////////////////////////////////////////////////////////////
 	//////////////////////////////////////////////////////////////////////////////
 	//////////////////////////////////////////////////////////////////////////////
@@ -964,8 +930,8 @@ bool LLAppViewer::init()
 	}
 	LL_INFOS("InitInfo") << "Cache initialization is done." << LL_ENDL ;
 
-	// Initialize the repeater service.
-	LLMainLoopRepeater::instance().start();
+    // Initialize event recorder
+    LLViewerEventRecorder::createInstance();
 
 	//
 	// Initialize the window
@@ -974,6 +940,9 @@ bool LLAppViewer::init()
 	initWindow();
 	LL_INFOS("InitInfo") << "Window is initialized." << LL_ENDL ;
 
+    // writeSystemInfo can be called after window is initialized (gViewerWindow non-null)
+    writeSystemInfo();
+
 	// initWindow also initializes the Feature List, so now we can initialize this global.
 	LLCubeMap::sUseCubeMaps = LLFeatureManager::getInstance()->isFeatureAvailable("RenderCubeMap");
 
@@ -988,29 +957,10 @@ bool LLAppViewer::init()
 	// If we don't have the right GL requirements, exit.
 	if (!gGLManager.mHasRequirements)
 	{
-		// can't use an alert here since we're exiting and
-		// all hell breaks lose.
-		LLUIString details = LLNotifications::instance().getGlobalString("UnsupportedGLRequirements");
-		OSMessageBox(
-			details.getString(),
-			LLStringUtil::null,
-			OSMB_OK);
+        // already handled with a MBVideoDrvErr
 		return 0;
 	}
 
-    // If we don't have the right shader requirements.
-    if (!gGLManager.mHasShaderObjects
-        || !gGLManager.mHasVertexShader
-        || !gGLManager.mHasFragmentShader)
-    {
-        LLUIString details = LLNotifications::instance().getGlobalString("UnsupportedShaderRequirements");
-        OSMessageBox(
-            details.getString(),
-            LLStringUtil::null,
-            OSMB_OK);
-        return 0;
-    }
-
 	// Without SSE2 support we will crash almost immediately, warn here.
 	if (!gSysCPU.hasSSE2())
 	{
@@ -1136,7 +1086,7 @@ bool LLAppViewer::init()
 		{
 			url = LLTrans::getString("NvidiaDriverPage");
 		}
-		else if (gGLManager.mIsATI)
+		else if (gGLManager.mIsAMD)
 		{
 			url = LLTrans::getString("AMDDriverPage");
 		}
@@ -1175,7 +1125,8 @@ bool LLAppViewer::init()
 	gGLActive = FALSE;
 
 #if LL_RELEASE_FOR_DOWNLOAD
-    if (!gSavedSettings.getBOOL("CmdLineSkipUpdater"))
+    // Skip updater if this is a non-interactive instance
+    if (!gSavedSettings.getBOOL("CmdLineSkipUpdater") && !gNonInteractive)
     {
         LLProcess::Params updater;
         updater.desc = "updater process";
@@ -1319,13 +1270,16 @@ bool LLAppViewer::init()
 	joystick = LLViewerJoystick::getInstance();
 	joystick->setNeedsReset(true);
 	/*----------------------------------------------------------------------*/
-
-	gSavedSettings.getControl("FramePerSecondLimit")->getSignal()->connect(boost::bind(&LLAppViewer::onChangeFrameLimit, this, _2));
-	onChangeFrameLimit(gSavedSettings.getLLSD("FramePerSecondLimit"));
-
 	// Load User's bindings
 	loadKeyBindings();
 
+    //LLSimpleton creations
+    LLEnvironment::createInstance();
+    LLEnvironment::getInstance()->initSingleton();
+    LLWorld::createInstance();
+    LLSelectMgr::createInstance();
+    LLViewerCamera::createInstance();
+
 #if LL_WINDOWS
     if (!mSecondInstance)
     {
@@ -1351,14 +1305,18 @@ void LLAppViewer::initMaxHeapSize()
 	//------------------------------------------------------------------------------------------
 	//currently SL is built under 32-bit setting, we set its max heap size no more than 1.6 GB.
 
-	//F32 max_heap_size_gb = llmin(1.6f, (F32)gSavedSettings.getF32("MaxHeapSize")) ;
-	F32Gigabytes max_heap_size_gb = (F32Gigabytes)gSavedSettings.getF32("MaxHeapSize") ;
+ #ifndef LL_X86_64
+    F32Gigabytes max_heap_size_gb = (F32Gigabytes)gSavedSettings.getF32("MaxHeapSize") ;
+#else
+    F32Gigabytes max_heap_size_gb = (F32Gigabytes)gSavedSettings.getF32("MaxHeapSize64");
+#endif
 
-	LLMemory::initMaxHeapSizeGB(max_heap_size_gb);
+    LLMemory::initMaxHeapSizeGB(max_heap_size_gb);
 }
 
 static LLTrace::BlockTimerStatHandle FTM_MESSAGES("System Messages");
-static LLTrace::BlockTimerStatHandle FTM_SLEEP("Sleep");
+static LLTrace::BlockTimerStatHandle FTM_SLEEP1("Sleep1");
+static LLTrace::BlockTimerStatHandle FTM_SLEEP2("Sleep2");
 static LLTrace::BlockTimerStatHandle FTM_YIELD("Yield");
 
 static LLTrace::BlockTimerStatHandle FTM_TEXTURE_CACHE("Texture Cache");
@@ -1419,13 +1377,26 @@ bool LLAppViewer::frame()
 
 bool LLAppViewer::doFrame()
 {
+	LL_RECORD_BLOCK_TIME(FTM_FRAME);
+
+    if (!LLWorld::instanceExists())
+    {
+        LLWorld::createInstance();
+    }
+
 	LLEventPump& mainloop(LLEventPumps::instance().obtain("mainloop"));
 	LLSD newFrame;
 
-	LL_RECORD_BLOCK_TIME(FTM_FRAME);
+	{
+        LL_PROFILE_ZONE_NAMED_CATEGORY_APP("df LLTrace");
+        if (LLFloaterReg::instanceVisible("block_timers"))
+        {
 	LLTrace::BlockTimer::processTimes();
+        }
+        
 	LLTrace::get_frame_recording().nextPeriod();
 	LLTrace::BlockTimer::logStats();
+	}
 
 	LLTrace::get_thread_recorder()->pullFromChildren();
 
@@ -1433,6 +1404,7 @@ bool LLAppViewer::doFrame()
 	LL_CLEAR_CALLSTACKS();
 
 	{
+		LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df processMiscNativeEvents" )
 		pingMainloopTimeout("Main:MiscNativeWindowEvents");
 
 		if (gViewerWindow)
@@ -1441,7 +1413,10 @@ bool LLAppViewer::doFrame()
 			gViewerWindow->getWindow()->processMiscNativeEvents();
 		}
 
+		{
+			LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df gatherInput" )
 		pingMainloopTimeout("Main:GatherInput");
+		}
 
 		if (gViewerWindow)
 		{
@@ -1465,13 +1440,23 @@ bool LLAppViewer::doFrame()
 			}
 		}
 
+		{
+			LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df mainloop" )
 		// canonical per-frame event
 		mainloop.post(newFrame);
+		}
+
+		{
+			LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df suspend" )
 		// give listeners a chance to run
 		llcoro::suspend();
+		// if one of our coroutines threw an uncaught exception, rethrow it now
+		LLCoros::instance().rethrow();
+		}
 
 		if (!LLApp::isExiting())
 		{
+			LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df JoystickKeyboard" )
 			pingMainloopTimeout("Main:JoystickKeyboard");
 
 			// Scan keyboard for movement keys.  Command keys and typing
@@ -1492,12 +1477,20 @@ bool LLAppViewer::doFrame()
 
 			// Update state based on messages, user input, object idle.
 			{
-				pauseMainloopTimeout(); // *TODO: Remove. Messages shouldn't be stalling for 20+ seconds!
+				{
+					LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df pauseMainloopTimeout" )
+					pauseMainloopTimeout(); // *TODO: Remove. Messages shouldn't be stalling for 20+ seconds!
+				}
 
-				LL_RECORD_BLOCK_TIME(FTM_IDLE);
-				idle();
+				{
+					LL_PROFILE_ZONE_NAMED_CATEGORY_APP("df idle"); //LL_RECORD_BLOCK_TIME(FTM_IDLE);
+					idle();
+				}
 
-				resumeMainloopTimeout();
+				{
+					LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df resumeMainloopTimeout" )
+					resumeMainloopTimeout();
+				}
 			}
 
 			if (gDoDisconnect && (LLStartUp::getStartupState() == STATE_STARTED))
@@ -1518,49 +1511,51 @@ bool LLAppViewer::doFrame()
 			// *TODO: Should we run display() even during gHeadlessClient?  DK 2011-02-18
 			if (!LLApp::isExiting() && !gHeadlessClient && gViewerWindow)
 			{
+				LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df Display" )
 				pingMainloopTimeout("Main:Display");
 				gGLActive = TRUE;
 
 				display();
 
-				static U64 last_call = 0;
-				if (!gTeleportDisplay)
 				{
-					// Frame/draw throttling, controlled by FramePerSecondLimit
-					U64 elapsed_time = LLTimer::getTotalTime() - last_call;
-					if (elapsed_time < mMinMicroSecPerFrame)
-					{
-						LL_RECORD_BLOCK_TIME(FTM_SLEEP);
-						// llclamp for when time function gets funky
-						U64 sleep_time = llclamp(mMinMicroSecPerFrame - elapsed_time, (U64)1, (U64)1e6);
-						micro_sleep(sleep_time, 0);
-					}
-				}
-				last_call = LLTimer::getTotalTime();
-
+					LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df Snapshot" )
 				pingMainloopTimeout("Main:Snapshot");
 				LLFloaterSnapshot::update(); // take snapshots
 					LLFloaterOutfitSnapshot::update();
 				gGLActive = FALSE;
 			}
 		}
+		}
 
+		{
+			LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df pauseMainloopTimeout" )
 		pingMainloopTimeout("Main:Sleep");
 
 		pauseMainloopTimeout();
+		}
 
 		// Sleep and run background threads
 		{
-			LL_RECORD_BLOCK_TIME(FTM_SLEEP);
+			//LL_RECORD_BLOCK_TIME(SLEEP2);
+			LL_PROFILE_ZONE_WARN( "Sleep2" )
 
 			// yield some time to the os based on command line option
 			static LLCachedControl<S32> yield_time(gSavedSettings, "YieldTime", -1);
 			if(yield_time >= 0)
 			{
 				LL_RECORD_BLOCK_TIME(FTM_YIELD);
+				LL_PROFILE_ZONE_NUM( yield_time )
 				ms_sleep(yield_time);
 			}
 
+			if (gNonInteractive)
+			{
+				S32 non_interactive_ms_sleep_time = 100;
+				LLAppViewer::getTextureCache()->pause();
+				LLAppViewer::getImageDecodeThread()->pause();
+				ms_sleep(non_interactive_ms_sleep_time);
+			}
+
 			// yield cooperatively when not running as foreground window
 			// and when not quiting (causes trouble at mac's cleanup stage)
 			if (!LLApp::isExiting()
@@ -1568,8 +1563,8 @@ bool LLAppViewer::doFrame()
 					|| !gFocusMgr.getAppHasFocus()))
 			{
 				// Sleep if we're not rendering, or the window is minimized.
-				static LLCachedControl<S32> s_bacground_yeild_time(gSavedSettings, "BackgroundYieldTime", 40);
-				S32 milliseconds_to_sleep = llclamp((S32)s_bacground_yeild_time, 0, 1000);
+				static LLCachedControl<S32> s_background_yield_time(gSavedSettings, "BackgroundYieldTime", 40);
+				S32 milliseconds_to_sleep = llclamp((S32)s_background_yield_time, 0, 1000);
 				// don't sleep when BackgroundYieldTime set to 0, since this will still yield to other threads
 				// of equal priority on Windows
 				if (milliseconds_to_sleep > 0)
@@ -1616,22 +1611,29 @@ bool LLAppViewer::doFrame()
 				total_io_pending += io_pending ;
 
 			}
+
+			{
+				LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df gMeshRepo" )
 			gMeshRepo.update() ;
+			}
 
 			if(!total_work_pending) //pause texture fetching threads if nothing to process.
 			{
+				LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df getTextureCache" )
 				LLAppViewer::getTextureCache()->pause();
 				LLAppViewer::getImageDecodeThread()->pause();
 				LLAppViewer::getTextureFetch()->pause();
 			}
 			if(!total_io_pending) //pause file threads if nothing to process.
 			{
+				LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df LLVFSThread" )
 				LLLFSThread::sLocal->pause();
 			}
 
 			//texture fetching debugger
 			if(LLTextureFetchDebugger::isEnabled())
 			{
+				LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df tex_fetch_debugger_instance" )
 				LLFloaterTextureFetchDebugger* tex_fetch_debugger_instance =
 					LLFloaterReg::findTypedInstance<LLFloaterTextureFetchDebugger>("tex_fetch_debugger");
 				if(tex_fetch_debugger_instance)
@@ -1640,8 +1642,10 @@ bool LLAppViewer::doFrame()
 				}
 			}
 
+			{
+				LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df resumeMainloopTimeout" )
 			resumeMainloopTimeout();
-
+			}
 			pingMainloopTimeout("Main:End");
 		}
 	}
@@ -1667,7 +1671,7 @@ bool LLAppViewer::doFrame()
 		LL_INFOS() << "Exiting main_loop" << LL_ENDL;
 	}
 
-    LLPROFILE_UPDATE();
+    LL_PROFILER_FRAME_END
 
 	return ! LLApp::isRunning();
 }
@@ -1754,6 +1758,7 @@ bool LLAppViewer::cleanup()
     LLPluginProcessParent::shutdown();
 
 	disconnectViewer();
+	LLViewerCamera::deleteSingleton();
 
 	LL_INFOS() << "Viewer disconnected" << LL_ENDL;
 	
@@ -1949,7 +1954,7 @@ bool LLAppViewer::cleanup()
 
     if (LLEnvironment::instanceExists())
     {
-        //Store environment settings if nessesary
+		//Store environment settings if necessary
         LLEnvironment::getInstance()->saveToSettings();
     }
 
@@ -2058,6 +2063,10 @@ bool LLAppViewer::cleanup()
 	sTextureCache->shutdown();
 	sImageDecodeThread->shutdown();
 	sPurgeDiskCacheThread->shutdown();
+    if (mGeneralThreadPool)
+    {
+        mGeneralThreadPool->close();
+    }
 
 	sTextureFetch->shutDownTextureCacheThread() ;
 	sTextureFetch->shutDownImageDecodeThread() ;
@@ -2082,6 +2091,8 @@ bool LLAppViewer::cleanup()
 	mFastTimerLogThread = NULL;
 	delete sPurgeDiskCacheThread;
 	sPurgeDiskCacheThread = NULL;
+    delete mGeneralThreadPool;
+    mGeneralThreadPool = NULL;
 
 	if (LLFastTimerView::sAnalyzePerformance)
 	{
@@ -2140,12 +2151,15 @@ bool LLAppViewer::cleanup()
 	SUBSYSTEM_CLEANUP(LLProxy);
     LLCore::LLHttp::cleanup();
 
-	LLMainLoopRepeater::instance().stop();
-
 	ll_close_fail_log();
 
 	LLError::LLCallStacks::cleanup();
 
+	LLEnvironment::deleteSingleton();
+	LLSelectMgr::deleteSingleton();
+	LLViewerEventRecorder::deleteSingleton();
+    LLWorld::deleteSingleton();
+
 	// It's not at first obvious where, in this long sequence, a generic cleanup
 	// call OUGHT to go. So let's say this: as we migrate cleanup from
 	// explicit hand-placed calls into the generic mechanism, eventually
@@ -2165,6 +2179,24 @@ bool LLAppViewer::cleanup()
 	return true;
 }
 
+void LLAppViewer::initGeneralThread()
+{
+    if (mGeneralThreadPool)
+    {
+        return;
+    }
+
+    LLSD poolSizes{ gSavedSettings.getLLSD("ThreadPoolSizes") };
+    LLSD sizeSpec{ poolSizes["General"] };
+    LLSD::Integer poolSize{ sizeSpec.isInteger() ? sizeSpec.asInteger() : 3 };
+    LL_DEBUGS("ThreadPool") << "Instantiating General pool with "
+        << poolSize << " threads" << LL_ENDL;
+    // We don't want anyone, especially the main thread, to have to block
+    // due to this ThreadPool being full.
+    mGeneralThreadPool = new LL::ThreadPool("General", poolSize, 1024 * 1024);
+    mGeneralThreadPool->start();
+}
+
 bool LLAppViewer::initThreads()
 {
 	static const bool enable_threads = true;
@@ -2328,7 +2360,7 @@ bool LLAppViewer::loadSettingsFromDirectory(const std::string& location_key,
 			LL_INFOS("Settings") << "Attempting to load settings for the group " << file.name()
 			    << " - from location " << location_key << LL_ENDL;
 
-			LLControlGroup* settings_group = LLControlGroup::getInstance(file.name);
+			auto settings_group = LLControlGroup::getInstance(file.name);
 			if(!settings_group)
 			{
 				LL_WARNS("Settings") << "No matching settings group for name " << file.name() << LL_ENDL;
@@ -2423,15 +2455,61 @@ namespace
     }
 } // anonymous namespace
 
+// Set a named control temporarily for this session, as when set via the command line --set option.
+// Name can be specified as "<control_group>.<control_name>", with default group being Global.
+bool tempSetControl(const std::string& name, const std::string& value)
+{
+	std::string name_part;
+	std::string group_part;
+	LLControlVariable* control = NULL;
+
+	// Name can be further split into ControlGroup.Name, with the default control group being Global
+	size_t pos = name.find('.');
+	if (pos != std::string::npos)
+	{
+		group_part = name.substr(0, pos);
+		name_part = name.substr(pos+1);
+		LL_INFOS() << "Setting " << group_part << "." << name_part << " to " << value << LL_ENDL;
+		auto g = LLControlGroup::getInstance(group_part);
+		if (g) control = g->getControl(name_part);
+	}
+	else
+	{
+		LL_INFOS() << "Setting Global." << name << " to " << value << LL_ENDL;
+		control = gSavedSettings.getControl(name);
+	}
+
+	if (control)
+	{
+		control->setValue(value, false);
+		return true;
+	}
+	return false;
+}
+
 bool LLAppViewer::initConfiguration()
 {
 	//Load settings files list
 	std::string settings_file_list = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "settings_files.xml");
 	LLXMLNodePtr root;
-	BOOL success  = LLXMLNode::parseFile(settings_file_list, root, NULL);
+	BOOL success = LLXMLNode::parseFile(settings_file_list, root, NULL);
 	if (!success)
 	{
-        LL_ERRS() << "Cannot load default configuration file " << settings_file_list << LL_ENDL;
+        LL_WARNS() << "Cannot load default configuration file " << settings_file_list << LL_ENDL;
+        if (gDirUtilp->fileExists(settings_file_list))
+        {
+            LL_ERRS() << "Cannot load default configuration file settings_files.xml. "
+                << "Please reinstall viewer from https://secondlife.com/support/downloads/ "
+                << "and contact https://support.secondlife.com if issue persists after reinstall."
+                << LL_ENDL;
+        }
+        else
+        {
+            LL_ERRS() << "Default configuration file settings_files.xml not found. "
+                << "Please reinstall viewer from https://secondlife.com/support/downloads/ "
+                << "and contact https://support.secondlife.com if issue persists after reinstall."
+                << LL_ENDL;
+        }
 	}
 
 	mSettingsLocationList = new SettingsFiles();
@@ -2473,12 +2551,7 @@ bool LLAppViewer::initConfiguration()
 #ifndef	LL_RELEASE_FOR_DOWNLOAD
 	// provide developer build only overrides for these control variables that are not
 	// persisted to settings.xml
-	LLControlVariable* c = gSavedSettings.getControl("ShowConsoleWindow");
-	if (c)
-	{
-		c->setValue(true, false);
-	}
-	c = gSavedSettings.getControl("AllowMultipleViewers");
+	LLControlVariable* c = gSavedSettings.getControl("AllowMultipleViewers");
 	if (c)
 	{
 		c->setValue(true, false);
@@ -2584,9 +2657,10 @@ bool LLAppViewer::initConfiguration()
 		disableCrashlogger();
 	}
 
+	gNonInteractive = gSavedSettings.getBOOL("NonInteractive");
 	// Handle initialization from settings.
 	// Start up the debugging console before handling other options.
-	if (gSavedSettings.getBOOL("ShowConsoleWindow"))
+	if (gSavedSettings.getBOOL("ShowConsoleWindow") && !gNonInteractive)
 	{
 		initConsole();
 	}
@@ -2619,31 +2693,7 @@ bool LLAppViewer::initConfiguration()
             {
                 const std::string& name = *itr;
                 const std::string& value = *(++itr);
-                std::string name_part;
-                std::string group_part;
-				LLControlVariable* control = NULL;
-
-				// Name can be further split into ControlGroup.Name, with the default control group being Global
-				size_t pos = name.find('.');
-				if (pos != std::string::npos)
-				{
-					group_part = name.substr(0, pos);
-					name_part = name.substr(pos+1);
-					LL_INFOS() << "Setting " << group_part << "." << name_part << " to " << value << LL_ENDL;
-					LLControlGroup* g = LLControlGroup::getInstance(group_part);
-					if (g) control = g->getControl(name_part);
-				}
-				else
-				{
-					LL_INFOS() << "Setting Global." << name << " to " << value << LL_ENDL;
-					control = gSavedSettings.getControl(name);
-				}
-
-                if (control)
-                {
-                    control->setValue(value, false);
-                }
-                else
+                if (!tempSetControl(name,value))
                 {
 					LL_WARNS() << "Failed --set " << name << ": setting name unknown." << LL_ENDL;
                 }
@@ -2682,19 +2732,14 @@ bool LLAppViewer::initConfiguration()
 
 	if (clp.hasOption("graphicslevel"))
 	{
-		// User explicitly requested --graphicslevel on the command line. We
-		// expect this switch has already set RenderQualityPerformance. Check
-		// that value for validity.
-		U32 graphicslevel = gSavedSettings.getU32("RenderQualityPerformance");
-		if (LLFeatureManager::instance().isValidGraphicsLevel(graphicslevel))
-        {
-			// graphicslevel is valid: save it and engage it later. Capture
-			// the requested value separately from the settings variable
-			// because, if this is the first run, LLViewerWindow's constructor
-			// will call LLFeatureManager::applyRecommendedSettings(), which
-			// overwrites this settings variable!
-			mForceGraphicsLevel = graphicslevel;
-        }
+        // User explicitly requested --graphicslevel on the command line. We
+        // expect this switch has already set RenderQualityPerformance. Check
+        // that value for validity later.
+        // Capture the requested value separately from the settings variable
+        // because, if this is the first run, LLViewerWindow's constructor
+        // will call LLFeatureManager::applyRecommendedSettings(), which
+        // overwrites this settings variable!
+        mForceGraphicsLevel = gSavedSettings.getU32("RenderQualityPerformance");
 	}
 
 	LLFastTimerView::sAnalyzePerformance = gSavedSettings.getBOOL("AnalyzePerformance");
@@ -2708,6 +2753,15 @@ bool LLAppViewer::initConfiguration()
 		ll_init_fail_log(gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "test_failures.log"));
 	}
 
+    if (gSavedSettings.getBOOL("RenderDebugGLSession"))
+    {
+        gDebugGLSession = TRUE;
+        gDebugGL = TRUE;
+        // gDebugGL can cause excessive logging
+        // so it's limited to a single session
+        gSavedSettings.setBOOL("RenderDebugGLSession", FALSE);
+    }
+
 	const LLControlVariable* skinfolder = gSavedSettings.getControl("SkinCurrent");
 	if(skinfolder && LLStringUtil::null != skinfolder->getValue().asString())
 	{
@@ -2731,6 +2785,19 @@ bool LLAppViewer::initConfiguration()
 		}
 	}
 
+	if (gNonInteractive)
+	{
+		tempSetControl("AllowMultipleViewers", "TRUE");
+		tempSetControl("SLURLPassToOtherInstance", "FALSE");
+		tempSetControl("RenderWater", "FALSE");
+		tempSetControl("FlyingAtExit", "FALSE");
+		tempSetControl("WindowWidth", "1024");
+		tempSetControl("WindowHeight", "200");
+		LLError::setEnabledLogTypesMask(0);
+		llassert_always(!gSavedSettings.getBOOL("SLURLPassToOtherInstance"));
+	}
+
+
 	// Handle slurl use. NOTE: Don't let SL-55321 reappear.
 	// This initial-SLURL logic, up through the call to
 	// sendURLToOtherInstance(), must precede LLSplashScreen::show() --
@@ -3030,7 +3097,7 @@ bool LLAppViewer::initWindow()
 	// Initialize GL stuff
 	//
 
-	if (mForceGraphicsLevel)
+	if (mForceGraphicsLevel && (LLFeatureManager::instance().isValidGraphicsLevel(*mForceGraphicsLevel)))
 	{
 		LLFeatureManager::getInstance()->setGraphicsLevel(*mForceGraphicsLevel, false);
 		gSavedSettings.setU32("RenderQualityPerformance", *mForceGraphicsLevel);
@@ -3086,6 +3153,16 @@ bool LLAppViewer::initWindow()
 	return true;
 }
 
+bool LLAppViewer::isUpdaterMissing()
+{
+    return mUpdaterNotFound;
+}
+
+bool LLAppViewer::waitForUpdater()
+{
+    return !gSavedSettings.getBOOL("CmdLineSkipUpdater") && !mUpdaterNotFound && !gNonInteractive;
+}
+
 void LLAppViewer::writeDebugInfo(bool isStatic)
 {
 #if LL_WINDOWS && LL_BUGSPLAT
@@ -3166,7 +3243,28 @@ LLSD LLAppViewer::getViewerInfo() const
 	info["GRAPHICS_CARD"] = ll_safe_string((const char*)(glGetString(GL_RENDERER)));
 
 #if LL_WINDOWS
-	std::string drvinfo = gDXHardware.getDriverVersionWMI();
+    std::string drvinfo;
+
+    if (gGLManager.mIsIntel)
+    {
+        drvinfo = gDXHardware.getDriverVersionWMI(LLDXHardware::GPU_INTEL);
+    }
+    else if (gGLManager.mIsNVIDIA)
+    {
+        drvinfo = gDXHardware.getDriverVersionWMI(LLDXHardware::GPU_NVIDIA);
+    }
+    else if (gGLManager.mIsAMD)
+    {
+        drvinfo = gDXHardware.getDriverVersionWMI(LLDXHardware::GPU_AMD);
+    }
+
+    if (drvinfo.empty())
+    {
+        // Generic/substitute windows driver? Unknown vendor?
+        LL_WARNS("DriverVersion") << "Vendor based driver search failed, searching for any driver" << LL_ENDL;
+        drvinfo = gDXHardware.getDriverVersionWMI(LLDXHardware::GPU_ANY);
+    }
+
 	if (!drvinfo.empty())
 	{
 		info["GRAPHICS_DRIVER_VERSION"] = drvinfo;
@@ -3209,9 +3307,18 @@ LLSD LLAppViewer::getViewerInfo() const
 	info["AUDIO_DRIVER_VERSION"] = gAudiop ? LLSD(gAudiop->getDriverName(want_fullname)) : "Undefined";
 	if(LLVoiceClient::getInstance()->voiceEnabled())
 	{
-		LLVoiceVersionInfo version = LLVoiceClient::getInstance()->getVersion();
+        LLVoiceVersionInfo version = LLVoiceClient::getInstance()->getVersion();
+        const std::string build_version = version.mBuildVersion;
 		std::ostringstream version_string;
-		version_string << version.serverType << " " << version.serverVersion << std::endl;
+        if (std::equal(build_version.begin(), build_version.begin() + version.serverVersion.size(),
+                       version.serverVersion.begin()))
+        {  // Normal case: Show type and build version.
+            version_string << version.serverType << " " << build_version << std::endl;
+        }
+        else
+        {  // Mismatch: Show both versions.
+            version_string << version.serverVersion << "/" << build_version << std::endl;
+        }
 		info["VOICE_VERSION"] = version_string.str();
 	}
 	else
@@ -3404,7 +3511,7 @@ void LLAppViewer::cleanupSavedSettings()
 		}
 	}
 
-	gSavedSettings.setF32("MapScale", LLWorldMapView::sMapScale );
+    gSavedSettings.setF32("MapScale", LLWorldMapView::getScaleSetting());
 
 	// Some things are cached in LLAgent.
 	if (gAgent.isInitialized())
@@ -3507,11 +3614,14 @@ void LLAppViewer::writeSystemInfo()
 	gDebugInfo["FirstRunThisInstall"] = gSavedSettings.getBOOL("FirstRunThisInstall");
     gDebugInfo["StartupState"] = LLStartUp::getStartupStateString();
 
+    if (gViewerWindow)
+    {
 	std::vector<std::string> resolutions = gViewerWindow->getWindow()->getDisplaysResolutionList();
 	for (auto res_iter : resolutions)
 	{
 		gDebugInfo["DisplayInfo"].append(res_iter);
 	}
+    }
 
 	writeDebugInfo(); // Save out debug_info.log early, in case of crash.
 }
@@ -4171,6 +4281,15 @@ U32 LLAppViewer::getTextureCacheVersion()
 	return TEXTURE_CACHE_VERSION ;
 }
 
+//static
+U32 LLAppViewer::getDiskCacheVersion()
+{
+    // Viewer disk cache version intorduced in Simple Cache Viewer, change if the cache format changes.
+    const U32 DISK_CACHE_VERSION = 1;
+
+    return DISK_CACHE_VERSION ;
+}
+
 //static
 U32 LLAppViewer::getObjectCacheVersion()
 {
@@ -4191,21 +4310,30 @@ bool LLAppViewer::initCache()
 	// initialize the new disk cache using saved settings
 	const std::string cache_dir_name = gSavedSettings.getString("DiskCacheDirName");
 
+	const U32 MB = 1024 * 1024;
+    const uintmax_t MIN_CACHE_SIZE = 256 * MB;
+	const uintmax_t MAX_CACHE_SIZE = 9984ll * MB;
+    const uintmax_t setting_cache_total_size = uintmax_t(gSavedSettings.getU32("CacheSize")) * MB;
+    const uintmax_t cache_total_size = llclamp(setting_cache_total_size, MIN_CACHE_SIZE, MAX_CACHE_SIZE);
+    const F64 disk_cache_percent = gSavedSettings.getF32("DiskCachePercentOfTotal");
+    const F64 texture_cache_percent = 100.0 - disk_cache_percent;
+
     // note that the maximum size of this cache is defined as a percentage of the 
     // total cache size - the 'CacheSize' pref - for all caches. 
-    const unsigned int cache_total_size_mb = gSavedSettings.getU32("CacheSize");
-    const double disk_cache_percent = gSavedSettings.getF32("DiskCachePercentOfTotal");
-    const unsigned int disk_cache_mb = cache_total_size_mb * disk_cache_percent / 100;
-    const uintmax_t disk_cache_bytes = disk_cache_mb * 1024 * 1024;
+    const uintmax_t disk_cache_size = uintmax_t(cache_total_size * disk_cache_percent / 100);
 	const bool enable_cache_debug_info = gSavedSettings.getBOOL("EnableDiskCacheDebugInfo");
 
 	bool texture_cache_mismatch = false;
+    bool remove_vfs_files = false;
 	if (gSavedSettings.getS32("LocalCacheVersion") != LLAppViewer::getTextureCacheVersion())
 	{
 		texture_cache_mismatch = true;
 		if(!read_only)
 		{
 			gSavedSettings.setS32("LocalCacheVersion", LLAppViewer::getTextureCacheVersion());
+
+            //texture cache version was bumped up in Simple Cache Viewer, and at this point old vfs files are not needed
+            remove_vfs_files = true;   
 		}
 	}
 
@@ -4247,18 +4375,30 @@ bool LLAppViewer::initCache()
 	}
 
 	const std::string cache_dir = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, cache_dir_name);
-	LLDiskCache::initParamSingleton(cache_dir, disk_cache_bytes, enable_cache_debug_info);
+    LLDiskCache::initParamSingleton(cache_dir, disk_cache_size, enable_cache_debug_info);
 
 	if (!read_only)
 	{
-		if (mPurgeCache)
+        if (gSavedSettings.getS32("DiskCacheVersion") != LLAppViewer::getDiskCacheVersion())
+        {
+            LLDiskCache::getInstance()->clearCache();
+            remove_vfs_files = true;
+            gSavedSettings.setS32("DiskCacheVersion", LLAppViewer::getDiskCacheVersion());
+        }
+
+        if (remove_vfs_files)
+        {
+            LLDiskCache::getInstance()->removeOldVFSFiles();
+        }
+        
+        if (mPurgeCache)
 		{
-			LLSplashScreen::update(LLTrans::getString("StartupClearingCache"));
-			purgeCache();
+		LLSplashScreen::update(LLTrans::getString("StartupClearingCache"));
+		purgeCache();
 
 			// clear the new C++ file system based cache
 			LLDiskCache::getInstance()->clearCache();
-		}
+	}
 		else
 		{
 			// purge excessive files from the new file system based cache
@@ -4270,18 +4410,10 @@ bool LLAppViewer::initCache()
 	LLSplashScreen::update(LLTrans::getString("StartupInitializingTextureCache"));
 
 	// Init the texture cache
-	// Allocate 80% of the cache size for textures
-	const S32 MB = 1024 * 1024;
-	const S64 MIN_CACHE_SIZE = 256 * MB;
-	const S64 MAX_CACHE_SIZE = 9984ll * MB;
+    // Allocate the remaining percent which is not allocated to the disk cache
+    const S64 texture_cache_size = S64(cache_total_size * texture_cache_percent / 100);
 
-	S64 cache_size = (S64)(gSavedSettings.getU32("CacheSize")) * MB;
-	cache_size = llclamp(cache_size, MIN_CACHE_SIZE, MAX_CACHE_SIZE);
-
-	S64 texture_cache_size = cache_size;
-
-	S64 extra = LLAppViewer::getTextureCache()->initCache(LL_PATH_CACHE, texture_cache_size, texture_cache_mismatch);
-	texture_cache_size -= extra;
+    LLAppViewer::getTextureCache()->initCache(LL_PATH_CACHE, texture_cache_size, texture_cache_mismatch);
 
 	LLVOCache::getInstance()->initCache(LL_PATH_CACHE, gSavedSettings.getU32("CacheNumberOfRegionsForObjects"), getObjectCacheVersion());
 
@@ -4290,7 +4422,7 @@ bool LLAppViewer::initCache()
 
 void LLAppViewer::addOnIdleCallback(const boost::function<void()>& cb)
 {
-	LLDeferredTaskList::instance().addTask(cb);
+	gMainloopWork.post(cb);
 }
 
 void LLAppViewer::loadKeyBindings()
@@ -4560,6 +4692,7 @@ static LLTrace::BlockTimerStatHandle FTM_HUD_EFFECTS("HUD Effects");
 ///////////////////////////////////////////////////////
 void LLAppViewer::idle()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_APP;
 	pingMainloopTimeout("Main:Idle");
 
 	// Update frame timers
@@ -4578,6 +4711,20 @@ void LLAppViewer::idle()
 	LLDirPickerThread::clearDead();
 	F32 dt_raw = idle_timer.getElapsedTimeAndResetF32();
 
+	// Service the WorkQueue we use for replies from worker threads.
+	// Use function statics for the timeslice setting so we only have to fetch
+	// and convert MainWorkTime once.
+	static F32 MainWorkTimeRaw = gSavedSettings.getF32("MainWorkTime");
+	static F32Milliseconds MainWorkTimeMs(MainWorkTimeRaw);
+	// MainWorkTime is specified in fractional milliseconds, but std::chrono
+	// uses integer representations. What if we want less than a microsecond?
+	// Use nanoseconds. We're very sure we will never need to specify a
+	// MainWorkTime that would be larger than we could express in
+	// std::chrono::nanoseconds.
+	static std::chrono::nanoseconds MainWorkTimeNanoSec{
+		std::chrono::nanoseconds::rep(MainWorkTimeMs.value() * 1000000)};
+	gMainloopWork.runFor(MainWorkTimeNanoSec);
+
 	// Cap out-of-control frame times
 	// Too low because in menus, swapping, debugger, etc.
 	// Too high because idle called with no objects in view, etc.
@@ -4631,7 +4778,7 @@ void LLAppViewer::idle()
 
 	if (!gDisconnected)
 	{
-		LL_RECORD_BLOCK_TIME(FTM_NETWORK);
+		LL_PROFILE_ZONE_NAMED_CATEGORY_NETWORK("network"); //LL_RECORD_BLOCK_TIME(FTM_NETWORK);
 		// Update spaceserver timeinfo
 	    LLWorld::getInstance()->setSpaceTimeUSec(LLWorld::getInstance()->getSpaceTimeUSec() + LLUnits::Seconds::fromValue(dt_raw));
 
@@ -4663,7 +4810,7 @@ void LLAppViewer::idle()
 							|| (agent_force_update_time > (1.0f / (F32) AGENT_FORCE_UPDATES_PER_SECOND));
 		if (force_update || (agent_update_time > (1.0f / (F32) AGENT_UPDATES_PER_SECOND)))
 		{
-			LL_RECORD_BLOCK_TIME(FTM_AGENT_UPDATE);
+			LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; //LL_RECORD_BLOCK_TIME(FTM_AGENT_UPDATE);
 			// Send avatar and camera info
 			mLastAgentControlFlags = gAgent.getControlFlags();
 			mLastAgentForceUpdate = force_update ? 0 : agent_force_update_time;
@@ -4767,13 +4914,18 @@ void LLAppViewer::idle()
 		}
 	}
 
+
+    // Update layonts, handle mouse events, tooltips, e t c
+    // updateUI() needs to be called even in case viewer disconected
+    // since related notification still needs handling and allows
+    // opening chat.
+    gViewerWindow->updateUI();
+
 	if (gDisconnected)
     {
 		return;
     }
 
-    gViewerWindow->updateUI();
-
 	if (gTeleportDisplay)
     {
 		return;
@@ -4900,8 +5052,10 @@ void LLAppViewer::idle()
 	// Here, particles are updated and drawables are moved.
 	//
 
-	LL_RECORD_BLOCK_TIME(FTM_WORLD_UPDATE);
-	gPipeline.updateMove();
+	{
+		LL_PROFILE_ZONE_NAMED_CATEGORY_APP("world update"); //LL_RECORD_BLOCK_TIME(FTM_WORLD_UPDATE);
+		gPipeline.updateMove();
+	}
 
 	LLWorld::getInstance()->updateParticles();
 
@@ -4940,7 +5094,7 @@ void LLAppViewer::idle()
 	LLAvatarRenderInfoAccountant::getInstance()->idle();
 
 	{
-		LL_RECORD_BLOCK_TIME(FTM_AUDIO_UPDATE);
+		LL_PROFILE_ZONE_NAMED_CATEGORY_APP("audio update"); //LL_RECORD_BLOCK_TIME(FTM_AUDIO_UPDATE);
 
 		if (gAudiop)
 		{
@@ -4949,14 +5103,10 @@ void LLAppViewer::idle()
 			audio_update_wind(false);
 
 			// this line actually commits the changes we've made to source positions, etc.
-			const F32 max_audio_decode_time = 0.002f; // 2 ms decode time
-			gAudiop->idle(max_audio_decode_time);
+			gAudiop->idle();
 		}
 	}
 
-	// Execute deferred tasks.
-	LLDeferredTaskList::instance().run();
-
 	// Handle shutdown process, for example,
 	// wait for floaters to close, send quit message,
 	// forcibly quit if it has taken too long
@@ -5184,6 +5334,7 @@ static LLTrace::BlockTimerStatHandle FTM_CHECK_REGION_CIRCUIT("Check Region Circ
 
 void LLAppViewer::idleNetwork()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
 	pingMainloopTimeout("idleNetwork");
 
 	gObjectList.mNumNewObjects = 0;
@@ -5191,7 +5342,7 @@ void LLAppViewer::idleNetwork()
 
 	if (!gSavedSettings.getBOOL("SpeedTest"))
 	{
-		LL_RECORD_BLOCK_TIME(FTM_IDLE_NETWORK); // decode
+		LL_PROFILE_ZONE_NAMED_CATEGORY_NETWORK("idle network"); //LL_RECORD_BLOCK_TIME(FTM_IDLE_NETWORK); // decode
 
 		LLTimer check_message_timer;
 		//  Read all available packets from network
@@ -5313,20 +5464,24 @@ void LLAppViewer::disconnectViewer()
 		gFloaterView->restoreAll();
 	}
 
-	if (LLSelectMgr::getInstance())
+	if (LLSelectMgr::instanceExists())
 	{
 		LLSelectMgr::getInstance()->deselectAll();
 	}
 
 	// save inventory if appropriate
-	gInventory.cache(gInventory.getRootFolderID(), gAgent.getID());
-	if (gInventory.getLibraryRootFolderID().notNull()
-		&& gInventory.getLibraryOwnerID().notNull())
-	{
-		gInventory.cache(
-			gInventory.getLibraryRootFolderID(),
-			gInventory.getLibraryOwnerID());
-	}
+    if (gInventory.isInventoryUsable()
+        && gAgent.getID().notNull()) // Shouldn't be null at this stage
+    {
+        gInventory.cache(gInventory.getRootFolderID(), gAgent.getID());
+        if (gInventory.getLibraryRootFolderID().notNull()
+            && gInventory.getLibraryOwnerID().notNull())
+        {
+            gInventory.cache(
+                gInventory.getLibraryRootFolderID(),
+                gInventory.getLibraryOwnerID());
+        }
+    }
 
 	saveNameCache();
 	if (LLExperienceCache::instanceExists())
@@ -5348,7 +5503,7 @@ void LLAppViewer::disconnectViewer()
 	// Now we just ask the LLWorld singleton to cleanly shut down.
 	if(LLWorld::instanceExists())
 	{
-		LLWorld::getInstance()->destroyClass();
+		LLWorld::getInstance()->resetClass();
 	}
 	LLVOCache::deleteSingleton();
 
@@ -5363,19 +5518,6 @@ void LLAppViewer::disconnectViewer()
 	LLUrlEntryParcel::setDisconnected(gDisconnected);
 }
 
-bool LLAppViewer::onChangeFrameLimit(LLSD const & evt)
-{
-	if (evt.asInteger() > 0)
-	{
-		mMinMicroSecPerFrame = (U64)(1000000.0f / F32(evt.asInteger()));
-	}
-	else
-	{
-		mMinMicroSecPerFrame = 0;
-	}
-	return false;
-}
-
 void LLAppViewer::forceErrorLLError()
 {
    	LL_ERRS() << "This is a deliberate llerror" << LL_ENDL;
diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h
index 0f06889d20b019217662b51f198e945a19ab6d7b..f28a90c70396e2866baaf51e5f7bf790584a44e7 100644
--- a/indra/newview/llappviewer.h
+++ b/indra/newview/llappviewer.h
@@ -50,6 +50,8 @@
 #include "lltimer.h"
 #include "llappcorehttp.h"
 
+#include <boost/signals2.hpp>
+
 class LLCommandLineParser;
 class LLFrameTimer;
 class LLPumpIO;
@@ -61,6 +63,11 @@ class LLViewerJoystick;
 class LLPurgeDiskCacheThread;
 class LLViewerRegion;
 
+namespace LL
+{
+    class ThreadPool;
+}
+
 extern LLTrace::BlockTimerStatHandle FTM_FRAME;
 
 class LLAppViewer : public LLApp
@@ -69,13 +76,13 @@ class LLAppViewer : public LLApp
 	LLAppViewer();
 	virtual ~LLAppViewer();
 
-    /**
-     * @brief Access to the LLAppViewer singleton.
-     * 
-     * The LLAppViewer singleton is created in main()/WinMain().
-     * So don't use it in pre-entry (static initialization) code.
-     */
-    static LLAppViewer* instance() {return sInstance; } 
+	/**
+	 * @brief Access to the LLAppViewer singleton.
+	 * 
+	 * The LLAppViewer singleton is created in main()/WinMain().
+	 * So don't use it in pre-entry (static initialization) code.
+	 */
+	static LLAppViewer* instance() {return sInstance; } 
 
 	//
 	// Main application logic
@@ -93,12 +100,13 @@ class LLAppViewer : public LLApp
     void earlyExit(const std::string& name, 
 				   const LLSD& substitutions = LLSD()); // Display an error dialog and forcibly quit.
 	void earlyExitNoNotify(); // Do not display error dialog then forcibly quit.
-    void abortQuit();  // Called to abort a quit request.
+	void abortQuit();  // Called to abort a quit request.
 
-    bool quitRequested() { return mQuitRequested; }
-    bool logoutRequestSent() { return mLogoutRequestSent; }
+	bool quitRequested() { return mQuitRequested; }
+	bool logoutRequestSent() { return mLogoutRequestSent; }
 	bool isSecondInstance() { return mSecondInstance; }
-    bool isUpdaterMissing() { return mUpdaterNotFound; }
+    bool isUpdaterMissing(); // In use by tests
+    bool waitForUpdater();
 
 	void writeDebugInfo(bool isStatic=true);
 
@@ -112,7 +120,7 @@ class LLAppViewer : public LLApp
 	virtual bool restoreErrorTrap() = 0; // Require platform specific override to reset error handling mechanism.
 	                                     // return false if the error trap needed restoration.
 	static void handleViewerCrash(); // Hey! The viewer crashed. Do this, soon.
-    void checkForCrash();
+	void checkForCrash();
     
 	// Thread accessors
 	static LLTextureCache* getTextureCache() { return sTextureCache; }
@@ -122,28 +130,29 @@ class LLAppViewer : public LLApp
 
 	static U32 getTextureCacheVersion() ;
 	static U32 getObjectCacheVersion() ;
+    static U32 getDiskCacheVersion() ;
 
 	const std::string& getSerialNumber() { return mSerialNumber; }
-	
+
 	bool getPurgeCache() const { return mPurgeCache; }
-	
+
 	std::string getSecondLifeTitle() const; // The Second Life title.
 	std::string getWindowTitle() const; // The window display name.
 
-    void forceDisconnect(const std::string& msg); // Force disconnection, with a message to the user.
-    void badNetworkHandler(); // Cause a crash state due to bad network packet.
+	void forceDisconnect(const std::string& msg); // Force disconnection, with a message to the user.
+	void badNetworkHandler(); // Cause a crash state due to bad network packet.
 
 	bool hasSavedFinalSnapshot() { return mSavedFinalSnapshot; }
 	void saveFinalSnapshot(); 
 
-    void loadNameCache();
-    void saveNameCache();
+	void loadNameCache();
+	void saveNameCache();
 
 	void loadExperienceCache();
 	void saveExperienceCache();
 
 	void removeMarkerFiles();
-	
+
 	void removeDumpDir();
     // LLAppViewer testing helpers.
     // *NOTE: These will potentially crash the viewer. Only for debugging.
@@ -187,22 +196,26 @@ class LLAppViewer : public LLApp
 	// *NOTE:Mani Fix this for login abstraction!!
 	void handleLoginComplete();
 
-    LLAllocator & getAllocator() { return mAlloc; }
+	LLAllocator & getAllocator() { return mAlloc; }
 
 	// On LoginCompleted callback
 	typedef boost::signals2::signal<void (void)> login_completed_signal_t;
 	login_completed_signal_t mOnLoginCompleted;
-	boost::signals2::connection setOnLoginCompletedCallback( const login_completed_signal_t::slot_type& cb ) { return mOnLoginCompleted.connect(cb); } 
+	boost::signals2::connection setOnLoginCompletedCallback( const login_completed_signal_t::slot_type& cb )
+	{
+		return mOnLoginCompleted.connect(cb);
+	}
 
 	void addOnIdleCallback(const boost::function<void()>& cb); // add a callback to fire (once) when idle
 
+    void initGeneralThread();
 	void purgeUserDataOnExit() { mPurgeUserDataOnExit = true; }
 	void purgeCache(); // Clear the local cache. 
 	void purgeCacheImmediate(); //clear local cache immediately.
 	S32  updateTextureThreads(F32 max_time);
 
 	void loadKeyBindings();
-	
+
 	// mute/unmute the system's master audio
 	virtual void setMasterSystemAudioMute(bool mute);
 	virtual bool getMasterSystemAudioMute();	
@@ -214,7 +227,7 @@ class LLAppViewer : public LLApp
 	// llcorehttp init/shutdown/config information.
 	LLAppCoreHttp & getAppCoreHttp()			{ return mAppCoreHttp; }
 
-    void updateNameLookupUrl(const LLViewerRegion* regionp);
+	void updateNameLookupUrl(const LLViewerRegion* regionp);
 
 protected:
 	virtual bool initWindow(); // Initialize the viewer's window.
@@ -225,7 +238,7 @@ class LLAppViewer : public LLApp
 	virtual bool sendURLToOtherInstance(const std::string& url);
 
 	virtual bool initParseCommandLine(LLCommandLineParser& clp) 
-        { return true; } // Allow platforms to specify the command line args.
+		{ return true; } // Allow platforms to specify the command line args.
 
 	virtual std::string generateSerialNumber() = 0; // Platforms specific classes generate this.
 
@@ -253,24 +266,21 @@ class LLAppViewer : public LLApp
 	void processMarkerFiles(); 
 	static void recordMarkerVersion(LLAPRFile& marker_file);
 	bool markerIsSameVersion(const std::string& marker_name) const;
-	
-    void idle(); 
-    void idleShutdown();
+
+	void idle(); 
+	void idleShutdown();
 	// update avatar SLID and display name caches
-	void idleExperienceCache();
 	void idleNameCache();
-    void idleNetwork();
-
-    void sendLogoutRequest();
-    void disconnectViewer();
+	void idleNetwork();
 
-	bool onChangeFrameLimit(LLSD const & evt);
+	void sendLogoutRequest();
+	void disconnectViewer();
 
 	// *FIX: the app viewer class should be some sort of singleton, no?
 	// Perhaps its child class is the singleton and this should be an abstract base.
 	static LLAppViewer* sInstance; 
 
-    bool mSecondInstance; // Is this a second instance of the app?
+	bool mSecondInstance; // Is this a second instance of the app?
 	bool mUpdaterNotFound; // True when attempt to start updater failed
 
 	std::string mMarkerFileName;
@@ -288,6 +298,7 @@ class LLAppViewer : public LLApp
 	static LLImageDecodeThread* sImageDecodeThread; 
 	static LLTextureFetch* sTextureFetch;
 	static LLPurgeDiskCacheThread* sPurgeDiskCacheThread;
+    LL::ThreadPool* mGeneralThreadPool;
 
 	S32 mNumSessions;
 
@@ -302,8 +313,8 @@ class LLAppViewer : public LLApp
 
 	boost::optional<U32> mForceGraphicsLevel;
 
-    bool mQuitRequested;				// User wants to quit, may have modified documents open.
-    bool mLogoutRequestSent;			// Disconnect message sent to simulator, no longer safe to send messages to the sim.
+	bool mQuitRequested;				// User wants to quit, may have modified documents open.
+	bool mLogoutRequestSent;			// Disconnect message sent to simulator, no longer safe to send messages to the sim.
 	U32 mLastAgentControlFlags;
 	F32 mLastAgentForceUpdate;
 	struct SettingsFiles* mSettingsLocationList;
@@ -317,15 +328,12 @@ class LLAppViewer : public LLApp
 	bool mAgentRegionLastAlive;
 	LLUUID mAgentRegionLastID;
 
-    LLAllocator mAlloc;
+	LLAllocator mAlloc;
 
 	// llcorehttp library init/shutdown helper
 	LLAppCoreHttp mAppCoreHttp;
 
-        bool mIsFirstRun;
-	U64 mMinMicroSecPerFrame; // frame throttling
-
-
+	bool mIsFirstRun;
 };
 
 // consts from viewer.h
diff --git a/indra/newview/llappviewerwin32.cpp b/indra/newview/llappviewerwin32.cpp
index ee533875b6c3e7a7f7823d71acb44ecff6b88cf0..a39ec7f51be6a58a43bda9da7543a0c03aca2089 100644
--- a/indra/newview/llappviewerwin32.cpp
+++ b/indra/newview/llappviewerwin32.cpp
@@ -329,6 +329,11 @@ int APIENTRY WINMAIN(HINSTANCE hInstance,
                      PWSTR     pCmdLine,
                      int       nCmdShow)
 {
+    // Call Tracy first thing to have it allocate memory
+    // https://github.com/wolfpld/tracy/issues/196
+    LL_PROFILER_FRAME_END;
+    LL_PROFILER_SET_THREAD_NAME("App");
+
 	const S32 MAX_HEAPS = 255;
 	DWORD heap_enable_lfh_error[MAX_HEAPS];
 	S32 num_heaps = 0;
diff --git a/indra/newview/llappviewerwin32.h b/indra/newview/llappviewerwin32.h
index 82b6b0c77c8089fa8ad911a481984f8b1df43273..ab52bf15f9e7d7fa51643dff8e526244c68b4fe4 100644
--- a/indra/newview/llappviewerwin32.h
+++ b/indra/newview/llappviewerwin32.h
@@ -51,8 +51,8 @@ class LLAppViewerWin32 : public LLAppViewer
 	bool initHardwareTest() override; // Win32 uses DX9 to test hardware.
 	bool initParseCommandLine(LLCommandLineParser& clp) override;
 
-	virtual bool beingDebugged();
-	virtual bool restoreErrorTrap();
+	bool beingDebugged() override;
+	bool restoreErrorTrap() override;
 
 	bool sendURLToOtherInstance(const std::string& url) override;
 
diff --git a/indra/newview/llaudiosourcevo.cpp b/indra/newview/llaudiosourcevo.cpp
index 4b6c855bde3427eb74aabd2e4432fb23629bd385..1846238d93e35e50c93114d03ee12ae9160ef4d7 100644
--- a/indra/newview/llaudiosourcevo.cpp
+++ b/indra/newview/llaudiosourcevo.cpp
@@ -34,6 +34,7 @@
 #include "llmutelist.h"
 #include "llviewercontrol.h"
 #include "llviewerparcelmgr.h"
+#include "llvoavatarself.h"
 
 LLAudioSourceVO::LLAudioSourceVO(const LLUUID &sound_id, const LLUUID& owner_id, const F32 gain, LLViewerObject *objectp)
 	:	LLAudioSource(sound_id, owner_id, gain, LLAudioEngine::AUDIO_TYPE_SFX), 
@@ -141,11 +142,36 @@ void LLAudioSourceVO::updateMute()
 	LLVector3d pos_global = getPosGlobal();
 
 	F32 cutoff = mObjectp->getSoundCutOffRadius();
-	if ((cutoff > 0.1f && !isInCutOffRadius(pos_global, cutoff)) // consider cutoff below 0.1m as off
-		|| !LLViewerParcelMgr::getInstance()->canHearSound(pos_global))
-	{
-		mute = true;
-	}
+    // Object can specify radius at which it turns off
+    // consider cutoff below 0.1m as 'cutoff off'
+    if (cutoff > 0.1f && !isInCutOffRadius(pos_global, cutoff))
+    {
+        mute = true;
+    }
+    // check if parcel allows sounds to pass border
+    else if (!LLViewerParcelMgr::getInstance()->canHearSound(pos_global))
+    {
+        if (isAgentAvatarValid() && gAgentAvatarp->getParent())
+        {
+            // Check if agent is riding this object
+            // Agent can ride something out of region border and canHearSound
+            // will treat object as not being part of agent's parcel.
+            LLViewerObject *sound_root = (LLViewerObject*)mObjectp->getRoot();
+            LLViewerObject *agent_root = (LLViewerObject*)gAgentAvatarp->getRoot();
+            if (sound_root != agent_root)
+            {
+                mute = true;
+            }
+            else
+            {
+                LL_INFOS() << "roots identical" << LL_ENDL;
+            }
+        }
+        else
+        {
+            mute = true;
+        }
+    }
 
 	if (!mute)
 	{
diff --git a/indra/newview/llavataractions.cpp b/indra/newview/llavataractions.cpp
index 1797d2dd6e525015f2bd40c9af31d8e8e2d1532d..3e450e6dec1072b5e65e5deedf70290632f8327a 100644
--- a/indra/newview/llavataractions.cpp
+++ b/indra/newview/llavataractions.cpp
@@ -48,6 +48,7 @@
 #include "llfloatergroups.h"
 #include "llfloaterreg.h"
 #include "llfloaterpay.h"
+#include "llfloaterprofile.h"
 #include "llfloatersidepanelcontainer.h"
 #include "llfloaterwebcontent.h"
 #include "llfloaterworldmap.h"
@@ -62,11 +63,14 @@
 #include "llnotificationsutil.h"	// for LLNotificationsUtil
 #include "llpaneloutfitedit.h"
 #include "llpanelprofile.h"
+#include "llparcel.h"
 #include "llrecentpeople.h"
 #include "lltrans.h"
 #include "llviewercontrol.h"
 #include "llviewerobjectlist.h"
 #include "llviewermessage.h"	// for handle_lure
+#include "llviewernetwork.h" //LLGridManager
+#include "llviewerparcelmgr.h"
 #include "llviewerregion.h"
 #include "lltrans.h"
 #include "llcallingcard.h"
@@ -74,6 +78,7 @@
 #include "llsidepanelinventory.h"
 #include "llavatarname.h"
 #include "llagentui.h"
+#include "lluiusage.h"
 
 // Flags for kick message
 const U32 KICK_FLAGS_DEFAULT	= 0x0;
@@ -81,6 +86,19 @@ const U32 KICK_FLAGS_FREEZE		= 1 << 0;
 const U32 KICK_FLAGS_UNFREEZE	= 1 << 1;
 
 
+std::string getProfileURL(const std::string& agent_name, bool feed_only)
+{
+    std::string url = "[WEB_PROFILE_URL][AGENT_NAME][FEED_ONLY]";
+	LLSD subs;
+	subs["WEB_PROFILE_URL"] = LLGridManager::getInstance()->getWebProfileURL();
+	subs["AGENT_NAME"] = agent_name;
+    subs["FEED_ONLY"] = feed_only ? "/?feed_only=true" : "";
+	url = LLWeb::expandURLSubstitutions(url, subs);
+	LLStringUtil::toLower(url);
+	return url;
+}
+
+
 // static
 void LLAvatarActions::requestFriendshipDialog(const LLUUID& id, const std::string& name)
 {
@@ -96,7 +114,7 @@ void LLAvatarActions::requestFriendshipDialog(const LLUUID& id, const std::strin
 	payload["id"] = id;
 	payload["name"] = name;
     
-    	LLNotificationsUtil::add("AddFriendWithMessage", args, payload, &callbackAddFriendWithMessage);
+	LLNotificationsUtil::add("AddFriendWithMessage", args, payload, &callbackAddFriendWithMessage);
 
 	// add friend to recent people list
 	LLRecentPeople::instance().add(id);
@@ -316,57 +334,144 @@ void LLAvatarActions::startConference(const uuid_vec_t& ids, const LLUUID& float
 	make_ui_sound("UISndStartIM");
 }
 
-static const char* get_profile_floater_name(const LLUUID& avatar_id)
+// static
+void LLAvatarActions::showProfile(const LLUUID& avatar_id)
 {
-	// Use different floater XML for our profile to be able to save its rect.
-	return avatar_id == gAgentID ? "my_profile" : "profile";
+	if (avatar_id.notNull())
+	{
+		LLFloaterReg::showInstance("profile", LLSD().with("id", avatar_id));
+	}
 }
 
-static void on_avatar_name_show_profile(const LLUUID& agent_id, const LLAvatarName& av_name)
+// static
+void LLAvatarActions::showPicks(const LLUUID& avatar_id)
 {
-	std::string url = getProfileURL(av_name.getAccountName());
+	if (avatar_id.notNull())
+	{
+        LLFloaterProfile* profilefloater = dynamic_cast<LLFloaterProfile*>(LLFloaterReg::showInstance("profile", LLSD().with("id", avatar_id)));
+        if (profilefloater)
+        {
+            profilefloater->showPick();
+        }
+	}
+}
 
-	// PROFILES: open in webkit window
-	LLFloaterWebContent::Params p;
-	p.url(url).id(agent_id.asString());
-	LLFloaterReg::showInstance(get_profile_floater_name(agent_id), p);
+// static
+void LLAvatarActions::showPick(const LLUUID& avatar_id, const LLUUID& pick_id)
+{
+	if (avatar_id.notNull())
+	{
+        LLFloaterProfile* profilefloater = dynamic_cast<LLFloaterProfile*>(LLFloaterReg::showInstance("profile", LLSD().with("id", avatar_id)));
+        if (profilefloater)
+        {
+            profilefloater->showPick(pick_id);
+        }
+	}
+}
+
+// static
+void LLAvatarActions::createPick()
+{
+    LLFloaterProfile* profilefloater = dynamic_cast<LLFloaterProfile*>(LLFloaterReg::showInstance("profile", LLSD().with("id", gAgent.getID())));
+    LLViewerRegion* region = gAgent.getRegion();
+    if (profilefloater && region)
+    {
+        LLPickData data;
+        data.pos_global = gAgent.getPositionGlobal();
+        data.sim_name = region->getName();
+
+        LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel();
+        if (parcel)
+        {
+            data.name = parcel->getName();
+            data.desc = parcel->getDesc();
+            data.snapshot_id = parcel->getSnapshotID();
+            data.parcel_id = parcel->getID();
+        }
+        else
+        {
+            data.name = region->getName();
+        }
+
+        profilefloater->createPick(data);
+    }
 }
 
 // static
-void LLAvatarActions::showProfile(const LLUUID& id)
+bool LLAvatarActions::isPickTabSelected(const LLUUID& avatar_id)
 {
-	if (id.notNull())
+    if (avatar_id.notNull())
+    {
+        LLFloaterProfile* profilefloater = LLFloaterReg::findTypedInstance<LLFloaterProfile>("profile", LLSD().with("id", avatar_id));
+        if (profilefloater)
+        {
+            return profilefloater->isPickTabSelected();
+        }
+    }
+    return false;
+}
+
+// static
+void LLAvatarActions::showClassifieds(const LLUUID& avatar_id)
+{
+	if (avatar_id.notNull())
+	{
+        LLFloaterProfile* profilefloater = dynamic_cast<LLFloaterProfile*>(LLFloaterReg::showInstance("profile", LLSD().with("id", avatar_id)));
+        if (profilefloater)
+        {
+            profilefloater->showClassified();
+        }
+	}
+}
+
+// static
+void LLAvatarActions::showClassified(const LLUUID& avatar_id, const LLUUID& classified_id, bool edit)
+{
+	if (avatar_id.notNull())
 	{
-		LLAvatarNameCache::get(id, boost::bind(&on_avatar_name_show_profile, _1, _2));
+        LLFloaterProfile* profilefloater = dynamic_cast<LLFloaterProfile*>(LLFloaterReg::showInstance("profile", LLSD().with("id", avatar_id)));
+        if (profilefloater)
+        {
+            profilefloater->showClassified(classified_id, edit);
+        }
 	}
 }
 
+// static
+void LLAvatarActions::createClassified()
+{
+    LLFloaterProfile* profilefloater = dynamic_cast<LLFloaterProfile*>(LLFloaterReg::showInstance("profile", LLSD().with("id", gAgent.getID())));
+    if (profilefloater)
+    {
+        profilefloater->createClassified();
+    }
+}
+
 //static 
-bool LLAvatarActions::profileVisible(const LLUUID& id)
+bool LLAvatarActions::profileVisible(const LLUUID& avatar_id)
 {
 	LLSD sd;
-	sd["id"] = id;
-	LLFloater* browser = getProfileFloater(id);
-	return browser && browser->isShown();
+	sd["id"] = avatar_id;
+	LLFloater* floater = getProfileFloater(avatar_id);
+	return floater && floater->isShown();
 }
 
 //static
-LLFloater* LLAvatarActions::getProfileFloater(const LLUUID& id)
+LLFloater* LLAvatarActions::getProfileFloater(const LLUUID& avatar_id)
 {
-	LLFloaterWebContent *browser = dynamic_cast<LLFloaterWebContent*>
-		(LLFloaterReg::findInstance(get_profile_floater_name(id), LLSD().with("id", id)));
-	return browser;
+    LLFloaterProfile* floater = LLFloaterReg::findTypedInstance<LLFloaterProfile>("profile", LLSD().with("id", avatar_id));
+    return floater;
 }
 
 //static 
-void LLAvatarActions::hideProfile(const LLUUID& id)
+void LLAvatarActions::hideProfile(const LLUUID& avatar_id)
 {
 	LLSD sd;
-	sd["id"] = id;
-	LLFloater* browser = getProfileFloater(id);
-	if (browser)
+	sd["id"] = avatar_id;
+	LLFloater* floater = getProfileFloater(avatar_id);
+	if (floater)
 	{
-		browser->closeFloater();
+		floater->closeFloater();
 	}
 }
 
@@ -990,7 +1095,7 @@ bool LLAvatarActions::canShareSelectedItems(LLInventoryPanel* inv_panel /* = NUL
 }
 
 // static
-void LLAvatarActions::toggleBlock(const LLUUID& id)
+bool LLAvatarActions::toggleBlock(const LLUUID& id)
 {
 	LLAvatarName av_name;
 	LLAvatarNameCache::get(id, &av_name);
@@ -1000,10 +1105,12 @@ void LLAvatarActions::toggleBlock(const LLUUID& id)
 	if (LLMuteList::getInstance()->isMuted(mute.mID, mute.mName))
 	{
 		LLMuteList::getInstance()->remove(mute);
+		return false;
 	}
 	else
 	{
 		LLMuteList::getInstance()->add(mute);
+		return true;
 	}
 }
 
@@ -1312,6 +1419,8 @@ bool LLAvatarActions::handleUnfreeze(const LLSD& notification, const LLSD& respo
 void LLAvatarActions::requestFriendship(const LLUUID& target_id, const std::string& target_name, const std::string& message)
 {
 	const LLUUID calling_card_folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_CALLINGCARD);
+	LLUIUsage::instance().logCommand("Agent.SendFriendRequest");
+
 	send_improved_im(target_id,
 					 target_name,
 					 message,
diff --git a/indra/newview/llavataractions.h b/indra/newview/llavataractions.h
index 7c721076c8810777ad4276ec8d567b32b6c5d66e..86183cc1191f2e1f3596117d0c01c2f662f0438a 100644
--- a/indra/newview/llavataractions.h
+++ b/indra/newview/llavataractions.h
@@ -38,6 +38,8 @@ class LLInventoryPanel;
 class LLFloater;
 class LLView;
 
+std::string getProfileURL(const std::string& agent_name, bool feed_only = false);
+
 /**
  * Friend-related actions (add, remove, offer teleport, etc)
  */
@@ -91,13 +93,20 @@ class LLAvatarActions
 	 */
 	static void startConference(const uuid_vec_t& ids, const LLUUID& floater_id = LLUUID::null);
 
-	/**
-	 * Show avatar profile.
-	 */
-	static void showProfile(const LLUUID& id);
-	static void hideProfile(const LLUUID& id);
-	static bool profileVisible(const LLUUID& id);
-	static LLFloater* getProfileFloater(const LLUUID& id);
+    /**
+     * Show avatar profile.
+     */
+    static void showProfile(const LLUUID& avatar_id);
+    static void showPicks(const LLUUID& avatar_id);
+    static void showPick(const LLUUID& avatar_id, const LLUUID& pick_id);
+    static void createPick();
+    static void showClassifieds(const LLUUID& avatar_id);
+    static void showClassified(const LLUUID& avatar_id, const LLUUID& classified_id, bool edit = false);
+    static void createClassified();
+    static void hideProfile(const LLUUID& avatar_id);
+    static bool profileVisible(const LLUUID& avatar_id);
+    static bool isPickTabSelected(const LLUUID& avatar_id);
+    static LLFloater* getProfileFloater(const LLUUID& avatar_id);
 
 	/**
 	 * Show avatar on world map.
@@ -126,9 +135,10 @@ class LLAvatarActions
 	static void shareWithAvatars(LLView * panel);
 
 	/**
-	 * Block/unblock the avatar.
+	 * Block/unblock the avatar by id.
+	 * Returns true if blocked, returns false if unblocked
 	 */
-	static void toggleBlock(const LLUUID& id);
+	static bool toggleBlock(const LLUUID& id);
 
 	/**
 	 * Mute/unmute avatar.
diff --git a/indra/newview/llavatarlist.cpp b/indra/newview/llavatarlist.cpp
index b0715a3afd38e54e22a6905e6371a6d684d00fee..c0990d9d113959d70839fcbdd7bb753d0d2688fa 100644
--- a/indra/newview/llavatarlist.cpp
+++ b/indra/newview/llavatarlist.cpp
@@ -241,21 +241,6 @@ void LLAvatarList::setDirty(bool val /*= true*/, bool force_refresh /*= false*/)
 	}
 }
 
-void LLAvatarList::addAvalineItem(const LLUUID& item_id, const LLUUID& session_id, const std::string& item_name)
-{
-	LL_DEBUGS("Avaline") << "Adding avaline item into the list: " << item_name << "|" << item_id << ", session: " << session_id << LL_ENDL;
-	LLAvalineListItem* item = new LLAvalineListItem(/*hide_number=*/false);
-	item->setAvatarId(item_id, session_id, true, false);
-	item->setName(item_name);
-	item->showLastInteractionTime(mShowLastInteractionTime);
-	item->showSpeakingIndicator(mShowSpeakingIndicator);
-	item->setOnline(false);
-
-	addItem(item, item_id);
-	mIDs.push_back(item_id);
-	sort();
-}
-
 //////////////////////////////////////////////////////////////////////////
 // PROTECTED SECTION
 //////////////////////////////////////////////////////////////////////////
@@ -296,18 +281,10 @@ void LLAvatarList::refresh()
 			{
 				// *NOTE: If you change the UI to show a different string,
 				// be sure to change the filter code below.
-				if (LLRecentPeople::instance().isAvalineCaller(buddy_id))
-				{
-					const LLSD& call_data = LLRecentPeople::instance().getData(buddy_id);
-					addAvalineItem(buddy_id, call_data["session_id"].asUUID(), call_data["call_number"].asString());
-				}
-				else
-				{
-					std::string display_name = getAvatarName(av_name);
-					addNewItem(buddy_id, 
-						display_name.empty() ? waiting_str : display_name, 
-						LLAvatarTracker::instance().isBuddyOnline(buddy_id));
-				}
+				std::string display_name = getAvatarName(av_name);
+				addNewItem(buddy_id, 
+					display_name.empty() ? waiting_str : display_name, 
+					LLAvatarTracker::instance().isBuddyOnline(buddy_id));
 				
 				modified = true;
 				nadded++;
@@ -463,7 +440,7 @@ void LLAvatarList::addNewItem(const LLUUID& id, const std::string& name, BOOL is
 BOOL LLAvatarList::handleRightMouseDown(S32 x, S32 y, MASK mask)
 {
 	BOOL handled = LLUICtrl::handleRightMouseDown(x, y, mask);
-	if ( mContextMenu && !isAvalineItemSelected())
+	if ( mContextMenu)
 	{
 		uuid_vec_t selected_uuids;
 		getSelectedUUIDs(selected_uuids);
@@ -523,21 +500,6 @@ BOOL LLAvatarList::handleHover(S32 x, S32 y, MASK mask)
 	return handled;
 }
 
-bool LLAvatarList::isAvalineItemSelected()
-{
-	std::vector<LLPanel*> selected_items;
-	getSelectedItems(selected_items);
-	std::vector<LLPanel*>::iterator it = selected_items.begin();
-	
-	for(; it != selected_items.end(); ++it)
-	{
-		if (dynamic_cast<LLAvalineListItem*>(*it))
-			return true;
-	}
-
-	return false;
-}
-
 void LLAvatarList::setVisible(BOOL visible)
 {
 	if ( visible == FALSE && mContextMenu )
@@ -626,63 +588,3 @@ bool LLAvatarItemAgentOnTopComparator::doCompare(const LLAvatarListItem* avatar_
 	}
 	return LLAvatarItemNameComparator::doCompare(avatar_item1,avatar_item2);
 }
-
-/************************************************************************/
-/*             class LLAvalineListItem                                  */
-/************************************************************************/
-LLAvalineListItem::LLAvalineListItem(bool hide_number/* = true*/) : LLAvatarListItem(false)
-, mIsHideNumber(hide_number)
-{
-	// should not use buildPanel from the base class to ensure LLAvalineListItem::postBuild is called.
-	buildFromFile( "panel_avatar_list_item.xml");
-}
-
-BOOL LLAvalineListItem::postBuild()
-{
-	BOOL rv = LLAvatarListItem::postBuild();
-
-	if (rv)
-	{
-		setOnline(true);
-		showLastInteractionTime(false);
-		setShowProfileBtn(false);
-		setShowInfoBtn(false);
-		mAvatarIcon->setValue("Avaline_Icon");
-		mAvatarIcon->setToolTip(std::string(""));
-	}
-	return rv;
-}
-
-// to work correctly this method should be called AFTER setAvatarId for avaline callers with hidden phone number
-void LLAvalineListItem::setName(const std::string& name)
-{
-	if (mIsHideNumber)
-	{
-		static U32 order = 0;
-		typedef std::map<LLUUID, U32> avaline_callers_nums_t;
-		static avaline_callers_nums_t mAvalineCallersNums;
-
-		llassert(getAvatarId() != LLUUID::null);
-
-		const LLUUID &uuid = getAvatarId();
-
-		if (mAvalineCallersNums.find(uuid) == mAvalineCallersNums.end())
-		{
-			mAvalineCallersNums[uuid] = ++order;
-			LL_DEBUGS("Avaline") << "Set name for new avaline caller: " << uuid << ", order: " << order << LL_ENDL;
-		}
-		LLStringUtil::format_map_t args;
-		args["[ORDER]"] = llformat("%u", mAvalineCallersNums[uuid]);
-		std::string hidden_name = LLTrans::getString("AvalineCaller", args);
-
-		LL_DEBUGS("Avaline") << "Avaline caller: " << uuid << ", name: " << hidden_name << LL_ENDL;
-		LLAvatarListItem::setAvatarName(hidden_name);
-		LLAvatarListItem::setAvatarToolTip(hidden_name);
-	}
-	else
-	{
-		const std::string& formatted_phone = LLTextUtil::formatPhoneNumber(name);
-		LLAvatarListItem::setAvatarName(formatted_phone);
-		LLAvatarListItem::setAvatarToolTip(formatted_phone);
-	}
-}
diff --git a/indra/newview/llavatarlist.h b/indra/newview/llavatarlist.h
index 1a672c279b1d94cec40d6f2fdc8a00dea0e5c372..48b0e70454c8d42b2ba4c1e980eb8eabca04b109 100644
--- a/indra/newview/llavatarlist.h
+++ b/indra/newview/llavatarlist.h
@@ -98,7 +98,6 @@ class LLAvatarList : public LLFlatListViewEx
 
 	virtual S32 notifyParent(const LLSD& info);
 
-	void addAvalineItem(const LLUUID& item_id, const LLUUID& session_id, const std::string& item_name);
 	void handleDisplayNamesOptionChanged();
 
 	void setShowCompleteName(bool show) { mShowCompleteName = show;};
@@ -118,8 +117,6 @@ class LLAvatarList : public LLFlatListViewEx
 
 private:
 
-	bool isAvalineItemSelected();
-
 	bool mIgnoreOnlineStatus;
 	bool mShowLastInteractionTime;
 	bool mDirty;
@@ -189,27 +186,4 @@ class LLAvatarItemAgentOnTopComparator : public LLAvatarItemNameComparator
 	virtual bool doCompare(const LLAvatarListItem* avatar_item1, const LLAvatarListItem* avatar_item2) const;
 };
 
-/**
- * Represents Avaline caller in Avatar list in Voice Control Panel and group chats.
- */
-class LLAvalineListItem : public LLAvatarListItem
-{
-public:
-
-	/**
-	 * Constructor
-	 *
-	 * @param hide_number - flag indicating if number should be hidden.
-	 *		In this case It will be shown as "Avaline Caller 1", "Avaline Caller 1", etc.
-	 */
-	LLAvalineListItem(bool hide_number = true);
-
-	/*virtual*/ BOOL postBuild();
-
-	/*virtual*/ void setName(const std::string& name);
-
-private:
-	bool mIsHideNumber;
-};
-
 #endif // LL_LLAVATARLIST_H
diff --git a/indra/newview/llavatarpropertiesprocessor.cpp b/indra/newview/llavatarpropertiesprocessor.cpp
index f41eb3daf4286369ca565c4649ecbb8192ca7ff3..dd0d06a8c8fcc9e37ada47d6263919f9b22f1f53 100644
--- a/indra/newview/llavatarpropertiesprocessor.cpp
+++ b/indra/newview/llavatarpropertiesprocessor.cpp
@@ -36,6 +36,7 @@
 #include "llstartup.h"
 
 // Linden library includes
+#include "llavataractions.h" // for getProfileUrl
 #include "lldate.h"
 #include "lltrans.h"
 #include "llui.h"				// LLUI::getLanguage()
@@ -94,54 +95,98 @@ void LLAvatarPropertiesProcessor::removeObserver(const LLUUID& avatar_id, LLAvat
 	}
 }
 
-
-void LLAvatarPropertiesProcessor::sendGenericRequest(const LLUUID& avatar_id, EAvatarProcessorType type, const std::string method)
+void LLAvatarPropertiesProcessor::sendRequest(const LLUUID& avatar_id, EAvatarProcessorType type, const std::string &method)
 {
+    // this is the startup state when send_complete_agent_movement() message is sent.
+    // Before this messages won't work so don't bother trying
+    if (LLStartUp::getStartupState() <= STATE_AGENT_SEND)
+    {
+        return;
+    }
+
+    if (avatar_id.isNull())
+    {
+        return;
+    }
+
 	// Suppress duplicate requests while waiting for a response from the network
 	if (isPendingRequest(avatar_id, type))
 	{
 		// waiting for a response, don't re-request
 		return;
 	}
-	// indicate we're going to make a request
-	addPendingRequest(avatar_id, type);
 
-	std::vector<std::string> strings;
-	strings.push_back( avatar_id.asString() );
-	send_generic_message(method, strings);
+    std::string cap;
+
+    switch (type)
+    {
+    case APT_PROPERTIES:
+        // indicate we're going to make a request
+        sendAvatarPropertiesRequestMessage(avatar_id);
+        // can use getRegionCapability("AgentProfile"), but it is heavy
+        // initAgentProfileCapRequest(avatar_id, cap);
+        break;
+    case APT_PICKS:
+    case APT_GROUPS:
+    case APT_NOTES:
+        if (cap.empty())
+        {
+            // indicate we're going to make a request
+            sendGenericRequest(avatar_id, type, method);
+        }
+        else
+        {
+            initAgentProfileCapRequest(avatar_id, cap);
+        }
+        break;
+    default:
+        sendGenericRequest(avatar_id, type, method);
+        break;
+    }
 }
 
-void LLAvatarPropertiesProcessor::sendAvatarPropertiesRequest(const LLUUID& avatar_id)
+void LLAvatarPropertiesProcessor::sendGenericRequest(const LLUUID& avatar_id, EAvatarProcessorType type, const std::string &method)
 {
-	// this is the startup state when send_complete_agent_movement() message is sent.
-	// Before this, the AvatarPropertiesRequest message  
-	// won't work so don't bother trying
-	if (LLStartUp::getStartupState() <= STATE_AGENT_SEND)
-	{
-		return;
-	}
+    // indicate we're going to make a request
+    addPendingRequest(avatar_id, type);
 
-	if (isPendingRequest(avatar_id, APT_PROPERTIES))
-	{
-		// waiting for a response, don't re-request
-		return;
-	}
-	// indicate we're going to make a request
-	addPendingRequest(avatar_id, APT_PROPERTIES);
+    std::vector<std::string> strings;
+    strings.push_back(avatar_id.asString());
+    send_generic_message(method, strings);
+}
 
-	LLMessageSystem *msg = gMessageSystem;
+void LLAvatarPropertiesProcessor::sendAvatarPropertiesRequestMessage(const LLUUID& avatar_id)
+{
+    addPendingRequest(avatar_id, APT_PROPERTIES);
 
-	msg->newMessageFast(_PREHASH_AvatarPropertiesRequest);
-	msg->nextBlockFast( _PREHASH_AgentData);
-	msg->addUUIDFast(   _PREHASH_AgentID, gAgent.getID() );
-	msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
-	msg->addUUIDFast(   _PREHASH_AvatarID, avatar_id);
-	gAgent.sendReliableMessage();
+    LLMessageSystem *msg = gMessageSystem;
+
+    msg->newMessageFast(_PREHASH_AvatarPropertiesRequest);
+    msg->nextBlockFast(_PREHASH_AgentData);
+    msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+    msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+    msg->addUUIDFast(_PREHASH_AvatarID, avatar_id);
+    gAgent.sendReliableMessage();
+}
+
+void LLAvatarPropertiesProcessor::initAgentProfileCapRequest(const LLUUID& avatar_id, const std::string& cap_url)
+{
+    addPendingRequest(avatar_id, APT_PROPERTIES);
+    addPendingRequest(avatar_id, APT_PICKS);
+    addPendingRequest(avatar_id, APT_GROUPS);
+    addPendingRequest(avatar_id, APT_NOTES);
+    LLCoros::instance().launch("requestAgentUserInfoCoro",
+        boost::bind(requestAvatarPropertiesCoro, cap_url, avatar_id));
+}
+
+void LLAvatarPropertiesProcessor::sendAvatarPropertiesRequest(const LLUUID& avatar_id)
+{
+    sendRequest(avatar_id, APT_PROPERTIES, "AvatarPropertiesRequest");
 }
 
 void LLAvatarPropertiesProcessor::sendAvatarPicksRequest(const LLUUID& avatar_id)
 {
-	sendGenericRequest(avatar_id, APT_PICKS, "avatarpicksrequest");
+    sendGenericRequest(avatar_id, APT_PICKS, "avatarpicksrequest");
 }
 
 void LLAvatarPropertiesProcessor::sendAvatarNotesRequest(const LLUUID& avatar_id)
@@ -174,7 +219,7 @@ void LLAvatarPropertiesProcessor::sendAvatarPropertiesUpdate(const LLAvatarData*
 		return;
 	}
 
-	LL_INFOS() << "Sending avatarinfo update" << LL_ENDL;
+	LL_WARNS() << "Sending avatarinfo update. This trims profile descriptions!!!" << LL_ENDL;
 
 	// This value is required by sendAvatarPropertiesUpdate method.
 	//A profile should never be mature. (From the original code)
@@ -266,6 +311,113 @@ bool LLAvatarPropertiesProcessor::hasPaymentInfoOnFile(const LLAvatarData* avata
 	return ((avatar_data->flags & AVATAR_TRANSACTED) || (avatar_data->flags & AVATAR_IDENTIFIED));
 }
 
+// static
+void LLAvatarPropertiesProcessor::requestAvatarPropertiesCoro(std::string cap_url, LLUUID agent_id)
+{
+    LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+    LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+        httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("requestAvatarPropertiesCoro", httpPolicy));
+    LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+    LLCore::HttpHeaders::ptr_t httpHeaders;
+
+    LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions);
+    httpOpts->setFollowRedirects(true);
+
+    std::string finalUrl = cap_url + "/" + agent_id.asString();
+
+    LLSD result = httpAdapter->getAndSuspend(httpRequest, finalUrl, httpOpts, httpHeaders);
+
+    LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+    LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+    if (!status
+        || !result.has("id")
+        || agent_id != result["id"].asUUID())
+    {
+        LL_WARNS("AvatarProperties") << "Failed to get agent information for id " << agent_id << LL_ENDL;
+        LLAvatarPropertiesProcessor* self = getInstance();
+        self->removePendingRequest(agent_id, APT_PROPERTIES);
+        self->removePendingRequest(agent_id, APT_PICKS);
+        self->removePendingRequest(agent_id, APT_GROUPS);
+        self->removePendingRequest(agent_id, APT_NOTES);
+        return;
+    }
+
+    // Avatar Data
+
+    LLAvatarData avatar_data;
+    std::string birth_date;
+
+    avatar_data.agent_id = agent_id;
+    avatar_data.avatar_id = agent_id;
+    avatar_data.image_id = result["sl_image_id"].asUUID();
+    avatar_data.fl_image_id = result["fl_image_id"].asUUID();
+    avatar_data.partner_id = result["partner_id"].asUUID();
+    avatar_data.about_text = result["sl_about_text"].asString();
+    avatar_data.fl_about_text = result["fl_about_text"].asString();
+    avatar_data.born_on = result["member_since"].asDate();
+    avatar_data.profile_url = getProfileURL(agent_id.asString());
+
+    avatar_data.flags = 0;
+    avatar_data.caption_index = 0;
+
+    LLAvatarPropertiesProcessor* self = getInstance();
+    // Request processed, no longer pending
+    self->removePendingRequest(agent_id, APT_PROPERTIES);
+    self->notifyObservers(agent_id, &avatar_data, APT_PROPERTIES);
+
+    // Picks
+
+    LLSD picks_array = result["picks"];
+    LLAvatarPicks avatar_picks;
+    avatar_picks.agent_id = agent_id; // Not in use?
+    avatar_picks.target_id = agent_id;
+
+    for (LLSD::array_const_iterator it = picks_array.beginArray(); it != picks_array.endArray(); ++it)
+    {
+        const LLSD& pick_data = *it;
+        avatar_picks.picks_list.emplace_back(pick_data["id"].asUUID(), pick_data["name"].asString());
+    }
+
+    // Request processed, no longer pending
+    self->removePendingRequest(agent_id, APT_PICKS);
+    self->notifyObservers(agent_id, &avatar_picks, APT_PICKS);
+
+    // Groups
+
+    LLSD groups_array = result["groups"];
+    LLAvatarGroups avatar_groups;
+    avatar_groups.agent_id = agent_id; // Not in use?
+    avatar_groups.avatar_id = agent_id; // target_id
+
+    for (LLSD::array_const_iterator it = groups_array.beginArray(); it != groups_array.endArray(); ++it)
+    {
+        const LLSD& group_info = *it;
+        LLAvatarGroups::LLGroupData group_data;
+        group_data.group_powers = 0; // Not in use?
+        group_data.group_title = group_info["name"].asString(); // Missing data, not in use?
+        group_data.group_id = group_info["id"].asUUID();
+        group_data.group_name = group_info["name"].asString();
+        group_data.group_insignia_id = group_info["image_id"].asUUID();
+
+        avatar_groups.group_list.push_back(group_data);
+    }
+
+    self->removePendingRequest(agent_id, APT_GROUPS);
+    self->notifyObservers(agent_id, &avatar_groups, APT_GROUPS);
+
+    // Notes
+    LLAvatarNotes avatar_notes;
+
+    avatar_notes.agent_id = agent_id;
+    avatar_notes.target_id = agent_id;
+    avatar_notes.notes = result["notes"].asString();
+
+    // Request processed, no longer pending
+    self->removePendingRequest(agent_id, APT_NOTES);
+    self->notifyObservers(agent_id, &avatar_notes, APT_NOTES);
+}
+
 void LLAvatarPropertiesProcessor::processAvatarPropertiesReply(LLMessageSystem* msg, void**)
 {
 	LLAvatarData avatar_data;
@@ -312,6 +464,21 @@ void LLAvatarPropertiesProcessor::processAvatarInterestsReply(LLMessageSystem* m
 	That will suppress the warnings and be compatible with old server versions.
 	WARNING: LLTemplateMessageReader::decodeData: Message from 216.82.37.237:13000 with no handler function received: AvatarInterestsReply
 */
+
+    LLInterestsData interests_data;
+    
+    msg->getUUIDFast(   _PREHASH_AgentData,         _PREHASH_AgentID,       interests_data.agent_id );
+    msg->getUUIDFast(   _PREHASH_AgentData,         _PREHASH_AvatarID,      interests_data.avatar_id );
+    msg->getU32Fast(    _PREHASH_PropertiesData,	_PREHASH_WantToMask,    interests_data.want_to_mask );
+    msg->getStringFast( _PREHASH_PropertiesData,    _PREHASH_WantToText,    interests_data.want_to_text );
+    msg->getU32Fast(    _PREHASH_PropertiesData,	_PREHASH_SkillsMask,    interests_data.skills_mask );
+    msg->getStringFast( _PREHASH_PropertiesData,    _PREHASH_SkillsText,    interests_data.skills_text );
+    msg->getString(     _PREHASH_PropertiesData,    _PREHASH_LanguagesText, interests_data.languages_text );
+    
+    LLAvatarPropertiesProcessor* self = getInstance();
+    // Request processed, no longer pending
+    self->removePendingRequest(interests_data.avatar_id, APT_INTERESTS_INFO);
+    self->notifyObservers(interests_data.avatar_id, &interests_data, APT_INTERESTS_INFO);
 }
 
 void LLAvatarPropertiesProcessor::processAvatarClassifiedsReply(LLMessageSystem* msg, void**)
@@ -385,7 +552,7 @@ void LLAvatarPropertiesProcessor::processAvatarNotesReply(LLMessageSystem* msg,
 void LLAvatarPropertiesProcessor::processAvatarPicksReply(LLMessageSystem* msg, void**)
 {
 	LLAvatarPicks avatar_picks;
-	msg->getUUID(_PREHASH_AgentData, _PREHASH_AgentID, avatar_picks.target_id);
+	msg->getUUID(_PREHASH_AgentData, _PREHASH_AgentID, avatar_picks.agent_id);
 	msg->getUUID(_PREHASH_AgentData, _PREHASH_TargetID, avatar_picks.target_id);
 
 	S32 block_count = msg->getNumberOfBlocks(_PREHASH_Data);
@@ -551,6 +718,29 @@ void LLAvatarPropertiesProcessor::sendClassifiedDelete(const LLUUID& classified_
 	gAgent.sendReliableMessage();
 }
 
+void LLAvatarPropertiesProcessor::sendInterestsInfoUpdate(const LLInterestsData* interests_data)
+{
+    if(!interests_data)
+    {
+        return;
+    }
+
+    LLMessageSystem* msg = gMessageSystem;
+
+    msg->newMessage(_PREHASH_AvatarInterestsUpdate);
+    msg->nextBlockFast( _PREHASH_AgentData);
+    msg->addUUIDFast(	_PREHASH_AgentID,       gAgent.getID() );
+    msg->addUUIDFast(   _PREHASH_SessionID,     gAgent.getSessionID() );
+    msg->nextBlockFast( _PREHASH_PropertiesData);
+    msg->addU32Fast(	_PREHASH_WantToMask,    interests_data->want_to_mask);
+    msg->addStringFast(	_PREHASH_WantToText,    interests_data->want_to_text);
+    msg->addU32Fast(	_PREHASH_SkillsMask,    interests_data->skills_mask);
+    msg->addStringFast(	_PREHASH_SkillsText,    interests_data->skills_text);
+    msg->addString(     _PREHASH_LanguagesText, interests_data->languages_text);
+    
+    gAgent.sendReliableMessage();
+}
+
 void LLAvatarPropertiesProcessor::sendPickInfoUpdate(const LLPickData* new_pick)
 {
 	if (!new_pick) return;
diff --git a/indra/newview/llavatarpropertiesprocessor.h b/indra/newview/llavatarpropertiesprocessor.h
index b063048c26c25241385df9e93fb207bdc0f7b2af..f778634d25f7a80eaa15df831f0888b51d71abc1 100644
--- a/indra/newview/llavatarpropertiesprocessor.h
+++ b/indra/newview/llavatarpropertiesprocessor.h
@@ -56,10 +56,22 @@ enum EAvatarProcessorType
 	APT_PICKS,
 	APT_PICK_INFO,
 	APT_TEXTURES,
+    APT_INTERESTS_INFO,
 	APT_CLASSIFIEDS,
 	APT_CLASSIFIED_INFO
 };
 
+struct LLInterestsData
+{
+    LLUUID      agent_id;
+    LLUUID      avatar_id; //target id
+    U32         want_to_mask;
+    std::string want_to_text;
+    U32         skills_mask;
+    std::string skills_text;
+    std::string languages_text;
+};
+
 struct LLAvatarData
 {
 	LLUUID 		agent_id;
@@ -223,6 +235,8 @@ class LLAvatarPropertiesProcessor
 
 	void sendClassifiedDelete(const LLUUID& classified_id);
 
+    void sendInterestsInfoUpdate(const LLInterestsData* interests_data);
+
 	// Returns translated, human readable string for account type, such
 	// as "Resident" or "Linden Employee".  Used for profiles, inspectors.
 	static std::string accountType(const LLAvatarData* avatar_data);
@@ -234,6 +248,8 @@ class LLAvatarPropertiesProcessor
 
 	static bool hasPaymentInfoOnFile(const LLAvatarData* avatar_data);
 
+    static void requestAvatarPropertiesCoro(std::string cap_url, LLUUID agent_id);
+
 	static void processAvatarPropertiesReply(LLMessageSystem* msg, void**);
 
 	static void processAvatarInterestsReply(LLMessageSystem* msg, void**);
@@ -252,7 +268,10 @@ class LLAvatarPropertiesProcessor
 
 protected:
 
-	void sendGenericRequest(const LLUUID& avatar_id, EAvatarProcessorType type, const std::string method);
+	void sendRequest(const LLUUID& avatar_id, EAvatarProcessorType type, const std::string &method);
+    void sendGenericRequest(const LLUUID& avatar_id, EAvatarProcessorType type, const std::string &method);
+    void sendAvatarPropertiesRequestMessage(const LLUUID& avatar_id);
+    void initAgentProfileCapRequest(const LLUUID& avatar_id, const std::string& cap_url);
 
 	void notifyObservers(const LLUUID& id,void* data, EAvatarProcessorType type);
 
diff --git a/indra/newview/llavatarrenderinfoaccountant.cpp b/indra/newview/llavatarrenderinfoaccountant.cpp
index ca83afb5ab070e69d40ae80bc457fdb4e911a4b6..275f17b02ae23647bdedd8d95ea7759909a958a3 100644
--- a/indra/newview/llavatarrenderinfoaccountant.cpp
+++ b/indra/newview/llavatarrenderinfoaccountant.cpp
@@ -82,7 +82,15 @@ void LLAvatarRenderInfoAccountant::avatarRenderInfoGetCoro(std::string url, U64
 
     LLSD result = httpAdapter->getAndSuspend(httpRequest, url);
 
-    LLViewerRegion * regionp = LLWorld::getInstance()->getRegionFromHandle(regionHandle);
+    LLWorld *world_inst = LLWorld::getInstance();
+    if (!world_inst)
+    {
+        LL_WARNS("AvatarRenderInfoAccountant") << "Avatar render weight info received but world no longer exists "
+            << regionHandle << LL_ENDL;
+        return;
+    }
+
+    LLViewerRegion * regionp = world_inst->getRegionFromHandle(regionHandle);
     if (!regionp)
     {
         LL_WARNS("AvatarRenderInfoAccountant") << "Avatar render weight info received but region not found for " 
@@ -183,7 +191,15 @@ void LLAvatarRenderInfoAccountant::avatarRenderInfoReportCoro(std::string url, U
         httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("AvatarRenderInfoAccountant", httpPolicy));
     LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
 
-    LLViewerRegion * regionp = LLWorld::getInstance()->getRegionFromHandle(regionHandle);
+    LLWorld *world_inst = LLWorld::getInstance();
+    if (!world_inst)
+    {
+        LL_WARNS("AvatarRenderInfoAccountant") << "Avatar render weight calculation but world no longer exists "
+            << regionHandle << LL_ENDL;
+        return;
+    }
+
+    LLViewerRegion * regionp = world_inst->getRegionFromHandle(regionHandle);
     if (!regionp)
     {
         LL_WARNS("AvatarRenderInfoAccountant") << "Avatar render weight calculation but region not found for "
@@ -239,9 +255,18 @@ void LLAvatarRenderInfoAccountant::avatarRenderInfoReportCoro(std::string url, U
     report[KEY_AGENTS] = agents;
 
     regionp = NULL;
+    world_inst = NULL;
     LLSD result = httpAdapter->postAndSuspend(httpRequest, url, report);
 
-    regionp = LLWorld::getInstance()->getRegionFromHandle(regionHandle);
+    world_inst = LLWorld::getInstance();
+    if (!world_inst)
+    {
+        LL_WARNS("AvatarRenderInfoAccountant") << "Avatar render weight POST result but world no longer exists "
+            << regionHandle << LL_ENDL;
+        return;
+    }
+
+    regionp = world_inst->getRegionFromHandle(regionHandle);
     if (!regionp)
     {
         LL_INFOS("AvatarRenderInfoAccountant") << "Avatar render weight POST result received but region not found for "
@@ -295,9 +320,16 @@ void LLAvatarRenderInfoAccountant::sendRenderInfoToRegion(LLViewerRegion * regio
         // make sure we won't re-report, coro will update timer with correct time later
         regionp->getRenderInfoReportTimer().resetWithExpiry(SECS_BETWEEN_REGION_REPORTS);
 
-        std::string coroname =
-            LLCoros::instance().launch("LLAvatarRenderInfoAccountant::avatarRenderInfoReportCoro",
-            boost::bind(&LLAvatarRenderInfoAccountant::avatarRenderInfoReportCoro, url, regionp->getHandle()));
+        try
+        {
+            std::string coroname =
+                LLCoros::instance().launch("LLAvatarRenderInfoAccountant::avatarRenderInfoReportCoro",
+                    boost::bind(&LLAvatarRenderInfoAccountant::avatarRenderInfoReportCoro, url, regionp->getHandle()));
+        }
+        catch (std::bad_alloc&)
+        {
+            LL_ERRS() << "LLCoros::launch() allocation failure" << LL_ENDL;
+        }
 	}
 }
 
@@ -318,10 +350,17 @@ void LLAvatarRenderInfoAccountant::getRenderInfoFromRegion(LLViewerRegion * regi
         // make sure we won't re-request, coro will update timer with correct time later
         regionp->getRenderInfoRequestTimer().resetWithExpiry(SECS_BETWEEN_REGION_REQUEST);
 
-		// First send a request to get the latest data
-        std::string coroname =
-            LLCoros::instance().launch("LLAvatarRenderInfoAccountant::avatarRenderInfoGetCoro",
-            boost::bind(&LLAvatarRenderInfoAccountant::avatarRenderInfoGetCoro, url, regionp->getHandle()));
+        try
+        {
+            // First send a request to get the latest data
+            std::string coroname =
+                LLCoros::instance().launch("LLAvatarRenderInfoAccountant::avatarRenderInfoGetCoro",
+                    boost::bind(&LLAvatarRenderInfoAccountant::avatarRenderInfoGetCoro, url, regionp->getHandle()));
+        }
+        catch (std::bad_alloc&)
+        {
+            LL_ERRS() << "LLCoros::launch() allocation failure" << LL_ENDL;
+        }
 	}
 }
 
@@ -345,6 +384,8 @@ void LLAvatarRenderInfoAccountant::idle()
 				&& regionp->capabilitiesReceived())
 			{
 				// each of these is further governed by and resets its own timer
+                // Note: We can have multiple regions, each launches up to two coroutines,
+                // it likely is expensive
 				sendRenderInfoToRegion(regionp);
 				getRenderInfoFromRegion(regionp);
 			}
diff --git a/indra/newview/llbrowsernotification.cpp b/indra/newview/llbrowsernotification.cpp
index 7614624306bca3ddd3a10f3b53a09147e5be607c..036215a845bfb16b86ed2b63a8fb8488c7587084 100644
--- a/indra/newview/llbrowsernotification.cpp
+++ b/indra/newview/llbrowsernotification.cpp
@@ -43,14 +43,14 @@ LLBrowserNotification::LLBrowserNotification()
 bool LLBrowserNotification::processNotification(const LLNotificationPtr& notification, bool should_log)
 {
 	LLUUID media_id = notification->getPayload()["media_id"].asUUID();
-	LLMediaCtrl* media_instance = LLMediaCtrl::getInstance(media_id);
+	auto media_instance = LLMediaCtrl::getInstance(media_id);
 	if (media_instance)
 	{
 		media_instance->showNotification(notification);
 	}
 	else if (LLViewerMediaFocus::instance().getControlsMediaID() == media_id)
 	{
-		LLViewerMediaImpl* impl = LLViewerMedia::getInstance()->getMediaImplFromTextureID(media_id);
+		auto impl = LLViewerMedia::getInstance()->getMediaImplFromTextureID(media_id);
 		if (impl)
 		{
 			impl->showNotification(notification);
diff --git a/indra/newview/llcallingcard.cpp b/indra/newview/llcallingcard.cpp
index 6d20b23e9f9b4a733ee936d60561c54f2fa5ac42..1ad2157df04b13bdfa5a69ce13290c02778eb889 100644
--- a/indra/newview/llcallingcard.cpp
+++ b/indra/newview/llcallingcard.cpp
@@ -53,6 +53,7 @@
 #include "llviewerobjectlist.h"
 #include "llvoavatar.h"
 #include "llavataractions.h"
+#include "lluiusage.h"
 
 ///----------------------------------------------------------------------------
 /// Local function declarations, constants, enums, and typedefs
@@ -294,6 +295,8 @@ void LLAvatarTracker::copyBuddyList(buddy_map_t& buddies) const
 void LLAvatarTracker::terminateBuddy(const LLUUID& id)
 {
 	LL_DEBUGS() << "LLAvatarTracker::terminateBuddy()" << LL_ENDL;
+	LLUIUsage::instance().logCommand("Agent.TerminateFriendship");
+
 	LLRelationship* buddy = get_ptr_in_map(mBuddyInfo, id);
 	if(!buddy) return;
 	mBuddyInfo.erase(id);
@@ -493,6 +496,7 @@ void LLAvatarTracker::notifyObservers()
 		// new masks and ids will be processed later from idle.
 		return;
 	}
+	LL_PROFILE_ZONE_SCOPED
 	mIsNotifyObservers = TRUE;
 
 	observer_list_t observers(mObservers);
@@ -639,13 +643,15 @@ void LLAvatarTracker::processChange(LLMessageSystem* msg)
 			if(mBuddyInfo.find(agent_related) != mBuddyInfo.end())
 			{
 				(mBuddyInfo[agent_related])->setRightsTo(new_rights);
+				mChangedBuddyIDs.insert(agent_related);
 			}
 		}
 		else
 		{
 			if(mBuddyInfo.find(agent_id) != mBuddyInfo.end())
 			{
-				if((mBuddyInfo[agent_id]->getRightsGrantedFrom() ^  new_rights) & LLRelationship::GRANT_MODIFY_OBJECTS)
+                if (((mBuddyInfo[agent_id]->getRightsGrantedFrom() ^  new_rights) & LLRelationship::GRANT_MODIFY_OBJECTS)
+                    && !gAgent.isDoNotDisturb())
 				{
 					LLSD args;
 					args["NAME"] = LLSLURL("agent", agent_id, "displayname").getSLURLString();
@@ -678,6 +684,7 @@ void LLAvatarTracker::processChangeUserRights(LLMessageSystem* msg, void**)
 
 void LLAvatarTracker::processNotify(LLMessageSystem* msg, bool online)
 {
+	LL_PROFILE_ZONE_SCOPED
 	S32 count = msg->getNumberOfBlocksFast(_PREHASH_AgentBlock);
 	BOOL chat_notify = gSavedSettings.getBOOL("ChatOnlineNotification");
 
@@ -712,8 +719,6 @@ void LLAvatarTracker::processNotify(LLMessageSystem* msg, bool online)
 				// we were tracking someone who went offline
 				deleteTrackingData();
 			}
-			// *TODO: get actual inventory id
-			gInventory.addChangedMask(LLInventoryObserver::CALLING_CARD, LLUUID::null);
 		}
 		if(chat_notify)
 		{
diff --git a/indra/newview/llchatbar.cpp b/indra/newview/llchatbar.cpp
index e400609a74631e374dd5aac78152ba066aaf4157..72f667a0b8ec4c609671ec8f9ef4d2b6b7d1ff47 100644
--- a/indra/newview/llchatbar.cpp
+++ b/indra/newview/llchatbar.cpp
@@ -568,8 +568,6 @@ void LLChatBar::sendChatFromViewer(const LLWString &wtext, EChatType type, BOOL
 	// how to chat
 	gWarningSettings.setBOOL("FirstOtherChatBeforeUser", FALSE);
 
-	LLUIUsage::instance().logCommand("Chat.Send"); // Pseudo-command
-	
 	// Look for "/20 foo" channel chats.
 	S32 channel = 0;
 	LLWString out_text = stripChannelNumber(wtext, &channel);
diff --git a/indra/newview/llchathistory.cpp b/indra/newview/llchathistory.cpp
index c110e0d815f11ed48c47d6b1946220bb879427a0..7ff24f64acf08513b4cfdae57401e35123766866 100644
--- a/indra/newview/llchathistory.cpp
+++ b/indra/newview/llchathistory.cpp
@@ -48,6 +48,7 @@
 #include "llspeakers.h" //for LLIMSpeakerMgr
 #include "lltrans.h"
 #include "llfloaterreg.h"
+#include "llfloaterreporter.h"
 #include "llfloatersidepanelcontainer.h"
 #include "llmutelist.h"
 #include "llstylemap.h"
@@ -118,6 +119,7 @@ class LLChatHistoryHeader: public LLPanel
 		mSourceType(CHAT_SOURCE_UNKNOWN),
 		mFrom(),
 		mSessionID(),
+        mCreationTime(time_corrected()),
 		mMinUserNameWidth(0),
 		mUserNameFont(NULL),
 		mUserNameTextBox(NULL),
@@ -403,6 +405,48 @@ class LLChatHistoryHeader: public LLPanel
 		{
 			LLAvatarActions::pay(getAvatarId());
 		}
+        else if (level == "report_abuse")
+        {
+            std::string time_string;
+            if (mTime > 0) // have frame time
+            {
+                time_t current_time = time_corrected();
+                time_t message_time = current_time - LLFrameTimer::getElapsedSeconds() + mTime;
+
+                time_string = "[" + LLTrans::getString("TimeMonth") + "]/["
+                    + LLTrans::getString("TimeDay") + "]/["
+                    + LLTrans::getString("TimeYear") + "] ["
+                    + LLTrans::getString("TimeHour") + "]:["
+                    + LLTrans::getString("TimeMin") + "]";
+
+                LLSD substitution;
+
+                substitution["datetime"] = (S32)message_time;
+                LLStringUtil::format(time_string, substitution);
+            }
+            else
+            {
+                // From history. This might be empty or not full.
+                // See LLChatLogParser::parse
+                time_string = getChild<LLTextBox>("time_box")->getValue().asString();
+
+                // Just add current date if not full.
+                // Should be fine since both times are supposed to be stl
+                if (!time_string.empty() && time_string.size() < 7)
+                {
+                    time_string = "[" + LLTrans::getString("TimeMonth") + "]/["
+                        + LLTrans::getString("TimeDay") + "]/["
+                        + LLTrans::getString("TimeYear") + "] " + time_string;
+
+                    LLSD substitution;
+                    // To avoid adding today's date to yesterday's timestamp,
+                    // use creation time instead of current time
+                    substitution["datetime"] = (S32)mCreationTime;
+                    LLStringUtil::format(time_string, substitution);
+                }
+            }
+            LLFloaterReporter::showFromChat(mAvatarID, mFrom, time_string, mText);
+        }
 		else if(level == "block_unblock")
 		{
 			LLAvatarActions::toggleMute(getAvatarId(), LLMute::flagVoiceChat);
@@ -477,6 +521,10 @@ class LLChatHistoryHeader: public LLPanel
 		{
 			return canModerate(userdata);
 		}
+        else if (level == "report_abuse")
+        {
+            return gAgentID != mAvatarID;
+        }
 		else if (level == "can_ban_member")
 		{
 			return canBanGroupMember(getAvatarId());
@@ -558,9 +606,15 @@ class LLChatHistoryHeader: public LLPanel
 		mTimeBoxTextBox = getChild<LLTextBox>("time_box");
 
 		mInfoCtrl = LLUICtrlFactory::getInstance()->createFromFile<LLUICtrl>("inspector_info_ctrl.xml", this, LLPanel::child_registry_t::instance());
-		llassert(mInfoCtrl != NULL);
-		mInfoCtrl->setCommitCallback(boost::bind(&LLChatHistoryHeader::onClickInfoCtrl, mInfoCtrl));
-		mInfoCtrl->setVisible(FALSE);
+        if (mInfoCtrl)
+        {
+            mInfoCtrl->setCommitCallback(boost::bind(&LLChatHistoryHeader::onClickInfoCtrl, mInfoCtrl));
+            mInfoCtrl->setVisible(FALSE);
+        }
+        else
+        {
+            LL_ERRS() << "Failed to create an interface element due to missing or corrupted file inspector_info_ctrl.xml" << LL_ENDL;
+        }
 
 		return LLPanel::postBuild();
 	}
@@ -628,6 +682,12 @@ class LLChatHistoryHeader: public LLPanel
 		mSessionID = chat.mSessionID;
 		mSourceType = chat.mSourceType;
 
+        // To be able to report a message, we need a copy of it's text
+        // and it's easier to store text directly than trying to get
+        // it from a lltextsegment or chat's mEditor
+        mText = chat.mText;
+        mTime = chat.mTime;
+
 		//*TODO overly defensive thing, source type should be maintained out there
 		if((chat.mFromID.isNull() && chat.mFromName.empty()) || (chat.mFromName == SYSTEM_FROM && chat.mFromID.isNull()))
 		{
@@ -752,7 +812,7 @@ class LLChatHistoryHeader: public LLPanel
 		if ( chat.mSourceType == CHAT_SOURCE_OBJECT)
 		{
 			std::string slurl = args["slurl"].asString();
-			if (slurl.empty())
+			if (slurl.empty() && LLWorld::instanceExists())
 			{
 				LLViewerRegion *region = LLWorld::getInstance()->getRegionFromPosAgent(chat.mPosAgent);
 				if(region)
@@ -977,6 +1037,9 @@ class LLChatHistoryHeader: public LLPanel
 	EChatSourceType		mSourceType;
 	std::string			mFrom;
 	LLUUID				mSessionID;
+    std::string			mText;
+    F64					mTime; // IM's frame time
+    time_t				mCreationTime; // Views's time
 
 	S32					mMinUserNameWidth;
 	const LLFontGL*		mUserNameFont;
diff --git a/indra/newview/llcolorswatch.cpp b/indra/newview/llcolorswatch.cpp
index 80d810d1591a027b68d483afe7cc6e354a0523b2..036ff170743d90125f4eeca6f8b2cd4c0b842c09 100644
--- a/indra/newview/llcolorswatch.cpp
+++ b/indra/newview/llcolorswatch.cpp
@@ -290,9 +290,14 @@ void LLColorSwatchCtrl::onColorChanged ( void* data, EColorPickOp pick_op )
 									pickerp->getCurG (), 
 									pickerp->getCurB (), 
 									subject->mColor.mV[VALPHA] ); // keep current alpha
-			subject->mColor = updatedColor;
-			subject->setControlValue(updatedColor.getValue());
-			pickerp->setRevertOnCancel(TRUE);
+
+            bool color_changed = subject->mColor != updatedColor;
+            if (color_changed)
+            {
+                subject->mColor = updatedColor;
+                subject->setControlValue(updatedColor.getValue());
+            }
+
 			if (pick_op == COLOR_CANCEL && subject->mOnCancelCallback)
 			{
 				subject->mOnCancelCallback( subject, LLSD());
@@ -306,6 +311,13 @@ void LLColorSwatchCtrl::onColorChanged ( void* data, EColorPickOp pick_op )
 				// just commit change
 				subject->onCommit ();
 			}
+
+            if (pick_op == COLOR_CANCEL || pick_op == COLOR_SELECT)
+            {
+                // both select and cancel close LLFloaterColorPicker
+                // but COLOR_CHANGE does not
+                subject->setFocus(TRUE);
+            }
 		}
 	}
 }
diff --git a/indra/newview/llcontrolavatar.cpp b/indra/newview/llcontrolavatar.cpp
index fab249f98807a865b7d4c21732eecd4c5443b440..4a8727337253e859a1ca7d6d4f1c2bf4caa6a2b8 100644
--- a/indra/newview/llcontrolavatar.cpp
+++ b/indra/newview/llcontrolavatar.cpp
@@ -241,7 +241,7 @@ void LLControlAvatar::matchVolumeTransform()
 			if (skin_info)
 			{
                 LL_DEBUGS("BindShape") << getFullname() << " bind shape " << skin_info->mBindShapeMatrix << LL_ENDL;
-                bind_rot = LLSkinningUtil::getUnscaledQuaternion(skin_info->mBindShapeMatrix);
+                bind_rot = LLSkinningUtil::getUnscaledQuaternion(LLMatrix4(skin_info->mBindShapeMatrix));
 			}
 #endif
 			setRotation(bind_rot*obj_rot);
@@ -299,7 +299,6 @@ void LLControlAvatar::updateVolumeGeom()
 	mRootVolp->mDrawable->makeActive();
 	gPipeline.markMoved(mRootVolp->mDrawable);
 	gPipeline.markTextured(mRootVolp->mDrawable); // face may need to change draw pool to/from POOL_HUD
-	mRootVolp->mDrawable->setState(LLDrawable::USE_BACKLIGHT);
 
 	LLViewerObject::const_child_list_t& child_list = mRootVolp->getChildren();
 	for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin();
@@ -308,7 +307,6 @@ void LLControlAvatar::updateVolumeGeom()
 		LLViewerObject* childp = *iter;
 		if (childp && childp->mDrawable.notNull())
 		{
-			childp->mDrawable->setState(LLDrawable::USE_BACKLIGHT);
 			gPipeline.markTextured(childp->mDrawable); // face may need to change draw pool to/from POOL_HUD
 			gPipeline.markMoved(childp->mDrawable);
         }
diff --git a/indra/newview/llconversationloglist.cpp b/indra/newview/llconversationloglist.cpp
index 86e23e7c83c5e4af85c62856b6bf55448a138a82..97b16a5e9305f9b16ac5542a481b6d1aab92d464 100644
--- a/indra/newview/llconversationloglist.cpp
+++ b/indra/newview/llconversationloglist.cpp
@@ -391,7 +391,8 @@ bool LLConversationLogList::isActionEnabled(const LLSD& userdata)
 			 "can_invite_to_group"	== command_name ||
 			 "can_share"			== command_name ||
 			 "can_block"			== command_name ||
-			 "can_pay"				== command_name)
+			 "can_pay"				== command_name ||
+			 "report_abuse"			== command_name)
 	{
 		return is_p2p;
 	}
diff --git a/indra/newview/llconversationmodel.cpp b/indra/newview/llconversationmodel.cpp
index a6856394275bdaef46472beea7374ba6cc8b9b45..9ec4fb085b2717b5790871b3ed341c39bdb33946 100644
--- a/indra/newview/llconversationmodel.cpp
+++ b/indra/newview/llconversationmodel.cpp
@@ -182,6 +182,7 @@ void LLConversationItem::buildParticipantMenuOptions(menuentry_vec_t& items, U32
 		items.push_back(std::string("map"));
 		items.push_back(std::string("share"));
 		items.push_back(std::string("pay"));
+        items.push_back(std::string("report_abuse"));
 		items.push_back(std::string("block_unblock"));
 		items.push_back(std::string("MuteText"));
 
diff --git a/indra/newview/llconversationview.cpp b/indra/newview/llconversationview.cpp
index fee85d50bd4305521109f995fcb8088ba1147687..48c7df40dfbe2045beb932119eac68c139b9e32b 100644
--- a/indra/newview/llconversationview.cpp
+++ b/indra/newview/llconversationview.cpp
@@ -96,10 +96,14 @@ LLConversationViewSession::~LLConversationViewSession()
 {
 	mActiveVoiceChannelConnection.disconnect();
 
-	if(LLVoiceClient::instanceExists() && mVoiceClientObserver)
-	{
-		LLVoiceClient::getInstance()->removeObserver(mVoiceClientObserver);
-	}
+    if (mVoiceClientObserver)
+    {
+        if (LLVoiceClient::instanceExists())
+        {
+            LLVoiceClient::getInstance()->removeObserver(mVoiceClientObserver);
+        }
+        delete mVoiceClientObserver;
+    }
 
 	mFlashTimer->unset();
 }
@@ -255,7 +259,12 @@ BOOL LLConversationViewSession::postBuild()
 			mIsInActiveVoiceChannel = true;
 			if(LLVoiceClient::instanceExists())
 			{
-				LLNearbyVoiceClientStatusObserver* mVoiceClientObserver = new LLNearbyVoiceClientStatusObserver(this);
+                if (mVoiceClientObserver)
+                {
+                    LLVoiceClient::getInstance()->removeObserver(mVoiceClientObserver);
+                    delete mVoiceClientObserver;
+                }
+				mVoiceClientObserver = new LLNearbyVoiceClientStatusObserver(this);
 				LLVoiceClient::getInstance()->addObserver(mVoiceClientObserver);
 			}
 			break;
@@ -263,9 +272,9 @@ BOOL LLConversationViewSession::postBuild()
 		default:
 			break;
 		}
-	}
 
-	refresh();
+        refresh(); // requires vmi
+	}
 
 	return TRUE;
 }
@@ -481,17 +490,20 @@ void LLConversationViewSession::refresh()
 {
 	// Refresh the session view from its model data
 	LLConversationItem* vmi = dynamic_cast<LLConversationItem*>(getViewModelItem());
-	vmi->resetRefresh();
+    if (vmi)
+    {
+        vmi->resetRefresh();
 
-	if (mSessionTitle)
-	{		
-		if (!highlightFriendTitle(vmi))
-		{
-			LLStyle::Params title_style;
-			title_style.color = LLUIColorTable::instance().getColor("LabelTextColor");
-			mSessionTitle->setText(vmi->getDisplayName(), title_style);
-		}
-	}
+        if (mSessionTitle)
+        {
+            if (!highlightFriendTitle(vmi))
+            {
+                LLStyle::Params title_style;
+                title_style.color = LLUIColorTable::instance().getColor("LabelTextColor");
+                mSessionTitle->setText(vmi->getDisplayName(), title_style);
+            }
+        }
+    }
 
 	// Update all speaking indicators
 	LLSpeakingIndicatorManager::updateSpeakingIndicators();
@@ -515,8 +527,11 @@ void LLConversationViewSession::refresh()
 	}
 
 	requestArrange();
-	// Do the regular upstream refresh
-	LLFolderViewFolder::refresh();
+    if (vmi)
+    {
+        // Do the regular upstream refresh
+        LLFolderViewFolder::refresh();
+    }
 }
 
 void LLConversationViewSession::onCurrentVoiceSessionChanged(const LLUUID& session_id)
@@ -618,8 +633,11 @@ BOOL LLConversationViewParticipant::postBuild()
     }
 
     updateChildren();
-	LLFolderViewItem::postBuild();
-    refresh();
+    if (getViewModelItem())
+    {
+        LLFolderViewItem::postBuild();
+        refresh();
+    }
     return TRUE;
 }
 
@@ -703,10 +721,10 @@ void LLConversationViewParticipant::refresh()
 
         // *TODO: We should also do something with vmi->isModerator() to echo that state in the UI somewhat
         mSpeakingIndicator->setIsModeratorMuted(participant_model->isModeratorMuted());
+        
+        // Do the regular upstream refresh
+        LLFolderViewItem::refresh();
     }
-
-	// Do the regular upstream refresh
-	LLFolderViewItem::refresh();
 }
 
 void LLConversationViewParticipant::addToFolder(LLFolderViewFolder* folder)
diff --git a/indra/newview/lldonotdisturbnotificationstorage.cpp b/indra/newview/lldonotdisturbnotificationstorage.cpp
index cb5f9c8a2c98cb0ce48e1212c4130db8dc7cc8f7..4d9ef99319fbd09448ab69216241879d68ad9888 100644
--- a/indra/newview/lldonotdisturbnotificationstorage.cpp
+++ b/indra/newview/lldonotdisturbnotificationstorage.cpp
@@ -80,9 +80,14 @@ LLDoNotDisturbNotificationStorage::~LLDoNotDisturbNotificationStorage()
 {
 }
 
+void LLDoNotDisturbNotificationStorage::reset()
+{
+    setFileName(gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, "dnd_notifications.xml"));
+}
+
 void LLDoNotDisturbNotificationStorage::initialize()
 {
-	setFileName(gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, "dnd_notifications.xml"));
+    reset();
 	getCommunicationChannel()->connectFailedFilter(boost::bind(&LLDoNotDisturbNotificationStorage::onChannelChanged, this, _1));
 }
 
@@ -96,11 +101,9 @@ void LLDoNotDisturbNotificationStorage::resetDirty()
     mDirty = false;
 }
 
-static LLTrace::BlockTimerStatHandle FTM_SAVE_DND_NOTIFICATIONS("Save DND Notifications");
-
 void LLDoNotDisturbNotificationStorage::saveNotifications()
 {
-	LL_RECORD_BLOCK_TIME(FTM_SAVE_DND_NOTIFICATIONS);
+    LL_PROFILE_ZONE_SCOPED;
 
 	LLNotificationChannelPtr channelPtr = getCommunicationChannel();
 	const LLCommunicationChannel *commChannel = dynamic_cast<LLCommunicationChannel*>(channelPtr.get());
diff --git a/indra/newview/lldonotdisturbnotificationstorage.h b/indra/newview/lldonotdisturbnotificationstorage.h
index c6f0bf1ab588ddd63fd52324bdf91f7dcd9d3516..237d58b4def8871397ec6d7e3fbc0d6c92694525 100644
--- a/indra/newview/lldonotdisturbnotificationstorage.h
+++ b/indra/newview/lldonotdisturbnotificationstorage.h
@@ -61,6 +61,7 @@ class LLDoNotDisturbNotificationStorage : public LLParamSingleton<LLDoNotDisturb
 	void loadNotifications();
     void updateNotifications();
     void removeNotification(const char * name, const LLUUID& id);
+    void reset();
 
 protected:
 
diff --git a/indra/newview/lldrawable.cpp b/indra/newview/lldrawable.cpp
index 4fe7e516cc201ded69569c52b8656f2feed87382..4a0c9d399f54d44de5de8779b5f868ffb7471e32 100644
--- a/indra/newview/lldrawable.cpp
+++ b/indra/newview/lldrawable.cpp
@@ -58,8 +58,6 @@ const F32 MIN_INTERPOLATE_DISTANCE_SQUARED = 0.001f * 0.001f;
 const F32 MAX_INTERPOLATE_DISTANCE_SQUARED = 10.f * 10.f;
 const F32 OBJECT_DAMPING_TIME_CONSTANT = 0.06f;
 
-static LLTrace::BlockTimerStatHandle FTM_CULL_REBOUND("Cull Rebound");
-
 extern bool gShiftFrame;
 
 
@@ -93,7 +91,6 @@ void LLDrawable::incrementVisible()
 
 LLDrawable::LLDrawable(LLViewerObject *vobj, bool new_entry)
 :	LLViewerOctreeEntryData(LLViewerOctreeEntry::LLDRAWABLE),
-	LLTrace::MemTrackable<LLDrawable, 16>("LLDrawable"),
 	mVObjp(vobj)
 {
 	init(new_entry); 
@@ -101,6 +98,8 @@ LLDrawable::LLDrawable(LLViewerObject *vobj, bool new_entry)
 
 void LLDrawable::init(bool new_entry)
 {
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE
+
 	// mXform
 	mParent = NULL;
 	mRenderType = 0;
@@ -150,21 +149,6 @@ void LLDrawable::unload()
 {
 	LLVOVolume *pVVol = getVOVolume();
 	pVVol->setNoLOD();
-
-	for (S32 i = 0; i < getNumFaces(); i++)
-	{
-		LLFace* facep = getFace(i);
-		if (facep->isState(LLFace::RIGGED))
-		{
-			LLDrawPoolAvatar* pool = (LLDrawPoolAvatar*)facep->getPool();
-			if (pool) {
-				pool->removeRiggedFace(facep);
-			}
-			facep->setVertexBuffer(NULL);
-		}
-		facep->clearState(LLFace::RIGGED);
-	}
-
 	pVVol->markForUpdate(TRUE);
 }
 
@@ -261,19 +245,13 @@ BOOL LLDrawable::isLight() const
 	}
 }
 
-static LLTrace::BlockTimerStatHandle FTM_CLEANUP_DRAWABLE("Cleanup Drawable");
-static LLTrace::BlockTimerStatHandle FTM_DEREF_DRAWABLE("Deref");
-static LLTrace::BlockTimerStatHandle FTM_DELETE_FACES("Faces");
-
 void LLDrawable::cleanupReferences()
 {
-	LL_RECORD_BLOCK_TIME(FTM_CLEANUP_DRAWABLE);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE;
 	
-	{
-		LL_RECORD_BLOCK_TIME(FTM_DELETE_FACES);
-		std::for_each(mFaces.begin(), mFaces.end(), DeletePointer());
-		mFaces.clear();
-	}
+	
+	std::for_each(mFaces.begin(), mFaces.end(), DeletePointer());
+	mFaces.clear();
 
 	gObjectList.removeDrawable(this);
 	
@@ -281,12 +259,9 @@ void LLDrawable::cleanupReferences()
 	
 	removeFromOctree();
 
-	{
-		LL_RECORD_BLOCK_TIME(FTM_DEREF_DRAWABLE);
-		// Cleanup references to other objects
-		mVObjp = NULL;
-		mParent = NULL;
-	}
+	// Cleanup references to other objects
+	mVObjp = NULL;
+	mParent = NULL;
 }
 
 void LLDrawable::removeFromOctree()
@@ -331,14 +306,12 @@ S32 LLDrawable::findReferences(LLDrawable *drawablep)
 	return count;
 }
 
-static LLTrace::BlockTimerStatHandle FTM_ALLOCATE_FACE("Allocate Face");
-
 LLFace*	LLDrawable::addFace(LLFacePool *poolp, LLViewerTexture *texturep)
 {
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE
 	
 	LLFace *face;
 	{
-		LL_RECORD_BLOCK_TIME(FTM_ALLOCATE_FACE);
 		face = new LLFace(this, mVObjp);
 	}
 
@@ -363,13 +336,12 @@ LLFace*	LLDrawable::addFace(LLFacePool *poolp, LLViewerTexture *texturep)
 
 LLFace*	LLDrawable::addFace(const LLTextureEntry *te, LLViewerTexture *texturep)
 {
-	LLFace *face;
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE
 
-	{
-		LL_RECORD_BLOCK_TIME(FTM_ALLOCATE_FACE);
-		face = new LLFace(this, mVObjp);
-	}
+	LLFace *face;
 
+	face = new LLFace(this, mVObjp);
+	
 	face->setTEOffset(mFaces.size());
 	face->setTexture(texturep);
 	face->setPoolType(gPipeline.getPoolTypeFromTE(te, texturep));
@@ -387,6 +359,8 @@ LLFace*	LLDrawable::addFace(const LLTextureEntry *te, LLViewerTexture *texturep)
 
 LLFace*	LLDrawable::addFace(const LLTextureEntry *te, LLViewerTexture *texturep, LLViewerTexture *normalp)
 {
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE
+
 	LLFace *face;
 	face = new LLFace(this, mVObjp);
 	
@@ -408,6 +382,8 @@ LLFace*	LLDrawable::addFace(const LLTextureEntry *te, LLViewerTexture *texturep,
 
 LLFace*	LLDrawable::addFace(const LLTextureEntry *te, LLViewerTexture *texturep, LLViewerTexture *normalp, LLViewerTexture *specularp)
 {
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE
+
 	LLFace *face;
 	face = new LLFace(this, mVObjp);
 	
@@ -430,6 +406,8 @@ LLFace*	LLDrawable::addFace(const LLTextureEntry *te, LLViewerTexture *texturep,
 
 void LLDrawable::setNumFaces(const S32 newFaces, LLFacePool *poolp, LLViewerTexture *texturep)
 {
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE
+
 	if (newFaces == (S32)mFaces.size())
 	{
 		return;
@@ -453,6 +431,8 @@ void LLDrawable::setNumFaces(const S32 newFaces, LLFacePool *poolp, LLViewerText
 
 void LLDrawable::setNumFacesFast(const S32 newFaces, LLFacePool *poolp, LLViewerTexture *texturep)
 {
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE
+
 	if (newFaces <= (S32)mFaces.size() && newFaces >= (S32)mFaces.size()/2)
 	{
 		return;
@@ -476,6 +456,8 @@ void LLDrawable::setNumFacesFast(const S32 newFaces, LLFacePool *poolp, LLViewer
 
 void LLDrawable::mergeFaces(LLDrawable* src)
 {
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE
+
 	U32 face_count = mFaces.size() + src->mFaces.size();
 
 	mFaces.reserve(face_count);
@@ -509,6 +491,8 @@ void LLDrawable::updateMaterial()
 
 void LLDrawable::makeActive()
 {		
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE
+
 #if !LL_RELEASE_FOR_DOWNLOAD
 	if (mVObjp.notNull())
 	{
@@ -572,6 +556,8 @@ void LLDrawable::makeActive()
 
 void LLDrawable::makeStatic(BOOL warning_enabled)
 {
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE
+
 	if (isState(ACTIVE) && 
 		!isState(ACTIVE_CHILD) && 
 		!mVObjp->isAttachment() && 
@@ -618,6 +604,8 @@ void LLDrawable::makeStatic(BOOL warning_enabled)
 // Returns "distance" between target destination and resulting xfrom
 F32 LLDrawable::updateXform(BOOL undamped)
 {
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE
+
 	BOOL damped = !undamped;
 
 	// Position
@@ -769,6 +757,8 @@ void LLDrawable::moveUpdatePipeline(BOOL moved)
 
 void LLDrawable::movePartition()
 {
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE
+
 	LLSpatialPartition* part = getSpatialPartition();
 	if (part)
 	{
@@ -813,6 +803,8 @@ BOOL LLDrawable::updateMoveUndamped()
 
 void LLDrawable::updatePartition()
 {
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE
+
 	if (!getVOVolume())
 	{
 		movePartition();
@@ -830,6 +822,8 @@ void LLDrawable::updatePartition()
 
 BOOL LLDrawable::updateMoveDamped()
 {
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE
+
 	F32 dist_squared = updateXform(FALSE);
 
 	mGeneration++;
@@ -853,6 +847,8 @@ BOOL LLDrawable::updateMoveDamped()
 
 void LLDrawable::updateDistance(LLCamera& camera, bool force_update)
 {
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE
+
 	if (LLViewerCamera::sCurCameraID != LLViewerCamera::CAMERA_WORLD)
 	{
 		LL_WARNS() << "Attempted to update distance for non-world camera." << LL_ENDL;
@@ -957,6 +953,8 @@ void LLDrawable::updateTexture()
 
 BOOL LLDrawable::updateGeometry(BOOL priority)
 {
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE
+
 	llassert(mVObjp.notNull());
 	BOOL res = mVObjp && mVObjp->updateGeometry(this);
 	return res;
@@ -1034,6 +1032,8 @@ const LLVector3& LLDrawable::getBounds(LLVector3& min, LLVector3& max) const
 
 void LLDrawable::updateSpatialExtents()
 {
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE
+
 	if (mVObjp)
 	{
 		const LLVector4a* exts = getSpatialExtents();
@@ -1162,19 +1162,26 @@ void LLDrawable::setGroup(LLViewerOctreeGroup *groupp)
 	LLViewerOctreeEntryData::setGroup(groupp);
 }
 
+/*
+* Get the SpatialPartition this Drawable should use.  
+* Checks current SpatialPartition assignment and corrects if it is invalid.
+*/
 LLSpatialPartition* LLDrawable::getSpatialPartition()
 { 
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE
+
 	LLSpatialPartition* retval = NULL;
-	
+
 	if (!mVObjp || 
 		!getVOVolume() ||
 		isStatic())
 	{
-		retval = gPipeline.getSpatialPartition((LLViewerObject*) mVObjp);
+        retval = gPipeline.getSpatialPartition((LLViewerObject*)mVObjp);
 	}
 	else if (isRoot())
 	{
-		if (mSpatialBridge)
+        // determine if the spatial bridge has changed
+        if (mSpatialBridge)
 		{
 			U32 partition_type = mSpatialBridge->asPartition()->mPartitionType;
 			bool is_hud = mVObjp->isHUDAttachment();
@@ -1191,14 +1198,14 @@ LLSpatialPartition* LLDrawable::getSpatialPartition()
 			{
 				// Was/became part of animesh
 				// remove obsolete bridge
-				mSpatialBridge->markDead();
+                mSpatialBridge->markDead();
 				setSpatialBridge(NULL);
 			}
 			else if ((partition_type == LLViewerRegion::PARTITION_AVATAR) != is_attachment)
 			{
 				// Was/became part of avatar
 				// remove obsolete bridge
-				mSpatialBridge->markDead();
+                mSpatialBridge->markDead();
 				setSpatialBridge(NULL);
 			}
 		}
@@ -1209,17 +1216,20 @@ LLSpatialPartition* LLDrawable::getSpatialPartition()
 			{
 				setSpatialBridge(new LLHUDBridge(this, getRegion()));
 			}
-			else if (mVObjp->isAnimatedObject() && mVObjp->getControlAvatar())
-			{
-				setSpatialBridge(new LLControlAVBridge(this, getRegion()));
-			}
+            else if (mVObjp->isAnimatedObject() && mVObjp->getControlAvatar())
+            {
+                setSpatialBridge(new LLControlAVBridge(this, getRegion()));
+            }
 			// check HUD first, because HUD is also attachment
 			else if (mVObjp->isAttachment())
 			{
+                // Attachment
+                // Use AvatarBridge of root object in attachment linkset
 				setSpatialBridge(new LLAvatarBridge(this, getRegion()));
 			}
 			else
 			{
+                // Moving linkset, use VolumeBridge of root object in linkset
 				setSpatialBridge(new LLVolumeBridge(this, getRegion()));
 			}
 		}
@@ -1247,6 +1257,8 @@ LLSpatialBridge::LLSpatialBridge(LLDrawable* root, BOOL render_by_group, U32 dat
 	LLDrawable(root->getVObj(), true),
 	LLSpatialPartition(data_mask, render_by_group, GL_STREAM_DRAW_ARB, regionp)
 {
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE
+
 	mBridge = this;
 	mDrawable = root;
 	root->setSpatialBridge(this);
@@ -1292,12 +1304,11 @@ void LLSpatialBridge::destroyTree()
 
 void LLSpatialBridge::updateSpatialExtents()
 {
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE
+
 	LLSpatialGroup* root = (LLSpatialGroup*) mOctree->getListener(0);
 	
-	{
-		LL_RECORD_BLOCK_TIME(FTM_CULL_REBOUND);
-		root->rebound();
-	}
+	root->rebound();
 	
 	const LLVector4a* root_bounds = root->getBounds();
 	LLVector4a offset;
@@ -1392,10 +1403,21 @@ LLCamera LLSpatialBridge::transformCamera(LLCamera& camera)
 
 	ret.setOrigin(delta);
 	ret.setAxes(lookAt, left_axis, up_axis);
-		
+
 	return ret;
 }
 
+void LLSpatialBridge::transformExtents(const LLVector4a* src, LLVector4a* dst)
+{
+    LLMatrix4 mat = mDrawable->getXform()->getWorldMatrix();
+    mat.invert();
+
+    LLMatrix4a world_to_bridge(mat);
+
+    matMulBoundBox(world_to_bridge, src, dst);
+}
+
+
 void LLDrawable::setVisible(LLCamera& camera, std::vector<LLDrawable*>* results, BOOL for_select)
 {
 	LLViewerOctreeEntryData::setVisible();
@@ -1455,6 +1477,8 @@ class LLOctreeMarkNotCulled: public OctreeTraveler
 
 void LLSpatialBridge::setVisible(LLCamera& camera_in, std::vector<LLDrawable*>* results, BOOL for_select)
 {
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE
+
 	if (!gPipeline.hasRenderType(mDrawableType))
 	{
 		return;
@@ -1552,6 +1576,8 @@ void LLSpatialBridge::setVisible(LLCamera& camera_in, std::vector<LLDrawable*>*
 
 void LLSpatialBridge::updateDistance(LLCamera& camera_in, bool force_update)
 {
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE
+
 	if (mDrawable == NULL)
 	{
 		markDead();
@@ -1723,6 +1749,17 @@ void LLDrawable::updateFaceSize(S32 idx)
 	}
 }
 
+LLDrawable* LLDrawable::getRoot()
+{
+    LLDrawable* ret = this;
+    while (!ret->isRoot())
+    {
+        ret = ret->getParent();
+    }
+
+    return ret;
+}
+
 LLBridgePartition::LLBridgePartition(LLViewerRegion* regionp)
 : LLSpatialPartition(0, FALSE, 0, regionp) 
 { 
diff --git a/indra/newview/lldrawable.h b/indra/newview/lldrawable.h
index 14d782d6f2683ff1bddb72aaf71994f4833ad142..2a0f4c93ac40f1b9ab8f4ddd68d218e87d11b93f 100644
--- a/indra/newview/lldrawable.h
+++ b/indra/newview/lldrawable.h
@@ -59,14 +59,15 @@ const U32 SILHOUETTE_HIGHLIGHT = 0;
 
 // All data for new renderer goes into this class.
 LL_ALIGN_PREFIX(16)
-class LLDrawable 
-:	public LLViewerOctreeEntryData,
-	public LLTrace::MemTrackable<LLDrawable, 16>
+class LLDrawable
+    : public LLViewerOctreeEntryData
 {
+    LL_ALIGN_NEW;
 public:
+    typedef std::vector<LLFace*> face_list_t;
+
 	LLDrawable(const LLDrawable& rhs) 
-	:	LLTrace::MemTrackable<LLDrawable, 16>("LLDrawable"),
-		LLViewerOctreeEntryData(rhs)
+        : LLViewerOctreeEntryData(rhs)
 	{
 		*this = rhs;
 	}
@@ -120,6 +121,7 @@ class LLDrawable
 
 	BOOL				isAvatar()	const			{ return mVObjp.notNull() && mVObjp->isAvatar(); }
 	BOOL				isRoot() const				{ return !mParent || mParent->isAvatar(); }
+    LLDrawable*         getRoot();
 	BOOL				isSpatialRoot() const		{ return !mParent || mParent->isAvatar(); }
 	virtual BOOL		isSpatialBridge() const		{ return FALSE; }
 	virtual LLSpatialPartition* asPartition()		{ return NULL; }
@@ -130,6 +132,8 @@ class LLDrawable
 	
 	inline LLFace*      getFace(const S32 i) const;
 	inline S32			getNumFaces()      	 const;
+    face_list_t& getFaces() { return mFaces; }
+    const face_list_t& getFaces() const { return mFaces; }
 
 	//void                removeFace(const S32 i); // SJB: Avoid using this, it's slow
 	LLFace*				addFace(LLFacePool *poolp, LLViewerTexture *texturep);
@@ -253,38 +257,34 @@ class LLDrawable
 	{
  		IN_REBUILD_Q1	= 0x00000001,
  		IN_REBUILD_Q2	= 0x00000002,
- 		IN_LIGHT_Q		= 0x00000004,
-		EARLY_MOVE		= 0x00000008,
-		MOVE_UNDAMPED	= 0x00000010,
-		ON_MOVE_LIST	= 0x00000020,
-		USE_BACKLIGHT	= 0x00000040,
-		UV				= 0x00000080,
-		UNLIT			= 0x00000100,
-		LIGHT			= 0x00000200,
-		LIGHTING_BUILT	= 0x00000400,
-		REBUILD_VOLUME  = 0x00000800,	//volume changed LOD or parameters, or vertex buffer changed
-		REBUILD_TCOORD	= 0x00001000,	//texture coordinates changed
-		REBUILD_COLOR	= 0x00002000,	//color changed
-		REBUILD_POSITION= 0x00004000,	//vertex positions/normals changed
+		EARLY_MOVE		= 0x00000004,
+		MOVE_UNDAMPED	= 0x00000008,
+		ON_MOVE_LIST	= 0x00000010,
+		UV				= 0x00000020,
+		UNLIT			= 0x00000040,
+		LIGHT			= 0x00000080,
+		REBUILD_VOLUME  = 0x00000100,	//volume changed LOD or parameters, or vertex buffer changed
+		REBUILD_TCOORD	= 0x00000200,	//texture coordinates changed
+		REBUILD_COLOR	= 0x00000400,	//color changed
+		REBUILD_POSITION= 0x00000800,	//vertex positions/normals changed
 		REBUILD_GEOMETRY= REBUILD_POSITION|REBUILD_TCOORD|REBUILD_COLOR,
 		REBUILD_MATERIAL= REBUILD_TCOORD|REBUILD_COLOR,
 		REBUILD_ALL		= REBUILD_GEOMETRY|REBUILD_VOLUME,
-		REBUILD_RIGGED	= 0x00008000,
-		ON_SHIFT_LIST	= 0x00010000,
-		BLOCKER			= 0x00020000,
-		ACTIVE			= 0x00040000,
-		DEAD			= 0x00080000,
-		INVISIBLE		= 0x00100000, // stay invisible until flag is cleared
- 		NEARBY_LIGHT	= 0x00200000, // In gPipeline.mNearbyLightSet
-		BUILT			= 0x00400000,
-		FORCE_INVISIBLE = 0x00800000, // stay invis until CLEAR_INVISIBLE is set (set of orphaned)
-		REBUILD_SHADOW =  0x02000000,
-		HAS_ALPHA		= 0x04000000,
-		RIGGED			= 0x08000000,
-		PARTITION_MOVE	= 0x10000000,
-		ANIMATED_CHILD  = 0x20000000,
-		ACTIVE_CHILD	= 0x40000000,
-		FOR_UNLOAD		= 0x80000000, //should be unload from memory
+		REBUILD_RIGGED	= 0x00001000,
+		ON_SHIFT_LIST	= 0x00002000,
+		ACTIVE			= 0x00004000,
+		DEAD			= 0x00008000,
+		INVISIBLE		= 0x00010000, // stay invisible until flag is cleared
+ 		NEARBY_LIGHT	= 0x00020000, // In gPipeline.mNearbyLightSet
+		BUILT			= 0x00040000,
+		FORCE_INVISIBLE = 0x00080000, // stay invis until CLEAR_INVISIBLE is set (set of orphaned)
+		HAS_ALPHA		= 0x00100000,
+		RIGGED			= 0x00200000, //has a rigged face
+        RIGGED_CHILD    = 0x00400000, //has a child with a rigged face
+		PARTITION_MOVE	= 0x00800000,
+		ANIMATED_CHILD  = 0x01000000,
+		ACTIVE_CHILD	= 0x02000000,
+		FOR_UNLOAD		= 0x04000000, //should be unload from memory
 	} EDrawableFlags;
 
 public:
@@ -298,8 +298,6 @@ class LLDrawable
 	static F32 sCurPixelAngle; //current pixels per radian
 
 private:
-	typedef std::vector<LLFace*> face_list_t;
-	
 	U32				mState;
 	S32				mRenderType;
 	LLPointer<LLViewerObject> mVObjp;
diff --git a/indra/newview/lldrawpool.cpp b/indra/newview/lldrawpool.cpp
index d583a692f9f26d4ca398ae88baeb75f9f9604d83..a3837fe10c68d3758bfbdada979edbe4402d7f84 100644
--- a/indra/newview/lldrawpool.cpp
+++ b/indra/newview/lldrawpool.cpp
@@ -50,6 +50,9 @@
 #include "lldrawpoolwlsky.h"
 #include "llglslshader.h"
 #include "llglcommonfunc.h"
+#include "llvoavatar.h"
+#include "llviewershadermgr.h"
+
 
 S32 LLDrawPool::sNumDrawPools = 0;
 
@@ -385,25 +388,48 @@ LLRenderPass::~LLRenderPass()
 }
 
 void LLRenderPass::renderGroup(LLSpatialGroup* group, U32 type, U32 mask, BOOL texture)
-{					
+{
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
 	LLSpatialGroup::drawmap_elem_t& draw_info = group->mDrawMap[type];
 	
 	for (LLSpatialGroup::drawmap_elem_t::iterator k = draw_info.begin(); k != draw_info.end(); ++k)	
 	{
 		LLDrawInfo *pparams = *k;
-		if (pparams) {
+		if (pparams) 
+        {
 			pushBatch(*pparams, mask, texture);
 		}
 	}
 }
 
-void LLRenderPass::renderTexture(U32 type, U32 mask, BOOL batch_textures)
+void LLRenderPass::renderRiggedGroup(LLSpatialGroup* group, U32 type, U32 mask, BOOL texture)
 {
-	pushBatches(type, mask, true, batch_textures);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
+    LLSpatialGroup::drawmap_elem_t& draw_info = group->mDrawMap[type];
+    LLVOAvatar* lastAvatar = nullptr;
+    U64 lastMeshId = 0;
+    mask |= LLVertexBuffer::MAP_WEIGHT4;
+
+    for (LLSpatialGroup::drawmap_elem_t::iterator k = draw_info.begin(); k != draw_info.end(); ++k)
+    {
+        LLDrawInfo* pparams = *k;
+        if (pparams) 
+        {
+            if (lastAvatar != pparams->mAvatar || lastMeshId != pparams->mSkinInfo->mHash)
+            {
+                uploadMatrixPalette(*pparams);
+                lastAvatar = pparams->mAvatar;
+                lastMeshId = pparams->mSkinInfo->mHash;
+            }
+
+            pushBatch(*pparams, mask, texture);
+        }
+    }
 }
 
 void LLRenderPass::pushBatches(U32 type, U32 mask, BOOL texture, BOOL batch_textures)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
 	for (LLCullResult::drawinfo_iterator i = gPipeline.beginRenderMap(type); i != gPipeline.endRenderMap(type); ++i)	
 	{
 		LLDrawInfo* pparams = *i;
@@ -414,27 +440,74 @@ void LLRenderPass::pushBatches(U32 type, U32 mask, BOOL texture, BOOL batch_text
 	}
 }
 
+void LLRenderPass::pushRiggedBatches(U32 type, U32 mask, BOOL texture, BOOL batch_textures)
+{
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
+    LLVOAvatar* lastAvatar = nullptr;
+    U64 lastMeshId = 0;
+    mask |= LLVertexBuffer::MAP_WEIGHT4;
+    for (LLCullResult::drawinfo_iterator i = gPipeline.beginRenderMap(type); i != gPipeline.endRenderMap(type); ++i)
+    {
+        LLDrawInfo* pparams = *i;
+        if (pparams)
+        {
+            if (pparams->mAvatar.notNull() && (lastAvatar != pparams->mAvatar || lastMeshId != pparams->mSkinInfo->mHash))
+            {
+                uploadMatrixPalette(*pparams);
+                lastAvatar = pparams->mAvatar;
+                lastMeshId = pparams->mSkinInfo->mHash;
+            }
+
+            pushBatch(*pparams, mask, texture, batch_textures);
+        }
+    }
+}
+
 void LLRenderPass::pushMaskBatches(U32 type, U32 mask, BOOL texture, BOOL batch_textures)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
 	for (LLCullResult::drawinfo_iterator i = gPipeline.beginRenderMap(type); i != gPipeline.endRenderMap(type); ++i)	
 	{
 		LLDrawInfo* pparams = *i;
 		if (pparams) 
 		{
-			if (LLGLSLShader::sCurBoundShaderPtr)
-			{
-				LLGLSLShader::sCurBoundShaderPtr->setMinimumAlpha(pparams->mAlphaMaskCutoff);
-			}
-			else
-			{
-				gGL.setAlphaRejectSettings(LLRender::CF_GREATER, pparams->mAlphaMaskCutoff);
-			}
-			
+			LLGLSLShader::sCurBoundShaderPtr->setMinimumAlpha(pparams->mAlphaMaskCutoff);
 			pushBatch(*pparams, mask, texture, batch_textures);
 		}
 	}
 }
 
+void LLRenderPass::pushRiggedMaskBatches(U32 type, U32 mask, BOOL texture, BOOL batch_textures)
+{
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
+    LLVOAvatar* lastAvatar = nullptr;
+    U64 lastMeshId = 0;
+    for (LLCullResult::drawinfo_iterator i = gPipeline.beginRenderMap(type); i != gPipeline.endRenderMap(type); ++i)
+    {
+        LLDrawInfo* pparams = *i;
+        if (pparams)
+        {
+            if (LLGLSLShader::sCurBoundShaderPtr)
+            {
+                LLGLSLShader::sCurBoundShaderPtr->setMinimumAlpha(pparams->mAlphaMaskCutoff);
+            }
+            else
+            {
+                gGL.flush();
+            }
+
+            if (lastAvatar != pparams->mAvatar || lastMeshId != pparams->mSkinInfo->mHash)
+            {
+                uploadMatrixPalette(*pparams);
+                lastAvatar = pparams->mAvatar;
+                lastMeshId = pparams->mSkinInfo->mHash;
+            }
+
+            pushBatch(*pparams, mask | LLVertexBuffer::MAP_WEIGHT4, texture, batch_textures);
+        }
+    }
+}
+
 void LLRenderPass::applyModelMatrix(const LLDrawInfo& params)
 {
 	if (params.mModelMatrix != gGLLastMatrix)
@@ -452,6 +525,7 @@ void LLRenderPass::applyModelMatrix(const LLDrawInfo& params)
 
 void LLRenderPass::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture, BOOL batch_textures)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
     if (!params.mCount)
     {
         return;
@@ -469,7 +543,7 @@ void LLRenderPass::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture, BOOL ba
 			{
 				if (params.mTextureList[i].notNull())
 				{
-					gGL.getTexUnit(i)->bind(params.mTextureList[i], TRUE);
+					gGL.getTexUnit(i)->bindFast(params.mTextureList[i]);
 				}
 			}
 		}
@@ -477,8 +551,7 @@ void LLRenderPass::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture, BOOL ba
 		{ //not batching textures or batch has only 1 texture -- might need a texture matrix
 			if (params.mTexture.notNull())
 			{
-				params.mTexture->addTextureStats(params.mVSize);
-				gGL.getTexUnit(0)->bind(params.mTexture, TRUE) ;
+				gGL.getTexUnit(0)->bindFast(params.mTexture);
 				if (params.mTextureMatrix)
 				{
 					tex_setup = true;
@@ -490,24 +563,20 @@ void LLRenderPass::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture, BOOL ba
 			}
 			else
 			{
-				gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+				gGL.getTexUnit(0)->unbindFast(LLTexUnit::TT_TEXTURE);
 			}
 		}
 	}
 	
-	if (params.mVertexBuffer.notNull())
-	{
-		if (params.mGroup)
-		{
-			params.mGroup->rebuildMesh();
-		}
+    if (params.mGroup)
+    {
+        params.mGroup->rebuildMesh();
+    }
 
-		LLGLEnableFunc stencil_test(GL_STENCIL_TEST, params.mSelected, &LLGLCommonFunc::selected_stencil_test);
-	
-		params.mVertexBuffer->setBuffer(mask);
-		params.mVertexBuffer->drawRange(params.mDrawMode, params.mStart, params.mEnd, params.mCount, params.mOffset);
-		gPipeline.addTrianglesDrawn(params.mCount, params.mDrawMode);
-	}
+    LLGLEnableFunc stencil_test(GL_STENCIL_TEST, params.mSelected, &LLGLCommonFunc::selected_stencil_test);
+
+    params.mVertexBuffer->setBufferFast(mask);
+    params.mVertexBuffer->drawRangeFast(params.mDrawMode, params.mStart, params.mEnd, params.mCount, params.mOffset);
 
 	if (tex_setup)
 	{
@@ -517,7 +586,34 @@ void LLRenderPass::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture, BOOL ba
 	}
 }
 
-void LLRenderPass::renderGroups(U32 type, U32 mask, BOOL texture)
+// static
+bool LLRenderPass::uploadMatrixPalette(LLDrawInfo& params)
+{
+    // upload matrix palette to shader
+    return uploadMatrixPalette(params.mAvatar, params.mSkinInfo);
+}
+
+//static
+bool LLRenderPass::uploadMatrixPalette(LLVOAvatar* avatar, LLMeshSkinInfo* skinInfo)
 {
-	gPipeline.renderGroups(this, type, mask, texture);
+    if (!avatar)
+    {
+        return false;
+    }
+    const LLVOAvatar::MatrixPaletteCache& mpc = avatar->updateSkinInfoMatrixPalette(skinInfo);
+    U32 count = mpc.mMatrixPalette.size();
+
+    if (count == 0)
+    {
+        //skin info not loaded yet, don't render
+        return false;
+    }
+
+    LLGLSLShader::sCurBoundShaderPtr->uniformMatrix3x4fv(LLViewerShaderMgr::AVATAR_MATRIX,
+        count,
+        FALSE,
+        (GLfloat*)&(mpc.mGLMp[0]));
+
+    return true;
 }
+
diff --git a/indra/newview/lldrawpool.h b/indra/newview/lldrawpool.h
index ecd9bd034ff85b84b0e825b185106b4af10c2651..fd1b022e5bf3d7b513de8f35c1b5b85a149098e0 100644
--- a/indra/newview/lldrawpool.h
+++ b/indra/newview/lldrawpool.h
@@ -37,6 +37,8 @@ class LLViewerTexture;
 class LLViewerFetchedTexture;
 class LLSpatialGroup;
 class LLDrawInfo;
+class LLVOAvatar;
+class LLMeshSkinInfo;
 
 class LLDrawPool
 {
@@ -125,38 +127,69 @@ class LLDrawPool
 class LLRenderPass : public LLDrawPool
 {
 public:
+    // list of possible LLRenderPass types to assign a render batch to
+    // NOTE: "rigged" variant MUST be non-rigged variant + 1
 	enum
 	{
 		PASS_SIMPLE = NUM_POOL_TYPES,
+        PASS_SIMPLE_RIGGED,
 		PASS_GRASS,
 		PASS_FULLBRIGHT,
+        PASS_FULLBRIGHT_RIGGED,
 		PASS_INVISIBLE,
-		PASS_INVISI_SHINY,
+        PASS_INVISIBLE_RIGGED,
+		PASS_INVISI_SHINY, 
+        PASS_INVISI_SHINY_RIGGED,
 		PASS_FULLBRIGHT_SHINY,
+        PASS_FULLBRIGHT_SHINY_RIGGED,
 		PASS_SHINY,
+        PASS_SHINY_RIGGED,
 		PASS_BUMP,
+        PASS_BUMP_RIGGED,
 		PASS_POST_BUMP,
+        PASS_POST_BUMP_RIGGED,
 		PASS_MATERIAL,
+        PASS_MATERIAL_RIGGED,
 		PASS_MATERIAL_ALPHA,
+        PASS_MATERIAL_ALPHA_RIGGED,
 		PASS_MATERIAL_ALPHA_MASK,              // Diffuse texture used as alpha mask
+        PASS_MATERIAL_ALPHA_MASK_RIGGED,
 		PASS_MATERIAL_ALPHA_EMISSIVE,
+        PASS_MATERIAL_ALPHA_EMISSIVE_RIGGED,
 		PASS_SPECMAP,
+        PASS_SPECMAP_RIGGED,
 		PASS_SPECMAP_BLEND,
+        PASS_SPECMAP_BLEND_RIGGED,
 		PASS_SPECMAP_MASK,                     // Diffuse texture used as alpha mask and specular texture(map)
+        PASS_SPECMAP_MASK_RIGGED,
 		PASS_SPECMAP_EMISSIVE,
+        PASS_SPECMAP_EMISSIVE_RIGGED,
 		PASS_NORMMAP,
+        PASS_NORMMAP_RIGGED,
 		PASS_NORMMAP_BLEND,
+        PASS_NORMMAP_BLEND_RIGGED,
 		PASS_NORMMAP_MASK,                     // Diffuse texture used as alpha mask and normal map
+        PASS_NORMMAP_MASK_RIGGED,
 		PASS_NORMMAP_EMISSIVE,
+        PASS_NORMMAP_EMISSIVE_RIGGED,
 		PASS_NORMSPEC,
-		PASS_NORMSPEC_BLEND,
+        PASS_NORMSPEC_RIGGED,
+		PASS_NORMSPEC_BLEND, 
+        PASS_NORMSPEC_BLEND_RIGGED,
 		PASS_NORMSPEC_MASK,                    // Diffuse texture used as alpha mask with normal and specular map
+        PASS_NORMSPEC_MASK_RIGGED,
 		PASS_NORMSPEC_EMISSIVE,
+        PASS_NORMSPEC_EMISSIVE_RIGGED,
 		PASS_GLOW,
+        PASS_GLOW_RIGGED,
 		PASS_ALPHA,
+        PASS_ALPHA_RIGGED,
 		PASS_ALPHA_MASK,
+        PASS_ALPHA_MASK_RIGGED,
 		PASS_FULLBRIGHT_ALPHA_MASK,            // Diffuse texture used as alpha mask and fullbright
+        PASS_FULLBRIGHT_ALPHA_MASK_RIGGED,
 		PASS_ALPHA_INVISIBLE,
+        PASS_ALPHA_INVISIBLE_RIGGED,
 		NUM_RENDER_TYPES,
 	};
 
@@ -169,12 +202,14 @@ class LLRenderPass : public LLDrawPool
 
 	static void applyModelMatrix(const LLDrawInfo& params);
 	virtual void pushBatches(U32 type, U32 mask, BOOL texture = TRUE, BOOL batch_textures = FALSE);
+    virtual void pushRiggedBatches(U32 type, U32 mask, BOOL texture = TRUE, BOOL batch_textures = FALSE);
 	virtual void pushMaskBatches(U32 type, U32 mask, BOOL texture = TRUE, BOOL batch_textures = FALSE);
+    virtual void pushRiggedMaskBatches(U32 type, U32 mask, BOOL texture = TRUE, BOOL batch_textures = FALSE);
 	virtual void pushBatch(LLDrawInfo& params, U32 mask, BOOL texture, BOOL batch_textures = FALSE);
+    static bool uploadMatrixPalette(LLDrawInfo& params);
+    static bool uploadMatrixPalette(LLVOAvatar* avatar, LLMeshSkinInfo* skinInfo);
 	virtual void renderGroup(LLSpatialGroup* group, U32 type, U32 mask, BOOL texture = TRUE);
-	virtual void renderGroups(U32 type, U32 mask, BOOL texture = TRUE);
-	virtual void renderTexture(U32 type, U32 mask, BOOL batch_textures = TRUE);
-
+    virtual void renderRiggedGroup(LLSpatialGroup* group, U32 type, U32 mask, BOOL texture = TRUE);
 };
 
 class LLFacePool : public LLDrawPool
diff --git a/indra/newview/lldrawpoolalpha.cpp b/indra/newview/lldrawpoolalpha.cpp
index 4ee08e869a087c650b66dff9dd3de387e0eba16a..6c1abb24c9a1ef1a5d80f4f2bca4cf0bde6217fc 100644
--- a/indra/newview/lldrawpoolalpha.cpp
+++ b/indra/newview/lldrawpoolalpha.cpp
@@ -48,34 +48,26 @@
 #include "lldrawpoolwater.h"
 #include "llspatialpartition.h"
 #include "llglcommonfunc.h"
+#include "llvoavatar.h"
 
 BOOL LLDrawPoolAlpha::sShowDebugAlpha = FALSE;
 
+#define current_shader (LLGLSLShader::sCurBoundShaderPtr)
+
 static BOOL deferred_render = FALSE;
 
-static LLTrace::BlockTimerStatHandle FTM_RENDER_ALPHA_SETUP("Alpha Setup");
-static LLTrace::BlockTimerStatHandle FTM_RENDER_ALPHA_GROUP_LOOP("Alpha Group");
-static LLTrace::BlockTimerStatHandle FTM_RENDER_ALPHA_PUSH("Alpha Push Verts");
-static LLTrace::BlockTimerStatHandle FTM_RENDER_ALPHA_DEFERRED("Alpha Deferred");
-static LLTrace::BlockTimerStatHandle FTM_RENDER_ALPHA_SETBUFFER("Alpha SetBuffer");
-static LLTrace::BlockTimerStatHandle FTM_RENDER_ALPHA_DRAW("Alpha Draw");
-static LLTrace::BlockTimerStatHandle FTM_RENDER_ALPHA_TEX_BINDS("Alpha Tex Binds");
-static LLTrace::BlockTimerStatHandle FTM_RENDER_ALPHA_MATS("Alpha Mat Tex Binds");
-static LLTrace::BlockTimerStatHandle FTM_RENDER_ALPHA_GLOW("Alpha Glow Binds");
-static LLTrace::BlockTimerStatHandle FTM_RENDER_ALPHA_SHADER_BINDS("Alpha Shader Binds");
-static LLTrace::BlockTimerStatHandle FTM_RENDER_ALPHA_DEFERRED_SHADER_BINDS("Alpha Def Binds");
-static LLTrace::BlockTimerStatHandle FTM_RENDER_ALPHA_DEFERRED_TEX_BINDS("Alpha Def Tex Binds");
-static LLTrace::BlockTimerStatHandle FTM_RENDER_ALPHA_MESH_REBUILD("Alpha Mesh Rebuild");
-static LLTrace::BlockTimerStatHandle FTM_RENDER_ALPHA_EMISSIVE("Alpha Emissive");
-static LLTrace::BlockTimerStatHandle FTM_RENDER_ALPHA_LIGHT_SETUP("Alpha Light Setup");
+// minimum alpha before discarding a fragment
+static const F32 MINIMUM_ALPHA = 0.004f; // ~ 1/255
+
+// minimum alpha before discarding a fragment when rendering impostors
+static const F32 MINIMUM_IMPOSTOR_ALPHA = 0.1f;
 
 LLDrawPoolAlpha::LLDrawPoolAlpha(U32 type) :
-		LLRenderPass(type), current_shader(NULL), target_shader(NULL),
-		simple_shader(NULL), fullbright_shader(NULL), emissive_shader(NULL),
+		LLRenderPass(type), target_shader(NULL),
 		mColorSFactor(LLRender::BF_UNDEF), mColorDFactor(LLRender::BF_UNDEF),
 		mAlphaSFactor(LLRender::BF_UNDEF), mAlphaDFactor(LLRender::BF_UNDEF)
 {
-
+ 
 }
 
 LLDrawPoolAlpha::~LLDrawPoolAlpha()
@@ -86,232 +78,213 @@ LLDrawPoolAlpha::~LLDrawPoolAlpha()
 void LLDrawPoolAlpha::prerender()
 {
 	mShaderLevel = LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_OBJECT);
+
+    // TODO: is this even necessay?  These are probably set to never discard
+    LLViewerFetchedTexture::sFlatNormalImagep->addTextureStats(1024.f*1024.f);
+    LLViewerFetchedTexture::sWhiteImagep->addTextureStats(1024.f * 1024.f);
 }
 
 S32 LLDrawPoolAlpha::getNumPostDeferredPasses() 
 { 
-	if (LLPipeline::sImpostorRender)
-	{ //skip depth buffer filling pass when rendering impostors
-		return 1;
-	}
-	else if (gSavedSettings.getBOOL("RenderDepthOfField"))
-	{
-		return 2; 
-	}
-	else
-	{
-		return 1;
-	}
+    return 1;
 }
 
-void LLDrawPoolAlpha::beginPostDeferredPass(S32 pass) 
-{ 
-    LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_DEFERRED);
+// set some common parameters on the given shader to prepare for alpha rendering
+static void prepare_alpha_shader(LLGLSLShader* shader, bool textureGamma, bool deferredEnvironment)
+{
+    static LLCachedControl<F32> displayGamma(gSavedSettings, "RenderDeferredDisplayGamma");
+    F32 gamma = displayGamma;
+
+    // Does this deferred shader need environment uniforms set such as sun_dir, etc. ?
+    // NOTE: We don't actually need a gbuffer since we are doing forward rendering (for transparency) post deferred rendering
+    // TODO: bindDeferredShader() probably should have the updating of the environment uniforms factored out into updateShaderEnvironmentUniforms()
+    // i.e. shaders\class1\deferred\alphaF.glsl
+    if (deferredEnvironment)
+    {
+        gPipeline.bindDeferredShader( *shader );
+    }
+    else
+    {
+        shader->bind();
+    }
+    shader->uniform1i(LLShaderMgr::NO_ATMO, (LLPipeline::sRenderingHUDs) ? 1 : 0);
+    shader->uniform1f(LLShaderMgr::DISPLAY_GAMMA, (gamma > 0.1f) ? 1.0f / gamma : (1.0f / 2.2f));
 
-    F32 gamma = gSavedSettings.getF32("RenderDeferredDisplayGamma");
+    if (LLPipeline::sImpostorRender)
+    {
+        shader->setMinimumAlpha(MINIMUM_IMPOSTOR_ALPHA);
+    }
+    else
+    {
+        shader->setMinimumAlpha(MINIMUM_ALPHA);
+    }
+    if (textureGamma)
+    {
+        shader->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 2.2f);
+    }
 
+    //also prepare rigged variant
+    if (shader->mRiggedVariant && shader->mRiggedVariant != shader)
+    { 
+        prepare_alpha_shader(shader->mRiggedVariant, textureGamma, deferredEnvironment);
+    }
+}
+
+void LLDrawPoolAlpha::renderPostDeferred(S32 pass) 
+{ 
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
+    deferred_render = TRUE;
+
+    // prepare shaders
     emissive_shader = (LLPipeline::sRenderDeferred)   ? &gDeferredEmissiveProgram    :
                       (LLPipeline::sUnderWaterRender) ? &gObjectEmissiveWaterProgram : &gObjectEmissiveProgram;
+    prepare_alpha_shader(emissive_shader, true, false);
 
-    emissive_shader->bind();
-    emissive_shader->uniform1i(LLShaderMgr::NO_ATMO, (LLPipeline::sRenderingHUDs) ? 1 : 0);
-    emissive_shader->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 2.2f); 
-	emissive_shader->uniform1f(LLShaderMgr::DISPLAY_GAMMA, (gamma > 0.1f) ? 1.0f / gamma : (1.0f/2.2f));
+    fullbright_shader   = (LLPipeline::sImpostorRender) ? &gDeferredFullbrightAlphaMaskProgram :
+        (LLPipeline::sUnderWaterRender) ? &gDeferredFullbrightWaterProgram : &gDeferredFullbrightAlphaMaskProgram;
+    prepare_alpha_shader(fullbright_shader, true, false);
 
-	if (pass == 0)
-	{
-        fullbright_shader = (LLPipeline::sImpostorRender)   ? &gDeferredFullbrightProgram      :
-                            (LLPipeline::sUnderWaterRender) ? &gDeferredFullbrightWaterProgram : &gDeferredFullbrightProgram;
+    simple_shader   = (LLPipeline::sImpostorRender) ? &gDeferredAlphaImpostorProgram :
+        (LLPipeline::sUnderWaterRender) ? &gDeferredAlphaWaterProgram : &gDeferredAlphaProgram;
+    prepare_alpha_shader(simple_shader, false, true); //prime simple shader (loads shadow relevant uniforms)
+
+    for (int i = 0; i < LLMaterial::SHADER_COUNT; ++i)
+    {
+        prepare_alpha_shader(LLPipeline::sUnderWaterRender ? &gDeferredMaterialWaterProgram[i] : &gDeferredMaterialProgram[i], false, false); // note: bindDeferredShader will get called during render loop for materials
+    }
 
-		fullbright_shader->bind();
-		fullbright_shader->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 2.2f); 
-		fullbright_shader->uniform1f(LLShaderMgr::DISPLAY_GAMMA, (gamma > 0.1f) ? 1.0f / gamma : (1.0f/2.2f));
-        fullbright_shader->uniform1i(LLShaderMgr::NO_ATMO, LLPipeline::sRenderingHUDs ? 1 : 0);
-		fullbright_shader->unbind();
+    // first pass, render rigged objects only and render to depth buffer
+    forwardRender(true);
 
-        simple_shader = (LLPipeline::sImpostorRender)   ? &gDeferredAlphaImpostorProgram :
-                        (LLPipeline::sUnderWaterRender) ? &gDeferredAlphaWaterProgram    : &gDeferredAlphaProgram;
+    // second pass, regular forward alpha rendering
+    forwardRender();
 
-		//prime simple shader (loads shadow relevant uniforms)
-		gPipeline.bindDeferredShader(*simple_shader);
+    // final pass, render to depth for depth of field effects
+    if (!LLPipeline::sImpostorRender && gSavedSettings.getBOOL("RenderDepthOfField"))
+    { 
+        //update depth buffer sampler
+        gPipeline.mScreen.flush();
+        gPipeline.mDeferredDepth.copyContents(gPipeline.mDeferredScreen, 0, 0, gPipeline.mDeferredScreen.getWidth(), gPipeline.mDeferredScreen.getHeight(),
+            0, 0, gPipeline.mDeferredDepth.getWidth(), gPipeline.mDeferredDepth.getHeight(), GL_DEPTH_BUFFER_BIT, GL_NEAREST);
+        gPipeline.mDeferredDepth.bindTarget();
+        simple_shader = fullbright_shader = &gObjectFullbrightAlphaMaskProgram;
 
-		simple_shader->uniform1f(LLShaderMgr::DISPLAY_GAMMA, (gamma > 0.1f) ? 1.0f / gamma : (1.0f/2.2f));
-        simple_shader->uniform1i(LLShaderMgr::NO_ATMO, LLPipeline::sRenderingHUDs ? 1 : 0);
-	}
-	else if (!LLPipeline::sImpostorRender)
-	{
-		//update depth buffer sampler
-		gPipeline.mScreen.flush();
-		gPipeline.mDeferredDepth.copyContents(gPipeline.mDeferredScreen, 0, 0, gPipeline.mDeferredScreen.getWidth(), gPipeline.mDeferredScreen.getHeight(),
-							0, 0, gPipeline.mDeferredDepth.getWidth(), gPipeline.mDeferredDepth.getHeight(), GL_DEPTH_BUFFER_BIT, GL_NEAREST);	
-		gPipeline.mDeferredDepth.bindTarget();
-		simple_shader = fullbright_shader = &gObjectFullbrightAlphaMaskProgram;
-		gObjectFullbrightAlphaMaskProgram.bind();
-		gObjectFullbrightAlphaMaskProgram.setMinimumAlpha(0.33f);
-	}
+        simple_shader->bind();
+        simple_shader->setMinimumAlpha(0.33f);
 
-	deferred_render = TRUE;
-	if (mShaderLevel > 0)
-	{
-		// Start out with no shaders.
-		current_shader = target_shader = NULL;
-	}
-	gPipeline.enableLightsDynamic();
-}
+        // mask off color buffer writes as we're only writing to depth buffer
+        gGL.setColorMask(false, false);
 
-void LLDrawPoolAlpha::endPostDeferredPass(S32 pass) 
-{ 
-    LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_DEFERRED);
+        // If the face is more than 90% transparent, then don't update the Depth buffer for Dof
+        // We don't want the nearly invisible objects to cause of DoF effects
+        renderAlpha(getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX | LLVertexBuffer::MAP_TANGENT | LLVertexBuffer::MAP_TEXCOORD1 | LLVertexBuffer::MAP_TEXCOORD2, 
+            true); // <--- discard mostly transparent faces
 
-	if (pass == 1 && !LLPipeline::sImpostorRender)
-	{
-		gPipeline.mDeferredDepth.flush();
-		gPipeline.mScreen.bindTarget();
-		gObjectFullbrightAlphaMaskProgram.unbind();
-	}
+        gPipeline.mDeferredDepth.flush();
+        gPipeline.mScreen.bindTarget();
+        gGL.setColorMask(true, false);
+    }
 
-	deferred_render = FALSE;
-	endRenderPass(pass);
+    deferred_render = FALSE;
 }
 
-void LLDrawPoolAlpha::renderPostDeferred(S32 pass) 
-{ 
-    LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_DEFERRED);
-	render(pass); 
+//set some generic parameters for forward (non-deferred) rendering
+static void prepare_forward_shader(LLGLSLShader* shader, F32 minimum_alpha)
+{
+    shader->bind();
+    shader->setMinimumAlpha(minimum_alpha);
+    shader->uniform1i(LLShaderMgr::NO_ATMO, LLPipeline::sRenderingHUDs ? 1 : 0);
+
+    //also prepare rigged variant
+    if (shader->mRiggedVariant && shader->mRiggedVariant != shader)
+    {
+        prepare_forward_shader(shader->mRiggedVariant, minimum_alpha);
+    }
 }
 
-void LLDrawPoolAlpha::beginRenderPass(S32 pass)
+void LLDrawPoolAlpha::render(S32 pass)
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_SETUP);
-	
-    simple_shader     = (LLPipeline::sImpostorRender)   ? &gObjectSimpleImpostorProgram  :
-                        (LLPipeline::sUnderWaterRender) ? &gObjectSimpleWaterProgram     : &gObjectSimpleProgram;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
 
-    fullbright_shader = (LLPipeline::sImpostorRender)   ? &gObjectFullbrightProgram      :
-                        (LLPipeline::sUnderWaterRender) ? &gObjectFullbrightWaterProgram : &gObjectFullbrightProgram;
+    simple_shader = (LLPipeline::sImpostorRender) ? &gObjectSimpleImpostorProgram :
+        (LLPipeline::sUnderWaterRender) ? &gObjectSimpleWaterProgram : &gObjectSimpleAlphaMaskProgram;
 
-    emissive_shader   = (LLPipeline::sImpostorRender)   ? &gObjectEmissiveProgram        :
-                        (LLPipeline::sUnderWaterRender) ? &gObjectEmissiveWaterProgram   : &gObjectEmissiveProgram;
+    fullbright_shader = (LLPipeline::sImpostorRender) ? &gObjectFullbrightAlphaMaskProgram :
+        (LLPipeline::sUnderWaterRender) ? &gObjectFullbrightWaterProgram : &gObjectFullbrightAlphaMaskProgram;
 
+    emissive_shader = (LLPipeline::sImpostorRender) ? &gObjectEmissiveProgram :
+        (LLPipeline::sUnderWaterRender) ? &gObjectEmissiveWaterProgram : &gObjectEmissiveProgram;
+
+    F32 minimum_alpha = MINIMUM_ALPHA;
     if (LLPipeline::sImpostorRender)
-	{
-        if (mShaderLevel > 0)
-		{
-            fullbright_shader->bind();
-			fullbright_shader->setMinimumAlpha(0.5f);
-            fullbright_shader->uniform1i(LLShaderMgr::NO_ATMO, LLPipeline::sRenderingHUDs ? 1 : 0);
-			simple_shader->bind();
-			simple_shader->setMinimumAlpha(0.5f);
-            simple_shader->uniform1i(LLShaderMgr::NO_ATMO, LLPipeline::sRenderingHUDs ? 1 : 0);
-        }
-        else
-        {
-            gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.5f); //OK
-        }
-	}
-    else
-	{
-        if (mShaderLevel > 0)
-	    {
-			fullbright_shader->bind();
-			fullbright_shader->setMinimumAlpha(0.f);
-            fullbright_shader->uniform1i(LLShaderMgr::NO_ATMO, LLPipeline::sRenderingHUDs ? 1 : 0);
-			simple_shader->bind();
-			simple_shader->setMinimumAlpha(0.f);
-            simple_shader->uniform1i(LLShaderMgr::NO_ATMO, LLPipeline::sRenderingHUDs ? 1 : 0);
-		}
-        else
-        {
-            gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT); //OK
-        }
+    {
+        minimum_alpha = MINIMUM_IMPOSTOR_ALPHA;
     }
-	gPipeline.enableLightsDynamic();
 
-    LLGLSLShader::bindNoShader();
-	current_shader = NULL;
-}
+    prepare_forward_shader(fullbright_shader, minimum_alpha);
+    prepare_forward_shader(simple_shader, minimum_alpha);
 
-void LLDrawPoolAlpha::endRenderPass( S32 pass )
-{
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_SETUP);
-	LLRenderPass::endRenderPass(pass);
+    for (int i = 0; i < LLMaterial::SHADER_COUNT; ++i)
+    {
+        prepare_forward_shader(LLPipeline::sUnderWaterRender ? &gDeferredMaterialWaterProgram[i] : &gDeferredMaterialProgram[i], minimum_alpha);
+    }
 
-	if(gPipeline.canUseWindLightShaders()) 
-	{
-		LLGLSLShader::bindNoShader();
-	}
+    //first pass -- rigged only and drawn to depth buffer
+    forwardRender(true);
+
+    //second pass -- non-rigged, no depth buffer writes
+    forwardRender();
 }
 
-void LLDrawPoolAlpha::render(S32 pass)
+void LLDrawPoolAlpha::forwardRender(bool rigged)
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA);
+    gPipeline.enableLightsDynamic();
 
-	LLGLSPipelineAlpha gls_pipeline_alpha;
+    LLGLSPipelineAlpha gls_pipeline_alpha;
 
-	if (deferred_render && pass == 1)
-	{ //depth only
-		gGL.setColorMask(false, false);
-	}
-	else
-	{
-		gGL.setColorMask(true, true);
-	}
-	
-	bool write_depth = LLDrawPoolWater::sSkipScreenCopy
-						 || (deferred_render && pass == 1)
-						 // we want depth written so that rendered alpha will
-						 // contribute to the alpha mask used for impostors
-						 || LLPipeline::sImpostorRenderAlphaDepthPass;
+    //enable writing to alpha for emissive effects
+    gGL.setColorMask(true, true);
 
-	LLGLDepthTest depth(GL_TRUE, write_depth ? GL_TRUE : GL_FALSE);
+    bool write_depth = rigged || 
+        LLDrawPoolWater::sSkipScreenCopy
+        // we want depth written so that rendered alpha will
+        // contribute to the alpha mask used for impostors
+        || LLPipeline::sImpostorRenderAlphaDepthPass;
 
-	if (deferred_render && pass == 1)
-	{
-		gGL.blendFunc(LLRender::BF_SOURCE_ALPHA, LLRender::BF_ONE_MINUS_SOURCE_ALPHA);
-	}
-	else
-	{
-		mColorSFactor = LLRender::BF_SOURCE_ALPHA;           // } regular alpha blend
-		mColorDFactor = LLRender::BF_ONE_MINUS_SOURCE_ALPHA; // }
-		mAlphaSFactor = LLRender::BF_ZERO;                         // } glow suppression
-		mAlphaDFactor = LLRender::BF_ONE_MINUS_SOURCE_ALPHA;       // }
-		gGL.blendFunc(mColorSFactor, mColorDFactor, mAlphaSFactor, mAlphaDFactor);
-	}
+    LLGLDepthTest depth(GL_TRUE, write_depth ? GL_TRUE : GL_FALSE);
 
-	if (mShaderLevel > 0)
-	{
-		renderAlpha(getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX | LLVertexBuffer::MAP_TANGENT | LLVertexBuffer::MAP_TEXCOORD1 | LLVertexBuffer::MAP_TEXCOORD2, pass);
-	}
-	else
-	{
-		renderAlpha(getVertexDataMask(), pass);
-	}
+    mColorSFactor = LLRender::BF_SOURCE_ALPHA;           // } regular alpha blend
+    mColorDFactor = LLRender::BF_ONE_MINUS_SOURCE_ALPHA; // }
+    mAlphaSFactor = LLRender::BF_ZERO;                         // } glow suppression
+    mAlphaDFactor = LLRender::BF_ONE_MINUS_SOURCE_ALPHA;       // }
+    gGL.blendFunc(mColorSFactor, mColorDFactor, mAlphaSFactor, mAlphaDFactor);
 
-	gGL.setColorMask(true, false);
+    // If the face is more than 90% transparent, then don't update the Depth buffer for Dof
+    // We don't want the nearly invisible objects to cause of DoF effects
+    renderAlpha(getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX | LLVertexBuffer::MAP_TANGENT | LLVertexBuffer::MAP_TEXCOORD1 | LLVertexBuffer::MAP_TEXCOORD2, false, rigged);
 
-	if (deferred_render && pass == 1)
-	{
-		gGL.setSceneBlendType(LLRender::BT_ALPHA);
-	}
+    gGL.setColorMask(true, false);
 
+    if (!rigged)
+    { //render "highlight alpha" on final non-rigged pass
+        // NOTE -- hacky call here protected by !rigged instead of alongside "forwardRender"
+        // so renderDebugAlpha is executed while gls_pipeline_alpha and depth GL state
+        // variables above are still in scope
+        renderDebugAlpha();
+    }
+}
+
+void LLDrawPoolAlpha::renderDebugAlpha()
+{
 	if (sShowDebugAlpha)
 	{
-		BOOL shaders = gPipeline.canUseVertexShaders();
-		if(shaders) 
-		{
-			gHighlightProgram.bind();
-		}
-		else
-		{
-			gPipeline.enableLightsFullbright();
-		}
+        gHighlightProgram.bind();
+        gGL.diffuseColor4f(1, 0, 0, 1);
+        LLViewerFetchedTexture::sSmokeImagep->addTextureStats(1024.f * 1024.f);
+        gGL.getTexUnit(0)->bindFast(LLViewerFetchedTexture::sSmokeImagep);
 
-		gGL.diffuseColor4f(1,0,0,1);
-				
-		LLViewerFetchedTexture::sSmokeImagep->addTextureStats(1024.f*1024.f);
-		gGL.getTexUnit(0)->bind(LLViewerFetchedTexture::sSmokeImagep, TRUE) ;
-		renderAlphaHighlight(LLVertexBuffer::MAP_VERTEX |
-							LLVertexBuffer::MAP_TEXCOORD0);
+        renderAlphaHighlight(LLVertexBuffer::MAP_VERTEX |
+            LLVertexBuffer::MAP_TEXCOORD0);
 
 		pushBatches(LLRenderPass::PASS_ALPHA_MASK, LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0, FALSE);
 		pushBatches(LLRenderPass::PASS_ALPHA_INVISIBLE, LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0, FALSE);
@@ -327,43 +300,85 @@ void LLDrawPoolAlpha::render(S32 pass)
 		gGL.diffuseColor4f(0, 1, 0, 1);
 		pushBatches(LLRenderPass::PASS_INVISIBLE, LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0, FALSE);
 
-		if(shaders) 
-		{
-			gHighlightProgram.unbind();
-		}
+        gHighlightProgram.mRiggedVariant->bind();
+        gGL.diffuseColor4f(1, 0, 0, 1);
+
+        pushRiggedBatches(LLRenderPass::PASS_ALPHA_MASK_RIGGED, LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0, FALSE);
+        pushRiggedBatches(LLRenderPass::PASS_ALPHA_INVISIBLE_RIGGED, LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0, FALSE);
+
+        // Material alpha mask
+        gGL.diffuseColor4f(0, 0, 1, 1);
+        pushRiggedBatches(LLRenderPass::PASS_MATERIAL_ALPHA_MASK_RIGGED, LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0, FALSE);
+        pushRiggedBatches(LLRenderPass::PASS_NORMMAP_MASK_RIGGED, LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0, FALSE);
+        pushRiggedBatches(LLRenderPass::PASS_SPECMAP_MASK_RIGGED, LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0, FALSE);
+        pushRiggedBatches(LLRenderPass::PASS_NORMSPEC_MASK_RIGGED, LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0, FALSE);
+        pushRiggedBatches(LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK_RIGGED, LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0, FALSE);
+
+        gGL.diffuseColor4f(0, 1, 0, 1);
+        pushRiggedBatches(LLRenderPass::PASS_INVISIBLE_RIGGED, LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0, FALSE);
+        LLGLSLShader::sCurBoundShaderPtr->unbind();
 	}
 }
 
 void LLDrawPoolAlpha::renderAlphaHighlight(U32 mask)
 {
-	for (LLCullResult::sg_iterator i = gPipeline.beginAlphaGroups(); i != gPipeline.endAlphaGroups(); ++i)
-	{
-		LLSpatialGroup* group = *i;
-		if (group->getSpatialPartition()->mRenderByGroup &&
-			!group->isDead())
-		{
-			LLSpatialGroup::drawmap_elem_t& draw_info = group->mDrawMap[LLRenderPass::PASS_ALPHA];	
+    for (int pass = 0; pass < 2; ++pass)
+    { //two passes, one rigged and one not
+        LLVOAvatar* lastAvatar = nullptr;
+        U64 lastMeshId = 0;
 
-			for (LLSpatialGroup::drawmap_elem_t::iterator k = draw_info.begin(); k != draw_info.end(); ++k)	
-			{
-				LLDrawInfo& params = **k;
-				
-				if (params.mParticle)
-				{
-					continue;
-				}
+        LLCullResult::sg_iterator begin = pass == 0 ? gPipeline.beginAlphaGroups() : gPipeline.beginRiggedAlphaGroups();
+        LLCullResult::sg_iterator end = pass == 0 ? gPipeline.endAlphaGroups() : gPipeline.endRiggedAlphaGroups();
 
-				LLRenderPass::applyModelMatrix(params);
-				if (params.mGroup)
-				{
-					params.mGroup->rebuildMesh();
-				}
-				params.mVertexBuffer->setBuffer(mask);
-				params.mVertexBuffer->drawRange(params.mDrawMode, params.mStart, params.mEnd, params.mCount, params.mOffset);
-				gPipeline.addTrianglesDrawn(params.mCount, params.mDrawMode);
-			}
-		}
-	}
+        for (LLCullResult::sg_iterator i = begin; i != end; ++i)
+        {
+            LLSpatialGroup* group = *i;
+            if (group->getSpatialPartition()->mRenderByGroup &&
+                !group->isDead())
+            {
+                LLSpatialGroup::drawmap_elem_t& draw_info = group->mDrawMap[LLRenderPass::PASS_ALPHA+pass]; // <-- hacky + pass to use PASS_ALPHA_RIGGED on second pass 
+
+                for (LLSpatialGroup::drawmap_elem_t::iterator k = draw_info.begin(); k != draw_info.end(); ++k)
+                {
+                    LLDrawInfo& params = **k;
+
+                    if (params.mParticle)
+                    {
+                        continue;
+                    }
+
+                    bool rigged = (params.mAvatar != nullptr);
+                    gHighlightProgram.bind(rigged);
+                    gGL.diffuseColor4f(1, 0, 0, 1);
+
+                    if (rigged)
+                    {
+                        if (lastAvatar != params.mAvatar ||
+                            lastMeshId != params.mSkinInfo->mHash)
+                        {
+                            if (!uploadMatrixPalette(params))
+                            {
+                                continue;
+                            }
+                            lastAvatar = params.mAvatar;
+                            lastMeshId = params.mSkinInfo->mHash;
+                        }
+                    }
+
+                    LLRenderPass::applyModelMatrix(params);
+                    if (params.mGroup)
+                    {
+                        params.mGroup->rebuildMesh();
+                    }
+                    params.mVertexBuffer->setBufferFast(rigged ? mask | LLVertexBuffer::MAP_WEIGHT4 : mask);
+                    params.mVertexBuffer->drawRangeFast(params.mDrawMode, params.mStart, params.mEnd, params.mCount, params.mOffset);
+                }
+            }
+        }
+    }
+
+    // make sure static version of highlight shader is bound before returning
+    gHighlightProgram.bind();
 }
 
 inline bool IsFullbright(LLDrawInfo& params)
@@ -383,47 +398,41 @@ inline bool IsEmissive(LLDrawInfo& params)
 
 inline void Draw(LLDrawInfo* draw, U32 mask)
 {
-    draw->mVertexBuffer->setBuffer(mask);
+    draw->mVertexBuffer->setBufferFast(mask);
     LLRenderPass::applyModelMatrix(*draw);
-	draw->mVertexBuffer->drawRange(draw->mDrawMode, draw->mStart, draw->mEnd, draw->mCount, draw->mOffset);                    
-    gPipeline.addTrianglesDrawn(draw->mCount, draw->mDrawMode);
+	draw->mVertexBuffer->drawRangeFast(draw->mDrawMode, draw->mStart, draw->mEnd, draw->mCount, draw->mOffset);                    
 }
 
-bool LLDrawPoolAlpha::TexSetup(LLDrawInfo* draw, bool use_shaders, bool use_material, LLGLSLShader* current_shader)
+bool LLDrawPoolAlpha::TexSetup(LLDrawInfo* draw, bool use_material)
 {
-    LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_TEX_BINDS);    
-
     bool tex_setup = false;
 
     if (deferred_render && use_material && current_shader)
     {
-        LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_DEFERRED_TEX_BINDS);
         if (draw->mNormalMap)
-		{            
+		{
 			draw->mNormalMap->addTextureStats(draw->mVSize);
 			current_shader->bindTexture(LLShaderMgr::BUMP_MAP, draw->mNormalMap);
 		} 
-						
+
 		if (draw->mSpecularMap)
 		{
 			draw->mSpecularMap->addTextureStats(draw->mVSize);
 			current_shader->bindTexture(LLShaderMgr::SPECULAR_MAP, draw->mSpecularMap);
 		} 
     }
-    else if (current_shader == simple_shader)
+    else if (current_shader == simple_shader || current_shader == simple_shader->mRiggedVariant)
     {
-        LLViewerFetchedTexture::sFlatNormalImagep->addTextureStats(draw->mVSize);	    
-	    LLViewerFetchedTexture::sWhiteImagep->addTextureStats(draw->mVSize);
-        current_shader->bindTexture(LLShaderMgr::BUMP_MAP, LLViewerFetchedTexture::sFlatNormalImagep);						
+        current_shader->bindTexture(LLShaderMgr::BUMP_MAP, LLViewerFetchedTexture::sFlatNormalImagep);
 	    current_shader->bindTexture(LLShaderMgr::SPECULAR_MAP, LLViewerFetchedTexture::sWhiteImagep);
     }
-	if (use_shaders && draw->mTextureList.size() > 1)
+	if (draw->mTextureList.size() > 1)
 	{
 		for (U32 i = 0; i < draw->mTextureList.size(); ++i)
 		{
 			if (draw->mTextureList[i].notNull())
 			{
-				gGL.getTexUnit(i)->bind(draw->mTextureList[i], TRUE);
+				gGL.getTexUnit(i)->bindFast(draw->mTextureList[i]);
 			}
 		}
 	}
@@ -431,16 +440,15 @@ bool LLDrawPoolAlpha::TexSetup(LLDrawInfo* draw, bool use_shaders, bool use_mate
 	{ //not batching textures or batch has only 1 texture -- might need a texture matrix
 		if (draw->mTexture.notNull())
 		{
-			draw->mTexture->addTextureStats(draw->mVSize);
-			if (use_shaders && use_material)
+			if (use_material)
 			{
 				current_shader->bindTexture(LLShaderMgr::DIFFUSE_MAP, draw->mTexture);
 			}
 			else
 			{
-			    gGL.getTexUnit(0)->bind(draw->mTexture, TRUE) ;
+			    gGL.getTexUnit(0)->bindFast(draw->mTexture);
 			}
-						
+
 			if (draw->mTextureMatrix)
 			{
 				tex_setup = true;
@@ -452,7 +460,7 @@ bool LLDrawPoolAlpha::TexSetup(LLDrawInfo* draw, bool use_shaders, bool use_mate
 		}
 		else
 		{
-			gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+			gGL.getTexUnit(0)->unbindFast(LLTexUnit::TT_TEXTURE);
 		}
 	}
     
@@ -470,160 +478,83 @@ void LLDrawPoolAlpha::RestoreTexSetup(bool tex_setup)
 	}
 }
 
-void LLDrawPoolAlpha::renderSimples(U32 mask, std::vector<LLDrawInfo*>& simples)
+void LLDrawPoolAlpha::drawEmissive(U32 mask, LLDrawInfo* draw)
 {
-    gPipeline.enableLightsDynamic();
-    simple_shader->bind();
-	simple_shader->bindTexture(LLShaderMgr::BUMP_MAP, LLViewerFetchedTexture::sFlatNormalImagep);
-	simple_shader->bindTexture(LLShaderMgr::SPECULAR_MAP, LLViewerFetchedTexture::sWhiteImagep);
-    simple_shader->uniform4f(LLShaderMgr::SPECULAR_COLOR, 1.0f, 1.0f, 1.0f, 1.0f);
-	simple_shader->uniform1f(LLShaderMgr::ENVIRONMENT_INTENSITY, 0.0f);
-    simple_shader->uniform1f(LLShaderMgr::EMISSIVE_BRIGHTNESS, 0.0f);
-    bool use_shaders = gPipeline.canUseVertexShaders();
-    for (LLDrawInfo* draw : simples)
-    {
-        bool tex_setup = TexSetup(draw, use_shaders, false, simple_shader);
-        LLGLEnableFunc stencil_test(GL_STENCIL_TEST, draw->mSelected, &LLGLCommonFunc::selected_stencil_test);
-		gGL.blendFunc((LLRender::eBlendFactor) draw->mBlendFuncSrc, (LLRender::eBlendFactor) draw->mBlendFuncDst, mAlphaSFactor, mAlphaDFactor);
-
-	    Draw(draw, mask);
-        RestoreTexSetup(tex_setup);
-    }
-    simple_shader->unbind();
+    LLGLSLShader::sCurBoundShaderPtr->uniform1f(LLShaderMgr::EMISSIVE_BRIGHTNESS, 1.f);
+    draw->mVertexBuffer->setBufferFast((mask & ~LLVertexBuffer::MAP_COLOR) | LLVertexBuffer::MAP_EMISSIVE);
+	draw->mVertexBuffer->drawRangeFast(draw->mDrawMode, draw->mStart, draw->mEnd, draw->mCount, draw->mOffset);
 }
 
-void LLDrawPoolAlpha::renderFullbrights(U32 mask, std::vector<LLDrawInfo*>& fullbrights)
-{
-    gPipeline.enableLightsFullbright();
-    fullbright_shader->bind();
-    fullbright_shader->uniform1f(LLShaderMgr::EMISSIVE_BRIGHTNESS, 1.0f);
-    bool use_shaders = gPipeline.canUseVertexShaders();
-    for (LLDrawInfo* draw : fullbrights)
-    {
-        bool tex_setup = TexSetup(draw, use_shaders, false, fullbright_shader);
 
-        LLGLEnableFunc stencil_test(GL_STENCIL_TEST, draw->mSelected, &LLGLCommonFunc::selected_stencil_test);
-		gGL.blendFunc((LLRender::eBlendFactor) draw->mBlendFuncSrc, (LLRender::eBlendFactor) draw->mBlendFuncDst, mAlphaSFactor, mAlphaDFactor);
+void LLDrawPoolAlpha::renderEmissives(U32 mask, std::vector<LLDrawInfo*>& emissives)
+{
+    emissive_shader->bind();
+    emissive_shader->uniform1f(LLShaderMgr::EMISSIVE_BRIGHTNESS, 1.f);
 
-        Draw(draw, mask & ~(LLVertexBuffer::MAP_TANGENT | LLVertexBuffer::MAP_TEXCOORD1 | LLVertexBuffer::MAP_TEXCOORD2));
+    for (LLDrawInfo* draw : emissives)
+    {
+        bool tex_setup = TexSetup(draw, false);
+        drawEmissive(mask, draw);
         RestoreTexSetup(tex_setup);
     }
-    fullbright_shader->unbind();
 }
 
-void LLDrawPoolAlpha::renderMaterials(U32 mask, std::vector<LLDrawInfo*>& materials)
+void LLDrawPoolAlpha::renderRiggedEmissives(U32 mask, std::vector<LLDrawInfo*>& emissives)
 {
-    LLGLSLShader::bindNoShader();
-    current_shader = NULL;
+    LLGLDepthTest depth(GL_TRUE, GL_FALSE); //disable depth writes since "emissive" is additive so sorting doesn't matter
+    LLGLSLShader* shader = emissive_shader->mRiggedVariant;
+    shader->bind();
+    shader->uniform1f(LLShaderMgr::EMISSIVE_BRIGHTNESS, 1.f);
 
-    gPipeline.enableLightsDynamic();
-    bool use_shaders = gPipeline.canUseVertexShaders();
-    for (LLDrawInfo* draw : materials)
-    {
-        U32 mask = draw->mShaderMask;
+    LLVOAvatar* lastAvatar = nullptr;
+    U64 lastMeshId = 0;
 
-		llassert(mask < LLMaterial::SHADER_COUNT);
-		target_shader = (LLPipeline::sUnderWaterRender) ? &(gDeferredMaterialWaterProgram[mask]) : &(gDeferredMaterialProgram[mask]);
-
-		if (current_shader != target_shader)
-		{
-            LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_DEFERRED_SHADER_BINDS);
-            if (current_shader)
-            {
-                gPipeline.unbindDeferredShader(*current_shader);
-            }
-			gPipeline.bindDeferredShader(*target_shader);
-            current_shader = target_shader;
-		}
-        
-        bool tex_setup = TexSetup(draw, use_shaders, true, current_shader);
-
-        current_shader->uniform4f(LLShaderMgr::SPECULAR_COLOR, draw->mSpecColor.mV[0], draw->mSpecColor.mV[1], draw->mSpecColor.mV[2], draw->mSpecColor.mV[3]);						
-		current_shader->uniform1f(LLShaderMgr::ENVIRONMENT_INTENSITY, draw->mEnvIntensity);
-		current_shader->uniform1f(LLShaderMgr::EMISSIVE_BRIGHTNESS, draw->mFullbright ? 1.f : 0.f);
+    mask |= LLVertexBuffer::MAP_WEIGHT4;
 
+    for (LLDrawInfo* draw : emissives)
+    {
+        bool tex_setup = TexSetup(draw, false);
+        if (lastAvatar != draw->mAvatar || lastMeshId != draw->mSkinInfo->mHash)
         {
-            LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_DEFERRED_TEX_BINDS);
-			if (draw->mNormalMap)
-			{
-				draw->mNormalMap->addTextureStats(draw->mVSize);
-				current_shader->bindTexture(LLShaderMgr::BUMP_MAP, draw->mNormalMap);
-			} 
-						
-			if (draw->mSpecularMap)
-			{
-				draw->mSpecularMap->addTextureStats(draw->mVSize);
-				current_shader->bindTexture(LLShaderMgr::SPECULAR_MAP, draw->mSpecularMap);
-			}
+            if (!uploadMatrixPalette(*draw))
+            { // failed to upload matrix palette, skip rendering
+                continue;
+            }
+            lastAvatar = draw->mAvatar;
+            lastMeshId = draw->mSkinInfo->mHash;
         }
-
-        LLGLEnableFunc stencil_test(GL_STENCIL_TEST, draw->mSelected, &LLGLCommonFunc::selected_stencil_test);
-		gGL.blendFunc((LLRender::eBlendFactor) draw->mBlendFuncSrc, (LLRender::eBlendFactor) draw->mBlendFuncDst, mAlphaSFactor, mAlphaDFactor);
-
-        Draw(draw, mask);
+        drawEmissive(mask, draw);
         RestoreTexSetup(tex_setup);
     }
 }
 
-void LLDrawPoolAlpha::drawEmissive(U32 mask, LLDrawInfo* draw)
-{
-    draw->mVertexBuffer->setBuffer((mask & ~LLVertexBuffer::MAP_COLOR) | LLVertexBuffer::MAP_EMISSIVE);
-	draw->mVertexBuffer->drawRange(draw->mDrawMode, draw->mStart, draw->mEnd, draw->mCount, draw->mOffset);
-	gPipeline.addTrianglesDrawn(draw->mCount, draw->mDrawMode);
-}
-
-void LLDrawPoolAlpha::drawEmissiveInline(U32 mask, LLDrawInfo* draw)
+void LLDrawPoolAlpha::renderAlpha(U32 mask, bool depth_only, bool rigged)
 {
-    // install glow-accumulating blend mode
-    gGL.blendFunc(
-            LLRender::BF_ZERO, LLRender::BF_ONE, // don't touch color
-			LLRender::BF_ONE, LLRender::BF_ONE); // add to alpha (glow)
-
-	emissive_shader->bind();
-					
-	drawEmissive(mask, draw);
-
-	// restore our alpha blend mode
-	gGL.blendFunc(mColorSFactor, mColorDFactor, mAlphaSFactor, mAlphaDFactor);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
+    BOOL initialized_lighting = FALSE;
+	BOOL light_enabled = TRUE;
 
-    current_shader->bind();
-}
+    LLVOAvatar* lastAvatar = nullptr;
+    U64 lastMeshId = 0;
+    LLGLSLShader* lastAvatarShader = nullptr;
 
-void LLDrawPoolAlpha::renderEmissives(U32 mask, std::vector<LLDrawInfo*>& emissives)
-{
-    emissive_shader->bind();
-    emissive_shader->uniform1f(LLShaderMgr::EMISSIVE_BRIGHTNESS, 1.f);
+    LLCullResult::sg_iterator begin;
+    LLCullResult::sg_iterator end;
 
-    gPipeline.enableLightsDynamic();
-
-    // install glow-accumulating blend mode
-    // don't touch color, add to alpha (glow)
-	gGL.blendFunc(LLRender::BF_ZERO, LLRender::BF_ONE, LLRender::BF_ONE, LLRender::BF_ONE); 
-    bool use_shaders = gPipeline.canUseVertexShaders();
-    for (LLDrawInfo* draw : emissives)
+    if (rigged)
     {
-        bool tex_setup = TexSetup(draw, use_shaders, false, emissive_shader);
-        drawEmissive(mask, draw);
-        RestoreTexSetup(tex_setup);
+        begin = gPipeline.beginRiggedAlphaGroups();
+        end = gPipeline.endRiggedAlphaGroups();
+    }
+    else
+    {
+        begin = gPipeline.beginAlphaGroups();
+        end = gPipeline.endAlphaGroups();
     }
 
-    // restore our alpha blend mode
-	gGL.blendFunc(mColorSFactor, mColorDFactor, mAlphaSFactor, mAlphaDFactor);
-
-    emissive_shader->unbind();
-}
-
-void LLDrawPoolAlpha::renderAlpha(U32 mask, S32 pass)
-{
-    BOOL batch_fullbrights = gSavedSettings.getBOOL("RenderAlphaBatchFullbrights");
-    BOOL batch_emissives   = gSavedSettings.getBOOL("RenderAlphaBatchEmissives");
-	BOOL initialized_lighting = FALSE;
-	BOOL light_enabled = TRUE;
-	
-	BOOL use_shaders = gPipeline.canUseVertexShaders();
-		
-	for (LLCullResult::sg_iterator i = gPipeline.beginAlphaGroups(); i != gPipeline.endAlphaGroups(); ++i)
+    for (LLCullResult::sg_iterator i = begin; i != end; ++i)
 	{
+        LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWPOOL("renderAlpha - group");
 		LLSpatialGroup* group = *i;
 		llassert(group);
 		llassert(group->getSpatialPartition());
@@ -631,25 +562,31 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, S32 pass)
 		if (group->getSpatialPartition()->mRenderByGroup &&
 		    !group->isDead())
 		{
-            std::vector<LLDrawInfo*> emissives;
-            std::vector<LLDrawInfo*> fullbrights;
+            static std::vector<LLDrawInfo*> emissives;
+            static std::vector<LLDrawInfo*> rigged_emissives;
+            emissives.resize(0);
+            rigged_emissives.resize(0);
 
 			bool is_particle_or_hud_particle = group->getSpatialPartition()->mPartitionType == LLViewerRegion::PARTITION_PARTICLE
 													  || group->getSpatialPartition()->mPartitionType == LLViewerRegion::PARTITION_HUD_PARTICLE;
 
 			bool draw_glow_for_this_partition = mShaderLevel > 0; // no shaders = no glow.
 
-			
-			LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_GROUP_LOOP);
-
 			bool disable_cull = is_particle_or_hud_particle;
 			LLGLDisable cull(disable_cull ? GL_CULL_FACE : 0);
 
-			LLSpatialGroup::drawmap_elem_t& draw_info = group->mDrawMap[LLRenderPass::PASS_ALPHA];
+			LLSpatialGroup::drawmap_elem_t& draw_info = rigged ? group->mDrawMap[LLRenderPass::PASS_ALPHA_RIGGED] : group->mDrawMap[LLRenderPass::PASS_ALPHA];
 
 			for (LLSpatialGroup::drawmap_elem_t::iterator k = draw_info.begin(); k != draw_info.end(); ++k)	
 			{
 				LLDrawInfo& params = **k;
+                if ((bool)params.mAvatar != rigged)
+                {
+                    continue;
+                }
+
+                LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWPOOL("ra - push batch")
+
                 U32 have_mask = params.mVertexBuffer->getTypeMask() & mask;
 				if (have_mask != mask)
 				{ //FIXME!
@@ -659,29 +596,21 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, S32 pass)
 					continue;
 				}
 
-				// Fix for bug - NORSPEC-271
-				// If the face is more than 90% transparent, then don't update the Depth buffer for Dof
-				// We don't want the nearly invisible objects to cause of DoF effects
-				if(pass == 1 && !LLPipeline::sImpostorRender)
+				if(depth_only)
 				{
+                    // when updating depth buffer, discard faces that are more than 90% transparent
 					LLFace*	face = params.mFace;
 					if(face)
 					{
 						const LLTextureEntry* tep = face->getTextureEntry();
 						if(tep)
-						{
-							if(tep->getColor().mV[3] < 0.1f)
+						{ // don't render faces that are more than 90% transparent
+							if(tep->getColor().mV[3] < MINIMUM_IMPOSTOR_ALPHA)
 								continue;
 						}
 					}
 				}
 
-                if (params.mFullbright && batch_fullbrights)
-				{
-                    fullbrights.push_back(&params);
-                    continue;
-				}
-
 				LLRenderPass::applyModelMatrix(params);
 
 				LLMaterial* mat = NULL;
@@ -696,34 +625,17 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, S32 pass)
 					// Turn off lighting if it hasn't already been so.
 					if (light_enabled || !initialized_lighting)
 					{
-                        LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_LIGHT_SETUP);
-
 						initialized_lighting = TRUE;
-						if (use_shaders) 
-						{
-							target_shader = fullbright_shader;
-						}
-						else
-						{
-							gPipeline.enableLightsFullbright();
-						}
+						target_shader = fullbright_shader;
+
 						light_enabled = FALSE;
 					}
 				}
 				// Turn on lighting if it isn't already.
 				else if (!light_enabled || !initialized_lighting)
 				{
-                    LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_LIGHT_SETUP);
-
 					initialized_lighting = TRUE;
-					if (use_shaders) 
-					{
-						target_shader = simple_shader;
-					}
-					else
-					{
-						gPipeline.enableLightsDynamic();
-					}
+					target_shader = simple_shader;
 					light_enabled = TRUE;
 				}
 
@@ -739,11 +651,15 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, S32 pass)
 						target_shader = &(gDeferredMaterialWaterProgram[mask]);
 					}
 
+                    if (params.mAvatar != nullptr)
+                    {
+                        llassert(target_shader->mRiggedVariant != nullptr);
+                        target_shader = target_shader->mRiggedVariant;
+                    }
+
 					if (current_shader != target_shader)
 					{
-                        LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_DEFERRED_SHADER_BINDS);
 						gPipeline.bindDeferredShader(*target_shader);
-                        current_shader = target_shader;
 					}
 				}
 				else if (!params.mFullbright)
@@ -755,25 +671,23 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, S32 pass)
 					target_shader = fullbright_shader;
 				}
 				
-				if(use_shaders && (current_shader != target_shader))
-				{// If we need shaders, and we're not ALREADY using the proper shader, then bind it
-				// (this way we won't rebind shaders unnecessarily).
-                    LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_SHADER_BINDS);
-					current_shader = target_shader;
-					current_shader->bind();
-				}
-				else if (!use_shaders && current_shader != NULL)
-				{
-					LLGLSLShader::bindNoShader();
-					current_shader = NULL;
-				}
+                if (params.mAvatar != nullptr)
+                {
+                    target_shader = target_shader->mRiggedVariant;
+                }
+
+                if (current_shader != target_shader)
+                {// If we need shaders, and we're not ALREADY using the proper shader, then bind it
+                // (this way we won't rebind shaders unnecessarily).
+                    target_shader->bind();
+                }
 
                 LLVector4 spec_color(1, 1, 1, 1);
                 F32 env_intensity = 0.0f;
                 F32 brightness = 1.0f;
 
                 // We have a material.  Supply the appropriate data here.
-				if (use_shaders && mat && deferred_render)
+				if (mat && deferred_render)
 				{
 					spec_color    = params.mSpecColor;
                     env_intensity = params.mEnvIntensity;
@@ -782,7 +696,7 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, S32 pass)
 
                 if (current_shader)
                 {
-                    current_shader->uniform4f(LLShaderMgr::SPECULAR_COLOR, spec_color.mV[0], spec_color.mV[1], spec_color.mV[2], spec_color.mV[3]);						
+                    current_shader->uniform4f(LLShaderMgr::SPECULAR_COLOR, spec_color.mV[0], spec_color.mV[1], spec_color.mV[2], spec_color.mV[3]);
 				    current_shader->uniform1f(LLShaderMgr::ENVIRONMENT_INTENSITY, env_intensity);
 					current_shader->uniform1f(LLShaderMgr::EMISSIVE_BRIGHTNESS, brightness);
                 }
@@ -792,38 +706,69 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, S32 pass)
 					params.mGroup->rebuildMesh();
 				}
 
-                bool tex_setup = TexSetup(&params, use_shaders, use_shaders && (mat != nullptr), current_shader);
+                if (params.mAvatar != nullptr)
+                {
+                    if (lastAvatar != params.mAvatar ||
+                        lastMeshId != params.mSkinInfo->mHash ||
+                        lastAvatarShader != LLGLSLShader::sCurBoundShaderPtr)
+                    {
+                        if (!uploadMatrixPalette(params))
+                        {
+                            continue;
+                        }
+                        lastAvatar = params.mAvatar;
+                        lastMeshId = params.mSkinInfo->mHash;
+                        lastAvatarShader = LLGLSLShader::sCurBoundShaderPtr;
+                    }
+                }
 
-				{
-					LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_PUSH);
+                bool tex_setup = TexSetup(&params, (mat != nullptr));
 
+				{
 					LLGLEnableFunc stencil_test(GL_STENCIL_TEST, params.mSelected, &LLGLCommonFunc::selected_stencil_test);
 
 					gGL.blendFunc((LLRender::eBlendFactor) params.mBlendFuncSrc, (LLRender::eBlendFactor) params.mBlendFuncDst, mAlphaSFactor, mAlphaDFactor);
-					params.mVertexBuffer->setBuffer(mask & ~(params.mFullbright ? (LLVertexBuffer::MAP_TANGENT | LLVertexBuffer::MAP_TEXCOORD1 | LLVertexBuffer::MAP_TEXCOORD2) : 0));
 
+                    bool reset_minimum_alpha = false;
+                    if (!LLPipeline::sImpostorRender &&
+                        params.mBlendFuncDst != LLRender::BF_SOURCE_ALPHA &&
+                        params.mBlendFuncSrc != LLRender::BF_SOURCE_ALPHA)
+                    { // this draw call has a custom blend function that may require rendering of "invisible" fragments
+                        current_shader->setMinimumAlpha(0.f);
+                        reset_minimum_alpha = true;
+                    }
+                    
+                    U32 drawMask = mask;
+                    if (params.mFullbright)
                     {
-                        LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_DRAW);
-					    params.mVertexBuffer->drawRange(params.mDrawMode, params.mStart, params.mEnd, params.mCount, params.mOffset);
-					    gPipeline.addTrianglesDrawn(params.mCount, params.mDrawMode);
+                        drawMask &= ~(LLVertexBuffer::MAP_TANGENT | LLVertexBuffer::MAP_TEXCOORD1 | LLVertexBuffer::MAP_TEXCOORD2);
+                    }
+                    if (params.mAvatar != nullptr)
+                    {
+                        drawMask |= LLVertexBuffer::MAP_WEIGHT4;
+                    }
+
+                    params.mVertexBuffer->setBufferFast(drawMask);
+                    params.mVertexBuffer->drawRangeFast(params.mDrawMode, params.mStart, params.mEnd, params.mCount, params.mOffset);
+
+                    if (reset_minimum_alpha)
+                    {
+                        current_shader->setMinimumAlpha(MINIMUM_ALPHA);
                     }
 				}
 
 				// If this alpha mesh has glow, then draw it a second time to add the destination-alpha (=glow).  Interleaving these state-changing calls is expensive, but glow must be drawn Z-sorted with alpha.
-				if (current_shader && 
-					draw_glow_for_this_partition &&
+				if (draw_glow_for_this_partition &&
 					params.mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_EMISSIVE))
 				{
-                    LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_EMISSIVE);
-
-                    if (batch_emissives)
+                    if (params.mAvatar != nullptr)
                     {
-                        emissives.push_back(&params);
+                        rigged_emissives.push_back(&params);
                     }
                     else
                     {
-                        drawEmissiveInline(mask, &params);
-                    } 
+                        emissives.push_back(&params);
+                    }
 				}
 			
 				if (tex_setup)
@@ -835,31 +780,71 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, S32 pass)
 				}
 			}
 
-            if (batch_fullbrights)
+            // render emissive faces into alpha channel for bloom effects
+            if (!depth_only)
             {
-                light_enabled = false;
-                renderFullbrights(mask, fullbrights);
-            }
+                gPipeline.enableLightsDynamic();
 
-            if (batch_emissives)
-            {
-                light_enabled = true;
-                renderEmissives(mask, emissives);
-            }
+                // install glow-accumulating blend mode
+                // don't touch color, add to alpha (glow)
+                gGL.blendFunc(LLRender::BF_ZERO, LLRender::BF_ONE, LLRender::BF_ONE, LLRender::BF_ONE);
 
-            if (current_shader)
-            {
-                current_shader->bind();
+                bool rebind = false;
+                LLGLSLShader* lastShader = current_shader;
+                if (!emissives.empty())
+                {
+                    light_enabled = true;
+                    renderEmissives(mask, emissives);
+                    rebind = true;
+                }
+
+                if (!rigged_emissives.empty())
+                {
+                    light_enabled = true;
+                    renderRiggedEmissives(mask, rigged_emissives);
+                    rebind = true;
+                }
+
+                // restore our alpha blend mode
+                gGL.blendFunc(mColorSFactor, mColorDFactor, mAlphaSFactor, mAlphaDFactor);
+
+                if (lastShader && rebind)
+                {
+                    lastShader->bind();
+                }
             }
-		}        
+		}
 	}
 
 	gGL.setSceneBlendType(LLRender::BT_ALPHA);
 
-	LLVertexBuffer::unbind();	
-		
+	LLVertexBuffer::unbind();
+
 	if (!light_enabled)
 	{
 		gPipeline.enableLightsDynamic();
 	}
 }
+
+bool LLDrawPoolAlpha::uploadMatrixPalette(const LLDrawInfo& params)
+{
+    if (params.mAvatar.isNull())
+    {
+        return false;
+    }
+    const LLVOAvatar::MatrixPaletteCache& mpc = params.mAvatar.get()->updateSkinInfoMatrixPalette(params.mSkinInfo);
+    U32 count = mpc.mMatrixPalette.size();
+
+    if (count == 0)
+    {
+        //skin info not loaded yet, don't render
+        return false;
+    }
+
+    LLGLSLShader::sCurBoundShaderPtr->uniformMatrix3x4fv(LLViewerShaderMgr::AVATAR_MATRIX,
+        count,
+        FALSE,
+        (GLfloat*)&(mpc.mGLMp[0]));
+
+    return true;
+}
diff --git a/indra/newview/lldrawpoolalpha.h b/indra/newview/lldrawpoolalpha.h
index a069f805e827c4d5b175a8a2224b8fa821da6c9d..fa8ef0f22763658f370e9241f14c60ff52fd7f1e 100644
--- a/indra/newview/lldrawpoolalpha.h
+++ b/indra/newview/lldrawpoolalpha.h
@@ -51,39 +51,34 @@ class LLDrawPoolAlpha: public LLRenderPass
 	/*virtual*/ ~LLDrawPoolAlpha();
 
 	/*virtual*/ S32 getNumPostDeferredPasses();
-	/*virtual*/ void beginPostDeferredPass(S32 pass);
-	/*virtual*/ void endPostDeferredPass(S32 pass);
 	/*virtual*/ void renderPostDeferred(S32 pass);
-
-	/*virtual*/ void beginRenderPass(S32 pass = 0);
-	/*virtual*/ void endRenderPass( S32 pass );
 	/*virtual*/ S32	 getNumPasses() { return 1; }
 
 	virtual void render(S32 pass = 0);
+    void forwardRender(bool write_depth = false);
 	/*virtual*/ void prerender();
 
+    void renderDebugAlpha();
+
 	void renderGroupAlpha(LLSpatialGroup* group, U32 type, U32 mask, BOOL texture = TRUE);
-	void renderAlpha(U32 mask, S32 pass);
+	void renderAlpha(U32 mask, bool depth_only = false, bool rigged = false);
 	void renderAlphaHighlight(U32 mask);
-		
+    bool uploadMatrixPalette(const LLDrawInfo& params);
+
 	static BOOL sShowDebugAlpha;
 
 private:
-	LLGLSLShader* current_shader;
 	LLGLSLShader* target_shader;
-	LLGLSLShader* simple_shader;
-	LLGLSLShader* fullbright_shader;	
-	LLGLSLShader* emissive_shader;
 
-    void renderSimples(U32 mask, std::vector<LLDrawInfo*>& simples);
-    void renderFullbrights(U32 mask, std::vector<LLDrawInfo*>& fullbrights);
-    void renderMaterials(U32 mask, std::vector<LLDrawInfo*>& fullbrights);
-    void renderEmissives(U32 mask, std::vector<LLDrawInfo*>& emissives);
+    // setup by beginFooPass, [0] is static variant, [1] is rigged variant
+    LLGLSLShader* simple_shader = nullptr;
+    LLGLSLShader* fullbright_shader = nullptr;
+    LLGLSLShader* emissive_shader = nullptr;
 
     void drawEmissive(U32 mask, LLDrawInfo* draw);
-    void drawEmissiveInline(U32 mask, LLDrawInfo* draw);
-
-    bool TexSetup(LLDrawInfo* draw, bool use_shaders, bool use_material, LLGLSLShader* current_shader);
+    void renderEmissives(U32 mask, std::vector<LLDrawInfo*>& emissives);
+    void renderRiggedEmissives(U32 mask, std::vector<LLDrawInfo*>& emissives);
+    bool TexSetup(LLDrawInfo* draw, bool use_material);
     void RestoreTexSetup(bool tex_setup);
 
 	// our 'normal' alpha blend function for this pass
@@ -91,6 +86,9 @@ class LLDrawPoolAlpha: public LLRenderPass
 	LLRender::eBlendFactor mColorDFactor;	
 	LLRender::eBlendFactor mAlphaSFactor;
 	LLRender::eBlendFactor mAlphaDFactor;
+
+    // if true, we're executing a rigged render pass
+    bool mRigged = false;
 };
 
 class LLDrawPoolAlphaPostWater : public LLDrawPoolAlpha
diff --git a/indra/newview/lldrawpoolavatar.cpp b/indra/newview/lldrawpoolavatar.cpp
index 76cbe85b7e3ced9ca065a406868f7060e4d514c8..4a9a3caaecb8f64b34ffba3cdbbab7d6ee09422d 100644
--- a/indra/newview/lldrawpoolavatar.cpp
+++ b/indra/newview/lldrawpoolavatar.cpp
@@ -103,8 +103,6 @@ S32 normal_channel = -1;
 S32 specular_channel = -1;
 S32 cube_channel = -1;
 
-static LLTrace::BlockTimerStatHandle FTM_SHADOW_AVATAR("Avatar Shadow");
-
 LLDrawPoolAvatar::LLDrawPoolAvatar(U32 type) : 
 	LLFacePool(type)	
 {
@@ -121,28 +119,27 @@ LLDrawPoolAvatar::~LLDrawPoolAvatar()
 // virtual
 BOOL LLDrawPoolAvatar::isDead()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR
+
     if (!LLFacePool::isDead())
     {
         return FALSE;
     }
     
-	for (U32 i = 0; i < NUM_RIGGED_PASSES; ++i)
-    {
-        if (mRiggedFace[i].size() > 0)
-        {
-            return FALSE;
-        }
-    }
     return TRUE;
 }
 
 S32 LLDrawPoolAvatar::getShaderLevel() const
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR
+
 	return (S32) LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_AVATAR);
 }
 
 void LLDrawPoolAvatar::prerender()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR
+
 	mShaderLevel = LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_AVATAR);
 	
 	sShaderLevel = mShaderLevel;
@@ -155,20 +152,12 @@ void LLDrawPoolAvatar::prerender()
 	{
 		sBufferUsage = GL_STREAM_DRAW_ARB;
 	}
-
-	if (!mDrawFace.empty())
-	{
-		const LLFace *facep = mDrawFace[0];
-		if (facep && facep->getDrawable())
-		{
-			LLVOAvatar* avatarp = (LLVOAvatar *)facep->getDrawable()->getVObj().get();
-			updateRiggedVertexBuffers(avatarp);
-		}
-	}
 }
 
 LLMatrix4& LLDrawPoolAvatar::getModelView()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR
+
 	static LLMatrix4 ret;
 
 	ret.initRows(LLVector4(gGLModelView+0),
@@ -187,7 +176,7 @@ LLMatrix4& LLDrawPoolAvatar::getModelView()
 
 void LLDrawPoolAvatar::beginDeferredPass(S32 pass)
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_CHARACTERS);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
 	
 	sSkipTransparent = TRUE;
 	is_deferred_render = true;
@@ -208,21 +197,12 @@ void LLDrawPoolAvatar::beginDeferredPass(S32 pass)
 	case 2:
 		beginDeferredSkinned();
 		break;
-	case 3:
-		beginDeferredRiggedSimple();
-		break;
-	case 4:
-		beginDeferredRiggedBump();
-		break;
-	default:
-		beginDeferredRiggedMaterial(pass-5);
-		break;
 	}
 }
 
 void LLDrawPoolAvatar::endDeferredPass(S32 pass)
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_CHARACTERS);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
 
 	sSkipTransparent = FALSE;
 	is_deferred_render = false;
@@ -243,58 +223,25 @@ void LLDrawPoolAvatar::endDeferredPass(S32 pass)
 	case 2:
 		endDeferredSkinned();
 		break;
-	case 3:
-		endDeferredRiggedSimple();
-		break;
-	case 4:
-		endDeferredRiggedBump();
-		break;
-	default:
-		endDeferredRiggedMaterial(pass-5);
-		break;
 	}
 }
 
 void LLDrawPoolAvatar::renderDeferred(S32 pass)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR
+
 	render(pass);
 }
 
 S32 LLDrawPoolAvatar::getNumPostDeferredPasses()
 {
-	return 10;
+	return 1;
 }
 
 void LLDrawPoolAvatar::beginPostDeferredPass(S32 pass)
 {
-	switch (pass)
-	{
-	case 0:
-		beginPostDeferredAlpha();
-		break;
-	case 1:
-		beginRiggedFullbright();
-		break;
-	case 2:
-		beginRiggedFullbrightShiny();
-		break;
-	case 3:
-		beginDeferredRiggedAlpha();
-		break;
-	case 4:
-		beginRiggedFullbrightAlpha();
-		break;
-	case 9:
-		beginRiggedGlow();
-		break;
-	default:
-		beginDeferredRiggedMaterialAlpha(pass-5);
-		break;
-	}
-}
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR
 
-void LLDrawPoolAvatar::beginPostDeferredAlpha()
-{
 	sSkipOpaque = TRUE;
 	sShaderLevel = mShaderLevel;
 	sVertexProgram = &gDeferredAvatarAlphaProgram;
@@ -307,80 +254,9 @@ void LLDrawPoolAvatar::beginPostDeferredAlpha()
 	sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
 }
 
-void LLDrawPoolAvatar::beginDeferredRiggedAlpha()
-{
-	sVertexProgram = &gDeferredSkinnedAlphaProgram;
-	gPipeline.bindDeferredShader(*sVertexProgram);
-	sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
-	gPipeline.enableLightsDynamic();
-}
-
-void LLDrawPoolAvatar::beginDeferredRiggedMaterialAlpha(S32 pass)
-{
-	switch (pass)
-	{
-	case 0: pass = 1; break;
-	case 1: pass = 5; break;
-	case 2: pass = 9; break;
-	default: pass = 13; break;
-	}
-
-	pass += LLMaterial::SHADER_COUNT;
-
-	sVertexProgram = &gDeferredMaterialProgram[pass];
-
-	if (LLPipeline::sUnderWaterRender)
-	{
-		sVertexProgram = &(gDeferredMaterialWaterProgram[pass]);
-	}
-
-	gPipeline.bindDeferredShader(*sVertexProgram);
-	sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
-	normal_channel = sVertexProgram->enableTexture(LLViewerShaderMgr::BUMP_MAP);
-	specular_channel = sVertexProgram->enableTexture(LLViewerShaderMgr::SPECULAR_MAP);
-	gPipeline.enableLightsDynamic();
-}
-
-void LLDrawPoolAvatar::endDeferredRiggedAlpha()
-{
-	LLVertexBuffer::unbind();
-	gPipeline.unbindDeferredShader(*sVertexProgram);
-	sDiffuseChannel = 0;
-	normal_channel = -1;
-	specular_channel = -1;
-	sVertexProgram = NULL;
-}
-
 void LLDrawPoolAvatar::endPostDeferredPass(S32 pass)
 {
-	switch (pass)
-	{
-	case 0:
-		endPostDeferredAlpha();
-		break;
-	case 1:
-		endRiggedFullbright();
-		break;
-	case 2:
-		endRiggedFullbrightShiny();
-		break;
-	case 3:
-		endDeferredRiggedAlpha();
-		break;
-	case 4:
-		endRiggedFullbrightAlpha();
-		break;
-	case 5:
-		endRiggedGlow();
-		break;
-	default:
-		endDeferredRiggedAlpha();
-		break;
-	}
-}
-
-void LLDrawPoolAvatar::endPostDeferredAlpha()
-{
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR
 	// if we're in software-blending, remember to set the fence _after_ we draw so we wait till this rendering is done
 	sRenderingSkinned = FALSE;
 	sSkipOpaque = FALSE;
@@ -392,29 +268,17 @@ void LLDrawPoolAvatar::endPostDeferredAlpha()
 
 void LLDrawPoolAvatar::renderPostDeferred(S32 pass)
 {
-	static const S32 actual_pass[] =
-	{ //map post deferred pass numbers to what render() expects
-		2, //skinned
-		4, // rigged fullbright
-		6, //rigged fullbright shiny
-		7, //rigged alpha
-		8, //rigged fullbright alpha
-		9, //rigged material alpha 1
-		10,//rigged material alpha 2
-		11,//rigged material alpha 3
-		12,//rigged material alpha 4
-		13, //rigged glow
-	};
-
-	S32 p = actual_pass[pass];
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR
 
+    is_post_deferred_render = true;
 	if (LLPipeline::sImpostorRender)
 	{ //HACK for impostors so actual pass ends up being proper pass
-		p -= 2;
+        render(0);
+	}
+    else
+    {
+        render(2);
 	}
-
-	is_post_deferred_render = true;
-	render(p);
 	is_post_deferred_render = false;
 }
 
@@ -427,7 +291,7 @@ S32 LLDrawPoolAvatar::getNumShadowPasses()
 
 void LLDrawPoolAvatar::beginShadowPass(S32 pass)
 {
-	LL_RECORD_BLOCK_TIME(FTM_SHADOW_AVATAR);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
 
 	if (pass == SHADOW_PASS_AVATAR_OPAQUE)
 	{
@@ -439,7 +303,7 @@ void LLDrawPoolAvatar::beginShadowPass(S32 pass)
 			sVertexProgram->bind();
 		}
 
-		gGL.diffuseColor4f(1,1,1,1);
+        gGL.diffuseColor4f(1, 1, 1, 1);
 	}
     else if (pass == SHADOW_PASS_AVATAR_ALPHA_BLEND)
 	{
@@ -459,7 +323,7 @@ void LLDrawPoolAvatar::beginShadowPass(S32 pass)
 			sVertexProgram->bind();
 		}
 
-		gGL.diffuseColor4f(1,1,1,1);
+        gGL.diffuseColor4f(1, 1, 1, 1);
 	}
     else if (pass == SHADOW_PASS_AVATAR_ALPHA_MASK)
 	{
@@ -479,69 +343,13 @@ void LLDrawPoolAvatar::beginShadowPass(S32 pass)
 			sVertexProgram->bind();
 		}
 
-		gGL.diffuseColor4f(1,1,1,1);
-	}
-    else if (pass == SHADOW_PASS_ATTACHMENT_ALPHA_BLEND)
-	{
-		sVertexProgram = &gDeferredAttachmentAlphaShadowProgram;
-
-        // bind diffuse tex so we can reference the alpha channel...
-        S32 loc = sVertexProgram->getUniformLocation(LLViewerShaderMgr::DIFFUSE_MAP);
-        sDiffuseChannel = 0;
-        if (loc != -1)
-        {
-            sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
-		}
-		
-		if ((sShaderLevel > 0))  // for hardware blending
-		{
-			sRenderingSkinned = TRUE;
-			sVertexProgram->bind();
-		}
-
-		gGL.diffuseColor4f(1,1,1,1);
-	}
-    else if (pass == SHADOW_PASS_ATTACHMENT_ALPHA_MASK)
-	{
-		sVertexProgram = &gDeferredAttachmentAlphaMaskShadowProgram;
-
-        // bind diffuse tex so we can reference the alpha channel...
-		S32 loc = sVertexProgram->getUniformLocation(LLViewerShaderMgr::DIFFUSE_MAP);
-        sDiffuseChannel = 0;
-        if (loc != -1)
-        {
-            sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
-		}
-
-		if ((sShaderLevel > 0))  // for hardware blending
-		{
-			sRenderingSkinned = TRUE;
-			sVertexProgram->bind();
-		}
-
-		gGL.diffuseColor4f(1,1,1,1);
-	}
-	else // SHADOW_PASS_ATTACHMENT_OPAQUE
-	{
-		sVertexProgram = &gDeferredAttachmentShadowProgram;
-		S32 loc = sVertexProgram->getUniformLocation(LLViewerShaderMgr::DIFFUSE_MAP);
-        sDiffuseChannel = 0;
-        if (loc != -1)
-        {
-            sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
-		}
-		sVertexProgram->bind();
+        gGL.diffuseColor4f(1, 1, 1, 1);
 	}
 }
 
 void LLDrawPoolAvatar::endShadowPass(S32 pass)
 {
-	LL_RECORD_BLOCK_TIME(FTM_SHADOW_AVATAR);
-
-	if (pass == SHADOW_PASS_ATTACHMENT_OPAQUE)
-	{
-		LLVertexBuffer::unbind();
-	}
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
 
     if (sShaderLevel > 0)
 	{			
@@ -554,7 +362,7 @@ void LLDrawPoolAvatar::endShadowPass(S32 pass)
 
 void LLDrawPoolAvatar::renderShadow(S32 pass)
 {
-	LL_RECORD_BLOCK_TIME(FTM_SHADOW_AVATAR);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
 
 	if (mDrawFace.empty())
 	{
@@ -574,9 +382,9 @@ void LLDrawPoolAvatar::renderShadow(S32 pass)
 	}
 	LLVOAvatar::AvatarOverallAppearance oa = avatarp->getOverallAppearance();
 	BOOL impostor = !LLPipeline::sImpostorRender && avatarp->isImpostor();
-	if (impostor || (oa == LLVOAvatar::AOA_INVISIBLE))
+    if (impostor || (oa == LLVOAvatar::AOA_INVISIBLE))
 	{
-		// No shadows for impostored (including jellydolled) or invisible avs.
+        // No shadows for impostored (including jellydolled) or invisible avs.
 		return;
 	}
 	
@@ -600,79 +408,23 @@ void LLDrawPoolAvatar::renderShadow(S32 pass)
 		avatarp->renderSkinned();
         LLDrawPoolAvatar::sSkipOpaque = false;
 	}
-    else if (pass == SHADOW_PASS_ATTACHMENT_ALPHA_BLEND) // rigged alpha
-	{
-        LLDrawPoolAvatar::sSkipOpaque = true;
-        renderRigged(avatarp, RIGGED_MATERIAL_ALPHA);
-        renderRigged(avatarp, RIGGED_MATERIAL_ALPHA_EMISSIVE);
-        renderRigged(avatarp, RIGGED_ALPHA);
-        renderRigged(avatarp, RIGGED_FULLBRIGHT_ALPHA);
-        renderRigged(avatarp, RIGGED_GLOW);
-        renderRigged(avatarp, RIGGED_SPECMAP_BLEND);
-        renderRigged(avatarp, RIGGED_NORMMAP_BLEND);
-        renderRigged(avatarp, RIGGED_NORMSPEC_BLEND);
-        LLDrawPoolAvatar::sSkipOpaque = false;
-	}
-    else if (pass == SHADOW_PASS_ATTACHMENT_ALPHA_MASK) // rigged alpha mask
-	{
-        LLDrawPoolAvatar::sSkipOpaque = true;
-        renderRigged(avatarp, RIGGED_MATERIAL_ALPHA_MASK);
-        renderRigged(avatarp, RIGGED_NORMMAP_MASK);
-        renderRigged(avatarp, RIGGED_SPECMAP_MASK);
-		renderRigged(avatarp, RIGGED_NORMSPEC_MASK);    
-        renderRigged(avatarp, RIGGED_GLOW);
-        LLDrawPoolAvatar::sSkipOpaque = false;
-	}
-	else // rigged opaque (SHADOW_PASS_ATTACHMENT_OPAQUE
-	{
-        LLDrawPoolAvatar::sSkipTransparent = true;
-		renderRigged(avatarp, RIGGED_MATERIAL);
-        renderRigged(avatarp, RIGGED_SPECMAP);
-		renderRigged(avatarp, RIGGED_SPECMAP_EMISSIVE);
-		renderRigged(avatarp, RIGGED_NORMMAP);		
-		renderRigged(avatarp, RIGGED_NORMMAP_EMISSIVE);
-		renderRigged(avatarp, RIGGED_NORMSPEC);
-		renderRigged(avatarp, RIGGED_NORMSPEC_EMISSIVE);
-		renderRigged(avatarp, RIGGED_SIMPLE);
-		renderRigged(avatarp, RIGGED_FULLBRIGHT);
-		renderRigged(avatarp, RIGGED_SHINY);
-		renderRigged(avatarp, RIGGED_FULLBRIGHT_SHINY);
-		renderRigged(avatarp, RIGGED_GLOW);
-		renderRigged(avatarp, RIGGED_DEFERRED_BUMP);
-		renderRigged(avatarp, RIGGED_DEFERRED_SIMPLE);
-        LLDrawPoolAvatar::sSkipTransparent = false;
-	}
 }
 
 S32 LLDrawPoolAvatar::getNumPasses()
 {
-	if (LLPipeline::sImpostorRender)
-	{
-		return 8;
-	}
-	else 
-	{
-		return 10;
-	}
+    return 3;
 }
 
 
 S32 LLDrawPoolAvatar::getNumDeferredPasses()
 {
-	if (LLPipeline::sImpostorRender)
-	{
-		return 19;
-	}
-	else
-	{
-		return 21;
-	}
+    return 3;
 }
 
 
 void LLDrawPoolAvatar::render(S32 pass)
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_CHARACTERS);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
 	if (LLPipeline::sImpostorRender)
 	{
 		renderAvatars(NULL, pass+2);
@@ -684,7 +436,7 @@ void LLDrawPoolAvatar::render(S32 pass)
 
 void LLDrawPoolAvatar::beginRenderPass(S32 pass)
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_CHARACTERS);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
 	//reset vertex buffer mappings
 	LLVertexBuffer::unbind();
 
@@ -704,27 +456,6 @@ void LLDrawPoolAvatar::beginRenderPass(S32 pass)
 	case 2:
 		beginSkinned();
 		break;
-	case 3:
-		beginRiggedSimple();
-		break;
-	case 4:
-		beginRiggedFullbright();
-		break;
-	case 5:
-		beginRiggedShinySimple();
-		break;
-	case 6:
-		beginRiggedFullbrightShiny();
-		break;
-	case 7:
-		beginRiggedAlpha();
-		break;
-	case 8:
-		beginRiggedFullbrightAlpha();
-		break;
-	case 9:
-		beginRiggedGlow();
-		break;
 	}
 
 	if (pass == 0)
@@ -735,7 +466,7 @@ void LLDrawPoolAvatar::beginRenderPass(S32 pass)
 
 void LLDrawPoolAvatar::endRenderPass(S32 pass)
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_CHARACTERS);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
 
 	if (LLPipeline::sImpostorRender)
 	{
@@ -753,43 +484,21 @@ void LLDrawPoolAvatar::endRenderPass(S32 pass)
 	case 2:
 		endSkinned();
 		break;
-	case 3:
-		endRiggedSimple();
-		break;
-	case 4:
-		endRiggedFullbright();
-		break;
-	case 5:
-		endRiggedShinySimple();
-		break;
-	case 6:
-		endRiggedFullbrightShiny();
-		break;
-	case 7:
-		endRiggedAlpha();
-		break;
-	case 8:
-		endRiggedFullbrightAlpha();
-		break;
-	case 9:
-		endRiggedGlow();
-		break;
 	}
 }
 
 void LLDrawPoolAvatar::beginImpostor()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR
+
 	if (!LLPipeline::sReflectionRender)
 	{
 		LLVOAvatar::sRenderDistance = llclamp(LLVOAvatar::sRenderDistance, 16.f, 256.f);
 		LLVOAvatar::sNumVisibleAvatars = 0;
 	}
 
-	if (LLGLSLShader::sNoFixedFunction)
-	{
 		gImpostorProgram.bind();
 		gImpostorProgram.setMinimumAlpha(0.01f);
-	}
 
 	gPipeline.enableLightsFullbright();
 	sDiffuseChannel = 0;
@@ -797,16 +506,17 @@ void LLDrawPoolAvatar::beginImpostor()
 
 void LLDrawPoolAvatar::endImpostor()
 {
-	if (LLGLSLShader::sNoFixedFunction)
-	{
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR
+
 		gImpostorProgram.unbind();
-	}
 	gPipeline.enableLightsDynamic();
 }
 
 void LLDrawPoolAvatar::beginRigid()
 {
-	if (gPipeline.canUseVertexShaders())
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR
+
+	if (gPipeline.shadersLoaded())
 	{
 		if (LLPipeline::sUnderWaterRender)
 		{
@@ -839,6 +549,8 @@ void LLDrawPoolAvatar::beginRigid()
 
 void LLDrawPoolAvatar::endRigid()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR
+
 	sShaderLevel = mShaderLevel;
 	if (sVertexProgram != NULL)
 	{
@@ -848,6 +560,8 @@ void LLDrawPoolAvatar::endRigid()
 
 void LLDrawPoolAvatar::beginDeferredImpostor()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR
+
 	if (!LLPipeline::sReflectionRender)
 	{
 		LLVOAvatar::sRenderDistance = llclamp(LLVOAvatar::sRenderDistance, 16.f, 256.f);
@@ -864,6 +578,8 @@ void LLDrawPoolAvatar::beginDeferredImpostor()
 
 void LLDrawPoolAvatar::endDeferredImpostor()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR
+
 	sShaderLevel = mShaderLevel;
 	sVertexProgram->disableTexture(LLViewerShaderMgr::DEFERRED_NORMAL);
 	sVertexProgram->disableTexture(LLViewerShaderMgr::SPECULAR_MAP);
@@ -875,6 +591,8 @@ void LLDrawPoolAvatar::endDeferredImpostor()
 
 void LLDrawPoolAvatar::beginDeferredRigid()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR
+
 	sVertexProgram = &gDeferredNonIndexedDiffuseAlphaMaskNoColorProgram;
 	sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
 	sVertexProgram->bind();
@@ -891,6 +609,8 @@ void LLDrawPoolAvatar::beginDeferredRigid()
 
 void LLDrawPoolAvatar::endDeferredRigid()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR
+
 	sShaderLevel = mShaderLevel;
 	sVertexProgram->disableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
 	sVertexProgram->unbind();
@@ -900,6 +620,8 @@ void LLDrawPoolAvatar::endDeferredRigid()
 
 void LLDrawPoolAvatar::beginSkinned()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR
+
 	if (sShaderLevel > 0)
 	{
 		if (LLPipeline::sUnderWaterRender)
@@ -942,7 +664,7 @@ void LLDrawPoolAvatar::beginSkinned()
 	}
 	else
 	{
-		if(gPipeline.canUseVertexShaders())
+		if(gPipeline.shadersLoaded())
 		{
 			// software skinning, use a basic shader for windlight.
 			// TODO: find a better fallback method for software skinning.
@@ -958,14 +680,13 @@ void LLDrawPoolAvatar::beginSkinned()
 		}
 	}
 
-	if (LLGLSLShader::sNoFixedFunction)
-	{
 		sVertexProgram->setMinimumAlpha(LLDrawPoolAvatar::sMinimumAlpha);
-	}
 }
 
 void LLDrawPoolAvatar::endSkinned()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR
+
 	// if we're in software-blending, remember to set the fence _after_ we draw so we wait till this rendering is done
 	if (sShaderLevel > 0)
 	{
@@ -977,7 +698,7 @@ void LLDrawPoolAvatar::endSkinned()
 	}
 	else
 	{
-		if(gPipeline.canUseVertexShaders())
+		if(gPipeline.shadersLoaded())
 		{
 			// software skinning, use a basic shader for windlight.
 			// TODO: find a better fallback method for software skinning.
@@ -988,1491 +709,207 @@ void LLDrawPoolAvatar::endSkinned()
 	gGL.getTexUnit(0)->activate();
 }
 
-void LLDrawPoolAvatar::beginRiggedSimple()
+void LLDrawPoolAvatar::beginDeferredSkinned()
 {
-	if (sShaderLevel > 0)
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR
+
+	sShaderLevel = mShaderLevel;
+	sVertexProgram = &gDeferredAvatarProgram;
+	sRenderingSkinned = TRUE;
+
+	sVertexProgram->bind();
+	sVertexProgram->setMinimumAlpha(LLDrawPoolAvatar::sMinimumAlpha);
+	if (LLPipeline::sRenderingHUDs)
 	{
-		if (LLPipeline::sUnderWaterRender)
-		{
-			sVertexProgram = &gSkinnedObjectSimpleWaterProgram;
-		}
-		else
-		{
-			sVertexProgram = &gSkinnedObjectSimpleProgram;
-		}
+		sVertexProgram->uniform1i(LLShaderMgr::NO_ATMO, 1);
 	}
 	else
 	{
-		if (LLPipeline::sUnderWaterRender)
-		{
-			sVertexProgram = &gObjectSimpleNonIndexedWaterProgram;
-		}
-		else
-		{
-			sVertexProgram = &gObjectSimpleNonIndexedProgram;
-		}
+		sVertexProgram->uniform1i(LLShaderMgr::NO_ATMO, 0);
 	}
 
-	if (sShaderLevel > 0 || gPipeline.canUseVertexShaders())
-	{
-		sDiffuseChannel = 0;
-		sVertexProgram->bind();
-        if (LLPipeline::sRenderingHUDs)
-	    {
-		    sVertexProgram->uniform1i(LLShaderMgr::NO_ATMO, 1);
-	    }
-	    else
-	    {
-		    sVertexProgram->uniform1i(LLShaderMgr::NO_ATMO, 0);
-	    }
-	}
+	sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
+	gGL.getTexUnit(0)->activate();
 }
 
-void LLDrawPoolAvatar::endRiggedSimple()
+void LLDrawPoolAvatar::endDeferredSkinned()
 {
-	LLVertexBuffer::unbind();
-	if (sShaderLevel > 0 || gPipeline.canUseVertexShaders())
-	{
-		sVertexProgram->unbind();
-		sVertexProgram = NULL;
-	}
-}
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR
 
-void LLDrawPoolAvatar::beginRiggedAlpha()
-{
-	beginRiggedSimple();
-}
+	// if we're in software-blending, remember to set the fence _after_ we draw so we wait till this rendering is done
+	sRenderingSkinned = FALSE;
+	sVertexProgram->unbind();
 
-void LLDrawPoolAvatar::endRiggedAlpha()
-{
-	endRiggedSimple();
-}
+	sVertexProgram->disableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
 
+	sShaderLevel = mShaderLevel;
 
-void LLDrawPoolAvatar::beginRiggedFullbrightAlpha()
-{
-	beginRiggedFullbright();
+	gGL.getTexUnit(0)->activate();
 }
 
-void LLDrawPoolAvatar::endRiggedFullbrightAlpha()
+void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass)
 {
-	endRiggedFullbright();
-}
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR; //LL_RECORD_BLOCK_TIME(FTM_RENDER_CHARACTERS);
 
-void LLDrawPoolAvatar::beginRiggedGlow()
-{
-	if (sShaderLevel > 0)
+	if (pass == -1)
 	{
-		if (LLPipeline::sUnderWaterRender)
-		{
-			sVertexProgram = &gSkinnedObjectEmissiveWaterProgram;
-		}
-		else
-		{
-			sVertexProgram = &gSkinnedObjectEmissiveProgram;
+		for (S32 i = 1; i < getNumPasses(); i++)
+		{ //skip foot shadows
+			prerender();
+			beginRenderPass(i);
+			renderAvatars(single_avatar, i);
+			endRenderPass(i);
 		}
-	}
-	else
-	{
-		if (LLPipeline::sUnderWaterRender)
-		{
-			sVertexProgram = &gObjectEmissiveNonIndexedWaterProgram;
-		}
-		else
-		{
-			sVertexProgram = &gObjectEmissiveNonIndexedProgram;
-		}
-	}
-
-	if (sShaderLevel > 0 || gPipeline.canUseVertexShaders())
-	{
-		sDiffuseChannel = 0;
-		sVertexProgram->bind();
-
-		sVertexProgram->uniform1f(LLShaderMgr::TEXTURE_GAMMA, LLPipeline::sRenderDeferred ? 2.2f : 1.1f);
-
-        if (LLPipeline::sRenderingHUDs)
-	    {
-		    sVertexProgram->uniform1i(LLShaderMgr::NO_ATMO, 1);
-	    }
-	    else
-	    {
-		    sVertexProgram->uniform1i(LLShaderMgr::NO_ATMO, 0);
-	    }
-
-		F32 gamma = gSavedSettings.getF32("RenderDeferredDisplayGamma");
-		sVertexProgram->uniform1f(LLShaderMgr::DISPLAY_GAMMA, (gamma > 0.1f) ? 1.0f / gamma : (1.0f/2.2f));
-	}
-}
-
-void LLDrawPoolAvatar::endRiggedGlow()
-{
-	endRiggedFullbright();
-}
-
-void LLDrawPoolAvatar::beginRiggedFullbright()
-{
-	if (sShaderLevel > 0)
-	{
-		if (LLPipeline::sUnderWaterRender)
-		{
-			sVertexProgram = &gSkinnedObjectFullbrightWaterProgram;
-		}
-		else
-		{
-			if (LLPipeline::sRenderDeferred)
-			{
-				sVertexProgram = &gDeferredSkinnedFullbrightProgram;
-			}
-			else
-			{
-				sVertexProgram = &gSkinnedObjectFullbrightProgram;
-			}
-		}
-	}
-	else
-	{
-		if (LLPipeline::sUnderWaterRender)
-		{
-			sVertexProgram = &gObjectFullbrightNonIndexedWaterProgram;
-		}
-		else
-		{
-			sVertexProgram = &gObjectFullbrightNonIndexedProgram;
-		}
-	}
-
-	if (sShaderLevel > 0 || gPipeline.canUseVertexShaders())
-	{
-		sDiffuseChannel = 0;
-		sVertexProgram->bind();
-
-        if (LLPipeline::sRenderingHUDs)
-        {            
-            sVertexProgram->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 1.0f);
-            sVertexProgram->uniform1i(LLShaderMgr::NO_ATMO, 1);
-        }
-		else if (LLPipeline::sRenderDeferred)
-		{
-            sVertexProgram->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 2.2f);
-            sVertexProgram->uniform1i(LLShaderMgr::NO_ATMO, 0);
-			F32 gamma = gSavedSettings.getF32("RenderDeferredDisplayGamma");
-			sVertexProgram->uniform1f(LLShaderMgr::DISPLAY_GAMMA, (gamma > 0.1f) ? 1.0f / gamma : (1.0f/2.2f));
-		} 
-		else 
-		{
-            sVertexProgram->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 1.0f);
-            sVertexProgram->uniform1i(LLShaderMgr::NO_ATMO, 0);
-		}
-	}
-}
-
-void LLDrawPoolAvatar::endRiggedFullbright()
-{
-	LLVertexBuffer::unbind();
-	if (sShaderLevel > 0 || gPipeline.canUseVertexShaders())
-	{
-		sVertexProgram->unbind();
-		sVertexProgram = NULL;
-	}
-}
-
-void LLDrawPoolAvatar::beginRiggedShinySimple()
-{
-	if (sShaderLevel > 0)
-	{
-		if (LLPipeline::sUnderWaterRender)
-		{
-			sVertexProgram = &gSkinnedObjectShinySimpleWaterProgram;
-		}
-		else
-		{
-			sVertexProgram = &gSkinnedObjectShinySimpleProgram;
-		}
-	}
-	else
-	{
-		if (LLPipeline::sUnderWaterRender)
-		{
-			sVertexProgram = &gObjectShinyNonIndexedWaterProgram;
-		}
-		else
-		{
-			sVertexProgram = &gObjectShinyNonIndexedProgram;
-		}
-	}
-
-	if (sShaderLevel > 0 || gPipeline.canUseVertexShaders())
-	{
-		sVertexProgram->bind();
-        if (LLPipeline::sRenderingHUDs)
-	    {
-		    sVertexProgram->uniform1i(LLShaderMgr::NO_ATMO, 1);
-	    }
-	    else
-	    {
-		    sVertexProgram->uniform1i(LLShaderMgr::NO_ATMO, 0);
-	    }
-		LLDrawPoolBump::bindCubeMap(sVertexProgram, 2, sDiffuseChannel, cube_channel, false);
-	}
-}
-
-void LLDrawPoolAvatar::endRiggedShinySimple()
-{
-	LLVertexBuffer::unbind();
-	if (sShaderLevel > 0 || gPipeline.canUseVertexShaders())
-	{
-		LLDrawPoolBump::unbindCubeMap(sVertexProgram, 2, sDiffuseChannel, cube_channel, false);
-		sVertexProgram->unbind();
-		sVertexProgram = NULL;
-	}
-}
-
-void LLDrawPoolAvatar::beginRiggedFullbrightShiny()
-{
-	if (sShaderLevel > 0)
-	{
-		if (LLPipeline::sUnderWaterRender)
-		{
-			sVertexProgram = &gSkinnedObjectFullbrightShinyWaterProgram;
-		}
-		else
-		{
-			if (LLPipeline::sRenderDeferred)
-			{
-				sVertexProgram = &gDeferredSkinnedFullbrightShinyProgram;
-			}
-			else
-			{
-				sVertexProgram = &gSkinnedObjectFullbrightShinyProgram;
-			}
-		}
-	}
-	else
-	{
-		if (LLPipeline::sUnderWaterRender)
-		{
-			sVertexProgram = &gObjectFullbrightShinyNonIndexedWaterProgram;
-		}
-		else
-		{
-			sVertexProgram = &gObjectFullbrightShinyNonIndexedProgram;
-		}
-	}
-
-	if (sShaderLevel > 0 || gPipeline.canUseVertexShaders())
-	{
-		sVertexProgram->bind();
-        if (LLPipeline::sRenderingHUDs)
-	    {
-		    sVertexProgram->uniform1i(LLShaderMgr::NO_ATMO, 1);
-	    }
-	    else
-	    {
-		    sVertexProgram->uniform1i(LLShaderMgr::NO_ATMO, 0);
-	    }
-		LLDrawPoolBump::bindCubeMap(sVertexProgram, 2, sDiffuseChannel, cube_channel, false);
-
-        if (LLPipeline::sRenderingHUDs)
-		{
-			sVertexProgram->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 1.0f);
-            sVertexProgram->uniform1i(LLShaderMgr::NO_ATMO, 1);
-        }
-		else if (LLPipeline::sRenderDeferred)
-		{
-            sVertexProgram->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 2.2f);
-			F32 gamma = gSavedSettings.getF32("RenderDeferredDisplayGamma");
-			sVertexProgram->uniform1f(LLShaderMgr::DISPLAY_GAMMA, (gamma > 0.1f) ? 1.0f / gamma : (1.0f/2.2f));
-            sVertexProgram->uniform1i(LLShaderMgr::NO_ATMO, 0);
-        }
-        else
-        {
-			sVertexProgram->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 1.0f);
-            sVertexProgram->uniform1i(LLShaderMgr::NO_ATMO, 0);
-		}
-	}
-}
-
-void LLDrawPoolAvatar::endRiggedFullbrightShiny()
-{
-	LLVertexBuffer::unbind();
-	if (sShaderLevel > 0 || gPipeline.canUseVertexShaders())
-	{
-		LLDrawPoolBump::unbindCubeMap(sVertexProgram, 2, sDiffuseChannel, cube_channel, false);
-		sVertexProgram->unbind();
-		sVertexProgram = NULL;
-	}
-}
-
-
-void LLDrawPoolAvatar::beginDeferredRiggedSimple()
-{
-	sVertexProgram = &gDeferredSkinnedDiffuseProgram;
-	sDiffuseChannel = 0;
-	sVertexProgram->bind();
-    if (LLPipeline::sRenderingHUDs)
-	{
-		sVertexProgram->uniform1i(LLShaderMgr::NO_ATMO, 1);
-	}
-	else
-	{
-		sVertexProgram->uniform1i(LLShaderMgr::NO_ATMO, 0);
-	}
-}
-
-void LLDrawPoolAvatar::endDeferredRiggedSimple()
-{
-	LLVertexBuffer::unbind();
-	sVertexProgram->unbind();
-	sVertexProgram = NULL;
-}
-
-void LLDrawPoolAvatar::beginDeferredRiggedBump()
-{
-	sVertexProgram = &gDeferredSkinnedBumpProgram;
-	sVertexProgram->bind();
-    if (LLPipeline::sRenderingHUDs)
-	{
-		sVertexProgram->uniform1i(LLShaderMgr::NO_ATMO, 1);
-	}
-	else
-	{
-		sVertexProgram->uniform1i(LLShaderMgr::NO_ATMO, 0);
-	}
-	normal_channel = sVertexProgram->enableTexture(LLViewerShaderMgr::BUMP_MAP);
-	sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
-}
-
-void LLDrawPoolAvatar::endDeferredRiggedBump()
-{
-	LLVertexBuffer::unbind();
-	sVertexProgram->disableTexture(LLViewerShaderMgr::BUMP_MAP);
-	sVertexProgram->disableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
-	sVertexProgram->unbind();
-	normal_channel = -1;
-	sDiffuseChannel = 0;
-	sVertexProgram = NULL;
-}
-
-void LLDrawPoolAvatar::beginDeferredRiggedMaterial(S32 pass)
-{
-	if (pass == 1 ||
-		pass == 5 ||
-		pass == 9 ||
-		pass == 13)
-	{ //skip alpha passes
-		return;
-	}
-	sVertexProgram = &gDeferredMaterialProgram[pass+LLMaterial::SHADER_COUNT];
-
-	if (LLPipeline::sUnderWaterRender)
-	{
-		sVertexProgram = &(gDeferredMaterialWaterProgram[pass+LLMaterial::SHADER_COUNT]);
-	}
-
-	sVertexProgram->bind();
-    if (LLPipeline::sRenderingHUDs)
-	{
-		sVertexProgram->uniform1i(LLShaderMgr::NO_ATMO, 1);
-	}
-	else
-	{
-		sVertexProgram->uniform1i(LLShaderMgr::NO_ATMO, 0);
-	}
-	normal_channel = sVertexProgram->enableTexture(LLViewerShaderMgr::BUMP_MAP);
-	specular_channel = sVertexProgram->enableTexture(LLViewerShaderMgr::SPECULAR_MAP);
-	sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
-}
-
-void LLDrawPoolAvatar::endDeferredRiggedMaterial(S32 pass)
-{
-	if (pass == 1 ||
-		pass == 5 ||
-		pass == 9 ||
-		pass == 13)
-	{
-		return;
-	}
-
-	LLVertexBuffer::unbind();
-	sVertexProgram->disableTexture(LLViewerShaderMgr::BUMP_MAP);
-	sVertexProgram->disableTexture(LLViewerShaderMgr::SPECULAR_MAP);
-	sVertexProgram->disableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
-	sVertexProgram->unbind();
-	normal_channel = -1;
-	sDiffuseChannel = 0;
-	sVertexProgram = NULL;
-}
-
-void LLDrawPoolAvatar::beginDeferredSkinned()
-{
-	sShaderLevel = mShaderLevel;
-	sVertexProgram = &gDeferredAvatarProgram;
-	sRenderingSkinned = TRUE;
-
-	sVertexProgram->bind();
-	sVertexProgram->setMinimumAlpha(LLDrawPoolAvatar::sMinimumAlpha);
-	if (LLPipeline::sRenderingHUDs)
-	{
-		sVertexProgram->uniform1i(LLShaderMgr::NO_ATMO, 1);
-	}
-	else
-	{
-		sVertexProgram->uniform1i(LLShaderMgr::NO_ATMO, 0);
-	}
-
-	sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
-	gGL.getTexUnit(0)->activate();
-}
-
-void LLDrawPoolAvatar::endDeferredSkinned()
-{
-	// if we're in software-blending, remember to set the fence _after_ we draw so we wait till this rendering is done
-	sRenderingSkinned = FALSE;
-	sVertexProgram->unbind();
-
-	sVertexProgram->disableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
-
-	sShaderLevel = mShaderLevel;
-
-	gGL.getTexUnit(0)->activate();
-}
-
-static LLTrace::BlockTimerStatHandle FTM_RENDER_AVATARS("renderAvatars");
-
-
-void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass)
-{
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_AVATARS);
-
-	if (pass == -1)
-	{
-		for (S32 i = 1; i < getNumPasses(); i++)
-		{ //skip foot shadows
-			prerender();
-			beginRenderPass(i);
-			renderAvatars(single_avatar, i);
-			endRenderPass(i);
-		}
-
-		return;
-	}
-
-	if (mDrawFace.empty() && !single_avatar)
-	{
-		return;
-	}
-
-	LLVOAvatar *avatarp = NULL;
-
-	if (single_avatar)
-	{
-		avatarp = single_avatar;
-	}
-	else
-	{
-		const LLFace *facep = mDrawFace[0];
-		if (!facep->getDrawable())
-		{
-			return;
-		}
-		avatarp = (LLVOAvatar *)facep->getDrawable()->getVObj().get();
-	}
-
-    if (avatarp->isDead() || avatarp->mDrawable.isNull())
-	{
-		return;
-	}
-
-	if (!single_avatar && !avatarp->isFullyLoaded() )
-	{
-		if (pass==0 && (!gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_PARTICLES) || LLViewerPartSim::getMaxPartCount() <= 0))
-		{
-			// debug code to draw a sphere in place of avatar
-			gGL.getTexUnit(0)->bind(LLViewerFetchedTexture::sWhiteImagep);
-			gGL.setColorMask(true, true);
-			LLVector3 pos = avatarp->getPositionAgent();
-			gGL.color4f(1.0f, 1.0f, 1.0f, 0.7f);
-			
-			gGL.pushMatrix();	 
-			gGL.translatef((F32)(pos.mV[VX]),	 
-						   (F32)(pos.mV[VY]),	 
-							(F32)(pos.mV[VZ]));	 
-			 gGL.scalef(0.15f, 0.15f, 0.3f);
-
-			 gSphere.renderGGL();
-				 
-			 gGL.popMatrix();
-			 gGL.setColorMask(true, false);
-		}
-		// don't render please
-		return;
-	}
-
-	BOOL impostor = !LLPipeline::sImpostorRender && avatarp->isImpostor() && !single_avatar;
-
-	if (( avatarp->isInMuteList() 
-		  || impostor 
-		  || (LLVOAvatar::AOA_NORMAL != avatarp->getOverallAppearance() && !avatarp->needsImpostorUpdate()) ) && pass != 0)
-//		  || (LLVOAvatar::AV_DO_NOT_RENDER == avatarp->getVisualMuteSettings() && !avatarp->needsImpostorUpdate()) ) && pass != 0)
-	{ //don't draw anything but the impostor for impostored avatars
-		return;
-	}
-	
-	if (pass == 0 && !impostor && LLPipeline::sUnderWaterRender)
-	{ //don't draw foot shadows under water
-		return;
-	}
-
-	LLVOAvatar *attached_av = avatarp->getAttachedAvatar();
-	if (attached_av && (LLVOAvatar::AOA_NORMAL != attached_av->getOverallAppearance() || !gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_AVATAR)))
-	{
-		// Animesh attachment of a jellydolled or invisible parent - don't show
-		return;
-	}
-
-	if (pass == 0)
-	{
-		if (!LLPipeline::sReflectionRender)
-		{
-			LLVOAvatar::sNumVisibleAvatars++;
-		}
-
-//		if (impostor || (LLVOAvatar::AV_DO_NOT_RENDER == avatarp->getVisualMuteSettings() && !avatarp->needsImpostorUpdate()))
-		if (impostor || (LLVOAvatar::AOA_NORMAL != avatarp->getOverallAppearance() && !avatarp->needsImpostorUpdate()))
-		{
-			if (LLPipeline::sRenderDeferred && !LLPipeline::sReflectionRender && avatarp->mImpostor.isComplete()) 
-			{
-				if (normal_channel > -1)
-				{
-					avatarp->mImpostor.bindTexture(2, normal_channel);
-				}
-				if (specular_channel > -1)
-				{
-					avatarp->mImpostor.bindTexture(1, specular_channel);
-				}
-			}
-			avatarp->renderImpostor(avatarp->getMutedAVColor(), sDiffuseChannel);
-		}
-		return;
-	}
-
-	if (pass == 1)
-	{
-		// render rigid meshes (eyeballs) first
-		avatarp->renderRigid();
-		return;
-	}
-
-	if (pass == 3)
-	{
-		if (is_deferred_render)
-		{
-			renderDeferredRiggedSimple(avatarp);
-		}
-		else
-		{
-			renderRiggedSimple(avatarp);
-
-			if (LLPipeline::sRenderDeferred)
-			{ //render "simple" materials
-				renderRigged(avatarp, RIGGED_MATERIAL);
-				renderRigged(avatarp, RIGGED_MATERIAL_ALPHA_MASK);
-				renderRigged(avatarp, RIGGED_MATERIAL_ALPHA_EMISSIVE);
-				renderRigged(avatarp, RIGGED_NORMMAP);
-				renderRigged(avatarp, RIGGED_NORMMAP_MASK);
-				renderRigged(avatarp, RIGGED_NORMMAP_EMISSIVE);	
-				renderRigged(avatarp, RIGGED_SPECMAP);
-				renderRigged(avatarp, RIGGED_SPECMAP_MASK);
-				renderRigged(avatarp, RIGGED_SPECMAP_EMISSIVE);
-				renderRigged(avatarp, RIGGED_NORMSPEC);
-				renderRigged(avatarp, RIGGED_NORMSPEC_MASK);
-				renderRigged(avatarp, RIGGED_NORMSPEC_EMISSIVE);
-			}
-		}
-		return;
-	}
-
-	if (pass == 4)
-	{
-		if (is_deferred_render)
-		{
-			renderDeferredRiggedBump(avatarp);
-		}
-		else
-		{
-			renderRiggedFullbright(avatarp);
-		}
-
-		return;
-	}
-
-	if (is_deferred_render && pass >= 5 && pass <= 21)
-	{
-		S32 p = pass-5;
-
-		if (p != 1 &&
-			p != 5 &&
-			p != 9 &&
-			p != 13)
-		{
-			renderDeferredRiggedMaterial(avatarp, p);
-		}
-		return;
-	}
-
-
-
-
-	if (pass == 5)
-	{
-		renderRiggedShinySimple(avatarp);
-				
-		return;
-	}
-
-	if (pass == 6)
-	{
-		renderRiggedFullbrightShiny(avatarp);
-		return;
-	}
-
-	if (pass >= 7 && pass < 13)
-	{
-		if (pass == 7)
-		{
-			renderRiggedAlpha(avatarp);
-
-			if (LLPipeline::sRenderDeferred && !is_post_deferred_render)
-			{ //render transparent materials under water
-				LLGLEnable blend(GL_BLEND);
-
-				gGL.setColorMask(true, true);
-				gGL.blendFunc(LLRender::BF_SOURCE_ALPHA,
-								LLRender::BF_ONE_MINUS_SOURCE_ALPHA,
-								LLRender::BF_ZERO,
-								LLRender::BF_ONE_MINUS_SOURCE_ALPHA);
-
-				renderRigged(avatarp, RIGGED_MATERIAL_ALPHA);
-				renderRigged(avatarp, RIGGED_SPECMAP_BLEND);
-				renderRigged(avatarp, RIGGED_NORMMAP_BLEND);
-				renderRigged(avatarp, RIGGED_NORMSPEC_BLEND);
-
-				gGL.setColorMask(true, false);
-			}
-			return;
-		}
-
-		if (pass == 8)
-		{
-			renderRiggedFullbrightAlpha(avatarp);
-			return;
-		}
-
-		if (LLPipeline::sRenderDeferred && is_post_deferred_render)
-		{
-			S32 p = 0;
-			switch (pass)
-			{
-			case 9: p = 1; break;
-			case 10: p = 5; break;
-			case 11: p = 9; break;
-			case 12: p = 13; break;
-			}
-
-			{
-				LLGLEnable blend(GL_BLEND);
-				renderDeferredRiggedMaterial(avatarp, p);
-			}
-			return;
-		}
-		else if (pass == 9)
-		{
-			renderRiggedGlow(avatarp);
-			return;
-		}
-	}
-
-	if (pass == 13)
-	{
-		renderRiggedGlow(avatarp);
-		
-		return;
-	}
-	
-	if ((sShaderLevel >= SHADER_LEVEL_CLOTH))
-	{
-		LLMatrix4 rot_mat;
-		LLViewerCamera::getInstance()->getMatrixToLocal(rot_mat);
-		LLMatrix4 cfr(OGL_TO_CFR_ROTATION);
-		rot_mat *= cfr;
-		
-		LLVector4 wind;
-		wind.setVec(avatarp->mWindVec);
-		wind.mV[VW] = 0;
-		wind = wind * rot_mat;
-		wind.mV[VW] = avatarp->mWindVec.mV[VW];
-
-		sVertexProgram->uniform4fv(LLViewerShaderMgr::AVATAR_WIND, 1, wind.mV);
-		F32 phase = -1.f * (avatarp->mRipplePhase);
-
-		F32 freq = 7.f + (noise1(avatarp->mRipplePhase) * 2.f);
-		LLVector4 sin_params(freq, freq, freq, phase);
-		sVertexProgram->uniform4fv(LLViewerShaderMgr::AVATAR_SINWAVE, 1, sin_params.mV);
-
-		LLVector4 gravity(0.f, 0.f, -CLOTHING_GRAVITY_EFFECT, 0.f);
-		gravity = gravity * rot_mat;
-		sVertexProgram->uniform4fv(LLViewerShaderMgr::AVATAR_GRAVITY, 1, gravity.mV);
-	}
-
-	if( !single_avatar || (avatarp == single_avatar) )
-	{
-		avatarp->renderSkinned();
-	}
-}
-
-void LLDrawPoolAvatar::getRiggedGeometry(
-    LLFace* face,
-    LLPointer<LLVertexBuffer>& buffer,
-    U32 data_mask,
-    const LLMeshSkinInfo* skin,
-    LLVolume* volume,
-    const LLVolumeFace& vol_face)
-{
-    face->setGeomIndex(0);
-    face->setIndicesIndex(0);
-
-    if (face->getTextureIndex() != FACE_DO_NOT_BATCH_TEXTURES)
-    {
-        face->setDrawInfo(NULL);
-    }
-
-    //rigged faces do not batch textures
-    face->setTextureIndex(FACE_DO_NOT_BATCH_TEXTURES);
-
-	if (buffer.isNull() || buffer->getTypeMask() != data_mask || !buffer->isWriteable())
-	{
-        // make a new buffer
-		if (sShaderLevel > 0)
-		{
-			buffer = new LLVertexBuffer(data_mask, GL_DYNAMIC_DRAW_ARB);
-		}
-		else
-		{
-			buffer = new LLVertexBuffer(data_mask, GL_STREAM_DRAW_ARB);
-		}
-
-		if (!buffer->allocateBuffer(vol_face.mNumVertices, vol_face.mNumIndices, true))
-		{
-			LL_WARNS("LLDrawPoolAvatar") << "Failed to allocate Vertex Buffer to "
-				<< vol_face.mNumVertices << " vertices and "
-				<< vol_face.mNumIndices << " indices" << LL_ENDL;
-			// allocate dummy triangle
-			buffer->allocateBuffer(1, 3, true);
-			memset((U8*)buffer->getMappedData(), 0, buffer->getSize());
-			memset((U8*)buffer->getMappedIndices(), 0, buffer->getIndicesSize());
-		}
-	}
-	else
-	{
-        //resize existing buffer
-		if(!buffer->resizeBuffer(vol_face.mNumVertices, vol_face.mNumIndices))
-		{
-			LL_WARNS("LLDrawPoolAvatar") << "Failed to resize Vertex Buffer to "
-				<< vol_face.mNumVertices << " vertices and "
-				<< vol_face.mNumIndices << " indices" << LL_ENDL;
-			// allocate dummy triangle
-			buffer->resizeBuffer(1, 3);
-			memset((U8*)buffer->getMappedData(), 0, buffer->getSize());
-			memset((U8*)buffer->getMappedIndices(), 0, buffer->getIndicesSize());
-		}
-	}
-
-	face->setSize(buffer->getNumVerts(), buffer->getNumIndices());
-	face->setVertexBuffer(buffer);
-
-	U16 offset = 0;
-		
-	LLMatrix4 mat_vert = skin->mBindShapeMatrix;
-	glh::matrix4f m((F32*) mat_vert.mMatrix);
-	m = m.inverse().transpose();
-		
-	F32 mat3[] = 
-        { m.m[0], m.m[1], m.m[2],
-          m.m[4], m.m[5], m.m[6],
-          m.m[8], m.m[9], m.m[10] };
-
-	LLMatrix3 mat_normal(mat3);				
-
-	//let getGeometryVolume know if alpha should override shiny
-	U32 type = gPipeline.getPoolTypeFromTE(face->getTextureEntry(), face->getTexture());
-
-	if (type == LLDrawPool::POOL_ALPHA)
-	{
-		face->setPoolType(LLDrawPool::POOL_ALPHA);
-	}
-	else
-	{
-		face->setPoolType(mType); // either POOL_AVATAR or POOL_CONTROL_AV
-	}
-
-	//LL_INFOS() << "Rebuilt face " << face->getTEOffset() << " of " << face->getDrawable() << " at " << gFrameTimeSeconds << LL_ENDL;
-
-	// Let getGeometryVolume know if a texture matrix is in play
-	if (face->mTextureMatrix)
-	{
-		face->setState(LLFace::TEXTURE_ANIM);
-	}
-	else
-	{
-		face->clearState(LLFace::TEXTURE_ANIM);
-	}
-	face->getGeometryVolume(*volume, face->getTEOffset(), mat_vert, mat_normal, offset, true);
-
-	buffer->flush();
-}
-
-void LLDrawPoolAvatar::updateRiggedFaceVertexBuffer(
-    LLVOAvatar* avatar,
-    LLFace* face,
-    const LLMeshSkinInfo* skin,
-    LLVolume* volume,
-    LLVolumeFace& vol_face)
-{
-	LLVector4a* weights = vol_face.mWeights;
-	if (!weights)
-	{
+
 		return;
 	}
 
-	LLPointer<LLVertexBuffer> buffer = face->getVertexBuffer();
-	LLDrawable* drawable = face->getDrawable();
-
-	if (drawable->getVOVolume() && drawable->getVOVolume()->isNoLOD())
+	if (mDrawFace.empty() && !single_avatar)
 	{
 		return;
 	}
 
-    const U32 max_joints = LLSkinningUtil::getMaxJointCount();
-
-#if USE_SEPARATE_JOINT_INDICES_AND_WEIGHTS
-    #define CONDITION_WEIGHT(f) ((U8)llclamp((S32)f, (S32)0, (S32)max_joints-1))
-    LLVector4a* just_weights = vol_face.mJustWeights;
-    // we need to calculate the separated indices and store just the matrix weights for this vol...
-    if (!vol_face.mJointIndices)
-    {
-        // not very consty after all...
-        vol_face.allocateJointIndices(vol_face.mNumVertices);
-        just_weights = vol_face.mJustWeights;
-
-        U8* joint_indices_cursor = vol_face.mJointIndices;
-        for (int i = 0; i < vol_face.mNumVertices; i++)
-        {
-            F32* w = weights[i].getF32ptr();
-            F32* w_ = just_weights[i].getF32ptr();
-
-            F32 w0 = floorf(w[0]);
-            F32 w1 = floorf(w[1]);
-            F32 w2 = floorf(w[2]);
-            F32 w3 = floorf(w[3]);
-
-            joint_indices_cursor[0] = CONDITION_WEIGHT(w0);
-            joint_indices_cursor[1] = CONDITION_WEIGHT(w1);
-            joint_indices_cursor[2] = CONDITION_WEIGHT(w2);
-            joint_indices_cursor[3] = CONDITION_WEIGHT(w3);
-
-            // remove joint portion of combined weight
-            w_[0] = w[0] - w0;
-            w_[1] = w[1] - w1;
-            w_[2] = w[2] - w2;
-            w_[3] = w[3] - w3;
-
-            joint_indices_cursor += 4;
-        }
-    }
-#endif
-
-    // FIXME ugly const cast
-    LLSkinningUtil::scrubInvalidJoints(avatar, const_cast<LLMeshSkinInfo*>(skin));
-
-	U32 data_mask = face->getRiggedVertexBufferDataMask();
+	LLVOAvatar *avatarp = NULL;
 
-    if (!vol_face.mWeightsScrubbed)
-    {
-        LLSkinningUtil::scrubSkinWeights(weights, vol_face.mNumVertices, skin);
-        vol_face.mWeightsScrubbed = TRUE;
-    }
-	
-	if (buffer.isNull() || 
-		buffer->getTypeMask() != data_mask ||
-		buffer->getNumVerts() != vol_face.mNumVertices ||
-		buffer->getNumIndices() != vol_face.mNumIndices ||
-		(drawable && drawable->isState(LLDrawable::REBUILD_ALL)))
+	if (single_avatar)
 	{
-		if (drawable && drawable->isState(LLDrawable::REBUILD_ALL))
-		{
-            //rebuild EVERY face in the drawable, not just this one, to avoid missing drawable wide rebuild issues
-			for (S32 i = 0; i < drawable->getNumFaces(); ++i)
-			{
-				LLFace* facep = drawable->getFace(i);
-				U32 face_data_mask = facep->getRiggedVertexBufferDataMask();
-				if (face_data_mask)
-				{
-					LLPointer<LLVertexBuffer> cur_buffer = facep->getVertexBuffer();
-					const LLVolumeFace& cur_vol_face = volume->getVolumeFace(i);
-					getRiggedGeometry(facep, cur_buffer, face_data_mask, skin, volume, cur_vol_face);
-				}
-			}
-			drawable->clearState(LLDrawable::REBUILD_ALL);
-
-			buffer = face->getVertexBuffer();
-		}
-		else
+		avatarp = single_avatar;
+	}
+	else
+	{
+		const LLFace *facep = mDrawFace[0];
+		if (!facep->getDrawable())
 		{
-			//just rebuild this face
-			getRiggedGeometry(face, buffer, data_mask, skin, volume, vol_face);
+			return;
 		}
+		avatarp = (LLVOAvatar *)facep->getDrawable()->getVObj().get();
 	}
 
-	if (buffer.isNull() ||
-		buffer->getNumVerts() != vol_face.mNumVertices ||
-		buffer->getNumIndices() != vol_face.mNumIndices)
+    if (avatarp->isDead() || avatarp->mDrawable.isNull())
 	{
-		// Allocation failed
 		return;
 	}
 
-	if (!buffer.isNull() && 
-		sShaderLevel <= 0 && 
-		face->mLastSkinTime < avatar->getLastSkinTime())
+	if (!single_avatar && !avatarp->isFullyLoaded() )
 	{
-		//perform software vertex skinning for this face
-		LLStrider<LLVector3> position;
-		LLStrider<LLVector3> normal;
-
-		bool has_normal = buffer->hasDataType(LLVertexBuffer::TYPE_NORMAL);
-		buffer->getVertexStrider(position);
-
-		if (has_normal)
+		if (pass==0 && (!gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_PARTICLES) || LLViewerPartSim::getMaxPartCount() <= 0))
 		{
-			buffer->getNormalStrider(normal);
+			// debug code to draw a sphere in place of avatar
+			gGL.getTexUnit(0)->bind(LLViewerFetchedTexture::sWhiteImagep);
+			gGL.setColorMask(true, true);
+			LLVector3 pos = avatarp->getPositionAgent();
+			gGL.color4f(1.0f, 1.0f, 1.0f, 0.7f);
+			
+			gGL.pushMatrix();	 
+			gGL.translatef((F32)(pos.mV[VX]),	 
+						   (F32)(pos.mV[VY]),	 
+							(F32)(pos.mV[VZ]));	 
+			 gGL.scalef(0.15f, 0.15f, 0.3f);
+
+			 gSphere.renderGGL();
+				 
+			 gGL.popMatrix();
+			 gGL.setColorMask(true, false);
 		}
+		// don't render please
+		return;
+	}
 
-		LLVector4a* pos = (LLVector4a*) position.get();
+	BOOL impostor = !LLPipeline::sImpostorRender && avatarp->isImpostor() && !single_avatar;
 
-		LLVector4a* norm = has_normal ? (LLVector4a*) normal.get() : NULL;
-		
-		//build matrix palette
-		LLMatrix4a mat[LL_MAX_JOINTS_PER_MESH_OBJECT];
-        U32 count = LLSkinningUtil::getMeshJointCount(skin);
-        LLSkinningUtil::initSkinningMatrixPalette((LLMatrix4*)mat, count, skin, avatar);
-        LLSkinningUtil::checkSkinWeights(weights, buffer->getNumVerts(), skin);
-
-		LLMatrix4a bind_shape_matrix;
-		bind_shape_matrix.loadu(skin->mBindShapeMatrix);
-
-#if USE_SEPARATE_JOINT_INDICES_AND_WEIGHTS
-        U8* joint_indices_cursor = vol_face.mJointIndices;
-        // fast path with joint indices separate from weights
-        if (joint_indices_cursor)
-        {
-            LLMatrix4a src[4];
-		    for (U32 j = 0; j < buffer->getNumVerts(); ++j)
-		    {
-			    LLMatrix4a final_mat;
-                //LLMatrix4a final_mat_correct;
-
-                F32* jw = just_weights[j].getF32ptr();
-
-                LLSkinningUtil::getPerVertexSkinMatrixWithIndices(jw, joint_indices_cursor, mat, final_mat, src);                
-
-                joint_indices_cursor += 4;
-
-			    LLVector4a& v = vol_face.mPositions[j];
-
-			    LLVector4a t;
-			    LLVector4a dst;
-			    bind_shape_matrix.affineTransform(v, t);
-			    final_mat.affineTransform(t, dst);
-			    pos[j] = dst;
-
-			    if (norm)
-			    {
-				    LLVector4a& n = vol_face.mNormals[j];
-				    bind_shape_matrix.rotate(n, t);
-				    final_mat.rotate(t, dst);
-				    dst.normalize3fast();
-				    norm[j] = dst;
-			    }
-		    }
-        }
-        // slow path with joint indices calculated from weights
-        else
-#endif
-        {
-            for (U32 j = 0; j < buffer->getNumVerts(); ++j)
-		    {
-			    LLMatrix4a final_mat;
-                LLSkinningUtil::getPerVertexSkinMatrix(weights[j].getF32ptr(), mat, false, final_mat, max_joints);
-
-			    LLVector4a& v = vol_face.mPositions[j];
-			    LLVector4a t;
-			    LLVector4a dst;
-			    bind_shape_matrix.affineTransform(v, t);
-			    final_mat.affineTransform(t, dst);
-			    pos[j] = dst;
-
-			    if (norm)
-			    {
-				    LLVector4a& n = vol_face.mNormals[j];
-				    bind_shape_matrix.rotate(n, t);
-				    final_mat.rotate(t, dst);
-				    //dst.normalize3fast();
-				    norm[j] = dst;
-			    }
-		    }
-        }
+	if (( avatarp->isInMuteList() 
+		  || impostor 
+		  || (LLVOAvatar::AOA_NORMAL != avatarp->getOverallAppearance() && !avatarp->needsImpostorUpdate()) ) && pass != 0)
+//		  || (LLVOAvatar::AV_DO_NOT_RENDER == avatarp->getVisualMuteSettings() && !avatarp->needsImpostorUpdate()) ) && pass != 0)
+	{ //don't draw anything but the impostor for impostored avatars
+		return;
+	}
+	
+	if (pass == 0 && !impostor && LLPipeline::sUnderWaterRender)
+	{ //don't draw foot shadows under water
+		return;
 	}
-}
 
-void LLDrawPoolAvatar::renderRigged(LLVOAvatar* avatar, U32 type, bool glow)
-{
-	if (!avatar->shouldRenderRigged())
+	LLVOAvatar *attached_av = avatarp->getAttachedAvatar();
+	if (attached_av && (LLVOAvatar::AOA_NORMAL != attached_av->getOverallAppearance() || !gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_AVATAR)))
 	{
+		// Animesh attachment of a jellydolled or invisible parent - don't show
 		return;
 	}
 
-	stop_glerror();
-
-	for (U32 i = 0; i < mRiggedFace[type].size(); ++i)
+	if (pass == 0)
 	{
-		LLFace* face = mRiggedFace[type][i];
-
-        S32 offset = face->getIndicesStart();
-		U32 count = face->getIndicesCount();
-
-        U16 start = face->getGeomStart();
-		U16 end = start + face->getGeomCount()-1;			
-
-		LLDrawable* drawable = face->getDrawable();
-		if (!drawable)
-		{
-			continue;
-		}
-
-		LLVOVolume* vobj = drawable->getVOVolume();
-
-		if (!vobj)
-		{
-			continue;
-		}
-
-		LLVolume* volume = vobj->getVolume();
-		S32 te = face->getTEOffset();
-
-		if (!volume || volume->getNumVolumeFaces() <= te || !volume->isMeshAssetLoaded())
+		if (!LLPipeline::sReflectionRender)
 		{
-			continue;
+			LLVOAvatar::sNumVisibleAvatars++;
 		}
 
-		const LLMeshSkinInfo* skin = vobj->getSkinInfo();
-		if (!skin)
+//		if (impostor || (LLVOAvatar::AV_DO_NOT_RENDER == avatarp->getVisualMuteSettings() && !avatarp->needsImpostorUpdate()))
+		if (impostor || (LLVOAvatar::AOA_NORMAL != avatarp->getOverallAppearance() && !avatarp->needsImpostorUpdate()))
 		{
-			continue;
-		}
-
-		//stop_glerror();
-
-		//const LLVolumeFace& vol_face = volume->getVolumeFace(te);
-		//updateRiggedFaceVertexBuffer(avatar, face, skin, volume, vol_face);
-		
-		//stop_glerror();
-
-		U32 data_mask = LLFace::getRiggedDataMask(type);
-
-		LLVertexBuffer* buff = face->getVertexBuffer();
-
-        const LLTextureEntry* tex_entry = face->getTextureEntry();
-		LLMaterial* mat = tex_entry ? tex_entry->getMaterialParams().get() : nullptr;
-
-        if (LLDrawPoolAvatar::sShadowPass >= 0)
-        {
-            bool is_alpha_blend = false;
-            bool is_alpha_mask  = false;
-
-            LLViewerTexture* tex = face->getTexture(LLRender::DIFFUSE_MAP);
-            if (tex)
-            {
-                if (tex->getIsAlphaMask())
-                {
-                    is_alpha_mask = true;
-                }
-            }
-
-            if (tex)
-            {
-                LLGLenum image_format = tex->getPrimaryFormat();
-                if (!is_alpha_mask && (image_format == GL_RGBA || image_format == GL_ALPHA))
-                {
-                    is_alpha_blend = true;
-                }
-            }
-
-            if (tex_entry)
-            {
-                if (tex_entry->getAlpha() <= 0.99f)
-                {
-                    is_alpha_blend = true;
-                }
-            }
-
-            if (mat)
-            {                
-                switch (LLMaterial::eDiffuseAlphaMode(mat->getDiffuseAlphaMode()))
-                {
-                    case LLMaterial::DIFFUSE_ALPHA_MODE_MASK:
-                    {
-                        is_alpha_mask  = true;
-                        is_alpha_blend = false;
-                    }
-                    break;
-
-                    case LLMaterial::DIFFUSE_ALPHA_MODE_BLEND:
-                    {
-                        is_alpha_blend = true;
-                        is_alpha_mask  = false;
-                    }
-                    break;
-
-                    case LLMaterial::DIFFUSE_ALPHA_MODE_EMISSIVE:
-                    case LLMaterial::DIFFUSE_ALPHA_MODE_DEFAULT:
-                    case LLMaterial::DIFFUSE_ALPHA_MODE_NONE:
-                    default:
-                        is_alpha_blend = false;
-                        is_alpha_mask  = false;
-                        break;
-                }
-            }
-
-            // if this is alpha mask content and we're doing opaques or a non-alpha-mask shadow pass...
-            if (is_alpha_mask && (LLDrawPoolAvatar::sSkipTransparent || LLDrawPoolAvatar::sShadowPass != SHADOW_PASS_ATTACHMENT_ALPHA_MASK))
-            {
-                return;
-            }
-
-            // if this is alpha blend content and we're doing opaques or a non-alpha-blend shadow pass...
-            if (is_alpha_blend && (LLDrawPoolAvatar::sSkipTransparent || LLDrawPoolAvatar::sShadowPass != SHADOW_PASS_ATTACHMENT_ALPHA_BLEND))
-            {
-                return;
-            }
-
-            // if this is opaque content and we're skipping opaques...
-            if (!is_alpha_mask && !is_alpha_blend && LLDrawPoolAvatar::sSkipOpaque)
-            {
-                return;
-            }
-        }
-
-		if (buff)
-		{        
-			if (sShaderLevel > 0)
-			{
-                // upload matrix palette to shader
-				LLMatrix4a mat[LL_MAX_JOINTS_PER_MESH_OBJECT];
-				U32 count = LLSkinningUtil::getMeshJointCount(skin);
-                LLSkinningUtil::initSkinningMatrixPalette((LLMatrix4*)mat, count, skin, avatar);
-
-				stop_glerror();
-
-				F32 mp[LL_MAX_JOINTS_PER_MESH_OBJECT*12];
-
-				for (U32 i = 0; i < count; ++i)
-				{
-					F32* m = (F32*) mat[i].mMatrix[0].getF32ptr();
-
-					U32 idx = i*12;
-
-					mp[idx+0] = m[0];
-					mp[idx+1] = m[1];
-					mp[idx+2] = m[2];
-					mp[idx+3] = m[12];
-
-					mp[idx+4] = m[4];
-					mp[idx+5] = m[5];
-					mp[idx+6] = m[6];
-					mp[idx+7] = m[13];
-
-					mp[idx+8] = m[8];
-					mp[idx+9] = m[9];
-					mp[idx+10] = m[10];
-					mp[idx+11] = m[14];
-				}
-
-				LLDrawPoolAvatar::sVertexProgram->uniformMatrix3x4fv(LLViewerShaderMgr::AVATAR_MATRIX, 
-					count,
-					FALSE,
-					(GLfloat*) mp);
-
-				stop_glerror();
-			}
-			else
-			{
-				data_mask &= ~LLVertexBuffer::MAP_WEIGHT4;
-			}
-
-			/*if (glow)
-			{
-				gGL.diffuseColor4f(0,0,0,face->getTextureEntry()->getGlow());
-			}*/
-
-			if (mat)
+			if (LLPipeline::sRenderDeferred && !LLPipeline::sReflectionRender && avatarp->mImpostor.isComplete()) 
 			{
-				//order is important here LLRender::DIFFUSE_MAP should be last, becouse it change 
-				//(gGL).mCurrTextureUnitIndex
-                LLViewerTexture* specular = NULL;
-                if (LLPipeline::sImpostorRender)
-                {
-                    specular = LLViewerTextureManager::findFetchedTexture(gBlackSquareID, TEX_LIST_STANDARD);
-                    llassert(NULL != specular);
-                }
-                else
-                {
-                    specular = face->getTexture(LLRender::SPECULAR_MAP);
-                }
-                if (specular)
-                {
-                    gGL.getTexUnit(specular_channel)->bind(specular);
-                }
-                
-				gGL.getTexUnit(normal_channel)->bind(face->getTexture(LLRender::NORMAL_MAP));
-				gGL.getTexUnit(sDiffuseChannel)->bind(face->getTexture(LLRender::DIFFUSE_MAP), false, true);
-
-
-				LLColor4 col = mat->getSpecularLightColor();
-				F32 spec = mat->getSpecularLightExponent()/255.f;
-
-				F32 env = mat->getEnvironmentIntensity()/255.f;
-
-				if (mat->getSpecularID().isNull())
-				{
-					env = tex_entry->getShiny()*0.25f;
-					col.set(env,env,env,0);
-					spec = env;
-				}
-		
-				BOOL fullbright = tex_entry->getFullbright();
-
-				sVertexProgram->uniform1f(LLShaderMgr::EMISSIVE_BRIGHTNESS, fullbright ? 1.f : 0.f);
-				sVertexProgram->uniform4f(LLShaderMgr::SPECULAR_COLOR, col.mV[0], col.mV[1], col.mV[2], spec);
-				sVertexProgram->uniform1f(LLShaderMgr::ENVIRONMENT_INTENSITY, env);
-
-				if (mat->getDiffuseAlphaMode() == LLMaterial::DIFFUSE_ALPHA_MODE_MASK)
-				{
-                    F32 cutoff = mat->getAlphaMaskCutoff()/255.f;
-					sVertexProgram->setMinimumAlpha(cutoff);
-				}
-				else
-				{
-					sVertexProgram->setMinimumAlpha(0.f);
-				}
-
-				for (U32 i = 0; i < LLRender::NUM_TEXTURE_CHANNELS; ++i)
+				if (normal_channel > -1)
 				{
-					LLViewerTexture* tex = face->getTexture(i);
-					if (tex)
-					{
-						tex->addTextureStats(avatar->getPixelArea());
-					}
+					avatarp->mImpostor.bindTexture(2, normal_channel);
 				}
-			}
-			else
-			{
-				gGL.getTexUnit(sDiffuseChannel)->bind(face->getTexture());
-				sVertexProgram->setMinimumAlpha(0.f);
-				if (normal_channel > -1)
+				if (specular_channel > -1)
 				{
-					LLDrawPoolBump::bindBumpMap(face, normal_channel);
+					avatarp->mImpostor.bindTexture(1, specular_channel);
 				}
 			}
-
-			if (face->mTextureMatrix && vobj->mTexAnimMode)
-			{
-                U32 tex_index = gGL.getCurrentTexUnitIndex();
-
-                if (tex_index <= 1)
-                {
-                    gGL.matrixMode(LLRender::eMatrixMode(LLRender::MM_TEXTURE0 + tex_index));
-                    gGL.pushMatrix();
-				    gGL.loadMatrix((F32*) face->mTextureMatrix->mMatrix);
-                }
-
-				buff->setBuffer(data_mask);
-				buff->drawRange(LLRender::TRIANGLES, start, end, count, offset);
-
-                if (tex_index <= 1)
-                {
-                    gGL.matrixMode(LLRender::eMatrixMode(LLRender::MM_TEXTURE0 + tex_index));
-				    gGL.popMatrix();
-                    gGL.matrixMode(LLRender::MM_MODELVIEW);
-                }
-			}
-			else
-			{
-				buff->setBuffer(data_mask);
-				buff->drawRange(LLRender::TRIANGLES, start, end, count, offset);		
-			}
-
-			gPipeline.addTrianglesDrawn(count, LLRender::TRIANGLES);
+			avatarp->renderImpostor(avatarp->getMutedAVColor(), sDiffuseChannel);
 		}
+		return;
 	}
-}
-
-void LLDrawPoolAvatar::renderDeferredRiggedSimple(LLVOAvatar* avatar)
-{
-	renderRigged(avatar, RIGGED_DEFERRED_SIMPLE);
-}
-
-void LLDrawPoolAvatar::renderDeferredRiggedBump(LLVOAvatar* avatar)
-{
-	renderRigged(avatar, RIGGED_DEFERRED_BUMP);
-}
 
-void LLDrawPoolAvatar::renderDeferredRiggedMaterial(LLVOAvatar* avatar, S32 pass)
-{
-	renderRigged(avatar, pass);
-}
-
-static LLTrace::BlockTimerStatHandle FTM_RIGGED_VBO("Rigged VBO");
-
-void LLDrawPoolAvatar::updateRiggedVertexBuffers(LLVOAvatar* avatar)
-{
-	LL_RECORD_BLOCK_TIME(FTM_RIGGED_VBO);
-
-	//update rigged vertex buffers
-	for (U32 type = 0; type < NUM_RIGGED_PASSES; ++type)
+	if (pass == 1)
 	{
-		for (U32 i = 0; i < mRiggedFace[type].size(); ++i)
-		{
-			LLFace* face = mRiggedFace[type][i];
-			LLDrawable* drawable = face->getDrawable();
-			if (!drawable)
-			{
-				continue;
-			}
-
-			LLVOVolume* vobj = drawable->getVOVolume();
-
-			if (!vobj || vobj->isNoLOD())
-			{
-				continue;
-			}
-
-			LLVolume* volume = vobj->getVolume();
-			S32 te = face->getTEOffset();
-
-			if (!volume || volume->getNumVolumeFaces() <= te)
-			{
-				continue;
-			}
-
-			const LLMeshSkinInfo* skin = vobj->getSkinInfo();
-			if (!skin)
-			{
-				continue;
-			}
-
-			stop_glerror();
-
-			LLVolumeFace& vol_face = volume->getVolumeFace(te);
-			updateRiggedFaceVertexBuffer(avatar, face, skin, volume, vol_face);
-		}
+		// render rigid meshes (eyeballs) first
+		avatarp->renderRigid();
+		return;
 	}
-}
-
-void LLDrawPoolAvatar::renderRiggedSimple(LLVOAvatar* avatar)
-{
-	renderRigged(avatar, RIGGED_SIMPLE);
-}
-
-void LLDrawPoolAvatar::renderRiggedFullbright(LLVOAvatar* avatar)
-{
-	renderRigged(avatar, RIGGED_FULLBRIGHT);
-}
-
-	
-void LLDrawPoolAvatar::renderRiggedShinySimple(LLVOAvatar* avatar)
-{
-	renderRigged(avatar, RIGGED_SHINY);
-}
-
-void LLDrawPoolAvatar::renderRiggedFullbrightShiny(LLVOAvatar* avatar)
-{
-	renderRigged(avatar, RIGGED_FULLBRIGHT_SHINY);
-}
 
-void LLDrawPoolAvatar::renderRiggedAlpha(LLVOAvatar* avatar)
-{
-	if (!mRiggedFace[RIGGED_ALPHA].empty())
+	if ((sShaderLevel >= SHADER_LEVEL_CLOTH))
 	{
-		LLGLEnable blend(GL_BLEND);
-
-		gGL.setColorMask(true, true);
-		gGL.blendFunc(LLRender::BF_SOURCE_ALPHA,
-						LLRender::BF_ONE_MINUS_SOURCE_ALPHA,
-						LLRender::BF_ZERO,
-						LLRender::BF_ONE_MINUS_SOURCE_ALPHA);
-
-		renderRigged(avatar, RIGGED_ALPHA);
-		gGL.setColorMask(true, false);
-	}
-}
+		LLMatrix4 rot_mat;
+		LLViewerCamera::getInstance()->getMatrixToLocal(rot_mat);
+		LLMatrix4 cfr(OGL_TO_CFR_ROTATION);
+		rot_mat *= cfr;
+		
+		LLVector4 wind;
+		wind.setVec(avatarp->mWindVec);
+		wind.mV[VW] = 0;
+		wind = wind * rot_mat;
+		wind.mV[VW] = avatarp->mWindVec.mV[VW];
 
-void LLDrawPoolAvatar::renderRiggedFullbrightAlpha(LLVOAvatar* avatar)
-{
-	if (!mRiggedFace[RIGGED_FULLBRIGHT_ALPHA].empty())
-	{
-		LLGLEnable blend(GL_BLEND);
+		sVertexProgram->uniform4fv(LLViewerShaderMgr::AVATAR_WIND, 1, wind.mV);
+		F32 phase = -1.f * (avatarp->mRipplePhase);
 
-		gGL.setColorMask(true, true);
-		gGL.blendFunc(LLRender::BF_SOURCE_ALPHA,
-						LLRender::BF_ONE_MINUS_SOURCE_ALPHA,
-						LLRender::BF_ZERO,
-						LLRender::BF_ONE_MINUS_SOURCE_ALPHA);
+		F32 freq = 7.f + (noise1(avatarp->mRipplePhase) * 2.f);
+		LLVector4 sin_params(freq, freq, freq, phase);
+		sVertexProgram->uniform4fv(LLViewerShaderMgr::AVATAR_SINWAVE, 1, sin_params.mV);
 
-		renderRigged(avatar, RIGGED_FULLBRIGHT_ALPHA);
-		gGL.setColorMask(true, false);
+		LLVector4 gravity(0.f, 0.f, -CLOTHING_GRAVITY_EFFECT, 0.f);
+		gravity = gravity * rot_mat;
+		sVertexProgram->uniform4fv(LLViewerShaderMgr::AVATAR_GRAVITY, 1, gravity.mV);
 	}
-}
 
-void LLDrawPoolAvatar::renderRiggedGlow(LLVOAvatar* avatar)
-{
-	if (!mRiggedFace[RIGGED_GLOW].empty())
+	if( !single_avatar || (avatarp == single_avatar) )
 	{
-		LLGLEnable blend(GL_BLEND);
-		LLGLDisable test(GL_ALPHA_TEST);
-		gGL.flush();
-
-		LLGLEnable polyOffset(GL_POLYGON_OFFSET_FILL);
-		glPolygonOffset(-1.0f, -1.0f);
-		gGL.setSceneBlendType(LLRender::BT_ADD);
-
-		LLGLDepthTest depth(GL_TRUE, GL_FALSE);
-		gGL.setColorMask(false, true);
-
-		renderRigged(avatar, RIGGED_GLOW, true);
-
-		gGL.setColorMask(true, false);
-		gGL.setSceneBlendType(LLRender::BT_ALPHA);
+		avatarp->renderSkinned();
 	}
 }
 
-
+static LLTrace::BlockTimerStatHandle FTM_RIGGED_VBO("Rigged VBO");
 
 //-----------------------------------------------------------------------------
 // getDebugTexture()
 //-----------------------------------------------------------------------------
 LLViewerTexture *LLDrawPoolAvatar::getDebugTexture()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR
+
 	if (mReferences.empty())
 	{
 		return NULL;
@@ -2494,68 +931,12 @@ LLColor3 LLDrawPoolAvatar::getDebugColor() const
 	return LLColor3(0.f, 1.f, 0.f);
 }
 
-void LLDrawPoolAvatar::addRiggedFace(LLFace* facep, U32 type)
-{
-    llassert (facep->isState(LLFace::RIGGED));
-    llassert(getType() == LLDrawPool::POOL_AVATAR || getType() == LLDrawPool::POOL_CONTROL_AV);
-    if (facep->getPool() && facep->getPool() != this)
-    {
-        LL_ERRS() << "adding rigged face that's already in another pool" << LL_ENDL;
-    }
-	if (type >= NUM_RIGGED_PASSES)
-	{
-		LL_ERRS() << "Invalid rigged face type." << LL_ENDL;
-	}
-	if (facep->getRiggedIndex(type) != -1)
-	{
-		LL_ERRS() << "Tried to add a rigged face that's referenced elsewhere." << LL_ENDL;
-	}	
-	
-	facep->setRiggedIndex(type, mRiggedFace[type].size());
-	facep->setPool(this);
-	mRiggedFace[type].push_back(facep);
-}
-
-void LLDrawPoolAvatar::removeRiggedFace(LLFace* facep)
-{
-    llassert (facep->isState(LLFace::RIGGED));
-    llassert(getType() == LLDrawPool::POOL_AVATAR || getType() == LLDrawPool::POOL_CONTROL_AV);
-    if (facep->getPool() != this)
-    {
-        LL_ERRS() << "Tried to remove a rigged face from the wrong pool" << LL_ENDL;
-    }
-	facep->setPool(NULL);
-
-	for (U32 i = 0; i < NUM_RIGGED_PASSES; ++i)
-	{
-		S32 index = facep->getRiggedIndex(i);
-		
-		if (index > -1)
-		{
-			if (mRiggedFace[i].size() > index && mRiggedFace[i][index] == facep)
-			{
-				facep->setRiggedIndex(i,-1);
-				mRiggedFace[i].erase(mRiggedFace[i].begin()+index);
-				for (U32 j = index; j < mRiggedFace[i].size(); ++j)
-				{ //bump indexes down for faces referenced after erased face
-					mRiggedFace[i][j]->setRiggedIndex(i, j);
-				}
-			}
-			else
-			{
-				LL_ERRS() << "Face reference data corrupt for rigged type " << i
-					<< ((mRiggedFace[i].size() <= index) ? "; wrong index (out of bounds)" : (mRiggedFace[i][index] != facep) ? "; wrong face pointer" : "")
-					<< LL_ENDL;
-			}
-		}
-	}
-}
 
 LLVertexBufferAvatar::LLVertexBufferAvatar()
 : LLVertexBuffer(sDataMask, 
 	GL_STREAM_DRAW_ARB) //avatars are always stream draw due to morph targets
 {
-
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR
 }
 
 
diff --git a/indra/newview/lldrawpoolavatar.h b/indra/newview/lldrawpoolavatar.h
index 92a85389588cb3a06c02e0bfc6f9ce14d68dba37..21add39b21be9ca48a7ef3fc86cde9632e1442ff 100644
--- a/indra/newview/lldrawpoolavatar.h
+++ b/indra/newview/lldrawpoolavatar.h
@@ -28,14 +28,18 @@
 #define LL_LLDRAWPOOLAVATAR_H
 
 #include "lldrawpool.h"
+#include "llmodel.h"
+
+#include <unordered_map>
 
 class LLVOAvatar;
+class LLVOVolume;
 class LLGLSLShader;
 class LLFace;
-class LLMeshSkinInfo;
 class LLVolume;
 class LLVolumeFace;
 
+extern U32 gFrameCount;
 
 class LLDrawPoolAvatar : public LLFacePool
 {
@@ -58,119 +62,11 @@ class LLDrawPoolAvatar : public LLFacePool
     ~LLDrawPoolAvatar();
     /*virtual*/ BOOL isDead();
 
-    typedef enum
-	{
-		RIGGED_MATERIAL=0,
-		RIGGED_MATERIAL_ALPHA,
-		RIGGED_MATERIAL_ALPHA_MASK,
-		RIGGED_MATERIAL_ALPHA_EMISSIVE,
-		RIGGED_SPECMAP,
-		RIGGED_SPECMAP_BLEND,
-		RIGGED_SPECMAP_MASK,
-		RIGGED_SPECMAP_EMISSIVE,
-		RIGGED_NORMMAP,
-		RIGGED_NORMMAP_BLEND,
-		RIGGED_NORMMAP_MASK,
-		RIGGED_NORMMAP_EMISSIVE,
-		RIGGED_NORMSPEC,
-		RIGGED_NORMSPEC_BLEND,
-		RIGGED_NORMSPEC_MASK,
-		RIGGED_NORMSPEC_EMISSIVE,
-		RIGGED_SIMPLE,
-		RIGGED_FULLBRIGHT,
-		RIGGED_SHINY,
-		RIGGED_FULLBRIGHT_SHINY,
-		RIGGED_GLOW,
-		RIGGED_ALPHA,
-		RIGGED_FULLBRIGHT_ALPHA,
-		RIGGED_DEFERRED_BUMP,
-		RIGGED_DEFERRED_SIMPLE,
-		NUM_RIGGED_PASSES,
-		RIGGED_UNKNOWN,
-	} eRiggedPass;
-
-	typedef enum
-	{
-		RIGGED_MATERIAL_MASK =
-						LLVertexBuffer::MAP_VERTEX | 
-						LLVertexBuffer::MAP_NORMAL | 
-						LLVertexBuffer::MAP_TEXCOORD0 |
-						LLVertexBuffer::MAP_COLOR |
-						LLVertexBuffer::MAP_WEIGHT4,
-		RIGGED_MATERIAL_ALPHA_VMASK = RIGGED_MATERIAL_MASK,
-		RIGGED_MATERIAL_ALPHA_MASK_MASK = RIGGED_MATERIAL_MASK,
-		RIGGED_MATERIAL_ALPHA_EMISSIVE_MASK = RIGGED_MATERIAL_MASK,
-		RIGGED_SPECMAP_VMASK =
-						LLVertexBuffer::MAP_VERTEX | 
-						LLVertexBuffer::MAP_NORMAL | 
-						LLVertexBuffer::MAP_TEXCOORD0 |
-						LLVertexBuffer::MAP_TEXCOORD2 |
-						LLVertexBuffer::MAP_COLOR |
-						LLVertexBuffer::MAP_WEIGHT4,
-		RIGGED_SPECMAP_BLEND_MASK = RIGGED_SPECMAP_VMASK,
-		RIGGED_SPECMAP_MASK_MASK = RIGGED_SPECMAP_VMASK,
-		RIGGED_SPECMAP_EMISSIVE_MASK = RIGGED_SPECMAP_VMASK,
-		RIGGED_NORMMAP_VMASK =
-						LLVertexBuffer::MAP_VERTEX | 
-						LLVertexBuffer::MAP_NORMAL | 
-						LLVertexBuffer::MAP_TANGENT | 
-						LLVertexBuffer::MAP_TEXCOORD0 |
-						LLVertexBuffer::MAP_TEXCOORD1 |
-						LLVertexBuffer::MAP_COLOR |
-						LLVertexBuffer::MAP_WEIGHT4,
-		RIGGED_NORMMAP_BLEND_MASK = RIGGED_NORMMAP_VMASK,
-		RIGGED_NORMMAP_MASK_MASK = RIGGED_NORMMAP_VMASK,
-		RIGGED_NORMMAP_EMISSIVE_MASK = RIGGED_NORMMAP_VMASK,
-		RIGGED_NORMSPEC_VMASK =
-						LLVertexBuffer::MAP_VERTEX | 
-						LLVertexBuffer::MAP_NORMAL | 
-						LLVertexBuffer::MAP_TANGENT | 
-						LLVertexBuffer::MAP_TEXCOORD0 |
-						LLVertexBuffer::MAP_TEXCOORD1 |
-						LLVertexBuffer::MAP_TEXCOORD2 |
-						LLVertexBuffer::MAP_COLOR |
-						LLVertexBuffer::MAP_WEIGHT4,
-		RIGGED_NORMSPEC_BLEND_MASK = RIGGED_NORMSPEC_VMASK,
-		RIGGED_NORMSPEC_MASK_MASK = RIGGED_NORMSPEC_VMASK,
-		RIGGED_NORMSPEC_EMISSIVE_MASK = RIGGED_NORMSPEC_VMASK,
-		RIGGED_SIMPLE_MASK = LLVertexBuffer::MAP_VERTEX | 
-							 LLVertexBuffer::MAP_NORMAL | 
-							 LLVertexBuffer::MAP_TEXCOORD0 |
-							 LLVertexBuffer::MAP_COLOR |
-							 LLVertexBuffer::MAP_WEIGHT4,
-		RIGGED_FULLBRIGHT_MASK = LLVertexBuffer::MAP_VERTEX | 
-							 LLVertexBuffer::MAP_TEXCOORD0 |
-							 LLVertexBuffer::MAP_COLOR |
-							 LLVertexBuffer::MAP_WEIGHT4,
-		RIGGED_SHINY_MASK = RIGGED_SIMPLE_MASK,
-		RIGGED_FULLBRIGHT_SHINY_MASK = RIGGED_SIMPLE_MASK,							 
-		RIGGED_GLOW_MASK = LLVertexBuffer::MAP_VERTEX | 
-							 LLVertexBuffer::MAP_TEXCOORD0 |
-							 LLVertexBuffer::MAP_EMISSIVE |
-							 LLVertexBuffer::MAP_WEIGHT4,
-		RIGGED_ALPHA_MASK = RIGGED_SIMPLE_MASK,
-		RIGGED_FULLBRIGHT_ALPHA_MASK = RIGGED_FULLBRIGHT_MASK,
-		RIGGED_DEFERRED_BUMP_MASK = LLVertexBuffer::MAP_VERTEX | 
-							 LLVertexBuffer::MAP_NORMAL | 
-							 LLVertexBuffer::MAP_TEXCOORD0 |
-							 LLVertexBuffer::MAP_TANGENT |
-							 LLVertexBuffer::MAP_COLOR |
-							 LLVertexBuffer::MAP_WEIGHT4,
-		RIGGED_DEFERRED_SIMPLE_MASK = LLVertexBuffer::MAP_VERTEX | 
-							 LLVertexBuffer::MAP_NORMAL | 
-							 LLVertexBuffer::MAP_TEXCOORD0 |
-							 LLVertexBuffer::MAP_COLOR |
-							 LLVertexBuffer::MAP_WEIGHT4,
-	} eRiggedDataMask;
-
 typedef enum
 	{
 		SHADOW_PASS_AVATAR_OPAQUE,
         SHADOW_PASS_AVATAR_ALPHA_BLEND,
         SHADOW_PASS_AVATAR_ALPHA_MASK,
-        SHADOW_PASS_ATTACHMENT_ALPHA_BLEND,
-        SHADOW_PASS_ATTACHMENT_ALPHA_MASK,
-        SHADOW_PASS_ATTACHMENT_OPAQUE,
         NUM_SHADOW_PASSES
 	} eShadowPass;
 
@@ -211,78 +107,19 @@ typedef enum
 	void endImpostor();
 	void endSkinned();
 
-	void beginDeferredImpostor();
-	void beginDeferredRigid();
-	void beginDeferredSkinned();
-	
-	void endDeferredImpostor();
-	void endDeferredRigid();
-	void endDeferredSkinned();
-	
-	void beginPostDeferredAlpha();
-	void endPostDeferredAlpha();
-
-	void beginRiggedSimple();
-	void beginRiggedFullbright();
-	void beginRiggedFullbrightShiny();
-	void beginRiggedShinySimple();
-	void beginRiggedAlpha();
-	void beginRiggedFullbrightAlpha();
-	void beginRiggedGlow();
-	void beginDeferredRiggedAlpha();
-	void beginDeferredRiggedMaterial(S32 pass);
-	void beginDeferredRiggedMaterialAlpha(S32 pass);
+    void beginDeferredRigid();
+    void beginDeferredImpostor();
+    void beginDeferredSkinned();
 
-	void endRiggedSimple();
-	void endRiggedFullbright();
-	void endRiggedFullbrightShiny();
-	void endRiggedShinySimple();
-	void endRiggedAlpha();
-	void endRiggedFullbrightAlpha();
-	void endRiggedGlow();
-	void endDeferredRiggedAlpha();
-	void endDeferredRiggedMaterial(S32 pass);
-	void endDeferredRiggedMaterialAlpha(S32 pass);
-
-	void beginDeferredRiggedSimple();
-	void beginDeferredRiggedBump();
-	
-	void endDeferredRiggedSimple();
-	void endDeferredRiggedBump();
-		
-	void getRiggedGeometry(LLFace* face, LLPointer<LLVertexBuffer>& buffer, U32 data_mask, const LLMeshSkinInfo* skin, LLVolume* volume, const LLVolumeFace& vol_face);
-	void updateRiggedFaceVertexBuffer(LLVOAvatar* avatar,
-									  LLFace* facep, 
-									  const LLMeshSkinInfo* skin, 
-									  LLVolume* volume,
-									  LLVolumeFace& vol_face);
-	void updateRiggedVertexBuffers(LLVOAvatar* avatar);
-
-	void renderRigged(LLVOAvatar* avatar, U32 type, bool glow = false);
-	void renderRiggedSimple(LLVOAvatar* avatar);
-	void renderRiggedAlpha(LLVOAvatar* avatar);
-	void renderRiggedFullbrightAlpha(LLVOAvatar* avatar);
-	void renderRiggedFullbright(LLVOAvatar* avatar);
-	void renderRiggedShinySimple(LLVOAvatar* avatar);
-	void renderRiggedFullbrightShiny(LLVOAvatar* avatar);
-	void renderRiggedGlow(LLVOAvatar* avatar);
-	void renderDeferredRiggedSimple(LLVOAvatar* avatar);
-	void renderDeferredRiggedBump(LLVOAvatar* avatar);
-	void renderDeferredRiggedMaterial(LLVOAvatar* avatar, S32 pass);
-	
-	
-
-	void addRiggedFace(LLFace* facep, U32 type);
-	void removeRiggedFace(LLFace* facep); 
-
-	std::vector<LLFace*> mRiggedFace[NUM_RIGGED_PASSES];
+    void endDeferredRigid();
+    void endDeferredImpostor();
+    void endDeferredSkinned();
 
 	/*virtual*/ LLViewerTexture *getDebugTexture();
 	/*virtual*/ LLColor3 getDebugColor() const; // For AGP debug display
 
 	void renderAvatars(LLVOAvatar *single_avatar, S32 pass = -1); // renders only one avatar if single_avatar is not null.
 
-
 	static BOOL sSkipOpaque;
 	static BOOL sSkipTransparent;
     static S32  sShadowPass;
diff --git a/indra/newview/lldrawpoolbump.cpp b/indra/newview/lldrawpoolbump.cpp
index 14069fa6c2bbef8b940093d12efada767f464049..ed991a2bbfe5e09e500dad505d2befb78608a078 100644
--- a/indra/newview/lldrawpoolbump.cpp
+++ b/indra/newview/lldrawpoolbump.cpp
@@ -47,12 +47,16 @@
 #include "pipeline.h"
 #include "llspatialpartition.h"
 #include "llviewershadermgr.h"
+#include "llmodel.h"
 
 //#include "llimagebmp.h"
 //#include "../tools/imdebug/imdebug.h"
 
 // static
 LLStandardBumpmap gStandardBumpmapList[TEM_BUMPMAP_COUNT]; 
+LL::WorkQueue::weak_t LLBumpImageList::sMainQueue;
+LL::WorkQueue::weak_t LLBumpImageList::sTexUpdateQueue;
+LLRenderTarget LLBumpImageList::sRenderTarget;
 
 // static
 U32 LLStandardBumpmap::sStandardBumpmapCount = 0;
@@ -73,6 +77,10 @@ static S32 cube_channel = -1;
 static S32 diffuse_channel = -1;
 static S32 bump_channel = -1;
 
+// Enabled after changing LLViewerTexture::mNeedsCreateTexture to an
+// LLAtomicBool; this should work just fine, now. HB
+#define LL_BUMPLIST_MULTITHREADED 1
+
 // static 
 void LLStandardBumpmap::init()
 {
@@ -199,32 +207,7 @@ void LLDrawPoolBump::prerender()
 // static
 S32 LLDrawPoolBump::numBumpPasses()
 {
-	if (gSavedSettings.getBOOL("RenderObjectBump"))
-	{
-		if (mShaderLevel > 1)
-		{
-			if (LLPipeline::sImpostorRender)
-			{
-				return 2;
-			}
-			else
-			{
-				return 3;
-			}
-		}
-		else if (LLPipeline::sImpostorRender)
-		{
-			return 1;
-		}
-		else
-		{
-			return 2;
-		}
-	}
-    else
-	{
-		return 0;
-	}
+    return 1;
 }
 
 S32 LLDrawPoolBump::getNumPasses()
@@ -232,140 +215,79 @@ S32 LLDrawPoolBump::getNumPasses()
 	return numBumpPasses();
 }
 
-void LLDrawPoolBump::beginRenderPass(S32 pass)
-{
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_BUMP);
-	switch( pass )
-	{
-		case 0:
-			beginShiny();
-			break;
-		case 1:
-			if (mShaderLevel > 1)
-			{
-				beginFullbrightShiny();
-			}
-			else 
-			{
-				beginBump();
-			}
-			break;
-		case 2:
-			beginBump();
-			break;
-		default:
-			llassert(0);
-			break;
-	}
-}
-
 void LLDrawPoolBump::render(S32 pass)
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_BUMP);
-	
-	if (!gPipeline.hasRenderType(LLDrawPool::POOL_SIMPLE))
-	{
-		return;
-	}
-	
-	switch( pass )
-	{
-		case 0:
-			renderShiny();
-			break;
-		case 1:
-			if (mShaderLevel > 1)
-			{
-				renderFullbrightShiny();
-			}
-			else 
-			{
-				renderBump(); 
-			}
-			break;
-		case 2:
-			renderBump();
-			break;
-		default:
-			llassert(0);
-			break;
-	}
-}
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_BUMP);
 
-void LLDrawPoolBump::endRenderPass(S32 pass)
-{
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_BUMP);
-	switch( pass )
-	{
-		case 0:
-			endShiny();
-			break;
-		case 1:
-			if (mShaderLevel > 1)
-			{
-				endFullbrightShiny();
-			}
-			else 
-			{
-				endBump();
-			}
-			break;
-		case 2:
-			endBump();
-			break;
-		default:
-			llassert(0);
-			break;
-	}
+    if (!gPipeline.hasRenderType(LLDrawPool::POOL_SIMPLE))
+    {
+        return;
+    }
+
+    for (int i = 0; i < 2; ++i)
+    {
+        mRigged = i == 1;
+
+        // first pass -- shiny
+        beginShiny();
+        renderShiny();
+        endShiny();
 
-	//to cleanup texture channels
-	LLRenderPass::endRenderPass(pass);
+        //second pass -- fullbright shiny
+        if (mShaderLevel > 1)
+        {
+            beginFullbrightShiny();
+            renderFullbrightShiny();
+            endFullbrightShiny();
+        }
+
+        //third pass -- bump
+        beginBump();
+        renderBump(LLRenderPass::PASS_BUMP);
+        endBump();
+    }
 }
 
+
 //static
-void LLDrawPoolBump::beginShiny(bool invisible)
+void LLDrawPoolBump::beginShiny()
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_SHINY);
-	if ((!invisible && !gPipeline.hasRenderBatches(LLRenderPass::PASS_SHINY))|| 
-		(invisible && !gPipeline.hasRenderBatches(LLRenderPass::PASS_INVISI_SHINY)))
-	{
-		return;
-	}
-
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_SHINY);
+	
 	mShiny = TRUE;
 	sVertexMask = VERTEX_MASK_SHINY;
 	// Second pass: environment map
-	if (!invisible && mShaderLevel > 1)
+	if (mShaderLevel > 1)
 	{
 		sVertexMask = VERTEX_MASK_SHINY | LLVertexBuffer::MAP_TEXCOORD0;
 	}
 	
-	if (getShaderLevel() > 0)
+	if (LLPipeline::sUnderWaterRender)
 	{
-		if (LLPipeline::sUnderWaterRender)
-		{
-			shader = &gObjectShinyWaterProgram;
-		}
-		else
-		{
-			shader = &gObjectShinyProgram;
-		}
-		shader->bind();
-        if (LLPipeline::sRenderingHUDs)
-        {
-            shader->uniform1i(LLShaderMgr::NO_ATMO, 1);
-        }
-        else
-        {
-            shader->uniform1i(LLShaderMgr::NO_ATMO, 0);
-        }
+		shader = &gObjectShinyWaterProgram;
 	}
 	else
 	{
-		shader = NULL;
+		shader = &gObjectShinyProgram;
 	}
 
-	bindCubeMap(shader, mShaderLevel, diffuse_channel, cube_channel, invisible);
+    if (mRigged)
+    {
+        llassert(shader->mRiggedVariant);
+        shader = shader->mRiggedVariant;
+    }
+
+	shader->bind();
+    if (LLPipeline::sRenderingHUDs)
+    {
+        shader->uniform1i(LLShaderMgr::NO_ATMO, 1);
+    }
+    else
+    {
+        shader->uniform1i(LLShaderMgr::NO_ATMO, 0);
+    }
+
+	bindCubeMap(shader, mShaderLevel, diffuse_channel, cube_channel);
 
 	if (mShaderLevel > 1)
 	{ //indexed texture rendering, channel 0 is always diffuse
@@ -374,12 +296,12 @@ void LLDrawPoolBump::beginShiny(bool invisible)
 }
 
 //static
-void LLDrawPoolBump::bindCubeMap(LLGLSLShader* shader, S32 shader_level, S32& diffuse_channel, S32& cube_channel, bool invisible)
+void LLDrawPoolBump::bindCubeMap(LLGLSLShader* shader, S32 shader_level, S32& diffuse_channel, S32& cube_channel)
 {
 	LLCubeMap* cube_map = gSky.mVOSkyp ? gSky.mVOSkyp->getCubeMap() : NULL;
 	if( cube_map )
 	{
-		if (!invisible && shader )
+		if (shader )
 		{
 			LLMatrix4 mat;
 			mat.initRows(LLVector4(gGLModelView+0),
@@ -391,19 +313,18 @@ void LLDrawPoolBump::bindCubeMap(LLGLSLShader* shader, S32 shader_level, S32& di
 			shader->uniform4fv(LLViewerShaderMgr::SHINY_ORIGIN, 1, vec4.mV);			
 			if (shader_level > 1)
 			{
-				cube_map->setMatrix(1);
+                cube_map->setMatrix(1);
 				// Make sure that texture coord generation happens for tex unit 1, as that's the one we use for 
 				// the cube map in the one pass shiny shaders
 				cube_channel = shader->enableTexture(LLViewerShaderMgr::ENVIRONMENT_MAP, LLTexUnit::TT_CUBE_MAP);
 				cube_map->enableTexture(cube_channel);
-				cube_map->enableTextureCoords(1);
 				diffuse_channel = shader->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
 			}
 			else
 			{
+                cube_map->setMatrix(0);
 				cube_channel = shader->enableTexture(LLViewerShaderMgr::ENVIRONMENT_MAP, LLTexUnit::TT_CUBE_MAP);
 				diffuse_channel = -1;
-				cube_map->setMatrix(0);
 				cube_map->enable(cube_channel);
 			}			
 			gGL.getTexUnit(cube_channel)->bind(cube_map);
@@ -415,49 +336,51 @@ void LLDrawPoolBump::bindCubeMap(LLGLSLShader* shader, S32 shader_level, S32& di
 			diffuse_channel = -1;
 			gGL.getTexUnit(0)->disable();
 			cube_map->enable(0);
-			cube_map->setMatrix(0);
+            cube_map->setMatrix(0);
 			gGL.getTexUnit(0)->bind(cube_map);
-
-			gGL.getTexUnit(0)->setTextureColorBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_TEX_COLOR);
-			gGL.getTexUnit(0)->setTextureAlphaBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_VERT_ALPHA);
 		}
 	}
 }
 
-void LLDrawPoolBump::renderShiny(bool invisible)
+void LLDrawPoolBump::renderShiny()
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_SHINY);
-	if ((!invisible && !gPipeline.hasRenderBatches(LLRenderPass::PASS_SHINY))|| 
-		(invisible && !gPipeline.hasRenderBatches(LLRenderPass::PASS_INVISI_SHINY)))
-	{
-		return;
-	}
-
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_SHINY);
+	
 	if( gSky.mVOSkyp->getCubeMap() )
 	{
 		LLGLEnable blend_enable(GL_BLEND);
-		if (!invisible && mShaderLevel > 1)
+		if (mShaderLevel > 1)
 		{
-			LLRenderPass::pushBatches(LLRenderPass::PASS_SHINY, sVertexMask | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
+            if (mRigged)
+            {
+                LLRenderPass::pushRiggedBatches(LLRenderPass::PASS_SHINY_RIGGED, sVertexMask | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
+            }
+            else
+            {
+                LLRenderPass::pushBatches(LLRenderPass::PASS_SHINY, sVertexMask | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
+            }
 		}
-		else if (!invisible)
+		else
 		{
-			renderGroups(LLRenderPass::PASS_SHINY, sVertexMask);
+            if (mRigged)
+            {
+                gPipeline.renderRiggedGroups(this, LLRenderPass::PASS_SHINY_RIGGED, sVertexMask, TRUE);
+            }
+            else
+            {
+                gPipeline.renderGroups(this, LLRenderPass::PASS_SHINY, sVertexMask, TRUE);
+            }
 		}
-		//else // invisible (deprecated)
-		//{
-			//renderGroups(LLRenderPass::PASS_INVISI_SHINY, sVertexMask);
-		//}
 	}
 }
 
 //static
-void LLDrawPoolBump::unbindCubeMap(LLGLSLShader* shader, S32 shader_level, S32& diffuse_channel, S32& cube_channel, bool invisible)
+void LLDrawPoolBump::unbindCubeMap(LLGLSLShader* shader, S32 shader_level, S32& diffuse_channel, S32& cube_channel)
 {
 	LLCubeMap* cube_map = gSky.mVOSkyp ? gSky.mVOSkyp->getCubeMap() : NULL;
 	if( cube_map )
 	{
-		if (!invisible && shader_level > 1)
+		if (shader_level > 1)
 		{
 			shader->disableTexture(LLViewerShaderMgr::ENVIRONMENT_MAP, LLTexUnit::TT_CUBE_MAP);
 					
@@ -472,29 +395,15 @@ void LLDrawPoolBump::unbindCubeMap(LLGLSLShader* shader, S32 shader_level, S32&
         // Moved below shader->disableTexture call to avoid false alarms from auto-re-enable of textures on stage 0
         // MAINT-755
 		cube_map->disable();
-		cube_map->restoreMatrix();
-	}
-
-	if (!LLGLSLShader::sNoFixedFunction)
-	{
-		gGL.getTexUnit(diffuse_channel)->disable();
-		gGL.getTexUnit(cube_channel)->disable();
-
-		gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
-		gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
+        cube_map->restoreMatrix();
 	}
 }
 
-void LLDrawPoolBump::endShiny(bool invisible)
+void LLDrawPoolBump::endShiny()
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_SHINY);
-	if ((!invisible && !gPipeline.hasRenderBatches(LLRenderPass::PASS_SHINY))|| 
-		(invisible && !gPipeline.hasRenderBatches(LLRenderPass::PASS_INVISI_SHINY)))
-	{
-		return;
-	}
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_SHINY);
 
-	unbindCubeMap(shader, mShaderLevel, diffuse_channel, cube_channel, invisible);
+	unbindCubeMap(shader, mShaderLevel, diffuse_channel, cube_channel);
 	if (shader)
 	{
 		shader->unbind();
@@ -507,12 +416,8 @@ void LLDrawPoolBump::endShiny(bool invisible)
 
 void LLDrawPoolBump::beginFullbrightShiny()
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_SHINY);
-	if (!gPipeline.hasRenderBatches(LLRenderPass::PASS_FULLBRIGHT_SHINY))
-	{
-		return;
-	}
-
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_SHINY);
+	
 	sVertexMask = VERTEX_MASK_SHINY | LLVertexBuffer::MAP_TEXCOORD0;
 
 	// Second pass: environment map
@@ -533,6 +438,12 @@ void LLDrawPoolBump::beginFullbrightShiny()
 		}
 	}
 
+    if (mRigged)
+    {
+        llassert(shader->mRiggedVariant);
+        shader = shader->mRiggedVariant;
+    }
+
 	LLCubeMap* cube_map = gSky.mVOSkyp ? gSky.mVOSkyp->getCubeMap() : NULL;
 	if( cube_map )
 	{
@@ -553,15 +464,14 @@ void LLDrawPoolBump::beginFullbrightShiny()
 
 		LLVector3 vec = LLVector3(gShinyOrigin) * mat;
 		LLVector4 vec4(vec, gShinyOrigin.mV[3]);
-		shader->uniform4fv(LLViewerShaderMgr::SHINY_ORIGIN, 1, vec4.mV);			
+		shader->uniform4fv(LLViewerShaderMgr::SHINY_ORIGIN, 1, vec4.mV);
 
-		cube_map->setMatrix(1);
+        cube_map->setMatrix(1);
 		// Make sure that texture coord generation happens for tex unit 1, as that's the one we use for 
 		// the cube map in the one pass shiny shaders
 		gGL.getTexUnit(1)->disable();
 		cube_channel = shader->enableTexture(LLViewerShaderMgr::ENVIRONMENT_MAP, LLTexUnit::TT_CUBE_MAP);
 		cube_map->enableTexture(cube_channel);
-		cube_map->enableTextureCoords(1);
 		diffuse_channel = shader->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
 
 		gGL.getTexUnit(cube_channel)->bind(cube_map);
@@ -578,11 +488,7 @@ void LLDrawPoolBump::beginFullbrightShiny()
 
 void LLDrawPoolBump::renderFullbrightShiny()
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_SHINY);
-	if (!gPipeline.hasRenderBatches(LLRenderPass::PASS_FULLBRIGHT_SHINY))
-	{
-		return;
-	}
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_SHINY);
 
 	if( gSky.mVOSkyp->getCubeMap() )
 	{
@@ -590,43 +496,41 @@ void LLDrawPoolBump::renderFullbrightShiny()
 
 		if (mShaderLevel > 1)
 		{
-			LLRenderPass::pushBatches(LLRenderPass::PASS_FULLBRIGHT_SHINY, sVertexMask | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
+            if (mRigged)
+            {
+                LLRenderPass::pushRiggedBatches(LLRenderPass::PASS_FULLBRIGHT_SHINY_RIGGED, sVertexMask | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
+            }
+            else
+            {
+                LLRenderPass::pushBatches(LLRenderPass::PASS_FULLBRIGHT_SHINY, sVertexMask | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
+            }
 		}
 		else
 		{
-			LLRenderPass::renderTexture(LLRenderPass::PASS_FULLBRIGHT_SHINY, sVertexMask);
+            if (mRigged)
+            {
+                LLRenderPass::pushRiggedBatches(LLRenderPass::PASS_FULLBRIGHT_SHINY_RIGGED, sVertexMask);
+            }
+            else
+            {
+                LLRenderPass::pushBatches(LLRenderPass::PASS_FULLBRIGHT_SHINY, sVertexMask);
+            }
 		}
 	}
 }
 
 void LLDrawPoolBump::endFullbrightShiny()
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_SHINY);
-	if (!gPipeline.hasRenderBatches(LLRenderPass::PASS_FULLBRIGHT_SHINY))
-	{
-		return;
-	}
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_SHINY);
 
 	LLCubeMap* cube_map = gSky.mVOSkyp ? gSky.mVOSkyp->getCubeMap() : NULL;
 	if( cube_map )
 	{
 		cube_map->disable();
-		cube_map->restoreMatrix();
-
-		/*if (diffuse_channel != 0)
-		{
-			shader->disableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
-		}
-		gGL.getTexUnit(0)->activate();
-		gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE);*/
-
+        cube_map->restoreMatrix();
 		shader->unbind();
-		//gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
 	}
 	
-	//gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
-	//gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
-
 	diffuse_channel = -1;
 	cube_channel = 0;
 	mShiny = FALSE;
@@ -677,6 +581,7 @@ BOOL LLDrawPoolBump::bindBumpMap(LLFace* face, S32 channel)
 //static
 BOOL LLDrawPoolBump::bindBumpMap(U8 bump_code, LLViewerTexture* texture, F32 vsize, S32 channel)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
 	//Note: texture atlas does not support bump texture now.
 	LLViewerFetchedTexture* tex = LLViewerTextureManager::staticCastToFetchedTexture(texture) ;
 	if(!tex)
@@ -693,7 +598,7 @@ BOOL LLDrawPoolBump::bindBumpMap(U8 bump_code, LLViewerTexture* texture, F32 vsi
 		break;
 	case BE_BRIGHTNESS: 
 	case BE_DARKNESS:
-		bump = gBumpImageList.getBrightnessDarknessImage( tex, bump_code );		
+		bump = gBumpImageList.getBrightnessDarknessImage( tex, bump_code );
 		break;
 
 	default:
@@ -709,12 +614,13 @@ BOOL LLDrawPoolBump::bindBumpMap(U8 bump_code, LLViewerTexture* texture, F32 vsi
 	{
 		if (channel == -2)
 		{
-			gGL.getTexUnit(1)->bind(bump);
-			gGL.getTexUnit(0)->bind(bump);
+			gGL.getTexUnit(1)->bindFast(bump);
+			gGL.getTexUnit(0)->bindFast(bump);
 		}
 		else
 		{
-			gGL.getTexUnit(channel)->bind(bump);
+            // NOTE: do not use bindFast here (see SL-16222)
+            gGL.getTexUnit(channel)->bind(bump);
 		}
 
 		return TRUE;
@@ -724,53 +630,22 @@ BOOL LLDrawPoolBump::bindBumpMap(U8 bump_code, LLViewerTexture* texture, F32 vsi
 }
 
 //static
-void LLDrawPoolBump::beginBump(U32 pass)
-{	
-	if (!gPipeline.hasRenderBatches(pass))
-	{
-		return;
-	}
-
+void LLDrawPoolBump::beginBump()
+{
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_BUMP);
 	sVertexMask = VERTEX_MASK_BUMP;
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_BUMP);
 	// Optional second pass: emboss bump map
 	stop_glerror();
 
-	if (LLGLSLShader::sNoFixedFunction)
-	{
-		gObjectBumpProgram.bind();
-	}
-	else
-	{
-		// TEXTURE UNIT 0
-		// Output.rgb = texture at texture coord 0
-		gGL.getTexUnit(0)->activate();
-
-		gGL.getTexUnit(0)->setTextureColorBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_TEX_ALPHA);
-		gGL.getTexUnit(0)->setTextureAlphaBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_TEX_ALPHA);
+    shader = &gObjectBumpProgram;
 
-		// TEXTURE UNIT 1
-		gGL.getTexUnit(1)->activate();
- 
-		gGL.getTexUnit(1)->enable(LLTexUnit::TT_TEXTURE);
+    if (mRigged)
+    {
+        llassert(shader->mRiggedVariant);
+        shader = shader->mRiggedVariant;
+    }
 
-		gGL.getTexUnit(1)->setTextureColorBlend(LLTexUnit::TBO_ADD_SIGNED, LLTexUnit::TBS_PREV_COLOR, LLTexUnit::TBS_ONE_MINUS_TEX_ALPHA);
-		gGL.getTexUnit(1)->setTextureAlphaBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_TEX_ALPHA);
-
-		// src	= tex0 + (1 - tex1) - 0.5
-		//		= (bump0/2 + 0.5) + (1 - (bump1/2 + 0.5)) - 0.5
-		//		= (1 + bump0 - bump1) / 2
-
-
-		// Blend: src * dst + dst * src
-		//		= 2 * src * dst
-		//		= 2 * ((1 + bump0 - bump1) / 2) * dst   [0 - 2 * dst]
-		//		= (1 + bump0 - bump1) * dst.rgb
-		//		= dst.rgb + dst.rgb * (bump0 - bump1)
-
-		gGL.getTexUnit(0)->activate();
-		gGL.getTexUnit(1)->unbind(LLTexUnit::TT_TEXTURE);
-	}
+    shader->bind();
 
 	gGL.setSceneBlendType(LLRender::BT_MULT_X2);
 	stop_glerror();
@@ -779,12 +654,7 @@ void LLDrawPoolBump::beginBump(U32 pass)
 //static
 void LLDrawPoolBump::renderBump(U32 pass)
 {
-	if (!gPipeline.hasRenderBatches(pass))
-	{
-		return;
-	}
-
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_BUMP);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_BUMP);
 	LLGLDisable fog(GL_FOG);
 	LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE, GL_LEQUAL);
 	LLGLEnable blend(GL_BLEND);
@@ -798,28 +668,9 @@ void LLDrawPoolBump::renderBump(U32 pass)
 //static
 void LLDrawPoolBump::endBump(U32 pass)
 {
-	if (!gPipeline.hasRenderBatches(pass))
-	{
-		return;
-	}
+    gObjectBumpProgram.unbind();
 
-	if (LLGLSLShader::sNoFixedFunction)
-	{
-		gObjectBumpProgram.unbind();
-	}
-	else
-	{
-		// Disable texture blending on unit 1
-		gGL.getTexUnit(1)->activate();
-		gGL.getTexUnit(1)->disable();
-		gGL.getTexUnit(1)->setTextureBlendType(LLTexUnit::TB_MULT);
-
-		// Disable texture blending on unit 0
-		gGL.getTexUnit(0)->activate();
-		gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
-	}
-	
-	gGL.setSceneBlendType(LLRender::BT_ALPHA);
+    gGL.setSceneBlendType(LLRender::BT_ALPHA);
 }
 
 S32 LLDrawPoolBump::getNumDeferredPasses()
@@ -834,101 +685,81 @@ S32 LLDrawPoolBump::getNumDeferredPasses()
 	}
 }
 
-void LLDrawPoolBump::beginDeferredPass(S32 pass)
-{
-	if (!gPipeline.hasRenderBatches(LLRenderPass::PASS_BUMP))
-	{
-		return;
-	}
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_BUMP);
-	mShiny = TRUE;
-	gDeferredBumpProgram.bind();
-	diffuse_channel = gDeferredBumpProgram.enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
-	bump_channel = gDeferredBumpProgram.enableTexture(LLViewerShaderMgr::BUMP_MAP);
-	gGL.getTexUnit(diffuse_channel)->unbind(LLTexUnit::TT_TEXTURE);
-	gGL.getTexUnit(bump_channel)->unbind(LLTexUnit::TT_TEXTURE);
-}
-
-void LLDrawPoolBump::endDeferredPass(S32 pass)
-{
-	if (!gPipeline.hasRenderBatches(LLRenderPass::PASS_BUMP))
-	{
-		return;
-	}
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_BUMP);
-	mShiny = FALSE;
-	gDeferredBumpProgram.disableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
-	gDeferredBumpProgram.disableTexture(LLViewerShaderMgr::BUMP_MAP);
-	gDeferredBumpProgram.unbind();
-	gGL.getTexUnit(0)->activate();
-}
-
 void LLDrawPoolBump::renderDeferred(S32 pass)
 {
-	if (!gPipeline.hasRenderBatches(LLRenderPass::PASS_BUMP))
-	{
-		return;
-	}
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_BUMP);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_BUMP);
 
-	U32 type = LLRenderPass::PASS_BUMP;
-	LLCullResult::drawinfo_iterator begin = gPipeline.beginRenderMap(type);
-	LLCullResult::drawinfo_iterator end = gPipeline.endRenderMap(type);
+    mShiny = TRUE;
+    for (int i = 0; i < 2; ++i)
+    {
+        bool rigged = i == 1;
+        gDeferredBumpProgram.bind(rigged);
+        diffuse_channel = LLGLSLShader::sCurBoundShaderPtr->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
+        bump_channel = LLGLSLShader::sCurBoundShaderPtr->enableTexture(LLViewerShaderMgr::BUMP_MAP);
+        gGL.getTexUnit(diffuse_channel)->unbind(LLTexUnit::TT_TEXTURE);
+        gGL.getTexUnit(bump_channel)->unbind(LLTexUnit::TT_TEXTURE);
 
-	U32 mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_TANGENT | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_COLOR;
-	
-	for (LLCullResult::drawinfo_iterator i = begin; i != end; ++i)	
-	{
-		LLDrawInfo& params = **i;
+        U32 type = rigged ? LLRenderPass::PASS_BUMP_RIGGED : LLRenderPass::PASS_BUMP;
+        LLCullResult::drawinfo_iterator begin = gPipeline.beginRenderMap(type);
+        LLCullResult::drawinfo_iterator end = gPipeline.endRenderMap(type);
 
-		gDeferredBumpProgram.setMinimumAlpha(params.mAlphaMaskCutoff);
-		LLDrawPoolBump::bindBumpMap(params, bump_channel);
-		pushBatch(params, mask, TRUE);
-	}
-}
+        U32 mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_TANGENT | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_COLOR;
 
-void LLDrawPoolBump::beginPostDeferredPass(S32 pass)
-{
-	switch (pass)
-	{
-	case 0:
-		beginFullbrightShiny();
-		break;
-	case 1:
-		beginBump(LLRenderPass::PASS_POST_BUMP);
-		break;
-	}
-}
+        LLVOAvatar* avatar = nullptr;
+        U64 skin = 0;
 
-void LLDrawPoolBump::endPostDeferredPass(S32 pass)
-{
-	switch (pass)
-	{
-	case 0:
-		endFullbrightShiny();
-		break;
-	case 1:
-		endBump(LLRenderPass::PASS_POST_BUMP);
-		break;
-	}
+        for (LLCullResult::drawinfo_iterator i = begin; i != end; ++i)
+        {
+            LLDrawInfo& params = **i;
+
+            LLGLSLShader::sCurBoundShaderPtr->setMinimumAlpha(params.mAlphaMaskCutoff);
+            LLDrawPoolBump::bindBumpMap(params, bump_channel);
+
+            if (rigged)
+            {
+                if (avatar != params.mAvatar || skin != params.mSkinInfo->mHash)
+                {
+                    uploadMatrixPalette(params);
+                    avatar = params.mAvatar;
+                    skin = params.mSkinInfo->mHash;
+                }
+                pushBatch(params, mask | LLVertexBuffer::MAP_WEIGHT4, TRUE, FALSE);
+            }
+            else
+            {
+                pushBatch(params, mask, TRUE, FALSE);
+            }
+        }
 
-	//to disable texture channels
-	LLRenderPass::endRenderPass(pass);
+        LLGLSLShader::sCurBoundShaderPtr->disableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
+        LLGLSLShader::sCurBoundShaderPtr->disableTexture(LLViewerShaderMgr::BUMP_MAP);
+        LLGLSLShader::sCurBoundShaderPtr->unbind();
+        gGL.getTexUnit(0)->activate();
+    }
+
+    mShiny = FALSE;
 }
 
+
 void LLDrawPoolBump::renderPostDeferred(S32 pass)
 {
-	switch (pass)
-	{
-	case 0:
-		renderFullbrightShiny();
-		break;
-	case 1:
-		renderBump(LLRenderPass::PASS_POST_BUMP);
-		break;
-	}
+    for (int i = 0; i < 2; ++i)
+    { // two passes -- static and rigged
+        mRigged = (i == 1);
+
+        // render shiny
+        beginFullbrightShiny();
+        renderFullbrightShiny();
+        endFullbrightShiny();
+
+        //render bump
+        beginBump();
+        renderBump(LLRenderPass::PASS_POST_BUMP);
+        endBump();
+    }
 }
 
+
 ////////////////////////////////////////////////////////////////
 // List of bump-maps created from other textures.
 
@@ -943,6 +774,8 @@ void LLBumpImageList::init()
 	LLStandardBumpmap::init();
 
 	LLStandardBumpmap::restoreGL();
+    sMainQueue = LL::WorkQueue::getInstance("mainloop");
+    sTexUpdateQueue = LL::WorkQueue::getInstance("LLImageGL"); // Share work queue with tex loader.
 }
 
 void LLBumpImageList::clear()
@@ -952,6 +785,8 @@ void LLBumpImageList::clear()
 	mBrightnessEntries.clear();
 	mDarknessEntries.clear();
 
+    sRenderTarget.release();
+
 	LLStandardBumpmap::clear();
 }
 
@@ -1061,6 +896,7 @@ void LLBumpImageList::updateImages()
 // Note: the caller SHOULD NOT keep the pointer that this function returns.  It may be updated as more data arrives.
 LLViewerTexture* LLBumpImageList::getBrightnessDarknessImage(LLViewerFetchedTexture* src_image, U8 bump_code )
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
 	llassert( (bump_code == BE_BRIGHTNESS) || (bump_code == BE_DARKNESS) );
 
 	LLViewerTexture* bump = NULL;
@@ -1090,10 +926,7 @@ LLViewerTexture* LLBumpImageList::getBrightnessDarknessImage(LLViewerFetchedText
 	}
 	else
 	{
-		LLPointer<LLImageRaw> raw = new LLImageRaw(1,1,1);
-		raw->clear(0x77, 0x77, 0xFF, 0xFF);
-
-		(*entries_list)[src_image->getID()] = LLViewerTextureManager::getLocalTexture( raw.get(), TRUE);
+		(*entries_list)[src_image->getID()] = LLViewerTextureManager::getLocalTexture( TRUE );
 		bump = (*entries_list)[src_image->getID()]; // In case callback was called immediately and replaced the image
 	}
 
@@ -1113,11 +946,10 @@ LLViewerTexture* LLBumpImageList::getBrightnessDarknessImage(LLViewerFetchedText
 }
 
 
-static LLTrace::BlockTimerStatHandle FTM_BUMP_SOURCE_STANDARD_LOADED("Bump Standard Callback");
-
 // static
 void LLBumpImageList::onSourceBrightnessLoaded( BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata )
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
 	LLUUID* source_asset_id = (LLUUID*)userdata;
 	LLBumpImageList::onSourceLoaded( success, src_vi, src, *source_asset_id, BE_BRIGHTNESS );
 	if( final )
@@ -1137,22 +969,17 @@ void LLBumpImageList::onSourceDarknessLoaded( BOOL success, LLViewerFetchedTextu
 	}
 }
 
-static LLTrace::BlockTimerStatHandle FTM_BUMP_GEN_NORMAL("Generate Normal Map");
-static LLTrace::BlockTimerStatHandle FTM_BUMP_CREATE_TEXTURE("Create GL Normal Map");
-
 void LLBumpImageList::onSourceStandardLoaded( BOOL success, LLViewerFetchedTexture* src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata)
 {
 	if (success && LLPipeline::sRenderDeferred)
 	{
-		LL_RECORD_BLOCK_TIME(FTM_BUMP_SOURCE_STANDARD_LOADED);
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
 		LLPointer<LLImageRaw> nrm_image = new LLImageRaw(src->getWidth(), src->getHeight(), 4);
 		{
-			LL_RECORD_BLOCK_TIME(FTM_BUMP_GEN_NORMAL);
 			generateNormalMapFromAlpha(src, nrm_image);
 		}
 		src_vi->setExplicitFormat(GL_RGBA, GL_RGBA);
 		{
-			LL_RECORD_BLOCK_TIME(FTM_BUMP_CREATE_TEXTURE);
 			src_vi->createGLTexture(src_vi->getDiscardLevel(), nrm_image);
 		}
 	}
@@ -1213,43 +1040,32 @@ void LLBumpImageList::generateNormalMapFromAlpha(LLImageRaw* src, LLImageRaw* nr
 	}
 }
 
-
-static LLTrace::BlockTimerStatHandle FTM_BUMP_SOURCE_LOADED("Bump Source Loaded");
-static LLTrace::BlockTimerStatHandle FTM_BUMP_SOURCE_ENTRIES_UPDATE("Entries Update");
-static LLTrace::BlockTimerStatHandle FTM_BUMP_SOURCE_MIN_MAX("Min/Max");
-static LLTrace::BlockTimerStatHandle FTM_BUMP_SOURCE_RGB2LUM("RGB to Luminance");
-static LLTrace::BlockTimerStatHandle FTM_BUMP_SOURCE_RESCALE("Rescale");
-static LLTrace::BlockTimerStatHandle FTM_BUMP_SOURCE_GEN_NORMAL("Generate Normal");
-static LLTrace::BlockTimerStatHandle FTM_BUMP_SOURCE_CREATE("Bump Source Create");
-
 // static
 void LLBumpImageList::onSourceLoaded( BOOL success, LLViewerTexture *src_vi, LLImageRaw* src, LLUUID& source_asset_id, EBumpEffect bump_code )
 {
+    LL_PROFILE_ZONE_SCOPED;
+
 	if( success )
 	{
-		LL_RECORD_BLOCK_TIME(FTM_BUMP_SOURCE_LOADED);
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
 
 
 		bump_image_map_t& entries_list(bump_code == BE_BRIGHTNESS ? gBumpImageList.mBrightnessEntries : gBumpImageList.mDarknessEntries );
 		bump_image_map_t::iterator iter = entries_list.find(source_asset_id);
 
 		{
-			LL_RECORD_BLOCK_TIME(FTM_BUMP_SOURCE_ENTRIES_UPDATE);
 			if (iter == entries_list.end() ||
 				iter->second.isNull() ||
 							iter->second->getWidth() != src->getWidth() ||
 							iter->second->getHeight() != src->getHeight()) // bump not cached yet or has changed resolution
 			{ //make sure an entry exists for this image
-				LLPointer<LLImageRaw> raw = new LLImageRaw(1,1,1);
-				raw->clear(0x77, 0x77, 0xFF, 0xFF);
-
-				entries_list[src_vi->getID()] = LLViewerTextureManager::getLocalTexture( raw.get(), TRUE);
+				entries_list[src_vi->getID()] = LLViewerTextureManager::getLocalTexture(TRUE);
 				iter = entries_list.find(src_vi->getID());
 			}
 		}
 
-		//if (iter->second->getWidth() != src->getWidth() ||
-		//	iter->second->getHeight() != src->getHeight()) // bump not cached yet or has changed resolution
+		if (iter->second->getWidth() != src->getWidth() ||
+			iter->second->getHeight() != src->getHeight()) // bump not cached yet or has changed resolution
 		{
 			LLPointer<LLImageRaw> dst_image = new LLImageRaw(src->getWidth(), src->getHeight(), 1);
 			U8* dst_data = dst_image->getData();
@@ -1277,7 +1093,6 @@ void LLBumpImageList::onSourceLoaded( BOOL success, LLViewerTexture *src_vi, LLI
 			case 1:
 			case 2:
 				{
-					LL_RECORD_BLOCK_TIME(FTM_BUMP_SOURCE_MIN_MAX);
 					if( src_data_size == dst_data_size * src_components )
 					{
 						for( S32 i = 0, j=0; i < dst_data_size; i++, j+= src_components )
@@ -1303,7 +1118,6 @@ void LLBumpImageList::onSourceLoaded( BOOL success, LLViewerTexture *src_vi, LLI
 			case 3:
 			case 4:
 				{
-					LL_RECORD_BLOCK_TIME(FTM_BUMP_SOURCE_RGB2LUM);
 					if( src_data_size == dst_data_size * src_components )
 					{
 						for( S32 i = 0, j=0; i < dst_data_size; i++, j+= src_components )
@@ -1336,7 +1150,6 @@ void LLBumpImageList::onSourceLoaded( BOOL success, LLViewerTexture *src_vi, LLI
 
 			if( maximum > minimum )
 			{
-				LL_RECORD_BLOCK_TIME(FTM_BUMP_SOURCE_RESCALE);
 				U8 bias_and_scale_lut[256];
 				F32 twice_one_over_range = 2.f / (maximum - minimum);
 				S32 i;
@@ -1366,113 +1179,146 @@ void LLBumpImageList::onSourceLoaded( BOOL success, LLViewerTexture *src_vi, LLI
 			}
 
 			//---------------------------------------------------
-			// immediately assign bump to a global smart pointer in case some local smart pointer
+			// immediately assign bump to a smart pointer in case some local smart pointer
 			// accidentally releases it.
-			LLPointer<LLViewerTexture> bump = LLViewerTextureManager::getLocalTexture( TRUE );
+            LLPointer<LLViewerTexture> bump = iter->second;
 
 			if (!LLPipeline::sRenderDeferred)
 			{
-				LL_RECORD_BLOCK_TIME(FTM_BUMP_SOURCE_CREATE);
 				bump->setExplicitFormat(GL_ALPHA8, GL_ALPHA);
-				bump->createGLTexture(0, dst_image);
+
+#if LL_BUMPLIST_MULTITHREADED
+                auto tex_queue = LLImageGLThread::sEnabled ? sTexUpdateQueue.lock() : nullptr;
+
+                if (tex_queue)
+                { //dispatch creation to background thread
+                    LLImageRaw* dst_ptr = dst_image;
+                    LLViewerTexture* bump_ptr = bump;
+                    dst_ptr->ref();
+                    bump_ptr->ref();
+                    tex_queue->post(
+                        [=]()
+                        {
+                            LL_PROFILE_ZONE_NAMED("bil - create texture");
+                            bump_ptr->createGLTexture(0, dst_ptr);
+                            bump_ptr->unref();
+                            dst_ptr->unref();
+                        });
+
+                }
+                else
+#endif
+                {
+                    bump->createGLTexture(0, dst_image);
+                }
 			}
 			else 
 			{ //convert to normal map
-				
-				//disable compression on normal maps to prevent errors below
-				bump->getGLTexture()->setAllowCompression(false);
-
-				{
-					LL_RECORD_BLOCK_TIME(FTM_BUMP_SOURCE_CREATE);
-					bump->setExplicitFormat(GL_RGBA8, GL_ALPHA);
-					bump->createGLTexture(0, dst_image);
-				}
-
-				{
-					LL_RECORD_BLOCK_TIME(FTM_BUMP_SOURCE_GEN_NORMAL);
-					gPipeline.mScreen.bindTarget();
-					
-					LLGLDepthTest depth(GL_FALSE);
-					LLGLDisable cull(GL_CULL_FACE);
-					LLGLDisable blend(GL_BLEND);
-					gGL.setColorMask(TRUE, TRUE);
-					gNormalMapGenProgram.bind();
-
-					static LLStaticHashedString sNormScale("norm_scale");
-					static LLStaticHashedString sStepX("stepX");
-					static LLStaticHashedString sStepY("stepY");
-
-					gNormalMapGenProgram.uniform1f(sNormScale, gSavedSettings.getF32("RenderNormalMapScale"));
-					gNormalMapGenProgram.uniform1f(sStepX, 1.f/bump->getWidth());
-					gNormalMapGenProgram.uniform1f(sStepY, 1.f/bump->getHeight());
-
-					LLVector2 v((F32) bump->getWidth()/gPipeline.mScreen.getWidth(),
-								(F32) bump->getHeight()/gPipeline.mScreen.getHeight());
-
-					gGL.getTexUnit(0)->bind(bump);
-					
-					S32 width = bump->getWidth();
-					S32 height = bump->getHeight();
-
-					S32 screen_width = gPipeline.mScreen.getWidth();
-					S32 screen_height = gPipeline.mScreen.getHeight();
-
-					glViewport(0, 0, screen_width, screen_height);
-
-					for (S32 left = 0; left < width; left += screen_width)
-					{
-						S32 right = left + screen_width;
-						right = llmin(right, width);
-						
-						F32 left_tc = (F32) left/ width;
-						F32 right_tc = (F32) right/width;
-
-						for (S32 bottom = 0; bottom < height; bottom += screen_height)
-						{
-							S32 top = bottom+screen_height;
-							top = llmin(top, height);
-
-							F32 bottom_tc = (F32) bottom/height;
-							F32 top_tc = (F32)(bottom+screen_height)/height;
-							top_tc = llmin(top_tc, 1.f);
-
-							F32 screen_right = (F32) (right-left)/screen_width;
-							F32 screen_top = (F32) (top-bottom)/screen_height;
-
-							gGL.begin(LLRender::TRIANGLE_STRIP);
-							gGL.texCoord2f(left_tc, bottom_tc);
-							gGL.vertex2f(0, 0);
-
-							gGL.texCoord2f(left_tc, top_tc);
-							gGL.vertex2f(0, screen_top);
-
-							gGL.texCoord2f(right_tc, bottom_tc);
-							gGL.vertex2f(screen_right, 0);
-
-							gGL.texCoord2f(right_tc, top_tc);
-							gGL.vertex2f(screen_right, screen_top);
-
-							gGL.end();
-
-							gGL.flush();
-
-							S32 w = right-left;
-							S32 h = top-bottom;
-
-							glCopyTexSubImage2D(GL_TEXTURE_2D, 0, left, bottom, 0, 0, w, h);
-						}
-					}
-
-					glGenerateMipmap(GL_TEXTURE_2D);
+                LL_PROFILE_ZONE_NAMED("bil - create normal map");
+                LLImageGL* img = bump->getGLTexture();
+                LLImageRaw* dst_ptr = dst_image.get();
+                LLGLTexture* bump_ptr = bump.get();
+
+                dst_ptr->ref();
+                img->ref();
+                bump_ptr->ref();
+                auto create_func = [=]()
+                {
+                    img->setUseMipMaps(TRUE);
+                    // upload dst_image to GPU (greyscale in red channel)
+                    img->setExplicitFormat(GL_RED, GL_RED);
+
+                    bump_ptr->createGLTexture(0, dst_ptr);
+                    dst_ptr->unref();
+                };
+
+                auto generate_func = [=]()
+                {
+                    // Allocate an empty RGBA texture at "tex_name" the same size as bump
+                    //  Note: bump will still point at GPU copy of dst_image
+                    bump_ptr->setExplicitFormat(GL_RGBA, GL_RGBA);
+                    LLGLuint tex_name;
+                    img->createGLTexture(0, nullptr, 0, 0, true, &tex_name);
+
+                    // point render target at empty buffer
+                    sRenderTarget.setColorAttachment(img, tex_name);
+
+                    // generate normal map in empty texture
+                    {
+                        sRenderTarget.bindTarget();
+
+                        LLGLDepthTest depth(GL_FALSE);
+                        LLGLDisable cull(GL_CULL_FACE);
+                        LLGLDisable blend(GL_BLEND);
+                        gGL.setColorMask(TRUE, TRUE);
+
+                        gNormalMapGenProgram.bind();
+
+                        static LLStaticHashedString sNormScale("norm_scale");
+                        static LLStaticHashedString sStepX("stepX");
+                        static LLStaticHashedString sStepY("stepY");
+
+                        gNormalMapGenProgram.uniform1f(sNormScale, gSavedSettings.getF32("RenderNormalMapScale"));
+                        gNormalMapGenProgram.uniform1f(sStepX, 1.f / bump_ptr->getWidth());
+                        gNormalMapGenProgram.uniform1f(sStepY, 1.f / bump_ptr->getHeight());
+
+                        gGL.getTexUnit(0)->bind(bump_ptr);
+
+                        gGL.begin(LLRender::TRIANGLE_STRIP);
+                        gGL.texCoord2f(0, 0);
+                        gGL.vertex2f(0, 0);
+
+                        gGL.texCoord2f(0, 1);
+                        gGL.vertex2f(0, 1);
+
+                        gGL.texCoord2f(1, 0);
+                        gGL.vertex2f(1, 0);
+
+                        gGL.texCoord2f(1, 1);
+                        gGL.vertex2f(1, 1);
+
+                        gGL.end();
+
+                        gGL.flush();
+
+                        gNormalMapGenProgram.unbind();
+
+                        sRenderTarget.flush();
+                        sRenderTarget.releaseColorAttachment();
+                    }
+
+                    // point bump at normal map and free gpu copy of dst_image
+                    img->syncTexName(tex_name);
+
+                    // generate mipmap
+                    gGL.getTexUnit(0)->bind(img);
+                    glGenerateMipmap(GL_TEXTURE_2D);
+                    gGL.getTexUnit(0)->disable();
+
+                    bump_ptr->unref();
+                    img->unref();
+                };
+
+#if LL_BUMPLIST_MULTITHREADED
+                auto main_queue = LLImageGLThread::sEnabled ? sMainQueue.lock() : nullptr;
+
+                if (main_queue)
+                { //dispatch texture upload to background thread, issue GPU commands to generate normal map on main thread
+                    main_queue->postTo(
+                        sTexUpdateQueue,
+                        create_func,
+                        generate_func);
+                }
+                else
+#endif
+                { // immediate upload texture and generate normal map
+                    create_func();
+                    generate_func();
+                }
 
-					gPipeline.mScreen.flush();
 
-					gNormalMapGenProgram.unbind();
-										
-					//generateNormalMapFromAlpha(dst_image, nrm_image);
-				}
 			}
-		
+
 			iter->second = bump; // derefs (and deletes) old image
 			//---------------------------------------------------
 		}
@@ -1481,8 +1327,17 @@ void LLBumpImageList::onSourceLoaded( BOOL success, LLViewerTexture *src_vi, LLI
 
 void LLDrawPoolBump::renderBump(U32 type, U32 mask)
 {	
-	LLCullResult::drawinfo_iterator begin = gPipeline.beginRenderMap(type);
-	LLCullResult::drawinfo_iterator end = gPipeline.endRenderMap(type);
+    LLVOAvatar* avatar = nullptr;
+    U64 skin = 0;
+
+    if (mRigged)
+    { // nudge type enum and include skinweights for rigged pass
+        type += 1;
+        mask |= LLVertexBuffer::MAP_WEIGHT4;
+    }
+
+    LLCullResult::drawinfo_iterator begin = gPipeline.beginRenderMap(type);
+    LLCullResult::drawinfo_iterator end = gPipeline.endRenderMap(type);
 
 	for (LLCullResult::drawinfo_iterator i = begin; i != end; ++i)	
 	{
@@ -1490,6 +1345,21 @@ void LLDrawPoolBump::renderBump(U32 type, U32 mask)
 
 		if (LLDrawPoolBump::bindBumpMap(params))
 		{
+            if (mRigged)
+            {
+                if (avatar != params.mAvatar || skin != params.mSkinInfo->mHash)
+                {
+                    if (uploadMatrixPalette(params))
+                    {
+                        avatar = params.mAvatar;
+                        skin = params.mSkinInfo->mHash;
+                    }
+                    else
+                    {
+                        continue;
+                    }
+                }
+            }
 			pushBatch(params, mask, FALSE);
 		}
 	}
@@ -1497,6 +1367,7 @@ void LLDrawPoolBump::renderBump(U32 type, U32 mask)
 
 void LLDrawPoolBump::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture, BOOL batch_textures)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
 	applyModelMatrix(params);
 
 	bool tex_setup = false;
@@ -1507,7 +1378,7 @@ void LLDrawPoolBump::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture, BOOL
 		{
 			if (params.mTextureList[i].notNull())
 			{
-				gGL.getTexUnit(i)->bind(params.mTextureList[i], TRUE);
+				gGL.getTexUnit(i)->bindFast(params.mTextureList[i]);
 			}
 		}
 	}
@@ -1522,13 +1393,6 @@ void LLDrawPoolBump::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture, BOOL
 			}
 			else
 			{
-				if (!LLGLSLShader::sNoFixedFunction)
-				{
-					gGL.getTexUnit(1)->activate();
-					gGL.matrixMode(LLRender::MM_TEXTURE);
-					gGL.loadMatrix((GLfloat*) params.mTextureMatrix->mMatrix);
-				}
-
 				gGL.getTexUnit(0)->activate();
 				gGL.matrixMode(LLRender::MM_TEXTURE);
 				gGL.loadMatrix((GLfloat*) params.mTextureMatrix->mMatrix);
@@ -1545,8 +1409,7 @@ void LLDrawPoolBump::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture, BOOL
 		{
 			if (params.mTexture.notNull())
 			{
-				gGL.getTexUnit(diffuse_channel)->bind(params.mTexture);
-				params.mTexture->addTextureStats(params.mVSize);		
+				gGL.getTexUnit(diffuse_channel)->bindFast(params.mTexture);
 			}
 			else
 			{
@@ -1559,10 +1422,10 @@ void LLDrawPoolBump::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture, BOOL
 	{
 		params.mGroup->rebuildMesh();
 	}
-	params.mVertexBuffer->setBuffer(mask);
-	params.mVertexBuffer->drawRange(params.mDrawMode, params.mStart, params.mEnd, params.mCount, params.mOffset);
-	gPipeline.addTrianglesDrawn(params.mCount, params.mDrawMode);
-	if (tex_setup)
+	params.mVertexBuffer->setBufferFast(mask);
+	params.mVertexBuffer->drawRangeFast(params.mDrawMode, params.mStart, params.mEnd, params.mCount, params.mOffset);
+
+    if (tex_setup)
 	{
 		if (mShiny)
 		{
@@ -1570,12 +1433,6 @@ void LLDrawPoolBump::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture, BOOL
 		}
 		else
 		{
-			if (!LLGLSLShader::sNoFixedFunction)
-			{
-				gGL.getTexUnit(1)->activate();
-				gGL.matrixMode(LLRender::MM_TEXTURE);
-				gGL.loadIdentity();
-			}
 			gGL.getTexUnit(0)->activate();
 			gGL.matrixMode(LLRender::MM_TEXTURE);
 		}
@@ -1586,9 +1443,9 @@ void LLDrawPoolBump::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture, BOOL
 
 void LLDrawPoolInvisible::render(S32 pass)
 { //render invisiprims
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_INVISIBLE);
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_INVISIBLE);
   
-	if (gPipeline.canUseVertexShaders())
+	if (gPipeline.shadersLoaded())
 	{
 		gOcclusionProgram.bind();
 	}
@@ -1600,48 +1457,8 @@ void LLDrawPoolInvisible::render(S32 pass)
 	gGL.setColorMask(true, false);
 	glStencilMask(0xFFFFFFFF);
 
-	if (gPipeline.canUseVertexShaders())
+	if (gPipeline.shadersLoaded())
 	{
 		gOcclusionProgram.unbind();
 	}
-
-	if (gPipeline.hasRenderBatches(LLRenderPass::PASS_INVISI_SHINY))
-	{
-		beginShiny(true);
-		renderShiny(true);
-		endShiny(true);
-	}
-}
-
-void LLDrawPoolInvisible::beginDeferredPass(S32 pass)
-{
-	beginRenderPass(pass);
-}
-
-void LLDrawPoolInvisible::endDeferredPass( S32 pass )
-{
-	endRenderPass(pass);
-}
-
-void LLDrawPoolInvisible::renderDeferred( S32 pass )
-{ //render invisiprims; this doesn't work becaue it also blocks all the post-deferred stuff
-#if 0 
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_INVISIBLE);
-  
-	U32 invisi_mask = LLVertexBuffer::MAP_VERTEX;
-	glStencilMask(0);
-	glStencilOp(GL_ZERO, GL_KEEP, GL_REPLACE);
-	gGL.setColorMask(false, false);
-	pushBatches(LLRenderPass::PASS_INVISIBLE, invisi_mask, FALSE);
-	gGL.setColorMask(true, true);
-	glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
-	glStencilMask(0xFFFFFFFF);
-	
-	if (gPipeline.hasRenderBatches(LLRenderPass::PASS_INVISI_SHINY))
-	{
-		beginShiny(true);
-		renderShiny(true);
-		endShiny(true);
-	}
-#endif
 }
diff --git a/indra/newview/lldrawpoolbump.h b/indra/newview/lldrawpoolbump.h
index 476b1d41b7d40d85ac08d6fb353cabe18d4773b3..e8a027967bcca922e44c560f2471874a1c22bed1 100644
--- a/indra/newview/lldrawpoolbump.h
+++ b/indra/newview/lldrawpoolbump.h
@@ -32,6 +32,8 @@
 #include "lltextureentry.h"
 #include "lluuid.h"
 
+#include <unordered_map>
+
 class LLImageRaw;
 class LLSpatialGroup;
 class LLDrawInfo;
@@ -46,52 +48,47 @@ protected :
 	static U32 sVertexMask;
 	BOOL mShiny;
 	
-	virtual U32 getVertexDataMask() { return sVertexMask; }
+	virtual U32 getVertexDataMask() override { return sVertexMask; }
 
 	LLDrawPoolBump();
 
-	virtual void render(S32 pass = 0);
-	virtual void beginRenderPass( S32 pass );
-	virtual void endRenderPass( S32 pass );
-	virtual S32	 getNumPasses();
-	/*virtual*/ void prerender();
-	/*virtual*/ void pushBatch(LLDrawInfo& params, U32 mask, BOOL texture, BOOL batch_textures = FALSE);
+	virtual void render(S32 pass = 0) override;
+	virtual S32	 getNumPasses() override;
+	/*virtual*/ void prerender() override;
+	void pushBatch(LLDrawInfo& params, U32 mask, BOOL texture, BOOL batch_textures = FALSE) override;
 
 	void renderBump(U32 type, U32 mask);
-	void renderGroup(LLSpatialGroup* group, U32 type, U32 mask, BOOL texture);
+	void renderGroup(LLSpatialGroup* group, U32 type, U32 mask, BOOL texture) override;
 		
 	S32 numBumpPasses();
 	
-	void beginShiny(bool invisible = false);
-	void renderShiny(bool invisible = false);
-	void endShiny(bool invisible = false);
+	void beginShiny();
+	void renderShiny();
+	void endShiny();
 	
 	void beginFullbrightShiny();
 	void renderFullbrightShiny();
 	void endFullbrightShiny();
 
-	void beginBump(U32 pass = LLRenderPass::PASS_BUMP);
+	void beginBump();
 	void renderBump(U32 pass = LLRenderPass::PASS_BUMP);
 	void endBump(U32 pass = LLRenderPass::PASS_BUMP);
 
-	static void bindCubeMap(LLGLSLShader* shader, S32 shader_level, S32& diffuse_channel, S32& cube_channel, bool invisible);
-	static void unbindCubeMap(LLGLSLShader* shader, S32 shader_level, S32& diffuse_channel, S32& cube_channel, bool invisible);
+	static void bindCubeMap(LLGLSLShader* shader, S32 shader_level, S32& diffuse_channel, S32& cube_channel);
+	static void unbindCubeMap(LLGLSLShader* shader, S32 shader_level, S32& diffuse_channel, S32& cube_channel);
 
-	virtual S32 getNumDeferredPasses();
-	/*virtual*/ void beginDeferredPass(S32 pass);
-	/*virtual*/ void endDeferredPass(S32 pass);
-	/*virtual*/ void renderDeferred(S32 pass);
+	virtual S32 getNumDeferredPasses() override;
+	/*virtual*/ void renderDeferred(S32 pass) override;
 
-	virtual S32 getNumPostDeferredPasses() { return 2; }
-	/*virtual*/ void beginPostDeferredPass(S32 pass);
-	/*virtual*/ void endPostDeferredPass(S32 pass);
-	/*virtual*/ void renderPostDeferred(S32 pass);
+    virtual S32 getNumPostDeferredPasses() override { return 1; }
+	/*virtual*/ void renderPostDeferred(S32 pass) override;
 
 	static BOOL bindBumpMap(LLDrawInfo& params, S32 channel = -2);
 	static BOOL bindBumpMap(LLFace* face, S32 channel = -2);
 
 private:
 	static BOOL bindBumpMap(U8 bump_code, LLViewerTexture* tex, F32 vsize, S32 channel);
+    bool mRigged = false; // if true, doing a rigged pass
 
 };
 
@@ -161,17 +158,20 @@ class LLBumpImageList
 	static void onSourceLoaded( BOOL success, LLViewerTexture *src_vi, LLImageRaw* src, LLUUID& source_asset_id, EBumpEffect bump );
 
 private:
-	typedef std::map<LLUUID, LLPointer<LLViewerTexture> > bump_image_map_t;
+	typedef std::unordered_map<LLUUID, LLPointer<LLViewerTexture> > bump_image_map_t;
 	bump_image_map_t mBrightnessEntries;
 	bump_image_map_t mDarknessEntries;
+    static LL::WorkQueue::weak_t sMainQueue;
+    static LL::WorkQueue::weak_t sTexUpdateQueue;
+    static LLRenderTarget sRenderTarget;
 };
 
 extern LLBumpImageList gBumpImageList;
 
-class LLDrawPoolInvisible : public LLDrawPoolBump
+class LLDrawPoolInvisible : public LLRenderPass
 {
 public:
-	LLDrawPoolInvisible() : LLDrawPoolBump(LLDrawPool::POOL_INVISIBLE) { }
+	LLDrawPoolInvisible() : LLRenderPass(LLDrawPool::POOL_INVISIBLE) { }
 
 	enum
 	{
@@ -186,11 +186,6 @@ class LLDrawPoolInvisible : public LLDrawPoolBump
 	virtual void beginRenderPass( S32 pass ) { }
 	virtual void endRenderPass( S32 pass ) { }
 	virtual S32	 getNumPasses() {return 1;}
-
-	virtual S32 getNumDeferredPasses() { return 1; }
-	/*virtual*/ void beginDeferredPass(S32 pass);
-	/*virtual*/ void endDeferredPass(S32 pass);
-	/*virtual*/ void renderDeferred(S32 pass);
 };
 
 
diff --git a/indra/newview/lldrawpoolmaterials.cpp b/indra/newview/lldrawpoolmaterials.cpp
index 05b0c1f1a93c6c666bee6916611e082206dccdd9..2b05f4c4532ae77301a51ae2a5061a7d0a941ef8 100644
--- a/indra/newview/lldrawpoolmaterials.cpp
+++ b/indra/newview/lldrawpoolmaterials.cpp
@@ -31,6 +31,7 @@
 #include "llviewershadermgr.h"
 #include "pipeline.h"
 #include "llglcommonfunc.h"
+#include "llvoavatar.h"
 
 S32 diffuse_channel = -1;
 
@@ -47,11 +48,20 @@ void LLDrawPoolMaterials::prerender()
 
 S32 LLDrawPoolMaterials::getNumDeferredPasses()
 {
-	return 12;
+    // 12 render passes times 2 (one for each rigged and non rigged)
+	return 12*2;
 }
 
 void LLDrawPoolMaterials::beginDeferredPass(S32 pass)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_MATERIAL;
+
+    bool rigged = false;
+    if (pass >= 12)
+    { 
+        rigged = true;
+        pass -= 12;
+    }
 	U32 shader_idx[] = 
 	{
 		0, //LLRenderPass::PASS_MATERIAL,
@@ -72,13 +82,22 @@ void LLDrawPoolMaterials::beginDeferredPass(S32 pass)
 		15, //LLRenderPass::PASS_NORMSPEC_GLOW,
 	};
 	
-	mShader = &(gDeferredMaterialProgram[shader_idx[pass]]);
-
-	if (LLPipeline::sUnderWaterRender)
-	{
-		mShader = &(gDeferredMaterialWaterProgram[shader_idx[pass]]);
-	}
-
+    U32 idx = shader_idx[pass];
+    
+    if (LLPipeline::sUnderWaterRender)
+    {
+        mShader = &(gDeferredMaterialWaterProgram[idx]);
+    }
+    else
+    {
+        mShader = &(gDeferredMaterialProgram[idx]);
+    }
+    
+    if (rigged)
+    {
+        llassert(mShader->mRiggedVariant != nullptr);
+        mShader = mShader->mRiggedVariant;
+    }
 	mShader->bind();
 
     if (LLPipeline::sRenderingHUDs)
@@ -91,13 +110,11 @@ void LLDrawPoolMaterials::beginDeferredPass(S32 pass)
     }
 
 	diffuse_channel = mShader->enableTexture(LLShaderMgr::DIFFUSE_MAP);
-		
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_MATERIALS);
 }
 
 void LLDrawPoolMaterials::endDeferredPass(S32 pass)
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_MATERIALS);
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_MATERIAL;
 
 	mShader->unbind();
 
@@ -106,6 +123,7 @@ void LLDrawPoolMaterials::endDeferredPass(S32 pass)
 
 void LLDrawPoolMaterials::renderDeferred(S32 pass)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_MATERIAL;
 	static const U32 type_list[] = 
 	{
 		LLRenderPass::PASS_MATERIAL,
@@ -126,9 +144,20 @@ void LLDrawPoolMaterials::renderDeferred(S32 pass)
 		LLRenderPass::PASS_NORMSPEC_EMISSIVE,
 	};
 
+    bool rigged = false;
+    if (pass >= 12)
+    {
+        rigged = true;
+        pass -= 12;
+    }
+
 	llassert(pass < sizeof(type_list)/sizeof(U32));
 
 	U32 type = type_list[pass];
+    if (rigged)
+    {
+        type += 1;
+    }
 
 	U32 mask = mShader->mAttributeMask;
 
@@ -157,7 +186,10 @@ void LLDrawPoolMaterials::renderDeferred(S32 pass)
 		mShader->setMinimumAlpha(params.mAlphaMaskCutoff);
 		mShader->uniform1f(LLShaderMgr::EMISSIVE_BRIGHTNESS, params.mFullbright ? 1.f : 0.f);
 
-		pushBatch(params, mask, TRUE);
+        {
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_MATERIAL;
+            pushMaterialsBatch(params, mask, rigged);
+        }
 	}
 }
 
@@ -171,49 +203,37 @@ void LLDrawPoolMaterials::bindNormalMap(LLViewerTexture* tex)
 	mShader->bindTexture(LLShaderMgr::BUMP_MAP, tex);
 }
 
-void LLDrawPoolMaterials::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture, BOOL batch_textures)
+void LLDrawPoolMaterials::pushMaterialsBatch(LLDrawInfo& params, U32 mask, bool rigged)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_MATERIAL;
 	applyModelMatrix(params);
 	
 	bool tex_setup = false;
 	
-	if (batch_textures && params.mTextureList.size() > 1)
+	//not batching textures or batch has only 1 texture -- might need a texture matrix
+	if (params.mTextureMatrix)
 	{
-		for (U32 i = 0; i < params.mTextureList.size(); ++i)
+		//if (mShiny)
 		{
-			if (params.mTextureList[i].notNull())
-			{
-				gGL.getTexUnit(i)->bind(params.mTextureList[i], TRUE);
-			}
+			gGL.getTexUnit(0)->activate();
+			gGL.matrixMode(LLRender::MM_TEXTURE);
 		}
-	}
-	else
-	{ //not batching textures or batch has only 1 texture -- might need a texture matrix
-		if (params.mTextureMatrix)
-		{
-			//if (mShiny)
-			{
-				gGL.getTexUnit(0)->activate();
-				gGL.matrixMode(LLRender::MM_TEXTURE);
-			}
 			
-			gGL.loadMatrix((GLfloat*) params.mTextureMatrix->mMatrix);
-			gPipeline.mTextureMatrixOps++;
+		gGL.loadMatrix((GLfloat*) params.mTextureMatrix->mMatrix);
+		gPipeline.mTextureMatrixOps++;
 			
-			tex_setup = true;
-		}
+		tex_setup = true;
+	}
 		
-		if (mShaderLevel > 1 && texture)
+	if (mShaderLevel > 1)
+	{
+		if (params.mTexture.notNull())
 		{
-			if (params.mTexture.notNull())
-			{
-				gGL.getTexUnit(diffuse_channel)->bind(params.mTexture);
-				params.mTexture->addTextureStats(params.mVSize);
-			}
-			else
-			{
-				gGL.getTexUnit(diffuse_channel)->unbind(LLTexUnit::TT_TEXTURE);
-			}
+			gGL.getTexUnit(diffuse_channel)->bindFast(params.mTexture);
+		}
+		else
+		{
+			gGL.getTexUnit(diffuse_channel)->unbindFast(LLTexUnit::TT_TEXTURE);
 		}
 	}
 	
@@ -222,11 +242,29 @@ void LLDrawPoolMaterials::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture,
 		params.mGroup->rebuildMesh();
 	}
 
+    // upload matrix palette to shader
+    if (rigged && params.mAvatar.notNull())
+    {
+        const LLVOAvatar::MatrixPaletteCache& mpc = params.mAvatar->updateSkinInfoMatrixPalette(params.mSkinInfo);
+        U32 count = mpc.mMatrixPalette.size();
+
+        if (count == 0)
+        {
+            //skin info not loaded yet, don't render
+            return;
+        }
+
+        mShader->uniformMatrix3x4fv(LLViewerShaderMgr::AVATAR_MATRIX,
+            count,
+            FALSE,
+            (GLfloat*)&(mpc.mGLMp[0]));
+    }
+
 	LLGLEnableFunc stencil_test(GL_STENCIL_TEST, params.mSelected, &LLGLCommonFunc::selected_stencil_test);
 
-	params.mVertexBuffer->setBuffer(mask);
-	params.mVertexBuffer->drawRange(params.mDrawMode, params.mStart, params.mEnd, params.mCount, params.mOffset);
-	gPipeline.addTrianglesDrawn(params.mCount, params.mDrawMode);
+	params.mVertexBuffer->setBufferFast(mask);
+	params.mVertexBuffer->drawRangeFast(params.mDrawMode, params.mStart, params.mEnd, params.mCount, params.mOffset);
+
 	if (tex_setup)
 	{
 		gGL.getTexUnit(0)->activate();
diff --git a/indra/newview/lldrawpoolmaterials.h b/indra/newview/lldrawpoolmaterials.h
index eae1aba87cd8ed375b7f278711ddbb5a56b53d78..8a3ad923dfccb4053f1f48d084e63615f85282f4 100644
--- a/indra/newview/lldrawpoolmaterials.h
+++ b/indra/newview/lldrawpoolmaterials.h
@@ -55,21 +55,21 @@ class LLDrawPoolMaterials : public LLRenderPass
 		LLVertexBuffer::MAP_TANGENT
 	};
 	
-	/*virtual*/ U32 getVertexDataMask() { return VERTEX_DATA_MASK; }
+	U32 getVertexDataMask() override { return VERTEX_DATA_MASK; }
 	
-	/*virtual*/ void render(S32 pass = 0) { }
-	/*virtual*/ S32	 getNumPasses() {return 0;}
-	/*virtual*/ void prerender();
+	void render(S32 pass = 0) override { }
+	S32	 getNumPasses() override {return 0;}
+	void prerender() override;
 	
-	/*virtual*/ S32 getNumDeferredPasses();
-	/*virtual*/ void beginDeferredPass(S32 pass);
-	/*virtual*/ void endDeferredPass(S32 pass);
-	/*virtual*/ void renderDeferred(S32 pass);
+	S32 getNumDeferredPasses() override;
+	void beginDeferredPass(S32 pass) override;
+	void endDeferredPass(S32 pass) override;
+	void renderDeferred(S32 pass) override;
 	
 	void bindSpecularMap(LLViewerTexture* tex);
 	void bindNormalMap(LLViewerTexture* tex);
 	
-	/*virtual*/ void pushBatch(LLDrawInfo& params, U32 mask, BOOL texture, BOOL batch_textures = FALSE);
+	void pushMaterialsBatch(LLDrawInfo& params, U32 mask, bool rigged);
 };
 
 #endif //LL_LLDRAWPOOLMATERIALS_H
diff --git a/indra/newview/lldrawpoolsimple.cpp b/indra/newview/lldrawpoolsimple.cpp
index f211cf6e27b6c24b981d9366d1b6f2e290f00795..e324a663f4cddcae707721e86af35590c51d5d2b 100644
--- a/indra/newview/lldrawpoolsimple.cpp
+++ b/indra/newview/lldrawpoolsimple.cpp
@@ -38,71 +38,54 @@
 #include "llrender.h"
 
 static LLGLSLShader* simple_shader = NULL;
-static LLGLSLShader* fullbright_shader = NULL;
 
 static LLTrace::BlockTimerStatHandle FTM_RENDER_SIMPLE_DEFERRED("Deferred Simple");
 static LLTrace::BlockTimerStatHandle FTM_RENDER_GRASS_DEFERRED("Deferred Grass");
 
-void LLDrawPoolGlow::beginPostDeferredPass(S32 pass)
+
+static void setup_simple_shader(LLGLSLShader* shader)
 {
-	gDeferredEmissiveProgram.bind();
-	gDeferredEmissiveProgram.uniform1f(LLShaderMgr::TEXTURE_GAMMA, 2.2f);
+    shader->bind();
+
     if (LLPipeline::sRenderingHUDs)
-	{
-		gDeferredEmissiveProgram.uniform1i(LLShaderMgr::NO_ATMO, 1);
-	}
-	else
-	{
-		gDeferredEmissiveProgram.uniform1i(LLShaderMgr::NO_ATMO, 0);
-	}
+    {
+        shader->uniform1i(LLShaderMgr::NO_ATMO, 1);
+    }
+    else
+    {
+        shader->uniform1i(LLShaderMgr::NO_ATMO, 0);
+    }
 }
 
-static LLTrace::BlockTimerStatHandle FTM_RENDER_GLOW_PUSH("Glow Push");
-
-void LLDrawPoolGlow::renderPostDeferred(S32 pass)
+static void setup_glow_shader(LLGLSLShader* shader)
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_GLOW);
-	LLGLEnable blend(GL_BLEND);
-	LLGLDisable test(GL_ALPHA_TEST);
-	gGL.flush();
-	/// Get rid of z-fighting with non-glow pass.
-	LLGLEnable polyOffset(GL_POLYGON_OFFSET_FILL);
-	glPolygonOffset(-1.0f, -1.0f);
-	gGL.setSceneBlendType(LLRender::BT_ADD);
-	
-	LLGLDepthTest depth(GL_TRUE, GL_FALSE);
-	gGL.setColorMask(false, true);
-
-	{
-		LL_RECORD_BLOCK_TIME(FTM_RENDER_GLOW_PUSH);
-		pushBatches(LLRenderPass::PASS_GLOW, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
-	}
-	
-	gGL.setColorMask(true, false);
-	gGL.setSceneBlendType(LLRender::BT_ALPHA);	
+    setup_simple_shader(shader);
+    if (LLPipeline::sRenderDeferred && !LLPipeline::sRenderingHUDs)
+    {
+        shader->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 2.2f);
+    }
+    else
+    {
+        shader->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 1.f);
+    }
 }
 
-void LLDrawPoolGlow::endPostDeferredPass(S32 pass)
+static void setup_fullbright_shader(LLGLSLShader* shader)
 {
-	gDeferredEmissiveProgram.unbind();
-	LLRenderPass::endRenderPass(pass);
+    setup_glow_shader(shader);
+    shader->uniform1f(LLViewerShaderMgr::FULLBRIGHT, 1.f);
 }
 
-S32 LLDrawPoolGlow::getNumPasses()
+
+void LLDrawPoolGlow::renderPostDeferred(S32 pass)
 {
-	if (LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_OBJECT) > 0)
-	{
-		return 1;
-	}
-	else
-	{
-		return 0;
-	}
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_GLOW);
+    render(&gDeferredEmissiveProgram);
 }
 
-void LLDrawPoolGlow::render(S32 pass)
+void LLDrawPoolGlow::render(LLGLSLShader* shader)
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_GLOW);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_GLOW);
 	LLGLEnable blend(GL_BLEND);
 	LLGLDisable test(GL_ALPHA_TEST);
 	gGL.flush();
@@ -111,51 +94,33 @@ void LLDrawPoolGlow::render(S32 pass)
 	glPolygonOffset(-1.0f, -1.0f);
 	gGL.setSceneBlendType(LLRender::BT_ADD);
 	
-	U32 shader_level = LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_OBJECT);
-
-	//should never get here without basic shaders enabled
-	llassert(shader_level > 0);
-	
-	LLGLSLShader* shader = LLPipeline::sUnderWaterRender ? &gObjectEmissiveWaterProgram : &gObjectEmissiveProgram;
-	shader->bind();
-	if (LLPipeline::sRenderDeferred)
-	{
-		shader->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 2.2f);
-	}
-	else
-	{
-		shader->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 1.f);
-	}	
-
-    if (LLPipeline::sRenderingHUDs)
-	{
-		shader->uniform1i(LLShaderMgr::NO_ATMO, 1);
-	}
-	else
-	{
-		shader->uniform1i(LLShaderMgr::NO_ATMO, 0);
-	}
-
 	LLGLDepthTest depth(GL_TRUE, GL_FALSE);
 	gGL.setColorMask(false, true);
 
-	pushBatches(LLRenderPass::PASS_GLOW, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
-	
-	gGL.setColorMask(true, false);
-	gGL.setSceneBlendType(LLRender::BT_ALPHA);
-	
-	if (shader_level > 0 && fullbright_shader)
-	{
-		shader->unbind();
-	}
+    //first pass -- static objects
+    setup_glow_shader(shader);
+    pushBatches(LLRenderPass::PASS_GLOW, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
+        
+    // second pass -- rigged objects
+    shader = shader->mRiggedVariant;
+    setup_glow_shader(shader);
+    pushRiggedBatches(LLRenderPass::PASS_GLOW_RIGGED, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
+ 
+    gGL.setColorMask(true, false);
+    gGL.setSceneBlendType(LLRender::BT_ALPHA);	
 }
 
-void LLDrawPoolGlow::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture, BOOL batch_textures)
+S32 LLDrawPoolGlow::getNumPasses()
 {
-	//gGL.diffuseColor4ubv(params.mGlowColor.mV);
-	LLRenderPass::pushBatch(params, mask, texture, batch_textures);
+    return 1;
 }
 
+void LLDrawPoolGlow::render(S32 pass)
+{
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
+    LLGLSLShader* shader = LLPipeline::sUnderWaterRender ? &gObjectEmissiveWaterProgram : &gObjectEmissiveProgram;
+    render(shader);
+}
 
 LLDrawPoolSimple::LLDrawPoolSimple() :
 	LLRenderPass(POOL_SIMPLE)
@@ -167,100 +132,73 @@ void LLDrawPoolSimple::prerender()
 	mShaderLevel = LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_OBJECT);
 }
 
-void LLDrawPoolSimple::beginRenderPass(S32 pass)
-{
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_SIMPLE);
-
-	if (LLPipeline::sImpostorRender)
-	{
-		simple_shader = &gObjectSimpleImpostorProgram;
-	}
-	else if (LLPipeline::sUnderWaterRender)
-	{
-		simple_shader = &gObjectSimpleWaterProgram;
-	}
-	else
-	{
-		simple_shader = &gObjectSimpleProgram;
-	}
-
-	if (mShaderLevel > 0)
-	{
-		simple_shader->bind();
-
-        if (LLPipeline::sRenderingHUDs)
-	    {
-		    simple_shader->uniform1i(LLShaderMgr::NO_ATMO, 1);
-	    }
-	    else
-	    {
-		    simple_shader->uniform1i(LLShaderMgr::NO_ATMO, 0);
-	    }
-	}
-	else 
-	{
-		// don't use shaders!
-		if (gGLManager.mHasShaderObjects)
-		{
-			LLGLSLShader::bindNoShader();
-		}		
-	}
-}
-
-void LLDrawPoolSimple::endRenderPass(S32 pass)
+S32 LLDrawPoolSimple::getNumPasses()
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_SIMPLE);
-	stop_glerror();
-	LLRenderPass::endRenderPass(pass);
-	stop_glerror();
-	if (mShaderLevel > 0)
-	{
-		simple_shader->unbind();
-	}
+    return 1;
 }
 
 void LLDrawPoolSimple::render(S32 pass)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_SIMPLE);
+
 	LLGLDisable blend(GL_BLEND);
 	
+    LLGLSLShader* shader = nullptr;
+    if (LLPipeline::sImpostorRender)
+    {
+        shader = &gObjectSimpleImpostorProgram;
+    }
+    else if (LLPipeline::sUnderWaterRender)
+    {
+        shader = &gObjectSimpleWaterProgram;
+    }
+    else
+    {
+        shader = &gObjectSimpleProgram;
+    }
+
 	{ //render simple
-		LL_RECORD_BLOCK_TIME(FTM_RENDER_SIMPLE);
+	
 		gPipeline.enableLightsDynamic();
 
-		if (mShaderLevel > 0)
-		{
-			U32 mask = getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX;
-
-			pushBatches(LLRenderPass::PASS_SIMPLE, mask, TRUE, TRUE);
-
-			if (LLPipeline::sRenderDeferred)
-			{ //if deferred rendering is enabled, bump faces aren't registered as simple
-				//render bump faces here as simple so bump faces will appear under water
-				pushBatches(LLRenderPass::PASS_BUMP, mask, TRUE, TRUE);			
-				pushBatches(LLRenderPass::PASS_MATERIAL, mask, TRUE, TRUE);
-				pushBatches(LLRenderPass::PASS_SPECMAP, mask, TRUE, TRUE);
-				pushBatches(LLRenderPass::PASS_NORMMAP, mask, TRUE, TRUE);
-				pushBatches(LLRenderPass::PASS_NORMSPEC, mask, TRUE, TRUE);		
-			}
-		}
-		else
-		{
-			LLGLDisable alpha_test(GL_ALPHA_TEST);
-			renderTexture(LLRenderPass::PASS_SIMPLE, getVertexDataMask());
-		}
-		
+		U32 mask = getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX;
+
+        // first pass -- static objects
+        {
+            setup_simple_shader(shader);
+            pushBatches(LLRenderPass::PASS_SIMPLE, mask, TRUE, TRUE);
+
+            if (LLPipeline::sRenderDeferred)
+            { //if deferred rendering is enabled, bump faces aren't registered as simple
+                //render bump faces here as simple so bump faces will appear under water
+                pushBatches(LLRenderPass::PASS_BUMP, mask, TRUE, TRUE);
+                pushBatches(LLRenderPass::PASS_MATERIAL, mask, TRUE, TRUE);
+                pushBatches(LLRenderPass::PASS_SPECMAP, mask, TRUE, TRUE);
+                pushBatches(LLRenderPass::PASS_NORMMAP, mask, TRUE, TRUE);
+                pushBatches(LLRenderPass::PASS_NORMSPEC, mask, TRUE, TRUE);
+            }
+        }
+        
+        //second pass, rigged
+        {
+            shader = shader->mRiggedVariant;
+            setup_simple_shader(shader);
+            pushRiggedBatches(LLRenderPass::PASS_SIMPLE_RIGGED, mask, TRUE, TRUE);
+
+            if (LLPipeline::sRenderDeferred)
+            { //if deferred rendering is enabled, bump faces aren't registered as simple
+                //render bump faces here as simple so bump faces will appear under water
+                pushRiggedBatches(LLRenderPass::PASS_BUMP_RIGGED, mask, TRUE, TRUE);
+                pushRiggedBatches(LLRenderPass::PASS_MATERIAL_RIGGED, mask, TRUE, TRUE);
+                pushRiggedBatches(LLRenderPass::PASS_SPECMAP_RIGGED, mask, TRUE, TRUE);
+                pushRiggedBatches(LLRenderPass::PASS_NORMMAP_RIGGED, mask, TRUE, TRUE);
+                pushRiggedBatches(LLRenderPass::PASS_NORMSPEC_RIGGED, mask, TRUE, TRUE);
+            }
+        }
 	}
 }
 
 
-
-
-
-
-
-
-
-
 static LLTrace::BlockTimerStatHandle FTM_RENDER_ALPHA_MASK("Alpha Mask");
 
 LLDrawPoolAlphaMask::LLDrawPoolAlphaMask() :
@@ -273,85 +211,36 @@ void LLDrawPoolAlphaMask::prerender()
 	mShaderLevel = LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_OBJECT);
 }
 
-void LLDrawPoolAlphaMask::beginRenderPass(S32 pass)
-{
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_MASK);
-
-	if (LLPipeline::sUnderWaterRender)
-	{
-		simple_shader = &gObjectSimpleWaterAlphaMaskProgram;
-	}
-	else
-	{
-		simple_shader = &gObjectSimpleAlphaMaskProgram;
-	}
-
-	if (mShaderLevel > 0)
-	{
-		simple_shader->bind();
-
-        if (LLPipeline::sRenderingHUDs)
-	    {
-		    simple_shader->uniform1i(LLShaderMgr::NO_ATMO, 1);
-	    }
-	    else
-	    {
-		    simple_shader->uniform1i(LLShaderMgr::NO_ATMO, 0);
-	    }
-	}
-	else 
-	{
-		// don't use shaders!
-		if (gGLManager.mHasShaderObjects)
-		{
-			LLGLSLShader::bindNoShader();
-		}		
-	}
-}
-
-void LLDrawPoolAlphaMask::endRenderPass(S32 pass)
-{
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_MASK);
-	stop_glerror();
-	LLRenderPass::endRenderPass(pass);
-	stop_glerror();
-	if (mShaderLevel > 0)
-	{
-		simple_shader->unbind();
-	}
-}
-
 void LLDrawPoolAlphaMask::render(S32 pass)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
 	LLGLDisable blend(GL_BLEND);
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_MASK);
 	
-	if (mShaderLevel > 0)
-	{
-		simple_shader->bind();
-		simple_shader->setMinimumAlpha(0.33f);
+    LLGLSLShader* shader = nullptr;
+    if (LLPipeline::sUnderWaterRender)
+    {
+        shader = &gObjectSimpleWaterAlphaMaskProgram;
+    }
+    else
+    {
+        shader = &gObjectSimpleAlphaMaskProgram;
+    }
 
-        if (LLPipeline::sRenderingHUDs)
-	    {
-		    simple_shader->uniform1i(LLShaderMgr::NO_ATMO, 1);
-	    }
-	    else
-	    {
-		    simple_shader->uniform1i(LLShaderMgr::NO_ATMO, 0);
-	    }
+    // render static
+    setup_simple_shader(shader);
+    pushMaskBatches(LLRenderPass::PASS_ALPHA_MASK, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
+	pushMaskBatches(LLRenderPass::PASS_MATERIAL_ALPHA_MASK, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
+	pushMaskBatches(LLRenderPass::PASS_SPECMAP_MASK, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
+	pushMaskBatches(LLRenderPass::PASS_NORMMAP_MASK, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
+	pushMaskBatches(LLRenderPass::PASS_NORMSPEC_MASK, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
 
-		pushMaskBatches(LLRenderPass::PASS_ALPHA_MASK, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
-		pushMaskBatches(LLRenderPass::PASS_MATERIAL_ALPHA_MASK, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
-		pushMaskBatches(LLRenderPass::PASS_SPECMAP_MASK, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
-		pushMaskBatches(LLRenderPass::PASS_NORMMAP_MASK, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
-		pushMaskBatches(LLRenderPass::PASS_NORMSPEC_MASK, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
-	}
-	else
-	{
-		LLGLEnable test(GL_ALPHA_TEST);
-		pushMaskBatches(LLRenderPass::PASS_ALPHA_MASK, getVertexDataMask(), TRUE, FALSE);
-		gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT); //OK
-	}
+    // render rigged
+    setup_simple_shader(shader->mRiggedVariant);
+    pushRiggedMaskBatches(LLRenderPass::PASS_ALPHA_MASK_RIGGED, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
+    pushRiggedMaskBatches(LLRenderPass::PASS_MATERIAL_ALPHA_MASK_RIGGED, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
+    pushRiggedMaskBatches(LLRenderPass::PASS_SPECMAP_MASK_RIGGED, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
+    pushRiggedMaskBatches(LLRenderPass::PASS_NORMMAP_MASK_RIGGED, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
+    pushRiggedMaskBatches(LLRenderPass::PASS_NORMSPEC_MASK_RIGGED, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
 }
 
 LLDrawPoolFullbrightAlphaMask::LLDrawPoolFullbrightAlphaMask() :
@@ -364,166 +253,70 @@ void LLDrawPoolFullbrightAlphaMask::prerender()
 	mShaderLevel = LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_OBJECT);
 }
 
-void LLDrawPoolFullbrightAlphaMask::beginRenderPass(S32 pass)
+void LLDrawPoolFullbrightAlphaMask::render(S32 pass)
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_MASK);
-
-	if (LLPipeline::sUnderWaterRender)
-	{
-		simple_shader = &gObjectFullbrightWaterAlphaMaskProgram;
-	}
-	else
-	{
-		simple_shader = &gObjectFullbrightAlphaMaskProgram;
-	}
-
-	if (mShaderLevel > 0)
-	{
-		simple_shader->bind();
-
-        if (LLPipeline::sRenderingHUDs)
-	    {
-		    simple_shader->uniform1i(LLShaderMgr::NO_ATMO, 1);
-	    }
-	    else
-	    {
-		    simple_shader->uniform1i(LLShaderMgr::NO_ATMO, 0);
-	    }
-	}
-	else 
-	{
-		// don't use shaders!
-		if (gGLManager.mHasShaderObjects)
-		{
-			LLGLSLShader::bindNoShader();
-		}		
-	}
-}
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_MASK);
 
-void LLDrawPoolFullbrightAlphaMask::endRenderPass(S32 pass)
-{
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_MASK);
-	stop_glerror();
-	LLRenderPass::endRenderPass(pass);
-	stop_glerror();
-	if (mShaderLevel > 0)
-	{
-		simple_shader->unbind();
-	}
-}
+    LLGLSLShader* shader = nullptr;
+    if (LLPipeline::sUnderWaterRender)
+    {
+        shader = &gObjectFullbrightWaterAlphaMaskProgram;
+    }
+    else
+    {
+        shader = &gObjectFullbrightAlphaMaskProgram;
+    }
 
-void LLDrawPoolFullbrightAlphaMask::render(S32 pass)
-{
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_MASK);
+    // render static
+    setup_fullbright_shader(shader);
+    pushMaskBatches(LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
 
-	if (mShaderLevel > 0)
-	{
-		if (simple_shader)
-		{
-			simple_shader->bind();
-			simple_shader->setMinimumAlpha(0.33f);
-
-            if (LLPipeline::sRenderingHUDs)
-	        {
-		        simple_shader->uniform1i(LLShaderMgr::NO_ATMO, 1);
-                simple_shader->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 1.0f);
-	        }
-	        else
-	        {
-		        simple_shader->uniform1i(LLShaderMgr::NO_ATMO, 0);
-                if (LLPipeline::sRenderDeferred)
-			    {
-                    simple_shader->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 2.2f);				    
-			    }
-                else
-                {
-				    simple_shader->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 1.0f);
-			    }
-	        }
-		}
-		pushMaskBatches(LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
-		//LLGLSLShader::bindNoShader();
-	}
-	else
-	{
-		LLGLEnable test(GL_ALPHA_TEST);
-		gPipeline.enableLightsFullbright();
-		pushMaskBatches(LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK, getVertexDataMask(), TRUE, FALSE);
-		gPipeline.enableLightsDynamic();
-		gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT); //OK
-	}
+    // render rigged
+    setup_fullbright_shader(shader->mRiggedVariant);
+    pushRiggedMaskBatches(LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK_RIGGED, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
 }
 
 //===============================
 //DEFERRED IMPLEMENTATION
 //===============================
 
-void LLDrawPoolSimple::beginDeferredPass(S32 pass)
-{
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_SIMPLE_DEFERRED);
-	gDeferredDiffuseProgram.bind();
-
-    if (LLPipeline::sRenderingHUDs)
-	{
-		gDeferredDiffuseProgram.uniform1i(LLShaderMgr::NO_ATMO, 1);
-	}
-	else
-	{
-		gDeferredDiffuseProgram.uniform1i(LLShaderMgr::NO_ATMO, 0);
-	}
-}
-
-void LLDrawPoolSimple::endDeferredPass(S32 pass)
+S32 LLDrawPoolSimple::getNumDeferredPasses()
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_SIMPLE_DEFERRED);
-	LLRenderPass::endRenderPass(pass);
-
-	gDeferredDiffuseProgram.unbind();
+    return 1;
 }
 
 void LLDrawPoolSimple::renderDeferred(S32 pass)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_SIMPLE_DEFERRED);
 	LLGLDisable blend(GL_BLEND);
 	LLGLDisable alpha_test(GL_ALPHA_TEST);
 
-	{ //render simple
-		LL_RECORD_BLOCK_TIME(FTM_RENDER_SIMPLE_DEFERRED);
-		pushBatches(LLRenderPass::PASS_SIMPLE, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
-	}
+	//render static
+    setup_simple_shader(&gDeferredDiffuseProgram);
+	pushBatches(LLRenderPass::PASS_SIMPLE, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
+	
+    //render rigged
+    setup_simple_shader(gDeferredDiffuseProgram.mRiggedVariant);
+    pushRiggedBatches(LLRenderPass::PASS_SIMPLE_RIGGED, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
 }
 
 static LLTrace::BlockTimerStatHandle FTM_RENDER_ALPHA_MASK_DEFERRED("Deferred Alpha Mask");
 
-void LLDrawPoolAlphaMask::beginDeferredPass(S32 pass)
-{
-	
-}
-
-void LLDrawPoolAlphaMask::endDeferredPass(S32 pass)
-{
-	
-}
 
 void LLDrawPoolAlphaMask::renderDeferred(S32 pass)
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_MASK_DEFERRED);
-	gDeferredDiffuseAlphaMaskProgram.bind();
-	gDeferredDiffuseAlphaMaskProgram.setMinimumAlpha(0.33f);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_MASK_DEFERRED);
+    LLGLSLShader* shader = &gDeferredDiffuseAlphaMaskProgram;
 
-    if (LLPipeline::sRenderingHUDs)
-	{
-		gDeferredDiffuseAlphaMaskProgram.uniform1i(LLShaderMgr::NO_ATMO, 1);
-	}
-	else
-	{
-		gDeferredDiffuseAlphaMaskProgram.uniform1i(LLShaderMgr::NO_ATMO, 0);
-	}
+    //render static
+    setup_simple_shader(shader);
+    pushMaskBatches(LLRenderPass::PASS_ALPHA_MASK, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
 
-	pushMaskBatches(LLRenderPass::PASS_ALPHA_MASK, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
-	gDeferredDiffuseAlphaMaskProgram.unbind();			
+    //render rigged
+    setup_simple_shader(shader->mRiggedVariant);
+    pushRiggedMaskBatches(LLRenderPass::PASS_ALPHA_MASK_RIGGED, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
 }
 
-
 // grass drawpool
 LLDrawPoolGrass::LLDrawPoolGrass() :
  LLRenderPass(POOL_GRASS)
@@ -539,7 +332,7 @@ void LLDrawPoolGrass::prerender()
 
 void LLDrawPoolGrass::beginRenderPass(S32 pass)
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_GRASS);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_GRASS);
 	stop_glerror();
 
 	if (LLPipeline::sUnderWaterRender)
@@ -566,18 +359,14 @@ void LLDrawPoolGrass::beginRenderPass(S32 pass)
 	}
 	else 
 	{
-		gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.5f);
-		// don't use shaders!
-		if (gGLManager.mHasShaderObjects)
-		{
-			LLGLSLShader::bindNoShader();
-		}		
+        gGL.flush();
+		LLGLSLShader::bindNoShader();
 	}
 }
 
 void LLDrawPoolGrass::endRenderPass(S32 pass)
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_GRASS);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_GRASS);
 	LLRenderPass::endRenderPass(pass);
 
 	if (mShaderLevel > 0)
@@ -586,20 +375,21 @@ void LLDrawPoolGrass::endRenderPass(S32 pass)
 	}
 	else
 	{
-		gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
+		gGL.flush();
 	}
 }
 
 void LLDrawPoolGrass::render(S32 pass)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
 	LLGLDisable blend(GL_BLEND);
 	
 	{
-		LL_RECORD_BLOCK_TIME(FTM_RENDER_GRASS);
+		//LL_RECORD_BLOCK_TIME(FTM_RENDER_GRASS);
 		LLGLEnable test(GL_ALPHA_TEST);
 		gGL.setSceneBlendType(LLRender::BT_ALPHA);
 		//render grass
-		LLRenderPass::renderTexture(LLRenderPass::PASS_GRASS, getVertexDataMask());
+		LLRenderPass::pushBatches(LLRenderPass::PASS_GRASS, getVertexDataMask());
 	}
 }
 
@@ -615,8 +405,9 @@ void LLDrawPoolGrass::endDeferredPass(S32 pass)
 
 void LLDrawPoolGrass::renderDeferred(S32 pass)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
 	{
-		LL_RECORD_BLOCK_TIME(FTM_RENDER_GRASS_DEFERRED);
+		//LL_RECORD_BLOCK_TIME(FTM_RENDER_GRASS_DEFERRED);
 		gDeferredNonIndexedDiffuseAlphaMaskProgram.bind();
 		gDeferredNonIndexedDiffuseAlphaMaskProgram.setMinimumAlpha(0.5f);
 
@@ -630,7 +421,7 @@ void LLDrawPoolGrass::renderDeferred(S32 pass)
 	    }
 
 		//render grass
-		LLRenderPass::renderTexture(LLRenderPass::PASS_GRASS, getVertexDataMask());
+		LLRenderPass::pushBatches(LLRenderPass::PASS_GRASS, getVertexDataMask());
 	}			
 }
 
@@ -646,120 +437,67 @@ void LLDrawPoolFullbright::prerender()
 	mShaderLevel = LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_OBJECT);
 }
 
-void LLDrawPoolFullbright::beginPostDeferredPass(S32 pass)
-{
-	if (LLPipeline::sUnderWaterRender)
-	{
-		gDeferredFullbrightWaterProgram.bind();
-	}
-	else
-	{
-		gDeferredFullbrightProgram.bind();
-
-        if (LLPipeline::sRenderingHUDs)
-	    {
-		    gDeferredFullbrightProgram.uniform1i(LLShaderMgr::NO_ATMO, 1);
-	    }
-	    else
-	    {
-		    gDeferredFullbrightProgram.uniform1i(LLShaderMgr::NO_ATMO, 0);
-	    }
-	}
-	
-}
 
 void LLDrawPoolFullbright::renderPostDeferred(S32 pass)
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_FULLBRIGHT);
-	
-	gGL.setSceneBlendType(LLRender::BT_ALPHA);
-	U32 fullbright_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_COLOR | LLVertexBuffer::MAP_TEXTURE_INDEX;
-	pushBatches(LLRenderPass::PASS_FULLBRIGHT, fullbright_mask, TRUE, TRUE);
-}
-
-void LLDrawPoolFullbright::endPostDeferredPass(S32 pass)
-{
-	if (LLPipeline::sUnderWaterRender)
-	{
-		gDeferredFullbrightWaterProgram.unbind();
-	}
-	else
-	{
-		gDeferredFullbrightProgram.unbind();
-	}
-	LLRenderPass::endRenderPass(pass);
-}
-
-void LLDrawPoolFullbright::beginRenderPass(S32 pass)
-{
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_FULLBRIGHT);
-	
-	if (LLPipeline::sUnderWaterRender)
-	{
-		fullbright_shader = &gObjectFullbrightWaterProgram;
-	}
-	else
-	{
-		fullbright_shader = &gObjectFullbrightProgram;
-	}
-}
-
-void LLDrawPoolFullbright::endRenderPass(S32 pass)
-{
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_FULLBRIGHT);
-	LLRenderPass::endRenderPass(pass);
-
-	stop_glerror();
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_FULLBRIGHT);
 
-	if (mShaderLevel > 0)
-	{
-		fullbright_shader->unbind();
-	}
+    LLGLSLShader* shader = nullptr;
+    if (LLPipeline::sUnderWaterRender)
+    {
+        shader = &gDeferredFullbrightWaterProgram;
+    }
+    else
+    {
+        shader = &gDeferredFullbrightProgram;
+    }
 
-	stop_glerror();
+	gGL.setSceneBlendType(LLRender::BT_ALPHA);
+	U32 fullbright_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_COLOR | LLVertexBuffer::MAP_TEXTURE_INDEX;
+    
+    // render static
+    setup_fullbright_shader(shader);
+    pushBatches(LLRenderPass::PASS_FULLBRIGHT, fullbright_mask, TRUE, TRUE);
+    
+    // render rigged
+    setup_fullbright_shader(shader->mRiggedVariant);
+    pushRiggedBatches(LLRenderPass::PASS_FULLBRIGHT_RIGGED, fullbright_mask, TRUE, TRUE);
 }
 
 void LLDrawPoolFullbright::render(S32 pass)
 { //render fullbright
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_FULLBRIGHT);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_FULLBRIGHT);
 	gGL.setSceneBlendType(LLRender::BT_ALPHA);
 
 	stop_glerror();
+    LLGLSLShader* shader = nullptr;
+    if (LLPipeline::sUnderWaterRender)
+    {
+        shader = &gObjectFullbrightWaterProgram;
+    }
+    else
+    {
+        shader = &gObjectFullbrightProgram;
+    }
 
-	if (mShaderLevel > 0)
-	{
-		fullbright_shader->bind();
-		fullbright_shader->uniform1f(LLViewerShaderMgr::FULLBRIGHT, 1.f);
-		fullbright_shader->uniform1f(LLViewerShaderMgr::TEXTURE_GAMMA, 1.f);
-
-        if (LLPipeline::sRenderingHUDs)
-	    {
-		    fullbright_shader->uniform1i(LLShaderMgr::NO_ATMO, 1);
-	    }
-	    else
-	    {
-		    fullbright_shader->uniform1i(LLShaderMgr::NO_ATMO, 0);
-	    }
 
-		U32 fullbright_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_COLOR | LLVertexBuffer::MAP_TEXTURE_INDEX;
-		pushBatches(LLRenderPass::PASS_FULLBRIGHT, fullbright_mask, TRUE, TRUE);
-		pushBatches(LLRenderPass::PASS_MATERIAL_ALPHA_EMISSIVE, fullbright_mask, TRUE, TRUE);
-		pushBatches(LLRenderPass::PASS_SPECMAP_EMISSIVE, fullbright_mask, TRUE, TRUE);
-		pushBatches(LLRenderPass::PASS_NORMMAP_EMISSIVE, fullbright_mask, TRUE, TRUE);
-		pushBatches(LLRenderPass::PASS_NORMSPEC_EMISSIVE, fullbright_mask, TRUE, TRUE);
-	}
-	else
-	{
-		gPipeline.enableLightsFullbright();
-		U32 fullbright_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_COLOR;
-		renderTexture(LLRenderPass::PASS_FULLBRIGHT, fullbright_mask);
-		pushBatches(LLRenderPass::PASS_MATERIAL_ALPHA_EMISSIVE, fullbright_mask);
-		pushBatches(LLRenderPass::PASS_SPECMAP_EMISSIVE, fullbright_mask);
-		pushBatches(LLRenderPass::PASS_NORMMAP_EMISSIVE, fullbright_mask);
-		pushBatches(LLRenderPass::PASS_NORMSPEC_EMISSIVE, fullbright_mask);
-	}
+	U32 mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_COLOR | LLVertexBuffer::MAP_TEXTURE_INDEX;
 
-	stop_glerror();
+    // render static
+    setup_fullbright_shader(shader);
+    pushBatches(LLRenderPass::PASS_FULLBRIGHT, mask, TRUE, TRUE);
+    pushBatches(LLRenderPass::PASS_MATERIAL_ALPHA_EMISSIVE, mask, TRUE, TRUE);
+    pushBatches(LLRenderPass::PASS_SPECMAP_EMISSIVE, mask, TRUE, TRUE);
+    pushBatches(LLRenderPass::PASS_NORMMAP_EMISSIVE, mask, TRUE, TRUE);
+    pushBatches(LLRenderPass::PASS_NORMSPEC_EMISSIVE, mask, TRUE, TRUE);
+ 
+    // render rigged
+    setup_fullbright_shader(shader->mRiggedVariant);
+    pushRiggedBatches(LLRenderPass::PASS_FULLBRIGHT_RIGGED, mask, TRUE, TRUE);
+    pushRiggedBatches(LLRenderPass::PASS_MATERIAL_ALPHA_EMISSIVE_RIGGED, mask, TRUE, TRUE);
+    pushRiggedBatches(LLRenderPass::PASS_SPECMAP_EMISSIVE_RIGGED, mask, TRUE, TRUE);
+    pushRiggedBatches(LLRenderPass::PASS_NORMMAP_EMISSIVE_RIGGED, mask, TRUE, TRUE);
+    pushRiggedBatches(LLRenderPass::PASS_NORMSPEC_EMISSIVE_RIGGED, mask, TRUE, TRUE);
 }
 
 S32 LLDrawPoolFullbright::getNumPasses()
@@ -767,65 +505,40 @@ S32 LLDrawPoolFullbright::getNumPasses()
 	return 1;
 }
 
-
-void LLDrawPoolFullbrightAlphaMask::beginPostDeferredPass(S32 pass)
+void LLDrawPoolFullbrightAlphaMask::renderPostDeferred(S32 pass)
 {
-	
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_FULLBRIGHT);
+    
+    LLGLSLShader* shader = nullptr;
     if (LLPipeline::sRenderingHUDs)
     {
-        gObjectFullbrightAlphaMaskProgram.bind();
-		gObjectFullbrightAlphaMaskProgram.uniform1f(LLShaderMgr::TEXTURE_GAMMA, 1.0f);
-        gObjectFullbrightAlphaMaskProgram.uniform1i(LLShaderMgr::NO_ATMO, 1);
+        shader = &gObjectFullbrightAlphaMaskProgram;
     }
-	else if (LLPipeline::sRenderDeferred)
-	{
+    else if (LLPipeline::sRenderDeferred)
+    {
         if (LLPipeline::sUnderWaterRender)
-		{
-			gDeferredFullbrightAlphaMaskWaterProgram.bind();
-			gDeferredFullbrightAlphaMaskWaterProgram.uniform1f(LLShaderMgr::TEXTURE_GAMMA, 2.2f);
-            gDeferredFullbrightAlphaMaskProgram.uniform1i(LLShaderMgr::NO_ATMO, 1);
-		}
-		else
-		{
-			gDeferredFullbrightAlphaMaskProgram.bind();
-			gDeferredFullbrightAlphaMaskProgram.uniform1f(LLShaderMgr::TEXTURE_GAMMA, 2.2f);
-            gDeferredFullbrightAlphaMaskProgram.uniform1i(LLShaderMgr::NO_ATMO, 0);
-		}
+        {
+            shader = &gDeferredFullbrightAlphaMaskWaterProgram;
+        }
+        else
+        {
+            shader = &gDeferredFullbrightAlphaMaskProgram;
+        }
     }
     else
     {
-		gObjectFullbrightAlphaMaskProgram.bind();
-		gObjectFullbrightAlphaMaskProgram.uniform1f(LLShaderMgr::TEXTURE_GAMMA, 1.0f);
-        gObjectFullbrightAlphaMaskProgram.uniform1i(LLShaderMgr::NO_ATMO, 0);
-	}
-}
+        shader = &gObjectFullbrightAlphaMaskProgram;
+    }
 
-void LLDrawPoolFullbrightAlphaMask::renderPostDeferred(S32 pass)
-{
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_FULLBRIGHT);
 	LLGLDisable blend(GL_BLEND);
 	U32 fullbright_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_COLOR | LLVertexBuffer::MAP_TEXTURE_INDEX;
-	pushMaskBatches(LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK, fullbright_mask, TRUE, TRUE);
+    
+    // render static
+    setup_fullbright_shader(shader);
+    pushMaskBatches(LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK, fullbright_mask, TRUE, TRUE);
+    
+    // render rigged
+    setup_fullbright_shader(shader->mRiggedVariant);
+    pushRiggedMaskBatches(LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK_RIGGED, fullbright_mask, TRUE, TRUE);
 }
 
-void LLDrawPoolFullbrightAlphaMask::endPostDeferredPass(S32 pass)
-{
-	if (LLPipeline::sRenderingHUDs || !LLPipeline::sRenderDeferred)
-	{
-		gObjectFullbrightAlphaMaskProgram.unbind();
-	}
-	else
-	{
-		if (LLPipeline::sUnderWaterRender)
-		{
-			gDeferredFullbrightAlphaMaskWaterProgram.unbind();
-		}
-		else
-		{
-			gDeferredFullbrightAlphaMaskProgram.unbind();
-		}
-	}
-	LLRenderPass::endRenderPass(pass);
-}
-
-
diff --git a/indra/newview/lldrawpoolsimple.h b/indra/newview/lldrawpoolsimple.h
index 608ad9e1eb0856a2095769b117f99fe070ee5cf9..cccbe5e495515aa5d1184f20e0a6936d251994f5 100644
--- a/indra/newview/lldrawpoolsimple.h
+++ b/indra/newview/lldrawpoolsimple.h
@@ -29,6 +29,8 @@
 
 #include "lldrawpool.h"
 
+class LLGLSLShader;
+
 class LLDrawPoolSimple : public LLRenderPass
 {
 public:
@@ -39,22 +41,17 @@ class LLDrawPoolSimple : public LLRenderPass
 							LLVertexBuffer::MAP_TEXCOORD0 |
 							LLVertexBuffer::MAP_COLOR
 	};
-	virtual U32 getVertexDataMask() { return VERTEX_DATA_MASK; }
+	virtual U32 getVertexDataMask() override { return VERTEX_DATA_MASK; }
 
 	LLDrawPoolSimple();
 	
-	/*virtual*/ S32 getNumDeferredPasses() { return 1; }
-	/*virtual*/ void beginDeferredPass(S32 pass);
-	/*virtual*/ void endDeferredPass(S32 pass);
-	/*virtual*/ void renderDeferred(S32 pass);
+    S32 getNumDeferredPasses() override;
+	void renderDeferred(S32 pass) override;
 
-	/*virtual*/ void beginRenderPass(S32 pass);
-	/*virtual*/ void endRenderPass(S32 pass);
 	/// We need two passes so we can handle emissive materials separately.
-	/*virtual*/ S32	 getNumPasses() { return 1; }
-	/*virtual*/ void render(S32 pass = 0);
-	/*virtual*/ void prerender();
-
+    S32	 getNumPasses() override;
+	void render(S32 pass = 0) override;
+	void prerender() override;
 };
 
 class LLDrawPoolGrass : public LLRenderPass
@@ -99,13 +96,9 @@ class LLDrawPoolAlphaMask : public LLRenderPass
 	LLDrawPoolAlphaMask();
 
 	/*virtual*/ S32 getNumDeferredPasses() { return 1; }
-	/*virtual*/ void beginDeferredPass(S32 pass);
-	/*virtual*/ void endDeferredPass(S32 pass);
 	/*virtual*/ void renderDeferred(S32 pass);
 
 	/*virtual*/ S32	 getNumPasses() { return 1; }
-	/*virtual*/ void beginRenderPass(S32 pass);
-	/*virtual*/ void endRenderPass(S32 pass);
 	/*virtual*/ void render(S32 pass = 0);
 	/*virtual*/ void prerender();
 
@@ -125,13 +118,9 @@ class LLDrawPoolFullbrightAlphaMask : public LLRenderPass
 	LLDrawPoolFullbrightAlphaMask();
 	
 	/*virtual*/ S32 getNumPostDeferredPasses() { return 1; }
-	/*virtual*/ void beginPostDeferredPass(S32 pass);
-	/*virtual*/ void endPostDeferredPass(S32 pass);
 	/*virtual*/ void renderPostDeferred(S32 pass);
 
 	/*virtual*/ S32	 getNumPasses() { return 1; }
-	/*virtual*/ void beginRenderPass(S32 pass);
-	/*virtual*/ void endRenderPass(S32 pass);
 	/*virtual*/ void render(S32 pass = 0);
 	/*virtual*/ void prerender();
 };
@@ -151,12 +140,8 @@ class LLDrawPoolFullbright : public LLRenderPass
 	LLDrawPoolFullbright();
 	
 	/*virtual*/ S32 getNumPostDeferredPasses() { return 1; }
-	/*virtual*/ void beginPostDeferredPass(S32 pass);
-	/*virtual*/ void endPostDeferredPass(S32 pass);
 	/*virtual*/ void renderPostDeferred(S32 pass);
 
-	/*virtual*/ void beginRenderPass(S32 pass);
-	/*virtual*/ void endRenderPass(S32 pass);
 	/*virtual*/ S32	 getNumPasses();
 	/*virtual*/ void render(S32 pass = 0);
 	/*virtual*/ void prerender();
@@ -180,14 +165,13 @@ class LLDrawPoolGlow : public LLRenderPass
 	virtual void prerender() { }
 
 	/*virtual*/ S32 getNumPostDeferredPasses() { return 1; }
-	/*virtual*/ void beginPostDeferredPass(S32 pass); 
-	/*virtual*/ void endPostDeferredPass(S32 pass);
 	/*virtual*/ void renderPostDeferred(S32 pass);
 
+    void render(LLGLSLShader* shader);
+
 	/*virtual*/ S32 getNumPasses();
 
 	void render(S32 pass = 0);
-	void pushBatch(LLDrawInfo& params, U32 mask, BOOL texture = TRUE, BOOL batch_textures = FALSE);
 
 };
 
diff --git a/indra/newview/lldrawpoolsky.cpp b/indra/newview/lldrawpoolsky.cpp
index b6f55e800afe8b21b57723351754763028bb2cd4..3a1efec91b712bc3292af056b0253f28d87fc6c6 100644
--- a/indra/newview/lldrawpoolsky.cpp
+++ b/indra/newview/lldrawpoolsky.cpp
@@ -76,22 +76,8 @@ void LLDrawPoolSky::render(S32 pass)
 	}
 
 
-	if (LLGLSLShader::sNoFixedFunction)
-	{ //just use the UI shader (generic single texture no lighting)
-		gOneTextureNoColorProgram.bind();
-	}
-	else
-	{
-		// don't use shaders!
-		if (gGLManager.mHasShaderObjects)
-		{
-			// Ironically, we must support shader objects to be
-			// able to use this call.
-			LLGLSLShader::bindNoShader();
-		}
-		mShader = NULL;
-	}
-	
+    //just use the UI shader (generic single texture no lighting)
+	gOneTextureNoColorProgram.bind();
 
 	LLGLSPipelineDepthTestSkyBox gls_skybox(true, false);
 
diff --git a/indra/newview/lldrawpoolterrain.cpp b/indra/newview/lldrawpoolterrain.cpp
index 37dc80e2b7d95e9e05c577eae0e94a78ee5d2b28..cc5cb667f0a7df2a77290d209a04d0dcd499beb1 100644
--- a/indra/newview/lldrawpoolterrain.cpp
+++ b/indra/newview/lldrawpoolterrain.cpp
@@ -111,7 +111,7 @@ void LLDrawPoolTerrain::prerender()
 
 void LLDrawPoolTerrain::beginRenderPass( S32 pass )
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_TERRAIN);
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_TERRAIN);
 	LLFacePool::beginRenderPass(pass);
 
 	sShader = LLPipeline::sUnderWaterRender ? 
@@ -126,7 +126,7 @@ void LLDrawPoolTerrain::beginRenderPass( S32 pass )
 
 void LLDrawPoolTerrain::endRenderPass( S32 pass )
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_TERRAIN);
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_TERRAIN);
 	//LLFacePool::endRenderPass(pass);
 
 	if (mShaderLevel > 1 && sShader->mShaderLevel > 0) {
@@ -154,7 +154,7 @@ void LLDrawPoolTerrain::boostTerrainDetailTextures()
 
 void LLDrawPoolTerrain::render(S32 pass)
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_TERRAIN);
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_TERRAIN);
 	
 	if (mDrawFace.empty())
 	{
@@ -213,7 +213,7 @@ void LLDrawPoolTerrain::render(S32 pass)
 
 void LLDrawPoolTerrain::beginDeferredPass(S32 pass)
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_TERRAIN);
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_TERRAIN);
 	LLFacePool::beginRenderPass(pass);
 
 	sShader = LLPipeline::sUnderWaterRender ? &gDeferredTerrainWaterProgram : &gDeferredTerrainProgram;
@@ -223,14 +223,14 @@ void LLDrawPoolTerrain::beginDeferredPass(S32 pass)
 
 void LLDrawPoolTerrain::endDeferredPass(S32 pass)
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_TERRAIN);
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_TERRAIN);
 	LLFacePool::endRenderPass(pass);
 	sShader->unbind();
 }
 
 void LLDrawPoolTerrain::renderDeferred(S32 pass)
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_TERRAIN);
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_TERRAIN);
 	if (mDrawFace.empty())
 	{
 		return;
@@ -250,7 +250,7 @@ void LLDrawPoolTerrain::renderDeferred(S32 pass)
 
 void LLDrawPoolTerrain::beginShadowPass(S32 pass)
 {
-	LL_RECORD_BLOCK_TIME(FTM_SHADOW_TERRAIN);
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_SHADOW_TERRAIN);
 	LLFacePool::beginRenderPass(pass);
 	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 	gDeferredShadowProgram.bind();
@@ -261,14 +261,14 @@ void LLDrawPoolTerrain::beginShadowPass(S32 pass)
 
 void LLDrawPoolTerrain::endShadowPass(S32 pass)
 {
-	LL_RECORD_BLOCK_TIME(FTM_SHADOW_TERRAIN);
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_SHADOW_TERRAIN);
 	LLFacePool::endRenderPass(pass);
 	gDeferredShadowProgram.unbind();
 }
 
 void LLDrawPoolTerrain::renderShadow(S32 pass)
 {
-	LL_RECORD_BLOCK_TIME(FTM_SHADOW_TERRAIN);
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_SHADOW_TERRAIN);
 	if (mDrawFace.empty())
 	{
 		return;
@@ -343,8 +343,6 @@ void LLDrawPoolTerrain::renderFullShader()
 
     LLSettingsWater::ptr_t pwater = LLEnvironment::instance().getCurrentWater();
 
-    ((LLSettingsVOWater*)pwater.get())->updateShader(shader);
-
 	//
 	// detail texture 1
 	//
@@ -469,8 +467,6 @@ void LLDrawPoolTerrain::renderFull4TU()
 	glTexGenfv(GL_S, GL_OBJECT_PLANE, tp0.mV);
 	glTexGenfv(GL_T, GL_OBJECT_PLANE, tp1.mV);
 
-	gGL.getTexUnit(0)->setTextureColorBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_TEX_COLOR);
-
 	//
 	// Stage 1: Generate alpha ramp for detail0/detail1 transition
 	//
@@ -479,10 +475,6 @@ void LLDrawPoolTerrain::renderFull4TU()
 	gGL.getTexUnit(1)->enable(LLTexUnit::TT_TEXTURE);
 	gGL.getTexUnit(1)->activate();
 	
-	// Care about alpha only
-	gGL.getTexUnit(1)->setTextureColorBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_PREV_COLOR);
-	gGL.getTexUnit(1)->setTextureAlphaBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_TEX_ALPHA);
-
 	//
 	// Stage 2: Interpolate detail1 with existing based on ramp
 	//
@@ -497,8 +489,6 @@ void LLDrawPoolTerrain::renderFull4TU()
 	glTexGenfv(GL_S, GL_OBJECT_PLANE, tp0.mV);
 	glTexGenfv(GL_T, GL_OBJECT_PLANE, tp1.mV);
 
-	gGL.getTexUnit(2)->setTextureColorBlend(LLTexUnit::TBO_LERP_PREV_ALPHA, LLTexUnit::TBS_PREV_COLOR, LLTexUnit::TBS_TEX_COLOR);
-
 	//
 	// Stage 3: Modulate with primary (vertex) color for lighting
 	//
@@ -506,9 +496,6 @@ void LLDrawPoolTerrain::renderFull4TU()
 	gGL.getTexUnit(3)->enable(LLTexUnit::TT_TEXTURE);
 	gGL.getTexUnit(3)->activate();
 	
-	// Set alpha texture and do lighting modulation
-	gGL.getTexUnit(3)->setTextureColorBlend(LLTexUnit::TBO_MULT, LLTexUnit::TBS_PREV_COLOR, LLTexUnit::TBS_VERT_COLOR);
-
 	gGL.getTexUnit(0)->activate();
 	
 	// GL_BLEND disabled by default
@@ -529,8 +516,6 @@ void LLDrawPoolTerrain::renderFull4TU()
 	glTexGenfv(GL_S, GL_OBJECT_PLANE, tp0.mV);
 	glTexGenfv(GL_T, GL_OBJECT_PLANE, tp1.mV);
 
-	gGL.getTexUnit(0)->setTextureColorBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_TEX_COLOR);
-
 	//
 	// Stage 1: Generate alpha ramp for detail2/detail3 transition
 	//
@@ -543,10 +528,6 @@ void LLDrawPoolTerrain::renderFull4TU()
 	gGL.loadIdentity();
 	gGL.translatef(-2.f, 0.f, 0.f);
 
-	// Care about alpha only
-	gGL.getTexUnit(1)->setTextureColorBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_PREV_COLOR);
-	gGL.getTexUnit(1)->setTextureAlphaBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_TEX_ALPHA);
-
 	//
 	// Stage 2: Interpolate detail2 with existing based on ramp
 	//
@@ -561,8 +542,6 @@ void LLDrawPoolTerrain::renderFull4TU()
 	glTexGenfv(GL_S, GL_OBJECT_PLANE, tp0.mV);
 	glTexGenfv(GL_T, GL_OBJECT_PLANE, tp1.mV);
 
-	gGL.getTexUnit(2)->setTextureColorBlend(LLTexUnit::TBO_LERP_PREV_ALPHA, LLTexUnit::TBS_TEX_COLOR, LLTexUnit::TBS_PREV_COLOR);	
-
 	//
 	// Stage 3: Generate alpha ramp for detail1/detail2 transition
 	//
@@ -576,10 +555,6 @@ void LLDrawPoolTerrain::renderFull4TU()
 	gGL.translatef(-1.f, 0.f, 0.f);
 	gGL.matrixMode(LLRender::MM_MODELVIEW);
 
-	// Set alpha texture and do lighting modulation
-	gGL.getTexUnit(3)->setTextureColorBlend(LLTexUnit::TBO_MULT, LLTexUnit::TBS_PREV_COLOR, LLTexUnit::TBS_VERT_COLOR);
-	gGL.getTexUnit(3)->setTextureAlphaBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_TEX_ALPHA);
-
 	gGL.getTexUnit(0)->activate();
 	{
 		LLGLEnable blend(GL_BLEND);
@@ -629,8 +604,6 @@ void LLDrawPoolTerrain::renderFull4TU()
 	gGL.matrixMode(LLRender::MM_TEXTURE);
 	gGL.loadIdentity();
 	gGL.matrixMode(LLRender::MM_MODELVIEW);
-
-	gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
 }
 
 void LLDrawPoolTerrain::renderFull2TU()
@@ -669,8 +642,6 @@ void LLDrawPoolTerrain::renderFull2TU()
 	glTexGenfv(GL_S, GL_OBJECT_PLANE, tp0.mV);
 	glTexGenfv(GL_T, GL_OBJECT_PLANE, tp1.mV);
 
-	gGL.getTexUnit(0)->setTextureColorBlend(LLTexUnit::TBO_MULT, LLTexUnit::TBS_TEX_COLOR, LLTexUnit::TBS_VERT_COLOR);
-
 	drawLoop();
 
 	//----------------------------------------------------------------------------
@@ -684,11 +655,6 @@ void LLDrawPoolTerrain::renderFull2TU()
 	glDisable(GL_TEXTURE_GEN_S);
 	glDisable(GL_TEXTURE_GEN_T);
 	
-	// Care about alpha only
-	gGL.getTexUnit(0)->setTextureColorBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_PREV_COLOR);
-	gGL.getTexUnit(0)->setTextureAlphaBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_TEX_ALPHA);
-
-
 	//
 	// Stage 1: Write detail1
 	//
@@ -703,9 +669,6 @@ void LLDrawPoolTerrain::renderFull2TU()
 	glTexGenfv(GL_S, GL_OBJECT_PLANE, tp0.mV);
 	glTexGenfv(GL_T, GL_OBJECT_PLANE, tp1.mV);
 
-	gGL.getTexUnit(1)->setTextureColorBlend(LLTexUnit::TBO_MULT, LLTexUnit::TBS_TEX_COLOR, LLTexUnit::TBS_VERT_COLOR);
-	gGL.getTexUnit(1)->setTextureAlphaBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_PREV_ALPHA);
-
 	gGL.getTexUnit(0)->activate();
 	{
 		LLGLEnable blend(GL_BLEND);
@@ -725,10 +688,6 @@ void LLDrawPoolTerrain::renderFull2TU()
 	gGL.translatef(-1.f, 0.f, 0.f);
 	gGL.matrixMode(LLRender::MM_MODELVIEW);
 
-	// Care about alpha only
-	gGL.getTexUnit(0)->setTextureColorBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_PREV_COLOR);
-	gGL.getTexUnit(0)->setTextureAlphaBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_TEX_ALPHA);
-
 	//
 	// Stage 1: Write detail2
 	//
@@ -743,9 +702,6 @@ void LLDrawPoolTerrain::renderFull2TU()
 	glTexGenfv(GL_S, GL_OBJECT_PLANE, tp0.mV);
 	glTexGenfv(GL_T, GL_OBJECT_PLANE, tp1.mV);
 
-	gGL.getTexUnit(1)->setTextureColorBlend(LLTexUnit::TBO_MULT, LLTexUnit::TBS_TEX_COLOR, LLTexUnit::TBS_VERT_COLOR);
-	gGL.getTexUnit(1)->setTextureAlphaBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_PREV_ALPHA);
-
 	{
 		LLGLEnable blend(GL_BLEND);
 		drawLoop();
@@ -765,10 +721,6 @@ void LLDrawPoolTerrain::renderFull2TU()
 	gGL.translatef(-2.f, 0.f, 0.f);
 	gGL.matrixMode(LLRender::MM_MODELVIEW);
 
-	// Care about alpha only
-	gGL.getTexUnit(0)->setTextureColorBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_PREV_COLOR);
-	gGL.getTexUnit(0)->setTextureAlphaBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_TEX_ALPHA);
-
 	// Stage 1: Write detail3
 	gGL.getTexUnit(1)->bind(detail_texture3p);
 	gGL.getTexUnit(1)->enable(LLTexUnit::TT_TEXTURE);
@@ -781,9 +733,6 @@ void LLDrawPoolTerrain::renderFull2TU()
 	glTexGenfv(GL_S, GL_OBJECT_PLANE, tp0.mV);
 	glTexGenfv(GL_T, GL_OBJECT_PLANE, tp1.mV);
 
-	gGL.getTexUnit(1)->setTextureColorBlend(LLTexUnit::TBO_MULT, LLTexUnit::TBS_TEX_COLOR, LLTexUnit::TBS_VERT_COLOR);
-	gGL.getTexUnit(1)->setTextureAlphaBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_PREV_ALPHA);
-
 	gGL.getTexUnit(0)->activate();
 	{
 		LLGLEnable blend(GL_BLEND);
@@ -816,7 +765,6 @@ void LLDrawPoolTerrain::renderFull2TU()
 	gGL.matrixMode(LLRender::MM_TEXTURE);
 	gGL.loadIdentity();
 	gGL.matrixMode(LLRender::MM_MODELVIEW);
-	gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
 }
 
 
@@ -839,22 +787,8 @@ void LLDrawPoolTerrain::renderSimple()
 	tp0.setVec(tscale, 0.f, 0.0f, -1.f*(origin_agent.mV[0]/256.f));
 	tp1.setVec(0.f, tscale, 0.0f, -1.f*(origin_agent.mV[1]/256.f));
 	
-	if (LLGLSLShader::sNoFixedFunction)
-	{
-		sShader->uniform4fv(LLShaderMgr::OBJECT_PLANE_S, 1, tp0.mV);
-		sShader->uniform4fv(LLShaderMgr::OBJECT_PLANE_T, 1, tp1.mV);
-	}
-	else
-	{
-		glEnable(GL_TEXTURE_GEN_S);
-		glEnable(GL_TEXTURE_GEN_T);
-		glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
-		glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
-		glTexGenfv(GL_S, GL_OBJECT_PLANE, tp0.mV);
-		glTexGenfv(GL_T, GL_OBJECT_PLANE, tp1.mV);
-	}
-
-	gGL.getTexUnit(0)->setTextureColorBlend(LLTexUnit::TBO_MULT, LLTexUnit::TBS_TEX_COLOR, LLTexUnit::TBS_VERT_COLOR);
+	sShader->uniform4fv(LLShaderMgr::OBJECT_PLANE_S, 1, tp0.mV);
+	sShader->uniform4fv(LLShaderMgr::OBJECT_PLANE_T, 1, tp1.mV);
 
 	drawLoop();
 
@@ -863,15 +797,9 @@ void LLDrawPoolTerrain::renderSimple()
 	
 	gGL.getTexUnit(0)->activate();
 	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
-	if (!LLGLSLShader::sNoFixedFunction)
-	{
-		glDisable(GL_TEXTURE_GEN_S);
-		glDisable(GL_TEXTURE_GEN_T);
-	}
 	gGL.matrixMode(LLRender::MM_TEXTURE);
 	gGL.loadIdentity();
 	gGL.matrixMode(LLRender::MM_MODELVIEW);
-	gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
 }
 
 //============================================================================
@@ -922,6 +850,7 @@ void LLDrawPoolTerrain::renderOwnership()
 
 void LLDrawPoolTerrain::dirtyTextures(const std::set<LLViewerFetchedTexture*>& textures)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
 	LLViewerFetchedTexture* tex = LLViewerTextureManager::staticCastToFetchedTexture(mTexturep) ;
 	if (tex && textures.find(tex) != textures.end())
 	{
diff --git a/indra/newview/lldrawpooltree.cpp b/indra/newview/lldrawpooltree.cpp
index 0d5195bdbfcd67211519270c39e3d029658905ed..facfb235c914e09caf964c56ceb6a4ca0ee37fda 100644
--- a/indra/newview/lldrawpooltree.cpp
+++ b/indra/newview/lldrawpooltree.cpp
@@ -42,7 +42,6 @@
 
 S32 LLDrawPoolTree::sDiffTex = 0;
 static LLGLSLShader* shader = NULL;
-static LLTrace::BlockTimerStatHandle FTM_SHADOW_TREE("Tree Shadow");
 
 LLDrawPoolTree::LLDrawPoolTree(LLViewerTexture *texturep) :
 	LLFacePool(POOL_TREE),
@@ -69,7 +68,7 @@ void LLDrawPoolTree::beginRenderPass(S32 pass)
 		shader = &gTreeProgram;
 	}
 
-	if (gPipeline.canUseVertexShaders())
+	if (gPipeline.shadersLoaded())
 	{
 		shader->bind();
 		shader->setMinimumAlpha(0.5f);
@@ -78,23 +77,24 @@ void LLDrawPoolTree::beginRenderPass(S32 pass)
 	else
 	{
 		gPipeline.enableLightsDynamic();
-		gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.5f);
+		gGL.flush();
 	}
 }
 
 void LLDrawPoolTree::render(S32 pass)
 {
-	LL_RECORD_BLOCK_TIME(LLPipeline::sShadowRender ? FTM_SHADOW_TREE : FTM_RENDER_TREES);
+    LL_PROFILE_ZONE_SCOPED;
 
 	if (mDrawFace.empty())
 	{
 		return;
 	}
 
-	LLGLState test(GL_ALPHA_TEST, LLGLSLShader::sNoFixedFunction ? 0 : 1);
+	LLGLState test(GL_ALPHA_TEST, 0);
+
+	gGL.getTexUnit(sDiffTex)->bindFast(mTexturep);
+    gPipeline.touchTexture(mTexturep, 1024.f * 1024.f); // <=== keep Linden tree textures at full res
 
-	gGL.getTexUnit(sDiffTex)->bind(mTexturep);
-				
 	for (std::vector<LLFace*>::iterator iter = mDrawFace.begin();
 		 iter != mDrawFace.end(); iter++)
 	{
@@ -117,9 +117,8 @@ void LLDrawPoolTree::render(S32 pass)
 				gPipeline.mMatrixOpCount++;
 			}
 
-			buff->setBuffer(LLDrawPoolTree::VERTEX_DATA_MASK);
-			buff->drawRange(LLRender::TRIANGLES, 0, buff->getNumVerts()-1, buff->getNumIndices(), 0); 
-			gPipeline.addTrianglesDrawn(buff->getNumIndices());
+			buff->setBufferFast(LLDrawPoolTree::VERTEX_DATA_MASK);
+			buff->drawRangeFast(LLRender::TRIANGLES, 0, buff->getNumVerts()-1, buff->getNumIndices(), 0); 
 		}
 	}
 }
@@ -135,7 +134,7 @@ void LLDrawPoolTree::endRenderPass(S32 pass)
 	
 	if (mShaderLevel <= 0)
 	{
-		gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
+        gGL.flush();
 	}
 }
 
@@ -153,6 +152,7 @@ void LLDrawPoolTree::beginDeferredPass(S32 pass)
 
 void LLDrawPoolTree::renderDeferred(S32 pass)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	render(pass);
 }
 
@@ -168,7 +168,7 @@ void LLDrawPoolTree::endDeferredPass(S32 pass)
 //============================================
 void LLDrawPoolTree::beginShadowPass(S32 pass)
 {
-	LL_RECORD_BLOCK_TIME(FTM_SHADOW_TREE);
+    LL_PROFILE_ZONE_SCOPED;
 	
 	glPolygonOffset(gSavedSettings.getF32("RenderDeferredTreeShadowOffset"),
 					gSavedSettings.getF32("RenderDeferredTreeShadowBias"));
@@ -187,7 +187,7 @@ void LLDrawPoolTree::renderShadow(S32 pass)
 
 void LLDrawPoolTree::endShadowPass(S32 pass)
 {
-	LL_RECORD_BLOCK_TIME(FTM_SHADOW_TREE);
+    LL_PROFILE_ZONE_SCOPED;
 	
 	glPolygonOffset(gSavedSettings.getF32("RenderDeferredSpotShadowOffset"),
 						gSavedSettings.getF32("RenderDeferredSpotShadowBias"));
diff --git a/indra/newview/lldrawpoolwater.cpp b/indra/newview/lldrawpoolwater.cpp
index aa426cd785667714b3d2928a06bb0ea1ab658f88..a84f62036e45c9739d4b0f60b5f4ec9e85405711 100644
--- a/indra/newview/lldrawpoolwater.cpp
+++ b/indra/newview/lldrawpoolwater.cpp
@@ -50,8 +50,6 @@
 #include "llsettingssky.h"
 #include "llsettingswater.h"
 
-static float sTime;
-
 BOOL deferred_render = FALSE;
 
 BOOL LLDrawPoolWater::sSkipScreenCopy = FALSE;
@@ -136,9 +134,17 @@ void LLDrawPoolWater::endPostDeferredPass(S32 pass)
 //===============================
 void LLDrawPoolWater::renderDeferred(S32 pass)
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_WATER);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_WATER);
+
+    if (!LLPipeline::sRenderTransparentWater)
+    {
+        // Will render opaque water without use of ALM
+        render(pass);
+        return;
+    }
+
 	deferred_render = TRUE;
-	shade();
+	renderWater();
 	deferred_render = FALSE;
 }
 
@@ -146,7 +152,7 @@ void LLDrawPoolWater::renderDeferred(S32 pass)
 
 void LLDrawPoolWater::render(S32 pass)
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_WATER);
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_WATER);
 	if (mDrawFace.empty() || LLDrawable::getCurrentFrame() <= 1)
 	{
 		return;
@@ -174,7 +180,7 @@ void LLDrawPoolWater::render(S32 pass)
 
 	if ((mShaderLevel > 0) && !sSkipScreenCopy)
 	{
-		shade();
+		renderWater();
 		return;
 	}
 
@@ -233,9 +239,6 @@ void LLDrawPoolWater::render(S32 pass)
 	glTexGenfv(GL_S, GL_OBJECT_PLANE, tp0);
 	glTexGenfv(GL_T, GL_OBJECT_PLANE, tp1);
 
-	gGL.getTexUnit(1)->setTextureColorBlend(LLTexUnit::TBO_MULT, LLTexUnit::TBS_TEX_COLOR, LLTexUnit::TBS_PREV_COLOR);
-	gGL.getTexUnit(1)->setTextureAlphaBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_PREV_ALPHA);
-
 	gGL.getTexUnit(0)->activate();
 	
 	glClearStencil(1);
@@ -293,8 +296,6 @@ void LLDrawPoolWater::render(S32 pass)
 		gGL.matrixMode(LLRender::MM_MODELVIEW);
 		LLOverrideFaceColor overrid(this, 1.f, 1.f, 1.f,  0.5f*up_dot);
 
-		gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
-
 		for (std::vector<LLFace*>::iterator iter = mDrawFace.begin();
 			 iter != mDrawFace.end(); iter++)
 		{
@@ -311,8 +312,6 @@ void LLDrawPoolWater::render(S32 pass)
 			}
 		}
 
-		gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
-
 		gSky.mVOSkyp->getCubeMap()->disable();
 		
 		gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
@@ -330,30 +329,31 @@ void LLDrawPoolWater::render(S32 pass)
 		glStencilFunc(GL_NOTEQUAL, 0, 0xFFFFFFFF);
 		renderReflection(refl_face);
 	}
-
-	gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
 }
 
 // for low end hardware
 void LLDrawPoolWater::renderOpaqueLegacyWater()
 {
-	LLVOSky *voskyp = gSky.mVOSkyp;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
+    LLVOSky *voskyp = gSky.mVOSkyp;
+
+    if (voskyp == NULL)
+    {
+        return;
+    }
 
 	LLGLSLShader* shader = NULL;
-	if (LLGLSLShader::sNoFixedFunction)
+	if (LLPipeline::sUnderWaterRender)
 	{
-		if (LLPipeline::sUnderWaterRender)
-		{
-			shader = &gObjectSimpleNonIndexedTexGenWaterProgram;
-		}
-		else
-		{
-			shader = &gObjectSimpleNonIndexedTexGenProgram;
-		}
-
-		shader->bind();
+		shader = &gObjectSimpleNonIndexedTexGenWaterProgram;
+	}
+	else
+	{
+		shader = &gObjectSimpleNonIndexedTexGenProgram;
 	}
 
+	shader->bind();
+
 	stop_glerror();
 
 	// Depth sorting and write to depth buffer
@@ -438,12 +438,12 @@ void LLDrawPoolWater::renderOpaqueLegacyWater()
 	}
 
 	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
-	gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
 }
 
 
 void LLDrawPoolWater::renderReflection(LLFace* face)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
 	LLVOSky *voskyp = gSky.mVOSkyp;
 
 	if (!voskyp)
@@ -470,330 +470,236 @@ void LLDrawPoolWater::renderReflection(LLFace* face)
 	face->renderIndexed();
 }
 
-void LLDrawPoolWater::shade2(bool edge, LLGLSLShader* shader, const LLColor3& light_diffuse, const LLVector3& light_dir, F32 light_exp)
+void LLDrawPoolWater::renderWater()
 {
-    F32  water_height  = LLEnvironment::instance().getWaterHeight(); 
-    F32  camera_height = LLViewerCamera::getInstance()->getOrigin().mV[2];
-    F32  eyedepth      = camera_height - water_height;
-    bool underwater    = eyedepth <= 0.0f;
-
-    LLEnvironment& environment = LLEnvironment::instance();
-    LLSettingsWater::ptr_t pwater = environment.getCurrentWater();
-    LLSettingsSky::ptr_t   psky   = environment.getCurrentSky();
-
-    shader->bind();
-
-// bind textures for water rendering
-	if (deferred_render)
-	{
-        if (shader->getUniformLocation(LLShaderMgr::DEFERRED_NORM_MATRIX) >= 0)
-	    {
-		    glh::matrix4f norm_mat = get_current_modelview().inverse().transpose();
-		    shader->uniformMatrix4fv(LLShaderMgr::DEFERRED_NORM_MATRIX, 1, FALSE, norm_mat.m);
-	    }
-	}
-
-    LLColor4 specular(psky->getIsSunUp() ? psky->getSunlightColor() : psky->getMoonlightColor());
-    shader->uniform4fv(LLShaderMgr::SPECULAR_COLOR, 1, specular.mV);
-
-	sTime = (F32)LLFrameTimer::getElapsedSeconds() * 0.5f;
-	
-	S32 reftex = shader->enableTexture(LLShaderMgr::WATER_REFTEX);
-		
-	if (reftex > -1)
-	{
-		gGL.getTexUnit(reftex)->activate();
-		gGL.getTexUnit(reftex)->bind(&gPipeline.mWaterRef);
-		gGL.getTexUnit(0)->activate();
-	}	
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
+    if (!deferred_render)
+    {
+        gGL.setColorMask(true, true);
+    }
 
-	//bind normal map
-	S32 bumpTex  = shader->enableTexture(LLViewerShaderMgr::BUMP_MAP);
-    S32 bumpTex2 = shader->enableTexture(LLViewerShaderMgr::BUMP_MAP2);
+    LLGLDisable blend(GL_BLEND);
 
-    LLViewerTexture* tex_a = mWaterNormp[0];
-    LLViewerTexture* tex_b = mWaterNormp[1];
+    LLColor3 light_diffuse(0, 0, 0);
+    F32      light_exp = 0.0f;
 
-    F32 blend_factor = LLEnvironment::instance().getCurrentWater()->getBlendFactor();
-	
-    gGL.getTexUnit(bumpTex)->unbind(LLTexUnit::TT_TEXTURE);
-    gGL.getTexUnit(bumpTex2)->unbind(LLTexUnit::TT_TEXTURE);
+    LLEnvironment &        environment     = LLEnvironment::instance();
+    LLSettingsWater::ptr_t pwater          = environment.getCurrentWater();
+    LLSettingsSky::ptr_t   psky            = environment.getCurrentSky();
+    LLVector3              light_dir       = environment.getLightDirection();
+    bool                   sun_up          = environment.getIsSunUp();
+    bool                   moon_up         = environment.getIsMoonUp();
+    bool                   has_normal_mips = gSavedSettings.getBOOL("RenderWaterMipNormal");
+    bool                   underwater      = LLViewerCamera::getInstance()->cameraUnderWater();
 
-    if (tex_a && (!tex_b || (tex_a == tex_b)))
+    if (sun_up)
     {
-		gGL.getTexUnit(bumpTex)->bind(tex_a);
-        blend_factor = 0; // only one tex provided, no blending
+        light_diffuse += psky->getSunlightColor();
     }
-    else if (tex_b && !tex_a)
+    // moonlight is several orders of magnitude less bright than sunlight,
+    // so only use this color when the moon alone is showing
+    else if (moon_up)
     {
-        gGL.getTexUnit(bumpTex)->bind(tex_b);
-        blend_factor = 0; // only one tex provided, no blending
+        light_diffuse += psky->getMoonlightColor();
     }
-    else if (tex_b != tex_a)
+
+    // Apply magic numbers translating light direction into intensities
+    light_dir.normalize();
+    F32 ground_proj_sq = light_dir.mV[0] * light_dir.mV[0] + light_dir.mV[1] * light_dir.mV[1];
+    light_exp          = llmax(32.f, 256.f * powf(ground_proj_sq, 16.0f));
+    if (0.f < light_diffuse.normalize())  // Normalizing a color? Puzzling...
     {
-        gGL.getTexUnit(bumpTex)->bind(tex_a);
-        gGL.getTexUnit(bumpTex2)->bind(tex_b);
+        light_diffuse *= (1.5f + (6.f * ground_proj_sq));
     }
-	
-    // bind reflection texture from RenderTarget
-	S32 screentex = shader->enableTexture(LLShaderMgr::WATER_SCREENTEX);
-	F32 screenRes[] = 
-	{
-		1.f/gGLViewport[2],
-		1.f/gGLViewport[3]
-	};
-		
-	S32 diffTex = shader->enableTexture(LLShaderMgr::DIFFUSE_MAP);
-	stop_glerror();
-
-// set uniforms for water rendering
-    shader->uniform2fv(LLShaderMgr::DEFERRED_SCREEN_RES, 1, screenRes);
-    shader->uniform1f(LLShaderMgr::BLEND_FACTOR, blend_factor);
 
-    LLColor4 fog_color(pwater->getWaterFogColor(), 0.0f);
-    F32      fog_density = pwater->getModifiedWaterFogDensity(underwater);
-
-    if (screentex > -1)
-	{
-		shader->uniform1f(LLShaderMgr::WATER_FOGDENSITY, fog_density);
-		gGL.getTexUnit(screentex)->bind(&gPipeline.mWaterDis);
-	}
-    
-    if (mShaderLevel == 1)
+    // set up normal maps filtering
+    for (auto norm_map : mWaterNormp)
     {
-        //F32 fog_density_slider_value = param_mgr->mDensitySliderValue;
-		//sWaterFogColor.mV[3] = fog_density_slider_value;
-        fog_color.mV[VW] = log(fog_density) / log(2);
-	}
+        if (norm_map) norm_map->setFilteringOption(has_normal_mips ? LLTexUnit::TFO_ANISOTROPIC : LLTexUnit::TFO_POINT);
+    }
 
-    shader->uniform4fv(LLShaderMgr::WATER_FOGCOLOR, 1, fog_color.mV);
+    LLColor4      specular(sun_up ? psky->getSunlightColor() : psky->getMoonlightColor());
+    F32           phase_time = (F32) LLFrameTimer::getElapsedSeconds() * 0.5f;
+    LLGLSLShader *shader     = nullptr;
 
-	//shader->uniformMatrix4fv("inverse_ref", 1, GL_FALSE, (GLfloat*) gGLObliqueProjectionInverse.mMatrix);
-	shader->uniform1f(LLShaderMgr::WATER_WATERHEIGHT, eyedepth);
-	shader->uniform1f(LLShaderMgr::WATER_TIME, sTime);
-	shader->uniform3fv(LLShaderMgr::WATER_EYEVEC, 1, LLViewerCamera::getInstance()->getOrigin().mV);
-	shader->uniform3fv(LLShaderMgr::WATER_SPECULAR, 1, light_diffuse.mV);
-	shader->uniform1f(LLShaderMgr::WATER_SPECULAR_EXP, light_exp);
-    if (LLEnvironment::instance().isCloudScrollPaused())
-    {
-        static const std::array<F32, 2> zerowave{ {0.0f, 0.0f} };
-        
-        shader->uniform2fv(LLShaderMgr::WATER_WAVE_DIR1, 1, zerowave.data());
-        shader->uniform2fv(LLShaderMgr::WATER_WAVE_DIR2, 1, zerowave.data());
-    }
-    else
+    // two passes, first with standard water shader bound, second with edge water shader bound
+    for( int edge = 0 ; edge < 2; edge++ )
     {
-        shader->uniform2fv(LLShaderMgr::WATER_WAVE_DIR1, 1, pwater->getWave1Dir().mV);
-        shader->uniform2fv(LLShaderMgr::WATER_WAVE_DIR2, 1, pwater->getWave2Dir().mV);
-    }
-	shader->uniform3fv(LLShaderMgr::WATER_LIGHT_DIR, 1, light_dir.mV);
+        // select shader
+        if (underwater && LLPipeline::sWaterReflections)
+        {
+            shader = deferred_render ? &gDeferredUnderWaterProgram : &gUnderWaterProgram;
+        }
+        else
+        {
+            if (edge && !deferred_render)
+            {
+                shader = &gWaterEdgeProgram;
+            }
+            else
+            {
+                shader = deferred_render ? &gDeferredWaterProgram : &gWaterProgram;
+            }
+        }
+        shader->bind();
 
-	shader->uniform3fv(LLShaderMgr::WATER_NORM_SCALE, 1, pwater->getNormalScale().mV);
-	shader->uniform1f(LLShaderMgr::WATER_FRESNEL_SCALE, pwater->getFresnelScale());
-	shader->uniform1f(LLShaderMgr::WATER_FRESNEL_OFFSET, pwater->getFresnelOffset());
-    shader->uniform1f(LLShaderMgr::WATER_BLUR_MULTIPLIER, pwater->getBlurMultiplier());
+        // bind textures for water rendering
+        S32 reftex = shader->enableTexture(LLShaderMgr::WATER_REFTEX);
+        if (reftex > -1)
+        {
+            gGL.getTexUnit(reftex)->activate();
+            gGL.getTexUnit(reftex)->bind(&gPipeline.mWaterRef);
+            gGL.getTexUnit(0)->activate();
+        }
 
-	F32 sunAngle = llmax(0.f, light_dir.mV[1]);
-	F32 scaledAngle = 1.f - sunAngle;
+        // bind normal map
+        S32 bumpTex  = shader->enableTexture(LLViewerShaderMgr::BUMP_MAP);
+        S32 bumpTex2 = shader->enableTexture(LLViewerShaderMgr::BUMP_MAP2);
 
-    shader->uniform1i(LLShaderMgr::SUN_UP_FACTOR, environment.getIsSunUp() ? 1 : 0);
-	shader->uniform1f(LLShaderMgr::WATER_SUN_ANGLE, sunAngle);
-	shader->uniform1f(LLShaderMgr::WATER_SCALED_ANGLE, scaledAngle);
-	shader->uniform1f(LLShaderMgr::WATER_SUN_ANGLE2, 0.1f + 0.2f*sunAngle);
-    shader->uniform1i(LLShaderMgr::WATER_EDGE_FACTOR, edge ? 1 : 0);
+        LLViewerTexture *tex_a = mWaterNormp[0];
+        LLViewerTexture *tex_b = mWaterNormp[1];
 
-    LLVector4 rotated_light_direction = LLEnvironment::instance().getRotatedLightNorm();
-    shader->uniform4fv(LLViewerShaderMgr::LIGHTNORM, 1, rotated_light_direction.mV);
-    shader->uniform3fv(LLShaderMgr::WL_CAMPOSLOCAL, 1, LLViewerCamera::getInstance()->getOrigin().mV);
+        F32 blend_factor = pwater->getBlendFactor();
 
-	if (LLViewerCamera::getInstance()->cameraUnderWater())
-	{
-		shader->uniform1f(LLShaderMgr::WATER_REFSCALE, pwater->getScaleBelow());
-	}
-	else
-	{
-		shader->uniform1f(LLShaderMgr::WATER_REFSCALE, pwater->getScaleAbove());
-	}
+        gGL.getTexUnit(bumpTex)->unbind(LLTexUnit::TT_TEXTURE);
+        gGL.getTexUnit(bumpTex2)->unbind(LLTexUnit::TT_TEXTURE);
 
-	{		
-		LLGLDisable cullface(GL_CULL_FACE);
-
-        if (edge)
+        if (tex_a && (!tex_b || (tex_a == tex_b)))
         {
-            for (std::vector<LLFace*>::iterator iter = mDrawFace.begin(); iter != mDrawFace.end(); iter++)
-		    {
-			    LLFace *face = *iter;
-                if (face)
-                {
-                    LLVOWater* water = (LLVOWater*) face->getViewerObject();
-			        gGL.getTexUnit(diffTex)->bind(face->getTexture());
-
-                    if (water)
-                    {
-                        bool edge_patch = water->getIsEdgePatch();
-                        if (edge_patch)
-                        {
-                            //sNeedsReflectionUpdate = TRUE;
-                            face->renderIndexed();
-                        }
-                    }
-                }
-		    }
+            gGL.getTexUnit(bumpTex)->bind(tex_a);
+            blend_factor = 0;  // only one tex provided, no blending
         }
-        else
+        else if (tex_b && !tex_a)
         {
-            for (std::vector<LLFace*>::iterator iter = mDrawFace.begin(); iter != mDrawFace.end(); iter++)
-		    {
-			    LLFace *face = *iter;
-                if (face)
-                {
-                    LLVOWater* water = (LLVOWater*) face->getViewerObject();
-			        gGL.getTexUnit(diffTex)->bind(face->getTexture());
-
-                    if (water)
-                    {
-                        bool edge_patch = water->getIsEdgePatch();
-                        if (!edge_patch)
-                        {
-                            sNeedsReflectionUpdate = TRUE;
-                            sNeedsDistortionUpdate = TRUE;
-                            face->renderIndexed();
-                        }
-                    }
-                }
-		    }
+            gGL.getTexUnit(bumpTex)->bind(tex_b);
+            blend_factor = 0;  // only one tex provided, no blending
+        }
+        else if (tex_b != tex_a)
+        {
+            gGL.getTexUnit(bumpTex)->bind(tex_a);
+            gGL.getTexUnit(bumpTex2)->bind(tex_b);
         }
-    }
-
-    gGL.getTexUnit(bumpTex)->unbind(LLTexUnit::TT_TEXTURE);
-    gGL.getTexUnit(bumpTex2)->unbind(LLTexUnit::TT_TEXTURE);
 
-	shader->disableTexture(LLShaderMgr::ENVIRONMENT_MAP, LLTexUnit::TT_CUBE_MAP);
-	shader->disableTexture(LLShaderMgr::WATER_SCREENTEX);	
-	shader->disableTexture(LLShaderMgr::BUMP_MAP);
-	shader->disableTexture(LLShaderMgr::DIFFUSE_MAP);
-	shader->disableTexture(LLShaderMgr::WATER_REFTEX);
-	shader->disableTexture(LLShaderMgr::WATER_SCREENDEPTH);
+        // bind reflection texture from RenderTarget
+        S32 screentex   = shader->enableTexture(LLShaderMgr::WATER_SCREENTEX);
+        F32 screenRes[] = {1.f / gGLViewport[2], 1.f / gGLViewport[3]};
 
-	shader->unbind();
-}
+        S32 diffTex = shader->enableTexture(LLShaderMgr::DIFFUSE_MAP);
 
-void LLDrawPoolWater::shade()
-{
-	if (!deferred_render)
-	{
-		gGL.setColorMask(true, true);
-	}
+        // set uniforms for shader
+        if (deferred_render)
+        {
+            if (shader->getUniformLocation(LLShaderMgr::DEFERRED_NORM_MATRIX) >= 0)
+            {
+                glh::matrix4f norm_mat = get_current_modelview().inverse().transpose();
+                shader->uniformMatrix4fv(LLShaderMgr::DEFERRED_NORM_MATRIX, 1, FALSE, norm_mat.m);
+            }
+        }
 
-	LLVOSky *voskyp = gSky.mVOSkyp;
+        shader->uniform2fv(LLShaderMgr::DEFERRED_SCREEN_RES, 1, screenRes);
+        shader->uniform1f(LLShaderMgr::BLEND_FACTOR, blend_factor);
 
-	if(voskyp == NULL) 
-	{
-		return;
-	}
+        LLColor4 fog_color(pwater->getWaterFogColor(), 0.0f);
+        F32      fog_density = pwater->getModifiedWaterFogDensity(underwater);
 
-	LLGLDisable blend(GL_BLEND);
+        if (screentex > -1)
+        {
+            shader->uniform1f(LLShaderMgr::WATER_FOGDENSITY, fog_density);
+            gGL.getTexUnit(screentex)->bind(&gPipeline.mWaterDis);
+        }
 
-	LLColor3 light_diffuse(0,0,0);
-	F32 light_exp = 0.0f;
-	LLVector3 light_dir;
+        if (mShaderLevel == 1)
+        {
+            fog_color.mV[VW] = log(fog_density) / log(2);
+        }
 
-    LLEnvironment& environment = LLEnvironment::instance();
-    LLSettingsWater::ptr_t pwater = environment.getCurrentWater();
-    LLSettingsSky::ptr_t   psky   = environment.getCurrentSky();
+        F32 water_height  = environment.getWaterHeight();
+        F32 camera_height = LLViewerCamera::getInstance()->getOrigin().mV[2];
+        shader->uniform1f(LLShaderMgr::WATER_WATERHEIGHT, camera_height - water_height);
+        shader->uniform1f(LLShaderMgr::WATER_TIME, phase_time);
+        shader->uniform3fv(LLShaderMgr::WATER_EYEVEC, 1, LLViewerCamera::getInstance()->getOrigin().mV);
 
-    light_dir = environment.getLightDirection();
-    light_dir.normalize();
+        shader->uniform4fv(LLShaderMgr::SPECULAR_COLOR, 1, specular.mV);
+        shader->uniform4fv(LLShaderMgr::WATER_FOGCOLOR, 1, fog_color.mV);
 
-    bool sun_up  = environment.getIsSunUp();
-    bool moon_up = environment.getIsMoonUp();
+        shader->uniform3fv(LLShaderMgr::WATER_SPECULAR, 1, light_diffuse.mV);
+        shader->uniform1f(LLShaderMgr::WATER_SPECULAR_EXP, light_exp);
 
-    if (sun_up)
-    {
-        light_diffuse += voskyp->getSun().getColorCached();
-    }
-    // moonlight is several orders of magnitude less bright than sunlight,
-    // so only use this color when the moon alone is showing
-    else if (moon_up)
-    {        
-        light_diffuse += psky->getMoonDiffuse(); 
-    }
+        shader->uniform2fv(LLShaderMgr::WATER_WAVE_DIR1, 1, pwater->getWave1Dir().mV);
+        shader->uniform2fv(LLShaderMgr::WATER_WAVE_DIR2, 1, pwater->getWave2Dir().mV);
 
-    light_exp = light_dir * LLVector3(light_dir.mV[0], light_dir.mV[1], 0.f);
+        shader->uniform3fv(LLShaderMgr::WATER_LIGHT_DIR, 1, light_dir.mV);
 
-    light_diffuse.normalize();
-    light_diffuse *= (light_exp + 0.25f);
+        shader->uniform3fv(LLShaderMgr::WATER_NORM_SCALE, 1, pwater->getNormalScale().mV);
+        shader->uniform1f(LLShaderMgr::WATER_FRESNEL_SCALE, pwater->getFresnelScale());
+        shader->uniform1f(LLShaderMgr::WATER_FRESNEL_OFFSET, pwater->getFresnelOffset());
+        shader->uniform1f(LLShaderMgr::WATER_BLUR_MULTIPLIER, pwater->getBlurMultiplier());
 
-	light_exp *= light_exp;
-	light_exp *= light_exp;
-	light_exp *= light_exp;
-	light_exp *= light_exp;
-	light_exp *= 256.f;
-	light_exp = light_exp > 32.f ? light_exp : 32.f;
+        F32 sunAngle    = llmax(0.f, light_dir.mV[1]);
+        F32 scaledAngle = 1.f - sunAngle;
 
-    light_diffuse *= 6.f;
+        shader->uniform1i(LLShaderMgr::SUN_UP_FACTOR, sun_up ? 1 : 0);
+        shader->uniform1f(LLShaderMgr::WATER_SUN_ANGLE, sunAngle);
+        shader->uniform1f(LLShaderMgr::WATER_SCALED_ANGLE, scaledAngle);
+        shader->uniform1f(LLShaderMgr::WATER_SUN_ANGLE2, 0.1f + 0.2f * sunAngle);
+        shader->uniform1i(LLShaderMgr::WATER_EDGE_FACTOR, edge ? 1 : 0);
 
-	LLGLSLShader* shader = nullptr;
-    LLGLSLShader* edge_shader = nullptr;
+        LLVector4 rotated_light_direction = LLEnvironment::instance().getRotatedLightNorm();
+        shader->uniform4fv(LLViewerShaderMgr::LIGHTNORM, 1, rotated_light_direction.mV);
+        shader->uniform3fv(LLShaderMgr::WL_CAMPOSLOCAL, 1, LLViewerCamera::getInstance()->getOrigin().mV);
 
-	F32 eyedepth = LLViewerCamera::getInstance()->getOrigin().mV[2] - LLEnvironment::instance().getWaterHeight();
-	
-	if (eyedepth < 0.f && LLPipeline::sWaterReflections)
-	{
-	    if (deferred_render)
-	    {
-            shader = &gDeferredUnderWaterProgram;
-	    }
-		else
+        if (LLViewerCamera::getInstance()->cameraUnderWater())
         {
-	        shader = &gUnderWaterProgram;
+            shader->uniform1f(LLShaderMgr::WATER_REFSCALE, pwater->getScaleBelow());
+        }
+        else
+        {
+            shader->uniform1f(LLShaderMgr::WATER_REFSCALE, pwater->getScaleAbove());
         }
-	}
-	else if (deferred_render)
-	{
-		shader = &gDeferredWaterProgram;
-        edge_shader = nullptr;
-	}
-	else
-	{
-		shader = &gWaterProgram;
-        edge_shader = &gWaterEdgeProgram;
-	}
 
-    if (mWaterNormp[0])
-    {
-	    if (gSavedSettings.getBOOL("RenderWaterMipNormal"))
-	    {
-		    mWaterNormp[0]->setFilteringOption(LLTexUnit::TFO_ANISOTROPIC);
-	    }
-	    else 
-	    {
-		    mWaterNormp[0]->setFilteringOption(LLTexUnit::TFO_POINT);
-	    }
-	}
+        LLGLDisable cullface(GL_CULL_FACE);
 
-    if (mWaterNormp[1])
-    {
-	    if (gSavedSettings.getBOOL("RenderWaterMipNormal"))
-	    {
-            mWaterNormp[1]->setFilteringOption(LLTexUnit::TFO_ANISOTROPIC);
-	    }
-	    else 
-	    {
-            mWaterNormp[1]->setFilteringOption(LLTexUnit::TFO_POINT);
-	    }
-	}
+        LLVOWater *water = nullptr;
+        for (LLFace *const &face : mDrawFace)
+        {
+            if (!face) continue;
+            water = static_cast<LLVOWater *>(face->getViewerObject());
+            if (!water) continue;
 
-    shade2(false, shader, light_diffuse, light_dir, light_exp);
-    shade2(true, edge_shader ? edge_shader : shader, light_diffuse, light_dir, light_exp);
+            gGL.getTexUnit(diffTex)->bind(face->getTexture());
 
-	gGL.getTexUnit(0)->activate();
-	gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE);
-	if (!deferred_render)
-	{
-		gGL.setColorMask(true, false);
-	}
+            if ((bool)edge == (bool) water->getIsEdgePatch())
+            {
+                face->renderIndexed();
 
+                // Note non-void water being drawn, updates required
+                if (!edge)  // SL-16461 remove !LLPipeline::sUseOcclusion check
+                {
+                    sNeedsReflectionUpdate = TRUE;
+                    sNeedsDistortionUpdate = TRUE;
+                }
+            }
+        }
+
+        shader->disableTexture(LLShaderMgr::ENVIRONMENT_MAP, LLTexUnit::TT_CUBE_MAP);
+        shader->disableTexture(LLShaderMgr::WATER_SCREENTEX);
+        shader->disableTexture(LLShaderMgr::BUMP_MAP);
+        shader->disableTexture(LLShaderMgr::DIFFUSE_MAP);
+        shader->disableTexture(LLShaderMgr::WATER_REFTEX);
+        shader->disableTexture(LLShaderMgr::WATER_SCREENDEPTH);
+
+        // clean up
+        shader->unbind();
+        gGL.getTexUnit(bumpTex)->unbind(LLTexUnit::TT_TEXTURE);
+        gGL.getTexUnit(bumpTex2)->unbind(LLTexUnit::TT_TEXTURE);
+    }
+
+    gGL.getTexUnit(0)->activate();
+    gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE);
+    if (!deferred_render)
+    {
+        gGL.setColorMask(true, false);
+    }
 }
 
 LLViewerTexture *LLDrawPoolWater::getDebugTexture()
diff --git a/indra/newview/lldrawpoolwater.h b/indra/newview/lldrawpoolwater.h
index a5d163e0d716d289ffbab6c3d8bd130763559c17..6f2fc3271dd2fbfa5414a30e750d773083a8479f 100644
--- a/indra/newview/lldrawpoolwater.h
+++ b/indra/newview/lldrawpoolwater.h
@@ -78,8 +78,7 @@ class LLDrawPoolWater: public LLFacePool
 	/*virtual*/ LLColor3 getDebugColor() const; // For AGP debug display
 
 	void renderReflection(LLFace* face);
-	void shade();
-    void shade2(bool edge, LLGLSLShader* shader, const LLColor3& light_diffuse, const LLVector3& light_dir, F32 light_exp);
+	void renderWater();
 
     void setTransparentTextures(const LLUUID& transparentTextureId, const LLUUID& nextTransparentTextureId);
     void setOpaqueTexture(const LLUUID& opaqueTextureId);
diff --git a/indra/newview/lldrawpoolwlsky.cpp b/indra/newview/lldrawpoolwlsky.cpp
index 0c3d8f3098fa334bd0ef8a4c1325a3766c0b93b8..9873846669edcc9f101526d14fe1c0b9319553d2 100644
--- a/indra/newview/lldrawpoolwlsky.cpp
+++ b/indra/newview/lldrawpoolwlsky.cpp
@@ -182,8 +182,6 @@ void LLDrawPoolWLSky::renderSkyHazeDeferred(const LLVector3& camPosLocal, F32 ca
         sky_shader->bindTexture(LLShaderMgr::RAINBOW_MAP, rainbow_tex);
         sky_shader->bindTexture(LLShaderMgr::HALO_MAP,  halo_tex);
 
-        ((LLSettingsVOSky*)psky.get())->updateShader(sky_shader);
-
         F32 moisture_level  = (float)psky->getSkyMoistureLevel();
         F32 droplet_radius  = (float)psky->getSkyDropletRadius();
         F32 ice_level       = (float)psky->getSkyIceLevel();
@@ -268,33 +266,14 @@ void LLDrawPoolWLSky::renderStars(const LLVector3& camPosLocal) const
 	gGL.pushMatrix();
 	gGL.translatef(camPosLocal.mV[0], camPosLocal.mV[1], camPosLocal.mV[2]);
 	gGL.rotatef(gFrameTimeSeconds*0.01f, 0.f, 0.f, 1.f);
-	if (LLGLSLShader::sNoFixedFunction)
-	{
-		gCustomAlphaProgram.bind();
-		gCustomAlphaProgram.uniform1f(sCustomAlpha, star_alpha.mV[3]);
-	}
-	else
-	{
-		gGL.getTexUnit(0)->setTextureColorBlend(LLTexUnit::TBO_MULT, LLTexUnit::TBS_TEX_COLOR, LLTexUnit::TBS_VERT_COLOR);
-		gGL.getTexUnit(0)->setTextureAlphaBlend(LLTexUnit::TBO_MULT_X2, LLTexUnit::TBS_CONST_ALPHA, LLTexUnit::TBS_TEX_ALPHA);
-		glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, star_alpha.mV);
-	}
+	gCustomAlphaProgram.bind();
+	gCustomAlphaProgram.uniform1f(sCustomAlpha, star_alpha.mV[3]);
 
 	gSky.mVOWLSkyp->drawStars();
 
     gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
-
 	gGL.popMatrix();
-
-	if (LLGLSLShader::sNoFixedFunction)
-	{
-		gCustomAlphaProgram.unbind();
-	}
-	else
-	{
-		// and disable the combiner states
-		gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
-	}
+	gCustomAlphaProgram.unbind();
 }
 
 void LLDrawPoolWLSky::renderStarsDeferred(const LLVector3& camPosLocal) const
@@ -406,8 +385,6 @@ void LLDrawPoolWLSky::renderSkyCloudsDeferred(const LLVector3& camPosLocal, F32
         cloudshader->uniform1f(LLShaderMgr::CLOUD_VARIANCE, cloud_variance);
         cloudshader->uniform1f(LLShaderMgr::SUN_MOON_GLOW_FACTOR, psky->getSunMoonGlowFactor());
 
-        ((LLSettingsVOSky*)psky.get())->updateShader(cloudshader);
-
 		/// Render the skydome
         renderDome(camPosLocal, camHeightLocal, cloudshader);
 
@@ -462,8 +439,6 @@ void LLDrawPoolWLSky::renderSkyClouds(const LLVector3& camPosLocal, F32 camHeigh
         cloudshader->uniform1f(LLShaderMgr::CLOUD_VARIANCE, cloud_variance);
         cloudshader->uniform1f(LLShaderMgr::SUN_MOON_GLOW_FACTOR, psky->getSunMoonGlowFactor());
 
-        ((LLSettingsVOSky*)psky.get())->updateShader(cloudshader);
-
 		/// Render the skydome
         renderDome(camPosLocal, camHeightLocal, cloudshader);
 
@@ -485,7 +460,7 @@ void LLDrawPoolWLSky::renderHeavenlyBodies()
 	LLFace * face = gSky.mVOSkyp->mFace[LLVOSky::FACE_SUN];
 
     F32 blend_factor = LLEnvironment::instance().getCurrentSky()->getBlendFactor();
-    bool can_use_vertex_shaders = gPipeline.canUseVertexShaders();
+    bool can_use_vertex_shaders = gPipeline.shadersLoaded();
     bool can_use_windlight_shaders = gPipeline.canUseWindLightShaders();
 
 
@@ -591,11 +566,11 @@ void LLDrawPoolWLSky::renderHeavenlyBodies()
 
 void LLDrawPoolWLSky::renderDeferred(S32 pass)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_WL_SKY);
 	if (!gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_SKY))
 	{
 		return;
 	}
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_WL_SKY);
 
     const F32 camHeightLocal = LLEnvironment::instance().getCamHeight();
 
@@ -615,11 +590,11 @@ void LLDrawPoolWLSky::renderDeferred(S32 pass)
 
 void LLDrawPoolWLSky::render(S32 pass)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_WL_SKY);
 	if (!gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_SKY))
 	{
 		return;
 	}
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_WL_SKY);
 
     const F32 camHeightLocal = LLEnvironment::instance().getCamHeight();
     LLVector3 const & origin = LLViewerCamera::getInstance()->getOrigin();
diff --git a/indra/newview/lldynamictexture.cpp b/indra/newview/lldynamictexture.cpp
index 8b8273d18304d4b259cfa477228d0680dc341389..361a7666fabe4177bbd614ab9fcda17cc517f8d2 100644
--- a/indra/newview/lldynamictexture.cpp
+++ b/indra/newview/lldynamictexture.cpp
@@ -119,10 +119,13 @@ BOOL LLViewerDynamicTexture::render()
 void LLViewerDynamicTexture::preRender(BOOL clear_depth)
 {
 	gPipeline.allocatePhysicsBuffer();
-	llassert(mFullWidth <= static_cast<S32>(gPipeline.mPhysicsDisplay.getWidth()));
-	llassert(mFullHeight <= static_cast<S32>(gPipeline.mPhysicsDisplay.getHeight()));
+	if (!gNonInteractive)
+	{
+		llassert(mFullWidth <= static_cast<S32>(gPipeline.mPhysicsDisplay.getWidth()));
+		llassert(mFullHeight <= static_cast<S32>(gPipeline.mPhysicsDisplay.getHeight()));
+	}
 
-	if (gGLManager.mHasFramebufferObject && gPipeline.mPhysicsDisplay.isComplete() && !gGLManager.mIsATI)
+	if (gPipeline.mPhysicsDisplay.isComplete() && !gGLManager.mIsAMD)
 	{ //using offscreen render target, just use the bottom left corner
 		mOrigin.set(0, 0);
 	}
@@ -209,7 +212,7 @@ BOOL LLViewerDynamicTexture::updateAllInstances()
 		return TRUE;
 	}
 
-	bool use_fbo = gGLManager.mHasFramebufferObject && gPipeline.mBake.isComplete() && !gGLManager.mIsATI;
+	bool use_fbo = gPipeline.mBake.isComplete() && !gGLManager.mIsAMD;
 
 	if (use_fbo)
 	{
diff --git a/indra/newview/lldynamictexture.h b/indra/newview/lldynamictexture.h
index 4bd74a84252ece10ee9e4ae884a83fcb9264be8b..caedf928c3b21fa596feaf8822e8ec067fcd0e64 100644
--- a/indra/newview/lldynamictexture.h
+++ b/indra/newview/lldynamictexture.h
@@ -35,16 +35,8 @@
 
 class LLViewerDynamicTexture : public LLViewerTexture
 {
+    LL_ALIGN_NEW
 public:
-	void* operator new(size_t size)
-	{
-		return LLTrace::MemTrackable<LLTexture>::aligned_new<16>(size);
-	}
-
-	void operator delete(void* ptr, size_t size)
-	{
-		LLTrace::MemTrackable<LLTexture>::aligned_delete<16>(ptr, size);
-	}
 
 	enum
 	{
diff --git a/indra/newview/llenvironment.cpp b/indra/newview/llenvironment.cpp
index cc2b1cc42cda139aca739f1fad3d20f5cfa770d1..1300cf3658a8be5cee521b241bdf72f917712456 100644
--- a/indra/newview/llenvironment.cpp
+++ b/indra/newview/llenvironment.cpp
@@ -105,7 +105,6 @@ namespace
 
     //---------------------------------------------------------------------
     LLTrace::BlockTimerStatHandle   FTM_ENVIRONMENT_UPDATE("Update Environment Tick");
-    LLTrace::BlockTimerStatHandle   FTM_SHADER_PARAM_UPDATE("Update Shader Parameters");
 
     LLSettingsBase::Seconds         DEFAULT_UPDATE_THRESHOLD(10.0);
     const LLSettingsBase::Seconds   MINIMUM_SPANLENGTH(0.01f);
@@ -612,6 +611,7 @@ namespace
             specialSet.insert(SETTING_CLOUD_TEXTUREID);
             specialSet.insert(SETTING_MOON_TEXTUREID);
             specialSet.insert(SETTING_SUN_TEXTUREID);
+            specialSet.insert(SETTING_CLOUD_SHADOW); // due to being part of skips
         }
         return specialSet;
     }
@@ -652,6 +652,7 @@ namespace
     template<>
     void LLSettingsInjected<LLSettingsVOSky>::updateSpecial(const typename LLSettingsInjected<LLSettingsVOSky>::Injection::ptr_t &injection, typename LLSettingsBase::BlendFactor mix)
     {
+        bool is_texture = true;
         if (injection->mKeyName == SETTING_SUN_TEXTUREID)
         {
             mNextSunTextureId = injection->mValue.asUUID();
@@ -676,9 +677,29 @@ namespace
         {
             mNextHaloTextureId = injection->mValue.asUUID();
         }
+        else if (injection->mKeyName == LLSettingsSky::SETTING_CLOUD_SHADOW)
+        {
+            // Special case due to being texture dependent and part of skips
+            is_texture = false;
+            if (!injection->mBlendIn)
+                mix = 1.0 - mix;
+            stringset_t dummy;
+            LLUUID cloud_noise_id = getCloudNoiseTextureId();
+            F64 value = this->mSettings[injection->mKeyName].asReal();
+            if (this->getCloudNoiseTextureId().isNull())
+            {
+                value = 0; // there was no texture so start from zero coverage
+            }
+            // Ideally we need to check for texture in injection, but
+            // in this case user is setting value explicitly, potentially
+            // with different transitions, don't ignore it
+            F64 result = lerp(value, injection->mValue.asReal(), mix);
+            injection->mLastValue = LLSD::Real(result);
+            this->mSettings[injection->mKeyName] = injection->mLastValue;
+        }
 
         // Unfortunately I don't have a per texture blend factor.  We'll just pick the one that is furthest along.
-        if (getBlendFactor() < mix)
+        if (is_texture && getBlendFactor() < mix)
         {
             setBlendFactor(mix);
         }
@@ -825,7 +846,6 @@ std::string env_selection_to_string(LLEnvironment::EnvSelection_t sel)
 #undef RTNENUM
 }
 
-
 //-------------------------------------------------------------------------
 LLEnvironment::LLEnvironment():
     mCloudScrollDelta(),
@@ -879,6 +899,7 @@ void LLEnvironment::cleanupSingleton()
 
 LLEnvironment::~LLEnvironment()
 {
+    cleanupSingleton();
 }
 
 bool LLEnvironment::canEdit() const
@@ -1134,6 +1155,10 @@ void LLEnvironment::setEnvironment(LLEnvironment::EnvSelection_t env, const LLSe
         mSignalEnvChanged(env, env_version);
 }
 
+void LLEnvironment::setCurrentEnvironmentSelection(LLEnvironment::EnvSelection_t env)
+{
+    mCurrentEnvironment->setEnvironmentSelection(env);
+}
 
 void LLEnvironment::setEnvironment(LLEnvironment::EnvSelection_t env, LLEnvironment::fixedEnvironment_t fixed, S32 env_version)
 {
@@ -1471,6 +1496,7 @@ LLEnvironment::DayInstance::ptr_t LLEnvironment::getSharedEnvironmentInstance()
 
 void LLEnvironment::updateEnvironment(LLSettingsBase::Seconds transition, bool forced)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_ENVIRONMENT;
     DayInstance::ptr_t pinstance = getSelectedEnvironmentInstance();
 
     if ((mCurrentEnvironment != pinstance) || forced)
@@ -1488,6 +1514,8 @@ void LLEnvironment::updateEnvironment(LLSettingsBase::Seconds transition, bool f
         {
             mCurrentEnvironment = pinstance;
         }
+
+        updateSettingsUniforms();
     }
 }
 
@@ -1594,7 +1622,7 @@ LLVector4 LLEnvironment::getRotatedLightNorm() const
 //-------------------------------------------------------------------------
 void LLEnvironment::update(const LLViewerCamera * cam)
 {
-    LL_RECORD_BLOCK_TIME(FTM_ENVIRONMENT_UPDATE);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_ENVIRONMENT; //LL_RECORD_BLOCK_TIME(FTM_ENVIRONMENT_UPDATE);
     //F32Seconds now(LLDate::now().secondsSinceEpoch());
     static LLFrameTimer timer;
 
@@ -1614,6 +1642,8 @@ void LLEnvironment::update(const LLViewerCamera * cam)
 
     stop_glerror();
 
+    updateSettingsUniforms();
+
     // *TODO: potential optimization - this block may only need to be
     // executed some of the time.  For example for water shaders only.
     {
@@ -1648,10 +1678,16 @@ void LLEnvironment::updateCloudScroll()
 }
 
 // static
-void LLEnvironment::updateGLVariablesForSettings(LLGLSLShader *shader, const LLSettingsBase::ptr_t &psetting)
+void LLEnvironment::updateGLVariablesForSettings(LLShaderUniforms* uniforms, const LLSettingsBase::ptr_t &psetting)
 {
-    LL_RECORD_BLOCK_TIME(FTM_SHADER_PARAM_UPDATE);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
 
+    for (int i = 0; i < LLGLSLShader::SG_COUNT; ++i)
+    {
+        uniforms[i].clear();
+    }
+
+    LLShaderUniforms* shader = &uniforms[LLGLSLShader::SG_ANY];
     //_WARNS("RIDER") << "----------------------------------------------------------------" << LL_ENDL;
     LLSettingsBase::parammapping_t params = psetting->getParameterMap();
     for (auto &it: params)
@@ -1694,7 +1730,7 @@ void LLEnvironment::updateGLVariablesForSettings(LLGLSLShader *shader, const LLS
         {
             LLVector4 vect4(value);
             //_WARNS("RIDER") << "pushing '" << (*it).first << "' as " << vect4 << LL_ENDL;
-            shader->uniform4fv(it.second.getShaderKey(), 1, vect4.mV);
+            shader->uniform4fv(it.second.getShaderKey(), vect4 );
             break;
         }
 
@@ -1707,17 +1743,44 @@ void LLEnvironment::updateGLVariablesForSettings(LLGLSLShader *shader, const LLS
         default:
             break;
         }
-        stop_glerror();
     }
     //_WARNS("RIDER") << "----------------------------------------------------------------" << LL_ENDL;
 
-    psetting->applySpecial(shader);
+    psetting->applySpecial(uniforms);
 }
 
-void LLEnvironment::updateShaderUniforms(LLGLSLShader *shader)
+void LLEnvironment::updateShaderUniforms(LLGLSLShader* shader)
 {
-    updateGLVariablesForSettings(shader, mCurrentEnvironment->getWater());
-    updateGLVariablesForSettings(shader, mCurrentEnvironment->getSky());
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
+
+    // apply uniforms that should be applied to all shaders
+    mSkyUniforms[LLGLSLShader::SG_ANY].apply(shader);
+    mWaterUniforms[LLGLSLShader::SG_ANY].apply(shader);
+
+    // apply uniforms specific to the given shader's shader group
+    auto group = shader->mShaderGroup;
+    mSkyUniforms[group].apply(shader);
+    mWaterUniforms[group].apply(shader);
+}
+
+void LLEnvironment::updateSettingsUniforms()
+{
+    if (mCurrentEnvironment->getWater())
+    {
+        updateGLVariablesForSettings(mWaterUniforms, mCurrentEnvironment->getWater());
+    }
+    else
+    {
+        LL_WARNS("ENVIRONMENT") << "Failed to update GL variable for water settings, environment is not properly set" << LL_ENDL;
+    }
+    if (mCurrentEnvironment->getSky())
+    {
+        updateGLVariablesForSettings(mSkyUniforms, mCurrentEnvironment->getSky());
+    }
+    else
+    {
+        LL_WARNS("ENVIRONMENT") << "Failed to update GL variable for sky settings, environment is not properly set" << LL_ENDL;
+    }
 }
 
 void LLEnvironment::recordEnvironment(S32 parcel_id, LLEnvironment::EnvironmentInfo::ptr_t envinfo, LLSettingsBase::Seconds transition)
@@ -2578,7 +2641,7 @@ void LLEnvironment::setExperienceEnvironment(LLUUID experience_id, LLSD data, F3
 
     if (!water.isUndefined())
     {
-        environment->injectWaterSettings(sky, experience_id, LLSettingsBase::Seconds(transition_time));
+        environment->injectWaterSettings(water, experience_id, LLSettingsBase::Seconds(transition_time));
     }
 
     if (updateenvironment)
@@ -2634,6 +2697,7 @@ LLEnvironment::DayInstance::ptr_t LLEnvironment::DayInstance::clone() const
 
 bool LLEnvironment::DayInstance::applyTimeDelta(const LLSettingsBase::Seconds& delta)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_ENVIRONMENT;
     ptr_t keeper(shared_from_this());   // makes sure that this does not go away while it is being worked on.
 
     bool changed(false);
diff --git a/indra/newview/llenvironment.h b/indra/newview/llenvironment.h
index 7cbf2d25bb50a496ae4ae18af59dcba4a16c8bb3..330de2bea87da56123b2164818e82dff3c237251 100644
--- a/indra/newview/llenvironment.h
+++ b/indra/newview/llenvironment.h
@@ -38,20 +38,21 @@
 
 #include "llatmosphere.h"
 
+#include "llglslshader.h"
+
 #include <boost/signals2.hpp>
 
 //-------------------------------------------------------------------------
 class LLViewerCamera;
-class LLGLSLShader;
 class LLParcel;
 
 //-------------------------------------------------------------------------
-class LLEnvironment : public LLSingleton<LLEnvironment>
+class LLEnvironment : public LLSimpleton<LLEnvironment>
 {
-    LLSINGLETON_C11(LLEnvironment);
     LOG_CLASS(LLEnvironment);
-
 public:
+    LLEnvironment();
+
     static const F64Seconds     TRANSITION_INSTANT;
     static const F64Seconds     TRANSITION_FAST;
     static const F64Seconds     TRANSITION_DEFAULT;
@@ -114,7 +115,7 @@ class LLEnvironment : public LLSingleton<LLEnvironment>
     typedef std::array<F32, 4>                                      altitude_list_t;
     typedef std::vector<F32>                                        altitudes_vect_t;
 
-    virtual                     ~LLEnvironment();
+    ~LLEnvironment();
 
     bool                        canEdit() const;
     bool                        isExtendedEnvironmentEnabled() const;
@@ -131,9 +132,14 @@ class LLEnvironment : public LLSingleton<LLEnvironment>
 
     void                        update(const LLViewerCamera * cam);
 
-    static void                 updateGLVariablesForSettings(LLGLSLShader *shader, const LLSettingsBase::ptr_t &psetting);
+    static void                 updateGLVariablesForSettings(LLShaderUniforms* uniforms, const LLSettingsBase::ptr_t &psetting);
+    
+    // apply current sky settings to given shader
     void                        updateShaderUniforms(LLGLSLShader *shader);
 
+    // prepare settings to be applied to shaders (call whenever settings are updated)
+    void                        updateSettingsUniforms();
+
     void                        setSelectedEnvironment(EnvSelection_t env, LLSettingsBase::Seconds transition = TRANSITION_DEFAULT, bool forced = false);
     EnvSelection_t              getSelectedEnvironment() const                  { return mSelectedEnvironment; }
 
@@ -152,6 +158,8 @@ class LLEnvironment : public LLSingleton<LLEnvironment>
 
     static void                 logEnvironment(EnvSelection_t env, const LLSettingsBase::ptr_t &settings, S32 env_version = NO_VERSION);
 
+    void                        setCurrentEnvironmentSelection(LLEnvironment::EnvSelection_t env);
+
 
     LLSettingsDay::ptr_t        getEnvironmentDay(EnvSelection_t env);
     LLSettingsDay::Seconds      getEnvironmentDayLength(EnvSelection_t env);
@@ -234,6 +242,11 @@ class LLEnvironment : public LLSingleton<LLEnvironment>
 
     void                        handleEnvironmentPush(LLSD &message);
 
+    //cached uniform values from LLSD values
+    LLShaderUniforms mWaterUniforms[LLGLSLShader::SG_COUNT];
+    LLShaderUniforms mSkyUniforms[LLGLSLShader::SG_COUNT];
+    // =======================================================================================
+
     class DayInstance: public std::enable_shared_from_this<DayInstance>
     {
     public:
@@ -288,6 +301,7 @@ class LLEnvironment : public LLSingleton<LLEnvironment>
         LLSettingsDay::ptr_t        mDayCycle;
         LLSettingsSky::ptr_t        mSky;
         LLSettingsWater::ptr_t      mWater;
+
         S32                         mSkyTrack;
 
         bool                        mInitialized;
@@ -325,9 +339,10 @@ class LLEnvironment : public LLSingleton<LLEnvironment>
     DayInstance::ptr_t          getSelectedEnvironmentInstance();
     DayInstance::ptr_t          getSharedEnvironmentInstance();
 
+    void                initSingleton();
+
 protected:
-    virtual void                initSingleton() override;
-    virtual void                cleanupSingleton() override;
+    void                cleanupSingleton();
 
 
 private:
diff --git a/indra/newview/llexperiencelog.cpp b/indra/newview/llexperiencelog.cpp
index ee5d56192776fc818cda6fe505688beca82a92ff..c441fbc09fbdf01d40a5c852b136a028f1e31346 100644
--- a/indra/newview/llexperiencelog.cpp
+++ b/indra/newview/llexperiencelog.cpp
@@ -149,10 +149,6 @@ std::string LLExperienceLog::getPermissionString( const LLSD& message, const std
 		{
 			buf.str(entry);
 		}
-		else
-		{
-			buf.str();
-		}
 	}
 
 	if(buf.str().empty())
diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp
index f1b64a58993f6c38490f62cf984006d652ad6075..c3b3ccabb4c5b00d462ade9e0a986b8fa91bb727 100644
--- a/indra/newview/llface.cpp
+++ b/indra/newview/llface.cpp
@@ -56,6 +56,7 @@
 #include "llviewertexture.h"
 #include "llvoavatar.h"
 #include "llsculptidsize.h"
+#include "llmeshrepository.h"
 
 #if LL_LINUX
 // Work-around spurious used before init warning on Vector4a
@@ -63,7 +64,6 @@
 #pragma GCC diagnostic ignored "-Wuninitialized"
 #endif
 
-extern BOOL gGLDebugLoggingEnabled;
 #define LL_MAX_INDICES_COUNT 1000000
 
 static LLStaticHashedString sTextureIndexIn("texture_index_in");
@@ -71,6 +71,7 @@ static LLStaticHashedString sColorIn("color_in");
 
 BOOL LLFace::sSafeRenderSelect = TRUE; // FALSE
 
+
 #define DOTVEC(a,b) (a.mV[0]*b.mV[0] + a.mV[1]*b.mV[1] + a.mV[2]*b.mV[2])
 
 /*
@@ -127,6 +128,7 @@ void planarProjection(LLVector2 &tc, const LLVector4a& normal,
 
 void LLFace::init(LLDrawable* drawablep, LLViewerObject* objp)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_FACE;
 	mLastUpdateTime = gFrameTimeSeconds;
 	mLastMoveTime = 0.f;
 	mLastSkinTime = gFrameTimeSeconds;
@@ -196,14 +198,7 @@ void LLFace::destroy()
 
 	if (mDrawPoolp)
 	{
-		if (this->isState(LLFace::RIGGED) && (mDrawPoolp->getType() == LLDrawPool::POOL_CONTROL_AV || mDrawPoolp->getType() == LLDrawPool::POOL_AVATAR))
-		{
-			((LLDrawPoolAvatar*) mDrawPoolp)->removeRiggedFace(this);
-		}
-		else
-		{
-			mDrawPoolp->removeFace(this);
-		}
+		mDrawPoolp->removeFace(this);
 		mDrawPoolp = NULL;
 	}
 
@@ -241,6 +236,8 @@ void LLFace::setPool(LLFacePool* pool)
 
 void LLFace::setPool(LLFacePool* new_pool, LLViewerTexture *texturep)
 {
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_FACE
+
 	if (!new_pool)
 	{
 		LL_ERRS() << "Setting pool to null!" << LL_ENDL;
@@ -320,6 +317,8 @@ void LLFace::setSpecularMap(LLViewerTexture* tex)
 
 void LLFace::dirtyTexture()
 {
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_FACE
+
 	LLDrawable* drawablep = getDrawable();
 
 	if (mVObjp.notNull() && mVObjp->getVolume())
@@ -535,6 +534,8 @@ void LLFace::updateCenterAgent()
 
 void LLFace::renderSelected(LLViewerTexture *imagep, const LLColor4& color)
 {
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_FACE
+
 	if (mDrawablep == NULL || mDrawablep->getSpatialGroup() == NULL)
 	{
 		return;
@@ -585,6 +586,7 @@ void LLFace::renderSelected(LLViewerTexture *imagep, const LLColor4& color)
 						glTexCoordPointer(2, GL_FLOAT, 8, vol_face.mTexCoords);
 					}
 					gGL.syncMatrices();
+					LL_PROFILER_GPU_ZONEC( "gl.DrawElements", 0x00FF00 );
 					glDrawElements(GL_TRIANGLES, vol_face.mNumIndices, GL_UNSIGNED_SHORT, vol_face.mIndices);
 					glDisableClientState(GL_TEXTURE_COORD_ARRAY);
 				}
@@ -605,6 +607,8 @@ void LLFace::renderSelected(LLViewerTexture *imagep, const LLColor4& color)
 
 void renderFace(LLDrawable* drawable, LLFace *face)
 {
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_FACE
+
     LLVOVolume* vobj = drawable->getVOVolume();
     if (vobj)
     {
@@ -648,7 +652,7 @@ void LLFace::renderOneWireframe(const LLColor4 &color, F32 fogCfx, bool wirefram
             glFogf(GL_FOG_END, d*(1 + (LLViewerCamera::getInstance()->getView() / LLViewerCamera::getInstance()->getDefaultFOV())));
             glFogfv(GL_FOG_COLOR, fogCol.mV);
 
-            gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
+            gGL.flush();
             {
                 gGL.diffuseColor4f(color.mV[VRED], color.mV[VGREEN], color.mV[VBLUE], 0.4f);
                 renderFace(mDrawablep, this);
@@ -891,6 +895,8 @@ bool less_than_max_mag(const LLVector4a& vec)
 BOOL LLFace::genVolumeBBoxes(const LLVolume &volume, S32 f,
                              const LLMatrix4& mat_vert_in, BOOL global_volume)
 {
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_FACE
+
 	//get bounding box
 	if (mDrawablep->isState(LLDrawable::REBUILD_VOLUME | LLDrawable::REBUILD_POSITION | LLDrawable::REBUILD_RIGGED))
 	{
@@ -1027,12 +1033,12 @@ void LLFace::getPlanarProjectedParams(LLQuaternion* face_rot, LLVector3* face_po
 {
 	const LLMatrix4& vol_mat = getWorldMatrix();
 	const LLVolumeFace& vf = getViewerObject()->getVolume()->getVolumeFace(mTEOffset);
-	const LLVector4a& normal4a = vf.mNormals[0];
-	const LLVector4a& tangent = vf.mTangents[0];
-	if (!&tangent)
+	if (! (vf.mNormals && vf.mTangents))
 	{
 		return;
 	}
+	const LLVector4a& normal4a = *vf.mNormals;
+	const LLVector4a& tangent  = *vf.mTangents;
 
 	LLVector4a binormal4a;
 	binormal4a.setCross3(normal4a, tangent);
@@ -1165,6 +1171,11 @@ bool LLFace::canRenderAsMask()
 		return true;
 	}
 
+    if (isState(LLFace::RIGGED))
+    { // never auto alpha-mask rigged faces
+        return false;
+    }
+
 	const LLTextureEntry* te = getTextureEntry();
 	if( !te || !getViewerObject() || !getTexture() )
 	{
@@ -1202,12 +1213,10 @@ bool LLFace::canRenderAsMask()
 }
 
 
-static LLTrace::BlockTimerStatHandle FTM_FACE_GEOM_VOLUME("Volume VB Cache");
-
 //static 
 void LLFace::cacheFaceInVRAM(const LLVolumeFace& vf)
 {
-	LL_RECORD_BLOCK_TIME(FTM_FACE_GEOM_VOLUME);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_FACE;
 	U32 mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 |
 				LLVertexBuffer::MAP_TANGENT | LLVertexBuffer::MAP_NORMAL;
 	
@@ -1269,41 +1278,13 @@ void push_for_transform(LLVertexBuffer* buff, U32 source_count, U32 dest_count)
 	}
 }
 
-static LLTrace::BlockTimerStatHandle FTM_FACE_GET_GEOM("Face Geom");
-static LLTrace::BlockTimerStatHandle FTM_FACE_GEOM_POSITION("Position");
-static LLTrace::BlockTimerStatHandle FTM_FACE_GEOM_NORMAL("Normal");
-static LLTrace::BlockTimerStatHandle FTM_FACE_GEOM_TEXTURE("Texture");
-static LLTrace::BlockTimerStatHandle FTM_FACE_GEOM_COLOR("Color");
-static LLTrace::BlockTimerStatHandle FTM_FACE_GEOM_EMISSIVE("Emissive");
-static LLTrace::BlockTimerStatHandle FTM_FACE_GEOM_WEIGHTS("Weights");
-static LLTrace::BlockTimerStatHandle FTM_FACE_GEOM_TANGENT("Binormal");
-
-static LLTrace::BlockTimerStatHandle FTM_FACE_GEOM_FEEDBACK("Face Feedback");
-static LLTrace::BlockTimerStatHandle FTM_FACE_GEOM_FEEDBACK_POSITION("Feedback Position");
-static LLTrace::BlockTimerStatHandle FTM_FACE_GEOM_FEEDBACK_NORMAL("Feedback  Normal");
-static LLTrace::BlockTimerStatHandle FTM_FACE_GEOM_FEEDBACK_TEXTURE("Feedback  Texture");
-static LLTrace::BlockTimerStatHandle FTM_FACE_GEOM_FEEDBACK_COLOR("Feedback  Color");
-static LLTrace::BlockTimerStatHandle FTM_FACE_GEOM_FEEDBACK_EMISSIVE("Feedback  Emissive");
-static LLTrace::BlockTimerStatHandle FTM_FACE_GEOM_FEEDBACK_BINORMAL("Feedback Binormal");
-
-static LLTrace::BlockTimerStatHandle FTM_FACE_GEOM_INDEX("Index");
-static LLTrace::BlockTimerStatHandle FTM_FACE_GEOM_INDEX_TAIL("Tail");
-static LLTrace::BlockTimerStatHandle FTM_FACE_POSITION_STORE("Pos");
-static LLTrace::BlockTimerStatHandle FTM_FACE_TEXTURE_INDEX_STORE("TexIdx");
-static LLTrace::BlockTimerStatHandle FTM_FACE_POSITION_PAD("Pad");
-static LLTrace::BlockTimerStatHandle FTM_FACE_TEX_DEFAULT("Default");
-static LLTrace::BlockTimerStatHandle FTM_FACE_TEX_QUICK("Quick");
-static LLTrace::BlockTimerStatHandle FTM_FACE_TEX_QUICK_NO_XFORM("No Xform");
-static LLTrace::BlockTimerStatHandle FTM_FACE_TEX_QUICK_XFORM("Xform");
-static LLTrace::BlockTimerStatHandle FTM_FACE_TEX_QUICK_PLANAR("Quick Planar");
-
 BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 							   const S32 &f,
 								const LLMatrix4& mat_vert_in, const LLMatrix3& mat_norm_in,
 								const U16 &index_offset,
 								bool force_rebuild)
 {
-	LL_RECORD_BLOCK_TIME(FTM_FACE_GET_GEOM);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_FACE;
 	llassert(verify());
 
 	if (volume.getNumVolumeFaces() <= f) {
@@ -1311,7 +1292,9 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 		return FALSE;
 	}
 
-	const LLVolumeFace &vf = volume.getVolumeFace(f);
+    bool rigged = isState(RIGGED);
+
+    const LLVolumeFace &vf = volume.getVolumeFace(f);
 	S32 num_vertices = (S32)vf.mNumVertices;
 	S32 num_indices = (S32) vf.mNumIndices;
 	
@@ -1444,7 +1427,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 	// INDICES
 	if (full_rebuild)
 	{
-		LL_RECORD_BLOCK_TIME(FTM_FACE_GEOM_INDEX);
+        LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - indices");
 		mVertexBuffer->getIndexStrider(indicesp, mIndicesIndex, mIndicesCount, map_range);
 
 		volatile __m128i* dst = (__m128i*) indicesp.get();
@@ -1460,7 +1443,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 		}
 
 		{
-			LL_RECORD_BLOCK_TIME(FTM_FACE_GEOM_INDEX_TAIL);
+            LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - indices tail");
 			U16* idx = (U16*) dst;
 
 			for (S32 i = end*8; i < num_indices; ++i)
@@ -1475,9 +1458,6 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 		}
 	}
 	
-	LLMatrix4a mat_normal;
-	mat_normal.loadu(mat_norm_in);
-	
 	F32 r = 0, os = 0, ot = 0, ms = 0, mt = 0, cos_ang = 0, sin_ang = 0;
 	bool do_xform = false;
 	if (rebuild_tcoord)
@@ -1512,6 +1492,45 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 		}
 	}
 	
+    const LLMeshSkinInfo* skin = nullptr;
+    LLMatrix4a mat_vert;
+    LLMatrix4a mat_normal;
+
+    // prepare mat_vert
+    if (rebuild_pos)
+    {
+        if (rigged)
+        { //override with bind shape matrix if rigged
+            skin = mSkinInfo;
+            mat_vert = skin->mBindShapeMatrix;
+        }
+        else
+        {
+            mat_vert.loadu(mat_vert_in);
+        }
+    }
+
+    if (rebuild_normal || rebuild_tangent)
+    { //override mat_normal with inverse of skin->mBindShapeMatrix
+        LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - norm mat override");
+        if (rigged)
+        {
+            if (skin == nullptr)
+            {
+                skin = mSkinInfo;
+            }
+
+            //TODO -- cache this (check profile marker above)?
+            glh::matrix4f m((F32*) skin->mBindShapeMatrix.getF32ptr());
+            m = m.inverse().transpose();
+            mat_normal.loadu(m.m);
+        }
+        else
+        {
+            mat_normal.loadu(mat_norm_in);
+        }
+    }
+
 	static LLCachedControl<bool> use_transform_feedback(gSavedSettings, "RenderUseTransformFeedback", false);
 
 #ifdef GL_TRANSFORM_FEEDBACK_BUFFER
@@ -1522,8 +1541,8 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 		!rebuild_weights && //TODO: add support for weights
 		!volume.isUnique()) //source volume is NOT flexi
 	{ //use transform feedback to pack vertex buffer
-		//gGLDebugLoggingEnabled = TRUE;
-		LL_RECORD_BLOCK_TIME(FTM_FACE_GEOM_FEEDBACK);
+
+        LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - transform feedback");
 		LLGLEnable discard(GL_RASTERIZER_DISCARD);
 		LLVertexBuffer* buff = (LLVertexBuffer*) vf.mVertexBuffer.get();
 
@@ -1541,7 +1560,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 
 		if (rebuild_pos)
 		{
-			LL_RECORD_BLOCK_TIME(FTM_FACE_GEOM_FEEDBACK_POSITION);
+            LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - tf position");
 			gTransformPositionProgram.bind();
 
 			mVertexBuffer->bindForFeedback(0, LLVertexBuffer::TYPE_VERTEX, mGeomIndex, mGeomCount);
@@ -1566,7 +1585,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 
 		if (rebuild_color)
 		{
-			LL_RECORD_BLOCK_TIME(FTM_FACE_GEOM_FEEDBACK_COLOR);
+            LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - tf color");
 			gTransformColorProgram.bind();
 			
 			mVertexBuffer->bindForFeedback(0, LLVertexBuffer::TYPE_COLOR, mGeomIndex, mGeomCount);
@@ -1582,7 +1601,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 
 		if (rebuild_emissive)
 		{
-			LL_RECORD_BLOCK_TIME(FTM_FACE_GEOM_FEEDBACK_EMISSIVE);
+            LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - tf emissive");
 			gTransformColorProgram.bind();
 			
 			mVertexBuffer->bindForFeedback(0, LLVertexBuffer::TYPE_EMISSIVE, mGeomIndex, mGeomCount);
@@ -1603,7 +1622,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 
 		if (rebuild_normal)
 		{
-			LL_RECORD_BLOCK_TIME(FTM_FACE_GEOM_FEEDBACK_NORMAL);
+            LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - tf normal");
 			gTransformNormalProgram.bind();
 			
 			mVertexBuffer->bindForFeedback(0, LLVertexBuffer::TYPE_NORMAL, mGeomIndex, mGeomCount);
@@ -1616,7 +1635,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 
 		if (rebuild_tangent)
 		{
-			LL_RECORD_BLOCK_TIME(FTM_FACE_GEOM_TANGENT);
+            LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - tf tangent");
 			gTransformTangentProgram.bind();
 			
 			mVertexBuffer->bindForFeedback(0, LLVertexBuffer::TYPE_TANGENT, mGeomIndex, mGeomCount);
@@ -1629,7 +1648,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 
 		if (rebuild_tcoord)
 		{
-			LL_RECORD_BLOCK_TIME(FTM_FACE_GEOM_FEEDBACK_TEXTURE);
+            LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - tf tcoord");
 			gTransformTexCoordProgram.bind();
 			
 			mVertexBuffer->bindForFeedback(0, LLVertexBuffer::TYPE_TEXCOORD0, mGeomIndex, mGeomCount);
@@ -1668,7 +1687,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 
 		if (rebuild_tcoord)
 		{
-			LL_RECORD_BLOCK_TIME(FTM_FACE_GEOM_TEXTURE);
+            LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - tcoord");
 									
 			//bump setup
 			LLVector4a binormal_dir( -sin_ang, cos_ang, 0.f );
@@ -1764,7 +1783,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 					do_xform = false;
 				}
 
-				if (getVirtualSize() >= MIN_TEX_ANIM_SIZE || isState(LLFace::RIGGED))
+				if (getVirtualSize() >= MIN_TEX_ANIM_SIZE) // || isState(LLFace::RIGGED))
 				{ //don't override texture transform during tc bake
 					tex_mode = 0;
 				}
@@ -1791,18 +1810,18 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 
 				if (texgen != LLTextureEntry::TEX_GEN_PLANAR)
 				{
-					LL_RECORD_BLOCK_TIME(FTM_FACE_TEX_QUICK);
+                    LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - texgen");
 					if (!do_tex_mat)
 					{
 						if (!do_xform)
 						{
-							LL_RECORD_BLOCK_TIME(FTM_FACE_TEX_QUICK_NO_XFORM);
+                            LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("ggv - texgen 1");
 							S32 tc_size = (num_vertices*2*sizeof(F32)+0xF) & ~0xF;
 							LLVector4a::memcpyNonAliased16((F32*) tex_coords0.get(), (F32*) vf.mTexCoords, tc_size);
 						}
 						else
 						{
-							LL_RECORD_BLOCK_TIME(FTM_FACE_TEX_QUICK_XFORM);
+                            LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("ggv - texgen 2");
 							F32* dst = (F32*) tex_coords0.get();
 							LLVector4a* src = (LLVector4a*) vf.mTexCoords;
 
@@ -1842,9 +1861,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 						for (S32 i = 0; i < num_vertices; i++)
 						{	
 							LLVector2 tc(vf.mTexCoords[i]);
-							//LLVector4a& norm = vf.mNormals[i];
-							//LLVector4a& center = *(vf.mCenter);
-
+							
 							LLVector3 tmp(tc.mV[0], tc.mV[1], 0.f);
 							tmp = tmp * *mTextureMatrix;
 							tc.mV[0] = tmp.mV[0];
@@ -1855,7 +1872,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 				}
 				else
 				{ //no bump, tex gen planar
-					LL_RECORD_BLOCK_TIME(FTM_FACE_TEX_QUICK_PLANAR);
+                    LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - texgen planar");
 					if (do_tex_mat)
 					{
 						for (S32 i = 0; i < num_vertices; i++)
@@ -1900,7 +1917,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 			}
 			else
 			{ //bump mapped or has material, just do the whole expensive loop
-				LL_RECORD_BLOCK_TIME(FTM_FACE_TEX_DEFAULT);
+                LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - texgen default");
 
 				std::vector<LLVector2> bump_tc;
 		
@@ -2058,14 +2075,11 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 			LLVector4a* end = src+num_vertices;
 			//LLVector4a* end_64 = end-4;
 
-			//LL_RECORD_TIME_BLOCK(FTM_FACE_GEOM_POSITION);
 			llassert(num_vertices > 0);
 		
 			mVertexBuffer->getVertexStrider(vert, mGeomIndex, mGeomCount, map_range);
 			
-			LLMatrix4a mat_vert;
-			mat_vert.loadu(mat_vert_in);
-
+			
 			F32* dst = (F32*) vert.get();
 			F32* end_f32 = dst+mGeomCount*4;
 
@@ -2095,53 +2109,19 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 
 			LLVector4a tmp;
 
-			{
-				//LL_RECORD_TIME_BLOCK(FTM_FACE_POSITION_STORE);
-
-				/*if (num_vertices > 4)
-				{ //more than 64 bytes
-					while (src < end_64)
-					{	
-						_mm_prefetch((char*)src + 64, _MM_HINT_T0);
-						_mm_prefetch((char*)dst + 64, _MM_HINT_T0);
-
-						mat_vert.affineTransform(*src, res0);
-						tmp.setSelectWithMask(mask, texIdx, res0);
-						tmp.store4a((F32*) dst);
-
-						mat_vert.affineTransform(*(src+1), res1);
-						tmp.setSelectWithMask(mask, texIdx, res1);
-						tmp.store4a((F32*) dst+4);
-
-						mat_vert.affineTransform(*(src+2), res2);
-						tmp.setSelectWithMask(mask, texIdx, res2);
-						tmp.store4a((F32*) dst+8);
-
-						mat_vert.affineTransform(*(src+3), res3);
-						tmp.setSelectWithMask(mask, texIdx, res3);
-						tmp.store4a((F32*) dst+12);
-
-						dst += 16;
-						src += 4;
-					}
-				}*/
-
-				while (src < end)
-				{	
-					mat_vert.affineTransform(*src++, res0);
-					tmp.setSelectWithMask(mask, texIdx, res0);
-					tmp.store4a((F32*) dst);
-					dst += 4;
-				}
+			
+			while (src < end)
+			{	
+				mat_vert.affineTransform(*src++, res0);
+				tmp.setSelectWithMask(mask, texIdx, res0);
+				tmp.store4a((F32*) dst);
+				dst += 4;
 			}
-
+			
+			while (dst < end_f32)
 			{
-				//LL_RECORD_TIME_BLOCK(FTM_FACE_POSITION_PAD);
-				while (dst < end_f32)
-				{
-					res0.store4a((F32*) dst);
-					dst += 4;
-				}
+				res0.store4a((F32*) dst);
+				dst += 4;
 			}
 
 			if (map_range)
@@ -2150,10 +2130,10 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 			}
 		}
 
-		
 		if (rebuild_normal)
 		{
-			//LL_RECORD_TIME_BLOCK(FTM_FACE_GEOM_NORMAL);
+            LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - normal");
+
 			mVertexBuffer->getNormalStrider(norm, mGeomIndex, mGeomCount, map_range);
 			F32* normals = (F32*) norm.get();
 			LLVector4a* src = vf.mNormals;
@@ -2175,7 +2155,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 		
 		if (rebuild_tangent)
 		{
-			LL_RECORD_BLOCK_TIME(FTM_FACE_GEOM_TANGENT);
+            LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - tangent");
 			mVertexBuffer->getTangentStrider(tangent, mGeomIndex, mGeomCount, map_range);
 			F32* tangents = (F32*) tangent.get();
 			
@@ -2208,7 +2188,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 	
 		if (rebuild_weights && vf.mWeights)
 		{
-			LL_RECORD_BLOCK_TIME(FTM_FACE_GEOM_WEIGHTS);
+            LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - weight");
 			mVertexBuffer->getWeight4Strider(wght, mGeomIndex, mGeomCount, map_range);
 			F32* weights = (F32*) wght.get();
 			LLVector4a::memcpyNonAliased16(weights, (F32*) vf.mWeights, num_vertices*4*sizeof(F32));
@@ -2220,7 +2200,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 
 		if (rebuild_color && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_COLOR) )
 		{
-			LL_RECORD_BLOCK_TIME(FTM_FACE_GEOM_COLOR);
+            LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - color");
 			mVertexBuffer->getColorStrider(colors, mGeomIndex, mGeomCount, map_range);
 
 			LLVector4a src;
@@ -2251,7 +2231,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 
 		if (rebuild_emissive)
 		{
-			LL_RECORD_BLOCK_TIME(FTM_FACE_GEOM_EMISSIVE);
+            LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - emissive");
 			LLStrider<LLColor4U> emissive;
 			mVertexBuffer->getEmissiveStrider(emissive, mGeomIndex, mGeomCount, map_range);
 
@@ -2382,12 +2362,35 @@ F32 LLFace::getTextureVirtualSize()
 
 BOOL LLFace::calcPixelArea(F32& cos_angle_to_view_dir, F32& radius)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_FACE;
+
 	//VECTORIZE THIS
 	//get area of circle around face
-	LLVector4a center;
-	center.load3(getPositionAgent().mV);
-	LLVector4a size;
-	size.setSub(mExtents[1], mExtents[0]);
+
+    LLVector4a center;
+    LLVector4a size;
+
+
+    if (isState(LLFace::RIGGED))
+    {
+        //override with avatar bounding box
+        LLVOAvatar* avatar = mVObjp->getAvatar();
+        if (avatar && avatar->mDrawable)
+        {
+            center.load3(avatar->getPositionAgent().mV);
+            const LLVector4a* exts = avatar->mDrawable->getSpatialExtents();
+            size.setSub(exts[1], exts[0]);
+        }
+        else
+        {
+            return false;
+        }
+    }
+    else
+    {
+        center.load3(getPositionAgent().mV);
+        size.setSub(mExtents[1], mExtents[0]);
+    }
 	size.mul(0.5f);
 
 	LLViewerCamera* camera = LLViewerCamera::getInstance();
@@ -2661,6 +2664,8 @@ const LLMatrix4& LLFace::getRenderMatrix() const
 
 S32 LLFace::renderElements(const U16 *index_array) const
 {
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_FACE
+
 	S32 ret = 0;
 	
 	if (isState(GLOBAL))
@@ -2680,6 +2685,8 @@ S32 LLFace::renderElements(const U16 *index_array) const
 
 S32 LLFace::renderIndexed()
 {
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_FACE
+
 	if(mDrawablep == NULL || mDrawPoolp == NULL)
 	{
 		return 0;
@@ -2690,6 +2697,8 @@ S32 LLFace::renderIndexed()
 
 S32 LLFace::renderIndexed(U32 mask)
 {
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_FACE
+
 	if (mVertexBuffer.isNull())
 	{
 		return 0;
@@ -2767,56 +2776,6 @@ void LLFace::clearVertexBuffer()
 	mVertexBuffer = NULL;
 }
 
-//static
-U32 LLFace::getRiggedDataMask(U32 type)
-{
-	static const U32 rigged_data_mask[] = {
-		LLDrawPoolAvatar::RIGGED_MATERIAL_MASK,
-		LLDrawPoolAvatar::RIGGED_MATERIAL_ALPHA_VMASK,
-		LLDrawPoolAvatar::RIGGED_MATERIAL_ALPHA_MASK_MASK,
-		LLDrawPoolAvatar::RIGGED_MATERIAL_ALPHA_EMISSIVE_MASK,
-		LLDrawPoolAvatar::RIGGED_SPECMAP_VMASK,
-		LLDrawPoolAvatar::RIGGED_SPECMAP_BLEND_MASK,
-		LLDrawPoolAvatar::RIGGED_SPECMAP_MASK_MASK,
-		LLDrawPoolAvatar::RIGGED_SPECMAP_EMISSIVE_MASK,
-		LLDrawPoolAvatar::RIGGED_NORMMAP_VMASK,
-		LLDrawPoolAvatar::RIGGED_NORMMAP_BLEND_MASK,
-		LLDrawPoolAvatar::RIGGED_NORMMAP_MASK_MASK,
-		LLDrawPoolAvatar::RIGGED_NORMMAP_EMISSIVE_MASK,
-		LLDrawPoolAvatar::RIGGED_NORMSPEC_VMASK,
-		LLDrawPoolAvatar::RIGGED_NORMSPEC_BLEND_MASK,
-		LLDrawPoolAvatar::RIGGED_NORMSPEC_MASK_MASK,
-		LLDrawPoolAvatar::RIGGED_NORMSPEC_EMISSIVE_MASK,
-		LLDrawPoolAvatar::RIGGED_SIMPLE_MASK,
-		LLDrawPoolAvatar::RIGGED_FULLBRIGHT_MASK,
-		LLDrawPoolAvatar::RIGGED_SHINY_MASK,
-		LLDrawPoolAvatar::RIGGED_FULLBRIGHT_SHINY_MASK,
-		LLDrawPoolAvatar::RIGGED_GLOW_MASK,
-		LLDrawPoolAvatar::RIGGED_ALPHA_MASK,
-		LLDrawPoolAvatar::RIGGED_FULLBRIGHT_ALPHA_MASK,
-		LLDrawPoolAvatar::RIGGED_DEFERRED_BUMP_MASK,						 
-		LLDrawPoolAvatar::RIGGED_DEFERRED_SIMPLE_MASK,
-	};
-
-	llassert(type < sizeof(rigged_data_mask)/sizeof(U32));
-
-	return rigged_data_mask[type];
-}
-
-U32 LLFace::getRiggedVertexBufferDataMask() const
-{
-	U32 data_mask = 0;
-	for (U32 i = 0; i < mRiggedIndex.size(); ++i)
-	{
-		if (mRiggedIndex[i] > -1)
-		{
-			data_mask |= LLFace::getRiggedDataMask(i);
-		}
-	}
-
-	return data_mask;
-}
-
 S32 LLFace::getRiggedIndex(U32 type) const
 {
 	if (mRiggedIndex.empty())
@@ -2829,19 +2788,7 @@ S32 LLFace::getRiggedIndex(U32 type) const
 	return mRiggedIndex[type];
 }
 
-void LLFace::setRiggedIndex(U32 type, S32 index)
+U64 LLFace::getSkinHash()
 {
-	if (mRiggedIndex.empty())
-	{
-		mRiggedIndex.resize(LLDrawPoolAvatar::NUM_RIGGED_PASSES);
-		for (U32 i = 0; i < mRiggedIndex.size(); ++i)
-		{
-			mRiggedIndex[i] = -1;
-		}
-	}
-
-	llassert(type < mRiggedIndex.size());
-
-	mRiggedIndex[type] = index;
+    return mSkinInfo ? mSkinInfo->mHash : 0;
 }
-
diff --git a/indra/newview/llface.h b/indra/newview/llface.h
index 3611539ff84a548d05e7949345387631a9754bef..aa00c9d052630c73c84ba55fffd9516301647468 100644
--- a/indra/newview/llface.h
+++ b/indra/newview/llface.h
@@ -47,18 +47,18 @@ class LLTextureEntry;
 class LLVertexProgram;
 class LLViewerTexture;
 class LLGeometryManager;
-class LLTextureAtlasSlot;
 class LLDrawInfo;
+class LLMeshSkinInfo;
 
 const F32 MIN_ALPHA_SIZE = 1024.f;
 const F32 MIN_TEX_ANIM_SIZE = 512.f;
 const U8 FACE_DO_NOT_BATCH_TEXTURES = 255;
 
-class LLFace : public LLTrace::MemTrackableNonVirtual<LLFace, 16>
+class alignas(16) LLFace
 {
+    LL_ALIGN_NEW
 public:
 	LLFace(const LLFace& rhs)
-	:	LLTrace::MemTrackableNonVirtual<LLFace, 16>("LLFace")
 	{
 		*this = rhs;
 	}
@@ -85,8 +85,8 @@ class LLFace : public LLTrace::MemTrackableNonVirtual<LLFace, 16>
 
 public:
 	LLFace(LLDrawable* drawablep, LLViewerObject* objp)
-	:	LLTrace::MemTrackableNonVirtual<LLFace, 16>("LLFace")
 	{
+        LL_PROFILE_ZONE_SCOPED;
 		init(drawablep, objp);
 	}
 	~LLFace()  { destroy(); }
@@ -143,7 +143,7 @@ class LLFace : public LLTrace::MemTrackableNonVirtual<LLFace, 16>
 	LLViewerObject*	getViewerObject()	const	{ return mVObjp; }
 	S32				getLOD()			const	{ return mVObjp.notNull() ? mVObjp->getLOD() : 0; }
 	void			setPoolType(U32 type)		{ mPoolType = type; }
-	S32				getTEOffset()				{ return mTEOffset; }
+	S32				getTEOffset()       const   { return mTEOffset; }
 	LLViewerTexture*	getTexture(U32 ch = LLRender::DIFFUSE_MAP) const;
 
 	void			setViewerObject(LLViewerObject* object);
@@ -228,15 +228,17 @@ class LLFace : public LLTrace::MemTrackableNonVirtual<LLFace, 16>
 	void setVertexBuffer(LLVertexBuffer* buffer);
 	void clearVertexBuffer(); //sets mVertexBuffer to NULL
 	LLVertexBuffer* getVertexBuffer()	const	{ return mVertexBuffer; }
-	U32 getRiggedVertexBufferDataMask() const;
 	S32 getRiggedIndex(U32 type) const;
-	void setRiggedIndex(U32 type, S32 index);
-
-	static U32 getRiggedDataMask(U32 type);
 
 	void	notifyAboutCreatingTexture(LLViewerTexture *texture);
 	void	notifyAboutMissingAsset(LLViewerTexture *texture);
 
+    // used to preserve draw order of faces that are batched together. 
+    // Allows content creators to manipulate linked sets and face ordering 
+    // for consistent alpha sorting results, particularly for rigged attachments
+    void setDrawOrderIndex(U32 index) { mDrawOrderIndex = index; }
+    U32 getDrawOrderIndex() const { return mDrawOrderIndex; }
+
 public: //aligned members
 	LLVector4a		mExtents[2];
 
@@ -261,6 +263,11 @@ class LLFace : public LLTrace::MemTrackableNonVirtual<LLFace, 16>
 	LLMatrix4*	mSpecMapMatrix;
 	LLMatrix4*	mNormalMapMatrix;
 	LLDrawInfo* mDrawInfo;
+    LLVOAvatar* mAvatar = nullptr;
+    LLMeshSkinInfo* mSkinInfo = nullptr;
+    
+    // return mSkinInfo->mHash or 0 if mSkinInfo is null
+    U64 getSkinHash();
 
 private:
 	LLPointer<LLVertexBuffer> mVertexBuffer;
@@ -271,10 +278,10 @@ class LLFace : public LLTrace::MemTrackableNonVirtual<LLFace, 16>
 	LLColor4	mFaceColor;			// overrides material color if state |= USE_FACE_COLOR
 	
 	U16			mGeomCount;			// vertex count for this face
-	U16			mGeomIndex;			// index into draw pool
+	U16			mGeomIndex;			// starting index into mVertexBuffer's vertex array
 	U8			mTextureIndex;		// index of texture channel to use for pseudo-atlasing
 	U32			mIndicesCount;
-	U32			mIndicesIndex;		// index into draw pool for indices (yeah, I know!)
+	U32			mIndicesIndex;		// index into mVertexBuffer's index array
 	S32         mIndexInTex[LLRender::NUM_TEXTURE_CHANNELS];
 
 	LLXformMatrix* mXform;
@@ -304,6 +311,7 @@ class LLFace : public LLTrace::MemTrackableNonVirtual<LLFace, 16>
 	bool        mHasMedia ;
 	bool        mIsMediaAllowed;
 
+    U32 mDrawOrderIndex = 0; // see setDrawOrderIndex
 	
 protected:
 	static BOOL	sSafeRenderSelect;
diff --git a/indra/newview/llfasttimerview.cpp b/indra/newview/llfasttimerview.cpp
index 239d1621010154363f144ac01ba00ba0d7bf82fe..9bb3bac1040b3f82581b3667d88ad48b1d20530f 100644
--- a/indra/newview/llfasttimerview.cpp
+++ b/indra/newview/llfasttimerview.cpp
@@ -504,20 +504,6 @@ void LLFastTimerView::exportCharts(const std::string& base, const std::string& t
 		is.close();
 	}
 
-	//get time domain
-	LLSD::Real cur_total_time = 0.0;
-
-	for (U32 i = 0; i < cur_data.size(); ++i)
-	{
-		cur_total_time += cur_data[i]["Total"]["Time"].asReal();
-	}
-
-	LLSD::Real base_total_time = 0.0;
-	for (U32 i = 0; i < base_data.size(); ++i)
-	{
-		base_total_time += base_data[i]["Total"]["Time"].asReal();
-	}
-
 	//allocate raw scratch space
 	LLPointer<LLImageRaw> scratch = new LLImageRaw(1024, 512, 3);
 
@@ -716,7 +702,6 @@ void LLFastTimerView::exportCharts(const std::string& base, const std::string& t
 		//======================================
 		buffer.clear();
 
-
 		gGL.color3fv(base_col.mV);
 		U32 count = 0;
 		U32 total_count = base_execution.size();
@@ -1019,11 +1004,9 @@ void LLFastTimerView::printLineStats()
 	}
 }
 
-static LLTrace::BlockTimerStatHandle FTM_DRAW_LINE_GRAPH("Draw line graph");
-
 void LLFastTimerView::drawLineGraph()
 {
-	LL_RECORD_BLOCK_TIME(FTM_DRAW_LINE_GRAPH);
+    LL_PROFILE_ZONE_SCOPED;
 	//draw line graph history
 	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 	LLLocalClipRect clip(mGraphRect);
@@ -1062,6 +1045,7 @@ void LLFastTimerView::drawLineGraph()
 
 	F32Seconds cur_max(0);
 	U32 cur_max_calls = 0;
+
 	for(block_timer_tree_df_iterator_t it = LLTrace::begin_block_timer_tree_df(FTM_FRAME);
 		it != LLTrace::end_block_timer_tree_df();
 		++it)
@@ -1096,6 +1080,7 @@ void LLFastTimerView::drawLineGraph()
 		F32 call_scale_factor = (F32)mGraphRect.getHeight() / (F32)max_calls;
 		F32 time_scale_factor = (F32)mGraphRect.getHeight() / max_time.value();
 		F32 hz_scale_factor = (F32) mGraphRect.getHeight() / (1.f / max_time.value());
+        
 		for (U32 j = mRecording.getNumRecordedPeriods();
 			j > 0;
 			j--)
@@ -1103,7 +1088,7 @@ void LLFastTimerView::drawLineGraph()
 			LLTrace::Recording& recording = mRecording.getPrevRecording(j);
 			F32Seconds time = llmax(recording.getSum(*idp), F64Seconds(0.000001));
 			U32 calls = recording.getSum(idp->callCount());
-
+            
 			if (is_hover_timer)
 			{ 
 				//normalize to highlighted timer
@@ -1450,6 +1435,7 @@ void LLFastTimerView::updateTotalTime()
 
 void LLFastTimerView::drawBars()
 {
+    LL_PROFILE_ZONE_SCOPED;
 	LLLocalClipRect clip(mBarRect);
 
 	S32 bar_height = mBarRect.getHeight() / (MAX_VISIBLE_HISTORY + 2);
@@ -1527,11 +1513,9 @@ void LLFastTimerView::drawBars()
 	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 }
 
-static LLTrace::BlockTimerStatHandle FTM_UPDATE_TIMER_BAR_WIDTHS("Update timer bar widths");
-
 F32Seconds LLFastTimerView::updateTimerBarWidths(LLTrace::BlockTimerStatHandle* time_block, TimerBarRow& row, S32 history_index, U32& bar_index)
 {
-	LL_RECORD_BLOCK_TIME(FTM_UPDATE_TIMER_BAR_WIDTHS);
+    LL_PROFILE_ZONE_SCOPED;
 	const F32Seconds self_time = history_index == -1
 										? mRecording.getPeriodMean(time_block->selfTime(), RUNNING_AVERAGE_WIDTH) 
 										: mRecording.getPrevRecording(history_index).getSum(time_block->selfTime());
@@ -1555,11 +1539,9 @@ F32Seconds LLFastTimerView::updateTimerBarWidths(LLTrace::BlockTimerStatHandle*
 	return full_time;
 }
 
-static LLTrace::BlockTimerStatHandle FTM_UPDATE_TIMER_BAR_FRACTIONS("Update timer bar fractions");
-
 S32 LLFastTimerView::updateTimerBarOffsets(LLTrace::BlockTimerStatHandle* time_block, TimerBarRow& row, S32 timer_bar_index)
 {
-	LL_RECORD_BLOCK_TIME(FTM_UPDATE_TIMER_BAR_FRACTIONS);
+    LL_PROFILE_ZONE_SCOPED;
 
 	TimerBar& timer_bar = row.mBars[timer_bar_index];
 	const F32Seconds bar_time = timer_bar.mTotalTime - timer_bar.mSelfTime;
@@ -1620,6 +1602,7 @@ S32 LLFastTimerView::updateTimerBarOffsets(LLTrace::BlockTimerStatHandle* time_b
 
 S32 LLFastTimerView::drawBar(LLRect bar_rect, TimerBarRow& row, S32 image_width, S32 image_height, bool hovered, bool visible, S32 bar_index)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	TimerBar& timer_bar = row.mBars[bar_index];
 	LLTrace::BlockTimerStatHandle* time_block = timer_bar.mTimeBlock;
 
diff --git a/indra/newview/llfavoritesbar.cpp b/indra/newview/llfavoritesbar.cpp
index c13b63433c42f760964d891e5429d378ae7443f3..70e843719094c41791d5ce14f34071b0bcd08c86 100644
--- a/indra/newview/llfavoritesbar.cpp
+++ b/indra/newview/llfavoritesbar.cpp
@@ -471,7 +471,25 @@ BOOL LLFavoritesBarCtrl::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
 			}
 
 			// check if we are dragging an existing item from the favorites bar
-			if (item && mDragItemId == item->getUUID())
+            bool existing_drop = false;
+            if (item && mDragItemId == item->getUUID())
+            {
+                // There is a chance of mDragItemId being obsolete
+                // ex: can happen if something interrupts viewer, which
+                // results in viewer not geting a 'mouse up' signal
+                for (LLInventoryModel::item_array_t::iterator i = mItems.begin(); i != mItems.end(); ++i)
+                {
+                    LLViewerInventoryItem* currItem = *i;
+
+                    if (currItem->getUUID() == mDragItemId)
+                    {
+                        existing_drop = true;
+                        break;
+                    }
+                }
+            }
+
+            if (existing_drop)
 			{
 				*accept = ACCEPT_YES_SINGLE;
 
@@ -500,6 +518,7 @@ BOOL LLFavoritesBarCtrl::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
 					if (mItems.empty())
 					{
 						setLandingTab(NULL);
+                        mLastTab = NULL;
 					}
 					handleNewFavoriteDragAndDrop(item, favorites_id, x, y);
 				}
@@ -515,6 +534,12 @@ BOOL LLFavoritesBarCtrl::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
 
 void LLFavoritesBarCtrl::handleExistingFavoriteDragAndDrop(S32 x, S32 y)
 {
+    if (mItems.empty())
+    {
+        // Isn't supposed to be empty
+        return;
+    }
+
 	// Identify the button hovered and the side to drop
 	LLFavoriteLandmarkButton* dest = dynamic_cast<LLFavoriteLandmarkButton*>(mLandingTab);
 	bool insert_before = true;	
@@ -772,6 +797,14 @@ void LLFavoritesBarCtrl::updateButtons(bool force_update)
 	    }
 	    LLFavoritesOrderStorage::instance().mPrevFavorites = mItems;
 		mGetPrevItems = false;
+
+		if (LLFavoritesOrderStorage::instance().isStorageUpdateNeeded())
+		{
+			if (!mItemsChangedTimer.getStarted())
+			{
+				mItemsChangedTimer.start();
+			}
+		}
 	}
 
 	const LLButton::Params& button_params = getButtonParams();
@@ -779,6 +812,7 @@ void LLFavoritesBarCtrl::updateButtons(bool force_update)
 	if(mItems.empty())
 	{
 		mBarLabel->setVisible(TRUE);
+        mLastTab = NULL;
 	}
 	else
 	{
@@ -825,6 +859,10 @@ void LLFavoritesBarCtrl::updateButtons(bool force_update)
 					dynamic_cast<LLFavoriteLandmarkButton*> (*cur_it);
 			if (button)
 			{
+                if (mLastTab == button)
+                {
+                    mLastTab = NULL;
+                }
 				removeChild(button);
 				delete button;
 			}
@@ -862,6 +900,17 @@ void LLFavoritesBarCtrl::updateButtons(bool force_update)
 
 			mLastTab = last_new_button;
 		}
+        if (!mLastTab && mItems.size() > 0)
+        {
+            // mMoreTextBox was removed, so LLFavoriteLandmarkButtons
+            // should be the only ones in the list
+            LLFavoriteLandmarkButton* button = dynamic_cast<LLFavoriteLandmarkButton*> (childs->back());
+            if (button)
+            {
+                mLastTab = button;
+            }
+        }
+
 		mFirstDropDownItem = j;
 		// Chevron button
 		if (mFirstDropDownItem < mItems.size())
@@ -1606,7 +1655,7 @@ void LLFavoritesOrderStorage::destroyClass()
 		file.close();
 		LLFile::remove(filename);
 	}
-	if(mSaveOnExit)
+	if(mSaveOnExit || gSavedSettings.getBOOL("UpdateRememberPasswordSetting"))
 	{
 	    LLFavoritesOrderStorage::instance().saveFavoritesRecord(true);
 	}
@@ -1650,7 +1699,6 @@ void LLFavoritesOrderStorage::load()
 			llifstream in_file;
 			in_file.open(filename.c_str());
 			LLSD fav_llsd;
-			LLSD user_llsd;
 			if (in_file.is_open())
 			{
 				LLSDSerialize::fromXML(fav_llsd, in_file);
@@ -1660,12 +1708,12 @@ void LLFavoritesOrderStorage::load()
 				in_file.close();
 				if (fav_llsd.isMap() && fav_llsd.has(gAgentUsername))
 				{
-					user_llsd = fav_llsd[gAgentUsername];
+					mStorageFavorites = fav_llsd[gAgentUsername];
 
 					S32 index = 0;
 					bool needs_validation = gSavedPerAccountSettings.getBOOL("ShowFavoritesOnLogin");
-					for (LLSD::array_iterator iter = user_llsd.beginArray();
-						iter != user_llsd.endArray(); ++iter)
+					for (LLSD::array_iterator iter = mStorageFavorites.beginArray();
+						iter != mStorageFavorites.endArray(); ++iter)
 					{
 						// Validation
 						LLUUID fv_id = iter->get("id").asUUID();
@@ -1967,7 +2015,7 @@ BOOL LLFavoritesOrderStorage::saveFavoritesRecord(bool pref_changed)
 		}
 	}
 
-	if((items != mPrevFavorites) || name_changed || pref_changed)
+	if((items != mPrevFavorites) || name_changed || pref_changed || gSavedSettings.getBOOL("UpdateRememberPasswordSetting"))
 	{
 	    std::string filename = getStoredFavoritesFilename();
 		if (!filename.empty())
@@ -1988,6 +2036,12 @@ BOOL LLFavoritesOrderStorage::saveFavoritesRecord(bool pref_changed)
 			LLSD user_llsd;
 			S32 fav_iter = 0;
 			mMissingSLURLs.clear();
+
+            LLSD save_pass;
+            save_pass["save_password"] = gSavedSettings.getBOOL("RememberPassword");
+            user_llsd[fav_iter] = save_pass;
+            fav_iter++;
+
 			for (LLInventoryModel::item_array_t::iterator it = items.begin(); it != items.end(); it++)
 			{
 				LLSD value;
@@ -2058,6 +2112,23 @@ void LLFavoritesOrderStorage::showFavoritesOnLoginChanged(BOOL show)
 	}
 }
 
+bool LLFavoritesOrderStorage::isStorageUpdateNeeded()
+{
+	if (!mRecreateFavoriteStorage)
+	{
+		for (LLSD::array_iterator iter = mStorageFavorites.beginArray();
+			iter != mStorageFavorites.endArray(); ++iter)
+		{
+			if (mFavoriteNames[iter->get("id").asUUID()] != iter->get("name").asString())
+			{
+				mRecreateFavoriteStorage = true;
+				return true;
+			}
+		}
+	}
+	return false;
+}
+
 void AddFavoriteLandmarkCallback::fire(const LLUUID& inv_item_id)
 {
 	if (mTargetLandmarkId.isNull()) return;
diff --git a/indra/newview/llfavoritesbar.h b/indra/newview/llfavoritesbar.h
index 2d7ba9df674a62c3657da0cfd304d8902f8556d3..3b439b31fddeedca07da361d02703d993bf8d91d 100644
--- a/indra/newview/llfavoritesbar.h
+++ b/indra/newview/llfavoritesbar.h
@@ -226,8 +226,11 @@ class LLFavoritesOrderStorage : public LLSingleton<LLFavoritesOrderStorage>
 	BOOL saveFavoritesRecord(bool pref_changed = false);
 	void showFavoritesOnLoginChanged(BOOL show);
 
-	LLInventoryModel::item_array_t mPrevFavorites;
+	bool isStorageUpdateNeeded();
 
+	LLInventoryModel::item_array_t mPrevFavorites;
+	LLSD mStorageFavorites;
+	bool mRecreateFavoriteStorage;
 
 	const static S32 NO_INDEX;
 	static bool mSaveOnExit;
@@ -254,7 +257,6 @@ class LLFavoritesOrderStorage : public LLSingleton<LLFavoritesOrderStorage>
 	slurls_map_t mSLURLs;
 	std::set<LLUUID> mMissingSLURLs;
 	bool mIsDirty;
-	bool mRecreateFavoriteStorage;
 
 	struct IsNotInFavorites
 	{
diff --git a/indra/newview/llfeaturemanager.cpp b/indra/newview/llfeaturemanager.cpp
index e6bbe234b3e56f93aca526375adecaa83c3f78d1..e934041e2eb0e486a21d98856ada51f81b20448d 100644
--- a/indra/newview/llfeaturemanager.cpp
+++ b/indra/newview/llfeaturemanager.cpp
@@ -381,7 +381,10 @@ F32 gpu_benchmark();
 
 F32 logExceptionBenchmark()
 {
-    // Todo: make a wrapper/class for SEH exceptions
+    // FIXME: gpu_benchmark uses many C++ classes on the stack to control state.
+    //  SEH exceptions with our current exception handling options do not call 
+    //  destructors for these classes, resulting in an undefined state should
+    //  this handler be invoked.  
     F32 gbps = -1;
     __try
     {
@@ -389,6 +392,9 @@ F32 logExceptionBenchmark()
     }
     __except (msc_exception_filter(GetExceptionCode(), GetExceptionInformation()))
     {
+        // HACK - ensure that profiling is disabled
+        LLGLSLShader::finishProfile(false);
+
         // convert to C++ styled exception
         char integer_string[32];
         sprintf(integer_string, "SEH, code: %lu\n", GetExceptionCode());
@@ -520,7 +526,6 @@ void LLFeatureManager::initSingleton()
 
 void LLFeatureManager::applyRecommendedSettings()
 {
-	loadGPUClass();
 	// apply saved settings
 	// cap the level at 2 (high)
 	U32 level = llmax(GPU_CLASS_0, llmin(mGPUClass, GPU_CLASS_5));
@@ -607,22 +612,6 @@ void LLFeatureManager::setGraphicsLevel(U32 level, bool skipFeatures)
 
     // if we're passed an invalid level, default to "Low"
     std::string features(isValidGraphicsLevel(level)? getNameForGraphicsLevel(level) : "Low");
-    if (features == "Low")
-    {
-#if LL_DARWIN
-        // This Mac-specific change is to insure that we force 'Basic Shaders' for all Mac
-        // systems which support them instead of falling back to fixed-function unnecessarily
-        // MAINT-2157
-        if (gGLManager.mGLVersion < 2.1f)
-#else
-        // only use fixed function by default if GL version < 3.0 or this is an intel graphics chip
-        if (gGLManager.mGLVersion < 3.f || gGLManager.mIsIntel)
-#endif
-        {
-            // same as Low, but with "Basic Shaders" disabled
-            features = "LowFixedFunction";
-        }
-    }
 
     maskFeatures(features);
 
@@ -670,46 +659,18 @@ void LLFeatureManager::applyBaseMasks()
 	}
 
 	// now all those wacky ones
-	if (!gGLManager.mHasFragmentShader)
-	{
-		maskFeatures("NoPixelShaders");
-	}
-	if (!gGLManager.mHasVertexShader || !mGPUSupported)
-	{
-		maskFeatures("NoVertexShaders");
-	}
 	if (gGLManager.mIsNVIDIA)
 	{
 		maskFeatures("NVIDIA");
 	}
-	if (gGLManager.mIsGF2or4MX)
-	{
-		maskFeatures("GeForce2");
-	}
-	if (gGLManager.mIsATI)
-	{
-		maskFeatures("ATI");
-	}
-	if (gGLManager.mHasATIMemInfo && gGLManager.mVRAM < 256)
+	if (gGLManager.mIsAMD)
 	{
-		maskFeatures("ATIVramLT256");
-	}
-	if (gGLManager.mATIOldDriver)
-	{
-		maskFeatures("ATIOldDriver");
-	}
-	if (gGLManager.mIsGFFX)
-	{
-		maskFeatures("GeForceFX");
+		maskFeatures("AMD");
 	}
 	if (gGLManager.mIsIntel)
 	{
 		maskFeatures("Intel");
 	}
-	if (gGLManager.mGLVersion < 1.5f)
-	{
-		maskFeatures("OpenGLPre15");
-	}
 	if (gGLManager.mGLVersion < 3.f)
 	{
 		maskFeatures("OpenGLPre30");
@@ -749,17 +710,6 @@ void LLFeatureManager::applyBaseMasks()
 	//LL_INFOS() << "Masking features from gpu table match: " << gpustr << LL_ENDL;
 	maskFeatures(gpustr);
 
-	// now mask cpu type ones
-	if (gSysMemory.getPhysicalMemoryKB() <= U32Megabytes(256))
-	{
-		maskFeatures("RAM256MB");
-	}
-	
-	if (gSysCPU.getMHz() < 1100)
-	{
-		maskFeatures("CPUSlow");
-	}
-
 	if (isSafe())
 	{
 		maskFeatures("safe");
@@ -774,11 +724,9 @@ LLSD LLFeatureManager::getRecommendedSettingsMap()
 
 	LLSD map(LLSD::emptyMap());
 
-	loadGPUClass();
 	U32 level = llmax(GPU_CLASS_0, llmin(mGPUClass, GPU_CLASS_5));
 	LL_INFOS("RenderInit") << "Getting the map of recommended settings for level " << level << LL_ENDL;
 
-	applyBaseMasks();
 	std::string features(isValidGraphicsLevel(level) ? getNameForGraphicsLevel(level) : "Low");
 
 	maskFeatures(features);
diff --git a/indra/newview/llflexibleobject.cpp b/indra/newview/llflexibleobject.cpp
index a24d1d1436153af96dbecf4bbe4fdd0778b27b52..d5115df35f6711967e3c2141905d22482d2e407e 100644
--- a/indra/newview/llflexibleobject.cpp
+++ b/indra/newview/llflexibleobject.cpp
@@ -47,9 +47,6 @@ static const F32 SEC_PER_FLEXI_FRAME = 1.f / 60.f; // 60 flexi updates per secon
 /*static*/ F32 LLVolumeImplFlexible::sUpdateFactor = 1.0f;
 std::vector<LLVolumeImplFlexible*> LLVolumeImplFlexible::sInstanceList;
 
-static LLTrace::BlockTimerStatHandle FTM_FLEXIBLE_REBUILD("Rebuild");
-static LLTrace::BlockTimerStatHandle FTM_DO_FLEXIBLE_UPDATE("Flexible Update");
-
 // LLFlexibleObjectData::pack/unpack now in llprimitive.cpp
 
 //-----------------------------------------------
@@ -95,7 +92,7 @@ LLVolumeImplFlexible::~LLVolumeImplFlexible()
 //static
 void LLVolumeImplFlexible::updateClass()
 {
-	LL_RECORD_BLOCK_TIME(FTM_DO_FLEXIBLE_UPDATE);
+    LL_PROFILE_ZONE_SCOPED;
 
 	U64 virtual_frame_num = LLTimer::getElapsedSeconds() / SEC_PER_FLEXI_FRAME;
 	for (std::vector<LLVolumeImplFlexible*>::iterator iter = sInstanceList.begin();
@@ -389,7 +386,8 @@ void LLVolumeImplFlexible::doIdleUpdate()
 						U64 throttling_delay = (virtual_frame_num + id) % update_period;
 
 						if ((throttling_delay == 0 && mLastFrameNum < virtual_frame_num) //one or more virtual frames per frame
-							|| (mLastFrameNum + update_period < virtual_frame_num)) // missed virtual frame
+							|| (mLastFrameNum + update_period < virtual_frame_num) // missed virtual frame
+							|| mLastFrameNum > virtual_frame_num) // overflow
 						{
 							// We need mLastFrameNum to compensate for 'unreliable time' and to filter 'duplicate' frames
 							// If happened too late, subtract throttling_delay (it is zero otherwise)
@@ -429,7 +427,7 @@ inline S32 log2(S32 x)
 
 void LLVolumeImplFlexible::doFlexibleUpdate()
 {
-	LL_RECORD_BLOCK_TIME(FTM_DO_FLEXIBLE_UPDATE);
+    LL_PROFILE_ZONE_SCOPED;
 	LLVolume* volume = mVO->getVolume();
 	LLPath *path = &volume->getPath();
 	if ((mSimulateRes == 0 || !mInitialized) && mVO->mDrawable->isVisible()) 
@@ -720,13 +718,12 @@ void LLVolumeImplFlexible::doFlexibleUpdate()
 	mLastSegmentRotation = parentSegmentRotation;
 }
 
-static LLTrace::BlockTimerStatHandle FTM_FLEXI_PREBUILD("Flexi Prebuild");
 
 void LLVolumeImplFlexible::preRebuild()
 {
 	if (!mUpdated)
 	{
-		LL_RECORD_BLOCK_TIME(FTM_FLEXI_PREBUILD);
+        LL_PROFILE_ZONE_SCOPED;
 		doFlexibleRebuild(false);
 	}
 }
@@ -755,6 +752,7 @@ void LLVolumeImplFlexible::onSetScale(const LLVector3& scale, BOOL damped)
 
 BOOL LLVolumeImplFlexible::doUpdateGeometry(LLDrawable *drawable)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	LLVOVolume *volume = (LLVOVolume*)mVO;
 
 	if (mVO->isAttachment())
@@ -790,11 +788,7 @@ BOOL LLVolumeImplFlexible::doUpdateGeometry(LLDrawable *drawable)
 
 	volume->updateRelativeXform();
 
-	if (mRenderRes > -1)
-	{
-		LL_RECORD_BLOCK_TIME(FTM_DO_FLEXIBLE_UPDATE);
-		doFlexibleUpdate();
-	}
+	doFlexibleUpdate();
 	
 	// Object may have been rotated, which means it needs a rebuild.  See SL-47220
 	BOOL	rotated = FALSE;
@@ -812,7 +806,6 @@ BOOL LLVolumeImplFlexible::doUpdateGeometry(LLDrawable *drawable)
 		volume->mDrawable->setState(LLDrawable::REBUILD_VOLUME);
 		volume->dirtySpatialGroup();
 		{
-			LL_RECORD_BLOCK_TIME(FTM_FLEXIBLE_REBUILD);
 			doFlexibleRebuild(volume->mVolumeChanged);
 		}
 		volume->genBBoxes(isVolumeGlobal());
diff --git a/indra/newview/llfloater360capture.cpp b/indra/newview/llfloater360capture.cpp
index ffbb0bbee9a062c9af631e0937e9b69192289feb..c075f7e8bdd3f9be33733f96677bf866830bb0d5 100644
--- a/indra/newview/llfloater360capture.cpp
+++ b/indra/newview/llfloater360capture.cpp
@@ -114,6 +114,11 @@ BOOL LLFloater360Capture::postBuild()
     // by default each time vs restoring the last value
     mQualityRadioGroup->setSelectedIndex(0);
 
+    return true;
+}
+
+void LLFloater360Capture::onOpen(const LLSD& key)
+{
     // Construct a URL pointing to the first page to load. Although
     // we do not use this page for anything (after some significant
     // design changes), we retain the code to load the start page
@@ -154,8 +159,6 @@ BOOL LLFloater360Capture::postBuild()
     // We do an initial capture when the floater is opened, albeit at a 'preview'
     // quality level (really low resolution, but really fast)
     onCapture360ImagesBtn();
-
-    return true;
 }
 
 // called when the user choose a quality level using
diff --git a/indra/newview/llfloater360capture.h b/indra/newview/llfloater360capture.h
index 6da7ee074a399e4fa25f76af36aac1d0b18ab718..8f765c0b1be16019fd22089cacf0891c56017788 100644
--- a/indra/newview/llfloater360capture.h
+++ b/indra/newview/llfloater360capture.h
@@ -47,6 +47,7 @@ class LLFloater360Capture:
 
         ~LLFloater360Capture();
         BOOL postBuild() override;
+        void onOpen(const LLSD& key) override;
         void handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event) override;
 
         void changeInterestListMode(bool send_everything);
diff --git a/indra/newview/llfloateravatarpicker.cpp b/indra/newview/llfloateravatarpicker.cpp
index ab95bc06b889f1fcbdf7da58130dc6690561e77f..0186c4aebefa2dea030c0d903de74a928bc164ee 100644
--- a/indra/newview/llfloateravatarpicker.cpp
+++ b/indra/newview/llfloateravatarpicker.cpp
@@ -105,6 +105,7 @@ LLFloaterAvatarPicker::LLFloaterAvatarPicker(const LLSD& key)
 	mNumResultsReturned(0),
 	mNearMeListComplete(FALSE),
 	mCloseOnSelect(FALSE),
+    mExcludeAgentFromSearchResults(FALSE),
     mContextConeOpacity	(0.f),
     mContextConeInAlpha(0.f),
     mContextConeOutAlpha(0.f),
@@ -295,7 +296,7 @@ void LLFloaterAvatarPicker::populateNearMe()
 	for(U32 i=0; i<avatar_ids.size(); i++)
 	{
 		LLUUID& av = avatar_ids[i];
-		if(av == gAgent.getID()) continue;
+		if(mExcludeAgentFromSearchResults && (av == gAgent.getID())) continue;
 		LLSD element;
 		element["id"] = av; // value
 		LLAvatarName av_name;
diff --git a/indra/newview/llfloaterbvhpreview.cpp b/indra/newview/llfloaterbvhpreview.cpp
index 687d820a18a7bef4acd1d89f6c1abf0d5ba1d4b8..ed3dc37043d27ac1c1ddc8ee1857836c6e769e6c 100644
--- a/indra/newview/llfloaterbvhpreview.cpp
+++ b/indra/newview/llfloaterbvhpreview.cpp
@@ -294,7 +294,7 @@ BOOL LLFloaterBvhPreview::postBuild()
 		loaderp->serialize(dp);
 		dp.reset();
 		LL_INFOS("BVH") << "Deserializing motionp" << LL_ENDL;
-		BOOL success = motionp && motionp->deserialize(dp, mMotionID);
+		BOOL success = motionp && motionp->deserialize(dp, mMotionID, false);
 		LL_INFOS("BVH") << "Done" << LL_ENDL;
 
 		delete []buffer;
@@ -1047,7 +1047,12 @@ LLPreviewAnimation::LLPreviewAnimation(S32 width, S32 height) : LLViewerDynamicT
 	mDummyAvatar = (LLVOAvatar*)gObjectList.createObjectViewer(LL_PCODE_LEGACY_AVATAR, gAgent.getRegion(), LLViewerObject::CO_FLAG_UI_AVATAR);
 	mDummyAvatar->mSpecialRenderMode = 1;
 	mDummyAvatar->startMotion(ANIM_AGENT_STAND, BASE_ANIM_TIME_OFFSET);
-	mDummyAvatar->hideSkirt();
+
+    // on idle overall apperance update will set skirt to visible, so either
+    // call early or account for mSpecialRenderMode in updateMeshVisibility
+    mDummyAvatar->updateOverallAppearance();
+    mDummyAvatar->hideHair();
+    mDummyAvatar->hideSkirt();
 
 	// stop extraneous animations
 	mDummyAvatar->stopMotion( ANIM_AGENT_HEAD_ROT, TRUE );
@@ -1087,10 +1092,7 @@ BOOL	LLPreviewAnimation::render()
 	gGL.pushMatrix();
 	gGL.loadIdentity();
 
-	if (LLGLSLShader::sNoFixedFunction)
-	{
-		gUIProgram.bind();
-	}
+	gUIProgram.bind();
 
 	LLGLSUIDefault def;
 	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
@@ -1138,6 +1140,7 @@ BOOL	LLPreviewAnimation::render()
 		{
 			LLDrawPoolAvatar *avatarPoolp = (LLDrawPoolAvatar *)face->getPool();
 			avatarp->dirtyMesh();
+            gPipeline.enableLightsPreview();
 			avatarPoolp->renderAvatars(avatarp);  // renders only one avatar
 		}
 	}
diff --git a/indra/newview/llfloatercamera.cpp b/indra/newview/llfloatercamera.cpp
index 3b192ff81b00c0ba6cdb1742ed94f78f570b4050..1c69b9d60baa026ba66c90e94c5b325658cc75b8 100644
--- a/indra/newview/llfloatercamera.cpp
+++ b/indra/newview/llfloatercamera.cpp
@@ -453,18 +453,18 @@ void LLFloaterCamera::setMode(ECameraControlMode mode)
 
 void LLFloaterCamera::switchMode(ECameraControlMode mode)
 {
-	setMode(mode);
-
 	switch (mode)
 	{
 	case CAMERA_CTRL_MODE_PRESETS:
 	case CAMERA_CTRL_MODE_PAN:
 		sFreeCamera = false;
+		setMode(mode); // depends onto sFreeCamera
 		clear_camera_tool();
 		break;
 
 	case CAMERA_CTRL_MODE_FREE_CAMERA:
 		sFreeCamera = true;
+		setMode(mode);
 		activate_camera_tool();
 		break;
 
diff --git a/indra/newview/llfloaterchatvoicevolume.cpp b/indra/newview/llfloaterchatvoicevolume.cpp
index 45aea00a49e3a31f5fe1ef65b836e0ece56e88f1..67c412dfa65f8955366426e38968eb7798d544b3 100644
--- a/indra/newview/llfloaterchatvoicevolume.cpp
+++ b/indra/newview/llfloaterchatvoicevolume.cpp
@@ -35,7 +35,7 @@ LLFloaterChatVoiceVolume::LLFloaterChatVoiceVolume(const LLSD& key)
 void LLFloaterChatVoiceVolume::onOpen(const LLSD& key)
 {
 	LLInspect::onOpen(key);
-	LLUI::getInstance()->positionViewNearMouse(this);
+	LLInspect::repositionInspector(key);
 }
 
 LLFloaterChatVoiceVolume::~LLFloaterChatVoiceVolume()
diff --git a/indra/newview/llfloaterclassified.cpp b/indra/newview/llfloaterclassified.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..3520b0f67aad50ef064618955e5129bfd7b11d69
--- /dev/null
+++ b/indra/newview/llfloaterclassified.cpp
@@ -0,0 +1,71 @@
+/**
+ * @file llfloaterclassified.cpp
+ * @brief LLFloaterClassified for displaying classifieds.
+ *
+ * $LicenseInfo:firstyear=2022&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2022, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llfloaterclassified.h"
+
+LLFloaterClassified::LLFloaterClassified(const LLSD& key)
+ : LLFloater(key)
+{
+}
+
+LLFloaterClassified::~LLFloaterClassified()
+{
+}
+
+void LLFloaterClassified::onOpen(const LLSD& key)
+{
+    LLPanel* panel = findChild<LLPanel>("main_panel", true);
+    if (panel)
+    {
+        panel->onOpen(key);
+    }
+    if (key.has("classified_name"))
+    {
+        setTitle(key["classified_name"].asString());
+    }
+    LLFloater::onOpen(key);
+}
+
+BOOL LLFloaterClassified::postBuild()
+{
+    return TRUE;
+}
+
+
+bool LLFloaterClassified::matchesKey(const LLSD& key)
+{
+    bool is_mkey_valid = mKey.has("classified_id");
+    bool is_key_valid = key.has("classified_id");
+    if (is_mkey_valid && is_key_valid)
+    {
+        return key["classified_id"].asUUID() == mKey["classified_id"].asUUID();
+    }
+    return is_mkey_valid == is_key_valid;
+}
+
+// eof
diff --git a/indra/newview/llfloaterclassified.h b/indra/newview/llfloaterclassified.h
new file mode 100644
index 0000000000000000000000000000000000000000..2c95d82b2c389dc7ab6284d6638585001b41fe6a
--- /dev/null
+++ b/indra/newview/llfloaterclassified.h
@@ -0,0 +1,45 @@
+/**
+ * @file llfloaterclassified.h
+ * @brief LLFloaterClassified for displaying classifieds.
+ *
+ * $LicenseInfo:firstyear=2022&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2022, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLFLOATERCLASSIFIED_H
+#define LL_LLFLOATERCLASSIFIED_H
+
+#include "llfloater.h"
+
+class LLFloaterClassified : public LLFloater
+{
+    LOG_CLASS(LLFloaterClassified);
+public:
+    LLFloaterClassified(const LLSD& key);
+    virtual ~LLFloaterClassified();
+
+    void onOpen(const LLSD& key) override;
+    BOOL postBuild() override;
+
+    bool matchesKey(const LLSD& key) override;
+};
+
+#endif // LL_LLFLOATERCLASSIFIED_H
diff --git a/indra/newview/llfloatercolorpicker.cpp b/indra/newview/llfloatercolorpicker.cpp
index 1a784223c2eb0084645ccef108fb203e3f09fcff..ba91277c79c7a325e6176d623db71358a608087d 100644
--- a/indra/newview/llfloatercolorpicker.cpp
+++ b/indra/newview/llfloatercolorpicker.cpp
@@ -173,7 +173,6 @@ void LLFloaterColorPicker::showUI ()
 	openFloater(getKey());
 	setVisible ( TRUE );
 	setFocus ( TRUE );
-	setRevertOnCancel(FALSE);
 
 	// HACK: if system color picker is required - close the SL one we made and use default system dialog
 	if ( gSavedSettings.getBOOL ( "UseDefaultColorPicker" ) )
@@ -185,15 +184,23 @@ void LLFloaterColorPicker::showUI ()
 		// code that will get switched in for default system color picker
 		if ( swatch )
 		{
+            // Todo: this needs to be threaded for viewer not to timeout
 			LLColor4 curCol = swatch->get ();
 			send_agent_pause();
-			getWindow()->dialogColorPicker( &curCol [ 0 ], &curCol [ 1 ], &curCol [ 2 ] );
+			bool commit = getWindow()->dialogColorPicker( &curCol [ 0 ], &curCol [ 1 ], &curCol [ 2 ] );
 			send_agent_resume();
 
-			setOrigRgb ( curCol [ 0 ], curCol [ 1 ], curCol [ 2 ] );
-			setCurRgb( curCol [ 0 ], curCol [ 1 ], curCol [ 2 ] );
-
-			LLColorSwatchCtrl::onColorChanged ( swatch, LLColorSwatchCtrl::COLOR_CHANGE );
+            if (commit)
+            {
+                setOrigRgb(curCol[0], curCol[1], curCol[2]);
+                setCurRgb(curCol[0], curCol[1], curCol[2]);
+
+                LLColorSwatchCtrl::onColorChanged(swatch, LLColorSwatchCtrl::COLOR_SELECT);
+            }
+            else
+            {
+                LLColorSwatchCtrl::onColorChanged(swatch, LLColorSwatchCtrl::COLOR_CANCEL);
+            }
 		}
 
 		closeFloater();
@@ -391,10 +398,7 @@ void LLFloaterColorPicker::onClickCancel ( void* data )
 
 		if ( self )
 		{
-		    if(self->getRevertOnCancel())
-		    {
-		        self->cancelSelection ();
-		    }
+		    self->cancelSelection();
 			self->closeFloater();
 		}
 	}
diff --git a/indra/newview/llfloatercolorpicker.h b/indra/newview/llfloatercolorpicker.h
index 16974a872ef4f167b2bf4379d150bf405098207d..39dbc5b763702a32fca903af45464da56f7a28dd 100644
--- a/indra/newview/llfloatercolorpicker.h
+++ b/indra/newview/llfloatercolorpicker.h
@@ -104,9 +104,6 @@ class LLFloaterColorPicker
 		void setMouseDownInSwatch (BOOL mouse_down_in_swatch);
 		BOOL getMouseDownInSwatch () { return mMouseDownInSwatch; }
 
-		void setRevertOnCancel (BOOL revertOnCancel) { mRevertOnCancel = revertOnCancel; };
-		BOOL getRevertOnCancel () { return mRevertOnCancel; }
-
 		BOOL isColorChanged ();
 
 		// called when text entries (RGB/HSL etc.) are changed by user
@@ -149,8 +146,6 @@ class LLFloaterColorPicker
 		BOOL mMouseDownInHueRegion;
 		BOOL mMouseDownInSwatch;
 
-		BOOL mRevertOnCancel;
-
 		const S32 mRGBViewerImageLeft;
 		const S32 mRGBViewerImageTop;
 		const S32 mRGBViewerImageWidth;
diff --git a/indra/newview/llfloatercreatelandmark.cpp b/indra/newview/llfloatercreatelandmark.cpp
index 6b1d9306fb2f9e481232db9b5b5861068767f2ce..7def855d83cd945d496c4f845becbbe066f2b894 100644
--- a/indra/newview/llfloatercreatelandmark.cpp
+++ b/indra/newview/llfloatercreatelandmark.cpp
@@ -46,19 +46,60 @@
 
 typedef std::pair<LLUUID, std::string> folder_pair_t;
 
-class LLLandmarksInventoryObserver : public LLInventoryAddedObserver
+class LLLandmarksInventoryObserver : public LLInventoryObserver
 {
 public:
 	LLLandmarksInventoryObserver(LLFloaterCreateLandmark* create_landmark_floater) :
 		mFloater(create_landmark_floater)
 	{}
 
+    void changed(U32 mask) override
+    {
+        if (mFloater->getItem())
+        {
+            checkChanged(mask);
+        }
+        else
+        {
+            checkCreated(mask);
+        }
+    }
+
 protected:
-	/*virtual*/ void done()
+	void checkCreated(U32 mask)
 	{
+        if (gInventory.getAddedIDs().empty())
+        {
+            return;
+        }
+
+        if (!(mask & LLInventoryObserver::ADD) ||
+            !(mask & LLInventoryObserver::CREATE) ||
+            !(mask & LLInventoryObserver::UPDATE_CREATE))
+        {
+            return;
+        }
+
 		mFloater->setItem(gInventory.getAddedIDs());
 	}
 
+    void checkChanged(U32 mask)
+    {
+        if (gInventory.getChangedIDs().empty())
+        {
+            return;
+        }
+
+        if ((mask & LLInventoryObserver::LABEL) ||
+            (mask & LLInventoryObserver::INTERNAL) ||
+            (mask & LLInventoryObserver::REMOVE) ||
+            (mask & LLInventoryObserver::STRUCTURE) ||
+            (mask & LLInventoryObserver::REBUILD))
+        {
+            mFloater->updateItem(gInventory.getChangedIDs(), mask);
+        }
+    }
+
 private:
 	LLFloaterCreateLandmark* mFloater;
 };
@@ -85,6 +126,9 @@ BOOL LLFloaterCreateLandmark::postBuild()
 	getChild<LLButton>("ok_btn")->setClickedCallback(boost::bind(&LLFloaterCreateLandmark::onSaveClicked, this));
 	getChild<LLButton>("cancel_btn")->setClickedCallback(boost::bind(&LLFloaterCreateLandmark::onCancelClicked, this));
 
+    mLandmarkTitleEditor->setCommitCallback([this](LLUICtrl* ctrl, const LLSD& param) { onCommitTextChanges(); });
+    mNotesEditor->setCommitCallback([this](LLUICtrl* ctrl, const LLSD& param) { onCommitTextChanges(); });
+
 	mLandmarksID = gInventory.findCategoryUUIDForType(LLFolderType::FT_LANDMARK);
 
 	return TRUE;
@@ -204,6 +248,33 @@ void LLFloaterCreateLandmark::populateFoldersList(const LLUUID &folder_id)
 	}
 }
 
+void LLFloaterCreateLandmark::onCommitTextChanges()
+{
+    if (mItem.isNull())
+    {
+        return;
+    }
+    std::string current_title_value = mLandmarkTitleEditor->getText();
+    std::string item_title_value = mItem->getName();
+    std::string current_notes_value = mNotesEditor->getText();
+    std::string item_notes_value = mItem->getDescription();
+
+    LLStringUtil::trim(current_title_value);
+    LLStringUtil::trim(current_notes_value);
+
+    if (!current_title_value.empty() &&
+        (item_title_value != current_title_value || item_notes_value != current_notes_value))
+    {
+        LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(mItem);
+        new_item->rename(current_title_value);
+        new_item->setDescription(current_notes_value);
+        LLPointer<LLInventoryCallback> cb;
+        LLInventoryModel::LLCategoryUpdate up(mItem->getParentUUID(), 0);
+        gInventory.accountForUpdate(up);
+        update_inventory_item(new_item, cb);
+    }
+}
+
 void LLFloaterCreateLandmark::onCreateFolderClicked()
 {
 	LLNotificationsUtil::add("CreateLandmarkFolder", LLSD(), LLSD(),
@@ -278,6 +349,8 @@ void LLFloaterCreateLandmark::onSaveClicked()
 		new_item->updateParentOnServer(FALSE);
 	}
 
+    removeObserver();
+
 	gInventory.updateItem(new_item);
 	gInventory.notifyObservers();
 
@@ -286,6 +359,7 @@ void LLFloaterCreateLandmark::onSaveClicked()
 
 void LLFloaterCreateLandmark::onCancelClicked()
 {
+    removeObserver();
 	if (!mItem.isNull())
 	{
 		LLUUID item_id = mItem->getUUID();
@@ -314,10 +388,59 @@ void LLFloaterCreateLandmark::setItem(const uuid_set_t& items)
 		{
 			if(!getItem())
 			{
-				removeObserver();
 				mItem = item;
+                mAssetID = mItem->getAssetUUID();
+                setVisibleAndFrontmost(true);
 				break;
 			}
 		}
 	}
 }
+
+void LLFloaterCreateLandmark::updateItem(const uuid_set_t& items, U32 mask)
+{
+    if (!getItem())
+    {
+        return;
+    }
+
+    LLUUID landmark_id = getItem()->getUUID();
+
+    for (uuid_set_t::const_iterator item_iter = items.begin();
+        item_iter != items.end();
+        ++item_iter)
+    {
+        const LLUUID& item_id = (*item_iter);
+        if (landmark_id == item_id)
+        {
+            if (getItem() != gInventory.getItem(item_id))
+            {
+                // item is obsolete or removed
+                closeFloater();
+            }
+
+            LLUUID folder_id = mFolderCombo->getValue().asUUID();
+            if (folder_id != mItem->getParentUUID())
+            {
+                // user moved landmark in inventory,
+                // assume that we are done all other changes should already be commited
+                closeFloater();
+            }
+
+            if ((mask & LLInventoryObserver::INTERNAL) && mAssetID != mItem->getAssetUUID())
+            {
+                closeFloater();
+            }
+
+            if (mask & LLInventoryObserver::LABEL)
+            {
+                mLandmarkTitleEditor->setText(mItem->getName());
+            }
+
+            if (mask & LLInventoryObserver::INTERNAL)
+            {
+                mNotesEditor->setText(mItem->getDescription());
+            }
+        }
+    }
+}
diff --git a/indra/newview/llfloatercreatelandmark.h b/indra/newview/llfloatercreatelandmark.h
index 74ac5e651c1a21bc3599089ee45de27170b4ccb1..d84f5ae1fc5d95d8536e4ba03d438d1a7975ff1d 100644
--- a/indra/newview/llfloatercreatelandmark.h
+++ b/indra/newview/llfloatercreatelandmark.h
@@ -49,6 +49,7 @@ class LLFloaterCreateLandmark:
 	void onOpen(const LLSD& key);
 
 	void setItem(const uuid_set_t& items);
+    void updateItem(const uuid_set_t& items, U32 mask);
 
 	LLInventoryItem* getItem() { return mItem; }
 
@@ -56,6 +57,7 @@ class LLFloaterCreateLandmark:
 	void setLandmarkInfo(const LLUUID &folder_id);
 	void removeObserver();
 	void populateFoldersList(const LLUUID &folder_id = LLUUID::null);
+    void onCommitTextChanges();
 	void onCreateFolderClicked();
 	void onSaveClicked();
 	void onCancelClicked();
@@ -66,6 +68,7 @@ class LLFloaterCreateLandmark:
 	LLLineEditor*	mLandmarkTitleEditor;
 	LLTextEditor*	mNotesEditor;
 	LLUUID			mLandmarksID;
+    LLUUID			mAssetID;
 
 	LLLandmarksInventoryObserver*	mInventoryObserver;
 	LLPointer<LLInventoryItem>		mItem;
diff --git a/indra/newview/llfloaterdisplayname.cpp b/indra/newview/llfloaterdisplayname.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..3b0c67415a35883eb8fe01973d01f5a061836842
--- /dev/null
+++ b/indra/newview/llfloaterdisplayname.cpp
@@ -0,0 +1,200 @@
+/** 
+ * @file llfloaterdisplayname.cpp
+ * @author Leyla Farazha
+ * @brief Implementation of the LLFloaterDisplayName class.
+ *
+ * $LicenseInfo:firstyear=2002&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+
+#include "llviewerprecompiledheaders.h"
+#include "llfloaterreg.h"
+#include "llfloater.h"
+
+#include "llnotificationsutil.h"
+#include "llviewerdisplayname.h"
+
+#include "llnotifications.h"
+#include "llfloaterdisplayname.h"
+#include "llavatarnamecache.h"
+
+#include "llagent.h"
+
+
+class LLFloaterDisplayName : public LLFloater
+{
+public:
+	LLFloaterDisplayName(const LLSD& key);
+	virtual ~LLFloaterDisplayName() { }
+	/*virtual*/	BOOL	postBuild();
+	void onSave();
+	void onCancel();
+	/*virtual*/ void onOpen(const LLSD& key);
+	
+private:
+	
+	void onCacheSetName(bool success,
+										  const std::string& reason,
+										  const LLSD& content);
+};
+
+LLFloaterDisplayName::LLFloaterDisplayName(const LLSD& key) :
+	LLFloater(key)
+{
+}
+
+void LLFloaterDisplayName::onOpen(const LLSD& key)
+{
+	getChild<LLUICtrl>("display_name_editor")->clear();
+	getChild<LLUICtrl>("display_name_confirm")->clear();
+
+	LLAvatarName av_name;
+	LLAvatarNameCache::get(gAgent.getID(), &av_name);
+
+	F64 now_secs = LLDate::now().secondsSinceEpoch();
+
+	if (now_secs < av_name.mNextUpdate)
+	{
+		// ...can't update until some time in the future
+		F64 next_update_local_secs =
+			av_name.mNextUpdate - LLStringOps::getLocalTimeOffset();
+		LLDate next_update_local(next_update_local_secs);
+		// display as "July 18 12:17 PM"
+		std::string next_update_string =
+		next_update_local.toHTTPDateString("%B %d %I:%M %p");
+		getChild<LLUICtrl>("lockout_text")->setTextArg("[TIME]", next_update_string);
+		getChild<LLUICtrl>("lockout_text")->setVisible(true);
+		getChild<LLUICtrl>("save_btn")->setEnabled(false);
+		getChild<LLUICtrl>("display_name_editor")->setEnabled(false);
+		getChild<LLUICtrl>("display_name_confirm")->setEnabled(false);
+		getChild<LLUICtrl>("cancel_btn")->setFocus(TRUE);
+		
+	}
+	else
+	{
+		getChild<LLUICtrl>("lockout_text")->setVisible(false);
+		getChild<LLUICtrl>("save_btn")->setEnabled(true);
+		getChild<LLUICtrl>("display_name_editor")->setEnabled(true);
+		getChild<LLUICtrl>("display_name_confirm")->setEnabled(true);
+
+	}
+}
+
+BOOL LLFloaterDisplayName::postBuild()
+{
+	getChild<LLUICtrl>("cancel_btn")->setCommitCallback(boost::bind(&LLFloaterDisplayName::onCancel, this));	
+	getChild<LLUICtrl>("save_btn")->setCommitCallback(boost::bind(&LLFloaterDisplayName::onSave, this));	
+	
+	center();
+
+	return TRUE;
+}
+
+void LLFloaterDisplayName::onCacheSetName(bool success,
+										  const std::string& reason,
+										  const LLSD& content)
+{
+	if (success)
+	{
+		// Inform the user that the change took place, but will take a while
+		// to percolate.
+		LLSD args;
+		args["DISPLAY_NAME"] = content["display_name"];
+		LLNotificationsUtil::add("SetDisplayNameSuccess", args);
+		return;
+	}
+
+	// Request failed, notify the user
+	std::string error_tag = content["error_tag"].asString();
+	LL_INFOS() << "set name failure error_tag " << error_tag << LL_ENDL;
+
+	// We might have a localized string for this message
+	// error_args will usually be empty from the server.
+	if (!error_tag.empty()
+		&& LLNotifications::getInstance()->templateExists(error_tag))
+	{
+		LLNotificationsUtil::add(error_tag);
+		return;
+	}
+
+	// The server error might have a localized message for us
+	std::string lang_code = LLUI::getLanguage();
+	LLSD error_desc = content["error_description"];
+	if (error_desc.has( lang_code ))
+	{
+		LLSD args;
+		args["MESSAGE"] = error_desc[lang_code].asString();
+		LLNotificationsUtil::add("GenericAlert", args);
+		return;
+	}
+
+	// No specific error, throw a generic one
+	LLNotificationsUtil::add("SetDisplayNameFailedGeneric");
+}
+
+void LLFloaterDisplayName::onCancel()
+{
+	setVisible(false);
+}
+
+void LLFloaterDisplayName::onSave()
+{
+	std::string display_name_utf8 = getChild<LLUICtrl>("display_name_editor")->getValue().asString();
+	std::string display_name_confirm = getChild<LLUICtrl>("display_name_confirm")->getValue().asString();
+
+	if (display_name_utf8.compare(display_name_confirm))
+	{
+		LLNotificationsUtil::add("SetDisplayNameMismatch");
+		return;
+	}
+
+	const U32 DISPLAY_NAME_MAX_LENGTH = 31; // characters, not bytes
+	LLWString display_name_wstr = utf8string_to_wstring(display_name_utf8);
+	if (display_name_wstr.size() > DISPLAY_NAME_MAX_LENGTH)
+	{
+		LLSD args;
+		args["LENGTH"] = llformat("%d", DISPLAY_NAME_MAX_LENGTH);
+		LLNotificationsUtil::add("SetDisplayNameFailedLength", args);
+		return;
+	}
+	
+    if (LLAvatarNameCache::getInstance()->hasNameLookupURL())
+	{
+		LLViewerDisplayName::set(display_name_utf8,boost::bind(&LLFloaterDisplayName::onCacheSetName, this, _1, _2, _3));	
+	}
+	else
+	{
+		LLNotificationsUtil::add("SetDisplayNameFailedGeneric");
+	}
+
+	setVisible(false);
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+// LLInspectObjectUtil
+//////////////////////////////////////////////////////////////////////////////
+void LLFloaterDisplayNameUtil::registerFloater()
+{
+	LLFloaterReg::add("display_name", "floater_display_name.xml",
+					  &LLFloaterReg::build<LLFloaterDisplayName>);
+}
diff --git a/indra/llcommon/timing.cpp b/indra/newview/llfloaterdisplayname.h
similarity index 77%
rename from indra/llcommon/timing.cpp
rename to indra/newview/llfloaterdisplayname.h
index c2dc695ef33304af0abd3df0c6fc78c0f2cb5a92..a00bf56712ce3dfbed1707f92ff971d4cfa71446 100644
--- a/indra/llcommon/timing.cpp
+++ b/indra/newview/llfloaterdisplayname.h
@@ -1,8 +1,7 @@
 /** 
- * @file timing.cpp
- * @brief This file will be deprecated in the future.
+ * @file llfloaterdisplayname.h
  *
- * $LicenseInfo:firstyear=2000&license=viewerlgpl$
+ * $LicenseInfo:firstyear=2009&license=viewerlgpl$
  * Second Life Viewer Source Code
  * Copyright (C) 2010, Linden Research, Inc.
  * 
@@ -23,3 +22,17 @@
  * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
  * $/LicenseInfo$
  */
+
+#ifndef LLFLOATERDISPLAYNAME_H
+#define LLFLOATERDISPLAYNAME_H
+
+
+namespace LLFloaterDisplayNameUtil
+{
+	// Register with LLFloaterReg
+	void registerFloater();
+}
+
+
+
+#endif
diff --git a/indra/newview/llfloatereditextdaycycle.cpp b/indra/newview/llfloatereditextdaycycle.cpp
index 24673d5a7c70796500c968c3a57aeb8c5c4a7982..297ad243595697e0b0902bc6baa59a39079b05ea 100644
--- a/indra/newview/llfloatereditextdaycycle.cpp
+++ b/indra/newview/llfloatereditextdaycycle.cpp
@@ -665,6 +665,7 @@ void LLFloaterEditExtDayCycle::onButtonApply(LLUICtrl *ctrl, const LLSD &data)
     if (ctrl_action == ACTION_SAVE)
     {
         doApplyUpdateInventory(dayclone);
+        clearDirtyFlag();
     }
     else if (ctrl_action == ACTION_SAVEAS)
     {
diff --git a/indra/newview/llfloaterevent.cpp b/indra/newview/llfloaterevent.cpp
index a6640cc073e672c14845b9ffa1687e083dc30324..a3504ac6eeb3a67d2f5e9318c26b40e8aa31cd6b 100644
--- a/indra/newview/llfloaterevent.cpp
+++ b/indra/newview/llfloaterevent.cpp
@@ -108,11 +108,12 @@ void LLFloaterEvent::setEventID(const U32 event_id)
 		LLSD subs;
 		subs["EVENT_ID"] = (S32)event_id;
         // get the search URL and expand all of the substitutions                                                       
-        // (also adds things like [LANGUAGE], [VERSION], [OS], etc.)                                                    
-		std::ostringstream url;
-		url <<  gSavedSettings.getString("EventURL") << event_id << std::endl;
+        // (also adds things like [LANGUAGE], [VERSION], [OS], etc.)              
+
+        std::string expanded_url = LLWeb::expandURLSubstitutions(gSavedSettings.getString("EventURL"), subs);
+
 		// and load the URL in the web view                                                                             
-        mBrowser->navigateTo(url.str());
+        mBrowser->navigateTo(expanded_url);
 		
 	}
 }
diff --git a/indra/newview/llfloaterfixedenvironment.cpp b/indra/newview/llfloaterfixedenvironment.cpp
index 4f2c36f45b6217ae609cd8ef2b3dc5f190191add..aa9a2c164a2b897a0d7f720f0685bcd432cf3ccb 100644
--- a/indra/newview/llfloaterfixedenvironment.cpp
+++ b/indra/newview/llfloaterfixedenvironment.cpp
@@ -137,6 +137,7 @@ void LLFloaterFixedEnvironment::onClose(bool app_quitting)
     doCloseInventoryFloater(app_quitting);
 
     LLEnvironment::instance().setSelectedEnvironment(LLEnvironment::ENV_LOCAL);
+    LLEnvironment::instance().setCurrentEnvironmentSelection(LLEnvironment::ENV_LOCAL);
     LLEnvironment::instance().clearEnvironment(LLEnvironment::ENV_EDIT);
 
     mSettings.reset();
@@ -295,6 +296,7 @@ void LLFloaterFixedEnvironment::onButtonApply(LLUICtrl *ctrl, const LLSD &data)
     if (ctrl_action == ACTION_SAVE)
     {
         doApplyUpdateInventory(setting_clone);
+        clearDirtyFlag();
     }
     else if (ctrl_action == ACTION_SAVEAS)
     {
diff --git a/indra/newview/llfloatergesture.cpp b/indra/newview/llfloatergesture.cpp
index c4e0dd483fa04521c72899959804f4f42927517c..d17889bed1e4ab391bcadb3d1c99ad125f11a415 100644
--- a/indra/newview/llfloatergesture.cpp
+++ b/indra/newview/llfloatergesture.cpp
@@ -122,7 +122,7 @@ LLFloaterGesture::LLFloaterGesture(const LLSD& key)
 	mObserver = new LLFloaterGestureObserver(this);
 	LLGestureMgr::instance().addObserver(mObserver);
 
-	mCommitCallbackRegistrar.add("Gesture.Action.ToogleActiveState", boost::bind(&LLFloaterGesture::onActivateBtnClick, this));
+	mCommitCallbackRegistrar.add("Gesture.Action.ToggleActiveState", boost::bind(&LLFloaterGesture::onActivateBtnClick, this));
 	mCommitCallbackRegistrar.add("Gesture.Action.ShowPreview", boost::bind(&LLFloaterGesture::onClickEdit, this));
 	mCommitCallbackRegistrar.add("Gesture.Action.CopyPaste", boost::bind(&LLFloaterGesture::onCopyPasteAction, this, _2));
 	mCommitCallbackRegistrar.add("Gesture.Action.SaveToCOF", boost::bind(&LLFloaterGesture::addToCurrentOutFit, this));
@@ -582,8 +582,7 @@ void LLFloaterGesture::onCopyPasteAction(const LLSD& command)
 			LLInventoryItem* item = gInventory.getItem(*it);
 			if(item  && item->getInventoryType() == LLInventoryType::IT_GESTURE)
 			{
-				LLWString item_name = utf8str_to_wstring(item->getName());
-				LLClipboard::instance().addToClipboard(item_name, 0, item_name.size());
+				LLClipboard::instance().addToClipboard(*it);
 			}
 		}
 	}
diff --git a/indra/newview/llfloaterhoverheight.cpp b/indra/newview/llfloaterhoverheight.cpp
index 42c5e40761660311cb129f1072293d1db5b90894..a00fc4aa84889fa36d99c685b634bac57be0eb36 100644
--- a/indra/newview/llfloaterhoverheight.cpp
+++ b/indra/newview/llfloaterhoverheight.cpp
@@ -100,11 +100,14 @@ void LLFloaterHoverHeight::onClose(bool app_quitting)
 // static
 void LLFloaterHoverHeight::onSliderMoved(LLUICtrl* ctrl, void* userData)
 {
-	LLSliderCtrl* sldrCtrl = static_cast<LLSliderCtrl*>(ctrl);
-	F32 value = sldrCtrl->getValueF32();
-	LLVector3 offset(0.0, 0.0, llclamp(value,MIN_HOVER_Z,MAX_HOVER_Z));
-	LL_INFOS("Avatar") << "setting hover from slider moved" << offset[2] << LL_ENDL;
-	gAgentAvatarp->setHoverOffset(offset, false);
+    if (isAgentAvatarValid())
+    {
+        LLSliderCtrl* sldrCtrl = static_cast<LLSliderCtrl*>(ctrl);
+        F32 value = sldrCtrl->getValueF32();
+        LLVector3 offset(0.0, 0.0, llclamp(value, MIN_HOVER_Z, MAX_HOVER_Z));
+        LL_INFOS("Avatar") << "setting hover from slider moved" << offset[2] << LL_ENDL;
+        gAgentAvatarp->setHoverOffset(offset, false);
+    }
 }
 
 // Do send-to-the-server work when slider drag completes, or new
diff --git a/indra/newview/llfloaterimagepreview.cpp b/indra/newview/llfloaterimagepreview.cpp
index 028c922a4da8c9ab586666bcf24fa2d14d8bf927..89ba687d2546d2173a7b8ea619c6e1d2c6396395 100644
--- a/indra/newview/llfloaterimagepreview.cpp
+++ b/indra/newview/llfloaterimagepreview.cpp
@@ -664,10 +664,7 @@ BOOL LLImagePreviewAvatar::render()
 	LLGLSUIDefault def;
 	gGL.color4f(0.15f, 0.2f, 0.3f, 1.f);
 
-	if (LLGLSLShader::sNoFixedFunction)
-	{
-		gUIProgram.bind();
-	}
+	gUIProgram.bind();
 
 	gl_rect_2d_simple( mFullWidth, mFullHeight );
 
@@ -866,10 +863,7 @@ BOOL LLImagePreviewSculpted::render()
 		
 	gGL.color4f(0.15f, 0.2f, 0.3f, 1.f);
 
-	if (LLGLSLShader::sNoFixedFunction)
-	{
-		gUIProgram.bind();
-	}
+	gUIProgram.bind();
 
 	gl_rect_2d_simple( mFullWidth, mFullHeight );
 	
@@ -903,10 +897,7 @@ BOOL LLImagePreviewSculpted::render()
 	
 	gPipeline.enableLightsAvatar();
 
-	if (LLGLSLShader::sNoFixedFunction)
-	{
-		gObjectPreviewProgram.bind();
-	}
+	gObjectPreviewProgram.bind();
 	gPipeline.enableLightsPreview();
 
 	gGL.pushMatrix();
@@ -920,10 +911,7 @@ BOOL LLImagePreviewSculpted::render()
 
 	gGL.popMatrix();
 
-	if (LLGLSLShader::sNoFixedFunction)
-	{
-		gObjectPreviewProgram.unbind();
-	}
+	gObjectPreviewProgram.unbind();
 
 	return TRUE;
 }
diff --git a/indra/newview/llfloaterimcontainer.cpp b/indra/newview/llfloaterimcontainer.cpp
index 6cd1648182fd625d6ccc7ff32bab0b716c888744..703b5d0011b4098fac38052e603553367746cab4 100644
--- a/indra/newview/llfloaterimcontainer.cpp
+++ b/indra/newview/llfloaterimcontainer.cpp
@@ -45,6 +45,7 @@
 #include "llflashtimer.h"
 #include "llfloateravatarpicker.h"
 #include "llfloaterpreference.h"
+#include "llfloaterreporter.h"
 #include "llimview.h"
 #include "llnotificationsutil.h"
 #include "lltoolbarview.h"
@@ -723,7 +724,8 @@ void LLFloaterIMContainer::setMinimized(BOOL b)
 }
 
 void LLFloaterIMContainer::setVisible(BOOL visible)
-{	LLFloaterIMNearbyChat* nearby_chat;
+{
+    LLFloaterIMNearbyChat* nearby_chat;
 	if (visible)
 	{
 		// Make sure we have the Nearby Chat present when showing the conversation container
@@ -758,22 +760,25 @@ void LLFloaterIMContainer::setVisible(BOOL visible)
 		LLFloaterIMSessionTab::addToHost(LLUUID());
 	}
 
-	// We need to show/hide all the associated conversations that have been torn off
-	// (and therefore, are not longer managed by the multifloater),
-	// so that they show/hide with the conversations manager.
-	conversations_widgets_map::iterator widget_it = mConversationsWidgets.begin();
-	for (;widget_it != mConversationsWidgets.end(); ++widget_it)
-	{
-		LLConversationViewSession* widget = dynamic_cast<LLConversationViewSession*>(widget_it->second);
-		if (widget)
-		{
-			LLFloater* session_floater = widget->getSessionFloater();
-			if (session_floater != nearby_chat)
-			{
-		    widget->setVisibleIfDetached(visible);
-		}
-	}
-	}
+    if (!LLFloater::isQuitRequested())
+    {
+        // We need to show/hide all the associated conversations that have been torn off
+        // (and therefore, are not longer managed by the multifloater),
+        // so that they show/hide with the conversations manager.
+        conversations_widgets_map::iterator widget_it = mConversationsWidgets.begin();
+        for (; widget_it != mConversationsWidgets.end(); ++widget_it)
+        {
+            LLConversationViewSession* widget = dynamic_cast<LLConversationViewSession*>(widget_it->second);
+            if (widget)
+            {
+                LLFloater* session_floater = widget->getSessionFloater();
+                if (session_floater != nearby_chat)
+                {
+                    widget->setVisibleIfDetached(visible);
+                }
+            }
+        }
+    }
 	
 	// Now, do the normal multifloater show/hide
 	LLMultiFloater::setVisible(visible);
@@ -1238,6 +1243,18 @@ void LLFloaterIMContainer::doToParticipants(const std::string& command, uuid_vec
 		{
 			LLAvatarActions::pay(userID);
 		}
+        else if ("report_abuse" == command)
+        {
+            LLAvatarName av_name;
+            if (LLAvatarNameCache::get(userID, &av_name))
+            {
+                LLFloaterReporter::showFromAvatar(userID, av_name.getCompleteName());
+            }
+            else
+            {
+                LLFloaterReporter::showFromAvatar(userID, "not avaliable");
+            }
+        }
 		else if ("block_unblock" == command)
 		{
 			LLAvatarActions::toggleMute(userID, LLMute::flagVoiceChat);
@@ -1503,7 +1520,11 @@ bool LLFloaterIMContainer::enableContextMenuItem(const std::string& item, uuid_v
 	}
 
 	// Handle all other options
-	if (("can_invite" == item) || ("can_chat_history" == item) || ("can_share" == item) || ("can_pay" == item))
+	if (("can_invite" == item)
+        || ("can_chat_history" == item)
+        || ("can_share" == item)
+        || ("can_pay" == item)
+        || ("report_abuse" == item))
 	{
 		// Those menu items are enable only if a single avatar is selected
 		return is_single_select;
diff --git a/indra/newview/llfloaterimnearbychat.cpp b/indra/newview/llfloaterimnearbychat.cpp
index 3a850d4b6822e1cb9676dd66426d90b90290b1b2..4cceddeefb455077dcefd7fd6e8f96cb6c607aa2 100644
--- a/indra/newview/llfloaterimnearbychat.cpp
+++ b/indra/newview/llfloaterimnearbychat.cpp
@@ -698,7 +698,6 @@ void LLFloaterIMNearbyChat::sendChatFromViewer(const std::string &utf8text, ECha
 
 void LLFloaterIMNearbyChat::sendChatFromViewer(const LLWString &wtext, EChatType type, BOOL animate)
 {
-	LLUIUsage::instance().logCommand("Chat.Send"); // pseuo-command
 	// Look for "/20 foo" channel chats.
 	S32 channel = 0;
 	LLWString out_text = stripChannelNumber(wtext, &channel);
@@ -858,6 +857,12 @@ LLWString LLFloaterIMNearbyChat::stripChannelNumber(const LLWString &mesg, S32*
 
 void send_chat_from_viewer(const std::string& utf8_out_text, EChatType type, S32 channel)
 {
+	LL_DEBUGS("UIUsage") << "Nearby chat, text " << utf8_out_text << " type " << type << " channel " << channel << LL_ENDL;
+	if (type != CHAT_TYPE_START && type != CHAT_TYPE_STOP) // prune back some redundant logging
+	{
+		LLUIUsage::instance().logCommand("Chat.SendNearby"); // pseuo-command
+	}
+
     LLMessageSystem* msg = gMessageSystem;
 
     if (channel >= 0)
diff --git a/indra/newview/llfloaterimsessiontab.cpp b/indra/newview/llfloaterimsessiontab.cpp
index 43dc304c1076039d180468a37dbd0d6dbab15372..93a0b39e023189167cdd50b4279c923e27b9da81 100644
--- a/indra/newview/llfloaterimsessiontab.cpp
+++ b/indra/newview/llfloaterimsessiontab.cpp
@@ -384,7 +384,7 @@ void LLFloaterIMSessionTab::draw()
 
 void LLFloaterIMSessionTab::enableDisableCallBtn()
 {
-    if (LLVoiceClient::instanceExists())
+    if (LLVoiceClient::instanceExists() && mVoiceButton)
     {
         mVoiceButton->setEnabled(
             mSessionID.notNull()
@@ -551,7 +551,7 @@ void LLFloaterIMSessionTab::removeConversationViewParticipant(const LLUUID& part
 void LLFloaterIMSessionTab::updateConversationViewParticipant(const LLUUID& participant_id)
 {
 	LLFolderViewItem* widget = get_ptr_in_map(mConversationsWidgets,participant_id);
-	if (widget)
+	if (widget && widget->getViewModelItem())
 	{
 		widget->refresh();
 	}
@@ -576,8 +576,11 @@ void LLFloaterIMSessionTab::refreshConversation()
 		{
 			participants_uuids.push_back(widget_it->first);
 		}
-		widget_it->second->refresh();
-		widget_it->second->setVisible(TRUE);
+        if (widget_it->second->getViewModelItem())
+        {
+            widget_it->second->refresh();
+            widget_it->second->setVisible(TRUE);
+        }
 		++widget_it;
 	}
 	if (is_ad_hoc || mIsP2PChat)
@@ -1126,7 +1129,10 @@ void LLFloaterIMSessionTab::getSelectedUUIDs(uuid_vec_t& selected_uuids)
     for (; it != it_end; ++it)
     {
         LLConversationItem* conversation_item = static_cast<LLConversationItem *>((*it)->getViewModelItem());
-        selected_uuids.push_back(conversation_item->getUUID());
+        if (conversation_item)
+        {
+            selected_uuids.push_back(conversation_item->getUUID());
+        }
     }
 }
 
diff --git a/indra/newview/llfloaterjoystick.cpp b/indra/newview/llfloaterjoystick.cpp
index 93a26f31ccf5706b3050b87aea09480fb9b64f1f..558b14bba7c0fecd71e3fd9255c5148788628f99 100644
--- a/indra/newview/llfloaterjoystick.cpp
+++ b/indra/newview/llfloaterjoystick.cpp
@@ -292,7 +292,7 @@ void LLFloaterJoystick::refreshListOfDevices()
         std::string desc = LLViewerJoystick::getInstance()->getDescription();
         if (!desc.empty())
         {
-            LLSD value = LLSD::Integer(0);
+            LLSD value = LLSD::Integer(1); // value for selection
             addDevice(desc, value);
             mHasDeviceList = true;
         }
@@ -392,6 +392,9 @@ void LLFloaterJoystick::onCommitJoystickEnabled(LLUICtrl*, void *joy_panel)
 
     LLSD value = self->mJoysticksCombo->getValue();
     bool joystick_enabled = true;
+    // value is 0 for no device,
+    // 1 for a device on Mac (single device, no list support yet)
+    // binary packed guid for a device on windows (can have multiple devices)
     if (value.isInteger())
     {
         // ndof already has a device selected, we are just setting it enabled or disabled
@@ -400,7 +403,7 @@ void LLFloaterJoystick::onCommitJoystickEnabled(LLUICtrl*, void *joy_panel)
     else
     {
         LLViewerJoystick::getInstance()->initDevice(value);
-        // else joystick is enabled, because combobox holds id of device
+        // else joystick is enabled, because combobox holds id of the device
         joystick_enabled = true;
     }
     gSavedSettings.setBOOL("JoystickEnabled", joystick_enabled);
diff --git a/indra/newview/llfloaterland.cpp b/indra/newview/llfloaterland.cpp
index 04133f27109d73b1e0e3164b2cfeed77fcf9bc06..1a98ab9d7664ca77b0744232ec661e74a0113dc1 100644
--- a/indra/newview/llfloaterland.cpp
+++ b/indra/newview/llfloaterland.cpp
@@ -452,7 +452,8 @@ BOOL LLPanelLandGeneral::postBuild()
 
 	mEditDesc = getChild<LLTextEditor>("Description");
 	mEditDesc->setCommitOnFocusLost(TRUE);
-	mEditDesc->setCommitCallback(onCommitAny, this);	
+	mEditDesc->setCommitCallback(onCommitAny, this);
+    mEditDesc->setContentTrusted(false);
 	// No prevalidate function - historically the prevalidate function was broken,
 	// allowing residents to put in characters like U+2661 WHITE HEART SUIT, so
 	// preserve that ability.
@@ -749,6 +750,7 @@ void LLPanelLandGeneral::refresh()
 		BOOL can_edit_identity = LLViewerParcelMgr::isParcelModifiableByAgent(parcel, GP_LAND_CHANGE_IDENTITY);
 		mEditName->setEnabled(can_edit_identity);
 		mEditDesc->setEnabled(can_edit_identity);
+        mEditDesc->setParseURLs(!can_edit_identity);
 
 		BOOL can_edit_agent_only = LLViewerParcelMgr::isParcelModifiableByAgent(parcel, GP_NO_POWERS);
 		mBtnSetGroup->setEnabled(can_edit_agent_only && !parcel->getIsGroupOwned());
@@ -3054,7 +3056,8 @@ BOOL LLPanelLandCovenant::postBuild()
 {
 	mLastRegionID = LLUUID::null;
 	mNextUpdateTime = 0;
-
+    mTextEstateOwner = getChild<LLTextBox>("estate_owner_text");
+    mTextEstateOwner->setIsFriendCallback(LLAvatarActions::isFriend);
 	return TRUE;
 }
 
@@ -3162,8 +3165,7 @@ void LLPanelLandCovenant::updateEstateOwnerName(const std::string& name)
 	LLPanelLandCovenant* self = LLFloaterLand::getCurrentPanelLandCovenant();
 	if (self)
 	{
-		LLTextBox* editor = self->getChild<LLTextBox>("estate_owner_text");
-		if (editor) editor->setText(name);
+		self->mTextEstateOwner->setText(name);
 	}
 }
 
diff --git a/indra/newview/llfloaterland.h b/indra/newview/llfloaterland.h
index 5d9b411f0458ddbec843bd01259c722eb862e960..684950d88b9dcc2b418e8696e6af6962e8df4856 100644
--- a/indra/newview/llfloaterland.h
+++ b/indra/newview/llfloaterland.h
@@ -413,6 +413,7 @@ class LLPanelLandCovenant
 private:
 	LLUUID mLastRegionID;
 	F64 mNextUpdateTime; //seconds since client start
+    LLTextBox* mTextEstateOwner;
 };
 
 #endif
diff --git a/indra/newview/llfloatermap.cpp b/indra/newview/llfloatermap.cpp
old mode 100644
new mode 100755
index fc2da772f347700277e6045c01f3226733f21b43..fd1af7ccc0933c4efacd3f83112383247c546b15
--- a/indra/newview/llfloatermap.cpp
+++ b/indra/newview/llfloatermap.cpp
@@ -51,7 +51,7 @@
 
 // The minor cardinal direction labels are hidden if their height is more
 // than this proportion of the map.
-const F32 MAP_MINOR_DIR_THRESHOLD = 0.07f;
+const F32 MAP_MINOR_DIR_THRESHOLD = 0.035f;
 
 //
 // Member functions
@@ -77,35 +77,44 @@ LLFloaterMap::~LLFloaterMap()
 
 BOOL LLFloaterMap::postBuild()
 {
-	mMap = getChild<LLNetMap>("Net Map");
-	if (gSavedSettings.getBOOL("DoubleClickTeleport"))
-	{
-		mMap->setToolTipMsg(getString("AltToolTipMsg"));
-	}
-	else if (gSavedSettings.getBOOL("DoubleClickShowWorldMap"))
-	{
-		mMap->setToolTipMsg(getString("ToolTipMsg"));
-	}
-	sendChildToBack(mMap);
-	
-	mTextBoxNorth = getChild<LLTextBox> ("floater_map_north");
-	mTextBoxEast = getChild<LLTextBox> ("floater_map_east");
-	mTextBoxWest = getChild<LLTextBox> ("floater_map_west");
-	mTextBoxSouth = getChild<LLTextBox> ("floater_map_south");
-	mTextBoxSouthEast = getChild<LLTextBox> ("floater_map_southeast");
-	mTextBoxNorthEast = getChild<LLTextBox> ("floater_map_northeast");
-	mTextBoxSouthWest = getChild<LLTextBox> ("floater_map_southwest");
-	mTextBoxNorthWest = getChild<LLTextBox> ("floater_map_northwest");
-
-	updateMinorDirections();
-
-	// Get the drag handle all the way in back
-	sendChildToBack(getDragHandle());
-
-	// keep onscreen
-	gFloaterView->adjustToFitScreen(this, FALSE);
-
-	return TRUE;
+    mMap = getChild<LLNetMap>("Net Map");
+    mMap->setToolTipMsg(getString("ToolTipMsg"));
+    mMap->setParcelNameMsg(getString("ParcelNameMsg"));
+    mMap->setParcelSalePriceMsg(getString("ParcelSalePriceMsg"));
+    mMap->setParcelSaleAreaMsg(getString("ParcelSaleAreaMsg"));
+    mMap->setParcelOwnerMsg(getString("ParcelOwnerMsg"));
+    mMap->setRegionNameMsg(getString("RegionNameMsg"));
+    mMap->setToolTipHintMsg(getString("ToolTipHintMsg"));
+    mMap->setAltToolTipHintMsg(getString("AltToolTipHintMsg"));
+    sendChildToBack(mMap);
+
+    mTextBoxNorth     = getChild<LLTextBox>("floater_map_north");
+    mTextBoxEast      = getChild<LLTextBox>("floater_map_east");
+    mTextBoxWest      = getChild<LLTextBox>("floater_map_west");
+    mTextBoxSouth     = getChild<LLTextBox>("floater_map_south");
+    mTextBoxSouthEast = getChild<LLTextBox>("floater_map_southeast");
+    mTextBoxNorthEast = getChild<LLTextBox>("floater_map_northeast");
+    mTextBoxSouthWest = getChild<LLTextBox>("floater_map_southwest");
+    mTextBoxNorthWest = getChild<LLTextBox>("floater_map_northwest");
+
+    mTextBoxNorth->reshapeToFitText();
+    mTextBoxEast->reshapeToFitText();
+    mTextBoxWest->reshapeToFitText();
+    mTextBoxSouth->reshapeToFitText();
+    mTextBoxSouthEast->reshapeToFitText();
+    mTextBoxNorthEast->reshapeToFitText();
+    mTextBoxSouthWest->reshapeToFitText();
+    mTextBoxNorthWest->reshapeToFitText();
+
+    updateMinorDirections();
+
+    // Get the drag handle all the way in back
+    sendChildToBack(getDragHandle());
+
+    // keep onscreen
+    gFloaterView->adjustToFitScreen(this, false);
+
+    return true;
 }
 
 BOOL LLFloaterMap::handleDoubleClick(S32 x, S32 y, MASK mask)
@@ -138,23 +147,44 @@ BOOL LLFloaterMap::handleDoubleClick(S32 x, S32 y, MASK mask)
 	return TRUE;
 }
 
-void LLFloaterMap::setDirectionPos( LLTextBox* text_box, F32 rotation )
+void LLFloaterMap::setDirectionPos(LLTextBox *text_box, F32 rotation)
 {
-	// Rotation is in radians.
-	// Rotation of 0 means x = 1, y = 0 on the unit circle.
-
-	F32 map_half_height = (F32)(getRect().getHeight() / 2) - getHeaderHeight()/2;
-	F32 map_half_width = (F32)(getRect().getWidth() / 2) ;
-	F32 text_half_height = (F32)(text_box->getRect().getHeight() / 2);
-	F32 text_half_width = (F32)(text_box->getRect().getWidth() / 2);
-	F32 radius = llmin( map_half_height - text_half_height, map_half_width - text_half_width );
-
-	// Inset by a little to account for position display.
-	radius -= 8.f;
-
-	text_box->setOrigin( 
-		ll_round(map_half_width - text_half_width + radius * cos( rotation )),
-		ll_round(map_half_height - text_half_height + radius * sin( rotation )) );
+    // Rotation is in radians.
+    // Rotation of 0 means x = 1, y = 0 on the unit circle.
+
+    F32 map_half_height  = (F32) (getRect().getHeight() / 2) - (getHeaderHeight() / 2);
+    F32 map_half_width   = (F32) (getRect().getWidth() / 2);
+    F32 text_half_height = (F32) (text_box->getRect().getHeight() / 2);
+    F32 text_half_width  = (F32) (text_box->getRect().getWidth() / 2);
+    F32 extra_padding    = (F32) (mTextBoxNorth->getRect().getWidth() / 2);
+    F32 pos_half_height  = map_half_height - text_half_height - extra_padding;
+    F32 pos_half_width   = map_half_width - text_half_width - extra_padding;
+
+    F32 corner_angle               = atan2(pos_half_height, pos_half_width);
+    F32 rotation_mirrored_into_top = abs(fmodf(rotation, F_PI));
+    if (rotation < 0)
+    {
+        rotation_mirrored_into_top = F_PI - rotation_mirrored_into_top;
+    }
+    F32  rotation_mirrored_into_top_right = (F_PI_BY_TWO - abs(rotation_mirrored_into_top - F_PI_BY_TWO));
+    bool at_left_right_edge               = rotation_mirrored_into_top_right < corner_angle;
+
+    F32 part_x = cos(rotation);
+    F32 part_y = sin(rotation);
+    F32 y;
+    F32 x;
+    if (at_left_right_edge)
+    {
+        x = std::copysign(pos_half_width, part_x);
+        y = x * part_y / part_x;
+    }
+    else
+    {
+        y = std::copysign(pos_half_height, part_y);
+        x = y * part_x / part_y;
+    }
+
+    text_box->setOrigin(ll_round(map_half_width + x - text_half_width), ll_round(map_half_height + y - text_half_height));
 }
 
 void LLFloaterMap::updateMinorDirections()
@@ -218,32 +248,6 @@ void LLFloaterMap::reshape(S32 width, S32 height, BOOL called_from_parent)
 	updateMinorDirections();
 }
 
-void LLFloaterMap::handleZoom(const LLSD& userdata)
-{
-	std::string level = userdata.asString();
-	
-	F32 scale = 0.0f;
-	if (level == std::string("default"))
-	{
-		LLControlVariable *pvar = gSavedSettings.getControl("MiniMapScale");
-		if(pvar)
-		{
-			pvar->resetToDefault();
-			scale = gSavedSettings.getF32("MiniMapScale");
-		}
-	}
-	else if (level == std::string("close"))
-		scale = LLNetMap::MAP_SCALE_MAX;
-	else if (level == std::string("medium"))
-		scale = LLNetMap::MAP_SCALE_MID;
-	else if (level == std::string("far"))
-		scale = LLNetMap::MAP_SCALE_MIN;
-	if (scale != 0.0f)
-	{
-		mMap->setScale(scale);
-	}
-}
-
 LLFloaterMap* LLFloaterMap::getInstance()
 {
 	return LLFloaterReg::getTypedInstance<LLFloaterMap>("mini_map");
diff --git a/indra/newview/llfloatermap.h b/indra/newview/llfloatermap.h
index ff2fb2053598a274326fc0d532a704580bee37a2..929b1795aaac17991d2794d101e82810f892835e 100644
--- a/indra/newview/llfloatermap.h
+++ b/indra/newview/llfloatermap.h
@@ -48,7 +48,6 @@ class LLFloaterMap : public LLFloater
 	/*virtual*/ void	draw();
 
 private:
-	void handleZoom(const LLSD& userdata);
 	void setDirectionPos( LLTextBox* text_box, F32 rotation );
 	void updateMinorDirections();
 
diff --git a/indra/newview/llfloatermarketplacelistings.cpp b/indra/newview/llfloatermarketplacelistings.cpp
index 524162ba513badb0bf3ff12ee459a2649ba84968..e755e9924c067a01a6c0f0cd717e7c49352e81da 100644
--- a/indra/newview/llfloatermarketplacelistings.cpp
+++ b/indra/newview/llfloatermarketplacelistings.cpp
@@ -579,7 +579,25 @@ void LLFloaterMarketplaceListings::updateView()
 
         // Update the top message or flip to the tabs and folders view
         // *TODO : check those messages and create better appropriate ones in strings.xml
-        if (mRootFolderId.notNull())
+        if (mkt_status == MarketplaceStatusCodes::MARKET_PLACE_CONNECTION_FAILURE)
+        {
+            std::string reason = LLMarketplaceData::instance().getSLMConnectionfailureReason();
+            if (reason.empty())
+            {
+                text = LLTrans::getString("InventoryMarketplaceConnectionError");
+            }
+            else
+            {
+                LLSD args;
+                args["[REASON]"] = reason;
+                text = LLTrans::getString("InventoryMarketplaceConnectionErrorReason", args);
+            }
+
+            title = LLTrans::getString("InventoryOutboxErrorTitle");
+            tooltip = LLTrans::getString("InventoryOutboxErrorTooltip");
+            LL_WARNS() << "Marketplace status code: " << mkt_status << LL_ENDL;
+        }
+        else if (mRootFolderId.notNull())
         {
             // "Marketplace listings is empty!" message strings
             text = LLTrans::getString("InventoryMarketplaceListingsNoItems", subs);
diff --git a/indra/newview/llfloatermediasettings.cpp b/indra/newview/llfloatermediasettings.cpp
index 2afd889609ff1a56a0541b1c0156efcc4d8058d4..b34961e8a2a67d30fe3f7aac2b4abc9609232137 100644
--- a/indra/newview/llfloatermediasettings.cpp
+++ b/indra/newview/llfloatermediasettings.cpp
@@ -156,6 +156,18 @@ void LLFloaterMediaSettings::apply()
 	}
 }
 
+////////////////////////////////////////////////////////////////////////////////
+void LLFloaterMediaSettings::onOpen(const LLSD& key)
+{
+    if (mPanelMediaSettingsGeneral)
+    {
+        // media is expensive, so only load it when nessesary.
+        // If we need to preload it, set volume to 0 and any pause
+        // if applicable, then unpause here
+        mPanelMediaSettingsGeneral->updateMediaPreview();
+    }
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 void LLFloaterMediaSettings::onClose(bool app_quitting)
 {
diff --git a/indra/newview/llfloatermediasettings.h b/indra/newview/llfloatermediasettings.h
index f93512eb3a6014e3d619c99f1c011f6e5ee043a3..151e43e6b9b95d7be0ab53cee9cb8fb1f840e472 100644
--- a/indra/newview/llfloatermediasettings.h
+++ b/indra/newview/llfloatermediasettings.h
@@ -42,6 +42,7 @@ class LLFloaterMediaSettings :
 	~LLFloaterMediaSettings();
 
 	/*virtual*/ BOOL postBuild();
+    /*virtual*/ void onOpen(const LLSD& key);
 	/*virtual*/ void onClose(bool app_quitting);
 
 	static LLFloaterMediaSettings* getInstance();
diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp
index 0fefb0d43291348f57e6bc310d87cd69a3eb233a..66a245b779598d2eff0d48a2999ed185df3a9d4f 100644
--- a/indra/newview/llfloatermodelpreview.cpp
+++ b/indra/newview/llfloatermodelpreview.cpp
@@ -138,10 +138,10 @@ mAvatarTabIndex(0)
 	mStatusLock = new LLMutex();
 	mModelPreview = NULL;
 
-	mLODMode[LLModel::LOD_HIGH] = 0;
+	mLODMode[LLModel::LOD_HIGH] = LLModelPreview::LOD_FROM_FILE;
 	for (U32 i = 0; i < LLModel::LOD_HIGH; i++)
 	{
-		mLODMode[i] = 1;
+		mLODMode[i] = LLModelPreview::MESH_OPTIMIZER_AUTO;
 	}
 }
 
@@ -351,15 +351,6 @@ void LLFloaterModelPreview::initModelPreview()
 //static
 bool LLFloaterModelPreview::showModelPreview()
 {
-#ifdef LL_GLOD
-    if (LLRender::sGLCoreProfile)
-    {
-        // GLOD is incompatible with RenderGLCoreProfile, will crash on init
-        LLNotificationsUtil::add("MeshUploadProfilerError");
-        return false;
-    }
-#endif
-
     LLFloaterModelPreview* fmp = (LLFloaterModelPreview*)LLFloaterReg::getInstance("upload_model");
     if (fmp && !fmp->isModelLoading())
     {
@@ -476,22 +467,25 @@ void LLFloaterModelPreview::loadHighLodModel()
 	loadModel(3);
 }
 
-void LLFloaterModelPreview::loadModel(S32 lod)
+void LLFloaterModelPreview::prepareToLoadModel(S32 lod)
 {
 	mModelPreview->mLoading = true;
 	if (lod == LLModel::LOD_PHYSICS)
 	{
 		// loading physics from file
 		mModelPreview->mPhysicsSearchLOD = lod;
+		mModelPreview->mWarnOfUnmatchedPhyicsMeshes = false;
 	}
-
+}
+void LLFloaterModelPreview::loadModel(S32 lod)
+{
+	prepareToLoadModel(lod);
 	(new LLMeshFilePicker(mModelPreview, lod))->getFile();
 }
 
 void LLFloaterModelPreview::loadModel(S32 lod, const std::string& file_name, bool force_disable_slm)
 {
-	mModelPreview->mLoading = true;
-
+	prepareToLoadModel(lod);
 	mModelPreview->loadModel(file_name, lod, force_disable_slm);
 }
 
@@ -516,6 +510,15 @@ void LLFloaterModelPreview::onClickCalculateBtn()
 
 	toggleCalculateButton(false);
 	mUploadBtn->setEnabled(false);
+ 
+    //disable "simplification" UI
+    LLPanel* simplification_panel = getChild<LLPanel>("physics simplification");
+    LLView* child = simplification_panel->getFirstChild();
+    while (child)
+    {
+        child->setEnabled(false);
+        child = simplification_panel->findNextSibling(child);
+    }
 }
 
 // Modified cell_params, make sure to clear values if you have to reuse cell_params outside of this function
@@ -744,7 +747,19 @@ void LLFloaterModelPreview::onAutoFillCommit(LLUICtrl* ctrl, void* userdata)
 
 void LLFloaterModelPreview::onLODParamCommit(S32 lod, bool enforce_tri_limit)
 {
-	mModelPreview->onLODParamCommit(lod, enforce_tri_limit);
+    LLComboBox* lod_source_combo = getChild<LLComboBox>("lod_source_" + lod_name[lod]);
+    S32 mode = lod_source_combo->getCurrentIndex();
+    switch (mode)
+    {
+    case LLModelPreview::MESH_OPTIMIZER_AUTO:
+    case LLModelPreview::MESH_OPTIMIZER_SLOPPY:
+    case LLModelPreview::MESH_OPTIMIZER_PRECISE:
+        mModelPreview->onLODMeshOptimizerParamCommit(lod, enforce_tri_limit, mode);
+        break;
+    default:
+        LL_ERRS() << "Only supposed to be called to generate models" << LL_ENDL;
+        break;
+    }
 
 	//refresh LoDs that reference this one
 	for (S32 i = lod - 1; i >= 0; --i)
@@ -1060,11 +1075,18 @@ void LLFloaterModelPreview::onPhysicsUseLOD(LLUICtrl* ctrl, void* userdata)
 	}
 
 	S32 file_mode = iface->getItemCount() - 1;
-	if (which_mode < file_mode)
+	S32 cube_mode = file_mode - 1;
+	if (which_mode < cube_mode)
 	{
 		S32 which_lod = num_lods - which_mode;
 		sInstance->mModelPreview->setPhysicsFromLOD(which_lod);
 	}
+	else if (which_mode == cube_mode)
+	{
+		std::string path = gDirUtilp->getAppRODataDir();
+		gDirUtilp->append(path, "cube.dae");
+		sInstance->loadModel(LLModel::LOD_PHYSICS, path);
+	}
 
 	LLModelPreview *model_preview = sInstance->mModelPreview;
 	if (model_preview)
@@ -1376,31 +1398,31 @@ void LLFloaterModelPreview::clearAvatarTab()
 			}
 
 void LLFloaterModelPreview::updateAvatarTab(bool highlight_overrides)
-			{
+{
     S32 display_lod = mModelPreview->mPreviewLOD;
     if (mModelPreview->mModel[display_lod].empty())
-				{
+    {
         mSelectedJointName.clear();
         return;
-					}
+    }
 
     // Joints will be listed as long as they are listed in mAlternateBindMatrix
     // even if they are for some reason identical to defaults.
     // Todo: Are overrides always identical for all lods? They normally are, but there might be situations where they aren't.
     if (mJointOverrides[display_lod].empty())
-					{
+    {
         // populate map
         for (LLModelLoader::scene::iterator iter = mModelPreview->mScene[display_lod].begin(); iter != mModelPreview->mScene[display_lod].end(); ++iter)
-					{
+        {
             for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter)
-					{
+            {
                 LLModelInstance& instance = *model_iter;
                 LLModel* model = instance.mModel;
                 const LLMeshSkinInfo *skin = &model->mSkinInfo;
                 U32 joint_count = LLSkinningUtil::getMeshJointCount(skin);
                 U32 bind_count = highlight_overrides ? skin->mAlternateBindMatrix.size() : 0; // simply do not include overrides if data is not needed
                 if (bind_count > 0 && bind_count != joint_count)
-						{
+                {
                     std::ostringstream out;
                     out << "Invalid joint overrides for model " << model->getName();
                     out << ". Amount of joints " << joint_count;
@@ -1409,68 +1431,68 @@ void LLFloaterModelPreview::updateAvatarTab(bool highlight_overrides)
                     addStringToLog(out.str(), true);
                     // Disable overrides for this model
                     bind_count = 0;
-						}
+                }
                 if (bind_count > 0)
-						{
+                {
                     for (U32 j = 0; j < joint_count; ++j)
-							{
-                        const LLVector3& joint_pos = skin->mAlternateBindMatrix[j].getTranslation();
+                    {
+                        const LLVector3& joint_pos = LLVector3(skin->mAlternateBindMatrix[j].getTranslation());
                         LLJointOverrideData &data = mJointOverrides[display_lod][skin->mJointNames[j]];
 
                         LLJoint* pJoint = LLModelPreview::lookupJointByName(skin->mJointNames[j], mModelPreview);
                         if (pJoint)
-							{
+                        {
                             // see how voavatar uses aboveJointPosThreshold
                             if (pJoint->aboveJointPosThreshold(joint_pos))
-				{
+                            {
                                 // valid override
                                 if (data.mPosOverrides.size() > 0
                                     && (data.mPosOverrides.begin()->second - joint_pos).lengthSquared() > (LL_JOINT_TRESHOLD_POS_OFFSET * LL_JOINT_TRESHOLD_POS_OFFSET))
-					{
+                                {
                                     // File contains multiple meshes with conflicting joint offsets
                                     // preview may be incorrect, upload result might wary (depends onto
                                     // mesh_id that hasn't been generated yet).
                                     data.mHasConflicts = true;
-							}
+                                }
                                 data.mPosOverrides[model->getName()] = joint_pos;
-						}
-						else
-						{
+                            }
+                            else
+                            {
                                 // default value, it won't be accounted for by avatar
                                 data.mModelsNoOverrides.insert(model->getName());
-					}
-					}
-				}
-			}
-			else
-			{
+                            }
+                        }
+                    }
+                }
+                else
+                {
                     for (U32 j = 0; j < joint_count; ++j)
-				{				
+                    {
                         LLJointOverrideData &data = mJointOverrides[display_lod][skin->mJointNames[j]];
                         data.mModelsNoOverrides.insert(model->getName());
                     }
                 }
-			}
-		}
-	}
+            }
+        }
+    }
 
     LLPanel *panel = mTabContainer->getPanelByName("rigging_panel");
     LLScrollListCtrl *joints_list = panel->getChild<LLScrollListCtrl>("joints_list");
 
     if (joints_list->isEmpty())
-	{
+    {
         // Populate table
 
-    std::map<std::string, std::string> joint_alias_map;
+        std::map<std::string, std::string> joint_alias_map;
         mModelPreview->getJointAliases(joint_alias_map);
-    
+
         S32 conflicts = 0;
         joint_override_data_map_t::iterator joint_iter = mJointOverrides[display_lod].begin();
         joint_override_data_map_t::iterator joint_end = mJointOverrides[display_lod].end();
         while (joint_iter != joint_end)
-	{
+        {
             const std::string& listName = joint_iter->first;
-        
+
             LLScrollListItem::Params item_params;
             item_params.value(listName);
 
@@ -1478,38 +1500,38 @@ void LLFloaterModelPreview::updateAvatarTab(bool highlight_overrides)
             cell_params.font = LLFontGL::getFontSansSerif();
             cell_params.value = listName;
             if (joint_alias_map.find(listName) == joint_alias_map.end())
-	{
+            {
                 // Missing names
                 cell_params.color = LLColor4::red;
-	}
+            }
             if (joint_iter->second.mHasConflicts)
-	{
+            {
                 // Conflicts
                 cell_params.color = LLColor4::orange;
                 conflicts++;
-	}
+            }
             if (highlight_overrides && joint_iter->second.mPosOverrides.size() > 0)
-	{
+            {
                 cell_params.font.style = "BOLD";
-	}
+            }
 
             item_params.columns.add(cell_params);
 
             joints_list->addRow(item_params, ADD_BOTTOM);
             joint_iter++;
-	}
+        }
         joints_list->selectFirstItem();
         LLScrollListItem *selected = joints_list->getFirstSelected();
         if (selected)
-{
+        {
             mSelectedJointName = selected->getValue().asString();
-	}
+        }
 
         LLTextBox *joint_conf_descr = panel->getChild<LLTextBox>("conflicts_description");
         joint_conf_descr->setTextArg("[CONFLICTS]", llformat("%d", conflicts));
         joint_conf_descr->setTextArg("[JOINTS_COUNT]", llformat("%d", mJointOverrides[display_lod].size()));
-		}
-	}
+    }
+}
 
 //-----------------------------------------------------------------------------
 // addStringToLogTab()
@@ -1659,15 +1681,15 @@ LLFloaterModelPreview::DecompRequest::DecompRequest(const std::string& stage, LL
 void LLFloaterModelPreview::setCtrlLoadFromFile(S32 lod)
 {
     if (lod == LLModel::LOD_PHYSICS)
-    {
+	{
         LLComboBox* lod_combo = findChild<LLComboBox>("physics_lod_combo");
         if (lod_combo)
         {
-            lod_combo->setCurrentByIndex(5);
+            lod_combo->setCurrentByIndex(lod_combo->getItemCount() - 1);
         }
     }
     else
-{
+	{
         LLComboBox* lod_combo = findChild<LLComboBox>("lod_source_" + lod_name[lod]);
         if (lod_combo)
 	{
@@ -1739,19 +1761,10 @@ void LLFloaterModelPreview::onLoDSourceCommit(S32 lod)
 	mModelPreview->updateLodControls(lod);
 
 	LLComboBox* lod_source_combo = getChild<LLComboBox>("lod_source_" + lod_name[lod]);
-
-    if (lod_source_combo->getCurrentIndex() == LLModelPreview::LOD_FROM_FILE
-        && mModelPreview->mLODFile[lod].empty())
-    {
-        // File wasn't selected, so nothing to do yet, refreshing
-        // hovewer will cause a small freeze with large meshes
-        // Might be good idea to open filepicker here
-        return;
-    }
-
-	refresh();
-
-	if (lod_source_combo->getCurrentIndex() == LLModelPreview::GENERATE)
+    S32 index = lod_source_combo->getCurrentIndex();
+	if (index == LLModelPreview::MESH_OPTIMIZER_AUTO
+        || index == LLModelPreview::MESH_OPTIMIZER_SLOPPY
+        || index == LLModelPreview::MESH_OPTIMIZER_PRECISE)
 	{ //rebuild LoD to update triangle counts
 		onLODParamCommit(lod, true);
 	}
@@ -1782,7 +1795,7 @@ void LLFloaterModelPreview::resetUploadOptions()
 	getChild<LLComboBox>("lod_source_" + lod_name[NUM_LOD - 1])->setCurrentByIndex(LLModelPreview::LOD_FROM_FILE);
 	for (S32 lod = 0; lod < NUM_LOD - 1; ++lod)
 	{
-		getChild<LLComboBox>("lod_source_" + lod_name[lod])->setCurrentByIndex(LLModelPreview::GENERATE);
+		getChild<LLComboBox>("lod_source_" + lod_name[lod])->setCurrentByIndex(LLModelPreview::MESH_OPTIMIZER_AUTO);
 		childSetValue("lod_file_" + lod_name[lod], "");
 	}
 
diff --git a/indra/newview/llfloatermodelpreview.h b/indra/newview/llfloatermodelpreview.h
index b5dab262a30a37df2e2b212fe5208d5372379269..bda042186bac288fb7480fb01590bdc0f4cfb4a3 100644
--- a/indra/newview/llfloatermodelpreview.h
+++ b/indra/newview/llfloatermodelpreview.h
@@ -197,9 +197,7 @@ class LLFloaterModelPreview : public LLFloaterModelUploadBase
 	std::map<std::string, bool> mViewOptionDisabled;
 	
 	//store which lod mode each LOD is using
-	// 0 - load from file
-	// 1 - auto generate
-	// 2 - use LoD above
+	// See eLoDMode
 	S32 mLODMode[4];
 
 	LLMutex* mStatusLock;
@@ -223,6 +221,7 @@ class LLFloaterModelPreview : public LLFloaterModelUploadBase
 
 	void resetUploadOptions();
 	void clearLogTab();
+	void prepareToLoadModel(S32 lod);
 
 	void createSmoothComboBox(LLComboBox* combo_box, float min, float max);
 
diff --git a/indra/newview/llfloateroutfitsnapshot.cpp b/indra/newview/llfloateroutfitsnapshot.cpp
index dccef88e410bb3236f6d33a323f91f97b953bf94..ad5e97e0677c7afea40fac8361fc727918b6ca0d 100644
--- a/indra/newview/llfloateroutfitsnapshot.cpp
+++ b/indra/newview/llfloateroutfitsnapshot.cpp
@@ -42,7 +42,6 @@
 #include "llviewercontrol.h"
 #include "lltoolfocus.h"
 #include "lltoolmgr.h"
-#include "llwebprofile.h"
 
 ///----------------------------------------------------------------------------
 /// Local function declarations, constants, enums, and typedefs
diff --git a/indra/newview/llfloaterpay.cpp b/indra/newview/llfloaterpay.cpp
index 87973c2286e3863051eaccadfd18ef49649741b9..94261b2e4e612079f284a6de61a71b65eabbd10e 100644
--- a/indra/newview/llfloaterpay.cpp
+++ b/indra/newview/llfloaterpay.cpp
@@ -72,7 +72,7 @@ struct LLGiveMoneyInfo
 		mFloater(floater), mAmount(amount){}
 };
 
-typedef boost::shared_ptr<LLGiveMoneyInfo> give_money_ptr;
+typedef std::shared_ptr<LLGiveMoneyInfo> give_money_ptr;
 
 ///----------------------------------------------------------------------------
 /// Class LLFloaterPay
diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp
index 1fc734ae39ca643c6571f14dbbb417b649910796..273810e8d421c6a99bd3a1dac0d2735ec0b5508e 100644
--- a/indra/newview/llfloaterpreference.cpp
+++ b/indra/newview/llfloaterpreference.cpp
@@ -333,60 +333,59 @@ void LLFloaterPreference::processProperties( void* pData, EAvatarProcessorType t
 		const LLAvatarData* pAvatarData = static_cast<const LLAvatarData*>( pData );
 		if (pAvatarData && (gAgent.getID() == pAvatarData->avatar_id) && (pAvatarData->avatar_id != LLUUID::null))
 		{
-			storeAvatarProperties( pAvatarData );
-			processProfileProperties( pAvatarData );
+            mAllowPublish = (bool)(pAvatarData->flags & AVATAR_ALLOW_PUBLISH);
+            mAvatarDataInitialized = true;
+            getChild<LLUICtrl>("online_searchresults")->setValue(mAllowPublish);
 		}
 	}	
 }
 
-void LLFloaterPreference::storeAvatarProperties( const LLAvatarData* pAvatarData )
+void LLFloaterPreference::saveAvatarProperties( void )
 {
-	if (LLStartUp::getStartupState() == STATE_STARTED)
-	{
-		mAvatarProperties.avatar_id		= pAvatarData->avatar_id;
-		mAvatarProperties.image_id		= pAvatarData->image_id;
-		mAvatarProperties.fl_image_id   = pAvatarData->fl_image_id;
-		mAvatarProperties.about_text	= pAvatarData->about_text;
-		mAvatarProperties.fl_about_text = pAvatarData->fl_about_text;
-		mAvatarProperties.profile_url   = pAvatarData->profile_url;
-		mAvatarProperties.flags		    = pAvatarData->flags;
-		mAvatarProperties.allow_publish	= pAvatarData->flags & AVATAR_ALLOW_PUBLISH;
+    const bool allowPublish = getChild<LLUICtrl>("online_searchresults")->getValue();
 
-		mAvatarDataInitialized = true;
-	}
-}
+    if ((LLStartUp::getStartupState() == STATE_STARTED)
+        && mAvatarDataInitialized
+        && (allowPublish != mAllowPublish))
+    {
+        std::string cap_url = gAgent.getRegionCapability("AgentProfile");
+        if (!cap_url.empty())
+        {
+            mAllowPublish = allowPublish;
 
-void LLFloaterPreference::processProfileProperties(const LLAvatarData* pAvatarData )
-{
-	getChild<LLUICtrl>("online_searchresults")->setValue( (bool)(pAvatarData->flags & AVATAR_ALLOW_PUBLISH) );	
+            LLCoros::instance().launch("requestAgentUserInfoCoro",
+                boost::bind(saveAvatarPropertiesCoro, cap_url, allowPublish));
+        }
+    }
 }
 
-void LLFloaterPreference::saveAvatarProperties( void )
+void LLFloaterPreference::saveAvatarPropertiesCoro(const std::string cap_url, bool allow_publish)
 {
-	const BOOL allowPublish = getChild<LLUICtrl>("online_searchresults")->getValue();
+    LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+    LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+        httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("put_avatar_properties_coro", httpPolicy));
+    LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+    LLCore::HttpHeaders::ptr_t httpHeaders;
 
-	if (allowPublish)
-	{
-		mAvatarProperties.flags |= AVATAR_ALLOW_PUBLISH;
-	}
+    LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions);
+    httpOpts->setFollowRedirects(true);
 
-	//
-	// NOTE: We really don't want to send the avatar properties unless we absolutely
-	//       need to so we can avoid the accidental profile reset bug, so, if we're
-	//       logged in, the avatar data has been initialized and we have a state change
-	//       for the "allow publish" flag, then set the flag to its new value and send
-	//       the properties update.
-	//
-	// NOTE: The only reason we can not remove this update altogether is because of the
-	//       "allow publish" flag, the last remaining profile setting in the viewer
-	//       that doesn't exist in the web profile.
-	//
-	if ((LLStartUp::getStartupState() == STATE_STARTED) && mAvatarDataInitialized && (allowPublish != mAvatarProperties.allow_publish))
-	{
-		mAvatarProperties.allow_publish = allowPublish;
+    std::string finalUrl = cap_url + "/" + gAgentID.asString();
+    LLSD data;
+    data["allow_publish"] = allow_publish;
 
-		LLAvatarPropertiesProcessor::getInstance()->sendAvatarPropertiesUpdate( &mAvatarProperties );
-	}
+    LLSD result = httpAdapter->putAndSuspend(httpRequest, finalUrl, data, httpOpts, httpHeaders);
+
+    LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+    LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+    if (!status)
+    {
+        LL_WARNS("Preferences") << "Failed to put agent information " << data << " for id " << gAgentID << LL_ENDL;
+        return;
+    }
+
+    LL_DEBUGS("Preferences") << "Agent id: " << gAgentID << " Data: " << data << " Result: " << httpResults << LL_ENDL;
 }
 
 BOOL LLFloaterPreference::postBuild()
@@ -938,7 +937,7 @@ void LLFloaterPreference::onBtnOK(const LLSD& userdata)
 	else
 	{
 		// Show beep, pop up dialog, etc.
-		LL_INFOS() << "Can't close preferences!" << LL_ENDL;
+		LL_INFOS("Preferences") << "Can't close preferences!" << LL_ENDL;
 	}
 
 	LLPanelLogin::updateLocationSelectorsVisibility();	
@@ -1196,14 +1195,10 @@ void LLFloaterPreference::refreshEnabledState()
 
 	//Deferred/SSAO/Shadows
 	BOOL bumpshiny = gGLManager.mHasCubeMap && LLCubeMap::sUseCubeMaps && LLFeatureManager::getInstance()->isFeatureAvailable("RenderObjectBump") && gSavedSettings.getBOOL("RenderObjectBump");
-	BOOL transparent_water = LLFeatureManager::getInstance()->isFeatureAvailable("RenderTransparentWater") && gSavedSettings.getBOOL("RenderTransparentWater");
 	BOOL shaders = gSavedSettings.getBOOL("WindLightUseAtmosShaders");
 	BOOL enabled = LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferred") &&
 						bumpshiny &&
-						transparent_water &&
 						shaders && 
-						gGLManager.mHasFramebufferObject &&
-						gSavedSettings.getBOOL("RenderAvatarVP") &&
 						(ctrl_wind_light->get()) ? TRUE : FALSE;
 
 	ctrl_deferred->setEnabled(enabled);
@@ -1224,37 +1219,14 @@ void LLFloaterPreferenceGraphicsAdvanced::refreshEnabledState()
 	ctrl_reflections->setEnabled(reflections);
 	reflections_text->setEnabled(reflections);
 
-    // Transparent Water
-    LLCheckBoxCtrl* transparent_water_ctrl = getChild<LLCheckBoxCtrl>("TransparentWater");
-
 	// Bump & Shiny	
 	LLCheckBoxCtrl* bumpshiny_ctrl = getChild<LLCheckBoxCtrl>("BumpShiny");
 	bool bumpshiny = gGLManager.mHasCubeMap && LLCubeMap::sUseCubeMaps && LLFeatureManager::getInstance()->isFeatureAvailable("RenderObjectBump");
 	bumpshiny_ctrl->setEnabled(bumpshiny ? TRUE : FALSE);
     
 	// Avatar Mode
-	// Enable Avatar Shaders
-	LLCheckBoxCtrl* ctrl_avatar_vp = getChild<LLCheckBoxCtrl>("AvatarVertexProgram");
 	// Avatar Render Mode
-	LLCheckBoxCtrl* ctrl_avatar_cloth = getChild<LLCheckBoxCtrl>("AvatarCloth");
-	
-	bool avatar_vp_enabled = LLFeatureManager::getInstance()->isFeatureAvailable("RenderAvatarVP");
-	if (LLViewerShaderMgr::sInitialized)
-	{
-		S32 max_avatar_shader = LLViewerShaderMgr::instance()->mMaxAvatarShaderLevel;
-		avatar_vp_enabled = (max_avatar_shader > 0) ? TRUE : FALSE;
-	}
-
-	ctrl_avatar_vp->setEnabled(avatar_vp_enabled);
-	
-    if (gSavedSettings.getBOOL("RenderAvatarVP") == FALSE)
-    {
-        ctrl_avatar_cloth->setEnabled(FALSE);
-    } 
-    else
-    {
-        ctrl_avatar_cloth->setEnabled(TRUE);
-    }
+    getChild<LLCheckBoxCtrl>("AvatarCloth")->setEnabled(TRUE);
 
     // Vertex Shaders, Global Shader Enable
     // SL-12594 Basic shaders are always enabled. DJH TODO clean up now-orphaned state handling code
@@ -1277,9 +1249,6 @@ void LLFloaterPreferenceGraphicsAdvanced::refreshEnabledState()
     
     BOOL enabled = LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferred") &&
                         ((bumpshiny_ctrl && bumpshiny_ctrl->get()) ? TRUE : FALSE) &&
-                        ((transparent_water_ctrl && transparent_water_ctrl->get()) ? TRUE : FALSE) &&
-                        gGLManager.mHasFramebufferObject &&
-                        gSavedSettings.getBOOL("RenderAvatarVP") &&
                         (ctrl_wind_light->get()) ? TRUE : FALSE;
 
     ctrl_deferred->setEnabled(enabled);
@@ -1378,7 +1347,6 @@ void LLFloaterPreferenceGraphicsAdvanced::disableUnavailableSettings()
 {	
 	LLComboBox* ctrl_reflections   = getChild<LLComboBox>("Reflections");
 	LLTextBox* reflections_text = getChild<LLTextBox>("ReflectionsText");
-	LLCheckBoxCtrl* ctrl_avatar_vp     = getChild<LLCheckBoxCtrl>("AvatarVertexProgram");
 	LLCheckBoxCtrl* ctrl_avatar_cloth  = getChild<LLCheckBoxCtrl>("AvatarCloth");
 	LLCheckBoxCtrl* ctrl_wind_light    = getChild<LLCheckBoxCtrl>("WindLightUseAtmosShaders");
 	LLCheckBoxCtrl* ctrl_deferred = getChild<LLCheckBoxCtrl>("UseLightShaders");
@@ -1414,8 +1382,7 @@ void LLFloaterPreferenceGraphicsAdvanced::disableUnavailableSettings()
 	}
 
 	// disabled deferred
-	if (!LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferred") ||
-		!gGLManager.mHasFramebufferObject)
+	if (!LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferred"))
 	{
 		ctrl_shadows->setEnabled(FALSE);
 		ctrl_shadows->setValue(0);
@@ -1454,30 +1421,6 @@ void LLFloaterPreferenceGraphicsAdvanced::disableUnavailableSettings()
 		reflections_text->setEnabled(FALSE);
 	}
 	
-	// disabled av
-	if (!LLFeatureManager::getInstance()->isFeatureAvailable("RenderAvatarVP"))
-	{
-		ctrl_avatar_vp->setEnabled(FALSE);
-		ctrl_avatar_vp->setValue(FALSE);
-		
-		ctrl_avatar_cloth->setEnabled(FALSE);
-		ctrl_avatar_cloth->setValue(FALSE);
-
-		//deferred needs AvatarVP, disable deferred
-		ctrl_shadows->setEnabled(FALSE);
-		ctrl_shadows->setValue(0);
-		shadows_text->setEnabled(FALSE);
-		
-		ctrl_ssao->setEnabled(FALSE);
-		ctrl_ssao->setValue(FALSE);
-
-		ctrl_dof->setEnabled(FALSE);
-		ctrl_dof->setValue(FALSE);
-
-		ctrl_deferred->setEnabled(FALSE);
-		ctrl_deferred->setValue(FALSE);
-	}
-
 	// disabled cloth
 	if (!LLFeatureManager::getInstance()->isFeatureAvailable("RenderAvatarCloth"))
 	{
@@ -1846,13 +1789,13 @@ bool LLFloaterPreference::loadFromFilename(const std::string& filename, std::map
 
     if (!LLXMLNode::parseFile(filename, root, NULL))
     {
-        LL_WARNS() << "Unable to parse file " << filename << LL_ENDL;
+        LL_WARNS("Preferences") << "Unable to parse file " << filename << LL_ENDL;
         return false;
     }
 
     if (!root->hasName("labels"))
     {
-        LL_WARNS() << filename << " is not a valid definition file" << LL_ENDL;
+        LL_WARNS("Preferences") << filename << " is not a valid definition file" << LL_ENDL;
         return false;
     }
 
@@ -1872,7 +1815,7 @@ bool LLFloaterPreference::loadFromFilename(const std::string& filename, std::map
     }
     else
     {
-        LL_WARNS() << filename << " failed to load" << LL_ENDL;
+        LL_WARNS("Preferences") << filename << " failed to load" << LL_ENDL;
         return false;
     }
 
@@ -2399,7 +2342,16 @@ void LLPanelPreference::saveSettings()
 		{
 			view_stack.push_back(*iter);
 		}
-	}	
+	}
+
+    if (LLStartUp::getStartupState() == STATE_STARTED)
+    {
+        LLControlVariable* control = gSavedPerAccountSettings.getControl("VoiceCallsFriendsOnly");
+        if (control)
+        {
+            mSavedValues[control] = control->getValue();
+        }
+    }
 }
 
 void LLPanelPreference::showMultipleViewersWarning(LLUICtrl* checkbox, const LLSD& value)
@@ -2769,7 +2721,7 @@ bool LLPanelPreferenceControls::addControlTableColumns(const std::string &filena
     LLScrollListCtrl::Contents contents;
     if (!LLUICtrlFactory::getLayeredXMLNode(filename, xmlNode))
     {
-        LL_WARNS() << "Failed to load " << filename << LL_ENDL;
+        LL_WARNS("Preferences") << "Failed to load " << filename << LL_ENDL;
         return false;
     }
     LLXUIParser parser;
@@ -2796,7 +2748,7 @@ bool LLPanelPreferenceControls::addControlTableRows(const std::string &filename)
     LLScrollListCtrl::Contents contents;
     if (!LLUICtrlFactory::getLayeredXMLNode(filename, xmlNode))
     {
-        LL_WARNS() << "Failed to load " << filename << LL_ENDL;
+        LL_WARNS("Preferences") << "Failed to load " << filename << LL_ENDL;
         return false;
     }
     LLXUIParser parser;
@@ -2902,7 +2854,7 @@ void LLPanelPreferenceControls::populateControlTable()
         {
             // Either unknown mode or MODE_SAVED_SETTINGS
             // It doesn't have UI or actual settings yet
-            LL_WARNS() << "Unimplemented mode" << LL_ENDL;
+            LL_WARNS("Preferences") << "Unimplemented mode" << LL_ENDL;
 
             // Searchable columns were removed, mark searchables for an update
             LLFloaterPreference* instance = LLFloaterReg::findTypedInstance<LLFloaterPreference>("preferences");
@@ -2942,7 +2894,7 @@ void LLPanelPreferenceControls::populateControlTable()
     }
     else
     {
-        LL_WARNS() << "Unimplemented mode" << LL_ENDL;
+        LL_WARNS("Preferences") << "Unimplemented mode" << LL_ENDL;
     }
 
     // explicit update to make sure table is ready for llsearchableui
@@ -2997,10 +2949,15 @@ void LLPanelPreferenceControls::cancel()
         if (mConflictHandler[i].hasUnsavedChanges())
         {
             mConflictHandler[i].clear();
+            if (mEditingMode == i)
+            {
+                // cancel() can be called either when preferences floater closes
+                // or when child floater closes (like advanced graphical settings)
+                // in which case we need to clear and repopulate table
+                regenerateControls();
+            }
         }
     }
-    pControlsTable->clearRows();
-    pControlsTable->clearColumns();
 }
 
 void LLPanelPreferenceControls::saveSettings()
diff --git a/indra/newview/llfloaterpreference.h b/indra/newview/llfloaterpreference.h
index 5ef2ca68d3665cfef5d403e0b3932ad362b95b5d..542df18ddba39f94107de156078dea33136dd72c 100644
--- a/indra/newview/llfloaterpreference.h
+++ b/indra/newview/llfloaterpreference.h
@@ -100,9 +100,8 @@ class LLFloaterPreference : public LLFloater, public LLAvatarPropertiesObserver,
 	static void updateShowFavoritesCheckbox(bool val);
 
 	void processProperties( void* pData, EAvatarProcessorType type );
-	void processProfileProperties(const LLAvatarData* pAvatarData );
-	void storeAvatarProperties( const LLAvatarData* pAvatarData );
 	void saveAvatarProperties( void );
+    static void saveAvatarPropertiesCoro(const std::string url, bool allow_publish);
 	void selectPrivacyPanel();
 	void selectChatPanel();
 	void getControlNames(std::vector<std::string>& names);
@@ -213,7 +212,7 @@ class LLFloaterPreference : public LLFloater, public LLAvatarPropertiesObserver,
 	bool mOriginalHideOnlineStatus;
 	std::string mDirectoryVisibility;
 	
-	LLAvatarData mAvatarProperties;
+	bool mAllowPublish; // Allow showing agent in search
 	std::string mSavedCameraPreset;
 	std::string mSavedGraphicsPreset;
 	LOG_CLASS(LLFloaterPreference);
diff --git a/indra/newview/llfloaterprofile.cpp b/indra/newview/llfloaterprofile.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..6ccdace6c5d9ad49770b97a5cd5d7bd5e056a679
--- /dev/null
+++ b/indra/newview/llfloaterprofile.cpp
@@ -0,0 +1,170 @@
+/**
+ * @file llfloaterprofile.cpp
+ * @brief Avatar profile floater.
+ *
+ * $LicenseInfo:firstyear=2022&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2022, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llfloaterprofile.h"
+
+#include "llagent.h" //gAgent
+#include "llnotificationsutil.h"
+#include "llpanelavatar.h"
+#include "llpanelprofile.h"
+
+static const std::string PANEL_PROFILE_VIEW = "panel_profile_view";
+
+LLFloaterProfile::LLFloaterProfile(const LLSD& key)
+ : LLFloater(key),
+ mAvatarId(key["id"].asUUID()),
+ mNameCallbackConnection()
+{
+	mDefaultRectForGroup = false;
+}
+
+LLFloaterProfile::~LLFloaterProfile()
+{
+    if (mNameCallbackConnection.connected())
+    {
+        mNameCallbackConnection.disconnect();
+    }
+}
+
+void LLFloaterProfile::onOpen(const LLSD& key)
+{
+    mPanelProfile->onOpen(key);
+
+    // Update the avatar name.
+    mNameCallbackConnection = LLAvatarNameCache::get(mAvatarId, boost::bind(&LLFloaterProfile::onAvatarNameCache, this, _1, _2));
+}
+
+BOOL LLFloaterProfile::postBuild()
+{
+    mPanelProfile = findChild<LLPanelProfile>(PANEL_PROFILE_VIEW);
+
+    return TRUE;
+}
+
+void LLFloaterProfile::onClickCloseBtn(bool app_quitting)
+{
+    if (!app_quitting)
+    {
+        if (mPanelProfile->hasUnpublishedClassifieds())
+        {
+            LLNotificationsUtil::add("ProfileUnpublishedClassified", LLSD(), LLSD(),
+                boost::bind(&LLFloaterProfile::onUnsavedChangesCallback, this, _1, _2, false));
+        }
+        else if (mPanelProfile->hasUnsavedChanges())
+        {
+            LLNotificationsUtil::add("ProfileUnsavedChanges", LLSD(), LLSD(),
+                boost::bind(&LLFloaterProfile::onUnsavedChangesCallback, this, _1, _2, true));
+        }
+        else
+        {
+            closeFloater();
+        }
+    }
+    else
+    {
+        closeFloater();
+    }
+}
+
+void LLFloaterProfile::onUnsavedChangesCallback(const LLSD& notification, const LLSD& response, bool can_save)
+{
+    S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+    if (can_save)
+    {
+        // savable content
+
+        if (option == 0) // Save
+        {
+            mPanelProfile->commitUnsavedChanges();
+            closeFloater();
+        }
+        if (option == 1) // Discard
+        {
+            closeFloater();
+        }
+        // else cancel
+    }
+    else
+    {
+        // classifieds
+
+        if (option == 0) // Ok
+        {
+            closeFloater();
+        }
+        // else cancel
+    }
+
+}
+
+void LLFloaterProfile::createPick(const LLPickData &data)
+{
+    mPanelProfile->createPick(data);
+}
+
+void LLFloaterProfile::showPick(const LLUUID& pick_id)
+{
+    mPanelProfile->showPick(pick_id);
+}
+
+bool LLFloaterProfile::isPickTabSelected()
+{
+    return mPanelProfile->isPickTabSelected();
+}
+
+void LLFloaterProfile::refreshName()
+{
+    if (!mNameCallbackConnection.connected())
+    {
+        mNameCallbackConnection = LLAvatarNameCache::get(mAvatarId, boost::bind(&LLFloaterProfile::onAvatarNameCache, this, _1, _2));
+    }
+
+    LLPanelProfileSecondLife *panel = findChild<LLPanelProfileSecondLife>("panel_profile_secondlife");
+    if (panel)
+    {
+        panel->refreshName();
+    }
+}
+
+void LLFloaterProfile::showClassified(const LLUUID& classified_id, bool edit)
+{
+    mPanelProfile->showClassified(classified_id, edit);
+}
+
+void LLFloaterProfile::createClassified()
+{
+    mPanelProfile->createClassified();
+}
+
+void LLFloaterProfile::onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name)
+{
+    mNameCallbackConnection.disconnect();
+    setTitle(av_name.getCompleteName());
+}
+
+// eof
diff --git a/indra/newview/llfloaterprofile.h b/indra/newview/llfloaterprofile.h
new file mode 100644
index 0000000000000000000000000000000000000000..b3ed02fc2c625929061a3d8a98e99c4fc5442fc6
--- /dev/null
+++ b/indra/newview/llfloaterprofile.h
@@ -0,0 +1,66 @@
+/**
+ * @file llfloaterprofile.h
+ * @brief Avatar profile floater.
+ *
+ * $LicenseInfo:firstyear=2022&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2022, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLFLOATERPROFILE_H
+#define LL_LLFLOATERPROFILE_H
+
+#include "llavatarnamecache.h"
+#include "llavatarpropertiesprocessor.h"
+#include "llfloater.h"
+
+class LLPanelProfile;
+
+class LLFloaterProfile : public LLFloater
+{
+    LOG_CLASS(LLFloaterProfile);
+public:
+    LLFloaterProfile(const LLSD& key);
+    virtual ~LLFloaterProfile();
+
+    BOOL postBuild() override;
+
+    void onOpen(const LLSD& key) override;
+    void onClickCloseBtn(bool app_quitting = false) override;
+    void onUnsavedChangesCallback(const LLSD& notification, const LLSD& response, bool can_save);
+
+    void createPick(const LLPickData &data);
+    void showPick(const LLUUID& pick_id = LLUUID::null);
+    bool isPickTabSelected();
+    void refreshName();
+
+    void showClassified(const LLUUID& classified_id = LLUUID::null, bool edit = false);
+    void createClassified();
+
+private:
+    LLAvatarNameCache::callback_connection_t mNameCallbackConnection;
+    void onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name);
+
+    LLPanelProfile* mPanelProfile;
+
+    LLUUID mAvatarId;
+};
+
+#endif // LL_LLFLOATERPROFILE_H
diff --git a/indra/newview/llfloaterprofiletexture.cpp b/indra/newview/llfloaterprofiletexture.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..bf1f56a6d1c686fd057003d73ee022e28339de86
--- /dev/null
+++ b/indra/newview/llfloaterprofiletexture.cpp
@@ -0,0 +1,223 @@
+/** 
+ * @file llfloaterprofiletexture.cpp
+ * @brief LLFloaterProfileTexture class implementation
+ *
+ * $LicenseInfo:firstyear=2022&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2022, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llfloaterprofiletexture.h"
+
+#include "llbutton.h"
+#include "llfloaterreg.h"
+#include "llpreview.h" // fors constants
+#include "lltrans.h"
+#include "llviewercontrol.h"
+#include "lltextureview.h"
+#include "llviewertexture.h"
+#include "llviewertexturelist.h"
+
+
+
+LLFloaterProfileTexture::LLFloaterProfileTexture(LLView* owner)
+    : LLFloater(LLSD())
+    , mUpdateDimensions(TRUE)
+    , mLastHeight(0)
+    , mLastWidth(0)
+    , mImage(NULL)
+    , mImageOldBoostLevel(LLGLTexture::BOOST_NONE)
+    , mOwnerHandle(owner->getHandle())
+{
+    buildFromFile("floater_profile_texture.xml");
+}
+
+LLFloaterProfileTexture::~LLFloaterProfileTexture()
+{
+    if (mImage.notNull())
+    {
+        mImage->setBoostLevel(mImageOldBoostLevel);
+        mImage = NULL;
+    }
+}
+
+// virtual
+BOOL LLFloaterProfileTexture::postBuild()
+{
+    mProfileIcon = getChild<LLIconCtrl>("profile_pic");
+
+    mCloseButton = getChild<LLButton>("close_btn");
+    mCloseButton->setCommitCallback([this](LLUICtrl*, void*) { closeFloater(); }, nullptr);
+
+	return TRUE;
+}
+
+// virtual
+void LLFloaterProfileTexture::reshape(S32 width, S32 height, BOOL called_from_parent)
+{
+	LLFloater::reshape(width, height, called_from_parent);
+}
+
+// It takes a while until we get height and width information.
+// When we receive it, reshape the window accordingly.
+void LLFloaterProfileTexture::updateDimensions()
+{
+    if (mImage.isNull())
+    {
+        return;
+    }
+    if ((mImage->getFullWidth() * mImage->getFullHeight()) == 0)
+    {
+        return;
+    }
+
+    S32 img_width = mImage->getFullWidth();
+    S32 img_height = mImage->getFullHeight();
+
+    if (mAssetStatus != LLPreview::PREVIEW_ASSET_LOADED
+        || mLastWidth != img_width
+        || mLastHeight != img_height)
+    {
+        mAssetStatus = LLPreview::PREVIEW_ASSET_LOADED;
+        // Asset has been fully loaded
+        mUpdateDimensions = TRUE;
+    }
+
+    mLastHeight = img_height;
+    mLastWidth = img_width;
+
+    // Reshape the floater only when required
+    if (mUpdateDimensions)
+    {
+        mUpdateDimensions = FALSE;
+
+        LLRect old_floater_rect = getRect();
+        LLRect old_image_rect = mProfileIcon->getRect();
+        S32 width = old_floater_rect.getWidth() - old_image_rect.getWidth() + mLastWidth;
+        S32 height = old_floater_rect.getHeight() - old_image_rect.getHeight() + mLastHeight;
+
+        const F32 MAX_DIMENTIONS = 512; // most profiles are supposed to be 256x256
+
+        S32 biggest_dim = llmax(width, height);
+        if (biggest_dim > MAX_DIMENTIONS)
+        {
+            F32 scale_down = MAX_DIMENTIONS / (F32)biggest_dim;
+            width *= scale_down;
+            height *= scale_down;
+        }
+
+        //reshape floater
+        reshape(width, height);
+
+        gFloaterView->adjustToFitScreen(this, FALSE);
+    }
+}
+
+void LLFloaterProfileTexture::draw()
+{
+    // drawFrustum
+    LLView *owner = mOwnerHandle.get();
+    static LLCachedControl<F32> max_opacity(gSavedSettings, "PickerContextOpacity", 0.4f);
+    drawConeToOwner(mContextConeOpacity, max_opacity, owner);
+
+    LLFloater::draw();
+}
+
+void LLFloaterProfileTexture::onOpen(const LLSD& key)
+{
+    mCloseButton->setFocus(true);
+}
+
+void LLFloaterProfileTexture::resetAsset()
+{
+    mProfileIcon->setValue("Generic_Person_Large");
+    mImageID = LLUUID::null;
+    if (mImage.notNull())
+    {
+        mImage->setBoostLevel(mImageOldBoostLevel);
+        mImage = NULL;
+    }
+}
+void LLFloaterProfileTexture::loadAsset(const LLUUID &image_id)
+{
+    if (mImageID != image_id)
+    {
+        if (mImage.notNull())
+        {
+            mImage->setBoostLevel(mImageOldBoostLevel);
+            mImage = NULL;
+        }
+    }
+    else
+    {
+        return;
+    }
+
+    mProfileIcon->setValue(image_id);
+    mImageID = image_id;
+    mImage = LLViewerTextureManager::getFetchedTexture(mImageID, FTT_DEFAULT, MIPMAP_TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE);
+    mImageOldBoostLevel = mImage->getBoostLevel();
+
+    if ((mImage->getFullWidth() * mImage->getFullHeight()) == 0)
+    {
+        mImage->setLoadedCallback(LLFloaterProfileTexture::onTextureLoaded,
+            0, TRUE, FALSE, new LLHandle<LLFloater>(getHandle()), &mCallbackTextureList);
+
+        mImage->setBoostLevel(LLGLTexture::BOOST_PREVIEW);
+        mAssetStatus = LLPreview::PREVIEW_ASSET_LOADING;
+    }
+    else
+    {
+        mAssetStatus = LLPreview::PREVIEW_ASSET_LOADED;
+    }
+
+    mUpdateDimensions = TRUE;
+    updateDimensions();
+}
+
+// static
+void LLFloaterProfileTexture::onTextureLoaded(
+    BOOL success,
+    LLViewerFetchedTexture *src_vi,
+    LLImageRaw* src,
+    LLImageRaw* aux_src,
+    S32 discard_level,
+    BOOL final,
+    void* userdata)
+{
+    LLHandle<LLFloater>* handle = (LLHandle<LLFloater>*)userdata;
+
+    if (!handle->isDead())
+    {
+        LLFloaterProfileTexture* floater = static_cast<LLFloaterProfileTexture*>(handle->get());
+        if (floater && success)
+        {
+            floater->mUpdateDimensions = TRUE;
+            floater->updateDimensions();
+        }
+    }
+
+    if (final || !success)
+    {
+        delete handle;
+    }
+}
diff --git a/indra/newview/llfloaterprofiletexture.h b/indra/newview/llfloaterprofiletexture.h
new file mode 100644
index 0000000000000000000000000000000000000000..66a61213ddafc7baa4aa94bc597226476ed44c4b
--- /dev/null
+++ b/indra/newview/llfloaterprofiletexture.h
@@ -0,0 +1,81 @@
+/** 
+ * @file llfloaterprofiletexture.h
+ * @brief LLFloaterProfileTexture class definition
+ *
+ * $LicenseInfo:firstyear=2022&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2022, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLFLOATERPROFILETEXTURE_H
+#define LL_LLFLOATERPROFILETEXTURE_H
+
+#include "llfloater.h"
+#include "llviewertexture.h"
+
+class LLButton;
+class LLImageRaw;
+class LLIconCtrl;
+
+class LLFloaterProfileTexture : public LLFloater
+{
+public:
+    LLFloaterProfileTexture(LLView* owner);
+    ~LLFloaterProfileTexture();
+
+    void draw() override;
+    void onOpen(const LLSD& key) override;
+
+    void resetAsset();
+    void loadAsset(const LLUUID &image_id);
+
+
+    static void onTextureLoaded(
+        BOOL success,
+        LLViewerFetchedTexture *src_vi,
+        LLImageRaw* src,
+        LLImageRaw* aux_src,
+        S32 discard_level,
+        BOOL final,
+        void* userdata);
+
+    void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE) override;
+protected:
+    BOOL postBuild() override;
+
+private:
+    void updateDimensions();
+
+    LLUUID mImageID;
+    LLPointer<LLViewerFetchedTexture> mImage;
+    S32 mImageOldBoostLevel;
+    S32 mAssetStatus;
+    F32 mContextConeOpacity;
+    S32 mLastHeight;
+    S32 mLastWidth;
+    BOOL mUpdateDimensions;
+
+    LLHandle<LLView> mOwnerHandle;
+    LLIconCtrl* mProfileIcon;
+    LLButton* mCloseButton;
+
+    LLLoadedCallbackEntry::source_callback_list_t mCallbackTextureList;
+};
+#endif  // LL_LLFLOATERPROFILETEXTURE_H
diff --git a/indra/newview/llfloaterregioninfo.cpp b/indra/newview/llfloaterregioninfo.cpp
index 19080f05c062ea408597861b93fad2941771deb3..07d4dcae38f766ea2fc2e3dcd3fa4e170af1f133 100644
--- a/indra/newview/llfloaterregioninfo.cpp
+++ b/indra/newview/llfloaterregioninfo.cpp
@@ -47,6 +47,7 @@
 
 #include "llagent.h"
 #include "llappviewer.h"
+#include "llavataractions.h"
 #include "llavatarname.h"
 #include "llfloateravatarpicker.h"
 #include "llbutton.h" 
@@ -1322,6 +1323,7 @@ void LLPanelRegionDebugInfo::onClickDebugConsole(void* data)
 
 BOOL LLPanelRegionTerrainInfo::validateTextureSizes()
 {
+    static const S32 MAX_TERRAIN_TEXTURE_SIZE = 1024;
 	for(S32 i = 0; i < TERRAIN_TEXTURE_COUNT; ++i)
 	{
 		std::string buffer;
@@ -1343,17 +1345,19 @@ BOOL LLPanelRegionTerrainInfo::validateTextureSizes()
 			LLSD args;
 			args["TEXTURE_NUM"] = i+1;
 			args["TEXTURE_BIT_DEPTH"] = llformat("%d",components * 8);
+            args["MAX_SIZE"] = MAX_TERRAIN_TEXTURE_SIZE;
 			LLNotificationsUtil::add("InvalidTerrainBitDepth", args);
 			return FALSE;
 		}
 
-		if (width > 512 || height > 512)
+		if (width > MAX_TERRAIN_TEXTURE_SIZE || height > MAX_TERRAIN_TEXTURE_SIZE)
 		{
 
 			LLSD args;
 			args["TEXTURE_NUM"] = i+1;
 			args["TEXTURE_SIZE_X"] = width;
 			args["TEXTURE_SIZE_Y"] = height;
+            args["MAX_SIZE"] = MAX_TERRAIN_TEXTURE_SIZE;
 			LLNotificationsUtil::add("InvalidTerrainSize", args);
 			return FALSE;
 			
@@ -1826,7 +1830,7 @@ void LLPanelEstateInfo::updateControls(LLViewerRegion* region)
 	setCtrlsEnabled(god || owner || manager);
 	
 	getChildView("apply_btn")->setEnabled(FALSE);
-
+    getChildView("estate_owner")->setEnabled(TRUE);
 	getChildView("message_estate_btn")->setEnabled(god || owner || manager);
 	getChildView("kick_user_from_estate_btn")->setEnabled(god || owner || manager);
 
@@ -1888,6 +1892,8 @@ BOOL LLPanelEstateInfo::postBuild()
 
 	getChild<LLUICtrl>("externally_visible_radio")->setFocus(TRUE);
 
+    getChild<LLTextBox>("estate_owner")->setIsFriendCallback(LLAvatarActions::isFriend);
+
 	return LLPanelRegionInfo::postBuild();
 }
 
@@ -2108,6 +2114,8 @@ bool LLPanelEstateCovenant::refreshFromRegion(LLViewerRegion* region)
 	
 	LLTextBox* region_landtype = getChild<LLTextBox>("region_landtype_text");
 	region_landtype->setText(region->getLocalizedSimProductName());
+
+    getChild<LLButton>("reset_covenant")->setEnabled(gAgent.isGodlike() || (region && region->canManageEstate()));
 	
 	// let the parent class handle the general data collection. 
 	bool rv = LLPanelRegionInfo::refreshFromRegion(region);
@@ -2132,6 +2140,7 @@ BOOL LLPanelEstateCovenant::postBuild()
 {
 	mEstateNameText = getChild<LLTextBox>("estate_name_text");
 	mEstateOwnerText = getChild<LLTextBox>("estate_owner_text");
+    mEstateOwnerText->setIsFriendCallback(LLAvatarActions::isFriend);
 	mLastModifiedText = getChild<LLTextBox>("covenant_timestamp_text");
 	mEditor = getChild<LLViewerTextEditor>("covenant_editor");
 	LLButton* reset_button = getChild<LLButton>("reset_covenant");
@@ -3681,7 +3690,7 @@ void LLPanelEstateAccess::searchAgent(LLNameListCtrl* listCtrl, const std::strin
 	if (!search_string.empty())
 	{
 		listCtrl->setSearchColumn(0); // name column
-		listCtrl->selectItemByPrefix(search_string, FALSE);
+		listCtrl->searchItems(search_string, false, true);
 	}
 	else
 	{
diff --git a/indra/newview/llfloaterreporter.cpp b/indra/newview/llfloaterreporter.cpp
index b73755cf4e21a54e5701b84428c179098c6ba4ca..2df4ca973d677f2f31ec7d5d1589f66708838ea5 100644
--- a/indra/newview/llfloaterreporter.cpp
+++ b/indra/newview/llfloaterreporter.cpp
@@ -54,6 +54,7 @@
 #include "llbutton.h"
 #include "llfloaterreg.h"
 #include "lltexturectrl.h"
+#include "lltexteditor.h"
 #include "llscrolllistctrl.h"
 #include "lldispatcher.h"
 #include "llviewerobject.h"
@@ -250,9 +251,6 @@ LLFloaterReporter::~LLFloaterReporter()
 
 	mPosition.setVec(0.0f, 0.0f, 0.0f);
 
-	std::for_each(mMCDList.begin(), mMCDList.end(), DeletePointer() );
-	mMCDList.clear();
-
 	delete mResourceDatap;
 }
 
@@ -661,6 +659,23 @@ void LLFloaterReporter::showFromAvatar(const LLUUID& avatar_id, const std::strin
 	show(avatar_id, avatar_name);
 }
 
+// static
+void LLFloaterReporter::showFromChat(const LLUUID& avatar_id, const std::string& avatar_name, const std::string& time, const std::string& description)
+{
+    show(avatar_id, avatar_name);
+
+    LLStringUtil::format_map_t args;
+    args["[MSG_TIME]"] = time;
+    args["[MSG_DESCRIPTION]"] = description;
+
+    LLFloaterReporter *self = LLFloaterReg::findTypedInstance<LLFloaterReporter>("reporter");
+    if (self)
+    {
+        std::string description = self->getString("chat_report_format", args);
+        self->getChild<LLUICtrl>("details_edit")->setValue(description);
+    }
+}
+
 void LLFloaterReporter::setPickedObjectProperties(const std::string& object_name, const std::string& owner_name, const LLUUID owner_id)
 {
 	getChild<LLUICtrl>("object_name")->setValue(object_name);
@@ -1028,37 +1043,3 @@ void LLFloaterReporter::onClose(bool app_quitting)
 	mSnapshotTimer.stop();
 	gSavedPerAccountSettings.setBOOL("PreviousScreenshotForReport", app_quitting);
 }
-
-
-// void LLFloaterReporter::setDescription(const std::string& description, LLMeanCollisionData *mcd)
-// {
-// 	LLFloaterReporter *self = LLFloaterReg::findTypedInstance<LLFloaterReporter>("reporter");
-// 	if (self)
-// 	{
-// 		self->getChild<LLUICtrl>("details_edit")->setValue(description);
-
-// 		for_each(self->mMCDList.begin(), self->mMCDList.end(), DeletePointer());
-// 		self->mMCDList.clear();
-// 		if (mcd)
-// 		{
-// 			self->mMCDList.push_back(new LLMeanCollisionData(mcd));
-// 		}
-// 	}
-// }
-
-// void LLFloaterReporter::addDescription(const std::string& description, LLMeanCollisionData *mcd)
-// {
-// 	LLFloaterReporter *self = LLFloaterReg::findTypedInstance<LLFloaterReporter>("reporter");
-// 	if (self)
-// 	{
-// 		LLTextEditor* text = self->getChild<LLTextEditor>("details_edit");
-// 		if (text)
-// 		{	
-// 			text->insertText(description);
-// 		}
-// 		if (mcd)
-// 		{
-// 			self->mMCDList.push_back(new LLMeanCollisionData(mcd));
-// 		}
-// 	}
-// }
diff --git a/indra/newview/llfloaterreporter.h b/indra/newview/llfloaterreporter.h
index c678df7155ae423466e2296457de673461ed7c2d..b6c70e866d1fb0b22f6265d58229ba9eba419dce 100644
--- a/indra/newview/llfloaterreporter.h
+++ b/indra/newview/llfloaterreporter.h
@@ -93,6 +93,7 @@ class LLFloaterReporter
 
 	static void showFromObject(const LLUUID& object_id, const LLUUID& experience_id = LLUUID::null);
 	static void showFromAvatar(const LLUUID& avatar_id, const std::string avatar_name);
+    static void showFromChat(const LLUUID& avatar_id, const std::string& avatar_name, const std::string& time, const std::string& description);
 	static void showFromExperience(const LLUUID& experience_id);
 
 	static void onClickSend			(void *userdata);
@@ -101,8 +102,6 @@ class LLFloaterReporter
 	void onClickSelectAbuser ();
 	static void closePickTool	(void *userdata);
 	static void uploadDoneCallback(const LLUUID &uuid, void* user_data, S32 result, LLExtStat ext_status);
-	static void addDescription(const std::string& description, LLMeanCollisionData *mcd = NULL);
-	static void setDescription(const std::string& description, LLMeanCollisionData *mcd = NULL);
 
 	void setPickedObjectProperties(const std::string& object_name, const std::string& owner_name, const LLUUID owner_id);
 
@@ -114,10 +113,8 @@ class LLFloaterReporter
 	static void show(const LLUUID& object_id, const std::string& avatar_name = LLStringUtil::null, const LLUUID& experience_id = LLUUID::null);
 
 	void takeScreenshot(bool use_prev_screenshot = false);
-	void sendReportViaCaps(std::string url);
 	void uploadImage();
 	bool validateReport();
-	void setReporterID();
 	LLSD gatherReport();
 	void sendReportViaLegacy(const LLSD & report);
 	void sendReportViaCaps(std::string url, std::string sshot_url, const LLSD & report);
@@ -144,7 +141,6 @@ class LLFloaterReporter
 	BOOL 			mPicking;
 	LLVector3		mPosition;
 	BOOL			mCopyrightWarningSeen;
-	std::list<LLMeanCollisionData*> mMCDList;
 	std::string		mDefaultSummary;
 	LLResourceData* mResourceDatap;
 	boost::signals2::connection mAvatarNameCacheConnection;
diff --git a/indra/newview/llfloatersearch.cpp b/indra/newview/llfloatersearch.cpp
index 779542cfcc8821d83232b693f5f02ae7663f1b72..bb3ed77772c6e372baa54eec25a7fe17b0c8cd6d 100644
--- a/indra/newview/llfloatersearch.cpp
+++ b/indra/newview/llfloatersearch.cpp
@@ -57,10 +57,10 @@ class LLSearchHandler : public LLCommandHandler
 		const size_t parts = tokens.size();
 
 		// get the (optional) category for the search
-		std::string category;
+		std::string collection;
 		if (parts > 0)
 		{
-			category = tokens[0].asString();
+            collection = tokens[0].asString();
 		}
 
 		// get the (optional) search string
@@ -72,7 +72,7 @@ class LLSearchHandler : public LLCommandHandler
 
 		// create the LLSD arguments for the search floater
 		LLFloaterSearch::Params p;
-		p.search.category = category;
+		p.search.collection = collection;
 		p.search.query = LLURI::unescape(search_text);
 
 		// open the search floater and perform the requested search
@@ -83,8 +83,9 @@ class LLSearchHandler : public LLCommandHandler
 LLSearchHandler gSearchHandler;
 
 LLFloaterSearch::SearchQuery::SearchQuery()
-:	category("category", ""),
-	query("query")
+:   category("category", ""),
+    collection("collection", ""),
+    query("query")
 {}
 
 LLFloaterSearch::LLFloaterSearch(const Params& key) :
@@ -93,16 +94,16 @@ LLFloaterSearch::LLFloaterSearch(const Params& key) :
 {
 	// declare a map that transforms a category name into
 	// the URL suffix that is used to search that category
-	mCategoryPaths = LLSD::emptyMap();
-	mCategoryPaths["all"]          = "search";
-	mCategoryPaths["people"]       = "search/people";
-	mCategoryPaths["places"]       = "search/places";
-	mCategoryPaths["events"]       = "search/events";
-	mCategoryPaths["groups"]       = "search/groups";
-	mCategoryPaths["wiki"]         = "search/wiki";
-	mCategoryPaths["land"]         = "land";
-	mCategoryPaths["destinations"] = "destinations";
-	mCategoryPaths["classifieds"]  = "classifieds";
+
+    mSearchType.insert("standard");
+    mSearchType.insert("land");
+    mSearchType.insert("classified");
+
+    mCollectionType.insert("events");
+    mCollectionType.insert("destinations");
+    mCollectionType.insert("places");
+    mCollectionType.insert("groups");
+    mCollectionType.insert("people");
 }
 
 BOOL LLFloaterSearch::postBuild()
@@ -157,40 +158,49 @@ void LLFloaterSearch::search(const SearchQuery &p)
 
 	// work out the subdir to use based on the requested category
 	LLSD subs;
-	if (mCategoryPaths.has(p.category))
+	if (mSearchType.find(p.category) != mSearchType.end())
 	{
-		subs["CATEGORY"] = mCategoryPaths[p.category].asString();
+		subs["TYPE"] = p.category;
 	}
 	else
 	{
-		subs["CATEGORY"] = mCategoryPaths["all"].asString();
+		subs["TYPE"] = "standard";
 	}
 
 	// add the search query string
 	subs["QUERY"] = LLURI::escape(p.query);
 
-	// add the permissions token that login.cgi gave us
-	// We use "search_token", and fallback to "auth_token" if not present.
-	LLSD search_token = LLLoginInstance::getInstance()->getResponse("search_token");
-	if (search_token.asString().empty())
-	{
-		search_token = LLLoginInstance::getInstance()->getResponse("auth_token");
-	}
-	subs["AUTH_TOKEN"] = search_token.asString();
+    subs["COLLECTION"] = "";
+    if (subs["TYPE"] == "standard")
+    {
+        if (mCollectionType.find(p.collection) != mCollectionType.end())
+        {
+            subs["COLLECTION"] = "&collection_chosen=" + std::string(p.collection);
+        }
+        else
+        {
+            std::string collection_args("");
+            for (std::set<std::string>::iterator it = mCollectionType.begin(); it != mCollectionType.end(); ++it)
+            {
+                collection_args += "&collection_chosen=" + std::string(*it);
+            }
+            subs["COLLECTION"] = collection_args;
+        }
+    }
 
 	// add the user's preferred maturity (can be changed via prefs)
 	std::string maturity;
 	if (gAgent.prefersAdult())
 	{
-		maturity = "42";  // PG,Mature,Adult
+		maturity = "gma";  // PG,Mature,Adult
 	}
 	else if (gAgent.prefersMature())
 	{
-		maturity = "21";  // PG,Mature
+		maturity = "gm";  // PG,Mature
 	}
 	else
 	{
-		maturity = "13";  // PG
+		maturity = "g";  // PG
 	}
 	subs["MATURITY"] = maturity;
 
diff --git a/indra/newview/llfloatersearch.h b/indra/newview/llfloatersearch.h
index 35b268e1b28f0774fdcfde386ea1de0e4db14582..cc77ce696fccf3709b5b683344cd9b409e0a252c 100644
--- a/indra/newview/llfloatersearch.h
+++ b/indra/newview/llfloatersearch.h
@@ -49,6 +49,7 @@ class LLFloaterSearch :
 	struct SearchQuery : public LLInitParam::Block<SearchQuery>
 	{
 		Optional<std::string> category;
+        Optional<std::string> collection;
 		Optional<std::string> query;
 
 		SearchQuery();
@@ -84,7 +85,8 @@ class LLFloaterSearch :
 private:
 	/*virtual*/ BOOL postBuild();
 
-	LLSD        mCategoryPaths;
+    std::set<std::string> mSearchType;
+    std::set<std::string> mCollectionType;
 	U8          mSearchGodLevel;
 };
 
diff --git a/indra/newview/llfloatertools.cpp b/indra/newview/llfloatertools.cpp
index 0429749e11dc0659a124006dfcac81c268ba54f2..b6acba6558b90cb2e8ac14aa548fb61655323add 100644
--- a/indra/newview/llfloatertools.cpp
+++ b/indra/newview/llfloatertools.cpp
@@ -46,7 +46,6 @@
 #include "llfloaterreg.h"
 #include "llfocusmgr.h"
 #include "llmediaentry.h"
-#include "llmediactrl.h"
 #include "llmenugl.h"
 #include "llnotificationsutil.h"
 #include "llpanelcontents.h"
@@ -240,7 +239,6 @@ BOOL	LLFloaterTools::postBuild()
 	mRadioGroupMove		= getChild<LLRadioGroup>("move_radio_group");
 	mRadioGroupEdit		= getChild<LLRadioGroup>("edit_radio_group");
 	mBtnGridOptions		= getChild<LLButton>("Options...");
-	mTitleMedia			= getChild<LLMediaCtrl>("title_media");
 	mBtnLink			= getChild<LLButton>("link_btn");
 	mBtnUnlink			= getChild<LLButton>("unlink_btn");
 	
@@ -329,7 +327,6 @@ LLFloaterTools::LLFloaterTools(const LLSD& key)
 
 	mCheckSnapToGrid(NULL),
 	mBtnGridOptions(NULL),
-	mTitleMedia(NULL),
 	mComboGridMode(NULL),
 	mCheckStretchUniform(NULL),
 	mCheckStretchTexture(NULL),
@@ -369,8 +366,7 @@ LLFloaterTools::LLFloaterTools(const LLSD& key)
 	mLandImpactsObserver(NULL),
 
 	mDirty(TRUE),
-	mHasSelection(TRUE),
-	mNeedMediaTitle(TRUE)
+	mHasSelection(TRUE)
 {
 	gFloaterTools = this;
 
@@ -394,9 +390,6 @@ LLFloaterTools::LLFloaterTools(const LLSD& key)
 	mCommitCallbackRegistrar.add("BuildTool.applyToSelection",	boost::bind(&click_apply_to_selection, this));
 	mCommitCallbackRegistrar.add("BuildTool.commitRadioLand",	boost::bind(&commit_radio_group_land,_1));
 	mCommitCallbackRegistrar.add("BuildTool.LandBrushForce",	boost::bind(&commit_slider_dozer_force,_1));
-	mCommitCallbackRegistrar.add("BuildTool.AddMedia",			boost::bind(&LLFloaterTools::onClickBtnAddMedia,this));
-	mCommitCallbackRegistrar.add("BuildTool.DeleteMedia",		boost::bind(&LLFloaterTools::onClickBtnDeleteMedia,this));
-	mCommitCallbackRegistrar.add("BuildTool.EditMedia",			boost::bind(&LLFloaterTools::onClickBtnEditMedia,this));
 
 	mCommitCallbackRegistrar.add("BuildTool.LinkObjects",		boost::bind(&LLSelectMgr::linkObjects, LLSelectMgr::getInstance()));
 	mCommitCallbackRegistrar.add("BuildTool.UnlinkObjects",		boost::bind(&LLSelectMgr::unlinkObjects, LLSelectMgr::getInstance()));
@@ -480,30 +473,61 @@ void LLFloaterTools::refresh()
 	else
 #endif
 	{
-		F32 link_cost  = LLSelectMgr::getInstance()->getSelection()->getSelectedLinksetCost();
-		S32 link_count = LLSelectMgr::getInstance()->getSelection()->getRootObjectCount();
+        LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection();
+        F32 link_cost = selection->getSelectedLinksetCost();
+        S32 link_count = selection->getRootObjectCount();
+        S32 object_count = selection->getObjectCount();
 
-		LLCrossParcelFunctor func;
-		if (LLSelectMgr::getInstance()->getSelection()->applyToRootObjects(&func, true))
-		{
-			// Selection crosses parcel bounds.
-			// We don't display remaining land capacity in this case.
-			const LLStringExplicit empty_str("");
-			childSetTextArg("remaining_capacity", "[CAPACITY_STRING]", empty_str);
-		}
-		else
-		{
-			LLViewerObject* selected_object = mObjectSelection->getFirstObject();
-			if (selected_object)
-			{
-				// Select a parcel at the currently selected object's position.
-				LLViewerParcelMgr::getInstance()->selectParcelAt(selected_object->getPositionGlobal());
-			}
-			else
-			{
-				LL_WARNS() << "Failed to get selected object" << LL_ENDL;
-			}
-		}
+        LLCrossParcelFunctor func;
+        if (!LLSelectMgr::getInstance()->getSelection()->applyToRootObjects(&func, true))
+        {
+            // Unless multiple parcels selected, higlight parcel object is at.
+            LLViewerObject* selected_object = mObjectSelection->getFirstObject();
+            if (selected_object)
+            {
+                // Select a parcel at the currently selected object's position.
+                LLViewerParcelMgr::getInstance()->selectParcelAt(selected_object->getPositionGlobal());
+            }
+            else
+            {
+                LL_WARNS() << "Failed to get selected object" << LL_ENDL;
+            }
+        }
+
+        if (object_count == 1)
+        {
+            // "selection_faces" shouldn't be visible if not LLToolFace::getInstance()
+            // But still need to be populated in case user switches
+
+            std::string faces_str = "";
+
+            for (LLObjectSelection::iterator iter = selection->begin(); iter != selection->end();)
+            {
+                LLObjectSelection::iterator nextiter = iter++; // not strictly needed, we have only one object
+                LLSelectNode* node = *nextiter;
+                LLViewerObject* object = (*nextiter)->getObject();
+                if (!object)
+                    continue;
+                S32 num_tes = llmin((S32)object->getNumTEs(), (S32)object->getNumFaces());
+                for (S32 te = 0; te < num_tes; ++te)
+                {
+                    if (node->isTESelected(te))
+                    {
+                        if (!faces_str.empty())
+                        {
+                            faces_str += ", ";
+                        }
+                        faces_str += llformat("%d", te);
+                    }
+                }
+            }
+
+            childSetTextArg("selection_faces", "[FACES_STRING]", faces_str);
+        }
+
+        bool show_faces = (object_count == 1)
+                          && LLToolFace::getInstance() == LLToolMgr::getInstance()->getCurrentTool();
+        getChildView("selection_faces")->setVisible(show_faces);
 
 		LLStringUtil::format_map_t selection_args;
 		selection_args["OBJ_COUNT"] = llformat("%.1d", link_count);
@@ -522,7 +546,7 @@ void LLFloaterTools::refresh()
 	mPanelObject->refresh();
 	mPanelVolume->refresh();
 	mPanelFace->refresh();
-	refreshMedia();
+    mPanelFace->refreshMedia();
 	mPanelContents->refresh();
 	mPanelLandInfo->refresh();
 
@@ -549,9 +573,6 @@ void LLFloaterTools::draw()
 		mDirty = FALSE;
 	}
 
-	// grab media name/title and update the UI widget
-	updateMediaTitle();
-
 	//	mCheckSelectIndividual->set(gSavedSettings.getBOOL("EditLinkedParts"));
 	LLFloater::draw();
 }
@@ -824,7 +845,8 @@ void LLFloaterTools::updatePopup(LLCoordGL center, MASK mask)
 	bool have_selection = !LLSelectMgr::getInstance()->getSelection()->isEmpty();
 
 	getChildView("selection_count")->setVisible(!land_visible && have_selection);
-	getChildView("remaining_capacity")->setVisible(!land_visible && have_selection);
+    getChildView("selection_faces")->setVisible(LLToolFace::getInstance() == LLToolMgr::getInstance()->getCurrentTool()
+                                                && LLSelectMgr::getInstance()->getSelection()->getObjectCount() == 1);
 	getChildView("selection_empty")->setVisible(!land_visible && !have_selection);
 	
 	mTab->setVisible(!land_visible);
@@ -874,8 +896,7 @@ void LLFloaterTools::onClose(bool app_quitting)
 	LLViewerJoystick::getInstance()->moveAvatar(false);
 
 	// destroy media source used to grab media title
-	if( mTitleMedia )
-		mTitleMedia->unloadMediaSource();
+	mPanelFace->unloadMedia();
 
     // Different from handle_reset_view in that it doesn't actually 
 	//   move the camera if EditCameraMovement is not set.
@@ -1095,7 +1116,7 @@ void LLFloaterTools::onClickGridOptions()
 {
 	LLFloater* floaterp = LLFloaterReg::showInstance("build_options");
 	// position floater next to build tools, not over
-	floaterp->setRect(gFloaterView->findNeighboringPosition(this, floaterp));
+	floaterp->setShape(gFloaterView->findNeighboringPosition(this, floaterp), true);
 }
 
 // static
@@ -1128,51 +1149,6 @@ void LLFloaterTools::onFocusReceived()
 	LLFloater::onFocusReceived();
 }
 
-// Media stuff
-void LLFloaterTools::refreshMedia()
-{
-	getMediaState();	
-}
-
-bool LLFloaterTools::selectedMediaEditable()
-{
-	U32 owner_mask_on;
-	U32 owner_mask_off;
-	U32 valid_owner_perms = LLSelectMgr::getInstance()->selectGetPerm( PERM_OWNER, 
-																	  &owner_mask_on, &owner_mask_off );
-	U32 group_mask_on;
-	U32 group_mask_off;
-	U32 valid_group_perms = LLSelectMgr::getInstance()->selectGetPerm( PERM_GROUP, 
-																	  &group_mask_on, &group_mask_off );
-	U32 everyone_mask_on;
-	U32 everyone_mask_off;
-	S32 valid_everyone_perms = LLSelectMgr::getInstance()->selectGetPerm( PERM_EVERYONE, 
-																		 &everyone_mask_on, &everyone_mask_off );
-	
-	bool selected_Media_editable = false;
-	
-	// if perms we got back are valid
-	if ( valid_owner_perms &&
-		valid_group_perms && 
-		valid_everyone_perms )
-	{
-		
-		if ( ( owner_mask_on & PERM_MODIFY ) ||
-			( group_mask_on & PERM_MODIFY ) || 
-			( group_mask_on & PERM_MODIFY ) )
-		{
-			selected_Media_editable = true;
-		}
-		else
-			// user is NOT allowed to press the RESET button
-		{
-			selected_Media_editable = false;
-		};
-	};
-	
-	return selected_Media_editable;
-}
-
 void LLFloaterTools::updateLandImpacts()
 {
 	LLParcel *parcel = mParcelSelection->getParcel();
@@ -1181,26 +1157,6 @@ void LLFloaterTools::updateLandImpacts()
 		return;
 	}
 
-	S32 rezzed_prims = parcel->getSimWidePrimCount();
-	S32 total_capacity = parcel->getSimWideMaxPrimCapacity();
-	LLViewerRegion* region = LLViewerParcelMgr::getInstance()->getSelectionRegion();
-	if (region)
-	{
-		S32 max_tasks_per_region = (S32)region->getMaxTasks();
-		total_capacity = llmin(total_capacity, max_tasks_per_region);
-	}
-	std::string remaining_capacity_str = "";
-
-	bool show_mesh_cost = gMeshRepo.meshRezEnabled();
-	if (show_mesh_cost)
-	{
-		LLStringUtil::format_map_t remaining_capacity_args;
-		remaining_capacity_args["LAND_CAPACITY"] = llformat("%d", total_capacity - rezzed_prims);
-		remaining_capacity_str = getString("status_remaining_capacity", remaining_capacity_args);
-	}
-
-	childSetTextArg("remaining_capacity", "[CAPACITY_STRING]", remaining_capacity_str);
-
 	// Update land impacts info in the weights floater
 	LLFloaterObjectWeights* object_weights_floater = LLFloaterReg::findTypedInstance<LLFloaterObjectWeights>("object_weights");
 	if(object_weights_floater)
@@ -1209,784 +1165,3 @@ void LLFloaterTools::updateLandImpacts()
 	}
 }
 
-void LLFloaterTools::getMediaState()
-{
-	LLObjectSelectionHandle selected_objects =LLSelectMgr::getInstance()->getSelection();
-	LLViewerObject* first_object = selected_objects->getFirstObject();
-	LLTextBox* media_info = getChild<LLTextBox>("media_info");
-	
-	if( !(first_object 
-		  && first_object->getPCode() == LL_PCODE_VOLUME
-		  &&first_object->permModify() 
-	      ))
-	{
-		getChildView("add_media")->setEnabled(FALSE);
-		media_info->clear();
-		clearMediaSettings();
-		return;
-	}
-	
-	std::string url = first_object->getRegion()->getCapability("ObjectMedia");
-	bool has_media_capability = (!url.empty());
-	
-	if(!has_media_capability)
-	{
-		getChildView("add_media")->setEnabled(FALSE);
-		LL_WARNS("LLFloaterToolsMedia") << "Media not enabled (no capability) in this region!" << LL_ENDL;
-		clearMediaSettings();
-		return;
-	}
-	
-	BOOL is_nonpermanent_enforced = (LLSelectMgr::getInstance()->getSelection()->getFirstRootNode() 
-		&& LLSelectMgr::getInstance()->selectGetRootsNonPermanentEnforced())
-		|| LLSelectMgr::getInstance()->selectGetNonPermanentEnforced();
-	bool editable = is_nonpermanent_enforced && (first_object->permModify() || selectedMediaEditable());
-
-	// Check modify permissions and whether any selected objects are in
-	// the process of being fetched.  If they are, then we're not editable
-	if (editable)
-	{
-		LLObjectSelection::iterator iter = selected_objects->begin(); 
-		LLObjectSelection::iterator end = selected_objects->end();
-		for ( ; iter != end; ++iter)
-		{
-			LLSelectNode* node = *iter;
-			LLVOVolume* object = dynamic_cast<LLVOVolume*>(node->getObject());
-			if (NULL != object)
-			{
-				if (!object->permModify())
-				{
-					LL_INFOS("LLFloaterToolsMedia")
-						<< "Selection not editable due to lack of modify permissions on object id "
-						<< object->getID() << LL_ENDL;
-					
-					editable = false;
-					break;
-				}
-				// XXX DISABLE this for now, because when the fetch finally 
-				// does come in, the state of this floater doesn't properly
-				// update.  Re-selecting fixes the problem, but there is 
-				// contention as to whether this is a sufficient solution.
-//				if (object->isMediaDataBeingFetched())
-//				{
-//					LL_INFOS("LLFloaterToolsMedia")
-//						<< "Selection not editable due to media data being fetched for object id "
-//						<< object->getID() << LL_ENDL;
-//						
-//					editable = false;
-//					break;
-//				}
-			}
-		}
-	}
-
-	// Media settings
-	bool bool_has_media = false;
-	struct media_functor : public LLSelectedTEGetFunctor<bool>
-	{
-		bool get(LLViewerObject* object, S32 face)
-		{
-			LLTextureEntry *te = object->getTE(face);
-			if (te)
-			{
-				return te->hasMedia();
-			}
-			return false;
-		}
-	} func;
-	
-	
-	// check if all faces have media(or, all dont have media)
-	LLFloaterMediaSettings::getInstance()->mIdenticalHasMediaInfo = selected_objects->getSelectedTEValue( &func, bool_has_media );
-	
-	const LLMediaEntry default_media_data;
-	
-	struct functor_getter_media_data : public LLSelectedTEGetFunctor< LLMediaEntry>
-    {
-		functor_getter_media_data(const LLMediaEntry& entry): mMediaEntry(entry) {}	
-
-        LLMediaEntry get( LLViewerObject* object, S32 face )
-        {
-            if ( object )
-                if ( object->getTE(face) )
-                    if ( object->getTE(face)->getMediaData() )
-                        return *(object->getTE(face)->getMediaData());
-			return mMediaEntry;
-        };
-		
-		const LLMediaEntry& mMediaEntry;
-		
-    } func_media_data(default_media_data);
-
-	LLMediaEntry media_data_get;
-    LLFloaterMediaSettings::getInstance()->mMultipleMedia = !(selected_objects->getSelectedTEValue( &func_media_data, media_data_get ));
-	
-	std::string multi_media_info_str = LLTrans::getString("Multiple Media");
-	std::string media_title = "";
-	// update UI depending on whether "object" (prim or face) has media
-	// and whether or not you are allowed to edit it.
-	
-	getChildView("add_media")->setEnabled(editable);
-	// IF all the faces have media (or all dont have media)
-	if ( LLFloaterMediaSettings::getInstance()->mIdenticalHasMediaInfo )
-	{
-		// TODO: get media title and set it.
-		media_info->clear();
-		// if identical is set, all faces are same (whether all empty or has the same media)
-		if(!(LLFloaterMediaSettings::getInstance()->mMultipleMedia) )
-		{
-			// Media data is valid
-			if(media_data_get!=default_media_data)
-			{
-				// initial media title is the media URL (until we get the name)
-				media_title = media_data_get.getHomeURL();
-			}
-			// else all faces might be empty. 
-		}
-		else // there' re Different Medias' been set on on the faces.
-		{
-			media_title = multi_media_info_str;
-		}
-		
-		getChildView("delete_media")->setEnabled(bool_has_media && editable );
-			// TODO: display a list of all media on the face - use 'identical' flag
-	}
-	else // not all face has media but at least one does.
-	{
-		// seleted faces have not identical value
-		LLFloaterMediaSettings::getInstance()->mMultipleValidMedia = selected_objects->isMultipleTEValue(&func_media_data, default_media_data );
-	
-		if(LLFloaterMediaSettings::getInstance()->mMultipleValidMedia)
-		{
-			media_title = multi_media_info_str;
-		}
-		else
-		{
-			// Media data is valid
-			if(media_data_get!=default_media_data)
-			{
-				// initial media title is the media URL (until we get the name)
-				media_title = media_data_get.getHomeURL();
-			}
-		}
-		
-		getChildView("delete_media")->setEnabled(TRUE);
-	}
-
-	navigateToTitleMedia(media_title);
-	media_info->setText(media_title);
-	
-	// load values for media settings
-	updateMediaSettings();
-	
-	LLFloaterMediaSettings::initValues(mMediaSettings, editable );
-}
-
-
-//////////////////////////////////////////////////////////////////////////////
-// called when a user wants to add media to a prim or prim face
-void LLFloaterTools::onClickBtnAddMedia()
-{
-	// check if multiple faces are selected
-	if(LLSelectMgr::getInstance()->getSelection()->isMultipleTESelected())
-	{
-		LLNotificationsUtil::add("MultipleFacesSelected", LLSD(), LLSD(), multipleFacesSelectedConfirm);
-	}
-	else
-	{
-		onClickBtnEditMedia();
-	}
-}
-
-// static
-bool LLFloaterTools::multipleFacesSelectedConfirm(const LLSD& notification, const LLSD& response)
-{
-	S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
-	switch( option )
-	{
-		case 0:  // "Yes"
-			gFloaterTools->onClickBtnEditMedia();
-			break;
-		case 1:  // "No"
-		default:
-			break;
-	}
-	return false;
-}
-
-//////////////////////////////////////////////////////////////////////////////
-// called when a user wants to edit existing media settings on a prim or prim face
-// TODO: test if there is media on the item and only allow editing if present
-void LLFloaterTools::onClickBtnEditMedia()
-{
-	refreshMedia();
-	LLFloaterReg::showInstance("media_settings");	
-}
-
-//////////////////////////////////////////////////////////////////////////////
-// called when a user wants to delete media from a prim or prim face
-void LLFloaterTools::onClickBtnDeleteMedia()
-{
-	LLNotificationsUtil::add("DeleteMedia", LLSD(), LLSD(), deleteMediaConfirm);
-}
-
-
-// static
-bool LLFloaterTools::deleteMediaConfirm(const LLSD& notification, const LLSD& response)
-{
-	S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
-	switch( option )
-	{
-		case 0:  // "Yes"
-			LLSelectMgr::getInstance()->selectionSetMedia( 0, LLSD() );
-			if(LLFloaterReg::instanceVisible("media_settings"))
-			{
-				LLFloaterReg::hideInstance("media_settings");
-			}
-			break;
-			
-		case 1:  // "No"
-		default:
-			break;
-	}
-	return false;
-}
-
-//////////////////////////////////////////////////////////////////////////////
-//
-void LLFloaterTools::clearMediaSettings()
-{
-	LLFloaterMediaSettings::clearValues(false);
-}
-
-//////////////////////////////////////////////////////////////////////////////
-//
-void LLFloaterTools::navigateToTitleMedia( const std::string url )
-{
-	std::string multi_media_info_str = LLTrans::getString("Multiple Media");
-	if (url.empty() || multi_media_info_str == url)
-	{
-		// nothing to show
-		mNeedMediaTitle = false;
-	}
-	else if (mTitleMedia)
-	{
-		LLPluginClassMedia* media_plugin = mTitleMedia->getMediaPlugin();
-
-		if ( media_plugin ) // Shouldn't this be after navigateTo creates plugin?
-		{
-			// if it's a movie, we don't want to hear it
-			media_plugin->setVolume( 0 );
-		};
-
-		// check if url changed or if we need a new media source
-		if (mTitleMedia->getCurrentNavUrl() != url || media_plugin == NULL)
-		{
-			mTitleMedia->navigateTo( url );
-		}
-
-		// flag that we need to update the title (even if no request were made)
-		mNeedMediaTitle = true;
-	}
-}
-
-//////////////////////////////////////////////////////////////////////////////
-//
-void LLFloaterTools::updateMediaTitle()
-{
-	// only get the media name if we need it
-	if ( ! mNeedMediaTitle )
-		return;
-
-	// get plugin impl
-	LLPluginClassMedia* media_plugin = mTitleMedia->getMediaPlugin();
-	if ( media_plugin )
-	{
-		// get the media name (asynchronous - must call repeatedly)
-		std::string media_title = media_plugin->getMediaName();
-
-		// only replace the title if what we get contains something
-		if ( ! media_title.empty() )
-		{
-			// update the UI widget
-			LLTextBox* media_title_field = getChild<LLTextBox>("media_info");
-			if ( media_title_field )
-			{
-				media_title_field->setText( media_title );
-
-				// stop looking for a title when we get one
-				// FIXME: check this is the right approach
-				mNeedMediaTitle = false;
-			};
-		};
-	};
-}
-
-//////////////////////////////////////////////////////////////////////////////
-//
-void LLFloaterTools::updateMediaSettings()
-{
-    bool identical( false );
-    std::string base_key( "" );
-    std::string value_str( "" );
-    int value_int = 0;
-    bool value_bool = false;
-	LLObjectSelectionHandle selected_objects =LLSelectMgr::getInstance()->getSelection();
-    // TODO: (CP) refactor this using something clever or boost or both !!
-
-    const LLMediaEntry default_media_data;
-
-    // controls 
-    U8 value_u8 = default_media_data.getControls();
-    struct functor_getter_controls : public LLSelectedTEGetFunctor< U8 >
-    {
-		functor_getter_controls(const LLMediaEntry &entry) : mMediaEntry(entry) {}
-		
-        U8 get( LLViewerObject* object, S32 face )
-        {
-            if ( object )
-                if ( object->getTE(face) )
-                    if ( object->getTE(face)->getMediaData() )
-                        return object->getTE(face)->getMediaData()->getControls();
-            return mMediaEntry.getControls();
-        };
-		
-		const LLMediaEntry &mMediaEntry;
-		
-    } func_controls(default_media_data);
-    identical = selected_objects->getSelectedTEValue( &func_controls, value_u8 );
-    base_key = std::string( LLMediaEntry::CONTROLS_KEY );
-    mMediaSettings[ base_key ] = value_u8;
-    mMediaSettings[ base_key + std::string( LLPanelContents::TENTATIVE_SUFFIX ) ] = ! identical;
-	
-    // First click (formerly left click)
-    value_bool = default_media_data.getFirstClickInteract();
-    struct functor_getter_first_click : public LLSelectedTEGetFunctor< bool >
-    {
-		functor_getter_first_click(const LLMediaEntry& entry): mMediaEntry(entry) {}		
-		
-        bool get( LLViewerObject* object, S32 face )
-        {
-            if ( object )
-                if ( object->getTE(face) )
-                    if ( object->getTE(face)->getMediaData() )
-                        return object->getTE(face)->getMediaData()->getFirstClickInteract();
-            return mMediaEntry.getFirstClickInteract();
-        };
-		
-		const LLMediaEntry &mMediaEntry;
-		
-    } func_first_click(default_media_data);
-    identical = selected_objects->getSelectedTEValue( &func_first_click, value_bool );
-    base_key = std::string( LLMediaEntry::FIRST_CLICK_INTERACT_KEY );
-    mMediaSettings[ base_key ] = value_bool;
-    mMediaSettings[ base_key + std::string( LLPanelContents::TENTATIVE_SUFFIX ) ] = ! identical;
-	
-    // Home URL
-    value_str = default_media_data.getHomeURL();
-    struct functor_getter_home_url : public LLSelectedTEGetFunctor< std::string >
-    {
-		functor_getter_home_url(const LLMediaEntry& entry): mMediaEntry(entry) {}		
-		
-        std::string get( LLViewerObject* object, S32 face )
-        {
-            if ( object )
-                if ( object->getTE(face) )
-                    if ( object->getTE(face)->getMediaData() )
-                        return object->getTE(face)->getMediaData()->getHomeURL();
-            return mMediaEntry.getHomeURL();
-        };
-		
-		const LLMediaEntry &mMediaEntry;
-		
-    } func_home_url(default_media_data);
-    identical = selected_objects->getSelectedTEValue( &func_home_url, value_str );
-    base_key = std::string( LLMediaEntry::HOME_URL_KEY );
-    mMediaSettings[ base_key ] = value_str;
-    mMediaSettings[ base_key + std::string( LLPanelContents::TENTATIVE_SUFFIX ) ] = ! identical;
-	
-    // Current URL
-    value_str = default_media_data.getCurrentURL();
-    struct functor_getter_current_url : public LLSelectedTEGetFunctor< std::string >
-    {
-		functor_getter_current_url(const LLMediaEntry& entry): mMediaEntry(entry) {}
-        
-		std::string get( LLViewerObject* object, S32 face )
-        {
-            if ( object )
-                if ( object->getTE(face) )
-                    if ( object->getTE(face)->getMediaData() )
-                        return object->getTE(face)->getMediaData()->getCurrentURL();
-            return mMediaEntry.getCurrentURL();
-        };
-		
-		const LLMediaEntry &mMediaEntry;
-		
-    } func_current_url(default_media_data);
-    identical = selected_objects->getSelectedTEValue( &func_current_url, value_str );
-    base_key = std::string( LLMediaEntry::CURRENT_URL_KEY );
-    mMediaSettings[ base_key ] = value_str;
-    mMediaSettings[ base_key + std::string( LLPanelContents::TENTATIVE_SUFFIX ) ] = ! identical;
-	
-    // Auto zoom
-    value_bool = default_media_data.getAutoZoom();
-    struct functor_getter_auto_zoom : public LLSelectedTEGetFunctor< bool >
-    {
-		
-		functor_getter_auto_zoom(const LLMediaEntry& entry)	: mMediaEntry(entry) {}	
-		
-        bool get( LLViewerObject* object, S32 face )
-        {
-            if ( object )
-                if ( object->getTE(face) )
-                    if ( object->getTE(face)->getMediaData() )
-                        return object->getTE(face)->getMediaData()->getAutoZoom();
-            return mMediaEntry.getAutoZoom();
-        };
-		
-		const LLMediaEntry &mMediaEntry;
-		
-    } func_auto_zoom(default_media_data);
-    identical = selected_objects->getSelectedTEValue( &func_auto_zoom, value_bool );
-    base_key = std::string( LLMediaEntry::AUTO_ZOOM_KEY );
-    mMediaSettings[ base_key ] = value_bool;
-    mMediaSettings[ base_key + std::string( LLPanelContents::TENTATIVE_SUFFIX ) ] = ! identical;
-	
-    // Auto play
-    //value_bool = default_media_data.getAutoPlay();
-	// set default to auto play TRUE -- angela  EXT-5172
-	value_bool = true;
-    struct functor_getter_auto_play : public LLSelectedTEGetFunctor< bool >
-    {
-		functor_getter_auto_play(const LLMediaEntry& entry)	: mMediaEntry(entry) {}	
-			
-        bool get( LLViewerObject* object, S32 face )
-        {
-            if ( object )
-                if ( object->getTE(face) )
-                    if ( object->getTE(face)->getMediaData() )
-                        return object->getTE(face)->getMediaData()->getAutoPlay();
-            //return mMediaEntry.getAutoPlay(); set default to auto play TRUE -- angela  EXT-5172
-			return true;
-        };
-		
-		const LLMediaEntry &mMediaEntry;
-		
-    } func_auto_play(default_media_data);
-    identical = selected_objects->getSelectedTEValue( &func_auto_play, value_bool );
-    base_key = std::string( LLMediaEntry::AUTO_PLAY_KEY );
-    mMediaSettings[ base_key ] = value_bool;
-    mMediaSettings[ base_key + std::string( LLPanelContents::TENTATIVE_SUFFIX ) ] = ! identical;
-	
-	
-    // Auto scale
-	// set default to auto scale TRUE -- angela  EXT-5172
-    //value_bool = default_media_data.getAutoScale();
-	value_bool = true;
-    struct functor_getter_auto_scale : public LLSelectedTEGetFunctor< bool >
-    {
-		functor_getter_auto_scale(const LLMediaEntry& entry): mMediaEntry(entry) {}	
-
-        bool get( LLViewerObject* object, S32 face )
-        {
-            if ( object )
-                if ( object->getTE(face) )
-                    if ( object->getTE(face)->getMediaData() )
-                        return object->getTE(face)->getMediaData()->getAutoScale();
-           // return mMediaEntry.getAutoScale();  set default to auto scale TRUE -- angela  EXT-5172
-			return true;
-		};
-		
-		const LLMediaEntry &mMediaEntry;
-		
-    } func_auto_scale(default_media_data);
-    identical = selected_objects->getSelectedTEValue( &func_auto_scale, value_bool );
-    base_key = std::string( LLMediaEntry::AUTO_SCALE_KEY );
-    mMediaSettings[ base_key ] = value_bool;
-    mMediaSettings[ base_key + std::string( LLPanelContents::TENTATIVE_SUFFIX ) ] = ! identical;
-	
-    // Auto loop
-    value_bool = default_media_data.getAutoLoop();
-    struct functor_getter_auto_loop : public LLSelectedTEGetFunctor< bool >
-    {
-		functor_getter_auto_loop(const LLMediaEntry& entry)	: mMediaEntry(entry) {}	
-
-        bool get( LLViewerObject* object, S32 face )
-        {
-            if ( object )
-                if ( object->getTE(face) )
-                    if ( object->getTE(face)->getMediaData() )
-                        return object->getTE(face)->getMediaData()->getAutoLoop();
-            return mMediaEntry.getAutoLoop();
-        };
-		
-		const LLMediaEntry &mMediaEntry;
-		
-    } func_auto_loop(default_media_data);
-    identical = selected_objects->getSelectedTEValue( &func_auto_loop, value_bool );
-    base_key = std::string( LLMediaEntry::AUTO_LOOP_KEY );
-    mMediaSettings[ base_key ] = value_bool;
-    mMediaSettings[ base_key + std::string( LLPanelContents::TENTATIVE_SUFFIX ) ] = ! identical;
-	
-    // width pixels (if not auto scaled)
-    value_int = default_media_data.getWidthPixels();
-    struct functor_getter_width_pixels : public LLSelectedTEGetFunctor< int >
-    {
-		functor_getter_width_pixels(const LLMediaEntry& entry): mMediaEntry(entry) {}		
-
-        int get( LLViewerObject* object, S32 face )
-        {
-            if ( object )
-                if ( object->getTE(face) )
-                    if ( object->getTE(face)->getMediaData() )
-                        return object->getTE(face)->getMediaData()->getWidthPixels();
-            return mMediaEntry.getWidthPixels();
-        };
-		
-		const LLMediaEntry &mMediaEntry;
-		
-    } func_width_pixels(default_media_data);
-    identical = selected_objects->getSelectedTEValue( &func_width_pixels, value_int );
-    base_key = std::string( LLMediaEntry::WIDTH_PIXELS_KEY );
-    mMediaSettings[ base_key ] = value_int;
-    mMediaSettings[ base_key + std::string( LLPanelContents::TENTATIVE_SUFFIX ) ] = ! identical;
-	
-    // height pixels (if not auto scaled)
-    value_int = default_media_data.getHeightPixels();
-    struct functor_getter_height_pixels : public LLSelectedTEGetFunctor< int >
-    {
-		functor_getter_height_pixels(const LLMediaEntry& entry)	: mMediaEntry(entry) {}
-        
-		int get( LLViewerObject* object, S32 face )
-        {
-            if ( object )
-                if ( object->getTE(face) )
-                    if ( object->getTE(face)->getMediaData() )
-                        return object->getTE(face)->getMediaData()->getHeightPixels();
-            return mMediaEntry.getHeightPixels();
-        };
-		
-		const LLMediaEntry &mMediaEntry;
-		
-    } func_height_pixels(default_media_data);
-    identical = selected_objects->getSelectedTEValue( &func_height_pixels, value_int );
-    base_key = std::string( LLMediaEntry::HEIGHT_PIXELS_KEY );
-    mMediaSettings[ base_key ] = value_int;
-    mMediaSettings[ base_key + std::string( LLPanelContents::TENTATIVE_SUFFIX ) ] = ! identical;
-	
-    // Enable Alt image
-    value_bool = default_media_data.getAltImageEnable();
-    struct functor_getter_enable_alt_image : public LLSelectedTEGetFunctor< bool >
-    {
-		functor_getter_enable_alt_image(const LLMediaEntry& entry): mMediaEntry(entry) {}
-        
-		bool get( LLViewerObject* object, S32 face )
-        {
-            if ( object )
-                if ( object->getTE(face) )
-                    if ( object->getTE(face)->getMediaData() )
-                        return object->getTE(face)->getMediaData()->getAltImageEnable();
-            return mMediaEntry.getAltImageEnable();
-        };
-		
-		const LLMediaEntry &mMediaEntry;
-		
-    } func_enable_alt_image(default_media_data);
-    identical = selected_objects->getSelectedTEValue( &func_enable_alt_image, value_bool );
-    base_key = std::string( LLMediaEntry::ALT_IMAGE_ENABLE_KEY );
-    mMediaSettings[ base_key ] = value_bool;
-    mMediaSettings[ base_key + std::string( LLPanelContents::TENTATIVE_SUFFIX ) ] = ! identical;
-	
-    // Perms - owner interact
-    value_bool = 0 != ( default_media_data.getPermsInteract() & LLMediaEntry::PERM_OWNER );
-    struct functor_getter_perms_owner_interact : public LLSelectedTEGetFunctor< bool >
-    {
-		functor_getter_perms_owner_interact(const LLMediaEntry& entry): mMediaEntry(entry) {}
-        
-		bool get( LLViewerObject* object, S32 face )
-        {
-            if ( object )
-                if ( object->getTE(face) )
-                    if ( object->getTE(face)->getMediaData() )
-                        return (0 != (object->getTE(face)->getMediaData()->getPermsInteract() & LLMediaEntry::PERM_OWNER));
-            return 0 != ( mMediaEntry.getPermsInteract() & LLMediaEntry::PERM_OWNER );
-        };
-		
-		const LLMediaEntry &mMediaEntry;
-		
-    } func_perms_owner_interact(default_media_data);
-    identical = selected_objects->getSelectedTEValue( &func_perms_owner_interact, value_bool );
-    base_key = std::string( LLPanelContents::PERMS_OWNER_INTERACT_KEY );
-    mMediaSettings[ base_key ] = value_bool;
-    mMediaSettings[ base_key + std::string( LLPanelContents::TENTATIVE_SUFFIX ) ] = ! identical;
-	
-    // Perms - owner control
-    value_bool = 0 != ( default_media_data.getPermsControl() & LLMediaEntry::PERM_OWNER );
-    struct functor_getter_perms_owner_control : public LLSelectedTEGetFunctor< bool >
-    {
-		functor_getter_perms_owner_control(const LLMediaEntry& entry)	: mMediaEntry(entry) {}
-        
-        bool get( LLViewerObject* object, S32 face )
-        {
-            if ( object )
-                if ( object->getTE(face) )
-                    if ( object->getTE(face)->getMediaData() )
-                        return (0 != (object->getTE(face)->getMediaData()->getPermsControl() & LLMediaEntry::PERM_OWNER));
-            return 0 != ( mMediaEntry.getPermsControl() & LLMediaEntry::PERM_OWNER );
-        };
-		
-		const LLMediaEntry &mMediaEntry;
-		
-    } func_perms_owner_control(default_media_data);
-    identical = selected_objects ->getSelectedTEValue( &func_perms_owner_control, value_bool );
-    base_key = std::string( LLPanelContents::PERMS_OWNER_CONTROL_KEY );
-    mMediaSettings[ base_key ] = value_bool;
-    mMediaSettings[ base_key + std::string( LLPanelContents::TENTATIVE_SUFFIX ) ] = ! identical;
-	
-    // Perms - group interact
-    value_bool = 0 != ( default_media_data.getPermsInteract() & LLMediaEntry::PERM_GROUP );
-    struct functor_getter_perms_group_interact : public LLSelectedTEGetFunctor< bool >
-    {
-		functor_getter_perms_group_interact(const LLMediaEntry& entry): mMediaEntry(entry) {}
-        
-        bool get( LLViewerObject* object, S32 face )
-        {
-            if ( object )
-                if ( object->getTE(face) )
-                    if ( object->getTE(face)->getMediaData() )
-                        return (0 != (object->getTE(face)->getMediaData()->getPermsInteract() & LLMediaEntry::PERM_GROUP));
-            return 0 != ( mMediaEntry.getPermsInteract() & LLMediaEntry::PERM_GROUP );
-        };
-		
-		const LLMediaEntry &mMediaEntry;
-		
-    } func_perms_group_interact(default_media_data);
-    identical = selected_objects->getSelectedTEValue( &func_perms_group_interact, value_bool );
-    base_key = std::string( LLPanelContents::PERMS_GROUP_INTERACT_KEY );
-    mMediaSettings[ base_key ] = value_bool;
-    mMediaSettings[ base_key + std::string( LLPanelContents::TENTATIVE_SUFFIX ) ] = ! identical;
-	
-    // Perms - group control
-    value_bool = 0 != ( default_media_data.getPermsControl() & LLMediaEntry::PERM_GROUP );
-    struct functor_getter_perms_group_control : public LLSelectedTEGetFunctor< bool >
-    {
-		functor_getter_perms_group_control(const LLMediaEntry& entry): mMediaEntry(entry) {}
-        
-        bool get( LLViewerObject* object, S32 face )
-        {
-            if ( object )
-                if ( object->getTE(face) )
-                    if ( object->getTE(face)->getMediaData() )
-                        return (0 != (object->getTE(face)->getMediaData()->getPermsControl() & LLMediaEntry::PERM_GROUP));
-            return 0 != ( mMediaEntry.getPermsControl() & LLMediaEntry::PERM_GROUP );
-        };
-		
-		const LLMediaEntry &mMediaEntry;
-		
-    } func_perms_group_control(default_media_data);
-    identical = selected_objects->getSelectedTEValue( &func_perms_group_control, value_bool );
-    base_key = std::string( LLPanelContents::PERMS_GROUP_CONTROL_KEY );
-    mMediaSettings[ base_key ] = value_bool;
-    mMediaSettings[ base_key + std::string( LLPanelContents::TENTATIVE_SUFFIX ) ] = ! identical;
-	
-    // Perms - anyone interact
-    value_bool = 0 != ( default_media_data.getPermsInteract() & LLMediaEntry::PERM_ANYONE );
-    struct functor_getter_perms_anyone_interact : public LLSelectedTEGetFunctor< bool >
-    {
-		functor_getter_perms_anyone_interact(const LLMediaEntry& entry): mMediaEntry(entry) {}
-        
-        bool get( LLViewerObject* object, S32 face )
-        {
-            if ( object )
-                if ( object->getTE(face) )
-                    if ( object->getTE(face)->getMediaData() )
-                        return (0 != (object->getTE(face)->getMediaData()->getPermsInteract() & LLMediaEntry::PERM_ANYONE));
-            return 0 != ( mMediaEntry.getPermsInteract() & LLMediaEntry::PERM_ANYONE );
-        };
-		
-		const LLMediaEntry &mMediaEntry;
-		
-    } func_perms_anyone_interact(default_media_data);
-    identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &func_perms_anyone_interact, value_bool );
-    base_key = std::string( LLPanelContents::PERMS_ANYONE_INTERACT_KEY );
-    mMediaSettings[ base_key ] = value_bool;
-    mMediaSettings[ base_key + std::string( LLPanelContents::TENTATIVE_SUFFIX ) ] = ! identical;
-	
-    // Perms - anyone control
-    value_bool = 0 != ( default_media_data.getPermsControl() & LLMediaEntry::PERM_ANYONE );
-    struct functor_getter_perms_anyone_control : public LLSelectedTEGetFunctor< bool >
-    {
-		functor_getter_perms_anyone_control(const LLMediaEntry& entry)	: mMediaEntry(entry) {}
-        
-        bool get( LLViewerObject* object, S32 face )
-        {
-            if ( object )
-                if ( object->getTE(face) )
-                    if ( object->getTE(face)->getMediaData() )
-                        return (0 != (object->getTE(face)->getMediaData()->getPermsControl() & LLMediaEntry::PERM_ANYONE));
-            return 0 != ( mMediaEntry.getPermsControl() & LLMediaEntry::PERM_ANYONE );
-        };
-		
-		const LLMediaEntry &mMediaEntry;
-		
-    } func_perms_anyone_control(default_media_data);
-    identical = selected_objects->getSelectedTEValue( &func_perms_anyone_control, value_bool );
-    base_key = std::string( LLPanelContents::PERMS_ANYONE_CONTROL_KEY );
-    mMediaSettings[ base_key ] = value_bool;
-    mMediaSettings[ base_key + std::string( LLPanelContents::TENTATIVE_SUFFIX ) ] = ! identical;
-	
-    // security - whitelist enable
-    value_bool = default_media_data.getWhiteListEnable();
-    struct functor_getter_whitelist_enable : public LLSelectedTEGetFunctor< bool >
-    {
-		functor_getter_whitelist_enable(const LLMediaEntry& entry)	: mMediaEntry(entry) {}
-        
-        bool get( LLViewerObject* object, S32 face )
-        {
-            if ( object )
-                if ( object->getTE(face) )
-                    if ( object->getTE(face)->getMediaData() )
-                        return object->getTE(face)->getMediaData()->getWhiteListEnable();
-            return mMediaEntry.getWhiteListEnable();
-        };
-		
-		const LLMediaEntry &mMediaEntry;
-		
-    } func_whitelist_enable(default_media_data);
-    identical = selected_objects->getSelectedTEValue( &func_whitelist_enable, value_bool );
-    base_key = std::string( LLMediaEntry::WHITELIST_ENABLE_KEY );
-    mMediaSettings[ base_key ] = value_bool;
-    mMediaSettings[ base_key + std::string( LLPanelContents::TENTATIVE_SUFFIX ) ] = ! identical;
-	
-    // security - whitelist URLs
-    std::vector<std::string> value_vector_str = default_media_data.getWhiteList();
-    struct functor_getter_whitelist_urls : public LLSelectedTEGetFunctor< std::vector<std::string> >
-    {
-		functor_getter_whitelist_urls(const LLMediaEntry& entry): mMediaEntry(entry) {}
-        
-        std::vector<std::string> get( LLViewerObject* object, S32 face )
-        {
-            if ( object )
-                if ( object->getTE(face) )
-                    if ( object->getTE(face)->getMediaData() )
-                        return object->getTE(face)->getMediaData()->getWhiteList();
-            return mMediaEntry.getWhiteList();
-        };
-		
-		const LLMediaEntry &mMediaEntry;
-		
-    } func_whitelist_urls(default_media_data);
-    identical = selected_objects->getSelectedTEValue( &func_whitelist_urls, value_vector_str );
-    base_key = std::string( LLMediaEntry::WHITELIST_KEY );
-	mMediaSettings[ base_key ].clear();
-    std::vector< std::string >::iterator iter = value_vector_str.begin();
-    while( iter != value_vector_str.end() )
-    {
-        std::string white_list_url = *iter;
-        mMediaSettings[ base_key ].append( white_list_url );
-        ++iter;
-    };
-	
-    mMediaSettings[ base_key + std::string( LLPanelContents::TENTATIVE_SUFFIX ) ] = ! identical;
-}
-
diff --git a/indra/newview/llfloatertools.h b/indra/newview/llfloatertools.h
index ffff564ad41b03fd5d5cc2101c6402edbc6be17b..3bb6492a6e2cbbaaef2ccb8e1504d51704cbadfa 100644
--- a/indra/newview/llfloatertools.h
+++ b/indra/newview/llfloatertools.h
@@ -44,7 +44,6 @@ class LLRadioGroup;
 class LLSlider;
 class LLTabContainer;
 class LLTextBox;
-class LLMediaCtrl;
 class LLTool;
 class LLParcelSelection;
 class LLObjectSelection;
@@ -98,11 +97,6 @@ class LLFloaterTools
 	static void setEditTool(void* data);
 	void setTool(const LLSD& user_data);
 	void saveLastTool();
-	void onClickBtnDeleteMedia();
-	void onClickBtnAddMedia();
-	void onClickBtnEditMedia();
-	void clearMediaSettings();
-	bool selectedMediaEditable();
 	void updateLandImpacts();
 
 	static void setGridMode(S32 mode);
@@ -111,13 +105,6 @@ class LLFloaterTools
 
 private:
 	void refresh();
-	void refreshMedia();
-	void getMediaState();
-	void updateMediaSettings();
-	void navigateToTitleMedia( const std::string url ); // navigate if changed
-	void updateMediaTitle();
-	static bool deleteMediaConfirm(const LLSD& notification, const LLSD& response);
-	static bool multipleFacesSelectedConfirm(const LLSD& notification, const LLSD& response);
 	static void setObjectType( LLPCode pcode );
 	void onClickGridOptions();
 
@@ -193,19 +180,12 @@ class LLFloaterTools
 	LLParcelSelectionHandle	mParcelSelection;
 	LLObjectSelectionHandle	mObjectSelection;
 
-	LLMediaCtrl				*mTitleMedia;
-	bool					mNeedMediaTitle;
-
 private:
 	BOOL					mDirty;
 	BOOL                    mHasSelection;
 
 	std::map<std::string, std::string> mStatusText;
 
-
-protected:
-	LLSD				mMediaSettings;
-
 public:
 	static bool		sShowObjectCost;
 	static bool		sPreviousFocusOnAvatar;
diff --git a/indra/newview/llfloaterurlentry.cpp b/indra/newview/llfloaterurlentry.cpp
index d5c2ad5f81f7f74dbe2f7caf03d5a57ce4424ed0..917d6dfcd0aebba72fc9cb88748a8b48eb2ac1fd 100644
--- a/indra/newview/llfloaterurlentry.cpp
+++ b/indra/newview/llfloaterurlentry.cpp
@@ -112,16 +112,6 @@ void LLFloaterURLEntry::headerFetchComplete(S32 status, const std::string& mime_
 		panel_media->setMediaType(mime_type);
 		panel_media->setMediaURL(mMediaURLEdit->getValue().asString());
 	}
-	else
-	{
-		LLPanelFace* panel_face = dynamic_cast<LLPanelFace*>(mPanelLandMediaHandle.get());
-		if(panel_face)
-		{
-			panel_face->setMediaType(mime_type);
-			panel_face->setMediaURL(mMediaURLEdit->getValue().asString());
-		}
-
-	}
 
 	getChildView("loading_label")->setVisible( false);
 	closeFloater();
diff --git a/indra/newview/llfloatervoicevolume.cpp b/indra/newview/llfloatervoicevolume.cpp
index 59e1f49f81d7895c4ab39813a350a5ffa1b81308..23f19dd5aad581161ff579e43aefa5d32a081b61 100644
--- a/indra/newview/llfloatervoicevolume.cpp
+++ b/indra/newview/llfloatervoicevolume.cpp
@@ -127,7 +127,7 @@ void LLFloaterVoiceVolume::onOpen(const LLSD& data)
 	// Extract appropriate avatar id
 	mAvatarID = data["avatar_id"];
 
-	LLUI::getInstance()->positionViewNearMouse(this);
+	LLInspect::repositionInspector(data);
 
 	getChild<LLUICtrl>("avatar_name")->setValue("");
 	updateVolumeControls();
diff --git a/indra/newview/llfloaterwebcontent.cpp b/indra/newview/llfloaterwebcontent.cpp
index 23fd6d9c8eb9d6fbfaddb87878270511828f1221..ceab472c5513b4493dd604f8238d1d671e021fc3 100644
--- a/indra/newview/llfloaterwebcontent.cpp
+++ b/indra/newview/llfloaterwebcontent.cpp
@@ -159,7 +159,7 @@ LLFloater* LLFloaterWebContent::create( Params p)
 //static
 void LLFloaterWebContent::closeRequest(const std::string &uuid)
 {
-	LLFloaterWebContent* floaterp = instance_tracker_t::getInstance(uuid);
+	auto floaterp = instance_tracker_t::getInstance(uuid);
 	if (floaterp)
 	{
 		floaterp->closeFloater(false);
@@ -169,7 +169,7 @@ void LLFloaterWebContent::closeRequest(const std::string &uuid)
 //static
 void LLFloaterWebContent::geometryChanged(const std::string &uuid, S32 x, S32 y, S32 width, S32 height)
 {
-	LLFloaterWebContent* floaterp = instance_tracker_t::getInstance(uuid);
+	auto floaterp = instance_tracker_t::getInstance(uuid);
 	if (floaterp)
 	{
 		floaterp->geometryChanged(x, y, width, height);
diff --git a/indra/newview/llfloaterwebprofile.cpp b/indra/newview/llfloaterwebprofile.cpp
deleted file mode 100644
index 891bb90c0eac6494d657b3d7fcc25ca12d48b3bd..0000000000000000000000000000000000000000
--- a/indra/newview/llfloaterwebprofile.cpp
+++ /dev/null
@@ -1,81 +0,0 @@
-/** 
- * @file llfloaterwebprofile.cpp
- * @brief Avatar profile floater.
- *
- * $LicenseInfo:firstyear=2009&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- * 
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- * 
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
- * $/LicenseInfo$
- */
-
-#include "llviewerprecompiledheaders.h"
-
-#include "llfloaterwebprofile.h"
-
-#include "llviewercontrol.h"
-
-LLFloaterWebProfile::LLFloaterWebProfile(const Params& key) :
-	LLFloaterWebContent(key)
-{
-}
-
-void LLFloaterWebProfile::onOpen(const LLSD& key)
-{
-	Params p(key);
-	p.show_chrome(true);
-	p.window_class("profile");
-	p.allow_address_entry(false);
-	p.trusted_content(true);
-	LLFloaterWebContent::onOpen(p);
-	applyPreferredRect();
-}
-
-// virtual
-void LLFloaterWebProfile::handleReshape(const LLRect& new_rect, bool by_user)
-{
-	LL_DEBUGS() << "handleReshape: " << new_rect << LL_ENDL;
-
-	if (by_user && !isMinimized())
-	{
-		LL_DEBUGS() << "Storing new rect" << LL_ENDL;
-		gSavedSettings.setRect("WebProfileFloaterRect", new_rect);
-	}
-
-	LLFloaterWebContent::handleReshape(new_rect, by_user);
-}
-
-LLFloater* LLFloaterWebProfile::create(const LLSD& key)
-{
-	LLFloaterWebContent::Params p(key);
-	preCreate(p);
-	return new LLFloaterWebProfile(p);
-}
-
-void LLFloaterWebProfile::applyPreferredRect()
-{
-	const LLRect preferred_rect = gSavedSettings.getRect("WebProfileFloaterRect");
-	LL_DEBUGS() << "Applying preferred rect: " << preferred_rect << LL_ENDL;
-
-	// Don't override position that may have been set by floater stacking code.
-	LLRect new_rect = getRect();
-	new_rect.setLeftTopAndSize(
-		new_rect.mLeft, new_rect.mTop,
-		preferred_rect.getWidth(), preferred_rect.getHeight());
-	setShape(new_rect);
-}
diff --git a/indra/newview/llfloaterwebprofile.h b/indra/newview/llfloaterwebprofile.h
deleted file mode 100644
index 4c355e401b6d425f8b97fb4929a3e98fab837187..0000000000000000000000000000000000000000
--- a/indra/newview/llfloaterwebprofile.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/** 
- * @file llfloaterwebprofile.h
- * @brief Avatar profile floater.
- *
- * $LicenseInfo:firstyear=2009&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- * 
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- * 
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
- * $/LicenseInfo$
- */
-
-#ifndef LL_LLFLOATERWEBPROFILE_H
-#define LL_LLFLOATERWEBPROFILE_H
-
-#include "llfloaterwebcontent.h"
-#include "llviewermediaobserver.h"
-
-#include <string>
-
-class LLMediaCtrl;
-
-/**
- * Displays avatar profile web page.
- */
-class LLFloaterWebProfile
-:	public LLFloaterWebContent
-{
-	LOG_CLASS(LLFloaterWebProfile);
-public:
-	typedef LLFloaterWebContent::Params Params;
-
-	LLFloaterWebProfile(const Params& key);
-
-	/*virtual*/ void onOpen(const LLSD& key);
-	/*virtual*/ void handleReshape(const LLRect& new_rect, bool by_user = false);
-
-	static LLFloater* create(const LLSD& key);
-
-private:
-	void applyPreferredRect();
-};
-
-#endif  // LL_LLFLOATERWEBPROFILE_H
-
diff --git a/indra/newview/llfloaterworldmap.cpp b/indra/newview/llfloaterworldmap.cpp
old mode 100644
new mode 100755
index 27197f0b065075055cef8c772c0a6f82247027a1..01bfae89346c5e33c055d6b4bd234e0c3dd37114
--- a/indra/newview/llfloaterworldmap.cpp
+++ b/indra/newview/llfloaterworldmap.cpp
@@ -45,6 +45,7 @@
 //#include "llfirstuse.h"
 #include "llfloaterreg.h"		// getTypedInstance()
 #include "llfocusmgr.h"
+#include "lliconctrl.h"
 #include "llinventoryfunctions.h"
 #include "llinventorymodel.h"
 #include "llinventorymodelbackgroundfetch.h"
@@ -56,10 +57,12 @@
 #include "llscrolllistctrl.h"
 #include "llslurl.h"
 #include "lltextbox.h"
+#include "lltoolbarview.h"
 #include "lltracker.h"
 #include "lltrans.h"
 #include "llviewerinventory.h"	// LLViewerInventoryItem
 #include "llviewermenu.h"
+#include "llviewerparcelmgr.h"
 #include "llviewerregion.h"
 #include "llviewerstats.h"
 #include "llviewertexture.h"
@@ -79,7 +82,6 @@
 //---------------------------------------------------------------------------
 // Constants
 //---------------------------------------------------------------------------
-static const F32 MAP_ZOOM_TIME = 0.2f;
 
 // Merov: we switched from using the "world size" (which varies depending where the user went) to a fixed
 // width of 512 regions max visible at a time. This makes the zoom slider works in a consistent way across
@@ -87,6 +89,9 @@ static const F32 MAP_ZOOM_TIME = 0.2f;
 // Currently (01/26/09), this value allows the whole grid to be visible in a 1024x1024 window.
 static const S32 MAX_VISIBLE_REGIONS = 512;
 
+
+const S32 HIDE_BEACON_PAD = 133;
+
 // It would be more logical to have this inside the method where it is used but to compile under gcc this
 // struct has to be here.
 struct SortRegionNames
@@ -279,7 +284,7 @@ void* LLFloaterWorldMap::createWorldMapView(void* data)
 
 BOOL LLFloaterWorldMap::postBuild()
 {
-	mPanel = getChild<LLPanel>("objects_mapview");
+    mMapView = dynamic_cast<LLWorldMapView*>(getChild<LLPanel>("objects_mapview"));
 	
 	LLComboBox *avatar_combo = getChild<LLComboBox>("friend combo");
 	avatar_combo->selectFirstItem();
@@ -300,13 +305,13 @@ BOOL LLFloaterWorldMap::postBuild()
 	landmark_combo->setTextChangedCallback( boost::bind(&LLFloaterWorldMap::onComboTextEntry, this) );
 	mListLandmarkCombo = dynamic_cast<LLCtrlListInterface *>(landmark_combo);
 	
-	mCurZoomVal = log(LLWorldMapView::sMapScale/256.f)/log(2.f);
-	getChild<LLUICtrl>("zoom slider")->setValue(mCurZoomVal);
+    F32 slider_zoom = mMapView->getZoom();
+    getChild<LLUICtrl>("zoom slider")->setValue(slider_zoom);
+    
+    getChild<LLPanel>("expand_btn_panel")->setMouseDownCallback(boost::bind(&LLFloaterWorldMap::onExpandCollapseBtn, this));
 	
 	setDefaultBtn(NULL);
 	
-	mZoomTimer.stop();
-	
 	onChangeMaturity();
 	
 	return TRUE;
@@ -316,7 +321,7 @@ BOOL LLFloaterWorldMap::postBuild()
 LLFloaterWorldMap::~LLFloaterWorldMap()
 {
 	// All cleaned up by LLView destructor
-	mPanel = NULL;
+    mMapView = NULL;
 	
 	// Inventory deletes all observers on shutdown
 	mInventory = NULL;
@@ -326,6 +331,8 @@ LLFloaterWorldMap::~LLFloaterWorldMap()
 	mFriendObserver = NULL;
 	
 	gFloaterWorldMap = NULL;
+
+    mTeleportFinishConnection.disconnect();
 }
 
 //static
@@ -339,26 +346,28 @@ void LLFloaterWorldMap::onClose(bool app_quitting)
 {
 	// While we're not visible, discard the overlay images we're using
 	LLWorldMap::getInstance()->clearImageRefs();
+    mTeleportFinishConnection.disconnect();
 }
 
 // virtual
 void LLFloaterWorldMap::onOpen(const LLSD& key)
 {
-	bool center_on_target = (key.asString() == "center");
+    mTeleportFinishConnection = LLViewerParcelMgr::getInstance()->
+        setTeleportFinishedCallback(boost::bind(&LLFloaterWorldMap::onTeleportFinished, this));
+ 
+    bool center_on_target = (key.asString() == "center");
 	
 	mIsClosing = FALSE;
 	
-	LLWorldMapView* map_panel;
-	map_panel = (LLWorldMapView*)gFloaterWorldMap->mPanel;
-	map_panel->clearLastClick();
+    mMapView->clearLastClick();
 	
 	{
 		// reset pan on show, so it centers on you again
 		if (!center_on_target)
 		{
-			LLWorldMapView::setPan(0, 0, TRUE);
+            mMapView->setPan(0, 0, true);
 		}
-		map_panel->updateVisibleBlocks();
+        mMapView->updateVisibleBlocks();
 		
 		// Reload items as they may have changed
 		LLWorldMap::getInstance()->reloadItems();
@@ -406,18 +415,21 @@ BOOL LLFloaterWorldMap::handleHover(S32 x, S32 y, MASK mask)
 
 BOOL LLFloaterWorldMap::handleScrollWheel(S32 x, S32 y, S32 clicks)
 {
-	if (!isMinimized() && isFrontmost())
-	{
-		if(mPanel->pointInView(x, y))
-		{
-			F32 slider_value = (F32)getChild<LLUICtrl>("zoom slider")->getValue().asReal();
-			slider_value += ((F32)clicks * -0.3333f);
-			getChild<LLUICtrl>("zoom slider")->setValue(LLSD(slider_value));
-			return TRUE;
-		}
-	}
-	
-	return LLFloater::handleScrollWheel(x, y, clicks);
+    if (!isMinimized() && isFrontmost())
+    {
+        S32 map_x = x - mMapView->getRect().mLeft;
+        S32 map_y = y - mMapView->getRect().mBottom;
+        if (mMapView->pointInView(map_x, map_y))
+        {
+            F32 old_slider_zoom = (F32) getChild<LLUICtrl>("zoom slider")->getValue().asReal();
+            F32 slider_zoom     = old_slider_zoom + ((F32) clicks * -0.3333f);
+            getChild<LLUICtrl>("zoom slider")->setValue(LLSD(slider_zoom));
+            mMapView->zoomWithPivot(slider_zoom, map_x, map_y);
+            return true;
+        }
+    }
+
+    return LLFloater::handleScrollWheel(x, y, clicks);
 }
 
 
@@ -496,26 +508,13 @@ void LLFloaterWorldMap::draw()
 	
 	setMouseOpaque(TRUE);
 	getDragHandle()->setMouseOpaque(TRUE);
-	
-	//RN: snaps to zoom value because interpolation caused jitter in the text rendering
-	if (!mZoomTimer.getStarted() && mCurZoomVal != (F32)getChild<LLUICtrl>("zoom slider")->getValue().asReal())
-	{
-		mZoomTimer.start();
-	}
-	F32 interp = mZoomTimer.getElapsedTimeF32() / MAP_ZOOM_TIME;
-	if (interp > 1.f)
-	{
-		interp = 1.f;
-		mZoomTimer.stop();
-	}
-	mCurZoomVal = lerp(mCurZoomVal, (F32)getChild<LLUICtrl>("zoom slider")->getValue().asReal(), interp);
-	F32 map_scale = 256.f*pow(2.f, mCurZoomVal);
-	LLWorldMapView::setScale( map_scale );
+
+    mMapView->zoom((F32)getChild<LLUICtrl>("zoom slider")->getValue().asReal());
 	
 	// Enable/disable checkboxes depending on the zoom level
 	// If above threshold level (i.e. low res) -> Disable all checkboxes
 	// If under threshold level (i.e. high res) -> Enable all checkboxes
-	bool enable = LLWorldMapView::showRegionInfo();
+    bool enable = mMapView->showRegionInfo();
 	getChildView("people_chk")->setEnabled(enable);
 	getChildView("infohub_chk")->setEnabled(enable);
 	getChildView("telehub_chk")->setEnabled(enable);
@@ -994,7 +993,7 @@ void LLFloaterWorldMap::clearAvatarSelection(BOOL clear_ui)
 	{
 		mTrackedStatus = LLTracker::TRACKING_NOTHING;
 		LLCtrlListInterface *list = mListFriendCombo;
-		if (list)
+		if (list && list->getSelectedValue().asString() != "None")
 		{
 			list->selectByValue( "None" );
 		}
@@ -1014,9 +1013,7 @@ void LLFloaterWorldMap::adjustZoomSliderBounds()
 	S32 world_height_regions = MAX_VISIBLE_REGIONS;
 	
 	// Find how much space we have to display the world
-	LLWorldMapView* map_panel;
-	map_panel = (LLWorldMapView*)mPanel;
-	LLRect view_rect = map_panel->getRect();
+    LLRect view_rect = mMapView->getRect();
 	
 	// View size in pixels
 	S32 view_width = view_rect.getWidth();
@@ -1284,9 +1281,9 @@ void LLFloaterWorldMap::onShowTargetBtn()
 
 void LLFloaterWorldMap::onShowAgentBtn()
 {
-	LLWorldMapView::setPan( 0, 0, FALSE); // FALSE == animate
-	// Set flag so user's location will be displayed if not tracking anything else
-	mSetToUserPosition = TRUE;	
+    mMapView->setPanWithInterpTime(0, 0, false, 0.1f);  // false == animate
+    // Set flag so user's location will be displayed if not tracking anything else
+    mSetToUserPosition = true;
 }
 
 void LLFloaterWorldMap::onClickTeleportBtn()
@@ -1304,6 +1301,22 @@ void LLFloaterWorldMap::onCopySLURL()
 	LLNotificationsUtil::add("CopySLURL", args);
 }
 
+void LLFloaterWorldMap::onExpandCollapseBtn()
+{
+    LLLayoutStack* floater_stack = getChild<LLLayoutStack>("floater_map_stack");
+    LLLayoutPanel* controls_panel = getChild<LLLayoutPanel>("controls_lp");
+    
+    bool toggle_collapse = !controls_panel->isCollapsed();
+    floater_stack->collapsePanel(controls_panel, toggle_collapse);
+    floater_stack->updateLayout();
+   
+    std::string image_name = getString(toggle_collapse ? "expand_icon" : "collapse_icon");
+    std::string tooltip = getString(toggle_collapse ? "expand_tooltip" : "collapse_tooltip");
+    getChild<LLIconCtrl>("expand_collapse_icon")->setImage(LLUI::getUIImage(image_name));
+    getChild<LLIconCtrl>("expand_collapse_icon")->setToolTip(tooltip);
+    getChild<LLPanel>("expand_btn_panel")->setToolTip(tooltip);
+}
+
 // protected
 void LLFloaterWorldMap::centerOnTarget(BOOL animate)
 {
@@ -1338,9 +1351,10 @@ void LLFloaterWorldMap::centerOnTarget(BOOL animate)
 		pos_global.clearVec();
 	}
 	
-	LLWorldMapView::setPan( -llfloor((F32)(pos_global.mdV[VX] * (F64)LLWorldMapView::sMapScale / REGION_WIDTH_METERS)), 
-						   -llfloor((F32)(pos_global.mdV[VY] * (F64)LLWorldMapView::sMapScale / REGION_WIDTH_METERS)),
-						   !animate);
+    F64 map_scale = (F64)mMapView->getScale();
+    mMapView->setPanWithInterpTime(-llfloor((F32)(pos_global.mdV[VX] * map_scale / REGION_WIDTH_METERS)),
+                           -llfloor((F32)(pos_global.mdV[VY] * map_scale / REGION_WIDTH_METERS)),
+                           !animate, 0.1f);
 	mWaitingForTracker = FALSE;
 }
 
@@ -1566,6 +1580,13 @@ void LLFloaterWorldMap::updateSims(bool found_null_sim)
 	}
 }
 
+void LLFloaterWorldMap::onTeleportFinished()
+{
+    if(isInVisibleChain())
+    {
+        mMapView->setPan(0, 0, TRUE);
+    }
+}
 
 void LLFloaterWorldMap::onCommitSearchResult()
 {
@@ -1638,7 +1659,106 @@ void LLFloaterWorldMap::onChangeMaturity()
 
 void LLFloaterWorldMap::onFocusLost()
 {
-	gViewerWindow->showCursor();
-	LLWorldMapView* map_panel = (LLWorldMapView*)gFloaterWorldMap->mPanel;
-	map_panel->mPanning = FALSE;
+    gViewerWindow->showCursor();
+    mMapView->mPanning = false;
+}
+
+LLPanelHideBeacon::LLPanelHideBeacon() :
+	mHideButton(NULL)
+{
+}
+
+// static
+LLPanelHideBeacon* LLPanelHideBeacon::getInstance()
+{
+	static LLPanelHideBeacon* panel = getPanelHideBeacon();
+	return panel;
+}
+
+
+BOOL LLPanelHideBeacon::postBuild()
+{
+	mHideButton = getChild<LLButton>("hide_beacon_btn");
+	mHideButton->setCommitCallback(boost::bind(&LLPanelHideBeacon::onHideButtonClick, this));
+
+	gViewerWindow->setOnWorldViewRectUpdated(boost::bind(&LLPanelHideBeacon::updatePosition, this));
+
+	return TRUE;
+}
+
+//virtual
+void LLPanelHideBeacon::draw()
+{
+	if (!LLTracker::isTracking(NULL))
+	{
+        mHideButton->setVisible(false);
+        return;
+	}
+    mHideButton->setVisible(true);
+	updatePosition(); 
+	LLPanel::draw();
+}
+
+//virtual
+void LLPanelHideBeacon::setVisible(BOOL visible)
+{
+	if (gAgentCamera.getCameraMode() == CAMERA_MODE_MOUSELOOK) visible = false;
+
+	if (visible)
+	{
+		updatePosition();
+	}
+
+	LLPanel::setVisible(visible);
+}
+
+
+//static
+LLPanelHideBeacon* LLPanelHideBeacon::getPanelHideBeacon()
+{
+	LLPanelHideBeacon* panel = new LLPanelHideBeacon();
+	panel->buildFromFile("panel_hide_beacon.xml");
+
+	LL_INFOS() << "Build LLPanelHideBeacon panel" << LL_ENDL;
+
+	panel->updatePosition();
+	return panel;
+}
+
+void LLPanelHideBeacon::onHideButtonClick()
+{
+	LLFloaterWorldMap* instance = LLFloaterWorldMap::getInstance();
+	if (instance)
+	{
+		instance->onClearBtn();
+	}
+}
+
+/**
+* Updates position of the panel (similar to Stand & Stop Flying panel).
+*/
+void LLPanelHideBeacon::updatePosition()
+{
+	S32 bottom_tb_center = 0;
+	if (LLToolBar* toolbar_bottom = gToolBarView->getToolbar(LLToolBarEnums::TOOLBAR_BOTTOM))
+	{
+		bottom_tb_center = toolbar_bottom->getRect().getCenterX();
+	}
+
+	S32 left_tb_width = 0;
+	if (LLToolBar* toolbar_left = gToolBarView->getToolbar(LLToolBarEnums::TOOLBAR_LEFT))
+	{
+		left_tb_width = toolbar_left->getRect().getWidth();
+	}
+
+	if (gToolBarView != NULL && gToolBarView->getToolbar(LLToolBarEnums::TOOLBAR_LEFT)->hasButtons())
+	{
+		S32 x_pos = bottom_tb_center - getRect().getWidth() / 2 - left_tb_width;
+		setOrigin( x_pos + HIDE_BEACON_PAD, 0);
+	}
+	else 
+	{
+		S32 x_pos = bottom_tb_center - getRect().getWidth() / 2;
+		setOrigin( x_pos + HIDE_BEACON_PAD, 0);
+	}
 }
diff --git a/indra/newview/llfloaterworldmap.h b/indra/newview/llfloaterworldmap.h
index 97e99297cfe60e11ee9f5b51d0c61c7075e18369..3702226d23a2124ad904ca01c24ef4885f69bc9e 100644
--- a/indra/newview/llfloaterworldmap.h
+++ b/indra/newview/llfloaterworldmap.h
@@ -44,6 +44,7 @@ class LLInventoryObserver;
 class LLItemInfo;
 class LLLineEditor;
 class LLTabContainer;
+class LLWorldMapView;
 
 class LLFloaterWorldMap : public LLFloater
 {
@@ -107,7 +108,8 @@ class LLFloaterWorldMap : public LLFloater
 	// teleport to the tracked item, if there is one
 	void			teleport();
 	void			onChangeMaturity();
-	
+
+	void			onClearBtn();
 	
 	//Slapp instigated avatar tracking
 	void			avatarTrackFromSlapp( const LLUUID& id ); 
@@ -124,12 +126,13 @@ class LLFloaterWorldMap : public LLFloater
 	void			onComboTextEntry( );
 	void			onSearchTextEntry( );
 
-	void			onClearBtn();
 	void			onClickTeleportBtn();
 	void			onShowTargetBtn();
 	void			onShowAgentBtn();
 	void			onCopySLURL();
 
+    void            onExpandCollapseBtn();
+
 	void			centerOnTarget(BOOL animate);
 	void			updateLocation();
 
@@ -151,14 +154,10 @@ class LLFloaterWorldMap : public LLFloater
 	void			onCoordinatesCommit();
 	void		    onCommitSearchResult();
 
-	void			cacheLandmarkPosition();
+    void            onTeleportFinished();
 
 private:
-	LLPanel*			mPanel;		// Panel displaying the map
-
-	// Ties to LLWorldMapView::sMapScale, in pixels per region
-	F32						mCurZoomVal;
-	LLFrameTimer			mZoomTimer;
+    LLWorldMapView* mMapView; // Panel displaying the map
 
 	// update display of teleport destination coordinates - pos is in global coordinates
 	void updateTeleportCoordsDisplay( const LLVector3d& pos );
@@ -195,9 +194,31 @@ class LLFloaterWorldMap : public LLFloater
 	LLCtrlListInterface *	mListFriendCombo;
 	LLCtrlListInterface *	mListLandmarkCombo;
 	LLCtrlListInterface *	mListSearchResults;
+
+    boost::signals2::connection mTeleportFinishConnection;
 };
 
 extern LLFloaterWorldMap* gFloaterWorldMap;
 
+
+class LLPanelHideBeacon : public LLPanel
+{
+public:
+	static LLPanelHideBeacon* getInstance();
+
+	LLPanelHideBeacon();
+	/*virtual*/ BOOL postBuild();
+	/*virtual*/ void setVisible(BOOL visible);
+	/*virtual*/ void draw();
+
+private:
+	static LLPanelHideBeacon* getPanelHideBeacon();
+	void onHideButtonClick();
+	void updatePosition();
+
+	LLButton* mHideButton;
+
+};
+
 #endif
 
diff --git a/indra/newview/llfriendcard.cpp b/indra/newview/llfriendcard.cpp
index 0be748ace9df10e4938a526acfdec8ffaaa96a24..e395da7f1e66d29e6f9e709cf2243e423a1389c9 100644
--- a/indra/newview/llfriendcard.cpp
+++ b/indra/newview/llfriendcard.cpp
@@ -327,22 +327,63 @@ void LLFriendCardsManager::syncFriendCardsFolders()
 /************************************************************************/
 /*		Private Methods                                                 */
 /************************************************************************/
-const LLUUID& LLFriendCardsManager::findFriendFolderUUIDImpl() const
+const LLUUID& LLFriendCardsManager::findFirstCallingCardSubfolder(const LLUUID &parent_id) const
 {
-	const LLUUID callingCardsFolderID = gInventory.findCategoryUUIDForType(LLFolderType::FT_CALLINGCARD);
+    if (parent_id.isNull())
+    {
+        return LLUUID::null;
+    }
 
-	std::string friendFolderName = get_friend_folder_name();
+    LLInventoryModel::cat_array_t* cats;
+    LLInventoryModel::item_array_t* items;
+    gInventory.getDirectDescendentsOf(parent_id, cats, items);
 
-	return findChildFolderUUID(callingCardsFolderID, friendFolderName);
+    if (!cats || !items || cats->size() == 0)
+    {
+        // call failed
+        return LLUUID::null;
+    }
+
+    if (cats->size() > 1)
+    {
+        const LLViewerInventoryCategory* friendFolder = gInventory.getCategory(parent_id);
+        if (friendFolder)
+        {
+            LL_WARNS_ONCE() << friendFolder->getName() << " folder contains more than one folder" << LL_ENDL;
+        }
+    }
+
+    for (LLInventoryModel::cat_array_t::const_iterator iter = cats->begin();
+        iter != cats->end();
+        ++iter)
+    {
+        const LLInventoryCategory* category = (*iter);
+        if (category->getPreferredType() == LLFolderType::FT_CALLINGCARD)
+        {
+            return category->getUUID();
+        }
+    }
+
+    return LLUUID::null;
 }
 
-const LLUUID& LLFriendCardsManager::findFriendAllSubfolderUUIDImpl() const
+// Inventorry ->
+//   Calling Cards - >
+//     Friends - > (the only expected folder)
+//       All (the only expected folder)
+
+const LLUUID& LLFriendCardsManager::findFriendFolderUUIDImpl() const
 {
-	LLUUID friendFolderUUID = findFriendFolderUUIDImpl();
+    const LLUUID callingCardsFolderID = gInventory.findCategoryUUIDForType(LLFolderType::FT_CALLINGCARD);
+
+    return findFirstCallingCardSubfolder(callingCardsFolderID);
+}
 
-	std::string friendAllSubfolderName = get_friend_all_subfolder_name();
+const LLUUID& LLFriendCardsManager::findFriendAllSubfolderUUIDImpl() const
+{
+    LLUUID friendFolderUUID = findFriendFolderUUIDImpl();
 
-	return findChildFolderUUID(friendFolderUUID, friendAllSubfolderName);
+    return findFirstCallingCardSubfolder(friendFolderUUID);
 }
 
 const LLUUID& LLFriendCardsManager::findChildFolderUUID(const LLUUID& parentFolderUUID, const std::string& nonLocalizedName) const
diff --git a/indra/newview/llfriendcard.h b/indra/newview/llfriendcard.h
index 2fb912a93048b87340a4b6e4e8d32e0a230f14f6..f5679d7d85d97749e494f803895bd11b866be87e 100644
--- a/indra/newview/llfriendcard.h
+++ b/indra/newview/llfriendcard.h
@@ -116,6 +116,7 @@ class LLFriendCardsManager
 	}
 
 	const LLUUID& findChildFolderUUID(const LLUUID& parentFolderUUID, const std::string& nonLocalizedName) const;
+    const LLUUID& findFirstCallingCardSubfolder(const LLUUID &parent_id) const;
 	const LLUUID& findFriendFolderUUIDImpl() const;
 	const LLUUID& findFriendAllSubfolderUUIDImpl() const;
 	const LLUUID& findFriendCardInventoryUUIDImpl(const LLUUID& avatarID);
diff --git a/indra/newview/llgesturemgr.cpp b/indra/newview/llgesturemgr.cpp
index 9f2119281d367d418d2b68f47479da252c3c6d22..489d34edca403173a755b0e3479a911c678f6223 100644
--- a/indra/newview/llgesturemgr.cpp
+++ b/indra/newview/llgesturemgr.cpp
@@ -483,8 +483,13 @@ void LLGestureMgr::replaceGesture(const LLUUID& item_id, LLMultiGesture* new_ges
 
 	mActive[base_item_id] = new_gesture;
 
-	delete old_gesture;
-	old_gesture = NULL;
+    // replaceGesture(const LLUUID& item_id, const LLUUID& new_asset_id)
+    // replaces ids without repalcing gesture
+    if (old_gesture != new_gesture)
+    {
+        delete old_gesture;
+        old_gesture = NULL;
+    }
 
 	if (asset_id.notNull())
 	{
@@ -910,7 +915,7 @@ void LLGestureMgr::stepGesture(LLMultiGesture* gesture)
 			else if (gesture->mWaitTimer.getElapsedTimeF32() > MAX_WAIT_ANIM_SECS)
 			{
 				// we've waited too long for an animation
-				LL_INFOS() << "Waited too long for animations to stop, continuing gesture."
+				LL_INFOS("GestureMgr") << "Waited too long for animations to stop, continuing gesture."
 					<< LL_ENDL;
 				gesture->mWaitingAnimations = FALSE;
 				gesture->mCurrentStep++;
@@ -1097,6 +1102,34 @@ void LLGestureMgr::onLoadComplete(const LLUUID& asset_uuid,
 				self.setFetchID(item_id);
 				self.startFetch();
 			}
+
+            item_map_t::iterator it = self.mActive.find(item_id);
+            if (it == self.mActive.end())
+            {
+                // Gesture is supposed to be present, active, but NULL
+                LL_DEBUGS("GestureMgr") << "Gesture " << item_id << " not found in active list" << LL_ENDL;
+            }
+            else
+            {
+                LLMultiGesture* old_gesture = (*it).second;
+                if (old_gesture && old_gesture != gesture)
+                {
+                    LL_DEBUGS("GestureMgr") << "Received dupplicate " << item_id << " callback" << LL_ENDL;
+                    // In case somebody managest to activate, deactivate and
+                    // then activate gesture again, before asset finishes loading.
+                    // LLLoadInfo will have a different pointer, asset storage will
+                    // see it as a different request, resulting in two callbacks.
+
+                    // deactivateSimilarGestures() did not turn this one off
+                    // because of matching item_id
+                    self.stopGesture(old_gesture);
+
+                    self.mActive.erase(item_id);
+                    delete old_gesture;
+                    old_gesture = NULL;
+                }
+            }
+
 			self.mActive[item_id] = gesture;
 
 			// Everything has been successful.  Add to the active list.
@@ -1131,9 +1164,23 @@ void LLGestureMgr::onLoadComplete(const LLUUID& asset_uuid,
 		}
 		else
 		{
-			LL_WARNS() << "Unable to load gesture" << LL_ENDL;
-
-			self.mActive.erase(item_id);
+			LL_WARNS("GestureMgr") << "Unable to load gesture" << LL_ENDL;
+
+            item_map_t::iterator it = self.mActive.find(item_id);
+            if (it != self.mActive.end())
+            {
+                LLMultiGesture* old_gesture = (*it).second;
+                if (old_gesture)
+                {
+                    // Shouldn't happen, just in case
+                    LL_WARNS("GestureMgr") << "Gesture " << item_id << " existed when it shouldn't" << LL_ENDL;
+
+                    self.stopGesture(old_gesture);
+                    delete old_gesture;
+                    old_gesture = NULL;
+                }
+                self.mActive.erase(item_id);
+            }
 			
 			delete gesture;
 			gesture = NULL;
@@ -1151,9 +1198,23 @@ void LLGestureMgr::onLoadComplete(const LLUUID& asset_uuid,
 			LLDelayedGestureError::gestureFailedToLoad( item_id );
 		}
 
-		LL_WARNS() << "Problem loading gesture: " << status << LL_ENDL;
-		
-		LLGestureMgr::instance().mActive.erase(item_id);			
+		LL_WARNS("GestureMgr") << "Problem loading gesture: " << status << LL_ENDL;
+        
+        item_map_t::iterator it = self.mActive.find(item_id);
+        if (it != self.mActive.end())
+        {
+            LLMultiGesture* old_gesture = (*it).second;
+            if (old_gesture)
+            {
+                // Shouldn't happen, just in case
+                LL_WARNS("GestureMgr") << "Gesture " << item_id << " existed when it shouldn't" << LL_ENDL;
+
+                self.stopGesture(old_gesture);
+                delete old_gesture;
+                old_gesture = NULL;
+            }
+            self.mActive.erase(item_id);
+        }
 	}
 }
 
diff --git a/indra/newview/llgesturemgr.h b/indra/newview/llgesturemgr.h
index 91ab445273563b9bd92427e7c1d541209a14742c..7c8e8279c257ee49038a071f58d3a9dae4a4943a 100644
--- a/indra/newview/llgesturemgr.h
+++ b/indra/newview/llgesturemgr.h
@@ -185,7 +185,7 @@ class LLGestureMgr : public LLSingleton<LLGestureMgr>, public LLInventoryFetchIt
 	std::set<LLUUID> mLoadingAssets;
 
 	// LLEventHost interface
-	boost::shared_ptr<LLGestureListener> mListener;
+	std::shared_ptr<LLGestureListener> mListener;
 };
 
 #endif
diff --git a/indra/newview/llglsandbox.cpp b/indra/newview/llglsandbox.cpp
index 698c15bd2d5f64c1703ae60c94608943149bfdb3..175f1849cf9ec934518f1767b8f57a30c2a3dc10 100644
--- a/indra/newview/llglsandbox.cpp
+++ b/indra/newview/llglsandbox.cpp
@@ -791,10 +791,7 @@ void LLViewerObjectList::renderObjectBeacons()
 
 	LLGLSUIDefault gls_ui;
 
-	if (LLGLSLShader::sNoFixedFunction)
-	{
-		gUIProgram.bind();
-	}
+	gUIProgram.bind();
 
 	{
 		gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
@@ -882,10 +879,7 @@ void LLViewerObjectList::renderObjectBeacons()
 void LLSky::renderSunMoonBeacons(const LLVector3& pos_agent, const LLVector3& direction, LLColor4 color)
 {
 	LLGLSUIDefault gls_ui;
-	if (LLGLSLShader::sNoFixedFunction)
-	{
-		gUIProgram.bind();
-	}
+	gUIProgram.bind();
 	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 
 	LLVector3 pos_end;
@@ -993,9 +987,8 @@ class ShaderBinder
 //-----------------------------------------------------------------------------
 F32 gpu_benchmark()
 {
-	if (!gGLManager.mHasShaderObjects || !gGLManager.mHasTimerQuery)
-	{ // don't bother benchmarking the fixed function
-      // or venerable drivers which don't support accurate timing anyway
+	if (!gGLManager.mHasTimerQuery)
+	{ // don't bother benchmarking venerable drivers which don't support accurate timing anyway
       // and are likely to be correctly identified by the GPU table already.
 		return -1.f;
 	}
@@ -1091,7 +1084,7 @@ F32 gpu_benchmark()
     delete [] pixels;
 
 	//make a dummy triangle to draw with
-	LLPointer<LLVertexBuffer> buff = new LLVertexBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0, GL_STREAM_DRAW_ARB);
+	LLPointer<LLVertexBuffer> buff = new LLVertexBuffer(LLVertexBuffer::MAP_VERTEX, GL_STREAM_DRAW_ARB);
 
 	if (!buff->allocateBuffer(3, 0, true))
 	{
@@ -1101,7 +1094,6 @@ F32 gpu_benchmark()
 	}
 
 	LLStrider<LLVector3> v;
-	LLStrider<LLVector2> tc;
 
 	if (! buff->getVertexStrider(v))
 	{
@@ -1123,6 +1115,16 @@ F32 gpu_benchmark()
 	// ensure matched pair of bind() and unbind() calls
 	ShaderBinder binder(gBenchmarkProgram);
 
+#ifdef GL_ARB_vertex_array_object
+    U32 glarray = 0;
+
+    if (LLRender::sGLCoreProfile)
+    {
+        glGenVertexArrays(1, &glarray);
+        glBindVertexArray(glarray);
+    }
+#endif
+
 	buff->setBuffer(LLVertexBuffer::MAP_VERTEX);
 	glFinish();
 
@@ -1155,6 +1157,15 @@ F32 gpu_benchmark()
 		}
 	}
 
+#ifdef GL_ARB_vertex_array_object
+    if (LLRender::sGLCoreProfile)
+    {
+        glBindVertexArray(0);
+        glDeleteVertexArrays(1, &glarray);
+    }
+#endif
+
+
 	std::sort(results.begin(), results.end());
 
 	F32 gbps = results[results.size()/2];
diff --git a/indra/newview/llgroupactions.cpp b/indra/newview/llgroupactions.cpp
index 9dca50926299a0a9e04ac27b0af1de9f0510759d..84a12787679e0846b1804172972831a6de85be6d 100644
--- a/indra/newview/llgroupactions.cpp
+++ b/indra/newview/llgroupactions.cpp
@@ -196,7 +196,7 @@ LLFetchLeaveGroupData* gFetchLeaveGroupData = NULL;
 // static
 void LLGroupActions::search()
 {
-	LLFloaterReg::showInstance("search", LLSD().with("category", "groups"));
+	LLFloaterReg::showInstance("search", LLSD().with("collection", "groups"));
 }
 
 // static
diff --git a/indra/newview/llgrouplist.cpp b/indra/newview/llgrouplist.cpp
index 62414d3bbb745e3e2b607e59321f09abbd0f161c..32af2592d32e25a4422915387c1887d282045549 100644
--- a/indra/newview/llgrouplist.cpp
+++ b/indra/newview/llgrouplist.cpp
@@ -45,7 +45,6 @@
 #include "llvoiceclient.h"
 
 static LLDefaultChildRegistry::Register<LLGroupList> r("group_list");
-S32 LLGroupListItem::sIconWidth = 0;
 
 class LLGroupComparator : public LLFlatListView::ItemComparator
 {
@@ -65,21 +64,81 @@ class LLGroupComparator : public LLFlatListView::ItemComparator
 	}
 };
 
-static const LLGroupComparator GROUP_COMPARATOR;
+class LLSharedGroupComparator : public LLFlatListView::ItemComparator
+{
+public:
+    LLSharedGroupComparator() {};
+
+    /*virtual*/ bool compare(const LLPanel* item1, const LLPanel* item2) const
+    {
+        const LLGroupListItem* group_item1 = static_cast<const LLGroupListItem*>(item1);
+        std::string name1 = group_item1->getGroupName();
+        bool item1_shared = gAgent.isInGroup(group_item1->getGroupID(), true);
+
+        const LLGroupListItem* group_item2 = static_cast<const LLGroupListItem*>(item2);
+        std::string name2 = group_item2->getGroupName();
+        bool item2_shared = gAgent.isInGroup(group_item2->getGroupID(), true);
 
+        if (item2_shared != item1_shared)
+        {
+            return item1_shared;
+        }
+
+        LLStringUtil::toUpper(name1);
+        LLStringUtil::toUpper(name2);
+
+        return name1 < name2;
+    }
+};
+
+static LLGroupComparator GROUP_COMPARATOR;
+static LLSharedGroupComparator SHARED_GROUP_COMPARATOR;
+
+LLGroupList::Params::Params()
+: for_agent("for_agent", true)
+{
+}
 
 LLGroupList::LLGroupList(const Params& p)
 :	LLFlatListViewEx(p)
+    , mForAgent(p.for_agent)
 	, mDirty(true) // to force initial update
+    , mShowIcons(false)
+    , mShowNone(true)
 {
-	// Listen for agent group changes.
-	gAgent.addListener(this, "new group");
-
-	mShowIcons = gSavedSettings.getBOOL("GroupListShowIcons");
 	setCommitOnSelectionChange(true);
 
 	// Set default sort order.
-	setComparator(&GROUP_COMPARATOR);
+    if (mForAgent)
+    {
+        setComparator(&GROUP_COMPARATOR);
+    }
+    else
+    {
+        // shared groups first
+        setComparator(&SHARED_GROUP_COMPARATOR);
+    }
+
+    if (mForAgent)
+	{
+        enableForAgent(true);
+    }
+}
+
+LLGroupList::~LLGroupList()
+{
+    if (mForAgent) gAgent.removeListener(this);
+    if (mContextMenuHandle.get()) mContextMenuHandle.get()->die();
+}
+
+void LLGroupList::enableForAgent(bool show_icons)
+{
+    mForAgent = true;
+
+    mShowIcons = mForAgent && gSavedSettings.getBOOL("GroupListShowIcons") && show_icons;
+
+    // Listen for agent group changes.
+    gAgent.addListener(this, "new group");
 
 	// Set up context menu.
 	LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
@@ -94,12 +153,6 @@ LLGroupList::LLGroupList(const Params& p)
 		mContextMenuHandle = context_menu->getHandle();
 }
 
-LLGroupList::~LLGroupList()
-{
-	gAgent.removeListener(this);
-	if (mContextMenuHandle.get()) mContextMenuHandle.get()->die();
-}
-
 // virtual
 void LLGroupList::draw()
 {
@@ -114,12 +167,15 @@ BOOL LLGroupList::handleRightMouseDown(S32 x, S32 y, MASK mask)
 {
 	BOOL handled = LLUICtrl::handleRightMouseDown(x, y, mask);
 
-	LLToggleableMenu* context_menu = mContextMenuHandle.get();
-	if (context_menu && size() > 0)
-	{
-		context_menu->buildDrawLabels();
-		context_menu->updateParent(LLMenuGL::sMenuContainer);
-		LLMenuGL::showPopup(this, context_menu, x, y);
+    if (mForAgent)
+    {
+        LLToggleableMenu* context_menu = mContextMenuHandle.get();
+        if (context_menu && size() > 0)
+        {
+            context_menu->buildDrawLabels();
+            context_menu->updateParent(LLMenuGL::sMenuContainer);
+            LLMenuGL::showPopup(this, context_menu, x, y);
+        }
 	}
 
 	return handled;
@@ -132,7 +188,7 @@ BOOL LLGroupList::handleDoubleClick(S32 x, S32 y, MASK mask)
 	// Handle double click only for the selected item in the list, skip clicks on empty space.
 	if (handled)
 	{
-		if (mDoubleClickSignal)
+		if (mDoubleClickSignal && getItemsRect().pointInRect(x, y))
 		{
 			(*mDoubleClickSignal)(this, x, y, mask);
 		}
@@ -164,34 +220,49 @@ static bool findInsensitive(std::string haystack, const std::string& needle_uppe
 
 void LLGroupList::refresh()
 {
-	const LLUUID& 		highlight_id	= gAgent.getGroupID();
-	S32					count			= gAgent.mGroups.size();
-	LLUUID				id;
-	bool				have_filter		= !mNameFilter.empty();
-
-	clear();
-
-	for(S32 i = 0; i < count; ++i)
-	{
-		id = gAgent.mGroups.at(i).mID;
-		const LLGroupData& group_data = gAgent.mGroups.at(i);
-		if (have_filter && !findInsensitive(group_data.mName, mNameFilter))
-			continue;
-		addNewItem(id, group_data.mName, group_data.mInsigniaID, ADD_BOTTOM);
-	}
-
-	// Sort the list.
-	sort();
-
-	// Add "none" to list at top if filter not set (what's the point of filtering "none"?).
-	// but only if some real groups exists. EXT-4838
-	if (!have_filter && count > 0)
-	{
-		std::string loc_none = LLTrans::getString("GroupsNone");
-		addNewItem(LLUUID::null, loc_none, LLUUID::null, ADD_TOP);
-	}
-
-	selectItemByUUID(highlight_id);
+    if (mForAgent)
+    {
+        const LLUUID& 		highlight_id	= gAgent.getGroupID();
+        S32					count			= gAgent.mGroups.size();
+        LLUUID				id;
+        bool				have_filter		= !mNameFilter.empty();
+
+        clear();
+
+        for(S32 i = 0; i < count; ++i)
+        {
+            id = gAgent.mGroups.at(i).mID;
+            const LLGroupData& group_data = gAgent.mGroups.at(i);
+            if (have_filter && !findInsensitive(group_data.mName, mNameFilter))
+                continue;
+            addNewItem(id, group_data.mName, group_data.mInsigniaID, ADD_BOTTOM, group_data.mListInProfile);
+        }
+
+        // Sort the list.
+        sort();
+
+        // Add "none" to list at top if filter not set (what's the point of filtering "none"?).
+        // but only if some real groups exists. EXT-4838
+        if (!have_filter && count > 0 && mShowNone)
+        {
+            std::string loc_none = LLTrans::getString("GroupsNone");
+            addNewItem(LLUUID::null, loc_none, LLUUID::null, ADD_TOP);
+        }
+
+        selectItemByUUID(highlight_id);
+    }
+    else
+    {
+        clear();
+
+        for (group_map_t::iterator it = mGroups.begin(); it != mGroups.end(); ++it)
+        {
+            addNewItem(it->second, it->first, LLUUID::null, ADD_BOTTOM);
+        }
+
+        // Sort the list.
+        sort();
+    }
 
 	setDirty(false);
 	onCommit();
@@ -212,13 +283,19 @@ void LLGroupList::toggleIcons()
 	}
 }
 
+void LLGroupList::setGroups(const std::map< std::string,LLUUID> group_list)
+{
+    mGroups = group_list;
+    setDirty(true);
+}
+
 //////////////////////////////////////////////////////////////////////////
 // PRIVATE Section
 //////////////////////////////////////////////////////////////////////////
 
-void LLGroupList::addNewItem(const LLUUID& id, const std::string& name, const LLUUID& icon_id, EAddPosition pos)
+void LLGroupList::addNewItem(const LLUUID& id, const std::string& name, const LLUUID& icon_id, EAddPosition pos, bool visible_in_profile)
 {
-	LLGroupListItem* item = new LLGroupListItem();
+	LLGroupListItem* item = new LLGroupListItem(mForAgent, mShowIcons);
 
 	item->setGroupID(id);
 	item->setName(name, mNameFilter);
@@ -227,7 +304,10 @@ void LLGroupList::addNewItem(const LLUUID& id, const std::string& name, const LL
 	item->getChildView("info_btn")->setVisible( false);
 	item->getChildView("profile_btn")->setVisible( false);
 	item->setGroupIconVisible(mShowIcons);
-
+    if (!mShowIcons)
+    {
+        item->setVisibleInProfile(visible_in_profile);
+    }
 	addItem(item, id, pos);
 
 //	setCommentVisible(false);
@@ -243,6 +323,29 @@ bool LLGroupList::handleEvent(LLPointer<LLOldEvents::LLEvent> event, const LLSD&
 		return true;
 	}
 
+    if (event->desc() == "value_changed")
+    {
+        LLSD data = event->getValue();
+        if (data.has("group_id") && data.has("visible"))
+        {
+            LLUUID group_id = data["group_id"].asUUID();
+            bool visible = data["visible"].asBoolean();
+
+            std::vector<LLPanel*> items;
+            getItems(items);
+            for (std::vector<LLPanel*>::iterator it = items.begin(); it != items.end(); ++it)
+            {
+                LLGroupListItem* item = dynamic_cast<LLGroupListItem*>(*it);
+                if (item && item->getGroupID() == group_id)
+                {
+                    item->setVisibleInProfile(visible);
+                    break;
+                }
+            }
+        }
+        return true;
+    }
+
 	return false;
 }
 
@@ -294,21 +397,25 @@ bool LLGroupList::onContextMenuItemEnable(const LLSD& userdata)
 /*          LLGroupListItem implementation                              */
 /************************************************************************/
 
-LLGroupListItem::LLGroupListItem()
+LLGroupListItem::LLGroupListItem(bool for_agent, bool show_icons)
 :	LLPanel(),
 mGroupIcon(NULL),
 mGroupNameBox(NULL),
 mInfoBtn(NULL),
-mGroupID(LLUUID::null)
+mProfileBtn(NULL),
+mVisibilityHideBtn(NULL),
+mVisibilityShowBtn(NULL),
+mGroupID(LLUUID::null),
+mForAgent(for_agent)
 {
-	buildFromFile( "panel_group_list_item.xml");
-
-	// Remember group icon width including its padding from the name text box,
-	// so that we can hide and show the icon again later.
-	if (!sIconWidth)
-	{
-		sIconWidth = mGroupNameBox->getRect().mLeft - mGroupIcon->getRect().mLeft;
-	}
+    if (show_icons)
+    {
+        buildFromFile( "panel_group_list_item.xml");
+    }
+    else
+    {
+        buildFromFile( "panel_group_list_item_short.xml");
+    }
 }
 
 LLGroupListItem::~LLGroupListItem()
@@ -325,7 +432,25 @@ BOOL  LLGroupListItem::postBuild()
 	mInfoBtn = getChild<LLButton>("info_btn");
 	mInfoBtn->setClickedCallback(boost::bind(&LLGroupListItem::onInfoBtnClick, this));
 
-	childSetAction("profile_btn", boost::bind(&LLGroupListItem::onProfileBtnClick, this));
+    mProfileBtn = getChild<LLButton>("profile_btn");
+    mProfileBtn->setClickedCallback([this](LLUICtrl *, const LLSD &) { onProfileBtnClick(); });
+
+    mVisibilityHideBtn = findChild<LLButton>("visibility_hide_btn");
+    if (mVisibilityHideBtn)
+    {
+        mVisibilityHideBtn->setClickedCallback([this](LLUICtrl *, const LLSD &) { onVisibilityBtnClick(false); });
+    }
+    mVisibilityShowBtn = findChild<LLButton>("visibility_show_btn");
+    if (mVisibilityShowBtn)
+    {
+        mVisibilityShowBtn->setClickedCallback([this](LLUICtrl *, const LLSD &) { onVisibilityBtnClick(true); });
+    }
+
+    // Remember group icon width including its padding from the name text box,
+    // so that we can hide and show the icon again later.
+    // Also note that panel_group_list_item and panel_group_list_item_short
+    // have icons of different sizes so we need to figure it per file.
+    mIconWidth = mGroupNameBox->getRect().mLeft - mGroupIcon->getRect().mLeft;
 
 	return TRUE;
 }
@@ -344,7 +469,16 @@ void LLGroupListItem::onMouseEnter(S32 x, S32 y, MASK mask)
 	if (mGroupID.notNull()) // don't show the info button for the "none" group
 	{
 		mInfoBtn->setVisible(true);
-		getChildView("profile_btn")->setVisible( true);
+        mProfileBtn->setVisible(true);
+        if (mForAgent && mVisibilityHideBtn)
+        {
+            LLGroupData agent_gdatap;
+            if (gAgent.getGroupData(mGroupID, agent_gdatap))
+            {
+                mVisibilityHideBtn->setVisible(agent_gdatap.mListInProfile);
+                mVisibilityShowBtn->setVisible(!agent_gdatap.mListInProfile);
+            }
+        }
 	}
 
 	LLPanel::onMouseEnter(x, y, mask);
@@ -354,7 +488,12 @@ void LLGroupListItem::onMouseLeave(S32 x, S32 y, MASK mask)
 {
 	getChildView("hovered_icon")->setVisible( false);
 	mInfoBtn->setVisible(false);
-	getChildView("profile_btn")->setVisible( false);
+    mProfileBtn->setVisible(false);
+    if (mVisibilityHideBtn)
+    {
+        mVisibilityHideBtn->setVisible(false);
+        mVisibilityShowBtn->setVisible(false);
+    }
 
 	LLPanel::onMouseLeave(x, y, mask);
 }
@@ -372,7 +511,17 @@ void LLGroupListItem::setGroupID(const LLUUID& group_id)
 	
 	mID = group_id;
 	mGroupID = group_id;
-	setActive(group_id == gAgent.getGroupID());
+
+    if (mForAgent)
+    {
+        // Active group should be bold.
+        setBold(group_id == gAgent.getGroupID());
+    }
+    else
+    {
+        // Groups shared with the agent should be bold
+        setBold(gAgent.isInGroup(group_id, true));
+    }
 
 	LLGroupMgr::getInstance()->addObserver(this);
 }
@@ -393,24 +542,28 @@ void LLGroupListItem::setGroupIconVisible(bool visible)
 
 	// Move the group name horizontally by icon size + its distance from the group name.
 	LLRect name_rect = mGroupNameBox->getRect();
-	name_rect.mLeft += visible ? sIconWidth : -sIconWidth;
+	name_rect.mLeft += visible ? mIconWidth : -mIconWidth;
 	mGroupNameBox->setRect(name_rect);
 }
 
+void LLGroupListItem::setVisibleInProfile(bool visible)
+{
+    mGroupNameBox->setColor(LLUIColorTable::instance().getColor((visible ? "GroupVisibleInProfile" : "GroupHiddenInProfile"), LLColor4::red).get());
+}
+
 //////////////////////////////////////////////////////////////////////////
 // Private Section
 //////////////////////////////////////////////////////////////////////////
-void LLGroupListItem::setActive(bool active)
+void LLGroupListItem::setBold(bool bold)
 {
 	// *BUG: setName() overrides the style params.
 
-	// Active group should be bold.
 	LLFontDescriptor new_desc(mGroupNameBox->getFont()->getFontDesc());
 
 	// *NOTE dzaporozhan
 	// On Windows LLFontGL::NORMAL will not remove LLFontGL::BOLD if font 
 	// is predefined as bold (SansSerifSmallBold, for example)
-	new_desc.setStyle(active ? LLFontGL::BOLD : LLFontGL::NORMAL);
+	new_desc.setStyle(bold ? LLFontGL::BOLD : LLFontGL::NORMAL);
 	LLFontGL* new_font = LLFontGL::getFont(new_desc);
 	mGroupNameStyle.font = new_font;
 
@@ -430,11 +583,25 @@ void LLGroupListItem::onProfileBtnClick()
 	LLGroupActions::show(mGroupID);
 }
 
+void LLGroupListItem::onVisibilityBtnClick(bool new_visibility)
+{
+    LLGroupData agent_gdatap;
+    if (gAgent.getGroupData(mGroupID, agent_gdatap))
+    {
+        gAgent.setUserGroupFlags(mGroupID, agent_gdatap.mAcceptNotices, new_visibility);
+        setVisibleInProfile(new_visibility);
+        mVisibilityHideBtn->setVisible(new_visibility);
+        mVisibilityShowBtn->setVisible(!new_visibility);
+    }
+}
+
 void LLGroupListItem::changed(LLGroupChange gc)
 {
 	LLGroupMgrGroupData* group_data = LLGroupMgr::getInstance()->getGroupData(mID);
-	if(group_data)
-		setGroupIconID(group_data->mInsigniaID);
+	if ((gc == GC_ALL || gc == GC_PROPERTIES) && group_data)
+    {
+        setGroupIconID(group_data->mInsigniaID);
+    }
 }
 
 //EOF
diff --git a/indra/newview/llgrouplist.h b/indra/newview/llgrouplist.h
index 171b77fb00d73b0e42a561ae44d61e45da7727ba..5cbabb712fdbae16a22ae2e7730df2655d9440c1 100644
--- a/indra/newview/llgrouplist.h
+++ b/indra/newview/llgrouplist.h
@@ -50,12 +50,15 @@ class LLGroupList: public LLFlatListViewEx, public LLOldEvents::LLSimpleListener
 public:
 	struct Params : public LLInitParam::Block<Params, LLFlatListViewEx::Params>
 	{
-		Params(){};
+        Optional<bool> for_agent;
+        Params();
 	};
 
 	LLGroupList(const Params& p);
 	virtual ~LLGroupList();
 
+    void enableForAgent(bool show_icons);
+
 	virtual void draw(); // from LLView
 	/*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); // from LLView
 	/*virtual*/ BOOL handleDoubleClick(S32 x, S32 y, MASK mask); // from LLView
@@ -63,13 +66,16 @@ class LLGroupList: public LLFlatListViewEx, public LLOldEvents::LLSimpleListener
 	void setNameFilter(const std::string& filter);
 	void toggleIcons();
 	bool getIconsVisible() const { return mShowIcons; }
+    void setIconsVisible(bool show_icons) { mShowIcons = show_icons; }
+    void setShowNone(bool show_none) { mShowNone = show_none; }
+    void setGroups(const std::map< std::string,LLUUID> group_list);
 
 	LLToggleableMenu* getContextMenu() const { return mContextMenuHandle.get(); }
 
 private:
 	void setDirty(bool val = true)		{ mDirty = val; }
 	void refresh();
-	void addNewItem(const LLUUID& id, const std::string& name, const LLUUID& icon_id, EAddPosition pos = ADD_BOTTOM);
+	void addNewItem(const LLUUID& id, const std::string& name, const LLUUID& icon_id, EAddPosition pos = ADD_BOTTOM, bool visible_in_profile = true);
 	bool handleEvent(LLPointer<LLOldEvents::LLEvent> event, const LLSD& userdata); // called on agent group list changes
 
 	bool onContextMenuItemClick(const LLSD& userdata);
@@ -80,6 +86,11 @@ class LLGroupList: public LLFlatListViewEx, public LLOldEvents::LLSimpleListener
 	bool mShowIcons;
 	bool mDirty;
 	std::string mNameFilter;
+
+    bool mForAgent;
+    bool mShowNone;
+    typedef std::map< std::string,LLUUID>	group_map_t;
+    group_map_t 			mGroups;
 };
 
 class LLButton;
@@ -90,7 +101,7 @@ class LLGroupListItem : public LLPanel
 	, public LLGroupMgrObserver
 {
 public:
-	LLGroupListItem();
+    LLGroupListItem(bool for_agent, bool show_icons);
 	~LLGroupListItem();
 	/*virtual*/ BOOL postBuild();
 	/*virtual*/ void setValue(const LLSD& value);
@@ -106,19 +117,26 @@ class LLGroupListItem : public LLPanel
 	void setGroupIconVisible(bool visible);
 
 	virtual void changed(LLGroupChange gc);
+
+    void setVisibleInProfile(bool visible);
 private:
-	void setActive(bool active);
+	void setBold(bool bold);
 	void onInfoBtnClick();
 	void onProfileBtnClick();
+    void onVisibilityBtnClick(bool new_visibility);
 
 	LLTextBox*	mGroupNameBox;
 	LLUUID		mGroupID;
 	LLGroupIconCtrl* mGroupIcon;
-	LLButton*	mInfoBtn;
+    LLButton*	mInfoBtn;
+    LLButton*	mProfileBtn;
+    LLButton*	mVisibilityHideBtn;
+    LLButton*	mVisibilityShowBtn;
 
 	std::string	mGroupName;
+    bool        mForAgent;
 	LLStyle::Params mGroupNameStyle;
 
-	static S32	sIconWidth; // icon width + padding
+	S32	mIconWidth;
 };
 #endif // LL_LLGROUPLIST_H
diff --git a/indra/newview/llgroupmgr.cpp b/indra/newview/llgroupmgr.cpp
index 32f88b49ac9595d2fbe335b3145f4f6c8cef7eac..a9e5e55451e3d8e4d84a6fae5d4020c66caab4e9 100644
--- a/indra/newview/llgroupmgr.cpp
+++ b/indra/newview/llgroupmgr.cpp
@@ -53,6 +53,7 @@
 #include "llviewerregion.h"
 #include <boost/regex.hpp>
 #include "llcorehttputil.h"
+#include "lluiusage.h"
 
 
 #if LL_MSVC
@@ -944,12 +945,10 @@ static void formatDateString(std::string &date_string)
 	}
 }
 
-static LLTrace::BlockTimerStatHandle FTM_PROCESS_GROUP_MEMBERS_REPLY("Process Group Members");
-
 // static
 void LLGroupMgr::processGroupMembersReply(LLMessageSystem* msg, void** data)
 {
-    LL_RECORD_BLOCK_TIME(FTM_PROCESS_GROUP_MEMBERS_REPLY);
+    LL_PROFILE_ZONE_SCOPED;
 
 	LL_DEBUGS("GrpMgr") << "LLGroupMgr::processGroupMembersReply" << LL_ENDL;
 	LLUUID agent_id;
@@ -1054,12 +1053,10 @@ void LLGroupMgr::processGroupMembersReply(LLMessageSystem* msg, void** data)
 	LLGroupMgr::getInstance()->notifyObservers(GC_MEMBER_DATA);
 }
 
-static LLTrace::BlockTimerStatHandle FTM_PROCESS_GROUP_PROPERTIES_REPLY("Process Group Properties");
-
 //static 
 void LLGroupMgr::processGroupPropertiesReply(LLMessageSystem* msg, void** data)
 {
-    LL_RECORD_BLOCK_TIME(FTM_PROCESS_GROUP_PROPERTIES_REPLY);
+    LL_PROFILE_ZONE_SCOPED;
 
 	LL_DEBUGS("GrpMgr") << "LLGroupMgr::processGroupPropertiesReply" << LL_ENDL;
 	if (!msg)
@@ -1139,11 +1136,10 @@ void LLGroupMgr::processGroupPropertiesReply(LLMessageSystem* msg, void** data)
 	LLGroupMgr::getInstance()->notifyObservers(GC_PROPERTIES);
 }
 
-static LLTrace::BlockTimerStatHandle FTM_PROCESS_GROUP_ROLE_DATA_REPLY("Process Group Role Data");
 // static
 void LLGroupMgr::processGroupRoleDataReply(LLMessageSystem* msg, void** data)
 {
-    LL_RECORD_BLOCK_TIME(FTM_PROCESS_GROUP_ROLE_DATA_REPLY);
+    LL_PROFILE_ZONE_SCOPED;
 
 	LL_DEBUGS("GrpMgr") << "LLGroupMgr::processGroupRoleDataReply" << LL_ENDL;
 	LLUUID agent_id;
@@ -1227,11 +1223,10 @@ void LLGroupMgr::processGroupRoleDataReply(LLMessageSystem* msg, void** data)
 	LLGroupMgr::getInstance()->notifyObservers(GC_ROLE_DATA);
 }
 
-static LLTrace::BlockTimerStatHandle FTM_PROCESS_GROUP_ROLE_MEMBERS_REPLY("Process Group Role Members");
 // static
 void LLGroupMgr::processGroupRoleMembersReply(LLMessageSystem* msg, void** data)
 {
-    LL_RECORD_BLOCK_TIME(FTM_PROCESS_GROUP_ROLE_MEMBERS_REPLY);
+    LL_PROFILE_ZONE_SCOPED;
 
 	LL_DEBUGS("GrpMgr") << "LLGroupMgr::processGroupRoleMembersReply" << LL_ENDL;
 	LLUUID agent_id;
@@ -1865,6 +1860,9 @@ void LLGroupMgr::sendGroupRoleMemberChanges(const LLUUID& group_id)
 //static
 void LLGroupMgr::sendGroupMemberJoin(const LLUUID& group_id)
 {
+
+	LLUIUsage::instance().logCommand("Group.Join");
+
 	LLMessageSystem *msg = gMessageSystem;
 
 	msg->newMessageFast(_PREHASH_JoinGroupRequest);
diff --git a/indra/newview/llhudnametag.cpp b/indra/newview/llhudnametag.cpp
index 9d49c30a49c2c2c6911e2b1849c2ad0d2bd4caa6..952fbf8e4b109e4793147ed4ad1611a89ca41d4b 100644
--- a/indra/newview/llhudnametag.cpp
+++ b/indra/newview/llhudnametag.cpp
@@ -224,6 +224,7 @@ BOOL LLHUDNameTag::lineSegmentIntersect(const LLVector4a& start, const LLVector4
 
 void LLHUDNameTag::render()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
 	if (sDisplayText)
 	{
 		LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE);
@@ -322,8 +323,6 @@ void LLHUDNameTag::renderText(BOOL for_select)
 		
 	// Render label
 	{
-		//gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
-
 		for(std::vector<LLHUDTextSegment>::iterator segment_iter = mLabelSegments.begin();
 			segment_iter != mLabelSegments.end(); ++segment_iter )
 		{
@@ -731,6 +730,7 @@ void LLHUDNameTag::updateSize()
 
 void LLHUDNameTag::updateAll()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
 	// iterate over all text objects, calculate their restoration forces,
 	// and add them to the visible set if they are on screen and close enough
 	sVisibleTextObjects.clear();
diff --git a/indra/newview/llhudtext.cpp b/indra/newview/llhudtext.cpp
index 598a8d4c050cd9523643ce176372febfb2c0d53c..5952edfc4449cefc88f11a9bf1a98b553243e869 100644
--- a/indra/newview/llhudtext.cpp
+++ b/indra/newview/llhudtext.cpp
@@ -188,9 +188,6 @@ void LLHUDText::renderText()
 	F32 y_offset = (F32)mOffsetY;
 		
 	// Render label
-	{
-		gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
-	}
 
 	// Render text
 	{
@@ -333,7 +330,7 @@ void LLHUDText::updateVisibility()
 
 	if (!mSourceObject)
 	{
-		LL_WARNS() << "HUD text: mSourceObject is NULL,  mOnHUDAttachment: " << mOnHUDAttachment << LL_ENDL;
+        // Beacons
 		mVisible = TRUE;
 		if (mOnHUDAttachment)
 		{
@@ -573,7 +570,6 @@ void LLHUDText::renderAllHUD()
 {
 	LLGLState::checkStates();
 	LLGLState::checkTextureChannels();
-	LLGLState::checkClientArrays();
 
 	{
 		LLGLEnable color_mat(GL_COLOR_MATERIAL);
@@ -591,7 +587,6 @@ void LLHUDText::renderAllHUD()
 
 	LLGLState::checkStates();
 	LLGLState::checkTextureChannels();
-	LLGLState::checkClientArrays();
 }
 
 void LLHUDText::shiftAll(const LLVector3& offset)
diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp
index 3017d927e5771dc7aeb07e81fa5e5258fb1d855e..4d6ebf9cbb4bee8e8b1a1ef1af0ca6489cc9c50b 100644
--- a/indra/newview/llimview.cpp
+++ b/indra/newview/llimview.cpp
@@ -69,7 +69,7 @@
 #include "message.h"
 #include "llviewerregion.h"
 #include "llcorehttputil.h"
-
+#include "lluiusage.h"
 
 const static std::string ADHOC_NAME_SUFFIX(" Conference");
 
@@ -532,7 +532,6 @@ LLIMModel::LLIMSession::LLIMSession(const LLUUID& session_id, const std::string&
 	mSessionInitialized(false),
 	mCallBackEnabled(true),
 	mTextIMPossible(true),
-	mOtherParticipantIsAvatar(true),
 	mStartCallOnInitialize(false),
 	mStartedAsIMCall(voice),
 	mIsDNDsend(false),
@@ -544,13 +543,6 @@ LLIMModel::LLIMSession::LLIMSession(const LLUUID& session_id, const std::string&
 	if (IM_NOTHING_SPECIAL == mType || IM_SESSION_P2P_INVITE == mType)
 	{
 		mVoiceChannel  = new LLVoiceChannelP2P(session_id, name, other_participant_id);
-		mOtherParticipantIsAvatar = LLVoiceClient::getInstance()->isParticipantAvatar(mSessionID);
-
-		// check if it was AVALINE call
-		if (!mOtherParticipantIsAvatar)
-		{
-			mSessionType = AVALINE_SESSION;
-		} 
 	}
 	else
 	{
@@ -651,9 +643,6 @@ void LLIMModel::LLIMSession::onVoiceChannelStateChanged(const LLVoiceChannel::ES
 
 	switch(mSessionType)
 	{
-	case AVALINE_SESSION:
-		// no text notifications
-		break;
 	case P2P_SESSION:
 		LLAvatarNameCache::get(mOtherParticipantID, &av_name);
 		other_avatar_name = av_name.getUserName();
@@ -781,6 +770,23 @@ void LLIMModel::LLIMSession::addMessage(const std::string& from, const LLUUID& f
 	message["index"] = (LLSD::Integer)mMsgs.size(); 
 	message["is_history"] = is_history;
 
+	LL_DEBUGS("UIUsage") << "addMessage " << " from " << from << " from_id " << from_id << " utf8_text " << utf8_text << " time " << time << " is_history " << is_history << " session mType " << mType << LL_ENDL;
+	if (from_id == gAgent.getID())
+	{
+		if (mType == IM_SESSION_GROUP_START)
+		{
+			LLUIUsage::instance().logCommand("Chat.SendGroup");
+		}
+		else if (mType == IM_NOTHING_SPECIAL)
+		{
+			LLUIUsage::instance().logCommand("Chat.SendIM");
+		}
+		else
+		{
+			LLUIUsage::instance().logCommand("Chat.SendOther");
+		}
+	}
+
 	mMsgs.push_front(message); 
 
 	if (mSpeakers && from_id.notNull())
@@ -913,11 +919,6 @@ bool LLIMModel::LLIMSession::isGroupChat()
 	return IM_SESSION_GROUP_START == mType || (IM_SESSION_INVITE == mType && gAgent.isInGroup(mSessionID, TRUE));
 }
 
-bool LLIMModel::LLIMSession::isOtherParticipantAvaline()
-{
-	return !mOtherParticipantIsAvatar;
-}
-
 LLUUID LLIMModel::LLIMSession::generateOutgoingAdHocHash() const
 {
 	LLUUID hash = LLUUID::null;
@@ -1229,7 +1230,6 @@ LLIMModel::LLIMSession* LLIMModel::addMessageSilently(const LLUUID& session_id,
 
 	if (!session)
 	{
-		LL_WARNS() << "session " << session_id << "does not exist " << LL_ENDL;
 		return NULL;
 	}
 
@@ -1796,7 +1796,6 @@ LLIMMgr::onConfirmForceCloseError(
 
 LLCallDialogManager::LLCallDialogManager():
 mPreviousSessionlName(""),
-mPreviousSessionType(LLIMModel::LLIMSession::P2P_SESSION),
 mCurrentSessionlName(""),
 mSession(NULL),
 mOldState(LLVoiceChannel::STATE_READY)
@@ -1827,12 +1826,6 @@ void LLCallDialogManager::onVoiceChannelChangedInt(const LLUUID &session_id)
 		mCurrentSessionlName = ""; // Empty string results in "Nearby Voice Chat" after substitution
 		return;
 	}
-	
-	if (mSession)
-	{
-		// store previous session type to process Avaline calls in dialogs
-		mPreviousSessionType = mSession->mSessionType;
-	}
 
 	mSession = session;
 
@@ -1858,7 +1851,6 @@ void LLCallDialogManager::onVoiceChannelChangedInt(const LLUUID &session_id)
 		mCallDialogPayload["session_name"] = mSession->mName;
 		mCallDialogPayload["other_user_id"] = mSession->mOtherParticipantID;
 		mCallDialogPayload["old_channel_name"] = mPreviousSessionlName;
-		mCallDialogPayload["old_session_type"] = mPreviousSessionType;
 		mCallDialogPayload["state"] = LLVoiceChannel::STATE_CALL_STARTED;
 		mCallDialogPayload["disconnected_channel_name"] = mSession->mName;
 		mCallDialogPayload["session_type"] = mSession->mSessionType;
@@ -1894,7 +1886,6 @@ void LLCallDialogManager::onVoiceChannelStateChangedInt(const LLVoiceChannel::ES
 	mCallDialogPayload["session_name"] = mSession->mName;
 	mCallDialogPayload["other_user_id"] = mSession->mOtherParticipantID;
 	mCallDialogPayload["old_channel_name"] = mPreviousSessionlName;
-	mCallDialogPayload["old_session_type"] = mPreviousSessionType;
 	mCallDialogPayload["state"] = new_state;
 	mCallDialogPayload["disconnected_channel_name"] = mSession->mName;
 	mCallDialogPayload["session_type"] = mSession->mSessionType;
@@ -1911,8 +1902,7 @@ void LLCallDialogManager::onVoiceChannelStateChangedInt(const LLVoiceChannel::ES
 		break;
 
 	case LLVoiceChannel::STATE_HUNG_UP:
-		// this state is coming before session is changed, so, put it into payload map
-		mCallDialogPayload["old_session_type"] = mSession->mSessionType;
+		// this state is coming before session is changed
 		break;
 
 	case LLVoiceChannel::STATE_CONNECTED :
@@ -2032,7 +2022,6 @@ void LLCallDialog::onOpen(const LLSD& key)
 
 void LLCallDialog::setIcon(const LLSD& session_id, const LLSD& participant_id)
 {
-	// *NOTE: 12/28/2009: check avaline calls: LLVoiceClient::isParticipantAvatar returns false for them
 	bool participant_is_avatar = LLVoiceClient::getInstance()->isParticipantAvatar(session_id);
 
 	bool is_group = participant_is_avatar && gAgent.isInGroup(session_id, TRUE);
@@ -2053,8 +2042,8 @@ void LLCallDialog::setIcon(const LLSD& session_id, const LLSD& participant_id)
 	}
 	else
 	{
-		avatar_icon->setValue("Avaline_Icon");
-		avatar_icon->setToolTip(std::string(""));
+        LL_WARNS() << "Participant neither avatar nor group" << LL_ENDL;
+        group_icon->setValue(session_id);
 	}
 }
 
@@ -2098,13 +2087,7 @@ void LLOutgoingCallDialog::show(const LLSD& key)
 	// tell the user which voice channel they are leaving
 	if (!mPayload["old_channel_name"].asString().empty())
 	{
-		bool was_avaline_call = LLIMModel::LLIMSession::AVALINE_SESSION == mPayload["old_session_type"].asInteger();
-
 		std::string old_caller_name = mPayload["old_channel_name"].asString();
-		if (was_avaline_call)
-		{
-			old_caller_name = LLTextUtil::formatPhoneNumber(old_caller_name);
-		}
 
 		getChild<LLUICtrl>("leaving")->setTextArg("[CURRENT_CHAT]", old_caller_name);
 		show_oldchannel = true;
@@ -2117,10 +2100,6 @@ void LLOutgoingCallDialog::show(const LLSD& key)
 	if (!mPayload["disconnected_channel_name"].asString().empty())
 	{
 		std::string channel_name = mPayload["disconnected_channel_name"].asString();
-		if (LLIMModel::LLIMSession::AVALINE_SESSION == mPayload["session_type"].asInteger())
-		{
-			channel_name = LLTextUtil::formatPhoneNumber(channel_name);
-		}
 		getChild<LLUICtrl>("nearby")->setTextArg("[VOICE_CHANNEL_NAME]", channel_name);
 
 		// skipping "You will now be reconnected to nearby" in notification when call is ended by disabling voice,
@@ -2136,16 +2115,11 @@ void LLOutgoingCallDialog::show(const LLSD& key)
 	std::string callee_name = mPayload["session_name"].asString();
 
 	LLUUID session_id = mPayload["session_id"].asUUID();
-	bool is_avatar = LLVoiceClient::getInstance()->isParticipantAvatar(session_id);
 
-	if (callee_name == "anonymous")
+	if (callee_name == "anonymous") // obsolete? Likely was part of avaline support
 	{
 		callee_name = getString("anonymous");
 	}
-	else if (!is_avatar)
-	{
-		callee_name = LLTextUtil::formatPhoneNumber(callee_name);
-	}
 	
 	LLSD callee_id = mPayload["other_user_id"];
 	// Beautification:  Since you know who you called, just show display name
@@ -2345,18 +2319,11 @@ BOOL LLIncomingCallDialog::postBuild()
 		call_type = getString(notify_box_type);
 	}
 
-	// check to see if this is an Avaline call
-	bool is_avatar = LLVoiceClient::getInstance()->isParticipantAvatar(session_id);
-	if (caller_name == "anonymous")
+	if (caller_name == "anonymous") // obsolete?  Likely was part of avaline support
 	{
 		caller_name = getString("anonymous");
 		setCallerName(caller_name, caller_name, call_type);
 	}
-	else if (!is_avatar)
-	{
-		caller_name = LLTextUtil::formatPhoneNumber(caller_name);
-		setCallerName(caller_name, caller_name, call_type);
-	}
 	else
 	{
 		// Get the full name information
@@ -2376,7 +2343,7 @@ BOOL LLIncomingCallDialog::postBuild()
 
 	if(notify_box_type != "VoiceInviteGroup" && notify_box_type != "VoiceInviteAdHoc")
 	{
-		// starting notification's timer for P2P and AVALINE invitations
+		// starting notification's timer for P2P invitations
 		mLifetimeTimer.start();
 	}
 	else
@@ -2385,7 +2352,7 @@ BOOL LLIncomingCallDialog::postBuild()
 	}
 
 	//it's not possible to connect to existing Ad-Hoc/Group chat through incoming ad-hoc call
-	//and no IM for avaline
+	bool is_avatar = LLVoiceClient::getInstance()->isParticipantAvatar(session_id);
 	getChildView("Start IM")->setVisible( is_avatar && notify_box_type != "VoiceInviteAdHoc" && notify_box_type != "VoiceInviteGroup");
 
 	setCanDrag(FALSE);
diff --git a/indra/newview/llimview.h b/indra/newview/llimview.h
index 79c831ebb6a6981d2f3695ee43c6bdc003bb615f..fdf9806e2ec22f2421e4e6801dea9062359cc4cb 100644
--- a/indra/newview/llimview.h
+++ b/indra/newview/llimview.h
@@ -72,7 +72,6 @@ class LLIMModel :  public LLSingleton<LLIMModel>
 			P2P_SESSION,
 			GROUP_SESSION,
 			ADHOC_SESSION,
-			AVALINE_SESSION,
 			NONE_SESSION,
 		} SType;
 
@@ -92,12 +91,10 @@ class LLIMModel :  public LLSingleton<LLIMModel>
 		bool isAdHoc();
 		bool isP2P();
 		bool isGroupChat();
-		bool isOtherParticipantAvaline();
 
 		bool isP2PSessionType() const { return mSessionType == P2P_SESSION;}
 		bool isAdHocSessionType() const { return mSessionType == ADHOC_SESSION;}
 		bool isGroupSessionType() const { return mSessionType == GROUP_SESSION;}
-		bool isAvalineSessionType() const { return mSessionType == AVALINE_SESSION;}
 
 		LLUUID generateOutgoingAdHocHash() const;
 
@@ -136,7 +133,6 @@ class LLIMModel :  public LLSingleton<LLIMModel>
 		bool mCallBackEnabled;
 
 		bool mTextIMPossible;
-		bool mOtherParticipantIsAvatar;
 		bool mStartCallOnInitialize;
 
 		//if IM session is created for a voice call
@@ -516,7 +512,6 @@ class LLCallDialogManager : public LLSingleton<LLCallDialogManager>
 
 protected:
 	std::string mPreviousSessionlName;
-	LLIMModel::LLIMSession::SType mPreviousSessionType;
 	std::string mCurrentSessionlName;
 	LLIMModel::LLIMSession* mSession;
 	LLVoiceChannel::EState mOldState;
diff --git a/indra/newview/llinspect.cpp b/indra/newview/llinspect.cpp
index 479e8f9abf96bf65ffe9c3dec18e4e83786567a4..f382b5985f37282bf89ddcf42cb29d757f0f1ee6 100644
--- a/indra/newview/llinspect.cpp
+++ b/indra/newview/llinspect.cpp
@@ -147,3 +147,19 @@ bool LLInspect::childHasVisiblePopupMenu()
 	}
 	return false;
 }
+
+void LLInspect::repositionInspector(const LLSD& data)
+{
+	// Position the inspector relative to the mouse cursor
+	// Similar to how tooltips are positioned
+	// See LLToolTipMgr::createToolTip
+	if (data.has("pos"))
+	{
+		LLUI::getInstance()->positionViewNearMouse(this, data["pos"]["x"].asInteger(), data["pos"]["y"].asInteger());
+	}
+	else
+	{
+		LLUI::getInstance()->positionViewNearMouse(this);
+	}
+	applyRectControl();
+}
diff --git a/indra/newview/llinspect.h b/indra/newview/llinspect.h
index 1f6aafc7bdc2446e18c66dd30800a94e73afcc0f..6909aa3f16daee578e01c15fb3e801a9a7205a0f 100644
--- a/indra/newview/llinspect.h
+++ b/indra/newview/llinspect.h
@@ -49,6 +49,8 @@ class LLInspect : public LLFloater
 	
 	/// Inspectors close themselves when they lose focus
 	/*virtual*/ void onFocusLost();
+
+	void repositionInspector(const LLSD& data);
 	
 protected:
 
diff --git a/indra/newview/llinspectavatar.cpp b/indra/newview/llinspectavatar.cpp
index 10814ac0769db1f3675c36211e83774d3a9eb84f..b11c440015061cdf946380e59e06be034a54b26e 100644
--- a/indra/newview/llinspectavatar.cpp
+++ b/indra/newview/llinspectavatar.cpp
@@ -45,7 +45,6 @@
 #include "llfloater.h"
 #include "llfloaterreg.h"
 #include "lltextbox.h"
-#include "lltooltip.h"	// positionViewNearMouse()
 #include "lltrans.h"
 
 class LLFetchAvatarData;
@@ -202,17 +201,7 @@ void LLInspectAvatar::onOpen(const LLSD& data)
 	// Extract appropriate avatar id
 	mAvatarID = data["avatar_id"];
 
-	// Position the inspector relative to the mouse cursor
-	// Similar to how tooltips are positioned
-	// See LLToolTipMgr::createToolTip
-	if (data.has("pos"))
-	{
-		LLUI::getInstance()->positionViewNearMouse(this, data["pos"]["x"].asInteger(), data["pos"]["y"].asInteger());
-	}
-	else
-	{
-		LLUI::getInstance()->positionViewNearMouse(this);
-	}
+	LLInspect::repositionInspector(data);
 
 	// Generate link to avatar profile.
 	LLTextBase* avatar_profile_link = getChild<LLTextBase>("avatar_profile_link");
@@ -348,7 +337,7 @@ void LLInspectAvatar::onClickMuteVolume()
 	LLMuteList* mute_list = LLMuteList::getInstance();
 	bool is_muted = mute_list->isMuted(mAvatarID, LLMute::flagVoiceChat);
 
-	LLMute mute(mAvatarID, mAvatarName.getDisplayName(), LLMute::AGENT);
+	LLMute mute(mAvatarID, mAvatarName.getUserName(), LLMute::AGENT);
 	if (!is_muted)
 	{
 		mute_list->add(mute, LLMute::flagVoiceChat);
diff --git a/indra/newview/llinspectgroup.cpp b/indra/newview/llinspectgroup.cpp
index fa8a53c5466db45f0bb051f6a2680db36b512f00..0a30ab92177a34eaec44f02850f8485f5a7f926e 100644
--- a/indra/newview/llinspectgroup.cpp
+++ b/indra/newview/llinspectgroup.cpp
@@ -38,7 +38,6 @@
 #include "llfloater.h"
 #include "llfloaterreg.h"
 #include "llresmgr.h"	// getMonetaryString()
-#include "lltooltip.h"	// positionViewNearMouse()
 #include "lltrans.h"
 #include "lluictrl.h"
 #include "llgroupiconctrl.h"
@@ -124,17 +123,7 @@ void LLInspectGroup::onOpen(const LLSD& data)
 
 	setGroupID(data["group_id"]);
 
-	// Position the inspector relative to the mouse cursor
-	// Similar to how tooltips are positioned
-	// See LLToolTipMgr::createToolTip
-	if (data.has("pos"))
-	{
-		LLUI::getInstance()->positionViewNearMouse(this, data["pos"]["x"].asInteger(), data["pos"]["y"].asInteger());
-	}
-	else
-	{
-		LLUI::getInstance()->positionViewNearMouse(this);
-	}
+	LLInspect::repositionInspector(data);
 
 	// can't call from constructor as widgets are not built yet
 	requestUpdate();
diff --git a/indra/newview/llinspectobject.cpp b/indra/newview/llinspectobject.cpp
index f78a5cc64e0c2b9a3b65a39f6e9a5517c30403f8..5329f1061248fc891cbe0ccc1c66c3323629339f 100644
--- a/indra/newview/llinspectobject.cpp
+++ b/indra/newview/llinspectobject.cpp
@@ -28,16 +28,17 @@
 #include "llinspectobject.h"
 
 // Viewer
+#include "llagent.h"            // To standup
 #include "llfloatersidepanelcontainer.h"
 #include "llinspect.h"
 #include "llmediaentry.h"
-#include "llnotificationsutil.h"	// *TODO: Eliminate, add LLNotificationsUtil wrapper
 #include "llselectmgr.h"
 #include "llslurl.h"
 #include "llviewermenu.h"		// handle_object_touch(), handle_buy()
 #include "llviewermedia.h"
 #include "llviewermediafocus.h"
 #include "llviewerobjectlist.h"	// to select the requested object
+#include "llvoavatarself.h"
 
 // Linden libraries
 #include "llbutton.h"			// setLabel(), not virtual!
@@ -49,7 +50,6 @@
 #include "lltextbox.h"			// for description truncation
 #include "lltoggleablemenu.h"
 #include "lltrans.h"
-#include "llui.h"				// positionViewNearMouse()
 #include "lluictrl.h"
 
 class LLViewerObject;
@@ -197,17 +197,8 @@ void LLInspectObject::onOpen(const LLSD& data)
 	{
 		mObjectFace = data["object_face"];
 	}
-	// Position the inspector relative to the mouse cursor
-	// Similar to how tooltips are positioned
-	// See LLToolTipMgr::createToolTip
-	if (data.has("pos"))
-	{
-		LLUI::getInstance()->positionViewNearMouse(this, data["pos"]["x"].asInteger(), data["pos"]["y"].asInteger());
-	}
-	else
-	{
-		LLUI::getInstance()->positionViewNearMouse(this);
-	}
+
+	LLInspect::repositionInspector(data);
 
 	// Promote hovered object to a complete selection, which will also force
 	// a request for selected object data off the network
@@ -635,7 +626,31 @@ void LLInspectObject::onClickTouch()
 
 void LLInspectObject::onClickSit()
 {
-	handle_object_sit_or_stand();
+    bool is_sitting = false;
+    if (mObjectSelection)
+    {
+        LLSelectNode* node = mObjectSelection->getFirstRootNode();
+        if (node && node->mValid)
+        {
+            LLViewerObject* root_object = node->getObject();
+            if (root_object
+                && isAgentAvatarValid()
+                && gAgentAvatarp->isSitting()
+                && gAgentAvatarp->getRoot() == root_object)
+            {
+                is_sitting = true;
+            }
+        }
+    }
+
+    if (is_sitting)
+    {
+        gAgent.standUp();
+    }
+    else
+    {
+        handle_object_sit(mObjectID);
+    }
 	closeFloater();
 }
 
diff --git a/indra/newview/llinspectremoteobject.cpp b/indra/newview/llinspectremoteobject.cpp
index 272c8acbd5b8fc0d683b52d0af7bb00ea1c9f6cc..77320510a6dd305e0498f0e25ff799edce084522 100644
--- a/indra/newview/llinspectremoteobject.cpp
+++ b/indra/newview/llinspectremoteobject.cpp
@@ -111,17 +111,7 @@ void LLInspectRemoteObject::onOpen(const LLSD& data)
 	// update the inspector with the current object state
 	update();
 
-	// Position the inspector relative to the mouse cursor
-	// Similar to how tooltips are positioned
-	// See LLToolTipMgr::createToolTip
-	if (data.has("pos"))
-	{
-		LLUI::getInstance()->positionViewNearMouse(this, data["pos"]["x"].asInteger(), data["pos"]["y"].asInteger());
-	}
-	else
-	{
-		LLUI::getInstance()->positionViewNearMouse(this);
-	}
+	LLInspect::repositionInspector(data);
 }
 
 void LLInspectRemoteObject::onClickMap()
diff --git a/indra/newview/llinspecttoast.cpp b/indra/newview/llinspecttoast.cpp
index d0034eff1346ea0bfdc34aef61576cc6251626ad..68801b08951b622e828d6c731d9f303b56b0157c 100644
--- a/indra/newview/llinspecttoast.cpp
+++ b/indra/newview/llinspecttoast.cpp
@@ -110,7 +110,7 @@ void LLInspectToast::onOpen(const LLSD& notification_id)
 	panel_rect = panel->getRect();
 	reshape(panel_rect.getWidth(), panel_rect.getHeight());
 
-	LLUI::getInstance()->positionViewNearMouse(this);
+	LLInspect::repositionInspector(notification_id);
 }
 
 // virtual
diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp
index 342920630b70eacf13191444f343653806a53cec..a0bc1035bfecbb0ac5650682dde81e54fb259810 100644
--- a/indra/newview/llinventorybridge.cpp
+++ b/indra/newview/llinventorybridge.cpp
@@ -792,6 +792,19 @@ void LLInvFVBridge::getClipboardEntries(bool show_asset_id,
 			disabled_items.push_back(std::string("Copy"));
 		}
 
+        if (isAgentInventory())
+        {
+            items.push_back(std::string("New folder from selected"));
+            items.push_back(std::string("Subfolder Separator"));
+            std::set<LLUUID> selected_uuid_set = LLAvatarActions::getInventorySelectedUUIDs();
+            uuid_vec_t ids;
+            std::copy(selected_uuid_set.begin(), selected_uuid_set.end(), std::back_inserter(ids));
+            if (!is_only_items_selected(ids) && !is_only_cats_selected(ids))
+            {
+                disabled_items.push_back(std::string("New folder from selected"));
+            }
+        }
+
 		if (obj->getIsLinkType())
 		{
 			items.push_back(std::string("Find Original"));
@@ -1102,7 +1115,10 @@ void LLInvFVBridge::addMarketplaceContextMenuOptions(U32 flags,
         LLInventoryModel::cat_array_t categories;
         LLInventoryModel::item_array_t items;
         gInventory.collectDescendents(local_version_folder_id, categories, items, FALSE);
-        if (categories.size() >= gSavedSettings.getU32("InventoryOutboxMaxFolderCount"))
+        LLCachedControl<U32> max_depth(gSavedSettings, "InventoryOutboxMaxFolderDepth", 4);
+        LLCachedControl<U32> max_count(gSavedSettings, "InventoryOutboxMaxFolderCount", 20);
+        if (categories.size() >= max_count
+            || depth > (max_depth + 1))
         {
             disabled_items.push_back(std::string("New Folder"));
         }
@@ -3798,7 +3814,20 @@ void LLFolderBridge::perform_pasteFromClipboard()
 				{
 					if (item && can_move_to_landmarks(item))
 					{
-						dropToFavorites(item);
+                        if (LLClipboard::instance().isCutMode())
+                        {
+                            LLViewerInventoryItem* viitem = dynamic_cast<LLViewerInventoryItem*>(item);
+                            llassert(viitem);
+                            if (viitem)
+                            {
+                                //changeItemParent() implicity calls dirtyFilter
+                                changeItemParent(model, viitem, parent_id, FALSE);
+                            }
+                        }
+                        else
+                        {
+                            dropToFavorites(item);
+                        }
 					}
 				}
 				else if (LLClipboard::instance().isCutMode())
@@ -4266,7 +4295,16 @@ void LLFolderBridge::buildContextMenuFolderOptions(U32 flags,   menuentry_vec_t&
 			items.push_back(std::string("Conference Chat Folder"));
 			items.push_back(std::string("IM All Contacts In Folder"));
 		}
+
+        if (((flags & ITEM_IN_MULTI_SELECTION) == 0) && hasChildren())
+        {
+            items.push_back(std::string("Ungroup folder items"));
+        }
 	}
+    else
+    {
+        disabled_items.push_back(std::string("New folder from selected"));
+    }
 
 #ifndef LL_RELEASE_FOR_DOWNLOAD
 	if (LLFolderType::lookupIsProtectedType(type) && is_agent_inventory)
@@ -5755,14 +5793,14 @@ class LLCallingCardObserver : public LLFriendObserver
 public:
 	LLCallingCardObserver(LLCallingCardBridge* bridge) : mBridgep(bridge) {}
 	virtual ~LLCallingCardObserver() { mBridgep = NULL; }
-	virtual void changed(U32 mask)
-	{
-		mBridgep->refreshFolderViewItem();
-		if (mask & LLFriendObserver::ONLINE)
-		{
-			mBridgep->checkSearchBySuffixChanges();
-		}
-	}
+    virtual void changed(U32 mask)
+    {
+        if (mask & LLFriendObserver::ONLINE)
+        {
+            mBridgep->refreshFolderViewItem();
+            mBridgep->checkSearchBySuffixChanges();
+        }
+    }
 protected:
 	LLCallingCardBridge* mBridgep;
 };
@@ -5776,14 +5814,16 @@ LLCallingCardBridge::LLCallingCardBridge(LLInventoryPanel* inventory,
 										 const LLUUID& uuid ) :
 	LLItemBridge(inventory, root, uuid)
 {
-	mObserver = new LLCallingCardObserver(this);
-	LLAvatarTracker::instance().addObserver(mObserver);
+    mObserver = new LLCallingCardObserver(this);
+    mCreatorUUID = getItem()->getCreatorUUID();
+    LLAvatarTracker::instance().addParticularFriendObserver(mCreatorUUID, mObserver);
 }
 
 LLCallingCardBridge::~LLCallingCardBridge()
 {
-	LLAvatarTracker::instance().removeObserver(mObserver);
-	delete mObserver;
+    LLAvatarTracker::instance().removeParticularFriendObserver(mCreatorUUID, mObserver);
+
+    delete mObserver;
 }
 
 void LLCallingCardBridge::refreshFolderViewItem()
diff --git a/indra/newview/llinventorybridge.h b/indra/newview/llinventorybridge.h
index c21bfbd02d6786fa8df11fabd3d8defd4cfefc9a..0b0ef273e17438df0d8147ad20a5a1c47d3087c4 100644
--- a/indra/newview/llinventorybridge.h
+++ b/indra/newview/llinventorybridge.h
@@ -457,6 +457,7 @@ class LLCallingCardBridge : public LLItemBridge
 	void checkSearchBySuffixChanges();
 protected:
 	LLCallingCardObserver* mObserver;
+    LLUUID mCreatorUUID;
 };
 
 class LLNotecardBridge : public LLItemBridge
diff --git a/indra/newview/llinventoryfilter.cpp b/indra/newview/llinventoryfilter.cpp
index 3b5ba24b9f7cbd6a33ae5de8e1072bc05e00ce51..707ff2b7b6170ed66ec3ff69633bf9676a69beaa 100644
--- a/indra/newview/llinventoryfilter.cpp
+++ b/indra/newview/llinventoryfilter.cpp
@@ -48,8 +48,6 @@
 #include "llclipboard.h"
 #include "lltrans.h"
 
-LLTrace::BlockTimerStatHandle FT_FILTER_CLIPBOARD("Filter Clipboard");
-
 LLInventoryFilter::FilterOps::FilterOps(const Params& p)
 :	mFilterObjectTypes(p.object_types),
 	mFilterCategoryTypes(p.category_types),
@@ -506,7 +504,7 @@ bool LLInventoryFilter::checkAgainstClipboard(const LLUUID& object_id) const
 {
 	if (LLClipboard::instance().isCutMode())
 	{
-		LL_RECORD_BLOCK_TIME(FT_FILTER_CLIPBOARD);
+        LL_PROFILE_ZONE_SCOPED;
 		LLUUID current_id = object_id;
 		LLInventoryObject *current_object = gInventory.getObject(object_id);
 		while (current_id.notNull() && current_object)
diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp
index d239b23e83da281636e8f275bdf9cc57f9841ae5..27edc8148efc638062c5d43063048263b98f0c6c 100644
--- a/indra/newview/llinventoryfunctions.cpp
+++ b/indra/newview/llinventoryfunctions.cpp
@@ -1868,6 +1868,86 @@ void change_item_parent(const LLUUID& item_id, const LLUUID& new_parent_id)
 	}
 }
 
+void move_items_to_folder(const LLUUID& new_cat_uuid, const uuid_vec_t& selected_uuids)
+{
+    for (uuid_vec_t::const_iterator it = selected_uuids.begin(); it != selected_uuids.end(); ++it)
+    {
+        LLInventoryItem* inv_item = gInventory.getItem(*it);
+        if (inv_item)
+        {
+            change_item_parent(*it, new_cat_uuid);
+        }
+        else
+        {
+            LLInventoryCategory* inv_cat = gInventory.getCategory(*it);
+            if (inv_cat && !LLFolderType::lookupIsProtectedType(inv_cat->getPreferredType()))
+            {
+                gInventory.changeCategoryParent((LLViewerInventoryCategory*)inv_cat, new_cat_uuid, false);
+            }
+        }
+    }
+
+    LLFloater* floater_inventory = LLFloaterReg::getInstance("inventory");
+    if (!floater_inventory)
+    {
+        LL_WARNS() << "Could not find My Inventory floater" << LL_ENDL;
+        return;
+    }
+    LLSidepanelInventory *sidepanel_inventory =	LLFloaterSidePanelContainer::getPanel<LLSidepanelInventory>("inventory");
+    if (sidepanel_inventory)
+    {
+        if (sidepanel_inventory->getActivePanel())
+        {
+            sidepanel_inventory->getActivePanel()->setSelection(new_cat_uuid, TAKE_FOCUS_YES);
+            LLFolderViewItem* fv_folder = sidepanel_inventory->getActivePanel()->getItemByID(new_cat_uuid);
+            if (fv_folder)
+            {
+                fv_folder->setOpen(TRUE);
+            }
+        }
+    }
+}
+
+bool is_only_cats_selected(const uuid_vec_t& selected_uuids)
+{
+    for (uuid_vec_t::const_iterator it = selected_uuids.begin(); it != selected_uuids.end(); ++it)
+    {
+        LLInventoryCategory* inv_cat = gInventory.getCategory(*it);
+        if (!inv_cat)
+        {
+            return false;
+        }
+    }
+    return true;
+}
+
+bool is_only_items_selected(const uuid_vec_t& selected_uuids)
+{
+    for (uuid_vec_t::const_iterator it = selected_uuids.begin(); it != selected_uuids.end(); ++it)
+    {
+        LLViewerInventoryItem* inv_item = gInventory.getItem(*it);
+        if (!inv_item)
+        {
+            return false;
+        }
+    }
+    return true;
+}
+
+
+void move_items_to_new_subfolder(const uuid_vec_t& selected_uuids, const std::string& folder_name)
+{
+    LLInventoryObject* first_item = gInventory.getObject(*selected_uuids.begin());
+    if (!first_item)
+    {
+        return;
+    }
+
+    inventory_func_type func = boost::bind(&move_items_to_folder, _1, selected_uuids);
+    gInventory.createNewCategory(first_item->getParentUUID(), LLFolderType::FT_NONE, folder_name, func);
+
+}
+
 ///----------------------------------------------------------------------------
 /// LLInventoryCollectFunctor implementations
 ///----------------------------------------------------------------------------
@@ -2522,6 +2602,81 @@ void LLInventoryAction::doToSelected(LLInventoryModel* model, LLFolderView* root
     {
         (new LLDirPickerThread(boost::bind(&LLInventoryAction::saveMultipleTextures, _1, selected_items, model), std::string()))->getFile();
     }
+    else if ("new_folder_from_selected" == action)
+    {
+
+        LLInventoryObject* first_item = gInventory.getObject(*ids.begin());
+        if (!first_item)
+        {
+            return;
+        }
+        const LLUUID& parent_uuid = first_item->getParentUUID();
+        for (uuid_vec_t::const_iterator it = ids.begin(); it != ids.end(); ++it)
+        {
+            LLInventoryObject *item = gInventory.getObject(*it);
+            if (!item || item->getParentUUID() != parent_uuid)
+            {
+                LLNotificationsUtil::add("SameFolderRequired");
+                return;
+            }
+        }
+        
+        LLSD args;
+        args["DESC"] = LLTrans::getString("New Folder");
+ 
+        LLNotificationsUtil::add("CreateSubfolder", args, LLSD(),
+            [ids](const LLSD& notification, const LLSD& response)
+        {
+            S32 opt = LLNotificationsUtil::getSelectedOption(notification, response);
+            if (opt == 0)
+            {
+                std::string settings_name = response["message"].asString();
+
+                LLInventoryObject::correctInventoryName(settings_name);
+                if (settings_name.empty())
+                {
+                    settings_name = LLTrans::getString("New Folder");
+                }
+                move_items_to_new_subfolder(ids, settings_name);
+            }
+        });
+    }
+    else if ("ungroup_folder_items" == action)
+    {
+        if (selected_uuid_set.size() == 1)
+        {
+            LLInventoryCategory* inv_cat = gInventory.getCategory(*ids.begin());
+            if (!inv_cat || LLFolderType::lookupIsProtectedType(inv_cat->getPreferredType()))
+            {
+                return;
+            }
+            const LLUUID &new_cat_uuid = inv_cat->getParentUUID();
+            LLInventoryModel::cat_array_t* cat_array;
+            LLInventoryModel::item_array_t* item_array;
+            gInventory.getDirectDescendentsOf(inv_cat->getUUID(), cat_array, item_array);
+            LLInventoryModel::cat_array_t cats = *cat_array;
+            LLInventoryModel::item_array_t items = *item_array;
+
+            for (LLInventoryModel::cat_array_t::const_iterator cat_iter = cats.begin(); cat_iter != cats.end(); ++cat_iter)
+            {
+                LLViewerInventoryCategory* cat = *cat_iter;
+                if (cat)
+                {
+                    gInventory.changeCategoryParent(cat, new_cat_uuid, false);
+                }
+            }
+            for (LLInventoryModel::item_array_t::const_iterator item_iter = items.begin(); item_iter != items.end(); ++item_iter)
+            {
+                LLViewerInventoryItem* item = *item_iter;
+                if(item)
+                {
+                    gInventory.changeItemParent(item, new_cat_uuid, false);
+                }
+            }
+            gInventory.removeCategory(inv_cat->getUUID());
+            gInventory.notifyObservers();
+        }
+    }
     else
     {
         std::set<LLFolderViewItem*>::iterator set_iter;
diff --git a/indra/newview/llinventoryfunctions.h b/indra/newview/llinventoryfunctions.h
index 8915bfa1e050d26f224a88dc8b883ab6e83a4b68..ba9f157e47ba97b389c9a51d14a49c87d3a5fc36 100644
--- a/indra/newview/llinventoryfunctions.h
+++ b/indra/newview/llinventoryfunctions.h
@@ -93,6 +93,10 @@ LLUUID nested_parent_id(LLUUID cur_uuid, S32 depth);
 S32 compute_stock_count(LLUUID cat_uuid, bool force_count = false);
 
 void change_item_parent(const LLUUID& item_id, const LLUUID& new_parent_id);
+void move_items_to_new_subfolder(const uuid_vec_t& selected_uuids, const std::string& folder_name);
+void move_items_to_folder(const LLUUID& new_cat_uuid, const uuid_vec_t& selected_uuids);
+bool is_only_cats_selected(const uuid_vec_t& selected_uuids);
+bool is_only_items_selected(const uuid_vec_t& selected_uuids);
 
 /**                    Miscellaneous global functions
  **                                                                            **
diff --git a/indra/newview/llinventoryitemslist.cpp b/indra/newview/llinventoryitemslist.cpp
index 1dc1aa395e0de7e9da2ca75b7deb50373ce716ed..23129f7d441e1a38abe4e0ed076e64d71de63d16 100644
--- a/indra/newview/llinventoryitemslist.cpp
+++ b/indra/newview/llinventoryitemslist.cpp
@@ -133,11 +133,9 @@ void LLInventoryItemsList::idle(void* user_data)
 	}
 }
 
-LLTrace::BlockTimerStatHandle FTM_INVENTORY_ITEMS_REFRESH("Inventory List Refresh");
-
 void LLInventoryItemsList::refresh()
 {
-    LL_RECORD_BLOCK_TIME(FTM_INVENTORY_ITEMS_REFRESH);
+    LL_PROFILE_ZONE_SCOPED;
 
     switch (mRefreshState)
     {
diff --git a/indra/newview/llinventorylistitem.cpp b/indra/newview/llinventorylistitem.cpp
index 12bb609df8c5cc4c1776ffd5861407415419912f..de6a850b5705ad221a8ec77c9db95e42c71075e2 100644
--- a/indra/newview/llinventorylistitem.cpp
+++ b/indra/newview/llinventorylistitem.cpp
@@ -298,31 +298,41 @@ LLPanelInventoryListItemBase::LLPanelInventoryListItemBase(LLViewerInventoryItem
 	applyXUILayout(icon_params, this);
 
 	mIconCtrl = LLUICtrlFactory::create<LLIconCtrl>(icon_params);
-	if (mIconCtrl)
-	{
-		addChild(mIconCtrl);
-	}
-	else
+    if (!mIconCtrl)
 	{
 		LLIconCtrl::Params icon_params;
 		icon_params.name = "item_icon";
 		mIconCtrl = LLUICtrlFactory::create<LLIconCtrl>(icon_params);
 	}
 
+    if (mIconCtrl)
+    {
+        addChild(mIconCtrl);
+    }
+    else
+    {
+        LL_ERRS() << "Failed to create mIconCtrl" << LL_ENDL;
+    }
+
 	LLTextBox::Params text_params(params.item_name);
 	applyXUILayout(text_params, this);
 
 	mTitleCtrl = LLUICtrlFactory::create<LLTextBox>(text_params);
-	if (mTitleCtrl)
+	if (!mTitleCtrl)
 	{
-		addChild(mTitleCtrl);
-	}
-	else
-	{
-		LLTextBox::Params text_aprams;
+		LLTextBox::Params text_params;
 		text_params.name = "item_title";
 		mTitleCtrl = LLUICtrlFactory::create<LLTextBox>(text_params);
 	}
+
+    if (mTitleCtrl)
+    {
+        addChild(mTitleCtrl);
+    }
+    else
+    {
+        LL_ERRS() << "Failed to create mTitleCtrl" << LL_ENDL;
+    }
 }
 
 class WidgetVisibilityChanger
diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp
index 0594b1e4ae98e38aef8efa9449f7b00332dbf94b..48fedeb9f5792184ac89f5c8e90eb73f85f9f06b 100644
--- a/indra/newview/llinventorymodel.cpp
+++ b/indra/newview/llinventorymodel.cpp
@@ -135,19 +135,16 @@ bool LLCanCache::operator()(LLInventoryCategory* cat, LLInventoryItem* item)
 ///----------------------------------------------------------------------------
 /// Class LLInventoryValidationInfo
 ///----------------------------------------------------------------------------
-LLInventoryValidationInfo::LLInventoryValidationInfo():
-	mFatalErrorCount(0),
-	mWarningCount(0),
-	mInitialized(false),
-	mFatalNoRootFolder(false),
-	mFatalNoLibraryRootFolder(false),
-	mFatalQADebugMode(false)
+LLInventoryValidationInfo::LLInventoryValidationInfo()
 {
 }
 
 void LLInventoryValidationInfo::toOstream(std::ostream& os) const
 {
-	os << "mFatalErrorCount " << mFatalErrorCount << " mWarningCount " << mWarningCount;
+	os << "mFatalErrorCount " << mFatalErrorCount
+       << " mWarningCount " << mWarningCount
+       << " mLoopCount " << mLoopCount
+       << " mOrphanedCount " << mOrphanedCount;
 }
 
 
@@ -160,12 +157,27 @@ std::ostream& operator<<(std::ostream& os, const LLInventoryValidationInfo& v)
 void LLInventoryValidationInfo::asLLSD(LLSD& sd) const
 {
 	sd["fatal_error_count"] = mFatalErrorCount;
-	sd["warning_count"] = mWarningCount;
+    sd["loop_count"] = mLoopCount;
+    sd["orphaned_count"] = mOrphanedCount;
 	sd["initialized"] = mInitialized;
 	sd["missing_system_folders_count"] = LLSD::Integer(mMissingRequiredSystemFolders.size());
 	sd["fatal_no_root_folder"] = mFatalNoRootFolder;
 	sd["fatal_no_library_root_folder"] = mFatalNoLibraryRootFolder;
 	sd["fatal_qa_debug_mode"] = mFatalQADebugMode;
+
+	sd["warning_count"] = mWarningCount;
+	if (mWarningCount>0)
+	{
+		sd["warnings"] = LLSD::emptyArray();
+		for (auto const& it : mWarnings)
+		{
+			S32 val =LLSD::Integer(it.second);
+			if (val>0)
+			{
+				sd["warnings"][it.first] = val;
+			}
+		}
+	}
 	if (mMissingRequiredSystemFolders.size()>0)
 	{
 		sd["missing_system_folders"] = LLSD::emptyArray();
@@ -337,21 +349,35 @@ const LLViewerInventoryCategory* LLInventoryModel::getFirstDescendantOf(const LL
 	return NULL;
 }
 
-bool LLInventoryModel::getObjectTopmostAncestor(const LLUUID& object_id, LLUUID& result) const
+LLInventoryModel::EAncestorResult LLInventoryModel::getObjectTopmostAncestor(const LLUUID& object_id, LLUUID& result) const
 {
 	LLInventoryObject *object = getObject(object_id);
-	while (object && object->getParentUUID().notNull())
-	{
-		LLInventoryObject *parent_object = getObject(object->getParentUUID());
+    if (!object)
+    {
+        LL_WARNS(LOG_INV) << "Unable to trace topmost ancestor, initial object " << object_id << " does not exist" << LL_ENDL;
+        return ANCESTOR_MISSING;
+    }
+
+    std::set<LLUUID> object_ids{ object_id }; // loop protection
+    while (object->getParentUUID().notNull())
+    {
+        LLUUID parent_id = object->getParentUUID();
+        if (object_ids.find(parent_id) != object_ids.end())
+        {
+            LL_WARNS(LOG_INV) << "Detected a loop on an object " << parent_id << " when searching for ancestor of " << object_id << LL_ENDL;
+            return ANCESTOR_LOOP;
+        }
+        object_ids.insert(parent_id);
+        LLInventoryObject *parent_object = getObject(parent_id);
 		if (!parent_object)
 		{
-			LL_WARNS(LOG_INV) << "unable to trace topmost ancestor, missing item for uuid " << object->getParentUUID() << LL_ENDL;
-			return false;
+			LL_WARNS(LOG_INV) << "unable to trace topmost ancestor of " << object_id << ", missing item for uuid " << parent_id << LL_ENDL;
+			return ANCESTOR_MISSING;
 		}
 		object = parent_object;
 	}
 	result = object->getUUID();
-	return true;
+	return ANCESTOR_OK;
 }
 
 // Get the object by id. Returns NULL if not found.
@@ -545,9 +571,18 @@ void LLInventoryModel::consolidateForType(const LLUUID& main_id, LLFolderType::E
             LLViewerInventoryCategory* cat = getCategory(*it);
             changeCategoryParent(cat, main_id, TRUE);
         }
-        
+
         // Purge the emptied folder
-        removeCategory(folder_id);
+        // Note that this might be a system folder, don't validate removability
+        LLViewerInventoryCategory* cat = getCategory(folder_id);
+        if (cat)
+        {
+            const LLUUID trash_id = findCategoryUUIDForType(LLFolderType::FT_TRASH);
+            if (trash_id.notNull())
+            {
+                changeCategoryParent(cat, trash_id, TRUE);
+            }
+        }
         remove_inventory_category(folder_id, NULL);
 	}
 }
@@ -2972,42 +3007,69 @@ bool LLInventoryModel::saveToFile(const std::string& filename,
 
 	LL_INFOS(LOG_INV) << "saving inventory to: (" << filename << ")" << LL_ENDL;
 
-	llofstream fileXML(filename.c_str());
-	if (!fileXML.is_open())
-	{
-		LL_WARNS(LOG_INV) << "unable to save inventory to: " << filename << LL_ENDL;
-		return false;
-	}
+    try
+    {
+        llofstream fileXML(filename.c_str());
+        if (!fileXML.is_open())
+        {
+            LL_WARNS(LOG_INV) << "Failed to open file. Unable to save inventory to: " << filename << LL_ENDL;
+            return false;
+        }
+
+        LLSD cache_ver;
+        cache_ver["inv_cache_version"] = sCurrentInvCacheVersion;
 
-	LLSD cache_ver;
-	cache_ver["inv_cache_version"] = sCurrentInvCacheVersion;
+        if (fileXML.fail())
+        {
+            LL_WARNS(LOG_INV) << "Failed to write cache version to file. Unable to save inventory to: " << filename << LL_ENDL;
+            return false;
+        }
 
-	fileXML << LLSDOStreamer<LLSDNotationFormatter>(cache_ver) << std::endl;
+        fileXML << LLSDOStreamer<LLSDNotationFormatter>(cache_ver) << std::endl;
 
-	S32 count = categories.size();
-	S32 cat_count = 0;
-	S32 i;
-	for(i = 0; i < count; ++i)
-	{
-		LLViewerInventoryCategory* cat = categories[i];
-		if(cat->getVersion() != LLViewerInventoryCategory::VERSION_UNKNOWN)
-		{
-			fileXML << LLSDOStreamer<LLSDNotationFormatter>(cat->exportLLSD()) << std::endl;
-			cat_count++;
-		}
-	}
+        S32 count = categories.size();
+        S32 cat_count = 0;
+        S32 i;
+        for (i = 0; i < count; ++i)
+        {
+            LLViewerInventoryCategory* cat = categories[i];
+            if (cat->getVersion() != LLViewerInventoryCategory::VERSION_UNKNOWN)
+            {
+                fileXML << LLSDOStreamer<LLSDNotationFormatter>(cat->exportLLSD()) << std::endl;
+                cat_count++;
+            }
 
-	S32 it_count = items.size();
-	for(i = 0; i < it_count; ++i)
-	{
-		fileXML << LLSDOStreamer<LLSDNotationFormatter>(items[i]->asLLSD()) << std::endl;
-	}
+            if (fileXML.fail())
+            {
+                LL_WARNS(LOG_INV) << "Failed to write a folder to file. Unable to save inventory to: " << filename << LL_ENDL;
+                return false;
+            }
+        }
+
+        S32 it_count = items.size();
+        for (i = 0; i < it_count; ++i)
+        {
+            fileXML << LLSDOStreamer<LLSDNotationFormatter>(items[i]->asLLSD()) << std::endl;
 
-	fileXML.close();
+            if (fileXML.fail())
+            {
+                LL_WARNS(LOG_INV) << "Failed to write an item to file. Unable to save inventory to: " << filename << LL_ENDL;
+                return false;
+            }
+        }
 
-	LL_INFOS(LOG_INV) << "Inventory saved: " << cat_count << " categories, " << it_count << " items." << LL_ENDL;
+        fileXML.close();
 
-	return true;
+        LL_INFOS(LOG_INV) << "Inventory saved: " << cat_count << " categories, " << it_count << " items." << LL_ENDL;
+    }
+    catch (...)
+    {
+        LOG_UNHANDLED_EXCEPTION("");
+        LL_INFOS(LOG_INV) << "Failed to save inventory to: (" << filename << ")" << LL_ENDL;
+        return false;
+    }
+
+    return true;
 }
 
 // message handling functionality
@@ -3109,7 +3171,6 @@ bool LLInventoryModel::messageUpdateCore(LLMessageSystem* msg, bool account, U32
 		gInventory.accountForUpdate(update);
 	}
 
-	U32 changes = 0x0;
 	if (account)
 	{
 		mask |= LLInventoryObserver::CREATE;
@@ -3117,7 +3178,7 @@ bool LLInventoryModel::messageUpdateCore(LLMessageSystem* msg, bool account, U32
 	//as above, this loop never seems to loop more than once per call
 	for (item_array_t::iterator it = items.begin(); it != items.end(); ++it)
 	{
-		changes |= gInventory.updateItem(*it, mask);
+		gInventory.updateItem(*it, mask);
 	}
 	gInventory.notifyObservers();
 	gViewerWindow->getWindow()->decBusyCount();
@@ -3875,20 +3936,23 @@ void LLInventoryModel::dumpInventory() const
 LLPointer<LLInventoryValidationInfo> LLInventoryModel::validate() const
 {
 	LLPointer<LLInventoryValidationInfo> validation_info = new LLInventoryValidationInfo;
-	S32 fatalities = 0;
-	S32 warnings = 0;
+	S32 fatal_errs = 0;
+	S32 warning_count= 0;
+    S32 loop_count = 0;
+    S32 orphaned_count = 0;
 
 	if (getRootFolderID().isNull())
 	{
 		LL_WARNS("Inventory") << "Fatal inventory corruption: no root folder id" << LL_ENDL;
 		validation_info->mFatalNoRootFolder = true;
-		fatalities++;
+        fatal_errs++;
 	}
 	if (getLibraryRootFolderID().isNull())
 	{
+        // Probably shouldn't be a fatality, inventory can function without a library 
 		LL_WARNS("Inventory") << "Fatal inventory corruption: no library root folder id" << LL_ENDL;
 		validation_info->mFatalNoLibraryRootFolder = true;
-		fatalities++;
+        fatal_errs++;
 	}
 
 	if (mCategoryMap.size() + 1 != mParentChildCategoryTree.size())
@@ -3896,7 +3960,9 @@ LLPointer<LLInventoryValidationInfo> LLInventoryModel::validate() const
 		// ParentChild should be one larger because of the special entry for null uuid.
 		LL_INFOS("Inventory") << "unexpected sizes: cat map size " << mCategoryMap.size()
 							  << " parent/child " << mParentChildCategoryTree.size() << LL_ENDL;
-		warnings++;
+
+		validation_info->mWarnings["category_map_size"]++;
+		warning_count++;
 	}
 	S32 cat_lock = 0;
 	S32 item_lock = 0;
@@ -3915,16 +3981,35 @@ LLPointer<LLInventoryValidationInfo> LLInventoryModel::validate() const
 		if (!cat)
 		{
 			LL_WARNS("Inventory") << "null cat" << LL_ENDL;
-			warnings++;
+			validation_info->mWarnings["null_cat"]++;
+			warning_count++;
 			continue;
 		}
 		LLUUID topmost_ancestor_id;
 		// Will leave as null uuid on failure
-		getObjectTopmostAncestor(cat_id, topmost_ancestor_id);
+        EAncestorResult res = getObjectTopmostAncestor(cat_id, topmost_ancestor_id);
+        switch (res)
+        {
+        case ANCESTOR_MISSING:
+            orphaned_count++;
+            break;
+        case ANCESTOR_LOOP:
+            loop_count++;
+            break;
+        case ANCESTOR_OK:
+            break;
+        default:
+            LL_WARNS("Inventory") << "Unknown ancestor error for " << cat_id << LL_ENDL;
+			validation_info->mWarnings["unknown_ancestor_status"]++;
+            warning_count++;
+            break;
+        }
+
 		if (cat_id != cat->getUUID())
 		{
 			LL_WARNS("Inventory") << "cat id/index mismatch " << cat_id << " " << cat->getUUID() << LL_ENDL;
-			warnings++;
+			validation_info->mWarnings["cat_id_index_mismatch"]++;
+			warning_count++;
 		}
 
 		if (cat->getParentUUID().isNull())
@@ -3934,7 +4019,8 @@ LLPointer<LLInventoryValidationInfo> LLInventoryModel::validate() const
 				LL_WARNS("Inventory") << "cat " << cat_id << " has no parent, but is not root ("
 									  << getRootFolderID() << ") or library root ("
 									  << getLibraryRootFolderID() << ")" << LL_ENDL;
-				warnings++;
+				validation_info->mWarnings["null_parent"]++;
+				warning_count++;
 			}
 		}
 		cat_array_t* cats;
@@ -3943,7 +4029,8 @@ LLPointer<LLInventoryValidationInfo> LLInventoryModel::validate() const
 		if (!cats || !items)
 		{
 			LL_WARNS("Inventory") << "invalid direct descendents for " << cat_id << LL_ENDL;
-			warnings++;
+			validation_info->mWarnings["direct_descendents"]++;
+			warning_count++;
 			continue;
 		}
 		if (cat->getDescendentCount() == LLViewerInventoryCategory::DESCENDENT_COUNT_UNKNOWN)
@@ -3961,7 +4048,8 @@ LLPointer<LLInventoryValidationInfo> LLInventoryModel::validate() const
 									  << " cached " << cat->getDescendentCount()
 									  << " expected " << cats->size() << "+" << items->size()
 									  << "=" << cats->size() +items->size() << LL_ENDL;
-				warnings++;
+				validation_info->mWarnings["invalid_descendent_count"]++;
+				warning_count++;
 			}
 		}
 		if (cat->getVersion() == LLViewerInventoryCategory::VERSION_UNKNOWN)
@@ -3985,7 +4073,8 @@ LLPointer<LLInventoryValidationInfo> LLInventoryModel::validate() const
 			if (!item)
 			{
 				LL_WARNS("Inventory") << "null item at index " << i << " for cat " << cat_id << LL_ENDL;
-				warnings++;
+				validation_info->mWarnings["null_item_at_index"]++;
+				warning_count++;
 				continue;
 			}
 
@@ -3996,7 +4085,8 @@ LLPointer<LLInventoryValidationInfo> LLInventoryModel::validate() const
 				LL_WARNS("Inventory") << "wrong parent for " << item_id << " found "
 									  << item->getParentUUID() << " expected " << cat_id
 									  << LL_ENDL;
-				warnings++;
+				validation_info->mWarnings["wrong_parent_for_item"]++;
+				warning_count++;
 			}
 
 
@@ -4006,7 +4096,8 @@ LLPointer<LLInventoryValidationInfo> LLInventoryModel::validate() const
 			{
 				LL_WARNS("Inventory") << "item " << item_id << " found as child of "
 									  << cat_id << " but not in top level mItemMap" << LL_ENDL;
-				warnings++;
+				validation_info->mWarnings["item_not_in_top_map"]++;
+				warning_count++;
 			}
 			else
 			{
@@ -4020,11 +4111,12 @@ LLPointer<LLInventoryValidationInfo> LLInventoryModel::validate() const
 
 			// Topmost ancestor should be root or library.
 			LLUUID topmost_ancestor_id;
-			bool found = getObjectTopmostAncestor(item_id, topmost_ancestor_id);
-			if (!found)
+            EAncestorResult found = getObjectTopmostAncestor(item_id, topmost_ancestor_id);
+			if (found != ANCESTOR_OK)
 			{
 				LL_WARNS("Inventory") << "unable to find topmost ancestor for " << item_id << LL_ENDL;
-				warnings++;
+				validation_info->mWarnings["topmost_ancestor_not_found"]++;
+				warning_count++;
 			}
 			else
 			{
@@ -4035,7 +4127,8 @@ LLPointer<LLInventoryValidationInfo> LLInventoryModel::validate() const
 										  << " got " << topmost_ancestor_id
 										  << " expected " << getRootFolderID()
 										  << " or " << getLibraryRootFolderID() << LL_ENDL;
-					warnings++;
+					validation_info->mWarnings["topmost_ancestor_not_recognized"]++;
+					warning_count++;
 				}
 			}
 		}
@@ -4051,7 +4144,7 @@ LLPointer<LLInventoryValidationInfo> LLInventoryModel::validate() const
 			{
 				LL_WARNS("Inventory") << "cat " << cat_id << " name [" << cat->getName()
 									  << "] orphaned - no child cat array for alleged parent " << parent_id << LL_ENDL;
-				warnings++;
+                orphaned_count++;
 			}
 			else
 			{
@@ -4069,6 +4162,7 @@ LLPointer<LLInventoryValidationInfo> LLInventoryModel::validate() const
 				{
 					LL_WARNS("Inventory") << "cat " << cat_id << " name [" << cat->getName()
 										  << "] orphaned - not found in child cat array of alleged parent " << parent_id << LL_ENDL;
+                    orphaned_count++;
 				}
 			}
 		}
@@ -4077,7 +4171,7 @@ LLPointer<LLInventoryValidationInfo> LLInventoryModel::validate() const
 		LLFolderType::EType folder_type = cat->getPreferredType();
 		bool cat_is_in_library = false;
 		LLUUID topmost_id;
-		if (getObjectTopmostAncestor(cat->getUUID(),topmost_id) && topmost_id == getLibraryRootFolderID())
+		if (getObjectTopmostAncestor(cat->getUUID(),topmost_id) == ANCESTOR_OK && topmost_id == getLibraryRootFolderID())
 		{
 			cat_is_in_library = true;
 		}
@@ -4110,13 +4204,15 @@ LLPointer<LLInventoryValidationInfo> LLInventoryModel::validate() const
 		if (item->getUUID() != item_id)
 		{
 			LL_WARNS("Inventory") << "item_id " << item_id << " does not match " << item->getUUID() << LL_ENDL;
-			warnings++;
+			validation_info->mWarnings["item_id_mismatch"]++;
+			warning_count++;
 		}
 
 		const LLUUID& parent_id = item->getParentUUID();
 		if (parent_id.isNull())
 		{
 			LL_WARNS("Inventory") << "item " << item_id << " name [" << item->getName() << "] has null parent id!" << LL_ENDL;
+            orphaned_count++;
 		}
 		else
 		{
@@ -4127,6 +4223,7 @@ LLPointer<LLInventoryValidationInfo> LLInventoryModel::validate() const
 			{
 				LL_WARNS("Inventory") << "item " << item_id << " name [" << item->getName()
 									  << "] orphaned - alleged parent has no child items list " << parent_id << LL_ENDL;
+                orphaned_count++;
 			}
 			else
 			{
@@ -4143,6 +4240,7 @@ LLPointer<LLInventoryValidationInfo> LLInventoryModel::validate() const
 				{
 					LL_WARNS("Inventory") << "item " << item_id << " name [" << item->getName()
 										  << "] orphaned - not found as child of alleged parent " << parent_id << LL_ENDL;
+                    orphaned_count++;
 				}
 			}
 				
@@ -4160,15 +4258,18 @@ LLPointer<LLInventoryValidationInfo> LLInventoryModel::validate() const
 				LL_WARNS("Inventory") << "link " << item->getUUID() << " type " << item->getActualType()
 									  << " missing backlink info at target_id " << target_id
 									  << LL_ENDL;
+                orphaned_count++;
 			}
 			// Links should have referents.
 			if (item->getActualType() == LLAssetType::AT_LINK && !target_item)
 			{
 				LL_WARNS("Inventory") << "broken item link " << item->getName() << " id " << item->getUUID() << LL_ENDL;
+                orphaned_count++;
 			}
 			else if (item->getActualType() == LLAssetType::AT_LINK_FOLDER && !target_cat)
 			{
 				LL_WARNS("Inventory") << "broken folder link " << item->getName() << " id " << item->getUUID() << LL_ENDL;
+                orphaned_count++;
 			}
 			if (target_item && target_item->getIsLinkType())
 			{
@@ -4240,25 +4341,42 @@ LLPointer<LLInventoryValidationInfo> LLInventoryModel::validate() const
 				if (is_automatic)
 				{
 					LL_WARNS("Inventory") << "Fatal inventory corruption: cannot create system folder of type " << ft << LL_ENDL;
-					fatalities++;
-					validation_info->mMissingRequiredSystemFolders.insert(LLFolderType::EType(ft));
+					validation_info->mMissingRequiredSystemFolders.insert(folder_type);
+                    fatal_errs++;
 				}
 				else
 				{
 					// Can create, and will when needed.
-					warnings++;
+					// (Not sure this is really a warning, but worth logging)
+					validation_info->mWarnings["missing_system_folder_can_create"]++;
+					warning_count++;
 				}
 			}
 			else if (count_under_root > 1)
 			{
 				LL_WARNS("Inventory") << "Fatal inventory corruption: system folder type has excess copies under root, type " << ft << " count " << count_under_root << LL_ENDL;
-				validation_info->mDuplicateRequiredSystemFolders.insert(LLFolderType::EType(ft));
-				fatalities++;
+				validation_info->mDuplicateRequiredSystemFolders.insert(folder_type);
+                if (!is_automatic && folder_type != LLFolderType::FT_SETTINGS)
+                {
+                    // It is a fatal problem or can lead to fatal problems for COF,
+                    // outfits, trash and other non-automatic folders.
+					validation_info->mFatalSystemDuplicate++;
+                    fatal_errs++;
+                }
+                else
+                {
+                    // For automatic folders it's not a fatal issue and shouldn't
+                    // break inventory or other functionality further
+                    // Exception: FT_SETTINGS is not automatic, but only deserves a warning.
+					validation_info->mWarnings["non_fatal_system_duplicate_under_root"]++;
+                    warning_count++;
+                }
 			}
 			if (count_elsewhere > 0)
 			{
 				LL_WARNS("Inventory") << "Found " << count_elsewhere << " extra folders of type " << ft << " outside of root" << LL_ENDL;
-				warnings++;
+				validation_info->mWarnings["non_fatal_system_duplicate_elsewhere"]++;
+				warning_count++;
 			}
 		}
 	}
@@ -4279,11 +4397,13 @@ LLPointer<LLInventoryValidationInfo> LLInventoryModel::validate() const
 	}
 
 	// FIXME need to fail login and tell user to retry, contact support if problem persists.
-	bool valid = (fatalities == 0);
-	LL_INFOS("Inventory") << "Validate done, fatal errors: " << fatalities << ", warnings: " << warnings << ", valid: " << valid << LL_ENDL;
+	bool valid = (fatal_errs == 0);
+	LL_INFOS("Inventory") << "Validate done, fatal errors: " << fatal_errs << ", warnings: " << warning_count << ", valid: " << valid << LL_ENDL;
 
-	validation_info->mFatalErrorCount = fatalities;
-	validation_info->mWarningCount = warnings;
+	validation_info->mFatalErrorCount = fatal_errs;
+	validation_info->mWarningCount = warning_count;
+    validation_info->mLoopCount = loop_count;
+    validation_info->mOrphanedCount = orphaned_count;
 
 	return validation_info; 
 }
@@ -4488,12 +4608,10 @@ void LLInventoryModel::FetchItemHttpHandler::processData(LLSD & content, LLCore:
 	}
 
 	// as above, this loop never seems to loop more than once per call
-	U32 changes(0U);
 	for (LLInventoryModel::item_array_t::iterator it = items.begin(); it != items.end(); ++it)
 	{
-		changes |= gInventory.updateItem(*it);
+		gInventory.updateItem(*it);
 	}
-	// *HUH:  Have computed 'changes', nothing uses it.
 	
 	gInventory.notifyObservers();
 	gViewerWindow->getWindow()->decBusyCount();
diff --git a/indra/newview/llinventorymodel.h b/indra/newview/llinventorymodel.h
index 0b0a56844285b1fd8c3e7df2b982f8138b29970f..b03181d646e151e973da8fb305becf586e097036 100644
--- a/indra/newview/llinventorymodel.h
+++ b/indra/newview/llinventorymodel.h
@@ -65,13 +65,19 @@ class LLInventoryValidationInfo: public LLRefCount
 	void toOstream(std::ostream& os) const;
 	void asLLSD(LLSD& sd) const;
 	
+	bool mInitialized{false};
+	S32 mWarningCount{0};
+	std::map<std::string,U32> mWarnings;
+
+    S32 mLoopCount{0}; // Presence of folders whose ancestors loop onto themselves
+    S32 mOrphanedCount{0}; // Missing or orphaned items, links and folders
+
+	S32 mFatalErrorCount{0};
+	bool mFatalNoRootFolder{false};
+	S32 mFatalSystemDuplicate{0};
+	bool mFatalNoLibraryRootFolder{false};
+	bool mFatalQADebugMode{false};
 
-	S32 mFatalErrorCount;
-	S32 mWarningCount;
-	bool mInitialized;
-	bool mFatalNoRootFolder;
-	bool mFatalNoLibraryRootFolder;
-	bool mFatalQADebugMode;
 	std::set<LLFolderType::EType> mMissingRequiredSystemFolders;
 	std::set<LLFolderType::EType> mDuplicateRequiredSystemFolders;
 };
@@ -284,9 +290,14 @@ class LLInventoryModel
 
 	// Check if one object has a parent chain up to the category specified by UUID.
 	BOOL isObjectDescendentOf(const LLUUID& obj_id, const LLUUID& cat_id) const;
-
+    
+    enum EAncestorResult{
+        ANCESTOR_OK = 0,
+        ANCESTOR_MISSING = 1,
+        ANCESTOR_LOOP = 2,
+    };
 	// Follow parent chain to the top.
-	bool getObjectTopmostAncestor(const LLUUID& object_id, LLUUID& result) const;
+    EAncestorResult getObjectTopmostAncestor(const LLUUID& object_id, LLUUID& result) const;
 
 	//--------------------------------------------------------------------
 	// Find
diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp
index 883473efa0cab4b765c4a6dbe879bf6caad4ec0d..dabe633b8c3e112a27a158f2054ad466e18843e7 100644
--- a/indra/newview/llinventorypanel.cpp
+++ b/indra/newview/llinventorypanel.cpp
@@ -689,10 +689,9 @@ void LLInventoryPanel::itemChanged(const LLUUID& item_id, U32 mask, const LLInve
 }
 
 // Called when something changed in the global model (new item, item coming through the wire, rename, move, etc...) (CHUI-849)
-static LLTrace::BlockTimerStatHandle FTM_REFRESH("Inventory Refresh");
 void LLInventoryPanel::modelChanged(U32 mask)
 {
-	LL_RECORD_BLOCK_TIME(FTM_REFRESH);
+    LL_PROFILE_ZONE_SCOPED;
 
 	if (mViewsInitialized != VIEWS_INITIALIZED) return;
 	
@@ -1858,10 +1857,9 @@ void LLInventoryPanel::removeItemID(const LLUUID& id)
 	}
 }
 
-LLTrace::BlockTimerStatHandle FTM_GET_ITEM_BY_ID("Get FolderViewItem by ID");
 LLFolderViewItem* LLInventoryPanel::getItemByID(const LLUUID& id)
 {
-	LL_RECORD_BLOCK_TIME(FTM_GET_ITEM_BY_ID);
+    LL_PROFILE_ZONE_SCOPED;
 
 	std::map<LLUUID, LLFolderViewItem*>::iterator map_it;
 	map_it = mItemMap.find(id);
diff --git a/indra/newview/llkeyconflict.cpp b/indra/newview/llkeyconflict.cpp
index b5ac94b1cd5d43d9744d8f52b1547c6f0aaf5976..d3ba18525be1803413e773660660a2ffc2547d09 100644
--- a/indra/newview/llkeyconflict.cpp
+++ b/indra/newview/llkeyconflict.cpp
@@ -411,8 +411,16 @@ void LLKeyConflictHandler::loadFromSettings(ESourceMode load_mode)
         filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, filename_default);
         if (!gDirUtilp->fileExists(filename) || !loadFromSettings(load_mode, filename, &mControlsMap))
         {
-            // mind placeholders
-            mControlsMap.insert(mDefaultsMap.begin(), mDefaultsMap.end());
+            // Mind placeholders
+            // Do not use mControlsMap.insert(mDefaultsMap) since mControlsMap has
+            // placeholders that won't be added over(to) by insert.
+            // Or instead move generatePlaceholders call to be after copying
+            control_map_t::iterator iter = mDefaultsMap.begin();
+            while (iter != mDefaultsMap.end())
+            {
+                mControlsMap[iter->first].mKeyBind = iter->second.mKeyBind;
+                iter++;
+            }
         }
     }
     mLoadMode = load_mode;
@@ -575,6 +583,8 @@ void LLKeyConflictHandler::saveToSettings(bool temporary)
                 break;
             }
 
+            keys.xml_version.set(keybindings_xml_version, true);
+
             if (temporary)
             {
                 // write to temporary xml and use it for gViewerInput
@@ -667,13 +677,19 @@ void LLKeyConflictHandler::resetToDefault(const std::string &control_name, U32 i
     {
         return;
     }
+    LLKeyConflict &type_data = mControlsMap[control_name];
+    if (!type_data.mAssignable)
+    {
+        return;
+    }
     LLKeyData data = getDefaultControl(control_name, index);
 
-    if (data != mControlsMap[control_name].getKeyData(index))
+    if (data != type_data.getKeyData(index))
     {
         // reset controls that might have been switched to our current control
         removeConflicts(data, mControlsMap[control_name].mConflictMask);
         mControlsMap[control_name].setKeyData(data, index);
+        mHasUnsavedChanges = true;
     }
 }
 
@@ -730,9 +746,9 @@ void LLKeyConflictHandler::resetToDefault(const std::string &control_name)
     resetToDefaultAndResolve(control_name, false);
 }
 
-void LLKeyConflictHandler::resetToDefaults(ESourceMode mode)
+void LLKeyConflictHandler::resetToDefaultsAndResolve()
 {
-    if (mode == MODE_SAVED_SETTINGS)
+    if (mLoadMode == MODE_SAVED_SETTINGS)
     {
         control_map_t::iterator iter = mControlsMap.begin();
         control_map_t::iterator end = mControlsMap.end();
@@ -745,8 +761,16 @@ void LLKeyConflictHandler::resetToDefaults(ESourceMode mode)
     else
     {
         mControlsMap.clear();
-        generatePlaceholders(mode);
+
+        // Set key combinations.
+        // Copy from mDefaultsMap before doing generatePlaceholders, otherwise
+        // insert() will fail to add some keys into pre-existing values from
+        // generatePlaceholders()
         mControlsMap.insert(mDefaultsMap.begin(), mDefaultsMap.end());
+
+        // Set conflict masks and mark functions (un)assignable
+        generatePlaceholders(mLoadMode);
+
     }
 
     mHasUnsavedChanges = true;
@@ -756,7 +780,7 @@ void LLKeyConflictHandler::resetToDefaults()
 {
     if (!empty())
     {
-        resetToDefaults(mLoadMode);
+        resetToDefaultsAndResolve();
     }
     else
     {
@@ -766,7 +790,7 @@ void LLKeyConflictHandler::resetToDefaults()
         // 3. We are loading 'current' only to replace it
         // but it is reliable and works Todo: consider optimizing.
         loadFromSettings(mLoadMode);
-        resetToDefaults(mLoadMode);
+        resetToDefaultsAndResolve();
     }
 }
 
@@ -799,7 +823,7 @@ void LLKeyConflictHandler::resetKeyboardBindings()
 
 void LLKeyConflictHandler::generatePlaceholders(ESourceMode load_mode)
 {
-    // These controls are meant to cause conflicts when user tries to assign same control somewhere else
+    // These placeholders are meant to cause conflict resolution when user tries to assign same control somewhere else
     // also this can be used to pre-record controls that should not conflict or to assign conflict groups/masks
 
     if (load_mode == MODE_FIRST_PERSON)
@@ -859,24 +883,60 @@ void LLKeyConflictHandler::generatePlaceholders(ESourceMode load_mode)
         registerTemporaryControl("spin_around_ccw_sitting");
         registerTemporaryControl("spin_around_cw_sitting");
     }
+
+
+    // Special case, mouse clicks passed to scripts have 'lowest' piority
+    // thus do not conflict, everything else has a chance before them
+    // also in ML they have highest priority, but only when script-grabbed,
+    // thus do not conflict
+    // (see AGENT_CONTROL_ML_LBUTTON_DOWN and CONTROL_LBUTTON_DOWN_INDEX)
+    LLKeyConflict *type_data = &mControlsMap[script_mouse_handler_name];
+    type_data->mAssignable = true;
+    type_data->mConflictMask = U32_MAX - CONFLICT_LMOUSE;
 }
 
-bool LLKeyConflictHandler::removeConflicts(const LLKeyData &data, const U32 &conlict_mask)
+bool LLKeyConflictHandler::removeConflicts(const LLKeyData &data, U32 conlict_mask)
 {
     if (conlict_mask == CONFLICT_NOTHING)
     {
         // Can't conflict
         return true;
     }
+
+    if (data.mMouse == CLICK_LEFT
+        && data.mMask == MASK_NONE
+        && data.mKey == KEY_NONE)
+    {
+        if ((conlict_mask & CONFLICT_LMOUSE) == 0)
+        {
+            // Can't conflict
+            return true;
+        }
+        else
+        {
+            // simplify conflict mask
+            conlict_mask = CONFLICT_LMOUSE;
+        }
+    }
+    else
+    {
+        // simplify conflict mask
+        conlict_mask &= ~CONFLICT_LMOUSE;
+    }
+
     std::map<std::string, S32> conflict_list;
     control_map_t::iterator cntrl_iter = mControlsMap.begin();
     control_map_t::iterator cntrl_end = mControlsMap.end();
     for (; cntrl_iter != cntrl_end; ++cntrl_iter)
     {
+        const U32 cmp_mask = cntrl_iter->second.mConflictMask;
+        if ((cmp_mask & conlict_mask) == 0)
+        {
+            // can't conflict
+            continue;
+        }
         S32 index = cntrl_iter->second.mKeyBind.findKeyData(data);
-        if (index >= 0
-            && cntrl_iter->second.mConflictMask != CONFLICT_NOTHING
-            && (cntrl_iter->second.mConflictMask & conlict_mask) != 0)
+        if (index >= 0)
         {
             if (cntrl_iter->second.mAssignable)
             {
diff --git a/indra/newview/llkeyconflict.h b/indra/newview/llkeyconflict.h
index 2926ca3aeb10f33f9ed3b7aaed53e78bf596579b..23c1adf1e4b16dab2ea423f1eeb03ff6f49ca661 100644
--- a/indra/newview/llkeyconflict.h
+++ b/indra/newview/llkeyconflict.h
@@ -66,6 +66,7 @@ class LLKeyConflictHandler
     };
 
     const U32 CONFLICT_NOTHING = 0;
+    const U32 CONFLICT_LMOUSE = 0x1 << 1;
     // at the moment this just means that key will conflict with everything that is identical
     const U32 CONFLICT_ANY = U32_MAX;
 
@@ -128,23 +129,24 @@ class LLKeyConflictHandler
     // resets current mode to defaults
     void resetToDefaults();
 
-    bool empty() { return mControlsMap.empty(); }
+    bool empty() const { return mControlsMap.empty(); }
     void clear();
 
     // reloads bindings from last valid user's xml or from default xml
     // to keyboard's handler
     static void resetKeyboardBindings();
 
-    bool hasUnsavedChanges() { return mHasUnsavedChanges; }
+    bool hasUnsavedChanges() const { return mHasUnsavedChanges; }
     void setLoadMode(ESourceMode mode) { mLoadMode = mode; }
-    ESourceMode getLoadMode() { return mLoadMode; }
+    ESourceMode getLoadMode() const { return mLoadMode; }
 
 private:
     void resetToDefaultAndResolve(const std::string &control_name, bool ignore_conflicts);
-    void resetToDefaults(ESourceMode mode);
+    void resetToDefaultsAndResolve();
 
     // at the moment these kind of control is not savable, but takes part in conflict resolution
     void registerTemporaryControl(const std::string &control_name, EMouseClickType mouse_ind, KEY key, MASK mask, U32 conflict_mask);
+    // conflict mask 0 means that any conflicts will be ignored
     void registerTemporaryControl(const std::string &control_name, U32 conflict_mask = 0);
 
     typedef std::map<std::string, LLKeyConflict> control_map_t;
@@ -152,7 +154,7 @@ class LLKeyConflictHandler
     bool loadFromSettings(const ESourceMode &load_mode, const std::string &filename, control_map_t *destination);
     void generatePlaceholders(ESourceMode load_mode); //E.x. non-assignable values
     // returns false in case user is trying to reuse control that can't be reassigned
-    bool removeConflicts(const LLKeyData &data, const U32 &conlict_mask);
+    bool removeConflicts(const LLKeyData &data, U32 conlict_mask);
 
     // removes flags and removes temporary file, returns 'true' if file was removed
     bool clearUnsavedChanges();
diff --git a/indra/newview/lllegacyatmospherics.cpp b/indra/newview/lllegacyatmospherics.cpp
index a2acb3efe2d9532fa8cefede51ad09f4d1beae04..ce4ec668f144f0045fc24c77977c7ddbd26aeeff 100644
--- a/indra/newview/lllegacyatmospherics.cpp
+++ b/indra/newview/lllegacyatmospherics.cpp
@@ -202,17 +202,11 @@ void LLAtmospherics::init()
 	mInitialized = true;
 }
 
-LLColor4 LLAtmospherics::calcSkyColorInDir(AtmosphericsVars& vars, const LLVector3 &dir, bool isShiny)
-{
-    LLSettingsSky::ptr_t psky = LLEnvironment::instance().getCurrentSky();
-    return calcSkyColorInDir(psky, vars, dir, isShiny);
-}
-
 // This cubemap is used as "environmentMap" in indra/newview/app_settings/shaders/class2/deferred/softenLightF.glsl
-LLColor4 LLAtmospherics::calcSkyColorInDir(const LLSettingsSky::ptr_t &psky, AtmosphericsVars& vars, const LLVector3 &dir, bool isShiny)
+LLColor4 LLAtmospherics::calcSkyColorInDir(const LLSettingsSky::ptr_t &psky, AtmosphericsVars& vars, const LLVector3 &dir, bool isShiny, bool low_end)
 {
-	F32 sky_saturation = 0.25f;
-	F32 land_saturation = 0.1f;
+	const F32 sky_saturation = 0.25f;
+	const F32 land_saturation = 0.1f;
 
 	if (isShiny && dir.mV[VZ] < -0.02f)
 	{
@@ -227,7 +221,7 @@ LLColor4 LLAtmospherics::calcSkyColorInDir(const LLSettingsSky::ptr_t &psky, Atm
 		}
 		F32 greyscale_sat = brightness * (1.0f - land_saturation);
 		desat_fog = desat_fog * land_saturation + smear(greyscale_sat);
-		if (!gPipeline.canUseWindLightShaders())
+		if (low_end)
 		{
 			col = LLColor4(desat_fog, 0.f);
 		}
@@ -258,8 +252,7 @@ LLColor4 LLAtmospherics::calcSkyColorInDir(const LLSettingsSky::ptr_t &psky, Atm
 		return LLColor4(sky_color, 0.0f);
 	}
 
-	bool low_end = !gPipeline.canUseWindLightShaders();
-	LLColor3 sky_color = low_end ? vars.hazeColor * 2.0f : psky->gammaCorrect(vars.hazeColor * 2.0f);
+	LLColor3 sky_color = low_end ? vars.hazeColor * 2.0f : psky->gammaCorrect(vars.hazeColor * 2.0f, vars.gamma);
 
 	return LLColor4(sky_color, 0.0f);
 }
@@ -270,11 +263,12 @@ LLColor4 LLAtmospherics::calcSkyColorInDir(const LLSettingsSky::ptr_t &psky, Atm
 //       indra\newview\lllegacyatmospherics.cpp
 void LLAtmospherics::calcSkyColorWLVert(const LLSettingsSky::ptr_t &psky, LLVector3 & Pn, AtmosphericsVars& vars)
 {
-    LLColor3    blue_density = vars.blue_density;
-    LLColor3    blue_horizon = vars.blue_horizon;
-    F32         haze_horizon = vars.haze_horizon;
-    F32         haze_density = vars.haze_density;
-    F32         density_multiplier = vars.density_multiplier;
+    const LLColor3    blue_density = vars.blue_density;
+    const LLColor3    blue_horizon = vars.blue_horizon;
+    const F32         haze_horizon = vars.haze_horizon;
+    const F32         haze_density = vars.haze_density;
+    const F32         density_multiplier = vars.density_multiplier;
+
     F32         max_y = vars.max_y;
     LLVector4   sun_norm = vars.sun_norm;
 
@@ -313,7 +307,7 @@ void LLAtmospherics::calcSkyColorWLVert(const LLSettingsSky::ptr_t &psky, LLVect
 	// Sunlight attenuation effect (hue and brightness) due to atmosphere
 	// this is used later for sunlight modulation at various altitudes
 	LLColor3 light_atten = vars.light_atten;
-    LLColor3 light_transmittance = psky->getLightTransmittance(Plen);
+    LLColor3 light_transmittance = psky->getLightTransmittanceFast(vars.total_density, vars.density_multiplier, Plen);
     (void)light_transmittance; // silence Clang warn-error
 
 	// Calculate relative weights
@@ -389,16 +383,9 @@ void LLAtmospherics::updateFog(const F32 distance, const LLVector3& tosun_in)
 
 	if (!gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_FOG))
 	{
-		if (!LLGLSLShader::sNoFixedFunction)
-		{
-			glFogf(GL_FOG_DENSITY, 0);
-			glFogfv(GL_FOG_COLOR, (F32 *) &LLColor4::white.mV);
-			glFogf(GL_FOG_END, 1000000.f);
-		}
 		return;
 	}
 
-	const BOOL hide_clip_plane = TRUE;
 	LLColor4 target_fog(0.f, 0.2f, 0.5f, 0.f);
 
 	const F32 water_height = gAgent.getRegion() ? gAgent.getRegion()->getWaterHeight() : 0.f;
@@ -436,12 +423,16 @@ void LLAtmospherics::updateFog(const F32 distance, const LLVector3& tosun_in)
 
     LLSettingsSky::ptr_t psky = LLEnvironment::instance().getCurrentSky();
 
+    // NOTE: This is very similar to LLVOSky::cacheEnvironment()
+    // Differences:
+    //     vars.sun_norm
+    //     vars.sunlight
     // invariants across whole sky tex process...
-    vars.blue_density = psky->getBlueDensity();    
+    vars.blue_density = psky->getBlueDensity();
     vars.blue_horizon = psky->getBlueHorizon();
     vars.haze_density = psky->getHazeDensity();
     vars.haze_horizon = psky->getHazeHorizon();
-    vars.density_multiplier = psky->getDensityMultiplier();    
+    vars.density_multiplier = psky->getDensityMultiplier();
     vars.distance_multiplier = psky->getDistanceMultiplier();
     vars.max_y = psky->getMaxY();
     vars.sun_norm = LLEnvironment::instance().getSunDirectionCFR();
@@ -456,9 +447,9 @@ void LLAtmospherics::updateFog(const F32 distance, const LLVector3& tosun_in)
     vars.total_density = psky->getTotalDensity();
     vars.gamma = psky->getGamma();
 
-	res_color[0] = calcSkyColorInDir(vars, tosun);
-	res_color[1] = calcSkyColorInDir(vars, perp_tosun);
-	res_color[2] = calcSkyColorInDir(vars, tosun_45);
+    res_color[0] = calcSkyColorInDir(psky, vars, tosun);
+    res_color[1] = calcSkyColorInDir(psky, vars, perp_tosun);
+    res_color[2] = calcSkyColorInDir(psky, vars, tosun_45);
 
 	sky_fog_color = color_norm(res_color[0] + res_color[1] + res_color[2]);
 
@@ -480,45 +471,17 @@ void LLAtmospherics::updateFog(const F32 distance, const LLVector3& tosun_in)
 
 	render_fog_color = sky_fog_color;
 
-	F32 fog_density = 0.f;
 	fog_distance = mFogRatio * distance;
 	
 	if (camera_height > water_height)
 	{
 		LLColor4 fog(render_fog_color);
-		if (!LLGLSLShader::sNoFixedFunction)
-		{
-			glFogfv(GL_FOG_COLOR, fog.mV);
-		}
 		mGLFogCol = fog;
-
-		if (hide_clip_plane)
-		{
-			// For now, set the density to extend to the cull distance.
-			const F32 f_log = 2.14596602628934723963618357029f; // sqrt(fabs(log(0.01f)))
-			fog_density = f_log/fog_distance;
-			if (!LLGLSLShader::sNoFixedFunction)
-			{
-				glFogi(GL_FOG_MODE, GL_EXP2);
-			}
-		}
-		else
-		{
-			const F32 f_log = 4.6051701859880913680359829093687f; // fabs(log(0.01f))
-			fog_density = (f_log)/fog_distance;
-			if (!LLGLSLShader::sNoFixedFunction)
-			{
-				glFogi(GL_FOG_MODE, GL_EXP);
-			}
-		}
 	}
 	else
 	{
         LLSettingsWater::ptr_t pwater = LLEnvironment::instance().getCurrentWater();
 		F32 depth = water_height - camera_height;
-		
-		// get the water param manager variables
-        float water_fog_density = pwater->getModifiedWaterFogDensity(depth <= 0.0f);
 
 		LLColor4 water_fog_color(pwater->getWaterFogColor());
 
@@ -532,15 +495,6 @@ void LLAtmospherics::updateFog(const F32 distance, const LLVector3& tosun_in)
 
 		// set the gl fog color
 		mGLFogCol = fogCol;
-
-		// set the density based on what the shaders use
-		fog_density = water_fog_density * gSavedSettings.getF32("WaterGLFogDensityScale");
-
-		if (!LLGLSLShader::sNoFixedFunction)
-		{
-			glFogfv(GL_FOG_COLOR, (F32 *) &fogCol.mV);
-			glFogi(GL_FOG_MODE, GL_EXP2);
-		}
 	}
 
 	mFogColor = sky_fog_color;
@@ -548,13 +502,6 @@ void LLAtmospherics::updateFog(const F32 distance, const LLVector3& tosun_in)
 
 	LLDrawPoolWater::sWaterFogEnd = fog_distance*2.2f;
 
-	if (!LLGLSLShader::sNoFixedFunction)
-	{
-		LLGLSFog gls_fog;
-		glFogf(GL_FOG_END, fog_distance*2.2f);
-		glFogf(GL_FOG_DENSITY, fog_density);
-		glHint(GL_FOG_HINT, GL_NICEST);
-	}
 	stop_glerror();
 }
 
diff --git a/indra/newview/lllegacyatmospherics.h b/indra/newview/lllegacyatmospherics.h
index 03c8efb91aed629c3abbb433238fe8aec9557ba1..d48f3040c356a0bf30e07a0bcc15829cfcea3ebf 100644
--- a/indra/newview/lllegacyatmospherics.h
+++ b/indra/newview/lllegacyatmospherics.h
@@ -257,13 +257,11 @@ class LLAtmospherics
     void setCloudDensity(F32 cloud_density)          { mCloudDensity = cloud_density; }
     void setWind ( const LLVector3& wind )           { mWind = wind.length(); }
 
-    LLColor4 calcSkyColorInDir(AtmosphericsVars& vars, const LLVector3& dir, bool isShiny = false);
-    LLColor4 calcSkyColorInDir(const LLSettingsSky::ptr_t &psky, AtmosphericsVars& vars, const LLVector3& dir, bool isShiny = false);
+    LLColor4 calcSkyColorInDir(const LLSettingsSky::ptr_t &psky, AtmosphericsVars& vars, const LLVector3& dir, bool isShiny = false, const bool low_end = false);
 
-protected:    
+protected:
 
     void     calcSkyColorWLVert(const LLSettingsSky::ptr_t &psky, LLVector3 & Pn, AtmosphericsVars& vars);
-    LLColor3 getHazeColor(LLSettingsSky::ptr_t psky, AtmosphericsVars& vars, F32 costheta, F32 cloud_shadow);
 
     LLHaze              mHaze;
     F32                 mHazeConcentration;
diff --git a/indra/newview/lllocalbitmaps.cpp b/indra/newview/lllocalbitmaps.cpp
index 5a17332fde653a868d52712c5bba8e9916fa4c5f..de8db69e191a6f5ae988e42478a6a02381768079 100644
--- a/indra/newview/lllocalbitmaps.cpp
+++ b/indra/newview/lllocalbitmaps.cpp
@@ -919,6 +919,36 @@ LLLocalBitmapMgr::~LLLocalBitmapMgr()
     mBitmapList.clear();
 }
 
+LLUUID LLLocalBitmapMgr::addUnit(const std::string &filename)
+{
+    if (!checkTextureDimensions(filename))
+    {
+        return LLUUID::null;
+    }
+
+    LLLocalBitmap* unit = new LLLocalBitmap(filename);
+
+    if (unit->getValid())
+    {
+        mBitmapList.push_back(unit);
+        return unit->getTrackingID();
+    }
+    else
+    {
+        LL_WARNS() << "Attempted to add invalid or unreadable image file, attempt cancelled.\n"
+            << "Filename: " << filename << LL_ENDL;
+
+        LLSD notif_args;
+        notif_args["FNAME"] = filename;
+        LLNotificationsUtil::add("LocalBitmapsVerifyFail", notif_args);
+
+        delete unit;
+        unit = NULL;
+    }
+
+    return LLUUID::null;
+}
+
 bool LLLocalBitmapMgr::addUnit()
 {
 	bool add_successful = false;
@@ -931,32 +961,10 @@ bool LLLocalBitmapMgr::addUnit()
 		std::string filename = picker.getFirstFile();
 		while(!filename.empty())
 		{
-			if(!checkTextureDimensions(filename))
-			{
-				filename = picker.getNextFile();
-				continue;
-			}
-
-			LLLocalBitmap* unit = new LLLocalBitmap(filename);
-
-			if (unit->getValid())
-			{
-				mBitmapList.push_back(unit);
-				add_successful = true;
-			}
-			else
-			{
-				LL_WARNS() << "Attempted to add invalid or unreadable image file, attempt cancelled.\n"
-					    << "Filename: " << filename << LL_ENDL;
-
-				LLSD notif_args;
-				notif_args["FNAME"] = filename;
-				LLNotificationsUtil::add("LocalBitmapsVerifyFail", notif_args);
-
-				delete unit;
-				unit = NULL;
-			}
-
+            if (addUnit(filename).notNull())
+            {
+                add_successful = true;
+            }
 			filename = picker.getNextFile();
 		}
 		
diff --git a/indra/newview/lllocalbitmaps.h b/indra/newview/lllocalbitmaps.h
index d5ee7efdc640cfa5c90028c5e8b8f7fd8d823986..02b8834c16c480566bec403bf8797c57bedd8e95 100644
--- a/indra/newview/lllocalbitmaps.h
+++ b/indra/newview/lllocalbitmaps.h
@@ -116,13 +116,14 @@ class LLLocalBitmapMgr : public LLSingleton<LLLocalBitmapMgr>
 	~LLLocalBitmapMgr();
 public:
 	bool         addUnit();
+    LLUUID       addUnit(const std::string &filename);
 	void         delUnit(LLUUID tracking_id);
 	bool 		checkTextureDimensions(std::string filename);
 
 	LLUUID       getWorldID(LLUUID tracking_id);
     bool         isLocal(LLUUID world_id);
 	std::string  getFilename(LLUUID tracking_id);
-
+    
 	void         feedScrollList(LLScrollListCtrl* ctrl);
 	void         doUpdates();
 	void         setNeedsRebake();
diff --git a/indra/newview/lllocationinputctrl.h b/indra/newview/lllocationinputctrl.h
index 79dbe17982aac21d4b7a5b7d186e60816e6511ba..af2a9f6afdde5c20a880edf4fdbf750d4de4c7a1 100644
--- a/indra/newview/lllocationinputctrl.h
+++ b/indra/newview/lllocationinputctrl.h
@@ -109,6 +109,8 @@ class LLLocationInputCtrl
 	LLLineEditor*			getTextEntry() const { return mTextEntry; }
 	void					handleLoginComplete();
 
+    bool isNavMeshDirty() { return mIsNavMeshDirty; }
+
 private:
 
 	enum EParcelIcon
diff --git a/indra/newview/lllogininstance.cpp b/indra/newview/lllogininstance.cpp
index e81d2cc0826e83e8b4ff0c4709722590f19d125b..dd8c9b2dde8343f226be7c9d97646c41557d36d1 100644
--- a/indra/newview/lllogininstance.cpp
+++ b/indra/newview/lllogininstance.cpp
@@ -61,6 +61,7 @@
 #include "lltrans.h"
 
 #include <boost/scoped_ptr.hpp>
+#include <boost/regex.hpp>
 #include <sstream>
 
 const S32 LOGIN_MAX_RETRIES = 0; // Viewer should not autmatically retry login
@@ -165,13 +166,12 @@ void LLLoginInstance::constructAuthParams(LLPointer<LLCredential> user_credentia
 	//requested_options.append("inventory-meat");
 	//requested_options.append("inventory-skel-targets");
 #if (!defined LL_MINIMIAL_REQUESTED_OPTIONS)
-	if(FALSE == gSavedSettings.getBOOL("NoInventoryLibrary"))
-	{
-		requested_options.append("inventory-lib-root");
-		requested_options.append("inventory-lib-owner");
-		requested_options.append("inventory-skel-lib");
+
+    // Not requesting library will trigger mFatalNoLibraryRootFolder
+	requested_options.append("inventory-lib-root");
+	requested_options.append("inventory-lib-owner");
+	requested_options.append("inventory-skel-lib");
 	//	requested_options.append("inventory-meat-lib");
-	}
 
 	requested_options.append("initial-outfit");
 	requested_options.append("gestures");
@@ -225,8 +225,9 @@ void LLLoginInstance::constructAuthParams(LLPointer<LLCredential> user_credentia
 	request_params["id0"] = mSerialNumber;
 	request_params["host_id"] = gSavedSettings.getString("HostID");
 	request_params["extended_errors"] = true; // request message_id and message_args
+	request_params["token"] = "";
 
-    // log request_params _before_ adding the credentials   
+    // log request_params _before_ adding the credentials or sensitive MFA hash data
     LL_DEBUGS("LLLogin") << "Login parameters: " << LLSDOStreamer<LLSDNotationFormatter>(request_params) << LL_ENDL;
 
     // Copy the credentials into the request after logging the rest
@@ -239,6 +240,33 @@ void LLLoginInstance::constructAuthParams(LLPointer<LLCredential> user_credentia
         request_params[it->first] = it->second;
     }
 
+    std::string mfa_hash = gSavedSettings.getString("MFAHash"); //non-persistent to enable testing
+    std::string grid(LLGridManager::getInstance()->getGridId());
+    std::string user_id = user_credential->userID();
+    if (gSecAPIHandler)
+    {
+        if (mfa_hash.empty())
+        {
+            // normal execution, mfa_hash was not set from debug setting so load from protected store
+            LLSD data_map = gSecAPIHandler->getProtectedData("mfa_hash", grid);
+            if (data_map.isMap() && data_map.has(user_id))
+            {
+                mfa_hash = data_map[user_id].asString();
+            }
+        }
+        else
+        {
+            // SL-16888 the mfa_hash is being overridden for testing so save it for consistency for future login requests
+            gSecAPIHandler->addToProtectedMap("mfa_hash", grid, user_id, mfa_hash);
+        }
+    }
+    else
+    {
+        LL_WARNS() << "unable to access protected store for mfa_hash" << LL_ENDL;
+    }
+
+    request_params["mfa_hash"] = mfa_hash;
+
 	// Specify desired timeout/retry options
 	LLSD http_params;
 	F32 srv_timeout = llclamp(gSavedSettings.getF32("LoginSRVTimeout"), LOGIN_SRV_TIMEOUT_MIN, LOGIN_SRV_TIMEOUT_MAX);
@@ -251,6 +279,11 @@ void LLLoginInstance::constructAuthParams(LLPointer<LLCredential> user_credentia
 	mRequestData["params"] = request_params;
 	mRequestData["options"] = requested_options;
 	mRequestData["http_params"] = http_params;
+#if LL_RELEASE_FOR_DOWNLOAD
+    mRequestData["wait_for_updater"] = LLAppViewer::instance()->waitForUpdater();
+#else
+    mRequestData["wait_for_updater"] = false;
+#endif
 }
 
 bool LLLoginInstance::handleLoginEvent(const LLSD& event)
@@ -407,6 +440,20 @@ void LLLoginInstance::handleLoginFailure(const LLSD& event)
                 boost::bind(&LLLoginInstance::syncWithUpdater, this, resp, _1, _2));
         }
     }
+    else if(reason_response == "mfa_challenge")
+    {
+        LL_DEBUGS("LLLogin") << " MFA challenge" << LL_ENDL;
+
+        if (gViewerWindow)
+        {
+            gViewerWindow->setShowProgress(FALSE);
+        }
+
+        LLSD args(llsd::map( "MESSAGE", LLTrans::getString(response["message_id"]) ));
+        LLSD payload;
+        LLNotificationsUtil::add("PromptMFAToken", args, payload,
+            boost::bind(&LLLoginInstance::handleMFAChallenge, this, _1, _2));
+    }
     else if(   reason_response == "key"
             || reason_response == "presence"
             || reason_response == "connect"
@@ -482,23 +529,59 @@ void LLLoginInstance::handleIndeterminate(const LLSD& event)
 
 bool LLLoginInstance::handleTOSResponse(bool accepted, const std::string& key)
 {
-	if(accepted)
-	{	
-		LL_INFOS("LLLogin") << "LLLoginInstance::handleTOSResponse: accepted" << LL_ENDL;
+    if(accepted)
+    {
+        LL_INFOS("LLLogin") << "LLLoginInstance::handleTOSResponse: accepted " << LL_ENDL;
 
-		// Set the request data to true and retry login.
-		mRequestData["params"][key] = true; 
-		reconnect();
-	}
-	else
-	{
-		LL_INFOS("LLLogin") << "LLLoginInstance::handleTOSResponse: attemptComplete" << LL_ENDL;
+        // Set the request data to true and retry login.
+        mRequestData["params"][key] = true;
 
-		attemptComplete();
-	}
+        if (!mRequestData["params"]["token"].asString().empty())
+        {
+            // SL-18511 this TOS failure happened while we are in the middle of an MFA challenge/response.
+            // the previously entered token is very likely expired, so prompt again
+            LLSD args(llsd::map( "MESSAGE", LLTrans::getString("LoginFailedAuthenticationMFARequired") ));
+            LLSD payload;
+            LLNotificationsUtil::add("PromptMFAToken", args, payload,
+                boost::bind(&LLLoginInstance::handleMFAChallenge, this, _1, _2));
+        }
+        else
+        {
+            reconnect();
+        }
+    }
+    else
+    {
+        LL_INFOS("LLLogin") << "LLLoginInstance::handleTOSResponse: attemptComplete" << LL_ENDL;
 
-	LLEventPumps::instance().obtain(TOS_REPLY_PUMP).stopListening(TOS_LISTENER_NAME);
-	return true;
+        attemptComplete();
+    }
+
+    LLEventPumps::instance().obtain(TOS_REPLY_PUMP).stopListening(TOS_LISTENER_NAME);
+    return true;
+}
+
+bool LLLoginInstance::handleMFAChallenge(LLSD const & notif, LLSD const & response)
+{
+    bool continue_clicked = response["continue"].asBoolean();
+    std::string token = response["token"].asString();
+    LL_DEBUGS("LLLogin") << "PromptMFAToken: response: " << response << " continue_clicked" << continue_clicked << LL_ENDL;
+
+    // strip out whitespace - SL-17034/BUG-231938
+    token = boost::regex_replace(token, boost::regex("\\s"), "");
+
+    if (continue_clicked && !token.empty())
+    {
+        LL_INFOS("LLLogin") << "PromptMFAToken: token submitted" << LL_ENDL;
+
+        // Set the request data to true and retry login.
+        mRequestData["params"]["token"] = token;
+        reconnect();
+    } else {
+        LL_INFOS("LLLogin") << "PromptMFAToken: no token, attemptComplete" << LL_ENDL;
+        attemptComplete();
+    }
+    return true;
 }
 
 std::string construct_start_string()
diff --git a/indra/newview/lllogininstance.h b/indra/newview/lllogininstance.h
index b759b43474d560c865b288bb41c4ac0c59f1b006..ee3ef0e4b1110c576dc874ba03229e69d9000d98 100644
--- a/indra/newview/lllogininstance.h
+++ b/indra/newview/lllogininstance.h
@@ -84,6 +84,7 @@ class LLLoginInstance : public LLSingleton<LLLoginInstance>
 	void syncWithUpdater(ResponsePtr resp, const LLSD& notification, const LLSD& response);
 
 	bool handleTOSResponse(bool v, const std::string& key);
+    bool handleMFAChallenge(LLSD const & notif, LLSD const & response);
 
 	void attemptComplete() { mAttemptComplete = true; } // In the future an event?
 
diff --git a/indra/newview/llmainlooprepeater.cpp b/indra/newview/llmainlooprepeater.cpp
deleted file mode 100644
index 6736e9a950d500d7d71aa119997e78d01a1e8bc3..0000000000000000000000000000000000000000
--- a/indra/newview/llmainlooprepeater.cpp
+++ /dev/null
@@ -1,88 +0,0 @@
-/** 
- * @file llmachineid.cpp
- * @brief retrieves unique machine ids
- *
- * $LicenseInfo:firstyear=2009&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- * 
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- * 
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
- * $/LicenseInfo$
- */
-
-#include "llviewerprecompiledheaders.h"
-#include "llapr.h"
-#include "llevents.h"
-#include "llmainlooprepeater.h"
-
-
-
-// LLMainLoopRepeater
-//-----------------------------------------------------------------------------
-
-
-LLMainLoopRepeater::LLMainLoopRepeater(void):
-	mQueue(0)
-{
-	; // No op.
-}
-
-
-void LLMainLoopRepeater::start(void)
-{
-	if(mQueue != 0) return;
-
-	mQueue = new LLThreadSafeQueue<LLSD>(1024);
-	mMainLoopConnection = LLEventPumps::instance().
-		obtain("mainloop").listen(LLEventPump::inventName(), boost::bind(&LLMainLoopRepeater::onMainLoop, this, _1));
-	mRepeaterConnection = LLEventPumps::instance().
-		obtain("mainlooprepeater").listen(LLEventPump::inventName(), boost::bind(&LLMainLoopRepeater::onMessage, this, _1));
-}
-
-
-void LLMainLoopRepeater::stop(void)
-{
-	mMainLoopConnection.release();
-	mRepeaterConnection.release();
-
-	delete mQueue;
-	mQueue = 0;
-}
-
-
-bool LLMainLoopRepeater::onMainLoop(LLSD const &)
-{
-	LLSD message;
-	while(mQueue->tryPopBack(message)) {
-		std::string pump = message["pump"].asString();
-		if(pump.length() == 0 ) continue; // No pump.
-		LLEventPumps::instance().obtain(pump).post(message["payload"]);
-	}
-	return false;
-}
-
-
-bool LLMainLoopRepeater::onMessage(LLSD const & event)
-{
-	try {
-		mQueue->pushFront(event);
-	} catch(LLThreadSafeQueueError & e) {
-		LL_WARNS() << "could not repeat message (" << e.what() << ")" << 
-			event.asString() << LL_ENDL;
-	}
-	return false;
-}
diff --git a/indra/newview/llmainlooprepeater.h b/indra/newview/llmainlooprepeater.h
deleted file mode 100644
index 2ec3a74e4ae3bc4a446182cc444c5d654cd044d6..0000000000000000000000000000000000000000
--- a/indra/newview/llmainlooprepeater.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/** 
- * @file llmainlooprepeater.h
- * @brief a service for repeating messages on the main loop.
- *
- * $LicenseInfo:firstyear=2010&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- * 
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- * 
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
- * $/LicenseInfo$
- */
-
-#ifndef LL_LLMAINLOOPREPEATER_H
-#define LL_LLMAINLOOPREPEATER_H
-
-
-#include "llsd.h"
-#include "llthreadsafequeue.h"
-
-
-//
-// A service which creates the pump 'mainlooprepeater' to which any thread can
-// post a message that will be re-posted on the main loop.
-//
-// The posted message should contain two map elements: pump and payload.  The
-// pump value is a string naming the pump to which the message should be
-// re-posted.  The payload value is what will be posted to the designated pump.
-//
-class LLMainLoopRepeater:
-	public LLSingleton<LLMainLoopRepeater>
-{
-	LLSINGLETON(LLMainLoopRepeater);
-public:
-	// Start the repeater service.
-	void start(void);
-	
-	// Stop the repeater service.
-	void stop(void);
-	
-private:
-	LLTempBoundListener mMainLoopConnection;
-	LLTempBoundListener mRepeaterConnection;
-	LLThreadSafeQueue<LLSD> * mQueue;
-	
-	bool onMainLoop(LLSD const &);
-	bool onMessage(LLSD const & event);
-};
-
-
-#endif
diff --git a/indra/newview/llmaniprotate.cpp b/indra/newview/llmaniprotate.cpp
index 3566ca7a351b8bf467709619fed0681096f8e04b..d85a846f4dedf74a28a5277725720678422c3ca1 100644
--- a/indra/newview/llmaniprotate.cpp
+++ b/indra/newview/llmaniprotate.cpp
@@ -157,10 +157,7 @@ void LLManipRotate::render()
 		}
 		else
 		{
-			if (LLGLSLShader::sNoFixedFunction)
-			{
-				gDebugProgram.bind();
-			}
+			gDebugProgram.bind();
 
 			LLGLEnable cull_face(GL_CULL_FACE);
 			LLGLDepthTest gls_depth(GL_FALSE);
@@ -213,10 +210,7 @@ void LLManipRotate::render()
 			}
 			gGL.popMatrix();
 
-			if (LLGLSLShader::sNoFixedFunction)
-			{
-				gUIProgram.bind();
-			}
+			gUIProgram.bind();
 		}
 		
 		gGL.translatef( center.mV[VX], center.mV[VY], center.mV[VZ] );
@@ -234,10 +228,7 @@ void LLManipRotate::render()
 		gGL.rotatef(angle_radians * RAD_TO_DEG, x, y, z);
 
 
-		if (LLGLSLShader::sNoFixedFunction)
-		{
-			gDebugProgram.bind();
-		}
+		gDebugProgram.bind();
 
 		if (mManipPart == LL_ROT_Z)
 		{
@@ -355,11 +346,7 @@ void LLManipRotate::render()
 			
 		}
 
-		if (LLGLSLShader::sNoFixedFunction)
-		{
-			gUIProgram.bind();
-		}
-		
+		gUIProgram.bind();
 	}
 	gGL.popMatrix();
 	gGL.popMatrix();
diff --git a/indra/newview/llmaniptranslate.cpp b/indra/newview/llmaniptranslate.cpp
index 8736d3b51febf7fad11eddc19ece97bb4af05791..0b2a1ef389c9e8cb606e52cb30946e8d6b8fa4d7 100644
--- a/indra/newview/llmaniptranslate.cpp
+++ b/indra/newview/llmaniptranslate.cpp
@@ -1565,11 +1565,6 @@ void LLManipTranslate::renderSnapGuides()
 					LLGLEnable stipple(GL_LINE_STIPPLE);
 					gGL.flush();
 
-					if (!LLGLSLShader::sNoFixedFunction)
-					{
-						glLineStipple(1, 0x3333);
-					}
-		
 					switch (mManipPart)
 					{
 					  case LL_YZ_PLANE:
@@ -1633,7 +1628,7 @@ void LLManipTranslate::highlightIntersection(LLVector3 normal,
 											 LLQuaternion grid_rotation, 
 											 LLColor4 inner_color)
 {
-	if (!gSavedSettings.getBOOL("GridCrossSections") || !LLGLSLShader::sNoFixedFunction)
+	if (!gSavedSettings.getBOOL("GridCrossSections"))
 	{
 		return;
 	}
diff --git a/indra/newview/llmarketplacefunctions.cpp b/indra/newview/llmarketplacefunctions.cpp
index 044c76ce2c3c807d9a8483a5851cc2de0109c274..dd4ae4d201c11ddf03f139b5e89608e01c3e3c70 100644
--- a/indra/newview/llmarketplacefunctions.cpp
+++ b/indra/newview/llmarketplacefunctions.cpp
@@ -758,7 +758,14 @@ void LLMarketplaceData::initializeSLM(const status_updated_signal_t::slot_type&
     if (mMarketPlaceStatus != MarketplaceStatusCodes::MARKET_PLACE_NOT_INITIALIZED)
     {
         // If already initialized, just confirm the status so the callback gets called
-        setSLMStatus(mMarketPlaceStatus);
+        if (mMarketPlaceFailureReason.empty())
+        {
+            setSLMStatus(mMarketPlaceStatus);
+        }
+        else
+        {
+            setSLMConnectionFailure(mMarketPlaceFailureReason);
+        }
     }
     else
     {
@@ -799,28 +806,27 @@ void LLMarketplaceData::getMerchantStatusCoro()
         if (httpCode == HTTP_NOT_FOUND)
         {
             log_SLM_infos("Get /merchant", httpCode, std::string("User is not a merchant"));
-            setSLMStatus(MarketplaceStatusCodes::MARKET_PLACE_NOT_MERCHANT);
+            LLMarketplaceData::instance().setSLMStatus(MarketplaceStatusCodes::MARKET_PLACE_NOT_MERCHANT);
         }
         else if (httpCode == HTTP_SERVICE_UNAVAILABLE)
         {
             log_SLM_infos("Get /merchant", httpCode, std::string("Merchant is not migrated"));
-            setSLMStatus(MarketplaceStatusCodes::MARKET_PLACE_NOT_MIGRATED_MERCHANT);
+            LLMarketplaceData::instance().setSLMStatus(MarketplaceStatusCodes::MARKET_PLACE_NOT_MIGRATED_MERCHANT);
         }
-        else if (httpCode == HTTP_INTERNAL_ERROR)
+        else
         {
-            // 499 includes timeout and ssl error - marketplace is down or having issues, we do not show it in this request according to MAINT-5938
             LL_WARNS("SLM") << "SLM Merchant Request failed with status: " << httpCode
                                     << ", reason : " << status.toString()
                                     << ", code : " << result["error_code"].asString()
                                     << ", description : " << result["error_description"].asString() << LL_ENDL;
-            LLMarketplaceData::instance().setSLMStatus(MarketplaceStatusCodes::MARKET_PLACE_CONNECTION_FAILURE);
-        }
-        else
-        {
-            std::string err_code = result["error_code"].asString();
-            //std::string err_description = result["error_description"].asString();
-            log_SLM_warning("Get /merchant", httpCode, status.toString(), err_code, result["error_description"]);
-            setSLMStatus(MarketplaceStatusCodes::MARKET_PLACE_CONNECTION_FAILURE);
+            std::string reason = status.toString();
+            if (reason.empty())
+            {
+                reason = result["error_code"].asString();
+            }
+            // Since user might not even have a marketplace, there is no reason to report the error
+            // to the user, instead write it down into listings' floater
+            LLMarketplaceData::instance().setSLMConnectionFailure(reason);
         }
         return;
     }
@@ -1298,6 +1304,17 @@ std::string LLMarketplaceData::getSLMConnectURL(const std::string& route)
 void LLMarketplaceData::setSLMStatus(U32 status)
 {
     mMarketPlaceStatus = status;
+    mMarketPlaceFailureReason.clear();
+    if (mStatusUpdatedSignal)
+    {
+        (*mStatusUpdatedSignal)();
+    }
+}
+
+void LLMarketplaceData::setSLMConnectionFailure(const std::string& reason)
+{
+    mMarketPlaceStatus = MarketplaceStatusCodes::MARKET_PLACE_CONNECTION_FAILURE;
+    mMarketPlaceFailureReason = reason;
     if (mStatusUpdatedSignal)
     {
         (*mStatusUpdatedSignal)();
diff --git a/indra/newview/llmarketplacefunctions.h b/indra/newview/llmarketplacefunctions.h
index fee9225f77c5905d04f5530e2694c14ece2e1c74..088507d85098d8ed0a8632b28ec43a2155d07d48 100644
--- a/indra/newview/llmarketplacefunctions.h
+++ b/indra/newview/llmarketplacefunctions.h
@@ -198,7 +198,9 @@ class LLMarketplaceData
 	typedef boost::signals2::signal<void ()> status_updated_signal_t;
     void initializeSLM(const status_updated_signal_t::slot_type& cb);
 	U32  getSLMStatus() const { return mMarketPlaceStatus; }
+    std::string getSLMConnectionfailureReason() { return mMarketPlaceFailureReason; }
 	void setSLMStatus(U32 status);
+    void setSLMConnectionFailure(const std::string& reason);
     void getSLMListings();
     bool isEmpty() { return (mMarketplaceItems.size() == 0); }
     void setDataFetchedSignal(const status_updated_signal_t::slot_type& cb);
@@ -272,6 +274,7 @@ class LLMarketplaceData
 
     // Handling Marketplace connection and inventory connection
 	U32  mMarketPlaceStatus;
+    std::string mMarketPlaceFailureReason;
 	status_updated_signal_t* mStatusUpdatedSignal;
 	LLInventoryObserver* mInventoryObserver;
     bool mDirtyCount;   // If true, stock count value need to be updated at the next check
diff --git a/indra/newview/llmaterialmgr.cpp b/indra/newview/llmaterialmgr.cpp
index 52b9fb40ae6233500f4389cc0f7038f6d36ebcba..11aa607393613149708b900950d7d6e6bdcb4fc1 100644
--- a/indra/newview/llmaterialmgr.cpp
+++ b/indra/newview/llmaterialmgr.cpp
@@ -580,11 +580,9 @@ void LLMaterialMgr::onPutResponse(bool success, const LLSD& content)
 	}
 }
 
-static LLTrace::BlockTimerStatHandle FTM_MATERIALS_IDLE("Idle Materials");
-
 void LLMaterialMgr::onIdle(void*)
 {
-	LL_RECORD_BLOCK_TIME(FTM_MATERIALS_IDLE);
+    LL_PROFILE_ZONE_SCOPED;
 
 	LLMaterialMgr* instancep = LLMaterialMgr::getInstance();
 
diff --git a/indra/newview/llmediactrl.cpp b/indra/newview/llmediactrl.cpp
index 5393d0b0b782f3fbf1c66ed2003982b26fb077b4..9142aadab9ff71d78b42019927fb88b10d0d8c8e 100644
--- a/indra/newview/llmediactrl.cpp
+++ b/indra/newview/llmediactrl.cpp
@@ -1146,6 +1146,11 @@ void LLMediaCtrl::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event)
             }
             else
             {
+                // Media might be blocked, waiting for a file,
+                // send an empty response to unblock it
+                const std::vector<std::string> empty_response;
+                self->sendPickFileResponse(empty_response);
+
                 LLNotificationsUtil::add("MediaFileDownloadUnsupported");
             }
 		};
diff --git a/indra/newview/llmediadataclient.cpp b/indra/newview/llmediadataclient.cpp
index bc45eb6d3aed19811d8a5d89d45fb5518e2d4db9..9d0f62a30d106cd83c1cc2c4c8b9f67c01cffa33 100644
--- a/indra/newview/llmediadataclient.cpp
+++ b/indra/newview/llmediadataclient.cpp
@@ -154,8 +154,7 @@ void mark_dead_and_remove_if(T &c, const PredicateMatchRequest &matchPred)
         if (matchPred(*it))
         {
             (*it)->markDead();
-            // *TDOO: When C++11 is in change the following line to: it = c.erase(it);
-            c.erase(it++);
+            it = c.erase(it);
         }
         else
         {
diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp
index 8080e43383a8a2128aa31499257e57281f49524d..a15a61429bf20a8fb17c1d71ed75e42a8aa3c32b 100644
--- a/indra/newview/llmeshrepository.cpp
+++ b/indra/newview/llmeshrepository.cpp
@@ -383,6 +383,9 @@ U32 LLMeshRepository::sLODPending = 0;
 
 U32 LLMeshRepository::sCacheBytesRead = 0;
 U32 LLMeshRepository::sCacheBytesWritten = 0;
+U32 LLMeshRepository::sCacheBytesHeaders = 0;
+U32 LLMeshRepository::sCacheBytesSkins = 0;
+U32 LLMeshRepository::sCacheBytesDecomps = 0;
 U32 LLMeshRepository::sCacheReads = 0;
 U32 LLMeshRepository::sCacheWrites = 0;
 U32 LLMeshRepository::sMaxLockHoldoffs = 0;
@@ -1877,6 +1880,7 @@ EMeshProcessingResult LLMeshRepoThread::headerReceived(const LLVolumeParams& mes
 			LLMutexLock lock(mHeaderMutex);
 			mMeshHeaderSize[mesh_id] = header_size;
 			mMeshHeader[mesh_id] = header;
+            LLMeshRepository::sCacheBytesHeaders += header_size;
 		}
 
 		
@@ -1972,7 +1976,7 @@ bool LLMeshRepoThread::skinInfoReceived(const LLUUID& mesh_id, U8* data, S32 dat
 		LLMeshSkinInfo info(skin);
 		info.mMeshID = mesh_id;
 
-		// LL_DEBUGS(LOG_MESH) << "info pelvis offset" << info.mPelvisOffset << LL_ENDL;
+        // LL_DEBUGS(LOG_MESH) << "info pelvis offset" << info.mPelvisOffset << LL_ENDL;
 		{
 			LLMutexLock lock(mMutex);
 			mSkinInfoQ.push_back(info);
@@ -2054,17 +2058,6 @@ EMeshProcessingResult LLMeshRepoThread::physicsShapeReceived(const LLUUID& mesh_
 
 		if (volume->unpackVolumeFaces(stream, data_size))
 		{
-			//load volume faces into decomposition buffer
-			S32 vertex_count = 0;
-			S32 index_count = 0;
-
-			for (S32 i = 0; i < volume->getNumVolumeFaces(); ++i)
-			{
-				const LLVolumeFace& face = volume->getVolumeFace(i);
-				vertex_count += face.mNumVertices;
-				index_count += face.mNumIndices;
-			}
-
 			d->mPhysicsShapeMesh.clear();
 
 			std::vector<LLVector3>& pos = d->mPhysicsShapeMesh.mPositions;
@@ -3019,27 +3012,6 @@ S32 LLMeshRepository::getActualMeshLOD(LLSD& header, S32 lod)
 	return -1;
 }
 
-void LLMeshRepository::cacheOutgoingMesh(LLMeshUploadData& data, LLSD& header)
-{
-	mThread->mMeshHeader[data.mUUID] = header;
-
-	// we cache the mesh for default parameters
-	LLVolumeParams volume_params;
-	volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE);
-	volume_params.setSculptID(data.mUUID, LL_SCULPT_TYPE_MESH);
-
-	for (U32 i = 0; i < 4; i++)
-	{
-		if (data.mModel[i].notNull())
-		{
-			LLPointer<LLVolume> volume = new LLVolume(volume_params, LLVolumeLODGroup::getVolumeScaleFromDetail(i));
-			volume->copyVolumeFaces(data.mModel[i]);
-			volume->setMeshAssetLoaded(TRUE);
-		}
-	}
-
-}
-
 // Handle failed or successful requests for mesh assets.
 //
 // Support for 200 responses was added for several reasons.  One,
@@ -3639,7 +3611,7 @@ S32 LLMeshRepository::update()
 
 S32 LLMeshRepository::loadMesh(LLVOVolume* vobj, const LLVolumeParams& mesh_params, S32 detail, S32 last_lod)
 {
-	LL_RECORD_BLOCK_TIME(FTM_MESH_FETCH);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; //LL_LL_RECORD_BLOCK_TIME(FTM_MESH_FETCH);
 	
 	// Manage time-to-load metrics for mesh download operations.
 	metricsProgress(1);
@@ -3722,7 +3694,7 @@ S32 LLMeshRepository::loadMesh(LLVOVolume* vobj, const LLVolumeParams& mesh_para
 
 void LLMeshRepository::notifyLoadedMeshes()
 { //called from main thread
-	LL_RECORD_BLOCK_TIME(FTM_MESH_FETCH);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; //LL_RECORD_BLOCK_TIME(FTM_MESH_FETCH);
 
     // GetMesh2 operation with keepalives, etc.  With pipelining,
     // we'll increase this.  See llappcorehttp and llcorehttp for
@@ -3957,6 +3929,8 @@ void LLMeshRepository::notifyLoadedMeshes()
 void LLMeshRepository::notifySkinInfoReceived(LLMeshSkinInfo& info)
 {
 	mSkinMap[info.mMeshID] = info;
+    // Alternative: We can get skin size from header
+    sCacheBytesSkins += info.sizeBytes();
 
 	skin_load_map::iterator iter = mLoadingSkins.find(info.mMeshID);
 	if (iter != mLoadingSkins.end())
@@ -3980,10 +3954,14 @@ void LLMeshRepository::notifyDecompositionReceived(LLModel::Decomposition* decom
 	{ //just insert decomp into map
 		mDecompositionMap[decomp->mMeshID] = decomp;
 		mLoadingDecompositions.erase(decomp->mMeshID);
+        sCacheBytesDecomps += decomp->sizeBytes();
 	}
 	else
 	{ //merge decomp with existing entry
+        sCacheBytesDecomps -= iter->second->sizeBytes();
 		iter->second->merge(decomp);
+        sCacheBytesDecomps += iter->second->sizeBytes();
+
 		mLoadingDecompositions.erase(decomp->mMeshID);
 		delete decomp;
 	}
@@ -4070,35 +4048,34 @@ S32 LLMeshRepository::getActualMeshLOD(const LLVolumeParams& mesh_params, S32 lo
 
 const LLMeshSkinInfo* LLMeshRepository::getSkinInfo(const LLUUID& mesh_id, const LLVOVolume* requesting_obj)
 {
-	LL_RECORD_BLOCK_TIME(FTM_MESH_FETCH);
-
-	if (mesh_id.notNull())
-	{
-		skin_map::iterator iter = mSkinMap.find(mesh_id);
-		if (iter != mSkinMap.end())
-		{
-			return &(iter->second);
-		}
-		
-		//no skin info known about given mesh, try to fetch it
-		{
-			LLMutexLock lock(mMeshMutex);
-			//add volume to list of loading meshes
-			skin_load_map::iterator iter = mLoadingSkins.find(mesh_id);
-			if (iter == mLoadingSkins.end())
-			{ //no request pending for this skin info
-				mPendingSkinRequests.push(mesh_id);
-			}
-			mLoadingSkins[mesh_id].insert(requesting_obj->getID());
-		}
-	}
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
+    if (mesh_id.notNull())
+    {
+        skin_map::iterator iter = mSkinMap.find(mesh_id);
+        if (iter != mSkinMap.end())
+        {
+            return &(iter->second);
+        }
 
+        //no skin info known about given mesh, try to fetch it
+        if (requesting_obj != nullptr)
+        {
+            LLMutexLock lock(mMeshMutex);
+            //add volume to list of loading meshes
+            skin_load_map::iterator iter = mLoadingSkins.find(mesh_id);
+            if (iter == mLoadingSkins.end())
+            { //no request pending for this skin info
+                mPendingSkinRequests.push(mesh_id);
+            }
+            mLoadingSkins[mesh_id].insert(requesting_obj->getID());
+        }
+    }
 	return NULL;
 }
 
 void LLMeshRepository::fetchPhysicsShape(const LLUUID& mesh_id)
 {
-	LL_RECORD_BLOCK_TIME(FTM_MESH_FETCH);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; //LL_RECORD_BLOCK_TIME(FTM_MESH_FETCH);
 
 	if (mesh_id.notNull())
 	{
@@ -4127,7 +4104,7 @@ void LLMeshRepository::fetchPhysicsShape(const LLUUID& mesh_id)
 
 LLModel::Decomposition* LLMeshRepository::getDecomposition(const LLUUID& mesh_id)
 {
-	LL_RECORD_BLOCK_TIME(FTM_MESH_FETCH);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; //LL_RECORD_BLOCK_TIME(FTM_MESH_FETCH);
 
 	LLModel::Decomposition* ret = NULL;
 
diff --git a/indra/newview/llmeshrepository.h b/indra/newview/llmeshrepository.h
index 441264d42fb8ecf3f2bae7b0086fe4a35dedbab2..f61da3e5715c98d9b369d80cbcd7017b3e184cc8 100644
--- a/indra/newview/llmeshrepository.h
+++ b/indra/newview/llmeshrepository.h
@@ -27,6 +27,7 @@
 #ifndef LL_MESH_REPOSITORY_H
 #define LL_MESH_REPOSITORY_H
 
+#include <unordered_map>
 #include "llassettype.h"
 #include "llmodel.h"
 #include "lluuid.h"
@@ -553,6 +554,9 @@ class LLMeshRepository
 	static U32 sLODProcessing;
 	static U32 sCacheBytesRead;
 	static U32 sCacheBytesWritten;
+    static U32 sCacheBytesHeaders;
+    static U32 sCacheBytesSkins;
+    static U32 sCacheBytesDecomps;
 	static U32 sCacheReads;						
 	static U32 sCacheWrites;
 	static U32 sMaxLockHoldoffs;				// Maximum sequential locking failures
@@ -584,7 +588,7 @@ class LLMeshRepository
 
 	S32 getActualMeshLOD(const LLVolumeParams& mesh_params, S32 lod);
 	static S32 getActualMeshLOD(LLSD& header, S32 lod);
-	const LLMeshSkinInfo* getSkinInfo(const LLUUID& mesh_id, const LLVOVolume* requesting_obj);
+	const LLMeshSkinInfo* getSkinInfo(const LLUUID& mesh_id, const LLVOVolume* requesting_obj = nullptr);
 	LLModel::Decomposition* getDecomposition(const LLUUID& mesh_id);
 	void fetchPhysicsShape(const LLUUID& mesh_id);
 	bool hasPhysicsShape(const LLUUID& mesh_id);
@@ -612,7 +616,7 @@ class LLMeshRepository
 	typedef std::map<LLVolumeParams, std::set<LLUUID> > mesh_load_map;
 	mesh_load_map mLoadingMeshes[4];
 	
-	typedef std::map<LLUUID, LLMeshSkinInfo> skin_map;
+	typedef std::unordered_map<LLUUID, LLMeshSkinInfo> skin_map;
 	skin_map mSkinMap;
 
 	typedef std::map<LLUUID, LLModel::Decomposition*> decomposition_map;
@@ -642,8 +646,6 @@ class LLMeshRepository
 	std::queue<LLUUID> mPendingPhysicsShapeRequests;
 	
 	U32 mMeshThreadCount;
-
-	void cacheOutgoingMesh(LLMeshUploadData& data, LLSD& header);
 	
 	LLMeshRepoThread* mThread;
 	std::vector<LLMeshUploadThread*> mUploads;
diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp
index 6b50e1f800c8f64536f87be6f6b9f52f568cc1f9..642df7f931fb56762dfa373b5d2014011b4a821e 100644
--- a/indra/newview/llmodelpreview.cpp
+++ b/indra/newview/llmodelpreview.cpp
@@ -41,6 +41,7 @@
 #include "lliconctrl.h"
 #include "llmatrix4a.h"
 #include "llmeshrepository.h"
+#include "llmeshoptimizer.h"
 #include "llrender.h"
 #include "llsdutil_math.h"
 #include "llskinningutil.h"
@@ -66,7 +67,6 @@
 #include "lltabcontainer.h"
 #include "lltextbox.h"
 
-#include "glod/glod.h"
 #include <boost/algorithm/string.hpp>
 
 bool LLModelPreview::sIgnoreLoadedCallback = false;
@@ -86,22 +86,10 @@ static const LLColor4 PREVIEW_DEG_FILL_COL(1.f, 0.f, 0.f, 0.5f);
 static const F32 PREVIEW_DEG_EDGE_WIDTH(3.f);
 static const F32 PREVIEW_DEG_POINT_SIZE(8.f);
 static const F32 PREVIEW_ZOOM_LIMIT(10.f);
+static const std::string DEFAULT_PHYSICS_MESH_NAME = "default_physics_shape";
 
 const F32 SKIN_WEIGHT_CAMERA_DISTANCE = 16.f;
 
-BOOL stop_gloderror()
-{
-    GLuint error = glodGetError();
-
-    if (error != GLOD_NO_ERROR)
-    {
-        LL_WARNS() << "GLOD error detected, cannot generate LOD: " << std::hex << error << LL_ENDL;
-        return TRUE;
-    }
-
-    return FALSE;
-}
-
 LLViewerFetchedTexture* bindMaterialDiffuseTexture(const LLImportMaterial& material)
 {
     LLViewerFetchedTexture *texture = LLViewerTextureManager::getFetchedTexture(material.getDiffuseMap(), FTT_DEFAULT, TRUE, LLGLTexture::BOOST_PREVIEW);
@@ -200,10 +188,6 @@ LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloater* fmp)
     mLoadState = LLModelLoader::STARTING;
     mGroup = 0;
     mLODFrozen = false;
-    mBuildShareTolerance = 0.f;
-    mBuildQueueMode = GLOD_QUEUE_GREEDY;
-    mBuildBorderMode = GLOD_BORDER_UNLOCK;
-    mBuildOperator = GLOD_OPERATOR_EDGE_COLLAPSE;
 
     for (U32 i = 0; i < LLModel::NUM_LODS; ++i)
     {
@@ -211,10 +195,6 @@ LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloater* fmp)
         mRequestedCreaseAngle[i] = -1.f;
         mRequestedLoDMode[i] = 0;
         mRequestedErrorThreshold[i] = 0.f;
-        mRequestedBuildOperator[i] = 0;
-        mRequestedQueueMode[i] = 0;
-        mRequestedBorderMode[i] = 0;
-        mRequestedShareTolerance[i] = 0.f;
     }
 
     mViewOption["show_textures"] = false;
@@ -224,23 +204,11 @@ LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloater* fmp)
     mHasPivot = false;
     mModelPivot = LLVector3(0.0f, 0.0f, 0.0f);
 
-    glodInit();
-
     createPreviewAvatar();
 }
 
 LLModelPreview::~LLModelPreview()
 {
-    // glod apparently has internal mem alignment issues that are angering
-    // the heap-check code in windows, these should be hunted down in that
-    // TP code, if possible
-    //
-    // kernel32.dll!HeapFree()  + 0x14 bytes	
-    // msvcr100.dll!free(void * pBlock)  Line 51	C
-    // glod.dll!glodGetGroupParameteriv()  + 0x119 bytes	
-    // glod.dll!glodShutdown()  + 0x77 bytes	
-    //
-    //glodShutdown();
     if (mModelLoader)
     {
         mModelLoader->shutdown();
@@ -465,6 +433,20 @@ void LLModelPreview::rebuildUploadData()
                         LLFloaterModelPreview::addStringToLog(out, false);
                     }
                 }
+                if (mWarnOfUnmatchedPhyicsMeshes && !lod_model && (i == LLModel::LOD_PHYSICS))
+                {
+                    // Despite the various strategies above, if we don't now have a physics model, we're going to end up with decomposition.
+                    // That's ok, but might not what they wanted. Use default_physics_shape if found.
+                    std::ostringstream out;
+                    out << "No physics model specified for " << instance.mLabel;
+                    if (mDefaultPhysicsShapeP)
+                    {
+                        out << " - using: " << DEFAULT_PHYSICS_MESH_NAME;
+                        lod_model = mDefaultPhysicsShapeP;
+                    }
+                    LL_WARNS() << out.str() << LL_ENDL;
+                    LLFloaterModelPreview::addStringToLog(out, !mDefaultPhysicsShapeP); // Flash log tab if no default.
+                }
 
                 if (lod_model)
                 {
@@ -527,7 +509,7 @@ void LLModelPreview::rebuildUploadData()
                 bool upload_skinweights = fmp && fmp->childGetValue("upload_skin").asBoolean();
                 if (upload_skinweights && high_lod_model->mSkinInfo.mJointNames.size() > 0)
                 {
-                    LLQuaternion bind_rot = LLSkinningUtil::getUnscaledQuaternion(high_lod_model->mSkinInfo.mBindShapeMatrix);
+                    LLQuaternion bind_rot = LLSkinningUtil::getUnscaledQuaternion(LLMatrix4(high_lod_model->mSkinInfo.mBindShapeMatrix));
                     LLQuaternion identity;
                     if (!bind_rot.isEqualEps(identity, 0.01))
                     {
@@ -762,11 +744,6 @@ void LLModelPreview::loadModel(std::string filename, S32 lod, bool force_disable
 
     mLODFile[lod] = filename;
 
-    if (lod == LLModel::LOD_HIGH)
-    {
-        clearGLODGroup();
-    }
-
     std::map<std::string, std::string> joint_alias_map;
     getJointAliases(joint_alias_map);
 
@@ -854,8 +831,10 @@ void LLModelPreview::clearIncompatible(S32 lod)
     // at this point we don't care about sub-models,
     // different amount of sub-models means face count mismatch, not incompatibility
     U32 lod_size = countRootModels(mModel[lod]);
+    bool replaced_base_model = (lod == LLModel::LOD_HIGH);
     for (U32 i = 0; i <= LLModel::LOD_HIGH; i++)
-    { //clear out any entries that aren't compatible with this model
+    {
+        // Clear out any entries that aren't compatible with this model
         if (i != lod)
         {
             if (countRootModels(mModel[i]) != lod_size)
@@ -867,29 +846,49 @@ void LLModelPreview::clearIncompatible(S32 lod)
                 if (i == LLModel::LOD_HIGH)
                 {
                     mBaseModel = mModel[lod];
-                    clearGLODGroup();
                     mBaseScene = mScene[lod];
                     mVertexBuffer[5].clear();
+                    replaced_base_model = true;
                 }
             }
         }
     }
-}
 
-void LLModelPreview::clearGLODGroup()
-{
-    if (mGroup)
+    if (replaced_base_model && !mGenLOD)
     {
-        for (std::map<LLPointer<LLModel>, U32>::iterator iter = mObject.begin(); iter != mObject.end(); ++iter)
+        // In case base was replaced, we might need to restart generation
+
+        // Check if already started
+        bool subscribe_for_generation = mLodsQuery.empty();
+        
+        // Remove previously scheduled work
+        mLodsQuery.clear();
+
+        LLFloaterModelPreview* fmp = LLFloaterModelPreview::sInstance;
+        if (!fmp) return;
+
+        // Schedule new work
+        for (S32 i = LLModel::LOD_HIGH; i >= 0; --i)
         {
-            glodDeleteObject(iter->second);
-            stop_gloderror();
+            if (mModel[i].empty())
+            {
+                // Base model was replaced, regenerate this lod if applicable
+                LLComboBox* lod_combo = mFMP->findChild<LLComboBox>("lod_source_" + lod_name[i]);
+                if (!lod_combo) return;
+
+                S32 lod_mode = lod_combo->getCurrentIndex();
+                if (lod_mode != LOD_FROM_FILE)
+                {
+                    mLodsQuery.push_back(i);
+                }
+            }
         }
-        mObject.clear();
 
-        glodDeleteGroup(mGroup);
-        stop_gloderror();
-        mGroup = 0;
+        // Subscribe if we have pending work and not subscribed yet
+        if (!mLodsQuery.empty() && subscribe_for_generation)
+        {
+            doOnIdleRepeating(lodQueryCallback);
+        }
     }
 }
 
@@ -1044,13 +1043,19 @@ void LLModelPreview::loadModelCallback(S32 loaded_lod)
             }
 
             mBaseModel = mModel[loaded_lod];
-            clearGLODGroup();
 
             mBaseScene = mScene[loaded_lod];
             mVertexBuffer[5].clear();
         }
         else
         {
+            if (loaded_lod == LLModel::LOD_PHYSICS)
+            {   // Explicitly loading physics. See if there is a default mesh.
+                LLMatrix4 ignored_transform; // Each mesh that uses this will supply their own.
+                mDefaultPhysicsShapeP = nullptr;
+                FindModel(mScene[loaded_lod], DEFAULT_PHYSICS_MESH_NAME + getLodSuffix(loaded_lod), mDefaultPhysicsShapeP, ignored_transform);
+                mWarnOfUnmatchedPhyicsMeshes = true;
+            }
             BOOL legacyMatching = gSavedSettings.getBOOL("ImporterLegacyMatching");
             if (!legacyMatching)
             {
@@ -1121,7 +1126,6 @@ void LLModelPreview::loadModelCallback(S32 loaded_lod)
                                     LL_WARNS() << out.str() << LL_ENDL;
                                     LLFloaterModelPreview::addStringToLog(out, false);
                                 }
-
                                 mModel[loaded_lod][idx]->mLabel = name;
                             }
                         }
@@ -1275,240 +1279,547 @@ void LLModelPreview::restoreNormals()
     updateStatusMessages();
 }
 
-void LLModelPreview::genLODs(S32 which_lod, U32 decimation, bool enforce_tri_limit)
+// Runs per object, but likely it is a better way to run per model+submodels
+// returns a ratio of base model indices to resulting indices
+// returns -1 in case of failure
+F32 LLModelPreview::genMeshOptimizerPerModel(LLModel *base_model, LLModel *target_model, F32 indices_decimator, F32 error_threshold, eSimplificationMode simplification_mode)
 {
-    // Allow LoD from -1 to LLModel::LOD_PHYSICS
-    if (which_lod < -1 || which_lod > LLModel::NUM_LODS - 1)
+    // I. Weld faces together
+    // Figure out buffer size
+    S32 size_indices = 0;
+    S32 size_vertices = 0;
+
+    for (U32 face_idx = 0; face_idx < base_model->getNumVolumeFaces(); ++face_idx)
     {
-        std::ostringstream out;
-        out << "Invalid level of detail: " << which_lod;
-        LL_WARNS() << out.str() << LL_ENDL;
-        LLFloaterModelPreview::addStringToLog(out, false);
-        assert(which_lod >= -1 && which_lod < LLModel::NUM_LODS);
-        return;
+        const LLVolumeFace &face = base_model->getVolumeFace(face_idx);
+        size_indices += face.mNumIndices;
+        size_vertices += face.mNumVertices;
     }
 
-    if (mBaseModel.empty())
+    if (size_indices < 3)
     {
-        return;
+        return -1;
     }
 
-    LLVertexBuffer::unbind();
+    // Allocate buffers, note that we are using U32 buffer instead of U16
+    U32* combined_indices = (U32*)ll_aligned_malloc_32(size_indices * sizeof(U32));
+    U32* output_indices = (U32*)ll_aligned_malloc_32(size_indices * sizeof(U32));
 
-    bool no_ff = LLGLSLShader::sNoFixedFunction;
-    LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
-    LLGLSLShader::sNoFixedFunction = false;
+    // extra space for normals and text coords
+    S32 tc_bytes_size = ((size_vertices * sizeof(LLVector2)) + 0xF) & ~0xF;
+    LLVector4a* combined_positions = (LLVector4a*)ll_aligned_malloc<64>(sizeof(LLVector4a) * 2 * size_vertices + tc_bytes_size);
+    LLVector4a* combined_normals = combined_positions + size_vertices;
+    LLVector2* combined_tex_coords = (LLVector2*)(combined_normals + size_vertices);
 
-    if (shader)
+    // copy indices and vertices into new buffers
+    S32 combined_positions_shift = 0;
+    S32 indices_idx_shift = 0;
+    S32 combined_indices_shift = 0;
+    for (U32 face_idx = 0; face_idx < base_model->getNumVolumeFaces(); ++face_idx)
     {
-        shader->unbind();
-    }
+        const LLVolumeFace &face = base_model->getVolumeFace(face_idx);
 
-    stop_gloderror();
-    static U32 cur_name = 1;
+        // Vertices
+        S32 copy_bytes = face.mNumVertices * sizeof(LLVector4a);
+        LLVector4a::memcpyNonAliased16((F32*)(combined_positions + combined_positions_shift), (F32*)face.mPositions, copy_bytes);
 
-    S32 limit = -1;
+        // Normals
+        LLVector4a::memcpyNonAliased16((F32*)(combined_normals + combined_positions_shift), (F32*)face.mNormals, copy_bytes);
 
-    U32 triangle_count = 0;
+        // Tex coords
+        copy_bytes = face.mNumVertices * sizeof(LLVector2);
+        memcpy((void*)(combined_tex_coords + combined_positions_shift), (void*)face.mTexCoords, copy_bytes);
 
-    U32 instanced_triangle_count = 0;
+        combined_positions_shift += face.mNumVertices;
 
-    //get the triangle count for the whole scene
-    for (LLModelLoader::scene::iterator iter = mBaseScene.begin(), endIter = mBaseScene.end(); iter != endIter; ++iter)
-    {
-        for (LLModelLoader::model_instance_list::iterator instance = iter->second.begin(), end_instance = iter->second.end(); instance != end_instance; ++instance)
+        // Indices
+        // Sadly can't do dumb memcpy for indices, need to adjust each value
+        for (S32 i = 0; i < face.mNumIndices; ++i)
         {
-            LLModel* mdl = instance->mModel;
-            if (mdl)
-            {
-                instanced_triangle_count += mdl->getNumTriangles();
-            }
+            U16 idx = face.mIndices[i];
+
+            combined_indices[combined_indices_shift] = idx + indices_idx_shift;
+            combined_indices_shift++;
         }
+        indices_idx_shift += face.mNumVertices;
     }
 
-    //get the triangle count for the non-instanced set of models
-    for (U32 i = 0; i < mBaseModel.size(); ++i)
+    // II. Generate a shadow buffer if nessesary.
+    // Welds together vertices if possible
+
+    U32* shadow_indices = NULL;
+    // if MESH_OPTIMIZER_FULL, just leave as is, since generateShadowIndexBufferU32
+    // won't do anything new, model was remaped on a per face basis.
+    // Similar for MESH_OPTIMIZER_NO_TOPOLOGY, it's pointless
+    // since 'simplifySloppy' ignores all topology, including normals and uvs.
+    // Note: simplifySloppy can affect UVs significantly.
+    if (simplification_mode == MESH_OPTIMIZER_NO_NORMALS)
+    {
+        // strip normals, reflections should restore relatively correctly
+        shadow_indices = (U32*)ll_aligned_malloc_32(size_indices * sizeof(U32));
+        LLMeshOptimizer::generateShadowIndexBufferU32(shadow_indices, combined_indices, size_indices, combined_positions, NULL, combined_tex_coords, size_vertices);
+    }
+    if (simplification_mode == MESH_OPTIMIZER_NO_UVS)
     {
-        triangle_count += mBaseModel[i]->getNumTriangles();
+        // strip uvs, can heavily affect textures
+        shadow_indices = (U32*)ll_aligned_malloc_32(size_indices * sizeof(U32));
+        LLMeshOptimizer::generateShadowIndexBufferU32(shadow_indices, combined_indices, size_indices, combined_positions, NULL, NULL, size_vertices);
     }
 
-    //get ratio of uninstanced triangles to instanced triangles
-    F32 triangle_ratio = (F32)triangle_count / (F32)instanced_triangle_count;
+    U32* source_indices = NULL;
+    if (shadow_indices)
+    {
+        source_indices = shadow_indices;
+    }
+    else
+    {
+        source_indices = combined_indices;
+    }
 
-    U32 base_triangle_count = triangle_count;
+    // III. Simplify
+    S32 target_indices = 0;
+    F32 result_error = 0; // how far from original the model is, 1 == 100%
+    S32 size_new_indices = 0;
 
-    U32 type_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0;
+    if (indices_decimator > 0)
+    {
+        target_indices = llclamp(llfloor(size_indices / indices_decimator), 3, (S32)size_indices); // leave at least one triangle
+    }
+    else // indices_decimator can be zero for error_threshold based calculations
+    {
+        target_indices = 3;
+    }
 
-    U32 lod_mode = 0;
+    size_new_indices = LLMeshOptimizer::simplifyU32(
+        output_indices,
+        source_indices,
+        size_indices,
+        combined_positions,
+        size_vertices,
+        LLVertexBuffer::sTypeSize[LLVertexBuffer::TYPE_VERTEX],
+        target_indices,
+        error_threshold,
+        simplification_mode == MESH_OPTIMIZER_NO_TOPOLOGY,
+        &result_error);
 
-    F32 lod_error_threshold = 0;
+    if (result_error < 0)
+    {
+        LL_WARNS() << "Negative result error from meshoptimizer for model " << target_model->mLabel
+            << " target Indices: " << target_indices
+            << " new Indices: " << size_new_indices
+            << " original count: " << size_indices << LL_ENDL;
+    }
 
-    // The LoD should be in range from Lowest to High
-    if (which_lod > -1 && which_lod < NUM_LOD)
+    // free unused buffers
+    ll_aligned_free_32(combined_indices);
+    ll_aligned_free_32(shadow_indices);
+    combined_indices = NULL;
+    shadow_indices = NULL;
+
+    if (size_new_indices < 3)
     {
-        LLCtrlSelectionInterface* iface = mFMP->childGetSelectionInterface("lod_mode_" + lod_name[which_lod]);
-        if (iface)
+        // Model should have at least one visible triangle
+        ll_aligned_free<64>(combined_positions);
+        ll_aligned_free_32(output_indices);
+
+        return -1;
+    }
+
+    // IV. Repack back into individual faces
+
+    LLVector4a* buffer_positions = (LLVector4a*)ll_aligned_malloc<64>(sizeof(LLVector4a) * 2 * size_vertices + tc_bytes_size);
+    LLVector4a* buffer_normals = buffer_positions + size_vertices;
+    LLVector2* buffer_tex_coords = (LLVector2*)(buffer_normals + size_vertices);
+    S32 buffer_idx_size = (size_indices * sizeof(U16) + 0xF) & ~0xF;
+    U16* buffer_indices = (U16*)ll_aligned_malloc_16(buffer_idx_size);
+    S32* old_to_new_positions_map = new S32[size_vertices];
+
+    S32 buf_positions_copied = 0;
+    S32 buf_indices_copied = 0;
+    indices_idx_shift = 0;
+    S32 valid_faces = 0;
+
+    // Crude method to copy indices back into face
+    for (U32 face_idx = 0; face_idx < base_model->getNumVolumeFaces(); ++face_idx)
+    {
+        const LLVolumeFace &face = base_model->getVolumeFace(face_idx);
+
+        // reset data for new run
+        buf_positions_copied = 0;
+        buf_indices_copied = 0;
+        bool copy_triangle = false;
+        S32 range = indices_idx_shift + face.mNumVertices;
+
+        for (S32 i = 0; i < size_vertices; i++)
         {
-            lod_mode = iface->getFirstSelectedIndex();
+            old_to_new_positions_map[i] = -1;
         }
 
-        lod_error_threshold = mFMP->childGetValue("lod_error_threshold_" + lod_name[which_lod]).asReal();
+        // Copy relevant indices and vertices
+        for (S32 i = 0; i < size_new_indices; ++i)
+        {
+            U32 idx = output_indices[i];
+
+            if ((i % 3) == 0)
+            {
+                copy_triangle = idx >= indices_idx_shift && idx < range;
+            }
+
+            if (copy_triangle)
+            {
+                if (old_to_new_positions_map[idx] == -1)
+                {
+                    // New position, need to copy it
+                    // Validate size
+                    if (buf_positions_copied >= U16_MAX)
+                    {
+                        // Normally this shouldn't happen since the whole point is to reduce amount of vertices
+                        // but it might happen if user tries to run optimization with too large triangle or error value
+                        // so fallback to 'per face' mode or verify requested limits and copy base model as is.
+                        LL_WARNS() << "Over triangle limit. Failed to optimize in 'per object' mode, falling back to per face variant for"
+                            << " model " << target_model->mLabel
+                            << " target Indices: " << target_indices
+                            << " new Indices: " << size_new_indices
+                            << " original count: " << size_indices
+                            << " error treshold: " << error_threshold
+                            << LL_ENDL;
+
+                        // U16 vertices overflow shouldn't happen, but just in case
+                        size_new_indices = 0;
+                        valid_faces = 0;
+                        for (U32 face_idx = 0; face_idx < base_model->getNumVolumeFaces(); ++face_idx)
+                        {
+                            genMeshOptimizerPerFace(base_model, target_model, face_idx, indices_decimator, error_threshold, simplification_mode);
+                            const LLVolumeFace &face = target_model->getVolumeFace(face_idx);
+                            size_new_indices += face.mNumIndices;
+                            if (face.mNumIndices >= 3)
+                            {
+                                valid_faces++;
+                            }
+                        }
+                        if (valid_faces)
+                        {
+                            return (F32)size_indices / (F32)size_new_indices;
+                        }
+                        else
+                        {
+                            return -1;
+                        }
+                    }
+
+                    // Copy vertice, normals, tcs
+                    buffer_positions[buf_positions_copied] = combined_positions[idx];
+                    buffer_normals[buf_positions_copied] = combined_normals[idx];
+                    buffer_tex_coords[buf_positions_copied] = combined_tex_coords[idx];
+
+                    old_to_new_positions_map[idx] = buf_positions_copied;
+
+                    buffer_indices[buf_indices_copied] = (U16)buf_positions_copied;
+                    buf_positions_copied++;
+                }
+                else
+                {
+                    // existing position
+                    buffer_indices[buf_indices_copied] = (U16)old_to_new_positions_map[idx];
+                }
+                buf_indices_copied++;
+            }
+        }
+
+        if (buf_positions_copied >= U16_MAX)
+        {
+            break;
+        }
+
+        LLVolumeFace &new_face = target_model->getVolumeFace(face_idx);
+        //new_face = face; //temp
+
+        if (buf_indices_copied < 3)
+        {
+            // face was optimized away
+            new_face.resizeIndices(3);
+            new_face.resizeVertices(1);
+            memset(new_face.mIndices, 0, sizeof(U16) * 3);
+            new_face.mPositions[0].clear(); // set first vertice to 0
+            new_face.mNormals[0].clear();
+            new_face.mTexCoords[0].setZero();
+        }
+        else
+        {
+            new_face.resizeIndices(buf_indices_copied);
+            new_face.resizeVertices(buf_positions_copied);
+
+            S32 idx_size = (buf_indices_copied * sizeof(U16) + 0xF) & ~0xF;
+            LLVector4a::memcpyNonAliased16((F32*)new_face.mIndices, (F32*)buffer_indices, idx_size);
+
+            LLVector4a::memcpyNonAliased16((F32*)new_face.mPositions, (F32*)buffer_positions, buf_positions_copied * sizeof(LLVector4a));
+            LLVector4a::memcpyNonAliased16((F32*)new_face.mNormals, (F32*)buffer_normals, buf_positions_copied * sizeof(LLVector4a));
+
+            U32 tex_size = (buf_positions_copied * sizeof(LLVector2) + 0xF)&~0xF;
+            LLVector4a::memcpyNonAliased16((F32*)new_face.mTexCoords, (F32*)buffer_tex_coords, tex_size);
+
+            valid_faces++;
+        }
+
+        indices_idx_shift += face.mNumVertices;
     }
 
-    if (which_lod != -1)
+    delete[]old_to_new_positions_map;
+    ll_aligned_free<64>(combined_positions);
+    ll_aligned_free<64>(buffer_positions);
+    ll_aligned_free_32(output_indices);
+    ll_aligned_free_16(buffer_indices);
+
+    if (size_new_indices < 3 || valid_faces == 0)
+    {
+        // Model should have at least one visible triangle
+        return -1;
+    }
+
+    return (F32)size_indices / (F32)size_new_indices;
+}
+
+F32 LLModelPreview::genMeshOptimizerPerFace(LLModel *base_model, LLModel *target_model, U32 face_idx, F32 indices_decimator, F32 error_threshold, eSimplificationMode simplification_mode)
+{
+    const LLVolumeFace &face = base_model->getVolumeFace(face_idx);
+    S32 size_indices = face.mNumIndices;
+    if (size_indices < 3)
+    {
+        return -1;
+    }
+
+    S32 size = (size_indices * sizeof(U16) + 0xF) & ~0xF;
+    U16* output_indices = (U16*)ll_aligned_malloc_16(size);
+
+    U16* shadow_indices = NULL;
+    // if MESH_OPTIMIZER_FULL, just leave as is, since generateShadowIndexBufferU32
+    // won't do anything new, model was remaped on a per face basis.
+    // Similar for MESH_OPTIMIZER_NO_TOPOLOGY, it's pointless
+    // since 'simplifySloppy' ignores all topology, including normals and uvs.
+    if (simplification_mode == MESH_OPTIMIZER_NO_NORMALS)
+    {
+        U16* shadow_indices = (U16*)ll_aligned_malloc_16(size);
+        LLMeshOptimizer::generateShadowIndexBufferU16(shadow_indices, face.mIndices, size_indices, face.mPositions, NULL, face.mTexCoords, face.mNumVertices);
+    }
+    if (simplification_mode == MESH_OPTIMIZER_NO_UVS)
+    {
+        U16* shadow_indices = (U16*)ll_aligned_malloc_16(size);
+        LLMeshOptimizer::generateShadowIndexBufferU16(shadow_indices, face.mIndices, size_indices, face.mPositions, NULL, NULL, face.mNumVertices);
+    }
+    // Don't run ShadowIndexBuffer for MESH_OPTIMIZER_NO_TOPOLOGY, it's pointless
+
+    U16* source_indices = NULL;
+    if (shadow_indices)
+    {
+        source_indices = shadow_indices;
+    }
+    else
+    {
+        source_indices = face.mIndices;
+    }
+
+    S32 target_indices = 0;
+    F32 result_error = 0; // how far from original the model is, 1 == 100%
+    S32 size_new_indices = 0;
+
+    if (indices_decimator > 0)
     {
-        mRequestedLoDMode[which_lod] = lod_mode;
+        target_indices = llclamp(llfloor(size_indices / indices_decimator), 3, (S32)size_indices); // leave at least one triangle
     }
+    else
+    {
+        target_indices = 3;
+    }
+
+    size_new_indices = LLMeshOptimizer::simplify(
+        output_indices,
+        source_indices,
+        size_indices,
+        face.mPositions,
+        face.mNumVertices,
+        LLVertexBuffer::sTypeSize[LLVertexBuffer::TYPE_VERTEX],
+        target_indices,
+        error_threshold,
+        simplification_mode == MESH_OPTIMIZER_NO_TOPOLOGY,
+        &result_error);
 
-    if (lod_mode == 0)
+    if (result_error < 0)
     {
-        lod_mode = GLOD_TRIANGLE_BUDGET;
+        LL_WARNS() << "Negative result error from meshoptimizer for face " << face_idx
+            << " of model " << target_model->mLabel
+            << " target Indices: " << target_indices
+            << " new Indices: " << size_new_indices
+            << " original count: " << size_indices
+            << " error treshold: " << error_threshold
+            << LL_ENDL;
+    }
+
+    LLVolumeFace &new_face = target_model->getVolumeFace(face_idx);
+
+    // Copy old values
+    new_face = face;
 
-        // The LoD should be in range from Lowest to High
-        if (which_lod > -1 && which_lod < NUM_LOD)
+    if (size_new_indices < 3)
+    {
+        if (simplification_mode != MESH_OPTIMIZER_NO_TOPOLOGY)
         {
-            limit = mFMP->childGetValue("lod_triangle_limit_" + lod_name[which_lod]).asInteger();
-            //convert from "scene wide" to "non-instanced" triangle limit
-            limit = (S32)((F32)limit*triangle_ratio);
+            // meshopt_optimizeSloppy() can optimize triangles away even if target_indices is > 2,
+            // but optimize() isn't supposed to
+            LL_INFOS() << "No indices generated by meshoptimizer for face " << face_idx
+                << " of model " << target_model->mLabel
+                << " target Indices: " << target_indices
+                << " original count: " << size_indices
+                << " error treshold: " << error_threshold
+                << LL_ENDL;
         }
+
+        // Face got optimized away
+        // Generate empty triangle
+        new_face.resizeIndices(3);
+        new_face.resizeVertices(1);
+        memset(new_face.mIndices, 0, sizeof(U16) * 3);
+        new_face.mPositions[0].clear(); // set first vertice to 0
+        new_face.mNormals[0].clear();
+        new_face.mTexCoords[0].setZero();
     }
     else
     {
-        lod_mode = GLOD_ERROR_THRESHOLD;
-    }
+        // Assign new values
+        new_face.resizeIndices(size_new_indices); // will wipe out mIndices, so new_face can't substitute output
+        S32 idx_size = (size_new_indices * sizeof(U16) + 0xF) & ~0xF;
+        LLVector4a::memcpyNonAliased16((F32*)new_face.mIndices, (F32*)output_indices, idx_size);
 
-    bool object_dirty = false;
+        // Clear unused values
+        new_face.optimize();
+    }
 
-    if (mGroup == 0)
+    ll_aligned_free_16(output_indices);
+    ll_aligned_free_16(shadow_indices);
+     
+    if (size_new_indices < 3)
     {
-        object_dirty = true;
-        mGroup = cur_name++;
-        glodNewGroup(mGroup);
+        // At least one triangle is needed
+        return -1;
     }
 
-    if (object_dirty)
+    return (F32)size_indices / (F32)size_new_indices;
+}
+
+void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 decimation, bool enforce_tri_limit)
+{
+    LL_INFOS() << "Generating lod " << which_lod << " using meshoptimizer" << LL_ENDL;
+    // Allow LoD from -1 to LLModel::LOD_PHYSICS
+    if (which_lod < -1 || which_lod > LLModel::NUM_LODS - 1)
     {
-        for (LLModelLoader::model_list::iterator iter = mBaseModel.begin(); iter != mBaseModel.end(); ++iter)
-        { //build GLOD objects for each model in base model list
-            LLModel* mdl = *iter;
+        std::ostringstream out;
+        out << "Invalid level of detail: " << which_lod;
+        LL_WARNS() << out.str() << LL_ENDL;
+        LLFloaterModelPreview::addStringToLog(out, false);
+        assert(lod >= -1 && lod < LLModel::NUM_LODS);
+        return;
+    }
 
-            if (mObject[mdl] != 0)
-            {
-                glodDeleteObject(mObject[mdl]);
-            }
+    if (mBaseModel.empty())
+    {
+        return;
+    }
 
-            mObject[mdl] = cur_name++;
+    //get the triangle count for all base models
+    S32 base_triangle_count = 0;
+    for (S32 i = 0; i < mBaseModel.size(); ++i)
+    {
+        base_triangle_count += mBaseModel[i]->getNumTriangles();
+    }
 
-            glodNewObject(mObject[mdl], mGroup, GLOD_DISCRETE);
-            stop_gloderror();
+    // Urgh...
+    // TODO: add interface to mFMP to get error treshold or let mFMP write one into LLModelPreview
+    // We should not be accesing views from other class!
+    U32 lod_mode = LIMIT_TRIANGLES;
+    F32 indices_decimator = 0;
+    F32 triangle_limit = 0;
+    F32 lod_error_threshold = 1; //100%
 
-            if (iter == mBaseModel.begin() && !mdl->mSkinWeights.empty())
-            { //regenerate vertex buffer for skinned models to prevent animation feedback during LOD generation
-                mVertexBuffer[5].clear();
-            }
+    // If requesting a single lod
+    if (which_lod > -1 && which_lod < NUM_LOD)
+    {
+        LLCtrlSelectionInterface* iface = mFMP->childGetSelectionInterface("lod_mode_" + lod_name[which_lod]);
+        if (iface)
+        {
+            lod_mode = iface->getFirstSelectedIndex();
+        }
 
-            if (mVertexBuffer[5].empty())
+        if (lod_mode == LIMIT_TRIANGLES)
+        {
+            if (!enforce_tri_limit)
             {
-                genBuffers(5, false);
-            }
+                triangle_limit = base_triangle_count;
+                // reset to default value for this lod
+                F32 pw = pow((F32)decimation, (F32)(LLModel::LOD_HIGH - which_lod));
 
-            U32 tri_count = 0;
-            for (U32 i = 0; i < mVertexBuffer[5][mdl].size(); ++i)
+                triangle_limit /= pw; //indices_ratio can be 1/pw
+            }
+            else
             {
-                LLVertexBuffer* buff = mVertexBuffer[5][mdl][i];
-                buff->setBuffer(type_mask & buff->getTypeMask());
 
-                U32 num_indices = mVertexBuffer[5][mdl][i]->getNumIndices();
-                if (num_indices > 2)
-                {
-                    glodInsertElements(mObject[mdl], i, GL_TRIANGLES, num_indices, GL_UNSIGNED_SHORT, (U8*)mVertexBuffer[5][mdl][i]->getIndicesPointer(), 0, 0.f);
-                }
-                tri_count += num_indices / 3;
-                stop_gloderror();
-            }
+                // UI spacifies limit for all models of single lod
+                triangle_limit = mFMP->childGetValue("lod_triangle_limit_" + lod_name[which_lod]).asInteger();
 
-            glodBuildObject(mObject[mdl]);
-            stop_gloderror();
+            }
+            // meshoptimizer doesn't use triangle limit, it uses indices limit, so convert it to aproximate ratio
+            // triangle_limit can be 0.
+            indices_decimator = (F32)base_triangle_count / llmax(triangle_limit, 1.f);
         }
+        else
+        {
+            // UI shows 0 to 100%, but meshoptimizer works with 0 to 1
+            lod_error_threshold = mFMP->childGetValue("lod_error_threshold_" + lod_name[which_lod]).asReal() / 100.f;
+        }
+    }
+    else
+    {
+        // we are genrating all lods and each lod will get own indices_decimator
+        indices_decimator = 1;
+        triangle_limit = base_triangle_count;
     }
 
+    mMaxTriangleLimit = base_triangle_count;
+
+    // Build models
 
     S32 start = LLModel::LOD_HIGH;
     S32 end = 0;
 
     if (which_lod != -1)
     {
-        start = end = which_lod;
+        start = which_lod;
+        end = which_lod;
     }
 
-    mMaxTriangleLimit = base_triangle_count;
-
     for (S32 lod = start; lod >= end; --lod)
     {
         if (which_lod == -1)
         {
+            // we are genrating all lods and each lod gets own indices_ratio
             if (lod < start)
             {
-                triangle_count /= decimation;
-            }
-        }
-        else
-        {
-            if (enforce_tri_limit)
-            {
-                triangle_count = limit;
-            }
-            else
-            {
-                for (S32 j = LLModel::LOD_HIGH; j>which_lod; --j)
-                {
-                    triangle_count /= decimation;
-                }
+                indices_decimator *= decimation;
+                triangle_limit /= decimation;
             }
         }
 
+        mRequestedTriangleCount[lod] = triangle_limit;
+        mRequestedErrorThreshold[lod] = lod_error_threshold * 100;
+        mRequestedLoDMode[lod] = lod_mode;
+
         mModel[lod].clear();
         mModel[lod].resize(mBaseModel.size());
         mVertexBuffer[lod].clear();
 
-        U32 actual_tris = 0;
-        U32 actual_verts = 0;
-        U32 submeshes = 0;
-
-        mRequestedTriangleCount[lod] = (S32)((F32)triangle_count / triangle_ratio);
-        mRequestedErrorThreshold[lod] = lod_error_threshold;
-
-        glodGroupParameteri(mGroup, GLOD_ADAPT_MODE, lod_mode);
-        stop_gloderror();
-
-        glodGroupParameteri(mGroup, GLOD_ERROR_MODE, GLOD_OBJECT_SPACE_ERROR);
-        stop_gloderror();
-
-        glodGroupParameterf(mGroup, GLOD_OBJECT_SPACE_ERROR_THRESHOLD, lod_error_threshold);
-        stop_gloderror();
-
-        if (lod_mode != GLOD_TRIANGLE_BUDGET)
-        {
-            glodGroupParameteri(mGroup, GLOD_MAX_TRIANGLES, 0);
-        }
-        else
-        {
-            //SH-632: always add 1 to desired amount to avoid decimating below desired amount
-            glodGroupParameteri(mGroup, GLOD_MAX_TRIANGLES, triangle_count + 1);
-        }
-
-        stop_gloderror();
-        glodAdaptGroup(mGroup);
-        stop_gloderror();
 
         for (U32 mdl_idx = 0; mdl_idx < mBaseModel.size(); ++mdl_idx)
         {
             LLModel* base = mBaseModel[mdl_idx];
 
-            GLint patch_count = 0;
-            glodGetObjectParameteriv(mObject[base], GLOD_NUM_PATCHES, &patch_count);
-            stop_gloderror();
-
             LLVolumeParams volume_params;
             volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE);
             mModel[lod][mdl_idx] = new LLModel(volume_params, 0.f);
@@ -1517,74 +1828,173 @@ void LLModelPreview::genLODs(S32 which_lod, U32 decimation, bool enforce_tri_lim
 
             mModel[lod][mdl_idx]->mLabel = name;
             mModel[lod][mdl_idx]->mSubmodelID = base->mSubmodelID;
-
-            GLint* sizes = new GLint[patch_count * 2];
-            glodGetObjectParameteriv(mObject[base], GLOD_PATCH_SIZES, sizes);
-            stop_gloderror();
-
-            GLint* names = new GLint[patch_count];
-            glodGetObjectParameteriv(mObject[base], GLOD_PATCH_NAMES, names);
-            stop_gloderror();
-
-            mModel[lod][mdl_idx]->setNumVolumeFaces(patch_count);
+            mModel[lod][mdl_idx]->setNumVolumeFaces(base->getNumVolumeFaces());
 
             LLModel* target_model = mModel[lod][mdl_idx];
 
-            for (GLint i = 0; i < patch_count; ++i)
-            {
-                type_mask = mVertexBuffer[5][base][i]->getTypeMask();
-
-                LLPointer<LLVertexBuffer> buff = new LLVertexBuffer(type_mask, 0);
+            S32 model_meshopt_mode = meshopt_mode;
 
-                if (sizes[i * 2 + 1] > 0 && sizes[i * 2] > 0)
+            // Ideally this should run not per model,
+            // but combine all submodels with origin model as well
+            if (model_meshopt_mode == MESH_OPTIMIZER_PRECISE)
+            {
+                // Run meshoptimizer for each face
+                for (U32 face_idx = 0; face_idx < base->getNumVolumeFaces(); ++face_idx)
                 {
-                    if (!buff->allocateBuffer(sizes[i * 2 + 1], sizes[i * 2], true))
+                    F32 res = genMeshOptimizerPerFace(base, target_model, face_idx, indices_decimator, lod_error_threshold, MESH_OPTIMIZER_FULL);
+                    if (res < 0)
                     {
-                        // Todo: find a way to stop preview in this case instead of crashing
-                        LL_ERRS() << "Failed buffer allocation during preview LOD generation."
-                            << " Vertices: " << sizes[i * 2 + 1]
-                            << " Indices: " << sizes[i * 2] << LL_ENDL;
+                        // Mesh optimizer failed and returned an invalid model
+                        const LLVolumeFace &face = base->getVolumeFace(face_idx);
+                        LLVolumeFace &new_face = target_model->getVolumeFace(face_idx);
+                        new_face = face;
                     }
-                    buff->setBuffer(type_mask);
-                    glodFillElements(mObject[base], names[i], GL_UNSIGNED_SHORT, (U8*)buff->getIndicesPointer());
-                    stop_gloderror();
                 }
-                else
+            }
+
+            if (model_meshopt_mode == MESH_OPTIMIZER_SLOPPY)
+            {
+                // Run meshoptimizer for each face
+                for (U32 face_idx = 0; face_idx < base->getNumVolumeFaces(); ++face_idx)
                 {
-                    // This face was eliminated or we failed to allocate buffer,
-                    // attempt to create a dummy triangle (one vertex, 3 indices, all 0)
-                    buff->allocateBuffer(1, 3, true);
-                    memset((U8*)buff->getMappedData(), 0, buff->getSize());
-                    memset((U8*)buff->getIndicesPointer(), 0, buff->getIndicesSize());
+                    if (genMeshOptimizerPerFace(base, target_model, face_idx, indices_decimator, lod_error_threshold, MESH_OPTIMIZER_NO_TOPOLOGY) < 0)
+                    {
+                        // Sloppy failed and returned an invalid model
+                        genMeshOptimizerPerFace(base, target_model, face_idx, indices_decimator, lod_error_threshold, MESH_OPTIMIZER_FULL);
+                    }
                 }
+            }
 
-                buff->validateRange(0, buff->getNumVerts() - 1, buff->getNumIndices(), 0);
-
-                LLStrider<LLVector3> pos;
-                LLStrider<LLVector3> norm;
-                LLStrider<LLVector2> tc;
-                LLStrider<U16> index;
+            if (model_meshopt_mode == MESH_OPTIMIZER_AUTO)
+            {
+                // Remove progressively more data if we can't reach the target.
+                F32 allowed_ratio_drift = 1.8f;
+                F32 precise_ratio = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, MESH_OPTIMIZER_FULL);
 
-                buff->getVertexStrider(pos);
-                if (type_mask & LLVertexBuffer::MAP_NORMAL)
+                if (precise_ratio < 0 || (precise_ratio * allowed_ratio_drift < indices_decimator))
                 {
-                    buff->getNormalStrider(norm);
+                    precise_ratio = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, MESH_OPTIMIZER_NO_NORMALS);
                 }
-                if (type_mask & LLVertexBuffer::MAP_TEXCOORD0)
+
+                if (precise_ratio < 0 || (precise_ratio * allowed_ratio_drift < indices_decimator))
                 {
-                    buff->getTexCoord0Strider(tc);
+                    precise_ratio = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, MESH_OPTIMIZER_NO_UVS);
                 }
+                
+                if (precise_ratio < 0 || (precise_ratio * allowed_ratio_drift < indices_decimator))
+                {
+                    // Try sloppy variant if normal one failed to simplify model enough.
+                    // Sloppy variant can fail entirely and has issues with precision,
+                    // so code needs to do multiple attempts with different decimators.
+                    // Todo: this is a bit of a mess, needs to be refined and improved
 
-                buff->getIndexStrider(index);
+                    F32 last_working_decimator = 0.f;
+                    F32 last_working_ratio = F32_MAX;
 
-                target_model->setVolumeFaceData(names[i], pos, norm, tc, index, buff->getNumVerts(), buff->getNumIndices());
-                actual_tris += buff->getNumIndices() / 3;
-                actual_verts += buff->getNumVerts();
-                ++submeshes;
+                    F32 sloppy_ratio = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, MESH_OPTIMIZER_NO_TOPOLOGY);
 
-                if (!validate_face(target_model->getVolumeFace(names[i])))
+                    if (sloppy_ratio > 0)
+                    {
+                        // Would be better to do a copy of target_model here, but if
+                        // we need to use sloppy decimation, model should be cheap
+                        // and fast to generate and it won't affect end result
+                        last_working_decimator = indices_decimator;
+                        last_working_ratio = sloppy_ratio;
+                    }
+
+                    // Sloppy has a tendecy to error into lower side, so a request for 100
+                    // triangles turns into ~70, so check for significant difference from target decimation
+                    F32 sloppy_ratio_drift = 1.4f;
+                    if (lod_mode == LIMIT_TRIANGLES
+                        && (sloppy_ratio > indices_decimator * sloppy_ratio_drift || sloppy_ratio < 0))
+                    {
+                        // Apply a correction to compensate.
+
+                        // (indices_decimator / res_ratio) by itself is likely to overshoot to a differend
+                        // side due to overal lack of precision, and we don't need an ideal result, which
+                        // likely does not exist, just a better one, so a partial correction is enough.
+                        F32 sloppy_decimator = indices_decimator * (indices_decimator / sloppy_ratio + 1) / 2;
+                        sloppy_ratio = genMeshOptimizerPerModel(base, target_model, sloppy_decimator, lod_error_threshold, MESH_OPTIMIZER_NO_TOPOLOGY);
+                    }
+
+                    if (last_working_decimator > 0 && sloppy_ratio < last_working_ratio)
+                    {
+                        // Compensation didn't work, return back to previous decimator
+                        sloppy_ratio = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, MESH_OPTIMIZER_NO_TOPOLOGY);
+                    }
+
+                    if (sloppy_ratio < 0)
+                    {
+                        // Sloppy method didn't work, try with smaller decimation values
+                        S32 size_vertices = 0;
+
+                        for (U32 face_idx = 0; face_idx < base->getNumVolumeFaces(); ++face_idx)
+                        {
+                            const LLVolumeFace &face = base->getVolumeFace(face_idx);
+                            size_vertices += face.mNumVertices;
+                        }
+
+                        // Complex models aren't supposed to get here, they are supposed
+                        // to work on a first try of sloppy due to having more viggle room.
+                        // If they didn't, something is likely wrong, no point locking the
+                        // thread in a long calculation that will fail.
+                        const U32 too_many_vertices = 27000;
+                        if (size_vertices > too_many_vertices)
+                        {
+                            LL_WARNS() << "Sloppy optimization method failed for a complex model " << target_model->getName() << LL_ENDL;
+                        }
+                        else
+                        {
+                            // Find a decimator that does work
+                            F32 sloppy_decimation_step = sqrt((F32)decimation); // example: 27->15->9->5->3
+                            F32 sloppy_decimator = indices_decimator / sloppy_decimation_step;
+
+                            while (sloppy_ratio < 0
+                                && sloppy_decimator > precise_ratio
+                                && sloppy_decimator > 1)// precise_ratio isn't supposed to be below 1, but check just in case
+                            {
+                                sloppy_ratio = genMeshOptimizerPerModel(base, target_model, sloppy_decimator, lod_error_threshold, MESH_OPTIMIZER_NO_TOPOLOGY);
+                                sloppy_decimator = sloppy_decimator / sloppy_decimation_step;
+                            }
+                        }
+                    }
+
+                    if (sloppy_ratio < 0 || sloppy_ratio < precise_ratio)
+                    {
+                        // Sloppy variant failed to generate triangles or is worse.
+                        // Can happen with models that are too simple as is.
+
+                        if (precise_ratio < 0)
+                        {
+                            // Precise method failed as well, just copy face over
+                            target_model->copyVolumeFaces(base);
+                            precise_ratio = 1.f;
+                        }
+                        else
+                        {
+                            // Fallback to normal method
+                            precise_ratio = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, MESH_OPTIMIZER_FULL);
+                        }
+
+                        LL_INFOS() << "Model " << target_model->getName()
+                            << " lod " << which_lod
+                            << " resulting ratio " << precise_ratio
+                            << " simplified using per model method." << LL_ENDL;
+                    }
+                    else
+                    {
+                        LL_INFOS() << "Model " << target_model->getName()
+                            << " lod " << which_lod
+                            << " resulting ratio " << sloppy_ratio
+                            << " sloppily simplified using per model method." << LL_ENDL;
+                    }
+                }
+                else
                 {
-                    LL_ERRS() << "Invalid face generated during LOD generation." << LL_ENDL;
+                    LL_INFOS() << "Model " << target_model->getName()
+                        << " lod " << which_lod
+                        << " resulting ratio " << precise_ratio
+                        << " simplified using per model method." << LL_ENDL;
                 }
             }
 
@@ -1594,6 +2004,7 @@ void LLModelPreview::genLODs(S32 which_lod, U32 decimation, bool enforce_tri_lim
             target_model->mPosition = base->mPosition;
             target_model->mSkinWeights = base->mSkinWeights;
             target_model->mSkinInfo = base->mSkinInfo;
+
             //copy material list
             target_model->mMaterialList = base->mMaterialList;
 
@@ -1601,9 +2012,6 @@ void LLModelPreview::genLODs(S32 which_lod, U32 decimation, bool enforce_tri_lim
             {
                 LL_ERRS() << "Invalid model generated when creating LODs" << LL_ENDL;
             }
-
-            delete[] sizes;
-            delete[] names;
         }
 
         //rebuild scene based on mBaseScene
@@ -1629,13 +2037,6 @@ void LLModelPreview::genLODs(S32 which_lod, U32 decimation, bool enforce_tri_lim
             }
         }
     }
-
-    LLVertexBuffer::unbind();
-    LLGLSLShader::sNoFixedFunction = no_ff;
-    if (shader)
-    {
-        shader->bind();
-    }
 }
 
 void LLModelPreview::updateStatusMessages()
@@ -2198,7 +2599,7 @@ void LLModelPreview::updateLodControls(S32 lod)
     S32 lod_mode = lod_combo->getCurrentIndex();
     if (lod_mode == LOD_FROM_FILE) // LoD from file
     {
-        fmp->mLODMode[lod] = 0;
+        fmp->mLODMode[lod] = LOD_FROM_FILE;
         for (U32 i = 0; i < num_file_controls; ++i)
         {
             mFMP->childSetVisible(file_controls[i] + lod_name[lod], true);
@@ -2211,7 +2612,7 @@ void LLModelPreview::updateLodControls(S32 lod)
     }
     else if (lod_mode == USE_LOD_ABOVE) // use LoD above
     {
-        fmp->mLODMode[lod] = 2;
+        fmp->mLODMode[lod] = USE_LOD_ABOVE;
         for (U32 i = 0; i < num_file_controls; ++i)
         {
             mFMP->childSetVisible(file_controls[i] + lod_name[lod], false);
@@ -2237,7 +2638,7 @@ void LLModelPreview::updateLodControls(S32 lod)
     }
     else // auto generate, the default case for all LoDs except High
     {
-        fmp->mLODMode[lod] = 1;
+        fmp->mLODMode[lod] = MESH_OPTIMIZER_AUTO;
 
         //don't actually regenerate lod when refreshing UI
         mLODFrozen = true;
@@ -2269,7 +2670,7 @@ void LLModelPreview::updateLodControls(S32 lod)
             threshold->setVisible(false);
 
             limit->setMaxValue(mMaxTriangleLimit);
-            limit->setIncrement(mMaxTriangleLimit / 32);
+            limit->setIncrement(llmax((U32)1, mMaxTriangleLimit / 32));
         }
         else
         {
@@ -2300,8 +2701,6 @@ void LLModelPreview::clearBuffers()
 
 void LLModelPreview::genBuffers(S32 lod, bool include_skin_weights)
 {
-    U32 tri_count = 0;
-    U32 vertex_count = 0;
     U32 mesh_count = 0;
 
 
@@ -2334,7 +2733,6 @@ void LLModelPreview::genBuffers(S32 lod, bool include_skin_weights)
             continue;
         }
 
-        LLModel* base_mdl = *base_iter;
         base_iter++;
 
         S32 num_faces = mdl->getNumVolumeFaces();
@@ -2409,7 +2807,7 @@ void LLModelPreview::genBuffers(S32 lod, bool include_skin_weights)
                     //find closest weight to vf.mVertices[i].mPosition
                     LLVector3 pos(vf.mPositions[i].getF32ptr());
 
-                    const LLModel::weight_list& weight_list = base_mdl->getJointInfluences(pos);
+                    const LLModel::weight_list& weight_list = mdl->getJointInfluences(pos);
                     llassert(weight_list.size()>0 && weight_list.size() <= 4); // LLModel::loadModel() should guarantee this
 
                     LLVector4 w(0, 0, 0, 0);
@@ -2433,12 +2831,11 @@ void LLModelPreview::genBuffers(S32 lod, bool include_skin_weights)
                 *(index_strider++) = vf.mIndices[i];
             }
 
+            vb->flush();
+
             mVertexBuffer[lod][mdl].push_back(vb);
 
-            vertex_count += num_vertices;
-            tri_count += num_indices / 3;
             ++mesh_count;
-
         }
     }
 }
@@ -2534,6 +2931,20 @@ void LLModelPreview::loadedCallback(
         {
             pPreview->lookupLODModelFiles(lod);
         }
+
+        const LLVOAvatar* avatarp = pPreview->getPreviewAvatar();
+        if (avatarp) { // set up ground plane for possible rendering
+            const LLVector3 root_pos = avatarp->mRoot->getPosition();
+            const LLVector4a* ext = avatarp->mDrawable->getSpatialExtents();
+            const LLVector4a min = ext[0], max = ext[1];
+            const F32 center = (max[2] - min[2]) * 0.5f;
+            const F32 ground = root_pos[2] - center;
+            auto plane = pPreview->mGroundPlane;
+            plane[0] = {min[0], min[1], ground};
+            plane[1] = {max[0], min[1], ground};
+            plane[2] = {max[0], max[1], ground};
+            plane[3] = {min[0], max[1], ground};
+        }
     }
 
 }
@@ -2549,7 +2960,9 @@ void LLModelPreview::lookupLODModelFiles(S32 lod)
 
     std::string lod_filename = mLODFile[LLModel::LOD_HIGH];
     std::string ext = ".dae";
-    std::string::size_type i = lod_filename.rfind(ext);
+    std::string lod_filename_lower(lod_filename);
+    LLStringUtil::toLower(lod_filename_lower);
+    std::string::size_type i = lod_filename_lower.rfind(ext);
     if (i != std::string::npos)
     {
         lod_filename.replace(i, lod_filename.size() - ext.size(), getLodSuffix(next_lod) + ext);
@@ -2657,8 +3070,6 @@ BOOL LLModelPreview::render()
     LLMutexLock lock(this);
     mNeedsUpdate = FALSE;
 
-    bool use_shaders = LLGLSLShader::sNoFixedFunction;
-
     bool edges = mViewOption["show_edges"];
     bool joint_overrides = mViewOption["show_joint_overrides"];
     bool joint_positions = mViewOption["show_joint_positions"];
@@ -2676,10 +3087,8 @@ BOOL LLModelPreview::render()
     LLGLDisable fog(GL_FOG);
 
     {
-        if (use_shaders)
-        {
-            gUIProgram.bind();
-        }
+        gUIProgram.bind();
+
         //clear background to grey
         gGL.matrixMode(LLRender::MM_PROJECTION);
         gGL.pushMatrix();
@@ -2698,10 +3107,7 @@ BOOL LLModelPreview::render()
 
         gGL.matrixMode(LLRender::MM_MODELVIEW);
         gGL.popMatrix();
-        if (use_shaders)
-        {
-            gUIProgram.unbind();
-        }
+        gUIProgram.unbind();
     }
 
     LLFloaterModelPreview* fmp = LLFloaterModelPreview::sInstance;
@@ -2746,6 +3152,9 @@ BOOL LLModelPreview::render()
                     // (note: all these UI updates need to be somewhere that is not render)
                     fmp->childSetValue("upload_skin", true);
                     mFirstSkinUpdate = false;
+                    upload_skin = true;
+                    skin_weight = true;
+                    mViewOption["show_skin_weight"] = true;
                 }
 
                 fmp->enableViewOption("show_skin_weight");
@@ -2852,10 +3261,7 @@ BOOL LLModelPreview::render()
         refresh();
     }
 
-    if (use_shaders)
-    {
-        gObjectPreviewProgram.bind();
-    }
+    gObjectPreviewProgram.bind();
 
     gGL.loadIdentity();
     gPipeline.enableLightsPreview();
@@ -2888,7 +3294,6 @@ BOOL LLModelPreview::render()
     {
         genBuffers(-1, skin_weight);
         //genBuffers(3);
-        //genLODs();
     }
 
     if (!mModel[mPreviewLOD].empty())
@@ -2916,6 +3321,11 @@ BOOL LLModelPreview::render()
             genBuffers(mPreviewLOD, skin_weight);
         }
 
+        if (physics && mVertexBuffer[LLModel::LOD_PHYSICS].empty())
+        {
+            genBuffers(LLModel::LOD_PHYSICS, false);
+        }
+
         if (!skin_weight)
         {
             for (LLMeshUploadThread::instance_list::iterator iter = mUploadData.begin(); iter != mUploadData.end(); ++iter)
@@ -2977,6 +3387,7 @@ BOOL LLModelPreview::render()
                         glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
                         glLineWidth(1.f);
                     }
+                    buffer->flush();
                 }
                 gGL.popMatrix();
             }
@@ -3037,6 +3448,14 @@ BOOL LLModelPreview::render()
 
                                 if (!physics.mMesh.empty())
                                 { //render hull instead of mesh
+                                    // SL-16993 physics.mMesh[i].mNormals were being used to light the exploded
+                                    // analyzed physics shape but the drawArrays() interface changed
+                                    //  causing normal data <0,0,0> to be passed to the shader.
+                                    // The Phyics Preview shader uses plain vertex coloring so the physics hull is full lit.
+                                    // We could also use interface/ui shaders.
+                                    gObjectPreviewProgram.unbind();
+                                    gPhysicsPreviewProgram.bind();
+
                                     for (U32 i = 0; i < physics.mMesh.size(); ++i)
                                     {
                                         if (explode > 0.f)
@@ -3057,24 +3476,22 @@ BOOL LLModelPreview::render()
                                         }
 
                                         gGL.diffuseColor4ubv(hull_colors[i].mV);
-                                        LLVertexBuffer::drawArrays(LLRender::TRIANGLES, physics.mMesh[i].mPositions, physics.mMesh[i].mNormals);
+                                        LLVertexBuffer::drawArrays(LLRender::TRIANGLES, physics.mMesh[i].mPositions);
 
                                         if (explode > 0.f)
                                         {
                                             gGL.popMatrix();
                                         }
                                     }
+
+                                    gPhysicsPreviewProgram.unbind();
+                                    gObjectPreviewProgram.bind();
                                 }
                             }
                         }
 
                         if (render_mesh)
                         {
-                            if (mVertexBuffer[LLModel::LOD_PHYSICS].empty())
-                            {
-                                genBuffers(LLModel::LOD_PHYSICS, false);
-                            }
-
                             U32 num_models = mVertexBuffer[LLModel::LOD_PHYSICS][model].size();
                             if (pass > 0){
                                 for (U32 i = 0; i < num_models; ++i)
@@ -3094,6 +3511,8 @@ BOOL LLModelPreview::render()
 
                                     glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
                                     glLineWidth(1.f);
+
+                                    buffer->flush();
                                 }
                             }
                         }
@@ -3138,11 +3557,6 @@ BOOL LLModelPreview::render()
 
                                 if (physics.mHull.empty())
                                 {
-                                    if (mVertexBuffer[LLModel::LOD_PHYSICS].empty())
-                                    {
-                                        genBuffers(LLModel::LOD_PHYSICS, false);
-                                    }
-
                                     U32 num_models = mVertexBuffer[LLModel::LOD_PHYSICS][model].size();
                                     for (U32 v = 0; v < num_models; ++v)
                                     {
@@ -3169,6 +3583,8 @@ BOOL LLModelPreview::render()
                                                 buffer->draw(LLRender::POINTS, 3, i);
                                             }
                                         }
+
+                                        buffer->flush();
                                     }
                                 }
                             }
@@ -3229,7 +3645,7 @@ BOOL LLModelPreview::render()
                                 LLJoint *joint = getPreviewAvatar()->getJoint(skin->mJointNums[j]);
                                 if (joint)
                                 {
-                                    const LLVector3& jointPos = skin->mAlternateBindMatrix[j].getTranslation();
+                                    const LLVector3& jointPos = LLVector3(skin->mAlternateBindMatrix[j].getTranslation());
                                     if (joint->aboveJointPosThreshold(jointPos))
                                     {
                                         bool override_changed;
@@ -3271,11 +3687,10 @@ BOOL LLModelPreview::render()
                             //build matrix palette
 
                             LLMatrix4a mat[LL_MAX_JOINTS_PER_MESH_OBJECT];
-                            LLSkinningUtil::initSkinningMatrixPalette((LLMatrix4*)mat, joint_count,
+                            LLSkinningUtil::initSkinningMatrixPalette(mat, joint_count,
                                 skin, getPreviewAvatar());
 
-                            LLMatrix4a bind_shape_matrix;
-                            bind_shape_matrix.loadu(skin->mBindShapeMatrix);
+                            const LLMatrix4a& bind_shape_matrix = skin->mBindShapeMatrix;
                             U32 max_joints = LLSkinningUtil::getMaxJointCount();
                             for (U32 j = 0; j < buffer->getNumVerts(); ++j)
                             {
@@ -3344,6 +3759,7 @@ BOOL LLModelPreview::render()
                 {
                     getPreviewAvatar()->renderBones();
                 }
+                renderGroundPlane(mPelvisZOffset);
                 if (shader)
                 {
                     shader->bind();
@@ -3358,16 +3774,35 @@ BOOL LLModelPreview::render()
         }
     }
 
-    if (use_shaders)
-    {
-        gObjectPreviewProgram.unbind();
-    }
+    gObjectPreviewProgram.unbind();
 
     gGL.popMatrix();
 
     return TRUE;
 }
 
+void LLModelPreview::renderGroundPlane(float z_offset)
+{   // Not necesarilly general - beware - but it seems to meet the needs of LLModelPreview::render
+
+	gGL.diffuseColor3f( 1.0f, 0.0f, 1.0f );
+
+	gGL.begin(LLRender::LINES);
+	gGL.vertex3fv(mGroundPlane[0].mV);
+	gGL.vertex3fv(mGroundPlane[1].mV);
+
+	gGL.vertex3fv(mGroundPlane[1].mV);
+	gGL.vertex3fv(mGroundPlane[2].mV);
+
+	gGL.vertex3fv(mGroundPlane[2].mV);
+	gGL.vertex3fv(mGroundPlane[3].mV);
+
+	gGL.vertex3fv(mGroundPlane[3].mV);
+	gGL.vertex3fv(mGroundPlane[0].mV);
+
+	gGL.end();
+}
+
+
 //-----------------------------------------------------------------------------
 // refresh()
 //-----------------------------------------------------------------------------
@@ -3475,7 +3910,7 @@ bool LLModelPreview::lodQueryCallback()
         {
             S32 lod = preview->mLodsQuery.back();
             preview->mLodsQuery.pop_back();
-            preview->genLODs(lod);
+            preview->genMeshOptimizerLODs(lod, MESH_OPTIMIZER_AUTO);
 
             if (preview->mLookUpLodFiles && (lod == LLModel::LOD_HIGH))
             {
@@ -3483,19 +3918,20 @@ bool LLModelPreview::lodQueryCallback()
             }
 
             // return false to continue cycle
-            return false;
+            return preview->mLodsQuery.empty();
         }
     }
     // nothing to process
     return true;
 }
 
-void LLModelPreview::onLODParamCommit(S32 lod, bool enforce_tri_limit)
+void LLModelPreview::onLODMeshOptimizerParamCommit(S32 requested_lod, bool enforce_tri_limit, S32 mode)
 {
     if (!mLODFrozen)
     {
-        genLODs(lod, 3, enforce_tri_limit);
+        genMeshOptimizerLODs(requested_lod, mode, 3, enforce_tri_limit);
         refresh();
+        mDirty = true;
     }
 }
 
diff --git a/indra/newview/llmodelpreview.h b/indra/newview/llmodelpreview.h
index 8e59c71a55070653252482579136dc64192d37cb..df7320768cfb1a07407a73f72bce7d19b056af0d 100644
--- a/indra/newview/llmodelpreview.h
+++ b/indra/newview/llmodelpreview.h
@@ -124,10 +124,18 @@ class LLModelPreview : public LLViewerDynamicTexture, public LLMutex
     typedef enum
     {
         LOD_FROM_FILE = 0,
-        GENERATE,
+        MESH_OPTIMIZER_AUTO, // automatically selects method based on model or face
+        MESH_OPTIMIZER_PRECISE, // combines faces into a single model, simplifies, then splits back into faces
+        MESH_OPTIMIZER_SLOPPY, // uses sloppy method, works per face
         USE_LOD_ABOVE,
     } eLoDMode;
 
+    typedef enum
+    {
+        LIMIT_TRIANGLES = 0,
+        LIMIT_ERROR_TRESHOLD,
+    } eLoDLimit;
+
 public:
     // Todo: model preview shouldn't need floater dependency, it
     // should just expose data to floater, not control flaoter like it does
@@ -155,7 +163,7 @@ class LLModelPreview : public LLViewerDynamicTexture, public LLMutex
     void loadModelCallback(S32 lod);
     bool lodsReady() { return !mGenLOD && mLodsQuery.empty(); }
     void queryLODs() { mGenLOD = true; };
-    void genLODs(S32 which_lod = -1, U32 decimation = 3, bool enforce_tri_limit = false);
+    void genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 decimation = 3, bool enforce_tri_limit = false);
     void generateNormals();
     void restoreNormals();
     void updateDimentionsAndOffsets();
@@ -165,8 +173,7 @@ class LLModelPreview : public LLViewerDynamicTexture, public LLMutex
     void clearIncompatible(S32 lod);
     void updateStatusMessages();
     void updateLodControls(S32 lod);
-    void clearGLODGroup();
-    void onLODParamCommit(S32 lod, bool enforce_tri_limit);
+    void onLODMeshOptimizerParamCommit(S32 lod, bool enforce_tri_limit, S32 mode);
     void addEmptyFace(LLModel* pTarget);
 
     const bool getModelPivot(void) const { return mHasPivot; }
@@ -217,6 +224,39 @@ class LLModelPreview : public LLViewerDynamicTexture, public LLMutex
     LLVOAvatar* getPreviewAvatar(void) { return mPreviewAvatar; }
     // Count amount of original models, excluding sub-models
     static U32 countRootModels(LLModelLoader::model_list models);
+    LLVector3   mGroundPlane[4];
+	void		renderGroundPlane(float z_offset = 0.0f);
+    /// Indicates whether we should warn of high-lod meshes that do not have a corresponding physics mesh.
+    /// Reset when resetting the modelpreview (i.e., when the uploader dialog is created or reset), and when
+    /// about to process a physics file. Set to true immediately after the file is loaded (before rebuildUploadData()).
+    ///
+    /// (The rules for mapping the correspondence of high-lod meshes to physics meshes are complex. When
+    /// lod rendering meshes are used, there is never an unmatched mesh. Nor is there a mismatch when
+    /// the high-lod file and physics file have ony one mesh each. In these cases, this value is moot.
+    /// When there are multiple meshes in each file, they are matched by name or order, and some meshes
+    /// are broken up by limitations into multiple objects, and thus there can be mismatches.)
+    bool mWarnOfUnmatchedPhyicsMeshes{false};
+    /// A mesh to use as the default physics shape in only those cases where the physics shape is not otherwise specified.
+    /// It is set only when the user chooses a physics shape file that contains a mesh with a name that matches DEFAULT_PHYSICS_MESH_NAME.
+    /// It is reset when such a name is not found, and when resetting the modelpreview.
+    /// Not read unless mWarnOfUnmatchedPhyicsMeshes is true.
+    LLModel* mDefaultPhysicsShapeP{};
+
+    typedef enum
+    {
+        MESH_OPTIMIZER_FULL,
+        MESH_OPTIMIZER_NO_NORMALS,
+        MESH_OPTIMIZER_NO_UVS,
+        MESH_OPTIMIZER_NO_TOPOLOGY,
+    } eSimplificationMode;
+
+    // Merges faces into single mesh, simplifies using mesh optimizer,
+    // then splits back into faces.
+    // Returns reached simplification ratio. -1 in case of a failure.
+    F32 genMeshOptimizerPerModel(LLModel *base_model, LLModel *target_model, F32 indices_ratio, F32 error_threshold, eSimplificationMode simplification_mode);
+    // Simplifies specified face using mesh optimizer.
+    // Returns reached simplification ratio. -1 in case of a failure.
+    F32 genMeshOptimizerPerFace(LLModel *base_model, LLModel *target_model, U32 face_idx, F32 indices_ratio, F32 error_threshold, eSimplificationMode simplification_mode);
 
 protected:
     friend class LLModelLoader;
@@ -248,19 +288,11 @@ class LLModelPreview : public LLViewerDynamicTexture, public LLMutex
 
     std::map<std::string, bool> mViewOption;
 
-    //GLOD object parameters (must rebuild object if these change)
+    // Model generation parameters (must rebuild object if these change)
     bool mLODFrozen;
-    F32 mBuildShareTolerance;
-    U32 mBuildQueueMode;
-    U32 mBuildOperator;
-    U32 mBuildBorderMode;
     U32 mRequestedLoDMode[LLModel::NUM_LODS];
     S32 mRequestedTriangleCount[LLModel::NUM_LODS];
     F32 mRequestedErrorThreshold[LLModel::NUM_LODS];
-    U32 mRequestedBuildOperator[LLModel::NUM_LODS];
-    U32 mRequestedQueueMode[LLModel::NUM_LODS];
-    U32 mRequestedBorderMode[LLModel::NUM_LODS];
-    F32 mRequestedShareTolerance[LLModel::NUM_LODS];
     F32 mRequestedCreaseAngle[LLModel::NUM_LODS];
 
     LLModelLoader* mModelLoader;
@@ -279,6 +311,8 @@ class LLModelPreview : public LLViewerDynamicTexture, public LLMutex
 
     U32 mGroup;
     std::map<LLPointer<LLModel>, U32> mObject;
+
+    // Amount of triangles in original(base) model
     U32 mMaxTriangleLimit;
 
     LLMeshUploadThread::instance_list mUploadData;
diff --git a/indra/newview/llmutelist.cpp b/indra/newview/llmutelist.cpp
index 4a8ef53a8ba03be21223eb4dfe777f065068d107..bf00d77dea955d897329eb9da79fffcbc09ea4d8 100644
--- a/indra/newview/llmutelist.cpp
+++ b/indra/newview/llmutelist.cpp
@@ -352,7 +352,7 @@ BOOL LLMuteList::add(const LLMute& mute, U32 flags)
 
 void LLMuteList::updateAdd(const LLMute& mute)
 {
-	// External mutes (e.g. Avaline callers) are local only, don't send them to the server.
+	// External mutes are local only, don't send them to the server.
 	if (mute.mType == LLMute::EXTERNAL)
 	{
 		return;
diff --git a/indra/newview/llnamelistctrl.cpp b/indra/newview/llnamelistctrl.cpp
index 5215126789a9ece96e47ece0e32b59f2a241cf8d..8058faa5c7c24b9ca7709e48d1d87163399f275a 100644
--- a/indra/newview/llnamelistctrl.cpp
+++ b/indra/newview/llnamelistctrl.cpp
@@ -271,6 +271,25 @@ BOOL LLNameListCtrl::handleToolTip(S32 x, S32 y, MASK mask)
 	return handled;
 }
 
+// virtual
+BOOL LLNameListCtrl::handleRightMouseDown(S32 x, S32 y, MASK mask)
+{
+    LLNameListItem* hit_item = dynamic_cast<LLNameListItem*>(hitItem(x, y));
+    LLFloater* floater = gFloaterView->getParentFloater(this);
+    if (floater && floater->isFrontmost() && hit_item)
+    {
+        if(hit_item->isGroup())
+        {
+            ContextMenuType prev_menu = getContextMenuType();
+            setContextMenu(MENU_GROUP);
+            BOOL handled = LLScrollListCtrl::handleRightMouseDown(x, y, mask);
+            setContextMenu(prev_menu);
+            return handled;
+        }
+    }
+    return LLScrollListCtrl::handleRightMouseDown(x, y, mask);    
+}
+
 // public
 void LLNameListCtrl::addGroupNameItem(const LLUUID& group_id, EAddPosition pos,
 									  BOOL enabled)
diff --git a/indra/newview/llnamelistctrl.h b/indra/newview/llnamelistctrl.h
index ef0be135e618e1c2b9473553700332eead2ef1d7..5dd5da5892ade23c01e7851e0fd8a3d3b6a1b3a3 100644
--- a/indra/newview/llnamelistctrl.h
+++ b/indra/newview/llnamelistctrl.h
@@ -170,6 +170,7 @@ class LLNameListCtrl
 	/*virtual*/ void updateColumns(bool force_update);
 
 	/*virtual*/ void mouseOverHighlightNthItem( S32 index );
+    /*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask);
 private:
 	void showInspector(const LLUUID& avatar_id, bool is_group, bool is_experience = false);
 	void onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name, std::string suffix, std::string prefix, LLHandle<LLNameListItem> item);
diff --git a/indra/newview/llnavigationbar.cpp b/indra/newview/llnavigationbar.cpp
index 19dbbeb60e500f92bf75a4a459de2af141c126e2..f5ee1171d92d75f923b013c12e279e6b63c86d1f 100644
--- a/indra/newview/llnavigationbar.cpp
+++ b/indra/newview/llnavigationbar.cpp
@@ -451,9 +451,9 @@ void LLNavigationBar::onLocationSelection()
 			
 			if(value.has("AssetUUID"))
 			{
-				
 				gAgent.teleportViaLandmark( LLUUID(value["AssetUUID"].asString()));
-				mSaveToLocationHistory = true;
+                // user teleported by manually inputting inventory landmark's name
+				mSaveToLocationHistory = false;
 				return;
 			}
 			else
@@ -713,7 +713,7 @@ void LLNavigationBar::resizeLayoutPanel()
 }
 void LLNavigationBar::invokeSearch(std::string search_text)
 {
-	LLFloaterReg::showInstance("search", LLSD().with("category", "all").with("query", LLSD(search_text)));
+	LLFloaterReg::showInstance("search", LLSD().with("category", "standard").with("query", LLSD(search_text)));
 }
 
 void LLNavigationBar::clearHistoryCache()
@@ -733,3 +733,8 @@ int LLNavigationBar::getDefFavBarHeight()
 {
 	return mDefaultFpRect.getHeight();
 }
+
+bool LLNavigationBar::isRebakeNavMeshAvailable()
+{
+    return mCmbLocation->isNavMeshDirty();
+}
diff --git a/indra/newview/llnavigationbar.h b/indra/newview/llnavigationbar.h
index 646911a62ca63458ab4a5f10e744d6746b189649..11c671294a3c4d745c3348c0ce39ad4068bf2871 100755
--- a/indra/newview/llnavigationbar.h
+++ b/indra/newview/llnavigationbar.h
@@ -102,6 +102,8 @@ class LLNavigationBar
 
 	int getDefNavBarHeight();
 	int getDefFavBarHeight();
+
+    bool isRebakeNavMeshAvailable();
 	
 private:
 	// the distance between navigation panel and favorites panel in pixels
diff --git a/indra/newview/llnetmap.cpp b/indra/newview/llnetmap.cpp
old mode 100644
new mode 100755
index 112da556825647b5d5d1ed65cd2119c8f576b1e2..b34be80b078ec0f279599593e22c235ca5982b84
--- a/indra/newview/llnetmap.cpp
+++ b/indra/newview/llnetmap.cpp
@@ -37,6 +37,7 @@
 #include "llfocusmgr.h"
 #include "lllocalcliprect.h"
 #include "llrender.h"
+#include "llresmgr.h"
 #include "llui.h"
 #include "lltooltip.h"
 
@@ -47,11 +48,16 @@
 #include "llagentcamera.h"
 #include "llappviewer.h" // for gDisconnected
 #include "llcallingcard.h" // LLAvatarTracker
+#include "llfloaterland.h"
 #include "llfloaterworldmap.h"
+#include "llparcel.h"
 #include "lltracker.h"
 #include "llsurface.h"
+#include "llurlmatch.h"
+#include "llurlregistry.h"
 #include "llviewercamera.h"
 #include "llviewercontrol.h"
+#include "llviewerparcelmgr.h"
 #include "llviewertexture.h"
 #include "llviewertexturelist.h"
 #include "llviewermenu.h"
@@ -64,7 +70,10 @@
 static LLDefaultChildRegistry::Register<LLNetMap> r1("net_map");
 
 const F32 LLNetMap::MAP_SCALE_MIN = 32;
-const F32 LLNetMap::MAP_SCALE_MID = 1024;
+const F32 LLNetMap::MAP_SCALE_FAR = 32;
+const F32 LLNetMap::MAP_SCALE_MEDIUM = 128;
+const F32 LLNetMap::MAP_SCALE_CLOSE = 256;
+const F32 LLNetMap::MAP_SCALE_VERY_CLOSE = 1024;
 const F32 LLNetMap::MAP_SCALE_MAX = 4096;
 
 const F32 MAP_SCALE_ZOOM_FACTOR = 1.04f; // Zoom in factor per click of scroll wheel (4%)
@@ -78,13 +87,13 @@ const F64 COARSEUPDATE_MAX_Z = 1020.0f;
 LLNetMap::LLNetMap (const Params & p)
 :	LLUICtrl (p),
 	mBackgroundColor (p.bg_color()),
-	mScale( MAP_SCALE_MID ),
-	mPixelsPerMeter( MAP_SCALE_MID / REGION_WIDTH_METERS ),
+    mScale( MAP_SCALE_MEDIUM ),
+    mPixelsPerMeter( MAP_SCALE_MEDIUM / REGION_WIDTH_METERS ),
 	mObjectMapTPM(0.f),
 	mObjectMapPixels(0.f),
-	mTargetPan(0.f, 0.f),
 	mCurPan(0.f, 0.f),
 	mStartPan(0.f, 0.f),
+    mPopupWorldPos(0.f, 0.f, 0.f),
 	mMouseDown(0, 0),
 	mPanning(false),
 	mUpdateNow(false),
@@ -97,6 +106,13 @@ LLNetMap::LLNetMap (const Params & p)
 	mPopupMenu(NULL)
 {
 	mScale = gSavedSettings.getF32("MiniMapScale");
+    if (gAgent.isFirstLogin())
+    {
+        // *HACK: On first run, set this to false for new users, otherwise the
+        // default is true to maintain consistent experience for existing
+        // users.
+        gSavedSettings.setBOOL("MiniMapRotate", false);
+    }
 	mPixelsPerMeter = mScale / REGION_WIDTH_METERS;
 	mDotRadius = llmax(DOT_SCALE * mPixelsPerMeter, MIN_DOT_RADIUS);
 }
@@ -107,13 +123,22 @@ LLNetMap::~LLNetMap()
 
 BOOL LLNetMap::postBuild()
 {
-	LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
-	
-	registrar.add("Minimap.Zoom", boost::bind(&LLNetMap::handleZoom, this, _2));
-	registrar.add("Minimap.Tracker", boost::bind(&LLNetMap::handleStopTracking, this, _2));
-
-	mPopupMenu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_mini_map.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
-	return TRUE;
+    LLUICtrl::CommitCallbackRegistry::ScopedRegistrar commitRegistrar;
+    LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enableRegistrar;
+
+    enableRegistrar.add("Minimap.Zoom.Check", boost::bind(&LLNetMap::isZoomChecked, this, _2));
+    commitRegistrar.add("Minimap.Zoom.Set", boost::bind(&LLNetMap::setZoom, this, _2));
+    commitRegistrar.add("Minimap.Tracker", boost::bind(&LLNetMap::handleStopTracking, this, _2));
+    commitRegistrar.add("Minimap.Center.Activate", boost::bind(&LLNetMap::activateCenterMap, this, _2));
+    enableRegistrar.add("Minimap.MapOrientation.Check", boost::bind(&LLNetMap::isMapOrientationChecked, this, _2));
+    commitRegistrar.add("Minimap.MapOrientation.Set", boost::bind(&LLNetMap::setMapOrientation, this, _2));
+    commitRegistrar.add("Minimap.AboutLand", boost::bind(&LLNetMap::popupShowAboutLand, this, _2));
+
+    mPopupMenu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_mini_map.xml", gMenuHolder,
+                                                                          LLViewerMenuHolderGL::child_registry_t::instance());
+    mPopupMenu->setItemEnabled("Re-center map", false);
+
+    return true;
 }
 
 void LLNetMap::setScale( F32 scale )
@@ -147,24 +172,43 @@ void LLNetMap::setScale( F32 scale )
 
 void LLNetMap::draw()
 {
+    if (!LLWorld::instanceExists())
+    {
+        return;
+    }
+    LL_PROFILE_ZONE_SCOPED;
  	static LLFrameTimer map_timer;
 	static LLUIColor map_avatar_color = LLUIColorTable::instance().getColor("MapAvatarColor", LLColor4::white);
 	static LLUIColor map_avatar_friend_color = LLUIColorTable::instance().getColor("MapAvatarFriendColor", LLColor4::white);
 	static LLUIColor map_track_color = LLUIColorTable::instance().getColor("MapTrackColor", LLColor4::white);
 	//static LLUIColor map_track_disabled_color = LLUIColorTable::instance().getColor("MapTrackDisabledColor", LLColor4::white);
 	static LLUIColor map_frustum_color = LLUIColorTable::instance().getColor("MapFrustumColor", LLColor4::white);
-	static LLUIColor map_frustum_rotating_color = LLUIColorTable::instance().getColor("MapFrustumRotatingColor", LLColor4::white);
+	static LLUIColor map_parcel_outline_color = LLUIColorTable::instance().getColor("MapParcelOutlineColor", LLColor4(LLColor3(LLColor4::yellow), 0.5f));
 	
 	if (mObjectImagep.isNull())
 	{
 		createObjectImage();
 	}
 
-	static LLUICachedControl<bool> auto_center("MiniMapAutoCenter", true);
-	if (auto_center)
+    static LLUICachedControl<bool> auto_center("MiniMapAutoCenter", true);
+    bool auto_centering = auto_center && !mPanning;
+    mCentering = mCentering && !mPanning;
+
+    if (auto_centering || mCentering)
 	{
-		mCurPan = lerp(mCurPan, mTargetPan, LLSmoothInterpolation::getInterpolant(0.1f));
+        mCurPan = lerp(mCurPan, LLVector2(0.0f, 0.0f) , LLSmoothInterpolation::getInterpolant(0.1f));
 	}
+    bool centered = abs(mCurPan.mV[VX]) < 0.5f && abs(mCurPan.mV[VY]) < 0.5f;
+    if (centered)
+    {
+        mCurPan.mV[0] = 0.0f;
+        mCurPan.mV[1] = 0.0f;
+        mCentering = false;
+    }
+
+    bool can_recenter_map = !(centered || mCentering || auto_centering);
+    mPopupMenu->setItemEnabled("Re-center map", can_recenter_map);
+    updateAboutLandPopupButton();
 
 	// Prepare a scissor region
 	F32 rotation = 0;
@@ -211,7 +255,8 @@ void LLNetMap::draw()
 		}
 
 		// figure out where agent is
-		S32 region_width = ll_round(LLWorld::getInstance()->getRegionWidthInMeters());
+		const S32 region_width = ll_round(LLWorld::getInstance()->getRegionWidthInMeters());
+        const F32 scale_pixels_per_meter = mScale / region_width;
 
 		for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
 			 iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
@@ -220,8 +265,8 @@ void LLNetMap::draw()
 			// Find x and y position relative to camera's center.
 			LLVector3 origin_agent = regionp->getOriginAgent();
 			LLVector3 rel_region_pos = origin_agent - gAgentCamera.getCameraPositionAgent();
-			F32 relative_x = (rel_region_pos.mV[0] / region_width) * mScale;
-			F32 relative_y = (rel_region_pos.mV[1] / region_width) * mScale;
+			F32 relative_x = rel_region_pos.mV[0] * scale_pixels_per_meter;
+			F32 relative_y = rel_region_pos.mV[1] * scale_pixels_per_meter;
 
 			// background region rectangle
 			F32 bottom =	relative_y;
@@ -244,6 +289,7 @@ void LLNetMap::draw()
 			}
 
 
+
 			// Draw using texture.
 			gGL.getTexUnit(0)->bind(regionp->getLand().getSTexture());
 			gGL.begin(LLRender::QUADS);
@@ -258,7 +304,7 @@ void LLNetMap::draw()
 			gGL.end();
 
 			// Draw water
-			gGL.setAlphaRejectSettings(LLRender::CF_GREATER, ABOVE_WATERLINE_ALPHA / 255.f);
+            gGL.flush();
 			{
 				if (regionp->getLand().getWaterTexture())
 				{
@@ -275,7 +321,7 @@ void LLNetMap::draw()
 					gGL.end();
 				}
 			}
-			gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
+            gGL.flush();
 		}
 
 		// Redraw object layer periodically
@@ -305,8 +351,8 @@ void LLNetMap::draw()
 		LLVector3 map_center_agent = gAgent.getPosAgentFromGlobal(mObjectImageCenterGlobal);
 		LLVector3 camera_position = gAgentCamera.getCameraPositionAgent();
 		map_center_agent -= camera_position;
-		map_center_agent.mV[VX] *= mScale/region_width;
-		map_center_agent.mV[VY] *= mScale/region_width;
+		map_center_agent.mV[VX] *= scale_pixels_per_meter;
+		map_center_agent.mV[VY] *= scale_pixels_per_meter;
 
 		gGL.getTexUnit(0)->bind(mObjectImagep);
 		F32 image_half_width = 0.5f*mObjectMapPixels;
@@ -322,6 +368,13 @@ void LLNetMap::draw()
 			gGL.texCoord2f(1.f, 1.f);
 			gGL.vertex2f(image_half_width + map_center_agent.mV[VX], image_half_height + map_center_agent.mV[VY]);
 		gGL.end();
+        
+		for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
+			 iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
+		{
+			LLViewerRegion* regionp = *iter;
+            regionp->renderPropertyLinesOnMinimap(scale_pixels_per_meter, map_parcel_outline_color.get().mV);
+        }
 
 		gGL.popMatrix();
 
@@ -446,41 +499,34 @@ void LLNetMap::draw()
 		F32 horiz_fov = LLViewerCamera::getInstance()->getView() * LLViewerCamera::getInstance()->getAspect();
 		F32 far_clip_meters = LLViewerCamera::getInstance()->getFar();
 		F32 far_clip_pixels = far_clip_meters * meters_to_pixels;
-
-		F32 half_width_meters = far_clip_meters * tan( horiz_fov / 2 );
-		F32 half_width_pixels = half_width_meters * meters_to_pixels;
 		
-		F32 ctr_x = (F32)center_sw_left;
-		F32 ctr_y = (F32)center_sw_bottom;
-
-
-		gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
-
-		if( rotate_map )
-		{
-			gGL.color4fv((map_frustum_color()).mV);
-
-			gGL.begin( LLRender::TRIANGLES  );
-				gGL.vertex2f( ctr_x, ctr_y );
-				gGL.vertex2f( ctr_x - half_width_pixels, ctr_y + far_clip_pixels );
-				gGL.vertex2f( ctr_x + half_width_pixels, ctr_y + far_clip_pixels );
-			gGL.end();
-		}
-		else
-		{
-			gGL.color4fv((map_frustum_rotating_color()).mV);
-			
-			// If we don't rotate the map, we have to rotate the frustum.
-			gGL.pushMatrix();
-				gGL.translatef( ctr_x, ctr_y, 0 );
-				gGL.rotatef( atan2( LLViewerCamera::getInstance()->getAtAxis().mV[VX], LLViewerCamera::getInstance()->getAtAxis().mV[VY] ) * RAD_TO_DEG, 0.f, 0.f, -1.f);
-				gGL.begin( LLRender::TRIANGLES  );
-					gGL.vertex2f( 0, 0 );
-					gGL.vertex2f( -half_width_pixels, far_clip_pixels );
-					gGL.vertex2f(  half_width_pixels, far_clip_pixels );
-				gGL.end();
-			gGL.popMatrix();
-		}
+        F32 ctr_x = (F32)center_sw_left;
+        F32 ctr_y = (F32)center_sw_bottom;
+
+        const F32 steps_per_circle = 40.0f;
+        const F32 steps_per_radian = steps_per_circle / F_TWO_PI;
+        const F32 arc_start = -(horiz_fov / 2.0f) + F_PI_BY_TWO;
+        const F32 arc_end = (horiz_fov / 2.0f) + F_PI_BY_TWO;
+        const S32 steps = llmax(1, (S32)((horiz_fov * steps_per_radian) + 0.5f));
+
+        gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+
+        if( rotate_map )
+        {
+            gGL.pushMatrix();
+                gGL.translatef( ctr_x, ctr_y, 0 );
+                gl_washer_segment_2d(far_clip_pixels, 0, arc_start, arc_end, steps, map_frustum_color(), map_frustum_color());
+            gGL.popMatrix();
+        }
+        else
+        {
+            gGL.pushMatrix();
+                gGL.translatef( ctr_x, ctr_y, 0 );
+                // If we don't rotate the map, we have to rotate the frustum.
+                gGL.rotatef( atan2( LLViewerCamera::getInstance()->getAtAxis().mV[VX], LLViewerCamera::getInstance()->getAtAxis().mV[VY] ) * RAD_TO_DEG, 0.f, 0.f, -1.f);
+                gl_washer_segment_2d(far_clip_pixels, 0, arc_start, arc_end, steps, map_frustum_color(), map_frustum_color());
+            gGL.popMatrix();
+        }
 	}
 	
 	gGL.popMatrix();
@@ -547,6 +593,65 @@ void LLNetMap::drawTracking(const LLVector3d& pos_global, const LLColor4& color,
 	}
 }
 
+bool LLNetMap::isMouseOnPopupMenu()
+{
+    if (!mPopupMenu->isOpen())
+    {
+        return false;
+    }
+
+    S32 popup_x;
+    S32 popup_y;
+    LLUI::getInstance()->getMousePositionLocal(mPopupMenu, &popup_x, &popup_y);
+    // *NOTE: Tolerance is larger than it needs to be because the context menu is offset from the mouse when the menu is opened from certain
+    // directions. This may be a quirk of LLMenuGL::showPopup. -Cosmic,2022-03-22
+    constexpr S32 tolerance = 10;
+    // Test tolerance from all four corners, as the popup menu can appear from a different direction if there's not enough space.
+    // Assume the size of the popup menu is much larger than the provided tolerance.
+    // In practice, this is a [tolerance]px margin around the popup menu.
+    for (S32 sign_x = -1; sign_x <= 1; sign_x += 2)
+    {
+        for (S32 sign_y = -1; sign_y <= 1; sign_y += 2)
+        {
+            if (mPopupMenu->pointInView(popup_x + (sign_x * tolerance), popup_y + (sign_y * tolerance)))
+            {
+                return true;
+            }
+        }
+    }
+    return false;
+}
+
+void LLNetMap::updateAboutLandPopupButton()
+{
+    if (!mPopupMenu->isOpen())
+    {
+        return;
+    }
+
+    LLViewerRegion *region = LLWorld::getInstance()->getRegionFromPosGlobal(mPopupWorldPos);
+    if (!region)
+    {
+        mPopupMenu->setItemEnabled("About Land", false);
+    }
+    else
+    {
+        // Check if the mouse is in the bounds of the popup. If so, it's safe to assume no other hover function will be called, so the hover
+        // parcel can be used to check if location-sensitive tooltip options are available.
+        if (isMouseOnPopupMenu())
+        {
+            LLViewerParcelMgr::getInstance()->setHoverParcel(mPopupWorldPos);
+            LLParcel *hover_parcel = LLViewerParcelMgr::getInstance()->getHoverParcel();
+            bool      valid_parcel = false;
+            if (hover_parcel)
+            {
+                valid_parcel = hover_parcel->getOwnerID().notNull();
+            }
+            mPopupMenu->setItemEnabled("About Land", valid_parcel);
+        }
+    }
+}
+
 LLVector3d LLNetMap::viewPosToGlobal( S32 x, S32 y )
 {
 	x -= ll_round(getRect().getWidth() / 2 + mCurPan.mV[VX]);
@@ -574,66 +679,152 @@ LLVector3d LLNetMap::viewPosToGlobal( S32 x, S32 y )
 
 BOOL LLNetMap::handleScrollWheel(S32 x, S32 y, S32 clicks)
 {
-	// note that clicks are reversed from what you'd think: i.e. > 0  means zoom out, < 0 means zoom in
-	F32 new_scale = mScale * pow(MAP_SCALE_ZOOM_FACTOR, -clicks);
+    // note that clicks are reversed from what you'd think: i.e. > 0  means zoom out, < 0 means zoom in
+    F32 new_scale = mScale * pow(MAP_SCALE_ZOOM_FACTOR, -clicks);
 	F32 old_scale = mScale;
 
-	setScale(new_scale);
+    setScale(new_scale);
 
-	static LLUICachedControl<bool> auto_center("MiniMapAutoCenter", true);
-	if (!auto_center)
-	{
-		// Adjust pan to center the zoom on the mouse pointer
-		LLVector2 zoom_offset;
-		zoom_offset.mV[VX] = x - getRect().getWidth() / 2;
-		zoom_offset.mV[VY] = y - getRect().getHeight() / 2;
-		mCurPan -= zoom_offset * mScale / old_scale - zoom_offset;
-	}
+    static LLUICachedControl<bool> auto_center("MiniMapAutoCenter", true);
+    if (!auto_center)
+    {
+        // Adjust pan to center the zoom on the mouse pointer
+        LLVector2 zoom_offset;
+        zoom_offset.mV[VX] = x - getRect().getWidth() / 2;
+        zoom_offset.mV[VY] = y - getRect().getHeight() / 2;
+        mCurPan -= zoom_offset * mScale / old_scale - zoom_offset;
+    }
 
-	return TRUE;
+    return true;
 }
 
-BOOL LLNetMap::handleToolTip( S32 x, S32 y, MASK mask )
+BOOL LLNetMap::handleToolTip(S32 x, S32 y, MASK mask)
 {
-	if (gDisconnected)
-	{
-		return FALSE;
-	}
-
-	// If the cursor is near an avatar on the minimap, a mini-inspector will be
-	// shown for the avatar, instead of the normal map tooltip.
-	if (handleToolTipAgent(mClosestAgentToCursor))
-	{
-		return TRUE;
-	}
-
-	LLRect sticky_rect;
-	std::string region_name;
-	LLViewerRegion*	region = LLWorld::getInstance()->getRegionFromPosGlobal( viewPosToGlobal( x, y ) );
-	if(region)
-	{
-		// set sticky_rect
-		S32 SLOP = 4;
-		localPointToScreen(x - SLOP, y - SLOP, &(sticky_rect.mLeft), &(sticky_rect.mBottom));
-		sticky_rect.mRight = sticky_rect.mLeft + 2 * SLOP;
-		sticky_rect.mTop = sticky_rect.mBottom + 2 * SLOP;
-
-		region_name = region->getName();
-		if (!region_name.empty())
-		{
-			region_name += "\n";
-		}
-	}
-
-	LLStringUtil::format_map_t args;
-	args["[REGION]"] = region_name;
-	std::string msg = mToolTipMsg;
-	LLStringUtil::format(msg, args);
-	LLToolTipMgr::instance().show(LLToolTip::Params()
-		.message(msg)
-		.sticky_rect(sticky_rect));
-		
-	return TRUE;
+    if (gDisconnected)
+    {
+        return false;
+    }
+
+    // If the cursor is near an avatar on the minimap, a mini-inspector will be
+    // shown for the avatar, instead of the normal map tooltip.
+    if (handleToolTipAgent(mClosestAgentToCursor))
+    {
+        return true;
+    }
+
+    // The popup menu uses the hover parcel when it is open and the mouse is on
+    // top of it, with some additional tolerance. Returning early here prevents
+    // fighting over that hover parcel when getting tooltip info in the
+    // tolerance region.
+    if (isMouseOnPopupMenu())
+    {
+        return false;
+    }
+
+    LLRect sticky_rect;
+    S32 SLOP = 4;
+    localPointToScreen(x - SLOP, y - SLOP, &(sticky_rect.mLeft), &(sticky_rect.mBottom));
+    sticky_rect.mRight = sticky_rect.mLeft + 2 * SLOP;
+    sticky_rect.mTop   = sticky_rect.mBottom + 2 * SLOP;
+
+    std::string parcel_name_msg;
+    std::string parcel_sale_price_msg;
+    std::string parcel_sale_area_msg;
+    std::string parcel_owner_msg;
+    std::string region_name_msg;
+
+    LLVector3d      posGlobal = viewPosToGlobal(x, y);
+    LLViewerRegion *region    = LLWorld::getInstance()->getRegionFromPosGlobal(posGlobal);
+    if (region)
+    {
+        std::string region_name = region->getName();
+        if (!region_name.empty())
+        {
+            region_name_msg = mRegionNameMsg;
+            LLStringUtil::format(region_name_msg, {{"[REGION_NAME]", region_name}});
+        }
+
+        // Only show parcel information in the tooltip if property lines are visible. Otherwise, the parcel the tooltip is referring to is
+        // ambiguous.
+        if (gSavedSettings.getBOOL("MiniMapShowPropertyLines"))
+        {
+            LLViewerParcelMgr::getInstance()->setHoverParcel(posGlobal);
+            LLParcel *hover_parcel = LLViewerParcelMgr::getInstance()->getHoverParcel();
+            if (hover_parcel)
+            {
+                std::string parcel_name = hover_parcel->getName();
+                if (!parcel_name.empty())
+                {
+                    parcel_name_msg = mParcelNameMsg;
+                    LLStringUtil::format(parcel_name_msg, {{"[PARCEL_NAME]", parcel_name}});
+                }
+
+                const LLUUID      parcel_owner          = hover_parcel->getOwnerID();
+                std::string       parcel_owner_name_url = LLSLURL("agent", parcel_owner, "inspect").getSLURLString();
+                static LLUrlMatch parcel_owner_name_url_match;
+                LLUrlRegistry::getInstance()->findUrl(parcel_owner_name_url, parcel_owner_name_url_match);
+                if (!parcel_owner_name_url_match.empty())
+                {
+                    parcel_owner_msg              = mParcelOwnerMsg;
+                    std::string parcel_owner_name = parcel_owner_name_url_match.getLabel();
+                    LLStringUtil::format(parcel_owner_msg, {{"[PARCEL_OWNER]", parcel_owner_name}});
+                }
+
+                if (hover_parcel->getForSale())
+                {
+                    const LLUUID auth_buyer_id = hover_parcel->getAuthorizedBuyerID();
+                    const LLUUID agent_id      = gAgent.getID();
+                    bool         show_for_sale = auth_buyer_id.isNull() || auth_buyer_id == agent_id || parcel_owner == agent_id;
+                    if (show_for_sale)
+                    {
+                        S32 price        = hover_parcel->getSalePrice();
+                        S32 area         = hover_parcel->getArea();
+                        F32 cost_per_sqm = 0.0f;
+                        if (area > 0)
+                        {
+                            cost_per_sqm = F32(price) / area;
+                        }
+                        std::string formatted_price          = LLResMgr::getInstance()->getMonetaryString(price);
+                        std::string formatted_cost_per_meter = llformat("%.1f", cost_per_sqm);
+                        parcel_sale_price_msg                = mParcelSalePriceMsg;
+                        LLStringUtil::format(parcel_sale_price_msg,
+                                             {{"[PRICE]", formatted_price}, {"[PRICE_PER_SQM]", formatted_cost_per_meter}});
+                        std::string formatted_area = llformat("%d", area);
+                        parcel_sale_area_msg       = mParcelSaleAreaMsg;
+                        LLStringUtil::format(parcel_sale_area_msg, {{"[AREA]", formatted_area}});
+                    }
+                }
+            }
+        }
+    }
+
+    std::string tool_tip_hint_msg;
+    if (gSavedSettings.getBOOL("DoubleClickTeleport"))
+    {
+        tool_tip_hint_msg = mAltToolTipHintMsg;
+    }
+    else if (gSavedSettings.getBOOL("DoubleClickShowWorldMap"))
+    {
+        tool_tip_hint_msg = mToolTipHintMsg;
+    }
+
+    LLStringUtil::format_map_t args;
+    args["[PARCEL_NAME_MSG]"]       = parcel_name_msg.empty() ? "" : parcel_name_msg + '\n';
+    args["[PARCEL_SALE_PRICE_MSG]"] = parcel_sale_price_msg.empty() ? "" : parcel_sale_price_msg + '\n';
+    args["[PARCEL_SALE_AREA_MSG]"]  = parcel_sale_area_msg.empty() ? "" : parcel_sale_area_msg + '\n';
+    args["[PARCEL_OWNER_MSG]"]      = parcel_owner_msg.empty() ? "" : parcel_owner_msg + '\n';
+    args["[REGION_NAME_MSG]"]       = region_name_msg.empty() ? "" : region_name_msg + '\n';
+    args["[TOOL_TIP_HINT_MSG]"]     = tool_tip_hint_msg.empty() ? "" : tool_tip_hint_msg + '\n';
+
+    std::string msg                 = mToolTipMsg;
+    LLStringUtil::format(msg, args);
+    if (msg.back() == '\n')
+    {
+        msg.resize(msg.size() - 1);
+    }
+    LLToolTipMgr::instance().show(LLToolTip::Params().message(msg).sticky_rect(sticky_rect));
+
+    return true;
 }
 
 BOOL LLNetMap::handleToolTipAgent(const LLUUID& avatar_id)
@@ -806,59 +997,58 @@ void LLNetMap::createObjectImage()
 	mUpdateNow = true;
 }
 
-BOOL LLNetMap::handleMouseDown( S32 x, S32 y, MASK mask )
+BOOL LLNetMap::handleMouseDown(S32 x, S32 y, MASK mask)
 {
-	if (!(mask & MASK_SHIFT)) return FALSE;
-
-	// Start panning
-	gFocusMgr.setMouseCapture(this);
+    // Start panning
+    gFocusMgr.setMouseCapture(this);
 
-	mStartPan = mCurPan;
-	mMouseDown.mX = x;
-	mMouseDown.mY = y;
-	return TRUE;
+    mStartPan     = mCurPan;
+    mMouseDown.mX = x;
+    mMouseDown.mY = y;
+    return true;
 }
 
-BOOL LLNetMap::handleMouseUp( S32 x, S32 y, MASK mask )
+BOOL LLNetMap::handleMouseUp(S32 x, S32 y, MASK mask)
 {
-	if(abs(mMouseDown.mX-x)<3 && abs(mMouseDown.mY-y)<3)
-		handleClick(x,y,mask);
-
-	if (hasMouseCapture())
-	{
-		if (mPanning)
-		{
-			// restore mouse cursor
-			S32 local_x, local_y;
-			local_x = mMouseDown.mX + llfloor(mCurPan.mV[VX] - mStartPan.mV[VX]);
-			local_y = mMouseDown.mY + llfloor(mCurPan.mV[VY] - mStartPan.mV[VY]);
-			LLRect clip_rect = getRect();
-			clip_rect.stretch(-8);
-			clip_rect.clipPointToRect(mMouseDown.mX, mMouseDown.mY, local_x, local_y);
-			LLUI::getInstance()->setMousePositionLocal(this, local_x, local_y);
-
-			// finish the pan
-			mPanning = false;
-
-			mMouseDown.set(0, 0);
-
-			// auto centre
-			mTargetPan.setZero();
-		}
-		gViewerWindow->showCursor();
-		gFocusMgr.setMouseCapture(NULL);
-		return TRUE;
-	}
-	return FALSE;
+    if (abs(mMouseDown.mX - x) < 3 && abs(mMouseDown.mY - y) < 3)
+    {
+        handleClick(x, y, mask);
+    }
+
+    if (hasMouseCapture())
+    {
+        if (mPanning)
+        {
+            // restore mouse cursor
+            S32 local_x, local_y;
+            local_x          = mMouseDown.mX + llfloor(mCurPan.mV[VX] - mStartPan.mV[VX]);
+            local_y          = mMouseDown.mY + llfloor(mCurPan.mV[VY] - mStartPan.mV[VY]);
+            LLRect clip_rect = getRect();
+            clip_rect.stretch(-8);
+            clip_rect.clipPointToRect(mMouseDown.mX, mMouseDown.mY, local_x, local_y);
+            LLUI::getInstance()->setMousePositionLocal(this, local_x, local_y);
+
+            // finish the pan
+            mPanning = false;
+
+            mMouseDown.set(0, 0);
+        }
+        gViewerWindow->showCursor();
+        gFocusMgr.setMouseCapture(NULL);
+        return true;
+    }
+
+    return false;
 }
 
 BOOL LLNetMap::handleRightMouseDown(S32 x, S32 y, MASK mask)
 {
 	if (mPopupMenu)
 	{
+        mPopupWorldPos = viewPosToGlobal(x, y);
 		mPopupMenu->buildDrawLabels();
 		mPopupMenu->updateParent(LLMenuGL::sMenuContainer);
-		mPopupMenu->setItemEnabled("Stop Tracking", LLTracker::isTracking(0));
+		mPopupMenu->setItemEnabled("Stop tracking", LLTracker::isTracking(0));
 		LLMenuGL::showPopup(this, mPopupMenu, x, y);
 	}
 	return TRUE;
@@ -906,6 +1096,27 @@ BOOL LLNetMap::handleDoubleClick(S32 x, S32 y, MASK mask)
 	return TRUE;
 }
 
+F32 LLNetMap::getScaleForName(std::string scale_name)
+{
+    if (scale_name == "very close")
+    {
+        return LLNetMap::MAP_SCALE_VERY_CLOSE;
+    }
+    else if (scale_name == "close")
+    {
+        return LLNetMap::MAP_SCALE_CLOSE;
+    }
+    else if (scale_name == "medium")
+    {
+        return LLNetMap::MAP_SCALE_MEDIUM;
+    }
+    else if (scale_name == "far")
+    {
+        return LLNetMap::MAP_SCALE_FAR;
+    }
+    return 0.0f;
+}
+
 // static
 bool LLNetMap::outsideSlop( S32 x, S32 y, S32 start_x, S32 start_y, S32 slop )
 {
@@ -923,7 +1134,7 @@ BOOL LLNetMap::handleHover( S32 x, S32 y, MASK mask )
 		{
 			if (!mPanning)
 			{
-				// just started panning, so hide cursor
+                // Just started panning. Hide cursor.
 				mPanning = true;
 				gViewerWindow->hideCursor();
 			}
@@ -933,61 +1144,89 @@ BOOL LLNetMap::handleHover( S32 x, S32 y, MASK mask )
 
 			// Set pan to value at start of drag + offset
 			mCurPan += delta;
-			mTargetPan = mCurPan;
 
 			gViewerWindow->moveCursorToCenter();
 		}
-
-		// Doesn't really matter, cursor should be hidden
-		gViewerWindow->setCursor( UI_CURSOR_TOOLPAN );
-	}
-	else
-	{
-		if (mask & MASK_SHIFT)
-		{
-			// If shift is held, change the cursor to hint that the map can be dragged
-			gViewerWindow->setCursor( UI_CURSOR_TOOLPAN );
-		}
-		else
-		{
-			gViewerWindow->setCursor( UI_CURSOR_CROSS );
-		}
 	}
 
+    if (mask & MASK_SHIFT)
+    {
+        // If shift is held, change the cursor to hint that the map can be
+        // dragged. However, holding shift is not required to drag the map.
+        gViewerWindow->setCursor( UI_CURSOR_TOOLPAN );
+    }
+    else
+    {
+        gViewerWindow->setCursor( UI_CURSOR_CROSS );
+    }
+
 	return TRUE;
 }
 
-void LLNetMap::handleZoom(const LLSD& userdata)
+bool LLNetMap::isZoomChecked(const LLSD &userdata)
 {
-	std::string level = userdata.asString();
-	
-	F32 scale = 0.0f;
-	if (level == std::string("default"))
-	{
-		LLControlVariable *pvar = gSavedSettings.getControl("MiniMapScale");
-		if(pvar)
-		{
-			pvar->resetToDefault();
-			scale = gSavedSettings.getF32("MiniMapScale");
-		}
-	}
-	else if (level == std::string("close"))
-		scale = LLNetMap::MAP_SCALE_MAX;
-	else if (level == std::string("medium"))
-		scale = LLNetMap::MAP_SCALE_MID;
-	else if (level == std::string("far"))
-		scale = LLNetMap::MAP_SCALE_MIN;
-	if (scale != 0.0f)
-	{
-		setScale(scale);
-	}
+    std::string level = userdata.asString();
+    F32         scale = getScaleForName(level);
+    return scale == mScale;
+}
+
+void LLNetMap::setZoom(const LLSD &userdata)
+{
+    std::string level = userdata.asString();
+    F32         scale = getScaleForName(level);
+    if (scale != 0.0f)
+    {
+        setScale(scale);
+    }
 }
 
 void LLNetMap::handleStopTracking (const LLSD& userdata)
 {
 	if (mPopupMenu)
 	{
-		mPopupMenu->setItemEnabled ("Stop Tracking", false);
+		mPopupMenu->setItemEnabled ("Stop tracking", false);
 		LLTracker::stopTracking (LLTracker::isTracking(NULL));
 	}
 }
+
+void LLNetMap::activateCenterMap(const LLSD &userdata) { mCentering = true; }
+
+bool LLNetMap::isMapOrientationChecked(const LLSD &userdata)
+{
+    const std::string command_name = userdata.asString();
+    const bool        rotate_map   = gSavedSettings.getBOOL("MiniMapRotate");
+    if (command_name == "north_at_top")
+    {
+        return !rotate_map;
+    }
+
+    if (command_name == "camera_at_top")
+    {
+        return rotate_map;
+    }
+
+    return false;
+}
+
+void LLNetMap::setMapOrientation(const LLSD &userdata)
+{
+    const std::string command_name = userdata.asString();
+    if (command_name == "north_at_top")
+    {
+        gSavedSettings.setBOOL("MiniMapRotate", false);
+    }
+    else if (command_name == "camera_at_top")
+    {
+        gSavedSettings.setBOOL("MiniMapRotate", true);
+    }
+}
+
+void LLNetMap::popupShowAboutLand(const LLSD &userdata)
+{
+    // Update parcel selection. It's important to deselect land first so the "About Land" floater doesn't refresh with the old selection.
+    LLViewerParcelMgr::getInstance()->deselectLand();
+    LLParcelSelectionHandle selection = LLViewerParcelMgr::getInstance()->selectParcelAt(mPopupWorldPos);
+    gMenuHolder->setParcelSelection(selection);
+
+    LLFloaterReg::showInstance("about_land", LLSD(), false);
+}
diff --git a/indra/newview/llnetmap.h b/indra/newview/llnetmap.h
index 1f7e7d68c60ffea70a2382de406fb00f5d1e4b62..fe1aca65a9b92220a5202e9639b2eccd8adc6977 100644
--- a/indra/newview/llnetmap.h
+++ b/indra/newview/llnetmap.h
@@ -62,9 +62,12 @@ class LLNetMap : public LLUICtrl
 public:
 	virtual ~LLNetMap();
 
-	static const F32 MAP_SCALE_MIN;
-	static const F32 MAP_SCALE_MID;
-	static const F32 MAP_SCALE_MAX;
+    static const F32 MAP_SCALE_MIN;
+    static const F32 MAP_SCALE_FAR;
+    static const F32 MAP_SCALE_MEDIUM;
+    static const F32 MAP_SCALE_CLOSE;
+    static const F32 MAP_SCALE_VERY_CLOSE;
+    static const F32 MAP_SCALE_MAX;
 
 	/*virtual*/ void	draw();
 	/*virtual*/ BOOL	handleScrollWheel(S32 x, S32 y, S32 clicks);
@@ -79,8 +82,17 @@ class LLNetMap : public LLUICtrl
 	/*virtual*/ BOOL	handleClick(S32 x, S32 y, MASK mask);
 	/*virtual*/ BOOL	handleDoubleClick( S32 x, S32 y, MASK mask );
 
-	void			setScale( F32 scale );
-	void			setToolTipMsg(const std::string& msg) { mToolTipMsg = msg; }
+    void            setScale(F32 scale);
+
+    void            setToolTipMsg(const std::string& msg) { mToolTipMsg = msg; }
+    void            setParcelNameMsg(const std::string& msg) { mParcelNameMsg = msg; }
+    void            setParcelSalePriceMsg(const std::string& msg) { mParcelSalePriceMsg = msg; }
+    void            setParcelSaleAreaMsg(const std::string& msg) { mParcelSaleAreaMsg = msg; }
+    void            setParcelOwnerMsg(const std::string& msg) { mParcelOwnerMsg = msg; }
+    void            setRegionNameMsg(const std::string& msg) { mRegionNameMsg = msg; }
+    void            setToolTipHintMsg(const std::string& msg) { mToolTipHintMsg = msg; }
+    void            setAltToolTipHintMsg(const std::string& msg) { mAltToolTipHintMsg = msg; }
+
 	void			renderScaledPointGlobal( const LLVector3d& pos, const LLColor4U &color, F32 radius );
 
 private:
@@ -94,11 +106,14 @@ class LLNetMap : public LLUICtrl
 	void			drawTracking( const LLVector3d& pos_global, 
 								  const LLColor4& color,
 								  BOOL draw_arrow = TRUE);
+    bool            isMouseOnPopupMenu();
+    void            updateAboutLandPopupButton();
 	BOOL			handleToolTipAgent(const LLUUID& avatar_id);
 	static void		showAvatarInspector(const LLUUID& avatar_id);
 
 	void			createObjectImage();
 
+    F32             getScaleForName(std::string scale_name);
 	static bool		outsideSlop(S32 x, S32 y, S32 start_x, S32 start_y, S32 slop);
 
 private:
@@ -112,11 +127,12 @@ class LLNetMap : public LLUICtrl
 	F32				mObjectMapPixels;		// Width of object map in pixels
 	F32				mDotRadius;				// Size of avatar markers
 
-	bool			mPanning;			// map is being dragged
-	LLVector2		mTargetPan;
-	LLVector2		mCurPan;
-	LLVector2		mStartPan;		// pan offset at start of drag
-	LLCoordGL		mMouseDown;			// pointer position at start of drag
+    bool            mPanning; // map is being dragged
+    bool            mCentering; // map is being re-centered around the agent
+    LLVector2       mCurPan;
+    LLVector2       mStartPan; // pan offset at start of drag
+    LLVector3d      mPopupWorldPos; // world position picked under mouse when context menu is opened
+    LLCoordGL       mMouseDown; // pointer position at start of drag
 
 	LLVector3d		mObjectImageCenterGlobal;
 	LLPointer<LLImageRaw> mObjectRawImagep;
@@ -125,14 +141,26 @@ class LLNetMap : public LLUICtrl
 	LLUUID			mClosestAgentToCursor;
 	LLUUID			mClosestAgentAtLastRightClick;
 
-	std::string		mToolTipMsg;
+    std::string     mToolTipMsg;
+    std::string     mParcelNameMsg;
+    std::string     mParcelSalePriceMsg;
+    std::string     mParcelSaleAreaMsg;
+    std::string     mParcelOwnerMsg;
+    std::string     mRegionNameMsg;
+    std::string     mToolTipHintMsg;
+    std::string     mAltToolTipHintMsg;
 
 public:
 	void			setSelected(uuid_vec_t uuids) { gmSelected=uuids; };
 
 private:
-	void handleZoom(const LLSD& userdata);
-	void handleStopTracking (const LLSD& userdata);
+    bool isZoomChecked(const LLSD& userdata);
+    void setZoom(const LLSD& userdata);
+    void handleStopTracking(const LLSD& userdata);
+    void activateCenterMap(const LLSD& userdata);
+    bool isMapOrientationChecked(const LLSD& userdata);
+    void setMapOrientation(const LLSD& userdata);
+    void popupShowAboutLand(const LLSD& userdata);
 
 	LLMenuGL*		mPopupMenu;
 	uuid_vec_t		gmSelected;
diff --git a/indra/newview/llnotificationofferhandler.cpp b/indra/newview/llnotificationofferhandler.cpp
index 201eaeb9f86eef3847e646d2efa49695cfd1bdf0..3f22467544a6f0f5100563e0c430ea232ea4ee63 100644
--- a/indra/newview/llnotificationofferhandler.cpp
+++ b/indra/newview/llnotificationofferhandler.cpp
@@ -166,14 +166,14 @@ bool LLOfferHandler::processNotification(const LLNotificationPtr& notification,
 
 /*virtual*/ void LLOfferHandler::onChange(LLNotificationPtr p)
 {
-	LLToastNotifyPanel* panelp = LLToastNotifyPanel::getInstance(p->getID());
+	auto panelp = LLToastNotifyPanel::getInstance(p->getID());
 	if (panelp)
 	{
 		//
 		// HACK: if we're dealing with a notification embedded in IM, update it
 		// otherwise remove its toast
 		//
-		if (dynamic_cast<LLIMToastNotifyPanel*>(panelp))
+		if (dynamic_cast<LLIMToastNotifyPanel*>(panelp.get()))
 		{
 			panelp->updateNotification();
 		}
diff --git a/indra/newview/llnotificationscripthandler.cpp b/indra/newview/llnotificationscripthandler.cpp
index 43c3ee3ce20f6f92894739d47fd1196c388127a9..bb39d8f362d3cc225ab303509a792a0fe2aad2d6 100644
--- a/indra/newview/llnotificationscripthandler.cpp
+++ b/indra/newview/llnotificationscripthandler.cpp
@@ -69,7 +69,8 @@ void LLScriptHandler::initChannel()
 //--------------------------------------------------------------------------
 void LLScriptHandler::addToastWithNotification(const LLNotificationPtr& notification)
 {
-	LLToastPanel* notify_box = LLToastPanel::buidPanelFromNotification(notification);
+    LL_PROFILE_ZONE_SCOPED
+    LLToastPanel* notify_box = LLToastPanel::buidPanelFromNotification(notification);
 
 	LLToast::Params p;
 	p.notif_id = notification->getID();
diff --git a/indra/newview/lloutfitgallery.cpp b/indra/newview/lloutfitgallery.cpp
index 4febb72c6c7ae97d1fdfd58b51ec5352a1b9c274..f419e2e06dd5eb56061cc21fd0706bddb33c03ea 100644
--- a/indra/newview/lloutfitgallery.cpp
+++ b/indra/newview/lloutfitgallery.cpp
@@ -1374,6 +1374,7 @@ void LLOutfitGallery::onSelectPhoto(LLUUID selected_outfit_id)
                 texture_floaterp->setOnFloaterCommitCallback(boost::bind(&LLOutfitGallery::onTexturePickerCommit, this, _1, _2));
                 texture_floaterp->setOnUpdateImageStatsCallback(boost::bind(&LLOutfitGallery::onTexturePickerUpdateImageStats, this, _1));
                 texture_floaterp->setLocalTextureEnabled(FALSE);
+                texture_floaterp->setBakeTextureEnabled(FALSE);
                 texture_floaterp->setCanApply(false, true);
             }
 
diff --git a/indra/newview/llpanelavatar.cpp b/indra/newview/llpanelavatar.cpp
index 37ed4bc74c2e3d1034da34316c15f488535aeaff..ff33efe4aaded79771b1fed2a0cfa017c87019d2 100644
--- a/indra/newview/llpanelavatar.cpp
+++ b/indra/newview/llpanelavatar.cpp
@@ -1,25 +1,25 @@
-/** 
+/**
  * @file llpanelavatar.cpp
  * @brief LLPanelAvatar and related class implementations
  *
  * $LicenseInfo:firstyear=2004&license=viewerlgpl$
  * Second Life Viewer Source Code
  * Copyright (C) 2010, Linden Research, Inc.
- * 
+ *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  * License as published by the Free Software Foundation;
  * version 2.1 of the License only.
- * 
+ *
  * This library is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * Lesser General Public License for more details.
- * 
+ *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- * 
+ *
  * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
  * $/LicenseInfo$
  */
@@ -28,173 +28,127 @@
 #include "llpanelavatar.h"
 
 #include "llagent.h"
-#include "llavataractions.h"
-#include "llcallingcard.h"
-#include "llcombobox.h"
-#include "lldateutil.h"			// ageFromDate()
-#include "llimview.h"
-#include "llmenubutton.h"
-#include "llnotificationsutil.h"
-#include "llslurl.h"
-#include "lltexteditor.h"
-#include "lltexturectrl.h"
-#include "lltoggleablemenu.h"
+#include "llloadingindicator.h"
 #include "lltooldraganddrop.h"
-#include "llscrollcontainer.h"
-#include "llavatariconctrl.h"
-#include "llfloaterreg.h"
-#include "llnotificationsutil.h"
-#include "llviewermenu.h" // is_agent_mappable
-#include "llvoiceclient.h"
-#include "lltextbox.h"
-#include "lltrans.h"
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Class LLDropTarget
-//
-// This handy class is a simple way to drop something on another
-// view. It handles drop events, always setting itself to the size of
-// its parent.
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-class LLDropTarget : public LLView
-{
-public:
-	struct Params : public LLInitParam::Block<Params, LLView::Params>
-	{
-		Optional<LLUUID> agent_id;
-		Params()
-		:	agent_id("agent_id")
-		{
-			changeDefault(mouse_opaque, false);
-			changeDefault(follows.flags, FOLLOWS_ALL);
-		}
-	};
-
-	LLDropTarget(const Params&);
-	~LLDropTarget();
-
-	void doDrop(EDragAndDropType cargo_type, void* cargo_data);
-
-	//
-	// LLView functionality
-	virtual BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
-								   EDragAndDropType cargo_type,
-								   void* cargo_data,
-								   EAcceptance* accept,
-								   std::string& tooltip_msg);
-	void setAgentID(const LLUUID &agent_id)		{ mAgentID = agent_id; }
-protected:
-	LLUUID mAgentID;
-};
-
-LLDropTarget::LLDropTarget(const LLDropTarget::Params& p) 
-:	LLView(p),
-	mAgentID(p.agent_id)
-{}
 
-LLDropTarget::~LLDropTarget()
+//////////////////////////////////////////////////////////////////////////
+// LLProfileDropTarget
+
+LLProfileDropTarget::LLProfileDropTarget(const LLProfileDropTarget::Params& p)
+:   LLView(p),
+    mAgentID(p.agent_id)
 {}
 
-void LLDropTarget::doDrop(EDragAndDropType cargo_type, void* cargo_data)
+void LLProfileDropTarget::doDrop(EDragAndDropType cargo_type, void* cargo_data)
 {
-	LL_INFOS() << "LLDropTarget::doDrop()" << LL_ENDL;
+    LL_INFOS() << "LLProfileDropTarget::doDrop()" << LL_ENDL;
 }
 
-BOOL LLDropTarget::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
-									 EDragAndDropType cargo_type,
-									 void* cargo_data,
-									 EAcceptance* accept,
-									 std::string& tooltip_msg)
+BOOL LLProfileDropTarget::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
+                                     EDragAndDropType cargo_type,
+                                     void* cargo_data,
+                                     EAcceptance* accept,
+                                     std::string& tooltip_msg)
 {
-	if(getParent())
-	{
-		LLToolDragAndDrop::handleGiveDragAndDrop(mAgentID, LLUUID::null, drop,
-												 cargo_type, cargo_data, accept);
+    if (getParent())
+    {
+        LLToolDragAndDrop::handleGiveDragAndDrop(mAgentID, LLUUID::null, drop,
+                                                 cargo_type, cargo_data, accept);
 
-		return TRUE;
-	}
+        return TRUE;
+    }
 
-	return FALSE;
+    return FALSE;
 }
 
-static LLDefaultChildRegistry::Register<LLDropTarget> r("drop_target");
+static LLDefaultChildRegistry::Register<LLProfileDropTarget> r("profile_drop_target");
 
 //////////////////////////////////////////////////////////////////////////
-//////////////////////////////////////////////////////////////////////////
-//////////////////////////////////////////////////////////////////////////
+// LLPanelProfileTab
 
 LLPanelProfileTab::LLPanelProfileTab()
 : LLPanel()
 , mAvatarId(LLUUID::null)
+, mLoadingState(PROFILE_INIT)
+, mSelfProfile(false)
 {
 }
 
 LLPanelProfileTab::~LLPanelProfileTab()
 {
-	if(getAvatarId().notNull())
-	{
-		LLAvatarPropertiesProcessor::getInstance()->removeObserver(getAvatarId(),this);
-	}
 }
 
-void LLPanelProfileTab::setAvatarId(const LLUUID& id)
+void LLPanelProfileTab::setAvatarId(const LLUUID& avatar_id)
 {
-	if(id.notNull())
-	{
-		if(getAvatarId().notNull())
-		{
-			LLAvatarPropertiesProcessor::getInstance()->removeObserver(mAvatarId,this);
-		}
-		mAvatarId = id;
-		LLAvatarPropertiesProcessor::getInstance()->addObserver(getAvatarId(),this);
-	}
+    if (avatar_id.notNull())
+    {
+        mAvatarId = avatar_id;
+        mSelfProfile = (getAvatarId() == gAgentID);
+    }
 }
 
 void LLPanelProfileTab::onOpen(const LLSD& key)
 {
-	// Don't reset panel if we are opening it for same avatar.
-	if(getAvatarId() != key.asUUID())
-	{
-		resetControls();
-		resetData();
-
-		scrollToTop();
-	}
-
-	// Update data even if we are viewing same avatar profile as some data might been changed.
-	setAvatarId(key.asUUID());
-	updateData();
-	updateButtons();
+    // Update data even if we are viewing same avatar profile as some data might been changed.
+    setAvatarId(key.asUUID());
+
+    setApplyProgress(true);
+}
+
+void LLPanelProfileTab::setLoaded()
+{
+    setApplyProgress(false);
+
+    mLoadingState = PROFILE_LOADED;
+}
+
+void LLPanelProfileTab::setApplyProgress(bool started)
+{
+    LLLoadingIndicator* indicator = findChild<LLLoadingIndicator>("progress_indicator");
+
+    if (indicator)
+    {
+        indicator->setVisible(started);
+
+        if (started)
+        {
+            indicator->start();
+        }
+        else
+        {
+            indicator->stop();
+        }
+    }
+
+    LLView* panel = findChild<LLView>("indicator_stack");
+    if (panel)
+    {
+        panel->setVisible(started);
+    }
 }
 
-void LLPanelProfileTab::scrollToTop()
+LLPanelProfilePropertiesProcessorTab::LLPanelProfilePropertiesProcessorTab()
+    : LLPanelProfileTab()
 {
-	LLScrollContainer* scrollContainer = findChild<LLScrollContainer>("profile_scroll");
-	if (scrollContainer)
-		scrollContainer->goToTop();
 }
 
-void LLPanelProfileTab::onMapButtonClick()
+LLPanelProfilePropertiesProcessorTab::~LLPanelProfilePropertiesProcessorTab()
 {
-	LLAvatarActions::showOnMap(getAvatarId());
+    if (getAvatarId().notNull())
+    {
+        LLAvatarPropertiesProcessor::getInstance()->removeObserver(getAvatarId(), this);
+    }
 }
 
-void LLPanelProfileTab::updateButtons()
+void LLPanelProfilePropertiesProcessorTab::setAvatarId(const LLUUID & avatar_id)
 {
-	bool is_buddy_online = LLAvatarTracker::instance().isBuddyOnline(getAvatarId());
-	
-	if(LLAvatarActions::isFriend(getAvatarId()))
-	{
-		getChildView("teleport")->setEnabled(is_buddy_online);
-	}
-	else
-	{
-		getChildView("teleport")->setEnabled(true);
-	}
-
-	bool enable_map_btn = (is_buddy_online &&
-			       is_agent_mappable(getAvatarId()))
-		|| gAgent.isGodlike();
-	getChildView("show_on_map_btn")->setEnabled(enable_map_btn);
+    if (avatar_id.notNull())
+    {
+        if (getAvatarId().notNull())
+        {
+            LLAvatarPropertiesProcessor::getInstance()->removeObserver(getAvatarId(), this);
+        }
+        LLPanelProfileTab::setAvatarId(avatar_id);
+        LLAvatarPropertiesProcessor::getInstance()->addObserver(getAvatarId(), this);
+    }
 }
diff --git a/indra/newview/llpanelavatar.h b/indra/newview/llpanelavatar.h
index e33a850cfa4a908926d7392b1e9faa58ede43bac..f182660c8ea68cbe09626c5d2f4e042e9f317695 100644
--- a/indra/newview/llpanelavatar.h
+++ b/indra/newview/llpanelavatar.h
@@ -1,25 +1,25 @@
-/** 
+/**
  * @file llpanelavatar.h
- * @brief LLPanelAvatar and related class definitions
+ * @brief Legacy profile panel base class
  *
- * $LicenseInfo:firstyear=2004&license=viewerlgpl$
+ * $LicenseInfo:firstyear=2019&license=viewerlgpl$
  * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- * 
+ * Copyright (C) 2019, Linden Research, Inc.
+ *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  * License as published by the Free Software Foundation;
  * version 2.1 of the License only.
- * 
+ *
  * This library is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * Lesser General Public License for more details.
- * 
+ *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- * 
+ *
  * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
  * $/LicenseInfo$
  */
@@ -29,80 +29,141 @@
 
 #include "llpanel.h"
 #include "llavatarpropertiesprocessor.h"
-#include "llcallingcard.h"
-#include "llvoiceclient.h"
 #include "llavatarnamecache.h"
 
 class LLComboBox;
 class LLLineEditor;
 
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Class LLProfileDropTarget
+//
+// This handy class is a simple way to drop something on another
+// view. It handles drop events, always setting itself to the size of
+// its parent.
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+class LLProfileDropTarget : public LLView
+{
+public:
+    struct Params : public LLInitParam::Block<Params, LLView::Params>
+    {
+        Optional<LLUUID> agent_id;
+        Params()
+        :   agent_id("agent_id")
+        {
+            changeDefault(mouse_opaque, false);
+            changeDefault(follows.flags, FOLLOWS_ALL);
+        }
+    };
+
+    LLProfileDropTarget(const Params&);
+    ~LLProfileDropTarget() {}
+
+    void doDrop(EDragAndDropType cargo_type, void* cargo_data);
+
+    //
+    // LLView functionality
+    virtual BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
+                                   EDragAndDropType cargo_type,
+                                   void* cargo_data,
+                                   EAcceptance* accept,
+                                   std::string& tooltip_msg);
+
+    void setAgentID(const LLUUID &agent_id)     { mAgentID = agent_id; }
+
+protected:
+    LLUUID mAgentID;
+};
+
+
 /**
 * Base class for any Profile View.
 */
 class LLPanelProfileTab
-	: public LLPanel
-	, public LLAvatarPropertiesObserver
+    : public LLPanel
 {
 public:
 
-	/**
-	 * Sets avatar ID, sets panel as observer of avatar related info replies from server.
-	 */
-	virtual void setAvatarId(const LLUUID& id);
-
-	/**
-	 * Returns avatar ID.
-	 */
-	virtual const LLUUID& getAvatarId() { return mAvatarId; }
-
-	/**
-	 * Sends update data request to server.
-	 */
-	virtual void updateData() = 0;
-
-	/**
-	 * Clears panel data if viewing avatar info for first time and sends update data request.
-	 */
-	virtual void onOpen(const LLSD& key);
-
-	/**
-	 * Profile tabs should close any opened panels here.
-	 *
-	 * Called from LLPanelProfile::onOpen() before opening new profile.
-	 * See LLPanelPicks::onClosePanel for example. LLPanelPicks closes picture info panel
-	 * before new profile is displayed, otherwise new profile will 
-	 * be hidden behind picture info panel.
-	 */
-	virtual void onClosePanel() {}
-
-	/**
-	 * Resets controls visibility, state, etc.
-	 */
-	virtual void resetControls(){};
-
-	/**
-	 * Clears all data received from server.
-	 */
-	virtual void resetData(){};
-
-	/*virtual*/ ~LLPanelProfileTab();
+    /**
+     * Sets avatar ID, sets panel as observer of avatar related info replies from server.
+     */
+    virtual void setAvatarId(const LLUUID& avatar_id);
+
+    /**
+     * Returns avatar ID.
+     */
+    virtual const LLUUID& getAvatarId() { return mAvatarId; }
+
+    /**
+     * Sends update data request to server.
+     */
+    virtual void updateData() {};
+
+    /**
+     * Clears panel data if viewing avatar info for first time and sends update data request.
+     */
+    virtual void onOpen(const LLSD& key);
+
+    /**
+     * Clears all data received from server.
+     */
+    virtual void resetData(){};
+
+    /*virtual*/ ~LLPanelProfileTab();
 
 protected:
 
-	LLPanelProfileTab();
+    LLPanelProfileTab();
+
+    enum ELoadingState
+    {
+        PROFILE_INIT,
+        PROFILE_LOADING,
+        PROFILE_LOADED,
+    };
+
+
+    // mLoading: false: Initial state, can request
+    //           true:  Data requested, skip duplicate requests (happens due to LLUI's habit of repeated callbacks)
+    // mLoaded:  false: Initial state, show loading indicator
+    //           true:  Data recieved, which comes in a single message, hide indicator
+    ELoadingState getLoadingState() { return mLoadingState; }
+    virtual void setLoaded();
+    void setApplyProgress(bool started);
+
+    const bool getSelfProfile() const { return mSelfProfile; }
 
-	/**
-	 * Scrolls panel to top when viewing avatar info for first time.
-	 */
-	void scrollToTop();
+public:
+    void setIsLoading() { mLoadingState = PROFILE_LOADING; }
+    void resetLoading() { mLoadingState = PROFILE_INIT; }
 
-	virtual void onMapButtonClick();
+    bool getStarted() { return mLoadingState != PROFILE_INIT; }
+    bool getIsLoaded() { return mLoadingState == PROFILE_LOADED; }
 
-	virtual void updateButtons();
+    virtual bool hasUnsavedChanges() { return false; }
+    virtual void commitUnsavedChanges() {}
 
 private:
 
-	LLUUID mAvatarId;
+    LLUUID  mAvatarId;
+    ELoadingState    mLoadingState;
+    bool    mSelfProfile;
+};
+
+class LLPanelProfilePropertiesProcessorTab
+    : public LLPanelProfileTab
+    , public LLAvatarPropertiesObserver
+{
+public:
+    LLPanelProfilePropertiesProcessorTab();
+    ~LLPanelProfilePropertiesProcessorTab();
+
+    /*virtual*/ void setAvatarId(const LLUUID& avatar_id);
+
+    /**
+     * Processes data received from server via LLAvatarPropertiesObserver.
+     */
+    virtual void processProperties(void* data, EAvatarProcessorType type) = 0;
 };
 
 #endif // LL_LLPANELAVATAR_H
diff --git a/indra/newview/llpanelblockedlist.cpp b/indra/newview/llpanelblockedlist.cpp
index 3322e8a3df435c58e87c5e076aa9cf06643a7e05..3a4fc613b7b08037d4ccaba0a37bc39c9f90ffce 100644
--- a/indra/newview/llpanelblockedlist.cpp
+++ b/indra/newview/llpanelblockedlist.cpp
@@ -232,7 +232,7 @@ void LLPanelBlockedList::onFilterEdit(const std::string& search_string)
 void LLPanelBlockedList::callbackBlockPicked(const uuid_vec_t& ids, const std::vector<LLAvatarName> names)
 {
 	if (names.empty() || ids.empty()) return;
-	LLMute mute(ids[0], names[0].getAccountName(), LLMute::AGENT);
+    LLMute mute(ids[0], names[0].getUserName(), LLMute::AGENT);
 	LLMuteList::getInstance()->add(mute);
 	showPanelAndSelect(mute.mID);
 }
diff --git a/indra/newview/llpanelclassified.cpp b/indra/newview/llpanelclassified.cpp
index c0342eef4e4de70ffe4e5b4101364c5a93946024..183000ceac2cb9d07da7bc6bb1e254eb1d3f5aa2 100644
--- a/indra/newview/llpanelclassified.cpp
+++ b/indra/newview/llpanelclassified.cpp
@@ -1,10 +1,10 @@
 /** 
  * @file llpanelclassified.cpp
- * @brief LLPanelClassified class implementation
+ * @brief LLPanelClassifiedInfo class implementation
  *
- * $LicenseInfo:firstyear=2005&license=viewerlgpl$
+ * $LicenseInfo:firstyear=2021&license=viewerlgpl$
  * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
+ * Copyright (C) 2021, Linden Research, Inc.
  * 
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -34,33 +34,21 @@
 
 #include "lldispatcher.h"
 #include "llfloaterreg.h"
-#include "llnotifications.h"
-#include "llnotificationsutil.h"
 #include "llparcel.h"
 
 #include "llagent.h"
 #include "llclassifiedflags.h"
-#include "llcommandhandler.h" // for classified HTML detail page click tracking
 #include "lliconctrl.h"
-#include "lllineeditor.h"
-#include "llcombobox.h"
 #include "lltexturectrl.h"
-#include "lltexteditor.h"
-#include "llviewerparcelmgr.h"
 #include "llfloaterworldmap.h"
 #include "llviewergenericmessage.h"	// send_generic_message
 #include "llviewerregion.h"
-#include "llviewertexture.h"
-#include "lltrans.h"
 #include "llscrollcontainer.h"
-#include "llstatusbar.h"
-#include "llviewertexture.h"
 #include "llcorehttputil.h"
 
-const S32 MINIMUM_PRICE_FOR_LISTING = 50;	// L$
-
 //static
 LLPanelClassifiedInfo::panel_list_t LLPanelClassifiedInfo::sAllPanels;
+static LLPanelInjector<LLPanelClassifiedInfo> t_panel_panel_classified_info("panel_classified_info");
 
 // "classifiedclickthrough"
 // strings[0] = classified_id
@@ -118,17 +106,8 @@ LLPanelClassifiedInfo::~LLPanelClassifiedInfo()
 	sAllPanels.remove(this);
 }
 
-// static
-LLPanelClassifiedInfo* LLPanelClassifiedInfo::create()
-{
-	LLPanelClassifiedInfo* panel = new LLPanelClassifiedInfo();
-	panel->buildFromFile("panel_classified_info.xml");
-	return panel;
-}
-
 BOOL LLPanelClassifiedInfo::postBuild()
 {
-	childSetAction("back_btn", boost::bind(&LLPanelClassifiedInfo::onExit, this));
 	childSetAction("show_on_map_btn", boost::bind(&LLPanelClassifiedInfo::onMapClick, this));
 	childSetAction("teleport_btn", boost::bind(&LLPanelClassifiedInfo::onTeleportClick, this));
 
@@ -144,16 +123,6 @@ BOOL LLPanelClassifiedInfo::postBuild()
 	return TRUE;
 }
 
-void LLPanelClassifiedInfo::setExitCallback(const commit_callback_t& cb)
-{
-	getChild<LLButton>("back_btn")->setClickedCallback(cb);
-}
-
-void LLPanelClassifiedInfo::setEditClassifiedCallback(const commit_callback_t& cb)
-{
-	getChild<LLButton>("edit_btn")->setClickedCallback(cb);
-}
-
 void LLPanelClassifiedInfo::reshape(S32 width, S32 height, BOOL called_from_parent /* = TRUE */)
 {
 	LLPanel::reshape(width, height, called_from_parent);
@@ -286,6 +255,8 @@ void LLPanelClassifiedInfo::processProperties(void* data, EAvatarProcessorType t
 			getChild<LLUICtrl>("creation_date")->setValue(date_str);
 
 			setInfoLoaded(true);
+
+			LLAvatarPropertiesProcessor::getInstance()->removeObserver(getAvatarId(), this);
 		}
 	}
 }
@@ -590,588 +561,4 @@ void LLPanelClassifiedInfo::onTeleportClick()
 	}
 }
 
-void LLPanelClassifiedInfo::onExit()
-{
-	LLAvatarPropertiesProcessor::getInstance()->removeObserver(getAvatarId(), this);
-	gGenericDispatcher.addHandler("classifiedclickthrough", NULL); // deregister our handler
-}
-
-//////////////////////////////////////////////////////////////////////////
-//////////////////////////////////////////////////////////////////////////
-//////////////////////////////////////////////////////////////////////////
-
-static const S32 CB_ITEM_MATURE = 0;
-static const S32 CB_ITEM_PG	   = 1;
-
-LLPanelClassifiedEdit::LLPanelClassifiedEdit()
- : LLPanelClassifiedInfo()
- , mIsNew(false)
- , mIsNewWithErrors(false)
- , mCanClose(false)
- , mPublishFloater(NULL)
-{
-}
-
-LLPanelClassifiedEdit::~LLPanelClassifiedEdit()
-{
-}
-
-//static
-LLPanelClassifiedEdit* LLPanelClassifiedEdit::create()
-{
-	LLPanelClassifiedEdit* panel = new LLPanelClassifiedEdit();
-	panel->buildFromFile("panel_edit_classified.xml");
-	return panel;
-}
-
-BOOL LLPanelClassifiedEdit::postBuild()
-{
-	LLPanelClassifiedInfo::postBuild();
-
-	LLUICtrl* edit_icon = getChild<LLUICtrl>("edit_icon");
-	mSnapshotCtrl->setMouseEnterCallback(boost::bind(&LLPanelClassifiedEdit::onTexturePickerMouseEnter, this, edit_icon));
-	mSnapshotCtrl->setMouseLeaveCallback(boost::bind(&LLPanelClassifiedEdit::onTexturePickerMouseLeave, this, edit_icon));
-	edit_icon->setVisible(false);
-
-	LLLineEditor* line_edit = getChild<LLLineEditor>("classified_name");
-	line_edit->setKeystrokeCallback(boost::bind(&LLPanelClassifiedEdit::onChange, this), NULL);
-
-	LLTextEditor* text_edit = getChild<LLTextEditor>("classified_desc");
-	text_edit->setKeystrokeCallback(boost::bind(&LLPanelClassifiedEdit::onChange, this));
-
-	LLComboBox* combobox = getChild<LLComboBox>( "category");
-	LLClassifiedInfo::cat_map::iterator iter;
-	for (iter = LLClassifiedInfo::sCategories.begin();
-		iter != LLClassifiedInfo::sCategories.end();
-		iter++)
-	{
-		combobox->add(LLTrans::getString(iter->second));
-	}
-
-	combobox->setCommitCallback(boost::bind(&LLPanelClassifiedEdit::onChange, this));
-
-	childSetCommitCallback("content_type", boost::bind(&LLPanelClassifiedEdit::onChange, this), NULL);
-	childSetCommitCallback("price_for_listing", boost::bind(&LLPanelClassifiedEdit::onChange, this), NULL);
-	childSetCommitCallback("auto_renew", boost::bind(&LLPanelClassifiedEdit::onChange, this), NULL);
-
-	childSetAction("save_changes_btn", boost::bind(&LLPanelClassifiedEdit::onSaveClick, this));
-	childSetAction("set_to_curr_location_btn", boost::bind(&LLPanelClassifiedEdit::onSetLocationClick, this));
-
-	mSnapshotCtrl->setOnSelectCallback(boost::bind(&LLPanelClassifiedEdit::onTextureSelected, this));
-
-	return TRUE;
-}
-
-void LLPanelClassifiedEdit::fillIn(const LLSD& key)
-{
-	setAvatarId(gAgent.getID());
-
-	if(key.isUndefined())
-	{
-		setPosGlobal(gAgent.getPositionGlobal());
-
-		LLUUID snapshot_id = LLUUID::null;
-		std::string desc;
-		LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel();
-
-		if(parcel)
-		{
-			desc = parcel->getDesc();
-			snapshot_id = parcel->getSnapshotID();
-		}
-
-		std::string region_name = LLTrans::getString("ClassifiedUpdateAfterPublish");
-		LLViewerRegion* region = gAgent.getRegion();
-		if (region)
-		{
-			region_name = region->getName();
-		}
-
-		getChild<LLUICtrl>("classified_name")->setValue(makeClassifiedName());
-		getChild<LLUICtrl>("classified_desc")->setValue(desc);
-		setSnapshotId(snapshot_id);
-		setClassifiedLocation(createLocationText(getLocationNotice(), region_name, getPosGlobal()));
-		// server will set valid parcel id
-		setParcelId(LLUUID::null);
-	}
-	else
-	{
-		setClassifiedId(key["classified_id"]);
-		setClassifiedName(key["name"]);
-		setDescription(key["desc"]);
-		setSnapshotId(key["snapshot_id"]);
-		setCategory((U32)key["category"].asInteger());
-		setContentType((U32)key["content_type"].asInteger());
-		setClassifiedLocation(key["location_text"]);
-		getChild<LLUICtrl>("auto_renew")->setValue(key["auto_renew"]);
-		getChild<LLUICtrl>("price_for_listing")->setValue(key["price_for_listing"].asInteger());
-	}
-}
-
-void LLPanelClassifiedEdit::onOpen(const LLSD& key)
-{
-	mIsNew = key.isUndefined();
-	
-	scrollToTop();
-
-	// classified is not created yet
-	bool is_new = isNew() || isNewWithErrors();
-
-	if(is_new)
-	{
-		resetData();
-		resetControls();
-
-		fillIn(key);
-
-		if(isNew())
-		{
-			LLAvatarPropertiesProcessor::getInstance()->addObserver(getAvatarId(), this);
-		}
-	}
-	else
-	{
-		LLPanelClassifiedInfo::onOpen(key);
-	}
-
-	std::string save_btn_label = is_new ? getString("publish_label") : getString("save_label");
-	getChild<LLUICtrl>("save_changes_btn")->setLabelArg("[LABEL]", save_btn_label);
-
-	enableVerbs(is_new);
-	enableEditing(is_new);
-	showEditing(!is_new);
-	resetDirty();
-	setInfoLoaded(false);
-}
-
-void LLPanelClassifiedEdit::processProperties(void* data, EAvatarProcessorType type)
-{
-	if(APT_CLASSIFIED_INFO == type)
-	{
-		LLAvatarClassifiedInfo* c_info = static_cast<LLAvatarClassifiedInfo*>(data);
-		if(c_info && getClassifiedId() == c_info->classified_id)
-		{
-			// see LLPanelClassifiedEdit::sendUpdate() for notes
-			mIsNewWithErrors = false;
-			// for just created classified - panel will probably be closed when we get here.
-			if(!getVisible())
-			{
-				return;
-			}
-
-			enableEditing(true);
-
-			setClassifiedName(c_info->name);
-			setDescription(c_info->description);
-			setSnapshotId(c_info->snapshot_id);
-			setParcelId(c_info->parcel_id);
-			setPosGlobal(c_info->pos_global);
-
-			setClassifiedLocation(createLocationText(c_info->parcel_name, c_info->sim_name, c_info->pos_global));
-			// *HACK see LLPanelClassifiedEdit::sendUpdate()
-			setCategory(c_info->category - 1);
-
-			bool mature = is_cf_mature(c_info->flags);
-			bool auto_renew = is_cf_auto_renew(c_info->flags);
-
-			setContentType(mature ? CB_ITEM_MATURE : CB_ITEM_PG);
-			getChild<LLUICtrl>("auto_renew")->setValue(auto_renew);
-			getChild<LLUICtrl>("price_for_listing")->setValue(c_info->price_for_listing);
-			getChildView("price_for_listing")->setEnabled(isNew());
-
-			resetDirty();
-			setInfoLoaded(true);
-			enableVerbs(false);
-
-			// for just created classified - in case user opened edit panel before processProperties() callback 
-			getChild<LLUICtrl>("save_changes_btn")->setLabelArg("[LABEL]", getString("save_label"));
-		}
-	}
-}
-
-BOOL LLPanelClassifiedEdit::isDirty() const
-{
-	if(mIsNew) 
-	{
-		return TRUE;
-	}
-
-	BOOL dirty = false;
-
-	dirty |= LLPanelClassifiedInfo::isDirty();
-	dirty |= getChild<LLUICtrl>("classified_snapshot")->isDirty();
-	dirty |= getChild<LLUICtrl>("classified_name")->isDirty();
-	dirty |= getChild<LLUICtrl>("classified_desc")->isDirty();
-	dirty |= getChild<LLUICtrl>("category")->isDirty();
-	dirty |= getChild<LLUICtrl>("content_type")->isDirty();
-	dirty |= getChild<LLUICtrl>("auto_renew")->isDirty();
-	dirty |= getChild<LLUICtrl>("price_for_listing")->isDirty();
-
-	return dirty;
-}
-
-void LLPanelClassifiedEdit::resetDirty()
-{
-	LLPanelClassifiedInfo::resetDirty();
-	getChild<LLUICtrl>("classified_snapshot")->resetDirty();
-	getChild<LLUICtrl>("classified_name")->resetDirty();
-
-	LLTextEditor* desc = getChild<LLTextEditor>("classified_desc");
-	// call blockUndo() to really reset dirty(and make isDirty work as intended)
-	desc->blockUndo();
-	desc->resetDirty();
-
-	getChild<LLUICtrl>("category")->resetDirty();
-	getChild<LLUICtrl>("content_type")->resetDirty();
-	getChild<LLUICtrl>("auto_renew")->resetDirty();
-	getChild<LLUICtrl>("price_for_listing")->resetDirty();
-}
-
-void LLPanelClassifiedEdit::setSaveCallback(const commit_signal_t::slot_type& cb)
-{
-	mSaveButtonClickedSignal.connect(cb);
-}
-
-void LLPanelClassifiedEdit::setCancelCallback(const commit_signal_t::slot_type& cb)
-{
-	getChild<LLButton>("cancel_btn")->setClickedCallback(cb);
-}
-
-void LLPanelClassifiedEdit::resetControls()
-{
-	LLPanelClassifiedInfo::resetControls();
-
-	getChild<LLComboBox>("category")->setCurrentByIndex(0);
-	getChild<LLComboBox>("content_type")->setCurrentByIndex(0);
-	getChild<LLUICtrl>("auto_renew")->setValue(false);
-	getChild<LLUICtrl>("price_for_listing")->setValue(MINIMUM_PRICE_FOR_LISTING);
-	getChildView("price_for_listing")->setEnabled(TRUE);
-}
-
-bool LLPanelClassifiedEdit::canClose()
-{
-	return mCanClose;
-}
-
-void LLPanelClassifiedEdit::draw()
-{
-	LLPanel::draw();
-
-	// Need to re-stretch on every draw because LLTextureCtrl::onSelectCallback
-	// does not trigger callbacks when user navigates through images.
-	stretchSnapshot();
-}
-
-void LLPanelClassifiedEdit::stretchSnapshot()
-{
-	LLPanelClassifiedInfo::stretchSnapshot();
-
-	getChild<LLUICtrl>("edit_icon")->setShape(mSnapshotCtrl->getRect());
-}
-
-U32 LLPanelClassifiedEdit::getContentType()
-{
-	LLComboBox* ct_cb = getChild<LLComboBox>("content_type");
-	return ct_cb->getCurrentIndex();
-}
-
-void LLPanelClassifiedEdit::setContentType(U32 content_type)
-{
-	LLComboBox* ct_cb = getChild<LLComboBox>("content_type");
-	ct_cb->setCurrentByIndex(content_type);
-	ct_cb->resetDirty();
-}
-
-bool LLPanelClassifiedEdit::getAutoRenew()
-{
-	return getChild<LLUICtrl>("auto_renew")->getValue().asBoolean();
-}
-
-void LLPanelClassifiedEdit::sendUpdate()
-{
-	LLAvatarClassifiedInfo c_data;
-
-	if(getClassifiedId().isNull())
-	{
-		setClassifiedId(LLUUID::generateNewID());
-	}
-
-	c_data.agent_id = gAgent.getID();
-	c_data.classified_id = getClassifiedId();
-	// *HACK 
-	// Categories on server start with 1 while combo-box index starts with 0
-	c_data.category = getCategory() + 1;
-	c_data.name = getClassifiedName();
-	c_data.description = getDescription();
-	c_data.parcel_id = getParcelId();
-	c_data.snapshot_id = getSnapshotId();
-	c_data.pos_global = getPosGlobal();
-	c_data.flags = getFlags();
-	c_data.price_for_listing = getPriceForListing();
-
-	LLAvatarPropertiesProcessor::getInstance()->sendClassifiedInfoUpdate(&c_data);
-	
-	if(isNew())
-	{
-		// Lets assume there will be some error.
-		// Successful sendClassifiedInfoUpdate will trigger processProperties and
-		// let us know there was no error.
-		mIsNewWithErrors = true;
-	}
-}
-
-U32 LLPanelClassifiedEdit::getCategory()
-{
-	LLComboBox* cat_cb = getChild<LLComboBox>("category");
-	return cat_cb->getCurrentIndex();
-}
-
-void LLPanelClassifiedEdit::setCategory(U32 category)
-{
-	LLComboBox* cat_cb = getChild<LLComboBox>("category");
-	cat_cb->setCurrentByIndex(category);
-	cat_cb->resetDirty();
-}
-
-U8 LLPanelClassifiedEdit::getFlags()
-{
-	bool auto_renew = getChild<LLUICtrl>("auto_renew")->getValue().asBoolean();
-
-	LLComboBox* content_cb = getChild<LLComboBox>("content_type");
-	bool mature = content_cb->getCurrentIndex() == CB_ITEM_MATURE;
-	
-	return pack_classified_flags_request(auto_renew, false, mature, false);
-}
-
-void LLPanelClassifiedEdit::enableVerbs(bool enable)
-{
-	getChildView("save_changes_btn")->setEnabled(enable);
-}
-
-void LLPanelClassifiedEdit::enableEditing(bool enable)
-{
-	getChildView("classified_snapshot")->setEnabled(enable);
-	getChildView("classified_name")->setEnabled(enable);
-	getChildView("classified_desc")->setEnabled(enable);
-	getChildView("set_to_curr_location_btn")->setEnabled(enable);
-	getChildView("category")->setEnabled(enable);
-	getChildView("content_type")->setEnabled(enable);
-	getChildView("price_for_listing")->setEnabled(enable);
-	getChildView("auto_renew")->setEnabled(enable);
-}
-
-void LLPanelClassifiedEdit::showEditing(bool show)
-{
-	getChildView("price_for_listing_label")->setVisible( show);
-	getChildView("price_for_listing")->setVisible( show);
-}
-
-std::string LLPanelClassifiedEdit::makeClassifiedName()
-{
-	std::string name;
-
-	LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel();
-	if(parcel)
-	{
-		name = parcel->getName();
-	}
-
-	if(!name.empty())
-	{
-		return name;
-	}
-
-	LLViewerRegion* region = gAgent.getRegion();
-	if(region)
-	{
-		name = region->getName();
-	}
-
-	return name;
-}
-
-S32 LLPanelClassifiedEdit::getPriceForListing()
-{
-	return getChild<LLUICtrl>("price_for_listing")->getValue().asInteger();
-}
-
-void LLPanelClassifiedEdit::setPriceForListing(S32 price)
-{
-	getChild<LLUICtrl>("price_for_listing")->setValue(price);
-}
-
-void LLPanelClassifiedEdit::onSetLocationClick()
-{
-	setPosGlobal(gAgent.getPositionGlobal());
-	setParcelId(LLUUID::null);
-
-	std::string region_name = LLTrans::getString("ClassifiedUpdateAfterPublish");
-	LLViewerRegion* region = gAgent.getRegion();
-	if (region)
-	{
-		region_name = region->getName();
-	}
-
-	setClassifiedLocation(createLocationText(getLocationNotice(), region_name, getPosGlobal()));
-
-	// mark classified as dirty
-	setValue(LLSD());
-
-	onChange();
-}
-
-void LLPanelClassifiedEdit::onChange()
-{
-	enableVerbs(isDirty());
-}
-
-void LLPanelClassifiedEdit::onSaveClick()
-{
-	mCanClose = false;
-
-	if(!isValidName())
-	{
-		notifyInvalidName();
-		return;
-	}
-	if(isNew() || isNewWithErrors())
-	{
-		if(gStatusBar->getBalance() < getPriceForListing())
-		{
-			LLNotificationsUtil::add("ClassifiedInsufficientFunds");
-			return;
-		}
-
-		mPublishFloater = LLFloaterReg::findTypedInstance<LLPublishClassifiedFloater>(
-			"publish_classified", LLSD());
-
-		if(!mPublishFloater)
-		{
-			mPublishFloater = LLFloaterReg::getTypedInstance<LLPublishClassifiedFloater>(
-				"publish_classified", LLSD());
-
-			mPublishFloater->setPublishClickedCallback(boost::bind
-				(&LLPanelClassifiedEdit::onPublishFloaterPublishClicked, this));
-		}
-
-		// set spinner value before it has focus or value wont be set
-		mPublishFloater->setPrice(getPriceForListing());
-		mPublishFloater->openFloater(mPublishFloater->getKey());
-		mPublishFloater->center();
-	}
-	else
-	{
-		doSave();
-	}
-}
-
-void LLPanelClassifiedEdit::doSave()
-{
-	mCanClose = true;
-	sendUpdate();
-	resetDirty();
-
-	mSaveButtonClickedSignal(this, LLSD());
-}
-
-void LLPanelClassifiedEdit::onPublishFloaterPublishClicked()
-{
-	setPriceForListing(mPublishFloater->getPrice());
-
-	doSave();
-}
-
-std::string LLPanelClassifiedEdit::getLocationNotice()
-{
-	static std::string location_notice = getString("location_notice");
-	return location_notice;
-}
-
-bool LLPanelClassifiedEdit::isValidName()
-{
-	std::string name = getClassifiedName();
-	if (name.empty())
-	{
-		return false;
-	}
-	if (!isalnum(name[0]))
-	{
-		return false;
-	}
-
-	return true;
-}
-
-void LLPanelClassifiedEdit::notifyInvalidName()
-{
-	std::string name = getClassifiedName();
-	if (name.empty())
-	{
-		LLNotificationsUtil::add("BlankClassifiedName");
-	}
-	else if (!isalnum(name[0]))
-	{
-		LLNotificationsUtil::add("ClassifiedMustBeAlphanumeric");
-	}
-}
-
-void LLPanelClassifiedEdit::onTexturePickerMouseEnter(LLUICtrl* ctrl)
-{
-	ctrl->setVisible(TRUE);
-}
-
-void LLPanelClassifiedEdit::onTexturePickerMouseLeave(LLUICtrl* ctrl)
-{
-	ctrl->setVisible(FALSE);
-}
-
-void LLPanelClassifiedEdit::onTextureSelected()
-{
-	setSnapshotId(mSnapshotCtrl->getValue().asUUID());
-	onChange();
-}
-
-//////////////////////////////////////////////////////////////////////////
-//////////////////////////////////////////////////////////////////////////
-//////////////////////////////////////////////////////////////////////////
-
-LLPublishClassifiedFloater::LLPublishClassifiedFloater(const LLSD& key)
- : LLFloater(key)
-{
-}
-
-LLPublishClassifiedFloater::~LLPublishClassifiedFloater()
-{
-}
-
-BOOL LLPublishClassifiedFloater::postBuild()
-{
-	LLFloater::postBuild();
-
-	childSetAction("publish_btn", boost::bind(&LLFloater::closeFloater, this, false));
-	childSetAction("cancel_btn", boost::bind(&LLFloater::closeFloater, this, false));
-
-	return TRUE;
-}
-
-void LLPublishClassifiedFloater::setPrice(S32 price)
-{
-	getChild<LLUICtrl>("price_for_listing")->setValue(price);
-}
-
-S32 LLPublishClassifiedFloater::getPrice()
-{
-	return getChild<LLUICtrl>("price_for_listing")->getValue().asInteger();
-}
-
-void LLPublishClassifiedFloater::setPublishClickedCallback(const commit_signal_t::slot_type& cb)
-{
-	getChild<LLButton>("publish_btn")->setClickedCallback(cb);
-}
-
-void LLPublishClassifiedFloater::setCancelClickedCallback(const commit_signal_t::slot_type& cb)
-{
-	getChild<LLButton>("cancel_btn")->setClickedCallback(cb);
-}
-
 //EOF
diff --git a/indra/newview/llpanelclassified.h b/indra/newview/llpanelclassified.h
index b29278261543123e1464e013f75044b9ea974f34..471becd0f7fe330dc0c34bc001a394f72cd2668d 100644
--- a/indra/newview/llpanelclassified.h
+++ b/indra/newview/llpanelclassified.h
@@ -1,10 +1,10 @@
 /** 
  * @file llpanelclassified.h
- * @brief LLPanelClassified class definition
+ * @brief LLPanelClassifiedInfo class definition
  *
- * $LicenseInfo:firstyear=2005&license=viewerlgpl$
+ * $LicenseInfo:firstyear=2021&license=viewerlgpl$
  * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
+ * Copyright (C) 2021, Linden Research, Inc.
  * 
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -35,39 +35,16 @@
 #include "llfloater.h"
 #include "llpanel.h"
 #include "llrect.h"
-#include "lluuid.h"
-#include "v3dmath.h"
-#include "llcoros.h"
-#include "lleventcoro.h"
 
 class LLScrollContainer;
 class LLTextureCtrl;
-class LLUICtrl;
-
-class LLPublishClassifiedFloater : public LLFloater
-{
-public:
-	LLPublishClassifiedFloater(const LLSD& key);
-	virtual ~LLPublishClassifiedFloater();
-
-	/*virtual*/ BOOL postBuild();
-
-	void setPrice(S32 price);
-	S32 getPrice();
-
-	void setPublishClickedCallback(const commit_signal_t::slot_type& cb);
-	void setCancelClickedCallback(const commit_signal_t::slot_type& cb);
-
-private:
-};
 
 class LLPanelClassifiedInfo : public LLPanel, public LLAvatarPropertiesObserver
 {
 	LOG_CLASS(LLPanelClassifiedInfo);
 public:
 
-	static LLPanelClassifiedInfo* create();
-
+	LLPanelClassifiedInfo();
 	virtual ~LLPanelClassifiedInfo();
 
 	/*virtual*/ void onOpen(const LLSD& key);
@@ -135,18 +112,12 @@ class LLPanelClassifiedInfo : public LLPanel, public LLAvatarPropertiesObserver
 			const LLVector3d& global_pos,
 			const std::string& sim_name);
 
-	void setExitCallback(const commit_callback_t& cb);
-
-	void setEditClassifiedCallback(const commit_callback_t& cb);
-
 	/*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE);
 
 	/*virtual*/ void draw();
 
 protected:
 
-	LLPanelClassifiedInfo();
-
 	virtual void resetData();
 
 	virtual void resetControls();
@@ -165,7 +136,6 @@ class LLPanelClassifiedInfo : public LLPanel, public LLAvatarPropertiesObserver
 
 	void onMapClick();
 	void onTeleportClick();
-	void onExit();
 
 	bool mSnapshotStreched;
 	LLRect mSnapshotRect;
@@ -202,100 +172,4 @@ class LLPanelClassifiedInfo : public LLPanel, public LLAvatarPropertiesObserver
 	static panel_list_t sAllPanels;
 };
 
-class LLPanelClassifiedEdit : public LLPanelClassifiedInfo
-{
-	LOG_CLASS(LLPanelClassifiedEdit);
-public:
-
-	static LLPanelClassifiedEdit* create();
-
-	virtual ~LLPanelClassifiedEdit();
-
-	/*virtual*/ BOOL postBuild();
-
-	void fillIn(const LLSD& key);
-
-	/*virtual*/ void onOpen(const LLSD& key);
-
-	/*virtual*/ void processProperties(void* data, EAvatarProcessorType type);
-
-	/*virtual*/ BOOL isDirty() const;
-
-	/*virtual*/ void resetDirty();
-
-	void setSaveCallback(const commit_signal_t::slot_type& cb);
-
-	void setCancelCallback(const commit_signal_t::slot_type& cb);
-
-	/*virtual*/ void resetControls();
-
-	bool isNew() { return mIsNew; }
-
-	bool isNewWithErrors() { return mIsNewWithErrors; }
-
-	bool canClose();
-
-	void draw();
-
-	void stretchSnapshot();
-
-	U32 getCategory();
-
-	void setCategory(U32 category);
-
-	U32 getContentType();
-
-	void setContentType(U32 content_type);
-
-	bool getAutoRenew();
-
-	S32 getPriceForListing();
-
-protected:
-
-	LLPanelClassifiedEdit();
-
-	void sendUpdate();
-
-	void enableVerbs(bool enable);
-
-	void enableEditing(bool enable);
-
-	void showEditing(bool show);
-
-	std::string makeClassifiedName();
-
-	void setPriceForListing(S32 price);
-
-	U8 getFlags();
-
-	std::string getLocationNotice();
-
-	bool isValidName();
-
-	void notifyInvalidName();
-
-	void onSetLocationClick();
-	void onChange();
-	void onSaveClick();
-
-	void doSave();
-
-	void onPublishFloaterPublishClicked();
-
-	void onTexturePickerMouseEnter(LLUICtrl* ctrl);
-	void onTexturePickerMouseLeave(LLUICtrl* ctrl);
-
-	void onTextureSelected();
-
-private:
-	bool mIsNew;
-	bool mIsNewWithErrors;
-	bool mCanClose;
-
-	LLPublishClassifiedFloater* mPublishFloater;
-
-	commit_signal_t mSaveButtonClickedSignal;
-};
-
 #endif // LL_LLPANELCLASSIFIED_H
diff --git a/indra/newview/llpaneleditwearable.cpp b/indra/newview/llpaneleditwearable.cpp
index be11a4a9f3ad285df567eb4a4de9d3e4187b0434..ea10aa75ae011aa7b7ce0da16ead9677519f2b16 100644
--- a/indra/newview/llpaneleditwearable.cpp
+++ b/indra/newview/llpaneleditwearable.cpp
@@ -1308,7 +1308,9 @@ void LLPanelEditWearable::changeCamera(U8 subpart)
         gMorphView->setCameraOffset( subpart_entry->mCameraOffset );
         if (gSavedSettings.getBOOL("AppearanceCameraMovement"))
         {
-                gMorphView->updateCamera();
+            // Unlock focus from avatar but don't stop animation to not interrupt ANIM_AGENT_CUSTOMIZE
+            gAgentCamera.setFocusOnAvatar(FALSE, gAgentCamera.getCameraAnimating());
+            gMorphView->updateCamera();
         }
 }
 
diff --git a/indra/newview/llpanelexperiences.h b/indra/newview/llpanelexperiences.h
index 9d5afd1a6af5ef3c47d26cdb061f98b9e7510833..11111f2a2e2281569e0c809432246d6a702b8f06 100644
--- a/indra/newview/llpanelexperiences.h
+++ b/indra/newview/llpanelexperiences.h
@@ -29,7 +29,6 @@
 
 #include "llaccordionctrltab.h"
 #include "llflatlistview.h"
-#include "llpanelavatar.h"
 
 class LLExperienceItem;
 class LLPanelProfile; 
diff --git a/indra/newview/llpanelface.cpp b/indra/newview/llpanelface.cpp
index 71657239a693fd5e3f6c7d92ad482283f9ce4dcb..178aba11a333183cd133b2022d5c0194121eb9aa 100644
--- a/indra/newview/llpanelface.cpp
+++ b/indra/newview/llpanelface.cpp
@@ -38,6 +38,7 @@
 #include "llfontgl.h"
 
 // project includes
+#include "llagent.h"
 #include "llagentdata.h"
 #include "llbutton.h"
 #include "llcheckboxctrl.h"
@@ -45,10 +46,18 @@
 #include "llcombobox.h"
 #include "lldrawpoolbump.h"
 #include "llface.h"
+#include "llinventoryfunctions.h"
+#include "llinventorymodel.h" // gInventory
+#include "llinventorymodelbackgroundfetch.h"
+#include "llfloatermediasettings.h"
+#include "llfloaterreg.h"
 #include "lllineeditor.h"
 #include "llmaterialmgr.h"
+#include "llmediactrl.h"
 #include "llmediaentry.h"
+#include "llmenubutton.h"
 #include "llnotificationsutil.h"
+#include "llpanelcontents.h"
 #include "llradiogroup.h"
 #include "llresmgr.h"
 #include "llselectmgr.h"
@@ -57,6 +66,8 @@
 #include "lltexturectrl.h"
 #include "lltextureentry.h"
 #include "lltooldraganddrop.h"
+#include "lltoolface.h"
+#include "lltoolmgr.h"
 #include "lltrans.h"
 #include "llui.h"
 #include "llviewercontrol.h"
@@ -92,10 +103,9 @@ std::string USE_TEXTURE;
 
 LLRender::eTexIndex LLPanelFace::getTextureChannelToEdit()
 {
-	LLComboBox* combobox_matmedia = getChild<LLComboBox>("combobox matmedia");
 	LLRadioGroup* radio_mat_type = getChild<LLRadioGroup>("radio_material_type");
 
-	LLRender::eTexIndex channel_to_edit = (combobox_matmedia && combobox_matmedia->getCurrentIndex() == MATMEDIA_MATERIAL) ?
+	LLRender::eTexIndex channel_to_edit = (mComboMatMedia && mComboMatMedia->getCurrentIndex() == MATMEDIA_MATERIAL) ?
 	                                                    (radio_mat_type ? (LLRender::eTexIndex)radio_mat_type->getSelectedIndex() : LLRender::DIFFUSE_MAP) : LLRender::DIFFUSE_MAP;
 
 	channel_to_edit = (channel_to_edit == LLRender::NORMAL_MAP)		? (getCurrentNormalMap().isNull()		? LLRender::DIFFUSE_MAP : channel_to_edit) : channel_to_edit;
@@ -154,6 +164,8 @@ BOOL	LLPanelFace::postBuild()
 	childSetCommitCallback("glossiness",&LLPanelFace::onCommitMaterialGloss, this);
 	childSetCommitCallback("environment",&LLPanelFace::onCommitMaterialEnv, this);
 	childSetCommitCallback("maskcutoff",&LLPanelFace::onCommitMaterialMaskCutoff, this);
+    childSetCommitCallback("add_media", &LLPanelFace::onClickBtnAddMedia, this);
+    childSetCommitCallback("delete_media", &LLPanelFace::onClickBtnDeleteMedia, this);
 
 	childSetAction("button align",&LLPanelFace::onClickAutoFix,this);
 	childSetAction("button align textures", &LLPanelFace::onAlignTexture, this);
@@ -165,7 +177,6 @@ BOOL	LLPanelFace::postBuild()
 	LLColorSwatchCtrl*	mShinyColorSwatch;
 
 	LLComboBox*		mComboTexGen;
-	LLComboBox*		mComboMatMedia;
 
 	LLCheckBoxCtrl	*mCheckFullbright;
 	
@@ -298,7 +309,12 @@ BOOL	LLPanelFace::postBuild()
 	{
 		mCtrlGlow->setCommitCallback(LLPanelFace::onCommitGlow, this);
 	}
-	
+
+    mMenuClipboardColor = getChild<LLMenuButton>("clipboard_color_params_btn");
+    mMenuClipboardTexture = getChild<LLMenuButton>("clipboard_texture_params_btn");
+    
+    mTitleMedia = getChild<LLMediaCtrl>("title_media");
+    mTitleMediaText = getChild<LLTextBox>("media_info");
 
 	clearCtrls();
 
@@ -307,17 +323,33 @@ BOOL	LLPanelFace::postBuild()
 
 LLPanelFace::LLPanelFace()
 :	LLPanel(),
-	mIsAlpha(false)
+    mIsAlpha(false),
+    mComboMatMedia(NULL),
+    mTitleMedia(NULL),
+    mTitleMediaText(NULL),
+    mNeedMediaTitle(true)
 {
-	USE_TEXTURE = LLTrans::getString("use_texture");
+    USE_TEXTURE = LLTrans::getString("use_texture");
+    mCommitCallbackRegistrar.add("PanelFace.menuDoToSelected", boost::bind(&LLPanelFace::menuDoToSelected, this, _2));
+    mEnableCallbackRegistrar.add("PanelFace.menuEnable", boost::bind(&LLPanelFace::menuEnableItem, this, _2));
 }
 
-
 LLPanelFace::~LLPanelFace()
 {
-	// Children all cleaned up by default view destructor.
+    unloadMedia();
 }
 
+void LLPanelFace::draw()
+{
+    updateCopyTexButton();
+
+    // grab media name/title and update the UI widget
+    // Todo: move it, it's preferable not to update
+    // labels inside draw
+    updateMediaTitle();
+
+    LLPanel::draw();
+}
 
 void LLPanelFace::sendTexture()
 {
@@ -806,21 +838,20 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)
 		BOOL editable = objectp->permModify() && !objectp->isPermanentEnforced();
 
 		// only turn on auto-adjust button if there is a media renderer and the media is loaded
-		getChildView("button align")->setEnabled(editable);
+        childSetEnabled("button align", editable);
 		
-		LLComboBox* combobox_matmedia = getChild<LLComboBox>("combobox matmedia");
-		if (combobox_matmedia)
+		if (mComboMatMedia)
 		{
-			if (combobox_matmedia->getCurrentIndex() < MATMEDIA_MATERIAL)
+			if (mComboMatMedia->getCurrentIndex() < MATMEDIA_MATERIAL)
 			{
-				combobox_matmedia->selectNthItem(MATMEDIA_MATERIAL);
+                mComboMatMedia->selectNthItem(MATMEDIA_MATERIAL);
 			}
+            mComboMatMedia->setEnabled(editable);
 		}
 		else
 		{
 			LL_WARNS() << "failed getChild for 'combobox matmedia'" << LL_ENDL;
 		}
-		getChildView("combobox matmedia")->setEnabled(editable);
 
 		LLRadioGroup* radio_mat_type = getChild<LLRadioGroup>("radio_material_type");
 		if(radio_mat_type)
@@ -829,7 +860,6 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)
 		    {
 		        radio_mat_type->selectNthItem(MATTYPE_DIFFUSE);
 		    }
-
 		}
 		else
 		{
@@ -858,22 +888,22 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)
 		{
 			getChildView("color label")->setEnabled(editable);
 		}
-		LLColorSwatchCtrl*	mColorSwatch = getChild<LLColorSwatchCtrl>("colorswatch");
+		LLColorSwatchCtrl*	color_swatch = findChild<LLColorSwatchCtrl>("colorswatch");
 
 		LLColor4 color					= LLColor4::white;
 		bool		identical_color	= false;
 
-		if(mColorSwatch)
+		if(color_swatch)
 		{
 			LLSelectedTE::getColor(color, identical_color);
-			LLColor4 prev_color = mColorSwatch->get();
+			LLColor4 prev_color = color_swatch->get();
 
-			mColorSwatch->setOriginal(color);
-			mColorSwatch->set(color, force_set_values || (prev_color != color) || !editable);
+            color_swatch->setOriginal(color);
+            color_swatch->set(color, force_set_values || (prev_color != color) || !editable);
 
-			mColorSwatch->setValid(editable);
-			mColorSwatch->setEnabled( editable );
-			mColorSwatch->setCanApplyImmediately( editable );
+            color_swatch->setValid(editable);
+            color_swatch->setEnabled( editable );
+            color_swatch->setCanApplyImmediately( editable );
 		}
 
 		// Color transparency
@@ -1356,7 +1386,7 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)
 				BOOL identical_repeats = true;
 				F32  repeats = 1.0f;
 
-				U32 material_type = (combobox_matmedia->getCurrentIndex() == MATMEDIA_MATERIAL) ? radio_mat_type->getSelectedIndex() : MATTYPE_DIFFUSE;
+				U32 material_type = (mComboMatMedia->getCurrentIndex() == MATMEDIA_MATERIAL) ? radio_mat_type->getSelectedIndex() : MATTYPE_DIFFUSE;
 				LLSelectMgr::getInstance()->setTextureChannel(LLRender::eTexIndex(material_type));
 
 				switch (material_type)
@@ -1508,6 +1538,9 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)
 				}
 			}
 		}
+        S32 selected_count = LLSelectMgr::getInstance()->getSelection()->getObjectCount();
+        BOOL single_volume = (selected_count == 1);
+        mMenuClipboardColor->setEnabled(editable && single_volume);
 
 		// Set variable values for numeric expressions
 		LLCalc* calcp = LLCalc::getInstance();
@@ -1568,12 +1601,772 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)
 }
 
 
+void LLPanelFace::updateCopyTexButton()
+{
+    LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getFirstObject();
+    mMenuClipboardTexture->setEnabled(objectp && objectp->getPCode() == LL_PCODE_VOLUME && objectp->permModify() 
+                                                    && !objectp->isPermanentEnforced() && !objectp->isInventoryPending() 
+                                                    && (LLSelectMgr::getInstance()->getSelection()->getObjectCount() == 1));
+    std::string tooltip = (objectp && objectp->isInventoryPending()) ? LLTrans::getString("LoadingContents") : getString("paste_options");
+    mMenuClipboardTexture->setToolTip(tooltip);
+
+}
+
 void LLPanelFace::refresh()
 {
 	LL_DEBUGS("Materials") << LL_ENDL;
 	getState();
 }
 
+void LLPanelFace::refreshMedia()
+{
+    LLObjectSelectionHandle selected_objects = LLSelectMgr::getInstance()->getSelection();
+    LLViewerObject* first_object = selected_objects->getFirstObject();
+
+    if (!(first_object
+        && first_object->getPCode() == LL_PCODE_VOLUME
+        && first_object->permModify()
+        ))
+    {
+        getChildView("add_media")->setEnabled(FALSE);
+        mTitleMediaText->clear();
+        clearMediaSettings();
+        return;
+    }
+
+    std::string url = first_object->getRegion()->getCapability("ObjectMedia");
+    bool has_media_capability = (!url.empty());
+
+    if (!has_media_capability)
+    {
+        getChildView("add_media")->setEnabled(FALSE);
+        LL_WARNS("LLFloaterToolsMedia") << "Media not enabled (no capability) in this region!" << LL_ENDL;
+        clearMediaSettings();
+        return;
+    }
+
+    BOOL is_nonpermanent_enforced = (LLSelectMgr::getInstance()->getSelection()->getFirstRootNode()
+        && LLSelectMgr::getInstance()->selectGetRootsNonPermanentEnforced())
+        || LLSelectMgr::getInstance()->selectGetNonPermanentEnforced();
+    bool editable = is_nonpermanent_enforced && (first_object->permModify() || selectedMediaEditable());
+
+    // Check modify permissions and whether any selected objects are in
+    // the process of being fetched.  If they are, then we're not editable
+    if (editable)
+    {
+        LLObjectSelection::iterator iter = selected_objects->begin();
+        LLObjectSelection::iterator end = selected_objects->end();
+        for (; iter != end; ++iter)
+        {
+            LLSelectNode* node = *iter;
+            LLVOVolume* object = dynamic_cast<LLVOVolume*>(node->getObject());
+            if (NULL != object)
+            {
+                if (!object->permModify())
+                {
+                    LL_INFOS("LLFloaterToolsMedia")
+                        << "Selection not editable due to lack of modify permissions on object id "
+                        << object->getID() << LL_ENDL;
+
+                    editable = false;
+                    break;
+                }
+            }
+        }
+    }
+
+    // Media settings
+    bool bool_has_media = false;
+    struct media_functor : public LLSelectedTEGetFunctor<bool>
+    {
+        bool get(LLViewerObject* object, S32 face)
+        {
+            LLTextureEntry *te = object->getTE(face);
+            if (te)
+            {
+                return te->hasMedia();
+            }
+            return false;
+        }
+    } func;
+
+
+    // check if all faces have media(or, all dont have media)
+    LLFloaterMediaSettings::getInstance()->mIdenticalHasMediaInfo = selected_objects->getSelectedTEValue(&func, bool_has_media);
+
+    const LLMediaEntry default_media_data;
+
+    struct functor_getter_media_data : public LLSelectedTEGetFunctor< LLMediaEntry>
+    {
+        functor_getter_media_data(const LLMediaEntry& entry) : mMediaEntry(entry) {}
+
+        LLMediaEntry get(LLViewerObject* object, S32 face)
+        {
+            if (object)
+                if (object->getTE(face))
+                    if (object->getTE(face)->getMediaData())
+                        return *(object->getTE(face)->getMediaData());
+            return mMediaEntry;
+        };
+
+        const LLMediaEntry& mMediaEntry;
+
+    } func_media_data(default_media_data);
+
+    LLMediaEntry media_data_get;
+    LLFloaterMediaSettings::getInstance()->mMultipleMedia = !(selected_objects->getSelectedTEValue(&func_media_data, media_data_get));
+
+    std::string multi_media_info_str = LLTrans::getString("Multiple Media");
+    std::string media_title = "";
+    // update UI depending on whether "object" (prim or face) has media
+    // and whether or not you are allowed to edit it.
+
+    getChildView("add_media")->setEnabled(editable);
+    // IF all the faces have media (or all dont have media)
+    if (LLFloaterMediaSettings::getInstance()->mIdenticalHasMediaInfo)
+    {
+        // TODO: get media title and set it.
+        mTitleMediaText->clear();
+        // if identical is set, all faces are same (whether all empty or has the same media)
+        if (!(LLFloaterMediaSettings::getInstance()->mMultipleMedia))
+        {
+            // Media data is valid
+            if (media_data_get != default_media_data)
+            {
+                // initial media title is the media URL (until we get the name)
+                media_title = media_data_get.getHomeURL();
+            }
+            // else all faces might be empty. 
+        }
+        else // there' re Different Medias' been set on on the faces.
+        {
+            media_title = multi_media_info_str;
+        }
+
+        getChildView("delete_media")->setEnabled(bool_has_media && editable);
+        // TODO: display a list of all media on the face - use 'identical' flag
+    }
+    else // not all face has media but at least one does.
+    {
+        // seleted faces have not identical value
+        LLFloaterMediaSettings::getInstance()->mMultipleValidMedia = selected_objects->isMultipleTEValue(&func_media_data, default_media_data);
+
+        if (LLFloaterMediaSettings::getInstance()->mMultipleValidMedia)
+        {
+            media_title = multi_media_info_str;
+        }
+        else
+        {
+            // Media data is valid
+            if (media_data_get != default_media_data)
+            {
+                // initial media title is the media URL (until we get the name)
+                media_title = media_data_get.getHomeURL();
+            }
+        }
+
+        getChildView("delete_media")->setEnabled(TRUE);
+    }
+
+    U32 materials_media = mComboMatMedia->getCurrentIndex();
+    if (materials_media == MATMEDIA_MEDIA)
+    {
+        // currently displaying media info, navigateTo and update title
+        navigateToTitleMedia(media_title);
+    }
+    else
+    {
+        // Media can be heavy, don't keep it around
+        // MAC specific: MAC doesn't support setVolume(0) so if  not
+        // unloaded, it might keep playing audio until user closes editor
+        unloadMedia();
+        mNeedMediaTitle = false;
+    }
+
+    mTitleMediaText->setText(media_title);
+
+    // load values for media settings
+    updateMediaSettings();
+
+    LLFloaterMediaSettings::initValues(mMediaSettings, editable);
+}
+
+void LLPanelFace::unloadMedia()
+{
+    // destroy media source used to grab media title
+    if (mTitleMedia)
+        mTitleMedia->unloadMediaSource();
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//
+void LLPanelFace::navigateToTitleMedia( const std::string url )
+{
+	std::string multi_media_info_str = LLTrans::getString("Multiple Media");
+	if (url.empty() || multi_media_info_str == url)
+	{
+		// nothing to show
+		mNeedMediaTitle = false;
+	}
+	else if (mTitleMedia)
+	{
+		LLPluginClassMedia* media_plugin = mTitleMedia->getMediaPlugin();
+		// check if url changed or if we need a new media source
+		if (mTitleMedia->getCurrentNavUrl() != url || media_plugin == NULL)
+		{
+			mTitleMedia->navigateTo( url );
+
+            LLViewerMediaImpl* impl = LLViewerMedia::getInstance()->getMediaImplFromTextureID(mTitleMedia->getTextureID());
+            if (impl)
+            {
+                // if it's a page with a movie, we don't want to hear it
+                impl->setVolume(0);
+            };
+		}
+
+		// flag that we need to update the title (even if no request were made)
+		mNeedMediaTitle = true;
+	}
+}
+
+bool LLPanelFace::selectedMediaEditable()
+{
+    U32 owner_mask_on;
+    U32 owner_mask_off;
+    U32 valid_owner_perms = LLSelectMgr::getInstance()->selectGetPerm(PERM_OWNER,
+        &owner_mask_on, &owner_mask_off);
+    U32 group_mask_on;
+    U32 group_mask_off;
+    U32 valid_group_perms = LLSelectMgr::getInstance()->selectGetPerm(PERM_GROUP,
+        &group_mask_on, &group_mask_off);
+    U32 everyone_mask_on;
+    U32 everyone_mask_off;
+    S32 valid_everyone_perms = LLSelectMgr::getInstance()->selectGetPerm(PERM_EVERYONE,
+        &everyone_mask_on, &everyone_mask_off);
+
+    bool selected_Media_editable = false;
+
+    // if perms we got back are valid
+    if (valid_owner_perms &&
+        valid_group_perms &&
+        valid_everyone_perms)
+    {
+
+        if ((owner_mask_on & PERM_MODIFY) ||
+            (group_mask_on & PERM_MODIFY) ||
+            (everyone_mask_on & PERM_MODIFY))
+        {
+            selected_Media_editable = true;
+        }
+        else
+            // user is NOT allowed to press the RESET button
+        {
+            selected_Media_editable = false;
+        };
+    };
+
+    return selected_Media_editable;
+}
+
+void LLPanelFace::clearMediaSettings()
+{
+    LLFloaterMediaSettings::clearValues(false);
+}
+
+void LLPanelFace::updateMediaSettings()
+{
+    bool identical(false);
+    std::string base_key("");
+    std::string value_str("");
+    int value_int = 0;
+    bool value_bool = false;
+    LLObjectSelectionHandle selected_objects = LLSelectMgr::getInstance()->getSelection();
+    // TODO: (CP) refactor this using something clever or boost or both !!
+
+    const LLMediaEntry default_media_data;
+
+    // controls 
+    U8 value_u8 = default_media_data.getControls();
+    struct functor_getter_controls : public LLSelectedTEGetFunctor< U8 >
+    {
+        functor_getter_controls(const LLMediaEntry &entry) : mMediaEntry(entry) {}
+
+        U8 get(LLViewerObject* object, S32 face)
+        {
+            if (object)
+                if (object->getTE(face))
+                    if (object->getTE(face)->getMediaData())
+                        return object->getTE(face)->getMediaData()->getControls();
+            return mMediaEntry.getControls();
+        };
+
+        const LLMediaEntry &mMediaEntry;
+
+    } func_controls(default_media_data);
+    identical = selected_objects->getSelectedTEValue(&func_controls, value_u8);
+    base_key = std::string(LLMediaEntry::CONTROLS_KEY);
+    mMediaSettings[base_key] = value_u8;
+    mMediaSettings[base_key + std::string(LLPanelContents::TENTATIVE_SUFFIX)] = !identical;
+
+    // First click (formerly left click)
+    value_bool = default_media_data.getFirstClickInteract();
+    struct functor_getter_first_click : public LLSelectedTEGetFunctor< bool >
+    {
+        functor_getter_first_click(const LLMediaEntry& entry) : mMediaEntry(entry) {}
+
+        bool get(LLViewerObject* object, S32 face)
+        {
+            if (object)
+                if (object->getTE(face))
+                    if (object->getTE(face)->getMediaData())
+                        return object->getTE(face)->getMediaData()->getFirstClickInteract();
+            return mMediaEntry.getFirstClickInteract();
+        };
+
+        const LLMediaEntry &mMediaEntry;
+
+    } func_first_click(default_media_data);
+    identical = selected_objects->getSelectedTEValue(&func_first_click, value_bool);
+    base_key = std::string(LLMediaEntry::FIRST_CLICK_INTERACT_KEY);
+    mMediaSettings[base_key] = value_bool;
+    mMediaSettings[base_key + std::string(LLPanelContents::TENTATIVE_SUFFIX)] = !identical;
+
+    // Home URL
+    value_str = default_media_data.getHomeURL();
+    struct functor_getter_home_url : public LLSelectedTEGetFunctor< std::string >
+    {
+        functor_getter_home_url(const LLMediaEntry& entry) : mMediaEntry(entry) {}
+
+        std::string get(LLViewerObject* object, S32 face)
+        {
+            if (object)
+                if (object->getTE(face))
+                    if (object->getTE(face)->getMediaData())
+                        return object->getTE(face)->getMediaData()->getHomeURL();
+            return mMediaEntry.getHomeURL();
+        };
+
+        const LLMediaEntry &mMediaEntry;
+
+    } func_home_url(default_media_data);
+    identical = selected_objects->getSelectedTEValue(&func_home_url, value_str);
+    base_key = std::string(LLMediaEntry::HOME_URL_KEY);
+    mMediaSettings[base_key] = value_str;
+    mMediaSettings[base_key + std::string(LLPanelContents::TENTATIVE_SUFFIX)] = !identical;
+
+    // Current URL
+    value_str = default_media_data.getCurrentURL();
+    struct functor_getter_current_url : public LLSelectedTEGetFunctor< std::string >
+    {
+        functor_getter_current_url(const LLMediaEntry& entry) : mMediaEntry(entry) {}
+
+        std::string get(LLViewerObject* object, S32 face)
+        {
+            if (object)
+                if (object->getTE(face))
+                    if (object->getTE(face)->getMediaData())
+                        return object->getTE(face)->getMediaData()->getCurrentURL();
+            return mMediaEntry.getCurrentURL();
+        };
+
+        const LLMediaEntry &mMediaEntry;
+
+    } func_current_url(default_media_data);
+    identical = selected_objects->getSelectedTEValue(&func_current_url, value_str);
+    base_key = std::string(LLMediaEntry::CURRENT_URL_KEY);
+    mMediaSettings[base_key] = value_str;
+    mMediaSettings[base_key + std::string(LLPanelContents::TENTATIVE_SUFFIX)] = !identical;
+
+    // Auto zoom
+    value_bool = default_media_data.getAutoZoom();
+    struct functor_getter_auto_zoom : public LLSelectedTEGetFunctor< bool >
+    {
+
+        functor_getter_auto_zoom(const LLMediaEntry& entry) : mMediaEntry(entry) {}
+
+        bool get(LLViewerObject* object, S32 face)
+        {
+            if (object)
+                if (object->getTE(face))
+                    if (object->getTE(face)->getMediaData())
+                        return object->getTE(face)->getMediaData()->getAutoZoom();
+            return mMediaEntry.getAutoZoom();
+        };
+
+        const LLMediaEntry &mMediaEntry;
+
+    } func_auto_zoom(default_media_data);
+    identical = selected_objects->getSelectedTEValue(&func_auto_zoom, value_bool);
+    base_key = std::string(LLMediaEntry::AUTO_ZOOM_KEY);
+    mMediaSettings[base_key] = value_bool;
+    mMediaSettings[base_key + std::string(LLPanelContents::TENTATIVE_SUFFIX)] = !identical;
+
+    // Auto play
+    //value_bool = default_media_data.getAutoPlay();
+    // set default to auto play TRUE -- angela  EXT-5172
+    value_bool = true;
+    struct functor_getter_auto_play : public LLSelectedTEGetFunctor< bool >
+    {
+        functor_getter_auto_play(const LLMediaEntry& entry) : mMediaEntry(entry) {}
+
+        bool get(LLViewerObject* object, S32 face)
+        {
+            if (object)
+                if (object->getTE(face))
+                    if (object->getTE(face)->getMediaData())
+                        return object->getTE(face)->getMediaData()->getAutoPlay();
+            //return mMediaEntry.getAutoPlay(); set default to auto play TRUE -- angela  EXT-5172
+            return true;
+        };
+
+        const LLMediaEntry &mMediaEntry;
+
+    } func_auto_play(default_media_data);
+    identical = selected_objects->getSelectedTEValue(&func_auto_play, value_bool);
+    base_key = std::string(LLMediaEntry::AUTO_PLAY_KEY);
+    mMediaSettings[base_key] = value_bool;
+    mMediaSettings[base_key + std::string(LLPanelContents::TENTATIVE_SUFFIX)] = !identical;
+
+
+    // Auto scale
+    // set default to auto scale TRUE -- angela  EXT-5172
+    //value_bool = default_media_data.getAutoScale();
+    value_bool = true;
+    struct functor_getter_auto_scale : public LLSelectedTEGetFunctor< bool >
+    {
+        functor_getter_auto_scale(const LLMediaEntry& entry) : mMediaEntry(entry) {}
+
+        bool get(LLViewerObject* object, S32 face)
+        {
+            if (object)
+                if (object->getTE(face))
+                    if (object->getTE(face)->getMediaData())
+                        return object->getTE(face)->getMediaData()->getAutoScale();
+            // return mMediaEntry.getAutoScale();  set default to auto scale TRUE -- angela  EXT-5172
+            return true;
+        };
+
+        const LLMediaEntry &mMediaEntry;
+
+    } func_auto_scale(default_media_data);
+    identical = selected_objects->getSelectedTEValue(&func_auto_scale, value_bool);
+    base_key = std::string(LLMediaEntry::AUTO_SCALE_KEY);
+    mMediaSettings[base_key] = value_bool;
+    mMediaSettings[base_key + std::string(LLPanelContents::TENTATIVE_SUFFIX)] = !identical;
+
+    // Auto loop
+    value_bool = default_media_data.getAutoLoop();
+    struct functor_getter_auto_loop : public LLSelectedTEGetFunctor< bool >
+    {
+        functor_getter_auto_loop(const LLMediaEntry& entry) : mMediaEntry(entry) {}
+
+        bool get(LLViewerObject* object, S32 face)
+        {
+            if (object)
+                if (object->getTE(face))
+                    if (object->getTE(face)->getMediaData())
+                        return object->getTE(face)->getMediaData()->getAutoLoop();
+            return mMediaEntry.getAutoLoop();
+        };
+
+        const LLMediaEntry &mMediaEntry;
+
+    } func_auto_loop(default_media_data);
+    identical = selected_objects->getSelectedTEValue(&func_auto_loop, value_bool);
+    base_key = std::string(LLMediaEntry::AUTO_LOOP_KEY);
+    mMediaSettings[base_key] = value_bool;
+    mMediaSettings[base_key + std::string(LLPanelContents::TENTATIVE_SUFFIX)] = !identical;
+
+    // width pixels (if not auto scaled)
+    value_int = default_media_data.getWidthPixels();
+    struct functor_getter_width_pixels : public LLSelectedTEGetFunctor< int >
+    {
+        functor_getter_width_pixels(const LLMediaEntry& entry) : mMediaEntry(entry) {}
+
+        int get(LLViewerObject* object, S32 face)
+        {
+            if (object)
+                if (object->getTE(face))
+                    if (object->getTE(face)->getMediaData())
+                        return object->getTE(face)->getMediaData()->getWidthPixels();
+            return mMediaEntry.getWidthPixels();
+        };
+
+        const LLMediaEntry &mMediaEntry;
+
+    } func_width_pixels(default_media_data);
+    identical = selected_objects->getSelectedTEValue(&func_width_pixels, value_int);
+    base_key = std::string(LLMediaEntry::WIDTH_PIXELS_KEY);
+    mMediaSettings[base_key] = value_int;
+    mMediaSettings[base_key + std::string(LLPanelContents::TENTATIVE_SUFFIX)] = !identical;
+
+    // height pixels (if not auto scaled)
+    value_int = default_media_data.getHeightPixels();
+    struct functor_getter_height_pixels : public LLSelectedTEGetFunctor< int >
+    {
+        functor_getter_height_pixels(const LLMediaEntry& entry) : mMediaEntry(entry) {}
+
+        int get(LLViewerObject* object, S32 face)
+        {
+            if (object)
+                if (object->getTE(face))
+                    if (object->getTE(face)->getMediaData())
+                        return object->getTE(face)->getMediaData()->getHeightPixels();
+            return mMediaEntry.getHeightPixels();
+        };
+
+        const LLMediaEntry &mMediaEntry;
+
+    } func_height_pixels(default_media_data);
+    identical = selected_objects->getSelectedTEValue(&func_height_pixels, value_int);
+    base_key = std::string(LLMediaEntry::HEIGHT_PIXELS_KEY);
+    mMediaSettings[base_key] = value_int;
+    mMediaSettings[base_key + std::string(LLPanelContents::TENTATIVE_SUFFIX)] = !identical;
+
+    // Enable Alt image
+    value_bool = default_media_data.getAltImageEnable();
+    struct functor_getter_enable_alt_image : public LLSelectedTEGetFunctor< bool >
+    {
+        functor_getter_enable_alt_image(const LLMediaEntry& entry) : mMediaEntry(entry) {}
+
+        bool get(LLViewerObject* object, S32 face)
+        {
+            if (object)
+                if (object->getTE(face))
+                    if (object->getTE(face)->getMediaData())
+                        return object->getTE(face)->getMediaData()->getAltImageEnable();
+            return mMediaEntry.getAltImageEnable();
+        };
+
+        const LLMediaEntry &mMediaEntry;
+
+    } func_enable_alt_image(default_media_data);
+    identical = selected_objects->getSelectedTEValue(&func_enable_alt_image, value_bool);
+    base_key = std::string(LLMediaEntry::ALT_IMAGE_ENABLE_KEY);
+    mMediaSettings[base_key] = value_bool;
+    mMediaSettings[base_key + std::string(LLPanelContents::TENTATIVE_SUFFIX)] = !identical;
+
+    // Perms - owner interact
+    value_bool = 0 != (default_media_data.getPermsInteract() & LLMediaEntry::PERM_OWNER);
+    struct functor_getter_perms_owner_interact : public LLSelectedTEGetFunctor< bool >
+    {
+        functor_getter_perms_owner_interact(const LLMediaEntry& entry) : mMediaEntry(entry) {}
+
+        bool get(LLViewerObject* object, S32 face)
+        {
+            if (object)
+                if (object->getTE(face))
+                    if (object->getTE(face)->getMediaData())
+                        return (0 != (object->getTE(face)->getMediaData()->getPermsInteract() & LLMediaEntry::PERM_OWNER));
+            return 0 != (mMediaEntry.getPermsInteract() & LLMediaEntry::PERM_OWNER);
+        };
+
+        const LLMediaEntry &mMediaEntry;
+
+    } func_perms_owner_interact(default_media_data);
+    identical = selected_objects->getSelectedTEValue(&func_perms_owner_interact, value_bool);
+    base_key = std::string(LLPanelContents::PERMS_OWNER_INTERACT_KEY);
+    mMediaSettings[base_key] = value_bool;
+    mMediaSettings[base_key + std::string(LLPanelContents::TENTATIVE_SUFFIX)] = !identical;
+
+    // Perms - owner control
+    value_bool = 0 != (default_media_data.getPermsControl() & LLMediaEntry::PERM_OWNER);
+    struct functor_getter_perms_owner_control : public LLSelectedTEGetFunctor< bool >
+    {
+        functor_getter_perms_owner_control(const LLMediaEntry& entry) : mMediaEntry(entry) {}
+
+        bool get(LLViewerObject* object, S32 face)
+        {
+            if (object)
+                if (object->getTE(face))
+                    if (object->getTE(face)->getMediaData())
+                        return (0 != (object->getTE(face)->getMediaData()->getPermsControl() & LLMediaEntry::PERM_OWNER));
+            return 0 != (mMediaEntry.getPermsControl() & LLMediaEntry::PERM_OWNER);
+        };
+
+        const LLMediaEntry &mMediaEntry;
+
+    } func_perms_owner_control(default_media_data);
+    identical = selected_objects->getSelectedTEValue(&func_perms_owner_control, value_bool);
+    base_key = std::string(LLPanelContents::PERMS_OWNER_CONTROL_KEY);
+    mMediaSettings[base_key] = value_bool;
+    mMediaSettings[base_key + std::string(LLPanelContents::TENTATIVE_SUFFIX)] = !identical;
+
+    // Perms - group interact
+    value_bool = 0 != (default_media_data.getPermsInteract() & LLMediaEntry::PERM_GROUP);
+    struct functor_getter_perms_group_interact : public LLSelectedTEGetFunctor< bool >
+    {
+        functor_getter_perms_group_interact(const LLMediaEntry& entry) : mMediaEntry(entry) {}
+
+        bool get(LLViewerObject* object, S32 face)
+        {
+            if (object)
+                if (object->getTE(face))
+                    if (object->getTE(face)->getMediaData())
+                        return (0 != (object->getTE(face)->getMediaData()->getPermsInteract() & LLMediaEntry::PERM_GROUP));
+            return 0 != (mMediaEntry.getPermsInteract() & LLMediaEntry::PERM_GROUP);
+        };
+
+        const LLMediaEntry &mMediaEntry;
+
+    } func_perms_group_interact(default_media_data);
+    identical = selected_objects->getSelectedTEValue(&func_perms_group_interact, value_bool);
+    base_key = std::string(LLPanelContents::PERMS_GROUP_INTERACT_KEY);
+    mMediaSettings[base_key] = value_bool;
+    mMediaSettings[base_key + std::string(LLPanelContents::TENTATIVE_SUFFIX)] = !identical;
+
+    // Perms - group control
+    value_bool = 0 != (default_media_data.getPermsControl() & LLMediaEntry::PERM_GROUP);
+    struct functor_getter_perms_group_control : public LLSelectedTEGetFunctor< bool >
+    {
+        functor_getter_perms_group_control(const LLMediaEntry& entry) : mMediaEntry(entry) {}
+
+        bool get(LLViewerObject* object, S32 face)
+        {
+            if (object)
+                if (object->getTE(face))
+                    if (object->getTE(face)->getMediaData())
+                        return (0 != (object->getTE(face)->getMediaData()->getPermsControl() & LLMediaEntry::PERM_GROUP));
+            return 0 != (mMediaEntry.getPermsControl() & LLMediaEntry::PERM_GROUP);
+        };
+
+        const LLMediaEntry &mMediaEntry;
+
+    } func_perms_group_control(default_media_data);
+    identical = selected_objects->getSelectedTEValue(&func_perms_group_control, value_bool);
+    base_key = std::string(LLPanelContents::PERMS_GROUP_CONTROL_KEY);
+    mMediaSettings[base_key] = value_bool;
+    mMediaSettings[base_key + std::string(LLPanelContents::TENTATIVE_SUFFIX)] = !identical;
+
+    // Perms - anyone interact
+    value_bool = 0 != (default_media_data.getPermsInteract() & LLMediaEntry::PERM_ANYONE);
+    struct functor_getter_perms_anyone_interact : public LLSelectedTEGetFunctor< bool >
+    {
+        functor_getter_perms_anyone_interact(const LLMediaEntry& entry) : mMediaEntry(entry) {}
+
+        bool get(LLViewerObject* object, S32 face)
+        {
+            if (object)
+                if (object->getTE(face))
+                    if (object->getTE(face)->getMediaData())
+                        return (0 != (object->getTE(face)->getMediaData()->getPermsInteract() & LLMediaEntry::PERM_ANYONE));
+            return 0 != (mMediaEntry.getPermsInteract() & LLMediaEntry::PERM_ANYONE);
+        };
+
+        const LLMediaEntry &mMediaEntry;
+
+    } func_perms_anyone_interact(default_media_data);
+    identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue(&func_perms_anyone_interact, value_bool);
+    base_key = std::string(LLPanelContents::PERMS_ANYONE_INTERACT_KEY);
+    mMediaSettings[base_key] = value_bool;
+    mMediaSettings[base_key + std::string(LLPanelContents::TENTATIVE_SUFFIX)] = !identical;
+
+    // Perms - anyone control
+    value_bool = 0 != (default_media_data.getPermsControl() & LLMediaEntry::PERM_ANYONE);
+    struct functor_getter_perms_anyone_control : public LLSelectedTEGetFunctor< bool >
+    {
+        functor_getter_perms_anyone_control(const LLMediaEntry& entry) : mMediaEntry(entry) {}
+
+        bool get(LLViewerObject* object, S32 face)
+        {
+            if (object)
+                if (object->getTE(face))
+                    if (object->getTE(face)->getMediaData())
+                        return (0 != (object->getTE(face)->getMediaData()->getPermsControl() & LLMediaEntry::PERM_ANYONE));
+            return 0 != (mMediaEntry.getPermsControl() & LLMediaEntry::PERM_ANYONE);
+        };
+
+        const LLMediaEntry &mMediaEntry;
+
+    } func_perms_anyone_control(default_media_data);
+    identical = selected_objects->getSelectedTEValue(&func_perms_anyone_control, value_bool);
+    base_key = std::string(LLPanelContents::PERMS_ANYONE_CONTROL_KEY);
+    mMediaSettings[base_key] = value_bool;
+    mMediaSettings[base_key + std::string(LLPanelContents::TENTATIVE_SUFFIX)] = !identical;
+
+    // security - whitelist enable
+    value_bool = default_media_data.getWhiteListEnable();
+    struct functor_getter_whitelist_enable : public LLSelectedTEGetFunctor< bool >
+    {
+        functor_getter_whitelist_enable(const LLMediaEntry& entry) : mMediaEntry(entry) {}
+
+        bool get(LLViewerObject* object, S32 face)
+        {
+            if (object)
+                if (object->getTE(face))
+                    if (object->getTE(face)->getMediaData())
+                        return object->getTE(face)->getMediaData()->getWhiteListEnable();
+            return mMediaEntry.getWhiteListEnable();
+        };
+
+        const LLMediaEntry &mMediaEntry;
+
+    } func_whitelist_enable(default_media_data);
+    identical = selected_objects->getSelectedTEValue(&func_whitelist_enable, value_bool);
+    base_key = std::string(LLMediaEntry::WHITELIST_ENABLE_KEY);
+    mMediaSettings[base_key] = value_bool;
+    mMediaSettings[base_key + std::string(LLPanelContents::TENTATIVE_SUFFIX)] = !identical;
+
+    // security - whitelist URLs
+    std::vector<std::string> value_vector_str = default_media_data.getWhiteList();
+    struct functor_getter_whitelist_urls : public LLSelectedTEGetFunctor< std::vector<std::string> >
+    {
+        functor_getter_whitelist_urls(const LLMediaEntry& entry) : mMediaEntry(entry) {}
+
+        std::vector<std::string> get(LLViewerObject* object, S32 face)
+        {
+            if (object)
+                if (object->getTE(face))
+                    if (object->getTE(face)->getMediaData())
+                        return object->getTE(face)->getMediaData()->getWhiteList();
+            return mMediaEntry.getWhiteList();
+        };
+
+        const LLMediaEntry &mMediaEntry;
+
+    } func_whitelist_urls(default_media_data);
+    identical = selected_objects->getSelectedTEValue(&func_whitelist_urls, value_vector_str);
+    base_key = std::string(LLMediaEntry::WHITELIST_KEY);
+    mMediaSettings[base_key].clear();
+    std::vector< std::string >::iterator iter = value_vector_str.begin();
+    while (iter != value_vector_str.end())
+    {
+        std::string white_list_url = *iter;
+        mMediaSettings[base_key].append(white_list_url);
+        ++iter;
+    };
+
+    mMediaSettings[base_key + std::string(LLPanelContents::TENTATIVE_SUFFIX)] = !identical;
+}
+
+void LLPanelFace::updateMediaTitle()
+{
+    // only get the media name if we need it
+    if (!mNeedMediaTitle)
+        return;
+
+    // get plugin impl
+    LLPluginClassMedia* media_plugin = mTitleMedia->getMediaPlugin();
+    if (media_plugin && mTitleMedia->getCurrentNavUrl() == media_plugin->getNavigateURI())
+    {
+        // get the media name (asynchronous - must call repeatedly)
+        std::string media_title = media_plugin->getMediaName();
+
+        // only replace the title if what we get contains something
+        if (!media_title.empty())
+        {
+            // update the UI widget
+            if (mTitleMediaText)
+            {
+                mTitleMediaText->setText(media_title);
+
+                // stop looking for a title when we get one
+                mNeedMediaTitle = false;
+            };
+        };
+    };
+}
+
 //
 // Static functions
 //
@@ -1632,30 +2425,29 @@ void LLPanelFace::onCommitMaterialsMedia(LLUICtrl* ctrl, void* userdata)
 	self->updateShinyControls(false,true);
 	self->updateBumpyControls(false,true);
 	self->updateUI();
+	self->refreshMedia();
 }
 
-// static
 void LLPanelFace::updateVisibility()
 {	
-	LLComboBox* combo_matmedia = getChild<LLComboBox>("combobox matmedia");
 	LLRadioGroup* radio_mat_type = getChild<LLRadioGroup>("radio_material_type");
 	LLComboBox* combo_shininess = getChild<LLComboBox>("combobox shininess");
 	LLComboBox* combo_bumpiness = getChild<LLComboBox>("combobox bumpiness");
-	if (!radio_mat_type || !combo_matmedia || !combo_shininess || !combo_bumpiness)
+	if (!radio_mat_type || !mComboMatMedia || !combo_shininess || !combo_bumpiness)
 	{
 		LL_WARNS("Materials") << "Combo box not found...exiting." << LL_ENDL;
 		return;
 	}
-	U32 materials_media = combo_matmedia->getCurrentIndex();
+	U32 materials_media = mComboMatMedia->getCurrentIndex();
 	U32 material_type = radio_mat_type->getSelectedIndex();
-	bool show_media = (materials_media == MATMEDIA_MEDIA) && combo_matmedia->getEnabled();
-	bool show_texture = (show_media || ((material_type == MATTYPE_DIFFUSE) && combo_matmedia->getEnabled()));
-	bool show_bumpiness = (!show_media) && (material_type == MATTYPE_NORMAL) && combo_matmedia->getEnabled();
-	bool show_shininess = (!show_media) && (material_type == MATTYPE_SPECULAR) && combo_matmedia->getEnabled();
+	bool show_media = (materials_media == MATMEDIA_MEDIA) && mComboMatMedia->getEnabled();
+	bool show_texture = (show_media || ((material_type == MATTYPE_DIFFUSE) && mComboMatMedia->getEnabled()));
+	bool show_bumpiness = (!show_media) && (material_type == MATTYPE_NORMAL) && mComboMatMedia->getEnabled();
+	bool show_shininess = (!show_media) && (material_type == MATTYPE_SPECULAR) && mComboMatMedia->getEnabled();
 	getChildView("radio_material_type")->setVisible(!show_media);
 
 	// Media controls
-	getChildView("media_info")->setVisible(show_media);
+    mTitleMediaText->setVisible(show_media);
 	getChildView("add_media")->setVisible(show_media);
 	getChildView("delete_media")->setVisible(show_media);
 	getChildView("button align")->setVisible(show_media);
@@ -1787,12 +2579,11 @@ void LLPanelFace::updateShinyControls(bool is_setting_texture, bool mess_with_sh
 	}
 
 
-	LLComboBox* combo_matmedia = getChild<LLComboBox>("combobox matmedia");
 	LLRadioGroup* radio_mat_type = getChild<LLRadioGroup>("radio_material_type");
-	U32 materials_media = combo_matmedia->getCurrentIndex();
+	U32 materials_media = mComboMatMedia->getCurrentIndex();
 	U32 material_type = radio_mat_type->getSelectedIndex();
-	bool show_media = (materials_media == MATMEDIA_MEDIA) && combo_matmedia->getEnabled();
-	bool show_shininess = (!show_media) && (material_type == MATTYPE_SPECULAR) && combo_matmedia->getEnabled();
+	bool show_media = (materials_media == MATMEDIA_MEDIA) && mComboMatMedia->getEnabled();
+	bool show_shininess = (!show_media) && (material_type == MATTYPE_SPECULAR) && mComboMatMedia->getEnabled();
 	U32 shiny_value = comboShiny->getCurrentIndex();
 	bool show_shinyctrls = (shiny_value == SHINY_TEXTURE) && show_shininess; // Use texture
 	getChildView("label glossiness")->setVisible(show_shinyctrls);
@@ -1866,11 +2657,10 @@ void LLPanelFace::updateAlphaControls()
 	U32 alpha_value = comboAlphaMode->getCurrentIndex();
 	bool show_alphactrls = (alpha_value == ALPHAMODE_MASK); // Alpha masking
     
-    LLComboBox* combobox_matmedia = getChild<LLComboBox>("combobox matmedia");
     U32 mat_media = MATMEDIA_MATERIAL;
-    if (combobox_matmedia)
+    if (mComboMatMedia)
     {
-        mat_media = combobox_matmedia->getCurrentIndex();
+        mat_media = mComboMatMedia->getCurrentIndex();
     }
     
     U32 mat_type = MATTYPE_DIFFUSE;
@@ -2027,6 +2817,77 @@ void LLPanelFace::onSelectNormalTexture(const LLSD& data)
 	sendBump(nmap_id.isNull() ? 0 : BUMPY_TEXTURE);
 }
 
+//////////////////////////////////////////////////////////////////////////////
+// called when a user wants to edit existing media settings on a prim or prim face
+// TODO: test if there is media on the item and only allow editing if present
+void LLPanelFace::onClickBtnEditMedia(LLUICtrl* ctrl, void* userdata)
+{
+    LLPanelFace* self = (LLPanelFace*)userdata;
+    self->refreshMedia();
+    LLFloaterReg::showInstance("media_settings");
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// called when a user wants to delete media from a prim or prim face
+void LLPanelFace::onClickBtnDeleteMedia(LLUICtrl* ctrl, void* userdata)
+{
+    LLNotificationsUtil::add("DeleteMedia", LLSD(), LLSD(), deleteMediaConfirm);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// called when a user wants to add media to a prim or prim face
+void LLPanelFace::onClickBtnAddMedia(LLUICtrl* ctrl, void* userdata)
+{
+    // check if multiple faces are selected
+    if (LLSelectMgr::getInstance()->getSelection()->isMultipleTESelected())
+    {
+        LLPanelFace* self = (LLPanelFace*)userdata;
+        self->refreshMedia();
+        LLNotificationsUtil::add("MultipleFacesSelected", LLSD(), LLSD(), multipleFacesSelectedConfirm);
+    }
+    else
+    {
+        onClickBtnEditMedia(ctrl, userdata);
+    }
+}
+
+// static
+bool LLPanelFace::deleteMediaConfirm(const LLSD& notification, const LLSD& response)
+{
+    S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+    switch (option)
+    {
+    case 0:  // "Yes"
+        LLSelectMgr::getInstance()->selectionSetMedia(0, LLSD());
+        if (LLFloaterReg::instanceVisible("media_settings"))
+        {
+            LLFloaterReg::hideInstance("media_settings");
+        }
+        break;
+
+    case 1:  // "No"
+    default:
+        break;
+    }
+    return false;
+}
+
+// static
+bool LLPanelFace::multipleFacesSelectedConfirm(const LLSD& notification, const LLSD& response)
+{
+    S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+    switch (option)
+    {
+    case 0:  // "Yes"
+        LLFloaterReg::showInstance("media_settings");
+        break;
+    case 1:  // "No"
+    default:
+        break;
+    }
+    return false;
+}
+
 //static
 void LLPanelFace::syncOffsetX(LLPanelFace* self, F32 offsetU)
 {
@@ -2404,10 +3265,9 @@ void LLPanelFace::onCommitRepeatsPerMeter(LLUICtrl* ctrl, void* userdata)
 	LLPanelFace* self = (LLPanelFace*) userdata;
 	
 	LLUICtrl*	repeats_ctrl	= self->getChild<LLUICtrl>("rptctrl");
-	LLComboBox* combo_matmedia = self->getChild<LLComboBox>("combobox matmedia");
 	LLRadioGroup* radio_mat_type = self->getChild<LLRadioGroup>("radio_material_type");
 	
-	U32 materials_media = combo_matmedia->getCurrentIndex();
+	U32 materials_media = self->mComboMatMedia->getCurrentIndex();
 
 	U32 material_type           = (materials_media == MATMEDIA_MATERIAL) ? radio_mat_type->getSelectedIndex() : 0;
 	F32 repeats_per_meter	= repeats_ctrl->getValue().asReal();
@@ -2538,15 +3398,811 @@ void LLPanelFace::onAlignTexture(void* userdata)
     self->alignTestureLayer();
 }
 
+enum EPasteMode
+{
+    PASTE_COLOR,
+    PASTE_TEXTURE
+};
+
+struct LLPanelFacePasteTexFunctor : public LLSelectedTEFunctor
+{
+    LLPanelFacePasteTexFunctor(LLPanelFace* panel, EPasteMode mode) :
+        mPanelFace(panel), mMode(mode) {}
+
+    virtual bool apply(LLViewerObject* objectp, S32 te)
+    {
+        switch (mMode)
+        {
+        case PASTE_COLOR:
+            mPanelFace->onPasteColor(objectp, te);
+            break;
+        case PASTE_TEXTURE:
+            mPanelFace->onPasteTexture(objectp, te);
+            break;
+        }
+        return true;
+    }
+private:
+    LLPanelFace *mPanelFace;
+    EPasteMode mMode;
+};
+
+struct LLPanelFaceUpdateFunctor : public LLSelectedObjectFunctor
+{
+    LLPanelFaceUpdateFunctor(bool update_media) : mUpdateMedia(update_media) {}
+    virtual bool apply(LLViewerObject* object)
+    {
+        object->sendTEUpdate();
+        if (mUpdateMedia)
+        {
+            LLVOVolume *vo = dynamic_cast<LLVOVolume*>(object);
+            if (vo && vo->hasMedia())
+            {
+                vo->sendMediaDataUpdate();
+            }
+        }
+        return true;
+    }
+private:
+    bool mUpdateMedia;
+};
+
+struct LLPanelFaceNavigateHomeFunctor : public LLSelectedTEFunctor
+{
+    virtual bool apply(LLViewerObject* objectp, S32 te)
+    {
+        if (objectp && objectp->getTE(te))
+        {
+            LLTextureEntry* tep = objectp->getTE(te);
+            const LLMediaEntry *media_data = tep->getMediaData();
+            if (media_data)
+            {
+                if (media_data->getCurrentURL().empty() && media_data->getAutoPlay())
+                {
+                    viewer_media_t media_impl =
+                        LLViewerMedia::getInstance()->getMediaImplFromTextureID(tep->getMediaData()->getMediaID());
+                    if (media_impl)
+                    {
+                        media_impl->navigateHome();
+                    }
+                }
+            }
+        }
+        return true;
+    }
+};
+
+void LLPanelFace::onCopyColor()
+{
+    LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getFirstObject();
+    LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstNode();
+    S32 selected_count = LLSelectMgr::getInstance()->getSelection()->getObjectCount();
+    if (!objectp || !node
+        || objectp->getPCode() != LL_PCODE_VOLUME
+        || !objectp->permModify()
+        || objectp->isPermanentEnforced()
+        || selected_count > 1)
+    {
+        return;
+    }
+
+    if (mClipboardParams.has("color"))
+    {
+        mClipboardParams["color"].clear();
+    }
+    else
+    {
+        mClipboardParams["color"] = LLSD::emptyArray();
+    }
+
+    std::map<LLUUID, LLUUID> asset_item_map;
+
+    // a way to resolve situations where source and target have different amount of faces
+    S32 num_tes = llmin((S32)objectp->getNumTEs(), (S32)objectp->getNumFaces());
+    mClipboardParams["color_all_tes"] = (num_tes != 1) || (LLToolFace::getInstance() == LLToolMgr::getInstance()->getCurrentTool());
+    for (S32 te = 0; te < num_tes; ++te)
+    {
+        if (node->isTESelected(te))
+        {
+            LLTextureEntry* tep = objectp->getTE(te);
+            if (tep)
+            {
+                LLSD te_data;
+
+                // asLLSD() includes media
+                te_data["te"] = tep->asLLSD(); // Note: includes a lot more than just color/alpha/glow
+
+                mClipboardParams["color"].append(te_data);
+            }
+        }
+    }
+}
+
+void LLPanelFace::onPasteColor()
+{
+    if (!mClipboardParams.has("color"))
+    {
+        return;
+    }
+
+    LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getFirstObject();
+    LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstNode();
+    S32 selected_count = LLSelectMgr::getInstance()->getSelection()->getObjectCount();
+    if (!objectp || !node
+        || objectp->getPCode() != LL_PCODE_VOLUME
+        || !objectp->permModify()
+        || objectp->isPermanentEnforced()
+        || selected_count > 1)
+    {
+        // not supposed to happen
+        LL_WARNS() << "Failed to paste color due to missing or wrong selection" << LL_ENDL;
+        return;
+    }
+
+    bool face_selection_mode = LLToolFace::getInstance() == LLToolMgr::getInstance()->getCurrentTool();
+    LLSD &clipboard = mClipboardParams["color"]; // array
+    S32 num_tes = llmin((S32)objectp->getNumTEs(), (S32)objectp->getNumFaces());
+    S32 compare_tes = num_tes;
+
+    if (face_selection_mode)
+    {
+        compare_tes = 0;
+        for (S32 te = 0; te < num_tes; ++te)
+        {
+            if (node->isTESelected(te))
+            {
+                compare_tes++;
+            }
+        }
+    }
+
+    // we can copy if single face was copied in edit face mode or if face count matches
+    if (!((clipboard.size() == 1) && mClipboardParams["color_all_tes"].asBoolean())
+        && compare_tes != clipboard.size())
+    {
+        LLSD notif_args;
+        if (face_selection_mode)
+        {
+            static std::string reason = getString("paste_error_face_selection_mismatch");
+            notif_args["REASON"] = reason;
+        }
+        else
+        {
+            static std::string reason = getString("paste_error_object_face_count_mismatch");
+            notif_args["REASON"] = reason;
+        }
+        LLNotificationsUtil::add("FacePasteFailed", notif_args);
+        return;
+    }
+
+    LLObjectSelectionHandle selected_objects = LLSelectMgr::getInstance()->getSelection();
 
-// TODO: I don't know who put these in or what these are for???
-void LLPanelFace::setMediaURL(const std::string& url)
+    LLPanelFacePasteTexFunctor paste_func(this, PASTE_COLOR);
+    selected_objects->applyToTEs(&paste_func);
+
+    LLPanelFaceUpdateFunctor sendfunc(false);
+    selected_objects->applyToObjects(&sendfunc);
+}
+
+void LLPanelFace::onPasteColor(LLViewerObject* objectp, S32 te)
 {
+    LLSD te_data;
+    LLSD &clipboard = mClipboardParams["color"]; // array
+    if ((clipboard.size() == 1) && mClipboardParams["color_all_tes"].asBoolean())
+    {
+        te_data = *(clipboard.beginArray());
+    }
+    else if (clipboard[te])
+    {
+        te_data = clipboard[te];
+    }
+    else
+    {
+        return;
+    }
+
+    LLTextureEntry* tep = objectp->getTE(te);
+    if (tep)
+    {
+        if (te_data.has("te"))
+        {
+            // Color / Alpha
+            if (te_data["te"].has("colors"))
+            {
+                LLColor4 color = tep->getColor();
+
+                LLColor4 clip_color;
+                clip_color.setValue(te_data["te"]["colors"]);
+
+                // Color
+                color.mV[VRED] = clip_color.mV[VRED];
+                color.mV[VGREEN] = clip_color.mV[VGREEN];
+                color.mV[VBLUE] = clip_color.mV[VBLUE];
+
+                // Alpha
+                color.mV[VALPHA] = clip_color.mV[VALPHA];
+
+                objectp->setTEColor(te, color);
+            }
+
+            // Color/fullbright
+            if (te_data["te"].has("fullbright"))
+            {
+                objectp->setTEFullbright(te, te_data["te"]["fullbright"].asInteger());
+            }
+
+            // Glow
+            if (te_data["te"].has("glow"))
+            {
+                objectp->setTEGlow(te, (F32)te_data["te"]["glow"].asReal());
+            }
+        }
+    }
 }
-void LLPanelFace::setMediaType(const std::string& mime_type)
+
+void LLPanelFace::onCopyTexture()
 {
+    LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getFirstObject();
+    LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstNode();
+    S32 selected_count = LLSelectMgr::getInstance()->getSelection()->getObjectCount();
+    if (!objectp || !node
+        || objectp->getPCode() != LL_PCODE_VOLUME
+        || !objectp->permModify()
+        || objectp->isPermanentEnforced()
+        || selected_count > 1)
+    {
+        return;
+    }
+
+    if (mClipboardParams.has("texture"))
+    {
+        mClipboardParams["texture"].clear();
+    }
+    else
+    {
+        mClipboardParams["texture"] = LLSD::emptyArray();
+    }
+
+    std::map<LLUUID, LLUUID> asset_item_map;
+
+    // a way to resolve situations where source and target have different amount of faces
+    S32 num_tes = llmin((S32)objectp->getNumTEs(), (S32)objectp->getNumFaces());
+    mClipboardParams["texture_all_tes"] = (num_tes != 1) || (LLToolFace::getInstance() == LLToolMgr::getInstance()->getCurrentTool());
+    for (S32 te = 0; te < num_tes; ++te)
+    {
+        if (node->isTESelected(te))
+        {
+            LLTextureEntry* tep = objectp->getTE(te);
+            if (tep)
+            {
+                LLSD te_data;
+
+                // asLLSD() includes media
+                te_data["te"] = tep->asLLSD();
+                te_data["te"]["shiny"] = tep->getShiny();
+                te_data["te"]["bumpmap"] = tep->getBumpmap();
+                te_data["te"]["bumpshiny"] = tep->getBumpShiny();
+                te_data["te"]["bumpfullbright"] = tep->getBumpShinyFullbright();
+
+                if (te_data["te"].has("imageid"))
+                {
+                    LLUUID item_id;
+                    LLUUID id = te_data["te"]["imageid"].asUUID();
+                    bool from_library = get_is_predefined_texture(id);
+                    bool full_perm = from_library;
+
+                    if (!full_perm
+                        && objectp->permCopy()
+                        && objectp->permTransfer()
+                        && objectp->permModify())
+                    {
+                        // If agent created this object and nothing is limiting permissions, mark as full perm
+                        // If agent was granted permission to edit objects owned and created by somebody else, mark full perm
+                        // This check is not perfect since we can't figure out whom textures belong to so this ended up restrictive
+                        std::string creator_app_link;
+                        LLUUID creator_id;
+                        LLSelectMgr::getInstance()->selectGetCreator(creator_id, creator_app_link);
+                        full_perm = objectp->mOwnerID == creator_id;
+                    }
+
+                    if (id.notNull() && !full_perm)
+                    {
+                        std::map<LLUUID, LLUUID>::iterator iter = asset_item_map.find(id);
+                        if (iter != asset_item_map.end())
+                        {
+                            item_id = iter->second;
+                        }
+                        else
+                        {
+                            // What this does is simply searches inventory for item with same asset id,
+                            // as result it is Hightly unreliable, leaves little control to user, borderline hack
+                            // but there are little options to preserve permissions - multiple inventory
+                            // items might reference same asset and inventory search is expensive.
+                            bool no_transfer = false;
+                            if (objectp->getInventoryItemByAsset(id))
+                            {
+                                no_transfer = !objectp->getInventoryItemByAsset(id)->getIsFullPerm();
+                            }
+                            item_id = get_copy_free_item_by_asset_id(id, no_transfer);
+                            // record value to avoid repeating inventory search when possible
+                            asset_item_map[id] = item_id;
+                        }
+                    }
+
+                    if (item_id.notNull() && gInventory.isObjectDescendentOf(item_id, gInventory.getLibraryRootFolderID()))
+                    {
+                        full_perm = true;
+                        from_library = true;
+                    }
+
+                    {
+                        te_data["te"]["itemfullperm"] = full_perm;
+                        te_data["te"]["fromlibrary"] = from_library; 
+
+                        // If full permission object, texture is free to copy,
+                        // but otherwise we need to check inventory and extract permissions
+                        //
+                        // Normally we care only about restrictions for current user and objects
+                        // don't inherit any 'next owner' permissions from texture, so there is
+                        // no need to record item id if full_perm==true
+                        if (!full_perm && !from_library && item_id.notNull())
+                        {
+                            LLViewerInventoryItem* itemp = gInventory.getItem(item_id);
+                            if (itemp)
+                            {
+                                LLPermissions item_permissions = itemp->getPermissions();
+                                if (item_permissions.allowOperationBy(PERM_COPY,
+                                    gAgent.getID(),
+                                    gAgent.getGroupID()))
+                                {
+                                    te_data["te"]["imageitemid"] = item_id;
+                                    te_data["te"]["itemfullperm"] = itemp->getIsFullPerm();
+                                    if (!itemp->isFinished())
+                                    {
+                                        // needed for dropTextureAllFaces
+                                        LLInventoryModelBackgroundFetch::instance().start(item_id, false);
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+
+                LLMaterialPtr material_ptr = tep->getMaterialParams();
+                if (!material_ptr.isNull())
+                {
+                    LLSD mat_data;
+
+                    mat_data["NormMap"] = material_ptr->getNormalID();
+                    mat_data["SpecMap"] = material_ptr->getSpecularID();
+
+                    mat_data["NormRepX"] = material_ptr->getNormalRepeatX();
+                    mat_data["NormRepY"] = material_ptr->getNormalRepeatY();
+                    mat_data["NormOffX"] = material_ptr->getNormalOffsetX();
+                    mat_data["NormOffY"] = material_ptr->getNormalOffsetY();
+                    mat_data["NormRot"] = material_ptr->getNormalRotation();
+
+                    mat_data["SpecRepX"] = material_ptr->getSpecularRepeatX();
+                    mat_data["SpecRepY"] = material_ptr->getSpecularRepeatY();
+                    mat_data["SpecOffX"] = material_ptr->getSpecularOffsetX();
+                    mat_data["SpecOffY"] = material_ptr->getSpecularOffsetY();
+                    mat_data["SpecRot"] = material_ptr->getSpecularRotation();
+
+                    mat_data["SpecColor"] = material_ptr->getSpecularLightColor().getValue();
+                    mat_data["SpecExp"] = material_ptr->getSpecularLightExponent();
+                    mat_data["EnvIntensity"] = material_ptr->getEnvironmentIntensity();
+                    mat_data["AlphaMaskCutoff"] = material_ptr->getAlphaMaskCutoff();
+                    mat_data["DiffuseAlphaMode"] = material_ptr->getDiffuseAlphaMode();
+
+                    // Replace no-copy textures, destination texture will get used instead if available
+                    if (mat_data.has("NormMap"))
+                    {
+                        LLUUID id = mat_data["NormMap"].asUUID();
+                        if (id.notNull() && !get_can_copy_texture(id))
+                        {
+                            mat_data["NormMap"] = LLUUID(gSavedSettings.getString("DefaultObjectTexture"));
+                            mat_data["NormMapNoCopy"] = true;
+                        }
+
+                    }
+                    if (mat_data.has("SpecMap"))
+                    {
+                        LLUUID id = mat_data["SpecMap"].asUUID();
+                        if (id.notNull() && !get_can_copy_texture(id))
+                        {
+                            mat_data["SpecMap"] = LLUUID(gSavedSettings.getString("DefaultObjectTexture"));
+                            mat_data["SpecMapNoCopy"] = true;
+                        }
+
+                    }
+
+                    te_data["material"] = mat_data;
+                }
+
+                mClipboardParams["texture"].append(te_data);
+            }
+        }
+    }
 }
 
+void LLPanelFace::onPasteTexture()
+{
+    if (!mClipboardParams.has("texture"))
+    {
+        return;
+    }
+
+    LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getFirstObject();
+    LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstNode();
+    S32 selected_count = LLSelectMgr::getInstance()->getSelection()->getObjectCount();
+    if (!objectp || !node
+        || objectp->getPCode() != LL_PCODE_VOLUME
+        || !objectp->permModify()
+        || objectp->isPermanentEnforced()
+        || selected_count > 1)
+    {
+        // not supposed to happen
+        LL_WARNS() << "Failed to paste texture due to missing or wrong selection" << LL_ENDL;
+        return;
+    }
+
+    bool face_selection_mode = LLToolFace::getInstance() == LLToolMgr::getInstance()->getCurrentTool();
+    LLSD &clipboard = mClipboardParams["texture"]; // array
+    S32 num_tes = llmin((S32)objectp->getNumTEs(), (S32)objectp->getNumFaces());
+    S32 compare_tes = num_tes;
+
+    if (face_selection_mode)
+    {
+        compare_tes = 0;
+        for (S32 te = 0; te < num_tes; ++te)
+        {
+            if (node->isTESelected(te))
+            {
+                compare_tes++;
+            }
+        }
+    }
+
+    // we can copy if single face was copied in edit face mode or if face count matches
+    if (!((clipboard.size() == 1) && mClipboardParams["texture_all_tes"].asBoolean()) 
+        && compare_tes != clipboard.size())
+    {
+        LLSD notif_args;
+        if (face_selection_mode)
+        {
+            static std::string reason = getString("paste_error_face_selection_mismatch");
+            notif_args["REASON"] = reason;
+        }
+        else
+        {
+            static std::string reason = getString("paste_error_object_face_count_mismatch");
+            notif_args["REASON"] = reason;
+        }
+        LLNotificationsUtil::add("FacePasteFailed", notif_args);
+        return;
+    }
+
+    bool full_perm_object = true;
+    LLSD::array_const_iterator iter = clipboard.beginArray();
+    LLSD::array_const_iterator end = clipboard.endArray();
+    for (; iter != end; ++iter)
+    {
+        const LLSD& te_data = *iter;
+        if (te_data.has("te") && te_data["te"].has("imageid"))
+        {
+            bool full_perm = te_data["te"].has("itemfullperm") && te_data["te"]["itemfullperm"].asBoolean();
+            full_perm_object &= full_perm;
+            if (!full_perm)
+            {
+                if (te_data["te"].has("imageitemid"))
+                {
+                    LLUUID item_id = te_data["te"]["imageitemid"].asUUID();
+                    if (item_id.notNull())
+                    {
+                        LLViewerInventoryItem* itemp = gInventory.getItem(item_id);
+                        if (!itemp)
+                        {
+                            // image might be in object's inventory, but it can be not up to date
+                            LLSD notif_args;
+                            static std::string reason = getString("paste_error_inventory_not_found");
+                            notif_args["REASON"] = reason;
+                            LLNotificationsUtil::add("FacePasteFailed", notif_args);
+                            return;
+                        }
+                    }
+                }
+                else
+                {
+                    // Item was not found on 'copy' stage
+                    // Since this happened at copy, might be better to either show this
+                    // at copy stage or to drop clipboard here
+                    LLSD notif_args;
+                    static std::string reason = getString("paste_error_inventory_not_found");
+                    notif_args["REASON"] = reason;
+                    LLNotificationsUtil::add("FacePasteFailed", notif_args);
+                    return;
+                }
+            }
+        }
+    }
+
+    if (!full_perm_object)
+    {
+        LLNotificationsUtil::add("FacePasteTexturePermissions");
+    }
+
+    LLObjectSelectionHandle selected_objects = LLSelectMgr::getInstance()->getSelection();
+
+    LLPanelFacePasteTexFunctor paste_func(this, PASTE_TEXTURE);
+    selected_objects->applyToTEs(&paste_func);
+
+    LLPanelFaceUpdateFunctor sendfunc(true);
+    selected_objects->applyToObjects(&sendfunc);
+
+    LLPanelFaceNavigateHomeFunctor navigate_home_func;
+    selected_objects->applyToTEs(&navigate_home_func);
+}
+
+void LLPanelFace::onPasteTexture(LLViewerObject* objectp, S32 te)
+{
+    LLSD te_data;
+    LLSD &clipboard = mClipboardParams["texture"]; // array
+    if ((clipboard.size() == 1) && mClipboardParams["texture_all_tes"].asBoolean())
+    {
+        te_data = *(clipboard.beginArray());
+    }
+    else if (clipboard[te])
+    {
+        te_data = clipboard[te];
+    }
+    else
+    {
+        return;
+    }
+
+    LLTextureEntry* tep = objectp->getTE(te);
+    if (tep)
+    {
+        if (te_data.has("te"))
+        {
+            // Texture
+            bool full_perm = te_data["te"].has("itemfullperm") && te_data["te"]["itemfullperm"].asBoolean();
+            bool from_library = te_data["te"].has("fromlibrary") && te_data["te"]["fromlibrary"].asBoolean();
+            if (te_data["te"].has("imageid"))
+            {
+                const LLUUID& imageid = te_data["te"]["imageid"].asUUID(); //texture or asset id
+                LLViewerInventoryItem* itemp_res = NULL;
+
+                if (te_data["te"].has("imageitemid"))
+                {
+                    LLUUID item_id = te_data["te"]["imageitemid"].asUUID();
+                    if (item_id.notNull())
+                    {
+                        LLViewerInventoryItem* itemp = gInventory.getItem(item_id);
+                        if (itemp && itemp->isFinished())
+                        {
+                            // dropTextureAllFaces will fail if incomplete
+                            itemp_res = itemp;
+                        }
+                        else
+                        {
+                            // Theoretically shouldn't happend, but if it does happen, we
+                            // might need to add a notification to user that paste will fail
+                            // since inventory isn't fully loaded
+                            LL_WARNS() << "Item " << item_id << " is incomplete, paste might fail silently." << LL_ENDL;
+                        }
+                    }
+                }
+                // for case when item got removed from inventory after we pressed 'copy'
+                // or texture got pasted into previous object
+                if (!itemp_res && !full_perm)
+                {
+                    // Due to checks for imageitemid in LLPanelFace::onPasteTexture() this should no longer be reachable.
+                    LL_INFOS() << "Item " << te_data["te"]["imageitemid"].asUUID() << " no longer in inventory." << LL_ENDL;
+                    // Todo: fix this, we are often searching same texture multiple times (equal to number of faces)
+                    // Perhaps just mPanelFace->onPasteTexture(objectp, te, &asset_to_item_id_map); ? Not pretty, but will work
+                    LLViewerInventoryCategory::cat_array_t cats;
+                    LLViewerInventoryItem::item_array_t items;
+                    LLAssetIDMatches asset_id_matches(imageid);
+                    gInventory.collectDescendentsIf(LLUUID::null,
+                        cats,
+                        items,
+                        LLInventoryModel::INCLUDE_TRASH,
+                        asset_id_matches);
+
+                    // Extremely unreliable and perfomance unfriendly.
+                    // But we need this to check permissions and it is how texture control finds items
+                    for (S32 i = 0; i < items.size(); i++)
+                    {
+                        LLViewerInventoryItem* itemp = items[i];
+                        if (itemp && itemp->isFinished())
+                        {
+                            // dropTextureAllFaces will fail if incomplete
+                            LLPermissions item_permissions = itemp->getPermissions();
+                            if (item_permissions.allowOperationBy(PERM_COPY,
+                                gAgent.getID(),
+                                gAgent.getGroupID()))
+                            {
+                                itemp_res = itemp;
+                                break; // first match
+                            }
+                        }
+                    }
+                }
+
+                if (itemp_res)
+                {
+                    if (te == -1) // all faces
+                    {
+                        LLToolDragAndDrop::dropTextureAllFaces(objectp,
+                            itemp_res,
+                            from_library ? LLToolDragAndDrop::SOURCE_LIBRARY : LLToolDragAndDrop::SOURCE_AGENT,
+                            LLUUID::null);
+                    }
+                    else // one face
+                    {
+                        LLToolDragAndDrop::dropTextureOneFace(objectp,
+                            te,
+                            itemp_res,
+                            from_library ? LLToolDragAndDrop::SOURCE_LIBRARY : LLToolDragAndDrop::SOURCE_AGENT,
+                            LLUUID::null,
+                            0);
+                    }
+                }
+                // not an inventory item or no complete items
+                else if (full_perm)
+                {
+                    // Either library, local or existed as fullperm when user made a copy
+                    LLViewerTexture* image = LLViewerTextureManager::getFetchedTexture(imageid, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE);
+                    objectp->setTEImage(U8(te), image);
+                }
+            }
+
+            if (te_data["te"].has("bumpmap"))
+            {
+                objectp->setTEBumpmap(te, (U8)te_data["te"]["bumpmap"].asInteger());
+            }
+            if (te_data["te"].has("bumpshiny"))
+            {
+                objectp->setTEBumpShiny(te, (U8)te_data["te"]["bumpshiny"].asInteger());
+            }
+            if (te_data["te"].has("bumpfullbright"))
+            {
+                objectp->setTEBumpShinyFullbright(te, (U8)te_data["te"]["bumpfullbright"].asInteger());
+            }
+
+            // Texture map
+            if (te_data["te"].has("scales") && te_data["te"].has("scalet"))
+            {
+                objectp->setTEScale(te, (F32)te_data["te"]["scales"].asReal(), (F32)te_data["te"]["scalet"].asReal());
+            }
+            if (te_data["te"].has("offsets") && te_data["te"].has("offsett"))
+            {
+                objectp->setTEOffset(te, (F32)te_data["te"]["offsets"].asReal(), (F32)te_data["te"]["offsett"].asReal());
+            }
+            if (te_data["te"].has("imagerot"))
+            {
+                objectp->setTERotation(te, (F32)te_data["te"]["imagerot"].asReal());
+            }
+
+            // Media
+            if (te_data["te"].has("media_flags"))
+            {
+                U8 media_flags = te_data["te"]["media_flags"].asInteger();
+                objectp->setTEMediaFlags(te, media_flags);
+                LLVOVolume *vo = dynamic_cast<LLVOVolume*>(objectp);
+                if (vo && te_data["te"].has(LLTextureEntry::TEXTURE_MEDIA_DATA_KEY))
+                {
+                    vo->syncMediaData(te, te_data["te"][LLTextureEntry::TEXTURE_MEDIA_DATA_KEY], true/*merge*/, true/*ignore_agent*/);
+                }
+            }
+            else
+            {
+                // Keep media flags on destination unchanged
+            }
+        }
+
+        if (te_data.has("material"))
+        {
+            LLUUID object_id = objectp->getID();
+
+            LLSelectedTEMaterial::setAlphaMaskCutoff(this, (U8)te_data["material"]["SpecRot"].asInteger(), te, object_id);
+
+            // Normal
+            // Replace placeholders with target's
+            if (te_data["material"].has("NormMapNoCopy"))
+            {
+                LLMaterialPtr material = tep->getMaterialParams();
+                if (material.notNull())
+                {
+                    LLUUID id = material->getNormalID();
+                    if (id.notNull())
+                    {
+                        te_data["material"]["NormMap"] = id;
+                    }
+                }
+            }
+            LLSelectedTEMaterial::setNormalID(this, te_data["material"]["NormMap"].asUUID(), te, object_id);
+            LLSelectedTEMaterial::setNormalRepeatX(this, (F32)te_data["material"]["NormRepX"].asReal(), te, object_id);
+            LLSelectedTEMaterial::setNormalRepeatY(this, (F32)te_data["material"]["NormRepY"].asReal(), te, object_id);
+            LLSelectedTEMaterial::setNormalOffsetX(this, (F32)te_data["material"]["NormOffX"].asReal(), te, object_id);
+            LLSelectedTEMaterial::setNormalOffsetY(this, (F32)te_data["material"]["NormOffY"].asReal(), te, object_id);
+            LLSelectedTEMaterial::setNormalRotation(this, (F32)te_data["material"]["NormRot"].asReal(), te, object_id);
+
+            // Specular
+                // Replace placeholders with target's
+            if (te_data["material"].has("SpecMapNoCopy"))
+            {
+                LLMaterialPtr material = tep->getMaterialParams();
+                if (material.notNull())
+                {
+                    LLUUID id = material->getSpecularID();
+                    if (id.notNull())
+                    {
+                        te_data["material"]["SpecMap"] = id;
+                    }
+                }
+            }
+            LLSelectedTEMaterial::setSpecularID(this, te_data["material"]["SpecMap"].asUUID(), te, object_id);
+            LLSelectedTEMaterial::setSpecularRepeatX(this, (F32)te_data["material"]["SpecRepX"].asReal(), te, object_id);
+            LLSelectedTEMaterial::setSpecularRepeatY(this, (F32)te_data["material"]["SpecRepY"].asReal(), te, object_id);
+            LLSelectedTEMaterial::setSpecularOffsetX(this, (F32)te_data["material"]["SpecOffX"].asReal(), te, object_id);
+            LLSelectedTEMaterial::setSpecularOffsetY(this, (F32)te_data["material"]["SpecOffY"].asReal(), te, object_id);
+            LLSelectedTEMaterial::setSpecularRotation(this, (F32)te_data["material"]["SpecRot"].asReal(), te, object_id);
+            LLColor4 spec_color(te_data["material"]["SpecColor"]);
+            LLSelectedTEMaterial::setSpecularLightColor(this, spec_color, te);
+            LLSelectedTEMaterial::setSpecularLightExponent(this, (U8)te_data["material"]["SpecExp"].asInteger(), te, object_id);
+            LLSelectedTEMaterial::setEnvironmentIntensity(this, (U8)te_data["material"]["EnvIntensity"].asInteger(), te, object_id);
+            LLSelectedTEMaterial::setDiffuseAlphaMode(this, (U8)te_data["material"]["SpecRot"].asInteger(), te, object_id);
+            if (te_data.has("te") && te_data["te"].has("shiny"))
+            {
+                objectp->setTEShiny(te, (U8)te_data["te"]["shiny"].asInteger());
+            }
+        }
+    }
+}
+
+void LLPanelFace::menuDoToSelected(const LLSD& userdata)
+{
+    std::string command = userdata.asString();
+
+    // paste
+    if (command == "color_paste")
+    {
+        onPasteColor();
+    }
+    else if (command == "texture_paste")
+    {
+        onPasteTexture();
+    }
+    // copy
+    else if (command == "color_copy")
+    {
+        onCopyColor();
+    }
+    else if (command == "texture_copy")
+    {
+        onCopyTexture();
+    }
+}
+
+bool LLPanelFace::menuEnableItem(const LLSD& userdata)
+{
+    std::string command = userdata.asString();
+
+    // paste options
+    if (command == "color_paste")
+    {
+        return mClipboardParams.has("color");
+    }
+    else if (command == "texture_paste")
+    {
+        return mClipboardParams.has("texture");
+    }
+    return false;
+}
+
+
 // static
 void LLPanelFace::onCommitPlanarAlign(LLUICtrl* ctrl, void* userdata)
 {
diff --git a/indra/newview/llpanelface.h b/indra/newview/llpanelface.h
index 2d57d89a44f5622fff5ccab80fc47cba0ff3caff..44bc442bbb8c640a962e9a54f540d603c7f10965 100644
--- a/indra/newview/llpanelface.h
+++ b/indra/newview/llpanelface.h
@@ -47,6 +47,8 @@ class LLUICtrl;
 class LLViewerObject;
 class LLFloater;
 class LLMaterialID;
+class LLMediaCtrl;
+class LLMenuButton;
 
 // Represents an edit for use in replicating the op across one or more materials in the selection set.
 //
@@ -97,8 +99,10 @@ class LLPanelFace : public LLPanel
 	virtual ~LLPanelFace();
 
 	void			refresh();
-	void			setMediaURL(const std::string& url);
-	void			setMediaType(const std::string& mime_type);
+    void			refreshMedia();
+    void			unloadMedia();
+
+    /*virtual*/ void draw();
 
 	LLMaterialPtr createDefaultMaterial(LLMaterialPtr current_material)
 	{
@@ -114,6 +118,12 @@ class LLPanelFace : public LLPanel
 	LLRender::eTexIndex getTextureChannelToEdit();
 
 protected:
+    void			navigateToTitleMedia(const std::string url);
+    bool			selectedMediaEditable();
+    void			clearMediaSettings();
+    void			updateMediaSettings();
+    void			updateMediaTitle();
+
 	void			getState();
 
 	void			sendTexture();			// applies and sends texture
@@ -128,6 +138,8 @@ class LLPanelFace : public LLPanel
 	void			sendMedia();
     void            alignTestureLayer();
 
+    void            updateCopyTexButton();
+
 	// this function is to return TRUE if the drag should succeed.
 	static BOOL onDragTexture(LLUICtrl* ctrl, LLInventoryItem* item);
 
@@ -150,6 +162,9 @@ class LLPanelFace : public LLPanel
 
 	void 	onCloseTexturePicker(const LLSD& data);
 
+    static bool deleteMediaConfirm(const LLSD& notification, const LLSD& response);
+    static bool multipleFacesSelectedConfirm(const LLSD& notification, const LLSD& response);
+
 	// Make UI reflect state of currently selected material (refresh)
 	// and UI mode (e.g. editing normal map v diffuse map)
 	//
@@ -194,6 +209,9 @@ class LLPanelFace : public LLPanel
 
 	static void		onCommitMaterialsMedia(	LLUICtrl* ctrl, void* userdata);
 	static void		onCommitMaterialType(	LLUICtrl* ctrl, void* userdata);
+	static void 	onClickBtnEditMedia(LLUICtrl* ctrl, void* userdata);
+	static void 	onClickBtnDeleteMedia(LLUICtrl* ctrl, void* userdata);
+	static void 	onClickBtnAddMedia(LLUICtrl* ctrl, void* userdata);
 	static void		onCommitBump(				LLUICtrl* ctrl, void* userdata);
 	static void		onCommitTexGen(			LLUICtrl* ctrl, void* userdata);
 	static void		onCommitShiny(				LLUICtrl* ctrl, void* userdata);
@@ -205,6 +223,18 @@ class LLPanelFace : public LLPanel
 	static void		onClickAutoFix(void*);
     static void		onAlignTexture(void*);
 
+public: // needs to be accessible to selection manager
+    void            onCopyColor(); // records all selected faces
+    void            onPasteColor(); // to specific face
+    void            onPasteColor(LLViewerObject* objectp, S32 te); // to specific face
+    void            onCopyTexture();
+    void            onPasteTexture();
+    void            onPasteTexture(LLViewerObject* objectp, S32 te);
+
+protected:
+    void            menuDoToSelected(const LLSD& userdata);
+    bool            menuEnableItem(const LLSD& userdata);
+
 	static F32     valueGlow(LLViewerObject* object, S32 face);
 
 	
@@ -234,6 +264,10 @@ class LLPanelFace : public LLPanel
 	F32		getCurrentShinyOffsetU();
 	F32		getCurrentShinyOffsetV();
 
+    LLComboBox *mComboMatMedia;
+    LLMediaCtrl *mTitleMedia;
+    LLTextBox *mTitleMediaText;
+
 	// Update visibility of controls to match current UI mode
 	// (e.g. materials vs media editing)
 	//
@@ -241,10 +275,6 @@ class LLPanelFace : public LLPanel
 	//
 	void updateVisibility();
 
-	// Make material(s) reflect current state of UI (apply edit)
-	//
-	void updateMaterial();
-
 	// Hey look everyone, a type-safe alternative to copy and paste! :)
 	//
 
@@ -400,7 +430,10 @@ class LLPanelFace : public LLPanel
 	 * If agent selects texture which is not allowed to be applied for the currently selected object,
 	 * all controls of the floater texture picker which allow to apply the texture will be disabled.
 	 */
-	void onTextureSelectionChanged(LLInventoryItem* itemp);
+    void onTextureSelectionChanged(LLInventoryItem* itemp);
+
+    LLMenuButton*   mMenuClipboardColor;
+    LLMenuButton*   mMenuClipboardTexture;
 
 	bool mIsAlpha;
 	
@@ -415,7 +448,12 @@ class LLPanelFace : public LLPanel
 	 * up-arrow on a spinner, and avoids running afoul of its throttle.
 	 */
 	bool mUpdateInFlight;
-	bool mUpdatePending;
+    bool mUpdatePending;
+
+    LLSD            mClipboardParams;
+
+    LLSD mMediaSettings;
+    bool mNeedMediaTitle;
 
 public:
 	#if defined(DEF_GET_MAT_STATE)
diff --git a/indra/newview/llpanelgroupcreate.cpp b/indra/newview/llpanelgroupcreate.cpp
index 52be75072cad4104c7ef714451bc890c85312c99..01a4ab0455f0477d5b82ad9eaa532dc074eb9508 100644
--- a/indra/newview/llpanelgroupcreate.cpp
+++ b/indra/newview/llpanelgroupcreate.cpp
@@ -104,7 +104,7 @@ void LLPanelGroupCreate::onOpen(const LLSD& key)
     // populate list
     addMembershipRow("Base");
     addMembershipRow("Premium");
-    addMembershipRow("Premium Plus");
+    addMembershipRow("Premium_Plus");
     addMembershipRow("Internal");// Present only if you are already in one, needed for testing
 
     S32 cost = LLAgentBenefitsMgr::current().getCreateGroupCost();
diff --git a/indra/newview/llpanelgroupgeneral.cpp b/indra/newview/llpanelgroupgeneral.cpp
index 375daf60f88ec6f55f661e2a571d1fec0aa84caf..04d3236bf1349acf45ecd4d405b9d95849fee96f 100644
--- a/indra/newview/llpanelgroupgeneral.cpp
+++ b/indra/newview/llpanelgroupgeneral.cpp
@@ -97,6 +97,7 @@ BOOL LLPanelGroupGeneral::postBuild()
 		mEditCharter->setCommitCallback(onCommitAny, this);
 		mEditCharter->setFocusReceivedCallback(boost::bind(onFocusEdit, _1, this));
 		mEditCharter->setFocusChangedCallback(boost::bind(onFocusEdit, _1, this));
+        mEditCharter->setContentTrusted(false);
 	}
 
 	// Options
@@ -575,7 +576,8 @@ void LLPanelGroupGeneral::update(LLGroupChange gc)
 
 	if (mEditCharter)
 	{
-		mEditCharter->setText(gdatap->mCharter);
+        mEditCharter->setParseURLs(!mAllowEdit || !can_change_ident);
+        mEditCharter->setText(gdatap->mCharter);
 	}
 	
 	resetDirty();
diff --git a/indra/newview/llpanelimcontrolpanel.cpp b/indra/newview/llpanelimcontrolpanel.cpp
index 389baa86cd49a8c95b0cf70c78930c9e8708d583..07a8641a928ad67f122787bcb6403277d6e051b6 100644
--- a/indra/newview/llpanelimcontrolpanel.cpp
+++ b/indra/newview/llpanelimcontrolpanel.cpp
@@ -1,6 +1,6 @@
 /**
- * @file llpanelavatar.cpp
- * @brief LLPanelAvatar and related class implementations
+ * @file llpanelimcontrolpanel.cpp
+ * @brief LLPanelIMControlPanel and related class implementations
  *
  * $LicenseInfo:firstyear=2004&license=viewerlgpl$
  * Second Life Viewer Source Code
diff --git a/indra/newview/llpanellandaudio.cpp b/indra/newview/llpanellandaudio.cpp
index e7bdc51b4a56597068511cd89d1b66c4b93ed4a0..9e3fc544773ab2c27285b870b4f18072c8b14318 100644
--- a/indra/newview/llpanellandaudio.cpp
+++ b/indra/newview/llpanellandaudio.cpp
@@ -97,6 +97,9 @@ BOOL LLPanelLandAudio::postBuild()
 	mCheckAVSoundGroup = getChild<LLCheckBoxCtrl>("group av sound check");
 	childSetCommitCallback("group av sound check", onCommitAny, this);
 
+    mCheckObscureMOAP = getChild<LLCheckBoxCtrl>("obscure_moap");
+    childSetCommitCallback("obscure_moap", onCommitAny, this);
+
 	return TRUE;
 }
 
@@ -157,6 +160,9 @@ void LLPanelLandAudio::refresh()
 
 		mCheckAVSoundGroup->set(parcel->getAllowGroupAVSounds() || parcel->getAllowAnyAVSounds());	// On if "Everyone" is on
 		mCheckAVSoundGroup->setEnabled(can_change_av_sounds && !parcel->getAllowAnyAVSounds());		// Enabled if "Everyone" is off
+
+        mCheckObscureMOAP->set(parcel->getObscureMOAP());
+        mCheckObscureMOAP->setEnabled(can_change_media);
 	}
 }
 // static
@@ -184,6 +190,8 @@ void LLPanelLandAudio::onCommitAny(LLUICtrl*, void *userdata)
 		group_av_sound = self->mCheckAVSoundGroup->get();
 	}
 
+    bool obscure_moap = self->mCheckObscureMOAP->get();
+
 	// Remove leading/trailing whitespace (common when copying/pasting)
 	LLStringUtil::trim(music_url);
 
@@ -194,6 +202,7 @@ void LLPanelLandAudio::onCommitAny(LLUICtrl*, void *userdata)
 	parcel->setMusicURL(music_url);
 	parcel->setAllowAnyAVSounds(any_av_sound);
 	parcel->setAllowGroupAVSounds(group_av_sound);
+    parcel->setObscureMOAP(obscure_moap);
 
 	// Send current parcel data upstream to server
 	LLViewerParcelMgr::getInstance()->sendParcelPropertiesUpdate( parcel );
diff --git a/indra/newview/llpanellandaudio.h b/indra/newview/llpanellandaudio.h
index 7e4fce80e412e38a86585abad2513e44742dde25..b54fe62179a9f294af384e0daa3c5a02e9926f07 100644
--- a/indra/newview/llpanellandaudio.h
+++ b/indra/newview/llpanellandaudio.h
@@ -53,6 +53,7 @@ class LLPanelLandAudio
 	LLLineEditor*	mMusicURLEdit;
 	LLCheckBoxCtrl* mCheckAVSoundAny;
 	LLCheckBoxCtrl* mCheckAVSoundGroup;
+    LLCheckBoxCtrl* mCheckObscureMOAP;
 
 	LLSafeHandle<LLParcelSelection>&	mParcel;
 };
diff --git a/indra/newview/llpanellandmarks.cpp b/indra/newview/llpanellandmarks.cpp
index ce17da30762f44c48c5bf63802f837c45b7d3a18..c3334605ae92adc5f542af240f4063d586724286 100644
--- a/indra/newview/llpanellandmarks.cpp
+++ b/indra/newview/llpanellandmarks.cpp
@@ -29,6 +29,7 @@
 #include "llpanellandmarks.h"
 
 #include "llbutton.h"
+#include "llfloaterprofile.h"
 #include "llfloaterreg.h"
 #include "llnotificationsutil.h"
 #include "llsdutil.h"
@@ -1003,17 +1004,6 @@ bool LLLandmarksPanel::canItemBeModified(const std::string& command_name, LLFold
 	return can_be_modified;
 }
 
-void LLLandmarksPanel::onPickPanelExit( LLPanelPickEdit* pick_panel, LLView* owner, const LLSD& params)
-{
-	pick_panel->setVisible(FALSE);
-	owner->removeChild(pick_panel);
-	//we need remove  observer to  avoid  processParcelInfo in the future.
-	LLRemoteParcelInfoProcessor::getInstance()->removeObserver(params["parcel_id"].asUUID(), this);
-
-	delete pick_panel;
-	pick_panel = NULL;
-}
-
 bool LLLandmarksPanel::handleDragAndDropToTrash(BOOL drop, EDragAndDropType cargo_type, void* cargo_data , EAcceptance* accept)
 {
 	*accept = ACCEPT_NO;
@@ -1080,49 +1070,21 @@ void LLLandmarksPanel::doProcessParcelInfo(LLLandmark* landmark,
 										   LLInventoryItem* inv_item,
 										   const LLParcelData& parcel_data)
 {
-	LLPanelPickEdit* panel_pick = LLPanelPickEdit::create();
 	LLVector3d landmark_global_pos;
 	landmark->getGlobalPos(landmark_global_pos);
 
-	// let's toggle pick panel into  panel places
-	LLPanel* panel_places = NULL;
-	LLFloaterSidePanelContainer* floaterp = LLFloaterReg::getTypedInstance<LLFloaterSidePanelContainer>("places");
-	if (floaterp)
-	{
-		panel_places = floaterp->findChild<LLPanel>("main_panel");
-	}
-
-	if (!panel_places)
-	{
-		llassert(NULL != panel_places);
-		return;
-	}
-	panel_places->addChild(panel_pick);
-	LLRect paren_rect(panel_places->getRect());
-	panel_pick->reshape(paren_rect.getWidth(),paren_rect.getHeight(), TRUE);
-	panel_pick->setRect(paren_rect);
-	panel_pick->onOpen(LLSD());
-
 	LLPickData data;
 	data.pos_global = landmark_global_pos;
 	data.name = inv_item->getName();
 	data.desc = inv_item->getDescription();
 	data.snapshot_id = parcel_data.snapshot_id;
 	data.parcel_id = parcel_data.parcel_id;
-	panel_pick->setPickData(&data);
-
-	LLSD params;
-	params["parcel_id"] = parcel_data.parcel_id;
-	/* set exit callback to get back onto panel places
-	 in callback we will make cleaning up( delete pick_panel instance,
-	 remove landmark panel from observer list
-	*/
-	panel_pick->setExitCallback(boost::bind(&LLLandmarksPanel::onPickPanelExit,this,
-			panel_pick, panel_places,params));
-	panel_pick->setSaveCallback(boost::bind(&LLLandmarksPanel::onPickPanelExit,this,
-		panel_pick, panel_places,params));
-	panel_pick->setCancelCallback(boost::bind(&LLLandmarksPanel::onPickPanelExit,this,
-					panel_pick, panel_places,params));
+
+    LLFloaterProfile* profile_floater = dynamic_cast<LLFloaterProfile*>(LLFloaterReg::showInstance("profile", LLSD().with("id", gAgentID)));
+    if (profile_floater)
+    {
+        profile_floater->createPick(data);
+    }
 }
 
 void LLLandmarksPanel::doCreatePick(LLLandmark* landmark, const LLUUID &item_id)
diff --git a/indra/newview/llpanellandmarks.h b/indra/newview/llpanellandmarks.h
index d7408269b5dfb6728dfb928bbb058e26da9031e8..16f3a5dc243033796bcb59be60c2e4d93d40dd75 100644
--- a/indra/newview/llpanellandmarks.h
+++ b/indra/newview/llpanellandmarks.h
@@ -34,7 +34,6 @@
 #include "llinventorymodel.h"
 #include "lllandmarklist.h"
 #include "llpanelplacestab.h"
-#include "llpanelpick.h"
 #include "llremoteparcelrequest.h"
 
 class LLAccordionCtrlTab;
@@ -136,7 +135,6 @@ class LLLandmarksPanel : public LLPanelPlacesTab, LLRemoteParcelInfoObserver
 	 * For now it checks cut/rename/delete/paste actions.
 	 */
 	bool canItemBeModified(const std::string& command_name, LLFolderViewItem* item) const;
-	void onPickPanelExit( LLPanelPickEdit* pick_panel, LLView* owner, const LLSD& params);
 
 	/**
 	 * Landmark actions callbacks. Fire when a landmark is loaded from the list.
diff --git a/indra/newview/llpanellogin.cpp b/indra/newview/llpanellogin.cpp
index 381b80fb66089162438f728bc7f2e17e25e2c220..9df3a8e31aaf4bd7428f5123e333c0cc4c4640c3 100644
--- a/indra/newview/llpanellogin.cpp
+++ b/indra/newview/llpanellogin.cpp
@@ -92,44 +92,6 @@ LLPointer<LLCredential> load_user_credentials(std::string &user_key)
     }
 }
 
-// keys are lower case to be case insensitive so they are not always
-// identical to names which retain user input, like:
-// "AwEsOmE Resident" -> "awesome_resident"
-std::string get_user_key_from_name(const std::string &username)
-{
-    std::string key = username;
-    LLStringUtil::trim(key);
-    LLStringUtil::toLower(key);
-    if (!LLGridManager::getInstance()->isSystemGrid())
-    {
-        size_t separator_index = username.find_first_of(" ");
-        if (separator_index == username.npos)
-        {
-            // CRED_IDENTIFIER_TYPE_ACCOUNT
-            return key;
-        }
-    }
-    // CRED_IDENTIFIER_TYPE_AGENT
-    size_t separator_index = username.find_first_of(" ._");
-    std::string first = username.substr(0, separator_index);
-    std::string last;
-    if (separator_index != username.npos)
-    {
-        last = username.substr(separator_index + 1, username.npos);
-        LLStringUtil::trim(last);
-    }
-    else
-    {
-        // ...on Linden grids, single username users as considered to have
-        // last name "Resident"
-        // *TODO: Make login.cgi support "account_name" like above
-        last = "resident";
-    }
-
-    key = first + "_" + last;
-    return key;
-}
-
 class LLLoginLocationAutoHandler : public LLCommandHandler
 {
 public:
@@ -361,11 +323,10 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect,
 	username_combo->setReturnCallback(boost::bind(&LLPanelLogin::onClickConnect, this));
 	username_combo->setKeystrokeOnEsc(TRUE);
 
-    if (!mFirstLoginThisInstall)
-    {
-        LLCheckBoxCtrl* remember_name = getChild<LLCheckBoxCtrl>("remember_name");
-        remember_name->setCommitCallback(boost::bind(&LLPanelLogin::onRememberUserCheck, this));
-    }
+
+    LLCheckBoxCtrl* remember_name = getChild<LLCheckBoxCtrl>("remember_name");
+    remember_name->setCommitCallback(boost::bind(&LLPanelLogin::onRememberUserCheck, this));
+    getChild<LLCheckBoxCtrl>("remember_password")->setCommitCallback(boost::bind(&LLPanelLogin::onRememberPasswordCheck, this));
 }
 
 void LLPanelLogin::addFavoritesToStartLocation()
@@ -438,10 +399,22 @@ void LLPanelLogin::addFavoritesToStartLocation()
 		combo->addSeparator();
 		LL_DEBUGS() << "Loading favorites for " << iter->first << LL_ENDL;
 		LLSD user_llsd = iter->second;
+        bool update_password_setting = true;
 		for (LLSD::array_const_iterator iter1 = user_llsd.beginArray();
 			iter1 != user_llsd.endArray(); ++iter1)
 		{
-			std::string label = (*iter1)["name"].asString();
+            if ((*iter1).has("save_password"))
+            {
+                bool save_password = (*iter1)["save_password"].asBoolean();
+                gSavedSettings.setBOOL("RememberPassword", save_password);
+                if (!save_password)
+                {
+                    getChild<LLButton>("connect_btn")->setEnabled(false);
+                }
+                update_password_setting = false;
+            }
+
+            std::string label = (*iter1)["name"].asString();
 			std::string value = (*iter1)["slurl"].asString();
 			if(label != "" && value != "")
 			{
@@ -453,6 +426,10 @@ void LLPanelLogin::addFavoritesToStartLocation()
 				}
 			}
 		}
+        if (update_password_setting)
+        {
+            gSavedSettings.setBOOL("UpdateRememberPasswordSetting", TRUE);
+        }
 		break;
 	}
 	if (combo->getValue().asString().empty())
@@ -565,21 +542,12 @@ void LLPanelLogin::populateFields(LLPointer<LLCredential> credential, bool remem
         LL_WARNS() << "Attempted fillFields with no login view shown" << LL_ENDL;
         return;
     }
-    if (sInstance->mFirstLoginThisInstall)
-    {
-        LLUICtrl* remember_check = sInstance->getChild<LLUICtrl>("remember_check");
-        remember_check->setValue(remember_psswrd);
-        // no list to populate
-        setFields(credential);
-    }
-    else
-    {
-        sInstance->getChild<LLUICtrl>("remember_name")->setValue(remember_user);
-        LLUICtrl* remember_password = sInstance->getChild<LLUICtrl>("remember_password");
-        remember_password->setValue(remember_user && remember_psswrd);
-        remember_password->setEnabled(remember_user);
-        sInstance->populateUserList(credential);
-    }
+
+    sInstance->getChild<LLUICtrl>("remember_name")->setValue(remember_user);
+    LLUICtrl* remember_password = sInstance->getChild<LLUICtrl>("remember_password");
+    remember_password->setValue(remember_user && remember_psswrd);
+    remember_password->setEnabled(remember_user);
+    sInstance->populateUserList(credential);
 }
 
 //static
@@ -690,39 +658,6 @@ void LLPanelLogin::getFields(LLPointer<LLCredential>& credential,
 	LL_INFOS("Credentials", "Authentication") << "retrieving username:" << username << LL_ENDL;
 	// determine if the username is a first/last form or not.
 	size_t separator_index = username.find_first_of(' ');
-	if (separator_index == username.npos
-		&& !LLGridManager::getInstance()->isSystemGrid())
-	{
-		LL_INFOS("Credentials", "Authentication") << "account: " << username << LL_ENDL;
-		// single username, so this is a 'clear' identifier
-		identifier["type"] = CRED_IDENTIFIER_TYPE_ACCOUNT;
-		identifier["account_name"] = username;
-		
-		if (LLPanelLogin::sInstance->mPasswordModified)
-		{
-			// password is plaintext
-			authenticator["type"] = CRED_AUTHENTICATOR_TYPE_CLEAR;
-			authenticator["secret"] = password;
-		}
-        else
-        {
-            credential = load_user_credentials(username);
-            if (credential.notNull())
-            {
-                authenticator = credential->getAuthenticator();
-                if (authenticator.emptyMap())
-                {
-                    // Likely caused by user trying to log in to non-system grid
-                    // with unsupported name format, just retry
-                    LL_WARNS() << "Authenticator failed to load for: " << username << LL_ENDL;
-                    // password is plaintext
-                    authenticator["type"] = CRED_AUTHENTICATOR_TYPE_CLEAR;
-                    authenticator["secret"] = password;
-                }
-            }
-        }
-	}
-	else
 	{
 		// Be lenient in terms of what separators we allow for two-word names
 		// and allow legacy users to login with firstname.lastname
@@ -773,16 +708,9 @@ void LLPanelLogin::getFields(LLPointer<LLCredential>& credential,
 		}
 	}
 	credential = gSecAPIHandler->createCredential(LLGridManager::getInstance()->getGrid(), identifier, authenticator);
-    if (!sInstance->mFirstLoginThisInstall)
-    {
-        remember_psswrd = sInstance->getChild<LLUICtrl>("remember_password")->getValue();
-        remember_user = sInstance->getChild<LLUICtrl>("remember_name")->getValue();
-    }
-    else
-    {
-        remember_psswrd = sInstance->getChild<LLUICtrl>("remember_check")->getValue();
-        remember_user = remember_psswrd; // on panel_login_first "remember_check" is named as 'remember me'
-    }
+
+    remember_psswrd = sInstance->getChild<LLUICtrl>("remember_password")->getValue();
+    remember_user = sInstance->getChild<LLUICtrl>("remember_name")->getValue();
 }
 
 
@@ -1145,17 +1073,18 @@ void LLPanelLogin::onUserListCommit(void*)
 }
 
 // static
-// At the moment only happens if !mFirstLoginThisInstall
 void LLPanelLogin::onRememberUserCheck(void*)
 {
-    if (sInstance && !sInstance->mFirstLoginThisInstall)
+    if (sInstance)
     {
         LLCheckBoxCtrl* remember_name(sInstance->getChild<LLCheckBoxCtrl>("remember_name"));
         LLCheckBoxCtrl* remember_psswrd(sInstance->getChild<LLCheckBoxCtrl>("remember_password"));
         LLComboBox* user_combo(sInstance->getChild<LLComboBox>("username_combo"));
 
         bool remember = remember_name->getValue().asBoolean();
-        if (user_combo->getCurrentIndex() != -1 && !remember)
+        if (!sInstance->mFirstLoginThisInstall
+            && user_combo->getCurrentIndex() != -1
+            && !remember)
         {
             remember = true;
             remember_name->setValue(true);
@@ -1169,6 +1098,14 @@ void LLPanelLogin::onRememberUserCheck(void*)
     }
 }
 
+void LLPanelLogin::onRememberPasswordCheck(void*)
+{
+    if (sInstance)
+    {
+        gSavedSettings.setBOOL("UpdateRememberPasswordSetting", TRUE);
+    }
+}
+
 // static
 void LLPanelLogin::onPassKey(LLLineEditor* caller, void* user_data)
 {
diff --git a/indra/newview/llpanellogin.h b/indra/newview/llpanellogin.h
index c5e6b41defb4ee24384b60b59d6d3119debb3e52..c6254f72cfbf0fa47eee0719885f9d1b5ef41413 100644
--- a/indra/newview/llpanellogin.h
+++ b/indra/newview/llpanellogin.h
@@ -107,6 +107,7 @@ class LLPanelLogin:
 	static void onUserNameTextEnty(void*);
 	static void onUserListCommit(void*);
 	static void onRememberUserCheck(void*);
+    static void onRememberPasswordCheck(void*);
 	static void onPassKey(LLLineEditor* caller, void* user_data);
 	static void updateServerCombo();
 
diff --git a/indra/newview/llpanelloginlistener.cpp b/indra/newview/llpanelloginlistener.cpp
index 33efde11f36e784cd03816c9c6bf184e57a614ba..fb3e8dc244a373d83d6e77298f51fc2553328e91 100644
--- a/indra/newview/llpanelloginlistener.cpp
+++ b/indra/newview/llpanelloginlistener.cpp
@@ -47,5 +47,5 @@ LLPanelLoginListener::LLPanelLoginListener(LLPanelLogin* instance):
 
 void LLPanelLoginListener::onClickConnect(const LLSD&) const
 {
-    mPanel->onClickConnect(NULL);
+    mPanel->onClickConnect(false);
 }
diff --git a/indra/newview/llpanelme.cpp b/indra/newview/llpanelme.cpp
deleted file mode 100644
index 55e4ffff5e10c5753dab5cfc0ee60e3301c47400..0000000000000000000000000000000000000000
--- a/indra/newview/llpanelme.cpp
+++ /dev/null
@@ -1,67 +0,0 @@
-/** 
- * @file llpanelme.cpp
- * @brief Side tray "Me" (My Profile) panel
- *
- * $LicenseInfo:firstyear=2009&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- * 
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- * 
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
- * $/LicenseInfo$
- */
-
-#include "llviewerprecompiledheaders.h"
-
-#include "llpanelme.h"
-
-// Viewer includes
-#include "llpanelprofile.h"
-#include "llagent.h"
-#include "llagentcamera.h"
-#include "llagentwearables.h"
-#include "llfirstuse.h"
-#include "llfloaterreg.h"
-#include "llhints.h"
-#include "llviewercontrol.h"
-
-// Linden libraries
-#include "llavatarnamecache.h"		// IDEVO
-#include "lliconctrl.h"
-#include "llnotifications.h"
-#include "llnotificationsutil.h"	// IDEVO
-#include "lltabcontainer.h"
-#include "lltexturectrl.h"
-
-static LLPanelInjector<LLPanelMe> t_panel_me_profile("panel_me");
-
-LLPanelMe::LLPanelMe(void) 
- : LLPanelProfile()
-{
-	setAvatarId(gAgent.getID());
-}
-
-BOOL LLPanelMe::postBuild()
-{
-	LLPanelProfile::postBuild();
-
-	return TRUE;
-}
-
-void LLPanelMe::onOpen(const LLSD& key)
-{
-	LLPanelProfile::onOpen(key);
-}
diff --git a/indra/newview/llpanelmediasettingsgeneral.cpp b/indra/newview/llpanelmediasettingsgeneral.cpp
index 9730f0f16d9df5f95b5a4815eb8ee42efaf28a5a..e1818cc68b3933c3d775e694690c958f6e6e823f 100644
--- a/indra/newview/llpanelmediasettingsgeneral.cpp
+++ b/indra/newview/llpanelmediasettingsgeneral.cpp
@@ -98,9 +98,6 @@ BOOL LLPanelMediaSettingsGeneral::postBuild()
 	childSetCommitCallback( LLMediaEntry::HOME_URL_KEY, onCommitHomeURL, this);
 	childSetCommitCallback( "current_url_reset_btn",onBtnResetCurrentUrl, this);
 
-	// interrogates controls and updates widgets as required
-	updateMediaPreview();
-
 	return true;
 }
 
@@ -313,9 +310,6 @@ void LLPanelMediaSettingsGeneral::initValues( void* userdata, const LLSD& _media
 			data_set[ i ].ctrl_ptr->setTentative( media_settings[ tentative_key ].asBoolean() );
 		};
 	};
-
-	// interrogates controls and updates widgets as required
-	self->updateMediaPreview();
 }
 
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/indra/newview/llpanelobject.cpp b/indra/newview/llpanelobject.cpp
index 831c89b00528402aaceb9dc75accf48ad0586bf5..0bfc1297d35b0339d4b1a06dadd81d102e1fc66d 100644
--- a/indra/newview/llpanelobject.cpp
+++ b/indra/newview/llpanelobject.cpp
@@ -46,6 +46,7 @@
 #include "llcombobox.h"
 #include "llfocusmgr.h"
 #include "llmanipscale.h"
+#include "llmenubutton.h"
 #include "llpreviewscript.h"
 #include "llresmgr.h"
 #include "llselectmgr.h"
@@ -117,8 +118,9 @@ BOOL	LLPanelObject::postBuild()
 	// Phantom checkbox
 	mCheckPhantom = getChild<LLCheckBoxCtrl>("Phantom Checkbox Ctrl");
 	childSetCommitCallback("Phantom Checkbox Ctrl",onCommitPhantom,this);
-       
+
 	// Position
+	mMenuClipboardPos = getChild<LLMenuButton>("clipboard_pos_btn");
 	mLabelPosition = getChild<LLTextBox>("label position");
 	mCtrlPosX = getChild<LLSpinCtrl>("Pos X");
 	childSetCommitCallback("Pos X",onCommitPosition,this);
@@ -128,6 +130,7 @@ BOOL	LLPanelObject::postBuild()
 	childSetCommitCallback("Pos Z",onCommitPosition,this);
 
 	// Scale
+	mMenuClipboardSize = getChild<LLMenuButton>("clipboard_size_btn");
 	mLabelSize = getChild<LLTextBox>("label size");
 	mCtrlScaleX = getChild<LLSpinCtrl>("Scale X");
 	childSetCommitCallback("Scale X",onCommitScale,this);
@@ -141,6 +144,7 @@ BOOL	LLPanelObject::postBuild()
 	childSetCommitCallback("Scale Z",onCommitScale,this);
 
 	// Rotation
+	mMenuClipboardRot = getChild<LLMenuButton>("clipboard_rot_btn");
 	mLabelRotation = getChild<LLTextBox>("label rotation");
 	mCtrlRotX = getChild<LLSpinCtrl>("Rot X");
 	childSetCommitCallback("Rot X",onCommitRotation,this);
@@ -155,6 +159,8 @@ BOOL	LLPanelObject::postBuild()
 	mComboBaseType = getChild<LLComboBox>("comboBaseType");
 	childSetCommitCallback("comboBaseType",onCommitParametric,this);
 
+	mMenuClipboardParams = getChild<LLMenuButton>("clipboard_obj_params_btn");
+
 	// Cut
 	mLabelCut = getChild<LLTextBox>("text cut");
 	mSpinCutBegin = getChild<LLSpinCtrl>("cut begin");
@@ -285,8 +291,13 @@ LLPanelObject::LLPanelObject()
 	mSelectedType(MI_BOX),
 	mSculptTextureRevert(LLUUID::null),
 	mSculptTypeRevert(0),
+    mHasClipboardPos(false),
+    mHasClipboardSize(false),
+    mHasClipboardRot(false),
 	mSizeChanged(FALSE)
 {
+    mCommitCallbackRegistrar.add("PanelObject.menuDoToSelected", boost::bind(&LLPanelObject::menuDoToSelected, this, _2));
+    mEnableCallbackRegistrar.add("PanelObject.menuEnable", boost::bind(&LLPanelObject::menuEnableItem, this, _2));
 }
 
 
@@ -373,7 +384,7 @@ void LLPanelObject::getState( )
 		calcp->clearVar(LLCalc::Z_POS);
 	}
 
-
+	mMenuClipboardPos->setEnabled(enable_move);
 	mLabelPosition->setEnabled( enable_move );
 	mCtrlPosX->setEnabled(enable_move);
 	mCtrlPosY->setEnabled(enable_move);
@@ -399,6 +410,7 @@ void LLPanelObject::getState( )
 		calcp->setVar(LLCalc::Z_SCALE, 0.f);
 	}
 
+	mMenuClipboardSize->setEnabled(enable_scale);
 	mLabelSize->setEnabled( enable_scale );
 	mCtrlScaleX->setEnabled( enable_scale );
 	mCtrlScaleY->setEnabled( enable_scale );
@@ -430,6 +442,7 @@ void LLPanelObject::getState( )
 		calcp->clearVar(LLCalc::Z_ROT);
 	}
 
+	mMenuClipboardRot->setEnabled(enable_rotate);
 	mLabelRotation->setEnabled( enable_rotate );
 	mCtrlRotX->setEnabled( enable_rotate );
 	mCtrlRotY->setEnabled( enable_rotate );
@@ -607,7 +620,7 @@ void LLPanelObject::getState( )
 		}
 		else
 		{
-			LL_INFOS() << "Unknown path " << (S32) path << " profile " << (S32) profile << " in getState" << LL_ENDL;
+			LL_INFOS("FloaterTools") << "Unknown path " << (S32) path << " profile " << (S32) profile << " in getState" << LL_ENDL;
 			selected_item = MI_BOX;
 		}
 
@@ -933,6 +946,7 @@ void LLPanelObject::getState( )
 
 	// Update field enablement
 	mComboBaseType	->setEnabled( enabled );
+	mMenuClipboardParams->setEnabled(enabled);
 
 	mLabelCut		->setEnabled( enabled );
 	mSpinCutBegin	->setEnabled( enabled );
@@ -1093,7 +1107,8 @@ void LLPanelObject::getState( )
 			}
 
 			mComboBaseType->setEnabled(!isMesh);
-			
+			mMenuClipboardParams->setEnabled(!isMesh);
+
 			if (mCtrlSculptType)
 			{
 				if (sculpt_stitching == LL_SCULPT_TYPE_NONE)
@@ -1157,11 +1172,11 @@ void LLPanelObject::sendIsPhysical()
 		LLSelectMgr::getInstance()->selectionUpdatePhysics(value);
 		mIsPhysical = value;
 
-		LL_INFOS() << "update physics sent" << LL_ENDL;
+		LL_INFOS("FloaterTools") << "update physics sent" << LL_ENDL;
 	}
 	else
 	{
-		LL_INFOS() << "update physics not changed" << LL_ENDL;
+		LL_INFOS("FloaterTools") << "update physics not changed" << LL_ENDL;
 	}
 }
 
@@ -1173,11 +1188,11 @@ void LLPanelObject::sendIsTemporary()
 		LLSelectMgr::getInstance()->selectionUpdateTemporary(value);
 		mIsTemporary = value;
 
-		LL_INFOS() << "update temporary sent" << LL_ENDL;
+		LL_INFOS("FloaterTools") << "update temporary sent" << LL_ENDL;
 	}
 	else
 	{
-		LL_INFOS() << "update temporary not changed" << LL_ENDL;
+		LL_INFOS("FloaterTools") << "update temporary not changed" << LL_ENDL;
 	}
 }
 
@@ -1190,11 +1205,11 @@ void LLPanelObject::sendIsPhantom()
 		LLSelectMgr::getInstance()->selectionUpdatePhantom(value);
 		mIsPhantom = value;
 
-		LL_INFOS() << "update phantom sent" << LL_ENDL;
+		LL_INFOS("FloaterTools") << "update phantom sent" << LL_ENDL;
 	}
 	else
 	{
-		LL_INFOS() << "update phantom not changed" << LL_ENDL;
+		LL_INFOS("FloaterTools") << "update phantom not changed" << LL_ENDL;
 	}
 }
 
@@ -1304,7 +1319,7 @@ void LLPanelObject::getVolumeParams(LLVolumeParams& volume_params)
 		break;
 		
 	default:
-		LL_WARNS() << "Unknown base type " << selected_type 
+		LL_WARNS("FloaterTools") << "Unknown base type " << selected_type 
 			<< " in getVolumeParams()" << LL_ENDL;
 		// assume a box
 		selected_type = MI_BOX;
@@ -1644,13 +1659,15 @@ void LLPanelObject::sendPosition(BOOL btn_down)
 	LLVector3 newpos(mCtrlPosX->get(), mCtrlPosY->get(), mCtrlPosZ->get());
 	LLViewerRegion* regionp = mObject->getRegion();
 
-	// Clamp the Z height
-	const F32 height = newpos.mV[VZ];
-	const F32 min_height = LLWorld::getInstance()->getMinAllowedZ(mObject, mObject->getPositionGlobal());
-	const F32 max_height = LLWorld::getInstance()->getRegionMaxHeight();
+	if (!regionp) return;
 
 	if (!mObject->isAttachment())
 	{
+        // Clamp the Z height
+        const F32 height = newpos.mV[VZ];
+        const F32 min_height = LLWorld::getInstance()->getMinAllowedZ(mObject, mObject->getPositionGlobal());
+        const F32 max_height = LLWorld::getInstance()->getRegionMaxHeight();
+
 		if ( height < min_height)
 		{
 			newpos.mV[VZ] = min_height;
@@ -1672,8 +1689,19 @@ void LLPanelObject::sendPosition(BOOL btn_down)
 	// Make sure new position is in a valid region, so the object
 	// won't get dumped by the simulator.
 	LLVector3d new_pos_global = regionp->getPosGlobalFromRegion(newpos);
-
-	if ( LLWorld::getInstance()->positionRegionValidGlobal(new_pos_global) )
+    bool is_valid_pos = true;
+    if (mObject->isAttachment())
+    {
+        LLVector3 delta_pos = mObject->getPositionEdit() - newpos;
+        LLVector3d attachment_pos = regionp->getPosGlobalFromRegion(mObject->getPositionRegion() + delta_pos);
+        is_valid_pos = LLWorld::getInstance()->positionRegionValidGlobal(attachment_pos);
+    }
+    else
+    {
+        is_valid_pos = LLWorld::getInstance()->positionRegionValidGlobal(new_pos_global);
+    }
+
+	if (is_valid_pos)
 	{
 		// send only if the position is changed, that is, the delta vector is not zero
 		LLVector3d old_pos_global = mObject->getPositionGlobal();
@@ -2000,3 +2028,283 @@ void LLPanelObject::onCommitSculptType(LLUICtrl *ctrl, void* userdata)
 
 	self->sendSculpt();
 }
+
+void LLPanelObject::menuDoToSelected(const LLSD& userdata)
+{
+    std::string command = userdata.asString();
+
+    // paste
+    if (command == "psr_paste")
+    {
+        onPastePos();
+        onPasteSize();
+        onPasteRot();
+    }
+    else if (command == "pos_paste")
+    {
+        onPastePos();
+    }
+    else if (command == "size_paste")
+    {
+        onPasteSize();
+    }
+    else if (command == "rot_paste")
+    {
+        onPasteRot();
+    }
+    else if (command == "params_paste")
+    {
+        onPasteParams();
+    }
+    // copy
+    else if (command == "psr_copy")
+    {
+        onCopyPos();
+        onCopySize();
+        onCopyRot();
+    }
+    else if (command == "pos_copy")
+    {
+        onCopyPos();
+    }
+    else if (command == "size_copy")
+    {
+        onCopySize();
+    }
+    else if (command == "rot_copy")
+    {
+        onCopyRot();
+    }
+    else if (command == "params_copy")
+    {
+        onCopyParams();
+    }
+}
+
+bool LLPanelObject::menuEnableItem(const LLSD& userdata)
+{
+    std::string command = userdata.asString();
+
+    // paste options
+    if (command == "psr_paste")
+    {
+        S32 selected_count = LLSelectMgr::getInstance()->getSelection()->getObjectCount();
+        BOOL single_volume = (LLSelectMgr::getInstance()->selectionAllPCode(LL_PCODE_VOLUME))
+            && (selected_count == 1);
+
+        if (!single_volume)
+        {
+            return false;
+        }
+
+        bool enable_move;
+        bool enable_modify;
+
+        LLSelectMgr::getInstance()->selectGetEditMoveLinksetPermissions(enable_move, enable_modify);
+
+        return enable_move && enable_modify && mHasClipboardPos && mHasClipboardSize && mHasClipboardRot;
+    }
+    else if (command == "pos_paste")
+    {
+        // assumes that menu won't be active if there is no move permission
+        return mHasClipboardPos;
+    }
+    else if (command == "size_paste")
+    {
+        return mHasClipboardSize;
+    }
+    else if (command == "rot_paste")
+    {
+        return mHasClipboardRot;
+    }
+    else if (command == "params_paste")
+    {
+        return mClipboardParams.isMap() && !mClipboardParams.emptyMap();
+    }
+    // copy options
+    else if (command == "psr_copy")
+    {
+        S32 selected_count = LLSelectMgr::getInstance()->getSelection()->getObjectCount();
+        BOOL single_volume = (LLSelectMgr::getInstance()->selectionAllPCode(LL_PCODE_VOLUME))
+            && (selected_count == 1);
+
+        if (!single_volume)
+        {
+            return false;
+        }
+
+        bool enable_move;
+        bool enable_modify;
+
+        LLSelectMgr::getInstance()->selectGetEditMoveLinksetPermissions(enable_move, enable_modify);
+
+        // since we forbid seeing values we also should forbid copying them
+        return enable_move && enable_modify;
+    }
+    return false;
+}
+
+void LLPanelObject::onCopyPos()
+{
+    mClipboardPos = LLVector3(mCtrlPosX->get(), mCtrlPosY->get(), mCtrlPosZ->get());
+
+    std::string stringVec = llformat("<%g, %g, %g>", mClipboardPos.mV[VX], mClipboardPos.mV[VY], mClipboardPos.mV[VZ]);
+    LLView::getWindow()->copyTextToClipboard(utf8str_to_wstring(stringVec));
+
+    mHasClipboardPos = true;
+}
+
+void LLPanelObject::onCopySize()
+{
+    mClipboardSize = LLVector3(mCtrlScaleX->get(), mCtrlScaleY->get(), mCtrlScaleZ->get());
+
+    std::string stringVec = llformat("<%g, %g, %g>", mClipboardSize.mV[VX], mClipboardSize.mV[VY], mClipboardSize.mV[VZ]);
+    LLView::getWindow()->copyTextToClipboard(utf8str_to_wstring(stringVec));
+
+    mHasClipboardSize = true;
+}
+
+void LLPanelObject::onCopyRot()
+{
+    mClipboardRot = LLVector3(mCtrlRotX->get(), mCtrlRotY->get(), mCtrlRotZ->get());
+
+    std::string stringVec = llformat("<%g, %g, %g>", mClipboardRot.mV[VX], mClipboardRot.mV[VY], mClipboardRot.mV[VZ]);
+    LLView::getWindow()->copyTextToClipboard(utf8str_to_wstring(stringVec));
+
+    mHasClipboardRot = true;
+}
+
+void LLPanelObject::onPastePos()
+{
+    if (!mHasClipboardPos) return;
+    if (mObject.isNull()) return;
+
+    LLViewerRegion* regionp = mObject->getRegion();
+    if (!regionp) return;
+
+
+    // Clamp pos on non-attachments, just keep the prims within the region
+    if (!mObject->isAttachment())
+    {
+        F32 max_width = regionp->getWidth(); // meters
+        mClipboardPos.mV[VX] = llclamp(mClipboardPos.mV[VX], 0.f, max_width);
+        mClipboardPos.mV[VY] = llclamp(mClipboardPos.mV[VY], 0.f, max_width);
+        //height will get properly clamped by sendPosition
+    }
+
+    mCtrlPosX->set( mClipboardPos.mV[VX] );
+    mCtrlPosY->set( mClipboardPos.mV[VY] );
+    mCtrlPosZ->set( mClipboardPos.mV[VZ] );
+
+    sendPosition(FALSE);
+}
+
+void LLPanelObject::onPasteSize()
+{
+    if (!mHasClipboardSize) return;
+
+    mClipboardSize.mV[VX] = llclamp(mClipboardSize.mV[VX], MIN_PRIM_SCALE, DEFAULT_MAX_PRIM_SCALE);
+    mClipboardSize.mV[VY] = llclamp(mClipboardSize.mV[VY], MIN_PRIM_SCALE, DEFAULT_MAX_PRIM_SCALE);
+    mClipboardSize.mV[VZ] = llclamp(mClipboardSize.mV[VZ], MIN_PRIM_SCALE, DEFAULT_MAX_PRIM_SCALE);
+
+    mCtrlScaleX->set(mClipboardSize.mV[VX]);
+    mCtrlScaleY->set(mClipboardSize.mV[VY]);
+    mCtrlScaleZ->set(mClipboardSize.mV[VZ]);
+
+    sendScale(FALSE);
+}
+
+void LLPanelObject::onPasteRot()
+{
+    if (!mHasClipboardRot) return;
+
+    mCtrlRotX->set(mClipboardRot.mV[VX]);
+    mCtrlRotY->set(mClipboardRot.mV[VY]);
+    mCtrlRotZ->set(mClipboardRot.mV[VZ]);
+
+    sendRotation(FALSE);
+}
+
+void LLPanelObject::onCopyParams()
+{
+    LLViewerObject* objectp = mObject;
+    if (!objectp || objectp->isMesh())
+    {
+        return;
+    }
+
+    mClipboardParams.clear();
+
+    // Parametrics
+    LLVolumeParams params;
+    getVolumeParams(params);
+    mClipboardParams["volume_params"] = params.asLLSD();
+
+    // Sculpted Prim
+    if (objectp->getParameterEntryInUse(LLNetworkData::PARAMS_SCULPT))
+    {
+        LLSculptParams *sculpt_params = (LLSculptParams *)objectp->getParameterEntry(LLNetworkData::PARAMS_SCULPT);
+
+        LLUUID texture_id = sculpt_params->getSculptTexture();
+        if (get_can_copy_texture(texture_id))
+        {
+            LL_DEBUGS("FloaterTools") << "Recording texture" << LL_ENDL;
+            mClipboardParams["sculpt"]["id"] = texture_id;
+        }
+        else
+        {
+            mClipboardParams["sculpt"]["id"] = LLUUID(SCULPT_DEFAULT_TEXTURE);
+        }
+
+        mClipboardParams["sculpt"]["type"] = sculpt_params->getSculptType();
+    }
+}
+
+void LLPanelObject::onPasteParams()
+{
+    LLViewerObject* objectp = mObject;
+    if (!objectp)
+    {
+        return;
+    }
+
+    // Sculpted Prim
+    if (mClipboardParams.has("sculpt"))
+    {
+        LLSculptParams sculpt_params;
+        LLUUID sculpt_id = mClipboardParams["sculpt"]["id"].asUUID();
+        U8 sculpt_type = (U8)mClipboardParams["sculpt"]["type"].asInteger();
+        sculpt_params.setSculptTexture(sculpt_id, sculpt_type);
+        objectp->setParameterEntry(LLNetworkData::PARAMS_SCULPT, sculpt_params, TRUE);
+    }
+    else
+    {
+        LLSculptParams *sculpt_params = (LLSculptParams *)objectp->getParameterEntry(LLNetworkData::PARAMS_SCULPT);
+        if (sculpt_params)
+        {
+            objectp->setParameterEntryInUse(LLNetworkData::PARAMS_SCULPT, FALSE, TRUE);
+        }
+    }
+
+    // volume params
+    // make sure updateVolume() won't affect flexible
+    if (mClipboardParams.has("volume_params"))
+    {
+        LLVolumeParams params;
+        params.fromLLSD(mClipboardParams["volume_params"]);
+        LLVOVolume *volobjp = (LLVOVolume *)objectp;
+        if (volobjp->isFlexible())
+        {
+            if (params.getPathParams().getCurveType() == LL_PCODE_PATH_LINE)
+            {
+                params.getPathParams().setCurveType(LL_PCODE_PATH_FLEXIBLE);
+            }
+        }
+        else if (params.getPathParams().getCurveType() == LL_PCODE_PATH_FLEXIBLE)
+        {
+            params.getPathParams().setCurveType(LL_PCODE_PATH_LINE);
+        }
+
+        objectp->updateVolume(params);
+    }
+}
diff --git a/indra/newview/llpanelobject.h b/indra/newview/llpanelobject.h
index 8829f493fa73621ecf60224835be0a6496a3779f..515dd27c0a8b313e128af523c90b06be83b1a7a6 100644
--- a/indra/newview/llpanelobject.h
+++ b/indra/newview/llpanelobject.h
@@ -37,6 +37,7 @@ class LLCheckBoxCtrl;
 class LLTextBox;
 class LLUICtrl;
 class LLButton;
+class LLMenuButton;
 class LLViewerObject;
 class LLComboBox;
 class LLColorSwatchCtrl;
@@ -66,6 +67,14 @@ class LLPanelObject : public LLPanel
 	static void 	onCommitPhantom(		LLUICtrl* ctrl, void* userdata);
 	static void 	onCommitPhysics(		LLUICtrl* ctrl, void* userdata);
 
+    void            onCopyPos();
+    void            onPastePos();
+    void            onCopySize();
+    void            onPasteSize();
+    void            onCopyRot();
+    void            onPasteRot();
+    void            onCopyParams();
+    void            onPasteParams();
 	static void 	onCommitParametric(LLUICtrl* ctrl, void* userdata);
 
 
@@ -75,6 +84,9 @@ class LLPanelObject : public LLPanel
 	BOOL     		onDropSculpt(LLInventoryItem* item);
 	static void     onCommitSculptType(    LLUICtrl *ctrl, void* userdata);
 
+    void            menuDoToSelected(const LLSD& userdata);
+    bool            menuEnableItem(const LLSD& userdata);
+
 protected:
 	void			getState();
 
@@ -92,6 +104,7 @@ class LLPanelObject : public LLPanel
 protected:
 	// Per-object options
 	LLComboBox*		mComboBaseType;
+	LLMenuButton*	mMenuClipboardParams;
 
 	LLTextBox*		mLabelCut;
 	LLSpinCtrl*		mSpinCutBegin;
@@ -131,17 +144,20 @@ class LLPanelObject : public LLPanel
 	LLTextBox*		mLabelRevolutions;
 	LLSpinCtrl*		mSpinRevolutions;
 
+	LLMenuButton*   mMenuClipboardPos;
 	LLTextBox*		mLabelPosition;
 	LLSpinCtrl*		mCtrlPosX;
 	LLSpinCtrl*		mCtrlPosY;
 	LLSpinCtrl*		mCtrlPosZ;
 
+	LLMenuButton*   mMenuClipboardSize;
 	LLTextBox*		mLabelSize;
 	LLSpinCtrl*		mCtrlScaleX;
 	LLSpinCtrl*		mCtrlScaleY;
 	LLSpinCtrl*		mCtrlScaleZ;
 	BOOL			mSizeChanged;
 
+	LLMenuButton*   mMenuClipboardRot;
 	LLTextBox*		mLabelRotation;
 	LLSpinCtrl*		mCtrlRotX;
 	LLSpinCtrl*		mCtrlRotY;
@@ -157,7 +173,7 @@ class LLPanelObject : public LLPanel
 	LLComboBox      *mCtrlSculptType;
 	LLCheckBoxCtrl  *mCtrlSculptMirror;
 	LLCheckBoxCtrl  *mCtrlSculptInvert;
-	
+
 	LLVector3		mCurEulerDegrees;		// to avoid sending rotation when not changed
 	BOOL			mIsPhysical;			// to avoid sending "physical" when not changed
 	BOOL			mIsTemporary;			// to avoid sending "temporary" when not changed
@@ -167,6 +183,15 @@ class LLPanelObject : public LLPanel
 	LLUUID          mSculptTextureRevert;   // so we can revert the sculpt texture on cancel
 	U8              mSculptTypeRevert;      // so we can revert the sculpt type on cancel
 
+    LLVector3       mClipboardPos;
+    LLVector3       mClipboardSize;
+    LLVector3       mClipboardRot;
+    LLSD            mClipboardParams;
+
+    bool            mHasClipboardPos;
+    bool            mHasClipboardSize;
+    bool            mHasClipboardRot;
+
 	LLPointer<LLViewerObject> mObject;
 	LLPointer<LLViewerObject> mRootObject;
 };
diff --git a/indra/newview/llpanelobjectinventory.cpp b/indra/newview/llpanelobjectinventory.cpp
index 0d987df6caf094b92b7aa4c1f22db823ae09c4d2..cfaa9456be3f1242305981d5e0d477eaafdbcfc0 100644
--- a/indra/newview/llpanelobjectinventory.cpp
+++ b/indra/newview/llpanelobjectinventory.cpp
@@ -618,7 +618,18 @@ const std::string& LLTaskCategoryBridge::getDisplayName() const
 
 	if (cat)
 	{
-		mDisplayName.assign(cat->getName());
+        std::string name = cat->getName();
+        if (mChildren.size() > 0)
+        {
+            // Add item count
+            // Normally we would be using getLabelSuffix for this
+            // but object's inventory just uses displaynames
+            LLStringUtil::format_map_t args;
+            args["[ITEMS_COUNT]"] = llformat("%d", mChildren.size());
+
+            name.append(" " + LLTrans::getString("InventoryItemsCount", args));
+        }
+		mDisplayName.assign(name);
 	}
 
 	return mDisplayName;
@@ -1522,6 +1533,8 @@ void LLPanelObjectInventory::createFolderViews(LLInventoryObject* inventory_root
 		{
 			createViewsForCategory(&contents, inventory_root, new_folder);
 		}
+        // Refresh for label to add item count
+        new_folder->refresh();
 	}
 }
 
diff --git a/indra/newview/llpanelpeople.cpp b/indra/newview/llpanelpeople.cpp
index 5997d522c4fac606c25c448089ebda150565ecb6..e424d6b5f53aca781e76df28e7085fbd8e24da66 100644
--- a/indra/newview/llpanelpeople.cpp
+++ b/indra/newview/llpanelpeople.cpp
@@ -1090,9 +1090,9 @@ void LLPanelPeople::onGroupLimitInfo()
 	args["MAX_BASIC"] = max_basic;
 	args["MAX_PREMIUM"] = max_premium;
 
-	if (LLAgentBenefitsMgr::has("Premium Plus"))
+	if (LLAgentBenefitsMgr::has("Premium_Plus"))
 	{
-		S32 max_premium_plus = LLAgentBenefitsMgr::get("Premium Plus").getGroupMembershipLimit();
+		S32 max_premium_plus = LLAgentBenefitsMgr::get("Premium_Plus").getGroupMembershipLimit();
 		args["MAX_PREMIUM_PLUS"] = max_premium_plus;
 		LLNotificationsUtil::add("GroupLimitInfoPlus", args);
 	}
diff --git a/indra/newview/llpanelpick.cpp b/indra/newview/llpanelpick.cpp
deleted file mode 100644
index 40326cfb39be221ab66f86b3acb7905e42aa9d56..0000000000000000000000000000000000000000
--- a/indra/newview/llpanelpick.cpp
+++ /dev/null
@@ -1,620 +0,0 @@
-/** 
- * @file llpanelpick.cpp
- * @brief LLPanelPick class implementation
- *
- * $LicenseInfo:firstyear=2004&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- * 
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- * 
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
- * $/LicenseInfo$
- */
-
-// Display of a "Top Pick" used both for the global top picks in the 
-// Find directory, and also for each individual user's picks in their
-// profile.
-
-#include "llviewerprecompiledheaders.h"
-
-#include "llpanelpick.h"
-
-#include "message.h"
-
-#include "llparcel.h"
-
-#include "llbutton.h"
-#include "llfloaterreg.h"
-#include "lliconctrl.h"
-#include "lllineeditor.h"
-#include "llpanel.h"
-#include "llscrollcontainer.h"
-#include "lltexteditor.h"
-
-#include "llagent.h"
-#include "llagentpicksinfo.h"
-#include "llavatarpropertiesprocessor.h"
-#include "llfloaterworldmap.h"
-#include "lltexturectrl.h"
-#include "lluiconstants.h"
-#include "llviewerparcelmgr.h"
-#include "llviewerregion.h"
-#include "llworldmap.h"
-
-
-#define XML_PANEL_EDIT_PICK "panel_edit_pick.xml"
-#define XML_PANEL_PICK_INFO "panel_pick_info.xml"
-
-#define XML_NAME		"pick_name"
-#define XML_DESC		"pick_desc"
-#define XML_SNAPSHOT	"pick_snapshot"
-#define XML_LOCATION	"pick_location"
-
-#define XML_BTN_ON_TXTR "edit_icon"
-#define XML_BTN_SAVE "save_changes_btn"
-
-//////////////////////////////////////////////////////////////////////////
-//////////////////////////////////////////////////////////////////////////
-//////////////////////////////////////////////////////////////////////////
-
-//static
-LLPanelPickInfo* LLPanelPickInfo::create()
-{
-	LLPanelPickInfo* panel = new LLPanelPickInfo();
-	panel->buildFromFile(XML_PANEL_PICK_INFO);
-	return panel;
-}
-
-LLPanelPickInfo::LLPanelPickInfo()
- : LLPanel()
- , LLAvatarPropertiesObserver()
- , LLRemoteParcelInfoObserver()
- , mAvatarId(LLUUID::null)
- , mSnapshotCtrl(NULL)
- , mPickId(LLUUID::null)
- , mParcelId(LLUUID::null)
- , mRequestedId(LLUUID::null)
- , mScrollingPanelMinHeight(0)
- , mScrollingPanelWidth(0)
- , mScrollingPanel(NULL)
- , mScrollContainer(NULL)
-{
-}
-
-LLPanelPickInfo::~LLPanelPickInfo()
-{
-	LLAvatarPropertiesProcessor::getInstance()->removeObserver(getAvatarId(), this);
-
-	if (mParcelId.notNull())
-	{
-		LLRemoteParcelInfoProcessor::getInstance()->removeObserver(mParcelId, this);
-	}
-}
-
-void LLPanelPickInfo::onOpen(const LLSD& key)
-{
-	LLUUID avatar_id = key["avatar_id"];
-	if(avatar_id.isNull())
-	{
-		return;
-	}
-
-	if(getAvatarId().notNull())
-	{
-		LLAvatarPropertiesProcessor::getInstance()->removeObserver(
-			getAvatarId(), this);
-	}
-
-	setAvatarId(avatar_id);
-
-	resetData();
-	resetControls();
-
-	setPickId(key["pick_id"]);
-	setPickName(key["pick_name"]);
-	setPickDesc(key["pick_desc"]);
-	setSnapshotId(key["snapshot_id"]);
-
-	LLAvatarPropertiesProcessor::getInstance()->addObserver(
-		getAvatarId(), this);
-	LLAvatarPropertiesProcessor::getInstance()->sendPickInfoRequest(
-		getAvatarId(), getPickId());
-}
-
-BOOL LLPanelPickInfo::postBuild()
-{
-	mSnapshotCtrl = getChild<LLTextureCtrl>(XML_SNAPSHOT);
-
-	childSetAction("teleport_btn", boost::bind(&LLPanelPickInfo::onClickTeleport, this));
-	childSetAction("show_on_map_btn", boost::bind(&LLPanelPickInfo::onClickMap, this));
-	childSetAction("back_btn", boost::bind(&LLPanelPickInfo::onClickBack, this));
-
-	mScrollingPanel = getChild<LLPanel>("scroll_content_panel");
-	mScrollContainer = getChild<LLScrollContainer>("profile_scroll");
-
-	mScrollingPanelMinHeight = mScrollContainer->getScrolledViewRect().getHeight();
-	mScrollingPanelWidth = mScrollingPanel->getRect().getWidth();
-
-	LLTextEditor* text_desc = getChild<LLTextEditor>(XML_DESC);
-	text_desc->setContentTrusted(false);
-
-	return TRUE;
-}
-
-void LLPanelPickInfo::reshape(S32 width, S32 height, BOOL called_from_parent)
-{
-	LLPanel::reshape(width, height, called_from_parent);
-
-	if (!mScrollContainer || !mScrollingPanel)
-		return;
-
-	static LLUICachedControl<S32> scrollbar_size ("UIScrollbarSize", 0);
-
-	S32 scroll_height = mScrollContainer->getRect().getHeight();
-	if (mScrollingPanelMinHeight >= scroll_height)
-	{
-		mScrollingPanel->reshape(mScrollingPanelWidth, mScrollingPanelMinHeight);
-	}
-	else
-	{
-		mScrollingPanel->reshape(mScrollingPanelWidth + scrollbar_size, scroll_height);
-	}
-}
-
-void LLPanelPickInfo::processProperties(void* data, EAvatarProcessorType type)
-{
-	if(APT_PICK_INFO != type)
-	{
-		return;
-	}
-	LLPickData* pick_info = static_cast<LLPickData*>(data);
-	if(!pick_info 
-		|| pick_info->creator_id != getAvatarId() 
-		|| pick_info->pick_id != getPickId())
-	{
-		return;
-	}
-
-	mParcelId = pick_info->parcel_id;
-	setSnapshotId(pick_info->snapshot_id);
-	setPickName(pick_info->name);
-	setPickDesc(pick_info->desc);
-	setPosGlobal(pick_info->pos_global);
-
-	// Send remote parcel info request to get parcel name and sim (region) name.
-	sendParcelInfoRequest();
-
-	// *NOTE dzaporozhan
-	// We want to keep listening to APT_PICK_INFO because user may 
-	// edit the Pick and we have to update Pick info panel.
-	// revomeObserver is called from onClickBack
-}
-
-void LLPanelPickInfo::sendParcelInfoRequest()
-{
-	if (mParcelId != mRequestedId)
-	{
-		LLRemoteParcelInfoProcessor::getInstance()->addObserver(mParcelId, this);
-		LLRemoteParcelInfoProcessor::getInstance()->sendParcelInfoRequest(mParcelId);
-
-		mRequestedId = mParcelId;
-	}
-}
-
-void LLPanelPickInfo::setExitCallback(const commit_callback_t& cb)
-{
-	getChild<LLButton>("back_btn")->setClickedCallback(cb);
-}
-
-void LLPanelPickInfo::processParcelInfo(const LLParcelData& parcel_data)
-{
-	setPickLocation(createLocationText(LLStringUtil::null, parcel_data.name,
-		parcel_data.sim_name, getPosGlobal()));
-
-	// We have received parcel info for the requested ID so clear it now.
-	mRequestedId.setNull();
-
-	if (mParcelId.notNull())
-	{
-		LLRemoteParcelInfoProcessor::getInstance()->removeObserver(mParcelId, this);
-	}
-}
-
-void LLPanelPickInfo::setEditPickCallback(const commit_callback_t& cb)
-{
-	getChild<LLButton>("edit_btn")->setClickedCallback(cb);
-}
-
-// PROTECTED AREA
-
-void LLPanelPickInfo::resetControls()
-{
-	if(getAvatarId() == gAgent.getID())
-	{
-		getChildView("edit_btn")->setEnabled(TRUE);
-		getChildView("edit_btn")->setVisible( TRUE);
-	}
-	else
-	{
-		getChildView("edit_btn")->setEnabled(FALSE);
-		getChildView("edit_btn")->setVisible( FALSE);
-	}
-}
-
-void LLPanelPickInfo::resetData()
-{
-	setPickName(LLStringUtil::null);
-	setPickDesc(LLStringUtil::null);
-	setPickLocation(LLStringUtil::null);
-	setPickId(LLUUID::null);
-	setSnapshotId(LLUUID::null);
-	mPosGlobal.clearVec();
-	mParcelId.setNull();
-	mRequestedId.setNull();
-}
-
-// static
-std::string LLPanelPickInfo::createLocationText(const std::string& owner_name, const std::string& original_name, const std::string& sim_name, const LLVector3d& pos_global)
-{
-	std::string location_text;
-	location_text.append(owner_name);
-	if (!original_name.empty())
-	{
-		if (!location_text.empty()) location_text.append(", ");
-		location_text.append(original_name);
-
-	}
-	if (!sim_name.empty())
-	{
-		if (!location_text.empty()) location_text.append(", ");
-		location_text.append(sim_name);
-	}
-
-	if (!location_text.empty()) location_text.append(" ");
-
-	if (!pos_global.isNull())
-	{
-		S32 region_x = ll_round((F32)pos_global.mdV[VX]) % REGION_WIDTH_UNITS;
-		S32 region_y = ll_round((F32)pos_global.mdV[VY]) % REGION_WIDTH_UNITS;
-		S32 region_z = ll_round((F32)pos_global.mdV[VZ]);
-		location_text.append(llformat(" (%d, %d, %d)", region_x, region_y, region_z));
-	}
-	return location_text;
-}
-
-void LLPanelPickInfo::setSnapshotId(const LLUUID& id) 
-{ 
-	mSnapshotCtrl->setImageAssetID(id);
-	mSnapshotCtrl->setValid(TRUE);
-}
-
-void LLPanelPickInfo::setPickName(const std::string& name)
-{
-	getChild<LLUICtrl>(XML_NAME)->setValue(name);
-}
-
-void LLPanelPickInfo::setPickDesc(const std::string& desc)
-{
-	getChild<LLUICtrl>(XML_DESC)->setValue(desc);
-}
-
-void LLPanelPickInfo::setPickLocation(const std::string& location)
-{
-	getChild<LLUICtrl>(XML_LOCATION)->setValue(location);
-}
-
-void LLPanelPickInfo::onClickMap()
-{
-	LLFloaterWorldMap::getInstance()->trackLocation(getPosGlobal());
-	LLFloaterReg::showInstance("world_map", "center");
-}
-
-void LLPanelPickInfo::onClickTeleport()
-{
-	if (!getPosGlobal().isExactlyZero())
-	{
-		gAgent.teleportViaLocation(getPosGlobal());
-		LLFloaterWorldMap::getInstance()->trackLocation(getPosGlobal());
-	}
-}
-
-void LLPanelPickInfo::onClickBack()
-{
-	LLAvatarPropertiesProcessor::getInstance()->removeObserver(getAvatarId(), this);
-}
-
-//////////////////////////////////////////////////////////////////////////
-//////////////////////////////////////////////////////////////////////////
-//////////////////////////////////////////////////////////////////////////
-
-//static
-LLPanelPickEdit* LLPanelPickEdit::create()
-{
-	LLPanelPickEdit* panel = new LLPanelPickEdit();
-	panel->buildFromFile(XML_PANEL_EDIT_PICK);
-	return panel;
-}
-
-LLPanelPickEdit::LLPanelPickEdit()
- : LLPanelPickInfo()
- , mLocationChanged(false)
- , mNeedData(true)
- , mNewPick(false)
-{
-}
-
-LLPanelPickEdit::~LLPanelPickEdit()
-{
-}
-
-void LLPanelPickEdit::onOpen(const LLSD& key)
-{
-	LLUUID pick_id = key["pick_id"];
-	mNeedData = true;
-
-	// creating new Pick
-	if(pick_id.isNull())
-	{
-		mNewPick = true;
-
-		setAvatarId(gAgent.getID());
-
-		resetData();
-		resetControls();
-
-		setPosGlobal(gAgent.getPositionGlobal());
-
-		LLUUID parcel_id = LLUUID::null, snapshot_id = LLUUID::null;
-		std::string pick_name, pick_desc, region_name;
-
-		LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel();
-		if(parcel)
-		{
-			parcel_id = parcel->getID();
-			pick_name = parcel->getName();
-			pick_desc = parcel->getDesc();
-			snapshot_id = parcel->getSnapshotID();
-		}
-
-		LLViewerRegion* region = gAgent.getRegion();
-		if(region)
-		{
-			region_name = region->getName();
-		}
-
-		setParcelID(parcel_id);
-		getChild<LLUICtrl>("pick_name")->setValue(pick_name.empty() ? region_name : pick_name);
-		getChild<LLUICtrl>("pick_desc")->setValue(pick_desc);
-		setSnapshotId(snapshot_id);
-		setPickLocation(createLocationText(getLocationNotice(), pick_name, region_name, getPosGlobal()));
-
-		enableSaveButton(true);
-	}
-	// editing existing pick
-	else
-	{
-		mNewPick = false;
-		LLPanelPickInfo::onOpen(key);
-
-		enableSaveButton(false);
-	}
-
-	resetDirty();
-}
-
-void LLPanelPickEdit::setPickData(const LLPickData* pick_data)
-{
-	if(!pick_data)
-	{
-		return;
-	}
-
-	mNeedData = false;
-
-	setParcelID(pick_data->parcel_id);
-	getChild<LLUICtrl>("pick_name")->setValue(pick_data->name);
-	getChild<LLUICtrl>("pick_desc")->setValue(pick_data->desc);
-	setSnapshotId(pick_data->snapshot_id);
-	setPosGlobal(pick_data->pos_global);
-	setPickLocation(createLocationText(LLStringUtil::null, pick_data->name,
-			pick_data->sim_name, pick_data->pos_global));
-}
-
-BOOL LLPanelPickEdit::postBuild()
-{
-	LLPanelPickInfo::postBuild();
-
-	mSnapshotCtrl->setCommitCallback(boost::bind(&LLPanelPickEdit::onSnapshotChanged, this));
-
-	LLLineEditor* line_edit = getChild<LLLineEditor>("pick_name");
-	line_edit->setKeystrokeCallback(boost::bind(&LLPanelPickEdit::onPickChanged, this, _1), NULL);
-
-	LLTextEditor* text_edit = getChild<LLTextEditor>("pick_desc");
-	text_edit->setKeystrokeCallback(boost::bind(&LLPanelPickEdit::onPickChanged, this, _1));
-
-	childSetAction(XML_BTN_SAVE, boost::bind(&LLPanelPickEdit::onClickSave, this));
-	childSetAction("set_to_curr_location_btn", boost::bind(&LLPanelPickEdit::onClickSetLocation, this));
-
-	initTexturePickerMouseEvents();
-
-	return TRUE;
-}
-
-void LLPanelPickEdit::setSaveCallback(const commit_callback_t& cb)
-{
-	getChild<LLButton>("save_changes_btn")->setClickedCallback(cb);
-}
-
-void LLPanelPickEdit::setCancelCallback(const commit_callback_t& cb)
-{
-	getChild<LLButton>("cancel_btn")->setClickedCallback(cb);
-}
-
-void LLPanelPickEdit::resetDirty()
-{
-	LLPanelPickInfo::resetDirty();
-
-	getChild<LLLineEditor>("pick_name")->resetDirty();
-	getChild<LLTextEditor>("pick_desc")->resetDirty();
-	mSnapshotCtrl->resetDirty();
-	mLocationChanged = false;
-}
-
-BOOL LLPanelPickEdit::isDirty() const
-{
-	if( mNewPick
-		|| LLPanelPickInfo::isDirty()
-		|| mLocationChanged
-		|| mSnapshotCtrl->isDirty()
-		|| getChild<LLLineEditor>("pick_name")->isDirty()
-		|| getChild<LLTextEditor>("pick_desc")->isDirty())
-	{
-		return TRUE;
-	}
-	return FALSE;
-}
-
-// PROTECTED AREA
-
-void LLPanelPickEdit::sendUpdate()
-{
-	LLPickData pick_data;
-
-	// If we don't have a pick id yet, we'll need to generate one,
-	// otherwise we'll keep overwriting pick_id 00000 in the database.
-	if (getPickId().isNull()) 
-	{
-		getPickId().generate();
-	}
-
-	pick_data.agent_id = gAgent.getID();
-	pick_data.session_id = gAgent.getSessionID();
-	pick_data.pick_id = getPickId();
-	pick_data.creator_id = gAgent.getID();;
-
-	//legacy var  need to be deleted
-	pick_data.top_pick = FALSE; 
-	pick_data.parcel_id = mParcelId;
-	pick_data.name = getChild<LLUICtrl>(XML_NAME)->getValue().asString();
-	pick_data.desc = getChild<LLUICtrl>(XML_DESC)->getValue().asString();
-	pick_data.snapshot_id = mSnapshotCtrl->getImageAssetID();
-	pick_data.pos_global = getPosGlobal();
-	pick_data.sort_order = 0;
-	pick_data.enabled = TRUE;
-
-	LLAvatarPropertiesProcessor::instance().sendPickInfoUpdate(&pick_data);
-
-	if(mNewPick)
-	{
-		// Assume a successful create pick operation, make new number of picks
-		// available immediately. Actual number of picks will be requested in 
-		// LLAvatarPropertiesProcessor::sendPickInfoUpdate and updated upon server respond.
-		LLAgentPicksInfo::getInstance()->incrementNumberOfPicks();
-	}
-}
-
-void LLPanelPickEdit::onSnapshotChanged()
-{
-	enableSaveButton(true);
-}
-
-void LLPanelPickEdit::onPickChanged(LLUICtrl* ctrl)
-{
-	enableSaveButton(isDirty());
-}
-
-void LLPanelPickEdit::resetData()
-{
-	LLPanelPickInfo::resetData();
-	mLocationChanged = false;
-}
-
-void LLPanelPickEdit::enableSaveButton(bool enable)
-{
-	getChildView(XML_BTN_SAVE)->setEnabled(enable);
-}
-
-void LLPanelPickEdit::onClickSetLocation()
-{
-	// Save location for later use.
-	setPosGlobal(gAgent.getPositionGlobal());
-
-	std::string parcel_name, region_name;
-
-	LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel();
-	if (parcel)
-	{
-		mParcelId = parcel->getID();
-		parcel_name = parcel->getName();
-	}
-
-	LLViewerRegion* region = gAgent.getRegion();
-	if(region)
-	{
-		region_name = region->getName();
-	}
-
-	setPickLocation(createLocationText(getLocationNotice(), parcel_name, region_name, getPosGlobal()));
-
-	mLocationChanged = true;
-	enableSaveButton(TRUE);
-}
-
-void LLPanelPickEdit::onClickSave()
-{
-	sendUpdate();
-
-	mLocationChanged = false;
-
-	LLSD params;
-	params["action"] = "save_new_pick";
-	notifyParent(params);
-}
-
-std::string LLPanelPickEdit::getLocationNotice()
-{
-	static std::string notice = getString("location_notice");
-	return notice;
-}
-
-void LLPanelPickEdit::processProperties(void* data, EAvatarProcessorType type)
-{
-	if(mNeedData)
-	{
-		LLPanelPickInfo::processProperties(data, type);
-	}
-}
-
-// PRIVATE AREA
-
-void LLPanelPickEdit::initTexturePickerMouseEvents()
-{
-	text_icon = getChild<LLIconCtrl>(XML_BTN_ON_TXTR);
-	mSnapshotCtrl->setMouseEnterCallback(boost::bind(&LLPanelPickEdit::onTexturePickerMouseEnter, this, _1));
-	mSnapshotCtrl->setMouseLeaveCallback(boost::bind(&LLPanelPickEdit::onTexturePickerMouseLeave, this, _1));
-	
-	text_icon->setVisible(FALSE);
-}
-		
-void LLPanelPickEdit::onTexturePickerMouseEnter(LLUICtrl* ctrl)
-{
-        text_icon->setVisible(TRUE);
-}
-
-void LLPanelPickEdit::onTexturePickerMouseLeave(LLUICtrl* ctrl)
-{
-	text_icon->setVisible(FALSE);
-}
diff --git a/indra/newview/llpanelpick.h b/indra/newview/llpanelpick.h
deleted file mode 100644
index 7a8bd66fcfe2420a503b3be2b8a107339ed9a62e..0000000000000000000000000000000000000000
--- a/indra/newview/llpanelpick.h
+++ /dev/null
@@ -1,264 +0,0 @@
-/** 
- * @file llpanelpick.h
- * @brief LLPanelPick class definition
- *
- * $LicenseInfo:firstyear=2004&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- * 
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- * 
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
- * $/LicenseInfo$
- */
-
-// Display of a "Top Pick" used both for the global top picks in the 
-// Find directory, and also for each individual user's picks in their
-// profile.
-
-#ifndef LL_LLPANELPICK_H
-#define LL_LLPANELPICK_H
-
-#include "llpanel.h"
-#include "llremoteparcelrequest.h"
-#include "llavatarpropertiesprocessor.h"
-
-class LLIconCtrl;
-class LLTextureCtrl;
-class LLScrollContainer;
-class LLMessageSystem;
-class LLAvatarPropertiesObserver;
-
-/**
- * Panel for displaying Pick Information - snapshot, name, description, etc.
- */
-class LLPanelPickInfo : public LLPanel, public LLAvatarPropertiesObserver, LLRemoteParcelInfoObserver
-{
-	LOG_CLASS(LLPanelPickInfo);
-public:
-	
-	// Creates new panel
-	static LLPanelPickInfo* create();
-
-	virtual ~LLPanelPickInfo();
-
-	/**
-	 * Initializes panel properties
-	 *
-	 * By default Pick will be created for current Agent location.
-	 * Use setPickData to change Pick properties.
-	 */
-	/*virtual*/ void onOpen(const LLSD& key);
-
-	/*virtual*/ BOOL postBuild();
-
-	/*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE);
-
-	/*virtual*/ void processProperties(void* data, EAvatarProcessorType type);
-
-	/**
-	 * Sends remote parcel info request to resolve parcel name from its ID.
-	 */
-	void sendParcelInfoRequest();
-
-	/**
-	 * Sets "Back" button click callback
-	 */
-	virtual void setExitCallback(const commit_callback_t& cb);
-
-	/**
-	 * Sets "Edit" button click callback
-	 */
-	virtual void setEditPickCallback(const commit_callback_t& cb);
-
-	//This stuff we got from LLRemoteParcelObserver, in the last one we intentionally do nothing
-	/*virtual*/ void processParcelInfo(const LLParcelData& parcel_data);
-	/*virtual*/ void setParcelID(const LLUUID& parcel_id) { mParcelId = parcel_id; }
-	/*virtual*/ void setErrorStatus(S32 status, const std::string& reason) {};
-
-protected:
-
-	LLPanelPickInfo();
-	
-	/**
-	 * Resets Pick information
-	 */
-	virtual void resetData();
-
-	/**
-	 * Resets UI controls (visibility, values)
-	 */
-	virtual void resetControls();
-
-	/** 
-	* "Location text" is actually the owner name, the original
-	* name that owner gave the parcel, and the location.
-	*/
-	static std::string createLocationText(
-		const std::string& owner_name, 
-		const std::string& original_name,
-		const std::string& sim_name, 
-		const LLVector3d& pos_global);
-
-	virtual void setAvatarId(const LLUUID& avatar_id) { mAvatarId = avatar_id; }
-	virtual LLUUID& getAvatarId() { return mAvatarId; }
-
-	/**
-	 * Sets snapshot id.
-	 *
-	 * Will mark snapshot control as valid if id is not null.
-	 * Will mark snapshot control as invalid if id is null. If null id is a valid value,
-	 * you have to manually mark snapshot is valid.
-	 */
-	virtual void setSnapshotId(const LLUUID& id);
-	
-	virtual void setPickId(const LLUUID& id) { mPickId = id; }
-	virtual LLUUID& getPickId() { return mPickId; }
-	
-	virtual void setPickName(const std::string& name);
-	
-	virtual void setPickDesc(const std::string& desc);
-	
-	virtual void setPickLocation(const std::string& location);
-	
-	virtual void setPosGlobal(const LLVector3d& pos) { mPosGlobal = pos; }
-	virtual LLVector3d& getPosGlobal() { return mPosGlobal; }
-
-	/**
-	 * Callback for "Map" button, opens Map
-	 */
-	void onClickMap();
-
-	/**
-	 * Callback for "Teleport" button, teleports user to Pick location.
-	 */
-	void onClickTeleport();
-
-	void onClickBack();
-
-protected:
-
-	S32						mScrollingPanelMinHeight;
-	S32						mScrollingPanelWidth;
-	LLScrollContainer*		mScrollContainer;
-	LLPanel*				mScrollingPanel;
-	LLTextureCtrl*			mSnapshotCtrl;
-
-	LLUUID mAvatarId;
-	LLVector3d mPosGlobal;
-	LLUUID mParcelId;
-	LLUUID mPickId;
-	LLUUID mRequestedId;
-};
-
-/**
- * Panel for creating/editing Pick.
- */
-class LLPanelPickEdit : public LLPanelPickInfo
-{
-	LOG_CLASS(LLPanelPickEdit);
-public:
-
-	/**
-	 * Creates new panel
-	 */
-	static LLPanelPickEdit* create();
-
-	/*virtual*/ ~LLPanelPickEdit();
-
-	/*virtual*/ void onOpen(const LLSD& key);
-
-	virtual void setPickData(const LLPickData* pick_data);
-
-	/*virtual*/ BOOL postBuild();
-
-	/**
-	 * Sets "Save" button click callback
-	 */
-	virtual void setSaveCallback(const commit_callback_t& cb);
-
-	/**
-	 * Sets "Cancel" button click callback
-	 */
-	virtual void setCancelCallback(const commit_callback_t& cb);
-
-	/**
-	 * Resets panel and all cantrols to unedited state
-	 */
-	/*virtual*/ void resetDirty();
-
-	/**
-	 * Returns true if any of Pick properties was changed by user.
-	 */
-	/*virtual*/ BOOL isDirty() const;
-
-	/*virtual*/ void processProperties(void* data, EAvatarProcessorType type);
-
-protected:
-
-	LLPanelPickEdit();
-
-	/**
-	 * Sends Pick properties to server.
-	 */
-	void sendUpdate();
-
-	/**
-	 * Called when snapshot image changes.
-	 */
-	void onSnapshotChanged();
-	
-	/**
-	 * Callback for Pick snapshot, name and description changed event.
-	 */
-	void onPickChanged(LLUICtrl* ctrl);
-
-	/*virtual*/ void resetData();
-
-	/**
-	 * Enables/disables "Save" button
-	 */
-	void enableSaveButton(bool enable);
-
-	/**
-	 * Callback for "Set Location" button click
-	 */
-	void onClickSetLocation();
-
-	/**
-	 * Callback for "Save" button click
-	 */
-	void onClickSave();
-
-	std::string getLocationNotice();
-
-protected:
-
-	bool mLocationChanged;
-	bool mNeedData;
-	bool mNewPick;
-
-private:
-
-	void initTexturePickerMouseEvents();
-        void onTexturePickerMouseEnter(LLUICtrl* ctrl);
-	void onTexturePickerMouseLeave(LLUICtrl* ctrl);
-
-private:
-
-	LLIconCtrl* text_icon;
-};
-
-#endif // LL_LLPANELPICK_H
diff --git a/indra/newview/llpanelpicks.cpp b/indra/newview/llpanelpicks.cpp
deleted file mode 100644
index 8294977f9940f6003d884bf8b26715bd55500bac..0000000000000000000000000000000000000000
--- a/indra/newview/llpanelpicks.cpp
+++ /dev/null
@@ -1,1484 +0,0 @@
-/** 
- * @file llpanelpicks.cpp
- * @brief LLPanelPicks and related class implementations
- *
- * $LicenseInfo:firstyear=2009&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- * 
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- * 
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
- * $/LicenseInfo$
- */
-
-#include "llviewerprecompiledheaders.h"
-
-#include "llpanelpicks.h"
-
-#include "llagent.h"
-#include "llagentpicksinfo.h"
-#include "llcommandhandler.h"
-#include "lldispatcher.h"
-#include "llflatlistview.h"
-#include "llfloaterreg.h"
-#include "llfloatersidepanelcontainer.h"
-#include "llfloaterworldmap.h"
-#include "llnotificationsutil.h"
-#include "llstartup.h"
-#include "lltexturectrl.h"
-#include "lltoggleablemenu.h"
-#include "lltrans.h"
-#include "llviewergenericmessage.h"	// send_generic_message
-#include "llmenugl.h"
-#include "llviewermenu.h"
-#include "llregistry.h"
-
-#include "llaccordionctrl.h"
-#include "llaccordionctrltab.h"
-#include "llavatarpropertiesprocessor.h"
-#include "llfloatersidepanelcontainer.h"
-#include "llpanelavatar.h"
-#include "llpanelprofile.h"
-#include "llpanelpick.h"
-#include "llpanelclassified.h"
-
-static const std::string XML_BTN_NEW = "new_btn";
-static const std::string XML_BTN_DELETE = "trash_btn";
-static const std::string XML_BTN_INFO = "info_btn";
-static const std::string XML_BTN_TELEPORT = "teleport_btn";
-static const std::string XML_BTN_SHOW_ON_MAP = "show_on_map_btn";
-
-static const std::string PICK_ID("pick_id");
-static const std::string PICK_CREATOR_ID("pick_creator_id");
-static const std::string PICK_NAME("pick_name");
-
-static const std::string CLASSIFIED_ID("classified_id");
-static const std::string CLASSIFIED_NAME("classified_name");
-
-
-static LLPanelInjector<LLPanelPicks> t_panel_picks("panel_picks");
-
-
-class LLPickHandler : public LLCommandHandler,
-					  public LLAvatarPropertiesObserver
-{
-public:
-
-	std::set<LLUUID> mPickIds;
-	
-	// requires trusted browser to trigger
-	LLPickHandler() : LLCommandHandler("pick", UNTRUSTED_THROTTLE) { }
-
-	bool handle(const LLSD& params, const LLSD& query_map,
-		LLMediaCtrl* web)
-	{
-		if (LLStartUp::getStartupState() < STATE_STARTED)
-		{
-			return true;
-		}
-
-		if (!LLUI::getInstance()->mSettingGroups["config"]->getBOOL("EnablePicks"))
-		{
-			LLNotificationsUtil::add("NoPicks", LLSD(), LLSD(), std::string("SwitchToStandardSkinAndQuit"));
-			return true;
-		}
-
-		// handle app/classified/create urls first
-		if (params.size() == 1 && params[0].asString() == "create")
-		{
-			createPick();
-			return true;
-		}
-
-		// then handle the general app/pick/{UUID}/{CMD} urls
-		if (params.size() < 2)
-		{
-			return false;
-		}
-
-		// get the ID for the pick_id
-		LLUUID pick_id;
-		if (!pick_id.set(params[0], FALSE))
-		{
-			return false;
-		}
-
-		// edit the pick in the side tray.
-		// need to ask the server for more info first though...
-		const std::string verb = params[1].asString();
-		if (verb == "edit")
-		{		
-			mPickIds.insert(pick_id);
-			LLAvatarPropertiesProcessor::getInstance()->addObserver(LLUUID(), this);
-			LLAvatarPropertiesProcessor::getInstance()->sendPickInfoRequest(gAgent.getID(),pick_id);
-			return true;
-		}
-		else
-		{
-			LL_WARNS() << "unknown verb " << verb << LL_ENDL;
-			return false;
-		}
-	}
-
-	void createPick()
-	{
-		// open the new pick panel on the Picks floater
-		LLFloater* picks_floater = LLFloaterReg::showInstance("picks");
-
-		LLPanelPicks* picks = picks_floater->findChild<LLPanelPicks>("panel_picks");
-		if (picks)
-		{
-			picks->createNewPick();
-		}
-	}
-
-	void editPick(LLPickData* pick_info)
-	{
-		LLSD params;
-		params["open_tab_name"] = "panel_picks";
-		params["show_tab_panel"] = "edit_pick";
-		params["pick_id"] = pick_info->pick_id;
-		params["avatar_id"] = pick_info->creator_id;
-		params["snapshot_id"] = pick_info->snapshot_id;
-		params["pick_name"] = pick_info->name;
-		params["pick_desc"] = pick_info->desc;
-		LLFloaterSidePanelContainer::showPanel("picks", params);
-	}
-	
-	/*virtual*/ void processProperties(void* data, EAvatarProcessorType type)
-	{
-		if (APT_PICK_INFO != type)
-		{
-			return;
-		}
-
-		// is this the pick that we asked for?
-		LLPickData* pick_info = static_cast<LLPickData*>(data);
-		if (!pick_info || mPickIds.find(pick_info->pick_id) == mPickIds.end())
-		{
-			return;
-		}
-
-		// open the edit side tray for this pick
-		if (pick_info->creator_id == gAgent.getID())
-		{
-			editPick(pick_info);
-		}
-		else
-		{
-			LL_WARNS() << "Can't edit a pick you did not create" << LL_ENDL;
-		}
-
-		// remove our observer now that we're done
-		mPickIds.erase(pick_info->pick_id);
-		LLAvatarPropertiesProcessor::getInstance()->removeObserver(LLUUID(), this);
-	}
-};
-
-LLPickHandler gPickHandler;
-
-class LLClassifiedHandler :
-	public LLCommandHandler,
-	public LLAvatarPropertiesObserver
-{
-public:
-	// throttle calls from untrusted browsers
-	LLClassifiedHandler() :	LLCommandHandler("classified", UNTRUSTED_THROTTLE) {}
-
-	std::set<LLUUID> mClassifiedIds;
-
-	std::string mRequestVerb;
-	
-	bool handle(const LLSD& params, const LLSD& query_map, LLMediaCtrl* web)
-	{
-		if (LLStartUp::getStartupState() < STATE_STARTED)
-		{
-			return true;
-		}
-
-		if (!LLUI::getInstance()->mSettingGroups["config"]->getBOOL("EnableClassifieds"))
-		{
-			LLNotificationsUtil::add("NoClassifieds", LLSD(), LLSD(), std::string("SwitchToStandardSkinAndQuit"));
-			return true;
-		}
-
-		// handle app/classified/create urls first
-		if (params.size() == 1 && params[0].asString() == "create")
-		{
-			createClassified();
-			return true;
-		}
-
-		// then handle the general app/classified/{UUID}/{CMD} urls
-		if (params.size() < 2)
-		{
-			return false;
-		}
-
-		// get the ID for the classified
-		LLUUID classified_id;
-		if (!classified_id.set(params[0], FALSE))
-		{
-			return false;
-		}
-
-		// show the classified in the side tray.
-		// need to ask the server for more info first though...
-		const std::string verb = params[1].asString();
-		if (verb == "about")
-		{
-			mRequestVerb = verb;
-			mClassifiedIds.insert(classified_id);
-			LLAvatarPropertiesProcessor::getInstance()->addObserver(LLUUID(), this);
-			LLAvatarPropertiesProcessor::getInstance()->sendClassifiedInfoRequest(classified_id);
-			return true;
-		}
-		else if (verb == "edit")
-		{
-			mRequestVerb = verb;
-			mClassifiedIds.insert(classified_id);
-			LLAvatarPropertiesProcessor::getInstance()->addObserver(LLUUID(), this);
-			LLAvatarPropertiesProcessor::getInstance()->sendClassifiedInfoRequest(classified_id);
-			return true;
-		}
-
-		return false;
-	}
-
-	void createClassified()
-	{
-		// open the new classified panel on the Picks floater
-		LLFloater* picks_floater = LLFloaterReg::showInstance("picks");
-
-		LLPanelPicks* picks = picks_floater->findChild<LLPanelPicks>("panel_picks");
-		if (picks)
-		{
-			picks->createNewClassified();
-		}
-	}
-
-	void openClassified(LLAvatarClassifiedInfo* c_info)
-	{
-		if (mRequestVerb == "about")
-		{
-			// open the classified info panel on the Me > Picks sidetray
-			LLSD params;
-			params["id"] = c_info->creator_id;
-			params["open_tab_name"] = "panel_picks";
-			params["show_tab_panel"] = "classified_details";
-			params["classified_id"] = c_info->classified_id;
-			params["classified_creator_id"] = c_info->creator_id;
-			params["classified_snapshot_id"] = c_info->snapshot_id;
-			params["classified_name"] = c_info->name;
-			params["classified_desc"] = c_info->description;
-			params["from_search"] = true;
-			LLFloaterSidePanelContainer::showPanel("picks", params);
-		}
-		else if (mRequestVerb == "edit")
-		{
-			if (c_info->creator_id == gAgent.getID())
-			{
-				LL_WARNS() << "edit in progress" << LL_ENDL;
-				// open the new classified panel on the Me > Picks sidetray
-				LLSD params;
-				params["id"] = gAgent.getID();
-				params["open_tab_name"] = "panel_picks";
-				params["show_tab_panel"] = "edit_classified";
-				params["classified_id"] = c_info->classified_id;
-				LLFloaterSidePanelContainer::showPanel("my_profile", params);
-			}
-			else
-			{
-				LL_WARNS() << "Can't edit a classified you did not create" << LL_ENDL;
-			}
-		}
-	}
-
-	/*virtual*/ void processProperties(void* data, EAvatarProcessorType type)
-	{
-		if (APT_CLASSIFIED_INFO != type)
-		{
-			return;
-		}
-
-		// is this the classified that we asked for?
-		LLAvatarClassifiedInfo* c_info = static_cast<LLAvatarClassifiedInfo*>(data);
-		if (!c_info || mClassifiedIds.find(c_info->classified_id) == mClassifiedIds.end())
-		{
-			return;
-		}
-
-		// open the detail side tray for this classified
-		openClassified(c_info);
-
-		// remove our observer now that we're done
-		mClassifiedIds.erase(c_info->classified_id);
-		LLAvatarPropertiesProcessor::getInstance()->removeObserver(LLUUID(), this);
-	}
-
-};
-LLClassifiedHandler gClassifiedHandler;
-
-//////////////////////////////////////////////////////////////////////////
-
-
-//-----------------------------------------------------------------------------
-// LLPanelPicks
-//-----------------------------------------------------------------------------
-LLPanelPicks::LLPanelPicks()
-:	LLPanelProfileTab(),
-	mPopupMenu(NULL),
-	mProfilePanel(NULL),
-	mPickPanel(NULL),
-	mPicksList(NULL),
-	mClassifiedsList(NULL),
-	mPanelPickInfo(NULL),
-	mPanelPickEdit(NULL),
-	mPlusMenu(NULL),
-	mPicksAccTab(NULL),
-	mClassifiedsAccTab(NULL),
-	mPanelClassifiedInfo(NULL),
-	mNoClassifieds(false),
-	mNoPicks(false)
-{
-}
-
-LLPanelPicks::~LLPanelPicks()
-{
-	if(getAvatarId().notNull())
-	{
-		LLAvatarPropertiesProcessor::getInstance()->removeObserver(getAvatarId(),this);
-	}
-}
-
-void* LLPanelPicks::create(void* data /* = NULL */)
-{
-	return new LLPanelPicks();
-}
-
-void LLPanelPicks::updateData()
-{
-	// Send Picks request only when we need to, not on every onOpen(during tab switch).
-	if(isDirty())
-	{
-		mNoPicks = false;
-		mNoClassifieds = false;
-
-		mNoItemsLabel->setValue(LLTrans::getString("PicksClassifiedsLoadingText"));
-		mNoItemsLabel->setVisible(TRUE);
-
-		mPicksList->clear();
-		LLAvatarPropertiesProcessor::getInstance()->sendAvatarPicksRequest(getAvatarId());
-
-		mClassifiedsList->clear();
-		LLAvatarPropertiesProcessor::getInstance()->sendAvatarClassifiedsRequest(getAvatarId());
-	}
-}
-
-void LLPanelPicks::processProperties(void* data, EAvatarProcessorType type)
-{
-	if(APT_PICKS == type)
-	{
-		LLAvatarPicks* avatar_picks = static_cast<LLAvatarPicks*>(data);
-		if(avatar_picks && getAvatarId() == avatar_picks->target_id)
-		{
-			LLAvatarName av_name;
-			LLAvatarNameCache::get(getAvatarId(), &av_name);
-			getChild<LLUICtrl>("pick_title")->setTextArg("[NAME]", av_name.getUserName());
-			
-			// Save selection, to be able to edit same item after saving changes. See EXT-3023.
-			LLUUID selected_id = mPicksList->getSelectedValue()[PICK_ID];
-
-			mPicksList->clear();
-
-			LLAvatarPicks::picks_list_t::const_iterator it = avatar_picks->picks_list.begin();
-			for(; avatar_picks->picks_list.end() != it; ++it)
-			{
-				LLUUID pick_id = it->first;
-				std::string pick_name = it->second;
-
-				LLPickItem* picture = LLPickItem::create();
-				picture->childSetAction("info_chevron", boost::bind(&LLPanelPicks::onClickInfo, this));
-				picture->setPickName(pick_name);
-				picture->setPickId(pick_id);
-				picture->setCreatorId(getAvatarId());
-
-				LLAvatarPropertiesProcessor::instance().addObserver(getAvatarId(), picture);
-				picture->update();
-
-				LLSD pick_value = LLSD();
-				pick_value.insert(PICK_ID, pick_id);
-				pick_value.insert(PICK_NAME, pick_name);
-				pick_value.insert(PICK_CREATOR_ID, getAvatarId());
-
-				mPicksList->addItem(picture, pick_value);
-
-				// Restore selection by item id. 
-				if ( pick_id == selected_id )
-					mPicksList->selectItemByValue(pick_value);
-
-				picture->setDoubleClickCallback(boost::bind(&LLPanelPicks::onDoubleClickPickItem, this, _1));
-				picture->setRightMouseUpCallback(boost::bind(&LLPanelPicks::onRightMouseUpItem, this, _1, _2, _3, _4));
-				picture->setMouseUpCallback(boost::bind(&LLPanelPicks::updateButtons, this));
-			}
-
-			showAccordion("tab_picks", mPicksList->size());
-
-			resetDirty();
-			updateButtons();
-		}
-		
-		mNoPicks = !mPicksList->size();
-	}
-	else if((APT_CLASSIFIEDS == type) || (APT_CLASSIFIED_INFO == type))
-	{
-		LLAvatarClassifieds* c_info = static_cast<LLAvatarClassifieds*>(data);
-		if(c_info && getAvatarId() == c_info->target_id)
-		{
-			// do not clear classified list in case we will receive two or more data packets.
-			// list has been cleared in updateData(). (fix for EXT-6436)
-
-			LLAvatarClassifieds::classifieds_list_t::const_iterator it = c_info->classifieds_list.begin();
-			for(; c_info->classifieds_list.end() != it; ++it)
-			{
-				LLAvatarClassifieds::classified_data c_data = *it;
-
-				LLClassifiedItem* c_item = new LLClassifiedItem(getAvatarId(), c_data.classified_id);
-				c_item->childSetAction("info_chevron", boost::bind(&LLPanelPicks::onClickInfo, this));
-				c_item->setClassifiedName(c_data.name);
-
-				LLSD pick_value = LLSD();
-				pick_value.insert(CLASSIFIED_ID, c_data.classified_id);
-				pick_value.insert(CLASSIFIED_NAME, c_data.name);
-
-				if (!findClassifiedById(c_data.classified_id))
-				{
-					mClassifiedsList->addItem(c_item, pick_value);
-				}
-
-				c_item->setDoubleClickCallback(boost::bind(&LLPanelPicks::onDoubleClickClassifiedItem, this, _1));
-				c_item->setRightMouseUpCallback(boost::bind(&LLPanelPicks::onRightMouseUpItem, this, _1, _2, _3, _4));
-				c_item->setMouseUpCallback(boost::bind(&LLPanelPicks::updateButtons, this));
-			}
-
-			showAccordion("tab_classifieds", mClassifiedsList->size());
-
-			resetDirty();
-			updateButtons();
-		}
-		
-		mNoClassifieds = !mClassifiedsList->size();
-	}
-
-    updateNoItemsLabel();
-}
-
-LLPickItem* LLPanelPicks::getSelectedPickItem()
-{
-	LLPanel* selected_item = mPicksList->getSelectedItem();
-	if (!selected_item) return NULL;
-
-	return dynamic_cast<LLPickItem*>(selected_item);
-}
-
-LLClassifiedItem* LLPanelPicks::getSelectedClassifiedItem()
-{
-	LLPanel* selected_item = mClassifiedsList->getSelectedItem();
-	if (!selected_item) 
-	{
-		return NULL;
-	}
-	return dynamic_cast<LLClassifiedItem*>(selected_item);
-}
-
-BOOL LLPanelPicks::postBuild()
-{
-	mPicksList = getChild<LLFlatListView>("picks_list");
-	mClassifiedsList = getChild<LLFlatListView>("classifieds_list");
-
-	mPicksList->setCommitOnSelectionChange(true);
-	mClassifiedsList->setCommitOnSelectionChange(true);
-
-	mPicksList->setCommitCallback(boost::bind(&LLPanelPicks::onListCommit, this, mPicksList));
-	mClassifiedsList->setCommitCallback(boost::bind(&LLPanelPicks::onListCommit, this, mClassifiedsList));
-
-	mPicksList->setNoItemsCommentText(getString("no_picks"));
-	mClassifiedsList->setNoItemsCommentText(getString("no_classifieds"));
-
-	mNoItemsLabel = getChild<LLUICtrl>("picks_panel_text");
-
-	childSetAction(XML_BTN_NEW, boost::bind(&LLPanelPicks::onClickPlusBtn, this));
-	childSetAction(XML_BTN_DELETE, boost::bind(&LLPanelPicks::onClickDelete, this));
-	childSetAction(XML_BTN_TELEPORT, boost::bind(&LLPanelPicks::onClickTeleport, this));
-	childSetAction(XML_BTN_SHOW_ON_MAP, boost::bind(&LLPanelPicks::onClickMap, this));
-	childSetAction(XML_BTN_INFO, boost::bind(&LLPanelPicks::onClickInfo, this));
-
-	mPicksAccTab = getChild<LLAccordionCtrlTab>("tab_picks");
-	mPicksAccTab->setDropDownStateChangedCallback(boost::bind(&LLPanelPicks::onAccordionStateChanged, this, mPicksAccTab));
-	mPicksAccTab->setDisplayChildren(true);
-
-	mClassifiedsAccTab = getChild<LLAccordionCtrlTab>("tab_classifieds");
-	mClassifiedsAccTab->setDropDownStateChangedCallback(boost::bind(&LLPanelPicks::onAccordionStateChanged, this, mClassifiedsAccTab));
-	mClassifiedsAccTab->setDisplayChildren(false);
-	
-	LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registar;
-	registar.add("Pick.Info", boost::bind(&LLPanelPicks::onClickInfo, this));
-	registar.add("Pick.Edit", boost::bind(&LLPanelPicks::onClickMenuEdit, this)); 
-	registar.add("Pick.Teleport", boost::bind(&LLPanelPicks::onClickTeleport, this));
-	registar.add("Pick.Map", boost::bind(&LLPanelPicks::onClickMap, this));
-	registar.add("Pick.Delete", boost::bind(&LLPanelPicks::onClickDelete, this));
-	LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registar;
-	enable_registar.add("Pick.Enable", boost::bind(&LLPanelPicks::onEnableMenuItem, this, _2));
-
-	mPopupMenu = LLUICtrlFactory::getInstance()->createFromFile<LLContextMenu>("menu_picks.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
-
-	LLUICtrl::CommitCallbackRegistry::ScopedRegistrar plus_registar;
-	plus_registar.add("Picks.Plus.Action", boost::bind(&LLPanelPicks::onPlusMenuItemClicked, this, _2));
-	mEnableCallbackRegistrar.add("Picks.Plus.Enable", boost::bind(&LLPanelPicks::isActionEnabled, this, _2));
-	mPlusMenu = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>("menu_picks_plus.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
-	
-	return TRUE;
-}
-
-void LLPanelPicks::onPlusMenuItemClicked(const LLSD& param)
-{
-	std::string value = param.asString();
-
-	if("new_pick" == value)
-	{
-		createNewPick();
-	}
-	else if("new_classified" == value)
-	{
-		createNewClassified();
-	}
-}
-
-bool LLPanelPicks::isActionEnabled(const LLSD& userdata) const
-{
-	std::string command_name = userdata.asString();
-
-	if (command_name == "new_pick" && LLAgentPicksInfo::getInstance()->isPickLimitReached())
-	{
-		return false;
-	}
-
-	return true;
-}
-
-bool LLPanelPicks::isClassifiedPublished(LLClassifiedItem* c_item)
-{
-	if(c_item)
-	{
-		LLPanelClassifiedEdit* panel = mEditClassifiedPanels[c_item->getClassifiedId()];
-		if(panel)
-		{
-			 return !panel->isNewWithErrors();
-		}
-
-		// we've got this classified from server - it's published
-		return true;
-	}
-	return false;
-}
-
-void LLPanelPicks::onAccordionStateChanged(const LLAccordionCtrlTab* acc_tab)
-{
-	if(!mPicksAccTab->getDisplayChildren())
-	{
-		mPicksList->resetSelection(true);
-	}
-	if(!mClassifiedsAccTab->getDisplayChildren())
-	{
-		mClassifiedsList->resetSelection(true);
-	}
-
-	updateButtons();
-}
-
-void LLPanelPicks::onOpen(const LLSD& key)
-{
-	const LLUUID id(key.asUUID());
-	BOOL self = (gAgent.getID() == id);
-
-	// only agent can edit her picks 
-	getChildView("edit_panel")->setEnabled(self);
-	getChildView("edit_panel")->setVisible( self);
-
-	// Disable buttons when viewing profile for first time
-	if(getAvatarId() != id)
-	{
-		getChildView(XML_BTN_INFO)->setEnabled(FALSE);
-		getChildView(XML_BTN_TELEPORT)->setEnabled(FALSE);
-		getChildView(XML_BTN_SHOW_ON_MAP)->setEnabled(FALSE);
-	}
-
-	// and see a special title - set as invisible by default in xml file
-	if (self)
-	{
-		getChildView("pick_title")->setVisible( !self);
-		getChildView("pick_title_agent")->setVisible( self);
-
-		mPopupMenu->setItemVisible("pick_delete", TRUE);
-		mPopupMenu->setItemVisible("pick_edit", TRUE);
-		mPopupMenu->setItemVisible("pick_separator", TRUE);
-	}
-
-	if(getAvatarId() != id)
-	{
-		showAccordion("tab_picks", false);
-		showAccordion("tab_classifieds", false);
-
-		mPicksList->goToTop();
-		// Set dummy value to make panel dirty and make it reload picks
-		setValue(LLSD());
-	}
-
-	LLPanelProfileTab::onOpen(key);
-}
-
-void LLPanelPicks::onClosePanel()
-{
-	if (mPanelClassifiedInfo)
-	{
-		onPanelClassifiedClose(mPanelClassifiedInfo);
-	}
-	if (mPanelPickInfo)
-	{
-		onPanelPickClose(mPanelPickInfo);
-	}
-}
-
-void LLPanelPicks::onListCommit(const LLFlatListView* f_list)
-{
-	// Make sure only one of the lists has selection.
-	if(f_list == mPicksList)
-	{
-		mClassifiedsList->resetSelection(true);
-	}
-	else if(f_list == mClassifiedsList)
-	{
-		mPicksList->resetSelection(true);
-	}
-	else
-	{
-		LL_WARNS() << "Unknown list" << LL_ENDL;
-	}
-
-	updateButtons();
-}
-
-//static
-void LLPanelPicks::onClickDelete()
-{
-	LLSD value = mPicksList->getSelectedValue();
-	if (value.isDefined())
-	{
-		LLSD args; 
-		args["PICK"] = value[PICK_NAME]; 
-		LLNotificationsUtil::add("DeleteAvatarPick", args, LLSD(), boost::bind(&LLPanelPicks::callbackDeletePick, this, _1, _2)); 
-		return;
-	}
-
-	value = mClassifiedsList->getSelectedValue();
-	if(value.isDefined())
-	{
-		LLSD args; 
-		args["NAME"] = value[CLASSIFIED_NAME]; 
-		LLNotificationsUtil::add("DeleteClassified", args, LLSD(), boost::bind(&LLPanelPicks::callbackDeleteClassified, this, _1, _2)); 
-		return;
-	}
-}
-
-bool LLPanelPicks::callbackDeletePick(const LLSD& notification, const LLSD& response) 
-{
-	S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
-	LLSD pick_value = mPicksList->getSelectedValue();
-
-	if (0 == option)
-	{
-		LLAvatarPropertiesProcessor::instance().sendPickDelete(pick_value[PICK_ID]);
-		mPicksList->removeItemByValue(pick_value);
-        
-        mNoPicks = !mPicksList->size();
-        if (mNoPicks)
-        {
-            showAccordion("tab_picks", false);
-        }
-        updateNoItemsLabel();
-	}
-	updateButtons();
-	return false;
-}
-
-bool LLPanelPicks::callbackDeleteClassified(const LLSD& notification, const LLSD& response) 
-{
-	S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
-	LLSD value = mClassifiedsList->getSelectedValue();
-
-	if (0 == option)
-	{
-		LLAvatarPropertiesProcessor::instance().sendClassifiedDelete(value[CLASSIFIED_ID]);
-		mClassifiedsList->removeItemByValue(value);
-
-        mNoClassifieds = !mClassifiedsList->size();
-        if (mNoClassifieds)
-        {
-            showAccordion("tab_classifieds", false);
-        }
-        updateNoItemsLabel();
-	}
-	updateButtons();
-	return false;
-}
-
-bool LLPanelPicks::callbackTeleport( const LLSD& notification, const LLSD& response )
-{
-	S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
-
-	if (0 == option)
-	{
-		onClickTeleport();
-	}
-	return false;
-}
-
-//static
-void LLPanelPicks::onClickTeleport()
-{
-	LLPickItem* pick_item = getSelectedPickItem();
-	LLClassifiedItem* c_item = getSelectedClassifiedItem();
-
-	LLVector3d pos;
-	if(pick_item)
-		pos = pick_item->getPosGlobal();
-	else if(c_item)
-	{
-		pos = c_item->getPosGlobal();
-		LLPanelClassifiedInfo::sendClickMessage("teleport", false,
-			c_item->getClassifiedId(), LLUUID::null, pos, LLStringUtil::null);
-	}
-
-	if (!pos.isExactlyZero())
-	{
-		gAgent.teleportViaLocation(pos);
-		LLFloaterWorldMap::getInstance()->trackLocation(pos);
-	}
-}
-
-//static
-void LLPanelPicks::onClickMap()
-{
-	LLPickItem* pick_item = getSelectedPickItem();
-	LLClassifiedItem* c_item = getSelectedClassifiedItem();
-
-	LLVector3d pos;
-	if (pick_item)
-		pos = pick_item->getPosGlobal();
-	else if(c_item)
-	{
-		LLPanelClassifiedInfo::sendClickMessage("map", false,
-			c_item->getClassifiedId(), LLUUID::null, pos, LLStringUtil::null);
-		pos = c_item->getPosGlobal();
-	}
-
-	LLFloaterWorldMap::getInstance()->trackLocation(pos);
-	LLFloaterReg::showInstance("world_map", "center");
-}
-
-
-void LLPanelPicks::onRightMouseUpItem(LLUICtrl* item, S32 x, S32 y, MASK mask)
-{
-	updateButtons();
-
-	if (mPopupMenu)
-	{
-		mPopupMenu->buildDrawLabels();
-		mPopupMenu->updateParent(LLMenuGL::sMenuContainer);
-		((LLContextMenu*)mPopupMenu)->show(x, y);
-		LLMenuGL::showPopup(item, mPopupMenu, x, y);
-	}
-}
-
-void LLPanelPicks::onDoubleClickPickItem(LLUICtrl* item)
-{
-	LLSD pick_value = mPicksList->getSelectedValue();
-	if (pick_value.isUndefined()) return;
-	
-	LLSD args; 
-	args["PICK"] = pick_value[PICK_NAME]; 
-	LLNotificationsUtil::add("TeleportToPick", args, LLSD(), boost::bind(&LLPanelPicks::callbackTeleport, this, _1, _2)); 
-}
-
-void LLPanelPicks::onDoubleClickClassifiedItem(LLUICtrl* item)
-{
-	LLSD value = mClassifiedsList->getSelectedValue();
-	if (value.isUndefined()) return;
-
-	LLSD args; 
-	args["CLASSIFIED"] = value[CLASSIFIED_NAME]; 
-	LLNotificationsUtil::add("TeleportToClassified", args, LLSD(), boost::bind(&LLPanelPicks::callbackTeleport, this, _1, _2)); 
-}
-
-void LLPanelPicks::updateButtons()
-{
-	bool has_selected = mPicksList->numSelected() > 0 || mClassifiedsList->numSelected() > 0;
-
-	if (getAvatarId() == gAgentID)
-	{
-		getChildView(XML_BTN_DELETE)->setEnabled(has_selected);
-	}
-
-	getChildView(XML_BTN_INFO)->setEnabled(has_selected);
-	getChildView(XML_BTN_TELEPORT)->setEnabled(has_selected);
-	getChildView(XML_BTN_SHOW_ON_MAP)->setEnabled(has_selected);
-
-	LLClassifiedItem* c_item = dynamic_cast<LLClassifiedItem*>(mClassifiedsList->getSelectedItem());
-	if(c_item)
-	{
-		getChildView(XML_BTN_INFO)->setEnabled(isClassifiedPublished(c_item));
-	}
-}
-
-void LLPanelPicks::updateNoItemsLabel()
-{
-    bool no_data = mNoPicks && mNoClassifieds;
-    mNoItemsLabel->setVisible(no_data);
-    if (no_data)
-    {
-        if (getAvatarId() == gAgentID)
-        {
-            mNoItemsLabel->setValue(LLTrans::getString("NoPicksClassifiedsText"));
-        }
-        else
-        {
-            mNoItemsLabel->setValue(LLTrans::getString("NoAvatarPicksClassifiedsText"));
-        }
-    }
-}
-
-void LLPanelPicks::setProfilePanel(LLPanelProfile* profile_panel)
-{
-	mProfilePanel = profile_panel;
-}
-
-
-void LLPanelPicks::buildPickPanel()
-{
-// 	if (mPickPanel == NULL)
-// 	{
-// 		mPickPanel = new LLPanelPick();
-// 		mPickPanel->setExitCallback(boost::bind(&LLPanelPicks::onPanelPickClose, this, NULL));
-// 	}
-}
-
-void LLPanelPicks::onClickPlusBtn()
-{
-	LLRect rect(getChildView(XML_BTN_NEW)->getRect());
-
-	mPlusMenu->updateParent(LLMenuGL::sMenuContainer);
-	mPlusMenu->setButtonRect(rect, this);
-	LLMenuGL::showPopup(this, mPlusMenu, rect.mLeft, rect.mTop);
-}
-
-void LLPanelPicks::createNewPick()
-{
-	createPickEditPanel();
-
-	getProfilePanel()->openPanel(mPanelPickEdit, LLSD());
-}
-
-void LLPanelPicks::createNewClassified()
-{
-	LLPanelClassifiedEdit* panel = NULL;
-	createClassifiedEditPanel(&panel);
-
-	getProfilePanel()->openPanel(panel, LLSD());
-}
-
-void LLPanelPicks::onClickInfo()
-{
-	if(mPicksList->numSelected() > 0)
-	{
-		openPickInfo();
-	}
-	else if(mClassifiedsList->numSelected() > 0)
-	{
-		openClassifiedInfo();
-	}
-}
-
-void LLPanelPicks::openPickInfo()
-{
-	LLSD selected_value = mPicksList->getSelectedValue();
-	if (selected_value.isUndefined()) return;
-
-	LLPickItem* pick = (LLPickItem*)mPicksList->getSelectedItem();
-
-	createPickInfoPanel();
-
-	LLSD params;
-	params["pick_id"] = pick->getPickId();
-	params["avatar_id"] = pick->getCreatorId();
-	params["snapshot_id"] = pick->getSnapshotId();
-	params["pick_name"] = pick->getPickName();
-	params["pick_desc"] = pick->getPickDesc();
-
-	getProfilePanel()->openPanel(mPanelPickInfo, params);
-}
-
-void LLPanelPicks::openClassifiedInfo()
-{
-	LLSD selected_value = mClassifiedsList->getSelectedValue();
-	if (selected_value.isUndefined()) return;
-
-	LLClassifiedItem* c_item = getSelectedClassifiedItem();
-	LLSD params;
-	params["classified_id"] = c_item->getClassifiedId();
-	params["classified_creator_id"] = c_item->getAvatarId();
-	params["classified_snapshot_id"] = c_item->getSnapshotId();
-	params["classified_name"] = c_item->getClassifiedName();
-	params["classified_desc"] = c_item->getDescription();
-	params["from_search"] = false;
-
-	openClassifiedInfo(params);
-}
-
-void LLPanelPicks::openClassifiedInfo(const LLSD &params)
-{
-	createClassifiedInfoPanel();
-	getProfilePanel()->openPanel(mPanelClassifiedInfo, params);
-}
-
-void LLPanelPicks::openClassifiedEdit(const LLSD& params)
-{
-	LLUUID classified_id = params["classified_id"].asUUID();;
-	LL_INFOS() << "opening classified " << classified_id << " for edit" << LL_ENDL;
-	editClassified(classified_id);
-}
-
-void LLPanelPicks::showAccordion(const std::string& name, bool show)
-{
-	LLAccordionCtrlTab* tab = getChild<LLAccordionCtrlTab>(name);
-	tab->setVisible(show);
-	LLAccordionCtrl* acc = getChild<LLAccordionCtrl>("accordion");
-	acc->arrange();
-}
-
-void LLPanelPicks::onPanelPickClose(LLPanel* panel)
-{
-	getProfilePanel()->closePanel(panel);
-}
-
-void LLPanelPicks::onPanelPickSave(LLPanel* panel)
-{
-	onPanelPickClose(panel);
-	updateButtons();
-}
-
-void LLPanelPicks::onPanelClassifiedSave(LLPanelClassifiedEdit* panel)
-{
-	if(!panel->canClose())
-	{
-		return;
-	}
-
-	if(panel->isNew())
-	{
-		mEditClassifiedPanels[panel->getClassifiedId()] = panel;
-
-		LLClassifiedItem* c_item = new LLClassifiedItem(getAvatarId(), panel->getClassifiedId());
-		c_item->fillIn(panel);
-
-		LLSD c_value;
-		c_value.insert(CLASSIFIED_ID, c_item->getClassifiedId());
-		c_value.insert(CLASSIFIED_NAME, c_item->getClassifiedName());
-		mClassifiedsList->addItem(c_item, c_value, ADD_TOP);
-
-		c_item->setDoubleClickCallback(boost::bind(&LLPanelPicks::onDoubleClickClassifiedItem, this, _1));
-		c_item->setRightMouseUpCallback(boost::bind(&LLPanelPicks::onRightMouseUpItem, this, _1, _2, _3, _4));
-		c_item->setMouseUpCallback(boost::bind(&LLPanelPicks::updateButtons, this));
-		c_item->childSetAction("info_chevron", boost::bind(&LLPanelPicks::onClickInfo, this));
-
-		// order does matter, showAccordion will invoke arrange for accordions.
-		mClassifiedsAccTab->changeOpenClose(false);
-		showAccordion("tab_classifieds", true);
-	}
-	else if(panel->isNewWithErrors())
-	{
-		LLClassifiedItem* c_item = dynamic_cast<LLClassifiedItem*>(mClassifiedsList->getSelectedItem());
-		llassert(c_item);
-		if (c_item)
-		{
-			c_item->fillIn(panel);
-		}
-	}
-	else 
-	{
-		onPanelClassifiedClose(panel);
-		return;
-	}
-
-	onPanelPickClose(panel);
-	updateButtons();
-}
-
-void LLPanelPicks::onPanelClassifiedClose(LLPanelClassifiedInfo* panel)
-{
-	if(panel->getInfoLoaded() && !panel->isDirty())
-	{
-		std::vector<LLSD> values;
-		mClassifiedsList->getValues(values);
-		for(size_t n = 0; n < values.size(); ++n)
-		{
-			LLUUID c_id = values[n][CLASSIFIED_ID].asUUID();
-			if(panel->getClassifiedId() == c_id)
-			{
-				LLClassifiedItem* c_item = dynamic_cast<LLClassifiedItem*>(
-					mClassifiedsList->getItemByValue(values[n]));
-				llassert(c_item);
-				if (c_item)
-				{
-					c_item->setClassifiedName(panel->getClassifiedName());
-					c_item->setDescription(panel->getDescription());
-					c_item->setSnapshotId(panel->getSnapshotId());
-				}
-			}
-		}
-	}
-
-	onPanelPickClose(panel);
-	updateButtons();
-}
-
-void LLPanelPicks::createPickInfoPanel()
-{
-	if(!mPanelPickInfo)
-	{
-		mPanelPickInfo = LLPanelPickInfo::create();
-		mPanelPickInfo->setExitCallback(boost::bind(&LLPanelPicks::onPanelPickClose, this, mPanelPickInfo));
-		mPanelPickInfo->setEditPickCallback(boost::bind(&LLPanelPicks::onPanelPickEdit, this));
-		mPanelPickInfo->setVisible(FALSE);
-	}
-}
-
-void LLPanelPicks::createClassifiedInfoPanel()
-{
-	mPanelClassifiedInfo = LLPanelClassifiedInfo::create();
-	mPanelClassifiedInfo->setExitCallback(boost::bind(&LLPanelPicks::onPanelClassifiedClose, this, mPanelClassifiedInfo));
-	mPanelClassifiedInfo->setEditClassifiedCallback(boost::bind(&LLPanelPicks::onPanelClassifiedEdit, this));
-	mPanelClassifiedInfo->setVisible(FALSE);
-}
-
-void LLPanelPicks::createClassifiedEditPanel(LLPanelClassifiedEdit** panel)
-{
-	if(panel)
-	{
-		LLPanelClassifiedEdit* new_panel = LLPanelClassifiedEdit::create();
-		new_panel->setExitCallback(boost::bind(&LLPanelPicks::onPanelClassifiedClose, this, new_panel));
-		new_panel->setSaveCallback(boost::bind(&LLPanelPicks::onPanelClassifiedSave, this, new_panel));
-		new_panel->setCancelCallback(boost::bind(&LLPanelPicks::onPanelClassifiedClose, this, new_panel));
-		new_panel->setVisible(FALSE);
-		*panel = new_panel;
-	}
-}
-
-void LLPanelPicks::createPickEditPanel()
-{
-	mPanelPickEdit = LLPanelPickEdit::create();
-	mPanelPickEdit->setExitCallback(boost::bind(&LLPanelPicks::onPanelPickClose, this, mPanelPickEdit));
-	mPanelPickEdit->setSaveCallback(boost::bind(&LLPanelPicks::onPanelPickSave, this, mPanelPickEdit));
-	mPanelPickEdit->setCancelCallback(boost::bind(&LLPanelPicks::onPanelPickClose, this, mPanelPickEdit));
-	mPanelPickEdit->setVisible(FALSE);
-}
-
-// void LLPanelPicks::openPickEditPanel(LLPickItem* pick)
-// {
-// 	if(!pick)
-// 	{
-// 		return;
-// 	}
-// }
-
-// void LLPanelPicks::openPickInfoPanel(LLPickItem* pick)
-// {
-// 	if(!mPanelPickInfo)
-// 	{
-// 		mPanelPickInfo = LLPanelPickInfo::create();
-// 		mPanelPickInfo->setExitCallback(boost::bind(&LLPanelPicks::onPanelPickClose, this, mPanelPickInfo));
-// 		mPanelPickInfo->setEditPickCallback(boost::bind(&LLPanelPicks::onPanelPickEdit, this));
-// 		mPanelPickInfo->setVisible(FALSE);
-// 	}
-// 
-// 	LLSD params;
-// 	params["pick_id"] = pick->getPickId();
-// 	params["avatar_id"] = pick->getCreatorId();
-// 	params["snapshot_id"] = pick->getSnapshotId();
-// 	params["pick_name"] = pick->getPickName();
-// 	params["pick_desc"] = pick->getPickDesc();
-// 
-// 	getProfilePanel()->openPanel(mPanelPickInfo, params);
-// }
-
-void LLPanelPicks::openPickEdit(const LLSD& params)
-{
-	createPickEditPanel();
-	getProfilePanel()->openPanel(mPanelPickEdit, params);
-}
-
-void LLPanelPicks::onPanelPickEdit()
-{
-	LLSD selected_value = mPicksList->getSelectedValue();
-	if (selected_value.isUndefined()) return;
-
-	LLPickItem* pick = dynamic_cast<LLPickItem*>(mPicksList->getSelectedItem());
-	
-	createPickEditPanel();
-
-	LLSD params;
-	params["pick_id"] = pick->getPickId();
-	params["avatar_id"] = pick->getCreatorId();
-	params["snapshot_id"] = pick->getSnapshotId();
-	params["pick_name"] = pick->getPickName();
-	params["pick_desc"] = pick->getPickDesc();
-
-	getProfilePanel()->openPanel(mPanelPickEdit, params);
-}
-
-void LLPanelPicks::onPanelClassifiedEdit()
-{
-	LLSD selected_value = mClassifiedsList->getSelectedValue();
-	if (selected_value.isUndefined()) 
-	{
-		return;
-	}
-
-	LLClassifiedItem* c_item = dynamic_cast<LLClassifiedItem*>(mClassifiedsList->getSelectedItem());
-	llassert(c_item);
-	if (!c_item)
-	{
-		return;
-	}
-	editClassified(c_item->getClassifiedId());
-}
-
-LLClassifiedItem *LLPanelPicks::findClassifiedById(const LLUUID& classified_id)
-{
-	// HACK - find item by classified id.  Should be a better way.
-	std::vector<LLPanel*> items;
-	mClassifiedsList->getItems(items);
-	LLClassifiedItem* c_item = NULL;
-	for(std::vector<LLPanel*>::iterator it = items.begin(); it != items.end(); ++it)
-	{
-		LLClassifiedItem *test_item = dynamic_cast<LLClassifiedItem*>(*it);
-		if (test_item && test_item->getClassifiedId() == classified_id)
-		{
-			c_item = test_item;
-			break;
-		}
-	}
-	return c_item;
-}
-
-void LLPanelPicks::editClassified(const LLUUID&  classified_id)
-{
-	LLClassifiedItem* c_item = findClassifiedById(classified_id);
-	if (!c_item)
-	{
-		LL_WARNS() << "item not found for classified_id " << classified_id << LL_ENDL;
-		return;
-	}
-
-	LLSD params;
-	params["classified_id"] = c_item->getClassifiedId();
-	params["classified_creator_id"] = c_item->getAvatarId();
-	params["snapshot_id"] = c_item->getSnapshotId();
-	params["name"] = c_item->getClassifiedName();
-	params["desc"] = c_item->getDescription();
-	params["category"] = (S32)c_item->getCategory();
-	params["content_type"] = (S32)c_item->getContentType();
-	params["auto_renew"] = c_item->getAutoRenew();
-	params["price_for_listing"] = c_item->getPriceForListing();
-	params["location_text"] = c_item->getLocationText();
-
-	LLPanelClassifiedEdit* panel = mEditClassifiedPanels[c_item->getClassifiedId()];
-	if(!panel)
-	{
-		createClassifiedEditPanel(&panel);
-		mEditClassifiedPanels[c_item->getClassifiedId()] = panel;
-	}
-	getProfilePanel()->openPanel(panel, params);
-	panel->setPosGlobal(c_item->getPosGlobal());
-}
-
-void LLPanelPicks::onClickMenuEdit()
-{
-	if(getSelectedPickItem())
-	{
-		onPanelPickEdit();
-	}
-	else if(getSelectedClassifiedItem())
-	{
-		onPanelClassifiedEdit();
-	}
-}
-
-bool LLPanelPicks::onEnableMenuItem(const LLSD& user_data)
-{
-	std::string param = user_data.asString();
-
-	LLClassifiedItem* c_item = dynamic_cast<LLClassifiedItem*>(mClassifiedsList->getSelectedItem());
-	if(c_item && "info" == param)
-	{
-		// dont show Info panel if classified was not created
-		return isClassifiedPublished(c_item);
-	}
-
-	return true;
-}
-
-inline LLPanelProfile* LLPanelPicks::getProfilePanel()
-{
-	llassert_always(NULL != mProfilePanel);
-	return mProfilePanel;
-}
-
-//-----------------------------------------------------------------------------
-// LLPanelPicks
-//-----------------------------------------------------------------------------
-LLPickItem::LLPickItem()
-: LLPanel()
-, mPickID(LLUUID::null)
-, mCreatorID(LLUUID::null)
-, mParcelID(LLUUID::null)
-, mSnapshotID(LLUUID::null)
-, mNeedData(true)
-{
-	buildFromFile("panel_pick_list_item.xml");
-}
-
-LLPickItem::~LLPickItem()
-{
-	if (mCreatorID.notNull())
-	{
-		LLAvatarPropertiesProcessor::instance().removeObserver(mCreatorID, this);
-	}
-
-}
-
-LLPickItem* LLPickItem::create()
-{
-	return new LLPickItem();
-}
-
-void LLPickItem::init(LLPickData* pick_data)
-{
-	setPickDesc(pick_data->desc);
-	setSnapshotId(pick_data->snapshot_id);
-	mPosGlobal = pick_data->pos_global;
-	mSimName = pick_data->sim_name;
-	mPickDescription = pick_data->desc;
-	mUserName = pick_data->user_name;
-	mOriginalName = pick_data->original_name;
-
-	LLTextureCtrl* picture = getChild<LLTextureCtrl>("picture");
-	picture->setImageAssetID(pick_data->snapshot_id);
-}
-
-void LLPickItem::setPickName(const std::string& name)
-{
-	mPickName = name;
-	getChild<LLUICtrl>("picture_name")->setValue(name);
-
-}
-
-const std::string& LLPickItem::getPickName()
-{
-	return mPickName;
-}
-
-const LLUUID& LLPickItem::getCreatorId()
-{
-	return mCreatorID;
-}
-
-const LLUUID& LLPickItem::getSnapshotId()
-{
-	return mSnapshotID;
-}
-
-void LLPickItem::setPickDesc(const std::string& descr)
-{
-	getChild<LLUICtrl>("picture_descr")->setValue(descr);
-}
-
-void LLPickItem::setPickId(const LLUUID& id)
-{
-	mPickID = id;
-}
-
-const LLUUID& LLPickItem::getPickId()
-{
-	return mPickID;
-}
-
-const LLVector3d& LLPickItem::getPosGlobal()
-{
-	return mPosGlobal;
-}
-
-const std::string LLPickItem::getDescription()
-{
-	return getChild<LLUICtrl>("picture_descr")->getValue().asString();
-}
-
-void LLPickItem::update()
-{
-	setNeedData(true);
-	LLAvatarPropertiesProcessor::instance().sendPickInfoRequest(mCreatorID, mPickID);
-}
-
-void LLPickItem::processProperties(void *data, EAvatarProcessorType type)
-{
-	if (APT_PICK_INFO != type) 
-	{
-		return;
-	}
-
-	LLPickData* pick_data = static_cast<LLPickData *>(data);
-	if (!pick_data || mPickID != pick_data->pick_id) 
-	{
-		return;
-	}
-
-	init(pick_data);
-	setNeedData(false);
-	LLAvatarPropertiesProcessor::instance().removeObserver(mCreatorID, this);
-}
-
-void set_child_visible(LLView* parent, const std::string& child_name, bool visible)
-{
-	parent->getChildView(child_name)->setVisible(visible);
-}
-
-BOOL LLPickItem::postBuild()
-{
-	setMouseEnterCallback(boost::bind(&set_child_visible, this, "hovered_icon", true));
-	setMouseLeaveCallback(boost::bind(&set_child_visible, this, "hovered_icon", false));
-	return TRUE;
-}
-
-void LLPickItem::setValue(const LLSD& value)
-{
-	if (!value.isMap()) return;;
-	if (!value.has("selected")) return;
-	getChildView("selected_icon")->setVisible( value["selected"]);
-}
-
-//////////////////////////////////////////////////////////////////////////
-//////////////////////////////////////////////////////////////////////////
-//////////////////////////////////////////////////////////////////////////
-
-LLClassifiedItem::LLClassifiedItem(const LLUUID& avatar_id, const LLUUID& classified_id)
- : LLPanel()
- , mAvatarId(avatar_id)
- , mClassifiedId(classified_id)
-{
-	buildFromFile("panel_classifieds_list_item.xml");
-
-	LLAvatarPropertiesProcessor::getInstance()->addObserver(getAvatarId(), this);
-	LLAvatarPropertiesProcessor::getInstance()->sendClassifiedInfoRequest(getClassifiedId());
-}
-
-LLClassifiedItem::~LLClassifiedItem()
-{
-	LLAvatarPropertiesProcessor::getInstance()->removeObserver(getAvatarId(), this);
-}
-
-void LLClassifiedItem::processProperties(void* data, EAvatarProcessorType type)
-{
-	if(APT_CLASSIFIED_INFO != type)
-	{
-		return;
-	}
-
-	LLAvatarClassifiedInfo* c_info = static_cast<LLAvatarClassifiedInfo*>(data);
-	if( !c_info || c_info->classified_id != getClassifiedId() )
-	{
-		return;
-	}
-
-	setClassifiedName(c_info->name);
-	setDescription(c_info->description);
-	setSnapshotId(c_info->snapshot_id);
-	setPosGlobal(c_info->pos_global);
-
-	LLAvatarPropertiesProcessor::getInstance()->removeObserver(getAvatarId(), this);
-}
-
-BOOL LLClassifiedItem::postBuild()
-{
-	setMouseEnterCallback(boost::bind(&set_child_visible, this, "hovered_icon", true));
-	setMouseLeaveCallback(boost::bind(&set_child_visible, this, "hovered_icon", false));
-	return TRUE;
-}
-
-void LLClassifiedItem::setValue(const LLSD& value)
-{
-	if (!value.isMap()) return;;
-	if (!value.has("selected")) return;
-	getChildView("selected_icon")->setVisible( value["selected"]);
-}
-
-void LLClassifiedItem::fillIn(LLPanelClassifiedEdit* panel)
-{
-	if(!panel)
-	{
-		return;
-	}
-
-	setClassifiedName(panel->getClassifiedName());
-	setDescription(panel->getDescription());
-	setSnapshotId(panel->getSnapshotId());
-	setCategory(panel->getCategory());
-	setContentType(panel->getContentType());
-	setAutoRenew(panel->getAutoRenew());
-	setPriceForListing(panel->getPriceForListing());
-	setPosGlobal(panel->getPosGlobal());
-	setLocationText(panel->getClassifiedLocation());
-}
-
-void LLClassifiedItem::setClassifiedName(const std::string& name)
-{
-	getChild<LLUICtrl>("name")->setValue(name);
-}
-
-void LLClassifiedItem::setDescription(const std::string& desc)
-{
-	getChild<LLUICtrl>("description")->setValue(desc);
-}
-
-void LLClassifiedItem::setSnapshotId(const LLUUID& snapshot_id)
-{
-	getChild<LLUICtrl>("picture")->setValue(snapshot_id);
-}
-
-LLUUID LLClassifiedItem::getSnapshotId()
-{
-	return getChild<LLUICtrl>("picture")->getValue();
-}
-
-//EOF
diff --git a/indra/newview/llpanelpicks.h b/indra/newview/llpanelpicks.h
deleted file mode 100644
index fd7688b99d37da40935f7521b27ddb84c3d554ef..0000000000000000000000000000000000000000
--- a/indra/newview/llpanelpicks.h
+++ /dev/null
@@ -1,315 +0,0 @@
-/** 
- * @file llpanelpicks.h
- * @brief LLPanelPicks and related class definitions
- *
- * $LicenseInfo:firstyear=2009&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- * 
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- * 
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
- * $/LicenseInfo$
- */
-
-#ifndef LL_LLPANELPICKS_H
-#define LL_LLPANELPICKS_H
-
-#include "llpanel.h"
-#include "v3dmath.h"
-#include "lluuid.h"
-#include "llavatarpropertiesprocessor.h"
-#include "llpanelavatar.h"
-#include "llregistry.h"
-
-class LLAccordionCtrlTab;
-class LLPanelProfile;
-class LLMessageSystem;
-class LLVector3d;
-class LLPanelProfileTab;
-class LLAgent;
-class LLMenuGL;
-class LLPickItem;
-class LLClassifiedItem;
-class LLFlatListView;
-class LLPanelPickInfo;
-class LLPanelPickEdit;
-class LLToggleableMenu;
-class LLPanelClassifiedInfo;
-class LLPanelClassifiedEdit;
-
-// *TODO
-// Panel Picks has been consolidated with Classifieds (EXT-2095), give LLPanelPicks
-// and corresponding files (cpp, h, xml) a new name. (new name is TBD at the moment)
-
-class LLPanelPicks 
-	: public LLPanelProfileTab
-{
-public:
-	LLPanelPicks();
-	~LLPanelPicks();
-
-	static void* create(void* data);
-
-	/*virtual*/ BOOL postBuild(void);
-
-	/*virtual*/ void onOpen(const LLSD& key);
-
-	/*virtual*/ void onClosePanel();
-
-	void processProperties(void* data, EAvatarProcessorType type);
-
-	void updateData();
-
-	// returns the selected pick item
-	LLPickItem* getSelectedPickItem();
-	LLClassifiedItem* getSelectedClassifiedItem();
-	LLClassifiedItem* findClassifiedById(const LLUUID& classified_id);
-
-	//*NOTE top down approch when panel toggling is done only by 
-	// parent panels failed to work (picks related code was in my profile panel)
-	void setProfilePanel(LLPanelProfile* profile_panel);
-
-	void createNewPick();
-	void createNewClassified();
-
-protected:
-	/*virtual*/void updateButtons();
-	void updateNoItemsLabel();
-
-private:
-	void onClickDelete();
-	void onClickTeleport();
-	void onClickMap();
-
-	void onPlusMenuItemClicked(const LLSD& param);
-	bool isActionEnabled(const LLSD& userdata) const;
-
-	bool isClassifiedPublished(LLClassifiedItem* c_item);
-
-	void onListCommit(const LLFlatListView* f_list);
-	void onAccordionStateChanged(const LLAccordionCtrlTab* acc_tab);
-
-	//------------------------------------------------
-	// Callbacks which require panel toggling
-	//------------------------------------------------
-	void onClickPlusBtn();
-	void onClickInfo();
-	void onPanelPickClose(LLPanel* panel);
-	void onPanelPickSave(LLPanel* panel);
-	void onPanelClassifiedSave(LLPanelClassifiedEdit* panel);
-	void onPanelClassifiedClose(LLPanelClassifiedInfo* panel);
-	void openPickEdit(const LLSD& params);
-	void onPanelPickEdit();
-	void onPanelClassifiedEdit();
-	void editClassified(const LLUUID&  classified_id);
-	void onClickMenuEdit();
-
-	bool onEnableMenuItem(const LLSD& user_data);
-
-	void openPickInfo();
-	void openClassifiedInfo();
-	void openClassifiedInfo(const LLSD& params);
-	void openClassifiedEdit(const LLSD& params);
-	friend class LLPanelProfile;
-
-	void showAccordion(const std::string& name, bool show);
-
-	void buildPickPanel();
-
-	bool callbackDeletePick(const LLSD& notification, const LLSD& response);
-	bool callbackDeleteClassified(const LLSD& notification, const LLSD& response);
-	bool callbackTeleport(const LLSD& notification, const LLSD& response);
-
-
-	virtual void onDoubleClickPickItem(LLUICtrl* item);
-	virtual void onDoubleClickClassifiedItem(LLUICtrl* item);
-	virtual void onRightMouseUpItem(LLUICtrl* item, S32 x, S32 y, MASK mask);
-
-	LLPanelProfile* getProfilePanel();
-
-	void createPickInfoPanel();
-	void createPickEditPanel();
-	void createClassifiedInfoPanel();
-	void createClassifiedEditPanel(LLPanelClassifiedEdit** panel);
-
-	LLMenuGL* mPopupMenu;
-	LLPanelProfile* mProfilePanel;
-	LLPanelPickInfo* mPickPanel;
-	LLFlatListView* mPicksList;
-	LLFlatListView* mClassifiedsList;
-	LLPanelPickInfo* mPanelPickInfo;
-	LLPanelClassifiedInfo* mPanelClassifiedInfo;
-	LLPanelPickEdit* mPanelPickEdit;
-	LLToggleableMenu* mPlusMenu;
-	LLUICtrl* mNoItemsLabel;
-
-	// <classified_id, edit_panel>
-	typedef std::map<LLUUID, LLPanelClassifiedEdit*> panel_classified_edit_map_t;
-
-	// This map is needed for newly created classifieds. The purpose of panel is to
-	// sit in this map and listen to LLPanelClassifiedEdit::processProperties callback.
-	panel_classified_edit_map_t mEditClassifiedPanels;
-
-	LLAccordionCtrlTab* mPicksAccTab;
-	LLAccordionCtrlTab* mClassifiedsAccTab;
-
-	//true if picks list is empty after processing picks
-	bool mNoPicks;
-	//true if classifieds list is empty after processing classifieds
-	bool mNoClassifieds;
-};
-
-class LLPickItem : public LLPanel, public LLAvatarPropertiesObserver
-{
-public:
-
-	LLPickItem();
-
-	static LLPickItem* create();
-
-	void init(LLPickData* pick_data);
-
-	void setPickName(const std::string& name);
-
-	void setPickDesc(const std::string& descr);
-
-	void setPickId(const LLUUID& id);
-
-	void setCreatorId(const LLUUID& id) {mCreatorID = id;};
-
-	void setSnapshotId(const LLUUID& id) {mSnapshotID = id;};
-
-	void setNeedData(bool need){mNeedData = need;};
-
-	const LLUUID& getPickId(); 
-
-	const std::string& getPickName();
-
-	const LLUUID& getCreatorId();
-
-	const LLUUID& getSnapshotId();
-
-	const LLVector3d& getPosGlobal();
-
-	const std::string getDescription();
-
-	const std::string& getSimName() { return mSimName; }
-
-	const std::string& getUserName() { return mUserName; }
-
-	const std::string& getOriginalName() { return mOriginalName; }
-
-	const std::string& getPickDesc() { return mPickDescription; }
-
-	/*virtual*/ void processProperties(void* data, EAvatarProcessorType type);
-
-	void update();
-
-	~LLPickItem();
-
-	/*virtual*/ BOOL postBuild();
-
-	/** setting on/off background icon to indicate selected state */
-	/*virtual*/ void setValue(const LLSD& value);
-
-protected:
-
-	LLUUID mPickID;
-	LLUUID mCreatorID;
-	LLUUID mParcelID;
-	LLUUID mSnapshotID;
-	LLVector3d mPosGlobal;
-	bool mNeedData;
-
-	std::string mPickName;
-	std::string mUserName;
-	std::string mOriginalName;
-	std::string mPickDescription;
-	std::string mSimName;
-};
-
-class LLClassifiedItem : public LLPanel, public LLAvatarPropertiesObserver
-{
-public:
-
-	LLClassifiedItem(const LLUUID& avatar_id, const LLUUID& classified_id);
-	
-	virtual ~LLClassifiedItem();
-
-	/*virtual*/ void processProperties(void* data, EAvatarProcessorType type);
-
-	/*virtual*/ BOOL postBuild();
-
-	/*virtual*/ void setValue(const LLSD& value);
-
-	void fillIn(LLPanelClassifiedEdit* panel);
-
-	LLUUID getAvatarId() {return mAvatarId;}
-	
-	void setAvatarId(const LLUUID& avatar_id) {mAvatarId = avatar_id;}
-
-	LLUUID getClassifiedId() {return mClassifiedId;}
-
-	void setClassifiedId(const LLUUID& classified_id) {mClassifiedId = classified_id;}
-
-	void setPosGlobal(const LLVector3d& pos) { mPosGlobal = pos; }
-
-	const LLVector3d getPosGlobal() { return mPosGlobal; }
-
-	void setLocationText(const std::string location) { mLocationText = location; }
-
-	std::string getLocationText() { return mLocationText; }
-
-	void setClassifiedName (const std::string& name);
-
-	std::string getClassifiedName() { return getChild<LLUICtrl>("name")->getValue().asString(); }
-
-	void setDescription(const std::string& desc);
-
-	std::string getDescription() { return getChild<LLUICtrl>("description")->getValue().asString(); }
-
-	void setSnapshotId(const LLUUID& snapshot_id);
-
-	LLUUID getSnapshotId();
-
-	void setCategory(U32 cat) { mCategory = cat; }
-
-	U32 getCategory() { return mCategory; }
-
-	void setContentType(U32 ct) { mContentType = ct; }
-
-	U32 getContentType() { return mContentType; }
-
-	void setAutoRenew(U32 renew) { mAutoRenew = renew; }
-
-	bool getAutoRenew() { return mAutoRenew; }
-
-	void setPriceForListing(S32 price) { mPriceForListing = price; }
-
-	S32 getPriceForListing() { return mPriceForListing; }
-
-private:
-	LLUUID mAvatarId;
-	LLUUID mClassifiedId;
-	LLVector3d mPosGlobal;
-	std::string mLocationText;
-	U32 mCategory;
-	U32 mContentType;
-	bool mAutoRenew;
-	S32 mPriceForListing;
-};
-
-#endif // LL_LLPANELPICKS_H
diff --git a/indra/newview/llpanelplaceinfo.cpp b/indra/newview/llpanelplaceinfo.cpp
index 9157df789fc25d4726da7a4cf7b92ae3ba056cab..fb5957ff8f87bcba13e9e8b915706e58b0e3423f 100644
--- a/indra/newview/llpanelplaceinfo.cpp
+++ b/indra/newview/llpanelplaceinfo.cpp
@@ -27,6 +27,8 @@
 #include "llviewerprecompiledheaders.h"
 
 #include "llpanelplaceinfo.h"
+#include "llfloaterprofile.h"
+#include "llfloaterreg.h"
 
 #include "llavatarname.h"
 #include "llsdutil.h"
@@ -42,7 +44,6 @@
 
 #include "llagent.h"
 #include "llexpandabletextbox.h"
-#include "llpanelpick.h"
 #include "llslurl.h"
 #include "lltexturectrl.h"
 #include "llviewerregion.h"
@@ -287,7 +288,7 @@ void LLPanelPlaceInfo::reshape(S32 width, S32 height, BOOL called_from_parent)
 	}
 }
 
-void LLPanelPlaceInfo::createPick(const LLVector3d& pos_global, LLPanelPickEdit* pick_panel)
+void LLPanelPlaceInfo::createPick(const LLVector3d& pos_global)
 {
 	LLPickData data;
 	data.pos_global = pos_global;
@@ -296,7 +297,12 @@ void LLPanelPlaceInfo::createPick(const LLVector3d& pos_global, LLPanelPickEdit*
 	data.desc = mDescEditor->getText();
 	data.snapshot_id = mSnapshotCtrl->getImageAssetID();
 	data.parcel_id = mParcelID;
-	pick_panel->setPickData(&data);
+
+    LLFloaterProfile* profile_floater = dynamic_cast<LLFloaterProfile*>(LLFloaterReg::showInstance("profile", LLSD().with("id", gAgentID)));
+    if (profile_floater)
+    {
+        profile_floater->createPick(data);
+    }
 }
 
 // static
diff --git a/indra/newview/llpanelplaceinfo.h b/indra/newview/llpanelplaceinfo.h
index 8bf67cfe7d41fdd23dcdacbbe443265bfc3de627..533215016aa2fc024da8fa73c2f02e118049c40a 100644
--- a/indra/newview/llpanelplaceinfo.h
+++ b/indra/newview/llpanelplaceinfo.h
@@ -38,7 +38,6 @@ class LLAvatarName;
 class LLExpandableTextBox;
 class LLIconCtrl;
 class LLInventoryItem;
-class LLPanelPickEdit;
 class LLParcel;
 class LLScrollContainer;
 class LLTextBox;
@@ -94,7 +93,7 @@ class LLPanelPlaceInfo : public LLPanel, LLRemoteParcelInfoObserver
 
 	// Create a pick for the location specified
 	// by global_pos.
-	void createPick(const LLVector3d& pos_global, LLPanelPickEdit* pick_panel);
+	void createPick(const LLVector3d& pos_global);
 
 protected:
 	static void onNameCache(LLTextBox* text, const std::string& full_name);
diff --git a/indra/newview/llpanelplaces.cpp b/indra/newview/llpanelplaces.cpp
index 69f181e1b3044216d9c70cdb7287c42ed54295ae..74ec57655463038bc1e4e23bed79550d92a311a5 100644
--- a/indra/newview/llpanelplaces.cpp
+++ b/indra/newview/llpanelplaces.cpp
@@ -63,7 +63,6 @@
 #include "lllayoutstack.h"
 #include "llpanellandmarkinfo.h"
 #include "llpanellandmarks.h"
-#include "llpanelpick.h"
 #include "llpanelplaceprofile.h"
 #include "llpanelteleporthistory.h"
 #include "llremoteparcelrequest.h"
@@ -238,7 +237,6 @@ LLPanelPlaces::LLPanelPlaces()
 		mFilterEditor(NULL),
 		mPlaceProfile(NULL),
 		mLandmarkInfo(NULL),
-		mPickPanel(NULL),
 		mItem(NULL),
 		mPlaceMenu(NULL),
 		mLandmarkMenu(NULL),
@@ -952,28 +950,11 @@ void LLPanelPlaces::onOverflowMenuItemClicked(const LLSD& param)
 	}
 	else if (item == "pick")
 	{
-		if (mPickPanel == NULL)
-		{
-			mPickPanel = LLPanelPickEdit::create();
-			addChild(mPickPanel);
-
-			mPickPanel->setExitCallback(boost::bind(&LLPanelPlaces::togglePickPanel, this, FALSE));
-			mPickPanel->setCancelCallback(boost::bind(&LLPanelPlaces::togglePickPanel, this, FALSE));
-			mPickPanel->setSaveCallback(boost::bind(&LLPanelPlaces::togglePickPanel, this, FALSE));
-		}
-
-		togglePickPanel(TRUE);
-		mPickPanel->onOpen(LLSD());
-
 		LLPanelPlaceInfo* panel = getCurrentInfoPanel();
 		if (panel)
 		{
-			panel->createPick(mPosGlobal, mPickPanel);
+			panel->createPick(mPosGlobal);
 		}
-
-		LLRect rect = getRect();
-		mPickPanel->reshape(rect.getWidth(), rect.getHeight());
-		mPickPanel->setRect(rect);
 	}
 	else if (item == "add_to_favbar")
 	{
@@ -1050,17 +1031,6 @@ bool LLPanelPlaces::handleDragAndDropToTrash(BOOL drop, EDragAndDropType cargo_t
     return false;
 }
 
-void LLPanelPlaces::togglePickPanel(BOOL visible)
-{
-	if (mPickPanel)
-	{
-		mPickPanel->setVisible(visible);
-		mPlaceProfile->setVisible(!visible);
-		updateVerbs();
-	}
-
-}
-
 void LLPanelPlaces::togglePlaceInfoPanel(BOOL visible)
 {
 	if (!mPlaceProfile || !mLandmarkInfo)
@@ -1309,15 +1279,11 @@ void LLPanelPlaces::updateVerbs()
 
 	bool is_agent_place_info_visible = mPlaceInfoType == AGENT_INFO_TYPE;
 	bool is_create_landmark_visible = mPlaceInfoType == CREATE_LANDMARK_INFO_TYPE;
-	bool is_pick_panel_visible = false;
-	if(mPickPanel)
-	{
-		is_pick_panel_visible = mPickPanel->isInVisibleChain();
-	}
+
 	bool have_3d_pos = ! mPosGlobal.isExactlyZero();
 
-	mTeleportBtn->setVisible(!is_create_landmark_visible && !isLandmarkEditModeOn && !is_pick_panel_visible);
-	mShowOnMapBtn->setVisible(!is_create_landmark_visible && !isLandmarkEditModeOn && !is_pick_panel_visible);
+	mTeleportBtn->setVisible(!is_create_landmark_visible && !isLandmarkEditModeOn);
+	mShowOnMapBtn->setVisible(!is_create_landmark_visible && !isLandmarkEditModeOn);
 	mSaveBtn->setVisible(isLandmarkEditModeOn);
 	mCancelBtn->setVisible(isLandmarkEditModeOn);
 	mCloseBtn->setVisible(is_create_landmark_visible && !isLandmarkEditModeOn);
diff --git a/indra/newview/llpanelplaces.h b/indra/newview/llpanelplaces.h
index 3b87eb6cb9521ac15ecfa72d18e534eea1f3bfde..e554099343cd972caceaf38c619901897bfed3d5 100644
--- a/indra/newview/llpanelplaces.h
+++ b/indra/newview/llpanelplaces.h
@@ -38,7 +38,6 @@ class LLLandmark;
 class LLPanelLandmarkInfo;
 class LLPanelPlaceProfile;
 
-class LLPanelPickEdit;
 class LLPanelPlaceInfo;
 class LLPanelPlacesTab;
 class LLParcelSelection;
@@ -95,7 +94,6 @@ class LLPanelPlaces : public LLPanel
 	void onOverflowButtonClicked();
 	void onOverflowMenuItemClicked(const LLSD& param);
 	bool onOverflowMenuItemEnable(const LLSD& param);
-	void onCreateLandmarkButtonClicked(const LLUUID& folder_id);
 	void onBackButtonClicked();
     void onGearMenuClick();
     void onSortingMenuClick();
@@ -103,9 +101,6 @@ class LLPanelPlaces : public LLPanel
     void onRemoveButtonClicked();
     bool handleDragAndDropToTrash(BOOL drop, EDragAndDropType cargo_type, void* cargo_data, EAcceptance* accept);
 
-
-	void toggleMediaPanel();
-	void togglePickPanel(BOOL visible);
 	void togglePlaceInfoPanel(BOOL visible);
 
 	/*virtual*/ void onVisibilityChange(BOOL new_visibility);
@@ -122,7 +117,6 @@ class LLPanelPlaces : public LLPanel
 	LLPanelPlaceProfile*		mPlaceProfile;
 	LLPanelLandmarkInfo*		mLandmarkInfo;
 
-	LLPanelPickEdit*			mPickPanel;
 	LLToggleableMenu*			mPlaceMenu;
 	LLToggleableMenu*			mLandmarkMenu;
 
diff --git a/indra/newview/llpanelprofile.cpp b/indra/newview/llpanelprofile.cpp
index 5f13b223fbbf097096a59ff12f4373a27dc1b094..f4eaa78f11367404b4a06e5dccaf5adfea8b3816 100644
--- a/indra/newview/llpanelprofile.cpp
+++ b/indra/newview/llpanelprofile.cpp
@@ -1,25 +1,25 @@
-/** 
+/**
 * @file llpanelprofile.cpp
 * @brief Profile panel implementation
 *
-* $LicenseInfo:firstyear=2009&license=viewerlgpl$
+* $LicenseInfo:firstyear=2022&license=viewerlgpl$
 * Second Life Viewer Source Code
-* Copyright (C) 2010, Linden Research, Inc.
-* 
+* Copyright (C) 2022, Linden Research, Inc.
+*
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation;
 * version 2.1 of the License only.
-* 
+*
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
-* 
+*
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
-* 
+*
 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 * $/LicenseInfo$
 */
@@ -27,32 +27,433 @@
 #include "llviewerprecompiledheaders.h"
 #include "llpanelprofile.h"
 
-#include "llagent.h"
+// Common
+#include "llavatarnamecache.h"
+#include "llsdutil.h"
+#include "llslurl.h"
+#include "lldateutil.h" //ageFromDate
+
+// UI
+#include "llavatariconctrl.h"
+#include "llclipboard.h"
+#include "llcheckboxctrl.h"
+#include "llcombobox.h"
+#include "lllineeditor.h"
+#include "llloadingindicator.h"
+#include "llmenubutton.h"
+#include "lltabcontainer.h"
+#include "lltextbox.h"
+#include "lltexteditor.h"
+#include "lltexturectrl.h"
+#include "lltoggleablemenu.h"
+#include "llgrouplist.h"
+#include "llurlaction.h"
+
+// Image
+#include "llimagej2c.h"
+
+// Newview
+#include "llagent.h" //gAgent
+#include "llagentpicksinfo.h"
 #include "llavataractions.h"
-#include "llfloaterreg.h"
+#include "llavatarpropertiesprocessor.h"
+#include "llcallingcard.h"
 #include "llcommandhandler.h"
-#include "llnotificationsutil.h"
-#include "llpanelpicks.h"
-#include "lltabcontainer.h"
-#include "llviewercontrol.h"
-#include "llviewernetwork.h"
+#include "llfloaterprofiletexture.h"
+#include "llfloaterreg.h"
+#include "llfloaterreporter.h"
+#include "llfilepicker.h"
+#include "llfirstuse.h"
+#include "llgroupactions.h"
+#include "lllogchat.h"
 #include "llmutelist.h"
+#include "llnotificationsutil.h"
 #include "llpanelblockedlist.h"
+#include "llpanelprofileclassifieds.h"
+#include "llpanelprofilepicks.h"
+#include "lltrans.h"
+#include "llviewercontrol.h"
+#include "llviewermenu.h" //is_agent_mappable
+#include "llviewermenufile.h"
+#include "llviewertexturelist.h"
+#include "llvoiceclient.h"
 #include "llweb.h"
 
-static const std::string PANEL_PICKS = "panel_picks";
 
-std::string getProfileURL(const std::string& agent_name)
+static LLPanelInjector<LLPanelProfileSecondLife> t_panel_profile_secondlife("panel_profile_secondlife");
+static LLPanelInjector<LLPanelProfileWeb> t_panel_web("panel_profile_web");
+static LLPanelInjector<LLPanelProfilePicks> t_panel_picks("panel_profile_picks");
+static LLPanelInjector<LLPanelProfileFirstLife> t_panel_firstlife("panel_profile_firstlife");
+static LLPanelInjector<LLPanelProfileNotes> t_panel_notes("panel_profile_notes");
+static LLPanelInjector<LLPanelProfile>          t_panel_profile("panel_profile");
+
+static const std::string PANEL_SECONDLIFE   = "panel_profile_secondlife";
+static const std::string PANEL_WEB          = "panel_profile_web";
+static const std::string PANEL_PICKS        = "panel_profile_picks";
+static const std::string PANEL_CLASSIFIEDS  = "panel_profile_classifieds";
+static const std::string PANEL_FIRSTLIFE    = "panel_profile_firstlife";
+static const std::string PANEL_NOTES        = "panel_profile_notes";
+static const std::string PANEL_PROFILE_VIEW = "panel_profile_view";
+
+static const std::string PROFILE_PROPERTIES_CAP = "AgentProfile";
+static const std::string PROFILE_IMAGE_UPLOAD_CAP = "UploadAgentProfileImage";
+
+
+//////////////////////////////////////////////////////////////////////////
+
+void request_avatar_properties_coro(std::string cap_url, LLUUID agent_id)
+{
+    LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+    LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+        httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("request_avatar_properties_coro", httpPolicy));
+    LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+    LLCore::HttpHeaders::ptr_t httpHeaders;
+
+    LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions);
+    httpOpts->setFollowRedirects(true);
+
+    std::string finalUrl = cap_url + "/" + agent_id.asString();
+
+    LLSD result = httpAdapter->getAndSuspend(httpRequest, finalUrl, httpOpts, httpHeaders);
+
+    LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+    LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+    LL_DEBUGS("AvatarProperties") << "Agent id: " << agent_id << " Result: " << httpResults << LL_ENDL;
+
+    if (!status
+        || !result.has("id")
+        || agent_id != result["id"].asUUID())
+    {
+        LL_WARNS("AvatarProperties") << "Failed to get agent information for id " << agent_id << LL_ENDL;
+        return;
+    }
+
+    LLFloater* floater_profile = LLFloaterReg::findInstance("profile", LLSD().with("id", agent_id));
+    if (!floater_profile)
+    {
+        // floater is dead, so panels are dead as well
+        return;
+    }
+
+    LLPanel *panel = floater_profile->findChild<LLPanel>(PANEL_PROFILE_VIEW, TRUE);
+    LLPanelProfile *panel_profile = dynamic_cast<LLPanelProfile*>(panel);
+    if (!panel_profile)
+    {
+        LL_WARNS() << PANEL_PROFILE_VIEW << " not found" << LL_ENDL;
+        return;
+    }
+
+
+    // Avatar Data
+
+    LLAvatarData *avatar_data = &panel_profile->mAvatarData;
+    std::string birth_date;
+
+    avatar_data->agent_id = agent_id;
+    avatar_data->avatar_id = agent_id;
+    avatar_data->image_id = result["sl_image_id"].asUUID();
+    avatar_data->fl_image_id = result["fl_image_id"].asUUID();
+    avatar_data->partner_id = result["partner_id"].asUUID();
+    avatar_data->about_text = result["sl_about_text"].asString();
+    avatar_data->fl_about_text = result["fl_about_text"].asString();
+    avatar_data->born_on = result["member_since"].asDate();
+    avatar_data->profile_url = getProfileURL(agent_id.asString());
+
+    avatar_data->flags = 0;
+
+    if (result["online"].asBoolean())
+    {
+        avatar_data->flags |= AVATAR_ONLINE;
+    }
+    if (result["allow_publish"].asBoolean())
+    {
+        avatar_data->flags |= AVATAR_ALLOW_PUBLISH;
+    }
+    if (result["identified"].asBoolean())
+    {
+        avatar_data->flags |= AVATAR_IDENTIFIED;
+    }
+    if (result["transacted"].asBoolean())
+    {
+        avatar_data->flags |= AVATAR_TRANSACTED;
+    }
+
+    avatar_data->caption_index = 0;
+    if (result.has("charter_member")) // won't be present if "caption" is set
+    {
+        avatar_data->caption_index = result["charter_member"].asInteger();
+    }
+    else if (result.has("caption"))
+    {
+        avatar_data->caption_text = result["caption"].asString();
+    }
+
+    panel = floater_profile->findChild<LLPanel>(PANEL_SECONDLIFE, TRUE);
+    LLPanelProfileSecondLife *panel_sl = dynamic_cast<LLPanelProfileSecondLife*>(panel);
+    if (panel_sl)
+    {
+        panel_sl->processProfileProperties(avatar_data);
+    }
+
+    panel = floater_profile->findChild<LLPanel>(PANEL_WEB, TRUE);
+    LLPanelProfileWeb *panel_web = dynamic_cast<LLPanelProfileWeb*>(panel);
+    if (panel_web)
+    {
+        panel_web->setLoaded();
+    }
+
+    panel = floater_profile->findChild<LLPanel>(PANEL_FIRSTLIFE, TRUE);
+    LLPanelProfileFirstLife *panel_first = dynamic_cast<LLPanelProfileFirstLife*>(panel);
+    if (panel_first)
+    {
+        panel_first->processProperties(avatar_data);
+    }
+
+    // Picks
+
+    LLSD picks_array = result["picks"];
+    LLAvatarPicks avatar_picks;
+    avatar_picks.agent_id = agent_id; // Not in use?
+    avatar_picks.target_id = agent_id;
+
+    for (LLSD::array_const_iterator it = picks_array.beginArray(); it != picks_array.endArray(); ++it)
+    {
+        const LLSD& pick_data = *it;
+        avatar_picks.picks_list.emplace_back(pick_data["id"].asUUID(), pick_data["name"].asString());
+    }
+
+    panel = floater_profile->findChild<LLPanel>(PANEL_PICKS, TRUE);
+    LLPanelProfilePicks *panel_picks = dynamic_cast<LLPanelProfilePicks*>(panel);
+    if (panel_picks)
+    {
+        // Refresh pick limit before processing
+        LLAgentPicksInfo::getInstance()->onServerRespond(&avatar_picks);
+        panel_picks->processProperties(&avatar_picks);
+    }
+
+    // Groups
+
+    LLSD groups_array = result["groups"];
+    LLAvatarGroups avatar_groups;
+    avatar_groups.agent_id = agent_id; // Not in use?
+    avatar_groups.avatar_id = agent_id; // target_id
+
+    for (LLSD::array_const_iterator it = groups_array.beginArray(); it != groups_array.endArray(); ++it)
+    {
+        const LLSD& group_info = *it;
+        LLAvatarGroups::LLGroupData group_data;
+        group_data.group_powers = 0; // Not in use?
+        group_data.group_title = group_info["name"].asString(); // Missing data, not in use?
+        group_data.group_id = group_info["id"].asUUID();
+        group_data.group_name = group_info["name"].asString();
+        group_data.group_insignia_id = group_info["image_id"].asUUID();
+
+        avatar_groups.group_list.push_back(group_data);
+    }
+
+    if (panel_sl)
+    {
+        panel_sl->processGroupProperties(&avatar_groups);
+    }
+
+    // Notes
+    LLAvatarNotes avatar_notes;
+
+    avatar_notes.agent_id = agent_id;
+    avatar_notes.target_id = agent_id;
+    avatar_notes.notes = result["notes"].asString();
+
+    panel = floater_profile->findChild<LLPanel>(PANEL_NOTES, TRUE);
+    LLPanelProfileNotes *panel_notes = dynamic_cast<LLPanelProfileNotes*>(panel);
+    if (panel_notes)
+    {
+        panel_notes->processProperties(&avatar_notes);
+    }
+}
+
+//TODO: changes take two minutes to propagate!
+// Add some storage that holds updated data for two minutes
+// for new instances to reuse the data
+// Profile data is only relevant to won avatar, but notes
+// are for everybody
+void put_avatar_properties_coro(std::string cap_url, LLUUID agent_id, LLSD data)
+{
+    LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+    LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+        httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("put_avatar_properties_coro", httpPolicy));
+    LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+    LLCore::HttpHeaders::ptr_t httpHeaders;
+
+    LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions);
+    httpOpts->setFollowRedirects(true);
+
+    std::string finalUrl = cap_url + "/" + agent_id.asString();
+
+    LLSD result = httpAdapter->putAndSuspend(httpRequest, finalUrl, data, httpOpts, httpHeaders);
+
+    LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+    LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+    if (!status)
+    {
+        LL_WARNS("AvatarProperties") << "Failed to put agent information " << data << " for id " << agent_id << LL_ENDL;
+        return;
+    }
+
+    LL_DEBUGS("AvatarProperties") << "Agent id: " << agent_id << " Data: " << data << " Result: " << httpResults << LL_ENDL;
+}
+
+LLUUID post_profile_image(std::string cap_url, const LLSD &first_data, std::string path_to_image, LLHandle<LLPanel> *handle)
+{
+    LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+    LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+        httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("post_profile_image_coro", httpPolicy));
+    LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+    LLCore::HttpHeaders::ptr_t httpHeaders;
+
+    LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions);
+    httpOpts->setFollowRedirects(true);
+    
+    LLSD result = httpAdapter->postAndSuspend(httpRequest, cap_url, first_data, httpOpts, httpHeaders);
+
+    LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+    LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+    if (!status)
+    {
+        // todo: notification?
+        LL_WARNS("AvatarProperties") << "Failed to get uploader cap " << status.toString() << LL_ENDL;
+        return LLUUID::null;
+    }
+    if (!result.has("uploader"))
+    {
+        // todo: notification?
+        LL_WARNS("AvatarProperties") << "Failed to get uploader cap, response contains no data." << LL_ENDL;
+        return LLUUID::null;
+    }
+    std::string uploader_cap = result["uploader"].asString();
+    if (uploader_cap.empty())
+    {
+        LL_WARNS("AvatarProperties") << "Failed to get uploader cap, cap invalid." << LL_ENDL;
+        return LLUUID::null;
+    }
+
+    // Upload the image
+
+    LLCore::HttpRequest::ptr_t uploaderhttpRequest(new LLCore::HttpRequest);
+    LLCore::HttpHeaders::ptr_t uploaderhttpHeaders(new LLCore::HttpHeaders);
+    LLCore::HttpOptions::ptr_t uploaderhttpOpts(new LLCore::HttpOptions);
+    S64 length;
+
+    {
+        llifstream instream(path_to_image.c_str(), std::iostream::binary | std::iostream::ate);
+        if (!instream.is_open())
+        {
+            LL_WARNS("AvatarProperties") << "Failed to open file " << path_to_image << LL_ENDL;
+            return LLUUID::null;
+        }
+        length = instream.tellg();
+    }
+
+    uploaderhttpHeaders->append(HTTP_OUT_HEADER_CONTENT_TYPE, "application/jp2"); // optional
+    uploaderhttpHeaders->append(HTTP_OUT_HEADER_CONTENT_LENGTH, llformat("%d", length)); // required!
+    uploaderhttpOpts->setFollowRedirects(true);
+
+    result = httpAdapter->postFileAndSuspend(uploaderhttpRequest, uploader_cap, path_to_image, uploaderhttpOpts, uploaderhttpHeaders);
+
+    httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+    status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+    LL_WARNS("AvatarProperties") << result << LL_ENDL;
+
+    if (!status)
+    {
+        LL_WARNS("AvatarProperties") << "Failed to upload image " << status.toString() << LL_ENDL;
+        return LLUUID::null;
+    }
+
+    if (result["state"].asString() != "complete")
+    {
+        if (result.has("message"))
+        {
+            LL_WARNS("AvatarProperties") << "Failed to upload image, state " << result["state"] << " message: " << result["message"] << LL_ENDL;
+        }
+        else
+        {
+            LL_WARNS("AvatarProperties") << "Failed to upload image " << result << LL_ENDL;
+        }
+        return LLUUID::null;
+    }
+
+    return result["new_asset"].asUUID();
+}
+
+enum EProfileImageType
+{
+    PROFILE_IMAGE_SL,
+    PROFILE_IMAGE_FL,
+};
+
+void post_profile_image_coro(std::string cap_url, EProfileImageType type, std::string path_to_image, LLHandle<LLPanel> *handle)
 {
-	std::string url = "[WEB_PROFILE_URL][AGENT_NAME]";
-	LLSD subs;
-	subs["WEB_PROFILE_URL"] = LLGridManager::getInstance()->getWebProfileURL();
-	subs["AGENT_NAME"] = agent_name;
-	url = LLWeb::expandURLSubstitutions(url, subs);
-	LLStringUtil::toLower(url);
-	return url;
+    LLSD data;
+    switch (type)
+    {
+    case PROFILE_IMAGE_SL:
+        data["profile-image-asset"] = "sl_image_id";
+        break;
+    case PROFILE_IMAGE_FL:
+        data["profile-image-asset"] = "fl_image_id";
+        break;
+    }
+
+    LLUUID result = post_profile_image(cap_url, data, path_to_image, handle);
+
+    // reset loading indicator
+    if (!handle->isDead())
+    {
+        switch (type)
+        {
+        case PROFILE_IMAGE_SL:
+            {
+                LLPanelProfileSecondLife* panel = static_cast<LLPanelProfileSecondLife*>(handle->get());
+                if (result.notNull())
+                {
+                    panel->setProfileImageUploaded(result);
+                }
+                else
+                {
+                    // failure, just stop progress indicator
+                    panel->setProfileImageUploading(false);
+                }
+                break;
+            }
+        case PROFILE_IMAGE_FL:
+            {
+                LLPanelProfileFirstLife* panel = static_cast<LLPanelProfileFirstLife*>(handle->get());
+                if (result.notNull())
+                {
+                    panel->setProfileImageUploaded(result);
+                }
+                else
+                {
+                    // failure, just stop progress indicator
+                    panel->setProfileImageUploading(false);
+                }
+                break;
+            }
+        }
+    }
+
+    // Cleanup
+    LLFile::remove(path_to_image);
+    delete handle;
 }
 
+//////////////////////////////////////////////////////////////////////////
+// LLProfileHandler
+
 class LLProfileHandler : public LLCommandHandler
 {
 public:
@@ -73,6 +474,10 @@ class LLProfileHandler : public LLCommandHandler
 };
 LLProfileHandler gProfileHandler;
 
+
+//////////////////////////////////////////////////////////////////////////
+// LLAgentHandler
+
 class LLAgentHandler : public LLCommandHandler
 {
 public:
@@ -178,279 +583,2070 @@ class LLAgentHandler : public LLCommandHandler
 			}
 			return true;
 		}
+
+        // reportAbuse is here due to convoluted avatar handling
+        // in LLScrollListCtrl and LLTextBase
+        if (verb == "reportAbuse" && web == NULL) 
+        {
+            LLAvatarName av_name;
+            if (LLAvatarNameCache::get(avatar_id, &av_name))
+            {
+                LLFloaterReporter::showFromAvatar(avatar_id, av_name.getCompleteName());
+            }
+            else
+            {
+                LLFloaterReporter::showFromAvatar(avatar_id, "not avaliable");
+            }
+            return true;
+        }
 		return false;
 	}
 };
 LLAgentHandler gAgentHandler;
 
 
-//-- LLPanelProfile::ChildStack begins ----------------------------------------
-LLPanelProfile::ChildStack::ChildStack()
-:	mParent(NULL)
+///----------------------------------------------------------------------------
+/// LLFloaterProfilePermissions
+///----------------------------------------------------------------------------
+
+class LLFloaterProfilePermissions
+    : public LLFloater
+    , public LLFriendObserver
+{
+public:
+    LLFloaterProfilePermissions(LLView * owner, const LLUUID &avatar_id);
+    ~LLFloaterProfilePermissions();
+    BOOL postBuild() override;
+    void onOpen(const LLSD& key) override;
+    void draw() override;
+    void changed(U32 mask) override; // LLFriendObserver
+
+    void onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name);
+    bool hasUnsavedChanges() { return mHasUnsavedPermChanges; }
+
+    void onApplyRights();
+
+private:
+    void fillRightsData();
+    void rightsConfirmationCallback(const LLSD& notification, const LLSD& response);
+    void confirmModifyRights(bool grant);
+    void onCommitSeeOnlineRights();
+    void onCommitEditRights();
+    void onCancel();
+
+    LLTextBase*         mDescription;
+    LLCheckBoxCtrl*     mOnlineStatus;
+    LLCheckBoxCtrl*     mMapRights;
+    LLCheckBoxCtrl*     mEditObjectRights;
+    LLButton*           mOkBtn;
+    LLButton*           mCancelBtn;
+
+    LLUUID              mAvatarID;
+    F32                 mContextConeOpacity;
+    bool                mHasUnsavedPermChanges;
+    LLHandle<LLView>    mOwnerHandle;
+
+    boost::signals2::connection	mAvatarNameCacheConnection;
+};
+
+LLFloaterProfilePermissions::LLFloaterProfilePermissions(LLView * owner, const LLUUID &avatar_id)
+    : LLFloater(LLSD())
+    , mAvatarID(avatar_id)
+    , mContextConeOpacity(0.0f)
+    , mHasUnsavedPermChanges(false)
+    , mOwnerHandle(owner->getHandle())
 {
+    buildFromFile("floater_profile_permissions.xml");
 }
 
-LLPanelProfile::ChildStack::~ChildStack()
+LLFloaterProfilePermissions::~LLFloaterProfilePermissions()
 {
-	while (mStack.size() != 0)
-	{
-		view_list_t& top = mStack.back();
-		for (view_list_t::const_iterator it = top.begin(); it != top.end(); ++it)
-		{
-			LLView* viewp = *it;
-			if (viewp)
-			{
-				viewp->die();
-			}
-		}
-		mStack.pop_back();
-	}
+    mAvatarNameCacheConnection.disconnect();
+    if (mAvatarID.notNull())
+    {
+        LLAvatarTracker::instance().removeParticularFriendObserver(mAvatarID, this);
+    }
 }
 
-void LLPanelProfile::ChildStack::setParent(LLPanel* parent)
+BOOL LLFloaterProfilePermissions::postBuild()
 {
-	llassert_always(parent != NULL);
-	mParent = parent;
+    mDescription = getChild<LLTextBase>("perm_description");
+    mOnlineStatus = getChild<LLCheckBoxCtrl>("online_check");
+    mMapRights = getChild<LLCheckBoxCtrl>("map_check");
+    mEditObjectRights = getChild<LLCheckBoxCtrl>("objects_check");
+    mOkBtn = getChild<LLButton>("perms_btn_ok");
+    mCancelBtn = getChild<LLButton>("perms_btn_cancel");
+
+    mOnlineStatus->setCommitCallback([this](LLUICtrl*, void*) { onCommitSeeOnlineRights(); }, nullptr);
+    mMapRights->setCommitCallback([this](LLUICtrl*, void*) { mHasUnsavedPermChanges = true; }, nullptr);
+    mEditObjectRights->setCommitCallback([this](LLUICtrl*, void*) { onCommitEditRights(); }, nullptr);
+    mOkBtn->setCommitCallback([this](LLUICtrl*, void*) { onApplyRights(); }, nullptr);
+    mCancelBtn->setCommitCallback([this](LLUICtrl*, void*) { onCancel(); }, nullptr);
+
+    return TRUE;
 }
 
-/// Save current parent's child views and remove them from the child list.
-bool LLPanelProfile::ChildStack::push()
+void LLFloaterProfilePermissions::onOpen(const LLSD& key)
 {
-	view_list_t vlist = *mParent->getChildList();
+    if (LLAvatarActions::isFriend(mAvatarID))
+    {
+        LLAvatarTracker::instance().addParticularFriendObserver(mAvatarID, this);
+        fillRightsData();
+    }
 
-	for (view_list_t::const_iterator it = vlist.begin(); it != vlist.end(); ++it)
-	{
-		LLView* viewp = *it;
-		mParent->removeChild(viewp);
-	}
+    mCancelBtn->setFocus(true);
 
-	mStack.push_back(vlist);
-	dump();
-	return true;
+    mAvatarNameCacheConnection = LLAvatarNameCache::get(mAvatarID, boost::bind(&LLFloaterProfilePermissions::onAvatarNameCache, this, _1, _2));
 }
 
-/// Restore saved children (adding them back to the child list).
-bool LLPanelProfile::ChildStack::pop()
+void LLFloaterProfilePermissions::draw()
 {
-	if (mStack.size() == 0)
-	{
-		LL_WARNS() << "Empty stack" << LL_ENDL;
-		llassert(mStack.size() == 0);
-		return false;
-	}
+    // drawFrustum
+    LLView *owner = mOwnerHandle.get();
+    static LLCachedControl<F32> max_opacity(gSavedSettings, "PickerContextOpacity", 0.4f);
+    drawConeToOwner(mContextConeOpacity, max_opacity, owner);
+    LLFloater::draw();
+}
 
-	view_list_t& top = mStack.back();
-	for (view_list_t::const_iterator it = top.begin(); it != top.end(); ++it)
-	{
-		LLView* viewp = *it;
-		mParent->addChild(viewp);
-	}
+void LLFloaterProfilePermissions::changed(U32 mask)
+{
+    if (mask != LLFriendObserver::ONLINE)
+    {
+        fillRightsData();
+    }
+}
+
+void LLFloaterProfilePermissions::onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name)
+{
+    mAvatarNameCacheConnection.disconnect();
 
-	mStack.pop_back();
-	dump();
-	return true;
+    LLStringUtil::format_map_t args;
+    args["[AGENT_NAME]"] = av_name.getDisplayName();
+    std::string descritpion = getString("description_string", args);
+    mDescription->setValue(descritpion);
 }
 
-/// Temporarily add all saved children back.
-void LLPanelProfile::ChildStack::preParentReshape()
+void LLFloaterProfilePermissions::fillRightsData()
 {
-	mSavedStack = mStack;
-	while(mStack.size() > 0)
-	{
-		pop();
-	}
+    const LLRelationship* relation = LLAvatarTracker::instance().getBuddyInfo(mAvatarID);
+    // If true - we are viewing friend's profile, enable check boxes and set values.
+    if (relation)
+    {
+        S32 rights = relation->getRightsGrantedTo();
+
+        BOOL see_online = LLRelationship::GRANT_ONLINE_STATUS & rights ? TRUE : FALSE;
+        mOnlineStatus->setValue(see_online);
+        mMapRights->setEnabled(see_online);
+        mMapRights->setValue(LLRelationship::GRANT_MAP_LOCATION & rights ? TRUE : FALSE);
+        mEditObjectRights->setValue(LLRelationship::GRANT_MODIFY_OBJECTS & rights ? TRUE : FALSE);
+    }
+    else
+    {
+        closeFloater();
+        LL_INFOS("ProfilePermissions") << "Floater closing since agent is no longer a friend" << LL_ENDL;
+    }
 }
 
-/// Add the temporarily saved children back.
-void LLPanelProfile::ChildStack::postParentReshape()
+void LLFloaterProfilePermissions::rightsConfirmationCallback(const LLSD& notification,
+    const LLSD& response)
 {
-	mStack = mSavedStack;
-	mSavedStack = stack_t();
+    S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+    if (option != 0) // canceled
+    {
+        mEditObjectRights->setValue(mEditObjectRights->getValue().asBoolean() ? FALSE : TRUE);
+    }
+    else
+    {
+        mHasUnsavedPermChanges = true;
+    }
+}
 
-	for (stack_t::const_iterator stack_it = mStack.begin(); stack_it != mStack.end(); ++stack_it)
-	{
-		const view_list_t& vlist = (*stack_it);
-		for (view_list_t::const_iterator list_it = vlist.begin(); list_it != vlist.end(); ++list_it)
-		{
-			LLView* viewp = *list_it;
-			LL_DEBUGS() << "removing " << viewp->getName() << LL_ENDL;
-			mParent->removeChild(viewp);
-		}
-	}
+void LLFloaterProfilePermissions::confirmModifyRights(bool grant)
+{
+    LLSD args;
+    args["NAME"] = LLSLURL("agent", mAvatarID, "completename").getSLURLString();
+    LLNotificationsUtil::add(grant ? "GrantModifyRights" : "RevokeModifyRights", args, LLSD(),
+        boost::bind(&LLFloaterProfilePermissions::rightsConfirmationCallback, this, _1, _2));
 }
 
-void LLPanelProfile::ChildStack::dump()
+void LLFloaterProfilePermissions::onCommitSeeOnlineRights()
 {
-	unsigned lvl = 0;
-	LL_DEBUGS() << "child stack dump:" << LL_ENDL;
-	for (stack_t::const_iterator stack_it = mStack.begin(); stack_it != mStack.end(); ++stack_it, ++lvl)
-	{
-		std::ostringstream dbg_line;
-		dbg_line << "lvl #" << lvl << ":";
-		const view_list_t& vlist = (*stack_it);
-		for (view_list_t::const_iterator list_it = vlist.begin(); list_it != vlist.end(); ++list_it)
-		{
-			dbg_line << " " << (*list_it)->getName();
-		}
-		LL_DEBUGS() << dbg_line.str() << LL_ENDL;
-	}
+    bool see_online = mOnlineStatus->getValue().asBoolean();
+    mMapRights->setEnabled(see_online);
+    if (see_online)
+    {
+        const LLRelationship* relation = LLAvatarTracker::instance().getBuddyInfo(mAvatarID);
+        if (relation)
+        {
+            S32 rights = relation->getRightsGrantedTo();
+            mMapRights->setValue(LLRelationship::GRANT_MAP_LOCATION & rights ? TRUE : FALSE);
+        }
+        else
+        {
+            closeFloater();
+            LL_INFOS("ProfilePermissions") << "Floater closing since agent is no longer a friend" << LL_ENDL;
+        }
+    }
+    else
+    {
+        mMapRights->setValue(FALSE);
+    }
+    mHasUnsavedPermChanges = true;
 }
 
-//-- LLPanelProfile::ChildStack ends ------------------------------------------
+void LLFloaterProfilePermissions::onCommitEditRights()
+{
+    const LLRelationship* buddy_relationship = LLAvatarTracker::instance().getBuddyInfo(mAvatarID);
 
-LLPanelProfile::LLPanelProfile()
- : LLPanel()
- , mAvatarId(LLUUID::null)
+    if (!buddy_relationship)
+    {
+        LL_WARNS("ProfilePermissions") << "Trying to modify rights for non-friend avatar. Closing floater." << LL_ENDL;
+        closeFloater();
+        return;
+    }
+
+    bool allow_modify_objects = mEditObjectRights->getValue().asBoolean();
+
+    // if modify objects checkbox clicked
+    if (buddy_relationship->isRightGrantedTo(
+        LLRelationship::GRANT_MODIFY_OBJECTS) != allow_modify_objects)
+    {
+        confirmModifyRights(allow_modify_objects);
+    }
+}
+
+void LLFloaterProfilePermissions::onApplyRights()
 {
-	mChildStack.setParent(this);
+    const LLRelationship* buddy_relationship = LLAvatarTracker::instance().getBuddyInfo(mAvatarID);
+
+    if (!buddy_relationship)
+    {
+        LL_WARNS("ProfilePermissions") << "Trying to modify rights for non-friend avatar. Skipped." << LL_ENDL;
+        return;
+    }
+
+    S32 rights = 0;
+
+    if (mOnlineStatus->getValue().asBoolean())
+    {
+        rights |= LLRelationship::GRANT_ONLINE_STATUS;
+    }
+    if (mMapRights->getValue().asBoolean())
+    {
+        rights |= LLRelationship::GRANT_MAP_LOCATION;
+    }
+    if (mEditObjectRights->getValue().asBoolean())
+    {
+        rights |= LLRelationship::GRANT_MODIFY_OBJECTS;
+    }
+
+    LLAvatarPropertiesProcessor::getInstance()->sendFriendRights(mAvatarID, rights);
+
+    closeFloater();
 }
 
-BOOL LLPanelProfile::postBuild()
+void LLFloaterProfilePermissions::onCancel()
 {
-	LLPanelPicks* panel_picks = findChild<LLPanelPicks>(PANEL_PICKS);
-	panel_picks->setProfilePanel(this);
+    closeFloater();
+}
 
-	getTabContainer()[PANEL_PICKS] = panel_picks;
+//////////////////////////////////////////////////////////////////////////
+// LLPanelProfileSecondLife
 
-	return TRUE;
+LLPanelProfileSecondLife::LLPanelProfileSecondLife()
+    : LLPanelProfileTab()
+    , mAvatarNameCacheConnection()
+    , mHasUnsavedDescriptionChanges(false)
+    , mWaitingForImageUpload(false)
+    , mAllowPublish(false)
+{
 }
 
-// virtual
-void LLPanelProfile::reshape(S32 width, S32 height, BOOL called_from_parent)
+LLPanelProfileSecondLife::~LLPanelProfileSecondLife()
 {
-	// Temporarily add saved children back and reshape them.
-	mChildStack.preParentReshape();
-	LLPanel::reshape(width, height, called_from_parent);
-	mChildStack.postParentReshape();
+    if (getAvatarId().notNull())
+    {
+        LLAvatarTracker::instance().removeParticularFriendObserver(getAvatarId(), this);
+    }
+
+    if (LLVoiceClient::instanceExists())
+    {
+        LLVoiceClient::getInstance()->removeObserver((LLVoiceClientStatusObserver*)this);
+    }
+
+    if (mAvatarNameCacheConnection.connected())
+    {
+        mAvatarNameCacheConnection.disconnect();
+    }
 }
 
-void LLPanelProfile::onOpen(const LLSD& key)
+BOOL LLPanelProfileSecondLife::postBuild()
 {
-	getTabContainer()[PANEL_PICKS]->onOpen(getAvatarId());
+    mGroupList              = getChild<LLGroupList>("group_list");
+    mShowInSearchCombo      = getChild<LLComboBox>("show_in_search");
+    mSecondLifePic          = getChild<LLIconCtrl>("2nd_life_pic");
+    mSecondLifePicLayout    = getChild<LLPanel>("image_panel");
+    mDescriptionEdit        = getChild<LLTextEditor>("sl_description_edit");
+    mAgentActionMenuButton  = getChild<LLMenuButton>("agent_actions_menu");
+    mSaveDescriptionChanges = getChild<LLButton>("save_description_changes");
+    mDiscardDescriptionChanges = getChild<LLButton>("discard_description_changes");
+    mCanSeeOnlineIcon       = getChild<LLIconCtrl>("can_see_online");
+    mCantSeeOnlineIcon      = getChild<LLIconCtrl>("cant_see_online");
+    mCanSeeOnMapIcon        = getChild<LLIconCtrl>("can_see_on_map");
+    mCantSeeOnMapIcon       = getChild<LLIconCtrl>("cant_see_on_map");
+    mCanEditObjectsIcon     = getChild<LLIconCtrl>("can_edit_objects");
+    mCantEditObjectsIcon    = getChild<LLIconCtrl>("cant_edit_objects");
 
-	// support commands to open further pieces of UI
-	if (key.has("show_tab_panel"))
-	{
-		std::string panel = key["show_tab_panel"].asString();
-		if (panel == "create_classified")
-		{
-			LLPanelPicks* picks = dynamic_cast<LLPanelPicks *>(getTabContainer()[PANEL_PICKS]);
-			if (picks)
-			{
-				picks->createNewClassified();
-			}
-		}
-		else if (panel == "classified_details")
-		{
-			LLPanelPicks* picks = dynamic_cast<LLPanelPicks *>(getTabContainer()[PANEL_PICKS]);
-			if (picks)
-			{
-				LLSD params = key;
-				params.erase("show_tab_panel");
-				params.erase("open_tab_name");
-				picks->openClassifiedInfo(params);
-			}
-		}
-		else if (panel == "edit_classified")
-		{
-			LLPanelPicks* picks = dynamic_cast<LLPanelPicks *>(getTabContainer()[PANEL_PICKS]);
-			if (picks)
-			{
-				LLSD params = key;
-				params.erase("show_tab_panel");
-				params.erase("open_tab_name");
-				picks->openClassifiedEdit(params);
-			}
-		}
-		else if (panel == "create_pick")
-		{
-			LLPanelPicks* picks = dynamic_cast<LLPanelPicks *>(getTabContainer()[PANEL_PICKS]);
-			if (picks)
-			{
-				picks->createNewPick();
-			}
-		}
-		else if (panel == "edit_pick")
-		{
-			LLPanelPicks* picks = dynamic_cast<LLPanelPicks *>(getTabContainer()[PANEL_PICKS]);
-			if (picks)
-			{
-				LLSD params = key;
-				params.erase("show_tab_panel");
-				params.erase("open_tab_name");
-				picks->openPickEdit(params);
-			}
-		}
-	}
+    mShowInSearchCombo->setCommitCallback([this](LLUICtrl*, void*) { onShowInSearchCallback(); }, nullptr);
+    mGroupList->setDoubleClickCallback([this](LLUICtrl*, S32 x, S32 y, MASK mask) { LLPanelProfileSecondLife::openGroupProfile(); });
+    mGroupList->setReturnCallback([this](LLUICtrl*, const LLSD&) { LLPanelProfileSecondLife::openGroupProfile(); });
+    mSaveDescriptionChanges->setCommitCallback([this](LLUICtrl*, void*) { onSaveDescriptionChanges(); }, nullptr);
+    mDiscardDescriptionChanges->setCommitCallback([this](LLUICtrl*, void*) { onDiscardDescriptionChanges(); }, nullptr);
+    mDescriptionEdit->setKeystrokeCallback([this](LLTextEditor* caller) { onSetDescriptionDirty(); });
+
+    mCanSeeOnlineIcon->setMouseUpCallback([this](LLUICtrl*, S32 x, S32 y, MASK mask) { onShowAgentPermissionsDialog(); });
+    mCantSeeOnlineIcon->setMouseUpCallback([this](LLUICtrl*, S32 x, S32 y, MASK mask) { onShowAgentPermissionsDialog(); });
+    mCanSeeOnMapIcon->setMouseUpCallback([this](LLUICtrl*, S32 x, S32 y, MASK mask) { onShowAgentPermissionsDialog(); });
+    mCantSeeOnMapIcon->setMouseUpCallback([this](LLUICtrl*, S32 x, S32 y, MASK mask) { onShowAgentPermissionsDialog(); });
+    mCanEditObjectsIcon->setMouseUpCallback([this](LLUICtrl*, S32 x, S32 y, MASK mask) { onShowAgentPermissionsDialog(); });
+    mCantEditObjectsIcon->setMouseUpCallback([this](LLUICtrl*, S32 x, S32 y, MASK mask) { onShowAgentPermissionsDialog(); });
+    mSecondLifePic->setMouseUpCallback([this](LLUICtrl*, S32 x, S32 y, MASK mask) { onShowAgentProfileTexture(); });
+
+    return TRUE;
 }
 
-void LLPanelProfile::onTabSelected(const LLSD& param)
+void LLPanelProfileSecondLife::onOpen(const LLSD& key)
 {
-	std::string tab_name = param.asString();
-	if (NULL != getTabContainer()[tab_name])
-	{
-		getTabContainer()[tab_name]->onOpen(getAvatarId());
-	}
+    LLPanelProfileTab::onOpen(key);
+
+    resetData();
+
+    LLUUID avatar_id = getAvatarId();
+
+    BOOL own_profile = getSelfProfile();
+
+    mGroupList->setShowNone(!own_profile);
+
+    childSetVisible("notes_panel", !own_profile);
+    childSetVisible("settings_panel", own_profile);
+    childSetVisible("about_buttons_panel", own_profile);
+
+    if (own_profile)
+    {
+        // Group list control cannot toggle ForAgent loading
+        // Less than ideal, but viewing own profile via search is edge case
+        mGroupList->enableForAgent(false);
+    }
+
+    // Init menu, menu needs to be created in scope of a registar to work correctly.
+    LLUICtrl::CommitCallbackRegistry::ScopedRegistrar commit;
+    commit.add("Profile.Commit", [this](LLUICtrl*, const LLSD& userdata) { onCommitMenu(userdata); });
+
+    LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable;
+    enable.add("Profile.EnableItem", [this](LLUICtrl*, const LLSD& userdata) { return onEnableMenu(userdata); });
+    enable.add("Profile.CheckItem", [this](LLUICtrl*, const LLSD& userdata) { return onCheckMenu(userdata); });
+
+    if (own_profile)
+    {
+        mAgentActionMenuButton->setMenu("menu_profile_self.xml", LLMenuButton::MP_BOTTOM_RIGHT);
+    }
+    else
+    {
+        // Todo: use PeopleContextMenu instead?
+        mAgentActionMenuButton->setMenu("menu_profile_other.xml", LLMenuButton::MP_BOTTOM_RIGHT);
+    }
+
+    mDescriptionEdit->setParseHTML(!own_profile);
+
+    if (!own_profile)
+    {
+        mVoiceStatus = LLAvatarActions::canCall() && (LLAvatarActions::isFriend(avatar_id) ? LLAvatarTracker::instance().isBuddyOnline(avatar_id) : TRUE);
+        updateOnlineStatus();
+        fillRightsData();
+    }
+
+    mAvatarNameCacheConnection = LLAvatarNameCache::get(getAvatarId(), boost::bind(&LLPanelProfileSecondLife::onAvatarNameCache, this, _1, _2));
 }
 
-void LLPanelProfile::openPanel(LLPanel* panel, const LLSD& params)
+void LLPanelProfileSecondLife::updateData()
 {
-	// Hide currently visible panel (STORM-690).
-	mChildStack.push();
+    LLUUID avatar_id = getAvatarId();
+    if (!getStarted() && avatar_id.notNull())
+    {
+        setIsLoading();
 
-	// Add the panel or bring it to front.
-	if (panel->getParent() != this)
-	{
-		addChild(panel);
-	}
-	else
-	{
-		sendChildToFront(panel);
-	}
+        std::string cap_url = gAgent.getRegionCapability(PROFILE_PROPERTIES_CAP);
+        if (!cap_url.empty())
+        {
+            LLCoros::instance().launch("requestAgentUserInfoCoro",
+                boost::bind(request_avatar_properties_coro, cap_url, avatar_id));
+        }
+        else
+        {
+            LL_WARNS() << "Failed to update profile data, no cap found" << LL_ENDL;
+        }
+    }
+}
 
-	panel->setVisible(TRUE);
-	panel->setFocus(TRUE); // prevent losing focus by the floater
-	panel->onOpen(params);
+void LLPanelProfileSecondLife::refreshName()
+{
+    if (!mAvatarNameCacheConnection.connected())
+    {
+        mAvatarNameCacheConnection = LLAvatarNameCache::get(getAvatarId(), boost::bind(&LLPanelProfileSecondLife::onAvatarNameCache, this, _1, _2));
+    }
+}
+
+void LLPanelProfileSecondLife::resetData()
+{
+    resetLoading();
+
+    // Set default image and 1:1 dimensions for it
+    mSecondLifePic->setValue("Generic_Person_Large");
+    mImageId = LLUUID::null;
+
+    LLRect imageRect = mSecondLifePicLayout->getRect();
+    mSecondLifePicLayout->reshape(imageRect.getHeight(), imageRect.getHeight());
+
+    setDescriptionText(LLStringUtil::null);
+    mGroups.clear();
+    mGroupList->setGroups(mGroups);
+
+    bool own_profile = getSelfProfile();
+    mCanSeeOnlineIcon->setVisible(false);
+    mCantSeeOnlineIcon->setVisible(!own_profile);
+    mCanSeeOnMapIcon->setVisible(false);
+    mCantSeeOnMapIcon->setVisible(!own_profile);
+    mCanEditObjectsIcon->setVisible(false);
+    mCantEditObjectsIcon->setVisible(!own_profile);
 
-	LLRect new_rect = getRect();
-	panel->reshape(new_rect.getWidth(), new_rect.getHeight());
-	new_rect.setLeftTopAndSize(0, new_rect.getHeight(), new_rect.getWidth(), new_rect.getHeight());
-	panel->setRect(new_rect);
+    mCanSeeOnlineIcon->setEnabled(false);
+    mCantSeeOnlineIcon->setEnabled(false);
+    mCanSeeOnMapIcon->setEnabled(false);
+    mCantSeeOnMapIcon->setEnabled(false);
+    mCanEditObjectsIcon->setEnabled(false);
+    mCantEditObjectsIcon->setEnabled(false);
+
+    childSetVisible("partner_layout", FALSE);
 }
 
-void LLPanelProfile::closePanel(LLPanel* panel)
+void LLPanelProfileSecondLife::processProfileProperties(const LLAvatarData* avatar_data)
 {
-	panel->setVisible(FALSE);
+    LLUUID avatar_id = getAvatarId();
+    const LLRelationship* relationship = LLAvatarTracker::instance().getBuddyInfo(getAvatarId());
+    if ((relationship != NULL || gAgent.isGodlike()) && !getSelfProfile())
+    {
+        // Relies onto friend observer to get information about online status updates.
+        // Once SL-17506 gets implemented, condition might need to become:
+        // (gAgent.isGodlike() || isRightGrantedFrom || flags & AVATAR_ONLINE)
+        processOnlineStatus(relationship != NULL,
+                            gAgent.isGodlike() || relationship->isRightGrantedFrom(LLRelationship::GRANT_ONLINE_STATUS),
+                            (avatar_data->flags & AVATAR_ONLINE));
+    }
 
-	if (panel->getParent() == this) 
-	{
-		removeChild(panel);
+    fillCommonData(avatar_data);
 
-		// Make the underlying panel visible.
-		mChildStack.pop();
+    fillPartnerData(avatar_data);
 
-		// Prevent losing focus by the floater
-		const child_list_t* child_list = getChildList();
-		if (child_list->size() > 0)
-		{
-			child_list->front()->setFocus(TRUE);
-		}
-		else
-		{
-			LL_WARNS() << "No underlying panel to focus." << LL_ENDL;
-		}
-	}
+    fillAccountStatus(avatar_data);
+
+    setLoaded();
 }
 
-S32 LLPanelProfile::notifyParent(const LLSD& info)
+void LLPanelProfileSecondLife::processGroupProperties(const LLAvatarGroups* avatar_groups)
 {
-	std::string action = info["action"];
-	// lets update Picks list after Pick was saved
-	if("save_new_pick" == action)
-	{
-		onOpen(info);
-		return 1;
-	}
 
-	return LLPanel::notifyParent(info);
+    LLAvatarGroups::group_list_t::const_iterator it = avatar_groups->group_list.begin();
+    const LLAvatarGroups::group_list_t::const_iterator it_end = avatar_groups->group_list.end();
+
+    for (; it_end != it; ++it)
+    {
+        LLAvatarGroups::LLGroupData group_data = *it;
+        mGroups[group_data.group_name] = group_data.group_id;
+    }
+
+    mGroupList->setGroups(mGroups);
+}
+
+void LLPanelProfileSecondLife::openGroupProfile()
+{
+    LLUUID group_id = mGroupList->getSelectedUUID();
+    LLGroupActions::show(group_id);
+}
+
+void LLPanelProfileSecondLife::onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name)
+{
+    mAvatarNameCacheConnection.disconnect();
+    getChild<LLUICtrl>("display_name")->setValue(av_name.getDisplayName());
+    getChild<LLUICtrl>("user_name")->setValue(av_name.getAccountName());
+}
+
+void LLPanelProfileSecondLife::setProfileImageUploading(bool loading)
+{
+    LLLoadingIndicator* indicator = getChild<LLLoadingIndicator>("image_upload_indicator");
+    indicator->setVisible(loading);
+    if (loading)
+    {
+        indicator->start();
+    }
+    else
+    {
+        indicator->stop();
+    }
+    mWaitingForImageUpload = loading;
+}
+
+void LLPanelProfileSecondLife::setProfileImageUploaded(const LLUUID &image_asset_id)
+{
+    mSecondLifePic->setValue(image_asset_id);
+    mImageId = image_asset_id;
+
+    LLViewerFetchedTexture* imagep = LLViewerTextureManager::getFetchedTexture(image_asset_id);
+    if (imagep->getFullHeight())
+    {
+        onImageLoaded(true, imagep);
+    }
+    else
+    {
+        imagep->setLoadedCallback(onImageLoaded,
+            MAX_DISCARD_LEVEL,
+            FALSE,
+            FALSE,
+            new LLHandle<LLPanel>(getHandle()),
+            NULL,
+            FALSE);
+    }
+
+    LLFloater *floater = mFloaterProfileTextureHandle.get();
+    if (floater)
+    {
+        LLFloaterProfileTexture * texture_view = dynamic_cast<LLFloaterProfileTexture*>(floater);
+        if (mImageId.notNull())
+        {
+            texture_view->loadAsset(mImageId);
+        }
+        else
+        {
+            texture_view->resetAsset();
+        }
+    }
+
+    setProfileImageUploading(false);
+}
+
+bool LLPanelProfileSecondLife::hasUnsavedChanges()
+{
+    LLFloater *floater = mFloaterPermissionsHandle.get();
+    if (floater)
+    {
+        LLFloaterProfilePermissions* perm = dynamic_cast<LLFloaterProfilePermissions*>(floater);
+        if (perm && perm->hasUnsavedChanges())
+        {
+            return true;
+        }
+    }
+    // if floater
+    return mHasUnsavedDescriptionChanges;
+}
+
+void LLPanelProfileSecondLife::commitUnsavedChanges()
+{
+    LLFloater *floater = mFloaterPermissionsHandle.get();
+    if (floater)
+    {
+        LLFloaterProfilePermissions* perm = dynamic_cast<LLFloaterProfilePermissions*>(floater);
+        if (perm && perm->hasUnsavedChanges())
+        {
+            perm->onApplyRights();
+        }
+    }
+    if (mHasUnsavedDescriptionChanges)
+    {
+        onSaveDescriptionChanges();
+    }
+}
+
+void LLPanelProfileSecondLife::fillCommonData(const LLAvatarData* avatar_data)
+{
+    // Refresh avatar id in cache with new info to prevent re-requests
+    // and to make sure icons in text will be up to date
+    LLAvatarIconIDCache::getInstance()->add(avatar_data->avatar_id, avatar_data->image_id);
+
+    fillAgeData(avatar_data->born_on);
+
+    setDescriptionText(avatar_data->about_text);
+
+    if (avatar_data->image_id.notNull())
+    {
+        mSecondLifePic->setValue(avatar_data->image_id);
+        mImageId = avatar_data->image_id;
+    }
+    else
+    {
+        mSecondLifePic->setValue("Generic_Person_Large");
+        mImageId = LLUUID::null;
+    }
+
+    // Will be loaded as a LLViewerFetchedTexture::BOOST_UI due to mSecondLifePic
+    LLViewerFetchedTexture* imagep = LLViewerTextureManager::getFetchedTexture(avatar_data->image_id);
+    if (imagep->getFullHeight())
+    {
+        onImageLoaded(true, imagep);
+    }
+    else
+    {
+        imagep->setLoadedCallback(onImageLoaded,
+                                  MAX_DISCARD_LEVEL,
+                                  FALSE,
+                                  FALSE,
+                                  new LLHandle<LLPanel>(getHandle()),
+                                  NULL,
+                                  FALSE);
+    }
+
+    if (getSelfProfile())
+    {
+        mAllowPublish = avatar_data->flags & AVATAR_ALLOW_PUBLISH;
+        mShowInSearchCombo->setValue((BOOL)mAllowPublish);
+    }
+}
+
+void LLPanelProfileSecondLife::fillPartnerData(const LLAvatarData* avatar_data)
+{
+    LLTextBox* partner_text_ctrl = getChild<LLTextBox>("partner_link");
+    if (avatar_data->partner_id.notNull())
+    {
+        childSetVisible("partner_layout", TRUE);
+        LLStringUtil::format_map_t args;
+        args["[LINK]"] = LLSLURL("agent", avatar_data->partner_id, "inspect").getSLURLString();
+        std::string partner_text = getString("partner_text", args);
+        partner_text_ctrl->setText(partner_text);
+    }
+    else
+    {
+        childSetVisible("partner_layout", FALSE);
+    }
+}
+
+void LLPanelProfileSecondLife::fillAccountStatus(const LLAvatarData* avatar_data)
+{
+    LLStringUtil::format_map_t args;
+    args["[ACCTTYPE]"] = LLAvatarPropertiesProcessor::accountType(avatar_data);
+    args["[PAYMENTINFO]"] = LLAvatarPropertiesProcessor::paymentInfo(avatar_data);
+
+    std::string caption_text = getString("CaptionTextAcctInfo", args);
+    getChild<LLUICtrl>("account_info")->setValue(caption_text);
 }
+
+void LLPanelProfileSecondLife::fillRightsData()
+{
+    if (getSelfProfile())
+    {
+        return;
+    }
+
+    const LLRelationship* relation = LLAvatarTracker::instance().getBuddyInfo(getAvatarId());
+    // If true - we are viewing friend's profile, enable check boxes and set values.
+    if (relation)
+    {
+        S32 rights = relation->getRightsGrantedTo();
+        bool can_see_online = LLRelationship::GRANT_ONLINE_STATUS & rights;
+        bool can_see_on_map = LLRelationship::GRANT_MAP_LOCATION & rights;
+        bool can_edit_objects = LLRelationship::GRANT_MODIFY_OBJECTS & rights;
+
+        mCanSeeOnlineIcon->setVisible(can_see_online);
+        mCantSeeOnlineIcon->setVisible(!can_see_online);
+        mCanSeeOnMapIcon->setVisible(can_see_on_map);
+        mCantSeeOnMapIcon->setVisible(!can_see_on_map);
+        mCanEditObjectsIcon->setVisible(can_edit_objects);
+        mCantEditObjectsIcon->setVisible(!can_edit_objects);
+
+        mCanSeeOnlineIcon->setEnabled(true);
+        mCantSeeOnlineIcon->setEnabled(true);
+        mCanSeeOnMapIcon->setEnabled(true);
+        mCantSeeOnMapIcon->setEnabled(true);
+        mCanEditObjectsIcon->setEnabled(true);
+        mCantEditObjectsIcon->setEnabled(true);
+    }
+    else
+    {
+        mCanSeeOnlineIcon->setVisible(false);
+        mCantSeeOnlineIcon->setVisible(false);
+        mCanSeeOnMapIcon->setVisible(false);
+        mCantSeeOnMapIcon->setVisible(false);
+        mCanEditObjectsIcon->setVisible(false);
+        mCantEditObjectsIcon->setVisible(false);
+    }
+}
+
+void LLPanelProfileSecondLife::fillAgeData(const LLDate &born_on)
+{
+    std::string name_and_date = getString("date_format");
+    LLSD args_name;
+    args_name["datetime"] = (S32)born_on.secondsSinceEpoch();
+    LLStringUtil::format(name_and_date, args_name);
+    getChild<LLUICtrl>("sl_birth_date")->setValue(name_and_date);
+
+    std::string register_date = getString("age_format");
+    LLSD args_age;
+    args_age["[AGE]"] = LLDateUtil::ageFromDate(born_on, LLDate::now());
+    LLStringUtil::format(register_date, args_age);
+    getChild<LLUICtrl>("user_age")->setValue(register_date);
+}
+
+void LLPanelProfileSecondLife::onImageLoaded(BOOL success, LLViewerFetchedTexture *imagep)
+{
+    LLRect imageRect = mSecondLifePicLayout->getRect();
+    if (!success || imagep->getFullWidth() == imagep->getFullHeight())
+    {
+        mSecondLifePicLayout->reshape(imageRect.getWidth(), imageRect.getWidth());
+    }
+    else
+    {
+        // assume 3:4, for sake of firestorm
+        mSecondLifePicLayout->reshape(imageRect.getWidth(), imageRect.getWidth() * 3 / 4);
+    }
+}
+
+//static
+void LLPanelProfileSecondLife::onImageLoaded(BOOL success,
+                                             LLViewerFetchedTexture *src_vi,
+                                             LLImageRaw* src,
+                                             LLImageRaw* aux_src,
+                                             S32 discard_level,
+                                             BOOL final,
+                                             void* userdata)
+{
+    if (!userdata) return;
+
+    LLHandle<LLPanel>* handle = (LLHandle<LLPanel>*)userdata;
+
+    if (!handle->isDead())
+    {
+        LLPanelProfileSecondLife* panel = static_cast<LLPanelProfileSecondLife*>(handle->get());
+        if (panel)
+        {
+            panel->onImageLoaded(success, src_vi);
+        }
+    }
+
+    if (final || !success)
+    {
+        delete handle;
+    }
+}
+
+// virtual, called by LLAvatarTracker
+void LLPanelProfileSecondLife::changed(U32 mask)
+{
+    updateOnlineStatus();
+    if (mask != LLFriendObserver::ONLINE)
+    {
+        fillRightsData();
+    }
+}
+
+// virtual, called by LLVoiceClient
+void LLPanelProfileSecondLife::onChange(EStatusType status, const std::string &channelURI, bool proximal)
+{
+    if(status == STATUS_JOINING || status == STATUS_LEFT_CHANNEL)
+    {
+        return;
+    }
+
+    mVoiceStatus = LLAvatarActions::canCall() && (LLAvatarActions::isFriend(getAvatarId()) ? LLAvatarTracker::instance().isBuddyOnline(getAvatarId()) : TRUE);
+}
+
+void LLPanelProfileSecondLife::setAvatarId(const LLUUID& avatar_id)
+{
+    if (avatar_id.notNull())
+    {
+        if (getAvatarId().notNull())
+        {
+            LLAvatarTracker::instance().removeParticularFriendObserver(getAvatarId(), this);
+        }
+
+        LLPanelProfileTab::setAvatarId(avatar_id);
+
+        if (LLAvatarActions::isFriend(getAvatarId()))
+        {
+            LLAvatarTracker::instance().addParticularFriendObserver(getAvatarId(), this);
+        }
+    }
+}
+
+// method was disabled according to EXT-2022. Re-enabled & improved according to EXT-3880
+void LLPanelProfileSecondLife::updateOnlineStatus()
+{
+    const LLRelationship* relationship = LLAvatarTracker::instance().getBuddyInfo(getAvatarId());
+    if (relationship != NULL)
+    {
+        // For friend let check if he allowed me to see his status
+        bool online = relationship->isOnline();
+        bool perm_granted = relationship->isRightGrantedFrom(LLRelationship::GRANT_ONLINE_STATUS);
+        processOnlineStatus(true, perm_granted, online);
+    }
+    else
+    {
+        childSetVisible("frind_layout", false);
+        childSetVisible("online_layout", false);
+        childSetVisible("offline_layout", false);
+    }
+}
+
+void LLPanelProfileSecondLife::processOnlineStatus(bool is_friend, bool show_online, bool online)
+{
+    childSetVisible("frind_layout", is_friend);
+    childSetVisible("online_layout", online && show_online);
+    childSetVisible("offline_layout", !online && show_online);
+}
+
+void LLPanelProfileSecondLife::setLoaded()
+{
+    LLPanelProfileTab::setLoaded();
+
+    if (getSelfProfile())
+    {
+        mShowInSearchCombo->setEnabled(TRUE);
+        mDescriptionEdit->setEnabled(TRUE);
+    }
+}
+
+
+
+class LLProfileImagePicker : public LLFilePickerThread
+{
+public:
+    LLProfileImagePicker(EProfileImageType type, LLHandle<LLPanel> *handle);
+    ~LLProfileImagePicker();
+    void notify(const std::vector<std::string>& filenames) override;
+
+private:
+    LLHandle<LLPanel> *mHandle;
+    EProfileImageType mType;
+};
+
+LLProfileImagePicker::LLProfileImagePicker(EProfileImageType type, LLHandle<LLPanel> *handle)
+    : LLFilePickerThread(LLFilePicker::FFLOAD_IMAGE),
+    mHandle(handle),
+    mType(type)
+{
+}
+
+LLProfileImagePicker::~LLProfileImagePicker()
+{
+    delete mHandle;
+}
+
+void LLProfileImagePicker::notify(const std::vector<std::string>& filenames)
+{
+    if (mHandle->isDead())
+    {
+        return;
+    }
+    if (filenames.empty())
+    {
+        return;
+    }
+    std::string file_path = filenames[0];
+    if (file_path.empty())
+    {
+        return;
+    }
+
+    // generate a temp texture file for coroutine
+    std::string temp_file = gDirUtilp->getTempFilename();
+    U32 codec = LLImageBase::getCodecFromExtension(gDirUtilp->getExtension(file_path));
+    const S32 MAX_DIM = 256;
+    if (!LLViewerTextureList::createUploadFile(file_path, temp_file, codec, MAX_DIM))
+    {
+        //todo: image not supported notification
+        LL_WARNS("AvatarProperties") << "Failed to upload profile image of type " << (S32)PROFILE_IMAGE_SL << ", failed to open image" << LL_ENDL;
+        return;
+    }
+
+    std::string cap_url = gAgent.getRegionCapability(PROFILE_IMAGE_UPLOAD_CAP);
+    if (cap_url.empty())
+    {
+        LL_WARNS("AvatarProperties") << "Failed to upload profile image of type " << (S32)PROFILE_IMAGE_SL << ", no cap found" << LL_ENDL;
+        return;
+    }
+
+    switch (mType)
+    {
+    case PROFILE_IMAGE_SL:
+        {
+            LLPanelProfileSecondLife* panel = static_cast<LLPanelProfileSecondLife*>(mHandle->get());
+            panel->setProfileImageUploading(true);
+        }
+        break;
+    case PROFILE_IMAGE_FL:
+        {
+            LLPanelProfileFirstLife* panel = static_cast<LLPanelProfileFirstLife*>(mHandle->get());
+            panel->setProfileImageUploading(true);
+        }
+        break;
+    }
+
+    LLCoros::instance().launch("postAgentUserImageCoro",
+        boost::bind(post_profile_image_coro, cap_url, mType, temp_file, mHandle));
+
+    mHandle = nullptr; // transferred to post_profile_image_coro
+}
+
+void LLPanelProfileSecondLife::onCommitMenu(const LLSD& userdata)
+{
+    const std::string item_name = userdata.asString();
+    const LLUUID agent_id = getAvatarId();
+    // todo: consider moving this into LLAvatarActions::onCommit(name, id)
+    // and making all other flaoters, like people menu do the same
+    if (item_name == "im")
+    {
+        LLAvatarActions::startIM(agent_id);
+    }
+    else if (item_name == "offer_teleport")
+    {
+        LLAvatarActions::offerTeleport(agent_id);
+    }
+    else if (item_name == "request_teleport")
+    {
+        LLAvatarActions::teleportRequest(agent_id);
+    }
+    else if (item_name == "voice_call")
+    {
+        LLAvatarActions::startCall(agent_id);
+    }
+    else if (item_name == "chat_history")
+    {
+        LLAvatarActions::viewChatHistory(agent_id);
+    }
+    else if (item_name == "add_friend")
+    {
+        LLAvatarActions::requestFriendshipDialog(agent_id);
+    }
+    else if (item_name == "remove_friend")
+    {
+        LLAvatarActions::removeFriendDialog(agent_id);
+    }
+    else if (item_name == "invite_to_group")
+    {
+        LLAvatarActions::inviteToGroup(agent_id);
+    }
+    else if (item_name == "can_show_on_map")
+    {
+        LLAvatarActions::showOnMap(agent_id);
+    }
+    else if (item_name == "share")
+    {
+        LLAvatarActions::share(agent_id);
+    }
+    else if (item_name == "pay")
+    {
+        LLAvatarActions::pay(agent_id);
+    }
+    else if (item_name == "toggle_block_agent")
+    {
+        LLAvatarActions::toggleBlock(agent_id);
+    }
+    else if (item_name == "copy_user_id")
+    {
+        LLWString wstr = utf8str_to_wstring(getAvatarId().asString());
+        LLClipboard::instance().copyToClipboard(wstr, 0, wstr.size());
+    }
+    else if (item_name == "agent_permissions")
+    {
+        onShowAgentPermissionsDialog();
+    }
+    else if (item_name == "copy_display_name"
+        || item_name == "copy_username")
+    {
+        LLAvatarName av_name;
+        if (!LLAvatarNameCache::get(getAvatarId(), &av_name))
+        {
+            // shouldn't happen, option is supposed to be invisible while name is fetching
+            LL_WARNS() << "Failed to get agent data" << LL_ENDL;
+            return;
+        }
+        LLWString wstr;
+        if (item_name == "copy_display_name")
+        {
+            wstr = utf8str_to_wstring(av_name.getDisplayName(true));
+        }
+        else if (item_name == "copy_username")
+        {
+            wstr = utf8str_to_wstring(av_name.getUserName());
+        }
+        LLClipboard::instance().copyToClipboard(wstr, 0, wstr.size());
+    }
+    else if (item_name == "edit_display_name")
+    {
+        LLAvatarNameCache::get(getAvatarId(), boost::bind(&LLPanelProfileSecondLife::onAvatarNameCacheSetName, this, _1, _2));
+        LLFirstUse::setDisplayName(false);
+    }
+    else if (item_name == "edit_partner")
+    {
+        std::string url = "https://[GRID]/my/account/partners.php";
+        LLSD subs;
+        url = LLWeb::expandURLSubstitutions(url, subs);
+        LLUrlAction::openURL(url);
+    }
+    else if (item_name == "upload_photo")
+    {
+        (new LLProfileImagePicker(PROFILE_IMAGE_SL, new LLHandle<LLPanel>(getHandle())))->getFile();
+
+        LLFloater* floaterp = mFloaterTexturePickerHandle.get();
+        if (floaterp)
+        {
+            floaterp->closeFloater();
+        }
+    }
+    else if (item_name == "change_photo")
+    {
+        onShowTexturePicker();
+    }
+    else if (item_name == "remove_photo")
+    {
+        onCommitProfileImage(LLUUID::null);
+
+        LLFloater* floaterp = mFloaterTexturePickerHandle.get();
+        if (floaterp)
+        {
+            floaterp->closeFloater();
+        }
+    }
+}
+
+bool LLPanelProfileSecondLife::onEnableMenu(const LLSD& userdata)
+{
+    const std::string item_name = userdata.asString();
+    const LLUUID agent_id = getAvatarId();
+    if (item_name == "offer_teleport" || item_name == "request_teleport")
+    {
+        return LLAvatarActions::canOfferTeleport(agent_id);
+    }
+    else if (item_name == "voice_call")
+    {
+        return mVoiceStatus;
+    }
+    else if (item_name == "chat_history")
+    {
+        return LLLogChat::isTranscriptExist(agent_id);
+    }
+    else if (item_name == "add_friend")
+    {
+        return !LLAvatarActions::isFriend(agent_id);
+    }
+    else if (item_name == "remove_friend")
+    {
+        return LLAvatarActions::isFriend(agent_id);
+    }
+    else if (item_name == "can_show_on_map")
+    {
+        return (LLAvatarTracker::instance().isBuddyOnline(agent_id) && is_agent_mappable(agent_id))
+        || gAgent.isGodlike();
+    }
+    else if (item_name == "toggle_block_agent")
+    {
+        return LLAvatarActions::canBlock(agent_id);
+    }
+    else if (item_name == "agent_permissions")
+    {
+        return LLAvatarActions::isFriend(agent_id);
+    }
+    else if (item_name == "copy_display_name"
+        || item_name == "copy_username")
+    {
+        return !mAvatarNameCacheConnection.connected();
+    }
+    else if (item_name == "upload_photo"
+        || item_name == "change_photo")
+    {
+        std::string cap_url = gAgent.getRegionCapability(PROFILE_IMAGE_UPLOAD_CAP);
+        return !cap_url.empty() && !mWaitingForImageUpload && getIsLoaded();
+    }
+    else if (item_name == "remove_photo")
+    {
+        std::string cap_url = gAgent.getRegionCapability(PROFILE_PROPERTIES_CAP);
+        return mImageId.notNull() && !cap_url.empty() && !mWaitingForImageUpload && getIsLoaded();
+    }
+
+    return false;
+}
+
+bool LLPanelProfileSecondLife::onCheckMenu(const LLSD& userdata)
+{
+    const std::string item_name = userdata.asString();
+    const LLUUID agent_id = getAvatarId();
+    if (item_name == "toggle_block_agent")
+    {
+        return LLAvatarActions::isBlocked(agent_id);
+    }
+    return false;
+}
+
+void LLPanelProfileSecondLife::onAvatarNameCacheSetName(const LLUUID& agent_id, const LLAvatarName& av_name)
+{
+    if (av_name.getDisplayName().empty())
+    {
+        // something is wrong, tell user to try again later
+        LLNotificationsUtil::add("SetDisplayNameFailedGeneric");
+        return;
+    }
+
+    LL_INFOS("LegacyProfile") << "name-change now " << LLDate::now() << " next_update "
+        << LLDate(av_name.mNextUpdate) << LL_ENDL;
+    F64 now_secs = LLDate::now().secondsSinceEpoch();
+
+    if (now_secs < av_name.mNextUpdate)
+    {
+        // if the update time is more than a year in the future, it means updates have been blocked
+        // show a more general message
+        static const S32 YEAR = 60*60*24*365;
+        if (now_secs + YEAR < av_name.mNextUpdate)
+        {
+            LLNotificationsUtil::add("SetDisplayNameBlocked");
+            return;
+        }
+    }
+
+    LLFloaterReg::showInstance("display_name");
+}
+
+void LLPanelProfileSecondLife::setDescriptionText(const std::string &text)
+{
+    mSaveDescriptionChanges->setEnabled(FALSE);
+    mDiscardDescriptionChanges->setEnabled(FALSE);
+    mHasUnsavedDescriptionChanges = false;
+
+    mDescriptionText = text;
+    mDescriptionEdit->setValue(mDescriptionText);
+}
+
+void LLPanelProfileSecondLife::onSetDescriptionDirty()
+{
+    mSaveDescriptionChanges->setEnabled(TRUE);
+    mDiscardDescriptionChanges->setEnabled(TRUE);
+    mHasUnsavedDescriptionChanges = true;
+}
+
+void LLPanelProfileSecondLife::onShowInSearchCallback()
+{
+    S32 value = mShowInSearchCombo->getValue().asInteger();
+    if (mAllowPublish == (bool)value)
+    {
+        return;
+    }
+    std::string cap_url = gAgent.getRegionCapability(PROFILE_PROPERTIES_CAP);
+    if (!cap_url.empty())
+    {
+        mAllowPublish = value;
+        LLSD data;
+        data["allow_publish"] = mAllowPublish;
+        LLCoros::instance().launch("putAgentUserInfoCoro",
+            boost::bind(put_avatar_properties_coro, cap_url, getAvatarId(), data));
+    }
+    else
+    {
+        LL_WARNS("AvatarProperties") << "Failed to update profile data, no cap found" << LL_ENDL;
+    }
+}
+
+void LLPanelProfileSecondLife::onSaveDescriptionChanges()
+{
+    mDescriptionText = mDescriptionEdit->getValue().asString();
+    std::string cap_url = gAgent.getRegionCapability(PROFILE_PROPERTIES_CAP);
+    if (!cap_url.empty())
+    {
+        LLCoros::instance().launch("putAgentUserInfoCoro",
+            boost::bind(put_avatar_properties_coro, cap_url, getAvatarId(), LLSD().with("sl_about_text", mDescriptionText)));
+    }
+    else
+    {
+        LL_WARNS("AvatarProperties") << "Failed to update profile data, no cap found" << LL_ENDL;
+    }
+
+    mSaveDescriptionChanges->setEnabled(FALSE);
+    mDiscardDescriptionChanges->setEnabled(FALSE);
+    mHasUnsavedDescriptionChanges = false;
+}
+
+void LLPanelProfileSecondLife::onDiscardDescriptionChanges()
+{
+    setDescriptionText(mDescriptionText);
+}
+
+void LLPanelProfileSecondLife::onShowAgentPermissionsDialog()
+{
+    LLFloater *floater = mFloaterPermissionsHandle.get();
+    if (!floater)
+    {
+        LLFloater* parent_floater = gFloaterView->getParentFloater(this);
+        if (parent_floater)
+        {
+            LLFloaterProfilePermissions * perms = new LLFloaterProfilePermissions(parent_floater, getAvatarId());
+            mFloaterPermissionsHandle = perms->getHandle();
+            perms->openFloater();
+            perms->setVisibleAndFrontmost(TRUE);
+
+            parent_floater->addDependentFloater(mFloaterPermissionsHandle);
+        }
+    }
+    else // already open
+    {
+        floater->setMinimized(FALSE);
+        floater->setVisibleAndFrontmost(TRUE);
+    }
+}
+
+void LLPanelProfileSecondLife::onShowAgentProfileTexture()
+{
+    if (!getIsLoaded())
+    {
+        return;
+    }
+
+    LLFloater *floater = mFloaterProfileTextureHandle.get();
+    if (!floater)
+    {
+        LLFloater* parent_floater = gFloaterView->getParentFloater(this);
+        if (parent_floater)
+        {
+            LLFloaterProfileTexture * texture_view = new LLFloaterProfileTexture(parent_floater);
+            mFloaterProfileTextureHandle = texture_view->getHandle();
+            if (mImageId.notNull())
+            {
+                texture_view->loadAsset(mImageId);
+            }
+            else
+            {
+                texture_view->resetAsset();
+            }
+            texture_view->openFloater();
+            texture_view->setVisibleAndFrontmost(TRUE);
+
+            parent_floater->addDependentFloater(mFloaterProfileTextureHandle);
+        }
+    }
+    else // already open
+    {
+        LLFloaterProfileTexture * texture_view = dynamic_cast<LLFloaterProfileTexture*>(floater);
+        texture_view->setMinimized(FALSE);
+        texture_view->setVisibleAndFrontmost(TRUE);
+        if (mImageId.notNull())
+        {
+            texture_view->loadAsset(mImageId);
+        }
+        else
+        {
+            texture_view->resetAsset();
+        }
+    }
+}
+
+void LLPanelProfileSecondLife::onShowTexturePicker()
+{
+    LLFloater* floaterp = mFloaterTexturePickerHandle.get();
+
+    // Show the dialog
+    if (!floaterp)
+    {
+        LLFloater* parent_floater = gFloaterView->getParentFloater(this);
+        if (parent_floater)
+        {
+            // because inventory construction is somewhat slow
+            getWindow()->setCursor(UI_CURSOR_WAIT);
+            LLFloaterTexturePicker* texture_floaterp = new LLFloaterTexturePicker(
+                this,
+                mImageId,
+                LLUUID::null,
+                mImageId,
+                FALSE,
+                FALSE,
+                "SELECT PHOTO",
+                PERM_NONE,
+                PERM_NONE,
+                PERM_NONE,
+                FALSE,
+                NULL);
+
+            mFloaterTexturePickerHandle = texture_floaterp->getHandle();
+
+            texture_floaterp->setOnFloaterCommitCallback([this](LLTextureCtrl::ETexturePickOp op, LLUUID id)
+            {
+                if (op == LLTextureCtrl::TEXTURE_SELECT)
+                {
+                    LLUUID image_asset_id;
+                    LLFloaterTexturePicker* floaterp = (LLFloaterTexturePicker*)mFloaterTexturePickerHandle.get();
+                    if (floaterp)
+                    {
+                        if (id.notNull())
+                        {
+                            image_asset_id = id;
+                        }
+                        else
+                        {
+                            image_asset_id = floaterp->getAssetID();
+                        }
+                    }
+
+                    onCommitProfileImage(image_asset_id);
+                }
+            });
+            texture_floaterp->setLocalTextureEnabled(FALSE);
+            texture_floaterp->setBakeTextureEnabled(FALSE);
+            texture_floaterp->setCanApply(false, true);
+
+            parent_floater->addDependentFloater(mFloaterTexturePickerHandle);
+
+            texture_floaterp->openFloater();
+            texture_floaterp->setFocus(TRUE);
+        }
+    }
+    else
+    {
+        floaterp->setMinimized(FALSE);
+        floaterp->setVisibleAndFrontmost(TRUE);
+    }
+}
+
+void LLPanelProfileSecondLife::onCommitProfileImage(const LLUUID& id)
+{
+    if (mImageId == id)
+    {
+        return;
+    }
+
+    std::string cap_url = gAgent.getRegionCapability(PROFILE_PROPERTIES_CAP);
+    if (!cap_url.empty())
+    {
+        LLSD params;
+        params["sl_image_id"] = id;
+        LLCoros::instance().launch("putAgentUserInfoCoro",
+            boost::bind(put_avatar_properties_coro, cap_url, getAvatarId(), params));
+
+        mImageId = id;
+        if (mImageId == LLUUID::null)
+        {
+            mSecondLifePic->setValue("Generic_Person_Large");
+        }
+        else
+        {
+            mSecondLifePic->setValue(mImageId);
+        }
+
+        LLFloater *floater = mFloaterProfileTextureHandle.get();
+        if (floater)
+        {
+            LLFloaterProfileTexture * texture_view = dynamic_cast<LLFloaterProfileTexture*>(floater);
+            if (mImageId == LLUUID::null)
+            {
+                texture_view->resetAsset();
+            }
+            else
+            {
+                texture_view->loadAsset(mImageId);
+            }
+        }
+    }
+    else
+    {
+        LL_WARNS("AvatarProperties") << "Failed to update profile data, no cap found" << LL_ENDL;
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////
+// LLPanelProfileWeb
+
+LLPanelProfileWeb::LLPanelProfileWeb()
+ : LLPanelProfileTab()
+ , mWebBrowser(NULL)
+ , mAvatarNameCacheConnection()
+{
+}
+
+LLPanelProfileWeb::~LLPanelProfileWeb()
+{
+    if (mAvatarNameCacheConnection.connected())
+    {
+        mAvatarNameCacheConnection.disconnect();
+    }
+}
+
+void LLPanelProfileWeb::onOpen(const LLSD& key)
+{
+    LLPanelProfileTab::onOpen(key);
+
+    resetData();
+
+    mAvatarNameCacheConnection = LLAvatarNameCache::get(getAvatarId(), boost::bind(&LLPanelProfileWeb::onAvatarNameCache, this, _1, _2));
+}
+
+BOOL LLPanelProfileWeb::postBuild()
+{
+    mWebBrowser = getChild<LLMediaCtrl>("profile_html");
+    mWebBrowser->addObserver(this);
+    mWebBrowser->setHomePageUrl("about:blank");
+
+    return TRUE;
+}
+
+void LLPanelProfileWeb::resetData()
+{
+    mWebBrowser->navigateHome();
+}
+
+void LLPanelProfileWeb::updateData()
+{
+    LLUUID avatar_id = getAvatarId();
+    if (!getStarted() && avatar_id.notNull() && !mURLWebProfile.empty())
+    {
+        setIsLoading();
+
+        mWebBrowser->setVisible(TRUE);
+        mPerformanceTimer.start();
+        mWebBrowser->navigateTo(mURLWebProfile, HTTP_CONTENT_TEXT_HTML);
+    }
+}
+
+void LLPanelProfileWeb::onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name)
+{
+    mAvatarNameCacheConnection.disconnect();
+
+    std::string username = av_name.getAccountName();
+    if (username.empty())
+    {
+        username = LLCacheName::buildUsername(av_name.getDisplayName());
+    }
+    else
+    {
+        LLStringUtil::replaceChar(username, ' ', '.');
+    }
+
+    mURLWebProfile = getProfileURL(username, true);
+    if (mURLWebProfile.empty())
+    {
+        return;
+    }
+
+    //if the tab was opened before name was resolved, load the panel now
+    updateData();
+}
+
+void LLPanelProfileWeb::onCommitLoad(LLUICtrl* ctrl)
+{
+    if (!mURLHome.empty())
+    {
+        LLSD::String valstr = ctrl->getValue().asString();
+        if (valstr.empty())
+        {
+            mWebBrowser->setVisible(TRUE);
+            mPerformanceTimer.start();
+            mWebBrowser->navigateTo( mURLHome, HTTP_CONTENT_TEXT_HTML );
+        }
+        else if (valstr == "popout")
+        {
+            // open in viewer's browser, new window
+            LLWeb::loadURLInternal(mURLHome);
+        }
+        else if (valstr == "external")
+        {
+            // open in external browser
+            LLWeb::loadURLExternal(mURLHome);
+        }
+    }
+}
+
+void LLPanelProfileWeb::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event)
+{
+    switch(event)
+    {
+        case MEDIA_EVENT_STATUS_TEXT_CHANGED:
+            childSetValue("status_text", LLSD( self->getStatusText() ) );
+        break;
+
+        case MEDIA_EVENT_NAVIGATE_BEGIN:
+        {
+            if (mFirstNavigate)
+            {
+                mFirstNavigate = false;
+            }
+            else
+            {
+                mPerformanceTimer.start();
+            }
+        }
+        break;
+
+        case MEDIA_EVENT_NAVIGATE_COMPLETE:
+        {
+            LLStringUtil::format_map_t args;
+            args["[TIME]"] = llformat("%.2f", mPerformanceTimer.getElapsedTimeF32());
+            childSetValue("status_text", LLSD( getString("LoadTime", args)) );
+        }
+        break;
+
+        default:
+            // Having a default case makes the compiler happy.
+        break;
+    }
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+
+LLPanelProfileFirstLife::LLPanelProfileFirstLife()
+ : LLPanelProfileTab()
+ , mHasUnsavedChanges(false)
+{
+}
+
+LLPanelProfileFirstLife::~LLPanelProfileFirstLife()
+{
+}
+
+BOOL LLPanelProfileFirstLife::postBuild()
+{
+    mDescriptionEdit = getChild<LLTextEditor>("fl_description_edit");
+    mPicture = getChild<LLIconCtrl>("real_world_pic");
+
+    mUploadPhoto = getChild<LLButton>("fl_upload_image");
+    mChangePhoto = getChild<LLButton>("fl_change_image");
+    mRemovePhoto = getChild<LLButton>("fl_remove_image");
+    mSaveChanges = getChild<LLButton>("fl_save_changes");
+    mDiscardChanges = getChild<LLButton>("fl_discard_changes");
+
+    mUploadPhoto->setCommitCallback([this](LLUICtrl*, void*) { onUploadPhoto(); }, nullptr);
+    mChangePhoto->setCommitCallback([this](LLUICtrl*, void*) { onChangePhoto(); }, nullptr);
+    mRemovePhoto->setCommitCallback([this](LLUICtrl*, void*) { onRemovePhoto(); }, nullptr);
+    mSaveChanges->setCommitCallback([this](LLUICtrl*, void*) { onSaveDescriptionChanges(); }, nullptr);
+    mDiscardChanges->setCommitCallback([this](LLUICtrl*, void*) { onDiscardDescriptionChanges(); }, nullptr);
+    mDescriptionEdit->setKeystrokeCallback([this](LLTextEditor* caller) { onSetDescriptionDirty(); });
+
+    return TRUE;
+}
+
+void LLPanelProfileFirstLife::onOpen(const LLSD& key)
+{
+    LLPanelProfileTab::onOpen(key);
+
+    if (!getSelfProfile())
+    {
+        // Otherwise as the only focusable element it will be selected
+        mDescriptionEdit->setTabStop(FALSE);
+    }
+
+    resetData();
+}
+
+void LLPanelProfileFirstLife::setProfileImageUploading(bool loading)
+{
+    mUploadPhoto->setEnabled(!loading);
+    mChangePhoto->setEnabled(!loading);
+    mRemovePhoto->setEnabled(!loading && mImageId.notNull());
+
+    LLLoadingIndicator* indicator = getChild<LLLoadingIndicator>("image_upload_indicator");
+    indicator->setVisible(loading);
+    if (loading)
+    {
+        indicator->start();
+    }
+    else
+    {
+        indicator->stop();
+    }
+}
+
+void LLPanelProfileFirstLife::setProfileImageUploaded(const LLUUID &image_asset_id)
+{
+    mPicture->setValue(image_asset_id);
+    mImageId = image_asset_id;
+    setProfileImageUploading(false);
+}
+
+void LLPanelProfileFirstLife::commitUnsavedChanges()
+{
+    if (mHasUnsavedChanges)
+    {
+        onSaveDescriptionChanges();
+    }
+}
+
+void LLPanelProfileFirstLife::onUploadPhoto()
+{
+    (new LLProfileImagePicker(PROFILE_IMAGE_FL, new LLHandle<LLPanel>(getHandle())))->getFile();
+
+    LLFloater* floaterp = mFloaterTexturePickerHandle.get();
+    if (floaterp)
+    {
+        floaterp->closeFloater();
+    }
+}
+
+void LLPanelProfileFirstLife::onChangePhoto()
+{
+    LLFloater* floaterp = mFloaterTexturePickerHandle.get();
+
+    // Show the dialog
+    if (!floaterp)
+    {
+        LLFloater* parent_floater = gFloaterView->getParentFloater(this);
+        if (parent_floater)
+        {
+            // because inventory construction is somewhat slow
+            getWindow()->setCursor(UI_CURSOR_WAIT);
+            LLFloaterTexturePicker* texture_floaterp = new LLFloaterTexturePicker(
+                this,
+                mImageId,
+                LLUUID::null,
+                mImageId,
+                FALSE,
+                FALSE,
+                "SELECT PHOTO",
+                PERM_NONE,
+                PERM_NONE,
+                PERM_NONE,
+                FALSE,
+                NULL);
+
+            mFloaterTexturePickerHandle = texture_floaterp->getHandle();
+
+            texture_floaterp->setOnFloaterCommitCallback([this](LLTextureCtrl::ETexturePickOp op, LLUUID id)
+            {
+                if (op == LLTextureCtrl::TEXTURE_SELECT)
+                {
+                    LLUUID image_asset_id;
+                    LLFloaterTexturePicker* floaterp = (LLFloaterTexturePicker*)mFloaterTexturePickerHandle.get();
+                    if (floaterp)
+                    {
+                        if (id.notNull())
+                        {
+                            image_asset_id = id;
+                        }
+                        else
+                        {
+                            image_asset_id = floaterp->getAssetID();
+                        }
+                    }
+
+                    onCommitPhoto(image_asset_id);
+                }
+            });
+            texture_floaterp->setLocalTextureEnabled(FALSE);
+            texture_floaterp->setCanApply(false, true);
+
+            parent_floater->addDependentFloater(mFloaterTexturePickerHandle);
+
+            texture_floaterp->openFloater();
+            texture_floaterp->setFocus(TRUE);
+        }
+    }
+    else
+    {
+        floaterp->setMinimized(FALSE);
+        floaterp->setVisibleAndFrontmost(TRUE);
+    }
+}
+
+void LLPanelProfileFirstLife::onRemovePhoto()
+{
+    onCommitPhoto(LLUUID::null);
+
+    LLFloater* floaterp = mFloaterTexturePickerHandle.get();
+    if (floaterp)
+    {
+        floaterp->closeFloater();
+    }
+}
+
+void LLPanelProfileFirstLife::onCommitPhoto(const LLUUID& id)
+{
+    if (mImageId == id)
+    {
+        return;
+    }
+
+    std::string cap_url = gAgent.getRegionCapability(PROFILE_PROPERTIES_CAP);
+    if (!cap_url.empty())
+    {
+        LLSD params;
+        params["fl_image_id"] = id;
+        LLCoros::instance().launch("putAgentUserInfoCoro",
+            boost::bind(put_avatar_properties_coro, cap_url, getAvatarId(), params));
+
+        mImageId = id;
+        if (mImageId.notNull())
+        {
+            mPicture->setValue(mImageId);
+        }
+        else
+        {
+            mPicture->setValue("Generic_Person_Large");
+        }
+
+        mRemovePhoto->setEnabled(mImageId.notNull());
+    }
+    else
+    {
+        LL_WARNS("AvatarProperties") << "Failed to update profile data, no cap found" << LL_ENDL;
+    }
+}
+
+void LLPanelProfileFirstLife::setDescriptionText(const std::string &text)
+{
+    mSaveChanges->setEnabled(FALSE);
+    mDiscardChanges->setEnabled(FALSE);
+    mHasUnsavedChanges = false;
+
+    mCurrentDescription = text;
+    mDescriptionEdit->setValue(mCurrentDescription);
+}
+
+void LLPanelProfileFirstLife::onSetDescriptionDirty()
+{
+    mSaveChanges->setEnabled(TRUE);
+    mDiscardChanges->setEnabled(TRUE);
+    mHasUnsavedChanges = true;
+}
+
+void LLPanelProfileFirstLife::onSaveDescriptionChanges()
+{
+    mCurrentDescription = mDescriptionEdit->getValue().asString();
+    std::string cap_url = gAgent.getRegionCapability(PROFILE_PROPERTIES_CAP);
+    if (!cap_url.empty())
+    {
+        LLCoros::instance().launch("putAgentUserInfoCoro",
+            boost::bind(put_avatar_properties_coro, cap_url, getAvatarId(), LLSD().with("fl_about_text", mCurrentDescription)));
+    }
+    else
+    {
+        LL_WARNS("AvatarProperties") << "Failed to update profile data, no cap found" << LL_ENDL;
+    }
+
+    mSaveChanges->setEnabled(FALSE);
+    mDiscardChanges->setEnabled(FALSE);
+    mHasUnsavedChanges = false;
+}
+
+void LLPanelProfileFirstLife::onDiscardDescriptionChanges()
+{
+    setDescriptionText(mCurrentDescription);
+}
+
+void LLPanelProfileFirstLife::processProperties(const LLAvatarData* avatar_data)
+{
+    setDescriptionText(avatar_data->fl_about_text);
+
+    mImageId = avatar_data->fl_image_id;
+
+    if (mImageId.notNull())
+    {
+        mPicture->setValue(mImageId);
+    }
+    else
+    {
+        mPicture->setValue("Generic_Person_Large");
+    }
+
+    setLoaded();
+}
+
+void LLPanelProfileFirstLife::resetData()
+{
+    setDescriptionText(std::string());
+    mPicture->setValue("Generic_Person_Large");
+    mImageId = LLUUID::null;
+
+    mUploadPhoto->setVisible(getSelfProfile());
+    mChangePhoto->setVisible(getSelfProfile());
+    mRemovePhoto->setVisible(getSelfProfile());
+    mSaveChanges->setVisible(getSelfProfile());
+    mDiscardChanges->setVisible(getSelfProfile());
+}
+
+void LLPanelProfileFirstLife::setLoaded()
+{
+    LLPanelProfileTab::setLoaded();
+
+    if (getSelfProfile())
+    {
+        mDescriptionEdit->setEnabled(TRUE);
+        mPicture->setEnabled(TRUE);
+        mRemovePhoto->setEnabled(mImageId.notNull());
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+
+LLPanelProfileNotes::LLPanelProfileNotes()
+: LLPanelProfileTab()
+ , mHasUnsavedChanges(false)
+{
+
+}
+
+LLPanelProfileNotes::~LLPanelProfileNotes()
+{
+}
+
+void LLPanelProfileNotes::updateData()
+{
+    LLUUID avatar_id = getAvatarId();
+    if (!getStarted() && avatar_id.notNull())
+    {
+        setIsLoading();
+
+        std::string cap_url = gAgent.getRegionCapability(PROFILE_PROPERTIES_CAP);
+        if (!cap_url.empty())
+        {
+            LLCoros::instance().launch("requestAgentUserInfoCoro",
+                boost::bind(request_avatar_properties_coro, cap_url, avatar_id));
+        }
+    }
+}
+
+void LLPanelProfileNotes::commitUnsavedChanges()
+{
+    if (mHasUnsavedChanges)
+    {
+        onSaveNotesChanges();
+    }
+}
+
+BOOL LLPanelProfileNotes::postBuild()
+{
+    mNotesEditor = getChild<LLTextEditor>("notes_edit");
+    mSaveChanges = getChild<LLButton>("notes_save_changes");
+    mDiscardChanges = getChild<LLButton>("notes_discard_changes");
+
+    mSaveChanges->setCommitCallback([this](LLUICtrl*, void*) { onSaveNotesChanges(); }, nullptr);
+    mDiscardChanges->setCommitCallback([this](LLUICtrl*, void*) { onDiscardNotesChanges(); }, nullptr);
+    mNotesEditor->setKeystrokeCallback([this](LLTextEditor* caller) { onSetNotesDirty(); });
+
+    return TRUE;
+}
+
+void LLPanelProfileNotes::onOpen(const LLSD& key)
+{
+    LLPanelProfileTab::onOpen(key);
+
+    resetData();
+}
+
+void LLPanelProfileNotes::setNotesText(const std::string &text)
+{
+    mSaveChanges->setEnabled(FALSE);
+    mDiscardChanges->setEnabled(FALSE);
+    mHasUnsavedChanges = false;
+
+    mCurrentNotes = text;
+    mNotesEditor->setValue(mCurrentNotes);
+}
+
+void LLPanelProfileNotes::onSetNotesDirty()
+{
+    mSaveChanges->setEnabled(TRUE);
+    mDiscardChanges->setEnabled(TRUE);
+    mHasUnsavedChanges = true;
+}
+
+void LLPanelProfileNotes::onSaveNotesChanges()
+{
+    mCurrentNotes = mNotesEditor->getValue().asString();
+    std::string cap_url = gAgent.getRegionCapability(PROFILE_PROPERTIES_CAP);
+    if (!cap_url.empty())
+    {
+        LLCoros::instance().launch("putAgentUserInfoCoro",
+            boost::bind(put_avatar_properties_coro, cap_url, getAvatarId(), LLSD().with("notes", mCurrentNotes)));
+    }
+    else
+    {
+        LL_WARNS("AvatarProperties") << "Failed to update profile data, no cap found" << LL_ENDL;
+    }
+
+    mSaveChanges->setEnabled(FALSE);
+    mDiscardChanges->setEnabled(FALSE);
+    mHasUnsavedChanges = false;
+}
+
+void LLPanelProfileNotes::onDiscardNotesChanges()
+{
+    setNotesText(mCurrentNotes);
+}
+
+void LLPanelProfileNotes::processProperties(LLAvatarNotes* avatar_notes)
+{
+    setNotesText(avatar_notes->notes);
+    mNotesEditor->setEnabled(TRUE);
+    setLoaded();
+}
+
+void LLPanelProfileNotes::resetData()
+{
+    resetLoading();
+    setNotesText(std::string());
+}
+
+void LLPanelProfileNotes::setAvatarId(const LLUUID& avatar_id)
+{
+    if (avatar_id.notNull())
+    {
+        LLPanelProfileTab::setAvatarId(avatar_id);
+    }
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+// LLPanelProfile
+
+LLPanelProfile::LLPanelProfile()
+ : LLPanelProfileTab()
+{
+}
+
+LLPanelProfile::~LLPanelProfile()
+{
+}
+
+BOOL LLPanelProfile::postBuild()
+{
+    return TRUE;
+}
+
+void LLPanelProfile::onTabChange()
+{
+    LLPanelProfileTab* active_panel = dynamic_cast<LLPanelProfileTab*>(mTabContainer->getCurrentPanel());
+    if (active_panel)
+    {
+        active_panel->updateData();
+    }
+}
+
+void LLPanelProfile::onOpen(const LLSD& key)
+{
+    LLUUID avatar_id = key["id"].asUUID();
+
+    // Don't reload the same profile
+    if (getAvatarId() == avatar_id)
+    {
+        return;
+    }
+
+    LLPanelProfileTab::onOpen(avatar_id);
+
+    mTabContainer       = getChild<LLTabContainer>("panel_profile_tabs");
+    mPanelSecondlife    = findChild<LLPanelProfileSecondLife>(PANEL_SECONDLIFE);
+    mPanelWeb           = findChild<LLPanelProfileWeb>(PANEL_WEB);
+    mPanelPicks         = findChild<LLPanelProfilePicks>(PANEL_PICKS);
+    mPanelClassifieds   = findChild<LLPanelProfileClassifieds>(PANEL_CLASSIFIEDS);
+    mPanelFirstlife     = findChild<LLPanelProfileFirstLife>(PANEL_FIRSTLIFE);
+    mPanelNotes         = findChild<LLPanelProfileNotes>(PANEL_NOTES);
+
+    mPanelSecondlife->onOpen(avatar_id);
+    mPanelWeb->onOpen(avatar_id);
+    mPanelPicks->onOpen(avatar_id);
+    mPanelClassifieds->onOpen(avatar_id);
+    mPanelFirstlife->onOpen(avatar_id);
+    mPanelNotes->onOpen(avatar_id);
+
+    // Always request the base profile info
+    resetLoading();
+    updateData();
+
+    // Some tabs only request data when opened
+    mTabContainer->setCommitCallback(boost::bind(&LLPanelProfile::onTabChange, this));
+}
+
+void LLPanelProfile::updateData()
+{
+    LLUUID avatar_id = getAvatarId();
+    // Todo: getIsloading functionality needs to be expanded to
+    // include 'inited' or 'data_provided' state to not rerequest
+    if (!getStarted() && avatar_id.notNull())
+    {
+        setIsLoading();
+
+        mPanelSecondlife->setIsLoading();
+        mPanelPicks->setIsLoading();
+        mPanelFirstlife->setIsLoading();
+        mPanelNotes->setIsLoading();
+
+        std::string cap_url = gAgent.getRegionCapability(PROFILE_PROPERTIES_CAP);
+        if (!cap_url.empty())
+        {
+            LLCoros::instance().launch("requestAgentUserInfoCoro",
+                boost::bind(request_avatar_properties_coro, cap_url, avatar_id));
+        }
+    }
+}
+
+void LLPanelProfile::refreshName()
+{
+    mPanelSecondlife->refreshName();
+}
+
+void LLPanelProfile::createPick(const LLPickData &data)
+{
+    mTabContainer->selectTabPanel(mPanelPicks);
+    mPanelPicks->createPick(data);
+}
+
+void LLPanelProfile::showPick(const LLUUID& pick_id)
+{
+    if (pick_id.notNull())
+    {
+        mPanelPicks->selectPick(pick_id);
+    }
+    mTabContainer->selectTabPanel(mPanelPicks);
+}
+
+bool LLPanelProfile::isPickTabSelected()
+{
+	return (mTabContainer->getCurrentPanel() == mPanelPicks);
+}
+
+bool LLPanelProfile::isNotesTabSelected()
+{
+	return (mTabContainer->getCurrentPanel() == mPanelNotes);
+}
+
+bool LLPanelProfile::hasUnsavedChanges()
+{
+    return mPanelSecondlife->hasUnsavedChanges()
+        || mPanelPicks->hasUnsavedChanges()
+        || mPanelClassifieds->hasUnsavedChanges()
+        || mPanelFirstlife->hasUnsavedChanges()
+        || mPanelNotes->hasUnsavedChanges();
+}
+
+bool LLPanelProfile::hasUnpublishedClassifieds()
+{
+    return mPanelClassifieds->hasNewClassifieds();
+}
+
+void LLPanelProfile::commitUnsavedChanges()
+{
+    mPanelSecondlife->commitUnsavedChanges();
+    mPanelPicks->commitUnsavedChanges();
+    mPanelClassifieds->commitUnsavedChanges();
+    mPanelFirstlife->commitUnsavedChanges();
+    mPanelNotes->commitUnsavedChanges();
+}
+
+void LLPanelProfile::showClassified(const LLUUID& classified_id, bool edit)
+{
+    if (classified_id.notNull())
+    {
+        mPanelClassifieds->selectClassified(classified_id, edit);
+    }
+    mTabContainer->selectTabPanel(mPanelClassifieds);
+}
+
+void LLPanelProfile::createClassified()
+{
+    mPanelClassifieds->createClassified();
+    mTabContainer->selectTabPanel(mPanelClassifieds);
+}
+
diff --git a/indra/newview/llpanelprofile.h b/indra/newview/llpanelprofile.h
index d97f60ed229ab16320932951e9a13c896e9b7177..d32bb943bd4cd01965f023d11904f8bc9b1dc2ff 100644
--- a/indra/newview/llpanelprofile.h
+++ b/indra/newview/llpanelprofile.h
@@ -1,25 +1,25 @@
-/** 
+/**
 * @file llpanelprofile.h
 * @brief Profile panel
 *
-* $LicenseInfo:firstyear=2009&license=viewerlgpl$
+* $LicenseInfo:firstyear=2022&license=viewerlgpl$
 * Second Life Viewer Source Code
-* Copyright (C) 2010, Linden Research, Inc.
-* 
+* Copyright (C) 2022, Linden Research, Inc.
+*
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation;
 * version 2.1 of the License only.
-* 
+*
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
-* 
+*
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
-* 
+*
 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 * $/LicenseInfo$
 */
@@ -27,76 +27,383 @@
 #ifndef LL_LLPANELPROFILE_H
 #define LL_LLPANELPROFILE_H
 
+#include "llavatarpropertiesprocessor.h"
+#include "llcallingcard.h"
+#include "llfloater.h"
 #include "llpanel.h"
 #include "llpanelavatar.h"
+#include "llmediactrl.h"
+#include "llvoiceclient.h"
+
+// class LLPanelProfileClassifieds;
+// class LLTabContainer;
 
+// class LLPanelProfileSecondLife;
+// class LLPanelProfileWeb;
+// class LLPanelProfilePicks;
+// class LLPanelProfileFirstLife;
+// class LLPanelProfileNotes;
+
+class LLAvatarName;
+class LLButton;
+class LLCheckBoxCtrl;
+class LLComboBox;
+class LLIconCtrl;
 class LLTabContainer;
+class LLTextBox;
+class LLTextureCtrl;
+class LLMediaCtrl;
+class LLGroupList;
+class LLTextBase;
+class LLMenuButton;
+class LLLineEditor;
+class LLTextEditor;
+class LLPanelProfileClassifieds;
+class LLPanelProfilePicks;
+class LLViewerFetchedTexture;
 
-std::string getProfileURL(const std::string& agent_name);
 
 /**
-* Base class for Profile View and My Profile.
+* Panel for displaying Avatar's second life related info.
 */
-class LLPanelProfile : public LLPanel
+class LLPanelProfileSecondLife
+	: public LLPanelProfileTab
+	, public LLFriendObserver
+	, public LLVoiceClientStatusObserver
 {
-	LOG_CLASS(LLPanelProfile);
+public:
+	LLPanelProfileSecondLife();
+	/*virtual*/ ~LLPanelProfileSecondLife();
+
+	void onOpen(const LLSD& key) override;
+
+	/**
+	 * LLFriendObserver trigger
+	 */
+	void changed(U32 mask) override;
+
+	// Implements LLVoiceClientStatusObserver::onChange() to enable the call
+	// button when voice is available
+	void onChange(EStatusType status, const std::string &channelURI, bool proximal) override;
+
+	void setAvatarId(const LLUUID& avatar_id) override;
+
+	BOOL postBuild() override;
+
+	void resetData() override;
+
+	/**
+	 * Sends update data request to server.
+	 */
+	void updateData() override;
+    void refreshName();
+
+	void onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name);
+
+    void setProfileImageUploading(bool loading);
+    void setProfileImageUploaded(const LLUUID &image_asset_id);
+
+    bool hasUnsavedChanges() override;
+    void commitUnsavedChanges() override;
+
+    friend void request_avatar_properties_coro(std::string cap_url, LLUUID agent_id);
+
+protected:
+	/**
+	 * Process profile related data received from server.
+	 */
+	void processProfileProperties(const LLAvatarData* avatar_data);
+
+	/**
+	 * Processes group related data received from server.
+	 */
+	void processGroupProperties(const LLAvatarGroups* avatar_groups);
+
+	/**
+	 * Fills common for Avatar profile and My Profile fields.
+	 */
+	void fillCommonData(const LLAvatarData* avatar_data);
+
+	/**
+	 * Fills partner data.
+	 */
+	void fillPartnerData(const LLAvatarData* avatar_data);
 
+	/**
+	 * Fills account status.
+	 */
+	void fillAccountStatus(const LLAvatarData* avatar_data);
+
+    /**
+     * Sets permissions specific icon
+     */
+    void fillRightsData();
+
+    /**
+     * Fills user name, display name, age.
+     */
+    void fillAgeData(const LLDate &born_on);
+
+    void onImageLoaded(BOOL success, LLViewerFetchedTexture *imagep);
+    static void onImageLoaded(BOOL success,
+                              LLViewerFetchedTexture *src_vi,
+                              LLImageRaw* src,
+                              LLImageRaw* aux_src,
+                              S32 discard_level,
+                              BOOL final,
+                              void* userdata);
+
+	/**
+	 * Displays avatar's online status if possible.
+	 *
+	 * Requirements from EXT-3880:
+	 * For friends:
+	 * - Online when online and privacy settings allow to show
+	 * - Offline when offline and privacy settings allow to show
+	 * - Else: nothing
+	 * For other avatars:
+	 *	- Online when online and was not set in Preferences/"Only Friends & Groups can see when I am online"
+	 *	- Else: Offline
+	 */
+	void updateOnlineStatus();
+	void processOnlineStatus(bool is_friend, bool show_online, bool online);
+
+private:
+    void setLoaded() override;
+    void onCommitMenu(const LLSD& userdata);
+    bool onEnableMenu(const LLSD& userdata);
+    bool onCheckMenu(const LLSD& userdata);
+	void onAvatarNameCacheSetName(const LLUUID& id, const LLAvatarName& av_name);
+
+    void setDescriptionText(const std::string &text);
+    void onSetDescriptionDirty();
+    void onShowInSearchCallback();
+    void onSaveDescriptionChanges();
+    void onDiscardDescriptionChanges();
+    void onShowAgentPermissionsDialog();
+    void onShowAgentProfileTexture();
+    void onShowTexturePicker();
+    void onCommitProfileImage(const LLUUID& id);
+
+private:
+	typedef std::map<std::string, LLUUID> group_map_t;
+	group_map_t				mGroups;
+	void					openGroupProfile();
+
+	LLGroupList*		mGroupList;
+    LLComboBox*			mShowInSearchCombo;
+    LLIconCtrl*			mSecondLifePic;
+	LLPanel*			mSecondLifePicLayout;
+    LLTextEditor*		mDescriptionEdit;
+    LLMenuButton*		mAgentActionMenuButton;
+    LLButton*			mSaveDescriptionChanges;
+    LLButton*			mDiscardDescriptionChanges;
+    LLIconCtrl*			mCanSeeOnlineIcon;
+    LLIconCtrl*			mCantSeeOnlineIcon;
+    LLIconCtrl*			mCanSeeOnMapIcon;
+    LLIconCtrl*			mCantSeeOnMapIcon;
+    LLIconCtrl*			mCanEditObjectsIcon;
+    LLIconCtrl*			mCantEditObjectsIcon;
+
+    LLHandle<LLFloater>	mFloaterPermissionsHandle;
+    LLHandle<LLFloater>	mFloaterProfileTextureHandle;
+    LLHandle<LLFloater>	mFloaterTexturePickerHandle;
+
+    bool				mHasUnsavedDescriptionChanges;
+	bool				mVoiceStatus;
+    bool				mWaitingForImageUpload;
+    bool				mAllowPublish;
+    std::string			mDescriptionText;
+    LLUUID				mImageId;
+
+	boost::signals2::connection	mAvatarNameCacheConnection;
+};
+
+
+/**
+* Panel for displaying Avatar's web profile and home page.
+*/
+class LLPanelProfileWeb
+	: public LLPanelProfileTab
+	, public LLViewerMediaObserver
+{
 public:
-	/*virtual*/ BOOL postBuild();
-	/*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE);
-	/*virtual*/ void onOpen(const LLSD& key);
+	LLPanelProfileWeb();
+	/*virtual*/ ~LLPanelProfileWeb();
+
+	void onOpen(const LLSD& key) override;
+
+	BOOL postBuild() override;
 
-	virtual void openPanel(LLPanel* panel, const LLSD& params);
+	void resetData() override;
 
-	virtual void closePanel(LLPanel* panel);
+	/**
+	 * Loads web profile.
+	 */
+	void updateData() override;
 
-	S32 notifyParent(const LLSD& info);
+	void handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event) override;
+
+	void onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name);
+
+    friend void request_avatar_properties_coro(std::string cap_url, LLUUID agent_id);
 
 protected:
+	void onCommitLoad(LLUICtrl* ctrl);
 
-	LLPanelProfile();
+private:
+	std::string			mURLHome;
+	std::string			mURLWebProfile;
+	LLMediaCtrl*		mWebBrowser;
 
-	virtual void onTabSelected(const LLSD& param);
+	LLFrameTimer		mPerformanceTimer;
+	bool				mFirstNavigate;
 
-	const LLUUID& getAvatarId() { return mAvatarId; }
+	boost::signals2::connection	mAvatarNameCacheConnection;
+};
+
+/**
+* Panel for displaying Avatar's first life related info.
+*/
+class LLPanelProfileFirstLife
+	: public LLPanelProfileTab
+{
+public:
+	LLPanelProfileFirstLife();
+	/*virtual*/ ~LLPanelProfileFirstLife();
+
+	void onOpen(const LLSD& key) override;
+
+	BOOL postBuild() override;
+
+    void processProperties(const LLAvatarData* avatar_data);
+
+	void resetData() override;
+
+    void setProfileImageUploading(bool loading);
+    void setProfileImageUploaded(const LLUUID &image_asset_id);
+
+    bool hasUnsavedChanges() override { return mHasUnsavedChanges; }
+    void commitUnsavedChanges() override;
+
+    friend void request_avatar_properties_coro(std::string cap_url, LLUUID agent_id);
+
+protected:
+	void setLoaded() override;
+
+    void onUploadPhoto();
+    void onChangePhoto();
+    void onRemovePhoto();
+    void onCommitPhoto(const LLUUID& id);
+    void setDescriptionText(const std::string &text);
+    void onSetDescriptionDirty();
+    void onSaveDescriptionChanges();
+    void onDiscardDescriptionChanges();
+
+	LLTextEditor*	mDescriptionEdit;
+    LLIconCtrl*		mPicture;
+    LLButton* mUploadPhoto;
+    LLButton* mChangePhoto;
+    LLButton* mRemovePhoto;
+    LLButton* mSaveChanges;
+    LLButton* mDiscardChanges;
+
+    LLHandle<LLFloater>	mFloaterTexturePickerHandle;
+
+    std::string		mCurrentDescription;
+    LLUUID			mImageId;
+    bool			mHasUnsavedChanges;
+};
+
+/**
+ * Panel for displaying Avatar's notes and modifying friend's rights.
+ */
+class LLPanelProfileNotes
+	: public LLPanelProfileTab
+{
+public:
+	LLPanelProfileNotes();
+	/*virtual*/ ~LLPanelProfileNotes();
 
-	void setAvatarId(const LLUUID& avatar_id) { mAvatarId = avatar_id; }
+	void setAvatarId(const LLUUID& avatar_id) override;
 
-	typedef std::map<std::string, LLPanelProfileTab*> profile_tabs_t;
+	void onOpen(const LLSD& key) override;
 
-	profile_tabs_t& getTabContainer() { return mTabContainer; }
+	BOOL postBuild() override;
+
+    void processProperties(LLAvatarNotes* avatar_notes);
+
+	void resetData() override;
+
+	void updateData() override;
+
+    bool hasUnsavedChanges() override { return mHasUnsavedChanges; }
+    void commitUnsavedChanges() override;
+
+protected:
+    void setNotesText(const std::string &text);
+    void onSetNotesDirty();
+    void onSaveNotesChanges();
+    void onDiscardNotesChanges();
+
+	LLTextEditor*       mNotesEditor;
+    LLButton* mSaveChanges;
+    LLButton* mDiscardChanges;
+
+    std::string		mCurrentNotes;
+    bool			mHasUnsavedChanges;
+};
+
+
+/**
+* Container panel for the profile tabs
+*/
+class LLPanelProfile
+    : public LLPanelProfileTab
+{
+public:
+    LLPanelProfile();
+    /*virtual*/ ~LLPanelProfile();
+
+    BOOL postBuild() override;
+
+    void updateData() override;
+    void refreshName();
+
+    void onOpen(const LLSD& key) override;
+
+    void createPick(const LLPickData &data);
+    void showPick(const LLUUID& pick_id = LLUUID::null);
+    bool isPickTabSelected();
+    bool isNotesTabSelected();
+    bool hasUnsavedChanges() override;
+    bool hasUnpublishedClassifieds();
+    void commitUnsavedChanges() override;
+
+    void showClassified(const LLUUID& classified_id = LLUUID::null, bool edit = false);
+    void createClassified();
+
+    LLAvatarData getAvatarData() { return mAvatarData; };
+
+    friend void request_avatar_properties_coro(std::string cap_url, LLUUID agent_id);
 
 private:
+    void onTabChange();
+
+    LLPanelProfileSecondLife*   mPanelSecondlife;
+    LLPanelProfileWeb*          mPanelWeb;
+    LLPanelProfilePicks*        mPanelPicks;
+    LLPanelProfileClassifieds*  mPanelClassifieds;
+    LLPanelProfileFirstLife*    mPanelFirstlife;
+    LLPanelProfileNotes*        mPanelNotes;
+    LLTabContainer*             mTabContainer;
 
-	//-- ChildStack begins ----------------------------------------------------
-	class ChildStack
-	{
-		LOG_CLASS(LLPanelProfile::ChildStack);
-	public:
-		ChildStack();
-		~ChildStack();
-		void setParent(LLPanel* parent);
-
-		bool push();
-		bool pop();
-		void preParentReshape();
-		void postParentReshape();
-
-	private:
-		void dump();
-
-		typedef LLView::child_list_t view_list_t;
-		typedef std::list<view_list_t> stack_t;
-
-		stack_t		mStack;
-		stack_t		mSavedStack;
-		LLPanel*	mParent;
-	};
-	//-- ChildStack ends ------------------------------------------------------
-
-	profile_tabs_t mTabContainer;
-	ChildStack		mChildStack;
-	LLUUID mAvatarId;
+    // Todo: due to server taking minutes to update this needs a more long term storage
+    // to reuse recently saved values if user opens floater again
+    // Storage implementation depends onto how a cap will be implemented, if cap will be
+    // enought to fully update LLAvatarPropertiesProcessor, then this storage can be
+    // implemented there.
+    LLAvatarData mAvatarData;
 };
 
 #endif //LL_LLPANELPROFILE_H
diff --git a/indra/newview/llpanelprofileclassifieds.cpp b/indra/newview/llpanelprofileclassifieds.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..a3913ddc49e49e6ef021670adf1f532a1761a977
--- /dev/null
+++ b/indra/newview/llpanelprofileclassifieds.cpp
@@ -0,0 +1,1513 @@
+/**
+ * @file llpanelprofileclassifieds.cpp
+ * @brief LLPanelProfileClassifieds and related class implementations
+ *
+ * $LicenseInfo:firstyear=2022&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2022, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llpanelprofileclassifieds.h"
+
+#include "llagent.h"
+#include "llavataractions.h"
+#include "llavatarpropertiesprocessor.h"
+#include "llclassifiedflags.h"
+#include "llcombobox.h"
+#include "llcommandhandler.h" // for classified HTML detail page click tracking
+#include "llcorehttputil.h"
+#include "lldispatcher.h"
+#include "llfloaterclassified.h"
+#include "llfloaterreg.h"
+#include "llfloatersidepanelcontainer.h"
+#include "llfloaterworldmap.h"
+#include "lliconctrl.h"
+#include "lllineeditor.h"
+#include "llnotifications.h"
+#include "llnotificationsutil.h"
+#include "llpanelavatar.h"
+#include "llparcel.h"
+#include "llregistry.h"
+#include "llscrollcontainer.h"
+#include "llstartup.h"
+#include "llstatusbar.h"
+#include "lltabcontainer.h"
+#include "lltexteditor.h"
+#include "lltexturectrl.h"
+#include "lltrans.h"
+#include "llviewergenericmessage.h" // send_generic_message
+#include "llviewerparcelmgr.h"
+#include "llviewerregion.h"
+#include "llviewertexture.h"
+#include "llviewertexture.h"
+
+
+//*TODO: verify this limit
+const S32 MAX_AVATAR_CLASSIFIEDS = 100;
+
+const S32 MINIMUM_PRICE_FOR_LISTING = 50; // L$
+const S32 DEFAULT_EDIT_CLASSIFIED_SCROLL_HEIGHT = 530;
+
+//static
+LLPanelProfileClassified::panel_list_t LLPanelProfileClassified::sAllPanels;
+
+static LLPanelInjector<LLPanelProfileClassifieds> t_panel_profile_classifieds("panel_profile_classifieds");
+static LLPanelInjector<LLPanelProfileClassified> t_panel_profile_classified("panel_profile_classified");
+
+class LLClassifiedHandler : public LLCommandHandler, public LLAvatarPropertiesObserver
+{
+public:
+    // throttle calls from untrusted browsers
+    LLClassifiedHandler() : LLCommandHandler("classified", UNTRUSTED_THROTTLE) {}
+	
+	std::set<LLUUID> mClassifiedIds;
+	std::string mRequestVerb;
+    
+	bool handle(const LLSD& params, const LLSD& query_map, LLMediaCtrl* web)
+    {
+        if (LLStartUp::getStartupState() < STATE_STARTED)
+        {
+            return true;
+        }
+
+        if (!LLUI::getInstance()->mSettingGroups["config"]->getBOOL("EnableClassifieds"))
+        {
+            LLNotificationsUtil::add("NoClassifieds", LLSD(), LLSD(), std::string("SwitchToStandardSkinAndQuit"));
+            return true;
+        }
+
+        // handle app/classified/create urls first
+        if (params.size() == 1 && params[0].asString() == "create")
+        {
+            LLAvatarActions::createClassified();
+            return true;
+        }
+
+        // then handle the general app/classified/{UUID}/{CMD} urls
+        if (params.size() < 2)
+        {
+            return false;
+        }
+
+        // get the ID for the classified
+        LLUUID classified_id;
+        if (!classified_id.set(params[0], FALSE))
+        {
+            return false;
+        }
+
+        // show the classified in the side tray.
+        // need to ask the server for more info first though...
+        const std::string verb = params[1].asString();
+        if (verb == "about")
+        {
+            mRequestVerb = verb;
+            mClassifiedIds.insert(classified_id);
+            LLAvatarPropertiesProcessor::getInstance()->addObserver(LLUUID(), this);
+            LLAvatarPropertiesProcessor::getInstance()->sendClassifiedInfoRequest(classified_id);
+            return true;
+        }
+        else if (verb == "edit")
+        {
+            LLAvatarActions::showClassified(gAgent.getID(), classified_id, true);
+            return true;
+        }
+
+        return false;
+    }
+
+    void openClassified(LLAvatarClassifiedInfo* c_info)
+    {
+        if (mRequestVerb == "about")
+        {
+            if (c_info->creator_id == gAgent.getID())
+            {
+                LLAvatarActions::showClassified(gAgent.getID(), c_info->classified_id, false);
+            }
+            else
+            {
+                LLSD params;
+                params["id"] = c_info->creator_id;
+                params["classified_id"] = c_info->classified_id;
+                params["classified_creator_id"] = c_info->creator_id;
+                params["classified_snapshot_id"] = c_info->snapshot_id;
+                params["classified_name"] = c_info->name;
+                params["classified_desc"] = c_info->description;
+                params["from_search"] = true;
+
+                LLFloaterClassified* floaterp = LLFloaterReg::getTypedInstance<LLFloaterClassified>("classified", params);
+                if (floaterp)
+                {
+                    floaterp->openFloater(params);
+                    floaterp->setVisibleAndFrontmost();
+                }
+            }
+        }
+    }
+
+    void processProperties(void* data, EAvatarProcessorType type)
+    {
+        if (APT_CLASSIFIED_INFO != type)
+        {
+            return;
+        }
+
+        // is this the classified that we asked for?
+        LLAvatarClassifiedInfo* c_info = static_cast<LLAvatarClassifiedInfo*>(data);
+        if (!c_info || mClassifiedIds.find(c_info->classified_id) == mClassifiedIds.end())
+        {
+            return;
+        }
+
+        // open the detail side tray for this classified
+        openClassified(c_info);
+
+        // remove our observer now that we're done
+        mClassifiedIds.erase(c_info->classified_id);
+        LLAvatarPropertiesProcessor::getInstance()->removeObserver(LLUUID(), this);
+    }
+};
+LLClassifiedHandler gClassifiedHandler;
+
+//////////////////////////////////////////////////////////////////////////
+
+
+//-----------------------------------------------------------------------------
+// LLPanelProfileClassifieds
+//-----------------------------------------------------------------------------
+
+LLPanelProfileClassifieds::LLPanelProfileClassifieds()
+ : LLPanelProfilePropertiesProcessorTab()
+ , mClassifiedToSelectOnLoad(LLUUID::null)
+ , mClassifiedEditOnLoad(false)
+ , mSheduledClassifiedCreation(false)
+{
+}
+
+LLPanelProfileClassifieds::~LLPanelProfileClassifieds()
+{
+}
+
+void LLPanelProfileClassifieds::onOpen(const LLSD& key)
+{
+    LLPanelProfilePropertiesProcessorTab::onOpen(key);
+
+    resetData();
+
+    bool own_profile = getSelfProfile();
+    if (own_profile)
+    {
+        mNewButton->setVisible(TRUE);
+        mNewButton->setEnabled(FALSE);
+
+        mDeleteButton->setVisible(TRUE);
+        mDeleteButton->setEnabled(FALSE);
+    }
+
+    childSetVisible("buttons_header", own_profile);
+
+}
+
+void LLPanelProfileClassifieds::selectClassified(const LLUUID& classified_id, bool edit)
+{
+    if (getIsLoaded())
+    {
+        for (S32 tab_idx = 0; tab_idx < mTabContainer->getTabCount(); ++tab_idx)
+        {
+            LLPanelProfileClassified* classified_panel = dynamic_cast<LLPanelProfileClassified*>(mTabContainer->getPanelByIndex(tab_idx));
+            if (classified_panel)
+            {
+                if (classified_panel->getClassifiedId() == classified_id)
+                {
+                    mTabContainer->selectTabPanel(classified_panel);
+                    if (edit)
+                    {
+                        classified_panel->setEditMode(TRUE);
+                    }
+                    break;
+                }
+            }
+        }
+    }
+    else
+    {
+        mClassifiedToSelectOnLoad = classified_id;
+        mClassifiedEditOnLoad = edit;
+    }
+}
+
+void LLPanelProfileClassifieds::createClassified()
+{
+    if (getIsLoaded())
+    {
+        mNoItemsLabel->setVisible(FALSE);
+        LLPanelProfileClassified* classified_panel = LLPanelProfileClassified::create();
+        classified_panel->onOpen(LLSD());
+        mTabContainer->addTabPanel(
+            LLTabContainer::TabPanelParams().
+            panel(classified_panel).
+            select_tab(true).
+            label(classified_panel->getClassifiedName()));
+        updateButtons();
+    }
+    else
+    {
+        mSheduledClassifiedCreation = true;
+    }
+}
+
+BOOL LLPanelProfileClassifieds::postBuild()
+{
+    mTabContainer = getChild<LLTabContainer>("tab_classifieds");
+    mNoItemsLabel = getChild<LLUICtrl>("classifieds_panel_text");
+    mNewButton = getChild<LLButton>("new_btn");
+    mDeleteButton = getChild<LLButton>("delete_btn");
+
+    mNewButton->setCommitCallback(boost::bind(&LLPanelProfileClassifieds::onClickNewBtn, this));
+    mDeleteButton->setCommitCallback(boost::bind(&LLPanelProfileClassifieds::onClickDelete, this));
+
+    return TRUE;
+}
+
+void LLPanelProfileClassifieds::onClickNewBtn()
+{
+    mNoItemsLabel->setVisible(FALSE);
+    LLPanelProfileClassified* classified_panel = LLPanelProfileClassified::create();
+    classified_panel->onOpen(LLSD());
+    mTabContainer->addTabPanel(
+        LLTabContainer::TabPanelParams().
+        panel(classified_panel).
+        select_tab(true).
+        label(classified_panel->getClassifiedName()));
+    updateButtons();
+}
+
+void LLPanelProfileClassifieds::onClickDelete()
+{
+    LLPanelProfileClassified* classified_panel = dynamic_cast<LLPanelProfileClassified*>(mTabContainer->getCurrentPanel());
+    if (classified_panel)
+    {
+        LLUUID classified_id = classified_panel->getClassifiedId();
+        LLSD args;
+        args["CLASSIFIED"] = classified_panel->getClassifiedName();
+        LLSD payload;
+        payload["classified_id"] = classified_id;
+        payload["tab_idx"] = mTabContainer->getCurrentPanelIndex();
+        LLNotificationsUtil::add("ProfileDeleteClassified", args, payload,
+            boost::bind(&LLPanelProfileClassifieds::callbackDeleteClassified, this, _1, _2));
+    }
+}
+
+void LLPanelProfileClassifieds::callbackDeleteClassified(const LLSD& notification, const LLSD& response)
+{
+    S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+
+    if (0 == option)
+    {
+        LLUUID classified_id = notification["payload"]["classified_id"].asUUID();
+        S32 tab_idx = notification["payload"]["tab_idx"].asInteger();
+
+        LLPanelProfileClassified* classified_panel = dynamic_cast<LLPanelProfileClassified*>(mTabContainer->getPanelByIndex(tab_idx));
+        if (classified_panel && classified_panel->getClassifiedId() == classified_id)
+        {
+            mTabContainer->removeTabPanel(classified_panel);
+        }
+
+        if (classified_id.notNull())
+        {
+            LLAvatarPropertiesProcessor::getInstance()->sendClassifiedDelete(classified_id);
+        }
+
+        updateButtons();
+
+        BOOL no_data = !mTabContainer->getTabCount();
+        mNoItemsLabel->setVisible(no_data);
+    }
+}
+
+void LLPanelProfileClassifieds::processProperties(void* data, EAvatarProcessorType type)
+{
+    if ((APT_CLASSIFIEDS == type) || (APT_CLASSIFIED_INFO == type))
+    {
+        LLUUID avatar_id = getAvatarId();
+
+        LLAvatarClassifieds* c_info = static_cast<LLAvatarClassifieds*>(data);
+        if (c_info && getAvatarId() == c_info->target_id)
+        {
+            // do not clear classified list in case we will receive two or more data packets.
+            // list has been cleared in updateData(). (fix for EXT-6436)
+            LLUUID selected_id = mClassifiedToSelectOnLoad;
+            bool has_selection = false;
+
+            LLAvatarClassifieds::classifieds_list_t::const_iterator it = c_info->classifieds_list.begin();
+            for (; c_info->classifieds_list.end() != it; ++it)
+            {
+                LLAvatarClassifieds::classified_data c_data = *it;
+
+                LLPanelProfileClassified* classified_panel = LLPanelProfileClassified::create();
+
+                LLSD params;
+                params["classified_creator_id"] = avatar_id;
+                params["classified_id"] = c_data.classified_id;
+                params["classified_name"] = c_data.name;
+                params["from_search"] = (selected_id == c_data.classified_id); //SLURL handling and stats tracking
+                params["edit"] = (selected_id == c_data.classified_id) && mClassifiedEditOnLoad;
+                classified_panel->onOpen(params);
+
+                mTabContainer->addTabPanel(
+                    LLTabContainer::TabPanelParams().
+                    panel(classified_panel).
+                    select_tab(selected_id == c_data.classified_id).
+                    label(c_data.name));
+
+                if (selected_id == c_data.classified_id)
+                {
+                    has_selection = true;
+                }
+            }
+
+            if (mSheduledClassifiedCreation)
+            {
+                LLPanelProfileClassified* classified_panel = LLPanelProfileClassified::create();
+                classified_panel->onOpen(LLSD());
+                mTabContainer->addTabPanel(
+                    LLTabContainer::TabPanelParams().
+                    panel(classified_panel).
+                    select_tab(!has_selection).
+                    label(classified_panel->getClassifiedName()));
+                has_selection = true;
+            }
+
+            // reset 'do on load' values
+            mClassifiedToSelectOnLoad = LLUUID::null;
+            mClassifiedEditOnLoad = false;
+            mSheduledClassifiedCreation = false;
+
+            // set even if not visible, user might delete own
+            // calassified and this string will need to be shown
+            if (getSelfProfile())
+            {
+                mNoItemsLabel->setValue(LLTrans::getString("NoClassifiedsText"));
+            }
+            else
+            {
+                mNoItemsLabel->setValue(LLTrans::getString("NoAvatarClassifiedsText"));
+            }
+
+            bool has_data = mTabContainer->getTabCount() > 0;
+            mNoItemsLabel->setVisible(!has_data);
+            if (has_data && !has_selection)
+            {
+                mTabContainer->selectFirstTab();
+            }
+
+            setLoaded();
+            updateButtons();
+        }
+    }
+}
+
+void LLPanelProfileClassifieds::resetData()
+{
+    resetLoading();
+    mTabContainer->deleteAllTabs();
+}
+
+void LLPanelProfileClassifieds::updateButtons()
+{
+    if (getSelfProfile())
+    {
+        mNewButton->setEnabled(canAddNewClassified());
+        mDeleteButton->setEnabled(canDeleteClassified());
+    }
+}
+
+void LLPanelProfileClassifieds::updateData()
+{
+    // Send picks request only once
+    LLUUID avatar_id = getAvatarId();
+    if (!getStarted() && avatar_id.notNull())
+    {
+        setIsLoading();
+        mNoItemsLabel->setValue(LLTrans::getString("PicksClassifiedsLoadingText"));
+        mNoItemsLabel->setVisible(TRUE);
+
+        LLAvatarPropertiesProcessor::getInstance()->sendAvatarClassifiedsRequest(avatar_id);
+    }
+}
+
+bool LLPanelProfileClassifieds::hasNewClassifieds()
+{
+    for (S32 tab_idx = 0; tab_idx < mTabContainer->getTabCount(); ++tab_idx)
+    {
+        LLPanelProfileClassified* classified_panel = dynamic_cast<LLPanelProfileClassified*>(mTabContainer->getPanelByIndex(tab_idx));
+        if (classified_panel && classified_panel->isNew())
+        {
+            return true;
+        }
+    }
+    return false;
+}
+
+bool LLPanelProfileClassifieds::hasUnsavedChanges()
+{
+    for (S32 tab_idx = 0; tab_idx < mTabContainer->getTabCount(); ++tab_idx)
+    {
+        LLPanelProfileClassified* classified_panel = dynamic_cast<LLPanelProfileClassified*>(mTabContainer->getPanelByIndex(tab_idx));
+        if (classified_panel && classified_panel->isDirty()) // includes 'new'
+        {
+            return true;
+        }
+    }
+    return false;
+}
+
+bool LLPanelProfileClassifieds::canAddNewClassified()
+{
+    return (mTabContainer->getTabCount() < MAX_AVATAR_CLASSIFIEDS);
+}
+
+bool LLPanelProfileClassifieds::canDeleteClassified()
+{
+    return (mTabContainer->getTabCount() > 0);
+}
+
+void LLPanelProfileClassifieds::commitUnsavedChanges()
+{
+    if (getIsLoaded())
+    {
+        for (S32 tab_idx = 0; tab_idx < mTabContainer->getTabCount(); ++tab_idx)
+        {
+            LLPanelProfileClassified* classified_panel = dynamic_cast<LLPanelProfileClassified*>(mTabContainer->getPanelByIndex(tab_idx));
+            if (classified_panel && classified_panel->isDirty() && !classified_panel->isNew())
+            {
+                classified_panel->doSave();
+            }
+        }
+    }
+}
+//-----------------------------------------------------------------------------
+// LLDispatchClassifiedClickThrough
+//-----------------------------------------------------------------------------
+
+// "classifiedclickthrough"
+// strings[0] = classified_id
+// strings[1] = teleport_clicks
+// strings[2] = map_clicks
+// strings[3] = profile_clicks
+class LLDispatchClassifiedClickThrough : public LLDispatchHandler
+{
+public:
+    virtual bool operator()(
+        const LLDispatcher* dispatcher,
+        const std::string& key,
+        const LLUUID& invoice,
+        const sparam_t& strings)
+    {
+        if (strings.size() != 4) return false;
+        LLUUID classified_id(strings[0]);
+        S32 teleport_clicks = atoi(strings[1].c_str());
+        S32 map_clicks = atoi(strings[2].c_str());
+        S32 profile_clicks = atoi(strings[3].c_str());
+
+        LLPanelProfileClassified::setClickThrough(
+            classified_id, teleport_clicks, map_clicks, profile_clicks, false);
+
+        return true;
+    }
+};
+static LLDispatchClassifiedClickThrough sClassifiedClickThrough;
+
+
+//-----------------------------------------------------------------------------
+// LLPanelProfileClassified
+//-----------------------------------------------------------------------------
+
+static const S32 CB_ITEM_MATURE = 0;
+static const S32 CB_ITEM_PG    = 1;
+
+LLPanelProfileClassified::LLPanelProfileClassified()
+ : LLPanelProfilePropertiesProcessorTab()
+ , mInfoLoaded(false)
+ , mTeleportClicksOld(0)
+ , mMapClicksOld(0)
+ , mProfileClicksOld(0)
+ , mTeleportClicksNew(0)
+ , mMapClicksNew(0)
+ , mProfileClicksNew(0)
+ , mPriceForListing(0)
+ , mSnapshotCtrl(NULL)
+ , mPublishFloater(NULL)
+ , mIsNew(false)
+ , mIsNewWithErrors(false)
+ , mCanClose(false)
+ , mEditMode(false)
+ , mEditOnLoad(false)
+{
+    sAllPanels.push_back(this);
+}
+
+LLPanelProfileClassified::~LLPanelProfileClassified()
+{
+    sAllPanels.remove(this);
+    gGenericDispatcher.addHandler("classifiedclickthrough", NULL); // deregister our handler
+}
+
+//static
+LLPanelProfileClassified* LLPanelProfileClassified::create()
+{
+    LLPanelProfileClassified* panel = new LLPanelProfileClassified();
+    panel->buildFromFile("panel_profile_classified.xml");
+    return panel;
+}
+
+BOOL LLPanelProfileClassified::postBuild()
+{
+    mScrollContainer    = getChild<LLScrollContainer>("profile_scroll");
+    mInfoPanel          = getChild<LLView>("info_panel");
+    mInfoScroll         = getChild<LLPanel>("info_scroll_content_panel");
+    mEditPanel          = getChild<LLPanel>("edit_panel");
+
+    mSnapshotCtrl       = getChild<LLTextureCtrl>("classified_snapshot");
+    mEditIcon           = getChild<LLUICtrl>("edit_icon");
+
+    //info
+    mClassifiedNameText = getChild<LLUICtrl>("classified_name");
+    mClassifiedDescText = getChild<LLTextEditor>("classified_desc");
+    mLocationText       = getChild<LLUICtrl>("classified_location");
+    mCategoryText       = getChild<LLUICtrl>("category");
+    mContentTypeText    = getChild<LLUICtrl>("content_type");
+    mContentTypeM       = getChild<LLIconCtrl>("content_type_moderate");
+    mContentTypeG       = getChild<LLIconCtrl>("content_type_general");
+    mPriceText          = getChild<LLUICtrl>("price_for_listing");
+    mAutoRenewText      = getChild<LLUICtrl>("auto_renew");
+
+    mMapButton          = getChild<LLButton>("show_on_map_btn");
+    mTeleportButton     = getChild<LLButton>("teleport_btn");
+    mEditButton         = getChild<LLButton>("edit_btn");
+
+    //edit
+    mClassifiedNameEdit = getChild<LLLineEditor>("classified_name_edit");
+    mClassifiedDescEdit = getChild<LLTextEditor>("classified_desc_edit");
+    mLocationEdit       = getChild<LLUICtrl>("classified_location_edit");
+    mCategoryCombo      = getChild<LLComboBox>("category_edit");
+    mContentTypeCombo   = getChild<LLComboBox>("content_type_edit");
+    mAutoRenewEdit      = getChild<LLUICtrl>("auto_renew_edit");
+
+    mSaveButton         = getChild<LLButton>("save_changes_btn");
+    mSetLocationButton  = getChild<LLButton>("set_to_curr_location_btn");
+    mCancelButton       = getChild<LLButton>("cancel_btn");
+
+    mUtilityBtnCnt = getChild<LLPanel>("util_buttons_lp");
+    mPublishBtnsCnt = getChild<LLPanel>("publish_layout_panel");
+    mCancelBtnCnt = getChild<LLPanel>("cancel_btn_lp");
+    mSaveBtnCnt = getChild<LLPanel>("save_btn_lp");
+
+    mSnapshotCtrl->setOnSelectCallback(boost::bind(&LLPanelProfileClassified::onTextureSelected, this));
+    mSnapshotCtrl->setMouseEnterCallback(boost::bind(&LLPanelProfileClassified::onTexturePickerMouseEnter, this));
+    mSnapshotCtrl->setMouseLeaveCallback(boost::bind(&LLPanelProfileClassified::onTexturePickerMouseLeave, this));
+    mEditIcon->setVisible(false);
+
+    mMapButton->setCommitCallback(boost::bind(&LLPanelProfileClassified::onMapClick, this));
+    mTeleportButton->setCommitCallback(boost::bind(&LLPanelProfileClassified::onTeleportClick, this));
+    mEditButton->setCommitCallback(boost::bind(&LLPanelProfileClassified::onEditClick, this));
+    mSaveButton->setCommitCallback(boost::bind(&LLPanelProfileClassified::onSaveClick, this));
+    mSetLocationButton->setCommitCallback(boost::bind(&LLPanelProfileClassified::onSetLocationClick, this));
+    mCancelButton->setCommitCallback(boost::bind(&LLPanelProfileClassified::onCancelClick, this));
+
+    LLClassifiedInfo::cat_map::iterator iter;
+    for (iter = LLClassifiedInfo::sCategories.begin();
+        iter != LLClassifiedInfo::sCategories.end();
+        iter++)
+    {
+        mCategoryCombo->add(LLTrans::getString(iter->second));
+    }
+
+    mClassifiedNameEdit->setKeystrokeCallback(boost::bind(&LLPanelProfileClassified::onChange, this), NULL);
+    mClassifiedDescEdit->setKeystrokeCallback(boost::bind(&LLPanelProfileClassified::onChange, this));
+    mCategoryCombo->setCommitCallback(boost::bind(&LLPanelProfileClassified::onChange, this));
+    mContentTypeCombo->setCommitCallback(boost::bind(&LLPanelProfileClassified::onChange, this));
+    mAutoRenewEdit->setCommitCallback(boost::bind(&LLPanelProfileClassified::onChange, this));
+
+    return TRUE;
+}
+
+void LLPanelProfileClassified::onOpen(const LLSD& key)
+{
+    mIsNew = key.isUndefined();
+
+    resetData();
+    resetControls();
+    scrollToTop();
+
+    // classified is not created yet
+    bool is_new = isNew() || isNewWithErrors();
+
+    if(is_new)
+    {
+        LLPanelProfilePropertiesProcessorTab::setAvatarId(gAgent.getID());
+
+        setPosGlobal(gAgent.getPositionGlobal());
+
+        LLUUID snapshot_id = LLUUID::null;
+        std::string desc;
+        LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel();
+        if(parcel)
+        {
+            desc = parcel->getDesc();
+            snapshot_id = parcel->getSnapshotID();
+        }
+
+        std::string region_name = LLTrans::getString("ClassifiedUpdateAfterPublish");
+        LLViewerRegion* region = gAgent.getRegion();
+        if (region)
+        {
+            region_name = region->getName();
+        }
+
+        setClassifiedName(makeClassifiedName());
+        setDescription(desc);
+        setSnapshotId(snapshot_id);
+        setClassifiedLocation(createLocationText(getLocationNotice(), region_name, getPosGlobal()));
+        // server will set valid parcel id
+        setParcelId(LLUUID::null);
+
+        mSaveButton->setLabelArg("[LABEL]", getString("publish_label"));
+
+        setEditMode(TRUE);
+        enableSave(true);
+        enableEditing(true);
+        resetDirty();
+        setInfoLoaded(false);
+    }
+    else
+    {
+        LLUUID avatar_id = key["classified_creator_id"];
+        if(avatar_id.isNull())
+        {
+            return;
+        }
+        LLPanelProfilePropertiesProcessorTab::setAvatarId(avatar_id);
+
+        setClassifiedId(key["classified_id"]);
+        setClassifiedName(key["classified_name"]);
+        setFromSearch(key["from_search"]);
+        mEditOnLoad = key["edit"];
+
+        LL_INFOS() << "Opening classified [" << getClassifiedName() << "] (" << getClassifiedId() << ")" << LL_ENDL;
+
+        LLAvatarPropertiesProcessor::getInstance()->sendClassifiedInfoRequest(getClassifiedId());
+
+        gGenericDispatcher.addHandler("classifiedclickthrough", &sClassifiedClickThrough);
+
+        if (gAgent.getRegion())
+        {
+            // While we're at it let's get the stats from the new table if that
+            // capability exists.
+            std::string url = gAgent.getRegion()->getCapability("SearchStatRequest");
+            if (!url.empty())
+            {
+                LL_INFOS() << "Classified stat request via capability" << LL_ENDL;
+                LLSD body;
+                LLUUID classifiedId = getClassifiedId();
+                body["classified_id"] = classifiedId;
+                LLCoreHttpUtil::HttpCoroutineAdapter::callbackHttpPost(url, body,
+                    boost::bind(&LLPanelProfileClassified::handleSearchStatResponse, classifiedId, _1));
+            }
+        }
+        // Update classified click stats.
+        // *TODO: Should we do this when opening not from search?
+        if (!fromSearch() )
+        {
+            sendClickMessage("profile");
+        }
+
+        setInfoLoaded(false);
+    }
+
+
+    bool is_self = getSelfProfile();
+    getChildView("auto_renew_layout_panel")->setVisible(is_self);
+    getChildView("clickthrough_layout_panel")->setVisible(is_self);
+
+    updateButtons();
+}
+
+void LLPanelProfileClassified::processProperties(void* data, EAvatarProcessorType type)
+{
+    if (APT_CLASSIFIED_INFO != type)
+    {
+        return;
+    }
+
+    LLAvatarClassifiedInfo* c_info = static_cast<LLAvatarClassifiedInfo*>(data);
+    if(c_info && getClassifiedId() == c_info->classified_id)
+    {
+        // see LLPanelProfileClassified::sendUpdate() for notes
+        if (mIsNewWithErrors)
+        {
+            // We just published it
+            setEditMode(FALSE);
+        }
+        mIsNewWithErrors = false;
+        mIsNew = false;
+
+        setClassifiedName(c_info->name);
+        setDescription(c_info->description);
+        setSnapshotId(c_info->snapshot_id);
+        setParcelId(c_info->parcel_id);
+        setPosGlobal(c_info->pos_global);
+        setSimName(c_info->sim_name);
+
+        setClassifiedLocation(createLocationText(c_info->parcel_name, c_info->sim_name, c_info->pos_global));
+
+        mCategoryText->setValue(LLClassifiedInfo::sCategories[c_info->category]);
+        // *HACK see LLPanelProfileClassified::sendUpdate()
+        setCategory(c_info->category - 1);
+
+        bool mature = is_cf_mature(c_info->flags);
+        setContentType(mature);
+
+        bool auto_renew = is_cf_auto_renew(c_info->flags);
+        std::string auto_renew_str = auto_renew ? getString("auto_renew_on") : getString("auto_renew_off");
+        mAutoRenewText->setValue(auto_renew_str);
+        mAutoRenewEdit->setValue(auto_renew);
+
+        static LLUIString  price_str = getString("l$_price");
+        price_str.setArg("[PRICE]", llformat("%d", c_info->price_for_listing));
+        mPriceText->setValue(LLSD(price_str));
+
+        static std::string date_fmt = getString("date_fmt");
+        std::string date_str = date_fmt;
+        LLStringUtil::format(date_str, LLSD().with("datetime", (S32) c_info->creation_date));
+        getChild<LLUICtrl>("creation_date")->setValue(date_str);
+
+        resetDirty();
+        setInfoLoaded(true);
+        enableSave(false);
+        enableEditing(true);
+
+        // for just created classified - in case user opened edit panel before processProperties() callback
+        mSaveButton->setLabelArg("[LABEL]", getString("save_label"));
+
+        setLoaded();
+        updateButtons();
+
+        if (mEditOnLoad)
+        {
+            setEditMode(TRUE);
+        }
+    }
+
+}
+
+void LLPanelProfileClassified::setEditMode(BOOL edit_mode)
+{
+    mEditMode = edit_mode;
+
+    mInfoPanel->setVisible(!edit_mode);
+    mEditPanel->setVisible(edit_mode);
+
+    // snapshot control is common between info and edit,
+    // enable it only when in edit mode
+    mSnapshotCtrl->setEnabled(edit_mode);
+
+    scrollToTop();
+    updateButtons();
+    updateInfoRect();
+}
+
+void LLPanelProfileClassified::updateButtons()
+{
+    bool edit_mode = getEditMode();
+    mUtilityBtnCnt->setVisible(!edit_mode);
+
+    // cancel button should either delete unpublished
+    // classified or not be there at all
+    mCancelBtnCnt->setVisible(edit_mode && !mIsNew);
+    mPublishBtnsCnt->setVisible(edit_mode);
+    mSaveBtnCnt->setVisible(edit_mode);
+    mEditButton->setVisible(!edit_mode && getSelfProfile());
+}
+
+void LLPanelProfileClassified::updateInfoRect()
+{
+    if (getEditMode())
+    {
+        // info_scroll_content_panel contains both info and edit panel
+        // info panel can be very large and scroll bar will carry over.
+        // Resize info panel to prevent scroll carry over when in edit mode.
+        mInfoScroll->reshape(mInfoScroll->getRect().getWidth(), DEFAULT_EDIT_CLASSIFIED_SCROLL_HEIGHT, FALSE);
+    }
+    else
+    {
+        // Adjust text height to make description scrollable.
+        S32 new_height = mClassifiedDescText->getTextBoundingRect().getHeight();
+        LLRect visible_rect = mClassifiedDescText->getVisibleDocumentRect();
+        S32 delta_height = new_height - visible_rect.getHeight() + 5;
+
+        LLRect rect = mInfoScroll->getRect();
+        mInfoScroll->reshape(rect.getWidth(), rect.getHeight() + delta_height, FALSE);
+    }
+}
+
+void LLPanelProfileClassified::enableEditing(bool enable)
+{
+    mEditButton->setEnabled(enable);
+    mClassifiedNameEdit->setEnabled(enable);
+    mClassifiedDescEdit->setEnabled(enable);
+    mSetLocationButton->setEnabled(enable);
+    mCategoryCombo->setEnabled(enable);
+    mContentTypeCombo->setEnabled(enable);
+    mAutoRenewEdit->setEnabled(enable);
+}
+
+void LLPanelProfileClassified::resetControls()
+{
+    updateButtons();
+
+    mCategoryCombo->setCurrentByIndex(0);
+    mContentTypeCombo->setCurrentByIndex(0);
+    mAutoRenewEdit->setValue(false);
+    mPriceForListing = MINIMUM_PRICE_FOR_LISTING;
+}
+
+void LLPanelProfileClassified::onEditClick()
+{
+    setEditMode(TRUE);
+}
+
+void LLPanelProfileClassified::onCancelClick()
+{
+    if (isNew())
+    {
+        mClassifiedNameEdit->setValue(mClassifiedNameText->getValue());
+        mClassifiedDescEdit->setValue(mClassifiedDescText->getValue());
+        mLocationEdit->setValue(mLocationText->getValue());
+        mCategoryCombo->setCurrentByIndex(0);
+        mContentTypeCombo->setCurrentByIndex(0);
+        mAutoRenewEdit->setValue(false);
+        mPriceForListing = MINIMUM_PRICE_FOR_LISTING;
+    }
+    else
+    {
+        // Reload data to undo changes to forms
+        LLAvatarPropertiesProcessor::getInstance()->sendClassifiedInfoRequest(getClassifiedId());
+    }
+
+    setInfoLoaded(false);
+
+    setEditMode(FALSE);
+}
+
+void LLPanelProfileClassified::onSaveClick()
+{
+    mCanClose = false;
+
+    if(!isValidName())
+    {
+        notifyInvalidName();
+        return;
+    }
+    if(isNew() || isNewWithErrors())
+    {
+        if(gStatusBar->getBalance() < getPriceForListing())
+        {
+            LLNotificationsUtil::add("ClassifiedInsufficientFunds");
+            return;
+        }
+
+        mPublishFloater = LLFloaterReg::findTypedInstance<LLPublishClassifiedFloater>(
+            "publish_classified", LLSD());
+
+        if(!mPublishFloater)
+        {
+            mPublishFloater = LLFloaterReg::getTypedInstance<LLPublishClassifiedFloater>(
+                "publish_classified", LLSD());
+
+            mPublishFloater->setPublishClickedCallback(boost::bind
+                (&LLPanelProfileClassified::onPublishFloaterPublishClicked, this));
+        }
+
+        // set spinner value before it has focus or value wont be set
+        mPublishFloater->setPrice(getPriceForListing());
+        mPublishFloater->openFloater(mPublishFloater->getKey());
+        mPublishFloater->center();
+    }
+    else
+    {
+        doSave();
+    }
+}
+
+/*static*/
+void LLPanelProfileClassified::handleSearchStatResponse(LLUUID classifiedId, LLSD result)
+{
+    S32 teleport = result["teleport_clicks"].asInteger();
+    S32 map = result["map_clicks"].asInteger();
+    S32 profile = result["profile_clicks"].asInteger();
+    S32 search_teleport = result["search_teleport_clicks"].asInteger();
+    S32 search_map = result["search_map_clicks"].asInteger();
+    S32 search_profile = result["search_profile_clicks"].asInteger();
+
+    LLPanelProfileClassified::setClickThrough(classifiedId,
+        teleport + search_teleport,
+        map + search_map,
+        profile + search_profile,
+        true);
+}
+
+void LLPanelProfileClassified::resetData()
+{
+    setClassifiedName(LLStringUtil::null);
+    setDescription(LLStringUtil::null);
+    setClassifiedLocation(LLStringUtil::null);
+    setClassifiedId(LLUUID::null);
+    setSnapshotId(LLUUID::null);
+    setPosGlobal(LLVector3d::zero);
+    setParcelId(LLUUID::null);
+    setSimName(LLStringUtil::null);
+    setFromSearch(false);
+
+    // reset click stats
+    mTeleportClicksOld  = 0;
+    mMapClicksOld       = 0;
+    mProfileClicksOld   = 0;
+    mTeleportClicksNew  = 0;
+    mMapClicksNew       = 0;
+    mProfileClicksNew   = 0;
+
+    mPriceForListing = MINIMUM_PRICE_FOR_LISTING;
+
+    mCategoryText->setValue(LLStringUtil::null);
+    mContentTypeText->setValue(LLStringUtil::null);
+    getChild<LLUICtrl>("click_through_text")->setValue(LLStringUtil::null);
+    mEditButton->setValue(LLStringUtil::null);
+    getChild<LLUICtrl>("creation_date")->setValue(LLStringUtil::null);
+    mContentTypeM->setVisible(FALSE);
+    mContentTypeG->setVisible(FALSE);
+}
+
+void LLPanelProfileClassified::setClassifiedName(const std::string& name)
+{
+    mClassifiedNameText->setValue(name);
+    mClassifiedNameEdit->setValue(name);
+}
+
+std::string LLPanelProfileClassified::getClassifiedName()
+{
+    return mClassifiedNameEdit->getValue().asString();
+}
+
+void LLPanelProfileClassified::setDescription(const std::string& desc)
+{
+    mClassifiedDescText->setValue(desc);
+    mClassifiedDescEdit->setValue(desc);
+
+    updateInfoRect();
+}
+
+std::string LLPanelProfileClassified::getDescription()
+{
+    return mClassifiedDescEdit->getValue().asString();
+}
+
+void LLPanelProfileClassified::setClassifiedLocation(const std::string& location)
+{
+    mLocationText->setValue(location);
+    mLocationEdit->setValue(location);
+}
+
+std::string LLPanelProfileClassified::getClassifiedLocation()
+{
+    return mLocationText->getValue().asString();
+}
+
+void LLPanelProfileClassified::setSnapshotId(const LLUUID& id)
+{
+    mSnapshotCtrl->setValue(id);
+}
+
+LLUUID LLPanelProfileClassified::getSnapshotId()
+{
+    return mSnapshotCtrl->getValue().asUUID();
+}
+
+// static
+void LLPanelProfileClassified::setClickThrough(
+    const LLUUID& classified_id,
+    S32 teleport,
+    S32 map,
+    S32 profile,
+    bool from_new_table)
+{
+    LL_INFOS() << "Click-through data for classified " << classified_id << " arrived: ["
+            << teleport << ", " << map << ", " << profile << "] ("
+            << (from_new_table ? "new" : "old") << ")" << LL_ENDL;
+
+    for (panel_list_t::iterator iter = sAllPanels.begin(); iter != sAllPanels.end(); ++iter)
+    {
+        LLPanelProfileClassified* self = *iter;
+        if (self->getClassifiedId() != classified_id)
+        {
+            continue;
+        }
+
+        // *HACK: Skip LLPanelProfileClassified instances: they don't display clicks data.
+        // Those instances should not be in the list at all.
+        if (typeid(*self) != typeid(LLPanelProfileClassified))
+        {
+            continue;
+        }
+
+        LL_INFOS() << "Updating classified info panel" << LL_ENDL;
+
+        // We need to check to see if the data came from the new stat_table
+        // or the old classified table. We also need to cache the data from
+        // the two separate sources so as to display the aggregate totals.
+
+        if (from_new_table)
+        {
+            self->mTeleportClicksNew = teleport;
+            self->mMapClicksNew = map;
+            self->mProfileClicksNew = profile;
+        }
+        else
+        {
+            self->mTeleportClicksOld = teleport;
+            self->mMapClicksOld = map;
+            self->mProfileClicksOld = profile;
+        }
+
+        static LLUIString ct_str = self->getString("click_through_text_fmt");
+
+        ct_str.setArg("[TELEPORT]", llformat("%d", self->mTeleportClicksNew + self->mTeleportClicksOld));
+        ct_str.setArg("[MAP]",      llformat("%d", self->mMapClicksNew + self->mMapClicksOld));
+        ct_str.setArg("[PROFILE]",  llformat("%d", self->mProfileClicksNew + self->mProfileClicksOld));
+
+        self->getChild<LLUICtrl>("click_through_text")->setValue(ct_str.getString());
+        // *HACK: remove this when there is enough room for click stats in the info panel
+        self->getChildView("click_through_text")->setToolTip(ct_str.getString());
+
+        LL_INFOS() << "teleport: " << llformat("%d", self->mTeleportClicksNew + self->mTeleportClicksOld)
+                << ", map: "    << llformat("%d", self->mMapClicksNew + self->mMapClicksOld)
+                << ", profile: " << llformat("%d", self->mProfileClicksNew + self->mProfileClicksOld)
+                << LL_ENDL;
+    }
+}
+
+// static
+std::string LLPanelProfileClassified::createLocationText(
+    const std::string& original_name,
+    const std::string& sim_name,
+    const LLVector3d& pos_global)
+{
+    std::string location_text;
+
+    location_text.append(original_name);
+
+    if (!sim_name.empty())
+    {
+        if (!location_text.empty())
+            location_text.append(", ");
+        location_text.append(sim_name);
+    }
+
+    if (!location_text.empty())
+        location_text.append(" ");
+
+    if (!pos_global.isNull())
+    {
+        S32 region_x = ll_round((F32)pos_global.mdV[VX]) % REGION_WIDTH_UNITS;
+        S32 region_y = ll_round((F32)pos_global.mdV[VY]) % REGION_WIDTH_UNITS;
+        S32 region_z = ll_round((F32)pos_global.mdV[VZ]);
+        location_text.append(llformat(" (%d, %d, %d)", region_x, region_y, region_z));
+    }
+
+    return location_text;
+}
+
+void LLPanelProfileClassified::scrollToTop()
+{
+    if (mScrollContainer)
+    {
+        mScrollContainer->goToTop();
+    }
+}
+
+//info
+// static
+// *TODO: move out of the panel
+void LLPanelProfileClassified::sendClickMessage(
+        const std::string& type,
+        bool from_search,
+        const LLUUID& classified_id,
+        const LLUUID& parcel_id,
+        const LLVector3d& global_pos,
+        const std::string& sim_name)
+{
+    if (gAgent.getRegion())
+    {
+        // You're allowed to click on your own ads to reassure yourself
+        // that the system is working.
+        LLSD body;
+        body["type"]            = type;
+        body["from_search"]     = from_search;
+        body["classified_id"]   = classified_id;
+        body["parcel_id"]       = parcel_id;
+        body["dest_pos_global"] = global_pos.getValue();
+        body["region_name"]     = sim_name;
+
+        std::string url = gAgent.getRegion()->getCapability("SearchStatTracking");
+        LL_INFOS() << "Sending click msg via capability (url=" << url << ")" << LL_ENDL;
+        LL_INFOS() << "body: [" << body << "]" << LL_ENDL;
+        LLCoreHttpUtil::HttpCoroutineAdapter::messageHttpPost(url, body,
+            "SearchStatTracking Click report sent.", "SearchStatTracking Click report NOT sent.");
+    }
+}
+
+void LLPanelProfileClassified::sendClickMessage(const std::string& type)
+{
+    sendClickMessage(
+        type,
+        fromSearch(),
+        getClassifiedId(),
+        getParcelId(),
+        getPosGlobal(),
+        getSimName());
+}
+
+void LLPanelProfileClassified::onMapClick()
+{
+    sendClickMessage("map");
+    LLFloaterWorldMap::getInstance()->trackLocation(getPosGlobal());
+    LLFloaterReg::showInstance("world_map", "center");
+}
+
+void LLPanelProfileClassified::onTeleportClick()
+{
+    if (!getPosGlobal().isExactlyZero())
+    {
+        sendClickMessage("teleport");
+        gAgent.teleportViaLocation(getPosGlobal());
+        LLFloaterWorldMap::getInstance()->trackLocation(getPosGlobal());
+    }
+}
+
+BOOL LLPanelProfileClassified::isDirty() const
+{
+    if(mIsNew)
+    {
+        return TRUE;
+    }
+
+    BOOL dirty = false;
+    dirty |= mSnapshotCtrl->isDirty();
+    dirty |= mClassifiedNameEdit->isDirty();
+    dirty |= mClassifiedDescEdit->isDirty();
+    dirty |= mCategoryCombo->isDirty();
+    dirty |= mContentTypeCombo->isDirty();
+    dirty |= mAutoRenewEdit->isDirty();
+
+    return dirty;
+}
+
+void LLPanelProfileClassified::resetDirty()
+{
+    mSnapshotCtrl->resetDirty();
+    mClassifiedNameEdit->resetDirty();
+
+    // call blockUndo() to really reset dirty(and make isDirty work as intended)
+    mClassifiedDescEdit->blockUndo();
+    mClassifiedDescEdit->resetDirty();
+
+    mCategoryCombo->resetDirty();
+    mContentTypeCombo->resetDirty();
+    mAutoRenewEdit->resetDirty();
+}
+
+bool LLPanelProfileClassified::canClose()
+{
+    return mCanClose;
+}
+
+U32 LLPanelProfileClassified::getContentType()
+{
+    return mContentTypeCombo->getCurrentIndex();
+}
+
+void LLPanelProfileClassified::setContentType(bool mature)
+{
+    static std::string mature_str = getString("type_mature");
+    static std::string pg_str = getString("type_pg");
+    mContentTypeText->setValue(mature ? mature_str : pg_str);
+    mContentTypeM->setVisible(mature);
+    mContentTypeG->setVisible(!mature);
+    mContentTypeCombo->setCurrentByIndex(mature ? CB_ITEM_MATURE : CB_ITEM_PG);
+    mContentTypeCombo->resetDirty();
+}
+
+bool LLPanelProfileClassified::getAutoRenew()
+{
+    return mAutoRenewEdit->getValue().asBoolean();
+}
+
+void LLPanelProfileClassified::sendUpdate()
+{
+    LLAvatarClassifiedInfo c_data;
+
+    if(getClassifiedId().isNull())
+    {
+        setClassifiedId(LLUUID::generateNewID());
+    }
+
+    c_data.agent_id = gAgent.getID();
+    c_data.classified_id = getClassifiedId();
+    // *HACK
+    // Categories on server start with 1 while combo-box index starts with 0
+    c_data.category = getCategory() + 1;
+    c_data.name = getClassifiedName();
+    c_data.description = getDescription();
+    c_data.parcel_id = getParcelId();
+    c_data.snapshot_id = getSnapshotId();
+    c_data.pos_global = getPosGlobal();
+    c_data.flags = getFlags();
+    c_data.price_for_listing = getPriceForListing();
+
+    LLAvatarPropertiesProcessor::getInstance()->sendClassifiedInfoUpdate(&c_data);
+
+    if(isNew())
+    {
+        // Lets assume there will be some error.
+        // Successful sendClassifiedInfoUpdate will trigger processProperties and
+        // let us know there was no error.
+        mIsNewWithErrors = true;
+    }
+}
+
+U32 LLPanelProfileClassified::getCategory()
+{
+    return mCategoryCombo->getCurrentIndex();
+}
+
+void LLPanelProfileClassified::setCategory(U32 category)
+{
+    mCategoryCombo->setCurrentByIndex(category);
+    mCategoryCombo->resetDirty();
+}
+
+U8 LLPanelProfileClassified::getFlags()
+{
+    bool auto_renew = mAutoRenewEdit->getValue().asBoolean();
+
+    bool mature = mContentTypeCombo->getCurrentIndex() == CB_ITEM_MATURE;
+
+    return pack_classified_flags_request(auto_renew, false, mature, false);
+}
+
+void LLPanelProfileClassified::enableSave(bool enable)
+{
+    mSaveButton->setEnabled(enable);
+}
+
+std::string LLPanelProfileClassified::makeClassifiedName()
+{
+    std::string name;
+
+    LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel();
+    if(parcel)
+    {
+        name = parcel->getName();
+    }
+
+    if(!name.empty())
+    {
+        return name;
+    }
+
+    LLViewerRegion* region = gAgent.getRegion();
+    if(region)
+    {
+        name = region->getName();
+    }
+
+    return name;
+}
+
+void LLPanelProfileClassified::onSetLocationClick()
+{
+    setPosGlobal(gAgent.getPositionGlobal());
+    setParcelId(LLUUID::null);
+
+    std::string region_name = LLTrans::getString("ClassifiedUpdateAfterPublish");
+    LLViewerRegion* region = gAgent.getRegion();
+    if (region)
+    {
+        region_name = region->getName();
+    }
+
+    setClassifiedLocation(createLocationText(getLocationNotice(), region_name, getPosGlobal()));
+
+    // mark classified as dirty
+    setValue(LLSD());
+
+    onChange();
+}
+
+void LLPanelProfileClassified::onChange()
+{
+    enableSave(isDirty());
+}
+
+void LLPanelProfileClassified::doSave()
+{
+    //*TODO: Fix all of this
+
+    mCanClose = true;
+    sendUpdate();
+    updateTabLabel(getClassifiedName());
+    resetDirty();
+
+    if (!canClose())
+    {
+        return;
+    }
+
+    if (!isNew() && !isNewWithErrors())
+    {
+        setEditMode(FALSE);
+        return;
+    }
+
+    updateButtons();
+}
+
+void LLPanelProfileClassified::onPublishFloaterPublishClicked()
+{
+    setPriceForListing(mPublishFloater->getPrice());
+
+    doSave();
+}
+
+std::string LLPanelProfileClassified::getLocationNotice()
+{
+    static std::string location_notice = getString("location_notice");
+    return location_notice;
+}
+
+bool LLPanelProfileClassified::isValidName()
+{
+    std::string name = getClassifiedName();
+    if (name.empty())
+    {
+        return false;
+    }
+    if (!isalnum(name[0]))
+    {
+        return false;
+    }
+
+    return true;
+}
+
+void LLPanelProfileClassified::notifyInvalidName()
+{
+    std::string name = getClassifiedName();
+    if (name.empty())
+    {
+        LLNotificationsUtil::add("BlankClassifiedName");
+    }
+    else if (!isalnum(name[0]))
+    {
+        LLNotificationsUtil::add("ClassifiedMustBeAlphanumeric");
+    }
+}
+
+void LLPanelProfileClassified::onTexturePickerMouseEnter()
+{
+    mEditIcon->setVisible(TRUE);
+}
+
+void LLPanelProfileClassified::onTexturePickerMouseLeave()
+{
+    mEditIcon->setVisible(FALSE);
+}
+
+void LLPanelProfileClassified::onTextureSelected()
+{
+    setSnapshotId(mSnapshotCtrl->getValue().asUUID());
+    onChange();
+}
+
+void LLPanelProfileClassified::updateTabLabel(const std::string& title)
+{
+    setLabel(title);
+    LLTabContainer* parent = dynamic_cast<LLTabContainer*>(getParent());
+    if (parent)
+    {
+        parent->setCurrentTabName(title);
+    }
+}
+
+
+//-----------------------------------------------------------------------------
+// LLPublishClassifiedFloater
+//-----------------------------------------------------------------------------
+
+LLPublishClassifiedFloater::LLPublishClassifiedFloater(const LLSD& key)
+ : LLFloater(key)
+{
+}
+
+LLPublishClassifiedFloater::~LLPublishClassifiedFloater()
+{
+}
+
+BOOL LLPublishClassifiedFloater::postBuild()
+{
+    LLFloater::postBuild();
+
+    childSetAction("publish_btn", boost::bind(&LLFloater::closeFloater, this, false));
+    childSetAction("cancel_btn", boost::bind(&LLFloater::closeFloater, this, false));
+
+    return TRUE;
+}
+
+void LLPublishClassifiedFloater::setPrice(S32 price)
+{
+    getChild<LLUICtrl>("price_for_listing")->setValue(price);
+}
+
+S32 LLPublishClassifiedFloater::getPrice()
+{
+    return getChild<LLUICtrl>("price_for_listing")->getValue().asInteger();
+}
+
+void LLPublishClassifiedFloater::setPublishClickedCallback(const commit_signal_t::slot_type& cb)
+{
+    getChild<LLButton>("publish_btn")->setClickedCallback(cb);
+}
+
+void LLPublishClassifiedFloater::setCancelClickedCallback(const commit_signal_t::slot_type& cb)
+{
+    getChild<LLButton>("cancel_btn")->setClickedCallback(cb);
+}
diff --git a/indra/newview/llpanelprofileclassifieds.h b/indra/newview/llpanelprofileclassifieds.h
new file mode 100644
index 0000000000000000000000000000000000000000..912819e86bce0729096def3ede8c3c0b76c48a05
--- /dev/null
+++ b/indra/newview/llpanelprofileclassifieds.h
@@ -0,0 +1,340 @@
+/**
+ * @file llpanelprofileclassifieds.h
+ * @brief LLPanelProfileClassifieds and related class implementations
+ *
+ * $LicenseInfo:firstyear=2022&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2022, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_PANELPROFILECLASSIFIEDS_H
+#define LL_PANELPROFILECLASSIFIEDS_H
+
+#include "llavatarpropertiesprocessor.h"
+#include "llclassifiedinfo.h"
+#include "llfloater.h"
+#include "llpanel.h"
+#include "llpanelavatar.h"
+#include "llrect.h"
+#include "lluuid.h"
+#include "v3dmath.h"
+#include "llcoros.h"
+#include "lleventcoro.h"
+
+class LLCheckBoxCtrl;
+class LLLineEditor;
+class LLMediaCtrl;
+class LLScrollContainer;
+class LLTabContainer;
+class LLTextEditor;
+class LLTextureCtrl;
+class LLUICtrl;
+
+
+class LLPublishClassifiedFloater : public LLFloater
+{
+public:
+    LLPublishClassifiedFloater(const LLSD& key);
+    virtual ~LLPublishClassifiedFloater();
+
+    BOOL postBuild() override;
+
+    void setPrice(S32 price);
+    S32 getPrice();
+
+    void setPublishClickedCallback(const commit_signal_t::slot_type& cb);
+    void setCancelClickedCallback(const commit_signal_t::slot_type& cb);
+};
+
+
+/**
+* Panel for displaying Avatar's picks.
+*/
+class LLPanelProfileClassifieds
+    : public LLPanelProfilePropertiesProcessorTab
+{
+public:
+    LLPanelProfileClassifieds();
+    /*virtual*/ ~LLPanelProfileClassifieds();
+
+    BOOL postBuild() override;
+
+    void onOpen(const LLSD& key) override;
+
+    void selectClassified(const LLUUID& classified_id, bool edit);
+
+    void createClassified();
+
+    void processProperties(void* data, EAvatarProcessorType type) override;
+
+    void resetData() override;
+
+    void updateButtons();
+
+    void updateData() override;
+
+    bool hasNewClassifieds();
+    bool hasUnsavedChanges() override;
+    // commits changes to existing classifieds, but does not publish new classified!
+    void commitUnsavedChanges() override;
+
+private:
+    void onClickNewBtn();
+    void onClickDelete();
+    void callbackDeleteClassified(const LLSD& notification, const LLSD& response);
+
+    bool canAddNewClassified();
+    bool canDeleteClassified();
+
+    LLTabContainer* mTabContainer;
+    LLUICtrl*       mNoItemsLabel;
+    LLButton*       mNewButton;
+    LLButton*       mDeleteButton;
+
+    LLUUID          mClassifiedToSelectOnLoad;
+    bool            mClassifiedEditOnLoad;
+    bool            mSheduledClassifiedCreation;
+};
+
+
+class LLPanelProfileClassified
+    : public LLPanelProfilePropertiesProcessorTab
+{
+public:
+
+    static LLPanelProfileClassified* create();
+
+    LLPanelProfileClassified();
+
+    /*virtual*/ ~LLPanelProfileClassified();
+
+    BOOL postBuild() override;
+
+    void onOpen(const LLSD& key) override;
+
+    void processProperties(void* data, EAvatarProcessorType type) override;
+
+    void setSnapshotId(const LLUUID& id);
+
+    LLUUID getSnapshotId();
+
+    void setClassifiedId(const LLUUID& id) { mClassifiedId = id; }
+
+    LLUUID& getClassifiedId() { return mClassifiedId; }
+
+    void setClassifiedName(const std::string& name);
+
+    std::string getClassifiedName();
+
+    void setDescription(const std::string& desc);
+
+    std::string getDescription();
+
+    void setClassifiedLocation(const std::string& location);
+
+    std::string getClassifiedLocation();
+
+    void setPosGlobal(const LLVector3d& pos) { mPosGlobal = pos; }
+
+    LLVector3d& getPosGlobal() { return mPosGlobal; }
+
+    void setParcelId(const LLUUID& id) { mParcelId = id; }
+
+    LLUUID getParcelId() { return mParcelId; }
+
+    void setSimName(const std::string& sim_name) { mSimName = sim_name; }
+
+    std::string getSimName() { return mSimName; }
+
+    void setFromSearch(bool val) { mFromSearch = val; }
+
+    bool fromSearch() { return mFromSearch; }
+
+    bool getInfoLoaded() { return mInfoLoaded; }
+
+    void setInfoLoaded(bool loaded) { mInfoLoaded = loaded; }
+
+    BOOL isDirty() const override;
+
+    void resetDirty() override;
+
+    bool isNew() { return mIsNew; }
+
+    bool isNewWithErrors() { return mIsNewWithErrors; }
+
+    bool canClose();
+
+    U32 getCategory();
+
+    void setCategory(U32 category);
+
+    U32 getContentType();
+
+    void setContentType(bool mature);
+
+    bool getAutoRenew();
+
+    S32 getPriceForListing() { return mPriceForListing; }
+
+    void setEditMode(BOOL edit_mode);
+    bool getEditMode() {return mEditMode;}
+
+    static void setClickThrough(
+        const LLUUID& classified_id,
+        S32 teleport,
+        S32 map,
+        S32 profile,
+        bool from_new_table);
+
+    static void sendClickMessage(
+            const std::string& type,
+            bool from_search,
+            const LLUUID& classified_id,
+            const LLUUID& parcel_id,
+            const LLVector3d& global_pos,
+            const std::string& sim_name);
+
+    void doSave();
+
+protected:
+
+    void resetData() override;
+
+    void resetControls();
+
+    void updateButtons();
+    void updateInfoRect();
+
+    static std::string createLocationText(
+        const std::string& original_name,
+        const std::string& sim_name,
+        const LLVector3d& pos_global);
+
+    void sendClickMessage(const std::string& type);
+
+    void scrollToTop();
+
+    void onEditClick();
+    void onCancelClick();
+    void onSaveClick();
+    void onMapClick();
+    void onTeleportClick();
+
+    void sendUpdate();
+
+    void enableSave(bool enable);
+
+    void enableEditing(bool enable);
+
+    std::string makeClassifiedName();
+
+    void setPriceForListing(S32 price) { mPriceForListing = price; }
+
+    U8 getFlags();
+
+    std::string getLocationNotice();
+
+    bool isValidName();
+
+    void notifyInvalidName();
+
+    void onSetLocationClick();
+    void onChange();
+
+    void onPublishFloaterPublishClicked();
+
+    void onTexturePickerMouseEnter();
+    void onTexturePickerMouseLeave();
+
+    void onTextureSelected();
+
+    void updateTabLabel(const std::string& title);
+
+private:
+
+    LLTextureCtrl*      mSnapshotCtrl;
+    LLUICtrl*           mEditIcon;
+    LLUICtrl*           mClassifiedNameText;
+    LLTextEditor*       mClassifiedDescText;
+    LLLineEditor*       mClassifiedNameEdit;
+    LLTextEditor*       mClassifiedDescEdit;
+    LLUICtrl*           mLocationText;
+    LLUICtrl*           mLocationEdit;
+    LLUICtrl*           mCategoryText;
+    LLComboBox*         mCategoryCombo;
+    LLUICtrl*           mContentTypeText;
+    LLIconCtrl*         mContentTypeM;
+    LLIconCtrl*         mContentTypeG;
+    LLComboBox*         mContentTypeCombo;
+    LLUICtrl*           mPriceText;
+    LLUICtrl*           mAutoRenewText;
+    LLUICtrl*           mAutoRenewEdit;
+
+    LLButton*           mMapButton;
+    LLButton*           mTeleportButton;
+    LLButton*           mEditButton;
+    LLButton*           mSaveButton;
+    LLButton*           mSetLocationButton;
+    LLButton*           mCancelButton;
+
+    LLPanel*            mUtilityBtnCnt;
+    LLPanel*            mPublishBtnsCnt;
+    LLPanel*            mSaveBtnCnt;
+    LLPanel*            mCancelBtnCnt;
+
+    LLScrollContainer*  mScrollContainer;
+    LLView*             mInfoPanel;
+    LLPanel*            mInfoScroll;
+    LLPanel*            mEditPanel;
+
+
+    LLUUID mClassifiedId;
+    LLVector3d mPosGlobal;
+    LLUUID mParcelId;
+    std::string mSimName;
+    bool mFromSearch;
+    bool mInfoLoaded;
+    bool mEditMode;
+
+    // Needed for stat tracking
+    S32 mTeleportClicksOld;
+    S32 mMapClicksOld;
+    S32 mProfileClicksOld;
+    S32 mTeleportClicksNew;
+    S32 mMapClicksNew;
+    S32 mProfileClicksNew;
+
+    S32 mPriceForListing;
+
+    static void handleSearchStatResponse(LLUUID classifiedId, LLSD result);
+
+    typedef std::list<LLPanelProfileClassified*> panel_list_t;
+    static panel_list_t sAllPanels;
+
+
+    bool mIsNew;
+    bool mIsNewWithErrors;
+    bool mCanClose;
+    bool mEditOnLoad;
+
+    LLPublishClassifiedFloater* mPublishFloater;
+};
+
+#endif // LL_PANELPROFILECLASSIFIEDS_H
diff --git a/indra/newview/llpanelprofilepicks.cpp b/indra/newview/llpanelprofilepicks.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..774119f16975e48fdb88ab6a84acf6b327bff26c
--- /dev/null
+++ b/indra/newview/llpanelprofilepicks.cpp
@@ -0,0 +1,883 @@
+/**
+ * @file llpanelprofilepicks.cpp
+ * @brief LLPanelProfilePicks and related class implementations
+ *
+ * $LicenseInfo:firstyear=2009&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llpanelprofilepicks.h"
+
+#include "llagent.h"
+#include "llagentpicksinfo.h"
+#include "llavataractions.h"
+#include "llavatarpropertiesprocessor.h"
+#include "llcommandhandler.h"
+#include "lldispatcher.h"
+#include "llfloaterreg.h"
+#include "llfloaterworldmap.h"
+#include "lllineeditor.h"
+#include "llnotificationsutil.h"
+#include "llpanelavatar.h"
+#include "llpanelprofile.h"
+#include "llparcel.h"
+#include "llstartup.h"
+#include "lltabcontainer.h"
+#include "lltextbox.h"
+#include "lltexteditor.h"
+#include "lltexturectrl.h"
+#include "lltexturectrl.h"
+#include "lltrans.h"
+#include "llviewergenericmessage.h" // send_generic_message
+#include "llviewerparcelmgr.h"
+#include "llviewerregion.h"
+
+static LLPanelInjector<LLPanelProfilePicks> t_panel_profile_picks("panel_profile_picks");
+static LLPanelInjector<LLPanelProfilePick> t_panel_profile_pick("panel_profile_pick");
+
+
+class LLPickHandler : public LLCommandHandler
+{
+public:
+
+    // requires trusted browser to trigger
+    LLPickHandler() : LLCommandHandler("pick", UNTRUSTED_THROTTLE) { }
+
+    bool handle(const LLSD& params, const LLSD& query_map,
+        LLMediaCtrl* web)
+    {
+        if (LLStartUp::getStartupState() < STATE_STARTED)
+        {
+            return true;
+        }
+
+        if (!LLUI::getInstance()->mSettingGroups["config"]->getBOOL("EnablePicks"))
+        {
+            LLNotificationsUtil::add("NoPicks", LLSD(), LLSD(), std::string("SwitchToStandardSkinAndQuit"));
+            return true;
+        }
+
+        // handle app/pick/create urls first
+        if (params.size() == 1 && params[0].asString() == "create")
+        {
+            LLAvatarActions::createPick();
+            return true;
+        }
+
+        // then handle the general app/pick/{UUID}/{CMD} urls
+        if (params.size() < 2)
+        {
+            return false;
+        }
+
+        // get the ID for the pick_id
+        LLUUID pick_id;
+        if (!pick_id.set(params[0], FALSE))
+        {
+            return false;
+        }
+
+        // edit the pick in the side tray.
+        // need to ask the server for more info first though...
+        const std::string verb = params[1].asString();
+        if (verb == "edit")
+        {
+            LLAvatarActions::showPick(gAgent.getID(), pick_id);
+            return true;
+        }
+        else
+        {
+            LL_WARNS() << "unknown verb " << verb << LL_ENDL;
+            return false;
+        }
+    }
+};
+LLPickHandler gPickHandler;
+
+
+//-----------------------------------------------------------------------------
+// LLPanelProfilePicks
+//-----------------------------------------------------------------------------
+
+LLPanelProfilePicks::LLPanelProfilePicks()
+ : LLPanelProfilePropertiesProcessorTab()
+ , mPickToSelectOnLoad(LLUUID::null)
+{
+}
+
+LLPanelProfilePicks::~LLPanelProfilePicks()
+{
+}
+
+void LLPanelProfilePicks::onOpen(const LLSD& key)
+{
+    LLPanelProfilePropertiesProcessorTab::onOpen(key);
+
+    resetData();
+
+    bool own_profile = getSelfProfile();
+    if (own_profile)
+    {
+        mNewButton->setVisible(TRUE);
+        mNewButton->setEnabled(FALSE);
+
+        mDeleteButton->setVisible(TRUE);
+        mDeleteButton->setEnabled(FALSE);
+    }
+
+    childSetVisible("buttons_header", own_profile);
+}
+
+void LLPanelProfilePicks::createPick(const LLPickData &data)
+{
+    if (getIsLoaded())
+    {
+        if (canAddNewPick())
+        {
+            mNoItemsLabel->setVisible(FALSE);
+            LLPanelProfilePick* pick_panel = LLPanelProfilePick::create();
+            pick_panel->setAvatarId(getAvatarId());
+            pick_panel->processProperties(&data);
+            mTabContainer->addTabPanel(
+                LLTabContainer::TabPanelParams().
+                panel(pick_panel).
+                select_tab(true).
+                label(pick_panel->getPickName()));
+            updateButtons();
+        }
+        else
+        {
+            // This means that something doesn't properly check limits
+            // before creating a pick
+            LL_WARNS() << "failed to add pick" << LL_ENDL;
+        }
+    }
+    else
+    {
+        mSheduledPickCreation.push_back(data);
+    }
+}
+
+void LLPanelProfilePicks::selectPick(const LLUUID& pick_id)
+{
+    if (getIsLoaded())
+    {
+        for (S32 tab_idx = 0; tab_idx < mTabContainer->getTabCount(); ++tab_idx)
+        {
+            LLPanelProfilePick* pick_panel = dynamic_cast<LLPanelProfilePick*>(mTabContainer->getPanelByIndex(tab_idx));
+            if (pick_panel)
+            {
+                if (pick_panel->getPickId() == pick_id)
+                {
+                    mTabContainer->selectTabPanel(pick_panel);
+                    break;
+                }
+            }
+        }
+    }
+    else
+    {
+        mPickToSelectOnLoad = pick_id;
+    }
+}
+
+BOOL LLPanelProfilePicks::postBuild()
+{
+    mTabContainer = getChild<LLTabContainer>("tab_picks");
+    mNoItemsLabel = getChild<LLUICtrl>("picks_panel_text");
+    mNewButton = getChild<LLButton>("new_btn");
+    mDeleteButton = getChild<LLButton>("delete_btn");
+
+    mNewButton->setCommitCallback(boost::bind(&LLPanelProfilePicks::onClickNewBtn, this));
+    mDeleteButton->setCommitCallback(boost::bind(&LLPanelProfilePicks::onClickDelete, this));
+
+    return TRUE;
+}
+
+void LLPanelProfilePicks::onClickNewBtn()
+{
+    mNoItemsLabel->setVisible(FALSE);
+    LLPanelProfilePick* pick_panel = LLPanelProfilePick::create();
+    pick_panel->setAvatarId(getAvatarId());
+    mTabContainer->addTabPanel(
+        LLTabContainer::TabPanelParams().
+        panel(pick_panel).
+        select_tab(true).
+        label(pick_panel->getPickName()));
+    updateButtons();
+}
+
+void LLPanelProfilePicks::onClickDelete()
+{
+    LLPanelProfilePick* pick_panel = dynamic_cast<LLPanelProfilePick*>(mTabContainer->getCurrentPanel());
+    if (pick_panel)
+    {
+        LLUUID pick_id = pick_panel->getPickId();
+        LLSD args;
+        args["PICK"] = pick_panel->getPickName();
+        LLSD payload;
+        payload["pick_id"] = pick_id;
+        payload["tab_idx"] = mTabContainer->getCurrentPanelIndex();
+        LLNotificationsUtil::add("ProfileDeletePick", args, payload,
+            boost::bind(&LLPanelProfilePicks::callbackDeletePick, this, _1, _2));
+    }
+}
+
+void LLPanelProfilePicks::callbackDeletePick(const LLSD& notification, const LLSD& response)
+{
+    S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+
+    if (0 == option)
+    {
+        LLUUID pick_id = notification["payload"]["pick_id"].asUUID();
+        S32 tab_idx = notification["payload"]["tab_idx"].asInteger();
+
+        LLPanelProfilePick* pick_panel = dynamic_cast<LLPanelProfilePick*>(mTabContainer->getPanelByIndex(tab_idx));
+        if (pick_panel && pick_panel->getPickId() == pick_id)
+        {
+            mTabContainer->removeTabPanel(pick_panel);
+        }
+
+        if (pick_id.notNull())
+        {
+            LLAvatarPropertiesProcessor::getInstance()->sendPickDelete(pick_id);
+        }
+
+        updateButtons();
+    }
+}
+
+void LLPanelProfilePicks::processProperties(void* data, EAvatarProcessorType type)
+{
+    if (APT_PICKS == type)
+    {
+        LLAvatarPicks* avatar_picks = static_cast<LLAvatarPicks*>(data);
+        if (avatar_picks && getAvatarId() == avatar_picks->target_id)
+        {
+            processProperties(avatar_picks);
+        }
+    }
+}
+
+void LLPanelProfilePicks::processProperties(const LLAvatarPicks* avatar_picks)
+{
+    LLUUID selected_id = mPickToSelectOnLoad;
+    bool has_selection = false;
+    if (mPickToSelectOnLoad.isNull())
+    {
+        if (mTabContainer->getTabCount() > 0)
+        {
+            LLPanelProfilePick* active_pick_panel = dynamic_cast<LLPanelProfilePick*>(mTabContainer->getCurrentPanel());
+            if (active_pick_panel)
+            {
+                selected_id = active_pick_panel->getPickId();
+            }
+        }
+    }
+
+    mTabContainer->deleteAllTabs();
+
+    LLAvatarPicks::picks_list_t::const_iterator it = avatar_picks->picks_list.begin();
+    for (; avatar_picks->picks_list.end() != it; ++it)
+    {
+        LLUUID pick_id = it->first;
+        std::string pick_name = it->second;
+
+        LLPanelProfilePick* pick_panel = LLPanelProfilePick::create();
+
+        pick_panel->setPickId(pick_id);
+        pick_panel->setPickName(pick_name);
+        pick_panel->setAvatarId(getAvatarId());
+
+        mTabContainer->addTabPanel(
+            LLTabContainer::TabPanelParams().
+            panel(pick_panel).
+            select_tab(selected_id == pick_id).
+            label(pick_name));
+
+        if (selected_id == pick_id)
+        {
+            has_selection = true;
+        }
+    }
+
+    while (!mSheduledPickCreation.empty() && canAddNewPick())
+    {
+        const LLPickData data =
+            mSheduledPickCreation.back();
+
+        LLPanelProfilePick* pick_panel = LLPanelProfilePick::create();
+        pick_panel->setAvatarId(getAvatarId());
+        pick_panel->processProperties(&data);
+        mTabContainer->addTabPanel(
+            LLTabContainer::TabPanelParams().
+            panel(pick_panel).
+            select_tab(!has_selection).
+            label(pick_panel->getPickName()));
+
+        mSheduledPickCreation.pop_back();
+        has_selection = true;
+    }
+
+    // reset 'do on load' values
+    mPickToSelectOnLoad = LLUUID::null;
+    mSheduledPickCreation.clear();
+
+    if (getSelfProfile())
+    {
+        mNoItemsLabel->setValue(LLTrans::getString("NoPicksText"));
+    }
+    else
+    {
+        mNoItemsLabel->setValue(LLTrans::getString("NoAvatarPicksText"));
+    }
+
+    bool has_data = mTabContainer->getTabCount() > 0;
+    mNoItemsLabel->setVisible(!has_data);
+    if (has_data && !has_selection)
+    {
+        mTabContainer->selectFirstTab();
+    }
+
+    setLoaded();
+    updateButtons();
+}
+
+void LLPanelProfilePicks::resetData()
+{
+    resetLoading();
+    mTabContainer->deleteAllTabs();
+}
+
+void LLPanelProfilePicks::updateButtons()
+{
+    if (getSelfProfile())
+    {
+        mNewButton->setEnabled(canAddNewPick());
+        mDeleteButton->setEnabled(canDeletePick());
+    }
+}
+
+void LLPanelProfilePicks::apply()
+{
+    if (getIsLoaded())
+    {
+        for (S32 tab_idx = 0; tab_idx < mTabContainer->getTabCount(); ++tab_idx)
+        {
+            LLPanelProfilePick* pick_panel = dynamic_cast<LLPanelProfilePick*>(mTabContainer->getPanelByIndex(tab_idx));
+            if (pick_panel)
+            {
+                pick_panel->apply();
+            }
+        }
+    }
+}
+
+void LLPanelProfilePicks::updateData()
+{
+    // Send picks request only once
+    LLUUID avatar_id = getAvatarId();
+    if (!getStarted() && avatar_id.notNull())
+    {
+        setIsLoading();
+
+        LLAvatarPropertiesProcessor::getInstance()->sendAvatarPicksRequest(avatar_id);
+    }
+    if (!getIsLoaded())
+    {
+        mNoItemsLabel->setValue(LLTrans::getString("PicksClassifiedsLoadingText"));
+        mNoItemsLabel->setVisible(TRUE);
+    }
+}
+
+bool LLPanelProfilePicks::hasUnsavedChanges()
+{
+    for (S32 tab_idx = 0; tab_idx < mTabContainer->getTabCount(); ++tab_idx)
+    {
+        LLPanelProfilePick* pick_panel = dynamic_cast<LLPanelProfilePick*>(mTabContainer->getPanelByIndex(tab_idx));
+        if (pick_panel && (pick_panel->isDirty() || pick_panel->isDirty()))
+        {
+            return true;
+        }
+    }
+    return false;
+}
+
+void LLPanelProfilePicks::commitUnsavedChanges()
+{
+    for (S32 tab_idx = 0; tab_idx < mTabContainer->getTabCount(); ++tab_idx)
+    {
+        LLPanelProfilePick* pick_panel = dynamic_cast<LLPanelProfilePick*>(mTabContainer->getPanelByIndex(tab_idx));
+        if (pick_panel)
+        {
+            pick_panel->apply();
+        }
+    }
+}
+
+bool LLPanelProfilePicks::canAddNewPick()
+{
+    return (!LLAgentPicksInfo::getInstance()->isPickLimitReached() &&
+        mTabContainer->getTabCount() < LLAgentPicksInfo::getInstance()->getMaxNumberOfPicks());
+}
+
+bool LLPanelProfilePicks::canDeletePick()
+{
+    return (mTabContainer->getTabCount() > 0);
+}
+
+
+//-----------------------------------------------------------------------------
+// LLPanelProfilePick
+//-----------------------------------------------------------------------------
+
+LLPanelProfilePick::LLPanelProfilePick()
+ : LLPanelProfilePropertiesProcessorTab()
+ , LLRemoteParcelInfoObserver()
+ , mSnapshotCtrl(NULL)
+ , mPickId(LLUUID::null)
+ , mParcelId(LLUUID::null)
+ , mRequestedId(LLUUID::null)
+ , mLocationChanged(false)
+ , mNewPick(false)
+ , mIsEditing(false)
+{
+}
+
+//static
+LLPanelProfilePick* LLPanelProfilePick::create()
+{
+    LLPanelProfilePick* panel = new LLPanelProfilePick();
+    panel->buildFromFile("panel_profile_pick.xml");
+    return panel;
+}
+
+LLPanelProfilePick::~LLPanelProfilePick()
+{
+    if (mParcelId.notNull())
+    {
+        LLRemoteParcelInfoProcessor::getInstance()->removeObserver(mParcelId, this);
+    }
+}
+
+void LLPanelProfilePick::setAvatarId(const LLUUID& avatar_id)
+{
+    if (avatar_id.isNull())
+    {
+        return;
+    }
+    LLPanelProfilePropertiesProcessorTab::setAvatarId(avatar_id);
+
+    // creating new Pick
+    if (getPickId().isNull() && getSelfProfile())
+    {
+        mNewPick = true;
+
+        setPosGlobal(gAgent.getPositionGlobal());
+
+        LLUUID parcel_id = LLUUID::null, snapshot_id = LLUUID::null;
+        std::string pick_name, pick_desc, region_name;
+
+        LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel();
+        if (parcel)
+        {
+            parcel_id = parcel->getID();
+            pick_name = parcel->getName();
+            pick_desc = parcel->getDesc();
+            snapshot_id = parcel->getSnapshotID();
+        }
+
+        LLViewerRegion* region = gAgent.getRegion();
+        if (region)
+        {
+            region_name = region->getName();
+        }
+
+        setParcelID(parcel_id);
+        setPickName(pick_name.empty() ? region_name : pick_name);
+        setPickDesc(pick_desc);
+        setSnapshotId(snapshot_id);
+        setPickLocation(createLocationText(getLocationNotice(), pick_name, region_name, getPosGlobal()));
+
+        enableSaveButton(TRUE);
+    }
+    else
+    {
+        LLAvatarPropertiesProcessor::getInstance()->sendPickInfoRequest(getAvatarId(), getPickId());
+
+        enableSaveButton(FALSE);
+    }
+
+    resetDirty();
+
+    if (getSelfProfile())
+    {
+        mPickName->setEnabled(TRUE);
+        mPickDescription->setEnabled(TRUE);
+        mSetCurrentLocationButton->setVisible(TRUE);
+    }
+    else
+    {
+        mSnapshotCtrl->setEnabled(FALSE);
+    }
+}
+
+BOOL LLPanelProfilePick::postBuild()
+{
+    mPickName = getChild<LLLineEditor>("pick_name");
+    mPickDescription = getChild<LLTextEditor>("pick_desc");
+    mSaveButton = getChild<LLButton>("save_changes_btn");
+    mCreateButton = getChild<LLButton>("create_changes_btn");
+    mCancelButton = getChild<LLButton>("cancel_changes_btn");
+    mSetCurrentLocationButton = getChild<LLButton>("set_to_curr_location_btn");
+
+    mSnapshotCtrl = getChild<LLTextureCtrl>("pick_snapshot");
+    mSnapshotCtrl->setCommitCallback(boost::bind(&LLPanelProfilePick::onSnapshotChanged, this));
+
+    childSetAction("teleport_btn", boost::bind(&LLPanelProfilePick::onClickTeleport, this));
+    childSetAction("show_on_map_btn", boost::bind(&LLPanelProfilePick::onClickMap, this));
+
+    mSaveButton->setCommitCallback(boost::bind(&LLPanelProfilePick::onClickSave, this));
+    mCreateButton->setCommitCallback(boost::bind(&LLPanelProfilePick::onClickSave, this));
+    mCancelButton->setCommitCallback(boost::bind(&LLPanelProfilePick::onClickCancel, this));
+    mSetCurrentLocationButton->setCommitCallback(boost::bind(&LLPanelProfilePick::onClickSetLocation, this));
+
+    mPickName->setKeystrokeCallback(boost::bind(&LLPanelProfilePick::onPickChanged, this, _1), NULL);
+    mPickName->setEnabled(FALSE);
+
+    mPickDescription->setKeystrokeCallback(boost::bind(&LLPanelProfilePick::onPickChanged, this, _1));
+    mPickDescription->setFocusReceivedCallback(boost::bind(&LLPanelProfilePick::onDescriptionFocusReceived, this));
+
+    getChild<LLUICtrl>("pick_location")->setEnabled(FALSE);
+
+    return TRUE;
+}
+
+void LLPanelProfilePick::onDescriptionFocusReceived()
+{
+    if (!mIsEditing && getSelfProfile())
+    {
+        mIsEditing = true;
+        mPickDescription->setParseHTML(false);
+    }
+}
+
+void LLPanelProfilePick::processProperties(void* data, EAvatarProcessorType type)
+{
+    if (APT_PICK_INFO != type)
+    {
+        return;
+    }
+
+    LLPickData* pick_info = static_cast<LLPickData*>(data);
+    if (!pick_info
+        || pick_info->creator_id != getAvatarId()
+        || pick_info->pick_id != getPickId())
+    {
+        return;
+    }
+
+    processProperties(pick_info);
+}
+
+void LLPanelProfilePick::processProperties(const LLPickData* pick_info)
+{
+    mIsEditing = false;
+    mPickDescription->setParseHTML(true);
+    mParcelId = pick_info->parcel_id;
+    setSnapshotId(pick_info->snapshot_id);
+    if (!getSelfProfile())
+    {
+        mSnapshotCtrl->setEnabled(FALSE);
+    }
+    setPickName(pick_info->name);
+    setPickDesc(pick_info->desc);
+    setPosGlobal(pick_info->pos_global);
+
+    // Send remote parcel info request to get parcel name and sim (region) name.
+    sendParcelInfoRequest();
+
+    // *NOTE dzaporozhan
+    // We want to keep listening to APT_PICK_INFO because user may
+    // edit the Pick and we have to update Pick info panel.
+    // revomeObserver is called from onClickBack
+
+    setLoaded();
+}
+
+void LLPanelProfilePick::apply()
+{
+    if ((mNewPick || getIsLoaded()) && isDirty())
+    {
+        sendUpdate();
+    }
+}
+
+void LLPanelProfilePick::setSnapshotId(const LLUUID& id)
+{
+    mSnapshotCtrl->setImageAssetID(id);
+    mSnapshotCtrl->setValid(TRUE);
+}
+
+void LLPanelProfilePick::setPickName(const std::string& name)
+{
+    mPickName->setValue(name);
+}
+
+const std::string LLPanelProfilePick::getPickName()
+{
+    return mPickName->getValue().asString();
+}
+
+void LLPanelProfilePick::setPickDesc(const std::string& desc)
+{
+    mPickDescription->setValue(desc);
+}
+
+void LLPanelProfilePick::setPickLocation(const std::string& location)
+{
+    getChild<LLUICtrl>("pick_location")->setValue(location);
+}
+
+void LLPanelProfilePick::onClickMap()
+{
+    LLFloaterWorldMap::getInstance()->trackLocation(getPosGlobal());
+    LLFloaterReg::showInstance("world_map", "center");
+}
+
+void LLPanelProfilePick::onClickTeleport()
+{
+    if (!getPosGlobal().isExactlyZero())
+    {
+        gAgent.teleportViaLocation(getPosGlobal());
+        LLFloaterWorldMap::getInstance()->trackLocation(getPosGlobal());
+    }
+}
+
+void LLPanelProfilePick::enableSaveButton(BOOL enable)
+{
+    childSetVisible("save_changes_lp", enable);
+
+    childSetVisible("save_btn_lp", enable && !mNewPick);
+    childSetVisible("create_btn_lp", enable && mNewPick);
+    childSetVisible("cancel_btn_lp", enable && !mNewPick);
+}
+
+void LLPanelProfilePick::onSnapshotChanged()
+{
+    enableSaveButton(TRUE);
+}
+
+void LLPanelProfilePick::onPickChanged(LLUICtrl* ctrl)
+{
+    if (ctrl && ctrl == mPickName)
+    {
+        updateTabLabel(mPickName->getText());
+    }
+
+    enableSaveButton(isDirty());
+}
+
+void LLPanelProfilePick::resetDirty()
+{
+    LLPanel::resetDirty();
+
+    mPickName->resetDirty();
+    mPickDescription->resetDirty();
+    mSnapshotCtrl->resetDirty();
+    mLocationChanged = false;
+}
+
+BOOL LLPanelProfilePick::isDirty() const
+{
+    if (mNewPick
+        || LLPanel::isDirty()
+        || mLocationChanged
+        || mSnapshotCtrl->isDirty()
+        || mPickName->isDirty()
+        || mPickDescription->isDirty())
+    {
+        return TRUE;
+    }
+    return FALSE;
+}
+
+void LLPanelProfilePick::onClickSetLocation()
+{
+    // Save location for later use.
+    setPosGlobal(gAgent.getPositionGlobal());
+
+    std::string parcel_name, region_name;
+
+    LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel();
+    if (parcel)
+    {
+        mParcelId = parcel->getID();
+        parcel_name = parcel->getName();
+    }
+
+    LLViewerRegion* region = gAgent.getRegion();
+    if (region)
+    {
+        region_name = region->getName();
+    }
+
+    setPickLocation(createLocationText(getLocationNotice(), parcel_name, region_name, getPosGlobal()));
+
+    mLocationChanged = true;
+    enableSaveButton(TRUE);
+}
+
+void LLPanelProfilePick::onClickSave()
+{
+    sendUpdate();
+
+    mLocationChanged = false;
+}
+
+void LLPanelProfilePick::onClickCancel()
+{
+    LLAvatarPropertiesProcessor::getInstance()->sendPickInfoRequest(getAvatarId(), getPickId());
+    mLocationChanged = false;
+    enableSaveButton(FALSE);
+}
+
+std::string LLPanelProfilePick::getLocationNotice()
+{
+    static const std::string notice = getString("location_notice");
+    return notice;
+}
+
+void LLPanelProfilePick::sendParcelInfoRequest()
+{
+    if (mParcelId != mRequestedId)
+    {
+        if (mRequestedId.notNull())
+        {
+            LLRemoteParcelInfoProcessor::getInstance()->removeObserver(mRequestedId, this);
+        }
+        LLRemoteParcelInfoProcessor::getInstance()->addObserver(mParcelId, this);
+        LLRemoteParcelInfoProcessor::getInstance()->sendParcelInfoRequest(mParcelId);
+
+        mRequestedId = mParcelId;
+    }
+}
+
+void LLPanelProfilePick::processParcelInfo(const LLParcelData& parcel_data)
+{
+    setPickLocation(createLocationText(LLStringUtil::null, parcel_data.name, parcel_data.sim_name, getPosGlobal()));
+
+    // We have received parcel info for the requested ID so clear it now.
+    mRequestedId.setNull();
+
+    if (mParcelId.notNull())
+    {
+        LLRemoteParcelInfoProcessor::getInstance()->removeObserver(mParcelId, this);
+    }
+}
+
+void LLPanelProfilePick::sendUpdate()
+{
+    LLPickData pick_data;
+
+    // If we don't have a pick id yet, we'll need to generate one,
+    // otherwise we'll keep overwriting pick_id 00000 in the database.
+    if (getPickId().isNull())
+    {
+        getPickId().generate();
+    }
+
+    pick_data.agent_id = gAgentID;
+    pick_data.session_id = gAgent.getSessionID();
+    pick_data.pick_id = getPickId();
+    pick_data.creator_id = gAgentID;;
+
+    //legacy var  need to be deleted
+    pick_data.top_pick = FALSE;
+    pick_data.parcel_id = mParcelId;
+    pick_data.name = getPickName();
+    pick_data.desc = mPickDescription->getValue().asString();
+    pick_data.snapshot_id = mSnapshotCtrl->getImageAssetID();
+    pick_data.pos_global = getPosGlobal();
+    pick_data.sort_order = 0;
+    pick_data.enabled = TRUE;
+
+    LLAvatarPropertiesProcessor::getInstance()->sendPickInfoUpdate(&pick_data);
+
+    if(mNewPick)
+    {
+        // Assume a successful create pick operation, make new number of picks
+        // available immediately. Actual number of picks will be requested in
+        // LLAvatarPropertiesProcessor::sendPickInfoUpdate and updated upon server respond.
+        LLAgentPicksInfo::getInstance()->incrementNumberOfPicks();
+    }
+}
+
+// static
+std::string LLPanelProfilePick::createLocationText(const std::string& owner_name, const std::string& original_name, const std::string& sim_name, const LLVector3d& pos_global)
+{
+    std::string location_text(owner_name);
+    if (!original_name.empty())
+    {
+        if (!location_text.empty())
+        {
+            location_text.append(", ");
+        }
+        location_text.append(original_name);
+
+    }
+
+    if (!sim_name.empty())
+    {
+        if (!location_text.empty())
+        {
+            location_text.append(", ");
+        }
+        location_text.append(sim_name);
+    }
+
+    if (!location_text.empty())
+    {
+        location_text.append(" ");
+    }
+
+    if (!pos_global.isNull())
+    {
+        S32 region_x = ll_round((F32)pos_global.mdV[VX]) % REGION_WIDTH_UNITS;
+        S32 region_y = ll_round((F32)pos_global.mdV[VY]) % REGION_WIDTH_UNITS;
+        S32 region_z = ll_round((F32)pos_global.mdV[VZ]);
+        location_text.append(llformat(" (%d, %d, %d)", region_x, region_y, region_z));
+    }
+    return location_text;
+}
+
+void LLPanelProfilePick::updateTabLabel(const std::string& title)
+{
+    setLabel(title);
+    LLTabContainer* parent = dynamic_cast<LLTabContainer*>(getParent());
+    if (parent)
+    {
+        parent->setCurrentTabName(title);
+    }
+}
+
diff --git a/indra/newview/llpanelprofilepicks.h b/indra/newview/llpanelprofilepicks.h
new file mode 100644
index 0000000000000000000000000000000000000000..f84463cc9b7f1cd2ee0b15cc6b89f62c730ea2b1
--- /dev/null
+++ b/indra/newview/llpanelprofilepicks.h
@@ -0,0 +1,248 @@
+/**
+ * @file llpanelprofilepicks.h
+ * @brief LLPanelProfilePicks and related class definitions
+ *
+ * $LicenseInfo:firstyear=2022&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2022, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLPANELPICKS_H
+#define LL_LLPANELPICKS_H
+
+#include "llpanel.h"
+#include "lluuid.h"
+#include "llavatarpropertiesprocessor.h"
+#include "llpanelavatar.h"
+#include "llremoteparcelrequest.h"
+
+class LLTabContainer;
+class LLTextureCtrl;
+class LLMediaCtrl;
+class LLLineEditor;
+class LLTextEditor;
+
+
+/**
+* Panel for displaying Avatar's picks.
+*/
+class LLPanelProfilePicks
+    : public LLPanelProfilePropertiesProcessorTab
+{
+public:
+    LLPanelProfilePicks();
+    /*virtual*/ ~LLPanelProfilePicks();
+
+    BOOL postBuild() override;
+
+    void onOpen(const LLSD& key) override;
+
+    void createPick(const LLPickData &data);
+    void selectPick(const LLUUID& pick_id);
+
+    void processProperties(void* data, EAvatarProcessorType type) override;
+    void processProperties(const LLAvatarPicks* avatar_picks);
+
+    void resetData() override;
+
+    void updateButtons();
+
+    /**
+     * Saves changes.
+     */
+    virtual void apply();
+
+    /**
+     * Sends update data request to server.
+     */
+    void updateData() override;
+
+    bool hasUnsavedChanges() override;
+    void commitUnsavedChanges() override;
+
+    friend void request_avatar_properties_coro(std::string cap_url, LLUUID agent_id);
+
+private:
+    void onClickNewBtn();
+    void onClickDelete();
+    void callbackDeletePick(const LLSD& notification, const LLSD& response);
+
+    bool canAddNewPick();
+    bool canDeletePick();
+
+    LLTabContainer* mTabContainer;
+    LLUICtrl*       mNoItemsLabel;
+    LLButton*       mNewButton;
+    LLButton*       mDeleteButton;
+
+    LLUUID          mPickToSelectOnLoad;
+    std::list<LLPickData> mSheduledPickCreation;
+};
+
+
+class LLPanelProfilePick
+    : public LLPanelProfilePropertiesProcessorTab
+    , public LLRemoteParcelInfoObserver
+{
+public:
+
+    // Creates new panel
+    static LLPanelProfilePick* create();
+
+    LLPanelProfilePick();
+
+    /*virtual*/ ~LLPanelProfilePick();
+
+    BOOL postBuild() override;
+
+    void setAvatarId(const LLUUID& avatar_id) override;
+
+    void setPickId(const LLUUID& id) { mPickId = id; }
+    virtual LLUUID& getPickId() { return mPickId; }
+
+    virtual void setPickName(const std::string& name);
+    const std::string getPickName();
+
+    void processProperties(void* data, EAvatarProcessorType type) override;
+    void processProperties(const LLPickData* pick_data);
+
+    /**
+     * Returns true if any of Pick properties was changed by user.
+     */
+    BOOL isDirty() const override;
+
+    /**
+     * Saves changes.
+     */
+    virtual void apply();
+
+    void updateTabLabel(const std::string& title);
+
+    //This stuff we got from LLRemoteParcelObserver, in the last one we intentionally do nothing
+    void processParcelInfo(const LLParcelData& parcel_data) override;
+    void setParcelID(const LLUUID& parcel_id) override { mParcelId = parcel_id; }
+    void setErrorStatus(S32 status, const std::string& reason) override {};
+
+protected:
+
+    /**
+     * Sends remote parcel info request to resolve parcel name from its ID.
+     */
+    void sendParcelInfoRequest();
+
+    /**
+    * "Location text" is actually the owner name, the original
+    * name that owner gave the parcel, and the location.
+    */
+    static std::string createLocationText(
+        const std::string& owner_name,
+        const std::string& original_name,
+        const std::string& sim_name,
+        const LLVector3d& pos_global);
+
+    /**
+     * Sets snapshot id.
+     *
+     * Will mark snapshot control as valid if id is not null.
+     * Will mark snapshot control as invalid if id is null. If null id is a valid value,
+     * you have to manually mark snapshot is valid.
+     */
+    virtual void setSnapshotId(const LLUUID& id);
+    virtual void setPickDesc(const std::string& desc);
+    virtual void setPickLocation(const std::string& location);
+
+    virtual void setPosGlobal(const LLVector3d& pos) { mPosGlobal = pos; }
+    virtual LLVector3d& getPosGlobal() { return mPosGlobal; }
+
+    /**
+     * Callback for "Map" button, opens Map
+     */
+    void onClickMap();
+
+    /**
+     * Callback for "Teleport" button, teleports user to Pick location.
+     */
+    void onClickTeleport();
+
+    /**
+     * Enables/disables "Save" button
+     */
+    void enableSaveButton(BOOL enable);
+
+    /**
+     * Called when snapshot image changes.
+     */
+    void onSnapshotChanged();
+
+    /**
+     * Callback for Pick snapshot, name and description changed event.
+     */
+    void onPickChanged(LLUICtrl* ctrl);
+
+    /**
+     * Resets panel and all cantrols to unedited state
+     */
+    void resetDirty() override;
+
+    /**
+     * Callback for "Set Location" button click
+     */
+    void onClickSetLocation();
+
+    /**
+     * Callback for "Save" and "Create" button click
+     */
+    void onClickSave();
+
+    /**
+     * Callback for "Save" button click
+     */
+    void onClickCancel();
+
+    std::string getLocationNotice();
+
+    /**
+     * Sends Pick properties to server.
+     */
+    void sendUpdate();
+
+protected:
+
+    LLTextureCtrl*      mSnapshotCtrl;
+    LLLineEditor*       mPickName;
+    LLTextEditor*       mPickDescription;
+    LLButton*           mSetCurrentLocationButton;
+    LLButton*           mSaveButton;
+    LLButton*           mCreateButton;
+    LLButton*           mCancelButton;
+
+    LLVector3d mPosGlobal;
+    LLUUID mParcelId;
+    LLUUID mPickId;
+    LLUUID mRequestedId;
+
+    bool mLocationChanged;
+    bool mNewPick;
+    bool                mIsEditing;
+
+    void onDescriptionFocusReceived();
+};
+
+#endif // LL_LLPANELPICKS_H
diff --git a/indra/newview/llpanelvolume.cpp b/indra/newview/llpanelvolume.cpp
index 89c558e4f8f4e23217008aa5960962c783c6f125..39f4c7485b20d4a3db25632912872b6581bd97ec 100644
--- a/indra/newview/llpanelvolume.cpp
+++ b/indra/newview/llpanelvolume.cpp
@@ -51,6 +51,7 @@
 #include "llfocusmgr.h"
 #include "llmanipscale.h"
 #include "llinventorymodel.h"
+#include "llmenubutton.h"
 #include "llpreviewscript.h"
 #include "llresmgr.h"
 #include "llselectmgr.h"
@@ -168,6 +169,9 @@ BOOL	LLPanelVolume::postBuild()
 		mSpinPhysicsRestitution->setCommitCallback(boost::bind(&LLPanelVolume::sendPhysicsRestitution, this, _1, mSpinPhysicsRestitution));
 	}
 
+    mMenuClipboardFeatures = getChild<LLMenuButton>("clipboard_features_params_btn");
+    mMenuClipboardLight = getChild<LLMenuButton>("clipboard_light_params_btn");
+
 	std::map<std::string, std::string> material_name_map;
 	material_name_map["Stone"]= LLTrans::getString("Stone");
 	material_name_map["Metal"]= LLTrans::getString("Metal");	
@@ -208,6 +212,8 @@ LLPanelVolume::LLPanelVolume()
 {
 	setMouseOpaque(FALSE);
 
+    mCommitCallbackRegistrar.add("PanelVolume.menuDoToSelected", boost::bind(&LLPanelVolume::menuDoToSelected, this, _2));
+    mEnableCallbackRegistrar.add("PanelVolume.menuEnable", boost::bind(&LLPanelVolume::menuEnableItem, this, _2));
 }
 
 
@@ -409,7 +415,6 @@ void LLPanelVolume::getState( )
 			gAgentAvatarp->updateMeshVisibility();
 		}
 	}
-	
 
 	// Flexible properties
 	BOOL is_flexible = volobjp && volobjp->isFlexible();
@@ -564,6 +569,9 @@ void LLPanelVolume::getState( )
 
 	mObject = objectp;
 	mRootObject = root_objectp;
+
+    mMenuClipboardFeatures->setEnabled(editable && single_volume && volobjp); // Note: physics doesn't need to be limited by single volume
+    mMenuClipboardLight->setEnabled(editable && single_volume && volobjp);
 }
 
 // static
@@ -587,13 +595,6 @@ void LLPanelVolume::refresh()
 		mRootObject = NULL;
 	}
 
-	BOOL visible = LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_DEFERRED) > 0 ? TRUE : FALSE;
-
-	getChildView("Light FOV")->setVisible( visible);
-	getChildView("Light Focus")->setVisible( visible);
-	getChildView("Light Ambiance")->setVisible( visible);
-	getChildView("light texture control")->setVisible( visible);
-
 	bool enable_mesh = false;
 
 	LLSD sim_features;
@@ -831,6 +832,290 @@ void LLPanelVolume::onLightSelectTexture(const LLSD& data)
 	}
 }
 
+void LLPanelVolume::onCopyFeatures()
+{
+    LLViewerObject* objectp = mObject;
+    if (!objectp)
+    {
+        return;
+    }
+
+    LLSD clipboard;
+
+    LLVOVolume *volobjp = NULL;
+    if (objectp && (objectp->getPCode() == LL_PCODE_VOLUME))
+    {
+        volobjp = (LLVOVolume *)objectp;
+    }
+
+    // Flexi Prim
+    if (volobjp && volobjp->isFlexible())
+    {
+        LLFlexibleObjectData *attributes = (LLFlexibleObjectData *)objectp->getParameterEntry(LLNetworkData::PARAMS_FLEXIBLE);
+        if (attributes)
+        {
+            clipboard["flex"]["lod"] = attributes->getSimulateLOD();
+            clipboard["flex"]["gav"] = attributes->getGravity();
+            clipboard["flex"]["ten"] = attributes->getTension();
+            clipboard["flex"]["fri"] = attributes->getAirFriction();
+            clipboard["flex"]["sen"] = attributes->getWindSensitivity();
+            LLVector3 force = attributes->getUserForce();
+            clipboard["flex"]["forx"] = force.mV[0];
+            clipboard["flex"]["fory"] = force.mV[1];
+            clipboard["flex"]["forz"] = force.mV[2];
+        }
+    }
+
+    // Physics
+    {
+        clipboard["physics"]["shape"] = objectp->getPhysicsShapeType();
+        clipboard["physics"]["gravity"] = objectp->getPhysicsGravity();
+        clipboard["physics"]["friction"] = objectp->getPhysicsFriction();
+        clipboard["physics"]["density"] = objectp->getPhysicsDensity();
+        clipboard["physics"]["restitution"] = objectp->getPhysicsRestitution();
+
+        U8 material_code = 0;
+        struct f : public LLSelectedTEGetFunctor<U8>
+        {
+            U8 get(LLViewerObject* object, S32 te)
+            {
+                return object->getMaterial();
+            }
+        } func;
+        bool material_same = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue(&func, material_code);
+        // This should always be true since material should be per object.
+        if (material_same)
+        {
+            clipboard["physics"]["material"] = material_code;
+        }
+    }
+
+    mClipboardParams["features"] = clipboard;
+}
+
+void LLPanelVolume::onPasteFeatures()
+{
+    LLViewerObject* objectp = mObject;
+    if (!objectp && mClipboardParams.has("features"))
+    {
+        return;
+    }
+
+    LLSD &clipboard = mClipboardParams["features"];
+
+    LLVOVolume *volobjp = NULL;
+    if (objectp && (objectp->getPCode() == LL_PCODE_VOLUME))
+    {
+        volobjp = (LLVOVolume *)objectp;
+    }
+
+    // Physics
+    bool is_root = objectp->isRoot();
+
+    // Not sure if phantom should go under physics, but doesn't fit elsewhere
+    BOOL is_phantom = clipboard["is_phantom"].asBoolean() && is_root;
+    LLSelectMgr::getInstance()->selectionUpdatePhantom(is_phantom);
+
+    BOOL is_physical = clipboard["is_physical"].asBoolean() && is_root;
+    LLSelectMgr::getInstance()->selectionUpdatePhysics(is_physical);
+
+    if (clipboard.has("physics"))
+    {
+        objectp->setPhysicsShapeType((U8)clipboard["physics"]["shape"].asInteger());
+        U8 cur_material = objectp->getMaterial();
+        U8 material = (U8)clipboard["physics"]["material"].asInteger() | (cur_material & ~LL_MCODE_MASK);
+
+        objectp->setMaterial(material);
+        objectp->sendMaterialUpdate();
+        objectp->setPhysicsGravity(clipboard["physics"]["gravity"].asReal());
+        objectp->setPhysicsFriction(clipboard["physics"]["friction"].asReal());
+        objectp->setPhysicsDensity(clipboard["physics"]["density"].asReal());
+        objectp->setPhysicsRestitution(clipboard["physics"]["restitution"].asReal());
+        objectp->updateFlags(TRUE);
+    }
+
+    // Flexible
+    bool is_flexible = clipboard.has("flex");
+    if (is_flexible && volobjp->canBeFlexible())
+    {
+        LLVOVolume *volobjp = (LLVOVolume *)objectp;
+        BOOL update_shape = FALSE;
+
+        // do before setParameterEntry or it will think that it is already flexi
+        update_shape = volobjp->setIsFlexible(is_flexible);
+
+        if (objectp->getClickAction() == CLICK_ACTION_SIT)
+        {
+            objectp->setClickAction(CLICK_ACTION_NONE);
+        }
+
+        LLFlexibleObjectData *attributes = (LLFlexibleObjectData *)objectp->getParameterEntry(LLNetworkData::PARAMS_FLEXIBLE);
+        if (attributes)
+        {
+            LLFlexibleObjectData new_attributes;
+            new_attributes = *attributes;
+            new_attributes.setSimulateLOD(clipboard["flex"]["lod"].asInteger());
+            new_attributes.setGravity(clipboard["flex"]["gav"].asReal());
+            new_attributes.setTension(clipboard["flex"]["ten"].asReal());
+            new_attributes.setAirFriction(clipboard["flex"]["fri"].asReal());
+            new_attributes.setWindSensitivity(clipboard["flex"]["sen"].asReal());
+            F32 fx = (F32)clipboard["flex"]["forx"].asReal();
+            F32 fy = (F32)clipboard["flex"]["fory"].asReal();
+            F32 fz = (F32)clipboard["flex"]["forz"].asReal();
+            LLVector3 force(fx, fy, fz);
+            new_attributes.setUserForce(force);
+            objectp->setParameterEntry(LLNetworkData::PARAMS_FLEXIBLE, new_attributes, true);
+        }
+
+        if (update_shape)
+        {
+            mObject->sendShapeUpdate();
+            LLSelectMgr::getInstance()->selectionUpdatePhantom(volobjp->flagPhantom());
+        }
+    }
+    else
+    {
+        LLVOVolume *volobjp = (LLVOVolume *)objectp;
+        if (volobjp->setIsFlexible(false))
+        {
+            mObject->sendShapeUpdate();
+            LLSelectMgr::getInstance()->selectionUpdatePhantom(volobjp->flagPhantom());
+        }
+    }
+}
+
+void LLPanelVolume::onCopyLight()
+{
+    LLViewerObject* objectp = mObject;
+    if (!objectp)
+    {
+        return;
+    }
+
+    LLSD clipboard;
+
+    LLVOVolume *volobjp = NULL;
+    if (objectp && (objectp->getPCode() == LL_PCODE_VOLUME))
+    {
+        volobjp = (LLVOVolume *)objectp;
+    }
+
+    // Light Source
+    if (volobjp && volobjp->getIsLight())
+    {
+        clipboard["light"]["intensity"] = volobjp->getLightIntensity();
+        clipboard["light"]["radius"] = volobjp->getLightRadius();
+        clipboard["light"]["falloff"] = volobjp->getLightFalloff();
+        LLColor3 color = volobjp->getLightSRGBColor();
+        clipboard["light"]["r"] = color.mV[0];
+        clipboard["light"]["g"] = color.mV[1];
+        clipboard["light"]["b"] = color.mV[2];
+
+        // Spotlight
+        if (volobjp->isLightSpotlight())
+        {
+            LLUUID id = volobjp->getLightTextureID();
+            if (id.notNull() && get_can_copy_texture(id))
+            {
+                clipboard["spot"]["id"] = id;
+                LLVector3 spot_params = volobjp->getSpotLightParams();
+                clipboard["spot"]["fov"] = spot_params.mV[0];
+                clipboard["spot"]["focus"] = spot_params.mV[1];
+                clipboard["spot"]["ambiance"] = spot_params.mV[2];
+            }
+        }
+    }
+
+    mClipboardParams["light"] = clipboard;
+}
+
+void LLPanelVolume::onPasteLight()
+{
+    LLViewerObject* objectp = mObject;
+    if (!objectp && mClipboardParams.has("light"))
+    {
+        return;
+    }
+
+    LLSD &clipboard = mClipboardParams["light"];
+
+    LLVOVolume *volobjp = NULL;
+    if (objectp && (objectp->getPCode() == LL_PCODE_VOLUME))
+    {
+        volobjp = (LLVOVolume *)objectp;
+    }
+
+    // Light Source
+    if (volobjp)
+    {
+        if (clipboard.has("light"))
+        {
+            volobjp->setIsLight(TRUE);
+            volobjp->setLightIntensity((F32)clipboard["light"]["intensity"].asReal());
+            volobjp->setLightRadius((F32)clipboard["light"]["radius"].asReal());
+            volobjp->setLightFalloff((F32)clipboard["light"]["falloff"].asReal());
+            F32 r = (F32)clipboard["light"]["r"].asReal();
+            F32 g = (F32)clipboard["light"]["g"].asReal();
+            F32 b = (F32)clipboard["light"]["b"].asReal();
+            volobjp->setLightSRGBColor(LLColor3(r, g, b));
+        }
+        else
+        {
+            volobjp->setIsLight(FALSE);
+        }
+
+        if (clipboard.has("spot"))
+        {
+            volobjp->setLightTextureID(clipboard["spot"]["id"].asUUID());
+            LLVector3 spot_params;
+            spot_params.mV[0] = (F32)clipboard["spot"]["fov"].asReal();
+            spot_params.mV[1] = (F32)clipboard["spot"]["focus"].asReal();
+            spot_params.mV[2] = (F32)clipboard["spot"]["ambiance"].asReal();
+            volobjp->setSpotLightParams(spot_params);
+        }
+    }
+}
+
+void LLPanelVolume::menuDoToSelected(const LLSD& userdata)
+{
+    std::string command = userdata.asString();
+
+    // paste
+    if (command == "features_paste")
+    {
+        onPasteFeatures();
+    }
+    else if (command == "light_paste")
+    {
+        onPasteLight();
+    }
+    // copy
+    else if (command == "features_copy")
+    {
+        onCopyFeatures();
+    }
+    else if (command == "light_copy")
+    {
+        onCopyLight();
+    }
+}
+
+bool LLPanelVolume::menuEnableItem(const LLSD& userdata)
+{
+    std::string command = userdata.asString();
+
+    // paste options
+    if (command == "features_paste")
+    {
+        return mClipboardParams.has("features");
+    }
+    else if (command == "light_paste")
+    {
+        return mClipboardParams.has("light");
+    }
+    return false;
+}
+
 // static
 void LLPanelVolume::onCommitMaterial( LLUICtrl* ctrl, void* userdata )
 {
diff --git a/indra/newview/llpanelvolume.h b/indra/newview/llpanelvolume.h
index 6e49ccb742649f769ea61ece67939a302854946a..d9198f36932a17576e7bdb0779eec1d4c4d2c56a 100644
--- a/indra/newview/llpanelvolume.h
+++ b/indra/newview/llpanelvolume.h
@@ -37,6 +37,7 @@ class LLCheckBoxCtrl;
 class LLTextBox;
 class LLUICtrl;
 class LLButton;
+class LLMenuButton;
 class LLViewerObject;
 class LLComboBox;
 class LLColorSwatchCtrl;
@@ -76,6 +77,13 @@ class LLPanelVolume : public LLPanel
 
     static void    setLightTextureID(const LLUUID &asset_id, const LLUUID &item_id, LLVOVolume* volobjp);
 
+    void            onCopyFeatures();
+    void            onPasteFeatures();
+    void            onCopyLight();
+    void            onPasteLight();
+ 
+    void        menuDoToSelected(const LLSD& userdata);
+    bool        menuEnableItem(const LLSD& userdata);
 
 protected:
 	void			getState();
@@ -123,6 +131,11 @@ class LLPanelVolume : public LLPanel
 	LLSpinCtrl*     mSpinPhysicsFriction;
 	LLSpinCtrl*     mSpinPhysicsDensity;
 	LLSpinCtrl*     mSpinPhysicsRestitution;
+
+    LLMenuButton*   mMenuClipboardFeatures;
+    LLMenuButton*   mMenuClipboardLight;
+
+    LLSD            mClipboardParams;
 };
 
 #endif
diff --git a/indra/newview/llparticipantlist.cpp b/indra/newview/llparticipantlist.cpp
index 94d20828eccfc48143fc00ea85ddf2b46dda3e40..9b60d1ae2f8936acfeb55c050f60600b27214c09 100644
--- a/indra/newview/llparticipantlist.cpp
+++ b/indra/newview/llparticipantlist.cpp
@@ -38,154 +38,11 @@
 #pragma warning (disable : 4355) // 'this' used in initializer list: yes, intentionally
 #endif
 
-// See EXT-4301.
-/**
- * class LLAvalineUpdater - observe the list of voice participants in session and check
- *  presence of Avaline Callers among them.
- *
- * LLAvalineUpdater is a LLVoiceClientParticipantObserver. It provides two kinds of validation:
- *	- whether Avaline caller presence among participants;
- *	- whether watched Avaline caller still exists in voice channel.
- * Both validations have callbacks which will notify subscriber if any of event occur.
- *
- * @see findAvalineCaller()
- * @see checkIfAvalineCallersExist()
- */
-class LLAvalineUpdater : public LLVoiceClientParticipantObserver
-{
-public:
-	typedef boost::function<void(const LLUUID& speaker_id)> process_avaline_callback_t;
-
-	LLAvalineUpdater(process_avaline_callback_t found_cb, process_avaline_callback_t removed_cb)
-		: mAvalineFoundCallback(found_cb)
-		, mAvalineRemovedCallback(removed_cb)
-	{
-		LLVoiceClient::getInstance()->addObserver(this);
-	}
-	~LLAvalineUpdater()
-	{
-		if (LLVoiceClient::instanceExists())
-		{
-			LLVoiceClient::getInstance()->removeObserver(this);
-		}
-	}
-
-	/**
-	 * Adds UUID of Avaline caller to watch.
-	 *
-	 * @see checkIfAvalineCallersExist().
-	 */
-	void watchAvalineCaller(const LLUUID& avaline_caller_id)
-	{
-		mAvalineCallers.insert(avaline_caller_id);
-	}
-
-	void onParticipantsChanged()
-	{
-		uuid_set_t participant_uuids;
-		LLVoiceClient::getInstance()->getParticipantList(participant_uuids);
-
-
-		// check whether Avaline caller exists among voice participants
-		// and notify Participant List
-		findAvalineCaller(participant_uuids);
-
-		// check whether watched Avaline callers still present among voice participant
-		// and remove if absents.
-		checkIfAvalineCallersExist(participant_uuids);
-	}
-
-private:
-	typedef std::set<LLUUID> uuid_set_t;
-
-	/**
-	 * Finds Avaline callers among voice participants and calls mAvalineFoundCallback.
-	 *
-	 * When Avatar is in group call with Avaline caller and then ends call Avaline caller stays
-	 * in Group Chat floater (exists in LLSpeakerMgr). If Avatar starts call with that group again
-	 * Avaline caller is added to voice channel AFTER Avatar is connected to group call.
-	 * But Voice Control Panel (VCP) is filled from session LLSpeakerMgr and there is no information
-	 * if a speaker is Avaline caller.
-	 *
-	 * In this case this speaker is created as avatar and will be recreated when it appears in
-	 * Avatar's Voice session.
-	 *
-	 * @see LLParticipantList::onAvalineCallerFound()
-	 */
-	void findAvalineCaller(const uuid_set_t& participant_uuids)
-	{
-		uuid_set_t::const_iterator it = participant_uuids.begin(), it_end = participant_uuids.end();
-
-		for(; it != it_end; ++it)
-		{
-			const LLUUID& participant_id = *it;
-			if (!LLVoiceClient::getInstance()->isParticipantAvatar(participant_id))
-			{
-				LL_DEBUGS("Avaline") << "Avaline caller found among voice participants: " << participant_id << LL_ENDL;
-
-				if (mAvalineFoundCallback)
-				{
-					mAvalineFoundCallback(participant_id);
-				}
-			}
-		}
-	}
-
-	/**
-	 * Finds Avaline callers which are not anymore among voice participants and calls mAvalineRemovedCallback.
-	 *
-	 * The problem is when Avaline caller ends a call it is removed from Voice Client session but
-	 * still exists in LLSpeakerMgr. Server does not send such information.
-	 * This method implements a HUCK to notify subscribers that watched Avaline callers by class
-	 * are not anymore in the call.
-	 *
-	 * @see LLParticipantList::onAvalineCallerRemoved()
-	 */
-	void checkIfAvalineCallersExist(const uuid_set_t& participant_uuids)
-	{
-		uuid_set_t::iterator it = mAvalineCallers.begin();
-		uuid_set_t::const_iterator participants_it_end = participant_uuids.end();
-
-		while (it != mAvalineCallers.end())
-		{
-			const LLUUID participant_id = *it;
-			LL_DEBUGS("Avaline") << "Check avaline caller: " << participant_id << LL_ENDL;
-			bool not_found = participant_uuids.find(participant_id) == participants_it_end;
-			if (not_found)
-			{
-				LL_DEBUGS("Avaline") << "Watched Avaline caller is not found among voice participants: " << participant_id << LL_ENDL;
-
-				// notify Participant List
-				if (mAvalineRemovedCallback)
-				{
-					mAvalineRemovedCallback(participant_id);
-				}
-
-				// remove from the watch list
-				mAvalineCallers.erase(it++);
-			}
-			else
-			{
-				++it;
-			}
-		}
-	}
-
-	process_avaline_callback_t mAvalineFoundCallback;
-	process_avaline_callback_t mAvalineRemovedCallback;
-
-	uuid_set_t mAvalineCallers;
-};
-
 LLParticipantList::LLParticipantList(LLSpeakerMgr* data_source, LLFolderViewModelInterface& root_view_model) :
 	LLConversationItemSession(data_source->getSessionID(), root_view_model),
 	mSpeakerMgr(data_source),
 	mValidateSpeakerCallback(NULL)
 {
-
-	mAvalineUpdater = new LLAvalineUpdater(boost::bind(&LLParticipantList::onAvalineCallerFound, this, _1),
-										   boost::bind(&LLParticipantList::onAvalineCallerRemoved, this, _1));
-
 	mSpeakerAddListener = new SpeakerAddListener(*this);
 	mSpeakerRemoveListener = new SpeakerRemoveListener(*this);
 	mSpeakerClearListener = new SpeakerClearListener(*this);
@@ -243,32 +100,6 @@ LLParticipantList::LLParticipantList(LLSpeakerMgr* data_source, LLFolderViewMode
 
 LLParticipantList::~LLParticipantList()
 {
-	delete mAvalineUpdater;
-}
-
-/*
-  Seems this method is not necessary after onAvalineCallerRemoved was implemented;
-
-  It does nothing because list item is always created with correct class type for Avaline caller.
-  For now Avaline Caller is removed from the LLSpeakerMgr List when it is removed from the Voice Client
-  session.
-  This happens in two cases: if Avaline Caller ends call itself or if Resident ends group call.
-
-  Probably Avaline caller should be removed from the LLSpeakerMgr list ONLY if it ends call itself.
-  Asked in EXT-4301.
-*/
-void LLParticipantList::onAvalineCallerFound(const LLUUID& participant_id)
-{
-	removeParticipant(participant_id);
-	// re-add avaline caller with a correct class instance.
-	addAvatarIDExceptAgent(participant_id);
-}
-
-void LLParticipantList::onAvalineCallerRemoved(const LLUUID& participant_id)
-{
-	LL_DEBUGS("Avaline") << "Removing avaline caller from the list: " << participant_id << LL_ENDL;
-
-	mSpeakerMgr->removeAvalineSpeaker(participant_id);
 }
 
 void LLParticipantList::setValidateSpeakerCallback(validate_speaker_callback_t cb)
@@ -386,7 +217,6 @@ void LLParticipantList::addAvatarIDExceptAgent(const LLUUID& avatar_id)
 		std::string display_name = LLVoiceClient::getInstance()->getDisplayName(avatar_id);
 		// Create a participant view model instance
 		participant = new LLConversationItemParticipant(display_name.empty() ? LLTrans::getString("AvatarNameWaiting") : display_name, avatar_id, mRootViewModel);
-		mAvalineUpdater->watchAvalineCaller(avatar_id);
 	}
 
 	// *TODO : Need to update the online/offline status of the participant
diff --git a/indra/newview/llparticipantlist.h b/indra/newview/llparticipantlist.h
index 3a3ae76604a9c17bc8d0df5629b082bf66f686e9..14c0a636926125c860d390f7a854498e1c4eb6e3 100644
--- a/indra/newview/llparticipantlist.h
+++ b/indra/newview/llparticipantlist.h
@@ -32,7 +32,6 @@
 
 class LLSpeakerMgr;
 class LLUICtrl;
-class LLAvalineUpdater;
 
 class LLParticipantList : public LLConversationItemSession
 {
@@ -133,8 +132,6 @@ class LLParticipantList : public LLConversationItemSession
 	};
 
 private:
-	void onAvalineCallerFound(const LLUUID& participant_id);
-	void onAvalineCallerRemoved(const LLUUID& participant_id);
 
 	/**
 	 * Adjusts passed participant to work properly.
@@ -156,7 +153,6 @@ class LLParticipantList : public LLConversationItemSession
 	LLPointer<SpeakerMuteListener>				mSpeakerMuteListener;
 
 	validate_speaker_callback_t mValidateSpeakerCallback;
-	LLAvalineUpdater* mAvalineUpdater;
 };
 
 #endif // LL_PARTICIPANTLIST_H
diff --git a/indra/newview/llpatchvertexarray.cpp b/indra/newview/llpatchvertexarray.cpp
index 6e3e3754884b8f302854e6af845c4204a2e5cf06..a7011dfad5057e6048c9f395c5ce2b815d9f9933 100644
--- a/indra/newview/llpatchvertexarray.cpp
+++ b/indra/newview/llpatchvertexarray.cpp
@@ -69,11 +69,9 @@ void LLPatchVertexArray::create(U32 surface_width, U32 patch_width, F32 meters_p
 	// (The -1 is there because an LLSurface has a buffer of 1 on 
 	// its East and North edges).
 	U32 power_of_two = 1;
-	U32 surface_order = 0;
 	while (power_of_two < (surface_width-1))
 	{
 		power_of_two *= 2;
-		surface_order += 1;
 	}
 
 	if (power_of_two == (surface_width-1))
diff --git a/indra/newview/llpathfindingmanager.cpp b/indra/newview/llpathfindingmanager.cpp
index cb4c07a417bb3d9ab012f8d9a54f9f7975431443..17b8ec0683fd04499444a8c376261568de603373 100644
--- a/indra/newview/llpathfindingmanager.cpp
+++ b/indra/newview/llpathfindingmanager.cpp
@@ -61,7 +61,8 @@
 
 #define CAP_SERVICE_NAVMESH_STATUS          "NavMeshGenerationStatus"
 
-#define CAP_SERVICE_OBJECT_LINKSETS         "ObjectNavMeshProperties"
+#define CAP_SERVICE_GET_OBJECT_LINKSETS     "RegionObjects"
+#define CAP_SERVICE_SET_OBJECT_LINKSETS     "ObjectNavMeshProperties"
 #define CAP_SERVICE_TERRAIN_LINKSETS        "TerrainNavMeshProperties"
 
 #define CAP_SERVICE_CHARACTERS              "CharacterProperties"
@@ -244,7 +245,7 @@ void LLPathfindingManager::requestGetLinksets(request_id_t pRequestId, object_re
 	}
 	else
 	{
-		std::string objectLinksetsURL = getObjectLinksetsURLForCurrentRegion();
+		std::string objectLinksetsURL = getRetrieveObjectLinksetsURLForCurrentRegion();
 		std::string terrainLinksetsURL = getTerrainLinksetsURLForCurrentRegion();
 		if (objectLinksetsURL.empty() || terrainLinksetsURL.empty())
 		{
@@ -273,7 +274,7 @@ void LLPathfindingManager::requestSetLinksets(request_id_t pRequestId, const LLP
 {
 	LLPathfindingObjectListPtr emptyLinksetListPtr;
 
-	std::string objectLinksetsURL = getObjectLinksetsURLForCurrentRegion();
+	std::string objectLinksetsURL = getChangeObjectLinksetsURLForCurrentRegion();
 	std::string terrainLinksetsURL = getTerrainLinksetsURLForCurrentRegion();
 	if (objectLinksetsURL.empty() || terrainLinksetsURL.empty())
 	{
@@ -755,9 +756,14 @@ std::string LLPathfindingManager::getRetrieveNavMeshURLForRegion(LLViewerRegion
 	return getCapabilityURLForRegion(pRegion, CAP_SERVICE_RETRIEVE_NAVMESH);
 }
 
-std::string LLPathfindingManager::getObjectLinksetsURLForCurrentRegion() const
+std::string LLPathfindingManager::getRetrieveObjectLinksetsURLForCurrentRegion() const
 {
-	return getCapabilityURLForCurrentRegion(CAP_SERVICE_OBJECT_LINKSETS);
+	return getCapabilityURLForCurrentRegion(CAP_SERVICE_GET_OBJECT_LINKSETS);
+}
+
+std::string LLPathfindingManager::getChangeObjectLinksetsURLForCurrentRegion() const
+{
+    return getCapabilityURLForCurrentRegion(CAP_SERVICE_SET_OBJECT_LINKSETS);
 }
 
 std::string LLPathfindingManager::getTerrainLinksetsURLForCurrentRegion() const
diff --git a/indra/newview/llpathfindingmanager.h b/indra/newview/llpathfindingmanager.h
index a44cd892da61c4d45028bb4680fa76c27f2e3bc6..bb44f780c8e09e465b600cfad3afc700ae5be965 100644
--- a/indra/newview/llpathfindingmanager.h
+++ b/indra/newview/llpathfindingmanager.h
@@ -122,7 +122,8 @@ class LLPathfindingManager : public LLSingleton<LLPathfindingManager>
 	std::string getNavMeshStatusURLForCurrentRegion() const;
 	std::string getNavMeshStatusURLForRegion(LLViewerRegion *pRegion) const;
 	std::string getRetrieveNavMeshURLForRegion(LLViewerRegion *pRegion) const;
-	std::string getObjectLinksetsURLForCurrentRegion() const;
+	std::string getRetrieveObjectLinksetsURLForCurrentRegion() const;
+    std::string getChangeObjectLinksetsURLForCurrentRegion() const;
 	std::string getTerrainLinksetsURLForCurrentRegion() const;
 	std::string getCharactersURLForCurrentRegion() const;
 	std::string	getAgentStateURLForRegion(LLViewerRegion *pRegion) const;
diff --git a/indra/newview/llpersistentnotificationstorage.cpp b/indra/newview/llpersistentnotificationstorage.cpp
index 18888f2723d0e1af3e69976b5815c172913d7fd2..9bf771db8a702473c56d53aa0cd04a84cdbbf5c7 100644
--- a/indra/newview/llpersistentnotificationstorage.cpp
+++ b/indra/newview/llpersistentnotificationstorage.cpp
@@ -47,11 +47,9 @@ LLPersistentNotificationStorage::~LLPersistentNotificationStorage()
 {
 }
 
-static LLTrace::BlockTimerStatHandle FTM_SAVE_NOTIFICATIONS("Save Notifications");
-
 void LLPersistentNotificationStorage::saveNotifications()
 {
-	LL_RECORD_BLOCK_TIME(FTM_SAVE_NOTIFICATIONS);
+    LL_PROFILE_ZONE_SCOPED;
 
 	boost::intrusive_ptr<LLPersistentNotificationChannel> history_channel = boost::dynamic_pointer_cast<LLPersistentNotificationChannel>(LLNotifications::instance().getChannel("Persistent"));
 	if (!history_channel)
@@ -90,11 +88,9 @@ void LLPersistentNotificationStorage::saveNotifications()
 	writeNotifications(output);
 }
 
-static LLTrace::BlockTimerStatHandle FTM_LOAD_NOTIFICATIONS("Load Notifications");
-
 void LLPersistentNotificationStorage::loadNotifications()
 {
-	LL_RECORD_BLOCK_TIME(FTM_LOAD_NOTIFICATIONS);
+    LL_PROFILE_ZONE_SCOPED;
 
 	LL_INFOS("LLPersistentNotificationStorage") << "start loading notifications" << LL_ENDL;
 
@@ -167,12 +163,16 @@ void LLPersistentNotificationStorage::loadNotifications()
 	LL_INFOS("LLPersistentNotificationStorage") << "finished loading notifications" << LL_ENDL;
 }
 
-void LLPersistentNotificationStorage::initialize()
+void LLPersistentNotificationStorage::reset()
 {
-	std::string file_name = "open_notifications_" + LLGridManager::getInstance()->getGrid() + ".xml";
-	setFileName(gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, file_name));
-	setOldFileName(gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, "open_notifications.xml"));
+    std::string file_name = "open_notifications_" + LLGridManager::getInstance()->getGrid() + ".xml";
+    setFileName(gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, file_name));
+    setOldFileName(gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, "open_notifications.xml"));
+}
 
+void LLPersistentNotificationStorage::initialize()
+{
+    reset();
 	LLNotifications::instance().getChannel("Persistent")->
 		connectChanged(boost::bind(&LLPersistentNotificationStorage::onPersistentChannelChanged, this, _1));
 }
diff --git a/indra/newview/llpersistentnotificationstorage.h b/indra/newview/llpersistentnotificationstorage.h
index 1fb44872867d9c0b4e1c4801766297c1b463782d..335d85aaf66f44184a75bf67ca2b78075d20bb66 100644
--- a/indra/newview/llpersistentnotificationstorage.h
+++ b/indra/newview/llpersistentnotificationstorage.h
@@ -52,6 +52,7 @@ class LLPersistentNotificationStorage : public LLParamSingleton<LLPersistentNoti
 
 	void saveNotifications();
 	void loadNotifications();
+    void reset();
 
 protected:
 
diff --git a/indra/newview/llphysicsmotion.cpp b/indra/newview/llphysicsmotion.cpp
index f48ce680fd159eb66f7e3e745f23b34ee23c541e..03a02ba26f0376e769cbfd80ca529d9d732e4991 100644
--- a/indra/newview/llphysicsmotion.cpp
+++ b/indra/newview/llphysicsmotion.cpp
@@ -453,6 +453,7 @@ F32 LLPhysicsMotion::calculateAcceleration_local(const F32 velocity_local, const
 
 BOOL LLPhysicsMotionController::onUpdate(F32 time, U8* joint_mask)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
         // Skip if disabled globally.
         if (!gSavedSettings.getBOOL("AvatarPhysics"))
         {
diff --git a/indra/newview/llphysicsshapebuilderutil.cpp b/indra/newview/llphysicsshapebuilderutil.cpp
index 5bfe5c9941c470443abd6bd3e96170040c240a4a..9603ee63295b0cc58dfff1fb5b3d16d8934b00df 100644
--- a/indra/newview/llphysicsshapebuilderutil.cpp
+++ b/indra/newview/llphysicsshapebuilderutil.cpp
@@ -29,7 +29,7 @@
 #include "llphysicsshapebuilderutil.h"
 
 /* static */
-void LLPhysicsShapeBuilderUtil::determinePhysicsShape( const LLPhysicsVolumeParams& volume_params, const LLVector3& scale, PhysicsShapeSpecification& specOut )
+void LLPhysicsShapeBuilderUtil::determinePhysicsShape( const LLPhysicsVolumeParams& volume_params, const LLVector3& scale, PhysicsShapeSpecification& specOut)
 {
 	const LLProfileParams& profile_params = volume_params.getProfileParams();
 	const LLPathParams& path_params = volume_params.getPathParams();
@@ -191,6 +191,7 @@ void LLPhysicsShapeBuilderUtil::determinePhysicsShape( const LLPhysicsVolumePara
 
 	if ( volume_params.shouldForceConvex() )
 	{
+        // Server distinguishes between convex of a prim vs isSculpt, but we don't care.
 		specOut.mType = PhysicsShapeSpecification::USER_CONVEX;
 	}	
 	// Make a simpler convex shape if we can.
@@ -199,6 +200,16 @@ void LLPhysicsShapeBuilderUtil::determinePhysicsShape( const LLPhysicsVolumePara
 	{
 		specOut.mType = PhysicsShapeSpecification::PRIM_CONVEX;
 	}
+    else if (volume_params.isMeshSculpt() &&
+             // Check overall dimensions, not individual triangles.
+             (scale.mV[0] < SHAPE_BUILDER_USER_MESH_CONVEXIFICATION_SIZE ||
+              scale.mV[1] < SHAPE_BUILDER_USER_MESH_CONVEXIFICATION_SIZE ||
+              scale.mV[2] < SHAPE_BUILDER_USER_MESH_CONVEXIFICATION_SIZE
+              ) )
+    {
+        // Server distinguishes between user-specified or default convex mesh, vs server's thin-triangle override, but we don't.
+        specOut.mType = PhysicsShapeSpecification::PRIM_CONVEX;
+    }
 	else if ( volume_params.isSculpt() ) // Is a sculpt of any kind (mesh or legacy)
 	{
 		specOut.mType = volume_params.isMeshSculpt() ? PhysicsShapeSpecification::USER_MESH : PhysicsShapeSpecification::SCULPT;
diff --git a/indra/newview/llphysicsshapebuilderutil.h b/indra/newview/llphysicsshapebuilderutil.h
index bd5b7d799cc7994855649f12bb469bd1536782d9..b3b100296f48e7cfbd759a28c9ed75d2b16a5a78 100644
--- a/indra/newview/llphysicsshapebuilderutil.h
+++ b/indra/newview/llphysicsshapebuilderutil.h
@@ -47,6 +47,7 @@ const F32 SHAPE_BUILDER_ENTRY_SNAP_SCALE_BIN_SIZE = 0.15f;
 const F32 SHAPE_BUILDER_ENTRY_SNAP_PARAMETER_BIN_SIZE = 0.010f;
 const F32 SHAPE_BUILDER_CONVEXIFICATION_SIZE = 2.f * COLLISION_TOLERANCE;
 const F32 SHAPE_BUILDER_MIN_GEOMETRY_SIZE = 0.5f * COLLISION_TOLERANCE;
+const F32 SHAPE_BUILDER_USER_MESH_CONVEXIFICATION_SIZE = 0.5f;
 
 class LLPhysicsVolumeParams : public LLVolumeParams
 {
diff --git a/indra/newview/llpresetsmanager.cpp b/indra/newview/llpresetsmanager.cpp
index c267c3c699520752b8d15dfc8453a153fec088dc..30d0a22ef07033049280efb045c3426c0d87fafa 100644
--- a/indra/newview/llpresetsmanager.cpp
+++ b/indra/newview/llpresetsmanager.cpp
@@ -332,7 +332,6 @@ bool LLPresetsManager::savePreset(const std::string& subdirectory, std::string n
 	else
 	{
 		ECameraPreset new_camera_preset = (ECameraPreset)gSavedSettings.getU32("CameraPresetType");
-		bool new_camera_offsets = false;
 		if (IS_CAMERA)
 		{
 			if (isDefaultCameraPreset(name))
@@ -354,7 +353,6 @@ bool LLPresetsManager::savePreset(const std::string& subdirectory, std::string n
 			{
 				new_camera_preset = CAMERA_PRESET_CUSTOM;
 			}
-			new_camera_offsets = (!isDefaultCameraPreset(name) || (ECameraPreset)gSavedSettings.getU32("CameraPresetType") != new_camera_preset);
 		}
 		for (std::vector<std::string>::iterator it = name_list.begin(); it != name_list.end(); ++it)
 		{
diff --git a/indra/newview/llpreviewgesture.cpp b/indra/newview/llpreviewgesture.cpp
index 061ecad099af5eda3d235b6964624f51486c47a8..759e7859f24317c996313c4ad0756d4b139cf5c0 100644
--- a/indra/newview/llpreviewgesture.cpp
+++ b/indra/newview/llpreviewgesture.cpp
@@ -347,9 +347,6 @@ BOOL LLPreviewGesture::postBuild()
 	LLTextBox* text;
 	LLCheckBoxCtrl* check;
 
-	edit = getChild<LLLineEditor>("name");
-	edit->setKeystrokeCallback(onKeystrokeCommit, this);
-
 	edit = getChild<LLLineEditor>("desc");
 	edit->setKeystrokeCallback(onKeystrokeCommit, this);
 
@@ -482,9 +479,6 @@ BOOL LLPreviewGesture::postBuild()
 	{
 		getChild<LLUICtrl>("desc")->setValue(item->getDescription());
 		getChild<LLLineEditor>("desc")->setPrevalidate(&LLTextValidate::validateASCIIPrintableNoPipe);
-		
-		getChild<LLUICtrl>("name")->setValue(item->getName());
-		getChild<LLLineEditor>("name")->setPrevalidate(&LLTextValidate::validateASCIIPrintableNoPipe);
 	}
 
 	return LLPreview::postBuild();
@@ -1029,7 +1023,6 @@ void LLPreviewGesture::finishInventoryUpload(LLUUID itemId, LLUUID newAssetId)
     // active map with the new pointer.				
     if (LLGestureMgr::instance().isGestureActive(itemId))
     {
-        //*TODO: This is crashing for some reason.  Fix it.
         // Active gesture edited from menu.
         LLGestureMgr::instance().replaceGesture(itemId, newAssetId);
         gInventory.notifyObservers();
diff --git a/indra/newview/llpreviewnotecard.cpp b/indra/newview/llpreviewnotecard.cpp
index 230def53626c6a50e9d62f1dbd6211560ae028c2..3fd4f51559e023af6be25256548f039e97e8b031 100644
--- a/indra/newview/llpreviewnotecard.cpp
+++ b/indra/newview/llpreviewnotecard.cpp
@@ -866,7 +866,10 @@ bool LLPreviewNotecard::loadNotecardText(const std::string& filename)
     buffer[nread] = '\0';
     fclose(file);
 
-    mEditor->setText(LLStringExplicit(buffer));
+    std::string text = std::string(buffer);
+    LLStringUtil::replaceTabsWithSpaces(text, LLTextEditor::spacesPerTab());
+
+    mEditor->setText(text);
     delete[] buffer;
 
     return true;
diff --git a/indra/newview/llpreviewscript.cpp b/indra/newview/llpreviewscript.cpp
index a32dc8beda72258e31cd7c508714ffbad3264147..d677a996c1f29ff83a150d3ae2421241eff155ea 100644
--- a/indra/newview/llpreviewscript.cpp
+++ b/indra/newview/llpreviewscript.cpp
@@ -601,7 +601,10 @@ bool LLScriptEdCore::loadScriptText(const std::string& filename)
 	buffer[nread] = '\0';
 	fclose(file);
 
-	mEditor->setText(LLStringExplicit(buffer));
+    std::string text = std::string(buffer);
+    LLStringUtil::replaceTabsWithSpaces(text, LLTextEditor::spacesPerTab());
+
+    mEditor->setText(text);
 	delete[] buffer;
 
 	return true;
diff --git a/indra/newview/llpreviewtexture.cpp b/indra/newview/llpreviewtexture.cpp
index cd7b93aba777a5e78d84bb1990e25c25eef45a0f..10177c8023d01b1b115747d1f6fc1b17538059fa 100644
--- a/indra/newview/llpreviewtexture.cpp
+++ b/indra/newview/llpreviewtexture.cpp
@@ -367,7 +367,10 @@ void LLPreviewTexture::reshape(S32 width, S32 height, BOOL called_from_parent)
 
 	// add space for dimensions and aspect ratio
 	S32 info_height = dim_rect.mTop + CLIENT_RECT_VPAD;
-
+	if (getChild<LLLayoutPanel>("buttons_panel")->getVisible())
+	{
+		info_height += getChild<LLLayoutPanel>("buttons_panel")->getRect().getHeight();
+	}
 	LLRect client_rect(horiz_pad, getRect().getHeight(), getRect().getWidth() - horiz_pad, 0);
 	client_rect.mTop -= (PREVIEW_HEADER_SIZE + CLIENT_RECT_VPAD);
 	client_rect.mBottom += PREVIEW_BORDER + CLIENT_RECT_VPAD + info_height ;
@@ -412,6 +415,16 @@ void LLPreviewTexture::openToSave()
 	mPreviewToSave = TRUE;
 }
 
+void LLPreviewTexture::hideCtrlButtons()
+{
+	getChildView("desc txt")->setVisible(false);
+	getChildView("desc")->setVisible(false);
+	getChild<LLLayoutStack>("preview_stack")->collapsePanel(getChild<LLLayoutPanel>("buttons_panel"), true);
+	getChild<LLLayoutPanel>("buttons_panel")->setVisible(false);
+	getChild<LLComboBox>("combo_aspect_ratio")->setCurrentByIndex(0); //unconstrained
+	reshape(getRect().getWidth(), getRect().getHeight());
+}
+
 // static
 void LLPreviewTexture::onFileLoadedForSave(BOOL success, 
 					   LLViewerFetchedTexture *src_vi,
diff --git a/indra/newview/llpreviewtexture.h b/indra/newview/llpreviewtexture.h
index 9b6a8438752f301edceccd6afad468a780eedfbb..16db51332ee38cccb87acb6c6509176049d8ff69 100644
--- a/indra/newview/llpreviewtexture.h
+++ b/indra/newview/llpreviewtexture.h
@@ -67,6 +67,8 @@ class LLPreviewTexture : public LLPreview
 	
 	static void			onSaveAsBtn(void* data);
 
+	void				hideCtrlButtons();
+
 	/*virtual*/ void setObjectID(const LLUUID& object_id);
 protected:
 	void				init();
diff --git a/indra/newview/llrecentpeople.cpp b/indra/newview/llrecentpeople.cpp
index 83b0c4f1bf29b81484484906418170209341d30b..0faf6bf88960de264a45737869b528672d629c64 100644
--- a/indra/newview/llrecentpeople.cpp
+++ b/indra/newview/llrecentpeople.cpp
@@ -42,14 +42,6 @@ bool LLRecentPeople::add(const LLUUID& id, const LLSD& userdata)
 
 	if (is_not_group_id)
 	{
-		// For each avaline call the id of caller is different even if
-		// the phone number is the same.
-		// To avoid duplication of avaline list items in the recent list
-		// of panel People, deleting id's with similar phone number.
-		const LLUUID& caller_id = getIDByPhoneNumber(userdata);
-		if (caller_id.notNull())
-			mPeople.erase(caller_id);
-
 		//[] instead of insert to replace existing id->llsd["date"] with new date value
 		mPeople[id] = userdata;
 		mChangedSignal();
@@ -90,35 +82,6 @@ const LLSD& LLRecentPeople::getData(const LLUUID& id) const
 	return no_data;
 }
 
-bool LLRecentPeople::isAvalineCaller(const LLUUID& id) const
-{
-	recent_people_t::const_iterator it = mPeople.find(id);
-
-	if (it != mPeople.end())
-	{
-		const LLSD& user = it->second;		
-		return user["avaline_call"].asBoolean();
-	}
-
-	return false;
-}
-
-const LLUUID& LLRecentPeople::getIDByPhoneNumber(const LLSD& userdata)
-{
-	if (!userdata["avaline_call"].asBoolean())
-		return LLUUID::null;
-
-	for (recent_people_t::const_iterator it = mPeople.begin(); it != mPeople.end(); ++it)
-	{
-		const LLSD& user_info = it->second;
-		
-		if (user_info["call_number"].asString() == userdata["call_number"].asString())
-			return it->first;
-	}
-	
-	return LLUUID::null;
-}
-
 // virtual
 bool LLRecentPeople::handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
 {
diff --git a/indra/newview/llrecentpeople.h b/indra/newview/llrecentpeople.h
index 18b669ff4fc81be07d5f47d1a1c78dee5aeae1e5..1b322f2c0a98b3a68d70ad59815b6987db474e4e 100644
--- a/indra/newview/llrecentpeople.h
+++ b/indra/newview/llrecentpeople.h
@@ -62,9 +62,7 @@ class LLRecentPeople: public LLSingleton<LLRecentPeople>, public LLOldEvents::LL
 	 * @param id avatar to add.
 	 *
 	 * @param userdata additional information about last interaction party.
-	 *				   For example when last interaction party is not an avatar
-	 *				   but an avaline caller, additional info (such as phone
-	 *				   number, session id and etc.) should be added.
+	 *				   For example session id can be added.
 	 *
 	 * @return false if the avatar is in the list already, true otherwise
 	 */
@@ -96,13 +94,6 @@ class LLRecentPeople: public LLSingleton<LLRecentPeople>, public LLOldEvents::LL
 	 */
 	const LLSD& getData(const LLUUID& id) const;
 
-	/**
-	 * Checks whether specific participant is an avaline caller
-	 *
-	 * @param id identifier of specific participant
-	 */
-	bool isAvalineCaller(const LLUUID& id) const;
-
 	/**
 	 * Set callback to be called when the list changed.
 	 * 
@@ -122,8 +113,6 @@ class LLRecentPeople: public LLSingleton<LLRecentPeople>, public LLOldEvents::LL
 
 private:
 
-	const LLUUID& getIDByPhoneNumber(const LLSD& userdata);
-
 	typedef std::map<LLUUID, LLSD> recent_people_t;
 	recent_people_t		mPeople;
 	signal_t			mChangedSignal;
diff --git a/indra/newview/llremoteparcelrequest.cpp b/indra/newview/llremoteparcelrequest.cpp
index 055ccd5818545c40f57c997141be639156cc428a..f4ace52faa11178130cb9e1e982b1d64035949a1 100644
--- a/indra/newview/llremoteparcelrequest.cpp
+++ b/indra/newview/llremoteparcelrequest.cpp
@@ -213,7 +213,12 @@ void LLRemoteParcelInfoProcessor::regionParcelInfoCoro(std::string url,
 
     if (!status)
     {
-        observer->setErrorStatus(status.getStatus(), status.getMessage());
+        std::string message = status.getMessage();
+        if (message.empty())
+        {
+            message = status.toString();
+        }
+        observer->setErrorStatus(status.getStatus(), message);
     }
     else 
     {
diff --git a/indra/newview/llscenemonitor.cpp b/indra/newview/llscenemonitor.cpp
index f9baf5fbd30b15fb90a3e353bbe67f858d788cc8..2e44dc1459259b69a0acc9d4019ad3275efcb55e 100644
--- a/indra/newview/llscenemonitor.cpp
+++ b/indra/newview/llscenemonitor.cpp
@@ -271,7 +271,7 @@ void LLSceneMonitor::capture()
 	static LLCachedControl<F32>  scene_load_sample_time(gSavedSettings, "SceneLoadingMonitorSampleTime");
 	static bool force_capture = true;
 
-	bool enabled = LLGLSLShader::sNoFixedFunction && (monitor_enabled || mDebugViewerVisible);
+	bool enabled = monitor_enabled || mDebugViewerVisible;
 	if(mEnabled != enabled)
 	{
 		if(mEnabled)
@@ -332,9 +332,6 @@ bool LLSceneMonitor::needsUpdate() const
 	return mDiffState == NEED_DIFF;
 }
 
-static LLTrace::BlockTimerStatHandle FTM_GENERATE_SCENE_LOAD_DITHER_TEXTURE("Generate Scene Load Dither Texture");
-static LLTrace::BlockTimerStatHandle FTM_SCENE_LOAD_IMAGE_DIFF("Scene Load Image Diff");
-
 static LLStaticHashedString sDitherScale("dither_scale");
 static LLStaticHashedString sDitherScaleS("dither_scale_s");
 static LLStaticHashedString sDitherScaleT("dither_scale_t");
@@ -356,14 +353,12 @@ void LLSceneMonitor::compare()
 		return; 
 	}
 
-	LL_RECORD_BLOCK_TIME(FTM_SCENE_LOAD_IMAGE_DIFF);
 	mDiffState = EXECUTE_DIFF;
 
 	S32 width = gViewerWindow->getWindowWidthRaw();
 	S32 height = gViewerWindow->getWindowHeightRaw();
 	if(!mDiff)
 	{
-		LL_RECORD_BLOCK_TIME(FTM_GENERATE_SCENE_LOAD_DITHER_TEXTURE);
 		mDiff = new LLRenderTarget();
 		mDiff->allocate(width, height, GL_RGBA, false, false, LLTexUnit::TT_TEXTURE, true);
 
@@ -371,7 +366,6 @@ void LLSceneMonitor::compare()
 	}
 	else if(mDiff->getWidth() != width || mDiff->getHeight() != height)
 	{
-		LL_RECORD_BLOCK_TIME(FTM_GENERATE_SCENE_LOAD_DITHER_TEXTURE);
 		mDiff->resize(width, height);
 		generateDitheringTexture(width, height);
 	}
@@ -427,8 +421,6 @@ void LLSceneMonitor::calcDiffAggregate()
 {
 #ifdef LL_WINDOWS
 
-	LL_RECORD_BLOCK_TIME(FTM_SCENE_LOAD_IMAGE_DIFF);
-
 	if(mDiffState != EXECUTE_DIFF && !mDebugViewerVisible)
 	{
 		return;
@@ -481,8 +473,6 @@ void LLSceneMonitor::calcDiffAggregate()
 static LLTrace::EventStatHandle<> sFramePixelDiff("FramePixelDifference");
 void LLSceneMonitor::fetchQueryResult()
 {
-	LL_RECORD_BLOCK_TIME(FTM_SCENE_LOAD_IMAGE_DIFF);
-
 	// also throttle timing here, to avoid going below sample time due to phasing with frame capture
 	static LLCachedControl<F32>  scene_load_sample_time_control(gSavedSettings, "SceneLoadingMonitorSampleTime");
 	F32Seconds scene_load_sample_time = (F32Seconds)scene_load_sample_time_control();
@@ -729,13 +719,6 @@ void LLSceneMonitorView::onTeleportFinished()
 
 void LLSceneMonitorView::onVisibilityChange(BOOL visible)
 {
-	if (!LLGLSLShader::sNoFixedFunction && visible)
-	{
-		visible = false;
-		// keep Scene monitor and its view in sycn
-		setVisible(false);
-		LL_WARNS("SceneMonitor") << "Incompatible graphical settings, Scene Monitor can't be turned on" << LL_ENDL; 
-	}
 	LLSceneMonitor::getInstance()->setDebugViewerVisible(visible);
 }
 
diff --git a/indra/newview/llsceneview.cpp b/indra/newview/llsceneview.cpp
index f7aa63e34d8a504696272cb98d0e37503d13f006..e250f9bc7a998730c056b98cc448ad670f229f06 100644
--- a/indra/newview/llsceneview.cpp
+++ b/indra/newview/llsceneview.cpp
@@ -266,14 +266,11 @@ void LLSceneView::draw()
 
 			U32 count = triangles[idx].size();
 
-			U32 total = 0;
-
 			gGL.begin(LLRender::LINE_STRIP);
 			//plot triangles
 			for (U32 i = 0; i < count; ++i)
 			{
 				U32 tri_count = triangles[idx][i];
-				total += tri_count;	
 				F32 y = (F32) (tri_count-tri_domain[0])/triangle_range*tri_rect.getHeight()+tri_rect.mBottom;
 				F32 x = (F32) i / count * tri_rect.getWidth() + tri_rect.mLeft;
 
@@ -290,15 +287,8 @@ void LLSceneView::draw()
 			gGL.end();
 			gGL.flush();
 
-			U32 total_visible = 0;
 			count = visible_triangles[idx].size();
 
-			for (U32 i = 0; i < count; ++i)
-			{
-				U32 tri_count = visible_triangles[idx][i];
-				total_visible += tri_count;	
-			}
-
 			std::string label = llformat("%s Object Triangle Counts (Ktris) -- Visible: %.2f/%.2f (%.2f KB Visible)",
 				category[idx], total_visible_triangles[idx]/1024.f, total_triangles[idx]/1024.f, total_visible_bytes[idx]/1024.f);
 
diff --git a/indra/newview/llscreenchannel.cpp b/indra/newview/llscreenchannel.cpp
index 681787bcbe937fb660b354fd8a943221ca76ccc9..17f2970f995cdcd5f8dc7fbaf4816465348aecdf 100644
--- a/indra/newview/llscreenchannel.cpp
+++ b/indra/newview/llscreenchannel.cpp
@@ -49,10 +49,9 @@ using namespace LLNotificationsUI;
 
 bool LLScreenChannel::mWasStartUpToastShown = false;
 
-LLTrace::BlockTimerStatHandle FTM_GET_CHANNEL_RECT("Calculate Notification Channel Region");
 LLRect LLScreenChannelBase::getChannelRect()
 {
-	LL_RECORD_BLOCK_TIME(FTM_GET_CHANNEL_RECT);
+    LL_PROFILE_ZONE_SCOPED;
 
 	if (mFloaterSnapRegion == NULL)
 	{
@@ -259,7 +258,8 @@ void LLScreenChannel::updatePositionAndSize(LLRect new_world_rect)
 //--------------------------------------------------------------------------
 void LLScreenChannel::addToast(const LLToast::Params& p)
 {
-	bool store_toast = false, show_toast = false;
+    LL_PROFILE_ZONE_SCOPED
+    bool store_toast = false, show_toast = false;
 
 	if (mDisplayToastsAlways)
 	{
diff --git a/indra/newview/llscripteditor.cpp b/indra/newview/llscripteditor.cpp
index cd3a4dfd11a712d8094c3abfa485732b644b6948..c6bb2f19dd45a47b90394ae550ec79b0bcb3f3f7 100644
--- a/indra/newview/llscripteditor.cpp
+++ b/indra/newview/llscripteditor.cpp
@@ -138,11 +138,9 @@ void LLScriptEditor::initKeywords()
 	mKeywords.initialize(LLSyntaxIdLSL::getInstance()->getKeywordsXML());
 }
 
-LLTrace::BlockTimerStatHandle FTM_SYNTAX_HIGHLIGHTING("Syntax Highlighting");
-
 void LLScriptEditor::loadKeywords()
 {
-	LL_RECORD_BLOCK_TIME(FTM_SYNTAX_HIGHLIGHTING);
+    LL_PROFILE_ZONE_SCOPED;
 	mKeywords.processTokens();
 	
 	segment_vec_t segment_list;
@@ -160,7 +158,7 @@ void LLScriptEditor::updateSegments()
 {
 	if (mReflowIndex < S32_MAX && mKeywords.isLoaded() && mParseOnTheFly)
 	{
-		LL_RECORD_BLOCK_TIME(FTM_SYNTAX_HIGHLIGHTING);
+        LL_PROFILE_ZONE_SCOPED;
 		// HACK:  No non-ascii keywords for now
 		segment_vec_t segment_list;
 		mKeywords.findSegments(&segment_list, getWText(), mDefaultColor.get(), *this);
diff --git a/indra/newview/llsearchableui.cpp b/indra/newview/llsearchableui.cpp
index 1119e80005ecaee81ff95099a46f9f3d493b4063..620bbdfcdf91ba60d4d4dbd82d43b1f8088b2c05 100644
--- a/indra/newview/llsearchableui.cpp
+++ b/indra/newview/llsearchableui.cpp
@@ -132,8 +132,11 @@ void ll::statusbar::SearchableItem::setNotHighlighted( )
 	{
 		mCtrl->setHighlighted( false );
 
-		if( mWasHiddenBySearch )
-			mMenu->setVisible( TRUE );
+        if (mWasHiddenBySearch)
+        {
+            mMenu->setVisible(TRUE);
+            mWasHiddenBySearch = false;
+        }
 	}
 }
 
diff --git a/indra/newview/llsearchableui.h b/indra/newview/llsearchableui.h
index e033cae3abe2597e910dbce7ad567daf6bbd6aab..31f11eb8ef037ea16e269ba335dd142d806b0280 100644
--- a/indra/newview/llsearchableui.h
+++ b/indra/newview/llsearchableui.h
@@ -41,9 +41,9 @@ namespace ll
 		struct PanelData;
 		struct TabContainerData;
 
-		typedef boost::shared_ptr< SearchableItem > SearchableItemPtr;
-		typedef boost::shared_ptr< PanelData > PanelDataPtr;
-		typedef boost::shared_ptr< TabContainerData > TabContainerDataPtr;
+		typedef std::shared_ptr< SearchableItem > SearchableItemPtr;
+		typedef std::shared_ptr< PanelData > PanelDataPtr;
+		typedef std::shared_ptr< TabContainerData > TabContainerDataPtr;
 
 		typedef std::vector< TabContainerData > tTabContainerDataList;
 		typedef std::vector< SearchableItemPtr > tSearchableItemList;
@@ -55,7 +55,7 @@ namespace ll
 			LLView const *mView;
 			ll::ui::SearchableControl const *mCtrl;
 
-			std::vector< boost::shared_ptr< SearchableItem >  > mChildren;
+			std::vector< std::shared_ptr< SearchableItem >  > mChildren;
 
 			virtual ~SearchableItem();
 
@@ -68,8 +68,8 @@ namespace ll
 			LLPanel const *mPanel;
 			std::string mLabel;
 
-			std::vector< boost::shared_ptr< SearchableItem > > mChildren;
-			std::vector< boost::shared_ptr< PanelData > > mChildPanel;
+			std::vector< std::shared_ptr< SearchableItem > > mChildren;
+			std::vector< std::shared_ptr< PanelData > > mChildPanel;
 
 			virtual ~PanelData();
 
diff --git a/indra/newview/llsecapi.h b/indra/newview/llsecapi.h
index e1320375abef84f7d3817c6bcbb981e19484417c..d8831fee93f2494d9439981ef5313f36ed1bf838 100644
--- a/indra/newview/llsecapi.h
+++ b/indra/newview/llsecapi.h
@@ -485,6 +485,9 @@ class LLSecAPIHandler : public LLThreadSafeRefCount
 										const std::string& data_id,
 										const std::string& map_elem)=0;
 
+	// ensure protected store's map is written to storage
+	virtual void syncProtectedMap() = 0;
+
 public:
 	virtual LLPointer<LLCredential> createCredential(const std::string& grid,
 													 const LLSD& identifier, 
diff --git a/indra/newview/llsechandler_basic.cpp b/indra/newview/llsechandler_basic.cpp
index 6b06abaf999d3b7b8fc3de693d93708c6cc9081f..d0da3387ec3c810a96a9a4c371cc32ca83ed27d9 100644
--- a/indra/newview/llsechandler_basic.cpp
+++ b/indra/newview/llsechandler_basic.cpp
@@ -1608,6 +1608,11 @@ void LLSecAPIBasicHandler::removeFromProtectedMap(const std::string& data_type,
     }
 }
 
+void LLSecAPIBasicHandler::syncProtectedMap()
+{
+    // TODO - consider unifing these functions
+    _writeProtectedData();
+}
 //
 // Create a credential object from an identifier and authenticator.  credentials are
 // per grid.
diff --git a/indra/newview/llsechandler_basic.h b/indra/newview/llsechandler_basic.h
index 17e9f72f076cd3e6a085127604006bd5cad69086..bd1a8f640c249eeca85feb09059c0159fb484425 100644
--- a/indra/newview/llsechandler_basic.h
+++ b/indra/newview/llsechandler_basic.h
@@ -278,6 +278,9 @@ class LLSecAPIBasicHandler : public LLSecAPIHandler
 										const std::string& data_id,
 										const std::string& map_elem);
 
+	// ensure protected store's map is written to storage
+	virtual void syncProtectedMap();
+
 	// credential management routines
 	
 	virtual LLPointer<LLCredential> createCredential(const std::string& grid,
diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp
index 7ed2d7ef626559f6befa4c5d315ddc6c51a37801..86f7d2bf2535780005711693f2dc1e0d6be3a00f 100644
--- a/indra/newview/llselectmgr.cpp
+++ b/indra/newview/llselectmgr.cpp
@@ -209,8 +209,6 @@ void LLSelectMgr::cleanupGlobals()
 	LLSelectMgr::getInstance()->clearSelections();
 }
 
-// Build time optimization, generate this function once here
-template class LLSelectMgr* LLSingleton<class LLSelectMgr>::getInstance();
 //-----------------------------------------------------------------------------
 // LLSelectMgr()
 //-----------------------------------------------------------------------------
@@ -312,14 +310,29 @@ void LLSelectMgr::resetObjectOverrides(LLObjectSelectionHandle selected_handle)
 {
     struct f : public LLSelectedNodeFunctor
     {
+        f(bool a, LLSelectMgr* p) : mAvatarOverridesPersist(a), mManager(p) {}
+        bool mAvatarOverridesPersist;
+        LLSelectMgr* mManager;
         virtual bool apply(LLSelectNode* node)
         {
+            if (mAvatarOverridesPersist)
+            {
+                LLViewerObject* object = node->getObject();
+                if (object && !object->getParent())
+                {
+                    LLVOAvatar* avatar = object->asAvatar();
+                    if (avatar)
+                    {
+                        mManager->mAvatarOverridesMap.emplace(avatar->getID(), AvatarPositionOverride(node->mLastPositionLocal, node->mLastRotation, object));
+                    }
+                }
+            }
             node->mLastPositionLocal.setVec(0, 0, 0);
             node->mLastRotation = LLQuaternion();
             node->mLastScale.setVec(0, 0, 0);
             return true;
         }
-    } func;
+    } func(mAllowSelectAvatar, this);
 
     selected_handle->applyToNodes(&func);
 }
@@ -353,6 +366,93 @@ void LLSelectMgr::overrideObjectUpdates()
 	getSelection()->applyToNodes(&func);
 }
 
+void LLSelectMgr::resetAvatarOverrides()
+{
+    mAvatarOverridesMap.clear();
+}
+
+void LLSelectMgr::overrideAvatarUpdates()
+{
+    if (mAvatarOverridesMap.size() == 0)
+    {
+        return;
+    }
+
+    if (!mAllowSelectAvatar || !gFloaterTools)
+    {
+        resetAvatarOverrides();
+        return;
+    }
+
+    if (!gFloaterTools->getVisible() && getSelection()->isEmpty())
+    {
+        // when user switches selection, floater is invisible and selection is empty
+        LLToolset *toolset = LLToolMgr::getInstance()->getCurrentToolset();
+        if (toolset->isShowFloaterTools()
+            && toolset->isToolSelected(0)) // Pie tool
+        {
+            resetAvatarOverrides();
+            return;
+        }
+    }
+
+    // remove selected avatars from this list,
+    // but set object overrides to make sure avatar won't snap back 
+    struct f : public LLSelectedNodeFunctor
+    {
+        f(LLSelectMgr* p) : mManager(p) {}
+        LLSelectMgr* mManager;
+        virtual bool apply(LLSelectNode* selectNode)
+        {
+            LLViewerObject* object = selectNode->getObject();
+            if (object && !object->getParent())
+            {
+                LLVOAvatar* avatar = object->asAvatar();
+                if (avatar)
+                {
+                    uuid_av_override_map_t::iterator iter = mManager->mAvatarOverridesMap.find(avatar->getID());
+                    if (iter != mManager->mAvatarOverridesMap.end())
+                    {
+                        if (selectNode->mLastPositionLocal.isExactlyZero())
+                        {
+                            selectNode->mLastPositionLocal = iter->second.mLastPositionLocal;
+                        }
+                        if (selectNode->mLastRotation == LLQuaternion())
+                        {
+                            selectNode->mLastRotation = iter->second.mLastRotation;
+                        }
+                        mManager->mAvatarOverridesMap.erase(iter);
+                    }
+                }
+            }
+            return true;
+        }
+    } func(this);
+    getSelection()->applyToNodes(&func);
+
+    // Override avatar positions
+    uuid_av_override_map_t::iterator it = mAvatarOverridesMap.begin();
+    while (it != mAvatarOverridesMap.end())
+    {
+        if (it->second.mObject->isDead())
+        {
+            it = mAvatarOverridesMap.erase(it);
+        }
+        else
+        {
+            if (!it->second.mLastPositionLocal.isExactlyZero())
+            {
+                it->second.mObject->setPosition(it->second.mLastPositionLocal);
+            }
+            if (it->second.mLastRotation != LLQuaternion())
+            {
+                it->second.mObject->setRotation(it->second.mLastRotation);
+            }
+            it++;
+        }
+    }
+}
+
 //-----------------------------------------------------------------------------
 // Select just the object, not any other group members.
 //-----------------------------------------------------------------------------
@@ -888,7 +988,7 @@ void LLSelectMgr::addAsFamily(std::vector<LLViewerObject*>& objects, BOOL add_to
 		
 		// Can't select yourself
 		if (objectp->mID == gAgentID
-			&& !LLSelectMgr::getInstance()->mAllowSelectAvatar)
+			&& !mAllowSelectAvatar)
 		{
 			continue;
 		}
@@ -5898,8 +5998,6 @@ void LLSelectMgr::updateSilhouettes()
 		LLViewerObject* objectp = *iter;
 		objectp->clearChanged(LLXform::MOVED | LLXform::SILHOUETTE);
 	}
-	
-	//gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
 }
 
 void LLSelectMgr::updateSelectionSilhouette(LLObjectSelectionHandle object_handle, S32& num_sils_genned, std::vector<LLViewerObject*>& changed_objects)
@@ -6285,6 +6383,24 @@ LLSelectNode::LLSelectNode(const LLSelectNode& nodep)
 
 LLSelectNode::~LLSelectNode()
 {
+    LLSelectMgr *manager = LLSelectMgr::getInstance();
+    if (manager->mAllowSelectAvatar
+        && (!mLastPositionLocal.isExactlyZero()
+            || mLastRotation != LLQuaternion()))
+    {
+        LLViewerObject* object = getObject(); //isDead() check
+        if (object && !object->getParent())
+        {
+            LLVOAvatar* avatar = object->asAvatar();
+            if (avatar)
+            {
+                // Avatar was moved and needs to stay that way
+                manager->mAvatarOverridesMap.emplace(avatar->getID(), LLSelectMgr::AvatarPositionOverride(mLastPositionLocal, mLastRotation, object));
+            }
+        }
+    }
+
+
 	delete mPermissions;
 	mPermissions = NULL;
 }
@@ -6624,7 +6740,7 @@ void LLSelectNode::renderOneSilhouette(const LLColor4 &color)
 			glFogfv(GL_FOG_COLOR, fogCol.mV);
 
 			LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE, GL_GEQUAL);
-			gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
+            gGL.flush();
 			gGL.begin(LLRender::LINES);
 			{
 				gGL.color4f(color.mV[VRED], color.mV[VGREEN], color.mV[VBLUE], 0.4f);
@@ -6792,6 +6908,10 @@ void LLSelectMgr::updateSelectionCenter()
 	const F32 MOVE_SELECTION_THRESHOLD = 1.f;		//  Movement threshold in meters for updating selection
 													//  center (tractor beam)
 
+    // override any avatar updates received
+    // Works only if avatar was repositioned
+    // and edit floater is visible
+    overrideAvatarUpdates();
 	//override any object updates received
 	//for selected objects
 	overrideObjectUpdates();
diff --git a/indra/newview/llselectmgr.h b/indra/newview/llselectmgr.h
index 2b00fa1595ae54d15a22d52264257238e6ec01f5..199141fc32e4e6c46ac1871fde1dd839f3376401 100644
--- a/indra/newview/llselectmgr.h
+++ b/indra/newview/llselectmgr.h
@@ -407,11 +407,8 @@ class LLSelectionCallbackData
     LLObjectSelectionHandle					mSelectedObjects;
 };
 
-class LLSelectMgr : public LLEditMenuHandler, public LLSingleton<LLSelectMgr>
+class LLSelectMgr : public LLEditMenuHandler, public LLSimpleton<LLSelectMgr>
 {
-	LLSINGLETON(LLSelectMgr);
-	~LLSelectMgr();
-
 public:
 	static BOOL					sRectSelectInclusive;	// do we need to surround an object to pick it?
 	static BOOL					sRenderHiddenSelections;	// do we show selection silhouettes that are occluded?
@@ -437,6 +434,9 @@ class LLSelectMgr : public LLEditMenuHandler, public LLSingleton<LLSelectMgr>
 	LLCachedControl<bool>					mDebugSelectMgr;
 
 public:
+    LLSelectMgr();
+    ~LLSelectMgr();
+
 	static void cleanupGlobals();
 
 	// LLEditMenuHandler interface
@@ -467,6 +467,30 @@ class LLSelectMgr : public LLEditMenuHandler, public LLSingleton<LLSelectMgr>
 	void resetObjectOverrides(LLObjectSelectionHandle selected_handle);
 	void overrideObjectUpdates();
 
+    void resetAvatarOverrides();
+    void overrideAvatarUpdates();
+
+    struct AvatarPositionOverride
+    {
+        AvatarPositionOverride();
+        AvatarPositionOverride(LLVector3 &vec, LLQuaternion &quat, LLViewerObject *obj) :
+            mLastPositionLocal(vec),
+            mLastRotation(quat),
+            mObject(obj)
+        {
+        }
+        LLVector3 mLastPositionLocal;
+        LLQuaternion mLastRotation;
+        LLPointer<LLViewerObject> mObject;
+    };
+
+    // Avatar overrides should persist even after selection
+    // was removed as long as edit floater is up
+    typedef std::map<LLUUID, AvatarPositionOverride> uuid_av_override_map_t;
+    uuid_av_override_map_t mAvatarOverridesMap;
+public:
+
+
 	// Returns the previous value of mForceSelection
 	BOOL setForceSelection(BOOL force);
 
diff --git a/indra/newview/llsettingsvo.cpp b/indra/newview/llsettingsvo.cpp
index 58cbe0e20a815826379d6280c268626af8cb5d7c..7c762170a77da6b753004d3b19ff3b456a174a33 100644
--- a/indra/newview/llsettingsvo.cpp
+++ b/indra/newview/llsettingsvo.cpp
@@ -637,6 +637,7 @@ LLSD LLSettingsVOSky::convertToLegacy(const LLSettingsSky::ptr_t &psky, bool isA
 //-------------------------------------------------------------------------
 void LLSettingsVOSky::updateSettings()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_ENVIRONMENT;
     LLSettingsSky::updateSettings();
     LLVector3 sun_direction  = getSunDirection();
     LLVector3 moon_direction = getMoonDirection();
@@ -665,55 +666,56 @@ void LLSettingsVOSky::updateSettings()
 
 void LLSettingsVOSky::applySpecial(void *ptarget, bool force)
 {
-    LLGLSLShader *shader = (LLGLSLShader *)ptarget;
-
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
     LLVector4 light_direction = LLEnvironment::instance().getClampedLightNorm();
 
-    if (shader->mShaderGroup == LLGLSLShader::SG_DEFAULT)
+    LLShaderUniforms* shader = &((LLShaderUniforms*)ptarget)[LLGLSLShader::SG_DEFAULT];
 	{        
-    shader->uniform4fv(LLViewerShaderMgr::LIGHTNORM, 1, light_direction.mV);
-	shader->uniform3fv(LLShaderMgr::WL_CAMPOSLOCAL, 1, LLViewerCamera::getInstance()->getOrigin().mV);
+        shader->uniform4fv(LLViewerShaderMgr::LIGHTNORM, light_direction);
+        shader->uniform3fv(LLShaderMgr::WL_CAMPOSLOCAL, LLViewerCamera::getInstance()->getOrigin());
 	} 
-	else if (shader->mShaderGroup == LLGLSLShader::SG_SKY)
+    
+    shader = &((LLShaderUniforms*)ptarget)[LLGLSLShader::SG_SKY];
 	{
-    shader->uniform4fv(LLViewerShaderMgr::LIGHTNORM, 1, light_direction.mV);        
+        shader->uniform4fv(LLViewerShaderMgr::LIGHTNORM, light_direction);
 
-    // Legacy? SETTING_CLOUD_SCROLL_RATE("cloud_scroll_rate")
-    LLVector4 vect_c_p_d1(mSettings[SETTING_CLOUD_POS_DENSITY1]);
-    LLVector4 cloud_scroll( LLEnvironment::instance().getCloudScrollDelta() );
+        // Legacy? SETTING_CLOUD_SCROLL_RATE("cloud_scroll_rate")
+        LLVector4 vect_c_p_d1(mSettings[SETTING_CLOUD_POS_DENSITY1]);
+        LLVector4 cloud_scroll( LLEnvironment::instance().getCloudScrollDelta() );
 
-    // SL-13084 EEP added support for custom cloud textures -- flip them horizontally to match the preview of Clouds > Cloud Scroll
-    // Keep in Sync!
-    // * indra\newview\llsettingsvo.cpp
-    // * indra\newview\app_settings\shaders\class2\windlight\cloudsV.glsl
-    // * indra\newview\app_settings\shaders\class1\deferred\cloudsV.glsl
-    cloud_scroll[0] = -cloud_scroll[0];
-    vect_c_p_d1 += cloud_scroll;
-    shader->uniform4fv(LLShaderMgr::CLOUD_POS_DENSITY1, 1, vect_c_p_d1.mV);
+        // SL-13084 EEP added support for custom cloud textures -- flip them horizontally to match the preview of Clouds > Cloud Scroll
+        // Keep in Sync!
+        // * indra\newview\llsettingsvo.cpp
+        // * indra\newview\app_settings\shaders\class2\windlight\cloudsV.glsl
+        // * indra\newview\app_settings\shaders\class1\deferred\cloudsV.glsl
+        cloud_scroll[0] = -cloud_scroll[0];
+        vect_c_p_d1 += cloud_scroll;
+        shader->uniform4fv(LLShaderMgr::CLOUD_POS_DENSITY1, vect_c_p_d1);
 
-    LLSettingsSky::ptr_t psky = LLEnvironment::instance().getCurrentSky();
+        LLSettingsSky::ptr_t psky = LLEnvironment::instance().getCurrentSky();
 
-    LLColor4 sunDiffuse = psky->getSunlightColor();
-    LLColor4 moonDiffuse = psky->getMoonlightColor();
+        LLVector4 sunDiffuse = LLVector4(psky->getSunlightColor().mV);
+        LLVector4 moonDiffuse = LLVector4(psky->getMoonlightColor().mV);
 
-    shader->uniform4fv(LLShaderMgr::SUNLIGHT_COLOR, 1, sunDiffuse.mV);
-    shader->uniform4fv(LLShaderMgr::MOONLIGHT_COLOR, 1, moonDiffuse.mV);
+        shader->uniform4fv(LLShaderMgr::SUNLIGHT_COLOR, sunDiffuse);
+        shader->uniform4fv(LLShaderMgr::MOONLIGHT_COLOR, moonDiffuse);
 
-    LLColor4 cloud_color(psky->getCloudColor(), 1.0);
-    shader->uniform4fv(LLShaderMgr::CLOUD_COLOR, 1, cloud_color.mV);
+        LLVector4 cloud_color(LLVector3(psky->getCloudColor().mV), 1.0);
+        shader->uniform4fv(LLShaderMgr::CLOUD_COLOR, cloud_color);
 	}
     
+    shader = &((LLShaderUniforms*)ptarget)[LLGLSLShader::SG_ANY];
     shader->uniform1f(LLShaderMgr::SCENE_LIGHT_STRENGTH, mSceneLightStrength);
 
     LLColor4 ambient(getTotalAmbient());
-    shader->uniform4fv(LLShaderMgr::AMBIENT, 1, ambient.mV);
+    shader->uniform4fv(LLShaderMgr::AMBIENT, LLVector4(ambient.mV));
 
     shader->uniform1i(LLShaderMgr::SUN_UP_FACTOR, getIsSunUp() ? 1 : 0);
     shader->uniform1f(LLShaderMgr::SUN_MOON_GLOW_FACTOR, getSunMoonGlowFactor());
     shader->uniform1f(LLShaderMgr::DENSITY_MULTIPLIER, getDensityMultiplier());
     shader->uniform1f(LLShaderMgr::DISTANCE_MULTIPLIER, getDistanceMultiplier());
     
-    F32 g             = getGamma();    
+    F32 g             = getGamma();
     F32 display_gamma = gSavedSettings.getF32("RenderDeferredDisplayGamma");
 
     shader->uniform1f(LLShaderMgr::GAMMA, g);
@@ -907,11 +909,13 @@ LLSD LLSettingsVOWater::convertToLegacy(const LLSettingsWater::ptr_t &pwater)
 //-------------------------------------------------------------------------
 void LLSettingsVOWater::applySpecial(void *ptarget, bool force)
 {
-    LLGLSLShader *shader = (LLGLSLShader *)ptarget;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
 
     LLEnvironment& env = LLEnvironment::instance();
 
-    if (force || (shader->mShaderGroup == LLGLSLShader::SG_WATER))
+    auto group = LLGLSLShader::SG_WATER;
+    LLShaderUniforms* shader = &((LLShaderUniforms*)ptarget)[group];
+    
 	{
         F32 water_height = env.getWaterHeight();
 
@@ -935,7 +939,7 @@ void LLSettingsVOWater::applySpecial(void *ptarget, bool force)
 
         LLVector4 waterPlane(enorm.v[0], enorm.v[1], enorm.v[2], -ep.dot(enorm));
 
-        shader->uniform4fv(LLShaderMgr::WATER_WATERPLANE, 1, waterPlane.mV);
+        shader->uniform4fv(LLShaderMgr::WATER_WATERPLANE, waterPlane.mV);
 
         LLVector4 light_direction = env.getClampedLightNorm();
 
@@ -950,18 +954,19 @@ void LLSettingsVOWater::applySpecial(void *ptarget, bool force)
         shader->uniform1f(LLShaderMgr::WATER_FOGDENSITY, waterFogDensity);
 
         LLColor4 fog_color(env.getCurrentWater()->getWaterFogColor(), 0.0f);
-        shader->uniform4fv(LLShaderMgr::WATER_FOGCOLOR, 1, fog_color.mV);
+        shader->uniform4fv(LLShaderMgr::WATER_FOGCOLOR, fog_color.mV);
 
         F32 blend_factor = env.getCurrentWater()->getBlendFactor();
         shader->uniform1f(LLShaderMgr::BLEND_FACTOR, blend_factor);
 
         // update to normal lightnorm, water shader itself will use rotated lightnorm as necessary
-        shader->uniform4fv(LLShaderMgr::LIGHTNORM, 1, light_direction.mV);
+        shader->uniform4fv(LLShaderMgr::LIGHTNORM, light_direction.mV);
     }
 }
 
 void LLSettingsVOWater::updateSettings()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
     // base class clears dirty flag so as to not trigger recursive update
     LLSettingsBase::updateSettings();
 
@@ -1021,12 +1026,39 @@ LLSettingsDay::ptr_t LLSettingsVODay::buildFromLegacyPreset(const std::string &n
     std::set<std::string> framenames;
     std::set<std::string> notfound;
 
+    // expected and correct folder sctructure is to have
+    // three folders in widnlight's root: days, water, skies 
     std::string base_path(gDirUtilp->getDirName(path));
     std::string water_path(base_path);
     std::string sky_path(base_path);
+    std::string day_path(base_path);
 
     gDirUtilp->append(water_path, "water");
     gDirUtilp->append(sky_path, "skies");
+    gDirUtilp->append(day_path, "days");
+
+    if (!gDirUtilp->fileExists(day_path))
+    {
+        LL_WARNS("SETTINGS") << "File " << name << ".xml is not in \"days\" folder." << LL_ENDL;
+    }
+
+    if (!gDirUtilp->fileExists(water_path))
+    {
+        LL_WARNS("SETTINGS") << "Failed to find accompaniying water folder for file " << name
+            << ".xml. Falling back to using default folder" << LL_ENDL;
+
+        water_path = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "windlight");
+        gDirUtilp->append(water_path, "water");
+    }
+
+    if (!gDirUtilp->fileExists(sky_path))
+    {
+        LL_WARNS("SETTINGS") << "Failed to find accompaniying skies folder for file " << name
+            << ".xml. Falling back to using default folder" << LL_ENDL;
+
+        sky_path = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "windlight");
+        gDirUtilp->append(sky_path, "skies");
+    }
 
     newsettings[SETTING_NAME] = name;
 
diff --git a/indra/newview/llsettingsvo.h b/indra/newview/llsettingsvo.h
index a1baf02fe7ac598568896f3aff268702fbd7f723..05ec0e927567fab096a40c971d19283faee7dc54 100644
--- a/indra/newview/llsettingsvo.h
+++ b/indra/newview/llsettingsvo.h
@@ -101,8 +101,6 @@ class LLSettingsVOSky : public LLSettingsSky
 
     bool isAdvanced() const { return  m_isAdvanced; }
 
-    virtual void updateShader(LLGLSLShader* shader) { applySpecial(shader, true); }
-
 protected:
     LLSettingsVOSky();
 
@@ -135,8 +133,6 @@ class LLSettingsVOWater : public LLSettingsWater
 
     static LLSD     convertToLegacy(const ptr_t &);
 
-    virtual void    updateShader(LLGLSLShader* shader) { applySpecial(shader, true); }
-
 protected:
     LLSettingsVOWater();
 
diff --git a/indra/newview/llskinningutil.cpp b/indra/newview/llskinningutil.cpp
index e02b21f0365369119df3949dda251febaa397583..cf3519c1c7f3c0df69f0303c1851b341daccfcfa 100644
--- a/indra/newview/llskinningutil.cpp
+++ b/indra/newview/llskinningutil.cpp
@@ -35,7 +35,6 @@
 #include "llrigginginfo.h"
 
 #define DEBUG_SKINNING  LL_DEBUG
-#define MAT_USE_SSE     1
 
 void dump_avatar_and_skin_state(const std::string& reason, LLVOAvatar *avatar, const LLMeshSkinInfo *skin)
 {
@@ -120,36 +119,26 @@ void LLSkinningUtil::scrubInvalidJoints(LLVOAvatar *avatar, LLMeshSkinInfo* skin
     skin->mInvalidJointsScrubbed = true;
 }
 
-#define MAT_USE_SSE 1
-
 void LLSkinningUtil::initSkinningMatrixPalette(
-    LLMatrix4* mat,
+    LLMatrix4a* mat,
     S32 count, 
     const LLMeshSkinInfo* skin,
     LLVOAvatar *avatar)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
+
     initJointNums(const_cast<LLMeshSkinInfo*>(skin), avatar);
+
+    LLMatrix4a world[LL_CHARACTER_MAX_ANIMATED_JOINTS];
+
     for (U32 j = 0; j < count; ++j)
     {
         S32 joint_num = skin->mJointNums[j];
-        LLJoint *joint = NULL;
-        if (joint_num >= 0 && joint_num < LL_CHARACTER_MAX_ANIMATED_JOINTS)
-        {
-            joint = avatar->getJoint(joint_num);
-        }
-        llassert(joint);
+        LLJoint *joint = avatar->getJoint(joint_num);
+
         if (joint)
         {
-#ifdef MAT_USE_SSE
-            LLMatrix4a bind, world, res;
-            bind.loadu(skin->mInvBindMatrix[j]);
-            world.loadu(joint->getWorldMatrix());
-            matMul(bind,world,res);
-            memcpy(mat[j].mMatrix,res.mMatrix,16*sizeof(float));
-#else
-            mat[j] = skin->mInvBindMatrix[j];
-            mat[j] *= joint->getWorldMatrix();
-#endif
+            world[j] = joint->getWorldMatrix4a();
         }
         else
         {
@@ -159,16 +148,27 @@ void LLSkinningUtil::initSkinningMatrixPalette(
             // rendering  should  be disabled  unless  all joints  are
             // valid.  In other  cases of  skinned  rendering, invalid
             // joints should already have  been removed during scrubInvalidJoints().
-            LL_WARNS_ONCE("Avatar") << avatar->getFullname() 
-                                    << " rigged to invalid joint name " << skin->mJointNames[j] 
-                                    << " num " << skin->mJointNums[j] << LL_ENDL;
-            LL_WARNS_ONCE("Avatar") << avatar->getFullname() 
-                                    << " avatar build state: isBuilt() " << avatar->isBuilt() 
-                                    << " mInitFlags " << avatar->mInitFlags << LL_ENDL;
+            LL_WARNS_ONCE("Avatar") << avatar->getFullname()
+                << " rigged to invalid joint name " << skin->mJointNames[j]
+                << " num " << skin->mJointNums[j] << LL_ENDL;
+            LL_WARNS_ONCE("Avatar") << avatar->getFullname()
+                << " avatar build state: isBuilt() " << avatar->isBuilt()
+                << " mInitFlags " << avatar->mInitFlags << LL_ENDL;
 #endif
             dump_avatar_and_skin_state("initSkinningMatrixPalette joint not found", avatar, skin);
         }
     }
+
+    //NOTE: pointer striders used here as a micro-optimization over vector/array lookups
+    const LLMatrix4a* invBind = &(skin->mInvBindMatrix[0]);
+    const LLMatrix4a* w = world;
+    LLMatrix4a* m = mat;
+    LLMatrix4a* end = m + count;
+
+    while (m < end)
+    {
+        matMulUnsafe(*(invBind++), *(w++), *(m++));
+    }
 }
 
 void LLSkinningUtil::checkSkinWeights(LLVector4a* weights, U32 num_vertices, const LLMeshSkinInfo* skin)
@@ -212,7 +212,7 @@ void LLSkinningUtil::scrubSkinWeights(LLVector4a* weights, U32 num_vertices, con
 
 void LLSkinningUtil::getPerVertexSkinMatrix(
     F32* weights,
-    LLMatrix4a* mat,
+    const LLMatrix4a* mat,
     bool handle_bad_scale,
     LLMatrix4a& final_mat,
     U32 max_joints)
@@ -270,6 +270,7 @@ void LLSkinningUtil::initJointNums(LLMeshSkinInfo* skin, LLVOAvatar *avatar)
 {
     if (!skin->mJointNumsInitialized)
     {
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
         for (U32 j = 0; j < skin->mJointNames.size(); ++j)
         {
     #if DEBUG_SKINNING     
@@ -357,13 +358,11 @@ void LLSkinningUtil::updateRiggingInfo(const LLMeshSkinInfo* skin, LLVOAvatar *a
                                 rig_info_tab[joint_num].setIsRiggedTo(true);
 
                                 // FIXME could precompute these matMuls.
-                                LLMatrix4a bind_shape;
-                                LLMatrix4a inv_bind;
+                                const LLMatrix4a& bind_shape = skin->mBindShapeMatrix;
+                                const LLMatrix4a& inv_bind = skin->mInvBindMatrix[joint_index];
                                 LLMatrix4a mat;
                                 LLVector4a pos_joint_space;
 
-                                bind_shape.loadu(skin->mBindShapeMatrix);
-                                inv_bind.loadu(skin->mInvBindMatrix[joint_index]);
                                 matMul(bind_shape, inv_bind, mat);
 
                                 mat.affineTransform(pos, pos_joint_space);
@@ -426,3 +425,4 @@ LLQuaternion LLSkinningUtil::getUnscaledQuaternion(const LLMatrix4& mat4)
     bind_rot.normalize();
     return bind_rot;
 }
+
diff --git a/indra/newview/llskinningutil.h b/indra/newview/llskinningutil.h
index efe7c85997d4281623d955a116e81f8db032a039..807418f9831e60ab0b2496f9a2b8204d130ae7e6 100644
--- a/indra/newview/llskinningutil.h
+++ b/indra/newview/llskinningutil.h
@@ -42,10 +42,10 @@ namespace LLSkinningUtil
     S32 getMaxJointCount();
     U32 getMeshJointCount(const LLMeshSkinInfo *skin);
     void scrubInvalidJoints(LLVOAvatar *avatar, LLMeshSkinInfo* skin);
-    void initSkinningMatrixPalette(LLMatrix4* mat, S32 count, const LLMeshSkinInfo* skin, LLVOAvatar *avatar);
+    void initSkinningMatrixPalette(LLMatrix4a* mat, S32 count, const LLMeshSkinInfo* skin, LLVOAvatar *avatar);
     void checkSkinWeights(LLVector4a* weights, U32 num_vertices, const LLMeshSkinInfo* skin);
     void scrubSkinWeights(LLVector4a* weights, U32 num_vertices, const LLMeshSkinInfo* skin);
-    void getPerVertexSkinMatrix(F32* weights, LLMatrix4a* mat, bool handle_bad_scale, LLMatrix4a& final_mat, U32 max_joints);
+    void getPerVertexSkinMatrix(F32* weights, const LLMatrix4a* mat, bool handle_bad_scale, LLMatrix4a& final_mat, U32 max_joints);
 
     LL_FORCE_INLINE void getPerVertexSkinMatrixWithIndices(
         F32*        weights,
diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp
index efa4a7fd66b55b27643c8d0ef1d07b25efbb2da2..42cd1133a2b1ebe95d6b295cade7df369c4f8a6b 100644
--- a/indra/newview/llspatialpartition.cpp
+++ b/indra/newview/llspatialpartition.cpp
@@ -51,13 +51,9 @@
 #include "llphysicsshapebuilderutil.h"
 #include "llvoavatar.h"
 #include "llvolumemgr.h"
-#include "lltextureatlas.h"
 #include "llviewershadermgr.h"
 #include "llcontrolavatar.h"
 
-static LLTrace::BlockTimerStatHandle FTM_FRUSTUM_CULL("Frustum Culling");
-static LLTrace::BlockTimerStatHandle FTM_CULL_REBOUND("Cull Rebound Partition");
-
 extern bool gShiftFrame;
 
 static U32 sZombieGroups = 0;
@@ -131,129 +127,6 @@ LLSpatialGroup::~LLSpatialGroup()
 	sNodeCount--;
 
 	clearDrawMap();
-	clearAtlasList() ;
-}
-
-BOOL LLSpatialGroup::hasAtlas(LLTextureAtlas* atlasp)
-{
-	S8 type = atlasp->getComponents() - 1 ;
-	for(std::list<LLTextureAtlas*>::iterator iter = mAtlasList[type].begin(); iter != mAtlasList[type].end() ; ++iter)
-	{
-		if(atlasp == *iter)
-		{
-			return TRUE ;
-		}
-	}
-	return FALSE ;
-}
-
-void LLSpatialGroup::addAtlas(LLTextureAtlas* atlasp, S8 recursive_level) 
-{		
-	if(!hasAtlas(atlasp))
-	{
-		mAtlasList[atlasp->getComponents() - 1].push_back(atlasp) ;
-		atlasp->addSpatialGroup(this) ;
-	}
-	
-	--recursive_level;
-	if(recursive_level)//levels propagating up.
-	{
-		LLSpatialGroup* parent = getParent() ;
-		if(parent)
-		{
-			parent->addAtlas(atlasp, recursive_level) ;
-		}
-	}	
-}
-
-void LLSpatialGroup::removeAtlas(LLTextureAtlas* atlasp, BOOL remove_group, S8 recursive_level) 
-{
-	mAtlasList[atlasp->getComponents() - 1].remove(atlasp) ;
-	if(remove_group)
-	{
-		atlasp->removeSpatialGroup(this) ;
-	}
-
-	--recursive_level;
-	if(recursive_level)//levels propagating up.
-	{
-		LLSpatialGroup* parent = getParent() ;
-		if(parent)
-		{
-			parent->removeAtlas(atlasp, recursive_level) ;
-		}
-	}	
-}
-
-void LLSpatialGroup::clearAtlasList() 
-{
-	std::list<LLTextureAtlas*>::iterator iter ;
-	for(S8 i = 0 ; i < 4 ; i++)
-	{
-		if(mAtlasList[i].size() > 0)
-		{
-			for(iter = mAtlasList[i].begin(); iter != mAtlasList[i].end() ; ++iter)
-			{
-				((LLTextureAtlas*)*iter)->removeSpatialGroup(this) ;			
-			}
-			mAtlasList[i].clear() ;
-		}
-	}
-}
-
-LLTextureAtlas* LLSpatialGroup::getAtlas(S8 ncomponents, S8 to_be_reserved, S8 recursive_level)
-{
-	S8 type = ncomponents - 1 ;
-	if(mAtlasList[type].size() > 0)
-	{
-		for(std::list<LLTextureAtlas*>::iterator iter = mAtlasList[type].begin(); iter != mAtlasList[type].end() ; ++iter)
-		{
-			if(!((LLTextureAtlas*)*iter)->isFull(to_be_reserved))
-			{
-				return *iter ;
-			}
-		}
-	}
-
-	--recursive_level;
-	if(recursive_level)
-	{
-		LLSpatialGroup* parent = getParent() ;
-		if(parent)
-		{
-			return parent->getAtlas(ncomponents, to_be_reserved, recursive_level) ;
-		}
-	}
-	return NULL ;
-}
-
-void LLSpatialGroup::setCurUpdatingSlot(LLTextureAtlasSlot* slotp) 
-{ 
-	mCurUpdatingSlotp = slotp;
-
-	//if(!hasAtlas(mCurUpdatingSlotp->getAtlas()))
-	//{
-	//	addAtlas(mCurUpdatingSlotp->getAtlas()) ;
-	//}
-}
-
-LLTextureAtlasSlot* LLSpatialGroup::getCurUpdatingSlot(LLViewerTexture* imagep, S8 recursive_level) 
-{ 
-	if(gFrameCount && mCurUpdatingTime == gFrameCount && mCurUpdatingTexture == imagep)
-	{
-		return mCurUpdatingSlotp ;
-	}
-
-	//--recursive_level ;
-	//if(recursive_level)
-	//{
-	//	LLSpatialGroup* parent = getParent() ;
-	//	if(parent)
-	//	{
-	//		return parent->getCurUpdatingSlot(imagep, recursive_level) ;
-	//	}
-	//}
-	return NULL ;
 }
 
 void LLSpatialGroup::clearDrawMap()
@@ -345,6 +218,7 @@ void LLSpatialGroup::validateDrawMap()
 
 BOOL LLSpatialGroup::updateInGroup(LLDrawable *drawablep, BOOL immediate)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	drawablep->updateSpatialExtents();
 
 	OctreeNode* parent = mOctreeNode->getOctParent();
@@ -409,11 +283,6 @@ void LLSpatialGroup::rebuildMesh()
 	}
 }
 
-static LLTrace::BlockTimerStatHandle FTM_REBUILD_VBO("VBO Rebuilt");
-static LLTrace::BlockTimerStatHandle FTM_ADD_GEOMETRY_COUNT("Add Geometry");
-static LLTrace::BlockTimerStatHandle FTM_CREATE_VB("Create VB");
-static LLTrace::BlockTimerStatHandle FTM_GET_GEOMETRY("Get Geometry");
-
 void LLSpatialPartition::rebuildGeom(LLSpatialGroup* group)
 {
 	if (group->isDead() || !group->hasState(LLSpatialGroup::GEOM_DIRTY))
@@ -427,7 +296,7 @@ void LLSpatialPartition::rebuildGeom(LLSpatialGroup* group)
 		group->mLastUpdateViewAngle = group->mViewAngle;
 	}
 	
-	LL_RECORD_BLOCK_TIME(FTM_REBUILD_VBO);	
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_SPATIAL;
 
 	group->clearDrawMap();
 	
@@ -435,15 +304,12 @@ void LLSpatialPartition::rebuildGeom(LLSpatialGroup* group)
 	U32 index_count = 0;
 	U32 vertex_count = 0;
 
-	{
-		LL_RECORD_BLOCK_TIME(FTM_ADD_GEOMETRY_COUNT);
-		addGeometryCount(group, vertex_count, index_count);
-	}
-
+    addGeometryCount(group, vertex_count, index_count);
+	
 	if (vertex_count > 0 && index_count > 0)
 	{ //create vertex buffer containing volume geometry for this node
 		{
-			LL_RECORD_BLOCK_TIME(FTM_CREATE_VB);
+
 			group->mBuilt = 1.f;
 			if (group->mVertexBuffer.isNull() ||
 				!group->mVertexBuffer->isWriteable() ||
@@ -458,7 +324,6 @@ void LLSpatialPartition::rebuildGeom(LLSpatialGroup* group)
 					group->mVertexBuffer = NULL;
 					group->mBufferMap.clear();
 				}
-				stop_glerror();
 			}
 			else
 			{
@@ -471,13 +336,11 @@ void LLSpatialPartition::rebuildGeom(LLSpatialGroup* group)
 					group->mVertexBuffer = NULL;
 					group->mBufferMap.clear();
 				}
-				stop_glerror();
 			}
 		}
 
 		if (group->mVertexBuffer)
 		{
-			LL_RECORD_BLOCK_TIME(FTM_GET_GEOMETRY);
 			getGeometry(group);
 		}
 	}
@@ -503,7 +366,9 @@ LLSpatialGroup* LLSpatialGroup::getParent()
 	}
 
 BOOL LLSpatialGroup::removeObject(LLDrawable *drawablep, BOOL from_octree)
-	{
+{
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_SPATIAL
+
 	if(!drawablep)
 	{
 		return FALSE;
@@ -591,6 +456,8 @@ class LLSpatialSetStateDiff : public LLSpatialSetState
 
 void LLSpatialGroup::setState(U32 state, S32 mode) 
 {
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_SPATIAL
+
 	llassert(state <= LLSpatialGroup::STATE_MASK);
 	
 	if (mode > STATE_MODE_SINGLE)
@@ -638,6 +505,8 @@ class LLSpatialClearStateDiff : public LLSpatialClearState
 
 void LLSpatialGroup::clearState(U32 state, S32 mode)
 {
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_SPATIAL
+
 	llassert(state <= LLSpatialGroup::STATE_MASK);
 
 	if (mode > STATE_MODE_SINGLE)
@@ -673,11 +542,7 @@ LLSpatialGroup::LLSpatialGroup(OctreeNode* node, LLSpatialPartition* part) : LLO
 	mDistance(0.f),
 	mDepth(0.f),
 	mLastUpdateDistance(-1.f), 
-	mLastUpdateTime(gFrameTimeSeconds),
-	mAtlasList(4),
-	mCurUpdatingTime(0),
-	mCurUpdatingSlotp(NULL),
-	mCurUpdatingTexture (NULL)
+	mLastUpdateTime(gFrameTimeSeconds)
 {
 	ll_assert_aligned(this,16);
 	
@@ -724,6 +589,8 @@ void LLSpatialGroup::updateDistance(LLCamera &camera)
 
 F32 LLSpatialPartition::calcDistance(LLSpatialGroup* group, LLCamera& camera)
 {
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_SPATIAL
+
 	LLVector4a eye;
 	LLVector4a origin;
 	origin.load3(camera.getOrigin().mV);
@@ -781,9 +648,11 @@ F32 LLSpatialPartition::calcDistance(LLSpatialGroup* group, LLCamera& camera)
 		dist = eye.getLength3().getF32();
 	}
 
+#if !LL_RELEASE
     LL_DEBUGS("RiggedBox") << "calcDistance, group " << group << " camera " << origin << " obj bounds " 
                            << group->mObjectBounds[0] << ", " << group->mObjectBounds[1] 
                            << " dist " << dist << " radius " << group->mRadius << LL_ENDL;
+#endif
 
 	if (dist < 16.f)
 	{
@@ -815,6 +684,8 @@ F32 LLSpatialGroup::getUpdateUrgency() const
 
 BOOL LLSpatialGroup::changeLOD()
 {
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_SPATIAL
+
 	if (hasState(ALPHA_DIRTY | OBJECT_DIRTY))
 	{
 		//a rebuild is going to happen, update distance and LoD
@@ -907,6 +778,8 @@ void LLSpatialGroup::handleDestruction(const TreeNode* node)
 
 void LLSpatialGroup::handleChildAddition(const OctreeNode* parent, OctreeNode* child) 
 {
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_SPATIAL
+
 	if (child->getListenerCount() == 0)
 	{
 		new LLSpatialGroup(child, getSpatialPartition());
@@ -979,10 +852,12 @@ LLSpatialPartition::LLSpatialPartition(U32 data_mask, BOOL render_by_group, U32
 
 LLSpatialPartition::~LLSpatialPartition()
 {
+    cleanup();
 }
 
 LLSpatialGroup *LLSpatialPartition::put(LLDrawable *drawablep, BOOL was_visible)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	drawablep->updateSpatialExtents();
 
 	//keep drawable from being garbage collected
@@ -1008,6 +883,7 @@ LLSpatialGroup *LLSpatialPartition::put(LLDrawable *drawablep, BOOL was_visible)
 
 BOOL LLSpatialPartition::remove(LLDrawable *drawablep, LLSpatialGroup *curp)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	if (!curp->removeObject(drawablep))
 	{
 		OCT_ERRS << "Failed to remove drawable from octree!" << LL_ENDL;
@@ -1024,6 +900,7 @@ BOOL LLSpatialPartition::remove(LLDrawable *drawablep, LLSpatialGroup *curp)
 
 void LLSpatialPartition::move(LLDrawable *drawablep, LLSpatialGroup *curp, BOOL immediate)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	// sanity check submitted by open source user bushing Spatula
 	// who was seeing crashing here. (See VWR-424 reported by Bunny Mayne)
 	if (!drawablep)
@@ -1477,12 +1354,12 @@ void LLSpatialPartition::resetVertexBuffers()
 
 BOOL LLSpatialPartition::getVisibleExtents(LLCamera& camera, LLVector3& visMin, LLVector3& visMax)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_SPATIAL;
 	LLVector4a visMina, visMaxa;
 	visMina.load3(visMin.mV);
 	visMaxa.load3(visMax.mV);
 
 	{
-		LL_RECORD_BLOCK_TIME(FTM_CULL_REBOUND);		
 		LLSpatialGroup* group = (LLSpatialGroup*) mOctree->getListener(0);
 		group->rebound();
 	}
@@ -1504,11 +1381,11 @@ BOOL LLSpatialPartition::visibleObjectsInFrustum(LLCamera& camera)
 
 S32 LLSpatialPartition::cull(LLCamera &camera, std::vector<LLDrawable *>* results, BOOL for_select)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_SPATIAL;
 #if LL_OCTREE_PARANOIA_CHECK
 	((LLSpatialGroup*)mOctree->getListener(0))->checkStates();
 #endif
 	{
-		LL_RECORD_BLOCK_TIME(FTM_CULL_REBOUND);		
 		LLSpatialGroup* group = (LLSpatialGroup*) mOctree->getListener(0);
 		group->rebound();
 	}
@@ -1525,37 +1402,32 @@ S32 LLSpatialPartition::cull(LLCamera &camera, std::vector<LLDrawable *>* result
 	
 S32 LLSpatialPartition::cull(LLCamera &camera, bool do_occlusion)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_SPATIAL;
 #if LL_OCTREE_PARANOIA_CHECK
 	((LLSpatialGroup*)mOctree->getListener(0))->checkStates();
 #endif
-	{
-		LL_RECORD_BLOCK_TIME(FTM_CULL_REBOUND);		
-		LLSpatialGroup* group = (LLSpatialGroup*) mOctree->getListener(0);
-		group->rebound();
-	}
+	LLSpatialGroup* group = (LLSpatialGroup*) mOctree->getListener(0);
+	group->rebound();
 
 #if LL_OCTREE_PARANOIA_CHECK
 	((LLSpatialGroup*)mOctree->getListener(0))->validate();
 #endif
 
-	if (LLPipeline::sShadowRender)
-	{
-		LL_RECORD_BLOCK_TIME(FTM_FRUSTUM_CULL);
-		LLOctreeCullShadow culler(&camera);
-		culler.traverse(mOctree);
-	}
-	else if (mInfiniteFarClip || !LLPipeline::sUseFarClip)
-	{
-		LL_RECORD_BLOCK_TIME(FTM_FRUSTUM_CULL);		
-		LLOctreeCullNoFarClip culler(&camera);
-		culler.traverse(mOctree);
-	}
-	else
-	{
-		LL_RECORD_BLOCK_TIME(FTM_FRUSTUM_CULL);		
-		LLOctreeCull culler(&camera);
-		culler.traverse(mOctree);
-	}
+    if (LLPipeline::sShadowRender)
+    {
+        LLOctreeCullShadow culler(&camera);
+        culler.traverse(mOctree);
+    }
+    else if (mInfiniteFarClip || !LLPipeline::sUseFarClip)
+    {
+        LLOctreeCullNoFarClip culler(&camera);
+        culler.traverse(mOctree);
+    }
+    else
+    {
+        LLOctreeCull culler(&camera);
+        culler.traverse(mOctree);
+    }
 	
 	return 0;
 }
@@ -1695,6 +1567,62 @@ void pushVertsColorCoded(LLSpatialGroup* group, U32 mask)
 	}
 }
 
+// return false if drawable is rigged and:
+//  - a linked rigged drawable has a different spatial group
+//  - a linked rigged drawable face has the wrong draw order index
+bool check_rigged_group(LLDrawable* drawable)
+{
+    if (drawable->isState(LLDrawable::RIGGED))
+    {
+        LLSpatialGroup* group = drawable->getSpatialGroup();
+        LLDrawable* root = drawable->getRoot();
+
+        if (root->isState(LLDrawable::RIGGED) && root->getSpatialGroup() != group)
+        {
+            llassert(false);
+            return false;
+        }
+
+        S32 last_draw_index = -1;
+        if (root->isState(LLDrawable::RIGGED))
+        {
+            for (auto& face : root->getFaces())
+            {
+                if ((S32) face->getDrawOrderIndex() <= last_draw_index)
+                {
+                    llassert(false);
+                    return false;
+                }
+                last_draw_index = face->getDrawOrderIndex();
+            }
+        }
+
+        for (auto& child : root->getVObj()->getChildren())
+        {
+            if (child->mDrawable->isState(LLDrawable::RIGGED))
+            {
+                for (auto& face : child->mDrawable->getFaces())
+                {
+                    if ((S32) face->getDrawOrderIndex() <= last_draw_index)
+                    {
+                        llassert(false);
+                        return false;
+                    }
+                    last_draw_index = face->getDrawOrderIndex();
+                }
+            }
+            
+            if (child->mDrawable->getSpatialGroup() != group)
+            {
+                llassert(false);
+                return false;
+            }
+        }
+    }
+
+    return true;
+}
+
 void renderOctree(LLSpatialGroup* group)
 {
 	//render solid object bounding box, color
@@ -1728,13 +1656,20 @@ void renderOctree(LLSpatialGroup* group)
 			gGL.flush();
 			glLineWidth(1.f);
 			gGL.flush();
+
+            LLVOAvatar* lastAvatar = nullptr;
+            U64 lastMeshId = 0;
+
 			for (LLSpatialGroup::element_iter i = group->getDataBegin(); i != group->getDataEnd(); ++i)
 			{
 				LLDrawable* drawable = (LLDrawable*)(*i)->getDrawable();
-				if(!drawable)
+				if(!drawable || drawable->getNumFaces() == 0)
 				{
 					continue;
 				}
+
+                llassert(check_rigged_group(drawable));
+
 				if (!group->getSpatialPartition()->isBridge())
 				{
 					gGL.pushMatrix();
@@ -1742,6 +1677,27 @@ void renderOctree(LLSpatialGroup* group)
 					gGL.translatef(trans.mV[0], trans.mV[1], trans.mV[2]);
 				}
 				
+                LLFace* face = drawable->getFace(0);
+                bool rigged = face->isState(LLFace::RIGGED);
+                gDebugProgram.bind(rigged);
+
+                gGL.diffuseColor4f(1, 0, 0, 1);
+
+                if (rigged)
+                {
+                    gGL.pushMatrix();
+                    gGL.loadMatrix(gGLModelView);
+                    if (lastAvatar != face->mAvatar ||
+                        lastMeshId != face->mSkinInfo->mHash)
+                    {
+                        if (!LLRenderPass::uploadMatrixPalette(face->mAvatar, face->mSkinInfo))
+                        {
+                            continue;
+                        }
+                        lastAvatar = face->mAvatar;
+                        lastMeshId = face->mSkinInfo->mHash;
+                    }
+                }
 				for (S32 j = 0; j < drawable->getNumFaces(); j++)
 				{
 					LLFace* face = drawable->getFace(j);
@@ -1760,19 +1716,25 @@ void renderOctree(LLSpatialGroup* group)
 							continue;
 						}
 
-						face->getVertexBuffer()->setBuffer(LLVertexBuffer::MAP_VERTEX);
+						face->getVertexBuffer()->setBuffer(LLVertexBuffer::MAP_VERTEX | (rigged ? LLVertexBuffer::MAP_WEIGHT4 : 0));
 						//drawBox((face->mExtents[0] + face->mExtents[1])*0.5f,
 						//		(face->mExtents[1]-face->mExtents[0])*0.5f);
 						face->getVertexBuffer()->draw(LLRender::TRIANGLES, face->getIndicesCount(), face->getIndicesStart());
 					}
 				}
 
+                if (rigged)
+                {
+                    gGL.popMatrix();
+                }
+
 				if (!group->getSpatialPartition()->isBridge())
 				{
 					gGL.popMatrix();
 				}
 			}
 			glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+            gDebugProgram.bind(); // make sure non-rigged variant is bound
 			gGL.diffuseColor4f(1,1,1,1);
 		}
 	}
@@ -2374,7 +2336,12 @@ void renderMeshBaseHull(LLVOVolume* volume, U32 data_mask, LLColor4& color, LLCo
 		if (!decomp->mBaseHullMesh.empty())
 		{
 			gGL.diffuseColor4fv(color.mV);
-			LLVertexBuffer::drawArrays(LLRender::TRIANGLES, decomp->mBaseHullMesh.mPositions, decomp->mBaseHullMesh.mNormals);
+			LLVertexBuffer::drawArrays(LLRender::TRIANGLES, decomp->mBaseHullMesh.mPositions);
+
+            glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+            gGL.diffuseColor4fv(line_color.mV);
+            LLVertexBuffer::drawArrays(LLRender::TRIANGLES, decomp->mBaseHullMesh.mPositions);
+            glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
 		}
 		else
 		{
@@ -2394,13 +2361,11 @@ void renderMeshBaseHull(LLVOVolume* volume, U32 data_mask, LLColor4& color, LLCo
 void render_hull(LLModel::PhysicsMesh& mesh, const LLColor4& color, const LLColor4& line_color)
 {
 	gGL.diffuseColor4fv(color.mV);
-	LLVertexBuffer::drawArrays(LLRender::TRIANGLES, mesh.mPositions, mesh.mNormals);
-	LLGLEnable offset(GL_POLYGON_OFFSET_LINE);
+	LLVertexBuffer::drawArrays(LLRender::TRIANGLES, mesh.mPositions);
 	glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
-	glPolygonOffset(3.f, 3.f);
 	glLineWidth(3.f);
 	gGL.diffuseColor4fv(line_color.mV);
-	LLVertexBuffer::drawArrays(LLRender::TRIANGLES, mesh.mPositions, mesh.mNormals);
+	LLVertexBuffer::drawArrays(LLRender::TRIANGLES, mesh.mPositions);
 	glLineWidth(1.f);
 	glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
 }
@@ -2455,6 +2420,9 @@ void renderPhysicsShape(LLDrawable* drawable, LLVOVolume* volume)
 	gGL.pushMatrix();
 	gGL.multMatrix((F32*) volume->getRelativeXform().mMatrix);
 		
+    LLGLEnable(GL_POLYGON_OFFSET_LINE);
+    glPolygonOffset(3.f, 3.f);
+
 	if (type == LLPhysicsShapeBuilderUtil::PhysicsShapeSpecification::USER_MESH)
 	{
 		LLUUID mesh_id = volume->getVolume()->getParams().getSculptID();
@@ -2482,12 +2450,12 @@ void renderPhysicsShape(LLDrawable* drawable, LLVOVolume* volume)
 			{ 
 				//decomp has physics mesh, render that mesh
 				gGL.diffuseColor4fv(color.mV);
-				LLVertexBuffer::drawArrays(LLRender::TRIANGLES, decomp->mPhysicsShapeMesh.mPositions, decomp->mPhysicsShapeMesh.mNormals);
+				LLVertexBuffer::drawArrays(LLRender::TRIANGLES, decomp->mPhysicsShapeMesh.mPositions);
 								
 				glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
 				gGL.diffuseColor4fv(line_color.mV);
-				LLVertexBuffer::drawArrays(LLRender::TRIANGLES, decomp->mPhysicsShapeMesh.mPositions, decomp->mPhysicsShapeMesh.mNormals);
-				glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+                LLVertexBuffer::drawArrays(LLRender::TRIANGLES, decomp->mPhysicsShapeMesh.mPositions);
+                glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
 			}
 			else
 			{ //no mesh or decomposition, render base hull
@@ -2613,9 +2581,9 @@ void renderPhysicsShape(LLDrawable* drawable, LLVOVolume* volume)
 				gGL.diffuseColor4fv(line_color.mV);
 				LLVertexBuffer::unbind();
 
-				llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShader != 0);
-							
-				LLVertexBuffer::drawElements(LLRender::TRIANGLES, phys_volume->mHullPoints, NULL, phys_volume->mNumHullIndices, phys_volume->mHullIndices);
+				llassert(LLGLSLShader::sCurBoundShader != 0);
+				
+                LLVertexBuffer::drawElements(LLRender::TRIANGLES, phys_volume->mHullPoints, NULL, phys_volume->mNumHullIndices, phys_volume->mHullIndices);
 				
 				gGL.diffuseColor4fv(color.mV);
 				glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
@@ -2695,16 +2663,22 @@ void renderPhysicsShape(LLDrawable* drawable, LLVOVolume* volume)
 		if (phys_volume->mHullPoints && phys_volume->mHullIndices)
 		{
 			glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
-			llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShader != 0);
+			llassert(LLGLSLShader::sCurBoundShader != 0);
 			LLVertexBuffer::unbind();
 			glVertexPointer(3, GL_FLOAT, 16, phys_volume->mHullPoints);
 			gGL.diffuseColor4fv(line_color.mV);
 			gGL.syncMatrices();
-			glDrawElements(GL_TRIANGLES, phys_volume->mNumHullIndices, GL_UNSIGNED_SHORT, phys_volume->mHullIndices);
+			{
+				LL_PROFILER_GPU_ZONEC( "gl.DrawElements", 0x20FF20 )
+				glDrawElements(GL_TRIANGLES, phys_volume->mNumHullIndices, GL_UNSIGNED_SHORT, phys_volume->mHullIndices);
+			}
 			
 			gGL.diffuseColor4fv(color.mV);
 			glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
-			glDrawElements(GL_TRIANGLES, phys_volume->mNumHullIndices, GL_UNSIGNED_SHORT, phys_volume->mHullIndices);			
+			{
+				LL_PROFILER_GPU_ZONEC( "gl.DrawElements", 0x40FF40 )
+				glDrawElements(GL_TRIANGLES, phys_volume->mNumHullIndices, GL_UNSIGNED_SHORT, phys_volume->mHullIndices);
+			}
 		}
 		else
 		{
@@ -2896,8 +2870,27 @@ void renderBatchSize(LLDrawInfo* params)
 {
 	LLGLEnable offset(GL_POLYGON_OFFSET_FILL);
 	glPolygonOffset(-1.f, 1.f);
-	gGL.diffuseColor4ubv((GLubyte*) &(params->mDebugColor));
-	pushVerts(params, LLVertexBuffer::MAP_VERTEX);
+    LLGLSLShader* old_shader = LLGLSLShader::sCurBoundShaderPtr;
+    U32 mask = LLVertexBuffer::MAP_VERTEX;
+    bool bind = false;
+    if (params->mAvatar)
+    { 
+        gGL.pushMatrix();
+        gGL.loadMatrix(gGLModelView);
+        bind = true;
+        old_shader->mRiggedVariant->bind();
+        LLRenderPass::uploadMatrixPalette(*params);
+        mask |= LLVertexBuffer::MAP_WEIGHT4;
+    }
+	
+    gGL.diffuseColor4ubv((GLubyte*)&(params->mDebugColor));
+	pushVerts(params, mask);
+
+    if (bind)
+    {
+        gGL.popMatrix();
+        old_shader->bind();
+    }
 }
 
 void renderShadowFrusta(LLDrawInfo* params)
@@ -3094,7 +3087,7 @@ class LLRenderOctreeRaycast : public LLOctreeTriangleRayIntersect
 
 	}
 
-	void visit(const LLOctreeNode<LLVolumeTriangle>* branch)
+    void visit(const LLOctreeNode<LLVolumeTriangle, LLVolumeTriangle*>* branch)
 	{
 		LLVolumeOctreeListener* vl = (LLVolumeOctreeListener*) branch->getListener(0);
 
@@ -3136,7 +3129,7 @@ class LLRenderOctreeRaycast : public LLOctreeTriangleRayIntersect
 			}
 
 			gGL.begin(LLRender::TRIANGLES);
-			for (LLOctreeNode<LLVolumeTriangle>::const_element_iter iter = branch->getDataBegin();
+            for (LLOctreeNode<LLVolumeTriangle, LLVolumeTriangle*>::const_element_iter iter = branch->getDataBegin();
 					iter != branch->getDataEnd();
 					++iter)
 			{
@@ -3222,6 +3215,7 @@ void renderRaycast(LLDrawable* drawablep)
 						gGL.diffuseColor4f(0,1,1,0.5f);
 						glVertexPointer(3, GL_FLOAT, sizeof(LLVector4a), face.mPositions);
 						gGL.syncMatrices();
+						LL_PROFILER_GPU_ZONEC( "gl.DrawElements", 0x60FF60 );
 						glDrawElements(GL_TRIANGLES, face.mNumIndices, GL_UNSIGNED_SHORT, face.mIndices);
 					}
 					
@@ -3229,14 +3223,14 @@ void renderRaycast(LLDrawable* drawablep)
 					{
 						F32 t = 1.f;
 
-						if (!face.mOctree)
+                        if (!face.getOctree())
 						{
 							((LLVolumeFace*) &face)->createOctree(); 
 						}
 
 						LLRenderOctreeRaycast render(start, dir, &t);
 					
-						render.traverse(face.mOctree);
+                        render.traverse(face.getOctree());
 					}
 
 					gGL.popMatrix();		
@@ -3774,10 +3768,7 @@ void LLSpatialPartition::renderDebug()
 		return;
 	}
 	
-	if (LLGLSLShader::sNoFixedFunction)
-	{
-		gDebugProgram.bind();
-	}
+	gDebugProgram.bind();
 
 	if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_PRIORITY))
 	{
@@ -3826,10 +3817,7 @@ void LLSpatialPartition::renderDebug()
 			glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
 		}
 	}
-	if (LLGLSLShader::sNoFixedFunction)
-	{
-		gDebugProgram.unbind();
-	}
+	gDebugProgram.unbind();
 }
 
 void LLSpatialGroup::drawObjectBox(LLColor4 col)
@@ -3858,7 +3846,7 @@ BOOL LLSpatialPartition::isVisible(const LLVector3& v)
 }
 
 LL_ALIGN_PREFIX(16)
-class LLOctreeIntersect : public LLOctreeTraveler<LLViewerOctreeEntry>
+class LLOctreeIntersect : public LLOctreeTraveler<LLViewerOctreeEntry, LLPointer<LLViewerOctreeEntry>>
 {
 public:
 	LL_ALIGN_16(LLVector4a mStart);
@@ -4023,8 +4011,7 @@ LLDrawInfo::LLDrawInfo(U16 start, U16 end, U32 count, U32 offset,
 					   LLViewerTexture* texture, LLVertexBuffer* buffer,
 					   bool selected,
 					   BOOL fullbright, U8 bump, BOOL particle, F32 part_size)
-:	LLTrace::MemTrackableNonVirtual<LLDrawInfo, 16>("LLDrawInfo"),
-	mVertexBuffer(buffer),
+:	mVertexBuffer(buffer),
 	mTexture(texture),
 	mTextureMatrix(NULL),
 	mModelMatrix(NULL),
@@ -4054,7 +4041,8 @@ LLDrawInfo::LLDrawInfo(U16 start, U16 end, U32 count, U32 offset,
 {
 	mVertexBuffer->validateRange(mStart, mEnd, mCount, mOffset);
 	
-	mDebugColor = (rand() << 16) + rand();
+    mDebugColor = (rand() << 16) + rand();
+    ((U8*)&mDebugColor)[3] = 200;
 }
 
 LLDrawInfo::~LLDrawInfo()	
@@ -4080,6 +4068,11 @@ void LLDrawInfo::validate()
 	mVertexBuffer->validateRange(mStart, mEnd, mCount, mOffset);
 }
 
+U64 LLDrawInfo::getSkinHash()
+{
+    return mSkinInfo ? mSkinInfo->mHash : 0;
+}
+
 LLVertexBuffer* LLGeometryManager::createVertexBuffer(U32 type_mask, U32 usage)
 {
 	return new LLVertexBuffer(type_mask, usage);
@@ -4089,6 +4082,7 @@ LLCullResult::LLCullResult()
 {
 	mVisibleGroupsAllocated = 0;
 	mAlphaGroupsAllocated = 0;
+    mRiggedAlphaGroupsAllocated = 0;
 	mOcclusionGroupsAllocated = 0;
 	mDrawableGroupsAllocated = 0;
 	mVisibleListAllocated = 0;
@@ -4100,6 +4094,9 @@ LLCullResult::LLCullResult()
 	mAlphaGroups.clear();
 	mAlphaGroups.push_back(NULL);
 	mAlphaGroupsEnd = &mAlphaGroups[0];
+    mRiggedAlphaGroups.clear();
+    mRiggedAlphaGroups.push_back(NULL);
+    mRiggedAlphaGroupsEnd = &mRiggedAlphaGroups[0];
 	mOcclusionGroups.clear();
 	mOcclusionGroups.push_back(NULL);
 	mOcclusionGroupsEnd = &mOcclusionGroups[0];
@@ -4140,6 +4137,9 @@ void LLCullResult::clear()
 	mAlphaGroupsSize = 0;
 	mAlphaGroupsEnd = &mAlphaGroups[0];
 
+    mRiggedAlphaGroupsSize = 0;
+    mRiggedAlphaGroupsEnd = &mRiggedAlphaGroups[0];
+
 	mOcclusionGroupsSize = 0;
 	mOcclusionGroupsEnd = &mOcclusionGroups[0];
 
@@ -4184,6 +4184,16 @@ LLCullResult::sg_iterator LLCullResult::endAlphaGroups()
 	return mAlphaGroupsEnd;
 }
 
+LLCullResult::sg_iterator LLCullResult::beginRiggedAlphaGroups()
+{
+    return &mRiggedAlphaGroups[0];
+}
+
+LLCullResult::sg_iterator LLCullResult::endRiggedAlphaGroups()
+{
+    return mRiggedAlphaGroupsEnd;
+}
+
 LLCullResult::sg_iterator LLCullResult::beginOcclusionGroups()
 {
 	return &mOcclusionGroups[0];
@@ -4262,6 +4272,20 @@ void LLCullResult::pushAlphaGroup(LLSpatialGroup* group)
 	mAlphaGroupsEnd = &mAlphaGroups[mAlphaGroupsSize];
 }
 
+void LLCullResult::pushRiggedAlphaGroup(LLSpatialGroup* group)
+{
+    if (mRiggedAlphaGroupsSize < mRiggedAlphaGroupsAllocated)
+    {
+        mRiggedAlphaGroups[mRiggedAlphaGroupsSize] = group;
+    }
+    else
+    {
+        pushBack(mRiggedAlphaGroups, mRiggedAlphaGroupsAllocated, group);
+    }
+    ++mRiggedAlphaGroupsSize;
+    mRiggedAlphaGroupsEnd = &mRiggedAlphaGroups[mRiggedAlphaGroupsSize];
+}
+
 void LLCullResult::pushOcclusionGroup(LLSpatialGroup* group)
 {
 	if (mOcclusionGroupsSize < mOcclusionGroupsAllocated)
diff --git a/indra/newview/llspatialpartition.h b/indra/newview/llspatialpartition.h
index 919f386d29b5095dd3fa1f4a34ffc8301a138e07..6d3ef338013d09bbdf5cbdc99e81d945a9ec759d 100644
--- a/indra/newview/llspatialpartition.h
+++ b/indra/newview/llspatialpartition.h
@@ -40,7 +40,10 @@
 #include "llface.h"
 #include "llviewercamera.h"
 #include "llvector4a.h"
+#include "llvoavatar.h"
+
 #include <queue>
+#include <unordered_map>
 
 #define SG_STATE_INHERIT_MASK (OCCLUDED)
 #define SG_INITIAL_STATE_MASK (DIRTY | GEOM_DIRTY)
@@ -49,20 +52,18 @@ class LLViewerOctreePartition;
 class LLSpatialPartition;
 class LLSpatialBridge;
 class LLSpatialGroup;
-class LLTextureAtlas;
-class LLTextureAtlasSlot;
 class LLViewerRegion;
 
 void pushVerts(LLFace* face, U32 mask);
 
-class LLDrawInfo : public LLRefCount, public LLTrace::MemTrackableNonVirtual<LLDrawInfo, 16>
+class LLDrawInfo : public LLRefCount
 {
+    LL_ALIGN_NEW;
 protected:
 	~LLDrawInfo();	
 	
 public:
 	LLDrawInfo(const LLDrawInfo& rhs)
-	:	LLTrace::MemTrackableNonVirtual<LLDrawInfo, 16>("LLDrawInfo")
 	{
 		*this = rhs;
 	}
@@ -81,12 +82,19 @@ class LLDrawInfo : public LLRefCount, public LLTrace::MemTrackableNonVirtual<LLD
 
 	void validate();
 
+    // return mSkinHash->mHash, or 0 if mSkinHash is null
+    U64 getSkinHash();
+
 	LLVector4a mExtents[2];
 	
 	LLPointer<LLVertexBuffer> mVertexBuffer;
 	LLPointer<LLViewerTexture>     mTexture;
 	std::vector<LLPointer<LLViewerTexture> > mTextureList;
 
+    // virtual size of mTexture and mTextureList textures
+    // used to update the decode priority of textures in this DrawInfo
+    std::vector<F32> mTextureListVSize;
+
 	S32 mDebugColor;
 	const LLMatrix4* mTextureMatrix;
 	const LLMatrix4* mModelMatrix;
@@ -119,6 +127,8 @@ class LLDrawInfo : public LLRefCount, public LLTrace::MemTrackableNonVirtual<LLD
 	F32  mAlphaMaskCutoff;
 	U8   mDiffuseAlphaMode;
 	bool mSelected;
+    LLPointer<LLVOAvatar> mAvatar = nullptr;
+    LLMeshSkinInfo* mSkinInfo = nullptr;
 
 
 	struct CompareTexture
@@ -216,10 +226,10 @@ class LLSpatialGroup : public LLOcclusionCullingGroup
 	typedef std::vector<LLPointer<LLSpatialGroup> > sg_vector_t;
 	typedef std::vector<LLPointer<LLSpatialBridge> > bridge_list_t;
 	typedef std::vector<LLPointer<LLDrawInfo> > drawmap_elem_t; 
-	typedef std::map<U32, drawmap_elem_t > draw_map_t;	
+	typedef std::unordered_map<U32, drawmap_elem_t > draw_map_t;	
 	typedef std::vector<LLPointer<LLVertexBuffer> > buffer_list_t;
-	typedef std::map<LLFace*, buffer_list_t> buffer_texture_map_t;
-	typedef std::map<U32, buffer_texture_map_t> buffer_map_t;
+	typedef std::unordered_map<LLFace*, buffer_list_t> buffer_texture_map_t;
+	typedef std::unordered_map<U32, buffer_texture_map_t> buffer_map_t;
 
 	struct CompareDistanceGreater
 	{
@@ -245,6 +255,19 @@ class LLSpatialGroup : public LLOcclusionCullingGroup
 		}
 	};
 
+    struct CompareRenderOrder
+    {
+        bool operator()(const LLSpatialGroup* const& lhs, const LLSpatialGroup* const& rhs)
+        {
+            if (lhs->mAvatarp != rhs->mAvatarp)
+            {
+                return lhs->mAvatarp < rhs->mAvatarp;
+            }
+
+            return lhs->mRenderOrder > rhs->mRenderOrder;
+        }
+    };
+
 	typedef enum
 	{
 		GEOM_DIRTY				= LLViewerOctreeGroup::INVALID_STATE,
@@ -298,49 +321,15 @@ class LLSpatialGroup : public LLOcclusionCullingGroup
 	virtual void handleDestruction(const TreeNode* node);
 	virtual void handleChildAddition(const OctreeNode* parent, OctreeNode* child);
 
-//-------------------
-//for atlas use
-//-------------------
-	//atlas	
-	void setCurUpdatingTime(U32 t) {mCurUpdatingTime = t ;}
-	U32  getCurUpdatingTime() const { return mCurUpdatingTime ;}
-	
-	void setCurUpdatingSlot(LLTextureAtlasSlot* slotp) ;
-	LLTextureAtlasSlot* getCurUpdatingSlot(LLViewerTexture* imagep, S8 recursive_level = 3) ;
-
-	void setCurUpdatingTexture(LLViewerTexture* tex){ mCurUpdatingTexture = tex ;}
-	LLViewerTexture* getCurUpdatingTexture() const { return mCurUpdatingTexture ;}
-	
-	BOOL hasAtlas(LLTextureAtlas* atlasp) ;
-	LLTextureAtlas* getAtlas(S8 ncomponents, S8 to_be_reserved, S8 recursive_level = 3) ;
-	void addAtlas(LLTextureAtlas* atlasp, S8 recursive_level = 3) ;
-	void removeAtlas(LLTextureAtlas* atlasp, BOOL remove_group = TRUE, S8 recursive_level = 3) ;
-	void clearAtlasList() ;
-
 public:
-
 	LL_ALIGN_16(LLVector4a mViewAngle);
 	LL_ALIGN_16(LLVector4a mLastUpdateViewAngle);
 
 	F32 mObjectBoxSize; //cached mObjectBounds[1].getLength3()
-		
-private:
-	U32                     mCurUpdatingTime ;
-	//do not make the below two to use LLPointer
-	//because mCurUpdatingTime invalidates them automatically.
-	LLTextureAtlasSlot* mCurUpdatingSlotp ;
-	LLViewerTexture*          mCurUpdatingTexture ;
-
-	std::vector< std::list<LLTextureAtlas*> > mAtlasList ; 
-//-------------------
-//end for atlas use
-//-------------------
 
 protected:
 	virtual ~LLSpatialGroup();
 
-	static S32 sLODSeed;
-
 public:
 	bridge_list_t mBridgeList;
 	buffer_map_t mBufferMap; //used by volume buffers to attempt to reuse vertex buffers
@@ -362,6 +351,10 @@ class LLSpatialGroup : public LLOcclusionCullingGroup
 	
 	F32 mPixelArea;
 	F32 mRadius;
+
+    //used by LLVOAVatar to set render order in alpha draw pool to preserve legacy render order behavior
+    LLVOAvatar* mAvatarp = nullptr;
+    U32 mRenderOrder = 0; 
 } LL_ALIGN_POSTFIX(64);
 
 class LLGeometryManager
@@ -465,8 +458,11 @@ class LLSpatialBridge : public LLDrawable, public LLSpatialPartition
 	virtual void cleanupReferences();
 	virtual LLSpatialPartition* asPartition()		{ return this; }
 		
+    //transform agent space camera into this Spatial Bridge's coordinate frame
 	virtual LLCamera transformCamera(LLCamera& camera);
-	
+
+    //transform agent space bounding box into this Spatial Bridge's coordinate frame
+    void transformExtents(const LLVector4a* src, LLVector4a* dst);
 	LLDrawable* mDrawable;
 };
 
@@ -493,6 +489,9 @@ class LLCullResult
 	sg_iterator beginAlphaGroups();
 	sg_iterator endAlphaGroups();
 
+    sg_iterator beginRiggedAlphaGroups();
+    sg_iterator endRiggedAlphaGroups();
+
 	bool hasOcclusionGroups() { return mOcclusionGroupsSize > 0; }
 	sg_iterator beginOcclusionGroups();
 	sg_iterator endOcclusionGroups();
@@ -511,6 +510,7 @@ class LLCullResult
 
 	void pushVisibleGroup(LLSpatialGroup* group);
 	void pushAlphaGroup(LLSpatialGroup* group);
+    void pushRiggedAlphaGroup(LLSpatialGroup* group);
 	void pushOcclusionGroup(LLSpatialGroup* group);
 	void pushDrawableGroup(LLSpatialGroup* group);
 	void pushDrawable(LLDrawable* drawable);
@@ -519,6 +519,7 @@ class LLCullResult
 	
 	U32 getVisibleGroupsSize()		{ return mVisibleGroupsSize; }
 	U32	getAlphaGroupsSize()		{ return mAlphaGroupsSize; }
+    U32	getRiggedAlphaGroupsSize() { return mRiggedAlphaGroupsSize; }
 	U32	getDrawableGroupsSize()		{ return mDrawableGroupsSize; }
 	U32	getVisibleListSize()		{ return mVisibleListSize; }
 	U32	getVisibleBridgeSize()		{ return mVisibleBridgeSize; }
@@ -532,6 +533,7 @@ class LLCullResult
 
 	U32					mVisibleGroupsSize;
 	U32					mAlphaGroupsSize;
+    U32                 mRiggedAlphaGroupsSize;
 	U32					mOcclusionGroupsSize;
 	U32					mDrawableGroupsSize;
 	U32					mVisibleListSize;
@@ -539,6 +541,7 @@ class LLCullResult
 
 	U32					mVisibleGroupsAllocated;
 	U32					mAlphaGroupsAllocated;
+    U32                 mRiggedAlphaGroupsAllocated;
 	U32					mOcclusionGroupsAllocated;
 	U32					mDrawableGroupsAllocated;
 	U32					mVisibleListAllocated;
@@ -550,6 +553,8 @@ class LLCullResult
 	sg_iterator			mVisibleGroupsEnd;
 	sg_list_t			mAlphaGroups;
 	sg_iterator			mAlphaGroupsEnd;
+    sg_list_t           mRiggedAlphaGroups;
+    sg_iterator         mRiggedAlphaGroupsEnd;
 	sg_list_t			mOcclusionGroups;
 	sg_iterator			mOcclusionGroupsEnd;
 	sg_list_t			mDrawableGroups;
@@ -646,7 +651,8 @@ class LLVolumeGeometryManager: public LLGeometryManager
 	virtual void rebuildGeom(LLSpatialGroup* group);
 	virtual void rebuildMesh(LLSpatialGroup* group);
 	virtual void getGeometry(LLSpatialGroup* group);
-	U32 genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace** faces, U32 face_count, BOOL distance_sort = FALSE, BOOL batch_textures = FALSE, BOOL no_materials = FALSE);
+    virtual void addGeometryCount(LLSpatialGroup* group, U32& vertex_count, U32& index_count);
+	U32 genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace** faces, U32 face_count, BOOL distance_sort = FALSE, BOOL batch_textures = FALSE, BOOL rigged = FALSE);
 	void registerFace(LLSpatialGroup* group, LLFace* facep, U32 type);
 
 private:
@@ -654,13 +660,13 @@ class LLVolumeGeometryManager: public LLGeometryManager
 	void freeFaces();
 
 	static int32_t sInstanceCount;
-	static LLFace** sFullbrightFaces;
-	static LLFace** sBumpFaces;
-	static LLFace** sSimpleFaces;
-	static LLFace** sNormFaces;
-	static LLFace** sSpecFaces;
-	static LLFace** sNormSpecFaces;
-	static LLFace** sAlphaFaces;
+	static LLFace** sFullbrightFaces[2];
+	static LLFace** sBumpFaces[2];
+	static LLFace** sSimpleFaces[2];
+	static LLFace** sNormFaces[2];
+	static LLFace** sSpecFaces[2];
+	static LLFace** sNormSpecFaces[2];
+	static LLFace** sAlphaFaces[2];
 };
 
 //spatial partition that uses volume geometry manager (implemented in LLVOVolume.cpp)
diff --git a/indra/newview/llspeakers.cpp b/indra/newview/llspeakers.cpp
index abb936c3e5bea91f7440d61964483a3cd4ed55ea..ea671a130e1c41d6b3c2d2a6b31bc6cb12a25348 100644
--- a/indra/newview/llspeakers.cpp
+++ b/indra/newview/llspeakers.cpp
@@ -534,7 +534,7 @@ void LLSpeakerMgr::updateSpeakerList()
 			}
 			else if (mSpeakers.size() == 0)
 			{
-				// For all other session type (ad-hoc, P2P, avaline), we use the initial participants targets list
+				// For all other session type (ad-hoc, P2P), we use the initial participants targets list
 				for (uuid_vec_t::iterator it = session->mInitialTargetIDs.begin();it!=session->mInitialTargetIDs.end();++it)
 				{
 					// Add buddies if they are on line, add any other avatar.
diff --git a/indra/newview/llspeakers.h b/indra/newview/llspeakers.h
index d1dbf72fe9e9c363fbfe79c595c3d0118446e7d9..ed795b515586ea1b41cc34d02afe412bcc61b3f0 100644
--- a/indra/newview/llspeakers.h
+++ b/indra/newview/llspeakers.h
@@ -244,14 +244,6 @@ class LLSpeakerMgr : public LLOldEvents::LLObservable
 	const LLUUID getSessionID();
 	bool isSpeakerToBeRemoved(const LLUUID& speaker_id);
 
-	/**
-	 * Removes avaline speaker.
-	 *
-	 * This is a HACK due to server does not send information that Avaline caller ends call.
-	 * It can be removed when server is updated. See EXT-4301 for details
-	 */
-	bool removeAvalineSpeaker(const LLUUID& speaker_id) { return removeSpeaker(speaker_id); }
-
 	/**
 	 * Initializes mVoiceModerated depend on LLSpeaker::mModeratorMutedVoice of agent's participant.
 	 *
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index 79ef0c075ecce691a424c42ad85a44d1ea9f9430..054e9530d445ec116614d3326e5efbc5f02a8dc3 100644
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -35,6 +35,7 @@
 #else
 #	include <sys/stat.h>		// mkdir()
 #endif
+#include <memory>                   // std::unique_ptr
 
 #include "llviewermedia_streamingaudio.h"
 #include "llaudioengine.h"
@@ -96,6 +97,7 @@
 #include "llfloateravatarpicker.h"
 #include "llcallbacklist.h"
 #include "llcallingcard.h"
+#include "llclassifiedinfo.h"
 #include "llconsole.h"
 #include "llcontainerview.h"
 #include "llconversationlog.h"
@@ -123,8 +125,6 @@
 #include "llpanellogin.h"
 #include "llmutelist.h"
 #include "llavatarpropertiesprocessor.h"
-#include "llpanelclassified.h"
-#include "llpanelpick.h"
 #include "llpanelgrouplandmoney.h"
 #include "llpanelgroupnotices.h"
 #include "llparcel.h"
@@ -133,6 +133,7 @@
 #include "llproxy.h"
 #include "llproductinforequest.h"
 #include "llqueryflags.h"
+#include "llsecapi.h"
 #include "llselectmgr.h"
 #include "llsky.h"
 #include "llstatview.h"
@@ -178,7 +179,6 @@
 #include "pipeline.h"
 #include "llappviewer.h"
 #include "llfasttimerview.h"
-#include "lltelemetry.h"
 #include "llfloatermap.h"
 #include "llweb.h"
 #include "llvoiceclient.h"
@@ -193,6 +193,7 @@
 #include "llavatariconctrl.h"
 #include "llvoicechannel.h"
 #include "llpathfindingmanager.h"
+#include "llremoteparcelrequest.h"
 
 #include "lllogin.h"
 #include "llevents.h"
@@ -205,6 +206,9 @@
 
 #include "llstacktrace.h"
 
+#include "threadpool.h"
+
+
 #if LL_WINDOWS
 #include "lldxhardware.h"
 #endif
@@ -251,10 +255,11 @@ static bool mLoginStatePastUI = false;
 static bool mBenefitsSuccessfullyInit = false;
 
 const F32 STATE_AGENT_WAIT_TIMEOUT = 240; //seconds
+const S32 MAX_SEED_CAP_ATTEMPTS_BEFORE_LOGIN = 3; // Give region 3 chances
 
-boost::scoped_ptr<LLEventPump> LLStartUp::sStateWatcher(new LLEventStream("StartupState"));
-boost::scoped_ptr<LLStartupListener> LLStartUp::sListener(new LLStartupListener());
-boost::scoped_ptr<LLViewerStats::PhaseMap> LLStartUp::sPhases(new LLViewerStats::PhaseMap);
+std::unique_ptr<LLEventPump> LLStartUp::sStateWatcher(new LLEventStream("StartupState"));
+std::unique_ptr<LLStartupListener> LLStartUp::sListener(new LLStartupListener());
+std::unique_ptr<LLViewerStats::PhaseMap> LLStartUp::sPhases(new LLViewerStats::PhaseMap);
 
 //
 // local function declaration
@@ -307,6 +312,12 @@ void update_texture_fetch()
 	LLAppViewer::getImageDecodeThread()->update(1); // unpauses the image thread
 	LLAppViewer::getTextureFetch()->update(1); // unpauses the texture fetch thread
 	gTextureList.updateImages(0.10f);
+
+    if (LLImageGLThread::sEnabled)
+    {
+        std::shared_ptr<LL::WorkQueue> main_queue = LL::WorkQueue::getInstance("mainloop");
+        main_queue->runFor(std::chrono::milliseconds(1));
+    }
 }
 
 void set_flags_and_update_appearance()
@@ -529,8 +540,6 @@ bool idle_startup()
 			}
 
 			#if LL_WINDOWS
-                LLPROFILE_STARTUP();
-
 				// On the windows dev builds, unpackaged, the message.xml file will 
 				// be located in indra/build-vc**/newview/<config>/app_settings.
 				std::string message_path = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,"message.xml");
@@ -653,7 +662,7 @@ bool idle_startup()
 #else
 				void* window_handle = NULL;
 #endif
-				bool init = gAudiop->init(kAUDIO_NUM_SOURCES, window_handle, LLAppViewer::instance()->getSecondLifeTitle());
+				bool init = gAudiop->init(window_handle, LLAppViewer::instance()->getSecondLifeTitle());
 				if(init)
 				{
 					gAudiop->setMuted(TRUE);
@@ -919,6 +928,12 @@ bool idle_startup()
 			LLPersistentNotificationStorage::initParamSingleton();
 			LLDoNotDisturbNotificationStorage::initParamSingleton();
 		}
+        else
+        {
+            // reinitialize paths in case user switched grids or accounts
+            LLPersistentNotificationStorage::getInstance()->reset();
+            LLDoNotDisturbNotificationStorage::getInstance()->reset();
+        }
 
 		// Set PerAccountSettingsFile to the default value.
 		std::string settings_per_account = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, LLAppViewer::instance()->getSettingsFilename("Default", "PerAccount"));
@@ -1054,7 +1069,7 @@ bool idle_startup()
 	{
 		// Generic failure message
 		std::ostringstream emsg;
-		emsg << LLTrans::getString("LoginFailed") << "\n";
+		emsg << LLTrans::getString("LoginFailedHeader") << "\n";
 		if(LLLoginInstance::getInstance()->authFailure())
 		{
 			LL_INFOS("LLStartup") << "Login failed, LLLoginInstance::getResponse(): "
@@ -1067,11 +1082,37 @@ bool idle_startup()
 			std::string message_id = response["message_id"];
 			std::string message; // actual string to show the user
 
-			if(!message_id.empty() && LLTrans::findString(message, message_id, response["message_args"]))
-			{
-				// message will be filled in with the template and arguments
-			}
-			else if(!message_response.empty())
+            bool localized_by_id = false;
+            if(!message_id.empty())
+            {
+                LLSD message_args = response["message_args"];
+                if (message_args.has("TIME")
+                    && (message_id == "LoginFailedAcountSuspended"
+                        || message_id == "LoginFailedAccountMaintenance"))
+                {
+                    LLDate date;
+                    std::string time_string;
+                    if (date.fromString(message_args["TIME"].asString()))
+                    {
+                        LLSD args;
+                        args["datetime"] = (S32)date.secondsSinceEpoch();
+                        LLTrans::findString(time_string, "LocalTime", args);
+                    }
+                    else
+                    {
+                        time_string = message_args["TIME"].asString() + " " + LLTrans::getString("PacificTime");
+                    }
+
+                    message_args["TIME"] = time_string;
+                }
+                // message will be filled in with the template and arguments
+                if (LLTrans::findString(message, message_id, message_args))
+                {
+                    localized_by_id = true;
+                }
+            }
+
+            if(!localized_by_id && !message_response.empty())
 			{
 				// *HACK: "no_inventory_host" sent as the message itself.
 				// Remove this clause when server is sending message_id as well.
@@ -1109,10 +1150,10 @@ bool idle_startup()
 			}
 			else 
 			{
-				if (reason_response != "tos") 
+				if (reason_response != "tos"  && reason_response != "mfa_challenge")
 				{
-					// Don't pop up a notification in the TOS case because
-					// LLFloaterTOS::onCancel() already scolded the user.
+					// Don't pop up a notification in the TOS or MFA cases because
+					// the specialized floater has already scolded the user.
 					std::string error_code;
 					if(response.has("errorcode"))
 					{
@@ -1354,10 +1395,21 @@ bool idle_startup()
 		{
 			LLStartUp::setStartupState( STATE_SEED_CAP_GRANTED );
 		}
+        else if (regionp->capabilitiesError())
+        {
+            // Try to connect despite capabilities' error state
+            LLStartUp::setStartupState(STATE_SEED_CAP_GRANTED);
+        }
 		else
 		{
 			U32 num_retries = regionp->getNumSeedCapRetries();
-			if (num_retries > 0)
+            if (num_retries > MAX_SEED_CAP_ATTEMPTS_BEFORE_LOGIN)
+            {
+                // Region will keep trying to get capabilities,
+                // but for now continue as if caps were granted
+                LLStartUp::setStartupState(STATE_SEED_CAP_GRANTED);
+            }
+			else if (num_retries > 0)
 			{
 				LLStringUtil::format_map_t args;
 				args["[NUMBER]"] = llformat("%d", num_retries + 1);
@@ -1488,6 +1540,9 @@ bool idle_startup()
 		gAgentCamera.resetCamera();
 		display_startup();
 
+		// start up the ThreadPool we'll use for textures et al.
+        LLAppViewer::instance()->initGeneralThread();
+
 		// Initialize global class data needed for surfaces (i.e. textures)
 		LL_DEBUGS("AppInit") << "Initializing sky..." << LL_ENDL;
 		// Initialize all of the viewer object classes for the first time (doing things like texture fetches.
@@ -1502,7 +1557,11 @@ bool idle_startup()
 		display_startup();
 
 		LL_DEBUGS("AppInit") << "Decoding images..." << LL_ENDL;
-		// For all images pre-loaded into viewer cache, decode them.
+		// For all images pre-loaded into viewer cache, init
+        // priorities and fetching using decodeAllImages.
+        // Most of the fetching and decoding likely to be done
+        // by update_texture_fetch() later, while viewer waits.
+        //
 		// Need to do this AFTER we init the sky
 		const S32 DECODE_TIME_SEC = 2;
 		for (int i = 0; i < DECODE_TIME_SEC; i++)
@@ -2222,10 +2281,6 @@ bool idle_startup()
 
 		// Have the agent start watching the friends list so we can update proxies
 		gAgent.observeFriends();
-		if (gSavedSettings.getBOOL("LoginAsGod"))
-		{
-			gAgent.requestEnterGodMode();
-		}
 		
 		// Start automatic replay if the flag is set.
 		if (gSavedSettings.getBOOL("StatsAutoRun") || gAgentPilot.getReplaySession())
@@ -2348,13 +2403,41 @@ void login_callback(S32 option, void *userdata)
 void show_release_notes_if_required()
 {
     static bool release_notes_shown = false;
+    // We happen to know that instantiating LLVersionInfo implicitly
+    // instantiates the LLEventMailDrop named "relnotes", which we (might) use
+    // below. If viewer release notes stop working, might be because that
+    // LLEventMailDrop got moved out of LLVersionInfo and hasn't yet been
+    // instantiated.
     if (!release_notes_shown && (LLVersionInfo::instance().getChannelAndVersion() != gLastRunVersion)
         && LLVersionInfo::instance().getViewerMaturity() != LLVersionInfo::TEST_VIEWER // don't show Release Notes for the test builds
         && gSavedSettings.getBOOL("UpdaterShowReleaseNotes")
         && !gSavedSettings.getBOOL("FirstLoginThisInstall"))
     {
-        LLSD info(LLAppViewer::instance()->getViewerInfo());
-        LLWeb::loadURLInternal(info["VIEWER_RELEASE_NOTES_URL"]);
+
+#if LL_RELEASE_FOR_DOWNLOAD
+        if (!gSavedSettings.getBOOL("CmdLineSkipUpdater")
+            && !LLAppViewer::instance()->isUpdaterMissing())
+        {
+            // Instantiate a "relnotes" listener which assumes any arriving event
+            // is the release notes URL string. Since "relnotes" is an
+            // LLEventMailDrop, this listener will be invoked whether or not the
+            // URL has already been posted. If so, it will fire immediately;
+            // otherwise it will fire whenever the URL is (later) posted. Either
+            // way, it will display the release notes as soon as the URL becomes
+            // available.
+            LLEventPumps::instance().obtain("relnotes").listen(
+                "showrelnotes",
+                [](const LLSD& url) {
+                LLWeb::loadURLInternal(url.asString());
+                return false;
+            });
+        }
+        else
+#endif // LL_RELEASE_FOR_DOWNLOAD
+        {
+            LLSD info(LLAppViewer::instance()->getViewerInfo());
+            LLWeb::loadURLInternal(info["VIEWER_RELEASE_NOTES_URL"]);
+        }
         release_notes_shown = true;
     }
 }
@@ -2592,7 +2675,6 @@ void register_viewer_callbacks(LLMessageSystem* msg)
 	msg->setHandlerFunc("EventInfoReply", LLEventNotifier::processEventInfoReply);
 	
 	msg->setHandlerFunc("PickInfoReply", &LLAvatarPropertiesProcessor::processPickInfoReply);
-//	msg->setHandlerFunc("ClassifiedInfoReply", LLPanelClassified::processClassifiedInfoReply);
 	msg->setHandlerFunc("ClassifiedInfoReply", LLAvatarPropertiesProcessor::processClassifiedInfoReply);
 	msg->setHandlerFunc("ParcelInfoReply", LLRemoteParcelInfoProcessor::processParcelInfoReply);
 	msg->setHandlerFunc("ScriptDialog", process_script_dialog);
@@ -2706,19 +2788,34 @@ void LLStartUp::loadInitialOutfit( const std::string& outfit_folder_name,
 
 	gAgentAvatarp->setSex(gender);
 
-	// try to find the outfit - if not there, create some default
-	// wearables.
+	// try to find the requested outfit or folder
+
+	// -- check for existing outfit in My Outfits
+	bool do_copy = false;
 	LLUUID cat_id = findDescendentCategoryIDByName(
-		gInventory.getLibraryRootFolderID(),
+		gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS),
 		outfit_folder_name);
+
+	// -- check for existing folder in Library
+	if (cat_id.isNull())
+	{
+		cat_id = findDescendentCategoryIDByName(
+			gInventory.getLibraryRootFolderID(),
+			outfit_folder_name);
+		if (!cat_id.isNull())
+		{
+			do_copy = true;
+		}
+	}
+
 	if (cat_id.isNull())
 	{
+		// -- final fallback: create standard wearables
 		LL_DEBUGS() << "standard wearables" << LL_ENDL;
 		gAgentWearables.createStandardWearables();
 	}
 	else
 	{
-		bool do_copy = true;
 		bool do_append = false;
 		LLViewerInventoryCategory *cat = gInventory.getCategory(cat_id);
 		// Need to fetch cof contents before we can wear.
@@ -2816,7 +2913,7 @@ void reset_login()
 	gAgentWearables.cleanup();
 	gAgentCamera.cleanup();
 	gAgent.cleanup();
-	LLWorld::getInstance()->destroyClass();
+	LLWorld::getInstance()->resetClass();
 
 	if ( gViewerWindow )
 	{	// Hide menus and normal buttons
@@ -3284,12 +3381,6 @@ bool init_benefits(LLSD& response)
 		succ = false;
 	}
 
-	// FIXME PREMIUM - for testing if login does not yet provide Premium Plus. Should be removed thereafter.
-	//if (succ && !LLAgentBenefitsMgr::has("Premium Plus"))
-	//{
-	//	LLAgentBenefitsMgr::init("Premium Plus", packages_sd["Premium"]["benefits"]);
-	//	llassert(LLAgentBenefitsMgr::has("Premium Plus"));
-	//}
 	return succ;
 }
 
@@ -3593,6 +3684,19 @@ bool process_login_success_response()
 		}
 	}
 
+	std::string fake_initial_outfit_name = gSavedSettings.getString("FakeInitialOutfitName");
+	if (!fake_initial_outfit_name.empty())
+	{
+		gAgent.setFirstLogin(TRUE);
+		sInitialOutfit = fake_initial_outfit_name;
+		if (sInitialOutfitGender.empty())
+		{
+			sInitialOutfitGender = "female"; // just guess, will get overridden when outfit is worn anyway.
+		}
+
+		LL_WARNS() << "Faking first-time login with initial outfit " << sInitialOutfit << LL_ENDL;
+	}
+
 	// set the location of the Agent Appearance service, from which we can request
 	// avatar baked textures if they are supported by the current region
 	std::string agent_appearance_url = response["agent_appearance_service"];
@@ -3616,6 +3720,17 @@ bool process_login_success_response()
 		LLViewerMedia::getInstance()->openIDSetup(openid_url, openid_token);
 	}
 
+
+	// Only save mfa_hash for future logins if the user wants their info remembered.
+	if(response.has("mfa_hash") && gSavedSettings.getBOOL("RememberUser") && gSavedSettings.getBOOL("RememberPassword"))
+	{
+		std::string grid(LLGridManager::getInstance()->getGridId());
+		std::string user_id(gUserCredential->userID());
+		gSecAPIHandler->addToProtectedMap("mfa_hash", grid, user_id, response["mfa_hash"]);
+		// TODO(brad) - related to SL-17223 consider building a better interface that sync's automatically
+		gSecAPIHandler->syncProtectedMap();
+	}
+
 	bool success = false;
 	// JC: gesture loading done below, when we have an asset system
 	// in place.  Don't delete/clear gUserCredentials until then.
diff --git a/indra/newview/llstartup.h b/indra/newview/llstartup.h
index 116aeb36a735ce1984080ec452a022e444f2b8d4..fe8e215f76a1677dba7e09148eff65ab72f89efd 100644
--- a/indra/newview/llstartup.h
+++ b/indra/newview/llstartup.h
@@ -27,7 +27,7 @@
 #ifndef LL_LLSTARTUP_H
 #define LL_LLSTARTUP_H
 
-#include <boost/scoped_ptr.hpp>
+#include <memory>                   // unique_ptr
 
 class LLViewerTexture ;
 class LLEventPump;
@@ -130,9 +130,9 @@ class LLStartUp
 
 	static std::string startupStateToString(EStartupState state);
 	static EStartupState gStartupState; // Do not set directly, use LLStartup::setStartupState
-	static boost::scoped_ptr<LLEventPump> sStateWatcher;
-	static boost::scoped_ptr<LLStartupListener> sListener;
-	static boost::scoped_ptr<LLViewerStats::PhaseMap> sPhases;
+	static std::unique_ptr<LLEventPump> sStateWatcher;
+	static std::unique_ptr<LLStartupListener> sListener;
+	static std::unique_ptr<LLViewerStats::PhaseMap> sPhases;
 };
 
 
diff --git a/indra/newview/llsurface.cpp b/indra/newview/llsurface.cpp
index cb356726e6aa4ea3c61f58a28966ee4e980b04a4..ea36e1d7be0e327c5a555671cb63e410473f9cdf 100644
--- a/indra/newview/llsurface.cpp
+++ b/indra/newview/llsurface.cpp
@@ -1214,6 +1214,7 @@ F32 LLSurface::getWaterHeight() const
 BOOL LLSurface::generateWaterTexture(const F32 x, const F32 y,
 									 const F32 width, const F32 height)
 {
+	LL_PROFILE_ZONE_SCOPED
 	if (!getWaterTexture())
 	{
 		return FALSE;
diff --git a/indra/newview/llsurfacepatch.cpp b/indra/newview/llsurfacepatch.cpp
index 5e056944e995252bb94dd0b7331cfe92ac4dce06..aeefcd6fb829d7e2fa08ed604ad45578d970d33a 100644
--- a/indra/newview/llsurfacepatch.cpp
+++ b/indra/newview/llsurfacepatch.cpp
@@ -728,6 +728,7 @@ BOOL LLSurfacePatch::updateTexture()
 
 void LLSurfacePatch::updateGL()
 {
+	LL_PROFILE_ZONE_SCOPED
 	F32 meters_per_grid = getSurface()->getMetersPerGrid();
 	F32 grids_per_patch_edge = (F32)getSurface()->getGridsPerPatchEdge();
 
diff --git a/indra/newview/lltelemetry.cpp b/indra/newview/lltelemetry.cpp
deleted file mode 100644
index 0c63e2fede5d45b4b56949d9399d812a98c166f4..0000000000000000000000000000000000000000
--- a/indra/newview/lltelemetry.cpp
+++ /dev/null
@@ -1,145 +0,0 @@
- /**
- * @file lltelemetry.cpp
- * @brief Wrapper for Rad Game Tools Telemetry
- *
- * $LicenseInfo:firstyear=2020&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2020, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
- * $/LicenseInfo$
- */
-
-#include "llviewerprecompiledheaders.h"
-
-#include "lltelemetry.h"
-
-#if LLPROFILE_USE_RAD_TELEMETRY_PROFILER
-    #if LL_WINDOWS
-        #include "llwin32headers.h"
-
-        // build-vc120-64\packages\lib\release
-        // build-vc150-64\packages\lib\release
-        #ifdef _MSC_VER
-            #pragma comment(lib,"rad_tm_win64.lib")
-        #else
-            #pragma message "NOTE: Rad GameTools Telemetry requested but non-MSVC compiler not yet supported on Windows"
-        #endif
-    #endif // LL_WINDOWS
-
-    #if LL_DARWIN
-        #pragma message "NOTE: Rad Game Tools Telemetry requested but not yet supported on Darwin"
-    #endif
-
-    #if LL_LINUX
-        #pragma message "NOTE: Rad Game Tools Telemetry requested but not yet supported on Linux"
-    #endif
-
-//
-// local consts
-//
-static const tm_int32 TELEMETRY_BUFFER_SIZE  = 8 * 1024 * 1024;
-
-//
-// local globals
-//
-static char *gTelemetryBufferPtr = NULL; // Telemetry
-
-static const char *tm_status[ TMERR_INIT_NETWORKING_FAILED + 1 ] =
-{
-      "Telemetry pass: connected"                       // TM_OK
-    , "Telemetry FAIL: disabled via #define NTELEMETRY" // TMERR_DISABLED
-    , "Telemetry FAIL: invalid paramater"               // TMERR_INVALID_PARAM
-    , "Telemetry FAIL: DLL not found"                   // TMERR_NULL_API
-    , "Telemetry FAIL: out of resources"                // TMERR_OUT_OF_RESOURCES
-    , "Telemetry FAIL: tmInitialize() not called"       // TMERR_UNINITIALIZED
-    , "Telemetry FAIL: bad hostname"                    // TMERR_BAD_HOSTNAME
-    , "Telemetry FAIL: couldn't connect to server"      // TMERR_COULD_NOT_CONNECT
-    , "Telemetry FAIL: unknown network error"           // TMERR_UNKNOWN_NETWORK
-    , "Telemetry FAIL: tmShutdown() already called"     // TMERR_ALREADY_SHUTDOWN
-    , "Telemetry FAIL: memory buffer too small"         // TMERR_ARENA_TOO_SMALL
-    , "Telemetry FAIL: server handshake error"          // TMERR_BAD_HANDSHAKE
-    , "Telemetry FAIL: unaligned parameters"            // TMERR_UNALIGNED
-    , "Telemetry FAIL: network not initialized"         // TMERR_NETWORK_NOT_INITIALIZED -- WSAStartup not called before tmOpen()
-    , "Telemetry FAIL: bad version"                     // TMERR_BAD_VERSION
-    , "Telemetry FAIL: timer too large"                 // TMERR_BAD_TIMER
-    , "Telemetry FAIL: tmOpen() already called"         // TMERR_ALREADY_OPENED
-    , "Telemetry FAIL: tmInitialize() already called"   // TMERR_ALREADY_INITIALIZED
-    , "Telemetry FAIL: could't open file"               // TMERR_FILE_OPEN_FAILED
-    , "Telemetry FAIL: tmOpen() failed networking"      // TMERR_INIT_NETWORKING_FAILED
-};
-
-//
-// exported functionality
-//
-
-void telemetry_shutdown()
-{
-    #if LL_WINDOWS
-        if (gTelemetryBufferPtr)
-        {
-            tmClose(0);
-            tmShutdown();
-
-            delete[] gTelemetryBufferPtr;
-            gTelemetryBufferPtr = NULL;
-        }
-    #endif
-}
-
-void telemetry_startup()
-{
-    #if LL_WINDOWS
-        tmLoadLibrary(TM_RELEASE); // Loads .dll
-
-        gTelemetryBufferPtr = new char[ TELEMETRY_BUFFER_SIZE ];
-        tmInitialize(TELEMETRY_BUFFER_SIZE, gTelemetryBufferPtr);
-
-        tm_error telemetry_status = tmOpen(
-            0,                     // unused
-            "SecondLife",          // app name
-            __DATE__ " " __TIME__, // build identifier
-            "localhost",           // server name (or filename)
-            TMCT_TCP,              // connection type (or TMCT_FILE)
-            4719,                  // port
-            TMOF_INIT_NETWORKING,  // open flags
-            250 );                 // timeout ms
-
-        if (telemetry_status == TMERR_UNKNOWN)
-        {
-            LL_ERRS() << "Telemetry FAIL: unknown error" << LL_ENDL;
-        }
-        else if (telemetry_status && (telemetry_status <= TMERR_INIT_NETWORKING_FAILED))
-        {
-            LL_INFOS() << tm_status[ telemetry_status ] << LL_ENDL;
-            free(gTelemetryBufferPtr);
-            gTelemetryBufferPtr = NULL;
-        }
-    #endif // LL_WINDOWS
-}
-
-// Called after we render a frame
-void telemetry_update()
-{
-    #if LL_WINDOWS
-        if (gTelemetryBufferPtr)
-        {
-            tmTick(0);
-        }
-    #endif
-}
-#endif // LLPROFILE_USE_RAD_TELEMETRY_PROFILER
diff --git a/indra/newview/lltelemetry.h b/indra/newview/lltelemetry.h
deleted file mode 100644
index a73e5fcfa27aef28cdd4ad71f6a273885bbba7b1..0000000000000000000000000000000000000000
--- a/indra/newview/lltelemetry.h
+++ /dev/null
@@ -1,81 +0,0 @@
-/**
- * @file lltelemetry.h
- * @brief Wrapper for Rad Game Tools Telemetry
- *
- * $LicenseInfo:firstyear=2020&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2020, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
- * $/LicenseInfo$
- */
-
-/*
-To use:
-
-1. Uncomment #define LLPROFILE_USE_RAD_TELEMETRY_PROFILER below
-
-2. Include this header file
-    #include "lltelemetry.h"
-
-3. Add zones to the functions you wish to profile
-    void onFoo()
-    {
-        LLPROFILE_ZONE("Foo");
-    }
-*/
-//#define LLPROFILE_USE_RAD_TELEMETRY_PROFILER 1
-
-// Default NO local telemetry profiling
-#ifndef LLPROFILE_USE_RAD_TELEMETRY_PROFILER
-    #define LLPROFILE_USE_RAD_TELEMETRY_PROFILER 0
-    #define LLPROFILE_SHUTDOWN( ...) {}
-    #define LLPROFILE_STARTUP(  ...) {}
-    #define LLPROFILE_UPDATE(   ...) {}
-
-    #define LLPROFILE_AUTO_CPU_MARKER_COLOR(r, g, b)
-    #define LLPROFILE_ENTER(name)
-    #define LLPROFILE_ENTER_FORMAT(format, ...)
-    #define LLPROFILE_FUNCTION
-    #define LLPROFILE_LEAVE()
-    #define LLPROFILE_THREAD_NAME(name)
-    #define LLPROFILE_ZONE(name)
-    #define LLPROFILE_ZONE_FORMAT(format, ...)
-#else
-    #include <rad_tm.h>
-
-    #define LLPROFILE_SHUTDOWN                       telemetry_shutdown
-    #define LLPROFILE_STARTUP                        telemetry_startup
-    #define LLPROFILE_UPDATE                         telemetry_update
-
-    #define LLPROFILE_AUTO_CPU_MARKER_COLOR(r, g, b) tmZoneColor(r, g, b)
-    #define LLPROFILE_ENTER(name)                    tmEnter(0, 0, name)
-    #define LLPROFILE_ENTER_FORMAT(format, ...)      tmEnter(0, 0, format, __VA_ARGS__)
-    #define LLPROFILE_FUNCTION                       tmFunction(0, 0)
-    #define LLPROFILE_LEAVE()                        tmLeave(0)
-    #define LLPROFILE_THREAD_NAME(name)              tmThreadName(0, 0, name)
-    #define LLPROFILE_ZONE(name)                     tmZone(0, 0, name)
-    #define LLPROFILE_ZONE_FORMAT(format, ...)       tmZone(0, 0, format, __VA_ARGS__)
-#endif // LLPROFILE_USE_RAD_TELEMETRY_PROFILER
-
-//
-// exported functionality
-//
-
-extern void telemetry_startup();
-extern void telemetry_shutdown();
-extern void telemetry_update(); // called after every frame update
diff --git a/indra/newview/llteleporthistory.cpp b/indra/newview/llteleporthistory.cpp
index 3c3c1c96ef99a7c285101803a77820cb66280ad8..3ece12931c6ffe365aa3b3c12ed76f0f8cb5e521 100644
--- a/indra/newview/llteleporthistory.cpp
+++ b/indra/newview/llteleporthistory.cpp
@@ -39,6 +39,11 @@
 #include "llviewerregion.h"
 #include "llworldmap.h"
 #include "llagentui.h"
+#include "llwindow.h"
+#include "llviewerwindow.h"
+#include "llavatarname.h"
+#include "llavatarnamecache.h"
+
 
 //////////////////////////////////////////////////////////////////////////////
 // LLTeleportHistoryItem
@@ -113,6 +118,20 @@ void LLTeleportHistory::handleLoginComplete()
 	updateCurrentLocation(gAgent.getPositionGlobal());
 }
 
+static void on_avatar_name_update_title(const LLAvatarName& av_name)
+{
+	if (gAgent.getRegion() && gViewerWindow && gViewerWindow->getWindow())
+	{
+		std::string region = gAgent.getRegion()->getName();
+		std::string username = av_name.getUserName();
+
+		// this first pass simply displays username and region name
+		// but could easily be extended to include other details like
+		// X/Y/Z location within a region etc.
+		std::string new_title = STRINGIZE(username << " @ " << region);
+		gViewerWindow->getWindow()->setTitle(new_title);
+	}	
+}
 
 void LLTeleportHistory::updateCurrentLocation(const LLVector3d& new_pos)
 {
@@ -174,6 +193,14 @@ void LLTeleportHistory::updateCurrentLocation(const LLVector3d& new_pos)
 	if (!mGotInitialUpdate)
 		mGotInitialUpdate = true;
 
+    // update Viewer window title with username and region name
+    // if we are in "non-interactive mode" (SL-15999) or the debug 
+    // setting to allow it is enabled (may be useful in other situations)
+    if (gNonInteractive || gSavedSettings.getBOOL("UpdateAppWindowTitleBar"))
+    {
+		LLAvatarNameCache::get(gAgent.getID(), boost::bind(&on_avatar_name_update_title, _2));
+    }
+
 	// Signal the interesting party that we've changed. 
 	onHistoryChanged();
 }
diff --git a/indra/newview/lltextureatlas.cpp b/indra/newview/lltextureatlas.cpp
deleted file mode 100644
index 1c8e4f796e0548226e420ebdf02b50542c781d43..0000000000000000000000000000000000000000
--- a/indra/newview/lltextureatlas.cpp
+++ /dev/null
@@ -1,416 +0,0 @@
-/** 
- * @file lltextureatlas.cpp
- * @brief LLTextureAtlas class implementation.
- *
- * $LicenseInfo:firstyear=2002&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- * 
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- * 
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
- * $/LicenseInfo$
- */
-#include "llviewerprecompiledheaders.h"
-#include "linden_common.h"
-#include "llerror.h"
-#include "llimage.h"
-#include "llmath.h"
-#include "llgl.h"
-#include "llrender.h"
-#include "lltextureatlas.h"
-
-//-------------------
-S16 LLTextureAtlas::sMaxSubTextureSize = 64 ;
-S16 LLTextureAtlas::sSlotSize = 32 ;
-
-#ifndef DEBUG_ATLAS
-#define DEBUG_ATLAS 0
-#endif
-
-#ifndef DEBUG_USAGE_BITS
-#define DEBUG_USAGE_BITS 0
-#endif
-//**************************************************************************************************************
-LLTextureAtlas::LLTextureAtlas(U8 ncomponents, S16 atlas_dim) : 
-    LLViewerTexture(atlas_dim * sSlotSize, atlas_dim * sSlotSize, ncomponents, TRUE),
-	mAtlasDim(atlas_dim),
-	mNumSlotsReserved(0),
-	mMaxSlotsInAtlas(atlas_dim * atlas_dim)
-{
-	generateEmptyUsageBits() ;
-
-	//generate an empty texture
-	generateGLTexture() ;
-	LLPointer<LLImageRaw> image_raw = new LLImageRaw(mFullWidth, mFullHeight, mComponents);
-	createGLTexture(0, image_raw, 0);
-	image_raw = NULL;
-}
-
-LLTextureAtlas::~LLTextureAtlas() 
-{
-	if(mSpatialGroupList.size() > 0)
-	{
-		LL_ERRS() << "Not clean up the spatial groups!" << LL_ENDL ;
-	}
-	releaseUsageBits() ;
-}
-
-//virtual 
-S8 LLTextureAtlas::getType() const
-{
-	return 0; //LLViewerTexture::ATLAS_TEXTURE ;
-}
-
-void LLTextureAtlas::getTexCoordOffset(S16 col, S16 row, F32& xoffset, F32& yoffset)
-{
-	xoffset = (F32)col / mAtlasDim ;
-	yoffset = (F32)row / mAtlasDim ;	
-}
-
-void LLTextureAtlas::getTexCoordScale(S32 w, S32 h, F32& xscale, F32& yscale)
-{
-	xscale = (F32)w / (mAtlasDim * sSlotSize) ;
-	yscale = (F32)h / (mAtlasDim * sSlotSize) ;	
-}
-
-//insert a texture piece into the atlas
-LLGLuint LLTextureAtlas::insertSubTexture(LLImageGL* source_gl_tex, S32 discard_level, const LLImageRaw* raw_image, S16 slot_col, S16 slot_row)
-{
-	if(!getTexName())
-	{
-		return 0 ;
-	}
-
-	S32 w = raw_image->getWidth() ;
-	S32 h = raw_image->getHeight() ;
-	if(w < 8 || w > sMaxSubTextureSize || h < 8 || h > sMaxSubTextureSize)
-	{
-		//size overflow
-		return 0 ;
-	}
-
-	BOOL res = gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, getTexName());
-	if (!res) 
-	{
-		LL_ERRS() << "bindTexture failed" << LL_ENDL;
-	}
-	
-	GLint xoffset = sSlotSize * slot_col ;
-	GLint yoffset = sSlotSize * slot_row ;
-
-	if(!source_gl_tex->preAddToAtlas(discard_level, raw_image))
-	{
-		return 0 ;
-	}
-
-	glTexSubImage2D(GL_TEXTURE_2D, 0, xoffset, yoffset, w, h,
-						mGLTexturep->getPrimaryFormat(), mGLTexturep->getFormatType(), raw_image->getData());
-	
-	source_gl_tex->postAddToAtlas() ;
-	return getTexName();
-}
-	
-//release a sub-texture slot from the atlas
-void LLTextureAtlas::releaseSlot(S16 slot_col, S16 slot_row, S8 slot_width)
-{
-	unmarkUsageBits(slot_width, slot_col, slot_row) ;
-	mNumSlotsReserved -= slot_width * slot_width ;
-}
-
-BOOL LLTextureAtlas::isEmpty() const 
-{
-	return !mNumSlotsReserved ;
-}
-	
-BOOL LLTextureAtlas::isFull(S8 to_be_reserved) const 
-{
-	return mNumSlotsReserved + to_be_reserved > mMaxSlotsInAtlas ;
-}
-F32  LLTextureAtlas::getFullness() const 
-{
-	return (F32)mNumSlotsReserved / mMaxSlotsInAtlas ;
-}
-
-void LLTextureAtlas::addSpatialGroup(LLSpatialGroup* groupp) 
-{
-	if(groupp && !hasSpatialGroup(groupp))
-	{
-		mSpatialGroupList.push_back(groupp);
-	}
-}
-
-void LLTextureAtlas::removeSpatialGroup(LLSpatialGroup* groupp) 
-{
-	if(groupp)
-	{
-		mSpatialGroupList.remove(groupp);
-	}
-}
-
-void LLTextureAtlas::clearSpatialGroup() 
-{
-	mSpatialGroupList.clear();
-}
-void LLTextureAtlas::removeLastSpatialGroup() 
-{
-	mSpatialGroupList.pop_back() ;
-}
-
-LLSpatialGroup* LLTextureAtlas::getLastSpatialGroup() 
-{
-	if(mSpatialGroupList.size() > 0)
-	{
-		return mSpatialGroupList.back() ;
-	}
-	return NULL ;
-}
-
-BOOL LLTextureAtlas::hasSpatialGroup(LLSpatialGroup* groupp) 
-{
-	for(std::list<LLSpatialGroup*>::iterator iter = mSpatialGroupList.begin(); iter != mSpatialGroupList.end() ; ++iter)
-	{
-		if(*iter == groupp)
-		{
-			return TRUE ;
-		}
-	}
-	return FALSE ;
-}
-
-//--------------------------------------------------------------------------------------
-//private
-void LLTextureAtlas::generateEmptyUsageBits()
-{
-	S32 col_len = (mAtlasDim + 7) >> 3 ;
-	mUsageBits = new U8*[mAtlasDim] ;
-	*mUsageBits = new U8[mAtlasDim * col_len] ;
-
-	mUsageBits[0] = *mUsageBits ;
-	for(S32 i = 1 ; i < mAtlasDim ; i++)
-	{
-	   mUsageBits[i] = mUsageBits[i-1] + col_len ;
-
-	   for(S32 j = 0 ; j < col_len ; j++)
-	   {
-		   //init by 0 for all bits.
-		   mUsageBits[i][j] = 0 ;
-	   }
-	}
-
-	//do not forget mUsageBits[0]!
-	for(S32 j = 0 ; j < col_len ; j++)
-	{
-		//init by 0 for all bits.
-		mUsageBits[0][j] = 0 ;
-	}
-
-	mTestBits = NULL ;
-#if DEBUG_USAGE_BITS
-	//------------
-	//test
-	mTestBits = new U8*[mAtlasDim] ;
-	*mTestBits = new U8[mAtlasDim * mAtlasDim] ;
-	mTestBits[0] = *mTestBits ;
-	for(S32 i = 1 ; i < mAtlasDim ; i++)
-	{
-	   mTestBits[i] = mTestBits[i-1] + mAtlasDim ;
-
-	   for(S32 j = 0 ; j < mAtlasDim ; j++)
-	   {
-		   //init by 0 for all bits.
-		   mTestBits[i][j] = 0 ;
-	   }
-	}
-
-	for(S32 j = 0 ; j < mAtlasDim ; j++)
-	{
-		//init by 0 for all bits.
-		mTestBits[0][j] = 0 ;
-	}
-#endif
-}
-
-void LLTextureAtlas::releaseUsageBits()
-{
-   if(mUsageBits)
-   {
-       delete[] *mUsageBits ;
-       delete[] mUsageBits ;
-   }
-   mUsageBits = NULL ;
-
-   //test
-   if( mTestBits)
-   {
-	   delete[] *mTestBits;
-	   delete[]  mTestBits;
-   }
-    mTestBits = NULL ;
-}
-
-void LLTextureAtlas::markUsageBits(S8 bits_len, U8 mask, S16 col, S16 row)
-{
-	S16 x = col >> 3 ;
-	
-	for(S8 i = 0 ; i < bits_len ; i++)
-	{
-		mUsageBits[row + i][x] |= mask ;
-	}
-
-#if DEBUG_USAGE_BITS
-	//test
-	for(S8 i = row ; i < row + bits_len ; i++)
-	{
-		for(S8 j = col ; j < col + bits_len ; j++)
-		{
-			mTestBits[i][j] = 1 ;
-		}
-	}
-#endif
-}
-
-void LLTextureAtlas::unmarkUsageBits(S8 bits_len, S16 col, S16 row)
-{
-	S16 x = col >> 3 ;
-	U8  mask = 1 ;
-	for(S8 i = 1 ; i < bits_len ; i++)
-	{
-		mask |= (1 << i) ;
-	}
-	mask <<= (col & 7) ;
-	mask = ~mask ;
-	
-	for(S8 i = 0 ; i < bits_len ; i++)
-	{
-		mUsageBits[row + i][x] &= mask ;
-	}
-
-#if DEBUG_USAGE_BITS
-	//test
-	for(S8 i = row ; i < row + bits_len ; i++)
-	{
-		for(S8 j = col ; j < col + bits_len ; j++)
-		{
-			mTestBits[i][j] = 0 ;
-		}
-	}
-#endif
-}
-
-//return true if any of bits in the range marked.
-BOOL LLTextureAtlas::areUsageBitsMarked(S8 bits_len, U8 mask, S16 col, S16 row)
-{
-	BOOL ret = FALSE ;	
-	S16 x = col >> 3 ;
-	
-	for(S8 i = 0 ; i < bits_len ; i++)
-	{
-		if(mUsageBits[row + i][x] & mask)
-		{
-			ret = TRUE ;
-			break ;
-			//return TRUE ;
-		}
-	}
-
-#if DEBUG_USAGE_BITS
-	//test
-	BOOL ret2 = FALSE ;
-	for(S8 i = row ; i < row + bits_len ; i++)
-	{
-		for(S8 j = col ; j < col + bits_len ; j++)
-		{
-			if(mTestBits[i][j])
-			{
-				ret2 = TRUE ;
-			}
-		}
-	}
-
-	if(ret != ret2)
-	{
-		LL_ERRS() << "bits map corrupted." << LL_ENDL ;
-	}
-#endif
-	return ret ;//FALSE ;
-}
-
-//----------------------------------------------------------------------
-//
-//index order: Z order, i.e.: 
-// |-----|-----|-----|-----|
-// |  10 |  11 | 14  | 15  |
-// |-----|-----|-----|-----|
-// |   8 |   9 | 12  | 13  |
-// |-----|-----|-----|-----|
-// |   2 |   3 |   6 |   7 |
-// |-----|-----|-----|-----|
-// |   0 |   1 |   4 |   5 |
-// |-----|-----|-----|-----|
-void LLTextureAtlas::getPositionFromIndex(S16 index, S16& col, S16& row)
-{
-	col = 0 ;
-	row = 0 ;
-
-	S16 index_copy = index ;
-	for(S16 i = 0 ; index_copy && i < 16 ; i += 2)
-	{
-		col |= ((index & (1 << i)) >> i) << (i >> 1) ;
-		row |= ((index & (1 << (i + 1))) >> (i + 1)) << (i >> 1) ;
-		index_copy >>= 2 ;
-	}
-}
-void LLTextureAtlas::getIndexFromPosition(S16 col, S16 row, S16& index)
-{
-	index = 0 ;
-	S16 col_copy = col ;
-	S16 row_copy = row ;
-	for(S16 i = 0 ; (col_copy || row_copy) && i < 16 ; i++)
-	{
-		index |= ((col & 1 << i) << i) | ((row & 1 << i) << ( i + 1)) ;
-		col_copy >>= 1 ;
-		row_copy >>= 1 ;
-	}
-}
-//----------------------------------------------------------------------
-//return TRUE if succeeds.
-BOOL LLTextureAtlas::getNextAvailableSlot(S8 bits_len, S16& col, S16& row)
-{
-    S16 index_step = bits_len * bits_len ;
-
-    U8 mask = 1 ;
-	for(S8 i = 1 ; i < bits_len ; i++)
-	{
-		mask |= (1 << i) ;
-	}	
-   
-	U8 cur_mask ;
-	for(S16 index = 0 ; index < mMaxSlotsInAtlas ; index += index_step)
-    {
-		getPositionFromIndex(index, col, row) ;
-		
-		cur_mask = mask << (col & 7) ;
-		if(!areUsageBitsMarked(bits_len, cur_mask, col, row))
-		{
-			markUsageBits(bits_len, cur_mask, col, row) ;
-			mNumSlotsReserved += bits_len * bits_len ;
-			
-			return TRUE ;
-		}
-    }
-
-   return FALSE ;
-}
diff --git a/indra/newview/lltextureatlas.h b/indra/newview/lltextureatlas.h
deleted file mode 100644
index 6b36eb7fe410742679ee6012b7ded1f3c6a1bad0..0000000000000000000000000000000000000000
--- a/indra/newview/lltextureatlas.h
+++ /dev/null
@@ -1,90 +0,0 @@
-/** 
- * @file lltextureatlas.h
- * @brief LLTextureAtlas base class.
- *
- * $LicenseInfo:firstyear=2002&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- * 
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- * 
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
- * $/LicenseInfo$
- */
-
-
-#ifndef LL_TEXTUREATLAS_H
-#define LL_TEXTUREATLAS_H
-
-#include "llviewertexture.h"
-class LLSpatialGroup ;
-
-class LLTextureAtlas : public LLViewerTexture
-{
-protected:
-	/*virtual*/ ~LLTextureAtlas() ;
-
-public:
-	LLTextureAtlas(U8 ncomponents, S16 atlas_dim = 16) ;	
-
-	/*virtual*/ S8 getType() const;
-
-	LLGLuint insertSubTexture(LLImageGL* source_gl_tex, S32 discard_level, const LLImageRaw* raw_image, S16 slot_col, S16 slot_row) ;
-	void releaseSlot(S16 slot_col, S16 slot_row, S8 slot_width);
-
-	BOOL getNextAvailableSlot(S8 bits_len, S16& col, S16& row) ;
-	void getTexCoordOffset(S16 col, S16 row, F32& xoffset, F32& yOffset) ;
-	void getTexCoordScale(S32 w, S32 h, F32& xscale, F32& yscale) ;
-
-	BOOL isEmpty() const ;
-	BOOL isFull(S8 to_be_reserved = 1) const ;
-	F32  getFullness() const ;
-
-	void addSpatialGroup(LLSpatialGroup* groupp) ;
-	void removeSpatialGroup(LLSpatialGroup* groupp) ;
-	LLSpatialGroup* getLastSpatialGroup() ;
-	void removeLastSpatialGroup() ;
-	BOOL hasSpatialGroup(LLSpatialGroup* groupp) ;
-	void clearSpatialGroup() ;
-	std::list<LLSpatialGroup*>* getSpatialGroupList() {return &mSpatialGroupList;}
-private:
-	void generateEmptyUsageBits() ;
-	void releaseUsageBits() ;
-
-	void markUsageBits(S8 bits_len, U8 mask, S16 col, S16 row) ;
-	void unmarkUsageBits(S8 bits_len, S16 col, S16 row) ;
-
-	void getPositionFromIndex(S16 index, S16& col, S16& row) ;
-	void getIndexFromPosition(S16 col, S16 row, S16& index) ;
-	BOOL areUsageBitsMarked(S8 bits_len, U8 mask, S16 col, S16 row) ;
-
-private:	
-	S16 mAtlasDim ; //number of slots per edge, i.e, there are "mAtlasDim * mAtlasDim" total slots in the atlas. 
-	S16 mNumSlotsReserved ;
-	S16 mMaxSlotsInAtlas ;
-	U8  **mUsageBits ;	
-	std::list<LLSpatialGroup*> mSpatialGroupList ;
-
-public:
-	//debug use only
-	U8  **mTestBits ;
-
-public:
-	static S16 sMaxSubTextureSize ;
-	static S16 sSlotSize ;
-};
-
-#endif
-
diff --git a/indra/newview/lltextureatlasmanager.cpp b/indra/newview/lltextureatlasmanager.cpp
deleted file mode 100644
index ca9d6da4db1b17b0b6a8b06738755941acf8f9ca..0000000000000000000000000000000000000000
--- a/indra/newview/lltextureatlasmanager.cpp
+++ /dev/null
@@ -1,268 +0,0 @@
-/** 
- * @file lltextureatlasmanager.cpp
- * @brief LLTextureAtlasManager class implementation.
- *
- * $LicenseInfo:firstyear=2002&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- * 
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- * 
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
- * $/LicenseInfo$
- */
-#include "llviewerprecompiledheaders.h"
-#include "linden_common.h"
-#include "llerror.h"
-#include "llmath.h"
-#include "lltextureatlas.h"
-#include "lltextureatlasmanager.h"
-#include "llspatialpartition.h"
-
-const S8 MAX_NUM_EMPTY_ATLAS = 2 ;
-const F32 MIN_ATLAS_FULLNESS = 0.6f ;
-
-//*********************************************************************************************
-//implementation of class LLTextureAtlasInfo
-//*********************************************************************************************
-LLTextureAtlasSlot::LLTextureAtlasSlot(LLTextureAtlas* atlasp, LLSpatialGroup* groupp, S16 col, S16 row, F32 xoffset, F32 yoffset, S8 slot_width) : 
-	mAtlasp(atlasp),
-	mGroupp(groupp),
-	mCol(col),
-	mRow(row),
-	mReservedSlotWidth(slot_width),
-	mValid(FALSE),
-	mUpdatedTime(0),
-	mTexCoordOffset(xoffset, yoffset),
-	mTexCoordScale(1.f, 1.f)
-{
-	llassert_always(mAtlasp || mGroupp || mReservedSlotWidth) ;
-}
-
-LLTextureAtlasSlot::~LLTextureAtlasSlot()
-{
-	if(mAtlasp)
-	{
-		mAtlasp->releaseSlot(mCol, mRow, mReservedSlotWidth) ;
-		if(mAtlasp->isEmpty())
-		{
-			LLTextureAtlasManager::getInstance()->releaseAtlas(mAtlasp) ;
-		}
-		mAtlasp = NULL ;
-	}
-}
-
-//void LLTextureAtlasSlot::setAtlas(LLTextureAtlas* atlasp) 
-//{
-//	mAtlasp = atlasp ;
-//}
-//void LLTextureAtlasSlot::setSlotPos(S16 col, S16 row) 
-//{
-//	mCol = col ;
-//	mRow = row ;
-//}
-//void LLTextureAtlasSlot::setSlotWidth(S8 width) 
-//{
-//	//slot is a square with each edge length a power-of-two number
-//	mReservedSlotWidth = width ;
-//}
-//void LLTextureAtlasSlot::setTexCoordOffset(F32 xoffset, F32 yoffset) 
-//{
-//	mTexCoordOffset.mV[0] = xoffset ;
-//	mTexCoordOffset.mV[1] = yoffset ;
-//}
-
-void LLTextureAtlasSlot::setSpatialGroup(LLSpatialGroup* groupp) 
-{
-	mGroupp = groupp ;
-}
-void LLTextureAtlasSlot::setTexCoordScale(F32 xscale, F32 yscale) 
-{
-	mTexCoordScale.mV[0] = xscale ;
-	mTexCoordScale.mV[1] = yscale ;
-}
-//*********************************************************************************************
-//END of implementation of class LLTextureAtlasInfo
-//*********************************************************************************************
-
-//*********************************************************************************************
-//implementation of class LLTextureAtlasManager
-//*********************************************************************************************
-LLTextureAtlasManager::LLTextureAtlasManager() :
-	mAtlasMap(4),
-	mEmptyAtlasMap(4) 
-{
-}
-
-LLTextureAtlasManager::~LLTextureAtlasManager()
-{
-	for(S32 i = 0 ; i < 4 ; i++)
-	{
-		for(ll_texture_atlas_list_t::iterator j = mAtlasMap[i].begin() ; j != mAtlasMap[i].end() ; ++j)
-		{
-			*j = NULL ;
-		}
-		for(ll_texture_atlas_list_t::iterator j = mEmptyAtlasMap[i].begin() ; j != mEmptyAtlasMap[i].end() ; ++j)
-		{
-			*j = NULL ;
-		}
-
-		mAtlasMap[i].clear() ;
-		mEmptyAtlasMap[i].clear() ;
-	}
-	mAtlasMap.clear() ;
-	mEmptyAtlasMap.clear() ;
-}
-
-//return TRUE if qualified
-BOOL LLTextureAtlasManager::canAddToAtlas(S32 w, S32 h, S8 ncomponents, LLGLenum target) 
-{
-	if(ncomponents < 1 || ncomponents > 4)
-	{
-		return FALSE ;
-	}
-	//only support GL_TEXTURE_2D
-	if(GL_TEXTURE_2D != target)
-	{
-		return FALSE ;
-	}
-	//real image size overflows
-	if(w < 8 || w > LLTextureAtlas::sMaxSubTextureSize || h < 8 || h > LLTextureAtlas::sMaxSubTextureSize)
-	{
-		return FALSE ;
-	}
-
-	//if non-power-of-two number
-	if((w & (w - 1)) || (h & (h - 1)))
-	{
-		return FALSE ;
-	}
-
-	return TRUE ;
-}
-
-void LLTextureAtlasManager::releaseAtlas(LLTextureAtlas* atlasp)
-{	
-	LLSpatialGroup* groupp = atlasp->getLastSpatialGroup() ;
-	while(groupp)
-	{
-		groupp->removeAtlas(atlasp, FALSE) ;
-		atlasp->removeLastSpatialGroup() ;
-
-		groupp = atlasp->getLastSpatialGroup() ;
-	}
-
-	S8 type = atlasp->getComponents() - 1 ;	
-	//insert to the empty list
-	if(mEmptyAtlasMap[type].size() < MAX_NUM_EMPTY_ATLAS)
-	{					
-		mEmptyAtlasMap[type].push_back(atlasp) ;
-	}
-		
-	//delete the atlasp
-	mAtlasMap[type].remove(atlasp) ;
-}
-
-//
-//this function reserves an appropriate slot from atlas pool for an image.
-//return non-NULL if succeeds.
-//Note:
-//1, this function does not check if the image this slot assigned for qualifies for atlas or not, 
-//       call LLTextureAtlasManager::canAddToAtlas(...) to do the check before calling this function.
-//2, this function also dose not check if the image is already in atlas. It always assigns a new slot anyway.
-//3, this function tries to group sub-textures from same spatial group into ONE atlas to improve render batching.
-//
-LLPointer<LLTextureAtlasSlot> LLTextureAtlasManager::reserveAtlasSlot(S32 sub_texture_size, S8 ncomponents, 
-																		  LLSpatialGroup* groupp, LLViewerTexture* imagep)
-{
-	if(!groupp)
-	{
-		//do not insert to atlas if does not have a group.
-		return NULL ;
-	}
-
-	//bits_len must <= 8 and is a power of two number, i.e.: must be one of these numbers: 1, 2, 4, 8.
-	if(sub_texture_size > LLTextureAtlas::sMaxSubTextureSize)
-	{
-		sub_texture_size = LLTextureAtlas::sMaxSubTextureSize ;
-	}
-	S8 bits_len = sub_texture_size / LLTextureAtlas::sSlotSize ;
-	if(bits_len < 1)
-	{
-	   bits_len = 1 ;
-	}
-		
-	S16 col = -1, row = -1;
-	S8 total_bits = bits_len * bits_len ;
-
-	//insert to the atlas reserved by the same spatial group
-	LLPointer<LLTextureAtlas> atlasp = groupp->getAtlas(ncomponents, total_bits) ;
-	if(atlasp.notNull())
-	{
-		if(!atlasp->getNextAvailableSlot(bits_len, col, row))
-		{
-			//failed
-			atlasp = NULL ;
-		}		
-	}
-
-   //search an atlas to fit for 'size'
-	if(!atlasp)
-	{
-		S8 atlas_index = ncomponents - 1 ;
-		ll_texture_atlas_list_t::iterator iter = mAtlasMap[atlas_index].begin() ;
-		for(; iter != mAtlasMap[atlas_index].end(); ++iter) 
-		{
-			LLTextureAtlas* cur = (LLTextureAtlas*)*iter ;
-			if(cur->getFullness() < MIN_ATLAS_FULLNESS)//this atlas is empty enough for this group to insert more sub-textures later if necessary.
-			{
-				if(cur->getNextAvailableSlot(bits_len, col, row))
-				{
-					atlasp = cur ;
-					groupp->addAtlas(atlasp) ;				
-					break ;
-				}
-			}
-		}
-	}
-
-	//create a new atlas if necessary
-	if(!atlasp)
-	{
-		if(mEmptyAtlasMap[ncomponents - 1].size() > 0)
-		{
-			//there is an empty one
-			atlasp = mEmptyAtlasMap[ncomponents - 1].back() ;
-			mEmptyAtlasMap[ncomponents - 1].pop_back() ;
-		}
-		else
-		{
-			atlasp = new LLTextureAtlas(ncomponents, 16) ;
-		}
-		mAtlasMap[ncomponents - 1].push_back(atlasp) ;
-		atlasp->getNextAvailableSlot(bits_len, col, row) ;		
-		groupp->addAtlas(atlasp) ;
-	}
-
-	F32 xoffset, yoffset ;
-	atlasp->getTexCoordOffset(col, row, xoffset, yoffset) ;
-	LLPointer<LLTextureAtlasSlot> slot_infop = new LLTextureAtlasSlot(atlasp, groupp, col, row, xoffset, yoffset, bits_len) ;
-	
-	return slot_infop ;
-}
-
-//*********************************************************************************************
-//END of implementation of class LLTextureAtlasManager
-//*********************************************************************************************
diff --git a/indra/newview/lltextureatlasmanager.h b/indra/newview/lltextureatlasmanager.h
deleted file mode 100644
index 1b8df708c6299abfb79bdb42e6da5bb76f693fa7..0000000000000000000000000000000000000000
--- a/indra/newview/lltextureatlasmanager.h
+++ /dev/null
@@ -1,105 +0,0 @@
-/** 
- * @file lltextureatlasmanager.h
- * @brief LLTextureAtlasManager base class.
- *
- * $LicenseInfo:firstyear=2002&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- * 
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- * 
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
- * $/LicenseInfo$
- */
-
-
-#ifndef LL_TEXTUREATLASMANAGER_H
-#define LL_TEXTUREATLASMANAGER_H
-
-#include "llmemory.h"
-
-class LLSpatialGroup ;
-class LLViewerTexture ;
-
-//just use it as a structure.
-class LLTextureAtlasSlot : public LLRefCount
-{
-public:
-	LLTextureAtlasSlot(LLTextureAtlas* atlasp, LLSpatialGroup* groupp, S16 col, S16 row, F32 xoffset, F32 yoffset, S8 slot_width) ;
-
-protected:
-	virtual ~LLTextureAtlasSlot();
-	
-public:
-
-	//
-	//do not allow to change those values
-	//
-	//void setAtlas(LLTextureAtlas* atlasp) ;	
-	//void setSlotPos(S16 col, S16 row) ;
-	//void setSlotWidth(S8 width) ;
-	//void setTexCoordOffset(F32 xoffser, F32 yoffset) ;
-	//
-
-	void setSpatialGroup(LLSpatialGroup* groupp) ;
-	void setTexCoordScale(F32 xscale, F32 yscale) ;
-	void setValid() {mValid = TRUE ;}
-
-	LLTextureAtlas* getAtlas()const {return mAtlasp;}
-	LLSpatialGroup* getSpatialGroup() const {return mGroupp ;} 
-	S16             getSlotCol()const {return mCol;}
-	S16             getSlotRow()const {return mRow;}
-	S8              getSlotWidth()const{return mReservedSlotWidth;}
-	BOOL            isValid()const { return mValid;}
-	const LLVector2*      getTexCoordOffset()const {return &mTexCoordOffset;}
-	const LLVector2*      getTexCoordScale() const {return &mTexCoordScale;}
-
-	void setUpdatedTime(U32 t) {mUpdatedTime = t;}
-	U32  getUpdatedTime()const {return mUpdatedTime;}
-
-private:
-	LLTextureAtlas* mAtlasp;
-	S16             mCol ;//col of the slot
-	S16             mRow ;//row of the slot
-	S8              mReservedSlotWidth ; //slot is a square with each edge length a power-of-two number	
-	LLSpatialGroup* mGroupp ;
-	BOOL            mValid ;
-
-	LLVector2       mTexCoordOffset ;
-	LLVector2       mTexCoordScale ;
-
-	U32             mUpdatedTime ;	
-} ;
-
-class LLTextureAtlasManager : public LLSingleton<LLTextureAtlasManager>
-{
-	LLSINGLETON(LLTextureAtlasManager);
-	~LLTextureAtlasManager();
-	typedef std::list<LLPointer<LLTextureAtlas> > ll_texture_atlas_list_t ;
-
-public:
-
-	LLPointer<LLTextureAtlasSlot> reserveAtlasSlot(S32 sub_texture_size, S8 ncomponents, 
-		LLSpatialGroup* groupp, LLViewerTexture* imagep) ;
-	void releaseAtlas(LLTextureAtlas* atlasp);
-
-	BOOL canAddToAtlas(S32 w, S32 h, S8 ncomponents, LLGLenum target) ;
-
-private:	
-	std::vector<ll_texture_atlas_list_t> mAtlasMap ;
-	std::vector<ll_texture_atlas_list_t> mEmptyAtlasMap ; //delay some empty atlases deletion to avoid possible creation of new atlas immediately.
-};
-
-#endif
diff --git a/indra/newview/lltexturecache.cpp b/indra/newview/lltexturecache.cpp
index d4fc6f3de28d9e88147b4fab81659cbbcd96499e..9403e73b87474eaa774a87c8a1fd9e0c0c41eb91 100644
--- a/indra/newview/lltexturecache.cpp
+++ b/indra/newview/lltexturecache.cpp
@@ -1042,7 +1042,8 @@ void LLTextureCache::setReadOnly(BOOL read_only)
 	mReadOnly = read_only ;
 }
 
-//called in the main thread.
+// Called in the main thread.
+// Returns the unused amount of max_size if any
 S64 LLTextureCache::initCache(ELLPath location, S64 max_size, BOOL texture_cache_mismatch)
 {
 	llassert_always(getPending() == 0) ; //should not start accessing the texture cache before initialized.
diff --git a/indra/newview/lltexturectrl.cpp b/indra/newview/lltexturectrl.cpp
index 1c4a56b549a78654afa0ffe93e9fad2f819ce43e..0ce82a12979412fa2a514dee68fb24dbbeee2560 100644
--- a/indra/newview/lltexturectrl.cpp
+++ b/indra/newview/lltexturectrl.cpp
@@ -48,6 +48,7 @@
 #include "llui.h"
 #include "llviewerinventory.h"
 #include "llpermissions.h"
+#include "llpreviewtexture.h"
 #include "llsaleinfo.h"
 #include "llassetstorage.h"
 #include "lltextbox.h"
@@ -80,6 +81,67 @@ static const S32 LOCAL_TRACKING_ID_COLUMN = 1;
 //static const char WHITE_IMAGE_NAME[] = "Blank Texture";
 //static const char NO_IMAGE_NAME[] = "None";
 
+
+
+//static
+bool get_is_predefined_texture(LLUUID asset_id)
+{
+    if (asset_id == LLUUID(gSavedSettings.getString("DefaultObjectTexture"))
+        || asset_id == LLUUID(gSavedSettings.getString("UIImgWhiteUUID"))
+        || asset_id == LLUUID(gSavedSettings.getString("UIImgInvisibleUUID"))
+        || asset_id == LLUUID(SCULPT_DEFAULT_TEXTURE))
+    {
+        return true;
+    }
+    return false;
+}
+
+LLUUID get_copy_free_item_by_asset_id(LLUUID asset_id, bool no_trans_perm)
+{
+    LLViewerInventoryCategory::cat_array_t cats;
+    LLViewerInventoryItem::item_array_t items;
+    LLAssetIDMatches asset_id_matches(asset_id);
+    gInventory.collectDescendentsIf(LLUUID::null,
+        cats,
+        items,
+        LLInventoryModel::INCLUDE_TRASH,
+        asset_id_matches);
+    
+    LLUUID res;
+    if (items.size())
+    {
+        for (S32 i = 0; i < items.size(); i++)
+        {
+            LLViewerInventoryItem* itemp = items[i];
+            if (itemp)
+            {
+                LLPermissions item_permissions = itemp->getPermissions();
+                if (item_permissions.allowOperationBy(PERM_COPY,
+                    gAgent.getID(),
+                    gAgent.getGroupID()))
+                {
+                    bool allow_trans = item_permissions.allowOperationBy(PERM_TRANSFER, gAgent.getID(), gAgent.getGroupID());
+                    if (allow_trans != no_trans_perm)
+                    {
+                        return itemp->getUUID();
+                    }
+                    res = itemp->getUUID();
+                }
+            }
+        }
+    }
+    return res;
+}
+
+bool get_can_copy_texture(LLUUID asset_id)
+{
+    // User is allowed to copy a texture if:
+    // library asset or default texture,
+    // or copy perm asset exists in user's inventory
+
+    return get_is_predefined_texture(asset_id) || get_copy_free_item_by_asset_id(asset_id).notNull();
+}
+
 LLFloaterTexturePicker::LLFloaterTexturePicker(	
 	LLView* owner,
 	LLUUID image_asset_id,
@@ -1154,6 +1216,7 @@ LLTextureCtrl::LLTextureCtrl(const LLTextureCtrl::Params& p)
 	mNeedsRawImageData( FALSE ),
 	mValid( TRUE ),
 	mShowLoadingPlaceholder( TRUE ),
+	mOpenTexPreview(false),
 	mImageAssetID(p.image_id),
 	mDefaultImageAssetID(p.default_image_id),
 	mDefaultImageName(p.default_image_name),
@@ -1410,12 +1473,31 @@ BOOL LLTextureCtrl::handleMouseDown(S32 x, S32 y, MASK mask)
 
 	if (!handled && mBorder->parentPointInView(x, y))
 	{
-		showPicker(FALSE);
-		//grab textures first...
-		LLInventoryModelBackgroundFetch::instance().start(gInventory.findCategoryUUIDForType(LLFolderType::FT_TEXTURE));
-		//...then start full inventory fetch.
-		LLInventoryModelBackgroundFetch::instance().start();
-		handled = TRUE;
+		if (!mOpenTexPreview)
+		{
+			showPicker(FALSE);
+			//grab textures first...
+			LLInventoryModelBackgroundFetch::instance().start(gInventory.findCategoryUUIDForType(LLFolderType::FT_TEXTURE));
+			//...then start full inventory fetch.
+			LLInventoryModelBackgroundFetch::instance().start();
+			handled = TRUE;
+		}
+		else
+		{
+			if (getImageAssetID().notNull())
+			{
+				LLPreviewTexture* preview_texture = LLFloaterReg::showTypedInstance<LLPreviewTexture>("preview_texture", getValue());
+				if (preview_texture && !preview_texture->isDependent())
+				{
+					LLFloater* root_floater = gFloaterView->getParentFloater(this);
+					if (root_floater)
+					{
+						root_floater->addDependentFloater(preview_texture);
+						preview_texture->hideCtrlButtons();
+					}
+				}
+			}
+		}
 	}
 
 	return handled;
diff --git a/indra/newview/lltexturectrl.h b/indra/newview/lltexturectrl.h
index 92f6f89af62ab1a947a795f403adc4bbe4146867..fbb38c4464ff9be37852c0ae05e8b69a5d689b96 100644
--- a/indra/newview/lltexturectrl.h
+++ b/indra/newview/lltexturectrl.h
@@ -52,6 +52,16 @@ class LLViewerFetchedTexture;
 typedef boost::function<BOOL (LLUICtrl*, LLInventoryItem*)> drag_n_drop_callback;
 typedef boost::function<void (LLInventoryItem*)> texture_selected_callback;
 
+// Helper functions for UI that work with picker
+bool get_is_predefined_texture(LLUUID asset_id);
+
+// texture picker works by asset ids since objects normaly do
+// not retain inventory ids as result these functions are looking
+// for textures in inventory by asset ids
+// This search can be performance unfriendly and doesn't warranty
+// that the texture is original source of asset
+LLUUID get_copy_free_item_by_asset_id(LLUUID image_id, bool no_trans_perm = false);
+bool get_can_copy_texture(LLUUID image_id);
 
 //////////////////////////////////////////////////////////////////////////////////////////
 // LLTextureCtrl
@@ -159,6 +169,8 @@ class LLTextureCtrl
 	void			setBlankImageAssetID( const LLUUID& id )	{ mBlankImageAssetID = id; }
 	const LLUUID&	getBlankImageAssetID() const { return mBlankImageAssetID; }
 
+	void			setOpenTexPreview(bool open_preview) { mOpenTexPreview = open_preview; }
+
 	void			setCaption(const std::string& caption);
 	void			setCanApplyImmediately(BOOL b);
 
@@ -238,6 +250,8 @@ class LLTextureCtrl
 	BOOL					 	mShowLoadingPlaceholder;
 	std::string				 	mLoadingPlaceholderString;
 	S32						 	mLabelWidth;
+	bool						mOpenTexPreview;
+	BOOL						mBakeTextureEnabled;
 };
 
 //////////////////////////////////////////////////////////////////////////////////////////
diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp
index e7b756bf4a8c318ce7db60aac11b0e5bc044a14e..0edaf40c66dd6064a1dbae688450b27ad49081c5 100644
--- a/indra/newview/lltexturefetch.cpp
+++ b/indra/newview/lltexturefetch.cpp
@@ -318,6 +318,7 @@ class LLTextureFetchWorker : public LLWorkerClass, public LLCore::HttpHandler
 		// Threads:  Ttc
 		virtual void completed(bool success)
 		{
+            LL_PROFILE_ZONE_SCOPED;
 			LLTextureFetchWorker* worker = mFetcher->getWorker(mID);
 			if (worker)
 			{
@@ -342,6 +343,7 @@ class LLTextureFetchWorker : public LLWorkerClass, public LLCore::HttpHandler
 		// Threads:  Ttc
 		virtual void completed(bool success)
 		{
+            LL_PROFILE_ZONE_SCOPED;
 			LLTextureFetchWorker* worker = mFetcher->getWorker(mID);
 			if (worker)
 			{
@@ -366,6 +368,7 @@ class LLTextureFetchWorker : public LLWorkerClass, public LLCore::HttpHandler
 		// Threads:  Tid
 		virtual void completed(bool success, LLImageRaw* raw, LLImageRaw* aux)
 		{
+            LL_PROFILE_ZONE_SCOPED;
 			LLTextureFetchWorker* worker = mFetcher->getWorker(mID);
 			if (worker)
 			{
@@ -1153,6 +1156,11 @@ void LLTextureFetchWorker::startWork(S32 param)
 // Threads:  Ttf
 bool LLTextureFetchWorker::doWork(S32 param)
 {
+    LL_PROFILE_ZONE_SCOPED;
+	if (gNonInteractive)
+	{
+		return true;
+	}
 	static const LLCore::HttpStatus http_not_found(HTTP_NOT_FOUND);						// 404
 	static const LLCore::HttpStatus http_service_unavail(HTTP_SERVICE_UNAVAILABLE);		// 503
 	static const LLCore::HttpStatus http_not_sat(HTTP_REQUESTED_RANGE_NOT_SATISFIABLE);	// 416;
diff --git a/indra/newview/lltextureview.cpp b/indra/newview/lltextureview.cpp
index 7a0f69fed565cec8f025e24c68f6a45157cb0cba..b74577315e30f33970719889e3b2b691a65351ec 100644
--- a/indra/newview/lltextureview.cpp
+++ b/indra/newview/lltextureview.cpp
@@ -549,9 +549,11 @@ void LLGLTexMemBar::draw()
     U32 texFetchLatMed = U32(recording.getMean(LLTextureFetch::sTexFetchLatency).value() * 1000.0f);
     U32 texFetchLatMax = U32(recording.getMax(LLTextureFetch::sTexFetchLatency).value() * 1000.0f);
 
-	text = llformat("GL Tot: %d/%d MB Bound: %4d/%4d MB FBO: %d MB Raw Tot: %d MB Bias: %.2f Cache: %.1f/%.1f MB",
+	text = llformat("GL Tot: %d/%d MB GL Free: %d Sys Free: %d MB Bound: %4d/%4d MB FBO: %d MB Raw Tot: %d MB Bias: %.2f Cache: %.1f/%.1f MB",
 					total_mem.value(),
 					max_total_mem.value(),
+                    LLImageGLThread::getFreeVRAMMegabytes(),
+                    LLMemory::getAvailableMemKB()/1024,
 					bound_mem.value(),
 					max_bound_mem.value(),
 					LLRenderTarget::sBytesAllocated/(1024*1024),
diff --git a/indra/newview/lltoastalertpanel.cpp b/indra/newview/lltoastalertpanel.cpp
index 8baad30e8f09e0593a2e617cb34e283ab46e47a9..692e8d91a9c8d90c4cadc48447d4a4f1b52e78dc 100644
--- a/indra/newview/lltoastalertpanel.cpp
+++ b/indra/newview/lltoastalertpanel.cpp
@@ -291,7 +291,7 @@ LLToastAlertPanel::LLToastAlertPanel( LLNotificationPtr notification, bool modal
 			mLineEditor->setText(edit_text_contents);
 
 			std::string notif_name = mNotification->getName();
-			if (("SaveOutfitAs" == notif_name) || ("SaveSettingAs" == notif_name) || ("CreateLandmarkFolder" == notif_name))
+			if (("SaveOutfitAs" == notif_name) || ("SaveSettingAs" == notif_name) || ("CreateLandmarkFolder" == notif_name) || ("CreateSubfolder" == notif_name))
 			{
 				mLineEditor->setPrevalidate(&LLTextValidate::validateASCII);
 			}
diff --git a/indra/newview/lltoastpanel.cpp b/indra/newview/lltoastpanel.cpp
index 100d5ee71359327311d51073058502fc5ad60373..d43da93c6189ad8e5b09b377e66d1a346e11905b 100644
--- a/indra/newview/lltoastpanel.cpp
+++ b/indra/newview/lltoastpanel.cpp
@@ -114,7 +114,8 @@ void LLToastPanel::snapToMessageHeight(LLTextBase* message, S32 maxLineCount)
 LLToastPanel* LLToastPanel::buidPanelFromNotification(
 		const LLNotificationPtr& notification)
 {
-	LLToastPanel* res = NULL;
+    LL_PROFILE_ZONE_SCOPED
+    LLToastPanel* res = NULL;
 
 	//process tip toast panels
 	if ("notifytip" == notification->getType())
diff --git a/indra/newview/lltoolcomp.cpp b/indra/newview/lltoolcomp.cpp
index ba328f27c4cf81640f781bda2e4935e26ebd010c..6d54a3770ce425aabf22a95133b7fecb954a6828 100644
--- a/indra/newview/lltoolcomp.cpp
+++ b/indra/newview/lltoolcomp.cpp
@@ -44,6 +44,7 @@
 #include "lltoolmgr.h"
 #include "lltoolselectrect.h"
 #include "lltoolplacer.h"
+#include "llviewerinput.h"
 #include "llviewermenu.h"
 #include "llviewerobject.h"
 #include "llviewerwindow.h"
@@ -745,7 +746,7 @@ BOOL LLToolCompGun::handleHover(S32 x, S32 y, MASK mask)
 BOOL LLToolCompGun::handleMouseDown(S32 x, S32 y, MASK mask)
 { 
 	// if the left button is grabbed, don't put up the pie menu
-	if (gAgent.leftButtonGrabbed())
+	if (gAgent.leftButtonGrabbed() && gViewerInput.isLMouseHandlingDefault(MODE_FIRST_PERSON))
 	{
 		gAgent.setControlFlags(AGENT_CONTROL_ML_LBUTTON_DOWN);
 		return FALSE;
@@ -762,7 +763,7 @@ BOOL LLToolCompGun::handleMouseDown(S32 x, S32 y, MASK mask)
 BOOL LLToolCompGun::handleDoubleClick(S32 x, S32 y, MASK mask)
 {
 	// if the left button is grabbed, don't put up the pie menu
-	if (gAgent.leftButtonGrabbed())
+	if (gAgent.leftButtonGrabbed() && gViewerInput.isLMouseHandlingDefault(MODE_FIRST_PERSON))
 	{
 		gAgent.setControlFlags(AGENT_CONTROL_ML_LBUTTON_DOWN);
 		return FALSE;
@@ -796,7 +797,10 @@ BOOL LLToolCompGun::handleRightMouseDown(S32 x, S32 y, MASK mask)
 
 BOOL LLToolCompGun::handleMouseUp(S32 x, S32 y, MASK mask)
 {
-	gAgent.setControlFlags(AGENT_CONTROL_ML_LBUTTON_UP);
+    if (gViewerInput.isLMouseHandlingDefault(MODE_FIRST_PERSON))
+    {
+        gAgent.setControlFlags(AGENT_CONTROL_ML_LBUTTON_UP);
+    }
 	setCurrentTool( (LLTool*) mGun );
 	return TRUE;
 }
diff --git a/indra/newview/lltooldraganddrop.cpp b/indra/newview/lltooldraganddrop.cpp
index 50868d0fa5aaa29b6501fff756fb3d8a14b83b4c..b16b26b96e188717d89df8e96fe819e80759cbdd 100644
--- a/indra/newview/lltooldraganddrop.cpp
+++ b/indra/newview/lltooldraganddrop.cpp
@@ -60,6 +60,7 @@
 #include "llvoavatarself.h"
 #include "llworld.h"
 #include "llpanelface.h"
+#include "lluiusage.h"
 
 // syntactic sugar
 #define callMemberFunction(object,ptrToMember)  ((object).*(ptrToMember))
@@ -1100,7 +1101,8 @@ void LLToolDragAndDrop::dropTextureOneFace(LLViewerObject* hit_obj,
 										   S32 hit_face,
 										   LLInventoryItem* item,
 										   LLToolDragAndDrop::ESource source,
-										   const LLUUID& src_id)
+										   const LLUUID& src_id,
+                                           S32 tex_channel)
 {
 	if (hit_face == -1) return;
 	if (!item)
@@ -1124,7 +1126,8 @@ void LLToolDragAndDrop::dropTextureOneFace(LLViewerObject* hit_obj,
 
 	if (gFloaterTools->getVisible() && panel_face)
 	{
-		switch (LLSelectMgr::getInstance()->getTextureChannel())
+        tex_channel = (tex_channel > -1) ? tex_channel : LLSelectMgr::getInstance()->getTextureChannel();
+        switch (tex_channel)
 		{
 
 		case 0:
@@ -1303,10 +1306,12 @@ void LLToolDragAndDrop::dropObject(LLViewerObject* raycast_target,
 	LLMessageSystem* msg = gMessageSystem;
 	if (mSource == SOURCE_NOTECARD)
 	{
+		LLUIUsage::instance().logCommand("Object.RezObjectFromNotecard");
 		msg->newMessageFast(_PREHASH_RezObjectFromNotecard);
 	}
 	else
 	{
+		LLUIUsage::instance().logCommand("Object.RezObject");
 		msg->newMessageFast(_PREHASH_RezObject);
 	}
 	msg->nextBlockFast(_PREHASH_AgentData);
diff --git a/indra/newview/lltooldraganddrop.h b/indra/newview/lltooldraganddrop.h
index 24a712029c9e30ed735f8e75335be0382a3a434e..4537d73332e346fff24d2e424f137b309b21f4db 100644
--- a/indra/newview/lltooldraganddrop.h
+++ b/indra/newview/lltooldraganddrop.h
@@ -244,7 +244,8 @@ class LLToolDragAndDrop : public LLTool, public LLSingleton<LLToolDragAndDrop>
 	static void dropTextureOneFace(LLViewerObject* hit_obj, S32 hit_face,
 								   LLInventoryItem* item,
 								   ESource source,
-								   const LLUUID& src_id);
+								   const LLUUID& src_id,
+                                   S32 tex_channel = -1);
 	static void dropTextureAllFaces(LLViewerObject* hit_obj,
 									LLInventoryItem* item,
 									ESource source,
diff --git a/indra/newview/lltoolgrab.cpp b/indra/newview/lltoolgrab.cpp
index f01b374db117fe9f4789959ff8ca96a2844eb194..897f8c1e5fe5c49b5ab974845fcc48e892e324ba 100644
--- a/indra/newview/lltoolgrab.cpp
+++ b/indra/newview/lltoolgrab.cpp
@@ -51,6 +51,7 @@
 #include "lltoolmgr.h"
 #include "lltoolpie.h"
 #include "llviewercamera.h"
+#include "llviewerinput.h"
 #include "llviewerobject.h"
 #include "llviewerobjectlist.h" 
 #include "llviewerregion.h"
@@ -140,7 +141,6 @@ BOOL LLToolGrabBase::handleMouseDown(S32 x, S32 y, MASK mask)
 		LL_INFOS() << "LLToolGrab handleMouseDown" << LL_ENDL;
 	}
 
-	// call the base class to propogate info to sim
 	LLTool::handleMouseDown(x, y, mask);
 
 	// leftButtonGrabbed() checks if controls are reserved by scripts, but does not take masks into account
@@ -150,6 +150,19 @@ BOOL LLToolGrabBase::handleMouseDown(S32 x, S32 y, MASK mask)
 		gViewerWindow->pickAsync(x, y, mask, pickCallback, /*BOOL pick_transparent*/ TRUE);
 	}
 	mClickedInMouselook = gAgentCamera.cameraMouselook();
+
+    if (mClickedInMouselook && gViewerInput.isLMouseHandlingDefault(MODE_FIRST_PERSON))
+    {
+        // LLToolCompGun::handleMouseDown handles the event if ML controls are grabed,
+        // but LLToolGrabBase is often the end point for mouselook clicks if ML controls
+        // are not grabbed and LLToolGrabBase::handleMouseDown consumes the event,
+        // so send clicks from here.
+        // We are sending specifically CONTROL_LBUTTON_DOWN instead of _ML_ version.
+        gAgent.setControlFlags(AGENT_CONTROL_LBUTTON_DOWN);
+
+        // Todo: LLToolGrabBase probably shouldn't consume the event if there is nothing
+        // to grab in Mouselook, it intercepts handling in scanMouse
+    }
 	return TRUE;
 }
 
@@ -529,8 +542,8 @@ void LLToolGrabBase::handleHoverActive(S32 x, S32 y, MASK mask)
 	const F32 RADIANS_PER_PIXEL_X = 0.01f;
 	const F32 RADIANS_PER_PIXEL_Y = 0.01f;
 
-	S32 dx = x - (gViewerWindow->getWorldViewWidthScaled() / 2);
-	S32 dy = y - (gViewerWindow->getWorldViewHeightScaled() / 2);
+    S32 dx = gViewerWindow->getCurrentMouseDX();
+    S32 dy = gViewerWindow->getCurrentMouseDY();
 
 	if (dx != 0 || dy != 0)
 	{
@@ -953,9 +966,18 @@ void LLToolGrabBase::handleHoverFailed(S32 x, S32 y, MASK mask)
 
 BOOL LLToolGrabBase::handleMouseUp(S32 x, S32 y, MASK mask)
 {
-	// call the base class to propogate info to sim
 	LLTool::handleMouseUp(x, y, mask);
 
+    if (gAgentCamera.cameraMouselook() && gViewerInput.isLMouseHandlingDefault(MODE_FIRST_PERSON))
+    {
+        // LLToolCompGun::handleMouseUp handles the event if ML controls are grabed,
+        // but LLToolGrabBase is often the end point for mouselook clicks if ML controls
+        // are not grabbed and LToolGrabBase::handleMouseUp consumes the event,
+        // so send clicks from here.
+        // We are sending specifically CONTROL_LBUTTON_UP instead of _ML_ version.
+        gAgent.setControlFlags(AGENT_CONTROL_LBUTTON_UP);
+    }
+
 	if( hasMouseCapture() )
 	{
 		setMouseCapture( FALSE );
diff --git a/indra/newview/lltoolmorph.cpp b/indra/newview/lltoolmorph.cpp
index 06a2caf75b36f5d87b9128ad2c37779c8026572c..d99c0ba2a6ae2508534dad913eb23346ec933642 100644
--- a/indra/newview/lltoolmorph.cpp
+++ b/indra/newview/lltoolmorph.cpp
@@ -195,10 +195,7 @@ BOOL LLVisualParamHint::render()
 	gGL.pushMatrix();
 	gGL.loadIdentity();
 
-	if (LLGLSLShader::sNoFixedFunction)
-	{
-		gUIProgram.bind();
-	}
+	gUIProgram.bind();
 
 	LLGLSUIDefault gls_ui;
 	//LLGLState::verify(TRUE);
@@ -242,17 +239,16 @@ BOOL LLVisualParamHint::render()
 
 	LLViewerCamera::getInstance()->setPerspective(FALSE, mOrigin.mX, mOrigin.mY, mFullWidth, mFullHeight, FALSE);
 
-	if (gAgentAvatarp->mDrawable.notNull() &&
-		gAgentAvatarp->mDrawable->getFace(0))
-	{
-		LLDrawPoolAvatar *avatarPoolp = (LLDrawPoolAvatar *)gAgentAvatarp->mDrawable->getFace(0)->getPool();
-		LLGLDepthTest gls_depth(GL_TRUE, GL_TRUE);
-		gGL.setAlphaRejectSettings(LLRender::CF_ALWAYS);
-		gGL.setSceneBlendType(LLRender::BT_REPLACE);
-		avatarPoolp->renderAvatars(gAgentAvatarp);  // renders only one avatar
-		gGL.setSceneBlendType(LLRender::BT_ALPHA);
-		gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
-	}
+    if (gAgentAvatarp->mDrawable.notNull())
+    {
+        LLGLDepthTest gls_depth(GL_TRUE, GL_TRUE);
+        gGL.flush();
+        gGL.setSceneBlendType(LLRender::BT_REPLACE);
+        gPipeline.generateImpostor(gAgentAvatarp, true);
+        gGL.setSceneBlendType(LLRender::BT_ALPHA);
+        gGL.flush();
+    }
+
 	gAgentAvatarp->setVisualParamWeight(mVisualParam->getID(), mLastParamWeight);
 	mWearablePtr->setVisualParamWeight(mVisualParam->getID(), mLastParamWeight);
 	LLViewerWearable* wearable = (LLViewerWearable*)mWearablePtr;
diff --git a/indra/newview/lltoolpie.cpp b/indra/newview/lltoolpie.cpp
index b4736841d639ed2287bf690ef4f89831dbf3b742..5fb83bf08e490a4761aeda3f368cb43811291bd1 100644
--- a/indra/newview/lltoolpie.cpp
+++ b/indra/newview/lltoolpie.cpp
@@ -71,6 +71,7 @@
 #include "llui.h"
 #include "llweb.h"
 #include "pipeline.h"	// setHighlightObject
+#include "lluiusage.h"
 
 extern BOOL gDebugClicks;
 
@@ -394,8 +395,9 @@ BOOL LLToolPie::handleLeftClickPick()
 		gFocusMgr.setKeyboardFocus(NULL);
 	}
 
-	BOOL touchable = (object && object->flagHandleTouch()) 
-					 || (parent && parent->flagHandleTouch());
+    bool touchable = object
+                     && (object->getClickAction() != CLICK_ACTION_DISABLED)
+                     && (object->flagHandleTouch() || (parent && parent->flagHandleTouch()));
 
 	// Switch to grab tool if physical or triggerable
 	if (object && 
@@ -567,6 +569,8 @@ bool LLToolPie::walkToClickedLocation()
         return false;
     }
 
+	LLUIUsage::instance().logCommand("Agent.WalkToClickedLocation");
+	
     LLPickInfo saved_pick = mPick;
     if (gAgentCamera.getCameraMode() != CAMERA_MODE_MOUSELOOK)
     {
@@ -656,6 +660,12 @@ bool LLToolPie::teleportToClickedLocation()
     LLViewerObject* objp = mHoverPick.getObject();
     LLViewerObject* parentp = objp ? objp->getRootEdit() : NULL;
 
+    if (objp && (objp->getAvatar() == gAgentAvatarp || objp == gAgentAvatarp)) // ex: nametag
+    {
+        // Don't teleport to self, teleporting to other avatars is fine
+        return false;
+    }
+
     bool is_in_world = mHoverPick.mObjectID.notNull() && objp && !objp->isHUDAttachment();
     bool is_land = mHoverPick.mPickType == LLPickInfo::PICK_LAND;
     bool pos_non_zero = !mHoverPick.mPosGlobal.isExactlyZero();
@@ -750,7 +760,7 @@ BOOL LLToolPie::handleHover(S32 x, S32 y, MASK mask)
 	else if (!mMouseOutsideSlop 
 		&& mMouseButtonDown
 		// disable camera steering if click on land is not used for moving
-		&& gViewerInput.isMouseBindUsed(CLICK_LEFT))
+		&& gViewerInput.isMouseBindUsed(CLICK_LEFT, MASK_NONE, MODE_THIRD_PERSON))
 	{
 		S32 delta_x = x - mMouseDownX;
 		S32 delta_y = y - mMouseDownY;
diff --git a/indra/newview/lltoolplacer.cpp b/indra/newview/lltoolplacer.cpp
index 814bade56ad675f882e2cb763cd78b7de0349cac..7cdd7cc5c8c5a074664129eff2fd10e0f6c3cd8e 100644
--- a/indra/newview/lltoolplacer.cpp
+++ b/indra/newview/lltoolplacer.cpp
@@ -62,6 +62,7 @@
 #include "llprimitive.h"
 #include "llwindow.h"			// incBusyCount()
 #include "material_codes.h"
+#include "lluiusage.h"
 
 const LLVector3 DEFAULT_OBJECT_SCALE(0.5f, 0.5f, 0.5f);
 
@@ -227,6 +228,7 @@ BOOL LLToolPlacer::addObject( LLPCode pcode, S32 x, S32 y, U8 use_physics )
 							   gAgent.getID(), 1.0f, LLAudioEngine::AUDIO_TYPE_UI);
 	}
 
+	LLUIUsage::instance().logCommand("Build.ObjectAdd");
 	gMessageSystem->newMessageFast(_PREHASH_ObjectAdd);
 	gMessageSystem->nextBlockFast(_PREHASH_AgentData);
 	gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
diff --git a/indra/newview/lltracker.cpp b/indra/newview/lltracker.cpp
index 728d0c9417218af854b2dee3e534fcb76d201f7f..ab4ad5817b95bc89530b74fe855244df48712fa0 100644
--- a/indra/newview/lltracker.cpp
+++ b/indra/newview/lltracker.cpp
@@ -109,7 +109,16 @@ void LLTracker::stopTracking(bool clear_ui)
 // static virtual
 void LLTracker::drawHUDArrow()
 {
-	if (!gSavedSettings.getBOOL("RenderTrackerBeacon")) return;
+    if (!LLWorld::instanceExists())
+    {
+        return;
+    }
+
+    static LLCachedControl<bool> render_beacon(gSavedSettings, "RenderTrackerBeacon", true);
+    if (!render_beacon)
+    {
+        return;
+    }
 
 	if (gViewerWindow->getProgressView()->getVisible()) return;
 
diff --git a/indra/newview/llviewerassetstorage.cpp b/indra/newview/llviewerassetstorage.cpp
index 6aa12731749fcd90ddd84d93d467a95e5bf9b9bb..70065cb5a049698ba081585cd3cdf9076711d33a 100644
--- a/indra/newview/llviewerassetstorage.cpp
+++ b/indra/newview/llviewerassetstorage.cpp
@@ -353,7 +353,7 @@ void LLViewerAssetStorage::checkForTimeouts()
     // Restore requests
     LLCoprocedureManager* manager = LLCoprocedureManager::getInstance();
     while (mCoroWaitList.size() > 0
-           && manager->count(VIEWER_ASSET_STORAGE_CORO_POOL) < LLCoprocedureManager::DEFAULT_QUEUE_SIZE)
+           && manager->count(VIEWER_ASSET_STORAGE_CORO_POOL) < (LLCoprocedureManager::DEFAULT_QUEUE_SIZE - 1))
     {
         CoroWaitList &request = mCoroWaitList.front();
         
@@ -425,13 +425,14 @@ void LLViewerAssetStorage::queueRequestHttp(
     if (!duplicate)
     {
         // Coroutine buffer has fixed size (synchronization buffer, so we have no alternatives), so buffer any request above limit
-        if (LLCoprocedureManager::instance().count(VIEWER_ASSET_STORAGE_CORO_POOL) < LLCoprocedureManager::DEFAULT_QUEUE_SIZE)
+        LLCoprocedureManager* manager = LLCoprocedureManager::getInstance();
+        if (manager->count(VIEWER_ASSET_STORAGE_CORO_POOL) < (LLCoprocedureManager::DEFAULT_QUEUE_SIZE - 1))
         {
             bool with_http = true;
             bool is_temp = false;
             LLViewerAssetStatsFF::record_enqueue(atype, with_http, is_temp);
 
-            LLCoprocedureManager::instance().enqueueCoprocedure(VIEWER_ASSET_STORAGE_CORO_POOL, "LLViewerAssetStorage::assetRequestCoro",
+            manager->enqueueCoprocedure(VIEWER_ASSET_STORAGE_CORO_POOL, "LLViewerAssetStorage::assetRequestCoro",
                 boost::bind(&LLViewerAssetStorage::assetRequestCoro, this, req, uuid, atype, callback, user_data));
         }
         else
diff --git a/indra/newview/llviewerassetupload.cpp b/indra/newview/llviewerassetupload.cpp
index 3f7e8531fb22e3c6625fb0137865745a04de14aa..14fae8d03553495b0555c6d88a1028ba8f21dbdd 100644
--- a/indra/newview/llviewerassetupload.cpp
+++ b/indra/newview/llviewerassetupload.cpp
@@ -50,6 +50,10 @@
 #include "llpreviewnotecard.h"
 #include "llpreviewgesture.h"
 #include "llcoproceduremanager.h"
+#include "llthread.h"
+#include "llkeyframemotion.h"
+#include "lldatapacker.h"
+#include "llvoavatarself.h"
 
 void dialog_refresh_all();
 
@@ -450,9 +454,62 @@ LLSD LLNewFileResourceUploadInfo::exportTempFile()
         errorLabel = "DoNotSupportBulkAnimationUpload";
         error = true;
     }
-    else if (assetType == LLAssetType::AT_ANIMATION)
+    else if (exten == "anim")
+    {
+		// Default unless everything succeeds
+		errorLabel = "ProblemWithFile";
+		error = true;
+
+        // read from getFileName()
+		LLAPRFile infile;
+		infile.open(getFileName(),LL_APR_RB);
+		if (!infile.getFileHandle())
+		{
+			LL_WARNS() << "Couldn't open file for reading: " << getFileName() << LL_ENDL;
+			errorMessage = llformat("Failed to open animation file %s\n", getFileName().c_str());
+		}
+		else
+		{
+			S32 size = LLAPRFile::size(getFileName());
+			U8* buffer = new U8[size];
+			S32 size_read = infile.read(buffer,size);
+			if (size_read != size)
+			{
+				errorMessage = llformat("Failed to read animation file %s: wanted %d bytes, got %d\n", getFileName().c_str(), size, size_read);
+			}
+			else
+			{
+				LLDataPackerBinaryBuffer dp(buffer, size);
+				LLKeyframeMotion *motionp = new LLKeyframeMotion(getAssetId());
+				motionp->setCharacter(gAgentAvatarp);
+				if (motionp->deserialize(dp, getAssetId(), false))
+				{
+					// write to temp file
+					bool succ = motionp->dumpToFile(filename);
+					if (succ)
+					{
+						assetType = LLAssetType::AT_ANIMATION;
+						errorLabel = "";
+						error = false;
+					}
+					else
+					{
+						errorMessage = "Failed saving temporary animation file";
+					}
+				}
+				else
+				{
+					errorMessage = "Failed reading animation file";
+				}
+			}
+		}
+    }
+    else
     {
-        filename = getFileName();
+        // Unknown extension
+        errorMessage = llformat(LLTrans::getString("UnknownFileExtension").c_str(), exten.c_str());
+        errorLabel = "ErrorMessage";
+        error = TRUE;;
     }
 
     if (error)
@@ -863,6 +920,7 @@ void LLViewerAssetUpload::HandleUploadError(LLCore::HttpStatus status, LLSD &res
     {
         args["FILE"] = uploadInfo->getDisplayName();
         args["REASON"] = reason;
+        args["ERROR"] = reason;
     }
 
     LLNotificationsUtil::add(label, args);
diff --git a/indra/newview/llvieweraudio.h b/indra/newview/llvieweraudio.h
index 782285ce36ffab98d09a9e2be047d2a396f28b04..febae36ae8beb5276f69eee7c30799849f9a0715 100644
--- a/indra/newview/llvieweraudio.h
+++ b/indra/newview/llvieweraudio.h
@@ -33,8 +33,6 @@
 // comment out to turn off wind
 #define kAUDIO_ENABLE_WIND 
 //#define kAUDIO_ENABLE_WATER 1	// comment out to turn off water
-#define kAUDIO_NUM_BUFFERS 30
-#define kAUDIO_NUM_SOURCES 30 
 
 void init_audio();
 void audio_update_volume(bool force_update = true);
diff --git a/indra/newview/llviewercamera.cpp b/indra/newview/llviewercamera.cpp
index 27a87ee1a0bce923e33448b3210fae0b6f7fbfb7..5d8e80cc412b0f7af2a8bc21125e52cd1081bd99 100644
--- a/indra/newview/llviewercamera.cpp
+++ b/indra/newview/llviewercamera.cpp
@@ -81,9 +81,6 @@ glh::matrix4f gl_pick_matrix(GLfloat x, GLfloat y, GLfloat width, GLfloat height
 	return glh::matrix4f(m);
 }
 
-// Build time optimization, generate this once in .cpp file
-template class LLViewerCamera* LLSingleton<class LLViewerCamera>::getInstance();
-
 LLViewerCamera::LLViewerCamera() : LLCamera()
 {
 	calcProjection(getFar());
diff --git a/indra/newview/llviewercamera.h b/indra/newview/llviewercamera.h
index fb07a3fb2df41a8482de8e447d3b02cad2fb0a70..549778a841241c72bdb0c30987595f1d1259bbd3 100644
--- a/indra/newview/llviewercamera.h
+++ b/indra/newview/llviewercamera.h
@@ -38,25 +38,11 @@ class LLViewerObject;
 const BOOL FOR_SELECTION = TRUE;
 const BOOL NOT_FOR_SELECTION = FALSE;
 
-// Build time optimization, generate this once in .cpp file
-#ifndef LLVIEWERCAMERA_CPP
-extern template class LLViewerCamera* LLSingleton<class LLViewerCamera>::getInstance();
-#endif
-
-LL_ALIGN_PREFIX(16)
-class LLViewerCamera : public LLCamera, public LLSingleton<LLViewerCamera>
+class alignas(16) LLViewerCamera : public LLCamera, public LLSimpleton<LLViewerCamera>
 {
-	LLSINGLETON(LLViewerCamera);
+    LL_ALIGN_NEW
 public:
-	void* operator new(size_t size)
-	{
-		return ll_aligned_malloc_16(size);
-	}
-
-	void operator delete(void* ptr)
-	{
-		ll_aligned_free_16(ptr);
-	}
+    LLViewerCamera();
 
 	typedef enum
 	{
@@ -141,7 +127,7 @@ class LLViewerCamera : public LLCamera, public LLSingleton<LLViewerCamera>
 	S16					mZoomSubregion;
 
 public:
-} LL_ALIGN_POSTFIX(16);
+};
 
 
 #endif // LL_LLVIEWERCAMERA_H
diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp
index bc425123e10326f891ae53ca4d858dd81972995c..bc46a61fb0a8fe95da5dbf2490af065c0a61ea2e 100644
--- a/indra/newview/llviewercontrol.cpp
+++ b/indra/newview/llviewercontrol.cpp
@@ -107,10 +107,14 @@ static bool handleRenderAvatarMouselookChanged(const LLSD& newvalue)
 
 static bool handleRenderFarClipChanged(const LLSD& newvalue)
 {
-	F32 draw_distance = (F32) newvalue.asReal();
+    if (LLStartUp::getStartupState() >= STATE_STARTED)
+    {
+        F32 draw_distance = (F32)newvalue.asReal();
 	gAgentCamera.mDrawDistance = draw_distance;
 	LLWorld::getInstance()->setLandFarClip(draw_distance);
 	return true;
+    }
+    return false;
 }
 
 static bool handleTerrainDetailChanged(const LLSD& newvalue)
@@ -162,17 +166,6 @@ static bool handleSetShaderChanged(const LLSD& newvalue)
 	return true;
 }
 
-static bool handleAvatarVPChanged(const LLSD& newvalue)
-{
-    LLRenderTarget::sUseFBO = newvalue.asBoolean()
-                                && gSavedSettings.getBOOL("RenderObjectBump")
-                                && gSavedSettings.getBOOL("RenderTransparentWater")
-                                && gSavedSettings.getBOOL("RenderDeferred");
-
-    handleSetShaderChanged(LLSD());
-    return true;
-}
-
 static bool handleRenderPerfTestChanged(const LLSD& newvalue)
 {
        bool status = !newvalue.asBoolean();
@@ -212,10 +205,6 @@ static bool handleRenderPerfTestChanged(const LLSD& newvalue)
 
 bool handleRenderTransparentWaterChanged(const LLSD& newvalue)
 {
-    LLRenderTarget::sUseFBO = newvalue.asBoolean() 
-                                && gSavedSettings.getBOOL("RenderObjectBump") 
-                                && gSavedSettings.getBOOL("RenderAvatarVP") 
-                                && gSavedSettings.getBOOL("RenderDeferred");
 	if (gPipeline.isInit())
 	{
 		gPipeline.updateRenderTransparentWater();
@@ -269,6 +258,13 @@ static bool handleAnisotropicChanged(const LLSD& newvalue)
 	return true;
 }
 
+static bool handleVSyncChanged(const LLSD& newvalue)
+{
+    gViewerWindow->getWindow()->toggleVSync(newvalue.asBoolean());
+
+    return true;
+}
+
 static bool handleVolumeLODChanged(const LLSD& newvalue)
 {
 	LLVOVolume::sLODFactor = llclamp((F32) newvalue.asReal(), 0.01f, MAX_LOD_FACTOR);
@@ -391,7 +387,7 @@ static bool handleJoystickChanged(const LLSD& newvalue)
 
 static bool handleUseOcclusionChanged(const LLSD& newvalue)
 {
-	LLPipeline::sUseOcclusion = (newvalue.asBoolean() && gGLManager.mHasOcclusionQuery && LLGLSLShader::sNoFixedFunction
+	LLPipeline::sUseOcclusion = (newvalue.asBoolean() && gGLManager.mHasOcclusionQuery
 		&& LLFeatureManager::getInstance()->isFeatureAvailable("UseOcclusion") && !gUseWireframe) ? 2 : 0;
 	return true;
 }
@@ -468,10 +464,7 @@ static bool handleRenderDeferredChanged(const LLSD& newvalue)
 //
 static bool handleRenderBumpChanged(const LLSD& newval)
 {
-    LLRenderTarget::sUseFBO = newval.asBoolean() 
-                                && gSavedSettings.getBOOL("RenderTransparentWater") 
-                                && gSavedSettings.getBOOL("RenderAvatarVP")
-                                && gSavedSettings.getBOOL("RenderDeferred");
+    LLRenderTarget::sUseFBO = newval.asBoolean() && gSavedSettings.getBOOL("RenderDeferred");
 	if (gPipeline.isInit())
 	{
 		gPipeline.updateRenderBump();
@@ -484,13 +477,6 @@ static bool handleRenderBumpChanged(const LLSD& newval)
 	return true;
 }
 
-static bool handleRenderDebugGLChanged(const LLSD& newvalue)
-{
-	gDebugGL = newvalue.asBoolean() || gDebugSession;
-	gGL.clearErrors();
-	return true;
-}
-
 static bool handleRenderDebugPipelineChanged(const LLSD& newvalue)
 {
 	gDebugPipeline = newvalue.asBoolean();
@@ -653,158 +639,186 @@ bool toggle_show_object_render_cost(const LLSD& newvalue)
 void handleRenderAutoMuteByteLimitChanged(const LLSD& new_value);
 ////////////////////////////////////////////////////////////////////////////
 
+LLPointer<LLControlVariable> setting_get_control(LLControlGroup& group, const std::string& setting)
+{
+    LLPointer<LLControlVariable> cntrl_ptr = group.getControl(setting);
+    if (cntrl_ptr.isNull())
+    {
+        LL_ERRS() << "Unable to set up setting listener for " << setting
+            << ". Please reinstall viewer from  https ://secondlife.com/support/downloads/ and contact https://support.secondlife.com if issue persists after reinstall."
+            << LL_ENDL;
+    }
+    return cntrl_ptr;
+}
+
+void setting_setup_signal_listener(LLControlGroup& group, const std::string& setting, std::function<void(const LLSD& newvalue)> callback)
+{
+    setting_get_control(group, setting)->getSignal()->connect([callback](LLControlVariable* control, const LLSD& new_val, const LLSD& old_val)
+    {
+        callback(new_val);
+    });
+}
+
+void setting_setup_signal_listener(LLControlGroup& group, const std::string& setting, std::function<void()> callback)
+{
+    setting_get_control(group, setting)->getSignal()->connect([callback](LLControlVariable* control, const LLSD& new_val, const LLSD& old_val)
+    {
+        callback();
+    });
+}
+
 void settings_setup_listeners()
 {
-	gSavedSettings.getControl("FirstPersonAvatarVisible")->getSignal()->connect(boost::bind(&handleRenderAvatarMouselookChanged, _2));
-	gSavedSettings.getControl("RenderFarClip")->getSignal()->connect(boost::bind(&handleRenderFarClipChanged, _2));
-	gSavedSettings.getControl("RenderTerrainDetail")->getSignal()->connect(boost::bind(&handleTerrainDetailChanged, _2));
-	gSavedSettings.getControl("OctreeStaticObjectSizeFactor")->getSignal()->connect(boost::bind(&handleRepartition, _2));
-	gSavedSettings.getControl("OctreeDistanceFactor")->getSignal()->connect(boost::bind(&handleRepartition, _2));
-	gSavedSettings.getControl("OctreeMaxNodeCapacity")->getSignal()->connect(boost::bind(&handleRepartition, _2));
-	gSavedSettings.getControl("OctreeAlphaDistanceFactor")->getSignal()->connect(boost::bind(&handleRepartition, _2));
-	gSavedSettings.getControl("OctreeAttachmentSizeFactor")->getSignal()->connect(boost::bind(&handleRepartition, _2));
-	gSavedSettings.getControl("RenderMaxTextureIndex")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _2));
-	gSavedSettings.getControl("RenderUseTriStrips")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _2));
-	gSavedSettings.getControl("RenderAvatarVP")->getSignal()->connect(boost::bind(&handleAvatarVPChanged, _2));
-	gSavedSettings.getControl("RenderUIBuffer")->getSignal()->connect(boost::bind(&handleWindowResized, _2));
-	gSavedSettings.getControl("RenderDepthOfField")->getSignal()->connect(boost::bind(&handleReleaseGLBufferChanged, _2));
-	gSavedSettings.getControl("RenderFSAASamples")->getSignal()->connect(boost::bind(&handleReleaseGLBufferChanged, _2));
-	gSavedSettings.getControl("RenderSpecularResX")->getSignal()->connect(boost::bind(&handleLUTBufferChanged, _2));
-	gSavedSettings.getControl("RenderSpecularResY")->getSignal()->connect(boost::bind(&handleLUTBufferChanged, _2));
-	gSavedSettings.getControl("RenderSpecularExponent")->getSignal()->connect(boost::bind(&handleLUTBufferChanged, _2));
-	gSavedSettings.getControl("RenderAnisotropic")->getSignal()->connect(boost::bind(&handleAnisotropicChanged, _2));
-	gSavedSettings.getControl("RenderShadowResolutionScale")->getSignal()->connect(boost::bind(&handleShadowsResized, _2));
-	gSavedSettings.getControl("RenderGlow")->getSignal()->connect(boost::bind(&handleReleaseGLBufferChanged, _2));
-	gSavedSettings.getControl("RenderGlow")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _2));
-	gSavedSettings.getControl("RenderGlowResolutionPow")->getSignal()->connect(boost::bind(&handleReleaseGLBufferChanged, _2));
-	gSavedSettings.getControl("RenderAvatarCloth")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _2));
-	gSavedSettings.getControl("WindLightUseAtmosShaders")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _2));
-	gSavedSettings.getControl("RenderGammaFull")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _2));
-	gSavedSettings.getControl("RenderVolumeLODFactor")->getSignal()->connect(boost::bind(&handleVolumeLODChanged, _2));
-	gSavedSettings.getControl("RenderAvatarLODFactor")->getSignal()->connect(boost::bind(&handleAvatarLODChanged, _2));
-	gSavedSettings.getControl("RenderAvatarPhysicsLODFactor")->getSignal()->connect(boost::bind(&handleAvatarPhysicsLODChanged, _2));
-	gSavedSettings.getControl("RenderTerrainLODFactor")->getSignal()->connect(boost::bind(&handleTerrainLODChanged, _2));
-	gSavedSettings.getControl("RenderTreeLODFactor")->getSignal()->connect(boost::bind(&handleTreeLODChanged, _2));
-	gSavedSettings.getControl("RenderFlexTimeFactor")->getSignal()->connect(boost::bind(&handleFlexLODChanged, _2));
-	gSavedSettings.getControl("RenderGamma")->getSignal()->connect(boost::bind(&handleGammaChanged, _2));
-	gSavedSettings.getControl("RenderFogRatio")->getSignal()->connect(boost::bind(&handleFogRatioChanged, _2));
-	gSavedSettings.getControl("RenderMaxPartCount")->getSignal()->connect(boost::bind(&handleMaxPartCountChanged, _2));
-	gSavedSettings.getControl("RenderDynamicLOD")->getSignal()->connect(boost::bind(&handleRenderDynamicLODChanged, _2));
-	gSavedSettings.getControl("RenderLocalLights")->getSignal()->connect(boost::bind(&handleRenderLocalLightsChanged, _2));
-	gSavedSettings.getControl("RenderDebugTextureBind")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _2));
-	gSavedSettings.getControl("RenderAutoMaskAlphaDeferred")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _2));
-	gSavedSettings.getControl("RenderAutoMaskAlphaNonDeferred")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _2));
-	gSavedSettings.getControl("RenderObjectBump")->getSignal()->connect(boost::bind(&handleRenderBumpChanged, _2));
-	gSavedSettings.getControl("RenderMaxVBOSize")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _2));
-	gSavedSettings.getControl("RenderDeferredNoise")->getSignal()->connect(boost::bind(&handleReleaseGLBufferChanged, _2));
-	gSavedSettings.getControl("RenderDebugGL")->getSignal()->connect(boost::bind(&handleRenderDebugGLChanged, _2));
-	gSavedSettings.getControl("RenderDebugPipeline")->getSignal()->connect(boost::bind(&handleRenderDebugPipelineChanged, _2));
-	gSavedSettings.getControl("RenderResolutionDivisor")->getSignal()->connect(boost::bind(&handleRenderResolutionDivisorChanged, _2));
-	gSavedSettings.getControl("RenderDeferred")->getSignal()->connect(boost::bind(&handleRenderDeferredChanged, _2));
-	gSavedSettings.getControl("RenderShadowDetail")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _2));
-	gSavedSettings.getControl("RenderDeferredSSAO")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _2));
-	gSavedSettings.getControl("RenderPerformanceTest")->getSignal()->connect(boost::bind(&handleRenderPerfTestChanged, _2));
-	gSavedSettings.getControl("TextureMemory")->getSignal()->connect(boost::bind(&handleVideoMemoryChanged, _2));
-	gSavedSettings.getControl("ChatFontSize")->getSignal()->connect(boost::bind(&handleChatFontSizeChanged, _2));
-	gSavedSettings.getControl("ChatPersistTime")->getSignal()->connect(boost::bind(&handleChatPersistTimeChanged, _2));
-	gSavedSettings.getControl("ConsoleMaxLines")->getSignal()->connect(boost::bind(&handleConsoleMaxLinesChanged, _2));
-	gSavedSettings.getControl("UploadBakedTexOld")->getSignal()->connect(boost::bind(&handleUploadBakedTexOldChanged, _2));
-	gSavedSettings.getControl("UseOcclusion")->getSignal()->connect(boost::bind(&handleUseOcclusionChanged, _2));
-	gSavedSettings.getControl("AudioLevelMaster")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _2));
-	gSavedSettings.getControl("AudioLevelSFX")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _2));
-	gSavedSettings.getControl("AudioLevelUI")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _2));
-	gSavedSettings.getControl("AudioLevelAmbient")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _2));
-	gSavedSettings.getControl("AudioLevelMusic")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _2));
-	gSavedSettings.getControl("AudioLevelMedia")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _2));
-	gSavedSettings.getControl("AudioLevelVoice")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _2));
-	gSavedSettings.getControl("AudioLevelDoppler")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _2));
-	gSavedSettings.getControl("AudioLevelRolloff")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _2));
-	gSavedSettings.getControl("AudioLevelUnderwaterRolloff")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _2));
-	gSavedSettings.getControl("MuteAudio")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _2));
-	gSavedSettings.getControl("MuteMusic")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _2));
-	gSavedSettings.getControl("MuteMedia")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _2));
-	gSavedSettings.getControl("MuteVoice")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _2));
-	gSavedSettings.getControl("MuteAmbient")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _2));
-	gSavedSettings.getControl("MuteUI")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _2));
-	gSavedSettings.getControl("RenderVBOEnable")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _2));
-	gSavedSettings.getControl("RenderUseVAO")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _2));
-	gSavedSettings.getControl("RenderVBOMappingDisable")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _2));
-	gSavedSettings.getControl("RenderUseStreamVBO")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _2));
-	gSavedSettings.getControl("RenderPreferStreamDraw")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _2));
-	gSavedSettings.getControl("WLSkyDetail")->getSignal()->connect(boost::bind(&handleWLSkyDetailChanged, _2));
-	gSavedSettings.getControl("JoystickAxis0")->getSignal()->connect(boost::bind(&handleJoystickChanged, _2));
-	gSavedSettings.getControl("JoystickAxis1")->getSignal()->connect(boost::bind(&handleJoystickChanged, _2));
-	gSavedSettings.getControl("JoystickAxis2")->getSignal()->connect(boost::bind(&handleJoystickChanged, _2));
-	gSavedSettings.getControl("JoystickAxis3")->getSignal()->connect(boost::bind(&handleJoystickChanged, _2));
-	gSavedSettings.getControl("JoystickAxis4")->getSignal()->connect(boost::bind(&handleJoystickChanged, _2));
-	gSavedSettings.getControl("JoystickAxis5")->getSignal()->connect(boost::bind(&handleJoystickChanged, _2));
-	gSavedSettings.getControl("JoystickAxis6")->getSignal()->connect(boost::bind(&handleJoystickChanged, _2));
-	gSavedSettings.getControl("FlycamAxisScale0")->getSignal()->connect(boost::bind(&handleJoystickChanged, _2));
-	gSavedSettings.getControl("FlycamAxisScale1")->getSignal()->connect(boost::bind(&handleJoystickChanged, _2));
-	gSavedSettings.getControl("FlycamAxisScale2")->getSignal()->connect(boost::bind(&handleJoystickChanged, _2));
-	gSavedSettings.getControl("FlycamAxisScale3")->getSignal()->connect(boost::bind(&handleJoystickChanged, _2));
-	gSavedSettings.getControl("FlycamAxisScale4")->getSignal()->connect(boost::bind(&handleJoystickChanged, _2));
-	gSavedSettings.getControl("FlycamAxisScale5")->getSignal()->connect(boost::bind(&handleJoystickChanged, _2));
-	gSavedSettings.getControl("FlycamAxisScale6")->getSignal()->connect(boost::bind(&handleJoystickChanged, _2));
-	gSavedSettings.getControl("FlycamAxisDeadZone0")->getSignal()->connect(boost::bind(&handleJoystickChanged, _2));
-	gSavedSettings.getControl("FlycamAxisDeadZone1")->getSignal()->connect(boost::bind(&handleJoystickChanged, _2));
-	gSavedSettings.getControl("FlycamAxisDeadZone2")->getSignal()->connect(boost::bind(&handleJoystickChanged, _2));
-	gSavedSettings.getControl("FlycamAxisDeadZone3")->getSignal()->connect(boost::bind(&handleJoystickChanged, _2));
-	gSavedSettings.getControl("FlycamAxisDeadZone4")->getSignal()->connect(boost::bind(&handleJoystickChanged, _2));
-	gSavedSettings.getControl("FlycamAxisDeadZone5")->getSignal()->connect(boost::bind(&handleJoystickChanged, _2));
-	gSavedSettings.getControl("FlycamAxisDeadZone6")->getSignal()->connect(boost::bind(&handleJoystickChanged, _2));
-	gSavedSettings.getControl("AvatarAxisScale0")->getSignal()->connect(boost::bind(&handleJoystickChanged, _2));
-	gSavedSettings.getControl("AvatarAxisScale1")->getSignal()->connect(boost::bind(&handleJoystickChanged, _2));
-	gSavedSettings.getControl("AvatarAxisScale2")->getSignal()->connect(boost::bind(&handleJoystickChanged, _2));
-	gSavedSettings.getControl("AvatarAxisScale3")->getSignal()->connect(boost::bind(&handleJoystickChanged, _2));
-	gSavedSettings.getControl("AvatarAxisScale4")->getSignal()->connect(boost::bind(&handleJoystickChanged, _2));
-	gSavedSettings.getControl("AvatarAxisScale5")->getSignal()->connect(boost::bind(&handleJoystickChanged, _2));
-	gSavedSettings.getControl("AvatarAxisDeadZone0")->getSignal()->connect(boost::bind(&handleJoystickChanged, _2));
-	gSavedSettings.getControl("AvatarAxisDeadZone1")->getSignal()->connect(boost::bind(&handleJoystickChanged, _2));
-	gSavedSettings.getControl("AvatarAxisDeadZone2")->getSignal()->connect(boost::bind(&handleJoystickChanged, _2));
-	gSavedSettings.getControl("AvatarAxisDeadZone3")->getSignal()->connect(boost::bind(&handleJoystickChanged, _2));
-	gSavedSettings.getControl("AvatarAxisDeadZone4")->getSignal()->connect(boost::bind(&handleJoystickChanged, _2));
-	gSavedSettings.getControl("AvatarAxisDeadZone5")->getSignal()->connect(boost::bind(&handleJoystickChanged, _2));
-	gSavedSettings.getControl("BuildAxisScale0")->getSignal()->connect(boost::bind(&handleJoystickChanged, _2));
-	gSavedSettings.getControl("BuildAxisScale1")->getSignal()->connect(boost::bind(&handleJoystickChanged, _2));
-	gSavedSettings.getControl("BuildAxisScale2")->getSignal()->connect(boost::bind(&handleJoystickChanged, _2));
-	gSavedSettings.getControl("BuildAxisScale3")->getSignal()->connect(boost::bind(&handleJoystickChanged, _2));
-	gSavedSettings.getControl("BuildAxisScale4")->getSignal()->connect(boost::bind(&handleJoystickChanged, _2));
-	gSavedSettings.getControl("BuildAxisScale5")->getSignal()->connect(boost::bind(&handleJoystickChanged, _2));
-	gSavedSettings.getControl("BuildAxisDeadZone0")->getSignal()->connect(boost::bind(&handleJoystickChanged, _2));
-	gSavedSettings.getControl("BuildAxisDeadZone1")->getSignal()->connect(boost::bind(&handleJoystickChanged, _2));
-	gSavedSettings.getControl("BuildAxisDeadZone2")->getSignal()->connect(boost::bind(&handleJoystickChanged, _2));
-	gSavedSettings.getControl("BuildAxisDeadZone3")->getSignal()->connect(boost::bind(&handleJoystickChanged, _2));
-	gSavedSettings.getControl("BuildAxisDeadZone4")->getSignal()->connect(boost::bind(&handleJoystickChanged, _2));
-	gSavedSettings.getControl("BuildAxisDeadZone5")->getSignal()->connect(boost::bind(&handleJoystickChanged, _2));
-	gSavedSettings.getControl("DebugViews")->getSignal()->connect(boost::bind(&handleDebugViewsChanged, _2));
-	gSavedSettings.getControl("UserLogFile")->getSignal()->connect(boost::bind(&handleLogFileChanged, _2));
-	gSavedSettings.getControl("RenderHideGroupTitle")->getSignal()->connect(boost::bind(handleHideGroupTitleChanged, _2));
-	gSavedSettings.getControl("HighResSnapshot")->getSignal()->connect(boost::bind(handleHighResSnapshotChanged, _2));
-	gSavedSettings.getControl("EnableVoiceChat")->getSignal()->connect(boost::bind(&handleVoiceClientPrefsChanged, _2));
-	gSavedSettings.getControl("PTTCurrentlyEnabled")->getSignal()->connect(boost::bind(&handleVoiceClientPrefsChanged, _2));
-	gSavedSettings.getControl("PushToTalkButton")->getSignal()->connect(boost::bind(&handleVoiceClientPrefsChanged, _2));
-	gSavedSettings.getControl("PushToTalkToggle")->getSignal()->connect(boost::bind(&handleVoiceClientPrefsChanged, _2));
-	gSavedSettings.getControl("VoiceEarLocation")->getSignal()->connect(boost::bind(&handleVoiceClientPrefsChanged, _2));
-	gSavedSettings.getControl("VoiceInputAudioDevice")->getSignal()->connect(boost::bind(&handleVoiceClientPrefsChanged, _2));
-	gSavedSettings.getControl("VoiceOutputAudioDevice")->getSignal()->connect(boost::bind(&handleVoiceClientPrefsChanged, _2));
-	gSavedSettings.getControl("AudioLevelMic")->getSignal()->connect(boost::bind(&handleVoiceClientPrefsChanged, _2));
-	gSavedSettings.getControl("LipSyncEnabled")->getSignal()->connect(boost::bind(&handleVoiceClientPrefsChanged, _2));	
-	gSavedSettings.getControl("VelocityInterpolate")->getSignal()->connect(boost::bind(&handleVelocityInterpolate, _2));
-	gSavedSettings.getControl("QAMode")->getSignal()->connect(boost::bind(&show_debug_menus));
-	gSavedSettings.getControl("UseDebugMenus")->getSignal()->connect(boost::bind(&show_debug_menus));
-	gSavedSettings.getControl("AgentPause")->getSignal()->connect(boost::bind(&toggle_agent_pause, _2));
-	gSavedSettings.getControl("ShowNavbarNavigationPanel")->getSignal()->connect(boost::bind(&toggle_show_navigation_panel, _2));
-	gSavedSettings.getControl("ShowMiniLocationPanel")->getSignal()->connect(boost::bind(&toggle_show_mini_location_panel, _2));
-	gSavedSettings.getControl("ShowObjectRenderingCost")->getSignal()->connect(boost::bind(&toggle_show_object_render_cost, _2));
-	gSavedSettings.getControl("ForceShowGrid")->getSignal()->connect(boost::bind(&handleForceShowGrid, _2));
-	gSavedSettings.getControl("RenderTransparentWater")->getSignal()->connect(boost::bind(&handleRenderTransparentWaterChanged, _2));
-	gSavedSettings.getControl("SpellCheck")->getSignal()->connect(boost::bind(&handleSpellCheckChanged));
-	gSavedSettings.getControl("SpellCheckDictionary")->getSignal()->connect(boost::bind(&handleSpellCheckChanged));
-	gSavedSettings.getControl("LoginLocation")->getSignal()->connect(boost::bind(&handleLoginLocationChanged));
-	gSavedSettings.getControl("DebugAvatarJoints")->getCommitSignal()->connect(boost::bind(&handleDebugAvatarJointsChanged, _2));
-	gSavedSettings.getControl("RenderAutoMuteByteLimit")->getSignal()->connect(boost::bind(&handleRenderAutoMuteByteLimitChanged, _2));
-	gSavedPerAccountSettings.getControl("AvatarHoverOffsetZ")->getCommitSignal()->connect(boost::bind(&handleAvatarHoverOffsetChanged, _2));
+    setting_setup_signal_listener(gSavedSettings, "FirstPersonAvatarVisible", handleRenderAvatarMouselookChanged);
+	setting_setup_signal_listener(gSavedSettings, "RenderFarClip", handleRenderFarClipChanged);
+	setting_setup_signal_listener(gSavedSettings, "RenderTerrainDetail", handleTerrainDetailChanged);
+	setting_setup_signal_listener(gSavedSettings, "OctreeStaticObjectSizeFactor", handleRepartition);
+	setting_setup_signal_listener(gSavedSettings, "OctreeDistanceFactor", handleRepartition);
+	setting_setup_signal_listener(gSavedSettings, "OctreeMaxNodeCapacity", handleRepartition);
+	setting_setup_signal_listener(gSavedSettings, "OctreeAlphaDistanceFactor", handleRepartition);
+	setting_setup_signal_listener(gSavedSettings, "OctreeAttachmentSizeFactor", handleRepartition);
+	setting_setup_signal_listener(gSavedSettings, "RenderMaxTextureIndex", handleSetShaderChanged);
+	setting_setup_signal_listener(gSavedSettings, "RenderUseTriStrips", handleResetVertexBuffersChanged);
+	setting_setup_signal_listener(gSavedSettings, "RenderUIBuffer", handleWindowResized);
+	setting_setup_signal_listener(gSavedSettings, "RenderDepthOfField", handleReleaseGLBufferChanged);
+	setting_setup_signal_listener(gSavedSettings, "RenderFSAASamples", handleReleaseGLBufferChanged);
+	setting_setup_signal_listener(gSavedSettings, "RenderSpecularResX", handleLUTBufferChanged);
+	setting_setup_signal_listener(gSavedSettings, "RenderSpecularResY", handleLUTBufferChanged);
+	setting_setup_signal_listener(gSavedSettings, "RenderSpecularExponent", handleLUTBufferChanged);
+	setting_setup_signal_listener(gSavedSettings, "RenderAnisotropic", handleAnisotropicChanged);
+	setting_setup_signal_listener(gSavedSettings, "RenderShadowResolutionScale", handleShadowsResized);
+	setting_setup_signal_listener(gSavedSettings, "RenderGlow", handleReleaseGLBufferChanged);
+	setting_setup_signal_listener(gSavedSettings, "RenderGlow", handleSetShaderChanged);
+	setting_setup_signal_listener(gSavedSettings, "RenderGlowResolutionPow", handleReleaseGLBufferChanged);
+	setting_setup_signal_listener(gSavedSettings, "RenderAvatarCloth", handleSetShaderChanged);
+	setting_setup_signal_listener(gSavedSettings, "WindLightUseAtmosShaders", handleSetShaderChanged);
+	setting_setup_signal_listener(gSavedSettings, "RenderGammaFull", handleSetShaderChanged);
+	setting_setup_signal_listener(gSavedSettings, "RenderVolumeLODFactor", handleVolumeLODChanged);
+	setting_setup_signal_listener(gSavedSettings, "RenderAvatarLODFactor", handleAvatarLODChanged);
+	setting_setup_signal_listener(gSavedSettings, "RenderAvatarPhysicsLODFactor", handleAvatarPhysicsLODChanged);
+	setting_setup_signal_listener(gSavedSettings, "RenderTerrainLODFactor", handleTerrainLODChanged);
+	setting_setup_signal_listener(gSavedSettings, "RenderTreeLODFactor", handleTreeLODChanged);
+	setting_setup_signal_listener(gSavedSettings, "RenderFlexTimeFactor", handleFlexLODChanged);
+	setting_setup_signal_listener(gSavedSettings, "RenderGamma", handleGammaChanged);
+	setting_setup_signal_listener(gSavedSettings, "RenderFogRatio", handleFogRatioChanged);
+	setting_setup_signal_listener(gSavedSettings, "RenderMaxPartCount", handleMaxPartCountChanged);
+	setting_setup_signal_listener(gSavedSettings, "RenderDynamicLOD", handleRenderDynamicLODChanged);
+	setting_setup_signal_listener(gSavedSettings, "RenderLocalLights", handleRenderLocalLightsChanged);
+	setting_setup_signal_listener(gSavedSettings, "RenderDebugTextureBind", handleResetVertexBuffersChanged);
+	setting_setup_signal_listener(gSavedSettings, "RenderAutoMaskAlphaDeferred", handleResetVertexBuffersChanged);
+	setting_setup_signal_listener(gSavedSettings, "RenderAutoMaskAlphaNonDeferred", handleResetVertexBuffersChanged);
+	setting_setup_signal_listener(gSavedSettings, "RenderObjectBump", handleRenderBumpChanged);
+	setting_setup_signal_listener(gSavedSettings, "RenderMaxVBOSize", handleResetVertexBuffersChanged);
+    setting_setup_signal_listener(gSavedSettings, "RenderVSyncEnable", handleVSyncChanged);
+	setting_setup_signal_listener(gSavedSettings, "RenderDeferredNoise", handleReleaseGLBufferChanged);
+	setting_setup_signal_listener(gSavedSettings, "RenderDebugPipeline", handleRenderDebugPipelineChanged);
+	setting_setup_signal_listener(gSavedSettings, "RenderResolutionDivisor", handleRenderResolutionDivisorChanged);
+	setting_setup_signal_listener(gSavedSettings, "RenderDeferred", handleRenderDeferredChanged);
+	setting_setup_signal_listener(gSavedSettings, "RenderShadowDetail", handleSetShaderChanged);
+	setting_setup_signal_listener(gSavedSettings, "RenderDeferredSSAO", handleSetShaderChanged);
+	setting_setup_signal_listener(gSavedSettings, "RenderPerformanceTest", handleRenderPerfTestChanged);
+	setting_setup_signal_listener(gSavedSettings, "TextureMemory", handleVideoMemoryChanged);
+	setting_setup_signal_listener(gSavedSettings, "ChatFontSize", handleChatFontSizeChanged);
+	setting_setup_signal_listener(gSavedSettings, "ChatPersistTime", handleChatPersistTimeChanged);
+	setting_setup_signal_listener(gSavedSettings, "ConsoleMaxLines", handleConsoleMaxLinesChanged);
+	setting_setup_signal_listener(gSavedSettings, "UploadBakedTexOld", handleUploadBakedTexOldChanged);
+	setting_setup_signal_listener(gSavedSettings, "UseOcclusion", handleUseOcclusionChanged);
+	setting_setup_signal_listener(gSavedSettings, "AudioLevelMaster", handleAudioVolumeChanged);
+	setting_setup_signal_listener(gSavedSettings, "AudioLevelSFX", handleAudioVolumeChanged);
+	setting_setup_signal_listener(gSavedSettings, "AudioLevelUI", handleAudioVolumeChanged);
+	setting_setup_signal_listener(gSavedSettings, "AudioLevelAmbient", handleAudioVolumeChanged);
+	setting_setup_signal_listener(gSavedSettings, "AudioLevelMusic", handleAudioVolumeChanged);
+	setting_setup_signal_listener(gSavedSettings, "AudioLevelMedia", handleAudioVolumeChanged);
+	setting_setup_signal_listener(gSavedSettings, "AudioLevelVoice", handleAudioVolumeChanged);
+	setting_setup_signal_listener(gSavedSettings, "AudioLevelDoppler", handleAudioVolumeChanged);
+	setting_setup_signal_listener(gSavedSettings, "AudioLevelRolloff", handleAudioVolumeChanged);
+	setting_setup_signal_listener(gSavedSettings, "AudioLevelUnderwaterRolloff", handleAudioVolumeChanged);
+	setting_setup_signal_listener(gSavedSettings, "MuteAudio", handleAudioVolumeChanged);
+	setting_setup_signal_listener(gSavedSettings, "MuteMusic", handleAudioVolumeChanged);
+	setting_setup_signal_listener(gSavedSettings, "MuteMedia", handleAudioVolumeChanged);
+	setting_setup_signal_listener(gSavedSettings, "MuteVoice", handleAudioVolumeChanged);
+	setting_setup_signal_listener(gSavedSettings, "MuteAmbient", handleAudioVolumeChanged);
+	setting_setup_signal_listener(gSavedSettings, "MuteUI", handleAudioVolumeChanged);
+	setting_setup_signal_listener(gSavedSettings, "RenderVBOEnable", handleResetVertexBuffersChanged);
+	setting_setup_signal_listener(gSavedSettings, "RenderUseVAO", handleResetVertexBuffersChanged);
+	setting_setup_signal_listener(gSavedSettings, "RenderVBOMappingDisable", handleResetVertexBuffersChanged);
+	setting_setup_signal_listener(gSavedSettings, "RenderUseStreamVBO", handleResetVertexBuffersChanged);
+	setting_setup_signal_listener(gSavedSettings, "RenderPreferStreamDraw", handleResetVertexBuffersChanged);
+	setting_setup_signal_listener(gSavedSettings, "WLSkyDetail", handleWLSkyDetailChanged);
+	setting_setup_signal_listener(gSavedSettings, "JoystickAxis0", handleJoystickChanged);
+	setting_setup_signal_listener(gSavedSettings, "JoystickAxis1", handleJoystickChanged);
+	setting_setup_signal_listener(gSavedSettings, "JoystickAxis2", handleJoystickChanged);
+	setting_setup_signal_listener(gSavedSettings, "JoystickAxis3", handleJoystickChanged);
+	setting_setup_signal_listener(gSavedSettings, "JoystickAxis4", handleJoystickChanged);
+	setting_setup_signal_listener(gSavedSettings, "JoystickAxis5", handleJoystickChanged);
+	setting_setup_signal_listener(gSavedSettings, "JoystickAxis6", handleJoystickChanged);
+	setting_setup_signal_listener(gSavedSettings, "FlycamAxisScale0", handleJoystickChanged);
+	setting_setup_signal_listener(gSavedSettings, "FlycamAxisScale1", handleJoystickChanged);
+	setting_setup_signal_listener(gSavedSettings, "FlycamAxisScale2", handleJoystickChanged);
+	setting_setup_signal_listener(gSavedSettings, "FlycamAxisScale3", handleJoystickChanged);
+	setting_setup_signal_listener(gSavedSettings, "FlycamAxisScale4", handleJoystickChanged);
+	setting_setup_signal_listener(gSavedSettings, "FlycamAxisScale5", handleJoystickChanged);
+	setting_setup_signal_listener(gSavedSettings, "FlycamAxisScale6", handleJoystickChanged);
+	setting_setup_signal_listener(gSavedSettings, "FlycamAxisDeadZone0", handleJoystickChanged);
+	setting_setup_signal_listener(gSavedSettings, "FlycamAxisDeadZone1", handleJoystickChanged);
+	setting_setup_signal_listener(gSavedSettings, "FlycamAxisDeadZone2", handleJoystickChanged);
+	setting_setup_signal_listener(gSavedSettings, "FlycamAxisDeadZone3", handleJoystickChanged);
+	setting_setup_signal_listener(gSavedSettings, "FlycamAxisDeadZone4", handleJoystickChanged);
+	setting_setup_signal_listener(gSavedSettings, "FlycamAxisDeadZone5", handleJoystickChanged);
+	setting_setup_signal_listener(gSavedSettings, "FlycamAxisDeadZone6", handleJoystickChanged);
+	setting_setup_signal_listener(gSavedSettings, "AvatarAxisScale0", handleJoystickChanged);
+	setting_setup_signal_listener(gSavedSettings, "AvatarAxisScale1", handleJoystickChanged);
+	setting_setup_signal_listener(gSavedSettings, "AvatarAxisScale2", handleJoystickChanged);
+	setting_setup_signal_listener(gSavedSettings, "AvatarAxisScale3", handleJoystickChanged);
+	setting_setup_signal_listener(gSavedSettings, "AvatarAxisScale4", handleJoystickChanged);
+	setting_setup_signal_listener(gSavedSettings, "AvatarAxisScale5", handleJoystickChanged);
+	setting_setup_signal_listener(gSavedSettings, "AvatarAxisDeadZone0", handleJoystickChanged);
+	setting_setup_signal_listener(gSavedSettings, "AvatarAxisDeadZone1", handleJoystickChanged);
+	setting_setup_signal_listener(gSavedSettings, "AvatarAxisDeadZone2", handleJoystickChanged);
+	setting_setup_signal_listener(gSavedSettings, "AvatarAxisDeadZone3", handleJoystickChanged);
+	setting_setup_signal_listener(gSavedSettings, "AvatarAxisDeadZone4", handleJoystickChanged);
+	setting_setup_signal_listener(gSavedSettings, "AvatarAxisDeadZone5", handleJoystickChanged);
+	setting_setup_signal_listener(gSavedSettings, "BuildAxisScale0", handleJoystickChanged);
+	setting_setup_signal_listener(gSavedSettings, "BuildAxisScale1", handleJoystickChanged);
+	setting_setup_signal_listener(gSavedSettings, "BuildAxisScale2", handleJoystickChanged);
+	setting_setup_signal_listener(gSavedSettings, "BuildAxisScale3", handleJoystickChanged);
+	setting_setup_signal_listener(gSavedSettings, "BuildAxisScale4", handleJoystickChanged);
+	setting_setup_signal_listener(gSavedSettings, "BuildAxisScale5", handleJoystickChanged);
+	setting_setup_signal_listener(gSavedSettings, "BuildAxisDeadZone0", handleJoystickChanged);
+	setting_setup_signal_listener(gSavedSettings, "BuildAxisDeadZone1", handleJoystickChanged);
+	setting_setup_signal_listener(gSavedSettings, "BuildAxisDeadZone2", handleJoystickChanged);
+	setting_setup_signal_listener(gSavedSettings, "BuildAxisDeadZone3", handleJoystickChanged);
+	setting_setup_signal_listener(gSavedSettings, "BuildAxisDeadZone4", handleJoystickChanged);
+	setting_setup_signal_listener(gSavedSettings, "BuildAxisDeadZone5", handleJoystickChanged);
+	setting_setup_signal_listener(gSavedSettings, "DebugViews", handleDebugViewsChanged);
+	setting_setup_signal_listener(gSavedSettings, "UserLogFile", handleLogFileChanged);
+	setting_setup_signal_listener(gSavedSettings, "RenderHideGroupTitle", handleHideGroupTitleChanged);
+	setting_setup_signal_listener(gSavedSettings, "HighResSnapshot", handleHighResSnapshotChanged);
+	setting_setup_signal_listener(gSavedSettings, "EnableVoiceChat", handleVoiceClientPrefsChanged);
+	setting_setup_signal_listener(gSavedSettings, "PTTCurrentlyEnabled", handleVoiceClientPrefsChanged);
+	setting_setup_signal_listener(gSavedSettings, "PushToTalkButton", handleVoiceClientPrefsChanged);
+	setting_setup_signal_listener(gSavedSettings, "PushToTalkToggle", handleVoiceClientPrefsChanged);
+	setting_setup_signal_listener(gSavedSettings, "VoiceEarLocation", handleVoiceClientPrefsChanged);
+	setting_setup_signal_listener(gSavedSettings, "VoiceInputAudioDevice", handleVoiceClientPrefsChanged);
+	setting_setup_signal_listener(gSavedSettings, "VoiceOutputAudioDevice", handleVoiceClientPrefsChanged);
+	setting_setup_signal_listener(gSavedSettings, "AudioLevelMic", handleVoiceClientPrefsChanged);
+	setting_setup_signal_listener(gSavedSettings, "LipSyncEnabled", handleVoiceClientPrefsChanged);	
+	setting_setup_signal_listener(gSavedSettings, "VelocityInterpolate", handleVelocityInterpolate);
+	setting_setup_signal_listener(gSavedSettings, "QAMode", show_debug_menus);
+	setting_setup_signal_listener(gSavedSettings, "UseDebugMenus", show_debug_menus);
+	setting_setup_signal_listener(gSavedSettings, "AgentPause", toggle_agent_pause);
+	setting_setup_signal_listener(gSavedSettings, "ShowNavbarNavigationPanel", toggle_show_navigation_panel);
+	setting_setup_signal_listener(gSavedSettings, "ShowMiniLocationPanel", toggle_show_mini_location_panel);
+	setting_setup_signal_listener(gSavedSettings, "ShowObjectRenderingCost", toggle_show_object_render_cost);
+	setting_setup_signal_listener(gSavedSettings, "ForceShowGrid", handleForceShowGrid);
+	setting_setup_signal_listener(gSavedSettings, "RenderTransparentWater", handleRenderTransparentWaterChanged);
+	setting_setup_signal_listener(gSavedSettings, "SpellCheck", handleSpellCheckChanged);
+	setting_setup_signal_listener(gSavedSettings, "SpellCheckDictionary", handleSpellCheckChanged);
+	setting_setup_signal_listener(gSavedSettings, "LoginLocation", handleLoginLocationChanged);
+	setting_setup_signal_listener(gSavedSettings, "DebugAvatarJoints", handleDebugAvatarJointsChanged);
+	setting_setup_signal_listener(gSavedSettings, "RenderAutoMuteByteLimit", handleRenderAutoMuteByteLimitChanged);
+
+    setting_setup_signal_listener(gSavedPerAccountSettings, "AvatarHoverOffsetZ", handleAvatarHoverOffsetChanged);
 }
 
 #if TEST_CACHED_CONTROL
diff --git a/indra/newview/llviewercontrollistener.cpp b/indra/newview/llviewercontrollistener.cpp
index 3443bb644a1e2cf507a58a6960a3ad909467a167..8820f9ec5676b9c7b698475d92bc116fdac790ec 100644
--- a/indra/newview/llviewercontrollistener.cpp
+++ b/indra/newview/llviewercontrollistener.cpp
@@ -127,7 +127,7 @@ struct Info
 
 	LLEventAPI::Response response;
 	std::string groupname;
-	LLControlGroup* group;
+	LLControlGroup::ptr_t group;
 	std::string key;
 	LLControlVariable* control;
 };
@@ -187,7 +187,7 @@ void LLViewerControlListener::groups(LLSD const & request)
 
 struct CollectVars: public LLControlGroup::ApplyFunctor
 {
-	CollectVars(LLControlGroup* g):
+	CollectVars(LLControlGroup::ptr_t g):
 		mGroup(g)
 	{}
 
@@ -200,7 +200,7 @@ struct CollectVars: public LLControlGroup::ApplyFunctor
 					("comment", control->getComment()));
 	}
 
-	LLControlGroup* mGroup;
+	LLControlGroup::ptr_t mGroup;
 	LLSD vars;
 };
 
@@ -210,7 +210,7 @@ void LLViewerControlListener::vars(LLSD const & request)
 	// control name.
 	Response response(LLSD(), request);
 	std::string groupname(request["group"]);
-	LLControlGroup* group(LLControlGroup::getInstance(groupname));
+	auto group(LLControlGroup::getInstance(groupname));
 	if (! group)
 	{
 		return response.error(STRINGIZE("Unrecognized group '" << groupname << "'"));
diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp
index 109dc93261329a50d590c2ad23ea3a15725b88e9..bc0fafb29f53a2165fddacf560122b95d647bda6 100644
--- a/indra/newview/llviewerdisplay.cpp
+++ b/indra/newview/llviewerdisplay.cpp
@@ -124,7 +124,8 @@ void display_startup()
 	if (   !gViewerWindow
 		|| !gViewerWindow->getActive()
 		|| !gViewerWindow->getWindow()->getVisible() 
-		|| gViewerWindow->getWindow()->getMinimized() )
+		|| gViewerWindow->getWindow()->getMinimized()
+		|| gNonInteractive)
 	{
 		return; 
 	}
@@ -165,8 +166,6 @@ void display_startup()
 
 	if (gViewerWindow)
 	gViewerWindow->setup2DRender();
-	gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
-
 	gGL.color4f(1,1,1,1);
 	if (gViewerWindow)
 	gViewerWindow->draw();
@@ -208,9 +207,11 @@ void display_update_camera()
 // Write some stats to LL_INFOS()
 void display_stats()
 {
+	LL_PROFILE_ZONE_SCOPED
 	F32 fps_log_freq = gSavedSettings.getF32("FPSLogFrequency");
 	if (fps_log_freq > 0.f && gRecentFPSTime.getElapsedTimeF32() >= fps_log_freq)
 	{
+		LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("DS - FPS");
 		F32 fps = gRecentFrameCount / fps_log_freq;
 		LL_INFOS() << llformat("FPS: %.02f", fps) << LL_ENDL;
 		gRecentFrameCount = 0;
@@ -219,6 +220,7 @@ void display_stats()
 	F32 mem_log_freq = gSavedSettings.getF32("MemoryLogFrequency");
 	if (mem_log_freq > 0.f && gRecentMemoryTime.getElapsedTimeF32() >= mem_log_freq)
 	{
+		LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("DS - Memory");
 		gMemoryAllocated = U64Bytes(LLMemory::getCurrentRSS());
 		U32Megabytes memory = gMemoryAllocated;
 		LL_INFOS() << "MEMORY: " << memory << LL_ENDL;
@@ -228,6 +230,7 @@ void display_stats()
     F32 asset_storage_log_freq = gSavedSettings.getF32("AssetStorageLogFrequency");
     if (asset_storage_log_freq > 0.f && gAssetStorageLogTime.getElapsedTimeF32() >= asset_storage_log_freq)
     {
+		LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("DS - Asset Storage");
         gAssetStorageLogTime.reset();
         gAssetStorage->logAssetStorageInfo();
     }
@@ -309,7 +312,8 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 	// Attempting to draw into a minimized window causes a GL error. JC
 	if (   !gViewerWindow->getActive()
 		|| !gViewerWindow->getWindow()->getVisible() 
-		|| gViewerWindow->getWindow()->getMinimized() )
+		|| gViewerWindow->getWindow()->getMinimized() 
+		|| gNonInteractive)
 	{
 		// Clean up memory the pools may have allocated
 		if (rebuild)
@@ -572,8 +576,11 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 	//
 
 	LLAppViewer::instance()->pingMainloopTimeout("Display:Camera");
-	LLViewerCamera::getInstance()->setZoomParameters(zoom_factor, subfield);
-	LLViewerCamera::getInstance()->setNear(MIN_NEAR_PLANE);
+    if (LLViewerCamera::instanceExists())
+    {
+        LLViewerCamera::getInstance()->setZoomParameters(zoom_factor, subfield);
+        LLViewerCamera::getInstance()->setNear(MIN_NEAR_PLANE);
+    }
 
 	//////////////////////////
 	//
@@ -630,6 +637,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 	
 	if (!gDisconnected)
 	{
+		LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("display - 1");
 		LLAppViewer::instance()->pingMainloopTimeout("Display:Update");
 		if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD))
 		{ //don't draw hud objects in this frame
@@ -641,9 +649,6 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 			gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_HUD_PARTICLES);
 		}
 
-		//upkeep gl name pools
-		LLGLNamePool::upkeepPools();
-		
 		stop_glerror();
 		display_update_camera();
 		stop_glerror();
@@ -675,21 +680,6 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 		
 		stop_glerror();
 
-		S32 water_clip = 0;
-		if ((LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_ENVIRONMENT) > 1) &&
-			 (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_WATER) || 
-			  gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_VOIDWATER)))
-		{
-			if (LLViewerCamera::getInstance()->cameraUnderWater())
-			{
-				water_clip = -1;
-			}
-			else
-			{
-				water_clip = 1;
-			}
-		}
-		
 		LLAppViewer::instance()->pingMainloopTimeout("Display:Cull");
 		
 		//Increment drawable frame counter
@@ -707,21 +697,20 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 
 		LLGLState::checkStates();
 		LLGLState::checkTextureChannels();
-		LLGLState::checkClientArrays();
 
 		static LLCullResult result;
 		LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD;
 		LLPipeline::sUnderWaterRender = LLViewerCamera::getInstance()->cameraUnderWater();
-		gPipeline.updateCull(*LLViewerCamera::getInstance(), result, water_clip);
+		gPipeline.updateCull(*LLViewerCamera::getInstance(), result);
 		stop_glerror();
 
 		LLGLState::checkStates();
 		LLGLState::checkTextureChannels();
-		LLGLState::checkClientArrays();
-
+		
 		LLAppViewer::instance()->pingMainloopTimeout("Display:Swap");
 		
 		{ 
+			LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("display - 2")
 			if (gResizeScreenTexture)
 			{
 				gResizeScreenTexture = FALSE;
@@ -733,7 +722,6 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 
 			LLGLState::checkStates();
 			LLGLState::checkTextureChannels();
-			LLGLState::checkClientArrays();
 
 			if (!for_snapshot)
 			{
@@ -747,12 +735,10 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 
 				LLGLState::checkStates();
 				LLGLState::checkTextureChannels();
-				LLGLState::checkClientArrays();
 
 				glh::matrix4f proj = get_current_projection();
 				glh::matrix4f mod = get_current_modelview();
 				glViewport(0,0,512,512);
-				LLVOAvatar::updateFreezeCounter() ;
 
 				LLVOAvatar::updateImpostors();
 
@@ -766,17 +752,16 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 
 				LLGLState::checkStates();
 				LLGLState::checkTextureChannels();
-				LLGLState::checkClientArrays();
 
 			}
 			glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
 		}
 
 		LLGLState::checkStates();
-		LLGLState::checkClientArrays();
 
 		//if (!for_snapshot)
 		{
+			LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("display - 3")
 			LLAppViewer::instance()->pingMainloopTimeout("Display:Imagery");
 			gPipeline.generateWaterReflection(*LLViewerCamera::getInstance());
 			gPipeline.generateHighlight(*LLViewerCamera::getInstance());
@@ -784,7 +769,6 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 		}
 
 		LLGLState::checkStates();
-		LLGLState::checkClientArrays();
 
 		//////////////////////////////////////
 		//
@@ -800,13 +784,11 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 			
 			{
 				LL_RECORD_BLOCK_TIME(FTM_IMAGE_UPDATE_CLASS);
-				LLTrace::CountStatHandle<>* velocity_stat = LLViewerCamera::getVelocityStat();
-				LLTrace::CountStatHandle<>* angular_velocity_stat = LLViewerCamera::getAngularVelocityStat();
-				LLViewerTexture::updateClass(LLTrace::get_frame_recording().getPeriodMeanPerSec(*velocity_stat),
-											LLTrace::get_frame_recording().getPeriodMeanPerSec(*angular_velocity_stat));
+				LLViewerTexture::updateClass();
 			}
 
-			
+            LLImageGLThread::updateClass();
+
 			{
 				LL_RECORD_BLOCK_TIME(FTM_IMAGE_UPDATE_BUMP);
 				gBumpImageList.updateImages();  // must be called before gTextureList version so that it's textures are thrown out first.
@@ -825,10 +807,9 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 				LLImageGL::deleteDeadTextures();
 				stop_glerror();
 			}*/
-			}
+		}
 
 		LLGLState::checkStates();
-		LLGLState::checkClientArrays();
 
 		///////////////////////////////////
 		//
@@ -840,6 +821,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 		//
 		LLAppViewer::instance()->pingMainloopTimeout("Display:StateSort");
 		{
+			LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("display - 4")
 			LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD;
 			gPipeline.stateSort(*LLViewerCamera::getInstance(), result);
 			stop_glerror();
@@ -859,13 +841,12 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 		LLSceneMonitor::getInstance()->fetchQueryResult();
 		
 		LLGLState::checkStates();
-		LLGLState::checkClientArrays();
 
 		LLPipeline::sUseOcclusion = occlusion;
 
 		{
 			LLAppViewer::instance()->pingMainloopTimeout("Display:Sky");
-			LL_RECORD_BLOCK_TIME(FTM_UPDATE_SKY);	
+			LL_PROFILE_ZONE_NAMED_CATEGORY_ENVIRONMENT("update sky"); //LL_RECORD_BLOCK_TIME(FTM_UPDATE_SKY);	
 			gSky.updateSky();
 		}
 
@@ -918,7 +899,6 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 		LLPipeline::sUnderWaterRender = LLViewerCamera::getInstance()->cameraUnderWater() ? TRUE : FALSE;
 
 		LLGLState::checkStates();
-		LLGLState::checkClientArrays();
 
 		stop_glerror();
 
@@ -948,9 +928,10 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 		if (!(LLAppViewer::instance()->logoutRequestSent() && LLAppViewer::instance()->hasSavedFinalSnapshot())
 				&& !gRestoreGL)
 		{
+			LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("display - 5")
 			LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD;
 
-			if (gSavedSettings.getBOOL("RenderDepthPrePass") && LLGLSLShader::sNoFixedFunction)
+			if (gSavedSettings.getBOOL("RenderDepthPrePass"))
 			{
 				gGL.setColorMask(false, false);
 
@@ -1259,7 +1240,7 @@ bool setup_hud_matrices(const LLRect& screen_region)
 
 void render_ui(F32 zoom_factor, int subfield)
 {
-    LL_RECORD_BLOCK_TIME(FTM_RENDER_UI);
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; //LL_RECORD_BLOCK_TIME(FTM_RENDER_UI);
 
 	LLGLState::checkStates();
 	
@@ -1274,7 +1255,6 @@ void render_ui(F32 zoom_factor, int subfield)
 	
 	if(LLSceneMonitor::getInstance()->needsUpdate())
 	{
-        LL_RECORD_BLOCK_TIME(FTM_RENDER_UI_SCENE_MON);
 		gGL.pushMatrix();
 		gViewerWindow->setup2DRender();
 		LLSceneMonitor::getInstance()->compare();
@@ -1282,55 +1262,61 @@ void render_ui(F32 zoom_factor, int subfield)
 		gGL.popMatrix();
 	}
 
-    // Finalize scene
-    gPipeline.renderFinalize();
-
-    LL_RECORD_BLOCK_TIME(FTM_RENDER_HUD);
-    render_hud_elements();
-	render_hud_attachments();
+	// Finalize scene
+	gPipeline.renderFinalize();
 
-	LLGLSDefault gls_default;
-	LLGLSUIDefault gls_ui;
 	{
-		gPipeline.disableLights();
-	}
+		// SL-15709
+		// NOTE: Tracy only allows one ZoneScoped per function.
+		// Solutions are:
+		// 1. Use a new scope
+		// 2. Use named zones
+		// 3. Use transient zones
+		LL_PROFILE_ZONE_NAMED_CATEGORY_UI("HUD"); //LL_RECORD_BLOCK_TIME(FTM_RENDER_HUD);
+		render_hud_elements();
+		render_hud_attachments();
+
+		LLGLSDefault gls_default;
+		LLGLSUIDefault gls_ui;
+		{
+			gPipeline.disableLights();
+		}
 
-	{
-		gGL.color4f(1,1,1,1);
-		if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
 		{
-			if (!gDisconnected)
+			gGL.color4f(1,1,1,1);
+			if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
 			{
-                LL_RECORD_BLOCK_TIME(FTM_RENDER_UI_3D);
-				render_ui_3d();
+				if (!gDisconnected)
+				{
+					LL_PROFILE_ZONE_NAMED_CATEGORY_UI("UI 3D"); //LL_RECORD_BLOCK_TIME(FTM_RENDER_UI_3D);
+					render_ui_3d();
+					LLGLState::checkStates();
+				}
+				else
+				{
+					render_disconnected_background();
+				}
+
+				LL_PROFILE_ZONE_NAMED_CATEGORY_UI("UI 2D"); //LL_RECORD_BLOCK_TIME(FTM_RENDER_UI_2D);
+				render_ui_2d();
 				LLGLState::checkStates();
 			}
-			else
-			{
-				render_disconnected_background();
-			}
+			gGL.flush();
 
-            LL_RECORD_BLOCK_TIME(FTM_RENDER_UI_2D);
-			render_ui_2d();
-			LLGLState::checkStates();
-		}
-		gGL.flush();
-
-		{
-            LL_RECORD_BLOCK_TIME(FTM_RENDER_UI_DEBUG_TEXT);
 			gViewerWindow->setup2DRender();
 			gViewerWindow->updateDebugText();
 			gViewerWindow->drawDebugText();
+
+			LLVertexBuffer::unbind();
 		}
 
-		LLVertexBuffer::unbind();
-	}
+		if (!gSnapshot)
+		{
+			set_current_modelview(saved_view);
+			gGL.popMatrix();
+		}
 
-	if (!gSnapshot)
-	{
-		set_current_modelview(saved_view);
-		gGL.popMatrix();
-	}
+	} // Tracy integration
 }
 
 static LLTrace::BlockTimerStatHandle FTM_SWAP("Swap");
@@ -1435,10 +1421,7 @@ void render_ui_3d()
 
 	stop_glerror();
 	
-	if (LLGLSLShader::sNoFixedFunction)
-	{
-		gUIProgram.bind();
-	}
+	gUIProgram.bind();
 
 	// Coordinate axes
 	if (gSavedSettings.getBOOL("ShowAxes"))
@@ -1478,7 +1461,6 @@ void render_ui_2d()
 	}
 
 	stop_glerror();
-	//gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
 
 	// render outline for HUD
 	if (isAgentAvatarValid() && gAgentCamera.mHUDCurZoom < 0.98f)
@@ -1568,10 +1550,7 @@ void render_ui_2d()
 
 void render_disconnected_background()
 {
-	if (LLGLSLShader::sNoFixedFunction)
-	{
-		gUIProgram.bind();
-	}
+	gUIProgram.bind();
 
 	gGL.color4f(1,1,1,1);
 	if (!gDisconnectedImagep && gDisconnected)
@@ -1643,11 +1622,7 @@ void render_disconnected_background()
 	}
 	gGL.flush();
 
-	if (LLGLSLShader::sNoFixedFunction)
-	{
-		gUIProgram.unbind();
-	}
-
+	gUIProgram.unbind();
 }
 
 void display_cleanup()
diff --git a/indra/newview/llviewerdisplayname.cpp b/indra/newview/llviewerdisplayname.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..cec08c4f152fdb6ee8ea9f3a3af1107bcc3594f0
--- /dev/null
+++ b/indra/newview/llviewerdisplayname.cpp
@@ -0,0 +1,226 @@
+/** 
+ * @file llviewerdisplayname.cpp
+ * @brief Wrapper for display name functionality
+ *
+ * $LicenseInfo:firstyear=2010&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llviewerdisplayname.h"
+
+// viewer includes
+#include "llagent.h"
+#include "llfloaterprofile.h"
+#include "llfloaterreg.h"
+#include "llviewerregion.h"
+#include "llvoavatar.h"
+
+// library includes
+#include "llavatarnamecache.h"
+#include "llhttpnode.h"
+#include "llnotificationsutil.h"
+#include "llui.h"					// getLanguage()
+
+namespace LLViewerDisplayName
+{
+	// Fired when viewer receives server response to display name change
+	set_name_signal_t sSetDisplayNameSignal;
+
+	// Fired when there is a change in the agent's name
+	name_changed_signal_t sNameChangedSignal;
+
+	void addNameChangedCallback(const name_changed_signal_t::slot_type& cb) 
+	{ 
+		sNameChangedSignal.connect(cb); 
+	}
+
+	void doNothing() { }
+}
+
+void LLViewerDisplayName::set(const std::string& display_name, const set_name_slot_t& slot)
+{
+	// TODO: simple validation here
+
+	LLViewerRegion* region = gAgent.getRegion();
+	llassert(region);
+	std::string cap_url = region->getCapability("SetDisplayName");
+	if (cap_url.empty())
+	{
+		// this server does not support display names, report error
+		slot(false, "unsupported", LLSD());
+		return;
+	}
+
+	// People API requires both the old and new value to change a variable.
+	// Our display name will be in cache before the viewer's UI is available
+	// to request a change, so we can use direct lookup without callback.
+	LLAvatarName av_name;
+	if (!LLAvatarNameCache::get( gAgent.getID(), &av_name))
+	{
+		slot(false, "name unavailable", LLSD());
+		return;
+	}
+
+	// People API expects array of [ "old value", "new value" ]
+	LLSD change_array = LLSD::emptyArray();
+	change_array.append(av_name.getDisplayName());
+	change_array.append(display_name);
+	
+	LL_INFOS() << "Set name POST to " << cap_url << LL_ENDL;
+
+	// Record our caller for when the server sends back a reply
+	sSetDisplayNameSignal.connect(slot);
+	
+	// POST the requested change.  The sim will not send a response back to
+	// this request directly, rather it will send a separate message after it
+	// communicates with the back-end.
+	LLSD body;
+	body["display_name"] = change_array;
+    LLCoros::instance().launch("LLViewerDisplayName::SetDisplayNameCoro",
+            boost::bind(&LLViewerDisplayName::setDisplayNameCoro, cap_url, body));
+}
+
+void LLViewerDisplayName::setDisplayNameCoro(const std::string& cap_url, const LLSD& body)
+{
+    LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+    LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+        httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("SetDisplayNameCoro", httpPolicy));
+    LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+    LLCore::HttpHeaders::ptr_t httpHeaders(new LLCore::HttpHeaders);
+
+    // People API can return localized error messages.  Indicate our
+    // language preference via header.
+    httpHeaders->append(HTTP_OUT_HEADER_ACCEPT_LANGUAGE, LLUI::getLanguage());
+
+    LLSD result = httpAdapter->postAndSuspend(httpRequest, cap_url, body, httpHeaders);
+
+    LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+    LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+    if (!status)
+    {
+        LL_WARNS() << "Unable to set display name. Status: " << status.toString() << LL_ENDL;
+        LLViewerDisplayName::sSetDisplayNameSignal(false, "", LLSD());
+        LLViewerDisplayName::sSetDisplayNameSignal.disconnect_all_slots();
+    }
+}
+
+class LLSetDisplayNameReply : public LLHTTPNode
+{
+	LOG_CLASS(LLSetDisplayNameReply);
+public:
+	/*virtual*/ void post(
+		LLHTTPNode::ResponsePtr response,
+		const LLSD& context,
+		const LLSD& input) const
+	{
+		LLSD body = input["body"];
+
+		S32 status = body["status"].asInteger();
+		bool success = (status == HTTP_OK);
+		std::string reason = body["reason"].asString();
+		LLSD content = body["content"];
+
+		LL_INFOS() << "status " << status << " reason " << reason << LL_ENDL;
+
+		// If viewer's concept of display name is out-of-date, the set request
+		// will fail with 409 Conflict.  If that happens, fetch up-to-date
+		// name information.
+		if (status == HTTP_CONFLICT)
+		{
+			LLUUID agent_id = gAgent.getID();
+			// Flush stale data
+			LLAvatarNameCache::getInstance()->erase( agent_id );
+			// Queue request for new data: nothing to do on callback though...
+			// Note: no need to disconnect the callback as it never gets out of scope
+            LLAvatarNameCache::getInstance()->get(agent_id, boost::bind(&LLViewerDisplayName::doNothing));
+			// Kill name tag, as it is wrong
+			LLVOAvatar::invalidateNameTag( agent_id );
+		}
+
+		// inform caller of result
+		LLViewerDisplayName::sSetDisplayNameSignal(success, reason, content);
+		LLViewerDisplayName::sSetDisplayNameSignal.disconnect_all_slots();
+	}
+};
+
+
+class LLDisplayNameUpdate : public LLHTTPNode
+{
+	/*virtual*/ void post(
+		LLHTTPNode::ResponsePtr response,
+		const LLSD& context,
+		const LLSD& input) const
+	{
+		LLSD body = input["body"];
+		LLUUID agent_id = body["agent_id"];
+		std::string old_display_name = body["old_display_name"];
+		// By convention this record is called "agent" in the People API
+		LLSD name_data = body["agent"];
+
+		// Inject the new name data into cache
+		LLAvatarName av_name;
+		av_name.fromLLSD( name_data );
+
+		LL_INFOS() << "name-update now " << LLDate::now()
+			<< " next_update " << LLDate(av_name.mNextUpdate)
+			<< LL_ENDL;
+
+		// Name expiration time may be provided in headers, or we may use a
+		// default value
+		// *TODO: get actual headers out of ResponsePtr
+		//LLSD headers = response->mHeaders;
+		LLSD headers;
+		av_name.mExpires = 
+            LLAvatarNameCache::getInstance()->nameExpirationFromHeaders(headers);
+
+        LLAvatarNameCache::getInstance()->insert(agent_id, av_name);
+
+		// force name tag to update
+		LLVOAvatar::invalidateNameTag(agent_id);
+
+		LLSD args;
+		args["OLD_NAME"] = old_display_name;
+		args["SLID"] = av_name.getUserName();
+		args["NEW_NAME"] = av_name.getDisplayName();
+		LLNotificationsUtil::add("DisplayNameUpdate", args);
+		if (agent_id == gAgent.getID())
+		{
+			LLViewerDisplayName::sNameChangedSignal();
+		}
+
+        LLFloaterProfile* profile_floater = dynamic_cast<LLFloaterProfile*>(LLFloaterReg::findInstance("profile", LLSD().with("id", agent_id)));
+        if (profile_floater)
+        {
+            profile_floater->refreshName();
+        }
+	}
+};
+
+LLHTTPRegistration<LLSetDisplayNameReply>
+    gHTTPRegistrationMessageSetDisplayNameReply(
+		"/message/SetDisplayNameReply");
+
+LLHTTPRegistration<LLDisplayNameUpdate>
+    gHTTPRegistrationMessageDisplayNameUpdate(
+		"/message/DisplayNameUpdate");
diff --git a/indra/newview/llviewerdisplayname.h b/indra/newview/llviewerdisplayname.h
new file mode 100644
index 0000000000000000000000000000000000000000..337aaa68b6056d5e664f75aaeef5527bc236d2dc
--- /dev/null
+++ b/indra/newview/llviewerdisplayname.h
@@ -0,0 +1,55 @@
+/** 
+ * @file llviewerdisplayname.h
+ * @brief Wrapper for display name functionality
+ *
+ * $LicenseInfo:firstyear=2010&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LLVIEWERDISPLAYNAME_H
+#define LLVIEWERDISPLAYNAME_H
+
+#include <boost/signals2.hpp>
+
+class LLSD;
+class LLUUID;
+
+namespace LLViewerDisplayName
+{
+	typedef boost::signals2::signal<
+		void (bool success, const std::string& reason, const LLSD& content)>
+			set_name_signal_t;
+	typedef set_name_signal_t::slot_type set_name_slot_t;
+	
+	typedef boost::signals2::signal<void (void)> name_changed_signal_t;
+	typedef name_changed_signal_t::slot_type name_changed_slot_t;
+
+	// Sends an update to the server to change a display name
+	// and call back when done.  May not succeed due to service
+	// unavailable or name not available.
+	void set(const std::string& display_name, const set_name_slot_t& slot);
+
+    void setDisplayNameCoro(const std::string& cap_url, const LLSD& body);
+
+	void addNameChangedCallback(const name_changed_signal_t::slot_type& cb);
+}
+
+#endif // LLVIEWERDISPLAYNAME_H
diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp
index 21ef4a1d8dbfc610d87601db48d415712c254899..149e73cad595caadb42e9536312a913ebdecd013 100644
--- a/indra/newview/llviewerfloaterreg.cpp
+++ b/indra/newview/llviewerfloaterreg.cpp
@@ -57,11 +57,13 @@
 #include "llfloatercamera.h"
 #include "llfloatercamerapresets.h"
 #include "llfloaterchatvoicevolume.h"
+#include "llfloaterclassified.h"
 #include "llfloaterconversationlog.h"
 #include "llfloaterconversationpreview.h"
 #include "llfloatercreatelandmark.h"
 #include "llfloaterdeleteprefpreset.h"
 #include "llfloaterdestinations.h"
+#include "llfloaterdisplayname.h"
 #include "llfloatereditextdaycycle.h"
 #include "llfloaterenvironmentadjust.h"
 #include "llfloaterexperienceprofile.h"
@@ -111,6 +113,7 @@
 #include "llfloaterpreference.h"
 #include "llfloaterpreferenceviewadvanced.h"
 #include "llfloaterpreviewtrash.h"
+#include "llfloaterprofile.h"
 #include "llfloaterproperties.h"
 #include "llfloaterregiondebugconsole.h"
 #include "llfloaterregioninfo.h"
@@ -141,7 +144,6 @@
 #include "llfloateruipreview.h"
 #include "llfloatervoiceeffect.h"
 #include "llfloaterwebcontent.h"
-#include "llfloaterwebprofile.h"
 #include "llfloatervoicevolume.h"
 #include "llfloaterwhitelistentry.h"
 #include "llfloaterwindowsize.h"
@@ -156,7 +158,7 @@
 #include "llmoveview.h"
 #include "llfloaterimnearbychat.h"
 #include "llpanelblockedlist.h"
-#include "llpanelclassified.h"
+#include "llpanelprofileclassifieds.h"
 #include "llpreviewanim.h"
 #include "llpreviewgesture.h"
 #include "llpreviewnotecard.h"
@@ -194,6 +196,10 @@ LLFloaterOpenHandler gFloaterOpenHandler;
 
 void LLViewerFloaterReg::registerFloaters()
 {
+	if (gNonInteractive)
+	{
+		return;
+	}
 	// *NOTE: Please keep these alphabetized for easier merges
 
 	LLFloaterAboutUtil::registerFloater();
@@ -225,6 +231,7 @@ void LLViewerFloaterReg::registerFloaters()
 	LLFloaterReg::add("camera_presets", "floater_camera_presets.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterCameraPresets>);
 	LLFloaterReg::add("chat_voice", "floater_voice_chat_volume.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterChatVoiceVolume>);
 	LLFloaterReg::add("nearby_chat", "floater_im_session.xml", (LLFloaterBuildFunc)&LLFloaterIMNearbyChat::buildFloater);
+    LLFloaterReg::add("classified", "floater_classified.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterClassified>);
 	LLFloaterReg::add("compile_queue", "floater_script_queue.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterCompileQueue>);
 	LLFloaterReg::add("conversation", "floater_conversation_log.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterConversationLog>);
 	LLFloaterReg::add("add_landmark", "floater_create_landmark.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterCreateLandmark>);
@@ -273,6 +280,7 @@ void LLViewerFloaterReg::registerFloaters()
 	LLInspectRemoteObjectUtil::registerFloater();
 	LLFloaterVoiceVolumeUtil::registerFloater();
 	LLNotificationsUI::registerFloater();
+	LLFloaterDisplayNameUtil::registerFloater();
 	
 	LLFloaterReg::add("lagmeter", "floater_lagmeter.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterLagMeter>);
 	LLFloaterReg::add("land_holdings", "floater_land_holdings.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterLandHoldings>);
@@ -318,7 +326,6 @@ void LLViewerFloaterReg::registerFloaters()
 	LLFloaterReg::add("prefs_translation", "floater_translation_settings.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterTranslationSettings>);
 	LLFloaterReg::add("prefs_spellchecker", "floater_spellcheck.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSpellCheckerSettings>);
 	LLFloaterReg::add("prefs_autoreplace", "floater_autoreplace.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterAutoReplaceSettings>);
-	LLFloaterReg::add("picks", "floater_picks.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSidePanelContainer>);
 	LLFloaterReg::add("pref_joystick", "floater_joystick.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterJoystick>);
 	LLFloaterReg::add("preview_anim", "floater_preview_animation.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLPreviewAnim>, "preview");
 	LLFloaterReg::add("preview_conversation", "floater_conversation_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterConversationPreview>);
@@ -365,8 +372,7 @@ void LLViewerFloaterReg::registerFloaters()
 	LLFloaterReg::add("snapshot", "floater_snapshot.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSnapshot>);
     LLFloaterReg::add("outfit_snapshot", "floater_outfit_snapshot.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterOutfitSnapshot>);
     LLFloaterReg::add("search", "floater_search.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSearch>);
-	LLFloaterReg::add("my_profile", "floater_my_web_profile.xml", (LLFloaterBuildFunc)&LLFloaterWebProfile::create);
-	LLFloaterReg::add("profile", "floater_web_profile.xml", (LLFloaterBuildFunc)&LLFloaterWebProfile::create);
+    LLFloaterReg::add("profile", "floater_profile.xml",(LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterProfile>);
 	LLFloaterReg::add("guidebook", "floater_how_to.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterHowTo>);
 
 	LLFloaterReg::add("big_preview", "floater_big_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterBigPreview>);
diff --git a/indra/newview/llviewerinput.cpp b/indra/newview/llviewerinput.cpp
index 94ec5347322c17e5dab24db59509d9f248c28170..43b9cd90bd6f90cdfb3917dff2acb79920ff2c90 100644
--- a/indra/newview/llviewerinput.cpp
+++ b/indra/newview/llviewerinput.cpp
@@ -816,13 +816,20 @@ bool toggle_enable_media(EKeystate s)
 
 bool walk_to(EKeystate s)
 {
-    if (KEYSTATE_DOWN != s) return true;
+    if (KEYSTATE_DOWN != s)
+    {
+        // teleport/walk is usually on mouseclick, mouseclick needs
+        // to let AGENT_CONTROL_LBUTTON_UP happen if teleport didn't,
+        // so return false, but if it causes issues, do some kind of
+        // "return !has_teleported"
+        return false;
+    }
     return LLToolPie::getInstance()->walkToClickedLocation();
 }
 
 bool teleport_to(EKeystate s)
 {
-    if (KEYSTATE_DOWN != s) return true;
+    if (KEYSTATE_DOWN != s) return false;
     return LLToolPie::getInstance()->teleportToClickedLocation();
 }
 
@@ -850,7 +857,47 @@ bool voice_follow_key(EKeystate s)
     return false;
 }
 
-bool agen_control_lbutton_handle(EKeystate s)
+bool script_trigger_lbutton(EKeystate s)
+{
+    // Check for script overriding/expecting left mouse button.
+    // Note that this does not pass event further and depends onto mouselook.
+    // Checks CONTROL_ML_LBUTTON_DOWN_INDEX for mouselook,
+    // CONTROL_LBUTTON_DOWN_INDEX for normal camera
+    if (gAgent.leftButtonGrabbed())
+    {
+        bool mouselook = gAgentCamera.cameraMouselook();
+        switch (s)
+        {
+        case KEYSTATE_DOWN:
+            if (mouselook)
+            {
+                gAgent.setControlFlags(AGENT_CONTROL_ML_LBUTTON_DOWN);
+            }
+            else
+            {
+                gAgent.setControlFlags(AGENT_CONTROL_LBUTTON_DOWN);
+            }
+            return true;
+        case KEYSTATE_UP:
+            if (mouselook)
+            {
+                gAgent.setControlFlags(AGENT_CONTROL_ML_LBUTTON_UP);
+            }
+            else
+            {
+                gAgent.setControlFlags(AGENT_CONTROL_LBUTTON_UP);
+            }
+            return true;
+        default:
+            break;
+        }
+    }
+    return false;
+}
+
+// Used by scripts, for overriding/handling left mouse button
+// see mControlsTakenCount
+bool agent_control_lbutton_handle(EKeystate s)
 {
     switch (s)
     {
@@ -922,6 +969,7 @@ REGISTER_KEYBOARD_ACTION("teleport_to", teleport_to);
 REGISTER_KEYBOARD_ACTION("walk_to", walk_to);
 REGISTER_KEYBOARD_GLOBAL_ACTION("toggle_voice", toggle_voice);
 REGISTER_KEYBOARD_GLOBAL_ACTION("voice_follow_key", voice_follow_key);
+REGISTER_KEYBOARD_ACTION(script_mouse_handler_name, script_trigger_lbutton);
 #undef REGISTER_KEYBOARD_ACTION
 
 LLViewerInput::LLViewerInput()
@@ -1193,6 +1241,20 @@ BOOL LLViewerInput::bindMouse(const S32 mode, const EMouseClickType mouse, const
     typedef boost::function<bool(EKeystate)> function_t;
     function_t function = NULL;
 
+    if (mouse == CLICK_LEFT
+        && mask == MASK_NONE
+        && function_name == script_mouse_handler_name)
+    {
+        // Special case
+        // Left click has script overrides and by default
+        // is handled via agent_control_lbutton as last option
+        // In case of mouselook and present overrides it has highest
+        // priority even over UI and is handled in LLToolCompGun::handleMouseDown
+        // so just mark it as having default handler
+        mLMouseDefaultHandling[mode] = true;
+        return TRUE;
+    }
+
     LLKeybindFunctionData* result = LLKeyboardActionRegistry::getValue(function_name);
     if (result)
     {
@@ -1269,7 +1331,8 @@ LLViewerInput::Keys::Keys()
 :	first_person("first_person"),
 	third_person("third_person"),
 	sitting("sitting"),
-	edit_avatar("edit_avatar")
+	edit_avatar("edit_avatar"),
+	xml_version("xml_version", 0)
 {}
 
 void LLViewerInput::resetBindings()
@@ -1280,6 +1343,7 @@ void LLViewerInput::resetBindings()
         mGlobalMouseBindings[i].clear();
         mKeyBindings[i].clear();
         mMouseBindings[i].clear();
+        mLMouseDefaultHandling[i] = false;
     }
 }
 
@@ -1298,6 +1362,65 @@ S32 LLViewerInput::loadBindingsXML(const std::string& filename)
 		binding_count += loadBindingMode(keys.third_person, MODE_THIRD_PERSON);
 		binding_count += loadBindingMode(keys.sitting, MODE_SITTING);
 		binding_count += loadBindingMode(keys.edit_avatar, MODE_EDIT_AVATAR);
+
+        // verify version
+        if (keys.xml_version < 1)
+        {
+            // updating from a version that was not aware of LMouse bindings
+            for (S32 i = 0; i < MODE_COUNT; i++)
+            {
+                mLMouseDefaultHandling[i] = true;
+            }
+
+            // fix missing values
+            KeyBinding mouse_binding;
+            mouse_binding.key = "";
+            mouse_binding.mask = "NONE";
+            mouse_binding.mouse = "LMB";
+            mouse_binding.command = script_mouse_handler_name;
+
+            if (keys.third_person.isProvided())
+            {
+                keys.third_person.bindings.add(mouse_binding);
+            }
+
+            if (keys.first_person.isProvided())
+            {
+                keys.first_person.bindings.add(mouse_binding);
+            }
+
+            if (keys.sitting.isProvided())
+            {
+                keys.sitting.bindings.add(mouse_binding);
+            }
+
+            if (keys.edit_avatar.isProvided())
+            {
+                keys.edit_avatar.bindings.add(mouse_binding);
+            }
+
+            // fix version
+            keys.xml_version.set(keybindings_xml_version, true);
+
+            // Write the resulting XML to file
+            LLXMLNodePtr output_node = new LLXMLNode("keys", false);
+            LLXUIParser write_parser;
+            write_parser.writeXUI(output_node, keys);
+
+            if (!output_node->isNull())
+            {
+                // file in app_settings is supposed to be up to date
+                // this is only for the file from user_settings
+                LL_INFOS("ViewerInput") << "Updating file " << filename << " to a newer version" << LL_ENDL;
+                LLFILE *fp = LLFile::fopen(filename, "w");
+                if (fp != NULL)
+                {
+                    LLXMLNode::writeHeaderToFile(fp);
+                    output_node->writeToFile(fp);
+                    fclose(fp);
+                }
+            }
+        }
 	}
 	return binding_count;
 }
@@ -1469,17 +1592,6 @@ bool LLViewerInput::scanKey(KEY key, BOOL key_down, BOOL key_up, BOOL key_level)
 
     bool res = scanKey(mKeyBindings[mode], mKeyBindings[mode].size(), key, mask, key_down, key_up, key_level, repeat);
 
-    if (!res && agent_control_lbutton.canHandle(CLICK_NONE, key, mask))
-    {
-        if (key_down && !repeat)
-        {
-            res = agen_control_lbutton_handle(KEYSTATE_DOWN);
-        }
-        if (key_up)
-        {
-            res = agen_control_lbutton_handle(KEYSTATE_UP);
-        }
-    }
     return res;
 }
 
@@ -1603,29 +1715,36 @@ bool LLViewerInput::scanMouse(EMouseClickType click, EMouseState state) const
     bool res = false;
     S32 mode = getMode();
     MASK mask = gKeyboard->currentMask(TRUE);
-
-    // By default mouse clicks require exact mask
-    // Todo: support for mIgnoreMasks because some functions like teleports
-    // expect to be canceled, but for voice it's prefered to ignore mask.
     res = scanMouse(mMouseBindings[mode], mMouseBindings[mode].size(), click, mask, state, false);
-    // no user defined actions found or those actions can't handle the key/button, handle control if nessesary
-    if (!res && agent_control_lbutton.canHandle(click, KEY_NONE, mask))
+
+    // No user defined actions found or those actions can't handle the key/button,
+    // so handle CONTROL_LBUTTON if nessesary.
+    //
+    // Default handling for MODE_FIRST_PERSON is in LLToolCompGun::handleMouseDown,
+    // and sends AGENT_CONTROL_ML_LBUTTON_DOWN, but it only applies if ML controls
+    // are leftButtonGrabbed(), send a normal click otherwise.
+
+    if (!res
+        && mLMouseDefaultHandling[mode]
+        && (mode != MODE_FIRST_PERSON || !gAgent.leftButtonGrabbed())
+        && (click == CLICK_LEFT || click == CLICK_DOUBLELEFT)
+        )
     {
         switch (state)
         {
         case MOUSE_STATE_DOWN:
-            agen_control_lbutton_handle(KEYSTATE_DOWN);
+            agent_control_lbutton_handle(KEYSTATE_DOWN);
             res = true;
             break;
         case MOUSE_STATE_CLICK:
             // might not work best with some functions,
             // but some function need specific states too specifically
-            agen_control_lbutton_handle(KEYSTATE_DOWN);
-            agen_control_lbutton_handle(KEYSTATE_UP);
+            agent_control_lbutton_handle(KEYSTATE_DOWN);
+            agent_control_lbutton_handle(KEYSTATE_UP);
             res = true;
             break;
         case MOUSE_STATE_UP:
-            agen_control_lbutton_handle(KEYSTATE_UP);
+            agent_control_lbutton_handle(KEYSTATE_UP);
             res = true;
             break;
         default:
@@ -1655,7 +1774,7 @@ void LLViewerInput::scanMouse()
     }
 }
 
-bool LLViewerInput::isMouseBindUsed(const EMouseClickType mouse, const MASK mask, const S32 mode)
+bool LLViewerInput::isMouseBindUsed(const EMouseClickType mouse, const MASK mask, const S32 mode) const
 {
     S32 size = mMouseBindings[mode].size();
     for (S32 index = 0; index < size; index++)
diff --git a/indra/newview/llviewerinput.h b/indra/newview/llviewerinput.h
index ca70ac76bf0f294c8655850efd94e3f07b879171..52e95e2168ba4103891e58ae9a9e6267cc328ebd 100644
--- a/indra/newview/llviewerinput.h
+++ b/indra/newview/llviewerinput.h
@@ -31,6 +31,8 @@
 #include "llinitparam.h"
 
 const S32 MAX_KEY_BINDINGS = 128; // was 60
+const S32 keybindings_xml_version = 1;
+const std::string script_mouse_handler_name = "script_trigger_lbutton";
 
 class LLNamedFunction
 {
@@ -100,7 +102,7 @@ class LLViewerInput
 							third_person,
 							sitting,
 							edit_avatar;
-
+		Optional<S32> xml_version; // 'xml', because 'version' appears to be reserved
 		Keys();
 	};
 
@@ -131,7 +133,8 @@ class LLViewerInput
     BOOL            handleMouse(LLWindow *window_impl, LLCoordGL pos, MASK mask, EMouseClickType clicktype, BOOL down);
     void            scanMouse();
 
-    bool            isMouseBindUsed(const EMouseClickType mouse, const MASK mask = MASK_NONE, const S32 mode = MODE_THIRD_PERSON);
+    bool            isMouseBindUsed(const EMouseClickType mouse, const MASK mask, const S32 mode) const;
+    bool            isLMouseHandlingDefault(const S32 mode) const { return mLMouseDefaultHandling[mode]; }
 
 private:
     bool            scanKey(const std::vector<LLKeyboardBinding> &binding,
@@ -171,6 +174,7 @@ class LLViewerInput
     // to send what we think function wants based on collection of bools (mKeyRepeated, mKeyLevel, mKeyDown)
     std::vector<LLKeyboardBinding>	mKeyBindings[MODE_COUNT];
     std::vector<LLMouseBinding>		mMouseBindings[MODE_COUNT];
+    bool							mLMouseDefaultHandling[MODE_COUNT]; // Due to having special priority
 
     // keybindings that do not consume event and are handled earlier, before floaters
     std::vector<LLKeyboardBinding>	mGlobalKeyBindings[MODE_COUNT];
diff --git a/indra/newview/llviewerjointattachment.cpp b/indra/newview/llviewerjointattachment.cpp
index 8a597ed7e65147c5c862ec3ed41b645f31b56944..fd314ed3dcafe8c30aae48171c1d7d8f9cfbb7b3 100644
--- a/indra/newview/llviewerjointattachment.cpp
+++ b/indra/newview/llviewerjointattachment.cpp
@@ -121,8 +121,7 @@ void LLViewerJointAttachment::setupDrawable(LLViewerObject *object)
 	object->mDrawable->mXform.setRotation(current_rot);
 	gPipeline.markMoved(object->mDrawable);
 	gPipeline.markTextured(object->mDrawable); // face may need to change draw pool to/from POOL_HUD
-	object->mDrawable->setState(LLDrawable::USE_BACKLIGHT);
-	
+
 	if(mIsHUDAttachment)
 	{
 		for (S32 face_num = 0; face_num < object->mDrawable->getNumFaces(); face_num++)
@@ -142,7 +141,6 @@ void LLViewerJointAttachment::setupDrawable(LLViewerObject *object)
 		LLViewerObject* childp = *iter;
 		if (childp && childp->mDrawable.notNull())
 		{
-			childp->mDrawable->setState(LLDrawable::USE_BACKLIGHT);
 			gPipeline.markTextured(childp->mDrawable); // face may need to change draw pool to/from POOL_HUD
 			gPipeline.markMoved(childp->mDrawable);
 
@@ -256,7 +254,6 @@ void LLViewerJointAttachment::removeObject(LLViewerObject *object)
 		object->mDrawable->mXform.setRotation(cur_rotation);
 		gPipeline.markMoved(object->mDrawable, TRUE);
 		gPipeline.markTextured(object->mDrawable); // face may need to change draw pool to/from POOL_HUD
-		object->mDrawable->clearState(LLDrawable::USE_BACKLIGHT);
 
 		if (mIsHUDAttachment)
 		{
@@ -278,7 +275,6 @@ void LLViewerJointAttachment::removeObject(LLViewerObject *object)
 		LLViewerObject* childp = *iter;
 		if (childp && childp->mDrawable.notNull())
 		{
-			childp->mDrawable->clearState(LLDrawable::USE_BACKLIGHT);
 			gPipeline.markTextured(childp->mDrawable); // face may need to change draw pool to/from POOL_HUD
 			if (mIsHUDAttachment)
 			{
diff --git a/indra/newview/llviewerjointmesh.cpp b/indra/newview/llviewerjointmesh.cpp
index 63ad708e59bd1f43e826c724f892b2683af9724e..f3b0e82b3af2f383ccd2692f1a9f6564343c3d14 100644
--- a/indra/newview/llviewerjointmesh.cpp
+++ b/indra/newview/llviewerjointmesh.cpp
@@ -225,7 +225,7 @@ U32 LLViewerJointMesh::drawShape( F32 pixelArea, BOOL first_pass, BOOL is_dummy)
 	if (!mValid || !mMesh || !mFace || !mVisible || 
 		!mFace->getVertexBuffer() ||
 		mMesh->getNumFaces() == 0 ||
-		(LLGLSLShader::sNoFixedFunction && LLGLSLShader::sCurBoundShaderPtr == NULL))
+		LLGLSLShader::sCurBoundShaderPtr == NULL)
 	{
 		return 0;
 	}
@@ -246,7 +246,7 @@ U32 LLViewerJointMesh::drawShape( F32 pixelArea, BOOL first_pass, BOOL is_dummy)
 
 	stop_glerror();
 	
-	LLGLSSpecular specular(LLColor4(1.f,1.f,1.f,1.f), (mFace->getPool()->getShaderLevel() > 0 || LLGLSLShader::sNoFixedFunction) ? 0.f : mShiny);
+	LLGLSSpecular specular(LLColor4(1.f,1.f,1.f,1.f), 0.f);
 
 	//----------------------------------------------------------------
 	// setup current texture
@@ -265,7 +265,6 @@ U32 LLViewerJointMesh::drawShape( F32 pixelArea, BOOL first_pass, BOOL is_dummy)
 		else
 		{
 			gGL.diffuseColor4f(0.7f, 0.6f, 0.3f, 1.f);
-			gGL.getTexUnit(diffuse_channel)->setTextureColorBlend(LLTexUnit::TBO_LERP_TEX_ALPHA, LLTexUnit::TBS_TEX_COLOR, LLTexUnit::TBS_PREV_COLOR);
 		}
 	}
 	else if( !is_dummy && layerset )
@@ -328,11 +327,6 @@ U32 LLViewerJointMesh::drawShape( F32 pixelArea, BOOL first_pass, BOOL is_dummy)
 
 	triangle_count += count;
 	
-	if (mTestImageName)
-	{
-		gGL.getTexUnit(diffuse_channel)->setTextureBlendType(LLTexUnit::TB_MULT);
-	}
-
 	return triangle_count;
 }
 
@@ -362,7 +356,6 @@ void LLViewerJointMesh::updateFaceSizes(U32 &num_vertices, U32& num_indices, F32
 //-----------------------------------------------------------------------------
 // updateFaceData()
 //-----------------------------------------------------------------------------
-static LLTrace::BlockTimerStatHandle FTM_AVATAR_FACE("Avatar Face");
 
 void LLViewerJointMesh::updateFaceData(LLFace *face, F32 pixel_area, BOOL damp_wind, bool terse_update)
 {
@@ -383,9 +376,8 @@ void LLViewerJointMesh::updateFaceData(LLFace *face, F32 pixel_area, BOOL damp_w
 	 // since mMesh is being copied into mVertexBuffer every frame
 		return;
 	}
-
-
-	LL_RECORD_BLOCK_TIME(FTM_AVATAR_FACE);
+    
+    LL_PROFILE_ZONE_SCOPED;
 
 	LLStrider<LLVector3> verticesp;
 	LLStrider<LLVector3> normalsp;
diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp
index 07190d0538f3aeaee3e0df9a58fc53eb9735d9a1..a1cb152e1e54c87d922d8853a4e932e6cc6fb0d9 100644
--- a/indra/newview/llviewermedia.cpp
+++ b/indra/newview/llviewermedia.cpp
@@ -39,6 +39,7 @@
 #include "llfilepicker.h"
 #include "llfloaterwebcontent.h"	// for handling window close requests and geometry change requests in media browser windows.
 #include "llfocusmgr.h"
+#include "llimagegl.h"
 #include "llkeyboard.h"
 #include "lllogininstance.h"
 #include "llmarketplacefunctions.h"
@@ -47,7 +48,7 @@
 #include "llmutelist.h"
 #include "llnotifications.h"
 #include "llnotificationsutil.h"
-#include "llpanelprofile.h"
+#include "llavataractions.h"
 #include "llparcel.h"
 #include "llpluginclassmedia.h"
 #include "llurldispatcher.h"
@@ -606,6 +607,7 @@ static bool proximity_comparitor(const LLViewerMediaImpl* i1, const LLViewerMedi
 static LLTrace::BlockTimerStatHandle FTM_MEDIA_UPDATE("Update Media");
 static LLTrace::BlockTimerStatHandle FTM_MEDIA_SPARE_IDLE("Spare Idle");
 static LLTrace::BlockTimerStatHandle FTM_MEDIA_UPDATE_INTEREST("Update/Interest");
+static LLTrace::BlockTimerStatHandle FTM_MEDIA_UPDATE_VOLUME("Update/Volume");
 static LLTrace::BlockTimerStatHandle FTM_MEDIA_SORT("Media Sort");
 static LLTrace::BlockTimerStatHandle FTM_MEDIA_SORT2("Media Sort 2");
 static LLTrace::BlockTimerStatHandle FTM_MEDIA_MISC("Misc");
@@ -620,11 +622,18 @@ void LLViewerMedia::onIdle(void *dummy_arg)
 //////////////////////////////////////////////////////////////////////////////////////////
 void LLViewerMedia::updateMedia(void *dummy_arg)
 {
-	LL_RECORD_BLOCK_TIME(FTM_MEDIA_UPDATE);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_MEDIA; //LL_RECORD_BLOCK_TIME(FTM_MEDIA_UPDATE);
 
 	// Enable/disable the plugin read thread
 	LLPluginProcessParent::setUseReadThread(gSavedSettings.getBOOL("PluginUseReadThread"));
 
+    // SL-16418 We can't call LLViewerMediaImpl->update() if we are in the state of shutting down.
+    if(LLApp::isExiting())
+    {
+        setAllMediaEnabled(false);
+        return;
+    }
+
 	// HACK: we always try to keep a spare running webkit plugin around to improve launch times.
 	// 2017-04-19 Removed CP - this doesn't appear to buy us much and consumes a lot of resources so
 	// removing it for now.
@@ -637,7 +646,7 @@ void LLViewerMedia::updateMedia(void *dummy_arg)
 	impl_list::iterator end = sViewerMediaImplList.end();
 
 	{
-		LL_RECORD_BLOCK_TIME(FTM_MEDIA_UPDATE_INTEREST);
+        LL_PROFILE_ZONE_NAMED_CATEGORY_MEDIA("media update interest"); //LL_RECORD_BLOCK_TIME(FTM_MEDIA_UPDATE_INTEREST);
 		for(; iter != end;)
 		{
 			LLViewerMediaImpl* pimpl = *iter++;
@@ -649,12 +658,12 @@ void LLViewerMedia::updateMedia(void *dummy_arg)
 	// Let the spare media source actually launch
 	if(mSpareBrowserMediaSource)
 	{
-		LL_RECORD_BLOCK_TIME(FTM_MEDIA_SPARE_IDLE);
+        LL_PROFILE_ZONE_NAMED_CATEGORY_MEDIA("media spare idle"); //LL_RECORD_BLOCK_TIME(FTM_MEDIA_SPARE_IDLE);
 		mSpareBrowserMediaSource->idle();
 	}
 
 	{
-		LL_RECORD_BLOCK_TIME(FTM_MEDIA_SORT);
+        LL_PROFILE_ZONE_NAMED_CATEGORY_MEDIA("media sort"); //LL_RECORD_BLOCK_TIME(FTM_MEDIA_SORT);
 		// Sort the static instance list using our interest criteria
 		sViewerMediaImplList.sort(priorityComparitor);
 	}
@@ -686,7 +695,7 @@ void LLViewerMedia::updateMedia(void *dummy_arg)
 	// If max_normal + max_low is less than max_instances, things will tend to get unloaded instead of being set to slideshow.
 
 	{
-		LL_RECORD_BLOCK_TIME(FTM_MEDIA_MISC);
+        LL_PROFILE_ZONE_NAMED_CATEGORY_MEDIA("media misc"); //LL_RECORD_BLOCK_TIME(FTM_MEDIA_MISC);
 		for(; iter != end; iter++)
 		{
 			LLViewerMediaImpl* pimpl = *iter;
@@ -871,7 +880,7 @@ void LLViewerMedia::updateMedia(void *dummy_arg)
 	}
 	else
 	{
-		LL_RECORD_BLOCK_TIME(FTM_MEDIA_SORT2);
+        LL_PROFILE_ZONE_NAMED_CATEGORY_MEDIA("media sort2"); // LL_RECORD_BLOCK_TIME(FTM_MEDIA_SORT2);
 		// Use a distance-based sort for proximity values.
 		std::stable_sort(proximity_order.begin(), proximity_order.end(), proximity_comparitor);
 	}
@@ -1187,7 +1196,7 @@ LLCore::HttpHeaders::ptr_t LLViewerMedia::getHttpHeaders()
 /////////////////////////////////////////////////////////////////////////////////////////
 void LLViewerMedia::setOpenIDCookie(const std::string& url)
 {
-	if(!mOpenIDCookie.empty())
+	if(!gNonInteractive && !mOpenIDCookie.empty())
 	{
         std::string profileUrl = getProfileURL("");
 
@@ -1561,6 +1570,8 @@ LLViewerMediaImpl::LLViewerMediaImpl(	  const LLUUID& texture_id,
 		media_tex->setMediaImpl();
 	}
 
+    mMainQueue = LL::WorkQueue::getInstance("mainloop");
+    mTexUpdateQueue = LL::WorkQueue::getInstance("LLImageGL"); // Share work queue with tex loader.
 }
 
 //////////////////////////////////////////////////////////////////////////////////////////
@@ -1647,11 +1658,13 @@ void LLViewerMediaImpl::destroyMediaSource()
 
 	cancelMimeTypeProbe();
 
+    mLock.lock();   // Delay tear-down while bg thread is updating
 	if(mMediaSource)
 	{
 		mMediaSource->setDeleteOK(true) ;
 		mMediaSource = NULL; // shared pointer
 	}
+    mLock.unlock();
 }
 
 //////////////////////////////////////////////////////////////////////////////////////////
@@ -1664,6 +1677,11 @@ void LLViewerMediaImpl::setMediaType(const std::string& media_type)
 /*static*/
 LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_type, LLPluginClassMediaOwner *owner /* may be NULL */, S32 default_width, S32 default_height, F64 zoom_factor, const std::string target, bool clean_browser)
 {
+	if (gNonInteractive)
+    {
+        return NULL;
+    }
+
 	std::string plugin_basename = LLMIMETypes::implType(media_type);
 	LLPluginClassMedia* media_source = NULL;
 
@@ -2055,6 +2073,7 @@ void LLViewerMediaImpl::setMute(bool mute)
 //////////////////////////////////////////////////////////////////////////////////////////
 void LLViewerMediaImpl::updateVolume()
 {
+    LL_RECORD_BLOCK_TIME(FTM_MEDIA_UPDATE_VOLUME);
 	if(mMediaSource)
 	{
 		// always scale the volume by the global media volume
@@ -2766,200 +2785,272 @@ static LLTrace::BlockTimerStatHandle FTM_MEDIA_SET_SUBIMAGE("Set Subimage");
 
 void LLViewerMediaImpl::update()
 {
-	LL_RECORD_BLOCK_TIME(FTM_MEDIA_DO_UPDATE);
-	if(mMediaSource == NULL)
-	{
-		if(mPriority == LLPluginClassMedia::PRIORITY_UNLOADED)
-		{
-			// This media source should not be loaded.
-		}
-		else if(mPriority <= LLPluginClassMedia::PRIORITY_SLIDESHOW)
-		{
-			// Don't load new instances that are at PRIORITY_SLIDESHOW or below.  They're just kept around to preserve state.
-		}
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_MEDIA; //LL_RECORD_BLOCK_TIME(FTM_MEDIA_DO_UPDATE);
+    if(mMediaSource == NULL)
+    {
+        if(mPriority == LLPluginClassMedia::PRIORITY_UNLOADED)
+        {
+            // This media source should not be loaded.
+        }
+        else if(mPriority <= LLPluginClassMedia::PRIORITY_SLIDESHOW)
+        {
+            // Don't load new instances that are at PRIORITY_SLIDESHOW or below.  They're just kept around to preserve state.
+        }
         else if (!mMimeProbe.expired())
-		{
-			// this media source is doing a MIME type probe -- don't try loading it again.
-		}
-		else
-		{
-			// This media may need to be loaded.
-			if(sMediaCreateTimer.hasExpired())
-			{
-				LL_DEBUGS("PluginPriority") << this << ": creating media based on timer expiration" << LL_ENDL;
-				createMediaSource();
-				sMediaCreateTimer.setTimerExpirySec(LLVIEWERMEDIA_CREATE_DELAY);
-			}
-			else
-			{
-				LL_DEBUGS("PluginPriority") << this << ": NOT creating media (waiting on timer)" << LL_ENDL;
-			}
-		}
-	}
-	else
-	{
-		updateVolume();
+        {
+            // this media source is doing a MIME type probe -- don't try loading it again.
+        }
+        else
+        {
+            // This media may need to be loaded.
+            if(sMediaCreateTimer.hasExpired())
+            {
+                LL_DEBUGS("PluginPriority") << this << ": creating media based on timer expiration" << LL_ENDL;
+                createMediaSource();
+                sMediaCreateTimer.setTimerExpirySec(LLVIEWERMEDIA_CREATE_DELAY);
+            }
+            else
+            {
+                LL_DEBUGS("PluginPriority") << this << ": NOT creating media (waiting on timer)" << LL_ENDL;
+            }
+        }
+    }
+    else
+    {
+        updateVolume();
 
-		// TODO: this is updated every frame - is this bad?
-		// Removing this as part of the post viewer64 media update
-		// Removed as not implemented in CEF embedded browser
-		// See MAINT-8194 for a more fuller description
-		// updateJavascriptObject();
-	}
+        // TODO: this is updated every frame - is this bad?
+        // Removing this as part of the post viewer64 media update
+        // Removed as not implemented in CEF embedded browser
+        // See MAINT-8194 for a more fuller description
+        // updateJavascriptObject();
+    }
 
 
-	if(mMediaSource == NULL)
-	{
-		return;
-	}
+    if(mMediaSource == NULL)
+    {
+        return;
+    }
 
-	// Make sure a navigate doesn't happen during the idle -- it can cause mMediaSource to get destroyed, which can cause a crash.
-	setNavigateSuspended(true);
+    // Make sure a navigate doesn't happen during the idle -- it can cause mMediaSource to get destroyed, which can cause a crash.
+    setNavigateSuspended(true);
 
-	mMediaSource->idle();
+    mMediaSource->idle();
 
-	setNavigateSuspended(false);
+    setNavigateSuspended(false);
 
-	if(mMediaSource == NULL)
-	{
-		return;
-	}
+    if(mMediaSource == NULL)
+    {
+        return;
+    }
 
-	if(mMediaSource->isPluginExited())
-	{
-		resetPreviousMediaState();
-		destroyMediaSource();
-		return;
-	}
+    if(mMediaSource->isPluginExited())
+    {
+        resetPreviousMediaState();
+        destroyMediaSource();
+        return;
+    }
 
-	if(!mMediaSource->textureValid())
-	{
-		return;
-	}
+    if(!mMediaSource->textureValid())
+    {
+        return;
+    }
 
-	if(mSuspendUpdates || !mVisible)
-	{
-		return;
-	}
+    if(mSuspendUpdates || !mVisible)
+    {
+        return;
+    }
 
-	LLViewerMediaTexture* placeholder_image = updatePlaceholderImage();
+    
+    LLViewerMediaTexture* media_tex;
+    U8* data;
+    S32 data_width;
+    S32 data_height;
+    S32 x_pos;
+    S32 y_pos;
+    S32 width;
+    S32 height;
+
+    if (preMediaTexUpdate(media_tex, data, data_width, data_height, x_pos, y_pos, width, height))
+    {
+        // Push update to worker thread
+        auto main_queue = LLImageGLThread::sEnabled ? mMainQueue.lock() : nullptr;
+        if (main_queue)
+        {
+            mTextureUpdatePending = true;
+            ref();  // protect texture from deletion while active on bg queue
+            media_tex->ref();
+            main_queue->postTo(
+                mTexUpdateQueue, // Worker thread queue
+                [=]() // work done on update worker thread
+                {
+#if LL_IMAGEGL_THREAD_CHECK
+                    media_tex->getGLTexture()->mActiveThread = LLThread::currentID();
+#endif
+                    doMediaTexUpdate(media_tex, data, data_width, data_height, x_pos, y_pos, width, height, true);
+                },
+                [=]() // callback to main thread
+                {
+#if LL_IMAGEGL_THREAD_CHECK
+                    media_tex->getGLTexture()->mActiveThread = LLThread::currentID();
+#endif
+                    mTextureUpdatePending = false;
+                    media_tex->unref();
+                    unref();
+                });
+        }
+        else
+        {
+            doMediaTexUpdate(media_tex, data, data_width, data_height, x_pos, y_pos, width, height, false); // otherwise, update on main thread
+        }
+    }
+}
 
-	if(placeholder_image)
-	{
-		LLRect dirty_rect;
+bool LLViewerMediaImpl::preMediaTexUpdate(LLViewerMediaTexture*& media_tex, U8*& data, S32& data_width, S32& data_height, S32& x_pos, S32& y_pos, S32& width, S32& height)
+{
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_MEDIA;
 
-		// Since we're updating this texture, we know it's playing.  Tell the texture to do its replacement magic so it gets rendered.
-		placeholder_image->setPlaying(TRUE);
+    bool retval = false;
 
-		if(mMediaSource->getDirty(&dirty_rect))
-		{
-			// Constrain the dirty rect to be inside the texture
-			S32 x_pos = llmax(dirty_rect.mLeft, 0);
-			S32 y_pos = llmax(dirty_rect.mBottom, 0);
-			S32 width = llmin(dirty_rect.mRight, placeholder_image->getWidth()) - x_pos;
-			S32 height = llmin(dirty_rect.mTop, placeholder_image->getHeight()) - y_pos;
+    if (!mTextureUpdatePending)
+    {
+        media_tex = updateMediaImage();
 
-			if(width > 0 && height > 0)
-			{
+        if (media_tex && mMediaSource)
+        {
+            LLRect dirty_rect;
+            S32 media_width = mMediaSource->getTextureWidth();
+            S32 media_height = mMediaSource->getTextureHeight();
+            //S32 media_depth = mMediaSource->getTextureDepth();
 
-				U8* data = NULL;
-				{
-					LL_RECORD_BLOCK_TIME(FTM_MEDIA_GET_DATA);
-					data = mMediaSource->getBitsData();
-				}
+            // Since we're updating this texture, we know it's playing.  Tell the texture to do its replacement magic so it gets rendered.
+            media_tex->setPlaying(TRUE);
 
-				if(data != NULL)
-				{
-					// Offset the pixels pointer to match x_pos and y_pos
-					data += ( x_pos * mMediaSource->getTextureDepth() * mMediaSource->getBitsWidth() );
-					data += ( y_pos * mMediaSource->getTextureDepth() );
+            if (mMediaSource->getDirty(&dirty_rect))
+            {
+                // Constrain the dirty rect to be inside the texture
+                x_pos = llmax(dirty_rect.mLeft, 0);
+                y_pos = llmax(dirty_rect.mBottom, 0);
+                width = llmin(dirty_rect.mRight, media_width) - x_pos;
+                height = llmin(dirty_rect.mTop, media_height) - y_pos;
 
-					{
-						LL_RECORD_BLOCK_TIME(FTM_MEDIA_SET_SUBIMAGE);
-									placeholder_image->setSubImage(
-									data,
-									mMediaSource->getBitsWidth(),
-									mMediaSource->getBitsHeight(),
-									x_pos,
-									y_pos,
-									width,
-									height);
-					}
-				}
+                if (width > 0 && height > 0)
+                {
+                    data = mMediaSource->getBitsData();
+                    data_width = mMediaSource->getWidth();
+                    data_height = mMediaSource->getHeight();
+
+                    if (data != NULL)
+                    {
+                        // data is ready to be copied to GL
+                        retval = true;
+                    }
+                }
 
-			}
+                mMediaSource->resetDirty();
+            }
+        }
+    }
 
-			mMediaSource->resetDirty();
-		}
-	}
+    return retval;
 }
 
+//////////////////////////////////////////////////////////////////////////////////////////
+void LLViewerMediaImpl::doMediaTexUpdate(LLViewerMediaTexture* media_tex, U8* data, S32 data_width, S32 data_height, S32 x_pos, S32 y_pos, S32 width, S32 height, bool sync)
+{
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_MEDIA;
+    mLock.lock();   // don't allow media source tear-down during update
+
+    // wrap "data" in an LLImageRaw but do NOT make a copy
+    LLPointer<LLImageRaw> raw = new LLImageRaw(data, media_tex->getWidth(), media_tex->getHeight(), media_tex->getComponents(), true);
+        
+    // Allocate GL texture based on LLImageRaw but do NOT copy to GL
+    LLGLuint tex_name = 0;
+    media_tex->createGLTexture(0, raw, 0, TRUE, LLGLTexture::OTHER, true, &tex_name);
+
+    // copy just the subimage covered by the image raw to GL
+    media_tex->setSubImage(data, data_width, data_height, x_pos, y_pos, width, height, tex_name);
+    
+    if (sync)
+    {
+        media_tex->getGLTexture()->syncToMainThread(tex_name);
+    }
+    else
+    {
+        media_tex->getGLTexture()->syncTexName(tex_name);
+    }
+    
+    // release the data pointer before freeing raw so LLImageRaw destructor doesn't
+    // free memory at data pointer
+    raw->releaseData();
+
+    mLock.unlock();
+}
 
 //////////////////////////////////////////////////////////////////////////////////////////
 void LLViewerMediaImpl::updateImagesMediaStreams()
 {
 }
 
-
 //////////////////////////////////////////////////////////////////////////////////////////
-LLViewerMediaTexture* LLViewerMediaImpl::updatePlaceholderImage()
+LLViewerMediaTexture* LLViewerMediaImpl::updateMediaImage()
 {
-	if(mTextureId.isNull())
-	{
-		// The code that created this instance will read from the plugin's bits.
-		return NULL;
-	}
-
-	LLViewerMediaTexture* placeholder_image = LLViewerTextureManager::getMediaTexture( mTextureId );
-
-	if (mNeedsNewTexture
-		|| placeholder_image->getUseMipMaps()
-		|| (placeholder_image->getWidth() != mMediaSource->getTextureWidth())
-		|| (placeholder_image->getHeight() != mMediaSource->getTextureHeight())
-		|| (mTextureUsedWidth != mMediaSource->getWidth())
-		|| (mTextureUsedHeight != mMediaSource->getHeight())
-		)
-	{
-		LL_DEBUGS("Media") << "initializing media placeholder" << LL_ENDL;
-		LL_DEBUGS("Media") << "movie image id " << mTextureId << LL_ENDL;
-
-		int texture_width = mMediaSource->getTextureWidth();
-		int texture_height = mMediaSource->getTextureHeight();
-		int texture_depth = mMediaSource->getTextureDepth();
-
-		// MEDIAOPT: check to see if size actually changed before doing work
-		placeholder_image->destroyGLTexture();
-		// MEDIAOPT: apparently just calling setUseMipMaps(FALSE) doesn't work?
-		placeholder_image->reinit(FALSE);	// probably not needed
-
-		// MEDIAOPT: seems insane that we actually have to make an imageraw then
-		// immediately discard it
-		LLPointer<LLImageRaw> raw = new LLImageRaw(texture_width, texture_height, texture_depth);
-		// Clear the texture to the background color, ignoring alpha.
-		// convert background color channels from [0.0, 1.0] to [0, 255];
-		raw->clear(int(mBackgroundColor.mV[VX] * 255.0f), int(mBackgroundColor.mV[VY] * 255.0f), int(mBackgroundColor.mV[VZ] * 255.0f), 0xff);
-		int discard_level = 0;
-
-		// ask media source for correct GL image format constants
-		placeholder_image->setExplicitFormat(mMediaSource->getTextureFormatInternal(),
-											 mMediaSource->getTextureFormatPrimary(),
-											 mMediaSource->getTextureFormatType(),
-											 mMediaSource->getTextureFormatSwapBytes());
-
-		placeholder_image->createGLTexture(discard_level, raw);
-
-		// MEDIAOPT: set this dynamically on play/stop
-		// FIXME
-//		placeholder_image->mIsMediaTexture = true;
-		mNeedsNewTexture = false;
-
-		// If the amount of the texture being drawn by the media goes down in either width or height,
-		// recreate the texture to avoid leaving parts of the old image behind.
-		mTextureUsedWidth = mMediaSource->getWidth();
-		mTextureUsedHeight = mMediaSource->getHeight();
-	}
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_MEDIA;
+    if (!mMediaSource)
+    {
+        return nullptr; // not ready for updating
+    }
 
-	return placeholder_image;
+    llassert(!mTextureId.isNull());
+    LLViewerMediaTexture* media_tex = LLViewerTextureManager::getMediaTexture( mTextureId );
+ 
+    if ( mNeedsNewTexture
+        || media_tex->getUseMipMaps()
+        || (media_tex->getWidth() != mMediaSource->getTextureWidth())
+        || (media_tex->getHeight() != mMediaSource->getTextureHeight())
+        || (mTextureUsedWidth != mMediaSource->getWidth())
+        || (mTextureUsedHeight != mMediaSource->getHeight())
+        )
+    {
+        LL_DEBUGS("Media") << "initializing media placeholder" << LL_ENDL;
+        LL_DEBUGS("Media") << "movie image id " << mTextureId << LL_ENDL;
+
+        int texture_width = mMediaSource->getTextureWidth();
+        int texture_height = mMediaSource->getTextureHeight();
+        int texture_depth = mMediaSource->getTextureDepth();
+
+        // MEDIAOPT: check to see if size actually changed before doing work
+        media_tex->destroyGLTexture();
+        // MEDIAOPT: apparently just calling setUseMipMaps(FALSE) doesn't work?
+        media_tex->reinit(FALSE);	// probably not needed
+
+        // MEDIAOPT: seems insane that we actually have to make an imageraw then
+        // immediately discard it
+        LLPointer<LLImageRaw> raw = new LLImageRaw(texture_width, texture_height, texture_depth);
+        // Clear the texture to the background color, ignoring alpha.
+        // convert background color channels from [0.0, 1.0] to [0, 255];
+        raw->clear(int(mBackgroundColor.mV[VX] * 255.0f), int(mBackgroundColor.mV[VY] * 255.0f), int(mBackgroundColor.mV[VZ] * 255.0f), 0xff);
+
+        // ask media source for correct GL image format constants
+        media_tex->setExplicitFormat(mMediaSource->getTextureFormatInternal(),
+            mMediaSource->getTextureFormatPrimary(),
+            mMediaSource->getTextureFormatType(),
+            mMediaSource->getTextureFormatSwapBytes());
+
+        int discard_level = 0;
+        media_tex->createGLTexture(discard_level, raw);
+
+        // MEDIAOPT: set this dynamically on play/stop
+        // FIXME
+//		media_tex->mIsMediaTexture = true;
+        mNeedsNewTexture = false;
+
+        // If the amount of the texture being drawn by the media goes down in either width or height,
+        // recreate the texture to avoid leaving parts of the old image behind.
+        mTextureUsedWidth = mMediaSource->getWidth();
+        mTextureUsedHeight = mMediaSource->getHeight();
+    }
+    return media_tex;
 }
 
 
@@ -3103,7 +3194,7 @@ bool LLViewerMediaImpl::isForcedUnloaded() const
 	}
 
 	// If this media's class is not supposed to be shown, unload
-	if (!shouldShowBasedOnClass())
+	if (!shouldShowBasedOnClass() || isObscured())
 	{
 		return true;
 	}
@@ -3198,10 +3289,6 @@ void LLViewerMediaImpl::handleMediaEvent(LLPluginClassMedia* plugin, LLPluginCla
 		case LLViewerMediaObserver::MEDIA_EVENT_FILE_DOWNLOAD:
 		{
 			LL_DEBUGS("Media") << "Media event - file download requested - filename is " << plugin->getFileDownloadFilename() << LL_ENDL;
-
-            //unblock media plugin
-            const std::vector<std::string> empty_response;
-            plugin->sendPickFileResponse(empty_response);
 		}
 		break;
 
@@ -3463,7 +3550,7 @@ static LLTrace::BlockTimerStatHandle FTM_MEDIA_CALCULATE_INTEREST("Calculate Int
 
 void LLViewerMediaImpl::calculateInterest()
 {
-	LL_RECORD_BLOCK_TIME(FTM_MEDIA_CALCULATE_INTEREST);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_MEDIA; //LL_RECORD_BLOCK_TIME(FTM_MEDIA_CALCULATE_INTEREST);
 	LLViewerMediaTexture* texture = LLViewerTextureManager::findMediaTexture( mTextureId );
 
 	if(texture != NULL)
@@ -3792,6 +3879,40 @@ bool LLViewerMediaImpl::shouldShowBasedOnClass() const
 	}
 }
 
+//////////////////////////////////////////////////////////////////////////////////////////
+//
+bool LLViewerMediaImpl::isObscured() const
+{
+    if (getUsedInUI() || isParcelMedia() || isAttachedToHUD()) return false;
+
+    LLParcel* agent_parcel = LLViewerParcelMgr::getInstance()->getAgentParcel();
+    if (!agent_parcel)
+    {
+        return false;
+    }
+    
+    if (agent_parcel->getObscureMOAP() && !isInAgentParcel())
+    {
+        return true;
+    }
+
+    return false;
+}
+
+bool LLViewerMediaImpl::isAttachedToHUD() const
+{
+    std::list< LLVOVolume* >::const_iterator iter = mObjectList.begin();
+    std::list< LLVOVolume* >::const_iterator end = mObjectList.end();
+    for ( ; iter != end; iter++)
+    {
+        if ((*iter)->isHUDAttachment())
+        {
+            return true;
+        }
+    }
+    return false;
+}
+
 //////////////////////////////////////////////////////////////////////////////////////////
 //
 bool LLViewerMediaImpl::isAttachedToAnotherAvatar() const
diff --git a/indra/newview/llviewermedia.h b/indra/newview/llviewermedia.h
index 71cec5125d91aa4f86cf1757b7eb8920af9fa421..f1f42afd81ac127be5f68b27b257f97d9acd8f1f 100644
--- a/indra/newview/llviewermedia.h
+++ b/indra/newview/llviewermedia.h
@@ -197,7 +197,7 @@ class LLViewerMediaImpl
 		U8 media_loop);
 
 	~LLViewerMediaImpl();
-	
+
 	// Override inherited version from LLViewerMediaEventEmitter 
 	virtual void emitEvent(LLPluginClassMedia* self, LLViewerMediaObserver::EMediaEvent event);
 
@@ -266,6 +266,8 @@ class LLViewerMediaImpl
 	void scaleTextureCoords(const LLVector2& texture_coords, S32 *x, S32 *y);
 
 	void update();
+    bool preMediaTexUpdate(LLViewerMediaTexture*& media_tex, U8*& data, S32& data_width, S32& data_height, S32& x_pos, S32& y_pos, S32& width, S32& height);
+    void doMediaTexUpdate(LLViewerMediaTexture* media_tex, U8* data, S32 data_width, S32 data_height, S32 x_pos, S32 y_pos, S32 width, S32 height, bool sync);
 	void updateImagesMediaStreams();
 	LLUUID getMediaTextureID() const;
 	
@@ -409,6 +411,8 @@ class LLViewerMediaImpl
 	
 	void cancelMimeTypeProbe();
 	
+    bool isAttachedToHUD() const;
+
 	// Is this media attached to an avatar *not* self
 	bool isAttachedToAnotherAvatar() const;
 	
@@ -421,12 +425,14 @@ class LLViewerMediaImpl
 private:
 	bool isAutoPlayable() const;
 	bool shouldShowBasedOnClass() const;
+	bool isObscured() const;
 	static bool isObjectAttachedToAnotherAvatar(LLVOVolume *obj);
 	static bool isObjectInAgentParcel(LLVOVolume *obj);
 	
 private:
 	// a single media url with some data and an impl.
 	boost::shared_ptr<LLPluginClassMedia> mMediaSource;
+    LLMutex mLock;
 	F64		mZoomFactor;
 	LLUUID mTextureId;
 	bool  mMovieImageHasMips;
@@ -446,6 +452,7 @@ class LLViewerMediaImpl
 	S32 mTextureUsedWidth;
 	S32 mTextureUsedHeight;
 	bool mSuspendUpdates;
+    bool mTextureUpdatePending = false;
 	bool mVisible;
 	ECursorType mLastSetCursor;
 	EMediaNavState mMediaNavState;
@@ -479,7 +486,7 @@ class LLViewerMediaImpl
 	LLNotificationPtr mNotification;
     bool mCleanBrowser;     // force the creation of a clean browsing target with full options enabled
     static std::vector<std::string> sMimeTypesFailed;
-
+    LLPointer<LLImageRaw> mRawImage; //backing buffer for texture updates
 private:
 	BOOL mIsUpdated ;
 	std::list< LLVOVolume* > mObjectList ;
@@ -489,7 +496,10 @@ class LLViewerMediaImpl
     bool mCanceling;
 
 private:
-	LLViewerMediaTexture *updatePlaceholderImage();
+	LLViewerMediaTexture *updateMediaImage();
+    LL::WorkQueue::weak_t mMainQueue;
+    LL::WorkQueue::weak_t mTexUpdateQueue;
+
 };
 
 #endif	// LLVIEWERMEDIA_H
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index 4ca449b6acaaeba3181106fc795a4f2b31075171..3573af40cb710dc75977fcc02b6dd918db6c59c4 100644
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -33,10 +33,11 @@
 #include "llviewermenu.h" 
 
 // linden library includes
-#include "llavatarnamecache.h"	// IDEVO
+#include "llavatarnamecache.h"  // IDEVO (I Are Not Men!)
+#include "llcombobox.h"
+#include "llcoros.h"
 #include "llfloaterreg.h"
 #include "llfloatersidepanelcontainer.h"
-#include "llcombobox.h"
 #include "llinventorypanel.h"
 #include "llnotifications.h"
 #include "llnotificationsutil.h"
@@ -53,6 +54,7 @@
 #include "llcompilequeue.h"
 #include "llconsole.h"
 #include "lldebugview.h"
+#include "lldiskcache.h"
 #include "llenvironment.h"
 #include "llfilepicker.h"
 #include "llfirstuse.h"
@@ -93,6 +95,7 @@
 #include "llmarketplacefunctions.h"
 #include "llmenuoptionpathfindingrebakenavmesh.h"
 #include "llmoveview.h"
+#include "llnavigationbar.h"
 #include "llparcel.h"
 #include "llrootview.h"
 #include "llsceneview.h"
@@ -398,7 +401,19 @@ void set_merchant_SLM_menu()
     // All other cases (new merchant, not merchant, migrated merchant): show the new Marketplace Listings menu and enable the tool
     gMenuHolder->getChild<LLView>("MarketplaceListings")->setVisible(TRUE);
     LLCommand* command = LLCommandManager::instance().getCommand("marketplacelistings");
-	gToolBarView->enableCommand(command->id(), true);
+    gToolBarView->enableCommand(command->id(), true);
+
+    const LLUUID marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);
+    if (marketplacelistings_id.isNull())
+    {
+        U32 mkt_status = LLMarketplaceData::instance().getSLMStatus();
+        bool is_merchant = (mkt_status == MarketplaceStatusCodes::MARKET_PLACE_MERCHANT) || (mkt_status == MarketplaceStatusCodes::MARKET_PLACE_MIGRATED_MERCHANT);
+        if (is_merchant)
+        {
+            gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, true);
+            LL_WARNS("SLM") << "Creating the marketplace listings folder for a merchant" << LL_ENDL;
+        }
+    }
 }
 
 void check_merchant_status(bool force)
@@ -2088,6 +2103,32 @@ class LLAdvancedDropPacket : public view_listener_t
 	}
 };
 
+//////////////////////
+// PURGE DISK CACHE //
+//////////////////////
+
+
+class LLAdvancedPurgeDiskCache : public view_listener_t
+{
+	bool handleEvent(const LLSD& userdata)
+	{
+        LL::WorkQueue::ptr_t main_queue = LL::WorkQueue::getInstance("mainloop");
+        LL::WorkQueue::ptr_t general_queue = LL::WorkQueue::getInstance("General");
+        llassert_always(main_queue);
+        llassert_always(general_queue);
+        main_queue->postTo(
+            general_queue,
+            []() // Work done on general queue
+            {
+                LLDiskCache::getInstance()->purge();
+                // Nothing needed to return
+            },
+            [](){}); // Callback to main thread is empty as there is nothing left to do
+
+		return true;
+	}
+};
+
 
 ////////////////////
 // EVENT Recorder //
@@ -2311,18 +2352,6 @@ class LLAdvancedEnableObjectObjectOcclusion: public view_listener_t
 }
 };
 
-/////////////////////////////////////
-// Enable Framebuffer Objects	  ///
-/////////////////////////////////////
-class LLAdvancedEnableRenderFBO: public view_listener_t
-{
-	bool handleEvent(const LLSD& userdata)
-	{
-		bool new_value = gGLManager.mHasFramebufferObject;
-		return new_value;
-	}
-};
-
 /////////////////////////////////////
 // Enable Deferred Rendering	  ///
 /////////////////////////////////////
@@ -2330,7 +2359,7 @@ class LLAdvancedEnableRenderDeferred: public view_listener_t
 {
 	bool handleEvent(const LLSD& userdata)
 	{
-		bool new_value = gGLManager.mHasFramebufferObject && LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_WINDLIGHT) > 1 &&
+		bool new_value = LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_WINDLIGHT) > 1 &&
 			LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_AVATAR) > 0;
 		return new_value;
 	}
@@ -2343,7 +2372,7 @@ class LLAdvancedEnableRenderDeferredOptions: public view_listener_t
 {
 	bool handleEvent(const LLSD& userdata)
 	{
-		bool new_value = gGLManager.mHasFramebufferObject && LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_WINDLIGHT) > 1 &&
+		bool new_value = LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_WINDLIGHT) > 1 &&
 			LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_AVATAR) > 0 && gSavedSettings.getBOOL("RenderDeferred");
 		return new_value;
 	}
@@ -2395,6 +2424,7 @@ class LLAdvancedForceErrorLlerror : public view_listener_t
 		return true;
 	}
 };
+
 class LLAdvancedForceErrorBadMemoryAccess : public view_listener_t
 {
 	bool handleEvent(const LLSD& userdata)
@@ -2404,6 +2434,22 @@ class LLAdvancedForceErrorBadMemoryAccess : public view_listener_t
 	}
 };
 
+class LLAdvancedForceErrorBadMemoryAccessCoro : public view_listener_t
+{
+    bool handleEvent(const LLSD& userdata)
+    {
+        LLCoros::instance().launch(
+            "AdvancedForceErrorBadMemoryAccessCoro",
+            [](){
+                // Wait for one mainloop() iteration, letting the enclosing
+                // handleEvent() method return.
+                llcoro::suspend();
+                force_error_bad_memory_access(NULL);
+            });
+        return true;
+    }
+};
+
 class LLAdvancedForceErrorInfiniteLoop : public view_listener_t
 {
 	bool handleEvent(const LLSD& userdata)
@@ -2422,6 +2468,22 @@ class LLAdvancedForceErrorSoftwareException : public view_listener_t
 	}
 };
 
+class LLAdvancedForceErrorSoftwareExceptionCoro : public view_listener_t
+{
+    bool handleEvent(const LLSD& userdata)
+    {
+        LLCoros::instance().launch(
+            "AdvancedForceErrorSoftwareExceptionCoro",
+            [](){
+                // Wait for one mainloop() iteration, letting the enclosing
+                // handleEvent() method return.
+                llcoro::suspend();
+                force_error_software_exception(NULL);
+            });
+        return true;
+    }
+};
+
 class LLAdvancedForceErrorDriverCrash : public view_listener_t
 {
 	bool handleEvent(const LLSD& userdata)
@@ -2713,6 +2775,32 @@ void handle_object_touch()
 	send_ObjectDeGrab_message(object, pick);
 }
 
+void handle_object_show_original()
+{
+    LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
+    if (!object)
+    {
+        return;
+    }
+
+    LLViewerObject *parent = (LLViewerObject*)object->getParent();
+    while (parent)
+    {
+        if(parent->isAvatar())
+        {
+            break;
+        }
+        object = parent;
+        parent = (LLViewerObject*)parent->getParent();
+    }
+
+    if (!object || object->isAvatar())
+    {
+        return;
+    }
+
+    show_item_original(object->getAttachmentItemID());
+}
 
 
 static void init_default_item_label(const std::string& item_name)
@@ -3597,6 +3685,11 @@ bool my_profile_visible()
 	return floaterp && floaterp->isInVisibleChain();
 }
 
+bool picks_tab_visible()
+{
+    return my_profile_visible() && LLAvatarActions::isPickTabSelected(gAgentID);
+}
+
 bool enable_freeze_eject(const LLSD& avatar_id)
 {
 	// Use avatar_id if available, otherwise default to right-click avatar
@@ -4177,23 +4270,9 @@ bool is_object_sittable()
 	}
 }
 
-
 // only works on pie menu
-void handle_object_sit_or_stand()
+void handle_object_sit(LLViewerObject *object, const LLVector3 &offset)
 {
-	LLPickInfo pick = LLToolPie::getInstance()->getPick();
-	LLViewerObject *object = pick.getObject();;
-	if (!object || pick.mPickType == LLPickInfo::PICK_FLORA)
-	{
-		return;
-	}
-
-	if (sitting_on_selection())
-	{
-		gAgent.standUp();
-		return;
-	}
-
 	// get object selection offset 
 
 	if (object && object->getPCode() == LL_PCODE_VOLUME)
@@ -4205,12 +4284,42 @@ void handle_object_sit_or_stand()
 		gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
 		gMessageSystem->nextBlockFast(_PREHASH_TargetObject);
 		gMessageSystem->addUUIDFast(_PREHASH_TargetID, object->mID);
-		gMessageSystem->addVector3Fast(_PREHASH_Offset, pick.mObjectOffset);
+		gMessageSystem->addVector3Fast(_PREHASH_Offset, offset);
 
 		object->getRegion()->sendReliableMessage();
 	}
 }
 
+void handle_object_sit_or_stand()
+{
+    LLPickInfo pick = LLToolPie::getInstance()->getPick();
+    LLViewerObject *object = pick.getObject();
+    if (!object || pick.mPickType == LLPickInfo::PICK_FLORA)
+    {
+        return;
+    }
+
+    if (sitting_on_selection())
+    {
+        gAgent.standUp();
+        return;
+    }
+
+    handle_object_sit(object, pick.mObjectOffset);
+}
+
+void handle_object_sit(const LLUUID& object_id)
+{
+    LLViewerObject* obj = gObjectList.findObject(object_id);
+    if (!obj)
+    {
+        return;
+    }
+
+    LLVector3 offset(0, 0, 0);
+    handle_object_sit(obj, offset);
+}
+
 void near_sit_down_point(BOOL success, void *)
 {
 	if (success)
@@ -5306,12 +5415,10 @@ class LLToolsEnablePathfindingRebakeRegion : public view_listener_t
 	{
 		bool returnValue = false;
 
-		if (LLPathfindingManager::getInstance() != NULL)
-		{
-			LLMenuOptionPathfindingRebakeNavmesh *rebakeInstance = LLMenuOptionPathfindingRebakeNavmesh::getInstance();
-			returnValue = (rebakeInstance->canRebakeRegion() &&
-				(rebakeInstance->getMode() == LLMenuOptionPathfindingRebakeNavmesh::kRebakeNavMesh_Available));
-		}
+        if (LLNavigationBar::instanceExists())
+        {
+            returnValue = LLNavigationBar::getInstance()->isRebakeNavMeshAvailable();
+        }
 		return returnValue;
 	}
 };
@@ -6274,6 +6381,29 @@ class LLAvatarToggleMyProfile : public view_listener_t
 	}
 };
 
+class LLAvatarTogglePicks : public view_listener_t
+{
+    bool handleEvent(const LLSD& userdata)
+    {
+        LLFloater * instance = LLAvatarActions::getProfileFloater(gAgent.getID());
+        if (LLFloater::isMinimized(instance) || (instance && !instance->hasFocus() && !instance->getIsChrome()))
+        {
+            instance->setMinimized(FALSE);
+            instance->setFocus(TRUE);
+            LLAvatarActions::showPicks(gAgent.getID());
+        }
+        else if (picks_tab_visible())
+        {
+            instance->closeFloater();
+        }
+        else
+        {
+            LLAvatarActions::showPicks(gAgent.getID());
+        }
+        return true;
+    }
+};
+
 class LLAvatarToggleSearch : public view_listener_t
 {
 	bool handleEvent(const LLSD& userdata)
@@ -6345,6 +6475,24 @@ class LLAvatarResetSkeletonAndAnimations : public view_listener_t
 	}
 };
 
+class LLAvatarResetSelfSkeletonAndAnimations : public view_listener_t
+{
+	bool handleEvent(const LLSD& userdata)
+	{
+		LLVOAvatar* avatar = find_avatar_from_object(LLSelectMgr::getInstance()->getSelection()->getPrimaryObject());
+		if (avatar)
+		{
+			avatar->resetSkeleton(true);
+		}
+		else
+		{
+			gAgentAvatarp->resetSkeleton(true);
+		}
+		return true;
+	}
+};
+
+
 class LLAvatarAddContact : public view_listener_t
 {
 	bool handleEvent(const LLSD& userdata)
@@ -6726,6 +6874,15 @@ class LLShowAgentProfile : public view_listener_t
 	}
 };
 
+class LLShowAgentProfilePicks : public view_listener_t
+{
+    bool handleEvent(const LLSD& userdata)
+    {
+        LLAvatarActions::showPicks(gAgent.getID());
+        return true;
+    }
+};
+
 class LLToggleAgentProfile : public view_listener_t
 {
 	bool handleEvent(const LLSD& userdata)
@@ -8412,6 +8569,7 @@ class LLViewHighlightTransparent : public view_listener_t
 	bool handleEvent(const LLSD& userdata)
 	{
 		LLDrawPoolAlpha::sShowDebugAlpha = !LLDrawPoolAlpha::sShowDebugAlpha;
+        gPipeline.resetVertexBuffers();
 		return true;
 	}
 };
@@ -9263,7 +9421,6 @@ void initialize_menus()
 	view_listener_t::addMenu(new LLAdvancedCheckWireframe(), "Advanced.CheckWireframe");
 	// Develop > Render
 	view_listener_t::addMenu(new LLAdvancedEnableObjectObjectOcclusion(), "Advanced.EnableObjectObjectOcclusion");
-	view_listener_t::addMenu(new LLAdvancedEnableRenderFBO(), "Advanced.EnableRenderFBO");
 	view_listener_t::addMenu(new LLAdvancedEnableRenderDeferred(), "Advanced.EnableRenderDeferred");
 	view_listener_t::addMenu(new LLAdvancedEnableRenderDeferredOptions(), "Advanced.EnableRenderDeferredOptions");
 	view_listener_t::addMenu(new LLAdvancedToggleRandomizeFramerate(), "Advanced.ToggleRandomizeFramerate");
@@ -9362,6 +9519,9 @@ void initialize_menus()
 	view_listener_t::addMenu(new LLAdvancedDisableMessageLog(), "Advanced.DisableMessageLog");
 	view_listener_t::addMenu(new LLAdvancedDropPacket(), "Advanced.DropPacket");
 
+    // Advanced > Cache
+    view_listener_t::addMenu(new LLAdvancedPurgeDiskCache(), "Advanced.PurgeDiskCache");
+
 	// Advanced > Recorder
 	view_listener_t::addMenu(new LLAdvancedAgentPilot(), "Advanced.AgentPilot");
 	view_listener_t::addMenu(new LLAdvancedToggleAgentPilotLoop(), "Advanced.ToggleAgentPilotLoop");
@@ -9372,8 +9532,10 @@ void initialize_menus()
 	view_listener_t::addMenu(new LLAdvancedForceErrorBreakpoint(), "Advanced.ForceErrorBreakpoint");
 	view_listener_t::addMenu(new LLAdvancedForceErrorLlerror(), "Advanced.ForceErrorLlerror");
 	view_listener_t::addMenu(new LLAdvancedForceErrorBadMemoryAccess(), "Advanced.ForceErrorBadMemoryAccess");
+	view_listener_t::addMenu(new LLAdvancedForceErrorBadMemoryAccessCoro(), "Advanced.ForceErrorBadMemoryAccessCoro");
 	view_listener_t::addMenu(new LLAdvancedForceErrorInfiniteLoop(), "Advanced.ForceErrorInfiniteLoop");
 	view_listener_t::addMenu(new LLAdvancedForceErrorSoftwareException(), "Advanced.ForceErrorSoftwareException");
+	view_listener_t::addMenu(new LLAdvancedForceErrorSoftwareExceptionCoro(), "Advanced.ForceErrorSoftwareExceptionCoro");
 	view_listener_t::addMenu(new LLAdvancedForceErrorDriverCrash(), "Advanced.ForceErrorDriverCrash");
     view_listener_t::addMenu(new LLAdvancedForceErrorCoroutineCrash(), "Advanced.ForceErrorCoroutineCrash");
     view_listener_t::addMenu(new LLAdvancedForceErrorThreadCrash(), "Advanced.ForceErrorThreadCrash");
@@ -9448,11 +9610,14 @@ void initialize_menus()
 	enable.add("Avatar.EnableCall", boost::bind(&LLAvatarActions::canCall));
 	view_listener_t::addMenu(new LLAvatarReportAbuse(), "Avatar.ReportAbuse");
 	view_listener_t::addMenu(new LLAvatarToggleMyProfile(), "Avatar.ToggleMyProfile");
+	view_listener_t::addMenu(new LLAvatarTogglePicks(), "Avatar.TogglePicks");
 	view_listener_t::addMenu(new LLAvatarToggleSearch(), "Avatar.ToggleSearch");
 	view_listener_t::addMenu(new LLAvatarResetSkeleton(), "Avatar.ResetSkeleton");
 	view_listener_t::addMenu(new LLAvatarEnableResetSkeleton(), "Avatar.EnableResetSkeleton");
 	view_listener_t::addMenu(new LLAvatarResetSkeletonAndAnimations(), "Avatar.ResetSkeletonAndAnimations");
+	view_listener_t::addMenu(new LLAvatarResetSelfSkeletonAndAnimations(), "Avatar.ResetSelfSkeletonAndAnimations");
 	enable.add("Avatar.IsMyProfileOpen", boost::bind(&my_profile_visible));
+    enable.add("Avatar.IsPicksTabOpen", boost::bind(&picks_tab_visible));
 
 	commit.add("Avatar.OpenMarketplace", boost::bind(&LLWeb::loadURLExternal, gSavedSettings.getString("MarketplaceURL")));
 	
@@ -9462,6 +9627,7 @@ void initialize_menus()
 	// Object pie menu
 	view_listener_t::addMenu(new LLObjectBuild(), "Object.Build");
 	commit.add("Object.Touch", boost::bind(&handle_object_touch));
+	commit.add("Object.ShowOriginal", boost::bind(&handle_object_show_original));
 	commit.add("Object.SitOrStand", boost::bind(&handle_object_sit_or_stand));
 	commit.add("Object.Delete", boost::bind(&handle_object_delete));
 	view_listener_t::addMenu(new LLObjectAttachToAvatar(true), "Object.AttachToAvatar");
@@ -9528,6 +9694,7 @@ void initialize_menus()
 	view_listener_t::addMenu(new LLToggleSpeak(), "ToggleSpeak");
 	view_listener_t::addMenu(new LLPromptShowURL(), "PromptShowURL");
 	view_listener_t::addMenu(new LLShowAgentProfile(), "ShowAgentProfile");
+    view_listener_t::addMenu(new LLShowAgentProfilePicks(), "ShowAgentProfilePicks");
 	view_listener_t::addMenu(new LLToggleAgentProfile(), "ToggleAgentProfile");
 	view_listener_t::addMenu(new LLToggleControl(), "ToggleControl");
     view_listener_t::addMenu(new LLToggleShaderControl(), "ToggleShaderControl");
diff --git a/indra/newview/llviewermenu.h b/indra/newview/llviewermenu.h
index 36b6971c8175ecb13a11cd1a080b4f59fe17285c..a90b32c984ea03956ad06e220e910953c0f15e39 100644
--- a/indra/newview/llviewermenu.h
+++ b/indra/newview/llviewermenu.h
@@ -135,6 +135,7 @@ void handle_save_snapshot(void *);
 void handle_toggle_flycam();
 
 void handle_object_sit_or_stand();
+void handle_object_sit(const LLUUID& object_id);
 void handle_give_money_dialog();
 bool enable_pay_object();
 bool enable_buy_object();
diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp
index 28ff69eaf532b9bf1edf406fe66984c53fcbee55..f1e2c06e0c761cd08ecdc4da63c67e57ec4fdd0d 100644
--- a/indra/newview/llviewermenufile.cpp
+++ b/indra/newview/llviewermenufile.cpp
@@ -255,13 +255,13 @@ void LLFilePickerReplyThread::notify(const std::vector<std::string>& filenames)
 
 LLMediaFilePicker::LLMediaFilePicker(LLPluginClassMedia* plugin, LLFilePicker::ELoadFilter filter, bool get_multiple)
     : LLFilePickerThread(filter, get_multiple),
-    mPlugin(plugin->getSharedPrt())
+    mPlugin(plugin->getSharedPtr())
 {
 }
 
 LLMediaFilePicker::LLMediaFilePicker(LLPluginClassMedia* plugin, LLFilePicker::ESaveFilter filter, const std::string &proposed_name)
     : LLFilePickerThread(filter, proposed_name),
-    mPlugin(plugin->getSharedPrt())
+    mPlugin(plugin->getSharedPtr())
 {
 }
 
diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp
index 10ffbc7fa768d688af76509cca99f2603af3b988..d97ed61e115f323ca093576d0e5ffe026b9071b6 100644
--- a/indra/newview/llviewermessage.cpp
+++ b/indra/newview/llviewermessage.cpp
@@ -33,6 +33,7 @@
 #include "llavataractions.h"
 #include "llavatarnamecache.h"		// IDEVO HACK
 #include "lleventtimer.h"
+#include "llfloatercreatelandmark.h"
 #include "llfloaterreg.h"
 #include "llfolderview.h"
 #include "llfollowcamparams.h"
@@ -122,6 +123,7 @@
 #include "llexperiencecache.h"
 
 #include "llexperiencecache.h"
+#include "lluiusage.h"
 
 extern void on_new_message(const LLSD& msg);
 
@@ -261,6 +263,7 @@ bool friendship_offer_callback(const LLSD& notification, const LLSD& response)
 	    {
 	    case 0:
 	    {
+			LLUIUsage::instance().logCommand("Agent.AcceptFriendship");
 		    // accept
 		    LLAvatarTracker::formFriendship(payload["from_id"]);
 
@@ -303,6 +306,7 @@ bool friendship_offer_callback(const LLSD& notification, const LLSD& response)
 	    // fall-through
 	    case 2: // Send IM - decline and start IM session
 		    {
+				LLUIUsage::instance().logCommand("Agent.DeclineFriendship");
 			    // decline
 			    // We no longer notify other viewers, but we DO still send
                 // the rejection to the simulator to delete the pending userop.
@@ -833,6 +837,11 @@ void send_join_group_response(LLUUID group_id, LLUUID transaction_id, bool accep
 
         EInstantMessage type = accept_invite ? IM_GROUP_INVITATION_ACCEPT : IM_GROUP_INVITATION_DECLINE;
 
+		if (accept_invite)
+		{
+			LLUIUsage::instance().logCommand("Group.Join");
+		}
+
         send_improved_im(group_id,
             std::string("name"),
             std::string("message"),
@@ -1560,6 +1569,17 @@ bool highlight_offered_object(const LLUUID& obj_id)
 		}
 	}
 
+    if (obj->getType() == LLAssetType::AT_LANDMARK)
+    {
+        LLFloaterCreateLandmark *floater = LLFloaterReg::findTypedInstance<LLFloaterCreateLandmark>("add_landmark");
+        if (floater && floater->getItem() && floater->getItem()->getUUID() == obj_id)
+        {
+            // LLFloaterCreateLandmark is supposed to handle this,
+            // keep landmark creation floater at the front
+            return false;
+        }
+    }
+
 	return true;
 }
 
@@ -2219,11 +2239,9 @@ class LLPostponedServerObjectNotification: public LLPostponedNotification
 	}
 };
 
-static LLTrace::BlockTimerStatHandle FTM_PROCESS_IMPROVED_IM("Process IM");
-
 void process_improved_im(LLMessageSystem *msg, void **user_data)
 {
-    LL_RECORD_BLOCK_TIME(FTM_PROCESS_IMPROVED_IM);
+    LL_PROFILE_ZONE_SCOPED;
 
     LLUUID from_id;
     BOOL from_group;
@@ -2423,6 +2441,10 @@ void translateFailure(LLChat chat, LLSD toastArgs, int status, const std::string
 
 void process_chat_from_simulator(LLMessageSystem *msg, void **user_data)
 {
+	if (gNonInteractive)
+	{
+		return;
+	}
 	LLChat	chat;
 	std::string		mesg;
 	std::string		from_name;
@@ -3263,10 +3285,9 @@ const F32 THRESHOLD_HEAD_ROT_QDOT = 0.9997f;	// ~= 2.5 degrees -- if its less th
 const F32 MAX_HEAD_ROT_QDOT = 0.99999f;			// ~= 0.5 degrees -- if its greater than this then no need to update head_rot
 												// between these values we delay the updates (but no more than one second)
 
-static LLTrace::BlockTimerStatHandle FTM_AGENT_UPDATE_SEND("Send Message");
-
 void send_agent_update(BOOL force_send, BOOL send_reliable)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	if (gAgent.getTeleportState() != LLAgent::TELEPORT_NONE)
 	{
 		// We don't care if they want to send an agent update, they're not allowed to until the simulator
@@ -3447,7 +3468,6 @@ void send_agent_update(BOOL force_send, BOOL send_reliable)
 		}
 		*/
 
-		LL_RECORD_BLOCK_TIME(FTM_AGENT_UPDATE_SEND);
 		// Build the message
 		msg->newMessageFast(_PREHASH_AgentUpdate);
 		msg->nextBlockFast(_PREHASH_AgentData);
@@ -3697,11 +3717,9 @@ void process_terse_object_update_improved(LLMessageSystem *mesgsys, void **user_
 	}
 }
 
-static LLTrace::BlockTimerStatHandle FTM_PROCESS_OBJECTS("Process Kill Objects");
-
 void process_kill_object(LLMessageSystem *mesgsys, void **user_data)
 {
-	LL_RECORD_BLOCK_TIME(FTM_PROCESS_OBJECTS);
+    LL_PROFILE_ZONE_SCOPED;
 
 	LLUUID		id;
 
@@ -3989,8 +4007,8 @@ void process_sim_stats(LLMessageSystem *msg, void **user_data)
 		F32 stat_value;
 		msg->getU32("Stat", "StatID", stat_id, i);
 		msg->getF32("Stat", "StatValue", stat_value, i);
-		LLStatViewer::SimMeasurementSampler* measurementp = LLStatViewer::SimMeasurementSampler::getInstance((ESimStatID)stat_id);
-		
+		auto measurementp = LLStatViewer::SimMeasurementSampler::getInstance((ESimStatID)stat_id);
+
 		if (measurementp )
 		{
 			measurementp->sample(stat_value);
@@ -5807,15 +5825,15 @@ void process_script_question(LLMessageSystem *msg, void **user_data)
 				if (("ScriptTakeMoney" == script_perm.question) && has_not_only_debit)
 					continue;
 
-                if (script_perm.question == "JoinAnExperience")
-                { // Some experience only permissions do not have an explicit permission bit.  Add them here.
-                    script_question += "    " + LLTrans::getString("ForceSitAvatar") + "\n";
+                if (LLTrans::getString(script_perm.question).empty())
+                {
+                    continue;
                 }
 
 				script_question += "    " + LLTrans::getString(script_perm.question) + "\n";
 			}
 		}
-	
+
 		args["QUESTIONS"] = script_question;
 
 		if (known_questions != questions)
diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp
index 31e80eb8655041a69b1da519ee8f67eaa06a8254..aad6c14b4d2006f2e5101ff18f953241e8e2c467 100644
--- a/indra/newview/llviewerobject.cpp
+++ b/indra/newview/llviewerobject.cpp
@@ -107,6 +107,7 @@
 #include "llcleanup.h"
 #include "llcallstack.h"
 #include "llmeshrepository.h"
+#include "llgl.h"
 
 //#define DEBUG_UPDATE_TYPE
 
@@ -145,21 +146,35 @@ const S32 MAX_OBJECT_BINARY_DATA_SIZE = 60 + 16;
 const F64 INVENTORY_UPDATE_WAIT_TIME_DESYNC = 5; // seconds
 const F64 INVENTORY_UPDATE_WAIT_TIME_OUTDATED = 1;
 
-static LLTrace::BlockTimerStatHandle FTM_CREATE_OBJECT("Create Object");
-
 // static
 LLViewerObject *LLViewerObject::createObject(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp, S32 flags)
 {
+    LL_PROFILE_ZONE_SCOPED;
     LL_DEBUGS("ObjectUpdate") << "creating " << id << LL_ENDL;
     dumpStack("ObjectUpdateStack");
     
 	LLViewerObject *res = NULL;
-	LL_RECORD_BLOCK_TIME(FTM_CREATE_OBJECT);
-	
+
+	if (gNonInteractive
+		&& pcode != LL_PCODE_LEGACY_AVATAR
+		&& pcode != LL_VO_SURFACE_PATCH
+		&& pcode != LL_VO_WATER
+		&& pcode != LL_VO_VOID_WATER
+		&& pcode != LL_VO_WL_SKY
+		&& pcode != LL_VO_SKY
+		&& pcode != LL_VO_GROUND
+		&& pcode != LL_VO_PART_GROUP
+		)
+	{
+		return res;
+	}
 	switch (pcode)
 	{
 	case LL_PCODE_VOLUME:
-	  res = new LLVOVolume(id, pcode, regionp); break;
+	{
+		res = new LLVOVolume(id, pcode, regionp); break;
+		break;
+	}
 	case LL_PCODE_LEGACY_AVATAR:
 	{
 		if (id == gAgentID)
@@ -235,8 +250,7 @@ LLViewerObject *LLViewerObject::createObject(const LLUUID &id, const LLPCode pco
 }
 
 LLViewerObject::LLViewerObject(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp, BOOL is_global)
-:	LLTrace::MemTrackable<LLViewerObject>("LLViewerObject"),
-	LLPrimitive(),
+:	LLPrimitive(),
 	mChildList(),
 	mID(id),
 	mLocalID(0),
@@ -342,6 +356,13 @@ LLViewerObject::~LLViewerObject()
 		mPartSourcep = NULL;
 	}
 
+    if (mText)
+    {
+        // something recovered LLHUDText when object was already dead
+        mText->markDead();
+        mText = NULL;
+    }
+
 	// Delete memory associated with extra parameters.
 	std::map<U16, ExtraParameter*>::iterator iter;
 	for (iter = mExtraParameterList.begin(); iter != mExtraParameterList.end(); ++iter)
@@ -1264,6 +1285,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys,
 				mesgsys->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_ObjectData, data, length, block_num, MAX_OBJECT_BINARY_DATA_SIZE);
 
 				mTotalCRC = crc;
+                // Might need to update mSourceMuted here to properly pick up new radius
 				mSoundCutOffRadius = cutoff;
 
 				// Owner ID used for sound muting or particle system muting
@@ -2442,11 +2464,19 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys,
 		needs_refresh = needs_refresh || child->mUserSelected;
 	}
 
+    static LLCachedControl<bool> allow_select_avatar(gSavedSettings, "AllowSelectAvatar", FALSE);
 	if (needs_refresh)
 	{
 		LLSelectMgr::getInstance()->updateSelectionCenter();
 		dialog_refresh_all();
-	} 
+	}
+    else if (allow_select_avatar && asAvatar())
+    {
+        // Override any avatar position updates received
+        // Works only if avatar was repositioned using build
+        // tools and build floater is visible
+        LLSelectMgr::getInstance()->overrideAvatarUpdates();
+    }
 
 
 	// Mark update time as approx. now, with the ping delay.
@@ -2501,9 +2531,6 @@ void LLViewerObject::loadFlags(U32 flags)
 
 void LLViewerObject::idleUpdate(LLAgent &agent, const F64 &frame_time)
 {
-	//static LLTrace::BlockTimerStatHandle ftm("Viewer Object");
-	//LL_RECORD_BLOCK_TIME(ftm);
-
 	if (!mDead)
 	{
 		if (!mStatic && sVelocityInterpolate && !isSelected())
@@ -5873,7 +5900,7 @@ void LLViewerObject::setAttachedSound(const LLUUID &audio_uuid, const LLUUID& ow
 		else if (flags & LL_SOUND_FLAG_STOP)
         {
 			// Just shut off the sound
-			mAudioSourcep->play(LLUUID::null);
+			mAudioSourcep->stop();
 		}
 		return;
 	}
@@ -5912,7 +5939,7 @@ void LLViewerObject::setAttachedSound(const LLUUID &audio_uuid, const LLUUID& ow
 		mAudioSourcep->setQueueSounds(queue);
 		if(!queue) // stop any current sound first to avoid "farts of doom" (SL-1541) -MG
 		{
-			mAudioSourcep->play(LLUUID::null);
+			mAudioSourcep->stop();
 		}
 		
 		// Play this sound if region maturity permits
diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h
index 250c4ac32867d62071dc3e87a32e01d017d55d7d..bef8e3e7e3c919517c5b5754a5be13d9aa0c178d 100644
--- a/indra/newview/llviewerobject.h
+++ b/indra/newview/llviewerobject.h
@@ -110,8 +110,7 @@ struct PotentialReturnableObject
 class LLViewerObject 
 :	public LLPrimitive, 
 	public LLRefCount, 
-	public LLGLUpdate,
-	public LLTrace::MemTrackable<LLViewerObject>
+	public LLGLUpdate
 {
 protected:
 	virtual ~LLViewerObject(); // use unref()
diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp
index 63e48d1dd090e18cb5e208654e91d96e2dce85ce..e930b581117a05aacfe0bbdcf128ee58c578cd29 100644
--- a/indra/newview/llviewerobjectlist.cpp
+++ b/indra/newview/llviewerobjectlist.cpp
@@ -72,7 +72,7 @@
 #ifdef LL_USESYSTEMLIBS
 #include <zlib.h>
 #else
-#include "zlib/zlib.h"
+#include "zlib-ng/zlib.h"
 #endif
 #include "object_flags.h"
 
@@ -80,6 +80,7 @@
 #include "llfloaterperms.h"
 #include "llvocache.h"
 #include "llcorehttputil.h"
+#include "llstartup.h"
 
 #include <algorithm>
 #include <iterator>
@@ -168,6 +169,8 @@ U64 LLViewerObjectList::getIndex(const U32 local_id,
 
 BOOL LLViewerObjectList::removeFromLocalIDTable(const LLViewerObject* objectp)
 {
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
+
 	if(objectp && objectp->getRegion())
 	{
 		U32 local_id = objectp->mLocalID;		
@@ -303,9 +306,11 @@ static LLTrace::BlockTimerStatHandle FTM_PROCESS_OBJECTS("Process Objects");
 
 LLViewerObject* LLViewerObjectList::processObjectUpdateFromCache(LLVOCacheEntry* entry, LLViewerRegion* regionp)
 {
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
+
 	LLDataPacker *cached_dpp = entry->getDP();
 
-	if (!cached_dpp)
+	if (!cached_dpp || gNonInteractive)
 	{
 		return NULL; //nothing cached.
 	}
@@ -566,7 +571,8 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,
         
 		if(update_cache)
 		{
-			objectp = regionp->updateCacheEntry(local_id, objectp, update_type);
+            //update object cache if the object receives a full-update or terse update
+			objectp = regionp->updateCacheEntry(local_id, objectp);
 		}
 
 		// This looks like it will break if the local_id of the object doesn't change
@@ -844,10 +850,10 @@ void LLViewerObjectList::updateApparentAngles(LLAgent &agent)
 	LLVOAvatar::cullAvatarsByPixelArea();
 }
 
-static LLTrace::BlockTimerStatHandle FTM_IDLE_COPY("Idle Copy");
-
 void LLViewerObjectList::update(LLAgent &agent)
 {
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
+
 	// Update globals
 	LLViewerObject::setVelocityInterpolate( gSavedSettings.getBOOL("VelocityInterpolate") );
 	LLViewerObject::setPingInterpolate( gSavedSettings.getBOOL("PingInterpolate") );
@@ -899,8 +905,6 @@ void LLViewerObjectList::update(LLAgent &agent)
 	U32 idle_count = 0;
 	
 	{
-		LL_RECORD_BLOCK_TIME(FTM_IDLE_COPY);
-
  		for (std::vector<LLPointer<LLViewerObject> >::iterator active_iter = mActiveObjects.begin();
 			active_iter != mActiveObjects.end(); active_iter++)
 		{
@@ -1293,6 +1297,8 @@ void LLViewerObjectList::clearDebugText()
 
 void LLViewerObjectList::cleanupReferences(LLViewerObject *objectp)
 {
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
+
 	bool new_dead_object = true;
 	if (mDeadObjects.find(objectp->mID) != mDeadObjects.end())
 	{
@@ -1343,11 +1349,9 @@ void LLViewerObjectList::cleanupReferences(LLViewerObject *objectp)
 	}
 }
 
-static LLTrace::BlockTimerStatHandle FTM_REMOVE_DRAWABLE("Remove Drawable");
-
 void LLViewerObjectList::removeDrawable(LLDrawable* drawablep)
 {
-	LL_RECORD_BLOCK_TIME(FTM_REMOVE_DRAWABLE);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE;
 
 	if (!drawablep)
 	{
@@ -1523,6 +1527,8 @@ void LLViewerObjectList::removeFromActiveList(LLViewerObject* objectp)
 
 void LLViewerObjectList::updateActive(LLViewerObject *objectp)
 {
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE;
+
 	if (objectp->isDead())
 	{
 		return; // We don't update dead objects!
@@ -1634,12 +1640,9 @@ void LLViewerObjectList::onPhysicsFlagsFetchFailure(const LLUUID& object_id)
 	mPendingPhysicsFlags.erase(object_id);
 }
 
-static LLTrace::BlockTimerStatHandle FTM_SHIFT_OBJECTS("Shift Objects");
-static LLTrace::BlockTimerStatHandle FTM_PIPELINE_SHIFT("Pipeline Shift");
-static LLTrace::BlockTimerStatHandle FTM_REGION_SHIFT("Region Shift");
-
 void LLViewerObjectList::shiftObjects(const LLVector3 &offset)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
 	// This is called when we shift our origin when we cross region boundaries...
 	// We need to update many object caches, I'll document this more as I dig through the code
 	// cleaning things out...
@@ -1649,7 +1652,6 @@ void LLViewerObjectList::shiftObjects(const LLVector3 &offset)
 		return;
 	}
 
-	LL_RECORD_BLOCK_TIME(FTM_SHIFT_OBJECTS);
 
 	LLViewerObject *objectp;
 	for (vobj_list_t::iterator iter = mObjects.begin(); iter != mObjects.end(); ++iter)
@@ -1667,16 +1669,10 @@ void LLViewerObjectList::shiftObjects(const LLVector3 &offset)
 		}
 	}
 
-	{
-		LL_RECORD_BLOCK_TIME(FTM_PIPELINE_SHIFT);
 	gPipeline.shiftObjects(offset);
-	}
-
-	{
-		LL_RECORD_BLOCK_TIME(FTM_REGION_SHIFT);
+	
 	LLWorld::getInstance()->shiftRegions(offset);
 }
-}
 
 void LLViewerObjectList::repartitionObjects()
 {
@@ -1843,6 +1839,8 @@ void LLViewerObjectList::renderObjectBounds(const LLVector3 &center)
 
 void LLViewerObjectList::generatePickList(LLCamera &camera)
 {
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
+
 		LLViewerObject *objectp;
 		S32 i;
 		// Reset all of the GL names to zero.
@@ -2051,7 +2049,6 @@ LLViewerObject *LLViewerObjectList::createObjectFromCache(const LLPCode pcode, L
 LLViewerObject *LLViewerObjectList::createObject(const LLPCode pcode, LLViewerRegion *regionp,
 												 const LLUUID &uuid, const U32 local_id, const LLHost &sender)
 {
-	
 	LLUUID fullid;
 	if (uuid == LLUUID::null)
 	{
@@ -2104,6 +2101,8 @@ LLViewerObject *LLViewerObjectList::replaceObject(const LLUUID &id, const LLPCod
 
 S32 LLViewerObjectList::findReferences(LLDrawable *drawablep) const
 {
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE;
+
 	LLViewerObject *objectp;
 	S32 num_refs = 0;
 	
@@ -2167,6 +2166,8 @@ void LLViewerObjectList::orphanize(LLViewerObject *childp, U32 parent_id, U32 ip
 
 void LLViewerObjectList::findOrphans(LLViewerObject* objectp, U32 ip, U32 port)
 {
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
+
 	if (objectp->isDead())
 	{
 		LL_WARNS() << "Trying to find orphans for dead obj " << objectp->mID 
diff --git a/indra/newview/llvieweroctree.cpp b/indra/newview/llvieweroctree.cpp
index 6365df09e13834e241806460fa332d85b8f6fc8e..36b2bd4c32bc8eb9bae12515a0dab07c2b9e28d9 100644
--- a/indra/newview/llvieweroctree.cpp
+++ b/indra/newview/llvieweroctree.cpp
@@ -32,6 +32,7 @@
 #include "llappviewer.h"
 #include "llglslshader.h"
 #include "llviewershadermgr.h"
+#include "lldrawpoolwater.h"
 
 //-----------------------------------------------------------------------------------
 //static variables definitions
@@ -231,8 +232,7 @@ S32 AABBSphereIntersectR2(const LLVector4a& min, const LLVector4a& max, const LL
 //class LLViewerOctreeEntry definitions
 //-----------------------------------------------------------------------------------
 LLViewerOctreeEntry::LLViewerOctreeEntry() 
-:	LLTrace::MemTrackable<LLViewerOctreeEntry, 16>("LLViewerOctreeEntry"),
-	mGroup(NULL),
+:	mGroup(NULL),
 	mBinRadius(0.f),
 	mBinIndex(-1),
 	mVisible(0)
@@ -458,8 +458,7 @@ LLViewerOctreeGroup::~LLViewerOctreeGroup()
 }
 
 LLViewerOctreeGroup::LLViewerOctreeGroup(OctreeNode* node)
-:	LLTrace::MemTrackable<LLViewerOctreeGroup, 16>("LLViewerOctreeGroup"),
-	mOctreeNode(node),
+:	mOctreeNode(node),
 	mAnyVisible(0),
 	mState(CLEAN)
 {
@@ -517,6 +516,7 @@ bool LLViewerOctreeGroup::removeFromGroup(LLViewerOctreeEntry* entry)
 //virtual 
 void LLViewerOctreeGroup::unbound()
 {
+    LL_PROFILE_ZONE_SCOPED;
 	if (isDirty())
 	{
 		return;
@@ -545,6 +545,7 @@ void LLViewerOctreeGroup::unbound()
 //virtual 
 void LLViewerOctreeGroup::rebound()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_OCTREE;
 	if (!isDirty())
 	{	
 		return;
@@ -563,7 +564,7 @@ void LLViewerOctreeGroup::rebound()
 		
 		group->setState(SKIP_FRUSTUM_CHECK);
 	}
-	else if (mOctreeNode->isLeaf())
+	else if (mOctreeNode->getChildCount() == 0)
 	{ //copy object bounding box if this is a leaf
 		boundObjects(TRUE, mExtents[0], mExtents[1]);
 		mBounds[0] = mObjectBounds[0];
@@ -786,42 +787,39 @@ void LLViewerOctreeGroup::checkStates()
 //occulsion culling functions and classes
 //-------------------------------------------------------------------------------------------
 std::set<U32> LLOcclusionCullingGroup::sPendingQueries;
-class LLOcclusionQueryPool : public LLGLNamePool
-{
-public:
-	LLOcclusionQueryPool()
-	{
-	}
 
-protected:
+static std::queue<GLuint> sFreeQueries;
 
-	virtual GLuint allocateName()
-	{
-		GLuint ret = 0;
-
-		glGenQueriesARB(1, &ret);
-	
-		return ret;
-	}
-
-	virtual void releaseName(GLuint name)
-	{
-#if LL_TRACK_PENDING_OCCLUSION_QUERIES
-		LLOcclusionCullingGroup::sPendingQueries.erase(name);
-#endif
-		glDeleteQueriesARB(1, &name);
-	}
-};
+#define QUERY_POOL_SIZE 1024
 
-static LLOcclusionQueryPool sQueryPool;
 U32 LLOcclusionCullingGroup::getNewOcclusionQueryObjectName()
 {
-	return sQueryPool.allocate();
+    LL_PROFILE_ZONE_SCOPED;
+    
+    if (sFreeQueries.empty())
+    {
+        //seed 1024 query names into the free query pool
+        GLuint queries[1024];
+        glGenQueriesARB(1024, queries);
+        for (int i = 0; i < 1024; ++i)
+        {
+            sFreeQueries.push(queries[i]);
+        }
+    }
+
+    // pull from pool
+    GLuint ret = sFreeQueries.front();
+    sFreeQueries.pop();
+    return ret;
 }
 
 void LLOcclusionCullingGroup::releaseOcclusionQueryObjectName(GLuint name)
 {
-	sQueryPool.release(name);
+    if (name != 0)
+    {
+        LL_PROFILE_ZONE_SCOPED;
+        sFreeQueries.push(name);
+    }
 }
 
 //=====================================
@@ -932,47 +930,55 @@ void LLOcclusionCullingGroup::releaseOcclusionQueryObjectNames()
 	}
 }
 
-void LLOcclusionCullingGroup::setOcclusionState(U32 state, S32 mode) 
-{
-	if (mode > STATE_MODE_SINGLE)
-	{
-		if (mode == STATE_MODE_DIFF)
-		{
-			LLSpatialSetOcclusionStateDiff setter(state);
-			setter.traverse(mOctreeNode);
-		}
-		else if (mode == STATE_MODE_BRANCH)
-		{
-			LLSpatialSetOcclusionState setter(state);
-			setter.traverse(mOctreeNode);
-		}
-		else
-		{
-			for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; i++)
-			{
-				mOcclusionState[i] |= state;
-
-				if ((state & DISCARD_QUERY) && mOcclusionQuery[i])
-				{
-					releaseOcclusionQueryObjectName(mOcclusionQuery[i]);
-					mOcclusionQuery[i] = 0;
-				}
-			}
-		}
-	}
-	else
-	{
-		if (state & OCCLUDED)
-		{
-			add(sNumObjectsOccluded, 1);
-		}
-		mOcclusionState[LLViewerCamera::sCurCameraID] |= state;
-		if ((state & DISCARD_QUERY) && mOcclusionQuery[LLViewerCamera::sCurCameraID])
-		{
-			releaseOcclusionQueryObjectName(mOcclusionQuery[LLViewerCamera::sCurCameraID]);
-			mOcclusionQuery[LLViewerCamera::sCurCameraID] = 0;
-		}
-	}
+void LLOcclusionCullingGroup::setOcclusionState(U32 state, S32 mode /* = STATE_MODE_SINGLE */ ) 
+{
+    switch (mode)
+    {
+    case STATE_MODE_SINGLE:
+        if (state & OCCLUDED)
+        {
+            add(sNumObjectsOccluded, 1);
+        }
+        mOcclusionState[LLViewerCamera::sCurCameraID] |= state;
+        if ((state & DISCARD_QUERY) && mOcclusionQuery[LLViewerCamera::sCurCameraID])
+        {
+            releaseOcclusionQueryObjectName(mOcclusionQuery[LLViewerCamera::sCurCameraID]);
+            mOcclusionQuery[LLViewerCamera::sCurCameraID] = 0;
+        }
+        break;
+
+    case STATE_MODE_DIFF:
+        if (mOctreeNode)
+        {
+            LLSpatialSetOcclusionStateDiff setter(state);
+            setter.traverse(mOctreeNode);
+        }
+        break;
+
+    case STATE_MODE_BRANCH:
+        if (mOctreeNode)
+        {
+            LLSpatialSetOcclusionState setter(state);
+            setter.traverse(mOctreeNode);
+        }
+        break;
+
+    case STATE_MODE_ALL_CAMERAS:
+        for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; i++)
+        {
+            mOcclusionState[i] |= state;
+
+            if ((state & DISCARD_QUERY) && mOcclusionQuery[i])
+            {
+                releaseOcclusionQueryObjectName(mOcclusionQuery[i]);
+                mOcclusionQuery[i] = 0;
+            }
+        }
+        break;
+
+    default:
+        break;
+    }
 }
 
 class LLSpatialClearOcclusionState : public OctreeTraveler
@@ -1007,43 +1013,49 @@ class LLSpatialClearOcclusionStateDiff : public LLSpatialClearOcclusionState
 	}
 };
 
-void LLOcclusionCullingGroup::clearOcclusionState(U32 state, S32 mode)
-{
-	if (mode > STATE_MODE_SINGLE)
-	{
-		if (mode == STATE_MODE_DIFF)
-		{
-			LLSpatialClearOcclusionStateDiff clearer(state);
-			clearer.traverse(mOctreeNode);
-		}
-		else if (mode == STATE_MODE_BRANCH)
-		{
-			LLSpatialClearOcclusionState clearer(state);
-			clearer.traverse(mOctreeNode);
-		}
-		else
-		{
-			for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; i++)
-			{
-				mOcclusionState[i] &= ~state;
-			}
-		}
-	}
-	else
-	{
-		if (state & OCCLUDED)
-		{
-			add(sNumObjectsUnoccluded, 1);
-		}
-		mOcclusionState[LLViewerCamera::sCurCameraID] &= ~state;
-	}
+void LLOcclusionCullingGroup::clearOcclusionState(U32 state, S32 mode /* = STATE_MODE_SINGLE */)
+{
+    switch (mode)
+    {
+        case STATE_MODE_SINGLE:
+            if (state & OCCLUDED)
+            {
+                add(sNumObjectsUnoccluded, 1);
+            }
+            mOcclusionState[LLViewerCamera::sCurCameraID] &= ~state;
+            break;
+
+        case STATE_MODE_DIFF:
+            if (mOctreeNode)
+            {
+                LLSpatialClearOcclusionStateDiff clearer(state);
+                clearer.traverse(mOctreeNode);
+            }
+            break;
+
+        case STATE_MODE_BRANCH:
+            if (mOctreeNode)
+            {
+                LLSpatialClearOcclusionState clearer(state);
+                clearer.traverse(mOctreeNode);
+            }
+            break;
+
+        case STATE_MODE_ALL_CAMERAS:
+            for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; i++)
+            {
+                mOcclusionState[i] &= ~state;
+            }
+            break;
+
+        default:
+            break;
+    }
 }
 
-static LLTrace::BlockTimerStatHandle FTM_OCCLUSION_READBACK("Readback Occlusion");
-static LLTrace::BlockTimerStatHandle FTM_OCCLUSION_WAIT("Occlusion Wait");
-
 BOOL LLOcclusionCullingGroup::earlyFail(LLCamera* camera, const LLVector4a* bounds)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_OCTREE;
 	if (camera->getOrigin().isExactlyZero())
 	{
 		return FALSE;
@@ -1092,100 +1104,82 @@ U32 LLOcclusionCullingGroup::getLastOcclusionIssuedTime()
 
 void LLOcclusionCullingGroup::checkOcclusion()
 {
-	if (LLPipeline::sUseOcclusion > 1)
-	{
-		LL_RECORD_BLOCK_TIME(FTM_OCCLUSION_READBACK);
-		LLOcclusionCullingGroup* parent = (LLOcclusionCullingGroup*)getParent();
-		if (parent && parent->isOcclusionState(LLOcclusionCullingGroup::OCCLUDED))
-		{	//if the parent has been marked as occluded, the child is implicitly occluded
-			clearOcclusionState(QUERY_PENDING | DISCARD_QUERY);
-		}
-		else if (isOcclusionState(QUERY_PENDING))
-		{	//otherwise, if a query is pending, read it back
-
-			GLuint available = 0;
-			if (mOcclusionQuery[LLViewerCamera::sCurCameraID])
-			{
-				glGetQueryObjectuivARB(mOcclusionQuery[LLViewerCamera::sCurCameraID], GL_QUERY_RESULT_AVAILABLE_ARB, &available);
-
-				static LLCachedControl<bool> wait_for_query(gSavedSettings, "RenderSynchronousOcclusion", true);
-
-				if (wait_for_query && mOcclusionIssued[LLViewerCamera::sCurCameraID] < gFrameCount)
-				{ //query was issued last frame, wait until it's available
-					S32 max_loop = 1024;
-					LL_RECORD_BLOCK_TIME(FTM_OCCLUSION_WAIT);
-					while (!available && max_loop-- > 0)
-					{
-						glGetQueryObjectuivARB(mOcclusionQuery[LLViewerCamera::sCurCameraID], GL_QUERY_RESULT_AVAILABLE_ARB, &available);
-					}
-				}
-			}
-			else
-			{
-				available = 1;
-			}
-
-			if (available)
-			{ //result is available, read it back, otherwise wait until next frame
-				GLuint res = 1;
-				if (!isOcclusionState(DISCARD_QUERY) && mOcclusionQuery[LLViewerCamera::sCurCameraID])
-				{
-					glGetQueryObjectuivARB(mOcclusionQuery[LLViewerCamera::sCurCameraID], GL_QUERY_RESULT_ARB, &res);	
+    if (LLPipeline::sUseOcclusion < 2) return;  // 0 - NoOcclusion, 1 = ReadOnly, 2 = ModifyOcclusionState  TODO: DJH 11-2021 ENUM this
+
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_OCTREE;
+    LLOcclusionCullingGroup* parent = (LLOcclusionCullingGroup*)getParent();
+    if (parent && parent->isOcclusionState(LLOcclusionCullingGroup::OCCLUDED))
+    {	//if the parent has been marked as occluded, the child is implicitly occluded
+        clearOcclusionState(QUERY_PENDING | DISCARD_QUERY);
+        return;
+    }
+
+    if (mOcclusionQuery[LLViewerCamera::sCurCameraID] && isOcclusionState(QUERY_PENDING))
+    {	
+        if (isOcclusionState(DISCARD_QUERY))
+        {   // delete the query to avoid holding onto hundreds of pending queries
+            releaseOcclusionQueryObjectName(mOcclusionQuery[LLViewerCamera::sCurCameraID]);
+            mOcclusionQuery[LLViewerCamera::sCurCameraID] = 0;
+            // mark non-occluded
+            clearOcclusionState(LLOcclusionCullingGroup::OCCLUDED, LLOcclusionCullingGroup::STATE_MODE_DIFF);
+            clearOcclusionState(QUERY_PENDING | DISCARD_QUERY);
+        }
+        else
+        {
+            GLuint available;
+            {
+                LL_PROFILE_ZONE_NAMED_CATEGORY_OCTREE("co - query available");
+                glGetQueryObjectuivARB(mOcclusionQuery[LLViewerCamera::sCurCameraID], GL_QUERY_RESULT_AVAILABLE_ARB, &available);
+            }
+
+            if (available)
+            {   
+                GLuint query_result;    // Will be # samples drawn, or a boolean depending on mHasOcclusionQuery2 (both are type GLuint)
+                {
+                    LL_PROFILE_ZONE_NAMED_CATEGORY_OCTREE("co - query result");
+                    glGetQueryObjectuivARB(mOcclusionQuery[LLViewerCamera::sCurCameraID], GL_QUERY_RESULT_ARB, &query_result);
+                }
 #if LL_TRACK_PENDING_OCCLUSION_QUERIES
-					sPendingQueries.erase(mOcclusionQuery[LLViewerCamera::sCurCameraID]);
+                sPendingQueries.erase(mOcclusionQuery[LLViewerCamera::sCurCameraID]);
 #endif
-				}
-				else if (mOcclusionQuery[LLViewerCamera::sCurCameraID])
-				{ //delete the query to avoid holding onto hundreds of pending queries
-					releaseOcclusionQueryObjectName(mOcclusionQuery[LLViewerCamera::sCurCameraID]);
-					mOcclusionQuery[LLViewerCamera::sCurCameraID] = 0;
-				}
-				
-				if (isOcclusionState(DISCARD_QUERY))
-				{
-					res = 2;
-				}
-
-				if (res > 0)
-				{
-					assert_states_valid(this);
-					clearOcclusionState(LLOcclusionCullingGroup::OCCLUDED, LLOcclusionCullingGroup::STATE_MODE_DIFF);
-					assert_states_valid(this);
-				}
-				else
-				{
-					assert_states_valid(this);
-					
-					setOcclusionState(LLOcclusionCullingGroup::OCCLUDED, LLOcclusionCullingGroup::STATE_MODE_DIFF);
-					
-					assert_states_valid(this);
-				}
 
-				clearOcclusionState(QUERY_PENDING | DISCARD_QUERY);
-			}
-		}
-		else if (mSpatialPartition->isOcclusionEnabled() && isOcclusionState(LLOcclusionCullingGroup::OCCLUDED))
-		{	//check occlusion has been issued for occluded node that has not had a query issued
-			assert_states_valid(this);
-			clearOcclusionState(LLOcclusionCullingGroup::OCCLUDED, LLOcclusionCullingGroup::STATE_MODE_DIFF);
-			assert_states_valid(this);
-		}
-	}
+#if 0   // (12/2021) occasional false-negative occlusion tests produce water reflection errors, SL-16461
+        // If/when water occlusion queries become 100% reliable, re-enable this optimization
+
+                if (LLPipeline::RENDER_TYPE_WATER == mSpatialPartition->mDrawableType)
+                {
+                    // Note any unoccluded water, for deciding on reflection/distortion passes
+                    // (If occlusion is disabled, these are set within LLDrawPoolWater::render)
+                    if (query_result > 0)
+                    {
+                        LLDrawPoolWater::sNeedsReflectionUpdate = TRUE;
+                        LLDrawPoolWater::sNeedsDistortionUpdate = TRUE;
+                    }
+                }
+#endif
+                if (query_result > 0)
+                {
+                    clearOcclusionState(LLOcclusionCullingGroup::OCCLUDED, LLOcclusionCullingGroup::STATE_MODE_DIFF);
+                }
+                else
+                {
+                    setOcclusionState(LLOcclusionCullingGroup::OCCLUDED, LLOcclusionCullingGroup::STATE_MODE_DIFF);
+                }
+                clearOcclusionState(QUERY_PENDING);
+            }
+        }
+    }
+    else if (mSpatialPartition->isOcclusionEnabled() && isOcclusionState(LLOcclusionCullingGroup::OCCLUDED))
+    {	//check occlusion has been issued for occluded node that has not had a query issued
+        assert_states_valid(this);
+        clearOcclusionState(LLOcclusionCullingGroup::OCCLUDED, LLOcclusionCullingGroup::STATE_MODE_DIFF);
+        assert_states_valid(this);
+    }
 }
 
-static LLTrace::BlockTimerStatHandle FTM_PUSH_OCCLUSION_VERTS("Push Occlusion");
-static LLTrace::BlockTimerStatHandle FTM_SET_OCCLUSION_STATE("Occlusion State");
-static LLTrace::BlockTimerStatHandle FTM_OCCLUSION_EARLY_FAIL("Occlusion Early Fail");
-static LLTrace::BlockTimerStatHandle FTM_OCCLUSION_ALLOCATE("Allocate");
-static LLTrace::BlockTimerStatHandle FTM_OCCLUSION_BUILD("Build");
-static LLTrace::BlockTimerStatHandle FTM_OCCLUSION_BEGIN_QUERY("Begin Query");
-static LLTrace::BlockTimerStatHandle FTM_OCCLUSION_END_QUERY("End Query");
-static LLTrace::BlockTimerStatHandle FTM_OCCLUSION_SET_BUFFER("Set Buffer");
-static LLTrace::BlockTimerStatHandle FTM_OCCLUSION_DRAW_WATER("Draw Water");
-static LLTrace::BlockTimerStatHandle FTM_OCCLUSION_DRAW("Draw");
-
 void LLOcclusionCullingGroup::doOcclusion(LLCamera* camera, const LLVector4a* shift)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_OCTREE;
 	if (mSpatialPartition->isOcclusionEnabled() && LLPipeline::sUseOcclusion > 1)
 	{
 		//move mBounds to the agent space if necessary
@@ -1198,7 +1192,7 @@ void LLOcclusionCullingGroup::doOcclusion(LLCamera* camera, const LLVector4a* sh
 		}
 
 		F32 OCCLUSION_FUDGE_Z = SG_OCCLUSION_FUDGE; //<-- #Solution #2
-		if (LLDrawPool::POOL_WATER == mSpatialPartition->mDrawableType)
+		if (LLPipeline::RENDER_TYPE_VOIDWATER == mSpatialPartition->mDrawableType)
 		{
 			OCCLUSION_FUDGE_Z = 1.;
 		}
@@ -1206,7 +1200,7 @@ void LLOcclusionCullingGroup::doOcclusion(LLCamera* camera, const LLVector4a* sh
 		// Don't cull hole/edge water, unless we have the GL_ARB_depth_clamp extension
 		if (earlyFail(camera, bounds))
 		{
-			LL_RECORD_BLOCK_TIME(FTM_OCCLUSION_EARLY_FAIL);
+            LL_PROFILE_ZONE_NAMED_CATEGORY_OCTREE("doOcclusion - early fail");
 			setOcclusionState(LLOcclusionCullingGroup::DISCARD_QUERY);
 			assert_states_valid(this);
 			clearOcclusionState(LLOcclusionCullingGroup::OCCLUDED, LLOcclusionCullingGroup::STATE_MODE_DIFF);
@@ -1217,11 +1211,10 @@ void LLOcclusionCullingGroup::doOcclusion(LLCamera* camera, const LLVector4a* sh
 			if (!isOcclusionState(QUERY_PENDING) || isOcclusionState(DISCARD_QUERY))
 			{
 				{ //no query pending, or previous query to be discarded
-					LL_RECORD_BLOCK_TIME(FTM_RENDER_OCCLUSION);
+                    LL_PROFILE_ZONE_NAMED_CATEGORY_OCTREE("doOcclusion - render");
 
 					if (!mOcclusionQuery[LLViewerCamera::sCurCameraID])
 					{
-						LL_RECORD_BLOCK_TIME(FTM_OCCLUSION_ALLOCATE);
 						mOcclusionQuery[LLViewerCamera::sCurCameraID] = getNewOcclusionQueryObjectName();
 					}
 
@@ -1229,8 +1222,8 @@ void LLOcclusionCullingGroup::doOcclusion(LLCamera* camera, const LLVector4a* sh
 					// behind the far clip plane, and in the case of edge water to avoid
 					// it being culled while still visible.
 					bool const use_depth_clamp = gGLManager.mHasDepthClamp &&
-												(mSpatialPartition->mDrawableType == LLDrawPool::POOL_WATER ||						
-												mSpatialPartition->mDrawableType == LLDrawPool::POOL_VOIDWATER);
+												(mSpatialPartition->mDrawableType == LLPipeline::RENDER_TYPE_WATER ||
+												mSpatialPartition->mDrawableType == LLPipeline::RENDER_TYPE_VOIDWATER);
 
 					LLGLEnable clamp(use_depth_clamp ? GL_DEPTH_CLAMP : 0);				
 						
@@ -1246,15 +1239,19 @@ void LLOcclusionCullingGroup::doOcclusion(LLCamera* camera, const LLVector4a* sh
 					add(sOcclusionQueries, 1);
 
 					{
-						LL_RECORD_BLOCK_TIME(FTM_PUSH_OCCLUSION_VERTS);
+                        LL_PROFILE_ZONE_NAMED_CATEGORY_OCTREE("doOcclusion - push");
 						
 						//store which frame this query was issued on
 						mOcclusionIssued[LLViewerCamera::sCurCameraID] = gFrameCount;
 
-						{
-							LL_RECORD_BLOCK_TIME(FTM_OCCLUSION_BEGIN_QUERY);
-							glBeginQueryARB(mode, mOcclusionQuery[LLViewerCamera::sCurCameraID]);					
-						}
+                        {
+                            LL_PROFILE_ZONE_NAMED("glBeginQuery");
+
+                            //get an occlusion query that hasn't been used in awhile
+                            releaseOcclusionQueryObjectName(mOcclusionQuery[LLViewerCamera::sCurCameraID]);
+                            mOcclusionQuery[LLViewerCamera::sCurCameraID] = getNewOcclusionQueryObjectName();
+                            glBeginQueryARB(mode, mOcclusionQuery[LLViewerCamera::sCurCameraID]);
+                        }
 					
 						LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
 						llassert(shader);
@@ -1264,9 +1261,9 @@ void LLOcclusionCullingGroup::doOcclusion(LLCamera* camera, const LLVector4a* sh
 																 bounds[1][1]+SG_OCCLUSION_FUDGE, 
 																 bounds[1][2]+OCCLUSION_FUDGE_Z);
 
-						if (!use_depth_clamp && mSpatialPartition->mDrawableType == LLDrawPool::POOL_VOIDWATER)
+						if (!use_depth_clamp && mSpatialPartition->mDrawableType == LLPipeline::RENDER_TYPE_VOIDWATER)
 						{
-							LL_RECORD_BLOCK_TIME(FTM_OCCLUSION_DRAW_WATER);
+                            LL_PROFILE_ZONE_NAMED_CATEGORY_OCTREE("doOcclusion - draw water");
 
 							LLGLSquashToFarClip squash;
 							if (camera->getOrigin().isExactlyZero())
@@ -1281,7 +1278,7 @@ void LLOcclusionCullingGroup::doOcclusion(LLCamera* camera, const LLVector4a* sh
 						}
 						else
 						{
-							LL_RECORD_BLOCK_TIME(FTM_OCCLUSION_DRAW);
+                            LL_PROFILE_ZONE_NAMED_CATEGORY_OCTREE("doOcclusion - draw");
 							if (camera->getOrigin().isExactlyZero())
 							{ //origin is invalid, draw entire box
 								gPipeline.mCubeVB->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, 0);
@@ -1292,17 +1289,16 @@ void LLOcclusionCullingGroup::doOcclusion(LLCamera* camera, const LLVector4a* sh
 								gPipeline.mCubeVB->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, get_box_fan_indices(camera, bounds[0]));
 							}
 						}
-
-
-						{
-							LL_RECORD_BLOCK_TIME(FTM_OCCLUSION_END_QUERY);
-							glEndQueryARB(mode);
-						}
+	
+                        {
+                            LL_PROFILE_ZONE_NAMED("glEndQuery");
+                            glEndQueryARB(mode);
+                        }
 					}
 				}
 
 				{
-					LL_RECORD_BLOCK_TIME(FTM_SET_OCCLUSION_STATE);
+                    LL_PROFILE_ZONE_NAMED_CATEGORY_OCTREE("doOcclusion - set state");
 					setOcclusionState(LLOcclusionCullingGroup::QUERY_PENDING);
 					clearOcclusionState(LLOcclusionCullingGroup::DISCARD_QUERY);
 				}
@@ -1333,8 +1329,13 @@ LLViewerOctreePartition::LLViewerOctreePartition() :
 	
 LLViewerOctreePartition::~LLViewerOctreePartition()
 {
-	delete mOctree;
-	mOctree = NULL;
+    cleanup();
+}
+
+void LLViewerOctreePartition::cleanup()
+{
+    delete mOctree;
+    mOctree = nullptr;
 }
 
 BOOL LLViewerOctreePartition::isOcclusionEnabled()
@@ -1342,6 +1343,7 @@ BOOL LLViewerOctreePartition::isOcclusionEnabled()
 	return mOcclusionEnabled || LLPipeline::sUseOcclusion > 2;
 }
 
+
 //-----------------------------------------------------------------------------------
 //class LLViewerOctreeCull definitions
 //-----------------------------------------------------------------------------------
diff --git a/indra/newview/llvieweroctree.h b/indra/newview/llvieweroctree.h
index 219ec7e8da7c47d2d46f6a512267ca2e6fd96bb0..7666062f990944701ad64be09627cd7f2a28e7ed 100644
--- a/indra/newview/llvieweroctree.h
+++ b/indra/newview/llvieweroctree.h
@@ -45,11 +45,11 @@ class LLViewerOctreeGroup;
 class LLViewerOctreeEntry;
 class LLViewerOctreePartition;
 
-typedef LLOctreeListener<LLViewerOctreeEntry>	OctreeListener;
-typedef LLTreeNode<LLViewerOctreeEntry>			TreeNode;
-typedef LLOctreeNode<LLViewerOctreeEntry>		OctreeNode;
-typedef LLOctreeRoot<LLViewerOctreeEntry>		OctreeRoot;
-typedef LLOctreeTraveler<LLViewerOctreeEntry>	OctreeTraveler;
+typedef LLOctreeListener<LLViewerOctreeEntry, LLPointer<LLViewerOctreeEntry>> OctreeListener;
+typedef LLTreeNode<LLViewerOctreeEntry> TreeNode;
+typedef LLOctreeNode<LLViewerOctreeEntry, LLPointer<LLViewerOctreeEntry>> OctreeNode;
+typedef LLOctreeRoot<LLViewerOctreeEntry, LLPointer<LLViewerOctreeEntry>> OctreeRoot;
+typedef LLOctreeTraveler<LLViewerOctreeEntry, LLPointer<LLViewerOctreeEntry>> OctreeTraveler;
 
 #if LL_OCTREE_PARANOIA_CHECK
 #define assert_octree_valid(x) x->validate()
@@ -71,8 +71,9 @@ S32 AABBSphereIntersectR2(const LLVector3& min, const LLVector3& max, const LLVe
 
 //defines data needed for octree of an entry
 //LL_ALIGN_PREFIX(16)
-class LLViewerOctreeEntry : public LLRefCount, public LLTrace::MemTrackable<LLViewerOctreeEntry, 16>
+class LLViewerOctreeEntry : public LLRefCount
 {
+    LL_ALIGN_NEW
 	friend class LLViewerOctreeEntryData;
 
 public:
@@ -178,8 +179,9 @@ class LLViewerOctreeEntryData : public LLRefCount
 //defines an octree group for an octree node, which contains multiple entries.
 //LL_ALIGN_PREFIX(16)
 class LLViewerOctreeGroup
-:	public LLOctreeListener<LLViewerOctreeEntry>, public LLTrace::MemTrackable<LLViewerOctreeGroup, 16>
+:	public OctreeListener
 {
+    LL_ALIGN_NEW
 	friend class LLViewerOctreeCull;
 protected:
 	virtual ~LLViewerOctreeGroup();
@@ -196,12 +198,11 @@ class LLViewerOctreeGroup
 	};
 
 public:
-	typedef LLOctreeNode<LLViewerOctreeEntry>::element_iter element_iter;
-	typedef LLOctreeNode<LLViewerOctreeEntry>::element_list element_list;
+	typedef OctreeNode::element_iter element_iter;
+	typedef OctreeNode::element_list element_list;
 
 	LLViewerOctreeGroup(OctreeNode* node);
 	LLViewerOctreeGroup(const LLViewerOctreeGroup& rhs)
-	: LLTrace::MemTrackable<LLViewerOctreeGroup, 16>("LLViewerOctreeGroup")
 	{
 		*this = rhs;
 	}
@@ -244,7 +245,6 @@ class LLViewerOctreeGroup
 	const LLVector4a* getObjectExtents() const {return mObjectExtents;}
 
 	//octree wrappers to make code more readable
-	element_list& getData() { return mOctreeNode->getData(); }
 	element_iter getDataBegin() { return mOctreeNode->getDataBegin(); }
 	element_iter getDataEnd() { return mOctreeNode->getDataEnd(); }
 	U32 getElementCount() const { return mOctreeNode->getElementCount(); }
@@ -351,6 +351,10 @@ class LLViewerOctreePartition
 	virtual S32 cull(LLCamera &camera, bool do_occlusion) = 0;
 	BOOL isOcclusionEnabled();
 
+protected:
+    // MUST call from destructor of any derived classes (SL-17276)
+    void cleanup();
+
 public:	
 	U32              mPartitionType;
 	U32              mDrawableType;
diff --git a/indra/newview/llviewerparcelmgr.cpp b/indra/newview/llviewerparcelmgr.cpp
index 56370df7513638ff54198a47c4f440de5d9b04f5..75eb16c085473905cbb9a4f51a4f993203cc946d 100644
--- a/indra/newview/llviewerparcelmgr.cpp
+++ b/indra/newview/llviewerparcelmgr.cpp
@@ -878,7 +878,7 @@ LLParcel* LLViewerParcelMgr::getCollisionParcel() const
 
 void LLViewerParcelMgr::render()
 {
-	if (mSelected && mRenderSelection && gSavedSettings.getBOOL("RenderParcelSelection"))
+	if (mSelected && mRenderSelection && gSavedSettings.getBOOL("RenderParcelSelection") && !gDisconnected)
 	{
 		// Rendering is done in agent-coordinates, so need to supply
 		// an appropriate offset to the render code.
@@ -1553,6 +1553,7 @@ void LLViewerParcelMgr::processParcelProperties(LLMessageSystem *msg, void **use
     BOOL    region_allow_environment_override = true;
     S32     parcel_environment_version = 0;
     BOOL	agent_parcel_update = false; // updating previous(existing) agent parcel
+    U32     extended_flags = 0; //obscure MOAP
 
     S32		other_clean_time = 0;
 
@@ -1591,6 +1592,8 @@ void LLViewerParcelMgr::processParcelProperties(LLMessageSystem *msg, void **use
     else if (sequence_id == 0 || sequence_id > parcel_mgr.mAgentParcelSequenceID)
     {
         // new agent parcel
+        // *TODO: Does it really make sense to set the agent parcel to this
+        // parcel if the client doesn't know what kind of parcel data this is?
         parcel_mgr.mAgentParcelSequenceID = sequence_id;
         parcel = parcel_mgr.mAgentParcel;
     }
@@ -1642,6 +1645,11 @@ void LLViewerParcelMgr::processParcelProperties(LLMessageSystem *msg, void **use
         msg->getBOOLFast(_PREHASH_RegionAllowAccessBlock, _PREHASH_RegionAllowAccessOverride, region_allow_access_override);
     }
 
+    if (msg->getNumberOfBlocks(_PREHASH_ParcelExtendedFlags))
+    {
+        msg->getU32Fast(_PREHASH_ParcelExtendedFlags, _PREHASH_Flags, extended_flags);
+     }
+
     if (msg->getNumberOfBlocks(_PREHASH_ParcelEnvironmentBlock))
     {
         msg->getS32Fast(_PREHASH_ParcelEnvironmentBlock, _PREHASH_ParcelEnvironmentVersion, parcel_environment_version);
@@ -1698,6 +1706,8 @@ void LLViewerParcelMgr::processParcelProperties(LLMessageSystem *msg, void **use
         parcel->setParcelEnvironmentVersion(cur_parcel_environment_version);
         parcel->setRegionAllowEnvironmentOverride(region_allow_environment_override);
 
+        parcel->setObscureMOAP((bool)extended_flags);
+
 		parcel->unpackMessage(msg);
 
 		if (parcel == parcel_mgr.mAgentParcel)
@@ -1879,8 +1889,13 @@ void LLViewerParcelMgr::processParcelProperties(LLMessageSystem *msg, void **use
 	}
 	else
 	{
-		// Check for video
-		LLViewerParcelMedia::getInstance()->update(parcel);
+        if (gNonInteractive)
+        {
+            return;
+        }
+    
+        // Check for video
+        LLViewerParcelMedia::getInstance()->update(parcel);
 
 		// Then check for music
 		if (gAudiop)
diff --git a/indra/newview/llviewerparceloverlay.cpp b/indra/newview/llviewerparceloverlay.cpp
old mode 100644
new mode 100755
index 7c3dd00e1a1ad88bf5b830461e8b4950f479a8bd..785c84c38d3b3494d7f6f7588bab3f3728c31c6a
--- a/indra/newview/llviewerparceloverlay.cpp
+++ b/indra/newview/llviewerparceloverlay.cpp
@@ -264,7 +264,7 @@ BOOL LLViewerParcelOverlay::isSoundLocal(const LLVector3& pos) const
 {
 	S32 row =    S32(pos.mV[VY] / PARCEL_GRID_STEP_METERS);
 	S32 column = S32(pos.mV[VX] / PARCEL_GRID_STEP_METERS);
-	return PARCEL_SOUND_LOCAL & mOwnership[row * mParcelGridsPerEdge + column];
+    return parcelFlags(row, column, PARCEL_SOUND_LOCAL);
 }
 
 U8 LLViewerParcelOverlay::ownership( const LLVector3& pos) const
@@ -278,12 +278,19 @@ U8 LLViewerParcelOverlay::parcelLineFlags(const LLVector3& pos) const
 {
     S32 row = S32(pos.mV[VY] / PARCEL_GRID_STEP_METERS);
     S32 column = S32(pos.mV[VX] / PARCEL_GRID_STEP_METERS);
-    return parcelLineFlags(row, column);
+    return parcelFlags(row, column, PARCEL_WEST_LINE | PARCEL_SOUTH_LINE);
 }
 U8 LLViewerParcelOverlay::parcelLineFlags(S32 row, S32 col) const
 {
-    U8 flags = PARCEL_WEST_LINE | PARCEL_SOUTH_LINE;
-    if (row > mParcelGridsPerEdge || col > mParcelGridsPerEdge)
+    return parcelFlags(row, col, PARCEL_WEST_LINE | PARCEL_SOUTH_LINE);
+}
+
+U8 LLViewerParcelOverlay::parcelFlags(S32 row, S32 col, U8 flags) const
+{
+    if (row >= mParcelGridsPerEdge
+        || col >= mParcelGridsPerEdge
+        || row < 0
+        || col < 0)
     {
         LL_WARNS() << "Attempted to get ownership out of region's overlay, row: " << row << " col: " << col << LL_ENDL;
         return flags;
@@ -847,6 +854,7 @@ void LLViewerParcelOverlay::setDirty()
 
 void LLViewerParcelOverlay::updateGL()
 {
+	LL_PROFILE_ZONE_SCOPED
 	updateOverlayTexture();
 }
 
@@ -907,8 +915,8 @@ S32 LLViewerParcelOverlay::renderPropertyLines	()
 	// Always fudge a little vertically.
 	pull_toward_camera.mV[VZ] += 0.01f;
 
-	gGL.matrixMode(LLRender::MM_MODELVIEW);
-	gGL.pushMatrix();
+    gGL.matrixMode(LLRender::MM_MODELVIEW);
+    gGL.pushMatrix();
 
 	// Move to appropriate region coords
 	LLVector3 origin = mRegion->getOriginAgent();
@@ -1013,7 +1021,66 @@ S32 LLViewerParcelOverlay::renderPropertyLines	()
 		
 	}
 
-	gGL.popMatrix();
+    gGL.popMatrix();
 
 	return drawn;
 }
+
+// Draw half of a single cell (no fill) in a grid drawn from left to right and from bottom to top
+void grid_2d_part_lines(const F32 left, const F32 top, const F32 right, const F32 bottom, bool has_left, bool has_bottom)
+{
+    gGL.begin(LLRender::LINES);
+
+    if (has_left)
+    {
+        gGL.vertex2f(left, bottom);
+        gGL.vertex2f(left, top);
+    }
+    if (has_bottom)
+    {
+        gGL.vertex2f(left, bottom);
+        gGL.vertex2f(right, bottom);
+    }
+
+    gGL.end();
+}
+
+void LLViewerParcelOverlay::renderPropertyLinesOnMinimap(F32 scale_pixels_per_meter, const F32 *parcel_outline_color)
+{
+    if (!mOwnership)
+    {
+        return;
+    }
+    if (!gSavedSettings.getBOOL("MiniMapShowPropertyLines"))
+    {
+        return;
+    }
+
+    LLVector3 origin_agent     = mRegion->getOriginAgent();
+    LLVector3 rel_region_pos   = origin_agent - gAgentCamera.getCameraPositionAgent();
+    F32       region_left      = rel_region_pos.mV[0] * scale_pixels_per_meter;
+    F32       region_bottom    = rel_region_pos.mV[1] * scale_pixels_per_meter;
+    F32       map_parcel_width = PARCEL_GRID_STEP_METERS * scale_pixels_per_meter;
+    const S32 GRIDS_PER_EDGE   = mParcelGridsPerEdge;
+
+    gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+    glLineWidth(1.0f);
+    gGL.color4fv(parcel_outline_color);
+    for (S32 i = 0; i < GRIDS_PER_EDGE + 1; i++)
+    {
+        const F32 bottom = region_bottom + (i * map_parcel_width);
+        const F32 top    = bottom + map_parcel_width;
+        for (S32 j = 0; j < GRIDS_PER_EDGE + 1; j++)
+        {
+            const F32  left               = region_left + (j * map_parcel_width);
+            const F32  right              = left + map_parcel_width;
+            const bool is_region_boundary = i == GRIDS_PER_EDGE || j == GRIDS_PER_EDGE;
+            const U8   overlay            = is_region_boundary ? 0 : mOwnership[(i * GRIDS_PER_EDGE) + j];
+            // The property line vertices are three-dimensional, but here we only care about the x and y coordinates, as we are drawing on a
+            // 2D map
+            const bool has_left   = i != GRIDS_PER_EDGE && (j == GRIDS_PER_EDGE || (overlay & PARCEL_WEST_LINE));
+            const bool has_bottom = j != GRIDS_PER_EDGE && (i == GRIDS_PER_EDGE || (overlay & PARCEL_SOUTH_LINE));
+            grid_2d_part_lines(left, top, right, bottom, has_left, has_bottom);
+        }
+    }
+}
diff --git a/indra/newview/llviewerparceloverlay.h b/indra/newview/llviewerparceloverlay.h
index e30dbf17b3ee01ce867e4979f2c324e1dc7ab2fc..c466cc3b6be1dcb8b72548d3cccb552c2913711c 100644
--- a/indra/newview/llviewerparceloverlay.h
+++ b/indra/newview/llviewerparceloverlay.h
@@ -69,6 +69,7 @@ class LLViewerParcelOverlay : public LLGLUpdate
 
 	// Returns the number of vertices drawn
 	S32				renderPropertyLines();
+    void			renderPropertyLinesOnMinimap(F32 scale_pixels_per_meter, const F32* parcel_outline_color);
 
 	U8				ownership( const LLVector3& pos) const;
 	U8				parcelLineFlags( const LLVector3& pos) const;
@@ -82,12 +83,14 @@ class LLViewerParcelOverlay : public LLGLUpdate
 
 	void	idleUpdate(bool update_now = false);
 	void	updateGL();
-
+    
 private:
 	// This is in parcel rows and columns, not grid rows and columns
 	// Stored in bottom three bits.
 	U8		ownership(S32 row, S32 col) const	
-				{ return 0x7 & mOwnership[row * mParcelGridsPerEdge + col]; }
+				{ return parcelFlags(row, col, (U8)0x7); }
+
+    U8		parcelFlags(S32 row, S32 col, U8 flags) const;
 
 	void	addPropertyLine(std::vector<LLVector3>& vertex_array,
 				std::vector<LLColor4U>& color_array,
diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp
old mode 100644
new mode 100755
index 27fbf39673a044c5b311c8a762f4269aa2aa6b95..ad7321ca4be7a2cfd38395bf2c92f64712394a3f
--- a/indra/newview/llviewerregion.cpp
+++ b/indra/newview/llviewerregion.cpp
@@ -95,8 +95,6 @@
 
 // The server only keeps our pending agent info for 60 seconds.
 // We want to allow for seed cap retry, but its not useful after that 60 seconds.
-// Give it 3 chances, each at 18 seconds to give ourselves a few seconds to connect anyways if we give up.
-const S32 MAX_SEED_CAP_ATTEMPTS_BEFORE_LOGIN = 3;
 // Even though we gave up on login, keep trying for caps after we are logged in:
 const S32 MAX_CAP_REQUEST_ATTEMPTS = 30;
 const U32 DEFAULT_MAX_REGION_WIDE_PRIM_COUNT = 15000;
@@ -178,7 +176,6 @@ class LLViewerRegionImpl
         mCompositionp(NULL),
         mEventPoll(NULL),
         mSeedCapMaxAttempts(MAX_CAP_REQUEST_ATTEMPTS),
-        mSeedCapMaxAttemptsBeforeLogin(MAX_SEED_CAP_ATTEMPTS_BEFORE_LOGIN),
         mSeedCapAttempts(0),
         mHttpResponderID(0),
         mLastCameraUpdate(0),
@@ -231,7 +228,6 @@ class LLViewerRegionImpl
 	LLEventPoll* mEventPoll;
 
 	S32 mSeedCapMaxAttempts;
-	S32 mSeedCapMaxAttemptsBeforeLogin;
 	S32 mSeedCapAttempts;
 
 	S32 mHttpResponderID;
@@ -266,6 +262,12 @@ void LLViewerRegionImpl::requestBaseCapabilitiesCoro(U64 regionHandle)
             return;
         }
 
+        if (!LLWorld::instanceExists())
+        {
+            LL_WARNS("AppInit", "Capabilities") << "Attempting to get capabilities, but world no longer exists!" << LL_ENDL;
+            return;
+        }
+
         regionp = LLWorld::getInstance()->getRegionFromHandle(regionHandle);
         if (!regionp) //region was removed
         {
@@ -280,19 +282,13 @@ void LLViewerRegionImpl::requestBaseCapabilitiesCoro(U64 regionHandle)
         if (url.empty())
         {
             LL_WARNS("AppInit", "Capabilities") << "Failed to get seed capabilities, and can not determine url!" << LL_ENDL;
+            regionp->setCapabilitiesError();
             return; // this error condition is not recoverable.
         }
 
         // record that we just entered a new region
         newRegionEntry(*regionp);
 
-        // After a few attempts, continue login.  But keep trying to get the caps:
-        if (impl->mSeedCapAttempts >= impl->mSeedCapMaxAttemptsBeforeLogin &&
-            STATE_SEED_GRANTED_WAIT == LLStartUp::getStartupState())
-        {
-            LLStartUp::setStartupState(STATE_SEED_CAP_GRANTED);
-        }
-
         if (impl->mSeedCapAttempts > impl->mSeedCapMaxAttempts)
         {
             // *TODO: Give a user pop-up about this error?
@@ -324,6 +320,13 @@ void LLViewerRegionImpl::requestBaseCapabilitiesCoro(U64 regionHandle)
 
         if (LLApp::isExiting() || gDisconnected)
         {
+            LL_DEBUGS("AppInit", "Capabilities") << "Shutting down" << LL_ENDL;
+            return;
+        }
+
+        if (!LLWorld::instanceExists())
+        {
+            LL_WARNS("AppInit", "Capabilities") << "Received capabilities, but world no longer exists!" << LL_ENDL;
             return;
         }
 
@@ -336,14 +339,7 @@ void LLViewerRegionImpl::requestBaseCapabilitiesCoro(U64 regionHandle)
 
         impl = regionp->getRegionImplNC();
 
-        ++impl->mSeedCapAttempts;
-
-        if (id != impl->mHttpResponderID) // region is no longer referring to this request
-        {
-            LL_WARNS("AppInit", "Capabilities") << "Received results for a stale capabilities request!" << LL_ENDL;
-            // setup for retry.
-            continue;
-        }
+        ++(impl->mSeedCapAttempts);
 
         if (!result.isMap() || result.has("error"))
         {
@@ -364,6 +360,13 @@ void LLViewerRegionImpl::requestBaseCapabilitiesCoro(U64 regionHandle)
         // remove the http_result from the llsd
         result.erase("http_result");
 
+        if (id != impl->mHttpResponderID) // region is no longer referring to this request
+        {
+            LL_WARNS("AppInit", "Capabilities") << "Received results for a stale capabilities request!" << LL_ENDL;
+            // setup for retry.
+            continue;
+        }
+
         LLSD::map_const_iterator iter;
         for (iter = result.beginMap(); iter != result.endMap(); ++iter)
         {
@@ -381,11 +384,6 @@ void LLViewerRegionImpl::requestBaseCapabilitiesCoro(U64 regionHandle)
 														 << " region name " << regionp->getName() << LL_ENDL;
         regionp->setCapabilitiesReceived(true);
 
-        if (STATE_SEED_GRANTED_WAIT == LLStartUp::getStartupState())
-        {
-            LLStartUp::setStartupState(STATE_SEED_CAP_GRANTED);
-        }
-
         break;
     } 
     while (true);
@@ -411,7 +409,14 @@ void LLViewerRegionImpl::requestBaseCapabilitiesCompleteCoro(U64 regionHandle)
     // This loop is used for retrying a capabilities request.
     do
     {
-        regionp = LLWorld::getInstance()->getRegionFromHandle(regionHandle);
+        LLWorld *world_inst = LLWorld::getInstance(); // Not a singleton!
+        if (!world_inst)
+        {
+            LL_WARNS("AppInit", "Capabilities") << "Attempting to get capabilities, but world no longer exists!" << LL_ENDL;
+            return;
+        }
+
+        regionp = world_inst->getRegionFromHandle(regionHandle);
         if (!regionp) //region was removed
         {
             LL_WARNS("AppInit", "Capabilities") << "Attempting to get capabilities for region that no longer exists!" << LL_ENDL;
@@ -422,6 +427,11 @@ void LLViewerRegionImpl::requestBaseCapabilitiesCompleteCoro(U64 regionHandle)
         if (url.empty())
         {
             LL_WARNS("AppInit", "Capabilities") << "Failed to get seed capabilities, and can not determine url!" << LL_ENDL;
+            if (regionp->getCapability("Seed").empty())
+            {
+                // initial attempt failed to get this cap as well
+                regionp->setCapabilitiesError();
+            }
             break; // this error condition is not recoverable.
         }
 
@@ -434,6 +444,7 @@ void LLViewerRegionImpl::requestBaseCapabilitiesCompleteCoro(U64 regionHandle)
         LL_INFOS("AppInit", "Capabilities") << "Requesting second Seed from " << url << " for region " << regionp->getRegionID() << LL_ENDL;
 
         regionp = NULL;
+        world_inst = NULL;
         result = httpAdapter->postAndSuspend(httpRequest, url, capabilityNames);
 
         LLSD httpResults = result["http_result"];
@@ -449,7 +460,14 @@ void LLViewerRegionImpl::requestBaseCapabilitiesCompleteCoro(U64 regionHandle)
             break;
         }
 
-        regionp = LLWorld::getInstance()->getRegionFromHandle(regionHandle);
+        world_inst = LLWorld::getInstance();
+        if (!world_inst)
+        {
+            LL_WARNS("AppInit", "Capabilities") << "Received capabilities, but world no longer exists!" << LL_ENDL;
+            return;
+        }
+
+        regionp = world_inst->getRegionFromHandle(regionHandle);
         if (!regionp) //region was removed
         {
             LL_WARNS("AppInit", "Capabilities") << "Received capabilities for region that no longer exists!" << LL_ENDL;
@@ -533,7 +551,14 @@ void LLViewerRegionImpl::requestSimulatorFeatureCoro(std::string url, U64 region
             break;
         }
 
-        regionp = LLWorld::getInstance()->getRegionFromHandle(regionHandle);
+        LLWorld *world_inst = LLWorld::getInstance(); // Not a singleton!
+        if (!world_inst)
+        {
+            LL_WARNS("AppInit", "Capabilities") << "Attempting to request Sim Feature, but world no longer exists!" << LL_ENDL;
+            return;
+        }
+
+        regionp = world_inst->getRegionFromHandle(regionHandle);
         if (!regionp) //region was removed
         {
             LL_WARNS("AppInit", "SimulatorFeatures") << "Attempting to request Sim Feature for region that no longer exists!" << LL_ENDL;
@@ -541,6 +566,7 @@ void LLViewerRegionImpl::requestSimulatorFeatureCoro(std::string url, U64 region
         }
 
         regionp = NULL;
+        world_inst = NULL;
         LLSD result = httpAdapter->getAndSuspend(httpRequest, url);
 
         LLSD httpResults = result["http_result"];
@@ -559,7 +585,14 @@ void LLViewerRegionImpl::requestSimulatorFeatureCoro(std::string url, U64 region
         // remove the http_result from the llsd
         result.erase("http_result");
 
-        regionp = LLWorld::getInstance()->getRegionFromHandle(regionHandle);
+        world_inst = LLWorld::getInstance();
+        if (!world_inst)
+        {
+            LL_WARNS("AppInit", "Capabilities") << "Attempting to request Sim Feature, but world no longer exists!" << LL_ENDL;
+            return;
+        }
+
+        regionp = world_inst->getRegionFromHandle(regionHandle);
         if (!regionp) //region was removed
         {
             LL_WARNS("AppInit", "SimulatorFeatures") << "Attempting to set Sim Feature for region that no longer exists!" << LL_ENDL;
@@ -600,7 +633,7 @@ LLViewerRegion::LLViewerRegion(const U64 &handle,
 	mCacheLoaded(FALSE),
 	mCacheDirty(FALSE),
 	mReleaseNotesRequested(FALSE),
-	mCapabilitiesReceived(false),
+	mCapabilitiesState(CAPABILITIES_STATE_INIT),
 	mSimulatorFeaturesReceived(false),
 	mBitsReceived(0.f),
 	mPacketsReceived(0.f),
@@ -1035,6 +1068,15 @@ S32 LLViewerRegion::renderPropertyLines()
 	}
 }
 
+void LLViewerRegion::renderPropertyLinesOnMinimap(F32 scale_pixels_per_meter, const F32 *parcel_outline_color)
+{
+    if (mParcelOverlay)
+    {
+        mParcelOverlay->renderPropertyLinesOnMinimap(scale_pixels_per_meter, parcel_outline_color);
+    }
+}
+
+
 // This gets called when the height field changes.
 void LLViewerRegion::dirtyHeights()
 {
@@ -1775,13 +1817,8 @@ LLViewerObject* LLViewerRegion::addNewObject(LLVOCacheEntry* entry)
 
 //update object cache if the object receives a full-update or terse update
 //update_type == EObjectUpdateType::OUT_TERSE_IMPROVED or EObjectUpdateType::OUT_FULL
-LLViewerObject* LLViewerRegion::updateCacheEntry(U32 local_id, LLViewerObject* objectp, U32 update_type)
+LLViewerObject* LLViewerRegion::updateCacheEntry(U32 local_id, LLViewerObject* objectp)
 {
-	if(objectp && update_type != (U32)OUT_TERSE_IMPROVED)
-	{
-		return objectp; //no need to access cache
-	}
-
 	LLVOCacheEntry* entry = getCacheEntry(local_id);
 	if (!entry)
 	{
@@ -1793,11 +1830,8 @@ LLViewerObject* LLViewerRegion::updateCacheEntry(U32 local_id, LLViewerObject* o
 		objectp = addNewObject(entry);
 	}
 
-	//remove from cache if terse update
-	if(update_type == (U32)OUT_TERSE_IMPROVED)
-	{
-		killCacheEntry(entry, true);
-	}
+    //remove from cache.
+    killCacheEntry(entry, true);
 
 	return objectp;
 }
@@ -2092,7 +2126,14 @@ class CoarseLocationUpdate : public LLHTTPNode
 		const LLSD& input) const
 	{
 		LLHost host(input["sender"].asString());
-		LLViewerRegion* region = LLWorld::getInstance()->getRegion(host);
+
+        LLWorld *world_inst = LLWorld::getInstance(); // Not a singleton!
+        if (!world_inst)
+        {
+            return;
+        }
+
+		LLViewerRegion* region = world_inst->getRegion(host);
 		if( !region )
 		{
 			return;
@@ -2250,6 +2291,11 @@ void LLViewerRegion::requestSimulatorFeatures()
         std::string coroname =
             LLCoros::instance().launch("LLViewerRegionImpl::requestSimulatorFeatureCoro",
                                        boost::bind(&LLViewerRegionImpl::requestSimulatorFeatureCoro, url, getHandle()));
+
+        // requestSimulatorFeatures can be called from other coros,
+        // launch() acts like a suspend()
+        // Make sure we are still good to do
+        LLCoros::checkStop();
         
         LL_INFOS("AppInit", "SimulatorFeatures") << "Launching " << coroname << " requesting simulator features from " << url << " for region " << getRegionID() << LL_ENDL;
     }
@@ -2950,6 +2996,7 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames)
 	capabilityNames.append("AcceptFriendship");
 	capabilityNames.append("AcceptGroupInvite"); // ReadOfflineMsgs recieved messages only!!!
 	capabilityNames.append("AgentPreferences");
+    capabilityNames.append("AgentProfile");
 	capabilityNames.append("AgentState");
 	capabilityNames.append("AttachmentResources");
 	capabilityNames.append("AvatarPickerSearch");
@@ -3014,6 +3061,7 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames)
 	capabilityNames.append("ProductInfoRequest");
 	capabilityNames.append("ProvisionVoiceAccountRequest");
 	capabilityNames.append("ReadOfflineMsgs"); // Requires to respond reliably: AcceptFriendship, AcceptGroupInvite, DeclineFriendship, DeclineGroupInvite
+	capabilityNames.append("RegionObjects");
 	capabilityNames.append("RemoteParcelRequest");
 	capabilityNames.append("RenderMaterials");
 	capabilityNames.append("RequestTextureDownload");
@@ -3043,6 +3091,7 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames)
 	capabilityNames.append("UpdateScriptTask");
     capabilityNames.append("UpdateSettingsAgentInventory");
     capabilityNames.append("UpdateSettingsTaskInventory");
+    capabilityNames.append("UploadAgentProfileImage");
 	capabilityNames.append("UploadBakedTexture");
     capabilityNames.append("UserInfo");
 	capabilityNames.append("ViewerAsset"); 
@@ -3068,6 +3117,12 @@ void LLViewerRegion::setSeedCapability(const std::string& url)
         std::string coroname =
             LLCoros::instance().launch("LLEnvironmentRequest::requestBaseCapabilitiesCompleteCoro",
             boost::bind(&LLViewerRegionImpl::requestBaseCapabilitiesCompleteCoro, getHandle()));
+
+        // setSeedCapability can be called from other coros,
+        // launch() acts like a suspend()
+        // Make sure we are still good to do
+        LLCoros::checkStop();
+
 		return;
     }
 	
@@ -3081,6 +3136,11 @@ void LLViewerRegion::setSeedCapability(const std::string& url)
         LLCoros::instance().launch("LLViewerRegionImpl::requestBaseCapabilitiesCoro",
         boost::bind(&LLViewerRegionImpl::requestBaseCapabilitiesCoro, getHandle()));
 
+    // setSeedCapability can be called from other coros,
+    // launch() acts like a suspend()
+    // Make sure we are still good to do
+    LLCoros::checkStop();
+
     LL_INFOS("AppInit", "Capabilities") << "Launching " << coroname << " requesting seed capabilities from " << url << " for region " << getRegionID() << LL_ENDL;
 }
 
@@ -3202,12 +3262,17 @@ bool LLViewerRegion::isCapabilityAvailable(const std::string& name) const
 
 bool LLViewerRegion::capabilitiesReceived() const
 {
-	return mCapabilitiesReceived;
+	return mCapabilitiesState == CAPABILITIES_STATE_RECEIVED;
+}
+
+bool LLViewerRegion::capabilitiesError() const
+{
+    return mCapabilitiesState == CAPABILITIES_STATE_ERROR;
 }
 
 void LLViewerRegion::setCapabilitiesReceived(bool received)
 {
-	mCapabilitiesReceived = received;
+	mCapabilitiesState = received ? CAPABILITIES_STATE_RECEIVED : CAPABILITIES_STATE_INIT;
 
 	// Tell interested parties that we've received capabilities,
 	// so that they can safely use getCapability().
@@ -3222,6 +3287,11 @@ void LLViewerRegion::setCapabilitiesReceived(bool received)
 	}
 }
 
+void LLViewerRegion::setCapabilitiesError()
+{
+    mCapabilitiesState = CAPABILITIES_STATE_ERROR;
+}
+
 boost::signals2::connection LLViewerRegion::setCapabilitiesReceivedCallback(const caps_received_signal_t::slot_type& cb)
 {
 	return mCapabilitiesReceivedSignal.connect(cb);
diff --git a/indra/newview/llviewerregion.h b/indra/newview/llviewerregion.h
index fcbf56c81f13c2c6e7ab83fb3548d3e681ce1c1d..6548e8d3728904990f2947afe132d4c698131473 100644
--- a/indra/newview/llviewerregion.h
+++ b/indra/newview/llviewerregion.h
@@ -154,6 +154,8 @@ class LLViewerRegion: public LLCapabilityProvider // implements this interface
 	// Draw lines in the dirt showing ownership. Return number of 
 	// vertices drawn.
 	S32 renderPropertyLines();
+    void renderPropertyLinesOnMinimap(F32 scale_pixels_per_meter, const F32* parcel_outline_color);
+
 
 	// Call this whenever you change the height data in the region.
 	// (Automatically called by LLSurfacePatch's update routine)
@@ -268,7 +270,9 @@ class LLViewerRegion: public LLCapabilityProvider // implements this interface
 
 	// has region received its final (not seed) capability list?
 	bool capabilitiesReceived() const;
+    bool capabilitiesError() const;
 	void setCapabilitiesReceived(bool received);
+	void setCapabilitiesError();
 	boost::signals2::connection setCapabilitiesReceivedCallback(const caps_received_signal_t::slot_type& cb);
 
 	static bool isSpecialCapabilityName(const std::string &name);
@@ -352,7 +356,7 @@ class LLViewerRegion: public LLCapabilityProvider // implements this interface
 	void requestCacheMisses();
 	void addCacheMissFull(const U32 local_id);
 	//update object cache if the object receives a full-update or terse update
-	LLViewerObject* updateCacheEntry(U32 local_id, LLViewerObject* objectp, U32 update_type);
+	LLViewerObject* updateCacheEntry(U32 local_id, LLViewerObject* objectp);
 	void findOrphans(U32 parent_id);
 	void clearCachedVisibleObjects();
 	void dumpCache();
@@ -527,12 +531,20 @@ class LLViewerRegion: public LLCapabilityProvider // implements this interface
 	BOOL									mCacheLoaded;
 	BOOL                                    mCacheDirty;
 	BOOL	mAlive;					// can become false if circuit disconnects
-	BOOL	mCapabilitiesReceived;
 	BOOL	mSimulatorFeaturesReceived;
 	BOOL    mReleaseNotesRequested;
 	BOOL    mDead;  //if true, this region is in the process of deleting.
 	BOOL    mPaused; //pause processing the objects in the region
 
+    typedef enum
+    {
+        CAPABILITIES_STATE_INIT = 0,
+        CAPABILITIES_STATE_ERROR,
+        CAPABILITIES_STATE_RECEIVED
+    } eCababilitiesState;
+
+    eCababilitiesState	mCapabilitiesState;
+
 	typedef std::map<U32, std::vector<U32> > orphan_list_t;
 	orphan_list_t mOrphanMap;
 
diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp
index 945b51d8196e1b8050d6ac18a8c23d8f94d5af70..1c9360a843be3f781955fb2a6884c4b74b2f9caf 100644
--- a/indra/newview/llviewershadermgr.cpp
+++ b/indra/newview/llviewershadermgr.cpp
@@ -77,6 +77,7 @@ LLGLSLShader			gTransformTangentProgram;
 
 //utility shaders
 LLGLSLShader	gOcclusionProgram;
+LLGLSLShader    gSkinnedOcclusionProgram;
 LLGLSLShader	gOcclusionCubeProgram;
 LLGLSLShader	gCustomAlphaProgram;
 LLGLSLShader	gGlowCombineProgram;
@@ -87,6 +88,7 @@ LLGLSLShader	gTwoTextureCompareProgram;
 LLGLSLShader	gOneTextureFilterProgram;
 LLGLSLShader	gOneTextureNoColorProgram;
 LLGLSLShader	gDebugProgram;
+LLGLSLShader    gSkinnedDebugProgram;
 LLGLSLShader	gClipProgram;
 LLGLSLShader	gDownsampleDepthProgram;
 LLGLSLShader	gDownsampleDepthRectProgram;
@@ -96,56 +98,50 @@ LLGLSLShader	gBenchmarkProgram;
 
 //object shaders
 LLGLSLShader		gObjectSimpleProgram;
+LLGLSLShader        gSkinnedObjectSimpleProgram;
 LLGLSLShader		gObjectSimpleImpostorProgram;
+LLGLSLShader        gSkinnedObjectSimpleImpostorProgram;
 LLGLSLShader		gObjectPreviewProgram;
+LLGLSLShader        gPhysicsPreviewProgram;
 LLGLSLShader		gObjectSimpleWaterProgram;
+LLGLSLShader        gSkinnedObjectSimpleWaterProgram;
 LLGLSLShader		gObjectSimpleAlphaMaskProgram;
+LLGLSLShader        gSkinnedObjectSimpleAlphaMaskProgram;
 LLGLSLShader		gObjectSimpleWaterAlphaMaskProgram;
+LLGLSLShader        gSkinnedObjectSimpleWaterAlphaMaskProgram;
 LLGLSLShader		gObjectFullbrightProgram;
+LLGLSLShader        gSkinnedObjectFullbrightProgram;
 LLGLSLShader		gObjectFullbrightWaterProgram;
+LLGLSLShader        gSkinnedObjectFullbrightWaterProgram;
 LLGLSLShader		gObjectEmissiveProgram;
+LLGLSLShader        gSkinnedObjectEmissiveProgram;
 LLGLSLShader		gObjectEmissiveWaterProgram;
+LLGLSLShader        gSkinnedObjectEmissiveWaterProgram;
 LLGLSLShader		gObjectFullbrightAlphaMaskProgram;
+LLGLSLShader        gSkinnedObjectFullbrightAlphaMaskProgram;
 LLGLSLShader		gObjectFullbrightWaterAlphaMaskProgram;
+LLGLSLShader        gSkinnedObjectFullbrightWaterAlphaMaskProgram;
 LLGLSLShader		gObjectFullbrightShinyProgram;
+LLGLSLShader        gSkinnedObjectFullbrightShinyProgram;
 LLGLSLShader		gObjectFullbrightShinyWaterProgram;
+LLGLSLShader        gSkinnedObjectFullbrightShinyWaterProgram;
 LLGLSLShader		gObjectShinyProgram;
+LLGLSLShader        gSkinnedObjectShinyProgram;
 LLGLSLShader		gObjectShinyWaterProgram;
+LLGLSLShader        gSkinnedObjectShinyWaterProgram;
 LLGLSLShader		gObjectBumpProgram;
+LLGLSLShader        gSkinnedObjectBumpProgram;
 LLGLSLShader		gTreeProgram;
 LLGLSLShader		gTreeWaterProgram;
 LLGLSLShader		gObjectFullbrightNoColorProgram;
 LLGLSLShader		gObjectFullbrightNoColorWaterProgram;
 
-LLGLSLShader		gObjectSimpleNonIndexedProgram;
 LLGLSLShader		gObjectSimpleNonIndexedTexGenProgram;
 LLGLSLShader		gObjectSimpleNonIndexedTexGenWaterProgram;
-LLGLSLShader		gObjectSimpleNonIndexedWaterProgram;
 LLGLSLShader		gObjectAlphaMaskNonIndexedProgram;
 LLGLSLShader		gObjectAlphaMaskNonIndexedWaterProgram;
 LLGLSLShader		gObjectAlphaMaskNoColorProgram;
 LLGLSLShader		gObjectAlphaMaskNoColorWaterProgram;
-LLGLSLShader		gObjectFullbrightNonIndexedProgram;
-LLGLSLShader		gObjectFullbrightNonIndexedWaterProgram;
-LLGLSLShader		gObjectEmissiveNonIndexedProgram;
-LLGLSLShader		gObjectEmissiveNonIndexedWaterProgram;
-LLGLSLShader		gObjectFullbrightShinyNonIndexedProgram;
-LLGLSLShader		gObjectFullbrightShinyNonIndexedWaterProgram;
-LLGLSLShader		gObjectShinyNonIndexedProgram;
-LLGLSLShader		gObjectShinyNonIndexedWaterProgram;
-
-//object hardware skinning shaders
-LLGLSLShader		gSkinnedObjectSimpleProgram;
-LLGLSLShader		gSkinnedObjectFullbrightProgram;
-LLGLSLShader		gSkinnedObjectEmissiveProgram;
-LLGLSLShader		gSkinnedObjectFullbrightShinyProgram;
-LLGLSLShader		gSkinnedObjectShinySimpleProgram;
-
-LLGLSLShader		gSkinnedObjectSimpleWaterProgram;
-LLGLSLShader		gSkinnedObjectFullbrightWaterProgram;
-LLGLSLShader		gSkinnedObjectEmissiveWaterProgram;
-LLGLSLShader		gSkinnedObjectFullbrightShinyWaterProgram;
-LLGLSLShader		gSkinnedObjectShinySimpleWaterProgram;
 
 //environment shaders
 LLGLSLShader		gTerrainProgram;
@@ -156,6 +152,7 @@ LLGLSLShader		gUnderWaterProgram;
 
 //interface shaders
 LLGLSLShader		gHighlightProgram;
+LLGLSLShader        gSkinnedHighlightProgram;
 LLGLSLShader		gHighlightNormalProgram;
 LLGLSLShader		gHighlightSpecularProgram;
 
@@ -191,17 +188,18 @@ LLGLSLShader			gDeferredWaterProgram;
 LLGLSLShader			gDeferredUnderWaterProgram;
 LLGLSLShader			gDeferredDiffuseProgram;
 LLGLSLShader			gDeferredDiffuseAlphaMaskProgram;
+LLGLSLShader            gDeferredSkinnedDiffuseAlphaMaskProgram;
 LLGLSLShader			gDeferredNonIndexedDiffuseProgram;
 LLGLSLShader			gDeferredNonIndexedDiffuseAlphaMaskProgram;
 LLGLSLShader			gDeferredNonIndexedDiffuseAlphaMaskNoColorProgram;
 LLGLSLShader			gDeferredSkinnedDiffuseProgram;
 LLGLSLShader			gDeferredSkinnedBumpProgram;
-LLGLSLShader			gDeferredSkinnedAlphaProgram;
 LLGLSLShader			gDeferredBumpProgram;
 LLGLSLShader			gDeferredTerrainProgram;
 LLGLSLShader            gDeferredTerrainWaterProgram;
 LLGLSLShader			gDeferredTreeProgram;
 LLGLSLShader			gDeferredTreeShadowProgram;
+LLGLSLShader            gDeferredSkinnedTreeShadowProgram;
 LLGLSLShader			gDeferredAvatarProgram;
 LLGLSLShader			gDeferredAvatarAlphaProgram;
 LLGLSLShader			gDeferredLightProgram;
@@ -213,9 +211,12 @@ LLGLSLShader			gDeferredBlurLightProgram;
 LLGLSLShader			gDeferredSoftenProgram;
 LLGLSLShader			gDeferredSoftenWaterProgram;
 LLGLSLShader			gDeferredShadowProgram;
+LLGLSLShader            gDeferredSkinnedShadowProgram;
 LLGLSLShader			gDeferredShadowCubeProgram;
 LLGLSLShader			gDeferredShadowAlphaMaskProgram;
+LLGLSLShader            gDeferredSkinnedShadowAlphaMaskProgram;
 LLGLSLShader			gDeferredShadowFullbrightAlphaMaskProgram;
+LLGLSLShader            gDeferredSkinnedShadowFullbrightAlphaMaskProgram;
 LLGLSLShader			gDeferredAvatarShadowProgram;
 LLGLSLShader			gDeferredAvatarAlphaShadowProgram;
 LLGLSLShader			gDeferredAvatarAlphaMaskShadowProgram;
@@ -223,14 +224,20 @@ LLGLSLShader			gDeferredAttachmentShadowProgram;
 LLGLSLShader			gDeferredAttachmentAlphaShadowProgram;
 LLGLSLShader			gDeferredAttachmentAlphaMaskShadowProgram;
 LLGLSLShader			gDeferredAlphaProgram;
+LLGLSLShader            gDeferredSkinnedAlphaProgram;
 LLGLSLShader			gDeferredAlphaImpostorProgram;
+LLGLSLShader            gDeferredSkinnedAlphaImpostorProgram;
 LLGLSLShader			gDeferredAlphaWaterProgram;
+LLGLSLShader            gDeferredSkinnedAlphaWaterProgram;
 LLGLSLShader			gDeferredAvatarEyesProgram;
 LLGLSLShader			gDeferredFullbrightProgram;
 LLGLSLShader			gDeferredFullbrightAlphaMaskProgram;
 LLGLSLShader			gDeferredFullbrightWaterProgram;
+LLGLSLShader            gDeferredSkinnedFullbrightWaterProgram;
 LLGLSLShader			gDeferredFullbrightAlphaMaskWaterProgram;
+LLGLSLShader            gDeferredSkinnedFullbrightAlphaMaskWaterProgram;
 LLGLSLShader			gDeferredEmissiveProgram;
+LLGLSLShader            gDeferredSkinnedEmissiveProgram;
 LLGLSLShader			gDeferredPostProgram;
 LLGLSLShader			gDeferredCoFProgram;
 LLGLSLShader			gDeferredDoFCombineProgram;
@@ -243,14 +250,31 @@ LLGLSLShader			gDeferredWLSunProgram;
 LLGLSLShader			gDeferredWLMoonProgram;
 LLGLSLShader			gDeferredStarProgram;
 LLGLSLShader			gDeferredFullbrightShinyProgram;
-LLGLSLShader			gDeferredSkinnedFullbrightShinyProgram;
+LLGLSLShader            gDeferredSkinnedFullbrightShinyProgram;
 LLGLSLShader			gDeferredSkinnedFullbrightProgram;
+LLGLSLShader            gDeferredSkinnedFullbrightAlphaMaskProgram;
 LLGLSLShader			gNormalMapGenProgram;
 
 // Deferred materials shaders
 LLGLSLShader			gDeferredMaterialProgram[LLMaterial::SHADER_COUNT*2];
 LLGLSLShader			gDeferredMaterialWaterProgram[LLMaterial::SHADER_COUNT*2];
 
+//helper for making a rigged variant of a given shader
+bool make_rigged_variant(LLGLSLShader& shader, LLGLSLShader& riggedShader)
+{
+    riggedShader.mName = llformat("Skinned %s", shader.mName.c_str());
+    riggedShader.mFeatures = shader.mFeatures;
+    riggedShader.mFeatures.hasObjectSkinning = true;
+    riggedShader.mDefines = shader.mDefines;    // NOTE: Must come before addPermutation
+    riggedShader.addPermutation("HAS_SKIN", "1");
+    riggedShader.mShaderFiles = shader.mShaderFiles;
+    riggedShader.mShaderLevel = shader.mShaderLevel;
+    riggedShader.mShaderGroup = shader.mShaderGroup;
+
+    shader.mRiggedVariant = &riggedShader;
+    return riggedShader.createShader(NULL, NULL);
+}
+
 LLViewerShaderMgr::LLViewerShaderMgr() :
 	mShaderLevel(SHADER_COUNT, 0),
 	mMaxAvatarShaderLevel(0)
@@ -263,75 +287,77 @@ LLViewerShaderMgr::LLViewerShaderMgr() :
 	mShaderList.push_back(&gWLMoonProgram);
 	mShaderList.push_back(&gAvatarProgram);
 	mShaderList.push_back(&gObjectShinyProgram);
-	mShaderList.push_back(&gObjectShinyNonIndexedProgram);
+    mShaderList.push_back(&gSkinnedObjectShinyProgram);
 	mShaderList.push_back(&gWaterProgram);
 	mShaderList.push_back(&gWaterEdgeProgram);
 	mShaderList.push_back(&gAvatarEyeballProgram); 
 	mShaderList.push_back(&gObjectSimpleProgram);
+    mShaderList.push_back(&gSkinnedObjectSimpleProgram);
 	mShaderList.push_back(&gObjectSimpleImpostorProgram);
+    mShaderList.push_back(&gSkinnedObjectSimpleImpostorProgram);
 	mShaderList.push_back(&gObjectPreviewProgram);
 	mShaderList.push_back(&gImpostorProgram);
 	mShaderList.push_back(&gObjectFullbrightNoColorProgram);
 	mShaderList.push_back(&gObjectFullbrightNoColorWaterProgram);
 	mShaderList.push_back(&gObjectSimpleAlphaMaskProgram);
+    mShaderList.push_back(&gSkinnedObjectSimpleAlphaMaskProgram);
 	mShaderList.push_back(&gObjectBumpProgram);
+    mShaderList.push_back(&gSkinnedObjectBumpProgram);
 	mShaderList.push_back(&gObjectEmissiveProgram);
+    mShaderList.push_back(&gSkinnedObjectEmissiveProgram);
 	mShaderList.push_back(&gObjectEmissiveWaterProgram);
+    mShaderList.push_back(&gSkinnedObjectEmissiveWaterProgram);
 	mShaderList.push_back(&gObjectFullbrightProgram);
+    mShaderList.push_back(&gSkinnedObjectFullbrightProgram);
 	mShaderList.push_back(&gObjectFullbrightAlphaMaskProgram);
+    mShaderList.push_back(&gSkinnedObjectFullbrightAlphaMaskProgram);
 	mShaderList.push_back(&gObjectFullbrightShinyProgram);
+    mShaderList.push_back(&gSkinnedObjectFullbrightShinyProgram);
 	mShaderList.push_back(&gObjectFullbrightShinyWaterProgram);
-	mShaderList.push_back(&gObjectSimpleNonIndexedProgram);
+    mShaderList.push_back(&gSkinnedObjectFullbrightShinyWaterProgram);
 	mShaderList.push_back(&gObjectSimpleNonIndexedTexGenProgram);
 	mShaderList.push_back(&gObjectSimpleNonIndexedTexGenWaterProgram);
-	mShaderList.push_back(&gObjectSimpleNonIndexedWaterProgram);
 	mShaderList.push_back(&gObjectAlphaMaskNonIndexedProgram);
 	mShaderList.push_back(&gObjectAlphaMaskNonIndexedWaterProgram);
 	mShaderList.push_back(&gObjectAlphaMaskNoColorProgram);
 	mShaderList.push_back(&gObjectAlphaMaskNoColorWaterProgram);
 	mShaderList.push_back(&gTreeProgram);
 	mShaderList.push_back(&gTreeWaterProgram);
-	mShaderList.push_back(&gObjectFullbrightNonIndexedProgram);
-	mShaderList.push_back(&gObjectFullbrightNonIndexedWaterProgram);
-	mShaderList.push_back(&gObjectEmissiveNonIndexedProgram);
-	mShaderList.push_back(&gObjectEmissiveNonIndexedWaterProgram);
-	mShaderList.push_back(&gObjectFullbrightShinyNonIndexedProgram);
-	mShaderList.push_back(&gObjectFullbrightShinyNonIndexedWaterProgram);
-	mShaderList.push_back(&gSkinnedObjectSimpleProgram);
-	mShaderList.push_back(&gSkinnedObjectFullbrightProgram);
-	mShaderList.push_back(&gSkinnedObjectEmissiveProgram);
-	mShaderList.push_back(&gSkinnedObjectFullbrightShinyProgram);
-	mShaderList.push_back(&gSkinnedObjectShinySimpleProgram);
-	mShaderList.push_back(&gSkinnedObjectSimpleWaterProgram);
-	mShaderList.push_back(&gSkinnedObjectFullbrightWaterProgram);
-	mShaderList.push_back(&gSkinnedObjectEmissiveWaterProgram);
-	mShaderList.push_back(&gSkinnedObjectFullbrightShinyWaterProgram);
-	mShaderList.push_back(&gSkinnedObjectShinySimpleWaterProgram);
 	mShaderList.push_back(&gTerrainProgram);
 	mShaderList.push_back(&gTerrainWaterProgram);
 	mShaderList.push_back(&gObjectSimpleWaterProgram);
+    mShaderList.push_back(&gSkinnedObjectSimpleWaterProgram);
 	mShaderList.push_back(&gObjectFullbrightWaterProgram);
+    mShaderList.push_back(&gSkinnedObjectFullbrightWaterProgram);
 	mShaderList.push_back(&gObjectSimpleWaterAlphaMaskProgram);
+    mShaderList.push_back(&gSkinnedObjectSimpleWaterAlphaMaskProgram);
 	mShaderList.push_back(&gObjectFullbrightWaterAlphaMaskProgram);
+    mShaderList.push_back(&gSkinnedObjectFullbrightWaterAlphaMaskProgram);
 	mShaderList.push_back(&gAvatarWaterProgram);
 	mShaderList.push_back(&gObjectShinyWaterProgram);
-	mShaderList.push_back(&gObjectShinyNonIndexedWaterProgram);
+    mShaderList.push_back(&gSkinnedObjectShinyWaterProgram);
 	mShaderList.push_back(&gUnderWaterProgram);
 	mShaderList.push_back(&gDeferredSunProgram);
 	mShaderList.push_back(&gDeferredSoftenProgram);
 	mShaderList.push_back(&gDeferredSoftenWaterProgram);
 	mShaderList.push_back(&gDeferredAlphaProgram);
+    mShaderList.push_back(&gDeferredSkinnedAlphaProgram);
 	mShaderList.push_back(&gDeferredAlphaImpostorProgram);
+    mShaderList.push_back(&gDeferredSkinnedAlphaImpostorProgram);
 	mShaderList.push_back(&gDeferredAlphaWaterProgram);
-	mShaderList.push_back(&gDeferredSkinnedAlphaProgram);
+    mShaderList.push_back(&gDeferredSkinnedAlphaWaterProgram);
 	mShaderList.push_back(&gDeferredFullbrightProgram);
 	mShaderList.push_back(&gDeferredFullbrightAlphaMaskProgram);
 	mShaderList.push_back(&gDeferredFullbrightWaterProgram);
-	mShaderList.push_back(&gDeferredFullbrightAlphaMaskWaterProgram);	
+    mShaderList.push_back(&gDeferredSkinnedFullbrightWaterProgram);
+	mShaderList.push_back(&gDeferredFullbrightAlphaMaskWaterProgram);
+    mShaderList.push_back(&gDeferredSkinnedFullbrightAlphaMaskWaterProgram);
 	mShaderList.push_back(&gDeferredFullbrightShinyProgram);
-	mShaderList.push_back(&gDeferredSkinnedFullbrightShinyProgram);
+    mShaderList.push_back(&gDeferredSkinnedFullbrightShinyProgram);
 	mShaderList.push_back(&gDeferredSkinnedFullbrightProgram);
+    mShaderList.push_back(&gDeferredSkinnedFullbrightAlphaMaskProgram);
 	mShaderList.push_back(&gDeferredEmissiveProgram);
+    mShaderList.push_back(&gDeferredSkinnedEmissiveProgram);
 	mShaderList.push_back(&gDeferredAvatarEyesProgram);
 	mShaderList.push_back(&gDeferredWaterProgram);
 	mShaderList.push_back(&gDeferredUnderWaterProgram);	
@@ -384,7 +410,7 @@ void LLViewerShaderMgr::initAttribsAndUniforms(void)
 
 S32 LLViewerShaderMgr::getShaderLevel(S32 type)
 {
-	return LLPipeline::sDisableShaders ? 0 : mShaderLevel[type];
+	return mShaderLevel[type];
 }
 
 //============================================================================
@@ -400,12 +426,10 @@ void LLViewerShaderMgr::setShaders()
         return;
     }
 
-    if (!gGLManager.mHasShaderObjects
-        || !gGLManager.mHasVertexShader
-        || !gGLManager.mHasFragmentShader)
+    if (!gGLManager.mHasRequirements)
     {
         // Viewer will show 'hardware requirements' warning later
-        LL_INFOS("ShaderLoading") << "Shaders not supported" << LL_ENDL;
+        LL_INFOS("ShaderLoading") << "Not supported hardware/software" << LL_ENDL;
         return;
     }
 
@@ -433,7 +457,7 @@ void LLViewerShaderMgr::setShaders()
     initAttribsAndUniforms();
     gPipeline.releaseGLBuffers();
 
-    LLPipeline::sWaterReflections = gGLManager.mHasCubeMap;
+    LLPipeline::sWaterReflections = gGLManager.mHasCubeMap && LLPipeline::sRenderTransparentWater;
     LLPipeline::sRenderGlow = gSavedSettings.getBOOL("RenderGlow"); 
     LLPipeline::updateRenderDeferred();
     
@@ -458,7 +482,6 @@ void LLViewerShaderMgr::setShaders()
     }
     mMaxAvatarShaderLevel = 0;
 
-    LLGLSLShader::sNoFixedFunction = false;
     LLVertexBuffer::unbind();
 
     llassert((gGLManager.mGLSLVersionMajor > 1 || gGLManager.mGLSLVersionMinor >= 10));
@@ -467,10 +490,7 @@ void LLViewerShaderMgr::setShaders()
     bool hasWindLightShaders     = LLFeatureManager::getInstance()->isFeatureAvailable("WindLightUseAtmosShaders");
     S32 shadow_detail            = gSavedSettings.getS32("RenderShadowDetail");
     bool doingWindLight          = hasWindLightShaders && gSavedSettings.getBOOL("WindLightUseAtmosShaders");
-    bool useRenderDeferred       = doingWindLight && canRenderDeferred && gSavedSettings.getBOOL("RenderDeferred") && gSavedSettings.getBOOL("RenderAvatarVP");
-
-    //using shaders, disable fixed function
-    LLGLSLShader::sNoFixedFunction = true;
+    bool useRenderDeferred       = doingWindLight && canRenderDeferred && gSavedSettings.getBOOL("RenderDeferred");
 
     S32 light_class = 3;
     S32 interface_class = 2;
@@ -536,199 +556,174 @@ void LLViewerShaderMgr::setShaders()
     mShaderLevel[SHADER_DEFERRED] = deferred_class;
     mShaderLevel[SHADER_TRANSFORM] = transform_class;
 
-    BOOL loaded = loadBasicShaders();
-    if (loaded)
+    std::string shader_name = loadBasicShaders();
+    if (shader_name.empty())
     {
         LL_INFOS() << "Loaded basic shaders." << LL_ENDL;
     }
     else
     {
-        LL_WARNS() << "Failed to load basic shaders." << LL_ENDL;
-        llassert(loaded);
+        LL_ERRS() << "Unable to load basic shader " << shader_name << ", verify graphics driver installed and current." << LL_ENDL;
+        reentrance = false; // For hygiene only, re-try probably helps nothing 
+        return;
     }
 
+    gPipeline.mShadersLoaded = true;
+
+    // Load all shaders to set max levels
+    BOOL loaded = loadShadersEnvironment();
+
     if (loaded)
     {
-        gPipeline.mVertexShadersEnabled = TRUE;
-        gPipeline.mVertexShadersLoaded = 1;
-
-        // Load all shaders to set max levels
-        loaded = loadShadersEnvironment();
+        LL_INFOS() << "Loaded environment shaders." << LL_ENDL;
+    }
+    else
+    {
+        LL_WARNS() << "Failed to load environment shaders." << LL_ENDL;
+        llassert(loaded);
+    }
 
+    if (loaded)
+    {
+        loaded = loadShadersWater();
         if (loaded)
         {
-            LL_INFOS() << "Loaded environment shaders." << LL_ENDL;
+            LL_INFOS() << "Loaded water shaders." << LL_ENDL;
         }
         else
         {
-            LL_WARNS() << "Failed to load environment shaders." << LL_ENDL;
+            LL_WARNS() << "Failed to load water shaders." << LL_ENDL;
             llassert(loaded);
         }
+    }
 
+    if (loaded)
+    {
+        loaded = loadShadersWindLight();
         if (loaded)
         {
-            loaded = loadShadersWater();
-            if (loaded)
-            {
-                LL_INFOS() << "Loaded water shaders." << LL_ENDL;
-            }
-            else
-            {
-                LL_WARNS() << "Failed to load water shaders." << LL_ENDL;
-                llassert(loaded);
-            }
+            LL_INFOS() << "Loaded windlight shaders." << LL_ENDL;
         }
-
-        if (loaded)
+        else
         {
-            loaded = loadShadersWindLight();
-            if (loaded)
-            {
-                LL_INFOS() << "Loaded windlight shaders." << LL_ENDL;
-            }
-            else
-            {
-                LL_WARNS() << "Failed to load windlight shaders." << LL_ENDL;
-                llassert(loaded);
-            }
+            LL_WARNS() << "Failed to load windlight shaders." << LL_ENDL;
+            llassert(loaded);
         }
+    }
 
+    if (loaded)
+    {
+        loaded = loadShadersEffects();
         if (loaded)
         {
-            loaded = loadShadersEffects();
-            if (loaded)
-            {
-                LL_INFOS() << "Loaded effects shaders." << LL_ENDL;
-            }
-            else
-            {
-                LL_WARNS() << "Failed to load effects shaders." << LL_ENDL;
-                llassert(loaded);
-            }
+            LL_INFOS() << "Loaded effects shaders." << LL_ENDL;
         }
-
-        if (loaded)
+        else
         {
-            loaded = loadShadersInterface();
-            if (loaded)
-            {
-                LL_INFOS() << "Loaded interface shaders." << LL_ENDL;
-            }
-            else
-            {
-                LL_WARNS() << "Failed to load interface shaders." << LL_ENDL;
-                llassert(loaded);
-            }
+            LL_WARNS() << "Failed to load effects shaders." << LL_ENDL;
+            llassert(loaded);
         }
+    }
 
+    if (loaded)
+    {
+        loaded = loadShadersInterface();
         if (loaded)
-
         {
-            loaded = loadTransformShaders();
-            if (loaded)
-            {
-                LL_INFOS() << "Loaded transform shaders." << LL_ENDL;
-            }
-            else
-            {
-                LL_WARNS() << "Failed to load transform shaders." << LL_ENDL;
-                llassert(loaded);
-            }
+            LL_INFOS() << "Loaded interface shaders." << LL_ENDL;
+        }
+        else
+        {
+            LL_WARNS() << "Failed to load interface shaders." << LL_ENDL;
+            llassert(loaded);
         }
+    }
+
+    if (loaded)
 
+    {
+        loaded = loadTransformShaders();
         if (loaded)
         {
-            // Load max avatar shaders to set the max level
-            mShaderLevel[SHADER_AVATAR] = 3;
-            mMaxAvatarShaderLevel = 3;
+            LL_INFOS() << "Loaded transform shaders." << LL_ENDL;
+        }
+        else
+        {
+            LL_WARNS() << "Failed to load transform shaders." << LL_ENDL;
+            llassert(loaded);
+        }
+    }
+
+    if (loaded)
+    {
+        // Load max avatar shaders to set the max level
+        mShaderLevel[SHADER_AVATAR] = 3;
+        mMaxAvatarShaderLevel = 3;
                 
-            if (gSavedSettings.getBOOL("RenderAvatarVP") && loadShadersObject())
-            { //hardware skinning is enabled and rigged attachment shaders loaded correctly
-                BOOL avatar_cloth = gSavedSettings.getBOOL("RenderAvatarCloth");
+            if (loadShadersObject())
+        { //hardware skinning is enabled and rigged attachment shaders loaded correctly
+            BOOL avatar_cloth = gSavedSettings.getBOOL("RenderAvatarCloth");
 
-                // cloth is a class3 shader
-                S32 avatar_class = avatar_cloth ? 3 : 1;
+            // cloth is a class3 shader
+            S32 avatar_class = avatar_cloth ? 3 : 1;
                 
-                // Set the actual level
-                mShaderLevel[SHADER_AVATAR] = avatar_class;
+            // Set the actual level
+            mShaderLevel[SHADER_AVATAR] = avatar_class;
 
-                loaded = loadShadersAvatar();
-                llassert(loaded);
+            loaded = loadShadersAvatar();
+            llassert(loaded);
 
-                if (mShaderLevel[SHADER_AVATAR] != avatar_class)
+            if (mShaderLevel[SHADER_AVATAR] != avatar_class)
+            {
+                if(llmax(mShaderLevel[SHADER_AVATAR]-1,0) >= 3)
                 {
-                    if (mShaderLevel[SHADER_AVATAR] == 0)
-                    {
-                        gSavedSettings.setBOOL("RenderAvatarVP", FALSE);
-                    }
-                    if(llmax(mShaderLevel[SHADER_AVATAR]-1,0) >= 3)
-                    {
-                        avatar_cloth = true;
-                    }
-                    else
-                    {
-                        avatar_cloth = false;
-                    }
-                    gSavedSettings.setBOOL("RenderAvatarCloth", avatar_cloth);
+                    avatar_cloth = true;
                 }
-            }
-            else
-            { //hardware skinning not possible, neither is deferred rendering
-                mShaderLevel[SHADER_AVATAR] = 0;
-                mShaderLevel[SHADER_DEFERRED] = 0;
-
-                if (gSavedSettings.getBOOL("RenderAvatarVP"))
+                else
                 {
-                    gSavedSettings.setBOOL("RenderDeferred", FALSE);
-                    gSavedSettings.setBOOL("RenderAvatarCloth", FALSE);
-                    gSavedSettings.setBOOL("RenderAvatarVP", FALSE);
+                    avatar_cloth = false;
                 }
-
-                loadShadersAvatar(); // unloads
-
-                loaded = loadShadersObject();
-                llassert(loaded);
+                gSavedSettings.setBOOL("RenderAvatarCloth", avatar_cloth);
             }
         }
+        else
+        { //hardware skinning not possible, neither is deferred rendering
+            mShaderLevel[SHADER_AVATAR] = 0;
+            mShaderLevel[SHADER_DEFERRED] = 0;
 
-        if (!loaded)
-        { //some shader absolutely could not load, try to fall back to a simpler setting
-            if (gSavedSettings.getBOOL("WindLightUseAtmosShaders"))
-            { //disable windlight and try again
-                gSavedSettings.setBOOL("WindLightUseAtmosShaders", FALSE);
-                LL_WARNS() << "Falling back to no windlight shaders." << LL_ENDL;
-                reentrance = false;
-                setShaders();
-                return;
-            }
-        }       
+                gSavedSettings.setBOOL("RenderDeferred", FALSE);
+                gSavedSettings.setBOOL("RenderAvatarCloth", FALSE);
 
-        llassert(loaded);
+            loadShadersAvatar(); // unloads
 
-        if (loaded && !loadShadersDeferred())
-        { //everything else succeeded but deferred failed, disable deferred and try again
-            gSavedSettings.setBOOL("RenderDeferred", FALSE);
-            LL_WARNS() << "Falling back to no deferred shaders." << LL_ENDL;
+            loaded = loadShadersObject();
+            llassert(loaded);
+        }
+    }
+
+    if (!loaded)
+    { //some shader absolutely could not load, try to fall back to a simpler setting
+        if (gSavedSettings.getBOOL("WindLightUseAtmosShaders"))
+        { //disable windlight and try again
+            gSavedSettings.setBOOL("WindLightUseAtmosShaders", FALSE);
+            LL_WARNS() << "Falling back to no windlight shaders." << LL_ENDL;
             reentrance = false;
             setShaders();
             return;
         }
+    }       
+
+    llassert(loaded);
+
+    if (loaded && !loadShadersDeferred())
+    { //everything else succeeded but deferred failed, disable deferred and try again
+        gSavedSettings.setBOOL("RenderDeferred", FALSE);
+        LL_WARNS() << "Falling back to no deferred shaders." << LL_ENDL;
+        reentrance = false;
+        setShaders();
+        return;
     }
-    else
-    {
-        LLGLSLShader::sNoFixedFunction = false;
-        gPipeline.mVertexShadersEnabled = FALSE;
-        gPipeline.mVertexShadersLoaded = 0;
-        mShaderLevel[SHADER_LIGHTING] = 0;
-        mShaderLevel[SHADER_INTERFACE] = 0;
-        mShaderLevel[SHADER_ENVIRONMENT] = 0;
-        mShaderLevel[SHADER_WATER] = 0;
-        mShaderLevel[SHADER_OBJECT] = 0;
-        mShaderLevel[SHADER_EFFECT] = 0;
-        mShaderLevel[SHADER_WINDLIGHT] = 0;
-        mShaderLevel[SHADER_AVATAR] = 0;
-    }
-    
+
     if (gViewerWindow)
     {
         gViewerWindow->setCursor(UI_CURSOR_ARROW);
@@ -741,8 +736,10 @@ void LLViewerShaderMgr::setShaders()
 void LLViewerShaderMgr::unloadShaders()
 {
 	gOcclusionProgram.unload();
+    gSkinnedOcclusionProgram.unload();
 	gOcclusionCubeProgram.unload();
 	gDebugProgram.unload();
+    gSkinnedDebugProgram.unload();
 	gClipProgram.unload();
 	gDownsampleDepthProgram.unload();
 	gDownsampleDepthRectProgram.unload();
@@ -764,58 +761,51 @@ void LLViewerShaderMgr::unloadShaders()
 	gObjectFullbrightNoColorProgram.unload();
 	gObjectFullbrightNoColorWaterProgram.unload();
 	gObjectSimpleProgram.unload();
+    gSkinnedObjectSimpleProgram.unload();
 	gObjectSimpleImpostorProgram.unload();
+    gSkinnedObjectSimpleImpostorProgram.unload();
 	gObjectPreviewProgram.unload();
+    gPhysicsPreviewProgram.unload();
 	gImpostorProgram.unload();
 	gObjectSimpleAlphaMaskProgram.unload();
+    gSkinnedObjectSimpleAlphaMaskProgram.unload();
 	gObjectBumpProgram.unload();
+    gSkinnedObjectBumpProgram.unload();
 	gObjectSimpleWaterProgram.unload();
+    gSkinnedObjectSimpleWaterProgram.unload();
 	gObjectSimpleWaterAlphaMaskProgram.unload();
+    gSkinnedObjectSimpleWaterAlphaMaskProgram.unload();
 	gObjectFullbrightProgram.unload();
+    gSkinnedObjectFullbrightProgram.unload();
 	gObjectFullbrightWaterProgram.unload();
+    gSkinnedObjectFullbrightWaterProgram.unload();
 	gObjectEmissiveProgram.unload();
+    gSkinnedObjectEmissiveProgram.unload();
 	gObjectEmissiveWaterProgram.unload();
+    gSkinnedObjectEmissiveWaterProgram.unload();
 	gObjectFullbrightAlphaMaskProgram.unload();
+    gSkinnedObjectFullbrightAlphaMaskProgram.unload();
 	gObjectFullbrightWaterAlphaMaskProgram.unload();
+    gSkinnedObjectFullbrightWaterAlphaMaskProgram.unload();
 
 	gObjectShinyProgram.unload();
+    gSkinnedObjectShinyProgram.unload();
 	gObjectFullbrightShinyProgram.unload();
+    gSkinnedObjectFullbrightShinyProgram.unload();
 	gObjectFullbrightShinyWaterProgram.unload();
+    gSkinnedObjectFullbrightShinyWaterProgram.unload();
 	gObjectShinyWaterProgram.unload();
+    gSkinnedObjectShinyWaterProgram.unload();
 
-	gObjectSimpleNonIndexedProgram.unload();
 	gObjectSimpleNonIndexedTexGenProgram.unload();
 	gObjectSimpleNonIndexedTexGenWaterProgram.unload();
-	gObjectSimpleNonIndexedWaterProgram.unload();
 	gObjectAlphaMaskNonIndexedProgram.unload();
 	gObjectAlphaMaskNonIndexedWaterProgram.unload();
 	gObjectAlphaMaskNoColorProgram.unload();
 	gObjectAlphaMaskNoColorWaterProgram.unload();
-	gObjectFullbrightNonIndexedProgram.unload();
-	gObjectFullbrightNonIndexedWaterProgram.unload();
-	gObjectEmissiveNonIndexedProgram.unload();
-	gObjectEmissiveNonIndexedWaterProgram.unload();
 	gTreeProgram.unload();
 	gTreeWaterProgram.unload();
 
-	gObjectShinyNonIndexedProgram.unload();
-	gObjectFullbrightShinyNonIndexedProgram.unload();
-	gObjectFullbrightShinyNonIndexedWaterProgram.unload();
-	gObjectShinyNonIndexedWaterProgram.unload();
-
-	gSkinnedObjectSimpleProgram.unload();
-	gSkinnedObjectFullbrightProgram.unload();
-	gSkinnedObjectEmissiveProgram.unload();
-	gSkinnedObjectFullbrightShinyProgram.unload();
-	gSkinnedObjectShinySimpleProgram.unload();
-	
-	gSkinnedObjectSimpleWaterProgram.unload();
-	gSkinnedObjectFullbrightWaterProgram.unload();
-	gSkinnedObjectEmissiveWaterProgram.unload();
-	gSkinnedObjectFullbrightShinyWaterProgram.unload();
-	gSkinnedObjectShinySimpleWaterProgram.unload();
-	
-
 	gWaterProgram.unload();
     gWaterEdgeProgram.unload();
 	gUnderWaterProgram.unload();
@@ -828,6 +818,7 @@ void LLViewerShaderMgr::unloadShaders()
 	gAvatarEyeballProgram.unload();
 	gAvatarPickProgram.unload();
 	gHighlightProgram.unload();
+    gSkinnedHighlightProgram.unload();
 	gHighlightNormalProgram.unload();
 	gHighlightSpecularProgram.unload();
 
@@ -841,13 +832,13 @@ void LLViewerShaderMgr::unloadShaders()
 
 	gDeferredDiffuseProgram.unload();
 	gDeferredDiffuseAlphaMaskProgram.unload();
+    gDeferredSkinnedDiffuseAlphaMaskProgram.unload();
 	gDeferredNonIndexedDiffuseAlphaMaskProgram.unload();
 	gDeferredNonIndexedDiffuseAlphaMaskNoColorProgram.unload();
 	gDeferredNonIndexedDiffuseProgram.unload();
 	gDeferredSkinnedDiffuseProgram.unload();
 	gDeferredSkinnedBumpProgram.unload();
-	gDeferredSkinnedAlphaProgram.unload();
-
+	
 	gTransformPositionProgram.unload();
 	gTransformTexCoordProgram.unload();
 	gTransformNormalProgram.unload();
@@ -864,10 +855,10 @@ void LLViewerShaderMgr::unloadShaders()
 	mShaderLevel[SHADER_WINDLIGHT] = 0;
 	mShaderLevel[SHADER_TRANSFORM] = 0;
 
-	gPipeline.mVertexShadersLoaded = 0;
+	gPipeline.mShadersLoaded = false;
 }
 
-BOOL LLViewerShaderMgr::loadBasicShaders()
+std::string LLViewerShaderMgr::loadBasicShaders()
 {
 	// Load basic dependency shaders first
 	// All of these have to load for any shaders to function
@@ -924,7 +915,7 @@ BOOL LLViewerShaderMgr::loadBasicShaders()
 	}
 	shaders.push_back( make_pair( "objects/nonindexedTextureV.glsl",        1 ) );
 
-	boost::unordered_map<std::string, std::string> attribs;
+	std::unordered_map<std::string, std::string> attribs;
 	attribs["MAX_JOINTS_PER_MESH_OBJECT"] = 
 		boost::lexical_cast<std::string>(LLSkinningUtil::getMaxJointCount());
 
@@ -953,8 +944,8 @@ BOOL LLViewerShaderMgr::loadBasicShaders()
 		// Note usage of GL_VERTEX_SHADER_ARB
 		if (loadShaderFile(shaders[i].first, shaders[i].second, GL_VERTEX_SHADER_ARB, &attribs) == 0)
 		{
-			LL_SHADER_LOADING_WARNS() << "Failed to load vertex shader " << shaders[i].first << LL_ENDL;
-			return FALSE;
+			LL_WARNS("Shader") << "Failed to load vertex shader " << shaders[i].first << LL_ENDL;
+			return shaders[i].first;
 		}
 	}
 
@@ -1013,12 +1004,12 @@ BOOL LLViewerShaderMgr::loadBasicShaders()
 		// Note usage of GL_FRAGMENT_SHADER_ARB
 		if (loadShaderFile(shaders[i].first, shaders[i].second, GL_FRAGMENT_SHADER_ARB, &attribs, index_channels[i]) == 0)
 		{
-			LL_SHADER_LOADING_WARNS() << "Failed to load fragment shader " << shaders[i].first << LL_ENDL;
-			return FALSE;
+			LL_WARNS("Shader") << "Failed to load fragment shader " << shaders[i].first << LL_ENDL;
+			return shaders[i].first;
 		}
 	}
 
-	return TRUE;
+	return std::string();
 }
 
 BOOL LLViewerShaderMgr::loadShadersEnvironment()
@@ -1236,14 +1227,15 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 	{
 		gDeferredTreeProgram.unload();
 		gDeferredTreeShadowProgram.unload();
+        gDeferredSkinnedTreeShadowProgram.unload();
 		gDeferredDiffuseProgram.unload();
 		gDeferredDiffuseAlphaMaskProgram.unload();
+        gDeferredSkinnedDiffuseAlphaMaskProgram.unload();
 		gDeferredNonIndexedDiffuseAlphaMaskProgram.unload();
 		gDeferredNonIndexedDiffuseAlphaMaskNoColorProgram.unload();
 		gDeferredNonIndexedDiffuseProgram.unload();
 		gDeferredSkinnedDiffuseProgram.unload();
 		gDeferredSkinnedBumpProgram.unload();
-		gDeferredSkinnedAlphaProgram.unload();
 		gDeferredBumpProgram.unload();
 		gDeferredImpostorProgram.unload();
 		gDeferredTerrainProgram.unload();
@@ -1260,9 +1252,12 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		gDeferredSoftenProgram.unload();
 		gDeferredSoftenWaterProgram.unload();
 		gDeferredShadowProgram.unload();
+        gDeferredSkinnedShadowProgram.unload();
 		gDeferredShadowCubeProgram.unload();
         gDeferredShadowAlphaMaskProgram.unload();
+        gDeferredSkinnedShadowAlphaMaskProgram.unload();
         gDeferredShadowFullbrightAlphaMaskProgram.unload();
+        gDeferredSkinnedShadowFullbrightAlphaMaskProgram.unload();
 		gDeferredAvatarShadowProgram.unload();
         gDeferredAvatarAlphaShadowProgram.unload();
         gDeferredAvatarAlphaMaskShadowProgram.unload();
@@ -1272,12 +1267,17 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		gDeferredAvatarProgram.unload();
 		gDeferredAvatarAlphaProgram.unload();
 		gDeferredAlphaProgram.unload();
+        gDeferredSkinnedAlphaProgram.unload();
 		gDeferredAlphaWaterProgram.unload();
+        gDeferredSkinnedAlphaWaterProgram.unload();
 		gDeferredFullbrightProgram.unload();
 		gDeferredFullbrightAlphaMaskProgram.unload();
 		gDeferredFullbrightWaterProgram.unload();
+        gDeferredSkinnedFullbrightWaterProgram.unload();
 		gDeferredFullbrightAlphaMaskWaterProgram.unload();
+        gDeferredSkinnedFullbrightAlphaMaskWaterProgram.unload();
 		gDeferredEmissiveProgram.unload();
+        gDeferredSkinnedEmissiveProgram.unload();
 		gDeferredAvatarEyesProgram.unload();
 		gDeferredPostProgram.unload();		
 		gDeferredCoFProgram.unload();		
@@ -1292,8 +1292,9 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
         gDeferredWLMoonProgram.unload();
 		gDeferredStarProgram.unload();
 		gDeferredFullbrightShinyProgram.unload();
-		gDeferredSkinnedFullbrightShinyProgram.unload();
+        gDeferredSkinnedFullbrightShinyProgram.unload();
 		gDeferredSkinnedFullbrightProgram.unload();
+        gDeferredSkinnedFullbrightAlphaMaskProgram.unload();
 
         gDeferredHighlightProgram.unload();
         gDeferredHighlightNormalProgram.unload();
@@ -1350,7 +1351,8 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		gDeferredDiffuseProgram.mShaderFiles.push_back(make_pair("deferred/diffuseIndexedF.glsl", GL_FRAGMENT_SHADER_ARB));
 		gDeferredDiffuseProgram.mFeatures.mIndexedTextureChannels = LLGLSLShader::sIndexedTextureChannels;
 		gDeferredDiffuseProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED];
-		success = gDeferredDiffuseProgram.createShader(NULL, NULL);
+        success = make_rigged_variant(gDeferredDiffuseProgram, gDeferredSkinnedDiffuseProgram);
+		success = success && gDeferredDiffuseProgram.createShader(NULL, NULL);
 	}
 
 	if (success)
@@ -1362,7 +1364,8 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		gDeferredDiffuseAlphaMaskProgram.mShaderFiles.push_back(make_pair("deferred/diffuseAlphaMaskIndexedF.glsl", GL_FRAGMENT_SHADER_ARB));
 		gDeferredDiffuseAlphaMaskProgram.mFeatures.mIndexedTextureChannels = LLGLSLShader::sIndexedTextureChannels;
 		gDeferredDiffuseAlphaMaskProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED];
-		success = gDeferredDiffuseAlphaMaskProgram.createShader(NULL, NULL);
+        success = make_rigged_variant(gDeferredDiffuseAlphaMaskProgram, gDeferredSkinnedDiffuseAlphaMaskProgram);
+		success = success && gDeferredDiffuseAlphaMaskProgram.createShader(NULL, NULL);
 	}
 
 	if (success)
@@ -1402,87 +1405,6 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
         llassert(success);
 	}
 
-	if (success)
-	{
-		gDeferredSkinnedDiffuseProgram.mName = "Deferred Skinned Diffuse Shader";
-		gDeferredSkinnedDiffuseProgram.mFeatures.hasObjectSkinning = true;
-		gDeferredSkinnedDiffuseProgram.mFeatures.encodesNormal = true;
-        gDeferredSkinnedDiffuseProgram.mFeatures.hasSrgb = true;
-		gDeferredSkinnedDiffuseProgram.mShaderFiles.clear();
-		gDeferredSkinnedDiffuseProgram.mShaderFiles.push_back(make_pair("deferred/diffuseSkinnedV.glsl", GL_VERTEX_SHADER_ARB));
-		gDeferredSkinnedDiffuseProgram.mShaderFiles.push_back(make_pair("deferred/diffuseF.glsl", GL_FRAGMENT_SHADER_ARB));
-		gDeferredSkinnedDiffuseProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED];
-		success = gDeferredSkinnedDiffuseProgram.createShader(NULL, NULL);
-		llassert(success);
-	}
-
-	if (success)
-	{
-		gDeferredSkinnedBumpProgram.mName = "Deferred Skinned Bump Shader";
-		gDeferredSkinnedBumpProgram.mFeatures.hasObjectSkinning = true;
-        gDeferredSkinnedBumpProgram.mFeatures.encodesNormal = true;
-		gDeferredSkinnedBumpProgram.mShaderFiles.clear();
-		gDeferredSkinnedBumpProgram.mShaderFiles.push_back(make_pair("deferred/bumpSkinnedV.glsl", GL_VERTEX_SHADER_ARB));
-		gDeferredSkinnedBumpProgram.mShaderFiles.push_back(make_pair("deferred/bumpF.glsl", GL_FRAGMENT_SHADER_ARB));
-		gDeferredSkinnedBumpProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED];
-		success = gDeferredSkinnedBumpProgram.createShader(NULL, NULL);
-        llassert(success);
-	}
-
-	if (success)
-	{
-		gDeferredSkinnedAlphaProgram.mName = "Deferred Skinned Alpha Shader";
-		gDeferredSkinnedAlphaProgram.mFeatures.hasObjectSkinning = true;
-		gDeferredSkinnedAlphaProgram.mFeatures.calculatesLighting = false;
-		gDeferredSkinnedAlphaProgram.mFeatures.hasLighting = false;
-		gDeferredSkinnedAlphaProgram.mFeatures.isAlphaLighting = true;
-		gDeferredSkinnedAlphaProgram.mFeatures.disableTextureIndex = true;
-		gDeferredSkinnedAlphaProgram.mFeatures.hasSrgb = true;
-		gDeferredSkinnedAlphaProgram.mFeatures.encodesNormal = true;
-		gDeferredSkinnedAlphaProgram.mFeatures.calculatesAtmospherics = true;
-		gDeferredSkinnedAlphaProgram.mFeatures.hasAtmospherics = true;
-		gDeferredSkinnedAlphaProgram.mFeatures.hasTransport = true;
-		gDeferredSkinnedAlphaProgram.mFeatures.hasGamma = true;
-		gDeferredSkinnedAlphaProgram.mFeatures.hasShadows = true;
-        
-		gDeferredSkinnedAlphaProgram.mShaderFiles.clear();
-		gDeferredSkinnedAlphaProgram.mShaderFiles.push_back(make_pair("deferred/alphaV.glsl", GL_VERTEX_SHADER_ARB));
-		gDeferredSkinnedAlphaProgram.mShaderFiles.push_back(make_pair("deferred/alphaF.glsl", GL_FRAGMENT_SHADER_ARB));
-		gDeferredSkinnedAlphaProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED];
-
-		gDeferredSkinnedAlphaProgram.clearPermutations();
-		gDeferredSkinnedAlphaProgram.addPermutation("USE_DIFFUSE_TEX", "1");
-		gDeferredSkinnedAlphaProgram.addPermutation("HAS_SKIN", "1");
-        gDeferredSkinnedAlphaProgram.addPermutation("USE_VERTEX_COLOR", "1");
-
-		if (use_sun_shadow)
-		{
-			gDeferredSkinnedAlphaProgram.addPermutation("HAS_SHADOW", "1");
-		}
-
-        if (ambient_kill)
-        {
-            gDeferredSkinnedAlphaProgram.addPermutation("AMBIENT_KILL", "1");
-        }
-
-        if (sunlight_kill)
-        {
-            gDeferredSkinnedAlphaProgram.addPermutation("SUNLIGHT_KILL", "1");
-        }
-
-        if (local_light_kill)
-        {
-            gDeferredSkinnedAlphaProgram.addPermutation("LOCAL_LIGHT_KILL", "1");
-        }
-
-		success = gDeferredSkinnedAlphaProgram.createShader(NULL, NULL);
-		llassert(success);
-
-		// Hack to include uniforms for lighting without linking in lighting file
-		gDeferredSkinnedAlphaProgram.mFeatures.calculatesLighting = true;
-		gDeferredSkinnedAlphaProgram.mFeatures.hasLighting = true;
-	}
-
 	if (success)
 	{
 		gDeferredBumpProgram.mName = "Deferred Bump Shader";
@@ -1491,7 +1413,8 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		gDeferredBumpProgram.mShaderFiles.push_back(make_pair("deferred/bumpV.glsl", GL_VERTEX_SHADER_ARB));
 		gDeferredBumpProgram.mShaderFiles.push_back(make_pair("deferred/bumpF.glsl", GL_FRAGMENT_SHADER_ARB));
 		gDeferredBumpProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED];
-		success = gDeferredBumpProgram.createShader(NULL, NULL);
+        success = make_rigged_variant(gDeferredBumpProgram, gDeferredSkinnedBumpProgram);
+		success = success && gDeferredBumpProgram.createShader(NULL, NULL);
 		llassert(success);
 	}
 
@@ -1560,6 +1483,12 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 
             gDeferredMaterialProgram[i].addPermutation("DIFFUSE_ALPHA_MODE", llformat("%d", alpha_mode));
 
+            if (alpha_mode != 0)
+            {
+                gDeferredMaterialProgram[i].mFeatures.hasAlphaMask = true;
+                gDeferredMaterialProgram[i].addPermutation("HAS_ALPHA_MASK", "1");
+            }
+
             if (use_sun_shadow)
             {
                 gDeferredMaterialProgram[i].addPermutation("HAS_SUN_SHADOW", "1");
@@ -1579,6 +1508,10 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
                 gDeferredMaterialProgram[i].addPermutation("HAS_SKIN", "1");
                 gDeferredMaterialProgram[i].mFeatures.hasObjectSkinning = true;
             }
+            else
+            {
+                gDeferredMaterialProgram[i].mRiggedVariant = &gDeferredMaterialProgram[i + 0x10];
+            }
 
             success = gDeferredMaterialProgram[i].createShader(NULL, NULL);
             llassert(success);
@@ -1614,6 +1547,12 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
             }
 
             gDeferredMaterialWaterProgram[i].addPermutation("DIFFUSE_ALPHA_MODE", llformat("%d", alpha_mode));
+            if (alpha_mode != 0)
+            {
+                gDeferredMaterialWaterProgram[i].mFeatures.hasAlphaMask = true;
+                gDeferredMaterialWaterProgram[i].addPermutation("HAS_ALPHA_MASK", "1");
+            }
+
             if (use_sun_shadow)
             {
                 gDeferredMaterialWaterProgram[i].addPermutation("HAS_SUN_SHADOW", "1");
@@ -1624,6 +1563,10 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
             {
                 gDeferredMaterialWaterProgram[i].addPermutation("HAS_SKIN", "1");
             }
+            else
+            {
+                gDeferredMaterialWaterProgram[i].mRiggedVariant = &(gDeferredMaterialWaterProgram[i + 0x10]);
+            }
             gDeferredMaterialWaterProgram[i].addPermutation("WATER_FOG","1");
 
             if (ambient_kill)
@@ -1700,10 +1643,25 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		gDeferredTreeShadowProgram.mShaderFiles.push_back(make_pair("deferred/treeShadowV.glsl", GL_VERTEX_SHADER_ARB));
 		gDeferredTreeShadowProgram.mShaderFiles.push_back(make_pair("deferred/treeShadowF.glsl", GL_FRAGMENT_SHADER_ARB));
 		gDeferredTreeShadowProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED];
+        gDeferredTreeShadowProgram.mRiggedVariant = &gDeferredSkinnedTreeShadowProgram;
 		success = gDeferredTreeShadowProgram.createShader(NULL, NULL);
         llassert(success);
 	}
 
+    if (success)
+    {
+        gDeferredSkinnedTreeShadowProgram.mName = "Deferred Skinned Tree Shadow Shader";
+        gDeferredSkinnedTreeShadowProgram.mShaderFiles.clear();
+        gDeferredSkinnedTreeShadowProgram.mFeatures.isDeferred = true;
+        gDeferredSkinnedTreeShadowProgram.mFeatures.hasShadows = true;
+        gDeferredSkinnedTreeShadowProgram.mFeatures.hasObjectSkinning = true;
+        gDeferredSkinnedTreeShadowProgram.mShaderFiles.push_back(make_pair("deferred/treeShadowSkinnedV.glsl", GL_VERTEX_SHADER_ARB));
+        gDeferredSkinnedTreeShadowProgram.mShaderFiles.push_back(make_pair("deferred/treeShadowF.glsl", GL_FRAGMENT_SHADER_ARB));
+        gDeferredSkinnedTreeShadowProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED];
+        success = gDeferredSkinnedTreeShadowProgram.createShader(NULL, NULL);
+        llassert(success);
+    }
+
 	if (success)
 	{
 		gDeferredImpostorProgram.mName = "Deferred Impostor Shader";
@@ -1892,172 +1850,238 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 
 	if (success)
 	{
-		gDeferredAlphaProgram.mName = "Deferred Alpha Shader";
-
-		gDeferredAlphaProgram.mFeatures.calculatesLighting = false;
-		gDeferredAlphaProgram.mFeatures.hasLighting = false;
-		gDeferredAlphaProgram.mFeatures.isAlphaLighting = true;
-		gDeferredAlphaProgram.mFeatures.disableTextureIndex = true; //hack to disable auto-setup of texture channels
-		gDeferredAlphaProgram.mFeatures.hasSrgb = true;
-		gDeferredAlphaProgram.mFeatures.encodesNormal = true;
-		gDeferredAlphaProgram.mFeatures.calculatesAtmospherics = true;
-        gDeferredAlphaProgram.mFeatures.hasAtmospherics = true;
-        gDeferredAlphaProgram.mFeatures.hasGamma = true;
-        gDeferredAlphaProgram.mFeatures.hasTransport = true;
-        gDeferredAlphaProgram.mFeatures.hasShadows = use_sun_shadow;
-
-        if (mShaderLevel[SHADER_DEFERRED] < 1)
+        for (int i = 0; i < 2 && success; ++i)
         {
-            gDeferredAlphaProgram.mFeatures.mIndexedTextureChannels = LLGLSLShader::sIndexedTextureChannels;
-        }
-        else
-        { //shave off some texture units for shadow maps
-            gDeferredAlphaProgram.mFeatures.mIndexedTextureChannels = llmax(LLGLSLShader::sIndexedTextureChannels - 6, 1);
-        }
-            
-        gDeferredAlphaProgram.mShaderFiles.clear();
-        gDeferredAlphaProgram.mShaderFiles.push_back(make_pair("deferred/alphaV.glsl", GL_VERTEX_SHADER_ARB));
-        gDeferredAlphaProgram.mShaderFiles.push_back(make_pair("deferred/alphaF.glsl", GL_FRAGMENT_SHADER_ARB));
-
-        gDeferredAlphaProgram.clearPermutations();
-        gDeferredAlphaProgram.addPermutation("USE_VERTEX_COLOR", "1");
-        gDeferredAlphaProgram.addPermutation("USE_INDEXED_TEX", "1");
-        if (use_sun_shadow)
-        {
-            gDeferredAlphaProgram.addPermutation("HAS_SHADOW", "1");
-        }
+            LLGLSLShader* shader = nullptr;
+            bool rigged = i == 1;
+            if (!rigged)
+            {
+                shader = &gDeferredAlphaProgram;
+                shader->mName = "Deferred Alpha Shader";
+                shader->mRiggedVariant = &gDeferredSkinnedAlphaProgram;
+            }
+            else
+            {
+                shader = &gDeferredSkinnedAlphaProgram;
+                shader->mName = "Skinned Deferred Alpha Shader";
+                shader->mFeatures.hasObjectSkinning = true;
+            }
 
-        if (ambient_kill)
-        {
-            gDeferredAlphaProgram.addPermutation("AMBIENT_KILL", "1");
-        }
+            shader->mFeatures.calculatesLighting = false;
+            shader->mFeatures.hasLighting = false;
+            shader->mFeatures.isAlphaLighting = true;
+            shader->mFeatures.disableTextureIndex = true; //hack to disable auto-setup of texture channels
+            shader->mFeatures.hasSrgb = true;
+            shader->mFeatures.encodesNormal = true;
+            shader->mFeatures.calculatesAtmospherics = true;
+            shader->mFeatures.hasAtmospherics = true;
+            shader->mFeatures.hasGamma = true;
+            shader->mFeatures.hasTransport = true;
+            shader->mFeatures.hasShadows = use_sun_shadow;
+
+            if (mShaderLevel[SHADER_DEFERRED] < 1)
+            {
+                shader->mFeatures.mIndexedTextureChannels = LLGLSLShader::sIndexedTextureChannels;
+            }
+            else
+            { //shave off some texture units for shadow maps
+                shader->mFeatures.mIndexedTextureChannels = llmax(LLGLSLShader::sIndexedTextureChannels - 6, 1);
+            }
 
-        if (sunlight_kill)
-        {
-            gDeferredAlphaProgram.addPermutation("SUNLIGHT_KILL", "1");
-        }
+            shader->mShaderFiles.clear();
+            shader->mShaderFiles.push_back(make_pair("deferred/alphaV.glsl", GL_VERTEX_SHADER_ARB));
+            shader->mShaderFiles.push_back(make_pair("deferred/alphaF.glsl", GL_FRAGMENT_SHADER_ARB));
 
-        if (local_light_kill)
-        {
-            gDeferredAlphaProgram.addPermutation("LOCAL_LIGHT_KILL", "1");
-        }
+            shader->clearPermutations();
+            shader->addPermutation("USE_VERTEX_COLOR", "1");
+            shader->addPermutation("HAS_ALPHA_MASK", "1");
+            shader->addPermutation("USE_INDEXED_TEX", "1");
+            if (use_sun_shadow)
+            {
+                shader->addPermutation("HAS_SHADOW", "1");
+            }
 
-        gDeferredAlphaProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED];
+            if (ambient_kill)
+            {
+                shader->addPermutation("AMBIENT_KILL", "1");
+            }
 
-        success = gDeferredAlphaProgram.createShader(NULL, NULL);
-        llassert(success);
+            if (sunlight_kill)
+            {
+                shader->addPermutation("SUNLIGHT_KILL", "1");
+            }
+
+            if (local_light_kill)
+            {
+                shader->addPermutation("LOCAL_LIGHT_KILL", "1");
+            }
+
+            if (rigged)
+            {
+                shader->addPermutation("HAS_SKIN", "1");
+            }
+
+            shader->mShaderLevel = mShaderLevel[SHADER_DEFERRED];
+
+            success = shader->createShader(NULL, NULL);
+            llassert(success);
 
-        // Hack
-        gDeferredAlphaProgram.mFeatures.calculatesLighting = true;
-        gDeferredAlphaProgram.mFeatures.hasLighting = true;
+            // Hack
+            shader->mFeatures.calculatesLighting = true;
+            shader->mFeatures.hasLighting = true;
+        }
     }
 
     if (success)
     {
-        gDeferredAlphaImpostorProgram.mName = "Deferred Alpha Impostor Shader";
+        LLGLSLShader* shaders[] = { 
+            &gDeferredAlphaImpostorProgram, 
+            &gDeferredSkinnedAlphaImpostorProgram 
+        };
 
-// Begin Hack
-		gDeferredAlphaImpostorProgram.mFeatures.calculatesLighting = false;
-		gDeferredAlphaImpostorProgram.mFeatures.hasLighting = false;
+        for (int i = 0; i < 2 && success; ++i)
+        {
+            bool rigged = i == 1;
+            LLGLSLShader* shader = shaders[i];
 
-        gDeferredAlphaImpostorProgram.mFeatures.hasSrgb = true;
-		gDeferredAlphaImpostorProgram.mFeatures.isAlphaLighting = true;
-        gDeferredAlphaImpostorProgram.mFeatures.encodesNormal = true;
-        gDeferredAlphaImpostorProgram.mFeatures.hasShadows = use_sun_shadow;
+            shader->mName = rigged ? "Skinned Deferred Alpha Impostor Shader" : "Deferred Alpha Impostor Shader";
 
-        if (mShaderLevel[SHADER_DEFERRED] < 1)
-        {
-            gDeferredAlphaImpostorProgram.mFeatures.mIndexedTextureChannels = LLGLSLShader::sIndexedTextureChannels;
-        }
-        else
-        { //shave off some texture units for shadow maps
-            gDeferredAlphaImpostorProgram.mFeatures.mIndexedTextureChannels = llmax(LLGLSLShader::sIndexedTextureChannels - 6, 1);
-        }
+            // Begin Hack
+            shader->mFeatures.calculatesLighting = false;
+            shader->mFeatures.hasLighting = false;
 
-        gDeferredAlphaImpostorProgram.mShaderFiles.clear();
-        gDeferredAlphaImpostorProgram.mShaderFiles.push_back(make_pair("deferred/alphaV.glsl", GL_VERTEX_SHADER_ARB));
-        gDeferredAlphaImpostorProgram.mShaderFiles.push_back(make_pair("deferred/alphaF.glsl", GL_FRAGMENT_SHADER_ARB));
+            shader->mFeatures.hasSrgb = true;
+            shader->mFeatures.isAlphaLighting = true;
+            shader->mFeatures.encodesNormal = true;
+            shader->mFeatures.hasShadows = use_sun_shadow;
 
-        gDeferredAlphaImpostorProgram.clearPermutations();
-        gDeferredAlphaImpostorProgram.addPermutation("USE_INDEXED_TEX", "1");
-        gDeferredAlphaImpostorProgram.addPermutation("FOR_IMPOSTOR", "1");
-        gDeferredAlphaImpostorProgram.addPermutation("USE_VERTEX_COLOR", "1");
+            if (mShaderLevel[SHADER_DEFERRED] < 1)
+            {
+                shader->mFeatures.mIndexedTextureChannels = LLGLSLShader::sIndexedTextureChannels;
+            }
+            else
+            { //shave off some texture units for shadow maps
+                shader->mFeatures.mIndexedTextureChannels = llmax(LLGLSLShader::sIndexedTextureChannels - 6, 1);
+            }
 
-        if (use_sun_shadow)
-        {
-            gDeferredAlphaImpostorProgram.addPermutation("HAS_SHADOW", "1");
-        }
+            shader->mShaderFiles.clear();
+            shader->mShaderFiles.push_back(make_pair("deferred/alphaV.glsl", GL_VERTEX_SHADER_ARB));
+            shader->mShaderFiles.push_back(make_pair("deferred/alphaF.glsl", GL_FRAGMENT_SHADER_ARB));
+
+            shader->clearPermutations();
+            shader->addPermutation("USE_INDEXED_TEX", "1");
+            shader->addPermutation("FOR_IMPOSTOR", "1");
+            shader->addPermutation("HAS_ALPHA_MASK", "1");
+            shader->addPermutation("USE_VERTEX_COLOR", "1");
+            if (rigged)
+            {
+                shader->mFeatures.hasObjectSkinning = true;
+                shader->addPermutation("HAS_SKIN", "1");
+            }
 
-        gDeferredAlphaImpostorProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED];
+            if (use_sun_shadow)
+            {
+                shader->addPermutation("HAS_SHADOW", "1");
+            }
 
-        success = gDeferredAlphaImpostorProgram.createShader(NULL, NULL);
-        llassert(success);
+            shader->mRiggedVariant = &gDeferredSkinnedAlphaImpostorProgram;
+            shader->mShaderLevel = mShaderLevel[SHADER_DEFERRED];
+            if (!rigged)
+            {
+                shader->mRiggedVariant = shaders[1];
+            }
+            success = shader->createShader(NULL, NULL);
+            llassert(success);
 
-// End Hack
-        gDeferredAlphaImpostorProgram.mFeatures.calculatesLighting = true;
-        gDeferredAlphaImpostorProgram.mFeatures.hasLighting = true;
+            // End Hack
+            shader->mFeatures.calculatesLighting = true;
+            shader->mFeatures.hasLighting = true;
+        }
     }
 
-	if (success)
-	{
-		gDeferredAlphaWaterProgram.mName = "Deferred Alpha Underwater Shader";
-		gDeferredAlphaWaterProgram.mFeatures.calculatesLighting = false;
-		gDeferredAlphaWaterProgram.mFeatures.hasLighting = false;
-		gDeferredAlphaWaterProgram.mFeatures.isAlphaLighting = true;
-		gDeferredAlphaWaterProgram.mFeatures.disableTextureIndex = true; //hack to disable auto-setup of texture channels
-		gDeferredAlphaWaterProgram.mFeatures.hasWaterFog = true;
-		gDeferredAlphaWaterProgram.mFeatures.hasSrgb = true;
-		gDeferredAlphaWaterProgram.mFeatures.encodesNormal = true;
-		gDeferredAlphaWaterProgram.mFeatures.calculatesAtmospherics = true;
-		gDeferredAlphaWaterProgram.mFeatures.hasAtmospherics = true;
-		gDeferredAlphaWaterProgram.mFeatures.hasGamma = true;
-		gDeferredAlphaWaterProgram.mFeatures.hasTransport = true;
-		gDeferredAlphaWaterProgram.mFeatures.hasShadows = use_sun_shadow;
-
-		if (mShaderLevel[SHADER_DEFERRED] < 1)
-		{
-			gDeferredAlphaWaterProgram.mFeatures.mIndexedTextureChannels = LLGLSLShader::sIndexedTextureChannels;
-		}
-		else
-		{ //shave off some texture units for shadow maps
-			gDeferredAlphaWaterProgram.mFeatures.mIndexedTextureChannels = llmax(LLGLSLShader::sIndexedTextureChannels - 6, 1);
-		}
-		gDeferredAlphaWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER;
-		gDeferredAlphaWaterProgram.mShaderFiles.clear();
-		gDeferredAlphaWaterProgram.mShaderFiles.push_back(make_pair("deferred/alphaV.glsl", GL_VERTEX_SHADER_ARB));
-		gDeferredAlphaWaterProgram.mShaderFiles.push_back(make_pair("deferred/alphaF.glsl", GL_FRAGMENT_SHADER_ARB));
-
-		gDeferredAlphaWaterProgram.clearPermutations();
-		gDeferredAlphaWaterProgram.addPermutation("USE_INDEXED_TEX", "1");
-		gDeferredAlphaWaterProgram.addPermutation("WATER_FOG", "1");
-        gDeferredAlphaWaterProgram.addPermutation("USE_VERTEX_COLOR", "1");
-		if (use_sun_shadow)
-		{
-			gDeferredAlphaWaterProgram.addPermutation("HAS_SHADOW", "1");
-		}
+    if (success)
+    {
+        LLGLSLShader* shader[] = {
+            &gDeferredAlphaWaterProgram,
+            &gDeferredSkinnedAlphaWaterProgram
+        };
+        
+        gDeferredAlphaWaterProgram.mRiggedVariant = &gDeferredSkinnedAlphaWaterProgram;
+		
+        gDeferredAlphaWaterProgram.mName = "Deferred Alpha Underwater Shader";
+        gDeferredSkinnedAlphaWaterProgram.mName = "Deferred Skinned Alpha Underwater Shader";
 
-        if (ambient_kill)
+        for (int i = 0; i < 2 && success; ++i)
         {
-            gDeferredAlphaWaterProgram.addPermutation("AMBIENT_KILL", "1");
-        }
+            shader[i]->mFeatures.calculatesLighting = false;
+            shader[i]->mFeatures.hasLighting = false;
+            shader[i]->mFeatures.isAlphaLighting = true;
+            shader[i]->mFeatures.disableTextureIndex = true; //hack to disable auto-setup of texture channels
+            shader[i]->mFeatures.hasWaterFog = true;
+            shader[i]->mFeatures.hasSrgb = true;
+            shader[i]->mFeatures.encodesNormal = true;
+            shader[i]->mFeatures.calculatesAtmospherics = true;
+            shader[i]->mFeatures.hasAtmospherics = true;
+            shader[i]->mFeatures.hasGamma = true;
+            shader[i]->mFeatures.hasTransport = true;
+            shader[i]->mFeatures.hasShadows = use_sun_shadow;
+
+            if (mShaderLevel[SHADER_DEFERRED] < 1)
+            {
+                shader[i]->mFeatures.mIndexedTextureChannels = LLGLSLShader::sIndexedTextureChannels;
+            }
+            else
+            { //shave off some texture units for shadow maps
+                shader[i]->mFeatures.mIndexedTextureChannels = llmax(LLGLSLShader::sIndexedTextureChannels - 6, 1);
+            }
+            shader[i]->mShaderGroup = LLGLSLShader::SG_WATER;
+            shader[i]->mShaderFiles.clear();
+            shader[i]->mShaderFiles.push_back(make_pair("deferred/alphaV.glsl", GL_VERTEX_SHADER_ARB));
+            shader[i]->mShaderFiles.push_back(make_pair("deferred/alphaF.glsl", GL_FRAGMENT_SHADER_ARB));
+
+            shader[i]->clearPermutations();
+            shader[i]->addPermutation("USE_INDEXED_TEX", "1");
+            shader[i]->addPermutation("WATER_FOG", "1");
+            shader[i]->addPermutation("USE_VERTEX_COLOR", "1");
+            shader[i]->addPermutation("HAS_ALPHA_MASK", "1");
+            if (use_sun_shadow)
+            {
+                shader[i]->addPermutation("HAS_SHADOW", "1");
+            }
 
-        if (sunlight_kill)
-        {
-            gDeferredAlphaWaterProgram.addPermutation("SUNLIGHT_KILL", "1");
-        }
+            if (ambient_kill)
+            {
+                shader[i]->addPermutation("AMBIENT_KILL", "1");
+            }
 
-        if (local_light_kill)
-        {
-            gDeferredAlphaWaterProgram.addPermutation("LOCAL_LIGHT_KILL", "1");
-        }
-        gDeferredAlphaWaterProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED];
+            if (sunlight_kill)
+            {
+                shader[i]->addPermutation("SUNLIGHT_KILL", "1");
+            }
 
-		success = gDeferredAlphaWaterProgram.createShader(NULL, NULL);
-		llassert(success);
+            if (local_light_kill)
+            {
+                shader[i]->addPermutation("LOCAL_LIGHT_KILL", "1");
+            }
 
-		// Hack
-		gDeferredAlphaWaterProgram.mFeatures.calculatesLighting = true;
-		gDeferredAlphaWaterProgram.mFeatures.hasLighting = true;
+            if (i == 1)
+            { // rigged variant
+                shader[i]->mFeatures.hasObjectSkinning = true;
+                shader[i]->addPermutation("HAS_SKIN", "1");
+            }
+            else
+            {
+                shader[i]->mRiggedVariant = shader[1];
+            }
+            shader[i]->mShaderLevel = mShaderLevel[SHADER_DEFERRED];
+
+            success = shader[i]->createShader(NULL, NULL);
+            llassert(success);
+
+            // Hack
+            shader[i]->mFeatures.calculatesLighting = true;
+            shader[i]->mFeatures.hasLighting = true;
+        }
 	}
 
 	if (success)
@@ -2091,6 +2115,7 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		gDeferredFullbrightProgram.mShaderFiles.push_back(make_pair("deferred/fullbrightV.glsl", GL_VERTEX_SHADER_ARB));
 		gDeferredFullbrightProgram.mShaderFiles.push_back(make_pair("deferred/fullbrightF.glsl", GL_FRAGMENT_SHADER_ARB));
 		gDeferredFullbrightProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED];
+        success = make_rigged_variant(gDeferredFullbrightProgram, gDeferredSkinnedFullbrightProgram);
 		success = gDeferredFullbrightProgram.createShader(NULL, NULL);
 		llassert(success);
 	}
@@ -2108,7 +2133,8 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		gDeferredFullbrightAlphaMaskProgram.mShaderFiles.push_back(make_pair("deferred/fullbrightF.glsl", GL_FRAGMENT_SHADER_ARB));
 		gDeferredFullbrightAlphaMaskProgram.addPermutation("HAS_ALPHA_MASK","1");
 		gDeferredFullbrightAlphaMaskProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED];
-		success = gDeferredFullbrightAlphaMaskProgram.createShader(NULL, NULL);
+        success = make_rigged_variant(gDeferredFullbrightAlphaMaskProgram, gDeferredSkinnedFullbrightAlphaMaskProgram);
+		success = success && gDeferredFullbrightAlphaMaskProgram.createShader(NULL, NULL);
 		llassert(success);
 	}
 
@@ -2127,10 +2153,11 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		gDeferredFullbrightWaterProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED];
 		gDeferredFullbrightWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER;
 		gDeferredFullbrightWaterProgram.addPermutation("WATER_FOG","1");
-		success = gDeferredFullbrightWaterProgram.createShader(NULL, NULL);
+        success = make_rigged_variant(gDeferredFullbrightWaterProgram, gDeferredSkinnedFullbrightWaterProgram);
+		success = success && gDeferredFullbrightWaterProgram.createShader(NULL, NULL);
 		llassert(success);
 	}
-
+    
 	if (success)
 	{
 		gDeferredFullbrightAlphaMaskWaterProgram.mName = "Deferred Fullbright Underwater Alpha Masking Shader";
@@ -2147,7 +2174,8 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		gDeferredFullbrightAlphaMaskWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER;
 		gDeferredFullbrightAlphaMaskWaterProgram.addPermutation("HAS_ALPHA_MASK","1");
 		gDeferredFullbrightAlphaMaskWaterProgram.addPermutation("WATER_FOG","1");
-		success = gDeferredFullbrightAlphaMaskWaterProgram.createShader(NULL, NULL);
+        success = make_rigged_variant(gDeferredFullbrightAlphaMaskWaterProgram, gDeferredSkinnedFullbrightAlphaMaskWaterProgram);
+		success = success && gDeferredFullbrightAlphaMaskWaterProgram.createShader(NULL, NULL);
 		llassert(success);
 	}
 
@@ -2164,43 +2192,8 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		gDeferredFullbrightShinyProgram.mShaderFiles.push_back(make_pair("deferred/fullbrightShinyV.glsl", GL_VERTEX_SHADER_ARB));
 		gDeferredFullbrightShinyProgram.mShaderFiles.push_back(make_pair("deferred/fullbrightShinyF.glsl", GL_FRAGMENT_SHADER_ARB));
 		gDeferredFullbrightShinyProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED];
-		success = gDeferredFullbrightShinyProgram.createShader(NULL, NULL);
-		llassert(success);
-	}
-
-	if (success)
-	{
-		gDeferredSkinnedFullbrightProgram.mName = "Skinned Fullbright Shader";
-		gDeferredSkinnedFullbrightProgram.mFeatures.calculatesAtmospherics = true;
-		gDeferredSkinnedFullbrightProgram.mFeatures.hasAtmospherics = true;
-		gDeferredSkinnedFullbrightProgram.mFeatures.hasGamma = true;
-		gDeferredSkinnedFullbrightProgram.mFeatures.hasTransport = true;
-		gDeferredSkinnedFullbrightProgram.mFeatures.hasObjectSkinning = true;
-		gDeferredSkinnedFullbrightProgram.mFeatures.disableTextureIndex = true;
-		gDeferredSkinnedFullbrightProgram.mFeatures.hasSrgb = true;
-		gDeferredSkinnedFullbrightProgram.mShaderFiles.clear();
-		gDeferredSkinnedFullbrightProgram.mShaderFiles.push_back(make_pair("objects/fullbrightSkinnedV.glsl", GL_VERTEX_SHADER_ARB));
-		gDeferredSkinnedFullbrightProgram.mShaderFiles.push_back(make_pair("deferred/fullbrightF.glsl", GL_FRAGMENT_SHADER_ARB));
-		gDeferredSkinnedFullbrightProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT];
-		success = gDeferredSkinnedFullbrightProgram.createShader(NULL, NULL);
-		llassert(success);
-	}
-
-	if (success)
-	{
-		gDeferredSkinnedFullbrightShinyProgram.mName = "Skinned Fullbright Shiny Shader";
-		gDeferredSkinnedFullbrightShinyProgram.mFeatures.calculatesAtmospherics = true;
-        gDeferredSkinnedFullbrightShinyProgram.mFeatures.hasAtmospherics = true;
-		gDeferredSkinnedFullbrightShinyProgram.mFeatures.hasGamma = true;
-		gDeferredSkinnedFullbrightShinyProgram.mFeatures.hasTransport = true;
-		gDeferredSkinnedFullbrightShinyProgram.mFeatures.hasObjectSkinning = true;
-		gDeferredSkinnedFullbrightShinyProgram.mFeatures.disableTextureIndex = true;
-        gDeferredSkinnedFullbrightShinyProgram.mFeatures.hasSrgb = true;
-		gDeferredSkinnedFullbrightShinyProgram.mShaderFiles.clear();
-		gDeferredSkinnedFullbrightShinyProgram.mShaderFiles.push_back(make_pair("objects/fullbrightShinySkinnedV.glsl", GL_VERTEX_SHADER_ARB));
-		gDeferredSkinnedFullbrightShinyProgram.mShaderFiles.push_back(make_pair("deferred/fullbrightShinyF.glsl", GL_FRAGMENT_SHADER_ARB));
-		gDeferredSkinnedFullbrightShinyProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT];
-		success = gDeferredSkinnedFullbrightShinyProgram.createShader(NULL, NULL);
+        success = make_rigged_variant(gDeferredFullbrightShinyProgram, gDeferredSkinnedFullbrightShinyProgram);
+		success = success && gDeferredFullbrightShinyProgram.createShader(NULL, NULL);
 		llassert(success);
 	}
 
@@ -2215,7 +2208,8 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		gDeferredEmissiveProgram.mShaderFiles.push_back(make_pair("deferred/emissiveV.glsl", GL_VERTEX_SHADER_ARB));
 		gDeferredEmissiveProgram.mShaderFiles.push_back(make_pair("deferred/emissiveF.glsl", GL_FRAGMENT_SHADER_ARB));
 		gDeferredEmissiveProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED];
-		success = gDeferredEmissiveProgram.createShader(NULL, NULL);
+        success = make_rigged_variant(gDeferredEmissiveProgram, gDeferredSkinnedEmissiveProgram);
+		success = success && gDeferredEmissiveProgram.createShader(NULL, NULL);
 		llassert(success);
 	}
 
@@ -2358,10 +2352,29 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		{
 			gDeferredShadowProgram.addPermutation("DEPTH_CLAMP", "1");
 		}
+        gDeferredShadowProgram.mRiggedVariant = &gDeferredSkinnedShadowProgram;
 		success = gDeferredShadowProgram.createShader(NULL, NULL);
 		llassert(success);
 	}
 
+    if (success)
+    {
+        gDeferredSkinnedShadowProgram.mName = "Deferred Skinned Shadow Shader";
+        gDeferredSkinnedShadowProgram.mFeatures.isDeferred = true;
+        gDeferredSkinnedShadowProgram.mFeatures.hasShadows = true;
+        gDeferredSkinnedShadowProgram.mFeatures.hasObjectSkinning = true;
+        gDeferredSkinnedShadowProgram.mShaderFiles.clear();
+        gDeferredSkinnedShadowProgram.mShaderFiles.push_back(make_pair("deferred/shadowSkinnedV.glsl", GL_VERTEX_SHADER_ARB));
+        gDeferredSkinnedShadowProgram.mShaderFiles.push_back(make_pair("deferred/shadowF.glsl", GL_FRAGMENT_SHADER_ARB));
+        gDeferredSkinnedShadowProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED];
+        if (gGLManager.mHasDepthClamp)
+        {
+            gDeferredSkinnedShadowProgram.addPermutation("DEPTH_CLAMP", "1");
+        }
+        success = gDeferredSkinnedShadowProgram.createShader(NULL, NULL);
+        llassert(success);
+    }
+
 	if (success)
 	{
 		gDeferredShadowCubeProgram.mName = "Deferred Shadow Cube Shader";
@@ -2395,10 +2408,31 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		}
         gDeferredShadowFullbrightAlphaMaskProgram.addPermutation("IS_FULLBRIGHT", "1");
 		gDeferredShadowFullbrightAlphaMaskProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED];
+        gDeferredShadowFullbrightAlphaMaskProgram.mRiggedVariant = &gDeferredSkinnedShadowFullbrightAlphaMaskProgram;
 		success = gDeferredShadowFullbrightAlphaMaskProgram.createShader(NULL, NULL);
 		llassert(success);
 	}
     
+    if (success)
+    {
+        gDeferredSkinnedShadowFullbrightAlphaMaskProgram.mName = "Deferred Skinned Shadow Fullbright Alpha Mask Shader";
+        gDeferredSkinnedShadowFullbrightAlphaMaskProgram.mFeatures.mIndexedTextureChannels = LLGLSLShader::sIndexedTextureChannels;
+        gDeferredSkinnedShadowFullbrightAlphaMaskProgram.mFeatures.hasObjectSkinning = true;
+        gDeferredSkinnedShadowFullbrightAlphaMaskProgram.mShaderFiles.clear();
+        gDeferredSkinnedShadowFullbrightAlphaMaskProgram.mShaderFiles.push_back(make_pair("deferred/shadowAlphaMaskSkinnedV.glsl", GL_VERTEX_SHADER_ARB));
+        gDeferredSkinnedShadowFullbrightAlphaMaskProgram.mShaderFiles.push_back(make_pair("deferred/shadowAlphaMaskF.glsl", GL_FRAGMENT_SHADER_ARB));
+
+        gDeferredSkinnedShadowFullbrightAlphaMaskProgram.clearPermutations();
+        if (gGLManager.mHasDepthClamp)
+        {
+            gDeferredSkinnedShadowFullbrightAlphaMaskProgram.addPermutation("DEPTH_CLAMP", "1");
+        }
+        gDeferredSkinnedShadowFullbrightAlphaMaskProgram.addPermutation("IS_FULLBRIGHT", "1");
+        gDeferredSkinnedShadowFullbrightAlphaMaskProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED];
+        success = gDeferredSkinnedShadowFullbrightAlphaMaskProgram.createShader(NULL, NULL);
+        llassert(success);
+    }
+
     if (success)
 	{
 		gDeferredShadowAlphaMaskProgram.mName = "Deferred Shadow Alpha Mask Shader";
@@ -2412,10 +2446,28 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 			gDeferredShadowAlphaMaskProgram.addPermutation("DEPTH_CLAMP", "1");
 		}
 		gDeferredShadowAlphaMaskProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED];
+        gDeferredShadowAlphaMaskProgram.mRiggedVariant = &gDeferredSkinnedShadowAlphaMaskProgram;
 		success = gDeferredShadowAlphaMaskProgram.createShader(NULL, NULL);
 		llassert(success);
 	}
 
+    if (success)
+    {
+        gDeferredSkinnedShadowAlphaMaskProgram.mName = "Deferred Skinned Shadow Alpha Mask Shader";
+        gDeferredSkinnedShadowAlphaMaskProgram.mFeatures.mIndexedTextureChannels = LLGLSLShader::sIndexedTextureChannels;
+        gDeferredSkinnedShadowAlphaMaskProgram.mFeatures.hasObjectSkinning = true;
+        gDeferredSkinnedShadowAlphaMaskProgram.mShaderFiles.clear();
+        gDeferredSkinnedShadowAlphaMaskProgram.mShaderFiles.push_back(make_pair("deferred/shadowAlphaMaskSkinnedV.glsl", GL_VERTEX_SHADER_ARB));
+        gDeferredSkinnedShadowAlphaMaskProgram.mShaderFiles.push_back(make_pair("deferred/shadowAlphaMaskF.glsl", GL_FRAGMENT_SHADER_ARB));
+        if (gGLManager.mHasDepthClamp)
+        {
+            gDeferredSkinnedShadowAlphaMaskProgram.addPermutation("DEPTH_CLAMP", "1");
+        }
+        gDeferredSkinnedShadowAlphaMaskProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED];
+        success = gDeferredSkinnedShadowAlphaMaskProgram.createShader(NULL, NULL);
+        llassert(success);
+    }
+
 	if (success)
 	{
 		gDeferredAvatarShadowProgram.mName = "Deferred Avatar Shadow Shader";
@@ -2791,77 +2843,7 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 BOOL LLViewerShaderMgr::loadShadersObject()
 {
 	BOOL success = TRUE;
-	
-	if (mShaderLevel[SHADER_OBJECT] == 0)
-	{
-		gObjectShinyProgram.unload();
-		gObjectFullbrightShinyProgram.unload();
-		gObjectFullbrightShinyWaterProgram.unload();
-		gObjectShinyWaterProgram.unload();
-		gObjectFullbrightNoColorProgram.unload();
-		gObjectFullbrightNoColorWaterProgram.unload();
-		gObjectSimpleProgram.unload();
-		gObjectSimpleImpostorProgram.unload();
-		gObjectPreviewProgram.unload();
-		gImpostorProgram.unload();
-		gObjectSimpleAlphaMaskProgram.unload();
-		gObjectBumpProgram.unload();
-		gObjectSimpleWaterProgram.unload();
-		gObjectSimpleWaterAlphaMaskProgram.unload();
-		gObjectEmissiveProgram.unload();
-		gObjectEmissiveWaterProgram.unload();
-		gObjectFullbrightProgram.unload();
-		gObjectFullbrightAlphaMaskProgram.unload();
-		gObjectFullbrightWaterProgram.unload();
-		gObjectFullbrightWaterAlphaMaskProgram.unload();
-		gObjectShinyNonIndexedProgram.unload();
-		gObjectFullbrightShinyNonIndexedProgram.unload();
-		gObjectFullbrightShinyNonIndexedWaterProgram.unload();
-		gObjectShinyNonIndexedWaterProgram.unload();
-		gObjectSimpleNonIndexedTexGenProgram.unload();
-		gObjectSimpleNonIndexedTexGenWaterProgram.unload();
-		gObjectSimpleNonIndexedWaterProgram.unload();
-		gObjectAlphaMaskNonIndexedProgram.unload();
-		gObjectAlphaMaskNonIndexedWaterProgram.unload();
-		gObjectAlphaMaskNoColorProgram.unload();
-		gObjectAlphaMaskNoColorWaterProgram.unload();
-		gObjectFullbrightNonIndexedProgram.unload();
-		gObjectFullbrightNonIndexedWaterProgram.unload();
-		gObjectEmissiveNonIndexedProgram.unload();
-		gObjectEmissiveNonIndexedWaterProgram.unload();
-		gSkinnedObjectSimpleProgram.unload();
-		gSkinnedObjectFullbrightProgram.unload();
-		gSkinnedObjectEmissiveProgram.unload();
-		gSkinnedObjectFullbrightShinyProgram.unload();
-		gSkinnedObjectShinySimpleProgram.unload();
-		gSkinnedObjectSimpleWaterProgram.unload();
-		gSkinnedObjectFullbrightWaterProgram.unload();
-		gSkinnedObjectEmissiveWaterProgram.unload();
-		gSkinnedObjectFullbrightShinyWaterProgram.unload();
-		gSkinnedObjectShinySimpleWaterProgram.unload();
-		gTreeProgram.unload();
-		gTreeWaterProgram.unload();
-	
-		return TRUE;
-	}
 
-	if (success)
-	{
-		gObjectSimpleNonIndexedProgram.mName = "Non indexed Shader";
-		gObjectSimpleNonIndexedProgram.mFeatures.calculatesLighting = true;
-		gObjectSimpleNonIndexedProgram.mFeatures.calculatesAtmospherics = true;
-		gObjectSimpleNonIndexedProgram.mFeatures.hasGamma = true;
-		gObjectSimpleNonIndexedProgram.mFeatures.hasAtmospherics = true;
-		gObjectSimpleNonIndexedProgram.mFeatures.hasLighting = true;
-        gObjectSimpleNonIndexedProgram.mFeatures.hasAlphaMask = true; // Fix for MAINT-8836
-		gObjectSimpleNonIndexedProgram.mFeatures.disableTextureIndex = true;
-		gObjectSimpleNonIndexedProgram.mShaderFiles.clear();
-		gObjectSimpleNonIndexedProgram.mShaderFiles.push_back(make_pair("objects/simpleV.glsl", GL_VERTEX_SHADER_ARB));
-		gObjectSimpleNonIndexedProgram.mShaderFiles.push_back(make_pair("objects/simpleF.glsl", GL_FRAGMENT_SHADER_ARB));
-		gObjectSimpleNonIndexedProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT];
-		success = gObjectSimpleNonIndexedProgram.createShader(NULL, NULL);
-	}
-	
 	if (success)
 	{
 		gObjectSimpleNonIndexedTexGenProgram.mName = "Non indexed tex-gen Shader";
@@ -2878,24 +2860,6 @@ BOOL LLViewerShaderMgr::loadShadersObject()
 		success = gObjectSimpleNonIndexedTexGenProgram.createShader(NULL, NULL);
 	}
 	
-
-	if (success)
-	{
-		gObjectSimpleNonIndexedWaterProgram.mName = "Non indexed Water Shader";
-		gObjectSimpleNonIndexedWaterProgram.mFeatures.calculatesLighting = true;
-		gObjectSimpleNonIndexedWaterProgram.mFeatures.calculatesAtmospherics = true;
-		gObjectSimpleNonIndexedWaterProgram.mFeatures.hasWaterFog = true;
-		gObjectSimpleNonIndexedWaterProgram.mFeatures.hasAtmospherics = true;
-		gObjectSimpleNonIndexedWaterProgram.mFeatures.hasLighting = true;
-		gObjectSimpleNonIndexedWaterProgram.mFeatures.disableTextureIndex = true;
-		gObjectSimpleNonIndexedWaterProgram.mShaderFiles.clear();
-		gObjectSimpleNonIndexedWaterProgram.mShaderFiles.push_back(make_pair("objects/simpleV.glsl", GL_VERTEX_SHADER_ARB));
-		gObjectSimpleNonIndexedWaterProgram.mShaderFiles.push_back(make_pair("objects/simpleWaterF.glsl", GL_FRAGMENT_SHADER_ARB));
-		gObjectSimpleNonIndexedWaterProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT];
-		gObjectSimpleNonIndexedWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER;
-		success = gObjectSimpleNonIndexedWaterProgram.createShader(NULL, NULL);
-	}
-
 	if (success)
 	{
 		gObjectSimpleNonIndexedTexGenWaterProgram.mName = "Non indexed tex-gen Water Shader";
@@ -3018,70 +2982,6 @@ BOOL LLViewerShaderMgr::loadShadersObject()
 		success = gTreeWaterProgram.createShader(NULL, NULL);
 	}
 
-	if (success)
-	{
-		gObjectFullbrightNonIndexedProgram.mName = "Non Indexed Fullbright Shader";
-		gObjectFullbrightNonIndexedProgram.mFeatures.calculatesAtmospherics = true;
-		gObjectFullbrightNonIndexedProgram.mFeatures.hasGamma = true;
-		gObjectFullbrightNonIndexedProgram.mFeatures.hasTransport = true;
-		gObjectFullbrightNonIndexedProgram.mFeatures.isFullbright = true;
-		gObjectFullbrightNonIndexedProgram.mFeatures.disableTextureIndex = true;
-		gObjectFullbrightNonIndexedProgram.mShaderFiles.clear();
-		gObjectFullbrightNonIndexedProgram.mShaderFiles.push_back(make_pair("objects/fullbrightV.glsl", GL_VERTEX_SHADER_ARB));
-		gObjectFullbrightNonIndexedProgram.mShaderFiles.push_back(make_pair("objects/fullbrightF.glsl", GL_FRAGMENT_SHADER_ARB));
-		gObjectFullbrightNonIndexedProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT];
-		success = gObjectFullbrightNonIndexedProgram.createShader(NULL, NULL);
-	}
-
-	if (success)
-	{
-		gObjectFullbrightNonIndexedWaterProgram.mName = "Non Indexed Fullbright Water Shader";
-		gObjectFullbrightNonIndexedWaterProgram.mFeatures.calculatesAtmospherics = true;
-		gObjectFullbrightNonIndexedWaterProgram.mFeatures.isFullbright = true;
-		gObjectFullbrightNonIndexedWaterProgram.mFeatures.hasWaterFog = true;		
-		gObjectFullbrightNonIndexedWaterProgram.mFeatures.hasTransport = true;
-		gObjectFullbrightNonIndexedWaterProgram.mFeatures.disableTextureIndex = true;
-		gObjectFullbrightNonIndexedWaterProgram.mFeatures.hasSrgb = true;
-		gObjectFullbrightNonIndexedWaterProgram.mShaderFiles.clear();
-		gObjectFullbrightNonIndexedWaterProgram.mShaderFiles.push_back(make_pair("objects/fullbrightV.glsl", GL_VERTEX_SHADER_ARB));
-		gObjectFullbrightNonIndexedWaterProgram.mShaderFiles.push_back(make_pair("objects/fullbrightWaterF.glsl", GL_FRAGMENT_SHADER_ARB));
-		gObjectFullbrightNonIndexedWaterProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT];
-		gObjectFullbrightNonIndexedWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER;
-		success = gObjectFullbrightNonIndexedWaterProgram.createShader(NULL, NULL);
-	}
-
-	if (success)
-	{
-		gObjectEmissiveNonIndexedProgram.mName = "Non Indexed Emissive Shader";
-		gObjectEmissiveNonIndexedProgram.mFeatures.calculatesAtmospherics = true;
-		gObjectEmissiveNonIndexedProgram.mFeatures.hasGamma = true;
-		gObjectEmissiveNonIndexedProgram.mFeatures.hasTransport = true;
-		gObjectEmissiveNonIndexedProgram.mFeatures.isFullbright = true;
-		gObjectEmissiveNonIndexedProgram.mFeatures.disableTextureIndex = true;
-		gObjectEmissiveNonIndexedProgram.mFeatures.hasSrgb = true;
-		gObjectEmissiveNonIndexedProgram.mShaderFiles.clear();
-		gObjectEmissiveNonIndexedProgram.mShaderFiles.push_back(make_pair("objects/emissiveV.glsl", GL_VERTEX_SHADER_ARB));
-		gObjectEmissiveNonIndexedProgram.mShaderFiles.push_back(make_pair("objects/fullbrightF.glsl", GL_FRAGMENT_SHADER_ARB));
-		gObjectEmissiveNonIndexedProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT];
-		success = gObjectEmissiveNonIndexedProgram.createShader(NULL, NULL);
-	}
-
-	if (success)
-	{
-		gObjectEmissiveNonIndexedWaterProgram.mName = "Non Indexed Emissive Water Shader";
-		gObjectEmissiveNonIndexedWaterProgram.mFeatures.calculatesAtmospherics = true;
-		gObjectEmissiveNonIndexedWaterProgram.mFeatures.isFullbright = true;
-		gObjectEmissiveNonIndexedWaterProgram.mFeatures.hasWaterFog = true;		
-		gObjectEmissiveNonIndexedWaterProgram.mFeatures.hasTransport = true;
-		gObjectEmissiveNonIndexedWaterProgram.mFeatures.disableTextureIndex = true;
-		gObjectEmissiveNonIndexedWaterProgram.mShaderFiles.clear();
-		gObjectEmissiveNonIndexedWaterProgram.mShaderFiles.push_back(make_pair("objects/emissiveV.glsl", GL_VERTEX_SHADER_ARB));
-		gObjectEmissiveNonIndexedWaterProgram.mShaderFiles.push_back(make_pair("objects/fullbrightWaterF.glsl", GL_FRAGMENT_SHADER_ARB));
-		gObjectEmissiveNonIndexedWaterProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT];
-		gObjectEmissiveNonIndexedWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER;
-		success = gObjectEmissiveNonIndexedWaterProgram.createShader(NULL, NULL);
-	}
-
 	if (success)
 	{
 		gObjectFullbrightNoColorProgram.mName = "Non Indexed no color Fullbright Shader";
@@ -3114,73 +3014,6 @@ BOOL LLViewerShaderMgr::loadShadersObject()
 		success = gObjectFullbrightNoColorWaterProgram.createShader(NULL, NULL);
 	}
 
-	if (success)
-	{
-		gObjectShinyNonIndexedProgram.mName = "Non Indexed Shiny Shader";
-		gObjectShinyNonIndexedProgram.mFeatures.calculatesAtmospherics = true;
-		gObjectShinyNonIndexedProgram.mFeatures.calculatesLighting = true;
-		gObjectShinyNonIndexedProgram.mFeatures.hasGamma = true;
-		gObjectShinyNonIndexedProgram.mFeatures.hasAtmospherics = true;
-		gObjectShinyNonIndexedProgram.mFeatures.isShiny = true;
-		gObjectShinyNonIndexedProgram.mFeatures.disableTextureIndex = true;
-		gObjectShinyNonIndexedProgram.mShaderFiles.clear();
-		gObjectShinyNonIndexedProgram.mShaderFiles.push_back(make_pair("objects/shinyV.glsl", GL_VERTEX_SHADER_ARB));
-		gObjectShinyNonIndexedProgram.mShaderFiles.push_back(make_pair("objects/shinyF.glsl", GL_FRAGMENT_SHADER_ARB));		
-		gObjectShinyNonIndexedProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT];
-		success = gObjectShinyNonIndexedProgram.createShader(NULL, NULL);
-	}
-
-	if (success)
-	{
-		gObjectShinyNonIndexedWaterProgram.mName = "Non Indexed Shiny Water Shader";
-		gObjectShinyNonIndexedWaterProgram.mFeatures.calculatesAtmospherics = true;
-		gObjectShinyNonIndexedWaterProgram.mFeatures.calculatesLighting = true;
-		gObjectShinyNonIndexedWaterProgram.mFeatures.isShiny = true;
-		gObjectShinyNonIndexedWaterProgram.mFeatures.hasWaterFog = true;
-		gObjectShinyNonIndexedWaterProgram.mFeatures.hasAtmospherics = true;
-		gObjectShinyNonIndexedWaterProgram.mFeatures.disableTextureIndex = true;
-		gObjectShinyNonIndexedWaterProgram.mShaderFiles.clear();
-		gObjectShinyNonIndexedWaterProgram.mShaderFiles.push_back(make_pair("objects/shinyWaterF.glsl", GL_FRAGMENT_SHADER_ARB));
-		gObjectShinyNonIndexedWaterProgram.mShaderFiles.push_back(make_pair("objects/shinyV.glsl", GL_VERTEX_SHADER_ARB));
-		gObjectShinyNonIndexedWaterProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT];
-		gObjectShinyNonIndexedWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER;
-		success = gObjectShinyNonIndexedWaterProgram.createShader(NULL, NULL);
-	}
-	
-    if (success)
-	{
-		gObjectFullbrightShinyNonIndexedProgram.mName = "Non Indexed Fullbright Shiny Shader";
-		gObjectFullbrightShinyNonIndexedProgram.mFeatures.calculatesAtmospherics = true;
-		gObjectFullbrightShinyNonIndexedProgram.mFeatures.isFullbright = true;
-		gObjectFullbrightShinyNonIndexedProgram.mFeatures.isShiny = true;
-		gObjectFullbrightShinyNonIndexedProgram.mFeatures.hasGamma = true;
-		gObjectFullbrightShinyNonIndexedProgram.mFeatures.hasTransport = true;
-		gObjectFullbrightShinyNonIndexedProgram.mFeatures.disableTextureIndex = true;
-		gObjectFullbrightShinyNonIndexedProgram.mShaderFiles.clear();
-		gObjectFullbrightShinyNonIndexedProgram.mShaderFiles.push_back(make_pair("objects/fullbrightShinyV.glsl", GL_VERTEX_SHADER_ARB));
-		gObjectFullbrightShinyNonIndexedProgram.mShaderFiles.push_back(make_pair("objects/fullbrightShinyF.glsl", GL_FRAGMENT_SHADER_ARB));
-		gObjectFullbrightShinyNonIndexedProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT];
-		success = gObjectFullbrightShinyNonIndexedProgram.createShader(NULL, NULL);
-	}
-
-	if (success)
-	{
-		gObjectFullbrightShinyNonIndexedWaterProgram.mName = "Non Indexed Fullbright Shiny Water Shader";
-		gObjectFullbrightShinyNonIndexedWaterProgram.mFeatures.calculatesAtmospherics = true;
-		gObjectFullbrightShinyNonIndexedWaterProgram.mFeatures.isFullbright = true;
-		gObjectFullbrightShinyNonIndexedWaterProgram.mFeatures.isShiny = true;
-		gObjectFullbrightShinyNonIndexedWaterProgram.mFeatures.hasGamma = true;
-		gObjectFullbrightShinyNonIndexedWaterProgram.mFeatures.hasTransport = true;
-		gObjectFullbrightShinyNonIndexedWaterProgram.mFeatures.hasWaterFog = true;
-		gObjectFullbrightShinyNonIndexedWaterProgram.mFeatures.disableTextureIndex = true;
-		gObjectFullbrightShinyNonIndexedWaterProgram.mShaderFiles.clear();
-		gObjectFullbrightShinyNonIndexedWaterProgram.mShaderFiles.push_back(make_pair("objects/fullbrightShinyV.glsl", GL_VERTEX_SHADER_ARB));
-		gObjectFullbrightShinyNonIndexedWaterProgram.mShaderFiles.push_back(make_pair("objects/fullbrightShinyWaterF.glsl", GL_FRAGMENT_SHADER_ARB));
-		gObjectFullbrightShinyNonIndexedWaterProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT];
-		gObjectFullbrightShinyNonIndexedWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER;
-		success = gObjectFullbrightShinyNonIndexedWaterProgram.createShader(NULL, NULL);
-	}
-
 	if (success)
 	{
 		gImpostorProgram.mName = "Impostor Shader";
@@ -3211,6 +3044,24 @@ BOOL LLViewerShaderMgr::loadShadersObject()
 		gObjectPreviewProgram.mFeatures.hasLighting = true;
 	}
 
+	if (success)
+	{
+		gPhysicsPreviewProgram.mName = "Preview Physics Shader";
+		gPhysicsPreviewProgram.mFeatures.calculatesLighting = false;
+		gPhysicsPreviewProgram.mFeatures.calculatesAtmospherics = false;
+		gPhysicsPreviewProgram.mFeatures.hasGamma = false;
+		gPhysicsPreviewProgram.mFeatures.hasAtmospherics = false;
+		gPhysicsPreviewProgram.mFeatures.hasLighting = false;
+		gPhysicsPreviewProgram.mFeatures.mIndexedTextureChannels = 0;
+		gPhysicsPreviewProgram.mFeatures.disableTextureIndex = true;
+		gPhysicsPreviewProgram.mShaderFiles.clear();
+		gPhysicsPreviewProgram.mShaderFiles.push_back(make_pair("objects/previewPhysicsV.glsl", GL_VERTEX_SHADER_ARB));
+		gPhysicsPreviewProgram.mShaderFiles.push_back(make_pair("objects/previewPhysicsF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gPhysicsPreviewProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT];
+		success = gPhysicsPreviewProgram.createShader(NULL, NULL);
+		gPhysicsPreviewProgram.mFeatures.hasLighting = false;
+	}
+
 	if (success)
 	{
 		gObjectSimpleProgram.mName = "Simple Shader";
@@ -3224,7 +3075,8 @@ BOOL LLViewerShaderMgr::loadShadersObject()
 		gObjectSimpleProgram.mShaderFiles.push_back(make_pair("objects/simpleV.glsl", GL_VERTEX_SHADER_ARB));
 		gObjectSimpleProgram.mShaderFiles.push_back(make_pair("objects/simpleF.glsl", GL_FRAGMENT_SHADER_ARB));
 		gObjectSimpleProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT];
-		success = gObjectSimpleProgram.createShader(NULL, NULL);
+        success = make_rigged_variant(gObjectSimpleProgram, gSkinnedObjectSimpleProgram);
+		success = success && gObjectSimpleProgram.createShader(NULL, NULL);
 	}
 
 	if (success)
@@ -3244,8 +3096,8 @@ BOOL LLViewerShaderMgr::loadShadersObject()
 		gObjectSimpleImpostorProgram.mShaderFiles.push_back(make_pair("objects/simpleV.glsl", GL_VERTEX_SHADER_ARB));
 		gObjectSimpleImpostorProgram.mShaderFiles.push_back(make_pair("objects/simpleF.glsl", GL_FRAGMENT_SHADER_ARB));
 		gObjectSimpleImpostorProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT];
-		
-		success = gObjectSimpleImpostorProgram.createShader(NULL, NULL);
+        success = make_rigged_variant(gObjectSimpleImpostorProgram, gSkinnedObjectSimpleImpostorProgram);
+		success = success && gObjectSimpleImpostorProgram.createShader(NULL, NULL);
 	}
 
 	if (success)
@@ -3262,30 +3114,30 @@ BOOL LLViewerShaderMgr::loadShadersObject()
 		gObjectSimpleWaterProgram.mShaderFiles.push_back(make_pair("objects/simpleWaterF.glsl", GL_FRAGMENT_SHADER_ARB));
 		gObjectSimpleWaterProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT];
 		gObjectSimpleWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER;
+        make_rigged_variant(gObjectSimpleWaterProgram, gSkinnedObjectSimpleWaterProgram);
 		success = gObjectSimpleWaterProgram.createShader(NULL, NULL);
 	}
 	
 	if (success)
 	{
 		gObjectBumpProgram.mName = "Bump Shader";
-		/*gObjectBumpProgram.mFeatures.calculatesLighting = true;
-		gObjectBumpProgram.mFeatures.calculatesAtmospherics = true;
-		gObjectBumpProgram.mFeatures.hasGamma = true;
-		gObjectBumpProgram.mFeatures.hasAtmospherics = true;
-		gObjectBumpProgram.mFeatures.hasLighting = true;
-		gObjectBumpProgram.mFeatures.mIndexedTextureChannels = 0;*/
 		gObjectBumpProgram.mFeatures.encodesNormal = true;
 		gObjectBumpProgram.mShaderFiles.clear();
 		gObjectBumpProgram.mShaderFiles.push_back(make_pair("objects/bumpV.glsl", GL_VERTEX_SHADER_ARB));
 		gObjectBumpProgram.mShaderFiles.push_back(make_pair("objects/bumpF.glsl", GL_FRAGMENT_SHADER_ARB));
 		gObjectBumpProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT];
-		success = gObjectBumpProgram.createShader(NULL, NULL);
+        success = make_rigged_variant(gObjectBumpProgram, gSkinnedObjectBumpProgram);
+		success = success && gObjectBumpProgram.createShader(NULL, NULL);
 		if (success)
 		{ //lldrawpoolbump assumes "texture0" has channel 0 and "texture1" has channel 1
-			gObjectBumpProgram.bind();
-			gObjectBumpProgram.uniform1i(sTexture0, 0);
-			gObjectBumpProgram.uniform1i(sTexture1, 1);
-			gObjectBumpProgram.unbind();
+            LLGLSLShader* shader[] = { &gObjectBumpProgram, &gSkinnedObjectBumpProgram };
+            for (int i = 0; i < 2; ++i)
+            {
+                shader[i]->bind();
+                shader[i]->uniform1i(sTexture0, 0);
+                shader[i]->uniform1i(sTexture1, 1);
+                shader[i]->unbind();
+            }
 		}
 	}
 	
@@ -3304,7 +3156,8 @@ BOOL LLViewerShaderMgr::loadShadersObject()
 		gObjectSimpleAlphaMaskProgram.mShaderFiles.push_back(make_pair("objects/simpleV.glsl", GL_VERTEX_SHADER_ARB));
 		gObjectSimpleAlphaMaskProgram.mShaderFiles.push_back(make_pair("objects/simpleF.glsl", GL_FRAGMENT_SHADER_ARB));
 		gObjectSimpleAlphaMaskProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT];
-		success = gObjectSimpleAlphaMaskProgram.createShader(NULL, NULL);
+        success = make_rigged_variant(gObjectSimpleAlphaMaskProgram, gSkinnedObjectSimpleAlphaMaskProgram);
+		success = success && gObjectSimpleAlphaMaskProgram.createShader(NULL, NULL);
 	}
 
 	if (success)
@@ -3322,7 +3175,8 @@ BOOL LLViewerShaderMgr::loadShadersObject()
 		gObjectSimpleWaterAlphaMaskProgram.mShaderFiles.push_back(make_pair("objects/simpleWaterF.glsl", GL_FRAGMENT_SHADER_ARB));
 		gObjectSimpleWaterAlphaMaskProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT];
 		gObjectSimpleWaterAlphaMaskProgram.mShaderGroup = LLGLSLShader::SG_WATER;
-		success = gObjectSimpleWaterAlphaMaskProgram.createShader(NULL, NULL);
+        success = make_rigged_variant(gObjectSimpleWaterAlphaMaskProgram, gSkinnedObjectSimpleWaterAlphaMaskProgram);
+		success = success && gObjectSimpleWaterAlphaMaskProgram.createShader(NULL, NULL);
 	}
 
 	if (success)
@@ -3338,7 +3192,8 @@ BOOL LLViewerShaderMgr::loadShadersObject()
 		gObjectFullbrightProgram.mShaderFiles.push_back(make_pair("objects/fullbrightV.glsl", GL_VERTEX_SHADER_ARB));
 		gObjectFullbrightProgram.mShaderFiles.push_back(make_pair("objects/fullbrightF.glsl", GL_FRAGMENT_SHADER_ARB));
 		gObjectFullbrightProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT];
-		success = gObjectFullbrightProgram.createShader(NULL, NULL);
+        success = make_rigged_variant(gObjectFullbrightProgram, gSkinnedObjectFullbrightProgram);
+        success = success && gObjectFullbrightProgram.createShader(NULL, NULL);
 	}
 
 	if (success)
@@ -3346,7 +3201,7 @@ BOOL LLViewerShaderMgr::loadShadersObject()
 		gObjectFullbrightWaterProgram.mName = "Fullbright Water Shader";
 		gObjectFullbrightWaterProgram.mFeatures.calculatesAtmospherics = true;
 		gObjectFullbrightWaterProgram.mFeatures.isFullbright = true;
-		gObjectFullbrightWaterProgram.mFeatures.hasWaterFog = true;		
+		gObjectFullbrightWaterProgram.mFeatures.hasWaterFog = true;
 		gObjectFullbrightWaterProgram.mFeatures.hasTransport = true;
 		gObjectFullbrightWaterProgram.mFeatures.mIndexedTextureChannels = 0;
 		gObjectFullbrightWaterProgram.mShaderFiles.clear();
@@ -3354,7 +3209,8 @@ BOOL LLViewerShaderMgr::loadShadersObject()
 		gObjectFullbrightWaterProgram.mShaderFiles.push_back(make_pair("objects/fullbrightWaterF.glsl", GL_FRAGMENT_SHADER_ARB));
 		gObjectFullbrightWaterProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT];
 		gObjectFullbrightWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER;
-		success = gObjectFullbrightWaterProgram.createShader(NULL, NULL);
+        success = make_rigged_variant(gObjectFullbrightWaterProgram, gSkinnedObjectFullbrightWaterProgram);
+		success = success && gObjectFullbrightWaterProgram.createShader(NULL, NULL);
 	}
 
 	if (success)
@@ -3370,7 +3226,8 @@ BOOL LLViewerShaderMgr::loadShadersObject()
 		gObjectEmissiveProgram.mShaderFiles.push_back(make_pair("objects/emissiveV.glsl", GL_VERTEX_SHADER_ARB));
 		gObjectEmissiveProgram.mShaderFiles.push_back(make_pair("objects/fullbrightF.glsl", GL_FRAGMENT_SHADER_ARB));
 		gObjectEmissiveProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT];
-		success = gObjectEmissiveProgram.createShader(NULL, NULL);
+        success = make_rigged_variant(gObjectEmissiveProgram, gSkinnedObjectEmissiveProgram);
+		success = success && gObjectEmissiveProgram.createShader(NULL, NULL);
 	}
 
 	if (success)
@@ -3386,7 +3243,8 @@ BOOL LLViewerShaderMgr::loadShadersObject()
 		gObjectEmissiveWaterProgram.mShaderFiles.push_back(make_pair("objects/fullbrightWaterF.glsl", GL_FRAGMENT_SHADER_ARB));
 		gObjectEmissiveWaterProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT];
 		gObjectEmissiveWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER;
-		success = gObjectEmissiveWaterProgram.createShader(NULL, NULL);
+        success = make_rigged_variant(gObjectEmissiveWaterProgram, gSkinnedObjectEmissiveWaterProgram);
+		success = success && gObjectEmissiveWaterProgram.createShader(NULL, NULL);
 	}
 
 	if (success)
@@ -3403,12 +3261,13 @@ BOOL LLViewerShaderMgr::loadShadersObject()
 		gObjectFullbrightAlphaMaskProgram.mShaderFiles.push_back(make_pair("objects/fullbrightV.glsl", GL_VERTEX_SHADER_ARB));
 		gObjectFullbrightAlphaMaskProgram.mShaderFiles.push_back(make_pair("objects/fullbrightF.glsl", GL_FRAGMENT_SHADER_ARB));
 		gObjectFullbrightAlphaMaskProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT];
-		success = gObjectFullbrightAlphaMaskProgram.createShader(NULL, NULL);
+        success = make_rigged_variant(gObjectFullbrightAlphaMaskProgram, gSkinnedObjectFullbrightAlphaMaskProgram);
+		success = success && gObjectFullbrightAlphaMaskProgram.createShader(NULL, NULL);
 	}
 
 	if (success)
 	{
-		gObjectFullbrightWaterAlphaMaskProgram.mName = "Fullbright Water Shader";
+		gObjectFullbrightWaterAlphaMaskProgram.mName = "Fullbright Water Alpha Mask Shader";
 		gObjectFullbrightWaterAlphaMaskProgram.mFeatures.calculatesAtmospherics = true;
 		gObjectFullbrightWaterAlphaMaskProgram.mFeatures.isFullbright = true;
 		gObjectFullbrightWaterAlphaMaskProgram.mFeatures.hasWaterFog = true;		
@@ -3420,7 +3279,8 @@ BOOL LLViewerShaderMgr::loadShadersObject()
 		gObjectFullbrightWaterAlphaMaskProgram.mShaderFiles.push_back(make_pair("objects/fullbrightWaterF.glsl", GL_FRAGMENT_SHADER_ARB));
 		gObjectFullbrightWaterAlphaMaskProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT];
 		gObjectFullbrightWaterAlphaMaskProgram.mShaderGroup = LLGLSLShader::SG_WATER;
-		success = gObjectFullbrightWaterAlphaMaskProgram.createShader(NULL, NULL);
+        success = make_rigged_variant(gObjectFullbrightWaterAlphaMaskProgram, gSkinnedObjectFullbrightWaterAlphaMaskProgram);
+		success = success && gObjectFullbrightWaterAlphaMaskProgram.createShader(NULL, NULL);
 	}
 
 	if (success)
@@ -3436,7 +3296,8 @@ BOOL LLViewerShaderMgr::loadShadersObject()
 		gObjectShinyProgram.mShaderFiles.push_back(make_pair("objects/shinyV.glsl", GL_VERTEX_SHADER_ARB));
 		gObjectShinyProgram.mShaderFiles.push_back(make_pair("objects/shinyF.glsl", GL_FRAGMENT_SHADER_ARB));		
 		gObjectShinyProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT];
-		success = gObjectShinyProgram.createShader(NULL, NULL);
+        success = make_rigged_variant(gObjectShinyProgram, gSkinnedObjectShinyProgram);
+		success = success && gObjectShinyProgram.createShader(NULL, NULL);
 	}
 
 	if (success)
@@ -3453,7 +3314,8 @@ BOOL LLViewerShaderMgr::loadShadersObject()
 		gObjectShinyWaterProgram.mShaderFiles.push_back(make_pair("objects/shinyV.glsl", GL_VERTEX_SHADER_ARB));
 		gObjectShinyWaterProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT];
 		gObjectShinyWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER;
-		success = gObjectShinyWaterProgram.createShader(NULL, NULL);
+        success = make_rigged_variant(gObjectShinyWaterProgram, gSkinnedObjectShinyWaterProgram);
+		success = success && gObjectShinyWaterProgram.createShader(NULL, NULL);
 	}
 	
 	if (success)
@@ -3469,7 +3331,8 @@ BOOL LLViewerShaderMgr::loadShadersObject()
 		gObjectFullbrightShinyProgram.mShaderFiles.push_back(make_pair("objects/fullbrightShinyV.glsl", GL_VERTEX_SHADER_ARB));
 		gObjectFullbrightShinyProgram.mShaderFiles.push_back(make_pair("objects/fullbrightShinyF.glsl", GL_FRAGMENT_SHADER_ARB));
 		gObjectFullbrightShinyProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT];
-		success = gObjectFullbrightShinyProgram.createShader(NULL, NULL);
+        success = make_rigged_variant(gObjectFullbrightShinyProgram, gSkinnedObjectFullbrightShinyProgram);
+		success = success && gObjectFullbrightShinyProgram.createShader(NULL, NULL);
 	}
 
 	if (success)
@@ -3487,196 +3350,8 @@ BOOL LLViewerShaderMgr::loadShadersObject()
 		gObjectFullbrightShinyWaterProgram.mShaderFiles.push_back(make_pair("objects/fullbrightShinyWaterF.glsl", GL_FRAGMENT_SHADER_ARB));
 		gObjectFullbrightShinyWaterProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT];
 		gObjectFullbrightShinyWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER;
-		success = gObjectFullbrightShinyWaterProgram.createShader(NULL, NULL);
-	}
-
-	if (mShaderLevel[SHADER_AVATAR] > 0)
-	{ //load hardware skinned attachment shaders
-		if (success)
-		{
-			gSkinnedObjectSimpleProgram.mName = "Skinned Simple Shader";
-			gSkinnedObjectSimpleProgram.mFeatures.calculatesLighting = true;
-			gSkinnedObjectSimpleProgram.mFeatures.calculatesAtmospherics = true;
-			gSkinnedObjectSimpleProgram.mFeatures.hasGamma = true;
-			gSkinnedObjectSimpleProgram.mFeatures.hasAtmospherics = true;
-			gSkinnedObjectSimpleProgram.mFeatures.hasLighting = true;
-			gSkinnedObjectSimpleProgram.mFeatures.hasObjectSkinning = true;
-			gSkinnedObjectSimpleProgram.mFeatures.hasAlphaMask = true;
-			gSkinnedObjectSimpleProgram.mFeatures.disableTextureIndex = true;
-			gSkinnedObjectSimpleProgram.mShaderFiles.clear();
-			gSkinnedObjectSimpleProgram.mShaderFiles.push_back(make_pair("objects/simpleSkinnedV.glsl", GL_VERTEX_SHADER_ARB));
-			gSkinnedObjectSimpleProgram.mShaderFiles.push_back(make_pair("objects/simpleF.glsl", GL_FRAGMENT_SHADER_ARB));
-			gSkinnedObjectSimpleProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT];
-			success = gSkinnedObjectSimpleProgram.createShader(NULL, NULL);
-		}
-
-		if (success)
-		{
-			gSkinnedObjectFullbrightProgram.mName = "Skinned Fullbright Shader";
-			gSkinnedObjectFullbrightProgram.mFeatures.calculatesAtmospherics = true;
-			gSkinnedObjectFullbrightProgram.mFeatures.hasGamma = true;
-			gSkinnedObjectFullbrightProgram.mFeatures.hasTransport = true;
-			gSkinnedObjectFullbrightProgram.mFeatures.isFullbright = true;
-			gSkinnedObjectFullbrightProgram.mFeatures.hasObjectSkinning = true;
-			gSkinnedObjectFullbrightProgram.mFeatures.hasAlphaMask = true;			
-			gSkinnedObjectFullbrightProgram.mFeatures.disableTextureIndex = true;
-			gSkinnedObjectFullbrightProgram.mFeatures.hasSrgb = true;
-			gSkinnedObjectFullbrightProgram.mShaderFiles.clear();
-			gSkinnedObjectFullbrightProgram.mShaderFiles.push_back(make_pair("objects/fullbrightSkinnedV.glsl", GL_VERTEX_SHADER_ARB));
-			gSkinnedObjectFullbrightProgram.mShaderFiles.push_back(make_pair("objects/fullbrightF.glsl", GL_FRAGMENT_SHADER_ARB));
-			gSkinnedObjectFullbrightProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT];
-			success = gSkinnedObjectFullbrightProgram.createShader(NULL, NULL);
-		}
-
-		if (success)
-		{
-			gSkinnedObjectEmissiveProgram.mName = "Skinned Emissive Shader";
-			gSkinnedObjectEmissiveProgram.mFeatures.calculatesAtmospherics = true;
-			gSkinnedObjectEmissiveProgram.mFeatures.hasGamma = true;
-			gSkinnedObjectEmissiveProgram.mFeatures.hasTransport = true;
-			gSkinnedObjectEmissiveProgram.mFeatures.isFullbright = true;
-			gSkinnedObjectEmissiveProgram.mFeatures.hasObjectSkinning = true;
-			gSkinnedObjectEmissiveProgram.mFeatures.disableTextureIndex = true;
-            gSkinnedObjectEmissiveProgram.mFeatures.hasSrgb = true;
-			gSkinnedObjectEmissiveProgram.mShaderFiles.clear();
-			gSkinnedObjectEmissiveProgram.mShaderFiles.push_back(make_pair("objects/emissiveSkinnedV.glsl", GL_VERTEX_SHADER_ARB));
-			gSkinnedObjectEmissiveProgram.mShaderFiles.push_back(make_pair("objects/fullbrightF.glsl", GL_FRAGMENT_SHADER_ARB));
-			gSkinnedObjectEmissiveProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT];
-			success = gSkinnedObjectEmissiveProgram.createShader(NULL, NULL);
-		}
-
-		if (success)
-		{
-			gSkinnedObjectEmissiveWaterProgram.mName = "Skinned Emissive Water Shader";
-			gSkinnedObjectEmissiveWaterProgram.mFeatures.calculatesAtmospherics = true;
-			gSkinnedObjectEmissiveWaterProgram.mFeatures.hasGamma = true;
-			gSkinnedObjectEmissiveWaterProgram.mFeatures.hasTransport = true;
-			gSkinnedObjectEmissiveWaterProgram.mFeatures.isFullbright = true;
-			gSkinnedObjectEmissiveWaterProgram.mFeatures.hasObjectSkinning = true;
-			gSkinnedObjectEmissiveWaterProgram.mFeatures.disableTextureIndex = true;
-			gSkinnedObjectEmissiveWaterProgram.mFeatures.hasWaterFog = true;
-			gSkinnedObjectEmissiveWaterProgram.mShaderFiles.clear();
-			gSkinnedObjectEmissiveWaterProgram.mShaderFiles.push_back(make_pair("objects/emissiveSkinnedV.glsl", GL_VERTEX_SHADER_ARB));
-			gSkinnedObjectEmissiveWaterProgram.mShaderFiles.push_back(make_pair("objects/fullbrightWaterF.glsl", GL_FRAGMENT_SHADER_ARB));
-			gSkinnedObjectEmissiveWaterProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT];
-			success = gSkinnedObjectEmissiveWaterProgram.createShader(NULL, NULL);
-		}
-
-		if (success)
-		{
-			gSkinnedObjectFullbrightShinyProgram.mName = "Skinned Fullbright Shiny Shader";
-			gSkinnedObjectFullbrightShinyProgram.mFeatures.calculatesAtmospherics = true;
-			gSkinnedObjectFullbrightShinyProgram.mFeatures.hasGamma = true;
-			gSkinnedObjectFullbrightShinyProgram.mFeatures.hasTransport = true;
-			gSkinnedObjectFullbrightShinyProgram.mFeatures.isShiny = true;
-			gSkinnedObjectFullbrightShinyProgram.mFeatures.isFullbright = true;
-			gSkinnedObjectFullbrightShinyProgram.mFeatures.hasObjectSkinning = true;
-			gSkinnedObjectFullbrightShinyProgram.mFeatures.hasAlphaMask = true;
-			gSkinnedObjectFullbrightShinyProgram.mFeatures.disableTextureIndex = true;
-			gSkinnedObjectFullbrightShinyProgram.mShaderFiles.clear();
-			gSkinnedObjectFullbrightShinyProgram.mShaderFiles.push_back(make_pair("objects/fullbrightShinySkinnedV.glsl", GL_VERTEX_SHADER_ARB));
-			gSkinnedObjectFullbrightShinyProgram.mShaderFiles.push_back(make_pair("objects/fullbrightShinyF.glsl", GL_FRAGMENT_SHADER_ARB));
-			gSkinnedObjectFullbrightShinyProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT];
-			success = gSkinnedObjectFullbrightShinyProgram.createShader(NULL, NULL);
-		}
-
-		if (success)
-		{
-			gSkinnedObjectShinySimpleProgram.mName = "Skinned Shiny Simple Shader";
-			gSkinnedObjectShinySimpleProgram.mFeatures.calculatesLighting = true;
-			gSkinnedObjectShinySimpleProgram.mFeatures.calculatesAtmospherics = true;
-			gSkinnedObjectShinySimpleProgram.mFeatures.hasGamma = true;
-			gSkinnedObjectShinySimpleProgram.mFeatures.hasAtmospherics = true;
-			gSkinnedObjectShinySimpleProgram.mFeatures.hasObjectSkinning = true;
-			gSkinnedObjectShinySimpleProgram.mFeatures.hasAlphaMask = true;
-			gSkinnedObjectShinySimpleProgram.mFeatures.isShiny = true;
-			gSkinnedObjectShinySimpleProgram.mFeatures.disableTextureIndex = true;
-			gSkinnedObjectShinySimpleProgram.mShaderFiles.clear();
-			gSkinnedObjectShinySimpleProgram.mShaderFiles.push_back(make_pair("objects/shinySimpleSkinnedV.glsl", GL_VERTEX_SHADER_ARB));
-			gSkinnedObjectShinySimpleProgram.mShaderFiles.push_back(make_pair("objects/shinyF.glsl", GL_FRAGMENT_SHADER_ARB));
-			gSkinnedObjectShinySimpleProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT];
-			success = gSkinnedObjectShinySimpleProgram.createShader(NULL, NULL);
-		}
-
-		if (success)
-		{
-			gSkinnedObjectSimpleWaterProgram.mName = "Skinned Simple Water Shader";
-			gSkinnedObjectSimpleWaterProgram.mFeatures.calculatesLighting = true;
-			gSkinnedObjectSimpleWaterProgram.mFeatures.calculatesAtmospherics = true;
-			gSkinnedObjectSimpleWaterProgram.mFeatures.hasGamma = true;
-			gSkinnedObjectSimpleWaterProgram.mFeatures.hasAtmospherics = true;
-			gSkinnedObjectSimpleWaterProgram.mFeatures.hasLighting = true;
-			gSkinnedObjectSimpleWaterProgram.mFeatures.disableTextureIndex = true;
-			gSkinnedObjectSimpleWaterProgram.mFeatures.hasWaterFog = true;
-			gSkinnedObjectSimpleWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER;
-			gSkinnedObjectSimpleWaterProgram.mFeatures.hasObjectSkinning = true;
-			gSkinnedObjectSimpleWaterProgram.mFeatures.disableTextureIndex = true;
-			gSkinnedObjectSimpleWaterProgram.mFeatures.hasAlphaMask = true;
-			gSkinnedObjectSimpleWaterProgram.mShaderFiles.clear();
-			gSkinnedObjectSimpleWaterProgram.mShaderFiles.push_back(make_pair("objects/simpleSkinnedV.glsl", GL_VERTEX_SHADER_ARB));
-			gSkinnedObjectSimpleWaterProgram.mShaderFiles.push_back(make_pair("objects/simpleWaterF.glsl", GL_FRAGMENT_SHADER_ARB));
-			gSkinnedObjectSimpleWaterProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT];
-			success = gSkinnedObjectSimpleWaterProgram.createShader(NULL, NULL);
-		}
-
-		if (success)
-		{
-			gSkinnedObjectFullbrightWaterProgram.mName = "Skinned Fullbright Water Shader";
-			gSkinnedObjectFullbrightWaterProgram.mFeatures.calculatesAtmospherics = true;
-			gSkinnedObjectFullbrightWaterProgram.mFeatures.hasGamma = true;
-			gSkinnedObjectFullbrightWaterProgram.mFeatures.hasTransport = true;
-			gSkinnedObjectFullbrightWaterProgram.mFeatures.isFullbright = true;
-			gSkinnedObjectFullbrightWaterProgram.mFeatures.hasObjectSkinning = true;
-			gSkinnedObjectFullbrightWaterProgram.mFeatures.hasAlphaMask = true;
-			gSkinnedObjectFullbrightWaterProgram.mFeatures.hasWaterFog = true;
-			gSkinnedObjectFullbrightWaterProgram.mFeatures.disableTextureIndex = true;
-			gSkinnedObjectFullbrightWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER;
-			gSkinnedObjectFullbrightWaterProgram.mShaderFiles.clear();
-			gSkinnedObjectFullbrightWaterProgram.mShaderFiles.push_back(make_pair("objects/fullbrightSkinnedV.glsl", GL_VERTEX_SHADER_ARB));
-			gSkinnedObjectFullbrightWaterProgram.mShaderFiles.push_back(make_pair("objects/fullbrightWaterF.glsl", GL_FRAGMENT_SHADER_ARB));
-			gSkinnedObjectFullbrightWaterProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT];
-			success = gSkinnedObjectFullbrightWaterProgram.createShader(NULL, NULL);
-		}
-
-		if (success)
-		{
-			gSkinnedObjectFullbrightShinyWaterProgram.mName = "Skinned Fullbright Shiny Water Shader";
-			gSkinnedObjectFullbrightShinyWaterProgram.mFeatures.calculatesAtmospherics = true;
-			gSkinnedObjectFullbrightShinyWaterProgram.mFeatures.hasGamma = true;
-			gSkinnedObjectFullbrightShinyWaterProgram.mFeatures.hasTransport = true;
-			gSkinnedObjectFullbrightShinyWaterProgram.mFeatures.isShiny = true;
-			gSkinnedObjectFullbrightShinyWaterProgram.mFeatures.isFullbright = true;
-			gSkinnedObjectFullbrightShinyWaterProgram.mFeatures.hasObjectSkinning = true;
-			gSkinnedObjectFullbrightShinyWaterProgram.mFeatures.hasAlphaMask = true;
-			gSkinnedObjectFullbrightShinyWaterProgram.mFeatures.hasWaterFog = true;
-			gSkinnedObjectFullbrightShinyWaterProgram.mFeatures.disableTextureIndex = true;
-			gSkinnedObjectFullbrightShinyWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER;
-			gSkinnedObjectFullbrightShinyWaterProgram.mShaderFiles.clear();
-			gSkinnedObjectFullbrightShinyWaterProgram.mShaderFiles.push_back(make_pair("objects/fullbrightShinySkinnedV.glsl", GL_VERTEX_SHADER_ARB));
-			gSkinnedObjectFullbrightShinyWaterProgram.mShaderFiles.push_back(make_pair("objects/fullbrightShinyWaterF.glsl", GL_FRAGMENT_SHADER_ARB));
-			gSkinnedObjectFullbrightShinyWaterProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT];
-			success = gSkinnedObjectFullbrightShinyWaterProgram.createShader(NULL, NULL);
-		}
-
-		if (success)
-		{
-			gSkinnedObjectShinySimpleWaterProgram.mName = "Skinned Shiny Simple Water Shader";
-			gSkinnedObjectShinySimpleWaterProgram.mFeatures.calculatesLighting = true;
-			gSkinnedObjectShinySimpleWaterProgram.mFeatures.calculatesAtmospherics = true;
-			gSkinnedObjectShinySimpleWaterProgram.mFeatures.hasGamma = true;
-			gSkinnedObjectShinySimpleWaterProgram.mFeatures.hasAtmospherics = true;
-			gSkinnedObjectShinySimpleWaterProgram.mFeatures.hasObjectSkinning = true;
-			gSkinnedObjectShinySimpleWaterProgram.mFeatures.hasAlphaMask = true;
-			gSkinnedObjectShinySimpleWaterProgram.mFeatures.isShiny = true;
-			gSkinnedObjectShinySimpleWaterProgram.mFeatures.hasWaterFog = true;
-			gSkinnedObjectShinySimpleWaterProgram.mFeatures.disableTextureIndex = true;
-			gSkinnedObjectShinySimpleWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER;
-			gSkinnedObjectShinySimpleWaterProgram.mShaderFiles.clear();
-			gSkinnedObjectShinySimpleWaterProgram.mShaderFiles.push_back(make_pair("objects/shinySimpleSkinnedV.glsl", GL_VERTEX_SHADER_ARB));
-			gSkinnedObjectShinySimpleWaterProgram.mShaderFiles.push_back(make_pair("objects/shinyWaterF.glsl", GL_FRAGMENT_SHADER_ARB));
-			gSkinnedObjectShinySimpleWaterProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT];
-			success = gSkinnedObjectShinySimpleWaterProgram.createShader(NULL, NULL);
-		}
+        success = make_rigged_variant(gObjectFullbrightShinyWaterProgram, gSkinnedObjectFullbrightShinyWaterProgram);
+		success = success && gObjectFullbrightShinyWaterProgram.createShader(NULL, NULL);
 	}
 
 	if( !success )
@@ -3789,12 +3464,6 @@ BOOL LLViewerShaderMgr::loadShadersInterface()
 {
 	BOOL success = TRUE;
 
-	if (mShaderLevel[SHADER_INTERFACE] == 0)
-	{
-		gHighlightProgram.unload();
-		return TRUE;
-	}
-	
 	if (success)
 	{
 		gHighlightProgram.mName = "Highlight Shader";
@@ -3802,7 +3471,8 @@ BOOL LLViewerShaderMgr::loadShadersInterface()
 		gHighlightProgram.mShaderFiles.push_back(make_pair("interface/highlightV.glsl", GL_VERTEX_SHADER_ARB));
 		gHighlightProgram.mShaderFiles.push_back(make_pair("interface/highlightF.glsl", GL_FRAGMENT_SHADER_ARB));
 		gHighlightProgram.mShaderLevel = mShaderLevel[SHADER_INTERFACE];
-		success = gHighlightProgram.createShader(NULL, NULL);
+        success = make_rigged_variant(gHighlightProgram, gSkinnedHighlightProgram);
+		success = success && gHighlightProgram.createShader(NULL, NULL);
 	}
 
 	if (success)
@@ -4004,9 +3674,21 @@ BOOL LLViewerShaderMgr::loadShadersInterface()
 		gOcclusionProgram.mShaderFiles.push_back(make_pair("interface/occlusionV.glsl", GL_VERTEX_SHADER_ARB));
 		gOcclusionProgram.mShaderFiles.push_back(make_pair("interface/occlusionF.glsl", GL_FRAGMENT_SHADER_ARB));
 		gOcclusionProgram.mShaderLevel = mShaderLevel[SHADER_INTERFACE];
+        gOcclusionProgram.mRiggedVariant = &gSkinnedOcclusionProgram;
 		success = gOcclusionProgram.createShader(NULL, NULL);
 	}
 
+    if (success)
+    {
+        gSkinnedOcclusionProgram.mName = "Skinned Occlusion Shader";
+        gSkinnedOcclusionProgram.mFeatures.hasObjectSkinning = true;
+        gSkinnedOcclusionProgram.mShaderFiles.clear();
+        gSkinnedOcclusionProgram.mShaderFiles.push_back(make_pair("interface/occlusionSkinnedV.glsl", GL_VERTEX_SHADER_ARB));
+        gSkinnedOcclusionProgram.mShaderFiles.push_back(make_pair("interface/occlusionF.glsl", GL_FRAGMENT_SHADER_ARB));
+        gSkinnedOcclusionProgram.mShaderLevel = mShaderLevel[SHADER_INTERFACE];
+        success = gSkinnedOcclusionProgram.createShader(NULL, NULL);
+    }
+
 	if (success)
 	{
 		gOcclusionCubeProgram.mName = "Occlusion Cube Shader";
@@ -4023,8 +3705,10 @@ BOOL LLViewerShaderMgr::loadShadersInterface()
 		gDebugProgram.mShaderFiles.clear();
 		gDebugProgram.mShaderFiles.push_back(make_pair("interface/debugV.glsl", GL_VERTEX_SHADER_ARB));
 		gDebugProgram.mShaderFiles.push_back(make_pair("interface/debugF.glsl", GL_FRAGMENT_SHADER_ARB));
+        gDebugProgram.mRiggedVariant = &gSkinnedDebugProgram;
 		gDebugProgram.mShaderLevel = mShaderLevel[SHADER_INTERFACE];
-		success = gDebugProgram.createShader(NULL, NULL);
+        success = make_rigged_variant(gDebugProgram, gSkinnedDebugProgram);
+		success = success && gDebugProgram.createShader(NULL, NULL);
 	}
 
 	if (success)
diff --git a/indra/newview/llviewershadermgr.h b/indra/newview/llviewershadermgr.h
index 081221f15be877a6950b33c2d262cdbcf780c514..f8a261805b7c375281ba136ae2e0e258a5e8e764 100644
--- a/indra/newview/llviewershadermgr.h
+++ b/indra/newview/llviewershadermgr.h
@@ -49,7 +49,11 @@ class LLViewerShaderMgr: public LLShaderMgr
 	void setShaders();
 	void unloadShaders();
     S32  getShaderLevel(S32 type);
-	BOOL loadBasicShaders();
+
+    // loadBasicShaders in case of a failure returns
+    // name of a file error happened at, otherwise
+    // returns an empty string
+    std::string loadBasicShaders();
 	BOOL loadShadersEffects();
 	BOOL loadShadersDeferred();
 	BOOL loadShadersObject();
@@ -181,13 +185,12 @@ extern LLGLSLShader			gOneTextureNoColorProgram;
 extern LLGLSLShader			gObjectSimpleProgram;
 extern LLGLSLShader			gObjectSimpleImpostorProgram;
 extern LLGLSLShader			gObjectPreviewProgram;
+extern LLGLSLShader			gPhysicsPreviewProgram;
 extern LLGLSLShader			gObjectSimpleAlphaMaskProgram;
 extern LLGLSLShader			gObjectSimpleWaterProgram;
 extern LLGLSLShader			gObjectSimpleWaterAlphaMaskProgram;
-extern LLGLSLShader			gObjectSimpleNonIndexedProgram;
 extern LLGLSLShader			gObjectSimpleNonIndexedTexGenProgram;
 extern LLGLSLShader			gObjectSimpleNonIndexedTexGenWaterProgram;
-extern LLGLSLShader			gObjectSimpleNonIndexedWaterProgram;
 extern LLGLSLShader			gObjectAlphaMaskNonIndexedProgram;
 extern LLGLSLShader			gObjectAlphaMaskNonIndexedWaterProgram;
 extern LLGLSLShader			gObjectAlphaMaskNoColorProgram;
@@ -200,8 +203,6 @@ extern LLGLSLShader			gObjectEmissiveProgram;
 extern LLGLSLShader			gObjectEmissiveWaterProgram;
 extern LLGLSLShader			gObjectFullbrightAlphaMaskProgram;
 extern LLGLSLShader			gObjectFullbrightWaterAlphaMaskProgram;
-extern LLGLSLShader			gObjectFullbrightNonIndexedProgram;
-extern LLGLSLShader			gObjectFullbrightNonIndexedWaterProgram;
 extern LLGLSLShader			gObjectEmissiveNonIndexedProgram;
 extern LLGLSLShader			gObjectEmissiveNonIndexedWaterProgram;
 extern LLGLSLShader			gObjectBumpProgram;
@@ -213,25 +214,9 @@ extern LLGLSLShader			gObjectFullbrightLODProgram;
 
 extern LLGLSLShader			gObjectFullbrightShinyProgram;
 extern LLGLSLShader			gObjectFullbrightShinyWaterProgram;
-extern LLGLSLShader			gObjectFullbrightShinyNonIndexedProgram;
-extern LLGLSLShader			gObjectFullbrightShinyNonIndexedWaterProgram;
 
 extern LLGLSLShader			gObjectShinyProgram;
 extern LLGLSLShader			gObjectShinyWaterProgram;
-extern LLGLSLShader			gObjectShinyNonIndexedProgram;
-extern LLGLSLShader			gObjectShinyNonIndexedWaterProgram;
-
-extern LLGLSLShader			gSkinnedObjectSimpleProgram;
-extern LLGLSLShader			gSkinnedObjectFullbrightProgram;
-extern LLGLSLShader			gSkinnedObjectEmissiveProgram;
-extern LLGLSLShader			gSkinnedObjectFullbrightShinyProgram;
-extern LLGLSLShader			gSkinnedObjectShinySimpleProgram;
-
-extern LLGLSLShader			gSkinnedObjectSimpleWaterProgram;
-extern LLGLSLShader			gSkinnedObjectFullbrightWaterProgram;
-extern LLGLSLShader			gSkinnedObjectEmissiveWaterProgram;
-extern LLGLSLShader			gSkinnedObjectFullbrightShinyWaterProgram;
-extern LLGLSLShader			gSkinnedObjectShinySimpleWaterProgram;
 
 //environment shaders
 extern LLGLSLShader			gTerrainProgram;
@@ -281,9 +266,6 @@ extern LLGLSLShader			gDeferredDiffuseAlphaMaskProgram;
 extern LLGLSLShader			gDeferredNonIndexedDiffuseAlphaMaskProgram;
 extern LLGLSLShader			gDeferredNonIndexedDiffuseAlphaMaskNoColorProgram;
 extern LLGLSLShader			gDeferredNonIndexedDiffuseProgram;
-extern LLGLSLShader			gDeferredSkinnedDiffuseProgram;
-extern LLGLSLShader			gDeferredSkinnedBumpProgram;
-extern LLGLSLShader			gDeferredSkinnedAlphaProgram;
 extern LLGLSLShader			gDeferredBumpProgram;
 extern LLGLSLShader			gDeferredTerrainProgram;
 extern LLGLSLShader			gDeferredTerrainWaterProgram;
@@ -330,8 +312,6 @@ extern LLGLSLShader			gDeferredWLSunProgram;
 extern LLGLSLShader			gDeferredWLMoonProgram;
 extern LLGLSLShader			gDeferredStarProgram;
 extern LLGLSLShader			gDeferredFullbrightShinyProgram;
-extern LLGLSLShader			gDeferredSkinnedFullbrightShinyProgram;
-extern LLGLSLShader			gDeferredSkinnedFullbrightProgram;
 extern LLGLSLShader			gNormalMapGenProgram;
 
 // Deferred materials shaders
diff --git a/indra/newview/llviewerstats.cpp b/indra/newview/llviewerstats.cpp
index 0ca4a3712dd7bf32b2159b995257e5fc11c7c051..a4fbbb3e785371dbb127436c307149e66bb6867f 100644
--- a/indra/newview/llviewerstats.cpp
+++ b/indra/newview/llviewerstats.cpp
@@ -182,8 +182,9 @@ SimMeasurement<F64Kilobytes >	SIM_UNACKED_BYTES("simtotalunackedbytes", "", LL_S
 SimMeasurement<F64Megabytes >	SIM_PHYSICS_MEM("physicsmemoryallocated", "", LL_SIM_STAT_SIMPHYSICSMEMORY);
 
 LLTrace::SampleStatHandle<F64Milliseconds >	FRAMETIME_JITTER("frametimejitter", "Average delta between successive frame times"),
-																FRAMETIME_SLEW("frametimeslew", "Average delta between frame time and mean"),
-																SIM_PING("simpingstat");
+											FRAMETIME_SLEW("frametimeslew", "Average delta between frame time and mean"),
+											FRAMETIME("frametime", "Measured frame time"),
+											SIM_PING("simpingstat");
 
 LLTrace::EventStatHandle<LLUnit<F64, LLUnits::Meters> > AGENT_POSITION_SNAP("agentpositionsnap", "agent position corrections");
 
@@ -261,8 +262,11 @@ void LLViewerStats::updateFrameStats(const F64Seconds time_diff)
 		// new "stutter" meter
 		add(LLStatViewer::FRAMETIME_DOUBLED, time_diff >= 2.0 * mLastTimeDiff ? 1 : 0);
 
+		sample(LLStatViewer::FRAMETIME, time_diff);
+
 		// old stats that were never really used
-		sample(LLStatViewer::FRAMETIME_JITTER, F64Milliseconds (mLastTimeDiff - time_diff));
+		F64Seconds jit = (F64Seconds) std::fabs((mLastTimeDiff - time_diff));
+		sample(LLStatViewer::FRAMETIME_JITTER, jit);
 			
 		F32Seconds average_frametime = gRenderStartTime.getElapsedTimeF32() / (F32)gFrameCount;
 		sample(LLStatViewer::FRAMETIME_SLEW, F64Milliseconds (average_frametime - time_diff));
@@ -388,8 +392,12 @@ void update_statistics()
 	gTransferManager.resetTransferBitsIn(LLTCT_ASSET);
 
 	sample(LLStatViewer::VISIBLE_AVATARS, LLVOAvatar::sNumVisibleAvatars);
-	LLWorld::getInstance()->updateNetStats();
-	LLWorld::getInstance()->requestCacheMisses();
+    LLWorld *world = LLWorld::getInstance(); // not LLSingleton
+    if (world)
+    {
+        world->updateNetStats();
+        world->requestCacheMisses();
+    }
 	
 	// Reset all of these values.
 	gVLManager.resetBitCounts();
@@ -498,7 +506,9 @@ void send_viewer_stats(bool include_preferences)
 	system["ram"] = (S32) gSysMemory.getPhysicalMemoryKB().value();
 	system["os"] = LLOSInfo::instance().getOSStringSimple();
 	system["cpu"] = gSysCPU.getCPUString();
+    system["cpu_sse"] = gSysCPU.getSSEVersions();
 	system["address_size"] = ADDRESS_SIZE;
+	system["os_bitness"] = LLOSInfo::instance().getOSBitness();
 	unsigned char MACAddress[MAC_ADDRESS_BYTES];
 	LLUUID::getNodeID(MACAddress);
 	std::string macAddressString = llformat("%02x-%02x-%02x-%02x-%02x-%02x",
@@ -540,7 +550,7 @@ void send_viewer_stats(bool include_preferences)
 	{
 		shader_level = 2;
 	}
-	else if (gPipeline.canUseVertexShaders())
+	else if (gPipeline.shadersLoaded())
 	{
 		shader_level = 1;
 	}
diff --git a/indra/newview/llviewerstats.h b/indra/newview/llviewerstats.h
index 4468e44ea8917020e2050f5c979390b36b222a7e..017c79b2e39279a43d6da989a6cd16993daef3e8 100644
--- a/indra/newview/llviewerstats.h
+++ b/indra/newview/llviewerstats.h
@@ -217,8 +217,8 @@ extern SimMeasurement<F64Megabytes >	SIM_PHYSICS_MEM;
 
 
 extern LLTrace::SampleStatHandle<F64Milliseconds >	FRAMETIME_JITTER,
-																		FRAMETIME_SLEW,
-																		SIM_PING;
+													FRAMETIME_SLEW,
+													SIM_PING;
 
 extern LLTrace::EventStatHandle<LLUnit<F64, LLUnits::Meters> > AGENT_POSITION_SNAP;
 
diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp
index 075588d577c7195edc0d21aaf71c3e2b5bb99ce3..8a11c5cf8f38ecf3a29b896851844e6d0af24556 100644
--- a/indra/newview/llviewertexture.cpp
+++ b/indra/newview/llviewertexture.cpp
@@ -182,6 +182,7 @@ void LLViewerTextureManager::findFetchedTextures(const LLUUID& id, std::vector<L
 
 void  LLViewerTextureManager::findTextures(const LLUUID& id, std::vector<LLViewerTexture*> &output)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
     std::vector<LLViewerFetchedTexture*> fetched_output;
     gTextureList.findTexturesByID(id, fetched_output);
     std::vector<LLViewerFetchedTexture*>::iterator iter = fetched_output.begin();
@@ -206,6 +207,7 @@ void  LLViewerTextureManager::findTextures(const LLUUID& id, std::vector<LLViewe
 
 LLViewerFetchedTexture* LLViewerTextureManager::findFetchedTexture(const LLUUID& id, S32 tex_type)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
     return gTextureList.findImage(id, (ETexListType)tex_type);
 }
 
@@ -477,11 +479,10 @@ const F32 GPU_MEMORY_CHECK_WAIT_TIME = 1.0f;
 F32 texmem_lower_bound_scale = 0.85f;
 F32 texmem_middle_bound_scale = 0.925f;
 
-static LLTrace::BlockTimerStatHandle FTM_TEXTURE_MEMORY_CHECK("Memory Check");
-
 //static 
 bool LLViewerTexture::isMemoryForTextureLow()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
     // Note: we need to figure out a better source for 'min' values,
     // what is free for low end at minimal settings is 'nothing left'
     // for higher end gpus at high settings.
@@ -498,6 +499,7 @@ bool LLViewerTexture::isMemoryForTextureLow()
 //static
 bool LLViewerTexture::isMemoryForTextureSuficientlyFree()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
     const S32Megabytes DESIRED_FREE_TEXTURE_MEMORY(50);
     const S32Megabytes DESIRED_FREE_MAIN_MEMORY(200);
 
@@ -511,10 +513,12 @@ bool LLViewerTexture::isMemoryForTextureSuficientlyFree()
 //static
 void LLViewerTexture::getGPUMemoryForTextures(S32Megabytes &gpu, S32Megabytes &physical)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
     static LLFrameTimer timer;
+
     static S32Megabytes gpu_res = S32Megabytes(S32_MAX);
     static S32Megabytes physical_res = S32Megabytes(S32_MAX);
-
+    
     if (timer.getElapsedTimeF32() < GPU_MEMORY_CHECK_WAIT_TIME) //call this once per second.
     {
         gpu = gpu_res;
@@ -523,48 +527,31 @@ void LLViewerTexture::getGPUMemoryForTextures(S32Megabytes &gpu, S32Megabytes &p
     }
     timer.reset();
 
-    LL_RECORD_BLOCK_TIME(FTM_TEXTURE_MEMORY_CHECK);
-
-    if (gGLManager.mHasATIMemInfo)
     {
-        S32 meminfo[4];
-        glGetIntegerv(GL_TEXTURE_FREE_MEMORY_ATI, meminfo);
-        gpu_res = (S32Megabytes)meminfo[0];
-
+        gpu_res = (S32Megabytes) LLImageGLThread::getFreeVRAMMegabytes();
+        
         //check main memory, only works for windows.
         LLMemory::updateMemoryInfo();
         physical_res = LLMemory::getAvailableMemKB();
-    }
-    else if (gGLManager.mHasNVXMemInfo)
-    {
-        S32 free_memory;
-        glGetIntegerv(GL_GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX, &free_memory);
-        gpu_res = (S32Megabytes)(free_memory / 1024);
-    }
 
-    gpu = gpu_res;
-    physical = physical_res;
+        gpu = gpu_res;
+        physical = physical_res;
+    }
 }
 
-static LLTrace::BlockTimerStatHandle FTM_TEXTURE_UPDATE_MEDIA("Media");
-static LLTrace::BlockTimerStatHandle FTM_TEXTURE_UPDATE_TEST("Test");
-
 //static
-void LLViewerTexture::updateClass(const F32 velocity, const F32 angular_velocity)
+void LLViewerTexture::updateClass()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	sCurrentTime = gFrameTimeSeconds;
 
 	LLTexturePipelineTester* tester = (LLTexturePipelineTester*)LLMetricPerformanceTesterBasic::getTester(sTesterName);
 	if (tester)
 	{
-		LL_RECORD_BLOCK_TIME(FTM_TEXTURE_UPDATE_TEST);
 		tester->update();
 	}
 
-	{
-		LL_RECORD_BLOCK_TIME(FTM_TEXTURE_UPDATE_MEDIA);
-		LLViewerMediaTexture::updateClass();
-	}
+	LLViewerMediaTexture::updateClass();
 
 	sBoundTextureMemory = LLImageGL::sBoundTextureMemory;
 	sTotalTextureMemory = LLImageGL::sGlobalTextureMemory;
@@ -680,6 +667,9 @@ void LLViewerTexture::init(bool firstinit)
 	
 	mVolumeList[LLRender::LIGHT_TEX].clear();
 	mVolumeList[LLRender::SCULPT_TEX].clear();
+
+	mMainQueue	= LL::WorkQueue::getInstance("mainloop");
+	mImageQueue = LL::WorkQueue::getInstance("LLImageGL");
 }
 
 //virtual 
@@ -701,6 +691,7 @@ void LLViewerTexture::cleanup()
 
 void LLViewerTexture::notifyAboutCreatingTexture()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	for(U32 ch = 0; ch < LLRender::NUM_TEXTURE_CHANNELS; ++ch)
 	{
 		for(U32 f = 0; f < mNumFaces[ch]; f++)
@@ -712,6 +703,7 @@ void LLViewerTexture::notifyAboutCreatingTexture()
 
 void LLViewerTexture::notifyAboutMissingAsset()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	for(U32 ch = 0; ch < LLRender::NUM_TEXTURE_CHANNELS; ++ch)
 	{
 		for(U32 f = 0; f < mNumFaces[ch]; f++)
@@ -724,6 +716,7 @@ void LLViewerTexture::notifyAboutMissingAsset()
 // virtual
 void LLViewerTexture::dump()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	LLGLTexture::dump();
 
 	LL_INFOS() << "LLViewerTexture"
@@ -759,6 +752,7 @@ bool LLViewerTexture::isActiveFetching()
 
 bool LLViewerTexture::bindDebugImage(const S32 stage)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	if (stage < 0) return false;
 
 	bool res = true;
@@ -777,6 +771,7 @@ bool LLViewerTexture::bindDebugImage(const S32 stage)
 
 bool LLViewerTexture::bindDefaultImage(S32 stage) 
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	if (stage < 0) return false;
 
 	bool res = true;
@@ -819,6 +814,7 @@ void LLViewerTexture::forceImmediateUpdate()
 
 void LLViewerTexture::addTextureStats(F32 virtual_size, BOOL needs_gltexture) const 
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	if(needs_gltexture)
 	{
 		mNeedsGLTexture = TRUE;
@@ -829,14 +825,14 @@ void LLViewerTexture::addTextureStats(F32 virtual_size, BOOL needs_gltexture) co
 	{
 		//flag to reset the values because the old values are used.
 		resetMaxVirtualSizeResetCounter();
-		mMaxVirtualSize = virtual_size;		
-		mAdditionalDecodePriority = 0.f;	
+		mMaxVirtualSize = virtual_size;
+		mAdditionalDecodePriority = 0.f;
 		mNeedsGLTexture = needs_gltexture;
 	}
 	else if (virtual_size > mMaxVirtualSize)
 	{
 		mMaxVirtualSize = virtual_size;
-	}	
+	}
 }
 
 void LLViewerTexture::resetTextureStats()
@@ -861,6 +857,7 @@ void LLViewerTexture::setKnownDrawSize(S32 width, S32 height)
 //virtual
 void LLViewerTexture::addFace(U32 ch, LLFace* facep) 
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	llassert(ch < LLRender::NUM_TEXTURE_CHANNELS);
 
 	if(mNumFaces[ch] >= mFaceList[ch].size())
@@ -876,6 +873,7 @@ void LLViewerTexture::addFace(U32 ch, LLFace* facep)
 //virtual
 void LLViewerTexture::removeFace(U32 ch, LLFace* facep) 
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	llassert(ch < LLRender::NUM_TEXTURE_CHANNELS);
 
 	if(mNumFaces[ch] > 1)
@@ -916,6 +914,7 @@ S32 LLViewerTexture::getNumFaces(U32 ch) const
 //virtual
 void LLViewerTexture::addVolume(U32 ch, LLVOVolume* volumep)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	if (mNumVolumes[ch] >= mVolumeList[ch].size())
 	{
 		mVolumeList[ch].resize(2 * mNumVolumes[ch] + 1);
@@ -929,6 +928,7 @@ void LLViewerTexture::addVolume(U32 ch, LLVOVolume* volumep)
 //virtual
 void LLViewerTexture::removeVolume(U32 ch, LLVOVolume* volumep)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	if (mNumVolumes[ch] > 1)
 	{
 		S32 index = volumep->getIndexInTex(ch); 
@@ -952,6 +952,7 @@ S32 LLViewerTexture::getNumVolumes(U32 ch) const
 
 void LLViewerTexture::reorganizeFaceList()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	static const F32 MAX_WAIT_TIME = 20.f; // seconds
 	static const U32 MAX_EXTRA_BUFFER_SIZE = 4;
 
@@ -975,6 +976,7 @@ void LLViewerTexture::reorganizeFaceList()
 
 void LLViewerTexture::reorganizeVolumeList()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	static const F32 MAX_WAIT_TIME = 20.f; // seconds
 	static const U32 MAX_EXTRA_BUFFER_SIZE = 4;
 
@@ -1116,7 +1118,7 @@ void LLViewerFetchedTexture::init(bool firstinit)
 	mLoadedCallbackDesiredDiscardLevel = S8_MAX;
 	mPauseLoadedCallBacks = FALSE;
 
-	mNeedsCreateTexture = FALSE;
+	mNeedsCreateTexture = false;
 	
 	mIsRawImageValid = FALSE;
 	mRawDiscardLevel = INVALID_DISCARD_LEVEL;
@@ -1177,6 +1179,7 @@ FTType LLViewerFetchedTexture::getFTType() const
 
 void LLViewerFetchedTexture::cleanup()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	for(callback_list_t::iterator iter = mLoadedCallbackList.begin();
 		iter != mLoadedCallbackList.end(); )
 	{
@@ -1202,6 +1205,7 @@ void LLViewerFetchedTexture::cleanup()
 //access the fast cache
 void LLViewerFetchedTexture::loadFromFastCache()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	if(!mInFastCacheList)
 	{
 		return; //no need to access the fast cache.
@@ -1347,6 +1351,7 @@ void LLViewerFetchedTexture::dump()
 // ONLY called from LLViewerFetchedTextureList
 void LLViewerFetchedTexture::destroyTexture() 
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	if(LLImageGL::sGlobalTextureMemory < sMaxDesiredTextureMem * 0.95f)//not ready to release unused memory.
 	{
 		return ;
@@ -1363,6 +1368,7 @@ void LLViewerFetchedTexture::destroyTexture()
 
 void LLViewerFetchedTexture::addToCreateTexture()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	bool force_update = false;
 	if (getComponents() != mRawImage->getComponents())
 	{
@@ -1394,16 +1400,17 @@ void LLViewerFetchedTexture::addToCreateTexture()
 	{
 		//just update some variables, not to create a real GL texture.
 		createGLTexture(mRawDiscardLevel, mRawImage, 0, FALSE);
-		mNeedsCreateTexture = FALSE;
+		mNeedsCreateTexture = false;
 		destroyRawImage();
 	}
 	else if(!force_update && getDiscardLevel() > -1 && getDiscardLevel() <= mRawDiscardLevel)
 	{
-		mNeedsCreateTexture = FALSE;
+		mNeedsCreateTexture = false;
 		destroyRawImage();
 	}
 	else
 	{	
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 #if 1
 		//
 		//if mRequestedDiscardLevel > mDesiredDiscardLevel, we assume the required image res keep going up,
@@ -1434,7 +1441,7 @@ void LLViewerFetchedTexture::addToCreateTexture()
 						mRawDiscardLevel += i;
 						if(mRawDiscardLevel >= getDiscardLevel() && getDiscardLevel() > 0)
 						{
-							mNeedsCreateTexture = FALSE;
+							mNeedsCreateTexture = false;
 							destroyRawImage();
 							return;
 						}
@@ -1448,99 +1455,104 @@ void LLViewerFetchedTexture::addToCreateTexture()
 			}
 		}
 #endif
-		mNeedsCreateTexture = TRUE;
-		gTextureList.mCreateTextureList.insert(this);
-	}	
+        scheduleCreateTexture();
+	}
 	return;
 }
 
 // ONLY called from LLViewerTextureList
-BOOL LLViewerFetchedTexture::createTexture(S32 usename/*= 0*/)
+BOOL LLViewerFetchedTexture::preCreateTexture(S32 usename/*= 0*/)
 {
-	if (!mNeedsCreateTexture)
-	{
-		destroyRawImage();
-		return FALSE;
-	}
-	mNeedsCreateTexture = FALSE;
-	if (mRawImage.isNull())
-	{
-		LL_ERRS() << "LLViewerTexture trying to create texture with no Raw Image" << LL_ENDL;
-	}
-	if (mRawImage->isBufferInvalid())
-	{
-		LL_WARNS() << "Can't create a texture: invalid image data" << LL_ENDL;
-		destroyRawImage();
-		return FALSE;
-	}
-// 	LL_INFOS() << llformat("IMAGE Creating (%d) [%d x %d] Bytes: %d ",
-// 						mRawDiscardLevel, 
-// 						mRawImage->getWidth(), mRawImage->getHeight(),mRawImage->getDataSize())
-// 			<< mID.getString() << LL_ENDL;
-	BOOL res = TRUE;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
+#if LL_IMAGEGL_THREAD_CHECK
+    mGLTexturep->checkActiveThread();
+#endif
 
-	// store original size only for locally-sourced images
-	if (mUrl.compare(0, 7, "file://") == 0)
-	{
-		mOrigWidth = mRawImage->getWidth();
-		mOrigHeight = mRawImage->getHeight();
+    if (!mNeedsCreateTexture)
+    {
+        destroyRawImage();
+        return FALSE;
+    }
+    mNeedsCreateTexture = false;
+
+    if (mRawImage.isNull())
+    {
+        LL_ERRS() << "LLViewerTexture trying to create texture with no Raw Image" << LL_ENDL;
+    }
+    if (mRawImage->isBufferInvalid())
+    {
+        LL_WARNS() << "Can't create a texture: invalid image data" << LL_ENDL;
+        destroyRawImage();
+        return FALSE;
+    }
+    // 	LL_INFOS() << llformat("IMAGE Creating (%d) [%d x %d] Bytes: %d ",
+    // 						mRawDiscardLevel, 
+    // 						mRawImage->getWidth(), mRawImage->getHeight(),mRawImage->getDataSize())
+    // 			<< mID.getString() << LL_ENDL;
+    BOOL res = TRUE;
+
+    // store original size only for locally-sourced images
+    if (mUrl.compare(0, 7, "file://") == 0)
+    {
+        mOrigWidth = mRawImage->getWidth();
+        mOrigHeight = mRawImage->getHeight();
 
         // This is only safe because it's a local image and fetcher doesn't use raw data
         // from local images, but this might become unsafe in case of changes to fetcher
-		if (mBoostLevel == BOOST_PREVIEW)
-		{ 
-			mRawImage->biasedScaleToPowerOfTwo(1024);
-		}
-		else
-		{ // leave black border, do not scale image content
-			mRawImage->expandToPowerOfTwo(MAX_IMAGE_SIZE, FALSE);
-		}
-		
-		mFullWidth = mRawImage->getWidth();
-		mFullHeight = mRawImage->getHeight();
-		setTexelsPerImage();
-	}
-	else
-	{
-		mOrigWidth = mFullWidth;
-		mOrigHeight = mFullHeight;
-	}
+        if (mBoostLevel == BOOST_PREVIEW)
+        {
+            mRawImage->biasedScaleToPowerOfTwo(1024);
+        }
+        else
+        { // leave black border, do not scale image content
+            mRawImage->expandToPowerOfTwo(MAX_IMAGE_SIZE, FALSE);
+        }
 
-	bool size_okay = true;
+        mFullWidth = mRawImage->getWidth();
+        mFullHeight = mRawImage->getHeight();
+        setTexelsPerImage();
+    }
+    else
+    {
+        mOrigWidth = mFullWidth;
+        mOrigHeight = mFullHeight;
+    }
 
-	S32 discard_level = mRawDiscardLevel;
-	if (mRawDiscardLevel < 0)
-	{
-		LL_DEBUGS() << "Negative raw discard level when creating image: " << mRawDiscardLevel << LL_ENDL;
-		discard_level = 0;
-	}
+    bool size_okay = true;
 
-	U32 raw_width = mRawImage->getWidth() << discard_level;
-	U32 raw_height = mRawImage->getHeight() << discard_level;
+    S32 discard_level = mRawDiscardLevel;
+    if (mRawDiscardLevel < 0)
+    {
+        LL_DEBUGS() << "Negative raw discard level when creating image: " << mRawDiscardLevel << LL_ENDL;
+        discard_level = 0;
+    }
 
-	if( raw_width > MAX_IMAGE_SIZE || raw_height > MAX_IMAGE_SIZE )
-	{
-		LL_INFOS() << "Width or height is greater than " << MAX_IMAGE_SIZE << ": (" << raw_width << "," << raw_height << ")" << LL_ENDL;
-		size_okay = false;
-	}
-	
-	if (!LLImageGL::checkSize(mRawImage->getWidth(), mRawImage->getHeight()))
-	{
-		// A non power-of-two image was uploaded (through a non standard client)
-		LL_INFOS() << "Non power of two width or height: (" << mRawImage->getWidth() << "," << mRawImage->getHeight() << ")" << LL_ENDL;
-		size_okay = false;
-	}
-	
-	if( !size_okay )
-	{
-		// An inappropriately-sized image was uploaded (through a non standard client)
-		// We treat these images as missing assets which causes them to
-		// be renderd as 'missing image' and to stop requesting data
-		LL_WARNS() << "!size_ok, setting as missing" << LL_ENDL;
-		setIsMissingAsset();
-		destroyRawImage();
-		return FALSE;
-	}
+    U32 raw_width = mRawImage->getWidth() << discard_level;
+    U32 raw_height = mRawImage->getHeight() << discard_level;
+
+    if (raw_width > MAX_IMAGE_SIZE || raw_height > MAX_IMAGE_SIZE)
+    {
+        LL_INFOS() << "Width or height is greater than " << MAX_IMAGE_SIZE << ": (" << raw_width << "," << raw_height << ")" << LL_ENDL;
+        size_okay = false;
+    }
+
+    if (!LLImageGL::checkSize(mRawImage->getWidth(), mRawImage->getHeight()))
+    {
+        // A non power-of-two image was uploaded (through a non standard client)
+        LL_INFOS() << "Non power of two width or height: (" << mRawImage->getWidth() << "," << mRawImage->getHeight() << ")" << LL_ENDL;
+        size_okay = false;
+    }
+
+    if (!size_okay)
+    {
+        // An inappropriately-sized image was uploaded (through a non standard client)
+        // We treat these images as missing assets which causes them to
+        // be renderd as 'missing image' and to stop requesting data
+        LL_WARNS() << "!size_ok, setting as missing" << LL_ENDL;
+        setIsMissingAsset();
+        destroyRawImage();
+        return FALSE;
+    }
 
     if (mGLTexturep->getHasExplicitFormat())
     {
@@ -1562,19 +1574,116 @@ BOOL LLViewerFetchedTexture::createTexture(S32 usename/*= 0*/)
         }
     }
 
-	res = mGLTexturep->createGLTexture(mRawDiscardLevel, mRawImage, usename, TRUE, mBoostLevel);
+    return res;
+}
 
-	notifyAboutCreatingTexture();
+BOOL LLViewerFetchedTexture::createTexture(S32 usename/*= 0*/)
+{
+    if (!mNeedsCreateTexture)
+    {
+        return FALSE;
+    }
 
-	setActive();
+	BOOL res = mGLTexturep->createGLTexture(mRawDiscardLevel, mRawImage, usename, TRUE, mBoostLevel);
+    
+	return res;
+}
 
-	if (!needsToSaveRawImage())
-	{
-		mNeedsAux = FALSE;
-		destroyRawImage();
-	}
+void LLViewerFetchedTexture::postCreateTexture()
+{
+    if (!mNeedsCreateTexture)
+    {
+        return;
+    }
+#if LL_IMAGEGL_THREAD_CHECK
+    mGLTexturep->checkActiveThread();
+#endif
 
-	return res;
+    notifyAboutCreatingTexture();
+
+    setActive();
+
+    if (!needsToSaveRawImage())
+    {
+        mNeedsAux = FALSE;
+        destroyRawImage();
+    }
+
+    mNeedsCreateTexture = false;
+}
+
+void LLViewerFetchedTexture::scheduleCreateTexture()
+{
+    if (!mNeedsCreateTexture)
+    {
+        mNeedsCreateTexture = true;
+        if (preCreateTexture())
+        {
+#if LL_IMAGEGL_THREAD_CHECK
+            //grab a copy of the raw image data to make sure it isn't modified pending texture creation
+            U8* data = mRawImage->getData();
+            U8* data_copy = nullptr;
+            S32 size = mRawImage->getDataSize();
+            if (data != nullptr && size > 0)
+            {
+                data_copy = new U8[size];
+                memcpy(data_copy, data, size);
+            }
+#endif
+            mNeedsCreateTexture = true;
+            auto mainq = LLImageGLThread::sEnabled ? mMainQueue.lock() : nullptr;
+            if (mainq)
+            {
+                ref();
+                mainq->postTo(
+                    mImageQueue,
+                    // work to be done on LLImageGL worker thread
+#if LL_IMAGEGL_THREAD_CHECK
+                    [this, data, data_copy, size]()
+                    {
+                        mGLTexturep->mActiveThread = LLThread::currentID();
+                        //verify data is unmodified
+                        llassert(data == mRawImage->getData());
+                        llassert(mRawImage->getDataSize() == size);
+                        llassert(memcmp(data, data_copy, size) == 0);
+#else
+                    [this]()
+                    {
+#endif
+                        //actually create the texture on a background thread
+                        createTexture();
+
+#if LL_IMAGEGL_THREAD_CHECK
+                        //verify data is unmodified
+                        llassert(data == mRawImage->getData());
+                        llassert(mRawImage->getDataSize() == size);
+                        llassert(memcmp(data, data_copy, size) == 0);
+#endif
+                    },
+                    // callback to be run on main thread
+#if LL_IMAGEGL_THREAD_CHECK
+                        [this, data, data_copy, size]()
+                    {
+                        mGLTexturep->mActiveThread = LLThread::currentID();
+                        llassert(data == mRawImage->getData());
+                        llassert(mRawImage->getDataSize() == size);
+                        llassert(memcmp(data, data_copy, size) == 0);
+                        delete[] data_copy;
+#else
+                        [this]()
+                        {
+#endif
+                        //finalize on main thread
+                        postCreateTexture();
+                        unref();
+                    });
+            }
+            else
+            {
+                gTextureList.mCreateTextureList.insert(this);
+            }
+        }
+    }
 }
 
 // Call with 0,0 to turn this feature off.
@@ -1866,6 +1975,7 @@ void LLViewerFetchedTexture::setAdditionalDecodePriority(F32 priority)
 
 void LLViewerFetchedTexture::updateVirtualSize() 
 {	
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	if(!mMaxVirtualSizeResetCounter)
 	{
 		addTextureStats(0.f, FALSE);//reset
@@ -1957,6 +2067,7 @@ bool LLViewerFetchedTexture::isActiveFetching()
 
 bool LLViewerFetchedTexture::updateFetch()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	static LLCachedControl<bool> textures_decode_disabled(gSavedSettings,"TextureDecodeDisabled", false);
 	static LLCachedControl<F32>  sCameraMotionThreshold(gSavedSettings,"TextureCameraMotionThreshold", 0.2);
 	static LLCachedControl<S32>  sCameraMotionBoost(gSavedSettings,"TextureCameraMotionBoost", 3);
@@ -2059,7 +2170,7 @@ bool LLViewerFetchedTexture::updateFetch()
 				}
 				else
 				{
-					mIsRawImageValid = TRUE;			
+					mIsRawImageValid = TRUE;
 					addToCreateTexture();
 				}
 
@@ -2537,6 +2648,7 @@ void LLViewerFetchedTexture::pauseLoadedCallbacks(const LLLoadedCallbackEntry::s
 
 bool LLViewerFetchedTexture::doLoadedCallbacks()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	static const F32 MAX_INACTIVE_TIME = 900.f ; //seconds
 	static const F32 MAX_IDLE_WAIT_TIME = 5.f ; //seconds
 
@@ -2887,7 +2999,9 @@ void LLViewerFetchedTexture::destroyRawImage()
 //virtual
 void LLViewerFetchedTexture::switchToCachedImage()
 {
-	if(mCachedRawImage.notNull())
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
+	if(mCachedRawImage.notNull() && 
+        !mNeedsCreateTexture) // <--- texture creation is pending, don't step on it
 	{
 		mRawImage = mCachedRawImage;
 						
@@ -2898,12 +3012,12 @@ void LLViewerFetchedTexture::switchToCachedImage()
 			mComponents = mRawImage->getComponents();
 			mGLTexturep->setComponents(mComponents);
 			gTextureList.dirtyImage(this);
-		}			
+		}
 
 		mIsRawImageValid = TRUE;
 		mRawDiscardLevel = mCachedRawDiscardLevel;
-		gTextureList.mCreateTextureList.insert(this);
-		mNeedsCreateTexture = TRUE;		
+
+        scheduleCreateTexture();
 	}
 }
 
@@ -3177,6 +3291,7 @@ bool LLViewerLODTexture::isUpdateFrozen()
 //virtual
 void LLViewerLODTexture::processTextureStats()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	updateVirtualSize();
 	
 	static LLCachedControl<bool> textures_fullres(gSavedSettings,"TextureLoadFullRes", false);
@@ -3340,6 +3455,7 @@ bool LLViewerLODTexture::scaleDown()
 //static
 void LLViewerMediaTexture::updateClass()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	static const F32 MAX_INACTIVE_TIME = 30.f;
 
 #if 0
diff --git a/indra/newview/llviewertexture.h b/indra/newview/llviewertexture.h
index 0de49073c8fa062421de07f776e3709da1fb49cb..2f5e0d01dfd494a4a8198332ac1c7c9fa80f9dc3 100644
--- a/indra/newview/llviewertexture.h
+++ b/indra/newview/llviewertexture.h
@@ -27,6 +27,7 @@
 #ifndef LL_LLVIEWERTEXTURE_H					
 #define LL_LLVIEWERTEXTURE_H
 
+#include "llatomic.h"
 #include "llgltexture.h"
 #include "lltimer.h"
 #include "llframetimer.h"
@@ -35,6 +36,7 @@
 #include "llrender.h"
 #include "llmetricperformancetester.h"
 #include "httpcommon.h"
+#include "workqueue.h"
 
 #include <map>
 #include <list>
@@ -114,7 +116,7 @@ class LLViewerTexture : public LLGLTexture
 
 public:	
 	static void initClass();
-	static void updateClass(const F32 velocity, const F32 angular_velocity) ;
+	static void updateClass();
 	
 	LLViewerTexture(BOOL usemipmaps = TRUE);
 	LLViewerTexture(const LLUUID& id, BOOL usemipmaps) ;
@@ -213,6 +215,9 @@ class LLViewerTexture : public LLGLTexture
 	//do not use LLPointer here.
 	LLViewerMediaTexture* mParcelMedia ;
 
+	LL::WorkQueue::weak_t mMainQueue;
+	LL::WorkQueue::weak_t mImageQueue;
+
 	static F32 sTexelPixelRatio;
 public:
 	static const U32 sCurrentFileVersion;	
@@ -321,9 +326,13 @@ class LLViewerFetchedTexture : public LLViewerTexture
 
 	void addToCreateTexture();
 
-
-	 // ONLY call from LLViewerTextureList
+    //call to determine if createTexture is necessary
+    BOOL preCreateTexture(S32 usename = 0);
+	 // ONLY call from LLViewerTextureList or ImageGL background thread
 	BOOL createTexture(S32 usename = 0);
+    void postCreateTexture();
+    void scheduleCreateTexture();
+
 	void destroyTexture() ;
 
 	virtual void processTextureStats() ;
@@ -520,7 +529,9 @@ class LLViewerFetchedTexture : public LLViewerTexture
 	LLFrameTimer mStopFetchingTimer;	// Time since mDecodePriority == 0.f.
 
 	BOOL  mInImageList;				// TRUE if image is in list (in which case don't reset priority!)
-	BOOL  mNeedsCreateTexture;	
+	// This needs to be atomic, since it is written both in the main thread
+	// and in the GL image worker thread... HB
+	LLAtomicBool  mNeedsCreateTexture;	
 
 	BOOL   mForSculpt ; //a flag if the texture is used as sculpt data.
 	BOOL   mIsFetched ; //is loaded from remote or from cache, not generated locally.
diff --git a/indra/newview/llviewertexturelist.cpp b/indra/newview/llviewertexturelist.cpp
index 37344056e10ac4c600c4d84a48ebfb60e0f0757c..da3c860ddbc63fcc287d4a6e77e6a7185fe7fe84 100644
--- a/indra/newview/llviewertexturelist.cpp
+++ b/indra/newview/llviewertexturelist.cpp
@@ -66,7 +66,6 @@ void (*LLViewerTextureList::sUUIDCallback)(void **, const LLUUID&) = NULL;
 S32 LLViewerTextureList::sNumImages = 0;
 
 LLViewerTextureList gTextureList;
-static LLTrace::BlockTimerStatHandle FTM_PROCESS_IMAGES("Process Images");
 
 ETexListType get_element_type(S32 priority)
 {
@@ -112,6 +111,7 @@ void LLViewerTextureList::init()
 
 void LLViewerTextureList::doPreloadImages()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	LL_DEBUGS("ViewerImages") << "Preloading images..." << LL_ENDL;
 	
 	llassert_always(mInitialized) ;
@@ -203,6 +203,7 @@ static std::string get_texture_list_name()
 
 void LLViewerTextureList::doPrefetchImages()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	gTextureTimer.start();
 	gTextureTimer.pause();
 
@@ -259,6 +260,7 @@ LLViewerTextureList::~LLViewerTextureList()
 
 void LLViewerTextureList::shutdown()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	// clear out preloads
 	mImagePreloads.clear();
 
@@ -334,6 +336,7 @@ void LLViewerTextureList::shutdown()
 
 void LLViewerTextureList::dump()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	LL_INFOS() << "LLViewerTextureList::dump()" << LL_ENDL;
 	for (image_priority_list_t::iterator it = mImageList.begin(); it != mImageList.end(); ++it)
 	{
@@ -378,6 +381,7 @@ LLViewerFetchedTexture* LLViewerTextureList::getImageFromFile(const std::string&
 												   LLGLenum primary_format, 
 												   const LLUUID& force_id)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	if(!mInitialized)
 	{
 		return NULL ;
@@ -405,6 +409,7 @@ LLViewerFetchedTexture* LLViewerTextureList::getImageFromUrl(const std::string&
 												   LLGLenum primary_format, 
 												   const LLUUID& force_id)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	if(!mInitialized)
 	{
 		return NULL ;
@@ -493,6 +498,7 @@ LLViewerFetchedTexture* LLViewerTextureList::getImage(const LLUUID &image_id,
 												   LLGLenum primary_format,
 												   LLHost request_from_host)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	if(!mInitialized)
 	{
 		return NULL ;
@@ -555,6 +561,7 @@ LLViewerFetchedTexture* LLViewerTextureList::createImage(const LLUUID &image_id,
 												   LLGLenum primary_format,
 												   LLHost request_from_host)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	static LLCachedControl<bool> fast_cache_fetching_enabled(gSavedSettings, "FastCacheFetchEnabled", true);
 
 	LLPointer<LLViewerFetchedTexture> imagep ;
@@ -610,6 +617,7 @@ LLViewerFetchedTexture* LLViewerTextureList::createImage(const LLUUID &image_id,
 
 void LLViewerTextureList::findTexturesByID(const LLUUID &image_id, std::vector<LLViewerFetchedTexture*> &output)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
     LLTextureKey search_key(image_id, TEX_LIST_STANDARD);
     uuid_map_t::iterator iter = mUUIDMap.lower_bound(search_key);
     while (iter != mUUIDMap.end() && iter->first.textureId == image_id)
@@ -621,6 +629,7 @@ void LLViewerTextureList::findTexturesByID(const LLUUID &image_id, std::vector<L
 
 LLViewerFetchedTexture *LLViewerTextureList::findImage(const LLTextureKey &search_key)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
     uuid_map_t::iterator iter = mUUIDMap.find(search_key);
     if (iter == mUUIDMap.end())
         return NULL;
@@ -634,6 +643,7 @@ LLViewerFetchedTexture *LLViewerTextureList::findImage(const LLUUID &image_id, E
 
 void LLViewerTextureList::addImageToList(LLViewerFetchedTexture *image)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	assert_main_thread();
 	llassert_always(mInitialized) ;
 	llassert(image);
@@ -653,6 +663,7 @@ void LLViewerTextureList::addImageToList(LLViewerFetchedTexture *image)
 
 void LLViewerTextureList::removeImageFromList(LLViewerFetchedTexture *image)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	assert_main_thread();
 	llassert_always(mInitialized) ;
 	llassert(image);
@@ -701,6 +712,7 @@ void LLViewerTextureList::removeImageFromList(LLViewerFetchedTexture *image)
 
 void LLViewerTextureList::addImage(LLViewerFetchedTexture *new_image, ETexListType tex_type)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	if (!new_image)
 	{
 		return;
@@ -724,6 +736,7 @@ void LLViewerTextureList::addImage(LLViewerFetchedTexture *new_image, ETexListTy
 
 void LLViewerTextureList::deleteImage(LLViewerFetchedTexture *image)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	if( image)
 	{
 		if (image->hasCallbacks())
@@ -748,18 +761,10 @@ void LLViewerTextureList::dirtyImage(LLViewerFetchedTexture *image)
 }
 
 ////////////////////////////////////////////////////////////////////////////
-static LLTrace::BlockTimerStatHandle FTM_IMAGE_MARK_DIRTY("Dirty Images");
-static LLTrace::BlockTimerStatHandle FTM_IMAGE_UPDATE_PRIORITIES("Prioritize");
-static LLTrace::BlockTimerStatHandle FTM_IMAGE_CALLBACKS("Callbacks");
-static LLTrace::BlockTimerStatHandle FTM_IMAGE_FETCH("Fetch");
-static LLTrace::BlockTimerStatHandle FTM_FAST_CACHE_IMAGE_FETCH("Fast Cache Fetch");
-static LLTrace::BlockTimerStatHandle FTM_IMAGE_CREATE("Create");
-static LLTrace::BlockTimerStatHandle FTM_IMAGE_STATS("Stats");
-static LLTrace::BlockTimerStatHandle FTM_UPDATE_TEXTURES("Update Textures");
 
 void LLViewerTextureList::updateImages(F32 max_time)
 {
-	LL_RECORD_BLOCK_TIME(FTM_UPDATE_TEXTURES);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	static BOOL cleared = FALSE;
 	if(gTeleportDisplay)
 	{
@@ -785,66 +790,49 @@ void LLViewerTextureList::updateImages(F32 max_time)
 		sample(FORMATTED_MEM, F64Bytes(LLImageFormatted::sGlobalFormattedMemory));
 	}
 
-	{
-		//loading from fast cache 
-		LL_RECORD_BLOCK_TIME(FTM_FAST_CACHE_IMAGE_FETCH);
-		max_time -= updateImagesLoadingFastCache(max_time);
-	}
-
-	{
-		LL_RECORD_BLOCK_TIME(FTM_IMAGE_UPDATE_PRIORITIES);
-		updateImagesDecodePriorities();
-	}
-
-	F32 total_max_time = max_time;
-
-	{
-		LL_RECORD_BLOCK_TIME(FTM_IMAGE_FETCH);
-		max_time -= updateImagesFetchTextures(max_time);
-	}
+	//loading from fast cache 
+	max_time -= updateImagesLoadingFastCache(max_time);
 	
-	{
-		LL_RECORD_BLOCK_TIME(FTM_IMAGE_CREATE);
-		max_time = llmax(max_time, total_max_time*.50f); // at least 50% of max_time
-		max_time -= updateImagesCreateTextures(max_time);
-	}
+	updateImagesDecodePriorities();
+	
+    F32 total_max_time = max_time;
+
+	max_time -= updateImagesFetchTextures(max_time);
+		
+	max_time = llmax(max_time, total_max_time*.50f); // at least 50% of max_time
+	max_time -= updateImagesCreateTextures(max_time);
 	
 	if (!mDirtyTextureList.empty())
 	{
-		LL_RECORD_BLOCK_TIME(FTM_IMAGE_MARK_DIRTY);
 		gPipeline.dirtyPoolObjectTextures(mDirtyTextureList);
 		mDirtyTextureList.clear();
 	}
 
+	bool didone = false;
+	for (image_list_t::iterator iter = mCallbackList.begin();
+		iter != mCallbackList.end(); )
 	{
-		LL_RECORD_BLOCK_TIME(FTM_IMAGE_CALLBACKS);
-		bool didone = false;
-		for (image_list_t::iterator iter = mCallbackList.begin();
-			iter != mCallbackList.end(); )
+		//trigger loaded callbacks on local textures immediately
+		LLViewerFetchedTexture* image = *iter++;
+		if (!image->getUrl().empty())
 		{
-			//trigger loaded callbacks on local textures immediately
-			LLViewerFetchedTexture* image = *iter++;
-			if (!image->getUrl().empty())
-			{
-				// Do stuff to handle callbacks, update priorities, etc.
-				didone = image->doLoadedCallbacks();
-			}
-			else if (!didone)
-			{
-				// Do stuff to handle callbacks, update priorities, etc.
-				didone = image->doLoadedCallbacks();
-			}
+			// Do stuff to handle callbacks, update priorities, etc.
+			didone = image->doLoadedCallbacks();
+		}
+		else if (!didone)
+		{
+			// Do stuff to handle callbacks, update priorities, etc.
+			didone = image->doLoadedCallbacks();
 		}
 	}
+	
 
-	{
-		LL_RECORD_BLOCK_TIME(FTM_IMAGE_STATS);
-		updateImagesUpdateStats();
-	}
+	updateImagesUpdateStats();
 }
 
 void LLViewerTextureList::clearFetchingRequests()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	if (LLAppViewer::getTextureFetch()->getNumRequests() == 0)
 	{
 		return;
@@ -862,6 +850,7 @@ void LLViewerTextureList::clearFetchingRequests()
 
 void LLViewerTextureList::updateImagesDecodePriorities()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	// Update the decode priority for N images each frame
 	{
 		F32 lazy_flush_timeout = 30.f; // stop decoding
@@ -977,6 +966,7 @@ void LLViewerTextureList::updateImagesDecodePriorities()
 
 void LLViewerTextureList::setDebugFetching(LLViewerFetchedTexture* tex, S32 debug_level)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	if(!tex->setDebugFetching(debug_level))
 	{
 		return;
@@ -1025,6 +1015,7 @@ void LLViewerTextureList::setDebugFetching(LLViewerFetchedTexture* tex, S32 debu
 
 F32 LLViewerTextureList::updateImagesCreateTextures(F32 max_time)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	if (gGLManager.mIsDisabled) return 0.0f;
 	
 	//
@@ -1041,6 +1032,7 @@ F32 LLViewerTextureList::updateImagesCreateTextures(F32 max_time)
 		enditer = iter;
 		LLViewerFetchedTexture *imagep = *curiter;
 		imagep->createTexture();
+        imagep->postCreateTexture();
 		if (create_timer.getElapsedTimeF32() > max_time)
 		{
 			break;
@@ -1052,6 +1044,7 @@ F32 LLViewerTextureList::updateImagesCreateTextures(F32 max_time)
 
 F32 LLViewerTextureList::updateImagesLoadingFastCache(F32 max_time)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	if (gGLManager.mIsDisabled) return 0.0f;
 	if(mFastCacheList.empty())
 	{
@@ -1082,6 +1075,7 @@ F32 LLViewerTextureList::updateImagesLoadingFastCache(F32 max_time)
 
 void LLViewerTextureList::forceImmediateUpdate(LLViewerFetchedTexture* imagep)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	if(!imagep)
 	{
 		return ;
@@ -1101,6 +1095,7 @@ void LLViewerTextureList::forceImmediateUpdate(LLViewerFetchedTexture* imagep)
 
 F32 LLViewerTextureList::updateImagesFetchTextures(F32 max_time)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	LLTimer image_op_timer;
 	
 	// Update fetch for N images each frame
@@ -1153,15 +1148,14 @@ F32 LLViewerTextureList::updateImagesFetchTextures(F32 max_time)
 			total_update_count--;
 		}
 	}
-	
-	S32 fetch_count = 0;
+
 	size_t min_update_count = llmin(MIN_UPDATE_COUNT,(S32)(entries.size()-max_priority_count));
 	S32 min_count = max_priority_count + min_update_count;
 	for (entries_list_t::iterator iter3 = entries.begin();
 		 iter3 != entries.end(); )
 	{
 		LLViewerFetchedTexture* imagep = *iter3++;
-		fetch_count += (imagep->updateFetch() ? 1 : 0);
+        imagep->updateFetch();
 		if (min_count <= min_update_count)
 		{
 			mLastFetchKey = LLTextureKey(imagep->getID(), (ETexListType)imagep->getTextureListType());
@@ -1176,6 +1170,7 @@ F32 LLViewerTextureList::updateImagesFetchTextures(F32 max_time)
 
 void LLViewerTextureList::updateImagesUpdateStats()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	if (mForceResetTextureStats)
 	{
 		for (image_priority_list_t::iterator iter = mImageList.begin();
@@ -1190,6 +1185,7 @@ void LLViewerTextureList::updateImagesUpdateStats()
 
 void LLViewerTextureList::decodeAllImages(F32 max_time)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	LLTimer timer;
 
 	//loading from fast cache 
@@ -1225,6 +1221,7 @@ void LLViewerTextureList::decodeAllImages(F32 max_time)
 		LLViewerFetchedTexture* imagep = *iter++;
 		imagep->updateFetch();
 	}
+    std::shared_ptr<LL::WorkQueue> main_queue = LLImageGLThread::sEnabled ? LL::WorkQueue::getInstance("mainloop") : NULL;
 	// Run threads
 	S32 fetch_pending = 0;
 	while (1)
@@ -1232,6 +1229,13 @@ void LLViewerTextureList::decodeAllImages(F32 max_time)
 		LLAppViewer::instance()->getTextureCache()->update(1); // unpauses the texture cache thread
 		LLAppViewer::instance()->getImageDecodeThread()->update(1); // unpauses the image thread
 		fetch_pending = LLAppViewer::instance()->getTextureFetch()->update(1); // unpauses the texture fetch thread
+
+        if (LLImageGLThread::sEnabled)
+        {
+            main_queue->runFor(std::chrono::milliseconds(1));
+            fetch_pending += main_queue->size();
+        }
+
 		if (fetch_pending == 0 || timer.getElapsedTimeF32() > max_time)
 		{
 			break;
@@ -1257,13 +1261,15 @@ void LLViewerTextureList::decodeAllImages(F32 max_time)
 
 BOOL LLViewerTextureList::createUploadFile(const std::string& filename,
 										 const std::string& out_filename,
-										 const U8 codec)
+										 const U8 codec,
+										 const S32 max_image_dimentions)
 {	
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	// Load the image
 	LLPointer<LLImageFormatted> image = LLImageFormatted::createFromType(codec);
 	if (image.isNull())
 	{
-		image->setLastError("Couldn't open the image to be uploaded.");
+		LL_WARNS() << "Couldn't open the image to be uploaded." << LL_ENDL;
 		return FALSE;
 	}	
 	if (!image->load(filename))
@@ -1285,7 +1291,7 @@ BOOL LLViewerTextureList::createUploadFile(const std::string& filename,
 		return FALSE;
 	}
 	// Convert to j2c (JPEG2000) and save the file locally
-	LLPointer<LLImageJ2C> compressedImage = convertToUploadFile(raw_image);	
+	LLPointer<LLImageJ2C> compressedImage = convertToUploadFile(raw_image, max_image_dimentions);
 	if (compressedImage.isNull())
 	{
 		image->setLastError("Couldn't convert the image to jpeg2000.");
@@ -1310,9 +1316,10 @@ BOOL LLViewerTextureList::createUploadFile(const std::string& filename,
 }
 
 // note: modifies the argument raw_image!!!!
-LLPointer<LLImageJ2C> LLViewerTextureList::convertToUploadFile(LLPointer<LLImageRaw> raw_image)
+LLPointer<LLImageJ2C> LLViewerTextureList::convertToUploadFile(LLPointer<LLImageRaw> raw_image, const S32 max_image_dimentions)
 {
-	raw_image->biasedScaleToPowerOfTwo(LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT);
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
+	raw_image->biasedScaleToPowerOfTwo(max_image_dimentions);
 	LLPointer<LLImageJ2C> compressedImage = new LLImageJ2C();
 	
 	if (gSavedSettings.getBOOL("LosslessJ2CUpload") &&
@@ -1345,6 +1352,7 @@ LLPointer<LLImageJ2C> LLViewerTextureList::convertToUploadFile(LLPointer<LLImage
 // Returns min setting for TextureMemory (in MB)
 S32Megabytes LLViewerTextureList::getMinVideoRamSetting()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	U32Megabytes system_ram = gSysMemory.getPhysicalMemoryKB();
 	//min texture mem sets to 64M if total physical mem is more than 1.5GB
 	return (system_ram > U32Megabytes(1500)) ? S32Megabytes(64) : gMinVideoRam ;
@@ -1354,6 +1362,7 @@ S32Megabytes LLViewerTextureList::getMinVideoRamSetting()
 // Returns max setting for TextureMemory (in MB)
 S32Megabytes LLViewerTextureList::getMaxVideoRamSetting(bool get_recommended, float mem_multiplier)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	S32Megabytes max_texmem;
 	if (gGLManager.mVRAM != 0)
 	{
@@ -1361,7 +1370,7 @@ S32Megabytes LLViewerTextureList::getMaxVideoRamSetting(bool get_recommended, fl
 		//  - it's going to be swapping constantly regardless
 		S32Megabytes max_vram(gGLManager.mVRAM);
 
-		if(gGLManager.mIsATI)
+		if(gGLManager.mIsAMD)
 		{
 			//shrink the availabe vram for ATI cards because some of them do not handel texture swapping well.
 			max_vram = max_vram * 0.75f; 
@@ -1434,6 +1443,7 @@ const S32Megabytes VIDEO_CARD_FRAMEBUFFER_MEM(12);
 const S32Megabytes MIN_MEM_FOR_NON_TEXTURE(512);
 void LLViewerTextureList::updateMaxResidentTexMem(S32Megabytes mem)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	// Initialize the image pipeline VRAM settings
 	S32Megabytes cur_mem(gSavedSettings.getS32("TextureMemory"));
 	F32 mem_multiplier = gSavedSettings.getF32("RenderTextureMemoryMultiple");
@@ -1496,8 +1506,8 @@ void LLViewerTextureList::receiveImageHeader(LLMessageSystem *msg, void **user_d
 {
 	static LLCachedControl<bool> log_texture_traffic(gSavedSettings,"LogTextureNetworkTraffic", false) ;
 
-	LL_RECORD_BLOCK_TIME(FTM_PROCESS_IMAGES);
-	
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
+
 	// Receive image header, copy into image object and decompresses 
 	// if this is a one-packet image. 
 	
@@ -1568,7 +1578,7 @@ void LLViewerTextureList::receiveImagePacket(LLMessageSystem *msg, void **user_d
 {
 	static LLCachedControl<bool> log_texture_traffic(gSavedSettings,"LogTextureNetworkTraffic", false) ;
 
-	LL_RECORD_BLOCK_TIME(FTM_PROCESS_IMAGES);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	
 	// Receives image packet, copy into image object,
 	// checks if all packets received, decompresses if so. 
@@ -1641,7 +1651,7 @@ void LLViewerTextureList::receiveImagePacket(LLMessageSystem *msg, void **user_d
 // static
 void LLViewerTextureList::processImageNotInDatabase(LLMessageSystem *msg,void **user_data)
 {
-	LL_RECORD_BLOCK_TIME(FTM_PROCESS_IMAGES);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	LLUUID image_id;
 	msg->getUUIDFast(_PREHASH_ImageID, _PREHASH_ID, image_id);
 	
@@ -1674,6 +1684,7 @@ void LLUIImageList::cleanUp()
 
 LLUIImagePtr LLUIImageList::getUIImageByID(const LLUUID& image_id, S32 priority)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	// use id as image name
 	std::string image_name = image_id.asString();
 
@@ -1692,6 +1703,7 @@ LLUIImagePtr LLUIImageList::getUIImageByID(const LLUUID& image_id, S32 priority)
 
 LLUIImagePtr LLUIImageList::getUIImage(const std::string& image_name, S32 priority)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	// look for existing image
 	uuid_ui_image_map_t::iterator found_it = mUIImages.find(image_name);
 	if (found_it != mUIImages.end())
@@ -1709,6 +1721,7 @@ LLUIImagePtr LLUIImageList::loadUIImageByName(const std::string& name, const std
 											  BOOL use_mips, const LLRect& scale_rect, const LLRect& clip_rect, LLViewerTexture::EBoostLevel boost_priority,
 											  LLUIImage::EScaleStyle scale_style)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	if (boost_priority == LLGLTexture::BOOST_NONE)
 	{
 		boost_priority = LLGLTexture::BOOST_UI;
@@ -1721,6 +1734,7 @@ LLUIImagePtr LLUIImageList::loadUIImageByID(const LLUUID& id,
 											BOOL use_mips, const LLRect& scale_rect, const LLRect& clip_rect, LLViewerTexture::EBoostLevel boost_priority,
 											LLUIImage::EScaleStyle scale_style)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	if (boost_priority == LLGLTexture::BOOST_NONE)
 	{
 		boost_priority = LLGLTexture::BOOST_UI;
@@ -1732,6 +1746,7 @@ LLUIImagePtr LLUIImageList::loadUIImageByID(const LLUUID& id,
 LLUIImagePtr LLUIImageList::loadUIImage(LLViewerFetchedTexture* imagep, const std::string& name, BOOL use_mips, const LLRect& scale_rect, const LLRect& clip_rect,
 										LLUIImage::EScaleStyle scale_style)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	if (!imagep) return NULL;
 
 	imagep->setAddressMode(LLTexUnit::TAM_CLAMP);
@@ -1769,6 +1784,7 @@ LLUIImagePtr LLUIImageList::loadUIImage(LLViewerFetchedTexture* imagep, const st
 
 LLUIImagePtr LLUIImageList::preloadUIImage(const std::string& name, const std::string& filename, BOOL use_mips, const LLRect& scale_rect, const LLRect& clip_rect, LLUIImage::EScaleStyle scale_style)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	// look for existing image
 	uuid_ui_image_map_t::iterator found_it = mUIImages.find(name);
 	if (found_it != mUIImages.end())
@@ -1783,6 +1799,7 @@ LLUIImagePtr LLUIImageList::preloadUIImage(const std::string& name, const std::s
 //static 
 void LLUIImageList::onUIImageLoaded( BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* src_aux, S32 discard_level, BOOL final, void* user_data )
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	if(!success || !user_data) 
 	{
 		return;
@@ -1884,6 +1901,7 @@ struct UIImageDeclarations : public LLInitParam::Block<UIImageDeclarations>
 
 bool LLUIImageList::initFromFile()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	// Look for textures.xml in all the right places. Pass
 	// constraint=LLDir::ALL_SKINS because we want to overlay textures.xml
 	// from all the skins directories.
@@ -1958,9 +1976,18 @@ bool LLUIImageList::initFromFile()
 			preloadUIImage(image.name, file_name, image.use_mips, image.scale, image.clip, image.scale_type);
 		}
 
-		if (cur_pass == PASS_DECODE_NOW && !gSavedSettings.getBOOL("NoPreload"))
+		if (!gSavedSettings.getBOOL("NoPreload"))
 		{
-			gTextureList.decodeAllImages(10.f); // decode preloaded images
+            if (cur_pass == PASS_DECODE_NOW)
+            {
+                // init fetching and decoding of preloaded images
+                gTextureList.decodeAllImages(9.f);
+            }
+            else
+            {
+                // decodeAllImages needs two passes to refresh stats and priorities on second pass
+                gTextureList.decodeAllImages(1.f);
+            }
 		}
 	}
 	return true;
diff --git a/indra/newview/llviewertexturelist.h b/indra/newview/llviewertexturelist.h
index fead2e52b29ea9381b465afd30ebc122ce349bbb..6fb0d3552e65a4d853c31a02c247c38de87bab71 100644
--- a/indra/newview/llviewertexturelist.h
+++ b/indra/newview/llviewertexturelist.h
@@ -92,8 +92,11 @@ class LLViewerTextureList
 	friend class LLLocalBitmap;
 	
 public:
-	static BOOL createUploadFile(const std::string& filename, const std::string& out_filename, const U8 codec);
-	static LLPointer<LLImageJ2C> convertToUploadFile(LLPointer<LLImageRaw> raw_image);
+    static BOOL createUploadFile(const std::string& filename,
+                                 const std::string& out_filename,
+                                 const U8 codec,
+                                 const S32 max_image_dimentions = LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT);
+	static LLPointer<LLImageJ2C> convertToUploadFile(LLPointer<LLImageRaw> raw_image, const S32 max_image_dimentions = LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT);
 	static void processImageNotInDatabase( LLMessageSystem *msg, void **user_data );
 	static void receiveImageHeader(LLMessageSystem *msg, void **user_data);
 	static void receiveImagePacket(LLMessageSystem *msg, void **user_data);
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index 050fb454ad37e36d41faae651c990ee0c4306f1f..8a7d5f12d0da13ecfe2446e4d4e53512a70901e2 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -103,7 +103,6 @@
 #include "llfilepicker.h"
 #include "llfirstuse.h"
 #include "llfloater.h"
-#include "llfloaterbuildoptions.h"
 #include "llfloaterbuyland.h"
 #include "llfloatercamera.h"
 #include "llfloaterland.h"
@@ -609,12 +608,6 @@ class LLDebugText
 		{
 			LLTrace::Recording& last_frame_recording = LLTrace::get_frame_recording().getLastRecording();
 
-			if (gPipeline.getUseVertexShaders() == 0)
-			{
-				addText(xpos, ypos, "Shaders Disabled");
-				ypos += y_inc;
-			}
-
 			if (gGLManager.mHasATIMemInfo)
 			{
 				S32 meminfo[4];
@@ -779,6 +772,12 @@ class LLDebugText
 				ypos += y_inc;
 
 				addText(xpos, ypos, llformat("%.3f/%.3f MB Mesh Cache Read/Write ", LLMeshRepository::sCacheBytesRead/(1024.f*1024.f), LLMeshRepository::sCacheBytesWritten/(1024.f*1024.f)));
+                ypos += y_inc;
+
+                addText(xpos, ypos, llformat("%.3f/%.3f MB Mesh Skins/Decompositions Memory", LLMeshRepository::sCacheBytesSkins / (1024.f*1024.f), LLMeshRepository::sCacheBytesDecomps / (1024.f*1024.f)));
+                ypos += y_inc;
+
+                addText(xpos, ypos, llformat("%.3f MB Mesh Headers Memory", LLMeshRepository::sCacheBytesHeaders / (1024.f*1024.f)));
 
 				ypos += y_inc;
 			}
@@ -1519,8 +1518,15 @@ BOOL LLViewerWindow::handleCloseRequest(LLWindow *window)
 
 void LLViewerWindow::handleQuit(LLWindow *window)
 {
-	LL_INFOS() << "Window forced quit" << LL_ENDL;
-	LLAppViewer::instance()->forceQuit();
+	if (gNonInteractive)
+	{
+		LLAppViewer::instance()->requestQuit();
+	}
+	else
+	{
+		LL_INFOS() << "Window forced quit" << LL_ENDL;
+		LLAppViewer::instance()->forceQuit();
+	}
 }
 
 void LLViewerWindow::handleResize(LLWindow *window,  S32 width,  S32 height)
@@ -1567,9 +1573,11 @@ void LLViewerWindow::handleFocusLost(LLWindow *window)
 	showCursor();
 	getWindow()->setMouseClipping(FALSE);
 
-	// If losing focus while keys are down, reset them.
+	// If losing focus while keys are down, handle them as
+    // an 'up' to correctly release states, then reset states
 	if (gKeyboard)
 	{
+        gKeyboard->resetKeyDownAndHandle();
 		gKeyboard->resetKeys();
 	}
 
@@ -1767,6 +1775,7 @@ void LLViewerWindow::handleDataCopy(LLWindow *window, S32 data_type, void *data)
 
 BOOL LLViewerWindow::handleTimerEvent(LLWindow *window)
 {
+    //TODO: just call this every frame from gatherInput instead of using a convoluted 30fps timer callback
 	if (LLViewerJoystick::getInstance()->getOverrideCamera())
 	{
 		LLViewerJoystick::getInstance()->updateStatus();
@@ -1907,17 +1916,11 @@ LLViewerWindow::LLViewerWindow(const Params& p)
 		p.title, p.name, p.x, p.y, p.width, p.height, 0,
 		p.fullscreen, 
 		gHeadlessClient,
-		gSavedSettings.getBOOL("DisableVerticalSync"),
+		gSavedSettings.getBOOL("RenderVSyncEnable"),
 		!gHeadlessClient,
 		p.ignore_pixel_depth,
 		gSavedSettings.getBOOL("RenderDeferred") ? 0 : gSavedSettings.getU32("RenderFSAASamples")); //don't use window level anti-aliasing if FBOs are enabled
 
-	if (!LLViewerShaderMgr::sInitialized)
-	{ //immediately initialize shaders
-		LLViewerShaderMgr::sInitialized = TRUE;
-		LLViewerShaderMgr::instance()->setShaders();
-	}
-
 	if (NULL == mWindow)
 	{
 		LLSplashScreen::update(LLTrans::getString("StartupRequireDriverUpdate"));
@@ -1936,6 +1939,12 @@ LLViewerWindow::LLViewerWindow(const Params& p)
 #endif
         LLAppViewer::instance()->fastQuit(1);
 	}
+    else if (!LLViewerShaderMgr::sInitialized)
+    {
+        //immediately initialize shaders
+        LLViewerShaderMgr::sInitialized = TRUE;
+        LLViewerShaderMgr::instance()->setShaders();
+    }
 	
 	if (!LLAppViewer::instance()->restoreErrorTrap())
 	{
@@ -1974,6 +1983,13 @@ LLViewerWindow::LLViewerWindow(const Params& p)
 	}
 	
 	LLFontManager::initClass();
+	// Init font system, load default fonts and generate basic glyphs
+	// currently it takes aprox. 0.5 sec and we would load these fonts anyway
+	// before login screen.
+	LLFontGL::initClass( gSavedSettings.getF32("FontScreenDPI"),
+		mDisplayScale.mV[VX],
+		mDisplayScale.mV[VY],
+		gDirUtilp->getAppRODataDir());
 
 	//
 	// We want to set this stuff up BEFORE we initialize the pipeline, so we can turn off
@@ -1989,7 +2005,7 @@ LLViewerWindow::LLViewerWindow(const Params& p)
 	}
 	LLVertexBuffer::initClass(gSavedSettings.getBOOL("RenderVBOEnable"), gSavedSettings.getBOOL("RenderVBOMappingDisable"));
 	LL_INFOS("RenderInit") << "LLVertexBuffer initialization done." << LL_ENDL ;
-	gGL.init() ;
+	gGL.init(true);
 
 	if (LLFeatureManager::getInstance()->isSafe()
 		|| (gSavedSettings.getS32("LastFeatureVersion") != LLFeatureManager::getInstance()->getVersion())
@@ -2015,20 +2031,12 @@ LLViewerWindow::LLViewerWindow(const Params& p)
 		
 	// Init the image list.  Must happen after GL is initialized and before the images that
 	// LLViewerWindow needs are requested.
-	LLImageGL::initClass(LLViewerTexture::MAX_GL_IMAGE_CATEGORY) ;
+    LLImageGL::initClass(mWindow, LLViewerTexture::MAX_GL_IMAGE_CATEGORY, false, gSavedSettings.getBOOL("RenderGLMultiThreaded"));
 	gTextureList.init();
 	LLViewerTextureManager::init() ;
 	gBumpImageList.init();
 	
-	// Init font system, but don't actually load the fonts yet
-	// because our window isn't onscreen and they take several
-	// seconds to parse.
-	LLFontGL::initClass( gSavedSettings.getF32("FontScreenDPI"),
-								mDisplayScale.mV[VX],
-								mDisplayScale.mV[VY],
-								gDirUtilp->getAppRODataDir());
-	
-	// Create container for all sub-views
+    // Create container for all sub-views
 	LLView::Params rvp;
 	rvp.name("root");
 	rvp.rect(mWindowRectScaled);
@@ -2058,29 +2066,6 @@ std::string LLViewerWindow::getLastSnapshotDir()
 
 void LLViewerWindow::initGLDefaults()
 {
-	gGL.setSceneBlendType(LLRender::BT_ALPHA);
-
-	if (!LLGLSLShader::sNoFixedFunction)
-	{ //initialize fixed function state
-		glColorMaterial( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE );
-
-		glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT,LLColor4::black.mV);
-		glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE,LLColor4::white.mV);
-
-		// lights for objects
-		glShadeModel( GL_SMOOTH );
-
-		gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE);
-		gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
-	}
-
-	glPixelStorei(GL_PACK_ALIGNMENT,1);
-	glPixelStorei(GL_UNPACK_ALIGNMENT,1);
-
-	gGL.setAmbientLightColor(LLColor4::black);
-		
-	glCullFace(GL_BACK);
-
 	// RN: Need this for translation and stretch manip.
 	gBox.prerender();
 }
@@ -2113,6 +2098,8 @@ void LLViewerWindow::initBase()
 	LL_DEBUGS("AppInit") << "initializing edit menu" << LL_ENDL;
 	initialize_edit_menu();
 
+    LLFontGL::loadCommonFonts();
+
 	// Create the floater view at the start so that other views can add children to it. 
 	// (But wait to add it as a child of the root view so that it will be in front of the 
 	// other views.)
@@ -2199,6 +2186,14 @@ void LLViewerWindow::initBase()
 
 void LLViewerWindow::initWorldUI()
 {
+	if (gNonInteractive)
+	{
+		gIMMgr = LLIMMgr::getInstance();
+		LLNavigationBar::getInstance();
+		gFloaterView->pushVisibleAll(FALSE);
+		return;
+	}
+	
 	S32 height = mRootView->getRect().getHeight();
 	S32 width = mRootView->getRect().getWidth();
 	LLRect full_window(0, height, width, 0);
@@ -2209,12 +2204,15 @@ void LLViewerWindow::initWorldUI()
 	//getRootView()->sendChildToFront(gFloaterView);
 	//getRootView()->sendChildToFront(gSnapshotFloaterView);
 
-	LLPanel* chiclet_container = getRootView()->getChild<LLPanel>("chiclet_container");
-	LLChicletBar* chiclet_bar = LLChicletBar::getInstance();
-	chiclet_bar->setShape(chiclet_container->getLocalRect());
-	chiclet_bar->setFollowsAll();
-	chiclet_container->addChild(chiclet_bar);
-	chiclet_container->setVisible(TRUE);
+	if (!gNonInteractive)
+	{
+		LLPanel* chiclet_container = getRootView()->getChild<LLPanel>("chiclet_container");
+		LLChicletBar* chiclet_bar = LLChicletBar::getInstance();
+		chiclet_bar->setShape(chiclet_container->getLocalRect());
+		chiclet_bar->setFollowsAll();
+		chiclet_container->addChild(chiclet_bar);
+		chiclet_container->setVisible(TRUE);
+	}
 
 	LLRect morph_view_rect = full_window;
 	morph_view_rect.stretch( -STATUS_BAR_HEIGHT );
@@ -2242,6 +2240,7 @@ void LLViewerWindow::initWorldUI()
 	gStatusBar->setShape(status_bar_container->getLocalRect());
 	// sync bg color with menu bar
 	gStatusBar->setBackgroundColor( gMenuBarView->getBackgroundColor().get() );
+    // add InBack so that gStatusBar won't be drawn over menu
 	status_bar_container->addChildInBack(gStatusBar);
 	status_bar_container->setVisible(TRUE);
 
@@ -2291,6 +2290,9 @@ void LLViewerWindow::initWorldUI()
 	LLPanelStandStopFlying* panel_stand_stop_flying	= LLPanelStandStopFlying::getInstance();
 	panel_ssf_container->addChild(panel_stand_stop_flying);
 
+	LLPanelHideBeacon* panel_hide_beacon = LLPanelHideBeacon::getInstance();
+	panel_ssf_container->addChild(panel_hide_beacon);
+
 	panel_ssf_container->setVisible(TRUE);
 
 	LLMenuOptionPathfindingRebakeNavmesh::getInstance()->initialize();
@@ -2303,21 +2305,24 @@ void LLViewerWindow::initWorldUI()
 		gToolBarView->setVisible(TRUE);
 	}
 
-	LLMediaCtrl* destinations = LLFloaterReg::getInstance("destinations")->getChild<LLMediaCtrl>("destination_guide_contents");
-	if (destinations)
-	{
-		destinations->setErrorPageURL(gSavedSettings.getString("GenericErrorPageURL"));
-		std::string url = gSavedSettings.getString("DestinationGuideURL");
-		url = LLWeb::expandURLSubstitutions(url, LLSD());
-		destinations->navigateTo(url, HTTP_CONTENT_TEXT_HTML);
-	}
-	LLMediaCtrl* avatar_picker = LLFloaterReg::getInstance("avatar")->findChild<LLMediaCtrl>("avatar_picker_contents");
-	if (avatar_picker)
+	if (!gNonInteractive)
 	{
-		avatar_picker->setErrorPageURL(gSavedSettings.getString("GenericErrorPageURL"));
-		std::string url = gSavedSettings.getString("AvatarPickerURL");
-		url = LLWeb::expandURLSubstitutions(url, LLSD());
-		avatar_picker->navigateTo(url, HTTP_CONTENT_TEXT_HTML);
+		LLMediaCtrl* destinations = LLFloaterReg::getInstance("destinations")->getChild<LLMediaCtrl>("destination_guide_contents");
+		if (destinations)
+		{
+			destinations->setErrorPageURL(gSavedSettings.getString("GenericErrorPageURL"));
+			std::string url = gSavedSettings.getString("DestinationGuideURL");
+			url = LLWeb::expandURLSubstitutions(url, LLSD());
+			destinations->navigateTo(url, HTTP_CONTENT_TEXT_HTML);
+		}
+		LLMediaCtrl* avatar_picker = LLFloaterReg::getInstance("avatar")->findChild<LLMediaCtrl>("avatar_picker_contents");
+		if (avatar_picker)
+		{
+			avatar_picker->setErrorPageURL(gSavedSettings.getString("GenericErrorPageURL"));
+			std::string url = gSavedSettings.getString("AvatarPickerURL");
+			url = LLWeb::expandURLSubstitutions(url, LLSD());
+			avatar_picker->navigateTo(url, HTTP_CONTENT_TEXT_HTML);
+		}
 	}
 }
 
@@ -2423,7 +2428,7 @@ void LLViewerWindow::shutdownGL()
 
 	LLViewerTextureManager::cleanup() ;
 	SUBSYSTEM_CLEANUP(LLImageGL) ;
-
+    
 	LL_INFOS() << "All textures and llimagegl images are destroyed!" << LL_ENDL ;
 
 	LL_INFOS() << "Cleaning up select manager" << LL_ENDL;
@@ -2513,10 +2518,11 @@ void LLViewerWindow::reshape(S32 width, S32 height)
 
 		//glViewport(0, 0, width, height );
 
-		if (height > 0)
+        LLViewerCamera * camera = LLViewerCamera::getInstance(); // simpleton, might not exist
+		if (height > 0 && camera)
 		{ 
-			LLViewerCamera::getInstance()->setViewHeightInPixels( mWorldViewRectRaw.getHeight() );
-			LLViewerCamera::getInstance()->setAspect( getWorldViewAspectRatio() );
+            camera->setViewHeightInPixels( mWorldViewRectRaw.getHeight() );
+            camera->setAspect( getWorldViewAspectRatio() );
 		}
 
 		calcDisplayScale();
@@ -2561,7 +2567,7 @@ void LLViewerWindow::reshape(S32 width, S32 height)
 			mWindow->setMinSize(min_window_width, min_window_height);
 
 			LLCoordScreen window_rect;
-			if (mWindow->getSize(&window_rect))
+			if (!gNonInteractive && mWindow->getSize(&window_rect))
 			{
 			// Only save size if not maximized
 				gSavedSettings.setU32("WindowWidth", window_rect.mX);
@@ -2673,10 +2679,7 @@ void LLViewerWindow::drawDebugText()
 	gGL.color4f(1,1,1,1);
 	gGL.pushMatrix();
 	gGL.pushUIMatrix();
-	if (LLGLSLShader::sNoFixedFunction)
-	{
-		gUIProgram.bind();
-	}
+	gUIProgram.bind();
 	{
 		// scale view by UI global scale factor and aspect ratio correction factor
 		gGL.scaleUI(mDisplayScale.mV[VX], mDisplayScale.mV[VY], 1.f);
@@ -2686,10 +2689,7 @@ void LLViewerWindow::drawDebugText()
 	gGL.popMatrix();
 
 	gGL.flush();
-	if (LLGLSLShader::sNoFixedFunction)
-	{
-		gUIProgram.unbind();
-	}
+	gUIProgram.unbind();
 }
 
 void LLViewerWindow::draw()
@@ -2735,10 +2735,7 @@ void LLViewerWindow::draw()
 	// Draw all nested UI views.
 	// No translation needed, this view is glued to 0,0
 
-	if (LLGLSLShader::sNoFixedFunction)
-	{
-		gUIProgram.bind();
-	}
+	gUIProgram.bind();
 
 	gGL.pushMatrix();
 	LLUI::pushMatrix();
@@ -2814,14 +2811,9 @@ void LLViewerWindow::draw()
 	LLUI::popMatrix();
 	gGL.popMatrix();
 
-	if (LLGLSLShader::sNoFixedFunction)
-	{
-		gUIProgram.unbind();
-	}
+	gUIProgram.unbind();
 
-//#if LL_DEBUG
 	LLView::sIsDrawing = FALSE;
-//#endif
 }
 
 // Takes a single keyup event, usually when UI is visible
@@ -3229,6 +3221,11 @@ void LLViewerWindow::handleScrollWheel(S32 clicks)
 
 void LLViewerWindow::handleScrollHWheel(S32 clicks)
 {
+    if (LLAppViewer::instance()->quitRequested())
+    {
+        return;
+    }
+    
     LLUI::getInstance()->resetMouseIdleTimer();
 
     LLMouseHandler* mouse_captor = gFocusMgr.getMouseCapture();
@@ -3352,7 +3349,7 @@ static LLTrace::BlockTimerStatHandle ftm("Update UI");
 // event processing.
 void LLViewerWindow::updateUI()
 {
-	LL_RECORD_BLOCK_TIME(ftm);
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; //LL_RECORD_BLOCK_TIME(ftm);
 
 	static std::string last_handle_msg;
 
@@ -3798,8 +3795,15 @@ void LLViewerWindow::updateLayout()
 
 void LLViewerWindow::updateMouseDelta()
 {
+#if LL_WINDOWS
+    LLCoordCommon delta; 
+    mWindow->getCursorDelta(&delta);
+    S32 dx = delta.mX;
+    S32 dy = delta.mY;
+#else
 	S32 dx = lltrunc((F32) (mCurrentMousePoint.mX - mLastMousePoint.mX) * LLUI::getScaleFactor().mV[VX]);
 	S32 dy = lltrunc((F32) (mCurrentMousePoint.mY - mLastMousePoint.mY) * LLUI::getScaleFactor().mV[VY]);
+#endif
 
 	//RN: fix for asynchronous notification of mouse leaving window not working
 	LLCoordWindow mouse_pos;
@@ -5396,6 +5400,7 @@ void LLViewerWindow::setup3DRender()
 
 void LLViewerWindow::setup3DViewport(S32 x_offset, S32 y_offset)
 {
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_UI
 	gGLViewport[0] = mWorldViewRectRaw.mLeft + x_offset;
 	gGLViewport[1] = mWorldViewRectRaw.mBottom + y_offset;
 	gGLViewport[2] = mWorldViewRectRaw.getWidth();
@@ -5614,8 +5619,6 @@ void LLViewerWindow::initFonts(F32 zoom_factor)
 								mDisplayScale.mV[VX] * zoom_factor,
 								mDisplayScale.mV[VY] * zoom_factor,
 								gDirUtilp->getAppRODataDir());
-	// Force font reloads, which can be very slow
-	LLFontGL::loadDefaultFonts();
 }
 
 void LLViewerWindow::requestResolutionUpdate()
@@ -5657,7 +5660,7 @@ void LLViewerWindow::restartDisplay(BOOL show_progress_bar)
 	}
 }
 
-BOOL LLViewerWindow::changeDisplaySettings(LLCoordScreen size, BOOL disable_vsync, BOOL show_progress_bar)
+BOOL LLViewerWindow::changeDisplaySettings(LLCoordScreen size, BOOL enable_vsync, BOOL show_progress_bar)
 {
 	//BOOL was_maximized = gSavedSettings.getBOOL("WindowMaximized");
 
diff --git a/indra/newview/llviewerwindow.h b/indra/newview/llviewerwindow.h
index 713cc51bf75de5a759f84d8c9a8ed1d26287ba62..979a560508635d334d85ba137a4e1aa3e7169360 100644
--- a/indra/newview/llviewerwindow.h
+++ b/indra/newview/llviewerwindow.h
@@ -427,7 +427,7 @@ class LLViewerWindow : public LLWindowCallbacks
 	void			requestResolutionUpdate();
 	void			checkSettings();
 	void			restartDisplay(BOOL show_progress_bar);
-	BOOL			changeDisplaySettings(LLCoordScreen size, BOOL disable_vsync, BOOL show_progress_bar);
+	BOOL			changeDisplaySettings(LLCoordScreen size, BOOL enable_vsync, BOOL show_progress_bar);
 	BOOL			getIgnoreDestroyWindow() { return mIgnoreActivate; }
 	F32				getWorldViewAspectRatio() const;
 	const LLVector2& getDisplayScale() const { return mDisplayScale; }
diff --git a/indra/newview/llvlcomposition.cpp b/indra/newview/llvlcomposition.cpp
index c63c5f6b23b9ffd04961f49c1f1cc27f25fd2016..46beac8255ce61fdcc84fe5203c8a908c5c5f0bd 100644
--- a/indra/newview/llvlcomposition.cpp
+++ b/indra/newview/llvlcomposition.cpp
@@ -254,6 +254,7 @@ BOOL LLVLComposition::generateComposition()
 BOOL LLVLComposition::generateTexture(const F32 x, const F32 y,
 									  const F32 width, const F32 height)
 {
+	LL_PROFILE_ZONE_SCOPED
 	llassert(mSurfacep);
 	llassert(x >= 0.f);
 	llassert(y >= 0.f);
diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp
index 5d994058c2e0ddf7cb253ffbc1e77dadd5ca644f..42550ed48d2176cd0c626c38d8649f37acc9e4aa 100644
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -1,4 +1,4 @@
-/** 
+/**
  * @File llvoavatar.cpp
  * @brief Implementation of LLVOAvatar class which is a derivation of LLViewerObject
  *
@@ -111,6 +111,7 @@
 #include "llsdserialize.h"
 #include "llcallstack.h"
 #include "llrendersphere.h"
+#include "llskinningutil.h"
 
 #include <boost/lexical_cast.hpp>
 
@@ -126,6 +127,12 @@ const F32 MIN_HOVER_Z = -2.0;
 const F32 MIN_ATTACHMENT_COMPLEXITY = 0.f;
 const F32 DEFAULT_MAX_ATTACHMENT_COMPLEXITY = 1.0e6f;
 
+// Unlike with 'self' avatar, server doesn't inform viewer about
+// expected attachments so viewer has to wait to see if anything
+// else will arrive
+const F32 FIRST_APPEARANCE_CLOUD_MIN_DELAY = 3.f; // seconds
+const F32 FIRST_APPEARANCE_CLOUD_MAX_DELAY = 45.f;
+
 using namespace LLAvatarAppearanceDefines;
 
 //-----------------------------------------------------------------------------
@@ -176,8 +183,6 @@ const F32 MAX_STANDOFF_DISTANCE_CHANGE = 32;
 // Should probably be 4 or 3, but didn't want to change it while change other logic - SJB
 const S32 SWITCH_TO_BAKED_DISCARD = 5;
 
-const F32 FOOT_COLLIDE_FUDGE = 0.04f;
-
 const F32 HOVER_EFFECT_MAX_SPEED = 3.f;
 const F32 HOVER_EFFECT_STRENGTH = 0.f;
 const F32 UNDERWATER_EFFECT_STRENGTH = 0.1f;
@@ -328,6 +333,7 @@ class LLBodyNoiseMotion :
 	// must return FALSE when the motion is completed.
 	virtual BOOL onUpdate(F32 time, U8* joint_mask)
 	{
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
 		F32 nx[2];
 		nx[0]=time*TORSO_NOISE_SPEED;
 		nx[1]=0.0f;
@@ -448,6 +454,7 @@ class LLBreatheMotionRot :
 	// must return FALSE when the motion is completed.
 	virtual BOOL onUpdate(F32 time, U8* joint_mask)
 	{
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
 		mBreatheRate = 1.f;
 
 		F32 breathe_amt = (sinf(mBreatheRate * time) * BREATHE_ROT_MOTION_STRENGTH);
@@ -549,6 +556,7 @@ class LLPelvisFixMotion :
 	// must return FALSE when the motion is completed.
 	virtual BOOL onUpdate(F32 time, U8* joint_mask)
 	{
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
 		mPelvisState->setPosition(LLVector3::zero);
 
 		return TRUE;
@@ -575,7 +583,6 @@ class LLPelvisFixMotion :
 //-----------------------------------------------------------------------------
 // Static Data
 //-----------------------------------------------------------------------------
-S32 LLVOAvatar::sFreezeCounter = 0;
 U32 LLVOAvatar::sMaxNonImpostors = 12; // Set from RenderAvatarMaxNonImpostors
 bool LLVOAvatar::sLimitNonImpostors = false; // True unless RenderAvatarMaxNonImpostors is 0 (unlimited)
 F32 LLVOAvatar::sRenderDistance = 256.f;
@@ -600,7 +607,6 @@ S32 LLVOAvatar::sNumVisibleChatBubbles = 0;
 BOOL LLVOAvatar::sDebugInvisible = FALSE;
 BOOL LLVOAvatar::sShowAttachmentPoints = FALSE;
 BOOL LLVOAvatar::sShowAnimationDebug = FALSE;
-BOOL LLVOAvatar::sShowFootPlane = FALSE;
 BOOL LLVOAvatar::sVisibleInFirstPerson = FALSE;
 F32 LLVOAvatar::sLODFactor = 1.f;
 F32 LLVOAvatar::sPhysicsLODFactor = 1.f;
@@ -609,6 +615,7 @@ F32 LLVOAvatar::sUnbakedTime = 0.f;
 F32 LLVOAvatar::sUnbakedUpdateTime = 0.f;
 F32 LLVOAvatar::sGreyTime = 0.f;
 F32 LLVOAvatar::sGreyUpdateTime = 0.f;
+LLPointer<LLViewerTexture> LLVOAvatar::sCloudTexture = NULL;
 
 //-----------------------------------------------------------------------------
 // Helper functions
@@ -664,6 +671,7 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id,
 	mVisuallyMuteSetting(AV_RENDER_NORMALLY),
 	mMutedAVColor(LLColor4::white /* used for "uninitialize" */),
 	mFirstFullyVisible(TRUE),
+	mFirstUseDelaySeconds(FIRST_APPEARANCE_CLOUD_MIN_DELAY),
 	mFullyLoaded(FALSE),
 	mPreviousFullyLoaded(FALSE),
 	mFullyLoadedInitialized(FALSE),
@@ -738,7 +746,7 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id,
 
 	mCurrentGesticulationLevel = 0;
 
-    
+    mFirstAppearanceMessageTimer.reset();
 	mRuthTimer.reset();
 	mRuthDebugTimer.reset();
 	mDebugExistenceTimer.reset();
@@ -767,6 +775,13 @@ std::string LLVOAvatar::avString() const
 
 void LLVOAvatar::debugAvatarRezTime(std::string notification_name, std::string comment)
 {
+    if (gDisconnected)
+    {
+        // If we disconected, these values are likely to be invalid and
+        // avString() might crash due to a dead sAvatarDictionary
+        return;
+    }
+
 	LL_INFOS("Avatar") << "REZTIME: [ " << (U32)mDebugExistenceTimer.getElapsedTimeF32()
 					   << "sec ]"
 					   << avString() 
@@ -1125,6 +1140,7 @@ void LLVOAvatar::initClass()
 
 	LLControlAvatar::sRegionChangedSlot = gAgent.addRegionChangedCallback(&LLControlAvatar::onRegionChanged);
 
+    sCloudTexture = LLViewerTextureManager::getFetchedTextureFromFile("cloud-particle.j2c");
 }
 
 
@@ -1317,13 +1333,12 @@ void LLVOAvatar::updateSpatialExtents(LLVector4a& newMin, LLVector4a &newMax)
 }
 
 
-static LLTrace::BlockTimerStatHandle FTM_AVATAR_EXTENT_UPDATE("Av Upd Extent");
-
 void LLVOAvatar::calculateSpatialExtents(LLVector4a& newMin, LLVector4a& newMax)
 {
-    LL_RECORD_BLOCK_TIME(FTM_AVATAR_EXTENT_UPDATE);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
 
-    S32 box_detail = gSavedSettings.getS32("AvatarBoundingBoxComplexity");
+    static LLCachedControl<S32> box_detail_cache(gSavedSettings, "AvatarBoundingBoxComplexity");
+    S32 box_detail = box_detail_cache;
     if (getOverallAppearance() != AOA_NORMAL)
     {
         if (isControlAvatar())
@@ -1424,7 +1439,7 @@ void LLVOAvatar::calculateSpatialExtents(LLVector4a& newMin, LLVector4a& newMax)
                             continue;
                         }
                         LLDrawable* drawable = attached_object->mDrawable;
-                        if (drawable && !drawable->isState(LLDrawable::RIGGED))
+                        if (drawable && !drawable->isState(LLDrawable::RIGGED | LLDrawable::RIGGED_CHILD)) // <-- don't extend bounding box if any rigged objects are present
                         {
                             LLSpatialBridge* bridge = drawable->getSpatialBridge();
                             if (bridge)
@@ -2490,10 +2505,6 @@ S32 LLVOAvatar::setTETexture(const U8 te, const LLUUID& uuid)
 	return setTETextureCore(te, image);
 }
 
-static LLTrace::BlockTimerStatHandle FTM_AVATAR_UPDATE("Avatar Update");
-static LLTrace::BlockTimerStatHandle FTM_AVATAR_UPDATE_COMPLEXITY("Avatar Update Complexity");
-static LLTrace::BlockTimerStatHandle FTM_JOINT_UPDATE("Update Joints");
-
 //------------------------------------------------------------------------
 // LLVOAvatar::dumpAnimationState()
 //------------------------------------------------------------------------
@@ -2526,16 +2537,17 @@ void LLVOAvatar::dumpAnimationState()
 //------------------------------------------------------------------------
 void LLVOAvatar::idleUpdate(LLAgent &agent, const F64 &time)
 {
-	LL_RECORD_BLOCK_TIME(FTM_AVATAR_UPDATE);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
 
 	if (isDead())
 	{
 		LL_INFOS() << "Warning!  Idle on dead avatar" << LL_ENDL;
 		return;
-	}	
+	}
 
+	static LLCachedControl<bool> disable_all_render_types(gSavedSettings, "DisableAllRenderTypes");
 	if (!(gPipeline.hasRenderType(mIsControlAvatar ? LLPipeline::RENDER_TYPE_CONTROL_AV : LLPipeline::RENDER_TYPE_AVATAR))
-		&& !(gSavedSettings.getBOOL("DisableAllRenderTypes")) && !isSelf())
+		&& !disable_all_render_types && !isSelf())
 	{
 		return;
 	}
@@ -2562,8 +2574,6 @@ void LLVOAvatar::idleUpdate(LLAgent &agent, const F64 &time)
 	// force asynchronous drawable update
 	if(mDrawable.notNull())
 	{	
-		LL_RECORD_BLOCK_TIME(FTM_JOINT_UPDATE);
-	
 		if (isSitting() && getParent())
 		{
 			LLViewerObject *root_object = (LLViewerObject*)getRoot();
@@ -2663,9 +2673,8 @@ void LLVOAvatar::idleUpdate(LLAgent &agent, const F64 &time)
 
     if ((LLFrameTimer::getFrameCount() + mID.mData[0]) % compl_upd_freq == 0)
     {
-        LL_RECORD_BLOCK_TIME(FTM_AVATAR_UPDATE_COMPLEXITY);
-	idleUpdateRenderComplexity();
-}
+        idleUpdateRenderComplexity();
+    }
     idleUpdateDebugInfo();
 }
 
@@ -2676,7 +2685,8 @@ void LLVOAvatar::idleUpdateVoiceVisualizer(bool voice_enabled)
 	// Don't render the user's own voice visualizer when in mouselook, or when opening the mic is disabled.
 	if(isSelf())
 	{
-		if(gAgentCamera.cameraMouselook() || gSavedSettings.getBOOL("VoiceDisableMic"))
+        static LLCachedControl<bool> voice_disable_mic(gSavedSettings, "VoiceDisableMic");
+		if(gAgentCamera.cameraMouselook() || voice_disable_mic)
 		{
 			render_visualizer = false;
 		}
@@ -2778,10 +2788,17 @@ void LLVOAvatar::idleUpdateVoiceVisualizer(bool voice_enabled)
 	}//if ( voiceEnabled )
 }		
 
-static LLTrace::BlockTimerStatHandle FTM_ATTACHMENT_UPDATE("Update Attachments");
+static void override_bbox(LLDrawable* drawable, LLVector4a* extents)
+{
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_SPATIAL;
+    drawable->setSpatialExtents(extents[0], extents[1]);
+    drawable->setPositionGroup(LLVector4a(0, 0, 0));
+    drawable->movePartition();
+}
 
 void LLVOAvatar::idleUpdateMisc(bool detailed_update)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
 	if (LLVOAvatar::sJointDebug)
 	{
 		LL_INFOS() << getFullname() << ": joint touches: " << LLJoint::sNumTouches << " updates: " << LLJoint::sNumUpdates << LL_ENDL;
@@ -2795,7 +2812,8 @@ void LLVOAvatar::idleUpdateMisc(bool detailed_update)
 	// update attachments positions
 	if (detailed_update)
 	{
-		LL_RECORD_BLOCK_TIME(FTM_ATTACHMENT_UPDATE);
+        U32 draw_order = 0;
+        S32 attachment_selected = LLSelectMgr::getInstance()->getSelection()->getObjectCount() && LLSelectMgr::getInstance()->getSelection()->isAttachment();
 		for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); 
 			 iter != mAttachmentPoints.end();
 			 ++iter)
@@ -2806,28 +2824,72 @@ void LLVOAvatar::idleUpdateMisc(bool detailed_update)
 				 attachment_iter != attachment->mAttachedObjects.end();
 				 ++attachment_iter)
 			{
-				LLViewerObject* attached_object = attachment_iter->get();
-				BOOL visibleAttachment = visible || (attached_object && 
-													 !(attached_object->mDrawable->getSpatialBridge() &&
-													   attached_object->mDrawable->getSpatialBridge()->getRadius() < 2.0));
+                LLViewerObject* attached_object = attachment_iter->get();
+                if (!attached_object
+                    || attached_object->isDead()
+                    || !attachment->getValid()
+                    || attached_object->mDrawable.isNull())
+                {
+                    continue;
+                }
+
+                LLSpatialBridge* bridge = attached_object->mDrawable->getSpatialBridge();
 				
-				if (visibleAttachment && attached_object && !attached_object->isDead() && attachment->getValid())
+				if (visible || !(bridge && bridge->getRadius() < 2.0))
 				{
-					// if selecting any attachments, update all of them as non-damped
-					if (LLSelectMgr::getInstance()->getSelection()->getObjectCount() && LLSelectMgr::getInstance()->getSelection()->isAttachment())
-					{
-						gPipeline.updateMoveNormalAsync(attached_object->mDrawable);
-					}
-					else
-					{
-						gPipeline.updateMoveDampedAsync(attached_object->mDrawable);
-					}
-					
-					LLSpatialBridge* bridge = attached_object->mDrawable->getSpatialBridge();
-					if (bridge)
-					{
-						gPipeline.updateMoveNormalAsync(bridge);
-					}
+                    //override rigged attachments' octree spatial extents with this avatar's bounding box
+                    bool rigged = false;
+                    if (bridge)
+                    {
+                        //transform avatar bounding box into attachment's coordinate frame
+                        LLVector4a extents[2];
+                        bridge->transformExtents(mDrawable->getSpatialExtents(), extents);
+
+                        if (attached_object->mDrawable->isState(LLDrawable::RIGGED | LLDrawable::RIGGED_CHILD))
+                        {
+                            rigged = true;
+                            override_bbox(attached_object->mDrawable, extents);
+                        }
+                    }
+
+                    // if selecting any attachments, update all of them as non-damped
+                    if (attachment_selected)
+                    {
+                        gPipeline.updateMoveNormalAsync(attached_object->mDrawable);
+                    }
+                    else
+                    {
+                        // Note: SL-17415; While most objects follow joints,
+                        // some objects get position updates from server
+                        gPipeline.updateMoveDampedAsync(attached_object->mDrawable);
+                    }
+
+                    // override_bbox calls movePartition() and getSpatialPartition(),
+                    // so bridge might no longer be valid, get it again.
+                    // ex: animesh stops being an animesh
+                    bridge = attached_object->mDrawable->getSpatialBridge();
+                    if (bridge)
+                    {
+                        if (!rigged)
+                        {
+                            gPipeline.updateMoveNormalAsync(bridge);
+                        }
+                        else
+                        {
+                            //specialized impl of updateMoveNormalAsync just for rigged attachment SpatialBridge
+                            bridge->setState(LLDrawable::MOVE_UNDAMPED);
+                            bridge->updateMove();
+                            bridge->setState(LLDrawable::EARLY_MOVE);
+
+                            LLSpatialGroup* group = attached_object->mDrawable->getSpatialGroup();
+                            if (group)
+                            { //set draw order of group
+                                group->mAvatarp = this;
+                                group->mRenderOrder = draw_order++;
+                            }
+                        }
+                    }
+
 					attached_object->updateText();	
 				}
 			}
@@ -3051,8 +3113,7 @@ void LLVOAvatar::idleUpdateLoadingEffect()
 			particle_parameters.mPartData.mStartColor        = LLColor4(1, 1, 1, 0.5f);
 			particle_parameters.mPartData.mEndColor          = LLColor4(1, 1, 1, 0.0f);
 			particle_parameters.mPartData.mStartScale.mV[VX] = 0.8f;
-			LLViewerTexture* cloud = LLViewerTextureManager::getFetchedTextureFromFile("cloud-particle.j2c");
-			particle_parameters.mPartImageID                 = cloud->getID();
+			particle_parameters.mPartImageID                 = sCloudTexture->getID();
 			particle_parameters.mMaxAge                      = 0.f;
 			particle_parameters.mPattern                     = LLPartSysData::LL_PART_SRC_PATTERN_ANGLE_CONE;
 			particle_parameters.mInnerAngle                  = F_PI;
@@ -3135,6 +3196,8 @@ void LLVOAvatar::idleUpdateWindEffect()
 
 void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
+
 	// update chat bubble
 	//--------------------------------------------------------------------
 	// draw text label over character's head
@@ -3145,11 +3208,14 @@ void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last)
 	}
 	
 	const F32 time_visible = mTimeVisible.getElapsedTimeF32();
-	const F32 NAME_SHOW_TIME = gSavedSettings.getF32("RenderNameShowTime");	// seconds
-	const F32 FADE_DURATION = gSavedSettings.getF32("RenderNameFadeDuration"); // seconds
-	BOOL visible_avatar = isVisible() || mNeedsAnimUpdate;
-	BOOL visible_chat = gSavedSettings.getBOOL("UseChatBubbles") && (mChats.size() || mTyping);
-	BOOL render_name =	visible_chat ||
+
+    static LLCachedControl<F32> NAME_SHOW_TIME(gSavedSettings, "RenderNameShowTime"); // seconds
+    static LLCachedControl<F32> FADE_DURATION(gSavedSettings, "RenderNameFadeDuration"); // seconds
+    static LLCachedControl<bool> use_chat_bubbles(gSavedSettings, "UseChatBubbles");
+
+	bool visible_avatar = isVisible() || mNeedsAnimUpdate;
+	bool visible_chat = use_chat_bubbles && (mChats.size() || mTyping);
+	bool render_name =	visible_chat ||
 		(visible_avatar &&
 		 ((sRenderName == RENDER_NAME_ALWAYS) ||
 		  (sRenderName == RENDER_NAME_FADE && time_visible < NAME_SHOW_TIME)));
@@ -3157,10 +3223,11 @@ void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last)
 	// draw if we're specifically hiding our own name.
 	if (isSelf())
 	{
+        static LLCachedControl<bool> render_name_show_self(gSavedSettings, "RenderNameShowSelf");
+        static LLCachedControl<S32> name_tag_mode(gSavedSettings, "AvatarNameTagMode");
 		render_name = render_name
 			&& !gAgentCamera.cameraMouselook()
-			&& (visible_chat || (gSavedSettings.getBOOL("RenderNameShowSelf") 
-								 && gSavedSettings.getS32("AvatarNameTagMode") ));
+			&& (visible_chat || (render_name_show_self && name_tag_mode));
 	}
 
 	if ( !render_name )
@@ -3175,7 +3242,7 @@ void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last)
 		return;
 	}
 
-	BOOL new_name = FALSE;
+	bool new_name = FALSE;
 	if (visible_chat != mVisibleChat)
 	{
 		mVisibleChat = visible_chat;
@@ -3240,7 +3307,7 @@ void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last)
 	idleUpdateNameTagAlpha(new_name, alpha);
 }
 
-void LLVOAvatar::idleUpdateNameTagText(BOOL new_name)
+void LLVOAvatar::idleUpdateNameTagText(bool new_name)
 {
 	LLNameValue *title = getNVPair("Title");
 	LLNameValue* firstname = getNVPair("FirstName");
@@ -3550,7 +3617,7 @@ void LLVOAvatar::idleUpdateNameTagPosition(const LLVector3& root_pos_last)
 	mNameText->setPositionAgent(name_position);				
 }
 
-void LLVOAvatar::idleUpdateNameTagAlpha(BOOL new_name, F32 alpha)
+void LLVOAvatar::idleUpdateNameTagAlpha(bool new_name, F32 alpha)
 {
 	llassert(mNameText);
 
@@ -3693,7 +3760,8 @@ void LLVOAvatar::updateAppearanceMessageDebugText()
 		{
 			debug_line += llformat(" - cof: %d req: %d rcv:%d",
 								   curr_cof_version, last_request_cof_version, last_received_cof_version);
-			if (gSavedSettings.getBOOL("DebugForceAppearanceRequestFailure"))
+			static LLCachedControl<bool> debug_force_failure(gSavedSettings, "DebugForceAppearanceRequestFailure");
+			if (debug_force_failure)
 			{
 				debug_line += " FORCING ERRS";
 			}
@@ -4041,8 +4109,7 @@ void LLVOAvatar::computeUpdatePeriod()
         && (!isSelf() || visually_muted)
         && !isUIAvatar()
         && (sLimitNonImpostors || visually_muted)
-        && !mNeedsAnimUpdate 
-        && !sFreezeCounter)
+        && !mNeedsAnimUpdate)
 	{
 		const LLVector4a* ext = mDrawable->getSpatialExtents();
 		LLVector4a size;
@@ -4555,7 +4622,12 @@ bool LLVOAvatar::updateCharacter(LLAgent &agent)
 	}
 	else if (!getParent() && isSitting() && !isMotionActive(ANIM_AGENT_SIT_GROUND_CONSTRAINED))
 	{
-		getOffObject();
+        // If we are starting up, motion might be loading
+        LLMotion *motionp = mMotionController.findMotion(ANIM_AGENT_SIT_GROUND_CONSTRAINED);
+        if (!motionp || !mMotionController.isMotionLoading(motionp))
+        {
+            getOffObject();
+        }
 	}
 
 	//--------------------------------------------------------------------
@@ -4883,6 +4955,8 @@ bool LLVOAvatar::shouldAlphaMask()
 //-----------------------------------------------------------------------------
 U32 LLVOAvatar::renderSkinned()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
+
 	U32 num_indices = 0;
 
 	if (!mIsBuilt)
@@ -5008,42 +5082,6 @@ U32 LLVOAvatar::renderSkinned()
 		return num_indices;
 	}
 
-	// render collision normal
-	// *NOTE: this is disabled (there is no UI for enabling sShowFootPlane) due
-	// to DEV-14477.  the code is left here to aid in tracking down the cause
-	// of the crash in the future. -brad
-	if (sShowFootPlane && mDrawable.notNull())
-	{
-		LLVector3 slaved_pos = mDrawable->getPositionAgent();
-		LLVector3 foot_plane_normal(mFootPlane.mV[VX], mFootPlane.mV[VY], mFootPlane.mV[VZ]);
-		F32 dist_from_plane = (slaved_pos * foot_plane_normal) - mFootPlane.mV[VW];
-		LLVector3 collide_point = slaved_pos;
-		collide_point.mV[VZ] -= foot_plane_normal.mV[VZ] * (dist_from_plane + COLLISION_TOLERANCE - FOOT_COLLIDE_FUDGE);
-
-		gGL.begin(LLRender::LINES);
-		{
-			F32 SQUARE_SIZE = 0.2f;
-			gGL.color4f(1.f, 0.f, 0.f, 1.f);
-			
-			gGL.vertex3f(collide_point.mV[VX] - SQUARE_SIZE, collide_point.mV[VY] - SQUARE_SIZE, collide_point.mV[VZ]);
-			gGL.vertex3f(collide_point.mV[VX] + SQUARE_SIZE, collide_point.mV[VY] - SQUARE_SIZE, collide_point.mV[VZ]);
-
-			gGL.vertex3f(collide_point.mV[VX] + SQUARE_SIZE, collide_point.mV[VY] - SQUARE_SIZE, collide_point.mV[VZ]);
-			gGL.vertex3f(collide_point.mV[VX] + SQUARE_SIZE, collide_point.mV[VY] + SQUARE_SIZE, collide_point.mV[VZ]);
-			
-			gGL.vertex3f(collide_point.mV[VX] + SQUARE_SIZE, collide_point.mV[VY] + SQUARE_SIZE, collide_point.mV[VZ]);
-			gGL.vertex3f(collide_point.mV[VX] - SQUARE_SIZE, collide_point.mV[VY] + SQUARE_SIZE, collide_point.mV[VZ]);
-			
-			gGL.vertex3f(collide_point.mV[VX] - SQUARE_SIZE, collide_point.mV[VY] + SQUARE_SIZE, collide_point.mV[VZ]);
-			gGL.vertex3f(collide_point.mV[VX] - SQUARE_SIZE, collide_point.mV[VY] - SQUARE_SIZE, collide_point.mV[VZ]);
-			
-			gGL.vertex3f(collide_point.mV[VX], collide_point.mV[VY], collide_point.mV[VZ]);
-			gGL.vertex3f(collide_point.mV[VX] + mFootPlane.mV[VX], collide_point.mV[VY] + mFootPlane.mV[VY], collide_point.mV[VZ] + mFootPlane.mV[VZ]);
-
-		}
-		gGL.end();
-		gGL.flush();
-	}
 	//--------------------------------------------------------------------
 	// render all geometry attached to the skeleton
 	//--------------------------------------------------------------------
@@ -5051,11 +5089,6 @@ U32 LLVOAvatar::renderSkinned()
 		bool should_alpha_mask = shouldAlphaMask();
 		LLGLState test(GL_ALPHA_TEST, should_alpha_mask);
 		
-		if (should_alpha_mask && !LLGLSLShader::sNoFixedFunction)
-		{
-			gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.5f);
-		}
-		
 		BOOL first_pass = TRUE;
 		if (!LLDrawPoolAvatar::sSkipOpaque)
 		{
@@ -5102,11 +5135,6 @@ U32 LLVOAvatar::renderSkinned()
 			}
 		}
 
-		if (should_alpha_mask && !LLGLSLShader::sNoFixedFunction)
-		{
-			gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
-		}
-
 		if (!LLDrawPoolAvatar::sSkipTransparent || LLPipeline::sImpostorRender)
 		{
 			LLGLState blend(GL_BLEND, !mIsDummy);
@@ -5122,21 +5150,21 @@ U32 LLVOAvatar::renderTransparent(BOOL first_pass)
 	U32 num_indices = 0;
 	if( isWearingWearableType( LLWearableType::WT_SKIRT ) && (isUIAvatar() || isTextureVisible(TEX_SKIRT_BAKED)) )
 	{
-		gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.25f);
+        gGL.flush();
 		LLViewerJoint* skirt_mesh = getViewerJoint(MESH_ID_SKIRT);
 		if (skirt_mesh)
 		{
 			num_indices += skirt_mesh->render(mAdjustedPixelArea, FALSE);
 		}
 		first_pass = FALSE;
-		gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
+        gGL.flush();
 	}
 
 	if (!isSelf() || gAgent.needsRenderHead() || LLPipeline::sShadowRender)
 	{
 		if (LLPipeline::sImpostorRender)
 		{
-			gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.5f);
+            gGL.flush();
 		}
 		
 		if (isTextureVisible(TEX_HEAD_BAKED))
@@ -5159,7 +5187,7 @@ U32 LLVOAvatar::renderTransparent(BOOL first_pass)
 		}
 		if (LLPipeline::sImpostorRender)
 		{
-			gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
+            gGL.flush();
 		}
 	}
 	
@@ -5191,11 +5219,6 @@ U32 LLVOAvatar::renderRigid()
 	bool should_alpha_mask = shouldAlphaMask();
 	LLGLState test(GL_ALPHA_TEST, should_alpha_mask);
 
-	if (should_alpha_mask && !LLGLSLShader::sNoFixedFunction)
-	{
-		gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.5f);
-	}
-
 	if (isTextureVisible(TEX_EYES_BAKED) || (getOverallAppearance() == AOA_JELLYDOLL && !isControlAvatar()) || isUIAvatar())
 	{
 		LLViewerJoint* eyeball_left = getViewerJoint(MESH_ID_EYEBALL_LEFT);
@@ -5210,11 +5233,6 @@ U32 LLVOAvatar::renderRigid()
 		}
 	}
 
-	if (should_alpha_mask && !LLGLSLShader::sNoFixedFunction)
-	{
-		gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
-	}
-	
 	return num_indices;
 }
 
@@ -5265,7 +5283,7 @@ U32 LLVOAvatar::renderImpostor(LLColor4U color, S32 diffuse_channel)
 	}
 	{
 	LLGLEnable test(GL_ALPHA_TEST);
-	gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.f);
+    gGL.flush();
 
 	gGL.color4ubv(color.mV);
 	gGL.getTexUnit(diffuse_channel)->bind(&mImpostor);
@@ -5927,7 +5945,8 @@ BOOL LLVOAvatar::processSingleAnimationStateChange( const LLUUID& anim_id, BOOL
 					//}
 					//else
 					{
-						LLUUID sound_id = LLUUID(gSavedSettings.getString("UISndTyping"));
+                        static LLCachedControl<std::string> ui_snd_string(gSavedSettings, "UISndTyping");
+						LLUUID sound_id = LLUUID(ui_snd_string);
 						gAudiop->triggerSound(sound_id, getID(), 1.0f, LLAudioEngine::AUDIO_TYPE_SFX, char_pos_global);
 					}
 				}
@@ -5995,7 +6014,7 @@ void LLVOAvatar::resetAnimations()
 // animations.
 LLUUID LLVOAvatar::remapMotionID(const LLUUID& id)
 {
-	BOOL use_new_walk_run = gSavedSettings.getBOOL("UseNewWalkRun");
+    static LLCachedControl<bool> use_new_walk_run(gSavedSettings, "UseNewWalkRun");
 	LLUUID result = id;
 
 	// start special case female walk for female avatars
@@ -6137,7 +6156,21 @@ LLJoint *LLVOAvatar::getJoint( const std::string &name )
 
 	if (iter == mJointMap.end() || iter->second == NULL)
 	{   //search for joint and cache found joint in lookup table
-		jointp = mRoot->findJoint(name);
+		if (mJointAliasMap.empty())
+		{
+			getJointAliases();
+		}
+		joint_alias_map_t::const_iterator alias_iter = mJointAliasMap.find(name);
+		std::string canonical_name;
+		if (alias_iter != mJointAliasMap.end())
+		{
+			canonical_name = alias_iter->second;
+		}
+		else
+		{
+			canonical_name = name;
+		}
+		jointp = mRoot->findJoint(canonical_name);
 		mJointMap[name] = jointp;
 	}
 	else
@@ -6157,27 +6190,29 @@ LLJoint *LLVOAvatar::getJoint( const std::string &name )
 LLJoint *LLVOAvatar::getJoint( S32 joint_num )
 {
     LLJoint *pJoint = NULL;
-    S32 collision_start = mNumBones;
-    S32 attachment_start = mNumBones + mNumCollisionVolumes;
-    if (joint_num>=attachment_start)
+    if (joint_num >= 0)
     {
-        // Attachment IDs start at 1
-        S32 attachment_id = joint_num - attachment_start + 1;
-        attachment_map_t::iterator iter = mAttachmentPoints.find(attachment_id);
-        if (iter != mAttachmentPoints.end())
+        if (joint_num < mNumBones)
         {
-            pJoint = iter->second;
+            pJoint = mSkeleton[joint_num];
+        }
+        else if (joint_num < mNumBones + mNumCollisionVolumes)
+        {
+            S32 collision_id = joint_num - mNumBones;
+            pJoint = &mCollisionVolumes[collision_id];
+        }
+        else
+        {
+            // Attachment IDs start at 1
+            S32 attachment_id = joint_num - (mNumBones + mNumCollisionVolumes) + 1;
+            attachment_map_t::iterator iter = mAttachmentPoints.find(attachment_id);
+            if (iter != mAttachmentPoints.end())
+            {
+                pJoint = iter->second;
+            }
         }
     }
-    else if (joint_num>=collision_start)
-    {
-        S32 collision_id = joint_num-collision_start;
-        pJoint = &mCollisionVolumes[collision_id];
-    }
-    else if (joint_num>=0)
-    {
-        pJoint = mSkeleton[joint_num];
-    }
+    
 	llassert(!pJoint || pJoint->getJointNum() == joint_num);
     return pJoint;
 }
@@ -6422,6 +6457,16 @@ void LLVOAvatar::updateAttachmentOverrides()
 #endif
 }
 
+void LLVOAvatar::notifyAttachmentMeshLoaded()
+{
+    if (!isFullyLoaded())
+    {
+        // We just received mesh or skin info
+        // Reset timer to wait for more potential meshes or changes
+        mFullyLoadedTimer.reset();
+    }
+}
+
 //-----------------------------------------------------------------------------
 // addAttachmentOverridesForObject
 //-----------------------------------------------------------------------------
@@ -6512,7 +6557,7 @@ void LLVOAvatar::addAttachmentOverridesForObject(LLViewerObject *vo, std::set<LL
 					LLJoint* pJoint = getJoint( lookingForJoint );
 					if (pJoint)
 					{   									
-						const LLVector3& jointPos = pSkinData->mAlternateBindMatrix[i].getTranslation();									
+						const LLVector3& jointPos = LLVector3(pSkinData->mAlternateBindMatrix[i].getTranslation());
                         if (pJoint->aboveJointPosThreshold(jointPos))
                         {
                             bool override_changed;
@@ -7116,6 +7161,7 @@ void LLVOAvatar::updateGL()
 {
 	if (mMeshTexturesDirty)
 	{
+		LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR
 		updateMeshTextures();
 		mMeshTexturesDirty = FALSE;
 	}
@@ -7124,10 +7170,9 @@ void LLVOAvatar::updateGL()
 //-----------------------------------------------------------------------------
 // updateGeometry()
 //-----------------------------------------------------------------------------
-static LLTrace::BlockTimerStatHandle FTM_UPDATE_AVATAR("Update Avatar");
 BOOL LLVOAvatar::updateGeometry(LLDrawable *drawable)
 {
-	LL_RECORD_BLOCK_TIME(FTM_UPDATE_AVATAR);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
 	if (!(gPipeline.hasRenderType(mIsControlAvatar ? LLPipeline::RENDER_TYPE_CONTROL_AV : LLPipeline::RENDER_TYPE_AVATAR)))
 	{
 		return TRUE;
@@ -7176,6 +7221,14 @@ LLViewerJoint*	LLVOAvatar::getViewerJoint(S32 idx)
 	return dynamic_cast<LLViewerJoint*>(mMeshLOD[idx]);
 }
 
+//-----------------------------------------------------------------------------
+// hideHair()
+//-----------------------------------------------------------------------------
+void LLVOAvatar::hideHair()
+{
+    mMeshLOD[MESH_ID_HAIR]->setVisible(FALSE, TRUE);
+}
+
 //-----------------------------------------------------------------------------
 // hideSkirt()
 //-----------------------------------------------------------------------------
@@ -7861,6 +7914,8 @@ void LLVOAvatar::onGlobalColorChanged(const LLTexGlobalColor* global_color)
 // Do rigged mesh attachments display with this av?
 bool LLVOAvatar::shouldRenderRigged() const
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
+
 	if (getOverallAppearance() == AOA_NORMAL)
 	{
 		return true;
@@ -8125,16 +8180,35 @@ void LLVOAvatar::updateRuthTimer(bool loading)
 BOOL LLVOAvatar::processFullyLoadedChange(bool loading)
 {
 	// We wait a little bit before giving the 'all clear', to let things to
-	// settle down (models to snap into place, textures to get first packets)
+	// settle down (models to snap into place, textures to get first packets).
+    // And if viewer isn't aware of some parts yet, this gives them a chance
+    // to arrive.
 	const F32 LOADED_DELAY = 1.f;
-	const F32 FIRST_USE_DELAY = 3.f;
 
-	if (loading)
-		mFullyLoadedTimer.reset();
+    if (loading)
+    {
+        mFullyLoadedTimer.reset();
+    }
 
 	if (mFirstFullyVisible)
 	{
-		mFullyLoaded = (mFullyLoadedTimer.getElapsedTimeF32() > FIRST_USE_DELAY);
+        if (!isSelf() && loading)
+        {
+                // Note that textures can causes 60s delay on thier own
+                // so this delay might end up on top of textures' delay
+                mFirstUseDelaySeconds = llclamp(
+                    mFirstAppearanceMessageTimer.getElapsedTimeF32(),
+                    FIRST_APPEARANCE_CLOUD_MIN_DELAY,
+                    FIRST_APPEARANCE_CLOUD_MAX_DELAY);
+
+                if (shouldImpostor())
+                {
+                    // Impostors are less of a priority,
+                    // let them stay cloud longer
+                    mFirstUseDelaySeconds *= 1.25;
+                }
+        }
+		mFullyLoaded = (mFullyLoadedTimer.getElapsedTimeF32() > mFirstUseDelaySeconds);
 	}
 	else
 	{
@@ -8183,7 +8257,8 @@ BOOL LLVOAvatar::isFullyLoaded() const
 bool LLVOAvatar::isTooComplex() const
 {
 	bool too_complex;
-	bool render_friend =  (LLAvatarTracker::instance().isBuddy(getID()) && gSavedSettings.getBOOL("AlwaysRenderFriends"));
+    static LLCachedControl<bool> always_render_friends(gSavedSettings, "AlwaysRenderFriends");
+	bool render_friend =  (LLAvatarTracker::instance().isBuddy(getID()) && always_render_friends);
 
 	if (isSelf() || render_friend || mVisuallyMuteSetting == AV_ALWAYS_RENDER)
 	{
@@ -8352,6 +8427,7 @@ void LLVOAvatar::updateMeshVisibility()
 // virtual
 void LLVOAvatar::updateMeshTextures()
 {
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR
 	static S32 update_counter = 0;
 	mBakedTextureDebugText.clear();
 	
@@ -8892,6 +8968,9 @@ void LLVOAvatar::onFirstTEMessageReceived()
 
         mMeshTexturesDirty = TRUE;
 		gPipeline.markGLRebuild(this);
+
+        mFirstAppearanceMessageTimer.reset();
+        mFullyLoadedTimer.reset();
 	}
 }
 
@@ -9036,7 +9115,8 @@ void LLVOAvatar::parseAppearanceMessage(LLMessageSystem* mesgsys, LLAppearanceMe
 	
 	// Parse visual params, if any.
 	S32 num_blocks = mesgsys->getNumberOfBlocksFast(_PREHASH_VisualParam);
-	bool drop_visual_params_debug = gSavedSettings.getBOOL("BlockSomeAvatarAppearanceVisualParams") && (ll_rand(2) == 0); // pretend that ~12% of AvatarAppearance messages arrived without a VisualParam block, for testing
+    static LLCachedControl<bool> block_some_avatars(gSavedSettings, "BlockSomeAvatarAppearanceVisualParams");
+	bool drop_visual_params_debug = block_some_avatars && (ll_rand(2) == 0); // pretend that ~12% of AvatarAppearance messages arrived without a VisualParam block, for testing
 	if( num_blocks > 1 && !drop_visual_params_debug)
 	{
 		//LL_DEBUGS("Avatar") << avString() << " handle visual params, num_blocks " << num_blocks << LL_ENDL;
@@ -9141,10 +9221,12 @@ bool resolve_appearance_version(const LLAppearanceMessageContents& contents, S32
 void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys )
 {
 	LL_DEBUGS("Avatar") << "starts" << LL_ENDL;
-	
-	bool enable_verbose_dumps = gSavedSettings.getBOOL("DebugAvatarAppearanceMessage");
+
+    static LLCachedControl<bool> enable_verbose_dumps(gSavedSettings, "DebugAvatarAppearanceMessage");
+    static LLCachedControl<bool> block_avatar_appearance_messages(gSavedSettings, "BlockAvatarAppearanceMessages");
+
 	std::string dump_prefix = getFullname() + "_" + (isSelf()?"s":"o") + "_";
-	if (gSavedSettings.getBOOL("BlockAvatarAppearanceMessages"))
+	if (block_avatar_appearance_messages)
 	{
 		LL_WARNS() << "Blocking AvatarAppearance message" << LL_ENDL;
 		return;
@@ -9420,6 +9502,54 @@ LLViewerTexture* LLVOAvatar::getBakedTexture(const U8 te)
 	
 }
 
+const LLVOAvatar::MatrixPaletteCache& LLVOAvatar::updateSkinInfoMatrixPalette(const LLMeshSkinInfo* skin)
+{
+    U64 hash = skin->mHash;
+    MatrixPaletteCache& entry = mMatrixPaletteCache[hash];
+
+    if (entry.mFrame != gFrameCount)
+    {
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
+
+        entry.mFrame = gFrameCount;
+
+        //build matrix palette
+        U32 count = LLSkinningUtil::getMeshJointCount(skin);
+        entry.mMatrixPalette.resize(count);
+        LLSkinningUtil::initSkinningMatrixPalette(&(entry.mMatrixPalette[0]), count, skin, this);
+
+        const LLMatrix4a* mat = &(entry.mMatrixPalette[0]);
+
+        entry.mGLMp.resize(count * 12);
+
+        F32* mp = &(entry.mGLMp[0]);
+
+        for (U32 i = 0; i < count; ++i)
+        {
+            F32* m = (F32*)mat[i].mMatrix[0].getF32ptr();
+
+            U32 idx = i * 12;
+
+            mp[idx + 0] = m[0];
+            mp[idx + 1] = m[1];
+            mp[idx + 2] = m[2];
+            mp[idx + 3] = m[12];
+
+            mp[idx + 4] = m[4];
+            mp[idx + 5] = m[5];
+            mp[idx + 6] = m[6];
+            mp[idx + 7] = m[13];
+
+            mp[idx + 8] = m[8];
+            mp[idx + 9] = m[9];
+            mp[idx + 10] = m[10];
+            mp[idx + 11] = m[14];
+        }
+    }
+
+    return entry;
+}
+
 // static
 void LLVOAvatar::getAnimLabels( std::vector<std::string>* labels )
 {
@@ -10104,23 +10234,6 @@ LLHost LLVOAvatar::getObjectHost() const
 	}
 }
 
-//static
-void LLVOAvatar::updateFreezeCounter(S32 counter)
-{
-	if(counter)
-	{
-		sFreezeCounter = counter;
-	}
-	else if(sFreezeCounter > 0)
-	{
-		sFreezeCounter--;
-	}
-	else
-	{
-		sFreezeCounter = 0;
-	}
-}
-
 BOOL LLVOAvatar::updateLOD()
 {
     if (mDrawable.isNull())
@@ -10183,6 +10296,7 @@ void showRigInfoTabExtents(LLVOAvatar *avatar, LLJointRiggingInfoTab& tab, S32&
 
 void LLVOAvatar::getAssociatedVolumes(std::vector<LLVOVolume*>& volumes)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
 	for ( LLVOAvatar::attachment_map_t::iterator iter = mAttachmentPoints.begin(); iter != mAttachmentPoints.end(); ++iter )
 	{
 		LLViewerJointAttachment* attachment = iter->second;
@@ -10240,27 +10354,19 @@ void LLVOAvatar::getAssociatedVolumes(std::vector<LLVOVolume*>& volumes)
     }
 }
 
-static LLTrace::BlockTimerStatHandle FTM_AVATAR_RIGGING_INFO_UPDATE("Av Upd Rig Info");
-static LLTrace::BlockTimerStatHandle FTM_AVATAR_RIGGING_KEY_UPDATE("Av Upd Rig Key");
-static LLTrace::BlockTimerStatHandle FTM_AVATAR_RIGGING_AVOL_UPDATE("Av Upd Avol");
-
 // virtual
 void LLVOAvatar::updateRiggingInfo()
 {
-    LL_RECORD_BLOCK_TIME(FTM_AVATAR_RIGGING_INFO_UPDATE);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
 
     LL_DEBUGS("RigSpammish") << getFullname() << " updating rig tab" << LL_ENDL;
 
     std::vector<LLVOVolume*> volumes;
 
-	{
-		LL_RECORD_BLOCK_TIME(FTM_AVATAR_RIGGING_AVOL_UPDATE);
-		getAssociatedVolumes(volumes);
-	}
+	getAssociatedVolumes(volumes);
 
 	std::map<LLUUID,S32> curr_rigging_info_key;
 	{
-		LL_RECORD_BLOCK_TIME(FTM_AVATAR_RIGGING_KEY_UPDATE);
 		// Get current rigging info key
 		for (std::vector<LLVOVolume*>::iterator it = volumes.begin(); it != volumes.end(); ++it)
 		{
@@ -10422,6 +10528,7 @@ void LLVOAvatar::updateImpostorRendering(U32 newMaxNonImpostorsValue)
 
 void LLVOAvatar::idleUpdateRenderComplexity()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
     if (isControlAvatar())
     {
         LLControlAvatar *cav = dynamic_cast<LLControlAvatar*>(this);
@@ -10949,6 +11056,7 @@ void LLVOAvatar::updateOverallAppearanceAnimations()
 // Based on isVisuallyMuted(), but has 3 possible results.
 LLVOAvatar::AvatarOverallAppearance LLVOAvatar::getOverallAppearance() const
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
 	AvatarOverallAppearance result = AOA_NORMAL;
 
 	// Priority order (highest priority first)
diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h
index 74ef589ca47a9532e7fc242c9d9e67fbf2acdf36..8d1dcbcda2a1bc9025556131bb762567187ceaf9 100644
--- a/indra/newview/llvoavatar.h
+++ b/indra/newview/llvoavatar.h
@@ -53,6 +53,7 @@
 #include "llviewerstats.h"
 #include "llvovolume.h"
 #include "llavatarrendernotifier.h"
+#include "llmodel.h"
 
 extern const LLUUID ANIM_AGENT_BODY_NOISE;
 extern const LLUUID ANIM_AGENT_BREATHE_ROT;
@@ -77,6 +78,7 @@ class LLViewerJointMesh;
 
 const F32 MAX_AVATAR_LOD_FACTOR = 1.0f;
 
+extern U32 gFrameCount;
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // LLVOAvatar
@@ -87,6 +89,7 @@ class LLVOAvatar :
 	public LLViewerObject,
 	public boost::signals2::trackable
 {
+    LL_ALIGN_NEW;
 	LOG_CLASS(LLVOAvatar);
 
 public:
@@ -99,16 +102,6 @@ class LLVOAvatar :
  **/
 
 public:
-	void* operator new(size_t size)
-	{
-		return LLTrace::MemTrackable<LLViewerObject>::aligned_new<16>(size);
-	}
-
-	void operator delete(void* ptr, size_t size)
-	{
-		LLTrace::MemTrackable<LLViewerObject>::aligned_delete<16>(ptr, size);
-	}
-
 	LLVOAvatar(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp);
 	virtual void		markDead();
 	static void			initClass(); // Initialize data that's only init'd once per class.
@@ -209,6 +202,11 @@ class LLVOAvatar :
 	virtual LLJoint*		getJoint(const std::string &name);
 	LLJoint*		        getJoint(S32 num);
 
+    //if you KNOW joint_num is a valid animated joint index, use getSkeletonJoint for efficiency
+    inline LLJoint* getSkeletonJoint(S32 joint_num) { return mSkeleton[joint_num]; }
+    inline size_t getSkeletonJointCount() const { return mSkeleton.size(); }
+
+    void 					notifyAttachmentMeshLoaded();
 	void 					addAttachmentOverridesForObject(LLViewerObject *vo, std::set<LLUUID>* meshes_seen = NULL, bool recursive = true);
 	void					removeAttachmentOverridesForObject(const LLUUID& mesh_id);
 	void					removeAttachmentOverridesForObject(LLViewerObject *vo);
@@ -284,9 +282,9 @@ class LLVOAvatar :
 	void 			idleUpdateLoadingEffect();
 	void 			idleUpdateWindEffect();
 	void 			idleUpdateNameTag(const LLVector3& root_pos_last);
-	void			idleUpdateNameTagText(BOOL new_name);
+	void			idleUpdateNameTagText(bool new_name);
 	void			idleUpdateNameTagPosition(const LLVector3& root_pos_last);
-	void			idleUpdateNameTagAlpha(BOOL new_name, F32 alpha);
+	void			idleUpdateNameTagAlpha(bool new_name, F32 alpha);
 	LLColor4		getNameTagColor(bool is_friend);
 	void			clearNameTag();
 	static void		invalidateNameTag(const LLUUID& agent_id);
@@ -328,7 +326,6 @@ class LLVOAvatar :
 	static bool		sLimitNonImpostors; // use impostors for far away avatars
 	static F32		sRenderDistance; // distance at which avatars will render.
 	static BOOL		sShowAnimationDebug; // show animation debug info
-	static BOOL		sShowFootPlane;	// show foot collision plane reported by server
 	static BOOL		sShowCollisionVolumes;	// show skeletal collision volumes
 	static BOOL		sVisibleInFirstPerson;
 	static S32		sNumLODChangesThisFrame;
@@ -338,7 +335,8 @@ class LLVOAvatar :
 	static F32		sLODFactor; // user-settable LOD factor
 	static F32		sPhysicsLODFactor; // user-settable physics LOD factor
 	static BOOL		sJointDebug; // output total number of joints being touched for each avatar
-	static BOOL		sDebugAvatarRotation;
+
+    static LLPointer<LLViewerTexture>  sCloudTexture;
 
 	//--------------------------------------------------------------------
 	// Region state
@@ -380,6 +378,9 @@ class LLVOAvatar :
 
 private:
 	BOOL			mFirstFullyVisible;
+	F32				mFirstUseDelaySeconds;
+	LLFrameTimer	mFirstAppearanceMessageTimer;
+
 	BOOL			mFullyLoaded;
 	BOOL			mPreviousFullyLoaded;
 	BOOL			mFullyLoadedInitialized;
@@ -615,14 +616,6 @@ class LLVOAvatar :
 private:
 	BOOL		mCulled;
 
-	//--------------------------------------------------------------------
-	// Freeze counter
-	//--------------------------------------------------------------------
-public:
-	static void updateFreezeCounter(S32 counter = 0);
-private:
-	static S32  sFreezeCounter;
-
 	//--------------------------------------------------------------------
 	// Constants
 	//--------------------------------------------------------------------
@@ -747,6 +740,34 @@ class LLVOAvatar :
 	void			updateMeshVisibility();
 	LLViewerTexture*		getBakedTexture(const U8 te);
 
+    // Matrix palette cache entry
+    class alignas(16) MatrixPaletteCache
+    {
+    public:
+        // Last frame this entry was updated
+        U32 mFrame;
+
+        // List of Matrix4a's for this entry
+        LLMeshSkinInfo::matrix_list_t mMatrixPalette;
+
+        // Float array ready to be sent to GL
+        std::vector<F32> mGLMp;
+
+        MatrixPaletteCache() :
+            mFrame(gFrameCount - 1)
+        {
+        }
+    };
+
+    // Accessor for Matrix Palette Cache
+    // Will do a map lookup for the entry associated with the given MeshSkinInfo
+    // Will update said entry if it hasn't been updated yet this frame
+    const MatrixPaletteCache& updateSkinInfoMatrixPalette(const LLMeshSkinInfo* skinInfo);
+
+    // Map of LLMeshSkinInfo::mHash to MatrixPaletteCache
+    typedef std::unordered_map<U64, MatrixPaletteCache> matrix_palette_cache_t;
+    matrix_palette_cache_t mMatrixPaletteCache;
+
 protected:
 	void 			releaseMeshData();
 	virtual void restoreMeshData();
@@ -778,6 +799,7 @@ class LLVOAvatar :
 	void 			parseAppearanceMessage(LLMessageSystem* mesgsys, LLAppearanceMessageContents& msg);
 	void 			processAvatarAppearance(LLMessageSystem* mesgsys);
     void            applyParsedAppearanceMessage(LLAppearanceMessageContents& contents, bool slam_params);
+    void 			hideHair();
 	void 			hideSkirt();
 	void			startAppearanceAnimation();
 	
@@ -908,7 +930,7 @@ class LLVOAvatar :
 	void	   		startTyping() { mTyping = TRUE; mTypingTimer.reset(); }
 	void			stopTyping() { mTyping = FALSE; }
 private:
-	BOOL			mVisibleChat;
+	bool			mVisibleChat;
 
 	//--------------------------------------------------------------------
 	// Lip synch morphs
diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp
index 60a69a4ac424f2f711aff57d51230f8cfb7a42a4..8fc1dcd81f027b85bbd59d8f64851c7a1571869a 100644
--- a/indra/newview/llvoavatarself.cpp
+++ b/indra/newview/llvoavatarself.cpp
@@ -67,6 +67,7 @@
 #include "llsdserialize.h"
 #include "llcallstack.h"
 #include "llcorehttputil.h"
+#include "lluiusage.h"
 
 #if LL_MSVC
 // disable boost::lexical_cast warning
@@ -2663,6 +2664,7 @@ void LLVOAvatarSelf::onCustomizeStart(bool disable_camera_switch)
 {
 	if (isAgentAvatarValid())
 	{
+		LLUIUsage::instance().logCommand("Avatar.CustomizeStart");
 		if (!gAgentAvatarp->mEndCustomizeCallback.get())
 		{
 			gAgentAvatarp->mEndCustomizeCallback = new LLUpdateAppearanceOnDestroy;
diff --git a/indra/newview/llvocache.cpp b/indra/newview/llvocache.cpp
index 5ebc65405ff91c88faada09b301c075876c7f65e..55fc66349632ada8eb9f22fe2d4bb71cf6b11fe5 100644
--- a/indra/newview/llvocache.cpp
+++ b/indra/newview/llvocache.cpp
@@ -63,8 +63,7 @@ BOOL check_write(LLAPRFile* apr_file, void* src, S32 n_bytes)
 //---------------------------------------------------------------------------
 
 LLVOCacheEntry::LLVOCacheEntry(U32 local_id, U32 crc, LLDataPackerBinaryBuffer &dp)
-:	LLTrace::MemTrackable<LLVOCacheEntry, 16>("LLVOCacheEntry"),
-	LLViewerOctreeEntryData(LLViewerOctreeEntry::LLVOCACHEENTRY),
+:	LLViewerOctreeEntryData(LLViewerOctreeEntry::LLVOCACHEENTRY),
 	mLocalID(local_id),
 	mCRC(crc),
 	mUpdateFlags(-1),
@@ -83,8 +82,7 @@ LLVOCacheEntry::LLVOCacheEntry(U32 local_id, U32 crc, LLDataPackerBinaryBuffer &
 }
 
 LLVOCacheEntry::LLVOCacheEntry()
-:	LLTrace::MemTrackable<LLVOCacheEntry, 16>("LLVOCacheEntry"),
-	LLViewerOctreeEntryData(LLViewerOctreeEntry::LLVOCACHEENTRY),
+:	LLViewerOctreeEntryData(LLViewerOctreeEntry::LLVOCACHEENTRY),
 	mLocalID(0),
 	mCRC(0),
 	mUpdateFlags(-1),
@@ -102,8 +100,7 @@ LLVOCacheEntry::LLVOCacheEntry()
 }
 
 LLVOCacheEntry::LLVOCacheEntry(LLAPRFile* apr_file)
-:	LLTrace::MemTrackable<LLVOCacheEntry, 16>("LLVOCacheEntry"),
-	LLViewerOctreeEntryData(LLViewerOctreeEntry::LLVOCACHEENTRY), 
+:	LLViewerOctreeEntryData(LLViewerOctreeEntry::LLVOCACHEENTRY), 
 	mBuffer(NULL),
 	mUpdateFlags(-1),
 	mState(INACTIVE),
@@ -369,15 +366,6 @@ void LLVOCacheEntry::updateDebugSettings()
 	}
 	timer.reset();
 
-	//the number of frames invisible objects stay in memory
-	static LLCachedControl<U32> inv_obj_time(gSavedSettings,"NonvisibleObjectsInMemoryTime");
-	sMinFrameRange = inv_obj_time - 1; //make 0 to be the maximum 
-
-	//min radius: all objects within this radius remain loaded in memory
-	static LLCachedControl<F32> min_radius(gSavedSettings,"SceneLoadMinRadius");
-	sNearRadius = llmin((F32)min_radius, gAgentCamera.mDrawDistance); //can not exceed the draw distance
-	sNearRadius = llmax(sNearRadius, 1.f); //minimum value is 1.0m
-
 	//objects within the view frustum whose visible area is greater than this threshold will be loaded
 	static LLCachedControl<F32> front_pixel_threshold(gSavedSettings,"SceneLoadFrontPixelThreshold");
 	sFrontPixelThreshold = front_pixel_threshold;
@@ -387,29 +375,38 @@ void LLVOCacheEntry::updateDebugSettings()
 	sRearPixelThreshold = rear_pixel_threshold;
 	sRearPixelThreshold = llmax(sRearPixelThreshold, sFrontPixelThreshold); //can not be smaller than sFrontPixelThreshold.
 
-	// a percentage of draw distance beyond which all objects outside of view frustum will be unloaded, regardless of pixel threshold
-	static LLCachedControl<F32> rear_max_radius_frac(gSavedSettings,"SceneLoadRearMaxRadiusFraction");
-	sRearFarRadius = llmax(rear_max_radius_frac * gAgentCamera.mDrawDistance / 100.f, 1.0f); //minimum value is 1.0m
-	sRearFarRadius = llmax(sRearFarRadius, (F32)min_radius); //can not be less than "SceneLoadMinRadius".
-	sRearFarRadius = llmin(sRearFarRadius, gAgentCamera.mDrawDistance); //can not be more than the draw distance.
-
-	//make the above parameters adaptive to memory usage
+	//make parameters adaptive to memory usage
 	//starts to put restrictions from low_mem_bound_MB, apply tightest restrictions when hits high_mem_bound_MB
 	static LLCachedControl<U32> low_mem_bound_MB(gSavedSettings,"SceneLoadLowMemoryBound");
 	static LLCachedControl<U32> high_mem_bound_MB(gSavedSettings,"SceneLoadHighMemoryBound");
 	
 	LLMemory::updateMemoryInfo() ;
 	U32 allocated_mem = LLMemory::getAllocatedMemKB().value();
-	allocated_mem /= 1024; //convert to MB.
-	if(allocated_mem < low_mem_bound_MB)
-	{
-		return; 
-	}
-	F32 adjust_factor = llmax(0.f, (F32)(high_mem_bound_MB - allocated_mem) / (high_mem_bound_MB - low_mem_bound_MB));
-
-	sRearFarRadius = llmin(adjust_factor * sRearFarRadius, 96.f);  //[0.f, 96.f]
-	sMinFrameRange = (U32)llclamp(adjust_factor * sMinFrameRange, 10.f, 64.f);  //[10, 64]
-	sNearRadius    = llmax(adjust_factor * sNearRadius, 1.0f);
+    static const F32 KB_to_MB = 1.f / 1024.f;
+	U32 clamped_memory = llclamp(allocated_mem * KB_to_MB, (F32) low_mem_bound_MB, (F32) high_mem_bound_MB);
+    const F32 adjust_range = high_mem_bound_MB - low_mem_bound_MB;
+    const F32 adjust_factor = (high_mem_bound_MB - clamped_memory) / adjust_range; // [0, 1]
+
+    //min radius: all objects within this radius remain loaded in memory
+    static LLCachedControl<F32> min_radius(gSavedSettings,"SceneLoadMinRadius");
+    static const F32 MIN_RADIUS = 1.0f;
+    const F32 draw_radius = gAgentCamera.mDrawDistance;
+    const F32 clamped_min_radius = llclamp((F32) min_radius, MIN_RADIUS, draw_radius); // [1, mDrawDistance]
+    sNearRadius = MIN_RADIUS + ((clamped_min_radius - MIN_RADIUS) * adjust_factor);
+
+    // a percentage of draw distance beyond which all objects outside of view frustum will be unloaded, regardless of pixel threshold
+    static LLCachedControl<F32> rear_max_radius_frac(gSavedSettings,"SceneLoadRearMaxRadiusFraction");
+    const F32 min_radius_plus_one = sNearRadius + 1.f;
+    const F32 max_radius = rear_max_radius_frac * gAgentCamera.mDrawDistance;
+    const F32 clamped_max_radius = llclamp(max_radius, min_radius_plus_one, draw_radius); // [sNearRadius, mDrawDistance]
+    sRearFarRadius = min_radius_plus_one + ((clamped_max_radius - min_radius_plus_one) * adjust_factor);
+
+    //the number of frames invisible objects stay in memory
+    static LLCachedControl<U32> inv_obj_time(gSavedSettings,"NonvisibleObjectsInMemoryTime");
+    static const U32 MIN_FRAMES = 10;
+    static const U32 MAX_FRAMES = 64;
+    const U32 clamped_frames = inv_obj_time ? llclamp((U32) inv_obj_time, MIN_FRAMES, MAX_FRAMES) : MAX_FRAMES; // [10, 64], with zero => 64
+    sMinFrameRange = MIN_FRAMES + ((clamped_frames - MIN_FRAMES) * adjust_factor);
 }
 
 //static 
@@ -619,7 +616,6 @@ void LLVOCacheGroup::handleChildAddition(const OctreeNode* parent, OctreeNode* c
 }
 
 LLVOCachePartition::LLVOCachePartition(LLViewerRegion* regionp)
-:	LLTrace::MemTrackable<LLVOCachePartition>("LLVOCachePartition")
 {
 	mLODPeriod = 16;
 	mRegionp = regionp;
@@ -636,6 +632,13 @@ LLVOCachePartition::LLVOCachePartition(LLViewerRegion* regionp)
 	new LLVOCacheGroup(mOctree, this);
 }
 
+LLVOCachePartition::~LLVOCachePartition()
+{
+    // SL-17276 make sure to do base class cleanup while this instance
+    // can still be treated as an LLVOCachePartition 
+    cleanup();
+}
+
 bool LLVOCachePartition::addEntry(LLViewerOctreeEntry* entry)
 {
 	llassert(entry->hasVOCacheEntry());
diff --git a/indra/newview/llvocache.h b/indra/newview/llvocache.h
index dd6afd6b8595f6742f4f9d15d91c4bd6fef7e867..55a13d934dd01f4652c6943be6047250bb5f179b 100644
--- a/indra/newview/llvocache.h
+++ b/indra/newview/llvocache.h
@@ -38,9 +38,9 @@
 class LLCamera;
 
 class LLVOCacheEntry 
-:	public LLViewerOctreeEntryData,
-	public LLTrace::MemTrackable<LLVOCacheEntry, 16>
+:	public LLViewerOctreeEntryData
 {
+    LL_ALIGN_NEW
 public:
 	enum 
 	{
@@ -185,10 +185,11 @@ class LLVOCacheGroup : public LLOcclusionCullingGroup
 	virtual ~LLVOCacheGroup();
 };
 
-class LLVOCachePartition : public LLViewerOctreePartition, public LLTrace::MemTrackable<LLVOCachePartition>
+class LLVOCachePartition : public LLViewerOctreePartition
 {
 public:
 	LLVOCachePartition(LLViewerRegion* regionp);
+    virtual ~LLVOCachePartition();
 
 	bool addEntry(LLViewerOctreeEntry* entry);
 	void removeEntry(LLViewerOctreeEntry* entry);
diff --git a/indra/newview/llvograss.cpp b/indra/newview/llvograss.cpp
index 345e87eea82f2172412f988ea95efe109ae2da5c..9a41eedb547b6777df0c70bcfdf2e8775685c85a 100644
--- a/indra/newview/llvograss.cpp
+++ b/indra/newview/llvograss.cpp
@@ -661,11 +661,9 @@ void LLGrassPartition::addGeometryCount(LLSpatialGroup* group, U32& vertex_count
 	}
 }
 
-static LLTrace::BlockTimerStatHandle FTM_REBUILD_GRASS_VB("Grass VB");
-
 void LLGrassPartition::getGeometry(LLSpatialGroup* group)
 {
-	LL_RECORD_BLOCK_TIME(FTM_REBUILD_GRASS_VB);
+    LL_PROFILE_ZONE_SCOPED;
 
 	std::sort(mFaceList.begin(), mFaceList.end(), LLFace::CompareDistanceGreater());
 
diff --git a/indra/newview/llvoicechannel.cpp b/indra/newview/llvoicechannel.cpp
index f971554c9dec325563225c1c4d109fb27769d245..b0eb8d962cf3f16c8da027908bc140dabfd82ee3 100644
--- a/indra/newview/llvoicechannel.cpp
+++ b/indra/newview/llvoicechannel.cpp
@@ -770,8 +770,6 @@ LLVoiceChannelP2P::LLVoiceChannelP2P(const LLUUID& session_id, const std::string
 		mReceivedCall(FALSE)
 {
 	// make sure URI reflects encoded version of other user's agent id
-	// *NOTE: in case of Avaline call generated SIP URL will be incorrect.
-	// But it will be overridden in LLVoiceChannelP2P::setSessionHandle() called when agent accepts call
 	setURI(LLVoiceClient::getInstance()->sipURIFromID(other_user_id));
 }
 
@@ -911,8 +909,6 @@ void LLVoiceChannelP2P::setSessionHandle(const std::string& handle, const std::s
 	else
 	{
 		LL_WARNS("Voice") << "incoming SIP URL is not provided. Channel may not work properly." << LL_ENDL;
-		// In the case of an incoming AvaLine call, the generated URI will be different from the
-		// original one. This is because the P2P URI is based on avatar UUID but Avaline is not.
 		// See LLVoiceClient::sessionAddedEvent()
 		setURI(LLVoiceClient::getInstance()->sipURIFromID(mOtherUserID));
 	}
@@ -947,22 +943,5 @@ void LLVoiceChannelP2P::setState(EState state)
 
 void LLVoiceChannelP2P::addToTheRecentPeopleList()
 {
-	bool avaline_call = LLIMModel::getInstance()->findIMSession(mSessionID)->isAvalineSessionType();
-	
-	if (avaline_call)
-	{
-		LLSD call_data;
-		std::string call_number = LLVoiceChannel::getSessionName();
-		
-		call_data["avaline_call"]	= true;
-		call_data["session_id"]		= mSessionID;
-		call_data["call_number"]	= call_number;
-		call_data["date"]			= LLDate::now();
-		
-		LLRecentPeople::instance().add(mOtherUserID, call_data);
-	}
-	else
-	{
-		LLRecentPeople::instance().add(mOtherUserID);
-	}
+	LLRecentPeople::instance().add(mOtherUserID);
 }
diff --git a/indra/newview/llvoiceclient.cpp b/indra/newview/llvoiceclient.cpp
index e2bd1a39c7f1899d9f5ed5f695bc66db45e75a8f..2ef2d66f1874b07aa2e591320d207302b7a61f5f 100644
--- a/indra/newview/llvoiceclient.cpp
+++ b/indra/newview/llvoiceclient.cpp
@@ -37,6 +37,7 @@
 #include "llui.h"
 #include "llkeyboard.h"
 #include "llagent.h"
+#include "lluiusage.h"
 
 const F32 LLVoiceClient::OVERDRIVEN_POWER_LEVEL = 0.7f;
 
@@ -200,6 +201,7 @@ const LLVoiceVersionInfo LLVoiceClient::getVersion()
 		LLVoiceVersionInfo result;
 		result.serverVersion = std::string();
 		result.serverType = std::string();
+		result.mBuildVersion = std::string();
 		return result;
 	}
 }
@@ -602,6 +604,10 @@ void LLVoiceClient::setMuteMic(bool muted)
 
 void LLVoiceClient::setUserPTTState(bool ptt)
 {
+	if (ptt)
+	{
+		LLUIUsage::instance().logCommand("Agent.EnableMicrophone");
+	}
 	mUserPTTState = ptt;
 	updateMicMuteLogic();
 	mMicroChangedSignal();
diff --git a/indra/newview/llvoiceclient.h b/indra/newview/llvoiceclient.h
index cf527a4464ffca1fd3978c5571dc81f3e6b60e05..246883b6110f5a9e945a1a7b72a68f59cf1f9b25 100644
--- a/indra/newview/llvoiceclient.h
+++ b/indra/newview/llvoiceclient.h
@@ -95,6 +95,7 @@ struct LLVoiceVersionInfo
 {
 	std::string serverType;
 	std::string serverVersion;
+	std::string mBuildVersion;
 };
 
 //////////////////////////////////
diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp
index 7a034022ea586d8d1bdf8d8c8733cc8029ae0efa..ac6369e4e2ccc9d012a9cbb28e59f2cae50f945b 100644
--- a/indra/newview/llvoicevivox.cpp
+++ b/indra/newview/llvoicevivox.cpp
@@ -690,6 +690,10 @@ void LLVivoxVoiceClient::voiceControlCoro()
         // surviving longer than LLVivoxVoiceClient
         voiceControlStateMachine(state);
     }
+    catch (const LLCoros::Stop&)
+    {
+        LL_DEBUGS("LLVivoxVoiceClient") << "Received a shutdown exception" << LL_ENDL;
+    }
     catch (const LLContinueError&)
     {
         LOG_UNHANDLED_EXCEPTION("LLVivoxVoiceClient");
@@ -1606,13 +1610,33 @@ bool LLVivoxVoiceClient::requestParcelVoiceInfo()
         }
         else
         {
-            LL_WARNS("Voice") << "No voice channel credentials" << LL_ENDL;
-
+            LLVoiceChannel* channel = LLVoiceChannel::getCurrentVoiceChannel();
+            if (channel != NULL)
+            {
+                if (channel->getSessionName().empty() && channel->getSessionID().isNull())
+                {
+                    if (LLViewerParcelMgr::getInstance()->allowAgentVoice())
+                    {
+                        LL_WARNS("Voice") << "No channel credentials for default channel" << LL_ENDL;
+                    }
+                }
+                else
+                {
+                    LL_WARNS("Voice") << "No voice channel credentials" << LL_ENDL;
+                }
+            }
         }
     }
     else
     {
-        LL_WARNS("Voice") << "No voice credentials" << LL_ENDL;
+        if (LLViewerParcelMgr::getInstance()->allowAgentVoice())
+        {
+            LL_WARNS("Voice") << "No voice credentials" << LL_ENDL;
+        }
+        else
+        {
+            LL_DEBUGS("Voice") << "No voice credentials" << LL_ENDL;
+        }
     }
 
     // set the spatial channel.  If no voice credentials or uri are 
@@ -4572,6 +4596,23 @@ void LLVivoxVoiceClient::sessionNotificationEvent(std::string &sessionHandle, st
 	}
 }
 
+void LLVivoxVoiceClient::voiceServiceConnectionStateChangedEvent(int statusCode, std::string &statusString, std::string &build_id)
+{
+	// We don't generally need to process this. However, one occurence is when we first connect, and so it is the
+	// earliest opportunity to learn what we're connected to.
+	if (statusCode)
+	{
+		LL_WARNS("Voice") << "VoiceServiceConnectionStateChangedEvent statusCode: " << statusCode <<
+			"statusString: " << statusString << LL_ENDL;
+		return;
+	}
+	if (build_id.empty())
+	{
+		return;
+	}
+	mVoiceVersion.mBuildVersion = build_id;
+}
+
 void LLVivoxVoiceClient::auxAudioPropertiesEvent(F32 energy)
 {
 	LL_DEBUGS("VoiceEnergy") << "got energy " << energy << LL_ENDL;
@@ -4758,7 +4799,7 @@ void LLVivoxVoiceClient::sessionState::VerifySessions()
         if ((*it).expired())
         {
             LL_WARNS("Voice") << "Expired session found! removing" << LL_ENDL;
-            mSession.erase(it++);
+            it = mSession.erase(it);
         }
         else
             ++it;
@@ -5584,7 +5625,9 @@ void LLVivoxVoiceClient::setVoiceEnabled(bool enabled)
 
 bool LLVivoxVoiceClient::voiceEnabled()
 {
-	return gSavedSettings.getBOOL("EnableVoiceChat") && !gSavedSettings.getBOOL("CmdLineDisableVoice");
+    return gSavedSettings.getBOOL("EnableVoiceChat") &&
+          !gSavedSettings.getBOOL("CmdLineDisableVoice") &&
+          !gNonInteractive;
 }
 
 void LLVivoxVoiceClient::setLipSyncEnabled(BOOL enabled)
@@ -6813,7 +6856,7 @@ void LLVivoxVoiceClient::deleteVoiceFont(const LLUUID& id)
 		if (list_iter->second == id)
 		{
 			LL_DEBUGS("VoiceFont") << "Removing " << id << " from the voice font list." << LL_ENDL;
-			mVoiceFontList.erase(list_iter++);
+            list_iter = mVoiceFontList.erase(list_iter);
 			mVoiceFontListDirty = true;
 		}
 		else
@@ -7552,6 +7595,8 @@ void LLVivoxProtocolParser::EndTag(const char *tag)
 			connectorHandle = string;
 		else if (!stricmp("VersionID", tag))
 			versionID = string;
+		else if (!stricmp("Version", tag))
+			mBuildID = string;
 		else if (!stricmp("AccountHandle", tag))
 			accountHandle = string;
 		else if (!stricmp("State", tag))
@@ -7854,7 +7899,8 @@ void LLVivoxProtocolParser::processResponse(std::string tag)
 			// We don't need to process this, but we also shouldn't warn on it, since that confuses people.
 		}
 		else if (!stricmp(eventTypeCstr, "VoiceServiceConnectionStateChangedEvent"))
-		{	// Yet another ignored event
+		{
+			LLVivoxVoiceClient::getInstance()->voiceServiceConnectionStateChangedEvent(statusCode, statusString, mBuildID);
 		}
 		else if (!stricmp(eventTypeCstr, "AudioDeviceHotSwapEvent"))
 		{
diff --git a/indra/newview/llvoicevivox.h b/indra/newview/llvoicevivox.h
index cf30a4e86ac67a192df89da1e17bdb7a3cae81e0..ebc3a62c350428e666be6b25e01d82ba996cbea3 100644
--- a/indra/newview/llvoicevivox.h
+++ b/indra/newview/llvoicevivox.h
@@ -465,6 +465,7 @@ class LLVivoxVoiceClient :	public LLSingleton<LLVivoxVoiceClient>,
 	void participantAddedEvent(std::string &sessionHandle, std::string &sessionGroupHandle, std::string &uriString, std::string &alias, std::string &nameString, std::string &displayNameString, int participantType);
 	void participantRemovedEvent(std::string &sessionHandle, std::string &sessionGroupHandle, std::string &uriString, std::string &alias, std::string &nameString);
 	void participantUpdatedEvent(std::string &sessionHandle, std::string &sessionGroupHandle, std::string &uriString, std::string &alias, bool isModeratorMuted, bool isSpeaking, int volume, F32 energy);
+	void voiceServiceConnectionStateChangedEvent(int statusCode, std::string &statusString, std::string &build_id);
 	void auxAudioPropertiesEvent(F32 energy);
 	void messageEvent(std::string &sessionHandle, std::string &uriString, std::string &alias, std::string &messageHeader, std::string &messageBody, std::string &applicationString);
 	void sessionNotificationEvent(std::string &sessionHandle, std::string &uriString, std::string &notificationType);
@@ -969,6 +970,7 @@ class LLVivoxProtocolParser : public LLIOPipe
 	std::string		actionString;
 	std::string		connectorHandle;
 	std::string		versionID;
+	std::string		mBuildID;
 	std::string		accountHandle;
 	std::string		sessionHandle;
 	std::string		sessionGroupHandle;
diff --git a/indra/newview/llvopartgroup.cpp b/indra/newview/llvopartgroup.cpp
index b31afca61da82e4dc202ca84587af4c1cfb55435..f3affbeb3342ca907204d74cbefd5a672bfd974c 100644
--- a/indra/newview/llvopartgroup.cpp
+++ b/indra/newview/llvopartgroup.cpp
@@ -306,10 +306,9 @@ LLVector3 LLVOPartGroup::getCameraPosition() const
 	return gAgentCamera.getCameraPositionAgent();
 }
 
-static LLTrace::BlockTimerStatHandle FTM_UPDATE_PARTICLES("Update Particles");
 BOOL LLVOPartGroup::updateGeometry(LLDrawable *drawable)
 {
-	LL_RECORD_BLOCK_TIME(FTM_UPDATE_PARTICLES);
+    LL_PROFILE_ZONE_SCOPED;
 
 	dirtySpatialGroup();
 	
@@ -754,10 +753,9 @@ LLHUDParticlePartition::LLHUDParticlePartition(LLViewerRegion* regionp) :
 	mPartitionType = LLViewerRegion::PARTITION_HUD_PARTICLE;
 }
 
-static LLTrace::BlockTimerStatHandle FTM_REBUILD_PARTICLE_VBO("Particle VBO");
-
 void LLParticlePartition::rebuildGeom(LLSpatialGroup* group)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	if (group->isDead() || !group->hasState(LLSpatialGroup::GEOM_DIRTY))
 	{
 		return;
@@ -769,8 +767,6 @@ void LLParticlePartition::rebuildGeom(LLSpatialGroup* group)
 		group->mLastUpdateViewAngle = group->mViewAngle;
 	}
 	
-	LL_RECORD_BLOCK_TIME(FTM_REBUILD_PARTICLE_VBO);	
-
 	group->clearDrawMap();
 	
 	//get geometry count
@@ -843,17 +839,12 @@ void LLParticlePartition::addGeometryCount(LLSpatialGroup* group, U32& vertex_co
 }
 
 
-static LLTrace::BlockTimerStatHandle FTM_REBUILD_PARTICLE_GEOM("Particle Geom");
-
 void LLParticlePartition::getGeometry(LLSpatialGroup* group)
 {
-	LL_RECORD_BLOCK_TIME(FTM_REBUILD_PARTICLE_GEOM);
+    LL_PROFILE_ZONE_SCOPED;
 
 	std::sort(mFaceList.begin(), mFaceList.end(), LLFace::CompareDistanceGreater());
 
-	U32 index_count = 0;
-	U32 vertex_count = 0;
-
 	group->clearDrawMap();
 
 	LLVertexBuffer* buffer = group->mVertexBuffer;
@@ -919,9 +910,6 @@ void LLParticlePartition::getGeometry(LLSpatialGroup* group)
 		llassert(facep->getIndicesCount() == 6);
 
 
-		vertex_count += facep->getGeomCount();
-		index_count += facep->getIndicesCount();
-
 		S32 idx = draw_vec.size()-1;
 
 		BOOL fullbright = facep->isState(LLFace::FULLBRIGHT);
diff --git a/indra/newview/llvosky.cpp b/indra/newview/llvosky.cpp
index 878d7287ede083fa1b371d42f9934da2343b6a7d..1aa00bc894c0bfc5b9356ab94b66ad2188af0b31 100644
--- a/indra/newview/llvosky.cpp
+++ b/indra/newview/llvosky.cpp
@@ -1,25 +1,25 @@
-/** 
+/**
  * @file llvosky.cpp
  * @brief LLVOSky class implementation
  *
  * $LicenseInfo:firstyear=2001&license=viewerlgpl$
  * Second Life Viewer Source Code
  * Copyright (C) 2010, Linden Research, Inc.
- * 
+ *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  * License as published by the Free Software Foundation;
  * version 2.1 of the License only.
- * 
+ *
  * This library is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * Lesser General Public License for more details.
- * 
+ *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- * 
+ *
  * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
  * $/LicenseInfo$
  */
@@ -64,7 +64,9 @@ namespace
     const S32 NUM_TILES_X = 8;
     const S32 NUM_TILES_Y = 4;
     const S32 NUM_TILES = NUM_TILES_X * NUM_TILES_Y;
-    const S32 NUM_CUBEMAP_FACES = 6;
+    const S32 NUM_CUBEMAP_FACES = 6; // See SKYTEX_RESOLUTION for face dimensions
+    const S32 TOTAL_TILES = NUM_CUBEMAP_FACES * NUM_TILES;
+    const S32 MAX_TILES = TOTAL_TILES + 1;
 
 // Heavenly body constants
     const F32 SUN_DISK_RADIUS	= 0.5f;
@@ -77,11 +79,6 @@ namespace
     const LLVector2 TEX10 = LLVector2(1.f, 0.f);
     const LLVector2 TEX11 = LLVector2(1.f, 1.f);
 
-    LLTrace::BlockTimerStatHandle FTM_VOSKY_UPDATETIMER("VOSky Update Timer Tick");
-    LLTrace::BlockTimerStatHandle FTM_VOSKY_CALC("VOSky Update Calculations");
-    LLTrace::BlockTimerStatHandle FTM_VOSKY_CREATETEXTURES("VOSky Update Textures");
-    LLTrace::BlockTimerStatHandle FTM_VOSKY_UPDATEFORCED("VOSky Update Forced");
-
     F32Seconds UPDATE_EXPRY(0.25f);
 
     const F32 UPDATE_MIN_DELTA_THRESHOLD = 0.0005f;
@@ -90,8 +87,6 @@ namespace
 		SkyTex
 ***************************************/
 
-S32 LLSkyTex::sComponents = 4;
-S32 LLSkyTex::sResolution = 64;
 S32 LLSkyTex::sCurrent = 0;
 
 
@@ -105,15 +100,15 @@ LLSkyTex::LLSkyTex() :
 void LLSkyTex::init(bool isShiny)
 {
     mIsShiny = isShiny;
-	mSkyData = new LLColor4[sResolution * sResolution];
-	mSkyDirs = new LLVector3[sResolution * sResolution];
+	mSkyData = new LLColor4[SKYTEX_RESOLUTION * SKYTEX_RESOLUTION];
+	mSkyDirs = new LLVector3[SKYTEX_RESOLUTION * SKYTEX_RESOLUTION];
 
 	for (S32 i = 0; i < 2; ++i)
 	{
 		mTexture[i] = LLViewerTextureManager::getLocalTexture(FALSE);
 		mTexture[i]->setAddressMode(LLTexUnit::TAM_CLAMP);
-		mImageRaw[i] = new LLImageRaw(sResolution, sResolution, sComponents);
-		
+		mImageRaw[i] = new LLImageRaw(SKYTEX_RESOLUTION, SKYTEX_RESOLUTION, SKYTEX_COMPONENTS);
+
 		initEmpty(i);
 	}
 }
@@ -144,7 +139,7 @@ LLSkyTex::~LLSkyTex()
 
 S32 LLSkyTex::getResolution()
 {
-    return sResolution;
+    return SKYTEX_RESOLUTION;
 }
 
 S32 LLSkyTex::getCurrent()
@@ -172,12 +167,12 @@ S32 LLSkyTex::getWhich(const BOOL curr)
 void LLSkyTex::initEmpty(const S32 tex)
 {
 	U8* data = mImageRaw[tex]->getData();
-	for (S32 i = 0; i < sResolution; ++i)
+	for (S32 i = 0; i < SKYTEX_RESOLUTION; ++i)
 	{
-		for (S32 j = 0; j < sResolution; ++j)
+		for (S32 j = 0; j < SKYTEX_RESOLUTION; ++j)
 		{
-			const S32 basic_offset = (i * sResolution + j);
-			S32 offset = basic_offset * sComponents;
+			const S32 basic_offset = (i * SKYTEX_RESOLUTION + j);
+			S32 offset = basic_offset * SKYTEX_COMPONENTS;
 			data[offset] = 0;
 			data[offset+1] = 0;
 			data[offset+2] = 0;
@@ -193,12 +188,12 @@ void LLSkyTex::initEmpty(const S32 tex)
 void LLSkyTex::create()
 {
 	U8* data = mImageRaw[sCurrent]->getData();
-	for (S32 i = 0; i < sResolution; ++i)
+	for (S32 i = 0; i < SKYTEX_RESOLUTION; ++i)
 	{
-		for (S32 j = 0; j < sResolution; ++j)
+		for (S32 j = 0; j < SKYTEX_RESOLUTION; ++j)
 		{
-			const S32 basic_offset = (i * sResolution + j);
-			S32 offset = basic_offset * sComponents;
+			const S32 basic_offset = (i * SKYTEX_RESOLUTION + j);
+			S32 offset = basic_offset * SKYTEX_COMPONENTS;
 			U32* pix = (U32*)(data + offset);
 			LLColor4U temp = LLColor4U(mSkyData[basic_offset]);
 			*pix = temp.asRGBA();
@@ -208,7 +203,7 @@ void LLSkyTex::create()
 }
 
 void LLSkyTex::createGLImage(S32 which)
-{	
+{
 	mTexture[which]->setExplicitFormat(GL_RGBA8, GL_RGBA);
 	mTexture[which]->createGLTexture(0, mImageRaw[which], 0, TRUE, LLGLTexture::LOCAL);
 	mTexture[which]->setAddressMode(LLTexUnit::TAM_CLAMP);
@@ -395,10 +390,8 @@ const LLVector3* LLHeavenBody::corners() const
 		Sky
 ***************************************/
 
-
-S32 LLVOSky::sResolution = LLSkyTex::getResolution();
-S32 LLVOSky::sTileResX = sResolution/NUM_TILES_X;
-S32 LLVOSky::sTileResY = sResolution/NUM_TILES_Y;
+const S32 SKYTEX_TILE_RES_X = SKYTEX_RESOLUTION / NUM_TILES_X;
+const S32 SKYTEX_TILE_RES_Y = SKYTEX_RESOLUTION / NUM_TILES_Y;
 
 LLVOSky::LLVOSky(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp)
 :	LLStaticViewerObject(id, pcode, regionp, TRUE),
@@ -433,7 +426,7 @@ LLVOSky::LLVOSky(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp)
 	{
 		mFace[i] = NULL;
 	}
-	
+
 	mCameraPosAgent = gAgentCamera.getCameraPositionAgent();
 	mAtmHeight = ATM_HEIGHT;
 	mEarthCenter = LLVector3(mCameraPosAgent.mV[0], mCameraPosAgent.mV[1], -EARTH_RADIUS);
@@ -461,30 +454,12 @@ void LLVOSky::init()
     llassert(!mInitialized);
 
     // Update sky at least once to get correct initial sun/moon directions and lighting calcs performed
-    LLEnvironment::instance().getCurrentSky()->update();
-
-	updateDirections();
-
     LLSettingsSky::ptr_t psky = LLEnvironment::instance().getCurrentSky();
+    psky->update();
 
-    // invariants across whole sky tex process...
-    m_atmosphericsVars.blue_density = psky->getBlueDensity();    
-    m_atmosphericsVars.blue_horizon = psky->getBlueHorizon();
-    m_atmosphericsVars.haze_density = psky->getHazeDensity();
-    m_atmosphericsVars.haze_horizon = psky->getHazeHorizon();
-    m_atmosphericsVars.density_multiplier = psky->getDensityMultiplier();
-    m_atmosphericsVars.max_y = psky->getMaxY();
-    m_atmosphericsVars.sun_norm = LLEnvironment::instance().getClampedSunNorm();
-    m_atmosphericsVars.sunlight = psky->getIsSunUp() ? psky->getSunlightColor() : psky->getMoonlightColor();
-    m_atmosphericsVars.ambient = psky->getAmbientColor();    
-    m_atmosphericsVars.glow = psky->getGlow();
-    m_atmosphericsVars.cloud_shadow = psky->getCloudShadow();
-    m_atmosphericsVars.dome_radius = psky->getDomeRadius();
-    m_atmosphericsVars.dome_offset = psky->getDomeOffset();
-    m_atmosphericsVars.light_atten = psky->getLightAttenuation(m_atmosphericsVars.max_y);
-    m_atmosphericsVars.light_transmittance = psky->getLightTransmittance(m_atmosphericsVars.max_y);
-    m_atmosphericsVars.total_density = psky->getTotalDensity();
-    m_atmosphericsVars.gamma = psky->getGamma();
+    updateDirections(psky);
+
+    cacheEnvironment(psky,m_atmosphericsVars);
 
 	// Initialize the cached normalized direction vectors
 	for (S32 side = 0; side < NUM_CUBEMAP_FACES; ++side)
@@ -492,7 +467,7 @@ void LLVOSky::init()
 		for (S32 tile = 0; tile < NUM_TILES; ++tile)
 		{
 			initSkyTextureDirs(side, tile);
-            createSkyTexture(m_atmosphericsVars, side, tile);
+            createSkyTexture(psky, m_atmosphericsVars, side, tile);
 		}
         mSkyTex[side].create();
         mShinyTex[side].create();
@@ -509,28 +484,35 @@ void LLVOSky::init()
 }
 
 
+void LLVOSky::cacheEnvironment(LLSettingsSky::ptr_t psky,AtmosphericsVars& atmosphericsVars)
+{
+    // NOTE: Also see: LLAtmospherics::updateFog()
+    // invariants across whole sky tex process...
+    atmosphericsVars.blue_density = psky->getBlueDensity();
+    atmosphericsVars.blue_horizon = psky->getBlueHorizon();
+    atmosphericsVars.haze_density = psky->getHazeDensity();
+    atmosphericsVars.haze_horizon = psky->getHazeHorizon();
+    atmosphericsVars.density_multiplier = psky->getDensityMultiplier();
+    atmosphericsVars.distance_multiplier = psky->getDistanceMultiplier();
+    atmosphericsVars.max_y = psky->getMaxY();
+    atmosphericsVars.sun_norm = LLEnvironment::instance().getClampedSunNorm();
+    atmosphericsVars.sunlight = psky->getIsSunUp() ? psky->getSunlightColor() : psky->getMoonlightColor();
+    atmosphericsVars.ambient = psky->getAmbientColor();
+    atmosphericsVars.glow = psky->getGlow();
+    atmosphericsVars.cloud_shadow = psky->getCloudShadow();
+    atmosphericsVars.dome_radius = psky->getDomeRadius();
+    atmosphericsVars.dome_offset = psky->getDomeOffset();
+    atmosphericsVars.light_atten = psky->getLightAttenuation(atmosphericsVars.max_y);
+    atmosphericsVars.light_transmittance = psky->getLightTransmittance(atmosphericsVars.max_y);
+    atmosphericsVars.total_density = psky->getTotalDensity();
+    atmosphericsVars.gamma = psky->getGamma();
+}
+
 void LLVOSky::calc()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_ENVIRONMENT;
     LLSettingsSky::ptr_t psky = LLEnvironment::instance().getCurrentSky();
-
-    // invariants across whole sky tex process...
-    m_atmosphericsVars.blue_density = psky->getBlueDensity();    
-    m_atmosphericsVars.blue_horizon = psky->getBlueHorizon();
-    m_atmosphericsVars.haze_density = psky->getHazeDensity();
-    m_atmosphericsVars.haze_horizon = psky->getHazeHorizon();
-    m_atmosphericsVars.density_multiplier = psky->getDensityMultiplier();
-    m_atmosphericsVars.distance_multiplier = psky->getDistanceMultiplier();
-    m_atmosphericsVars.max_y = psky->getMaxY();
-    m_atmosphericsVars.sun_norm = LLEnvironment::instance().getClampedSunNorm();
-    m_atmosphericsVars.sunlight = psky->getIsSunUp() ? psky->getSunlightColor() : psky->getMoonlightColor();
-    m_atmosphericsVars.ambient = psky->getAmbientColor();    
-    m_atmosphericsVars.glow = psky->getGlow();
-    m_atmosphericsVars.cloud_shadow = psky->getCloudShadow();
-    m_atmosphericsVars.dome_radius = psky->getDomeRadius();
-    m_atmosphericsVars.dome_offset = psky->getDomeOffset();
-    m_atmosphericsVars.light_atten = psky->getLightAttenuation(m_atmosphericsVars.max_y);
-    m_atmosphericsVars.light_transmittance = psky->getLightTransmittance(m_atmosphericsVars.max_y);
-    m_atmosphericsVars.gamma = psky->getGamma();
+    cacheEnvironment(psky,m_atmosphericsVars);
 
 	mSun.setColor(psky->getSunDiffuse());
 	mMoon.setColor(LLColor3(1.0f, 1.0f, 1.0f));
@@ -541,14 +523,14 @@ void LLVOSky::calc()
 	mMoon.renewColor();
 }
 
-void LLVOSky::initCubeMap() 
+void LLVOSky::initCubeMap()
 {
 	std::vector<LLPointer<LLImageRaw> > images;
 	for (S32 side = 0; side < NUM_CUBEMAP_FACES; side++)
 	{
 		images.push_back(mShinyTex[side].getImageRaw());
 	}
-	
+
 	if (!mCubeMap && gSavedSettings.getBOOL("RenderWater") && gGLManager.mHasCubeMap && LLCubeMap::sUseCubeMaps)
 	{
         mCubeMap = new LLCubeMap(false);
@@ -592,12 +574,12 @@ void LLVOSky::restoreGL()
         setMoonTextures(psky->getMoonTextureId(), psky->getNextMoonTextureId());
     }
 
-	updateDirections();
+	updateDirections(psky);
 
 	if (gSavedSettings.getBOOL("RenderWater") && gGLManager.mHasCubeMap && LLCubeMap::sUseCubeMaps)
-		{
+	{
 		initCubeMap();
-		}
+	}
 
     forceSkyUpdate();
 
@@ -613,8 +595,8 @@ void LLVOSky::initSkyTextureDirs(const S32 side, const S32 tile)
 	S32 tile_x = tile % NUM_TILES_X;
 	S32 tile_y = tile / NUM_TILES_X;
 
-	S32 tile_x_pos = tile_x * sTileResX;
-	S32 tile_y_pos = tile_y * sTileResY;
+	S32 tile_x_pos = tile_x * SKYTEX_TILE_RES_X;
+	S32 tile_y_pos = tile_y * SKYTEX_TILE_RES_Y;
 
 	F32 coeff[3] = {0, 0, 0};
 	const S32 curr_coef = side >> 1; // 0/1 = Z axis, 2/3 = Y, 4/5 = X
@@ -624,11 +606,11 @@ void LLVOSky::initSkyTextureDirs(const S32 side, const S32 tile)
 
 	coeff[curr_coef] = (F32)side_dir;
 
-	F32 inv_res = 1.f/sResolution;
+	F32 inv_res = 1.f/SKYTEX_RESOLUTION;
 	S32 x, y;
-	for (y = tile_y_pos; y < (tile_y_pos + sTileResY); ++y)
+	for (y = tile_y_pos; y < (tile_y_pos + SKYTEX_TILE_RES_Y); ++y)
 	{
-		for (x = tile_x_pos; x < (tile_x_pos + sTileResX); ++x)
+		for (x = tile_x_pos; x < (tile_x_pos + SKYTEX_TILE_RES_X); ++x)
 		{
 			coeff[x_coef] = F32((x<<1) + 1) * inv_res - 1.f;
 			coeff[y_coef] = F32((y<<1) + 1) * inv_res - 1.f;
@@ -640,37 +622,35 @@ void LLVOSky::initSkyTextureDirs(const S32 side, const S32 tile)
 	}
 }
 
-void LLVOSky::createSkyTexture(AtmosphericsVars& vars, const S32 side, const S32 tile)
+void LLVOSky::createSkyTexture(const LLSettingsSky::ptr_t &psky, AtmosphericsVars& vars, const S32 side, const S32 tile)
 {
-	LLSettingsSky::ptr_t psky = LLEnvironment::instance().getCurrentSky();
+    const bool low_end = !gPipeline.canUseWindLightShaders();
 
 	S32 tile_x = tile % NUM_TILES_X;
 	S32 tile_y = tile / NUM_TILES_X;
 
-	S32 tile_x_pos = tile_x * sTileResX;
-	S32 tile_y_pos = tile_y * sTileResY;
+	S32 tile_x_pos = tile_x * SKYTEX_TILE_RES_X;
+	S32 tile_y_pos = tile_y * SKYTEX_TILE_RES_Y;
 
 	S32 x, y;
-	for (y = tile_y_pos; y < (tile_y_pos + sTileResY); ++y)
+	for (y = tile_y_pos; y < (tile_y_pos + SKYTEX_TILE_RES_Y); ++y)
 	{
-		for (x = tile_x_pos; x < (tile_x_pos + sTileResX); ++x)
+		for (x = tile_x_pos; x < (tile_x_pos + SKYTEX_TILE_RES_X); ++x)
 		{
-			mSkyTex[side].setPixel(m_legacyAtmospherics.calcSkyColorInDir(psky, vars, mSkyTex[side].getDir(x, y), false), x, y);
-			mShinyTex[side].setPixel(m_legacyAtmospherics.calcSkyColorInDir(psky, vars, mShinyTex[side].getDir(x, y), true), x, y);
+			mSkyTex  [side].setPixel(m_legacyAtmospherics.calcSkyColorInDir(psky, vars, mSkyTex  [side].getDir(x, y), false, low_end), x, y);
+			mShinyTex[side].setPixel(m_legacyAtmospherics.calcSkyColorInDir(psky, vars, mShinyTex[side].getDir(x, y), true , low_end), x, y);
 		}
 	}
 }
 
-void LLVOSky::updateDirections(void)
+void LLVOSky::updateDirections(LLSettingsSky::ptr_t psky)
 {
-    LLSettingsSky::ptr_t psky = LLEnvironment::instance().getCurrentSky();
-
     mSun.setDirection(psky->getSunDirection());
-	mMoon.setDirection(psky->getMoonDirection());
+    mMoon.setDirection(psky->getMoonDirection());
     mSun.setRotation(psky->getSunRotation());
-	mMoon.setRotation(psky->getMoonRotation());
-	mSun.renewDirection();
-	mMoon.renewDirection();
+    mMoon.setRotation(psky->getMoonRotation());
+    mSun.renewDirection();
+    mMoon.renewDirection();
 }
 
 void LLVOSky::idleUpdate(LLAgent &agent, const F64 &time)
@@ -680,9 +660,7 @@ void LLVOSky::idleUpdate(LLAgent &agent, const F64 &time)
 void LLVOSky::forceSkyUpdate()
 {
     mForceUpdate = TRUE;
-
-    memset(&m_lastAtmosphericsVars, 0x00, sizeof(AtmosphericsVars));
-
+    m_lastAtmosphericsVars = {};
     mCubeMapUpdateStage = -1;
 }
 
@@ -691,11 +669,6 @@ bool LLVOSky::updateSky()
     LLSettingsSky::ptr_t psky = LLEnvironment::instance().getCurrentSky();
 
 	if (mDead || !(gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_SKY)))
-	{
-		return TRUE;
-	}
-
-	if (mDead)
 	{
 		// It's dead.  Don't update it.
 		return TRUE;
@@ -706,18 +679,18 @@ bool LLVOSky::updateSky()
 		return TRUE;
 	}
 
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_ENVIRONMENT;
+
 	static S32 next_frame = 0;
-	const S32 total_no_tiles = NUM_CUBEMAP_FACES * NUM_TILES;
-	const S32 cycle_frame_no = total_no_tiles + 1;
-	
+
     mNeedUpdate = mForceUpdate;
 
 	++next_frame;
-	next_frame = next_frame % cycle_frame_no;
+	next_frame = next_frame % MAX_TILES;
 
-	mInterpVal = (!mInitialized) ? 1 : (F32)next_frame / cycle_frame_no;
+	mInterpVal = (!mInitialized) ? 1 : (F32)next_frame / MAX_TILES;
 	LLHeavenBody::setInterpVal( mInterpVal );
-	updateDirections();
+	updateDirections(psky);
 
     if (!mCubeMap)
 	{
@@ -725,10 +698,9 @@ bool LLVOSky::updateSky()
         mForceUpdate = FALSE;
         return TRUE;
 	}
-	
+
     if (mCubeMapUpdateStage < 0)
     {
-        LL_RECORD_BLOCK_TIME(FTM_VOSKY_CALC);
         calc();
 
         bool same_atmospherics = approximatelyEqual(m_lastAtmosphericsVars, m_atmosphericsVars, UPDATE_MIN_DELTA_THRESHOLD);
@@ -745,7 +717,7 @@ bool LLVOSky::updateSky()
 	}
     else if (mCubeMapUpdateStage == NUM_CUBEMAP_FACES)
 	{
-        LL_RECORD_BLOCK_TIME(FTM_VOSKY_UPDATEFORCED);
+        LL_PROFILE_ZONE_NAMED("updateSky - forced");
         LLSkyTex::stepCurrent();
 
         bool is_alm_wl_sky = gPipeline.canUseWindLightShaders();
@@ -805,8 +777,8 @@ bool LLVOSky::updateSky()
     }
     // run 0 to 5 faces, each face in own frame
     else if (mCubeMapUpdateStage >= 0 && mCubeMapUpdateStage < NUM_CUBEMAP_FACES)
-		{
-        LL_RECORD_BLOCK_TIME(FTM_VOSKY_CREATETEXTURES);
+	{
+        LL_PROFILE_ZONE_NAMED("updateSky - create");
         S32 side = mCubeMapUpdateStage;
         // CPU hungry part, createSkyTexture() is math heavy
         // Prior to EEP it was mostly per tile, but since EPP it is per face.
@@ -815,7 +787,7 @@ bool LLVOSky::updateSky()
         // instead of executing per face, or may be can be moved to shaders)
         for (S32 tile = 0; tile < NUM_TILES; tile++)
         {
-            createSkyTexture(m_atmosphericsVars, side, tile);
+            createSkyTexture(psky, m_atmosphericsVars, side, tile);
         }
         mCubeMapUpdateStage++;
     }
@@ -889,10 +861,10 @@ void LLVOSky::setSunScale(F32 sun_scale)
 void LLVOSky::setMoonScale(F32 moon_scale)
 {
     mMoonScale = moon_scale;
-	}
-	
+}
+
 void LLVOSky::setSunTextures(const LLUUID& sun_texture, const LLUUID& sun_texture_next)
-	{
+{
     // We test the UUIDs here because we explicitly do not want the default image returned by getFetchedTexture in that case...
     mSunTexturep[0] = sun_texture.isNull() ? nullptr : LLViewerTextureManager::getFetchedTexture(sun_texture, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_UI);
     mSunTexturep[1] = sun_texture_next.isNull() ? nullptr : LLViewerTextureManager::getFetchedTexture(sun_texture_next, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_UI);
@@ -910,32 +882,32 @@ void LLVOSky::setSunTextures(const LLUUID& sun_texture, const LLUUID& sun_textur
         LLViewerTexture* current_tex1 = mFace[FACE_SUN]->getTexture(LLRender::ALTERNATE_DIFFUSE_MAP);
 
         if (current_tex0 && (mSunTexturep[0] != current_tex0) && current_tex0->isViewerMediaTexture())
-			{
+        {
             static_cast<LLViewerMediaTexture*>(current_tex0)->removeMediaFromFace(mFace[FACE_SUN]);
         }
 
         if (current_tex1 && (mSunTexturep[1] != current_tex1) && current_tex1->isViewerMediaTexture())
-				{
+        {
             static_cast<LLViewerMediaTexture*>(current_tex1)->removeMediaFromFace(mFace[FACE_SUN]);
-						}
+        }
 
         mFace[FACE_SUN]->setTexture(LLRender::DIFFUSE_MAP, mSunTexturep[0]);
 
         if (can_use_wl)
         {
             if (mSunTexturep[1])
-						{
-	            mSunTexturep[1]->setAddressMode(LLTexUnit::TAM_CLAMP);            
-						}
+            {
+                mSunTexturep[1]->setAddressMode(LLTexUnit::TAM_CLAMP);
+            }
             mFace[FACE_SUN]->setTexture(LLRender::ALTERNATE_DIFFUSE_MAP, mSunTexturep[1]);
-					}
-				}
-			}
+        }
+    }
+}
 
 void LLVOSky::setMoonTextures(const LLUUID& moon_texture, const LLUUID& moon_texture_next)
-			{
+{
     LLSettingsSky::ptr_t psky = LLEnvironment::instance().getCurrentSky();
-			
+
     bool can_use_wl = gPipeline.canUseWindLightShaders();
 
     mMoonTexturep[0] = moon_texture.isNull()      ? nullptr : LLViewerTextureManager::getFetchedTexture(moon_texture, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_UI);
@@ -944,17 +916,17 @@ void LLVOSky::setMoonTextures(const LLUUID& moon_texture, const LLUUID& moon_tex
     if (mFace[FACE_MOON])
     {
         if (mMoonTexturep[0])
-		{
-	        mMoonTexturep[0]->setAddressMode(LLTexUnit::TAM_CLAMP);
-	}
+        {
+            mMoonTexturep[0]->setAddressMode(LLTexUnit::TAM_CLAMP);
+        }
         mFace[FACE_MOON]->setTexture(LLRender::DIFFUSE_MAP, mMoonTexturep[0]);
 
         if (mMoonTexturep[1] && can_use_wl)
-	{
-	        mMoonTexturep[1]->setAddressMode(LLTexUnit::TAM_CLAMP);
+        {
+            mMoonTexturep[1]->setAddressMode(LLTexUnit::TAM_CLAMP);
             mFace[FACE_MOON]->setTexture(LLRender::ALTERNATE_DIFFUSE_MAP, mMoonTexturep[1]);
-	}
-	}
+        }
+    }
 }
 
 void LLVOSky::setCloudNoiseTextures(const LLUUID& cloud_noise_texture, const LLUUID& cloud_noise_texture_next)
@@ -963,7 +935,7 @@ void LLVOSky::setCloudNoiseTextures(const LLUUID& cloud_noise_texture, const LLU
 
     mCloudNoiseTexturep[0] = cloud_noise_texture.isNull() ? nullptr : LLViewerTextureManager::getFetchedTexture(cloud_noise_texture, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_UI);
     mCloudNoiseTexturep[1] = cloud_noise_texture_next.isNull() ? nullptr : LLViewerTextureManager::getFetchedTexture(cloud_noise_texture_next, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_UI);
-	
+
     if (mCloudNoiseTexturep[0])
 	{
 	    mCloudNoiseTexturep[0]->setAddressMode(LLTexUnit::TAM_WRAP);
@@ -986,21 +958,19 @@ void LLVOSky::setBloomTextures(const LLUUID& bloom_texture, const LLUUID& bloom_
     mBloomTexturep[1] = bloom_tex_next.isNull() ? nullptr : LLViewerTextureManager::getFetchedTexture(bloom_tex_next, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_UI);
 
     if (mBloomTexturep[0])
-{	
-	    mBloomTexturep[0]->setAddressMode(LLTexUnit::TAM_CLAMP);
+    {
+        mBloomTexturep[0]->setAddressMode(LLTexUnit::TAM_CLAMP);
     }
 
     if (mBloomTexturep[1])
-	{
-	    mBloomTexturep[1]->setAddressMode(LLTexUnit::TAM_CLAMP);
+    {
+        mBloomTexturep[1]->setAddressMode(LLTexUnit::TAM_CLAMP);
     }
-	}
-
-static LLTrace::BlockTimerStatHandle FTM_GEO_SKY("Sky Geometry");
+}
 
 BOOL LLVOSky::updateGeometry(LLDrawable *drawable)
 {
-	LL_RECORD_BLOCK_TIME(FTM_GEO_SKY);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE;
 	if (mFace[FACE_REFLECTION] == NULL)
 	{
 		LLDrawPoolWater *poolp = (LLDrawPoolWater*) gPipeline.getPool(LLDrawPool::POOL_WATER);
@@ -1029,11 +999,11 @@ BOOL LLVOSky::updateGeometry(LLDrawable *drawable)
 	LLStrider<LLVector2> texCoordsp;
 	LLStrider<U16> indicesp;
 	U16 index_offset;
-	LLFace *face;	
+	LLFace *face;
 
 	for (S32 side = 0; side < NUM_CUBEMAP_FACES; ++side)
 	{
-		face = mFace[FACE_SIDE0 + side]; 
+		face = mFace[FACE_SIDE0 + side];
 
 		if (!face->getVertexBuffer())
 		{
@@ -1045,7 +1015,7 @@ BOOL LLVOSky::updateGeometry(LLDrawable *drawable)
 			face->setVertexBuffer(buff);
 
 			index_offset = face->getGeometry(verticesp,normalsp,texCoordsp, indicesp);
-			
+
 			S32 vtx = 0;
 			S32 curr_bit = side >> 1; // 0/1 = Z axis, 2/3 = Y, 4/5 = X
 			S32 side_dir = side & 1;  // even - 0, odd - 1
@@ -1164,11 +1134,11 @@ bool LLVOSky::updateHeavenlyBodyGeometry(LLDrawable *drawable, F32 scale, const
 
 	hb.setVisible(TRUE);
 
-	facep = mFace[f]; 
+	facep = mFace[f];
 
 	if (!facep->getVertexBuffer())
 	{
-		facep->setSize(4, 6);	
+		facep->setSize(4, 6);
 		LLVertexBuffer* buff = new LLVertexBuffer(LLDrawPoolSky::VERTEX_DATA_MASK, GL_STREAM_DRAW_ARB);
 		if (!buff->allocateBuffer(facep->getGeomCount(), facep->getIndicesCount(), TRUE))
 		{
@@ -1402,7 +1372,7 @@ void LLVOSky::updateReflectionGeometry(LLDrawable *drawable, F32 H,
 		dt_clip = -0.1f;
 	}
 
-	LLFace *face = mFace[FACE_REFLECTION]; 
+	LLFace *face = mFace[FACE_REFLECTION];
 
     if (face)
     {
@@ -1420,13 +1390,13 @@ void LLVOSky::updateReflectionGeometry(LLDrawable *drawable, F32 H,
 		face->setGeomIndex(0);
 		face->setVertexBuffer(buff);
 	}
-	
+
 	LLStrider<LLVector3> verticesp;
 	LLStrider<LLVector3> normalsp;
 	LLStrider<LLVector2> texCoordsp;
 	LLStrider<U16> indicesp;
 	S32 index_offset;
-	
+
 	index_offset = face->getGeometry(verticesp,normalsp,texCoordsp, indicesp);
 	if (-1 == index_offset)
 	{
@@ -1444,7 +1414,7 @@ void LLVOSky::updateReflectionGeometry(LLDrawable *drawable, F32 H,
 
         LLColor4 hb_refl_col = (1 - attenuation) * hb_col + attenuation * getSkyFogColor();
 	face->setFaceColor(hb_refl_col);
-	
+
 	LLVector3 v_far[2];
 	v_far[0] = v_refl_corner[1];
 	v_far[1] = v_refl_corner[3];
@@ -1568,52 +1538,53 @@ void LLVOSky::updateFog(const F32 distance)
 	}
 
 void LLVOSky::setSunAndMoonDirectionsCFR(const LLVector3 &sun_dir_cfr, const LLVector3 &moon_dir_cfr)
-	{
-    mSun.setDirection(sun_dir_cfr);	
-	mMoon.setDirection(moon_dir_cfr);
+{
+    mSun.setDirection(sun_dir_cfr);
+    mMoon.setDirection(moon_dir_cfr);
 
-	// Push the sun "South" as it approaches directly overhead so that we can always see bump mapping
-	// on the upward facing faces of cubes.
-	{
-	    // Same as dot product with the up direction + clamp.
-	    F32 sunDot = llmax(0.f, sun_dir_cfr.mV[2]);
-	    sunDot *= sunDot;	
-
-	    // Create normalized vector that has the sunDir pushed south about an hour and change.
-	    LLVector3 adjustedDir = (sun_dir_cfr + LLVector3(0.f, -0.70711f, 0.70711f)) * 0.5f;
-		
-	    // Blend between normal sun dir and adjusted sun dir based on how close we are
-	    // to having the sun overhead.
-	    mBumpSunDir = adjustedDir * sunDot + sun_dir_cfr * (1.0f - sunDot);
-	    mBumpSunDir.normalize();
-		}
-	updateDirections();
-	}
+    // Push the sun "South" as it approaches directly overhead so that we can always see bump mapping
+    // on the upward facing faces of cubes.
+    // Same as dot product with the up direction + clamp.
+    F32 sunDot = llmax(0.f, sun_dir_cfr.mV[2]);
+    sunDot *= sunDot;
+
+    // Create normalized vector that has the sunDir pushed south about an hour and change.
+    LLVector3 adjustedDir = (sun_dir_cfr + LLVector3(0.f, -0.70711f, 0.70711f)) * 0.5f;
+
+    // Blend between normal sun dir and adjusted sun dir based on how close we are
+    // to having the sun overhead.
+    mBumpSunDir = adjustedDir * sunDot + sun_dir_cfr * (1.0f - sunDot);
+    mBumpSunDir.normalize();
+
+    LLSettingsSky::ptr_t psky = LLEnvironment::instance().getCurrentSky();
+    updateDirections(psky);
+}
 
 void LLVOSky::setSunDirectionCFR(const LLVector3 &sun_dir_cfr)
-	{
-    mSun.setDirection(sun_dir_cfr);	
+{
+    mSun.setDirection(sun_dir_cfr);
 
-	// Push the sun "South" as it approaches directly overhead so that we can always see bump mapping
-	// on the upward facing faces of cubes.
-    {
-	// Same as dot product with the up direction + clamp.
-	    F32 sunDot = llmax(0.f, sun_dir_cfr.mV[2]);
-	sunDot *= sunDot;	
+    // Push the sun "South" as it approaches directly overhead so that we can always see bump mapping
+    // on the upward facing faces of cubes.
+    // Same as dot product with the up direction + clamp.
+    F32 sunDot = llmax(0.f, sun_dir_cfr.mV[2]);
+    sunDot *= sunDot;
 
-	// Create normalized vector that has the sunDir pushed south about an hour and change.
-	    LLVector3 adjustedDir = (sun_dir_cfr + LLVector3(0.f, -0.70711f, 0.70711f)) * 0.5f;
+    // Create normalized vector that has the sunDir pushed south about an hour and change.
+    LLVector3 adjustedDir = (sun_dir_cfr + LLVector3(0.f, -0.70711f, 0.70711f)) * 0.5f;
 
-	// Blend between normal sun dir and adjusted sun dir based on how close we are
-	// to having the sun overhead.
-	    mBumpSunDir = adjustedDir * sunDot + sun_dir_cfr * (1.0f - sunDot);
-	mBumpSunDir.normalize();
-    }
-	updateDirections();
+    // Blend between normal sun dir and adjusted sun dir based on how close we are
+    // to having the sun overhead.
+    mBumpSunDir = adjustedDir * sunDot + sun_dir_cfr * (1.0f - sunDot);
+    mBumpSunDir.normalize();
+
+    LLSettingsSky::ptr_t psky = LLEnvironment::instance().getCurrentSky();
+    updateDirections(psky);
 }
 
 void LLVOSky::setMoonDirectionCFR(const LLVector3 &moon_dir_cfr)
 {
-	mMoon.setDirection(moon_dir_cfr);
-	updateDirections();
+    mMoon.setDirection(moon_dir_cfr);
+    LLSettingsSky::ptr_t psky = LLEnvironment::instance().getCurrentSky();
+    updateDirections(psky);
 }
diff --git a/indra/newview/llvosky.h b/indra/newview/llvosky.h
index 39e42bbb2420c9d185bb398ff1ba9d8ef8d0d898..5941ab6e3bd1699393f5f5462e465c042b9512f9 100644
--- a/indra/newview/llvosky.h
+++ b/indra/newview/llvosky.h
@@ -43,6 +43,9 @@ const F32 HEAVENLY_BODY_DIST	= HORIZON_DIST - 20.f;
 const F32 HEAVENLY_BODY_FACTOR	= 0.1f;
 const F32 HEAVENLY_BODY_SCALE	= HEAVENLY_BODY_DIST * HEAVENLY_BODY_FACTOR;
 
+const F32 SKYTEX_COMPONENTS = 4;
+const F32 SKYTEX_RESOLUTION = 64;
+
 class LLFace;
 class LLHaze;
 
@@ -50,8 +53,6 @@ class LLSkyTex
 {
 	friend class LLVOSky;
 private:
-	static S32		sResolution;
-	static S32		sComponents;
 	LLPointer<LLViewerTexture> mTexture[2];
 	LLPointer<LLImageRaw> mImageRaw[2];
 	LLColor4		*mSkyData;
@@ -82,25 +83,25 @@ class LLSkyTex
 
 	void setDir(const LLVector3 &dir, const S32 i, const S32 j)
 	{
-		S32 offset = i * sResolution + j;
+		S32 offset = i * SKYTEX_RESOLUTION + j;
 		mSkyDirs[offset] = dir;
 	}
 
 	const LLVector3 &getDir(const S32 i, const S32 j) const
 	{
-		S32 offset = i * sResolution + j;
+		S32 offset = i * SKYTEX_RESOLUTION + j;
 		return mSkyDirs[offset];
 	}
 
 	void setPixel(const LLColor4 &col, const S32 i, const S32 j)
 	{
-		S32 offset = i * sResolution + j;
+		S32 offset = i * SKYTEX_RESOLUTION + j;
 		mSkyData[offset] = col;
 	}
 
 	void setPixel(const LLColor4U &col, const S32 i, const S32 j)
 	{
-		S32 offset = (i * sResolution + j) * sComponents;
+		S32 offset = (i * SKYTEX_RESOLUTION + j) * SKYTEX_COMPONENTS;
 		U32* pix = (U32*) &(mImageRaw[sCurrent]->getData()[offset]);
 		*pix = col.asRGBA();
 	}
@@ -108,7 +109,7 @@ class LLSkyTex
 	LLColor4U getPixel(const S32 i, const S32 j)
 	{
 		LLColor4U col;
-		S32 offset = (i * sResolution + j) * sComponents;
+		S32 offset = (i * SKYTEX_RESOLUTION + j) * SKYTEX_COMPONENTS;
 		U32* pix = (U32*) &(mImageRaw[sCurrent]->getData()[offset]);
 		col.fromRGBA( *pix );
 		return col;
@@ -214,12 +215,12 @@ class LLVOSky : public LLStaticViewerObject
 	// Initialize/delete data that's only inited once per class.
 	void init();
 	void initCubeMap();
-	void initEmpty();
 	
 	void cleanupGL();
 	void restoreGL();
 
     void calc();
+    void cacheEnvironment(LLSettingsSky::ptr_t psky, AtmosphericsVars& atmosphericsVars);
 
 	/*virtual*/ void idleUpdate(LLAgent &agent, const F64 &time);
 	bool updateSky();
@@ -253,8 +254,6 @@ class LLVOSky : public LLStaticViewerObject
     LLColor4 getSkyFogColor() const                        { return m_legacyAtmospherics.getFogColor(); }
     LLColor4 getGLFogColor() const                      { return m_legacyAtmospherics.getGLFogColor(); }
 
-    LLColor4U getFadeColor() const;
-
 	void setCloudDensity(F32 cloud_density)				{ mCloudDensity = cloud_density; }
 	void setWind ( const LLVector3& wind )				{ mWind = wind.length(); }
 
@@ -299,10 +298,10 @@ class LLVOSky : public LLStaticViewerObject
 protected:
 	~LLVOSky();
 
-	void updateDirections(void);
+	void updateDirections(LLSettingsSky::ptr_t psky);
 
 	void initSkyTextureDirs(const S32 side, const S32 tile);
-	void createSkyTexture(AtmosphericsVars& vars, const S32 side, const S32 tile);
+	void createSkyTexture(const LLSettingsSky::ptr_t &psky, AtmosphericsVars& vars, const S32 side, const S32 tile);
 
 	LLPointer<LLViewerFetchedTexture> mSunTexturep[2];
 	LLPointer<LLViewerFetchedTexture> mMoonTexturep[2];
diff --git a/indra/newview/llvosurfacepatch.cpp b/indra/newview/llvosurfacepatch.cpp
index 897bace4e1ca9b0b3cc6aa8d52e9fd0f3d26f4c1..b0af565867725d991563bbbb6d311058d355b6f9 100644
--- a/indra/newview/llvosurfacepatch.cpp
+++ b/indra/newview/llvosurfacepatch.cpp
@@ -59,63 +59,7 @@ class LLVertexBufferTerrain : public LLVertexBuffer
 	// virtual
 	void setupVertexBuffer(U32 data_mask)
 	{	
-		if (LLGLSLShader::sNoFixedFunction)
-		{ //just use default if shaders are in play
-			LLVertexBuffer::setupVertexBuffer(data_mask & ~(MAP_TEXCOORD2 | MAP_TEXCOORD3));
-			return;
-		}
-
-		volatile U8* base = useVBOs() ? (U8*) mAlignedOffset : mMappedData;
-
-		//assume tex coords 2 and 3 are present
-		U32 type_mask = mTypeMask | MAP_TEXCOORD2 | MAP_TEXCOORD3;
-
-		if ((data_mask & type_mask) != data_mask)
-		{
-			LL_ERRS() << "LLVertexBuffer::setupVertexBuffer missing required components for supplied data mask." << LL_ENDL;
-		}
-
-		if (data_mask & MAP_NORMAL)
-		{
-			glNormalPointer(GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_NORMAL], (void*)(base + mOffsets[TYPE_NORMAL]));
-		}
-		if (data_mask & MAP_TEXCOORD3)
-		{ //substitute tex coord 1 for tex coord 3
-			glClientActiveTextureARB(GL_TEXTURE3_ARB);
-			glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD1], (void*)(base + mOffsets[TYPE_TEXCOORD1]));
-			glClientActiveTextureARB(GL_TEXTURE0_ARB);
-		}
-		if (data_mask & MAP_TEXCOORD2)
-		{ //substitute tex coord 0 for tex coord 2
-			glClientActiveTextureARB(GL_TEXTURE2_ARB);
-			glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD0], (void*)(base + mOffsets[TYPE_TEXCOORD0]));
-			glClientActiveTextureARB(GL_TEXTURE0_ARB);
-		}
-		if (data_mask & MAP_TEXCOORD1)
-		{
-			glClientActiveTextureARB(GL_TEXTURE1_ARB);
-			glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD1], (void*)(base + mOffsets[TYPE_TEXCOORD1]));
-			glClientActiveTextureARB(GL_TEXTURE0_ARB);
-		}
-		if (data_mask & MAP_TANGENT)
-		{
-			glClientActiveTextureARB(GL_TEXTURE2_ARB);
-			glTexCoordPointer(3,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TANGENT], (void*)(base + mOffsets[TYPE_TANGENT]));
-			glClientActiveTextureARB(GL_TEXTURE0_ARB);
-		}
-		if (data_mask & MAP_TEXCOORD0)
-		{
-			glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD0], (void*)(base + mOffsets[TYPE_TEXCOORD0]));
-		}
-		if (data_mask & MAP_COLOR)
-		{
-			glColorPointer(4, GL_UNSIGNED_BYTE, LLVertexBuffer::sTypeSize[TYPE_COLOR], (void*)(base + mOffsets[TYPE_COLOR]));
-		}
-		
-		if (data_mask & MAP_VERTEX)
-		{
-			glVertexPointer(3,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_VERTEX], (void*)(base + 0));
-		}
+		LLVertexBuffer::setupVertexBuffer(data_mask & ~(MAP_TEXCOORD2 | MAP_TEXCOORD3));
 	}
 };
 
@@ -212,19 +156,19 @@ LLDrawable *LLVOSurfacePatch::createDrawable(LLPipeline *pipeline)
 	return mDrawable;
 }
 
-static LLTrace::BlockTimerStatHandle FTM_UPDATE_TERRAIN("Update Terrain");
 
 void LLVOSurfacePatch::updateGL()
 {
 	if (mPatchp)
 	{
+		LL_PROFILE_ZONE_SCOPED
 		mPatchp->updateGL();
 	}
 }
 
 BOOL LLVOSurfacePatch::updateGeometry(LLDrawable *drawable)
 {
-	LL_RECORD_BLOCK_TIME(FTM_UPDATE_TERRAIN);
+    LL_PROFILE_ZONE_SCOPED;
 
 	dirtySpatialGroup(TRUE);
 	
@@ -1070,10 +1014,9 @@ LLVertexBuffer* LLTerrainPartition::createVertexBuffer(U32 type_mask, U32 usage)
 	return new LLVertexBufferTerrain();
 }
 
-static LLTrace::BlockTimerStatHandle FTM_REBUILD_TERRAIN_VB("Terrain VB");
 void LLTerrainPartition::getGeometry(LLSpatialGroup* group)
 {
-	LL_RECORD_BLOCK_TIME(FTM_REBUILD_TERRAIN_VB);
+    LL_PROFILE_ZONE_SCOPED;
 
 	LLVertexBuffer* buffer = group->mVertexBuffer;
 
diff --git a/indra/newview/llvotree.cpp b/indra/newview/llvotree.cpp
index 41099cb5700dbc61e3830ab9e1dbf9e794a92c11..493162b47b55dbe7638f59ad5a86db28a0d1c21f 100644
--- a/indra/newview/llvotree.cpp
+++ b/indra/newview/llvotree.cpp
@@ -493,11 +493,9 @@ LLDrawable* LLVOTree::createDrawable(LLPipeline *pipeline)
 const S32 LEAF_INDICES = 24;
 const S32 LEAF_VERTICES = 16;
 
-static LLTrace::BlockTimerStatHandle FTM_UPDATE_TREE("Update Tree");
-
 BOOL LLVOTree::updateGeometry(LLDrawable *drawable)
 {
-	LL_RECORD_BLOCK_TIME(FTM_UPDATE_TREE);
+    LL_PROFILE_ZONE_SCOPED;
 
 	if(mTrunkLOD >= sMAX_NUM_TREE_LOD_LEVELS) //do not display the tree.
 	{
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index 77f756a1230d88dd07f61bac619bc91cf44a8c4b..a4e0d367c8bf793c003f16805897de8367f02fb1 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -71,6 +71,8 @@
 #include "llmediaentry.h"
 #include "llmediadataclient.h"
 #include "llmeshrepository.h"
+#include "llnotifications.h"
+#include "llnotificationsutil.h"
 #include "llagent.h"
 #include "llviewermediafocus.h"
 #include "lldatapacker.h"
@@ -103,12 +105,6 @@ S32 LLVOVolume::mRenderComplexity_current = 0;
 LLPointer<LLObjectMediaDataClient> LLVOVolume::sObjectMediaClient = NULL;
 LLPointer<LLObjectMediaNavigateClient> LLVOVolume::sObjectMediaNavigateClient = NULL;
 
-static LLTrace::BlockTimerStatHandle FTM_GEN_TRIANGLES("Generate Triangles");
-static LLTrace::BlockTimerStatHandle FTM_GEN_VOLUME("Generate Volumes");
-static LLTrace::BlockTimerStatHandle FTM_VOLUME_TEXTURES("Volume Textures");
-
-extern BOOL gGLDebugLoggingEnabled;
-
 // Implementation class of LLMediaDataClientObject.  See llmediadataclient.h
 class LLMediaDataClientObjectImpl : public LLMediaDataClientObject
 {
@@ -229,10 +225,12 @@ LLVOVolume::LLVOVolume(const LLUUID &id, const LLPCode pcode, LLViewerRegion *re
 	mNumFaces = 0;
 	mLODChanged = FALSE;
 	mSculptChanged = FALSE;
+    mColorChanged = FALSE;
 	mSpotLightPriority = 0.f;
 
 	mMediaImplList.resize(getNumTEs());
 	mLastFetchedMediaVersion = -1;
+    mServerDrawableUpdateCount = 0;
 	memset(&mIndexInTex, 0, sizeof(S32) * LLRender::NUM_VOLUME_TEXTURE_CHANNELS);
 	mMDCImplCount = 0;
 	mLastRiggingInfoLOD = -1;
@@ -328,6 +326,9 @@ U32 LLVOVolume::processUpdateMessage(LLMessageSystem *mesgsys,
 	 	
 	LLColor4U color;
 	const S32 teDirtyBits = (TEM_CHANGE_TEXTURE|TEM_CHANGE_COLOR|TEM_CHANGE_MEDIA);
+    const bool previously_volume_changed = mVolumeChanged;
+    const bool previously_face_mapping_changed = mFaceMappingChanged;
+    const bool previously_color_changed = mColorChanged;
 
 	// Do base class updates...
 	U32 retval = LLViewerObject::processUpdateMessage(mesgsys, user_data, block_num, update_type, dp);
@@ -551,9 +552,31 @@ U32 LLVOVolume::processUpdateMessage(LLMessageSystem *mesgsys,
 	// ...and clean up any media impls
 	cleanUpMediaImpls();
 
+    if ((
+            (mVolumeChanged && !previously_volume_changed) ||
+            (mFaceMappingChanged && !previously_face_mapping_changed) ||
+            (mColorChanged && !previously_color_changed)
+        )
+        && !mLODChanged) {
+        onDrawableUpdateFromServer();
+    }
+
 	return retval;
 }
 
+// Called when a volume, material, etc is updated by the server, possibly by a
+// script. If this occurs too often for this object, mark it as active so that
+// it doesn't disrupt the octree/render batches, thereby potentially causing a
+// big performance penalty.
+void LLVOVolume::onDrawableUpdateFromServer()
+{
+    constexpr U32 UPDATES_UNTIL_ACTIVE = 8;
+    ++mServerDrawableUpdateCount;
+    if (mDrawable && !mDrawable->isActive() && mServerDrawableUpdateCount > UPDATES_UNTIL_ACTIVE)
+    {
+        mDrawable->makeActive();
+    }
+}
 
 void LLVOVolume::animateTextures()
 {
@@ -716,7 +739,7 @@ BOOL LLVOVolume::isVisible() const
 
 void LLVOVolume::updateTextureVirtualSize(bool forced)
 {
-	LL_RECORD_BLOCK_TIME(FTM_VOLUME_TEXTURES);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME;
 	// Update the pixel area of all faces
 
     if (mDrawable.isNull())
@@ -995,6 +1018,7 @@ LLDrawable *LLVOVolume::createDrawable(LLPipeline *pipeline)
 
 BOOL LLVOVolume::setVolume(const LLVolumeParams &params_in, const S32 detail, bool unique_volume)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME;
 	LLVolumeParams volume_params = params_in;
 
 	S32 last_lod = mVolumep.notNull() ? LLVolumeLODGroup::getVolumeDetailFromScale(mVolumep->getDetail()) : -1;
@@ -1173,13 +1197,17 @@ void LLVOVolume::notifyMeshLoaded()
 	mSculptChanged = TRUE;
 	gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_GEOMETRY, TRUE);
 
-    if (getAvatar() && !isAnimatedObject())
+    LLVOAvatar *av = getAvatar();
+    if (av && !isAnimatedObject())
     {
-        getAvatar()->addAttachmentOverridesForObject(this);
+        av->addAttachmentOverridesForObject(this);
+        av->notifyAttachmentMeshLoaded();
     }
-    if (getControlAvatar() && isAnimatedObject())
+    LLControlAvatar *cav = getControlAvatar();
+    if (cav && isAnimatedObject())
     {
-        getControlAvatar()->addAttachmentOverridesForObject(this);
+        cav->addAttachmentOverridesForObject(this);
+        cav->notifyAttachmentMeshLoaded();
     }
     updateVisualComplexity();
 }
@@ -1622,6 +1650,7 @@ BOOL LLVOVolume::setParent(LLViewerObject* parent)
 // NOTE: regenFaces() MUST be followed by genTriangles()!
 void LLVOVolume::regenFaces()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME;
 	// remove existing faces
 	BOOL count_changed = mNumFaces != getNumTEs();
 	
@@ -1667,16 +1696,17 @@ void LLVOVolume::regenFaces()
 	}
 }
 
-BOOL LLVOVolume::genBBoxes(BOOL force_global)
+BOOL LLVOVolume::genBBoxes(BOOL force_global, BOOL should_update_octree_bounds)
 {
-	BOOL res = TRUE;
+    LL_PROFILE_ZONE_SCOPED;
+    BOOL res = TRUE;
 
-	LLVector4a min,max;
+    LLVector4a min, max;
 
-	min.clear();
-	max.clear();
+    min.clear();
+    max.clear();
 
-	BOOL rebuild = mDrawable->isState(LLDrawable::REBUILD_VOLUME | LLDrawable::REBUILD_POSITION | LLDrawable::REBUILD_RIGGED);
+    BOOL rebuild = mDrawable->isState(LLDrawable::REBUILD_VOLUME | LLDrawable::REBUILD_POSITION | LLDrawable::REBUILD_RIGGED);
 
     if (getRiggedVolume())
     {
@@ -1685,76 +1715,103 @@ BOOL LLVOVolume::genBBoxes(BOOL force_global)
         // updates needed, set REBUILD_RIGGED accordingly.
 
         // Without the flag, this will remove unused rigged volumes, which we are not currently very aggressive about.
-        updateRiggedVolume();
+        updateRiggedVolume(false);
+    }
+
+    LLVolume* volume = mRiggedVolume;
+    if (!volume)
+    {
+        volume = getVolume();
     }
-    
-	LLVolume* volume = mRiggedVolume;
-	if (!volume)
-	{
-		volume = getVolume();
-	}
 
     bool any_valid_boxes = false;
-    
+
     if (getRiggedVolume())
     {
         LL_DEBUGS("RiggedBox") << "rebuilding box, volume face count " << getVolume()->getNumVolumeFaces() << " drawable face count " << mDrawable->getNumFaces() << LL_ENDL;
     }
+
     // There's no guarantee that getVolume()->getNumFaces() == mDrawable->getNumFaces()
-	for (S32 i = 0;
-		 i < getVolume()->getNumVolumeFaces() && i < mDrawable->getNumFaces() && i < getNumTEs();
-		 i++)
-	{
-		LLFace *face = mDrawable->getFace(i);
-		if (!face)
-		{
-			continue;
-		}
+    for (S32 i = 0;
+        i < getVolume()->getNumVolumeFaces() && i < mDrawable->getNumFaces() && i < getNumTEs();
+        i++)
+    {
+        LLFace* face = mDrawable->getFace(i);
+        if (!face)
+        {
+            continue;
+        }
 
         BOOL face_res = face->genVolumeBBoxes(*volume, i,
-                                              mRelativeXform, 
-                                              (mVolumeImpl && mVolumeImpl->isVolumeGlobal()) || force_global);
+            mRelativeXform,
+            (mVolumeImpl && mVolumeImpl->isVolumeGlobal()) || force_global);
         res &= face_res; // note that this result is never used
-		
+
         // MAINT-8264 - ignore bboxes of ill-formed faces.
         if (!face_res)
         {
             continue;
         }
-		if (rebuild)
-		{
+        if (rebuild)
+        {
             if (getRiggedVolume())
             {
                 LL_DEBUGS("RiggedBox") << "rebuilding box, face " << i << " extents " << face->mExtents[0] << ", " << face->mExtents[1] << LL_ENDL;
             }
-			if (!any_valid_boxes)
-			{
-				min = face->mExtents[0];
-				max = face->mExtents[1];
+            if (!any_valid_boxes)
+            {
+                min = face->mExtents[0];
+                max = face->mExtents[1];
                 any_valid_boxes = true;
-			}
-			else
-			{
-				min.setMin(min, face->mExtents[0]);
-				max.setMax(max, face->mExtents[1]);
-			}
-		}
-	}
+            }
+            else
+            {
+                min.setMin(min, face->mExtents[0]);
+                max.setMax(max, face->mExtents[1]);
+            }
+        }
+    }
 
     if (any_valid_boxes)
     {
-        if (rebuild)
+        if (rebuild && should_update_octree_bounds)
         {
-            if (getRiggedVolume())
+            //get the Avatar associated with this object if it's rigged
+            LLVOAvatar* avatar = nullptr;
+            if (isRiggedMesh())
+            {
+                if (!isAnimatedObject())
+                {
+                    if (isAttachment())
+                    {
+                        avatar = getAvatar();
+                    }
+                }
+                else
+                {
+                    LLControlAvatar* controlAvatar = getControlAvatar();
+                    if (controlAvatar && controlAvatar->mPlaying)
+                    {
+                        avatar = controlAvatar;
+                    }
+                }
+            }
+
+            mDrawable->setSpatialExtents(min, max);
+
+            if (avatar)
             {
-                LL_DEBUGS("RiggedBox") << "rebuilding got extents " << min << ", " << max << LL_ENDL;
+                // put all rigged drawables in the same octree node for better batching
+                mDrawable->setPositionGroup(LLVector4a(0, 0, 0));
+            }
+            else
+            {
+                min.add(max);
+                min.mul(0.5f);
+                mDrawable->setPositionGroup(min);
             }
-            mDrawable->setSpatialExtents(min,max);
-            min.add(max);
-            min.mul(0.5f);
-            mDrawable->setPositionGroup(min);	
         }
-
+        
         updateRadius();
         mDrawable->movePartition();
     }
@@ -1762,8 +1819,8 @@ BOOL LLVOVolume::genBBoxes(BOOL force_global)
     {
         LL_DEBUGS("RiggedBox") << "genBBoxes failed to find any valid face boxes" << LL_ENDL;
     }
-				
-	return res;
+
+    return res;
 }
 
 void LLVOVolume::preRebuild()
@@ -1879,12 +1936,9 @@ void LLVOVolume::updateRelativeXform(bool force_identity)
 	}
 }
 
-static LLTrace::BlockTimerStatHandle FTM_GEN_FLEX("Generate Flexies");
-static LLTrace::BlockTimerStatHandle FTM_UPDATE_PRIMITIVES("Update Primitives");
-static LLTrace::BlockTimerStatHandle FTM_UPDATE_RIGGED_VOLUME("Update Rigged");
-
-bool LLVOVolume::lodOrSculptChanged(LLDrawable *drawable, BOOL &compiled)
+bool LLVOVolume::lodOrSculptChanged(LLDrawable *drawable, BOOL &compiled, BOOL &should_update_octree_bounds)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME;
 	bool regen_faces = false;
 
 	LLVolume *old_volumep, *new_volumep;
@@ -1897,7 +1951,6 @@ bool LLVOVolume::lodOrSculptChanged(LLDrawable *drawable, BOOL &compiled)
 	old_volumep = NULL;
 
 	{
-		LL_RECORD_BLOCK_TIME(FTM_GEN_VOLUME);
 		const LLVolumeParams &volume_params = getVolume()->getParams();
 		setVolume(volume_params, 0);
 	}
@@ -1915,6 +1968,9 @@ bool LLVOVolume::lodOrSculptChanged(LLDrawable *drawable, BOOL &compiled)
         }
 
 		compiled = TRUE;
+        // new_lod > old_lod breaks a feedback loop between LOD updates and
+        // bounding box updates.
+        should_update_octree_bounds = should_update_octree_bounds || mSculptChanged || new_lod > old_lod;
 		sNumLODChanges += new_num_faces;
 
 		if ((S32)getNumTEs() != getVolume()->getNumFaces())
@@ -1925,7 +1981,6 @@ bool LLVOVolume::lodOrSculptChanged(LLDrawable *drawable, BOOL &compiled)
 		drawable->setState(LLDrawable::REBUILD_VOLUME); // for face->genVolumeTriangles()
 
 		{
-			LL_RECORD_BLOCK_TIME(FTM_GEN_TRIANGLES);
 			regen_faces = new_num_faces != old_num_faces || mNumFaces != (S32)getNumTEs();
 			if (regen_faces)
 			{
@@ -1950,14 +2005,11 @@ bool LLVOVolume::lodOrSculptChanged(LLDrawable *drawable, BOOL &compiled)
 
 BOOL LLVOVolume::updateGeometry(LLDrawable *drawable)
 {
-	LL_RECORD_BLOCK_TIME(FTM_UPDATE_PRIMITIVES);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME;
 	
 	if (mDrawable->isState(LLDrawable::REBUILD_RIGGED))
 	{
-		{
-			LL_RECORD_BLOCK_TIME(FTM_UPDATE_RIGGED_VOLUME);
-			updateRiggedVolume();
-		}
+        updateRiggedVolume(false);
 		genBBoxes(FALSE);
 		mDrawable->clearState(LLDrawable::REBUILD_RIGGED);
 	}
@@ -1966,7 +2018,6 @@ BOOL LLVOVolume::updateGeometry(LLDrawable *drawable)
 	{
 		BOOL res;
 		{
-			LL_RECORD_BLOCK_TIME(FTM_GEN_FLEX);
 			res = mVolumeImpl->doUpdateGeometry(drawable);
 		}
 		updateFaceFlags();
@@ -1979,8 +2030,6 @@ BOOL LLVOVolume::updateGeometry(LLDrawable *drawable)
 		group->dirtyMesh();
 	}
 
-	BOOL compiled = FALSE;
-			
 	updateRelativeXform();
 	
 	if (mDrawable.isNull()) // Not sure why this is happening, but it is...
@@ -1988,51 +2037,55 @@ BOOL LLVOVolume::updateGeometry(LLDrawable *drawable)
 		return TRUE; // No update to complete
 	}
 
+	BOOL compiled = FALSE;
+    // This should be true in most cases, unless we're sure no octree update is
+    // needed.
+    BOOL should_update_octree_bounds = bool(getRiggedVolume()) || mDrawable->isState(LLDrawable::REBUILD_POSITION) || !mDrawable->getSpatialExtents()->isFinite3();
+
 	if (mVolumeChanged || mFaceMappingChanged)
 	{
 		dirtySpatialGroup(drawable->isState(LLDrawable::IN_REBUILD_Q1));
 
 		bool was_regen_faces = false;
+        should_update_octree_bounds = true;
 
 		if (mVolumeChanged)
 		{
-			was_regen_faces = lodOrSculptChanged(drawable, compiled);
+            was_regen_faces = lodOrSculptChanged(drawable, compiled, should_update_octree_bounds);
 			drawable->setState(LLDrawable::REBUILD_VOLUME);
 		}
-		else if (mSculptChanged || mLODChanged)
+		else if (mSculptChanged || mLODChanged || mColorChanged)
 		{
 			compiled = TRUE;
-			was_regen_faces = lodOrSculptChanged(drawable, compiled);
+            was_regen_faces = lodOrSculptChanged(drawable, compiled, should_update_octree_bounds);
 		}
 
 		if (!was_regen_faces) {
-			LL_RECORD_BLOCK_TIME(FTM_GEN_TRIANGLES);
 			regenFaces();
 		}
-
-		genBBoxes(FALSE);
 	}
-	else if (mLODChanged || mSculptChanged)
+	else if (mLODChanged || mSculptChanged || mColorChanged)
 	{
 		dirtySpatialGroup(drawable->isState(LLDrawable::IN_REBUILD_Q1));
 		compiled = TRUE;
-		lodOrSculptChanged(drawable, compiled);
+        lodOrSculptChanged(drawable, compiled, should_update_octree_bounds);
 		
 		if(drawable->isState(LLDrawable::REBUILD_RIGGED | LLDrawable::RIGGED)) 
 		{
 			updateRiggedVolume(false);
 		}
-		genBBoxes(FALSE);
 	}
 	// it has its own drawable (it's moved) or it has changed UVs or it has changed xforms from global<->local
 	else
 	{
 		compiled = TRUE;
 		// All it did was move or we changed the texture coordinate offset
-		LL_RECORD_BLOCK_TIME(FTM_GEN_TRIANGLES);
-		genBBoxes(FALSE);
 	}
 
+    // Generate bounding boxes if needed, and update the object's size in the
+    // octree
+    genBBoxes(FALSE, should_update_octree_bounds);
+
 	// Update face flags
 	updateFaceFlags();
 	
@@ -2045,6 +2098,7 @@ BOOL LLVOVolume::updateGeometry(LLDrawable *drawable)
 	mLODChanged = FALSE;
 	mSculptChanged = FALSE;
 	mFaceMappingChanged = FALSE;
+    mColorChanged = FALSE;
 	
 	return LLViewerObject::updateGeometry(drawable);
 }
@@ -2183,6 +2237,7 @@ S32 LLVOVolume::setTEColor(const U8 te, const LLColor4& color)
 		if (mDrawable.notNull() && retval)
 		{
 			// These should only happen on updates which are not the initial update.
+            mColorChanged = TRUE;
 			mDrawable->setState(LLDrawable::REBUILD_COLOR);
 			dirtyMesh();
 		}
@@ -2960,6 +3015,17 @@ void LLVOVolume::mediaEvent(LLViewerMediaImpl *impl, LLPluginClassMedia* plugin,
 			}
 		}
 		break;
+
+        case LLViewerMediaObserver::MEDIA_EVENT_FILE_DOWNLOAD:
+        {
+            // Media might be blocked, waiting for a file,
+            // send an empty response to unblock it
+            const std::vector<std::string> empty_response;
+            plugin->sendPickFileResponse(empty_response);
+
+            LLNotificationsUtil::add("MediaFileDownloadUnsupported");
+        }
+        break;
 		
 		default:
 		break;
@@ -3579,7 +3645,7 @@ const LLMeshSkinInfo* LLVOVolume::getSkinInfo() const
 {
     if (getVolume())
     {
-        return gMeshRepo.getSkinInfo(getVolume()->getParams().getSculptID(), this);
+        return gMeshRepo.getSkinInfo(getMeshID(), this);
     }
     else
     {
@@ -3741,11 +3807,9 @@ void LLVOVolume::afterReparent()
 }
 
 //----------------------------------------------------------------------------
-static LLTrace::BlockTimerStatHandle FTM_VOVOL_RIGGING_INFO("VOVol Rigging Info");
-
 void LLVOVolume::updateRiggingInfo()
 {
-    LL_RECORD_BLOCK_TIME(FTM_VOVOL_RIGGING_INFO);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME;
     if (isRiggedMesh())
     {
         const LLMeshSkinInfo* skin = getSkinInfo();
@@ -4355,6 +4419,7 @@ void LLVOVolume::updateSpatialExtents(LLVector4a& newMin, LLVector4a& newMax)
 
 F32 LLVOVolume::getBinRadius()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME;
 	F32 radius;
 	
 	F32 scale = 1.f;
@@ -4550,7 +4615,7 @@ BOOL LLVOVolume::lineSegmentIntersect(const LLVector4a& start, const LLVector4a&
 	{
 		if ((pick_rigged) || (getAvatar() && (getAvatar()->isSelf()) && (LLFloater::isVisible(gFloaterTools))))
 		{
-			updateRiggedVolume(true);
+            updateRiggedVolume(true, LLRiggedVolume::DO_NOT_UPDATE_FACES);
 			volume = mRiggedVolume;
 			transform = false;
 		}
@@ -4625,6 +4690,9 @@ BOOL LLVOVolume::lineSegmentIntersect(const LLVector4a& start, const LLVector4a&
 				continue;
 			}
 
+            // This calculates the bounding box of the skinned mesh from scratch. It's actually quite expensive, but not nearly as expensive as building a full octree.
+            // rebuild_face_octrees = false because an octree for this face will be built later only if needed for narrow phase picking.
+            updateRiggedVolume(true, i, false);
 			face_hit = volume->lineSegmentIntersect(local_start, local_end, i,
 													&p, &tc, &n, &tn);
 			
@@ -4748,12 +4816,13 @@ void LLVOVolume::clearRiggedVolume()
 	}
 }
 
-void LLVOVolume::updateRiggedVolume(bool force_update)
+void LLVOVolume::updateRiggedVolume(bool force_treat_as_rigged, LLRiggedVolume::FaceIndex face_index, bool rebuild_face_octrees)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME;
 	//Update mRiggedVolume to match current animation frame of avatar. 
 	//Also update position/size in octree.  
 
-	if ((!force_update) && (!treatAsRigged()))
+    if ((!force_treat_as_rigged) && (!treatAsRigged()))
 	{
 		clearRiggedVolume();
 		
@@ -4782,14 +4851,12 @@ void LLVOVolume::updateRiggedVolume(bool force_update)
 		updateRelativeXform();
 	}
 
-	mRiggedVolume->update(skin, avatar, volume);
+    mRiggedVolume->update(skin, avatar, volume, face_index, rebuild_face_octrees);
 }
 
-static LLTrace::BlockTimerStatHandle FTM_SKIN_RIGGED("Skin");
-static LLTrace::BlockTimerStatHandle FTM_RIGGED_OCTREE("Octree");
-
-void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, const LLVolume* volume)
+void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, const LLVolume* volume, FaceIndex face_index, bool rebuild_face_octrees)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME;
 	bool copy = false;
 	if (volume->getNumVolumeFaces() != getNumVolumeFaces())
 	{ 
@@ -4810,7 +4877,7 @@ void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, cons
 
 	if (copy)
 	{
-		copyVolumeFaces(volume);	
+		copyVolumeFaces(volume);
 	}
     else
     {
@@ -4818,7 +4885,7 @@ void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, cons
 		if (is_paused)
 		{
             S32 frames_paused = LLFrameTimer::getFrameCount() - avatar->getMotionController().getPausedFrame();
-            if (frames_paused > 2)
+            if (frames_paused > 1)
             {
                 return;
             }
@@ -4831,12 +4898,30 @@ void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, cons
 
 	LLMatrix4a mat[kMaxJoints];
 	U32 maxJoints = LLSkinningUtil::getMeshJointCount(skin);
-    LLSkinningUtil::initSkinningMatrixPalette((LLMatrix4*)mat, maxJoints, skin, avatar);
+    LLSkinningUtil::initSkinningMatrixPalette(mat, maxJoints, skin, avatar);
+    const LLMatrix4a bind_shape_matrix = skin->mBindShapeMatrix;
 
     S32 rigged_vert_count = 0;
     S32 rigged_face_count = 0;
     LLVector4a box_min, box_max;
-	for (S32 i = 0; i < volume->getNumVolumeFaces(); ++i)
+    S32 face_begin;
+    S32 face_end;
+    if (face_index == DO_NOT_UPDATE_FACES)
+    {
+        face_begin = 0;
+        face_end = 0;
+    }
+    else if (face_index == UPDATE_ALL_FACES)
+    {
+        face_begin = 0;
+        face_end = volume->getNumVolumeFaces();
+    }
+    else
+    {
+        face_begin = face_index;
+        face_end = face_begin + 1;
+    }
+    for (S32 i = face_begin; i < face_end; ++i)
 	{
 		const LLVolumeFace& vol_face = volume->getVolumeFace(i);
 		
@@ -4847,15 +4932,11 @@ void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, cons
 		if ( weight )
 		{
             LLSkinningUtil::checkSkinWeights(weight, dst_face.mNumVertices, skin);
-			LLMatrix4a bind_shape_matrix;
-			bind_shape_matrix.loadu(skin->mBindShapeMatrix);
 
 			LLVector4a* pos = dst_face.mPositions;
 
 			if (pos && dst_face.mExtents)
 			{
-				LL_RECORD_BLOCK_TIME(FTM_SKIN_RIGGED);
-
                 U32 max_joints = LLSkinningUtil::getMaxJointCount();
                 rigged_vert_count += dst_face.mNumVertices;
                 rigged_face_count++;
@@ -4925,16 +5006,10 @@ void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, cons
 
 			}
 
+            if (rebuild_face_octrees)
 			{
-				LL_RECORD_BLOCK_TIME(FTM_RIGGED_OCTREE);
-				delete dst_face.mOctree;
-				dst_face.mOctree = NULL;
-
-				LLVector4a size;
-				size.setSub(dst_face.mExtents[1], dst_face.mExtents[0]);
-				size.splat(size.getLength3().getF32()*0.5f);
-			
-				dst_face.createOctree(1.f);
+                dst_face.destroyOctree();
+                dst_face.createOctree();
 			}
 		}
 	}
@@ -5029,13 +5104,13 @@ bool can_batch_texture(LLFace* facep)
 
 const static U32 MAX_FACE_COUNT = 4096U;
 int32_t LLVolumeGeometryManager::sInstanceCount = 0;
-LLFace** LLVolumeGeometryManager::sFullbrightFaces = NULL;
-LLFace** LLVolumeGeometryManager::sBumpFaces = NULL;
-LLFace** LLVolumeGeometryManager::sSimpleFaces = NULL;
-LLFace** LLVolumeGeometryManager::sNormFaces = NULL;
-LLFace** LLVolumeGeometryManager::sSpecFaces = NULL;
-LLFace** LLVolumeGeometryManager::sNormSpecFaces = NULL;
-LLFace** LLVolumeGeometryManager::sAlphaFaces = NULL;
+LLFace** LLVolumeGeometryManager::sFullbrightFaces[2] = { NULL };
+LLFace** LLVolumeGeometryManager::sBumpFaces[2] = { NULL };
+LLFace** LLVolumeGeometryManager::sSimpleFaces[2] = { NULL };
+LLFace** LLVolumeGeometryManager::sNormFaces[2] = { NULL };
+LLFace** LLVolumeGeometryManager::sSpecFaces[2] = { NULL };
+LLFace** LLVolumeGeometryManager::sNormSpecFaces[2] = { NULL };
+LLFace** LLVolumeGeometryManager::sAlphaFaces[2] = { NULL };
 
 LLVolumeGeometryManager::LLVolumeGeometryManager()
 	: LLGeometryManager()
@@ -5063,39 +5138,43 @@ LLVolumeGeometryManager::~LLVolumeGeometryManager()
 
 void LLVolumeGeometryManager::allocateFaces(U32 pMaxFaceCount)
 {
-	sFullbrightFaces = static_cast<LLFace**>(ll_aligned_malloc<64>(pMaxFaceCount*sizeof(LLFace*)));
-	sBumpFaces = static_cast<LLFace**>(ll_aligned_malloc<64>(pMaxFaceCount*sizeof(LLFace*)));
-	sSimpleFaces = static_cast<LLFace**>(ll_aligned_malloc<64>(pMaxFaceCount*sizeof(LLFace*)));
-	sNormFaces = static_cast<LLFace**>(ll_aligned_malloc<64>(pMaxFaceCount*sizeof(LLFace*)));
-	sSpecFaces = static_cast<LLFace**>(ll_aligned_malloc<64>(pMaxFaceCount*sizeof(LLFace*)));
-	sNormSpecFaces = static_cast<LLFace**>(ll_aligned_malloc<64>(pMaxFaceCount*sizeof(LLFace*)));
-	sAlphaFaces = static_cast<LLFace**>(ll_aligned_malloc<64>(pMaxFaceCount*sizeof(LLFace*)));
+    for (int i = 0; i < 2; ++i)
+    {
+        sFullbrightFaces[i] = static_cast<LLFace**>(ll_aligned_malloc<64>(pMaxFaceCount * sizeof(LLFace*)));
+        sBumpFaces[i] = static_cast<LLFace**>(ll_aligned_malloc<64>(pMaxFaceCount * sizeof(LLFace*)));
+        sSimpleFaces[i] = static_cast<LLFace**>(ll_aligned_malloc<64>(pMaxFaceCount * sizeof(LLFace*)));
+        sNormFaces[i] = static_cast<LLFace**>(ll_aligned_malloc<64>(pMaxFaceCount * sizeof(LLFace*)));
+        sSpecFaces[i] = static_cast<LLFace**>(ll_aligned_malloc<64>(pMaxFaceCount * sizeof(LLFace*)));
+        sNormSpecFaces[i] = static_cast<LLFace**>(ll_aligned_malloc<64>(pMaxFaceCount * sizeof(LLFace*)));
+        sAlphaFaces[i] = static_cast<LLFace**>(ll_aligned_malloc<64>(pMaxFaceCount * sizeof(LLFace*)));
+    }
 }
 
 void LLVolumeGeometryManager::freeFaces()
 {
-	ll_aligned_free<64>(sFullbrightFaces);
-	ll_aligned_free<64>(sBumpFaces);
-	ll_aligned_free<64>(sSimpleFaces);
-	ll_aligned_free<64>(sNormFaces);
-	ll_aligned_free<64>(sSpecFaces);
-	ll_aligned_free<64>(sNormSpecFaces);
-	ll_aligned_free<64>(sAlphaFaces);
-
-	sFullbrightFaces = NULL;
-	sBumpFaces = NULL;
-	sSimpleFaces = NULL;
-	sNormFaces = NULL;
-	sSpecFaces = NULL;
-	sNormSpecFaces = NULL;
-	sAlphaFaces = NULL;
+    for (int i = 0; i < 2; ++i)
+    {
+        ll_aligned_free<64>(sFullbrightFaces[i]);
+        ll_aligned_free<64>(sBumpFaces[i]);
+        ll_aligned_free<64>(sSimpleFaces[i]);
+        ll_aligned_free<64>(sNormFaces[i]);
+        ll_aligned_free<64>(sSpecFaces[i]);
+        ll_aligned_free<64>(sNormSpecFaces[i]);
+        ll_aligned_free<64>(sAlphaFaces[i]);
+
+        sFullbrightFaces[i] = NULL;
+        sBumpFaces[i] = NULL;
+        sSimpleFaces[i] = NULL;
+        sNormFaces[i] = NULL;
+        sSpecFaces[i] = NULL;
+        sNormSpecFaces[i] = NULL;
+        sAlphaFaces[i] = NULL;
+    }
 }
 
-static LLTrace::BlockTimerStatHandle FTM_REGISTER_FACE("Register Face");
-
 void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep, U32 type)
 {
-	LL_RECORD_BLOCK_TIME(FTM_REGISTER_FACE);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME;
 	if (   type == LLRenderPass::PASS_ALPHA 
 		&& facep->getTextureEntry()->getMaterialParams().notNull() 
 		&& !facep->getVertexBuffer()->hasDataType(LLVertexBuffer::TYPE_TANGENT)
@@ -5111,8 +5190,18 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep,
 		return;
 	}
 
+    U32 passType = type;
+
+    bool rigged = facep->isState(LLFace::RIGGED);
+
+    if (rigged)
+    {
+        // hacky, should probably clean up -- if this face is rigged, put it in "type + 1"
+        // See LLRenderPass PASS_foo enum
+        passType += 1;
+    }
 	//add face to drawmap
-	LLSpatialGroup::drawmap_elem_t& draw_vec = group->mDrawMap[type];	
+	LLSpatialGroup::drawmap_elem_t& draw_vec = group->mDrawMap[passType];
 
 	S32 idx = draw_vec.size()-1;
 
@@ -5138,7 +5227,12 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep,
 
 	LLDrawable* drawable = facep->getDrawable();
 	
-	if (drawable->isState(LLDrawable::ANIMATED_CHILD))
+    if (rigged)
+    {
+        // rigged meshes ignore their model matrix
+        model_mat = nullptr;
+    }
+	else if (drawable->isState(LLDrawable::ANIMATED_CHILD))
 	{
 		model_mat = &drawable->getWorldMatrix();
 	}
@@ -5179,6 +5273,7 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep,
 		}
 	}
 
+    F32 vsize = facep->getVirtualSize(); //TODO -- adjust by texture scale?
 
 	if (index < FACE_DO_NOT_BATCH_TEXTURES && idx >= 0)
 	{
@@ -5192,10 +5287,12 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep,
 			{
 				batchable = true;
 				draw_vec[idx]->mTextureList[index] = tex;
+                draw_vec[idx]->mTextureListVSize[index] = vsize;
 			}
 			else if (draw_vec[idx]->mTextureList[index] == tex)
 			{ //this face's texture index can be used with this batch
 				batchable = true;
+                draw_vec[idx]->mTextureListVSize[index] = llmax(vsize, draw_vec[idx]->mTextureListVSize[index]);
 			}
 		}
 		else
@@ -5212,7 +5309,7 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep,
 		draw_vec[idx]->mEnd - draw_vec[idx]->mStart + facep->getGeomCount() <= (U32) gGLManager.mGLMaxVertexRange &&
 		draw_vec[idx]->mCount + facep->getIndicesCount() <= (U32) gGLManager.mGLMaxIndexRange &&
 #endif
-		draw_vec[idx]->mMaterial == mat &&
+		//draw_vec[idx]->mMaterial == mat &&
 		draw_vec[idx]->mMaterialID == mat_id &&
 		draw_vec[idx]->mFullbright == fullbright &&
 		draw_vec[idx]->mBump == bump &&
@@ -5220,16 +5317,20 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep,
 		draw_vec[idx]->mTextureMatrix == tex_mat &&
 		draw_vec[idx]->mModelMatrix == model_mat &&
 		draw_vec[idx]->mShaderMask == shader_mask &&
-		draw_vec[idx]->mSelected == selected)
+		draw_vec[idx]->mSelected == selected &&
+        draw_vec[idx]->mAvatar == facep->mAvatar &&
+        draw_vec[idx]->getSkinHash() == facep->getSkinHash())
 	{
 		draw_vec[idx]->mCount += facep->getIndicesCount();
 		draw_vec[idx]->mEnd += facep->getGeomCount();
-		draw_vec[idx]->mVSize = llmax(draw_vec[idx]->mVSize, facep->getVirtualSize());
+		draw_vec[idx]->mVSize = llmax(draw_vec[idx]->mVSize, vsize);
 
 		if (index < FACE_DO_NOT_BATCH_TEXTURES && index >= draw_vec[idx]->mTextureList.size())
 		{
 			draw_vec[idx]->mTextureList.resize(index+1);
 			draw_vec[idx]->mTextureList[index] = tex;
+            draw_vec[idx]->mTextureListVSize.resize(index + 1);
+            draw_vec[idx]->mTextureListVSize[index] = vsize;
 		}
 		draw_vec[idx]->validate();
 		update_min_max(draw_vec[idx]->mExtents[0], draw_vec[idx]->mExtents[1], facep->mExtents[0]);
@@ -5244,7 +5345,7 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep,
 		LLPointer<LLDrawInfo> draw_info = new LLDrawInfo(start,end,count,offset, tex, 
 			facep->getVertexBuffer(), selected, fullbright, bump);
 		draw_info->mGroup = group;
-		draw_info->mVSize = facep->getVirtualSize();
+		draw_info->mVSize = vsize;
 		draw_vec.push_back(draw_info);
 		draw_info->mTextureMatrix = tex_mat;
 		draw_info->mModelMatrix = model_mat;
@@ -5266,6 +5367,8 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep,
 		draw_info->mSpecularMap = NULL;
 		draw_info->mMaterial = mat;
 		draw_info->mShaderMask = shader_mask;
+        draw_info->mAvatar = facep->mAvatar;
+        draw_info->mSkinInfo = facep->mSkinInfo;
 
 		if (mat)
 		{
@@ -5317,6 +5420,8 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep,
 		{ //initialize texture list for texture batching
 			draw_info->mTextureList.resize(index+1);
 			draw_info->mTextureList[index] = tex;
+            draw_info->mTextureListVSize.resize(index + 1);
+            draw_info->mTextureListVSize[index] = vsize;
 		}
 		draw_info->validate();
 	}
@@ -5327,38 +5432,6 @@ void LLVolumeGeometryManager::getGeometry(LLSpatialGroup* group)
 
 }
 
-static LLTrace::BlockTimerStatHandle FTM_REBUILD_VOLUME_VB("Volume VB");
-static LLTrace::BlockTimerStatHandle FTM_REBUILD_VOLUME_FACE_LIST("Build Face List");
-static LLTrace::BlockTimerStatHandle FTM_REBUILD_VOLUME_GEN_DRAW_INFO("Gen Draw Info");
-
-static LLDrawPoolAvatar* get_avatar_drawpool(LLViewerObject* vobj)
-{
-	LLVOAvatar* avatar = vobj->getAvatar();
-					
-	if (avatar)
-	{
-		LLDrawable* drawable = avatar->mDrawable;
-		if (drawable && drawable->getNumFaces() > 0)
-		{
-			LLFace* face = drawable->getFace(0);
-			if (face)
-			{
-				LLDrawPool* drawpool = face->getPool();
-				if (drawpool)
-				{
-					if (drawpool->getType() == LLDrawPool::POOL_AVATAR
-						|| drawpool->getType() == LLDrawPool::POOL_CONTROL_AV)
-					{
-						return (LLDrawPoolAvatar*) drawpool;
-					}
-				}
-			}
-		}
-	}
-
-	return NULL;
-}
-
 void handleRenderAutoMuteByteLimitChanged(const LLSD& new_value)
 {
 	static LLCachedControl<U32> render_auto_mute_byte_limit(gSavedSettings, "RenderAutoMuteByteLimit", 0U);
@@ -5434,8 +5507,32 @@ void handleRenderAutoMuteByteLimitChanged(const LLSD& new_value)
 	}
 }
 
+// add a face pointer to a list of face pointers without going over MAX_COUNT faces
+template<typename T>
+static inline void add_face(T*** list, U32* count, T* face)
+{
+    if (face->isState(LLFace::RIGGED))
+    {
+        if (count[1] < MAX_FACE_COUNT)
+        {
+            face->setDrawOrderIndex(count[1]);
+            list[1][count[1]++] = face;
+        }
+    }
+    else
+    {
+        if (count[0] < MAX_FACE_COUNT)
+        {
+            face->setDrawOrderIndex(count[0]);
+            list[0][count[0]++] = face;
+        }
+    }
+}
+
 void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME;
+
 	if (group->changeLOD())
 	{
 		group->mLastUpdateDistance = group->mDistance;
@@ -5452,8 +5549,6 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 		return;
 	}
 
-	LL_RECORD_BLOCK_TIME(FTM_REBUILD_VOLUME_VB);
-
 	group->mBuilt = 1.f;
 	
 	LLSpatialBridge* bridge = group->getSpatialPartition()->asBridge();
@@ -5479,16 +5574,13 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 
 	group->clearDrawMap();
 
-	mFaceList.clear();
-
-	U32 fullbright_count = 0;
-	U32 bump_count = 0;
-	U32 simple_count = 0;
-	U32 alpha_count = 0;
-	U32 norm_count = 0;
-	U32 spec_count = 0;
-	U32 normspec_count = 0;
-
+    U32 fullbright_count[2] = { 0 };
+	U32 bump_count[2] = { 0 };
+	U32 simple_count[2] = { 0 };
+	U32 alpha_count[2] = { 0 };
+	U32 norm_count[2] = { 0 };
+	U32 spec_count[2] = { 0 };
+	U32 normspec_count[2] = { 0 };
 
 	U32 useage = group->getSpatialPartition()->mBufferUsage;
 
@@ -5510,7 +5602,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 #endif
 
 	{
-		LL_RECORD_BLOCK_TIME(FTM_REBUILD_VOLUME_FACE_LIST);
+        LL_PROFILE_ZONE_NAMED("rebuildGeom - face list");
 
 		//get all the faces into a list
 		for (LLSpatialGroup::element_iter drawable_iter = group->getDataBegin(); 
@@ -5537,7 +5629,8 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 
             std::string vobj_name = llformat("Vol%p", vobj);
 
-			if (vobj->isMesh() &&
+            bool is_mesh = vobj->isMesh();
+			if (is_mesh &&
 				((vobj->getVolume() && !vobj->getVolume()->isMeshAssetLoaded()) || !gMeshRepo.meshRezEnabled()))
 			{
 				continue;
@@ -5550,7 +5643,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 				group->mSurfaceArea += volume->getSurfaceArea() * llmax(llmax(scale.mV[0], scale.mV[1]), scale.mV[2]);
 			}
 
-            bool is_mesh = vobj->isMesh();
+            
             F32 est_tris = vobj->getEstTrianglesMax();
 
             vobj->updateControlAvatar();
@@ -5574,15 +5667,32 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 
 			drawablep->clearState(LLDrawable::HAS_ALPHA);
 
-            if (vobj->isRiggedMesh() &&
-                ((vobj->isAnimatedObject() && vobj->getControlAvatar()) ||
-                 (!vobj->isAnimatedObject() && vobj->getAvatar())))
+            LLVOAvatar* avatar = nullptr;
+            const LLMeshSkinInfo* skinInfo = nullptr;
+            if (is_mesh)
             {
-                vobj->getAvatar()->addAttachmentOverridesForObject(vobj, NULL, false);
+                skinInfo = vobj->getSkinInfo();
             }
-            
+
+            if (skinInfo)
+            {
+                if (vobj->isAnimatedObject())
+                {
+                    avatar = vobj->getControlAvatar();
+                }
+                else
+                {
+                    avatar = vobj->getAvatar();
+                }
+            }
+
+            if (avatar != nullptr)
+            {
+                avatar->addAttachmentOverridesForObject(vobj, NULL, false);
+            }
+
             // Standard rigged mesh attachments: 
-			bool rigged = !vobj->isAnimatedObject() && vobj->isRiggedMesh() && vobj->isAttachment();
+			bool rigged = !vobj->isAnimatedObject() && skinInfo && vobj->isAttachment();
             // Animated objects. Have to check for isRiggedMesh() to
             // exclude static objects in animated object linksets.
 			rigged = rigged || (vobj->isAnimatedObject() && vobj->isRiggedMesh() &&
@@ -5606,183 +5716,34 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 			
 				//sum up face verts and indices
 				drawablep->updateFaceSize(i);
-			
-				if (rigged)
-				{
-					if (!facep->isState(LLFace::RIGGED))
-					{ //completely reset vertex buffer
-						facep->clearVertexBuffer();
-					}
-		
-					facep->setState(LLFace::RIGGED);
-					any_rigged_face = true;
-				
-					//get drawpool of avatar with rigged face
-					LLDrawPoolAvatar* pool = get_avatar_drawpool(vobj);				
-					
-					if (pool)
-					{
-						const LLTextureEntry* te = facep->getTextureEntry();
-
-						//remove face from old pool if it exists
-						LLDrawPool* old_pool = facep->getPool();
-						if (old_pool
-							&& (old_pool->getType() == LLDrawPool::POOL_AVATAR || old_pool->getType() == LLDrawPool::POOL_CONTROL_AV))
-						{
-							((LLDrawPoolAvatar*) old_pool)->removeRiggedFace(facep);
-						}
-
-						//add face to new pool
-						LLViewerTexture* tex = facep->getTexture();
-						U32 type = gPipeline.getPoolTypeFromTE(te, tex);
-
-                        F32 te_alpha = te->getColor().mV[3];
-
-						if (te->getGlow())
-						{
-							pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_GLOW);
-						}
-
-						LLMaterial* mat = te->getMaterialParams().get();
-                        bool fullbright = te->getFullbright();
 
-						if (mat && LLPipeline::sRenderDeferred)
-						{
-							U8 alpha_mode = mat->getDiffuseAlphaMode();
-
-							bool is_alpha = type == LLDrawPool::POOL_ALPHA &&
-								(alpha_mode == LLMaterial::DIFFUSE_ALPHA_MODE_BLEND ||
-								te_alpha < 0.999f);
-
-							if (is_alpha)
-							{ //this face needs alpha blending, override alpha mode
-								alpha_mode = LLMaterial::DIFFUSE_ALPHA_MODE_BLEND;
-							}
-
-                            if (fullbright && (alpha_mode == LLMaterial::DIFFUSE_ALPHA_MODE_NONE))
-                            {
-                                pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_FULLBRIGHT);
-                            }
-							else if (!is_alpha || te_alpha > 0.f)  // //only add the face if it will actually be visible
-							{ 
-								U32 mask = mat->getShaderMask(alpha_mode);
-								pool->addRiggedFace(facep, mask);
-							}
-
-							if(vobj->isAnimatedObject() && vobj->isRiggedMesh())
-							{
-								pool->updateRiggedVertexBuffers(vobj->getAvatar());
-							}
-						}
-						else if (mat)
-						{							
-							bool is_alpha = type == LLDrawPool::POOL_ALPHA;
-							U8 mode = mat->getDiffuseAlphaMode();
-							bool can_be_shiny = mode == LLMaterial::DIFFUSE_ALPHA_MODE_NONE ||
-												mode == LLMaterial::DIFFUSE_ALPHA_MODE_EMISSIVE;
-							
-							if (mode == LLMaterial::DIFFUSE_ALPHA_MODE_MASK && te->getColor().mV[3] >= 0.999f)
-							{
-								pool->addRiggedFace(facep, fullbright ? LLDrawPoolAvatar::RIGGED_FULLBRIGHT : LLDrawPoolAvatar::RIGGED_SIMPLE);
-							}
-							else if (is_alpha || (te->getColor().mV[3] < 0.999f))
-							{
-								if (te->getColor().mV[3] > 0.f)
-								{
-									pool->addRiggedFace(facep, fullbright ? LLDrawPoolAvatar::RIGGED_FULLBRIGHT_ALPHA : LLDrawPoolAvatar::RIGGED_ALPHA);
-								}
-							}
-							else if (gPipeline.canUseVertexShaders()
-								&& LLPipeline::sRenderBump 
-								&& te->getShiny() 
-								&& can_be_shiny)
-							{
-								pool->addRiggedFace(facep, fullbright ? LLDrawPoolAvatar::RIGGED_FULLBRIGHT_SHINY : LLDrawPoolAvatar::RIGGED_SHINY);
-							}
-							else
-							{
-								pool->addRiggedFace(facep, fullbright ? LLDrawPoolAvatar::RIGGED_FULLBRIGHT : LLDrawPoolAvatar::RIGGED_SIMPLE);
-							}
-						}
-						else
-						{
-						if (type == LLDrawPool::POOL_ALPHA)
-						{
-							if (te->getColor().mV[3] > 0.f)
-							{
-								if (te->getFullbright())
-								{
-									pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_FULLBRIGHT_ALPHA);
-								}
-								else
-								{
-									pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_ALPHA);
-								}
-							}
-						}
-						else if (te->getShiny())
-						{
-							if (te->getFullbright())
-							{
-								pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_FULLBRIGHT_SHINY);
-							}
-							else
-							{
-								if (LLPipeline::sRenderDeferred)
-								{
-									pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_SIMPLE);
-								}
-								else
-								{
-									pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_SHINY);
-								}
-							}
-						}
-						else
-						{
-							if (te->getFullbright())
-							{
-								pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_FULLBRIGHT);
-							}
-							else
-							{
-								pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_SIMPLE);
-							}
-						}
-
-
-						if (LLPipeline::sRenderDeferred)
-						{
-							if (type != LLDrawPool::POOL_ALPHA && !te->getFullbright())
-							{
-								if (te->getBumpmap())
-								{
-									pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_DEFERRED_BUMP);
-								}
-								else
-								{
-									pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_DEFERRED_SIMPLE);
-								}
-							}
-						}
-					}
-					}
-
-					continue;
-				}
-				else
-				{
-					if (facep->isState(LLFace::RIGGED))
-					{ //face is not rigged but used to be, remove from rigged face pool
-						LLDrawPoolAvatar* pool = (LLDrawPoolAvatar*) facep->getPool();
-						if (pool)
-						{
-							pool->removeRiggedFace(facep);
-						}
-						facep->clearState(LLFace::RIGGED);
-					}
-				}
+                if (rigged)
+                {
+                    if (!facep->isState(LLFace::RIGGED))
+                    { //completely reset vertex buffer
+                        facep->clearVertexBuffer();
+                    }
 
+                    facep->setState(LLFace::RIGGED);
+                    facep->mSkinInfo = (LLMeshSkinInfo*) skinInfo; // TODO -- fix ugly de-consting here
+                    facep->mAvatar = avatar;
+                    any_rigged_face = true;
+                }
+                else
+                {
+                    if (facep->isState(LLFace::RIGGED))
+                    { 
+                        //face is not rigged but used to be, remove from rigged face pool
+                        LLDrawPoolAvatar* pool = (LLDrawPoolAvatar*)facep->getPool();
+                        if (pool)
+                        {
+                            pool->removeFace(facep);
+                        }
+                        facep->clearState(LLFace::RIGGED);
+                        facep->mAvatar = NULL;
+                        facep->mSkinInfo = NULL;
+                    }
+                }
 
 				if (cur_total > max_total || facep->getIndicesCount() <= 0 || facep->getGeomCount() <= 0)
 				{
@@ -5790,10 +5751,12 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 					continue;
 				}
 
-				cur_total += facep->getGeomCount();
-
-				if (facep->hasGeometry() && facep->getPixelArea() > FORCE_CULL_AREA)
+				if (facep->hasGeometry() &&
+                    (rigged ||  // <-- HACK FIXME -- getPixelArea might be incorrect for rigged objects
+                        facep->getPixelArea() > FORCE_CULL_AREA)) // <-- don't render tiny faces
 				{
+                    cur_total += facep->getGeomCount();
+
 					const LLTextureEntry* te = facep->getTextureEntry();
 					LLViewerTexture* tex = facep->getTexture();
 
@@ -5851,21 +5814,19 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 					{
 						if (facep->canRenderAsMask())
 						{ //can be treated as alpha mask
-							if (simple_count < MAX_FACE_COUNT)
-							{
-								sSimpleFaces[simple_count++] = facep;
-							}
+                            add_face(sSimpleFaces, simple_count, facep);
 						}
 						else
 						{
-							if (te->getColor().mV[3] > 0.f)
-							{ //only treat as alpha in the pipeline if < 100% transparent
-								drawablep->setState(LLDrawable::HAS_ALPHA);
-							}
-							if (alpha_count < MAX_FACE_COUNT)
-							{
-								sAlphaFaces[alpha_count++] = facep;
-							}
+                            if (te->getColor().mV[3] > 0.f || te->getGlow() > 0.f)
+                            { //only treat as alpha in the pipeline if < 100% transparent
+                                drawablep->setState(LLDrawable::HAS_ALPHA);
+                                add_face(sAlphaFaces, alpha_count, facep);
+                            }
+                            else if (LLDrawPoolAlpha::sShowDebugAlpha)
+                            {
+                                add_face(sAlphaFaces, alpha_count, facep);
+                            }
 						}
 					}
 					else
@@ -5885,81 +5846,51 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 								{
 									if (mat->getSpecularID().notNull())
 									{ //has normal and specular maps (needs texcoord1, texcoord2, and tangent)
-										if (normspec_count < MAX_FACE_COUNT)
-										{
-											sNormSpecFaces[normspec_count++] = facep;
-										}
+                                        add_face(sNormSpecFaces, normspec_count, facep);
 									}
 									else
 									{ //has normal map (needs texcoord1 and tangent)
-										if (norm_count < MAX_FACE_COUNT)
-										{
-											sNormFaces[norm_count++] = facep;
-										}
+                                        add_face(sNormFaces, norm_count, facep);
 									}
 								}
 								else if (mat->getSpecularID().notNull())
 								{ //has specular map but no normal map, needs texcoord2
-									if (spec_count < MAX_FACE_COUNT)
-									{
-										sSpecFaces[spec_count++] = facep;
-									}
+                                    add_face(sSpecFaces, spec_count, facep);
 								}
 								else
 								{ //has neither specular map nor normal map, only needs texcoord0
-									if (simple_count < MAX_FACE_COUNT)
-									{
-										sSimpleFaces[simple_count++] = facep;
-									}
+                                    add_face(sSimpleFaces, simple_count, facep);
 								}									
 							}
 							else if (te->getBumpmap())
 							{ //needs normal + tangent
-								if (bump_count < MAX_FACE_COUNT)
-								{
-									sBumpFaces[bump_count++] = facep;
-								}
+                                add_face(sBumpFaces, bump_count, facep);
 							}
 							else if (te->getShiny() || !te->getFullbright())
 							{ //needs normal
-								if (simple_count < MAX_FACE_COUNT)
-								{
-									sSimpleFaces[simple_count++] = facep;
-								}
+                                add_face(sSimpleFaces, simple_count, facep);
 							}
 							else 
 							{ //doesn't need normal
 								facep->setState(LLFace::FULLBRIGHT);
-								if (fullbright_count < MAX_FACE_COUNT)
-								{
-									sFullbrightFaces[fullbright_count++] = facep;
-								}
+                                add_face(sFullbrightFaces, fullbright_count, facep);
 							}
 						}
 						else
 						{
 							if (te->getBumpmap() && LLPipeline::sRenderBump)
 							{ //needs normal + tangent
-								if (bump_count < MAX_FACE_COUNT)
-								{
-									sBumpFaces[bump_count++] = facep;
-								}
+                                add_face(sBumpFaces, bump_count, facep);
 							}
 							else if ((te->getShiny() && LLPipeline::sRenderBump) ||
 								!(te->getFullbright() || bake_sunlight))
 							{ //needs normal
-								if (simple_count < MAX_FACE_COUNT)
-								{
-									sSimpleFaces[simple_count++] = facep;
-								}
+                                add_face(sSimpleFaces, simple_count, facep);
 							}
 							else 
 							{ //doesn't need normal
 								facep->setState(LLFace::FULLBRIGHT);
-								if (fullbright_count < MAX_FACE_COUNT)
-								{
-									sFullbrightFaces[fullbright_count++] = facep;
-								}
+                                add_face(sFullbrightFaces, fullbright_count, facep);
 							}
 						}
 					}
@@ -5975,6 +5906,11 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 				if (!drawablep->isState(LLDrawable::RIGGED))
 				{
 					drawablep->setState(LLDrawable::RIGGED);
+                    LLDrawable* root = drawablep->getRoot();
+                    if (root != drawablep)
+                    {
+                        root->setState(LLDrawable::RIGGED_CHILD);
+                    }
 
 					//first time this is drawable is being marked as rigged,
 					// do another LoD update to use avatar bounding box
@@ -5984,7 +5920,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 			else
 			{
 				drawablep->clearState(LLDrawable::RIGGED);
-                vobj->updateRiggedVolume();
+                vobj->updateRiggedVolume(false);
 			}
 		}
 	}
@@ -6014,6 +5950,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 
 	BOOL batch_textures = LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_OBJECT) > 1;
 
+    // add extra vertex data for deferred rendering (not necessarily for batching textures)
 	if (batch_textures)
 	{
 		bump_mask = bump_mask | LLVertexBuffer::MAP_TANGENT;
@@ -6026,13 +5963,24 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 
 	U32 geometryBytes = 0;
 
-	geometryBytes += genDrawInfo(group, simple_mask | LLVertexBuffer::MAP_TEXTURE_INDEX, sSimpleFaces, simple_count, FALSE, batch_textures, FALSE);
-	geometryBytes += genDrawInfo(group, fullbright_mask | LLVertexBuffer::MAP_TEXTURE_INDEX, sFullbrightFaces, fullbright_count, FALSE, batch_textures);
-	geometryBytes += genDrawInfo(group, alpha_mask | LLVertexBuffer::MAP_TEXTURE_INDEX, sAlphaFaces, alpha_count, TRUE, batch_textures);
-	geometryBytes += genDrawInfo(group, bump_mask | LLVertexBuffer::MAP_TEXTURE_INDEX, sBumpFaces, bump_count, FALSE, FALSE);
-	geometryBytes += genDrawInfo(group, norm_mask | LLVertexBuffer::MAP_TEXTURE_INDEX, sNormFaces, norm_count, FALSE, FALSE);
-	geometryBytes += genDrawInfo(group, spec_mask | LLVertexBuffer::MAP_TEXTURE_INDEX, sSpecFaces, spec_count, FALSE, FALSE);
-	geometryBytes += genDrawInfo(group, normspec_mask | LLVertexBuffer::MAP_TEXTURE_INDEX, sNormSpecFaces, normspec_count, FALSE, FALSE);
+    // generate render batches for static geometry
+    U32 extra_mask = LLVertexBuffer::MAP_TEXTURE_INDEX;
+    BOOL alpha_sort = TRUE;
+    BOOL rigged = FALSE;
+    for (int i = 0; i < 2; ++i) //two sets, static and rigged)
+    {
+        geometryBytes += genDrawInfo(group, simple_mask | extra_mask, sSimpleFaces[i], simple_count[i], FALSE, batch_textures, rigged);
+        geometryBytes += genDrawInfo(group, fullbright_mask | extra_mask, sFullbrightFaces[i], fullbright_count[i], FALSE, batch_textures, rigged);
+        geometryBytes += genDrawInfo(group, alpha_mask | extra_mask, sAlphaFaces[i], alpha_count[i], alpha_sort, batch_textures, rigged);
+        geometryBytes += genDrawInfo(group, bump_mask | extra_mask, sBumpFaces[i], bump_count[i], FALSE, FALSE, rigged);
+        geometryBytes += genDrawInfo(group, norm_mask | extra_mask, sNormFaces[i], norm_count[i], FALSE, FALSE, rigged);
+        geometryBytes += genDrawInfo(group, spec_mask | extra_mask, sSpecFaces[i], spec_count[i], FALSE, FALSE, rigged);
+        geometryBytes += genDrawInfo(group, normspec_mask | extra_mask, sNormSpecFaces[i], normspec_count[i], FALSE, FALSE, rigged);
+
+        // for rigged set, add weights and disable alpha sorting (rigged items use depth buffer)
+        extra_mask |= LLVertexBuffer::MAP_WEIGHT4;
+        rigged = TRUE;
+    }
 
 	group->mGeometryBytes = geometryBytes;
 
@@ -6058,156 +6006,144 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 		group->setState(LLSpatialGroup::MESH_DIRTY | LLSpatialGroup::NEW_DRAWINFO);
 	}
 
-	mFaceList.clear();
 }
 
-static LLTrace::BlockTimerStatHandle FTM_REBUILD_MESH_FLUSH("Flush Mesh");
-
 void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME;
 	llassert(group);
 	if (group && group->hasState(LLSpatialGroup::MESH_DIRTY) && !group->hasState(LLSpatialGroup::GEOM_DIRTY))
 	{
-		LL_RECORD_BLOCK_TIME(FTM_REBUILD_VOLUME_VB);
-		LL_RECORD_BLOCK_TIME(FTM_REBUILD_VOLUME_GEN_DRAW_INFO); //make sure getgeometryvolume shows up in the right place in timers
+		{
+            LL_PROFILE_ZONE_NAMED("rebuildMesh - gen draw info");
 
-		group->mBuilt = 1.f;
+            group->mBuilt = 1.f;
 		
-		S32 num_mapped_vertex_buffer = LLVertexBuffer::sMappedCount ;
+			S32 num_mapped_vertex_buffer = LLVertexBuffer::sMappedCount ;
 
-		const U32 MAX_BUFFER_COUNT = 4096;
-		LLVertexBuffer* locked_buffer[MAX_BUFFER_COUNT];
-		
-		U32 buffer_count = 0;
+			const U32 MAX_BUFFER_COUNT = 4096;
+			LLVertexBuffer* locked_buffer[MAX_BUFFER_COUNT];
 
-		for (LLSpatialGroup::element_iter drawable_iter = group->getDataBegin(); drawable_iter != group->getDataEnd(); ++drawable_iter)
-		{
-			LLDrawable* drawablep = (LLDrawable*)(*drawable_iter)->getDrawable();
+			U32 buffer_count = 0;
 
-			if (drawablep && !drawablep->isDead() && drawablep->isState(LLDrawable::REBUILD_ALL) && !drawablep->isState(LLDrawable::RIGGED) )
+			for (LLSpatialGroup::element_iter drawable_iter = group->getDataBegin(); drawable_iter != group->getDataEnd(); ++drawable_iter)
 			{
-				LLVOVolume* vobj = drawablep->getVOVolume();
-                if (debugLoggingEnabled("AnimatedObjectsLinkset"))
-                {
-                    if (vobj && vobj->isAnimatedObject() && vobj->isRiggedMesh())
-                    {
-                        std::string vobj_name = llformat("Vol%p", vobj);
-                        F32 est_tris = vobj->getEstTrianglesMax();
-                        LL_DEBUGS("AnimatedObjectsLinkset") << vobj_name << " rebuildMesh, tris " << est_tris << LL_ENDL;
-                    }
-                }
-
-                if (!vobj || vobj->isNoLOD())
-                {
-                    continue;
-                }
-
-                LLVolume* volume = vobj->getVolume();
-
-                if (!volume)
-                {
-                    continue;
-                }
-
-				vobj->preRebuild();
-
-				if (drawablep->isState(LLDrawable::ANIMATED_CHILD))
-				{
-					vobj->updateRelativeXform(true);
-				}
+				LLDrawable* drawablep = (LLDrawable*)(*drawable_iter)->getDrawable();
 
-				for (S32 i = 0; i < drawablep->getNumFaces(); ++i)
+				if (drawablep && !drawablep->isDead() && drawablep->isState(LLDrawable::REBUILD_ALL))
 				{
-					LLFace* face = drawablep->getFace(i);
-					if (face)
+					LLVOVolume* vobj = drawablep->getVOVolume();
+					
+					if (!vobj) continue;
+					
+					if (debugLoggingEnabled("AnimatedObjectsLinkset"))
 					{
-						LLVertexBuffer* buff = face->getVertexBuffer();
-						if (buff)
+						if (vobj->isAnimatedObject() && vobj->isRiggedMesh())
 						{
-							llassert(!face->isState(LLFace::RIGGED));
+							std::string vobj_name = llformat("Vol%p", vobj);
+							F32 est_tris = vobj->getEstTrianglesMax();
+							LL_DEBUGS("AnimatedObjectsLinkset") << vobj_name << " rebuildMesh, tris " << est_tris << LL_ENDL;
+						}
+					}
+					if (vobj->isNoLOD()) continue;
 
-							if (!face->getGeometryVolume(*volume, face->getTEOffset(), 
-								vobj->getRelativeXform(), vobj->getRelativeXformInvTrans(), face->getGeomIndex()))
-							{ //something's gone wrong with the vertex buffer accounting, rebuild this group 
-								group->dirtyGeom();
-								gPipeline.markRebuild(group, TRUE);
-							}
+					vobj->preRebuild();
 
+					if (drawablep->isState(LLDrawable::ANIMATED_CHILD))
+					{
+						vobj->updateRelativeXform(true);
+					}
 
-							if (buff->isLocked() && buffer_count < MAX_BUFFER_COUNT)
+					LLVolume* volume = vobj->getVolume();
+					if (!volume) continue;
+					for (S32 i = 0; i < drawablep->getNumFaces(); ++i)
+					{
+						LLFace* face = drawablep->getFace(i);
+						if (face)
+						{
+							LLVertexBuffer* buff = face->getVertexBuffer();
+							if (buff)
 							{
-								locked_buffer[buffer_count++] = buff;
+								if (!face->getGeometryVolume(*volume, face->getTEOffset(), 
+									vobj->getRelativeXform(), vobj->getRelativeXformInvTrans(), face->getGeomIndex()))
+								{ //something's gone wrong with the vertex buffer accounting, rebuild this group 
+									group->dirtyGeom();
+									gPipeline.markRebuild(group, TRUE);
+								}
+
+
+								if (buff->isLocked() && buffer_count < MAX_BUFFER_COUNT)
+								{
+									locked_buffer[buffer_count++] = buff;
+								}
 							}
 						}
 					}
+
+					if (drawablep->isState(LLDrawable::ANIMATED_CHILD))
+					{
+						vobj->updateRelativeXform();
+					}
+
+					drawablep->clearState(LLDrawable::REBUILD_ALL);
 				}
+			}
 
-				if (drawablep->isState(LLDrawable::ANIMATED_CHILD))
+			{
+                LL_PROFILE_ZONE_NAMED("rebuildMesh - flush");
+				for (LLVertexBuffer** iter = locked_buffer, ** end_iter = locked_buffer+buffer_count; iter != end_iter; ++iter)
 				{
-					vobj->updateRelativeXform();
+					(*iter)->flush();
 				}
 
-				
-				drawablep->clearState(LLDrawable::REBUILD_ALL);
+				// don't forget alpha
+				if(group != NULL &&
+				   !group->mVertexBuffer.isNull() &&
+				   group->mVertexBuffer->isLocked())
+				{
+					group->mVertexBuffer->flush();
+				}
 			}
-		}
-		
-		{
-			LL_RECORD_BLOCK_TIME(FTM_REBUILD_MESH_FLUSH);
-			for (LLVertexBuffer** iter = locked_buffer, ** end_iter = locked_buffer+buffer_count; iter != end_iter; ++iter)
-		{
-			(*iter)->flush();
-		}
 
-		// don't forget alpha
-		if(group != NULL && 
-		   !group->mVertexBuffer.isNull() && 
-		   group->mVertexBuffer->isLocked())
-		{
-			group->mVertexBuffer->flush();
-		}
-		}
-
-		//if not all buffers are unmapped
-		if(num_mapped_vertex_buffer != LLVertexBuffer::sMappedCount) 
-		{
-			LL_WARNS() << "Not all mapped vertex buffers are unmapped!" << LL_ENDL ; 
-			for (LLSpatialGroup::element_iter drawable_iter = group->getDataBegin(); drawable_iter != group->getDataEnd(); ++drawable_iter)
+			//if not all buffers are unmapped
+			if(num_mapped_vertex_buffer != LLVertexBuffer::sMappedCount)
 			{
-				LLDrawable* drawablep = (LLDrawable*)(*drawable_iter)->getDrawable();
-				if(!drawablep)
+				LL_WARNS() << "Not all mapped vertex buffers are unmapped!" << LL_ENDL ;
+				for (LLSpatialGroup::element_iter drawable_iter = group->getDataBegin(); drawable_iter != group->getDataEnd(); ++drawable_iter)
 				{
-					continue;
-				}
-				for (S32 i = 0; i < drawablep->getNumFaces(); ++i)
-				{
-					LLFace* face = drawablep->getFace(i);
-					if (face)
+					LLDrawable* drawablep = (LLDrawable*)(*drawable_iter)->getDrawable();
+					if(!drawablep)
 					{
-						LLVertexBuffer* buff = face->getVertexBuffer();
-						if (buff && buff->isLocked())
+						continue;
+					}
+					for (S32 i = 0; i < drawablep->getNumFaces(); ++i)
+					{
+						LLFace* face = drawablep->getFace(i);
+						if (face)
 						{
-							buff->flush();
+							LLVertexBuffer* buff = face->getVertexBuffer();
+							if (buff && buff->isLocked())
+							{
+								buff->flush();
+							}
 						}
 					}
 				}
-			} 
-		}
-
-		group->clearState(LLSpatialGroup::MESH_DIRTY | LLSpatialGroup::NEW_DRAWINFO);
-	}
+			}
 
-//	llassert(!group || !group->isState(LLSpatialGroup::NEW_DRAWINFO));
+			group->clearState(LLSpatialGroup::MESH_DIRTY | LLSpatialGroup::NEW_DRAWINFO);
+		}
+	} 
 }
 
-struct CompareBatchBreakerModified
+struct CompareBatchBreaker
 {
 	bool operator()(const LLFace* const& lhs, const LLFace* const& rhs)
 	{
 		const LLTextureEntry* lte = lhs->getTextureEntry();
 		const LLTextureEntry* rte = rhs->getTextureEntry();
 
-		if (lte->getBumpmap() != rte->getBumpmap())
+        if (lte->getBumpmap() != rte->getBumpmap())
 		{
 			return lte->getBumpmap() < rte->getBumpmap();
 		}
@@ -6215,34 +6151,50 @@ struct CompareBatchBreakerModified
 		{
 			return lte->getFullbright() < rte->getFullbright();
 		}
-		else if (LLPipeline::sRenderDeferred && lte->getMaterialParams() != rte->getMaterialParams())
-		{
-			return lte->getMaterialParams() < rte->getMaterialParams();
-		}
-		else if (LLPipeline::sRenderDeferred && (lte->getMaterialParams() == rte->getMaterialParams()) && (lte->getShiny() != rte->getShiny()))
+        else if (LLPipeline::sRenderDeferred && lte->getMaterialID() != rte->getMaterialID())
+        {
+            return lte->getMaterialID() < rte->getMaterialID();
+        }
+		else if (lte->getShiny() != rte->getShiny())
 		{
 			return lte->getShiny() < rte->getShiny();
 		}
-		else
+        else if (lhs->getTexture() != rhs->getTexture())
 		{
 			return lhs->getTexture() < rhs->getTexture();
 		}
+        else 
+        {
+            // all else being equal, maintain consistent draw order
+            return lhs->getDrawOrderIndex() < rhs->getDrawOrderIndex();
+        }
 	}
 };
 
-static LLTrace::BlockTimerStatHandle FTM_GEN_DRAW_INFO_SORT("Draw Info Face Sort");
-static LLTrace::BlockTimerStatHandle FTM_GEN_DRAW_INFO_FACE_SIZE("Face Sizing");
-static LLTrace::BlockTimerStatHandle FTM_GEN_DRAW_INFO_ALLOCATE("Allocate VB");
-static LLTrace::BlockTimerStatHandle FTM_GEN_DRAW_INFO_FIND_VB("Find VB");
-static LLTrace::BlockTimerStatHandle FTM_GEN_DRAW_INFO_RESIZE_VB("Resize VB");
-
-
-
-
+struct CompareBatchBreakerRigged
+{
+    bool operator()(const LLFace* const& lhs, const LLFace* const& rhs)
+    {
+        if (lhs->mAvatar != rhs->mAvatar)
+        {
+            return lhs->mAvatar < rhs->mAvatar;
+        }
+        else if (lhs->mSkinInfo->mHash != rhs->mSkinInfo->mHash)
+        {
+            return lhs->mSkinInfo->mHash < rhs->mSkinInfo->mHash;
+        }
+        else
+        {
+            // "inherit" non-rigged behavior
+            CompareBatchBreaker comp;
+            return comp(lhs, rhs);
+        }
+    }
+};
 
-U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace** faces, U32 face_count, BOOL distance_sort, BOOL batch_textures, BOOL no_materials)
+U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace** faces, U32 face_count, BOOL distance_sort, BOOL batch_textures, BOOL rigged)
 {
-	LL_RECORD_BLOCK_TIME(FTM_REBUILD_VOLUME_GEN_DRAW_INFO);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME;
 
 	U32 geometryBytes = 0;
 	U32 buffer_usage = group->mBufferUsage;
@@ -6274,12 +6226,21 @@ U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace
 	max_vertices = llmin(max_vertices, (U32) 65535);
 
 	{
-		LL_RECORD_BLOCK_TIME(FTM_GEN_DRAW_INFO_SORT);
-		if (!distance_sort)
-		{
-			//sort faces by things that break batches
-			std::sort(faces, faces+face_count, CompareBatchBreakerModified());
-		}
+        LL_PROFILE_ZONE_NAMED("genDrawInfo - sort");
+        
+        if (rigged)
+        {
+            if (!distance_sort) // <--- alpha "sort" rigged faces by maintaining original draw order
+            {
+                //sort faces by things that break batches, including avatar and mesh id
+                std::sort(faces, faces + face_count, CompareBatchBreakerRigged());
+            }
+        }
+        else if (!distance_sort)
+        {
+            //sort faces by things that break batches, not including avatar and mesh id
+            std::sort(faces, faces + face_count, CompareBatchBreaker());
+        }
 		else
 		{
 			//sort faces by distance
@@ -6296,11 +6257,6 @@ U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace
 	LLViewerTexture* last_tex = NULL;
 	S32 buffer_index = 0;
 
-	if (distance_sort)
-	{
-		buffer_index = -1;
-	}
-
 	S32 texture_index_channels = 1;
 	
 	if (gGLManager.mGLSLVersionMajor > 1 || gGLManager.mGLSLVersionMinor >= 30)
@@ -6312,6 +6268,11 @@ U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace
 	{
 		texture_index_channels = gDeferredAlphaProgram.mFeatures.mIndexedTextureChannels;
 	}
+    
+    if (distance_sort)
+    {
+        buffer_index = -1;
+    }
 
 	static LLCachedControl<U32> max_texture_index(gSavedSettings, "RenderMaxTextureIndex", 16);
 	texture_index_channels = llmin(texture_index_channels, (S32) max_texture_index);
@@ -6326,7 +6287,9 @@ U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace
 		//pull off next face
 		LLFace* facep = *face_iter;
 		LLViewerTexture* tex = facep->getTexture();
-		LLMaterialPtr mat = facep->getTextureEntry()->getMaterialParams();
+        const LLTextureEntry* te = facep->getTextureEntry();
+		LLMaterialPtr mat = te->getMaterialParams();
+        LLMaterialID matId = te->getMaterialID();
 
 		if (distance_sort)
 		{
@@ -6360,7 +6323,7 @@ U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace
 		U32 texture_count = 0;
 
 		{
-			LL_RECORD_BLOCK_TIME(FTM_GEN_DRAW_INFO_FACE_SIZE);
+            LL_PROFILE_ZONE_NAMED("genDrawInfo - face size");
 			if (batch_textures)
 			{
 				U8 cur_tex = 0;
@@ -6449,11 +6412,14 @@ U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace
 				while (i != end_faces && 
 					(LLPipeline::sTextureBindTest || 
 						(distance_sort || 
-							((*i)->getTexture() == tex &&
-							((*i)->getTextureEntry()->getMaterialParams() == mat)))))
+							((*i)->getTexture() == tex))))
 				{
 					facep = *i;
-			
+                    const LLTextureEntry* nextTe = facep->getTextureEntry();
+                    if (nextTe->getMaterialID() != matId)
+                    {
+                        break;
+                    }
 
 					//face has no texture index
 					facep->mDrawInfo = NULL;
@@ -6483,7 +6449,7 @@ U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace
 		LLPointer<LLVertexBuffer> buffer;
 
 		{
-			LL_RECORD_BLOCK_TIME(FTM_GEN_DRAW_INFO_ALLOCATE);
+            LL_PROFILE_ZONE_NAMED("genDrawInfo - allocate");
 			buffer = createVertexBuffer(mask, buffer_usage);
 			if(!buffer->allocateBuffer(geom_count, index_count, TRUE))
 			{
@@ -6543,8 +6509,6 @@ U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace
 
 					U32 te_idx = facep->getTEOffset();
 
-					llassert(!facep->isState(LLFace::RIGGED));
-
 					if (!facep->getGeometryVolume(*volume, te_idx, 
 						vobj->getRelativeXform(), vobj->getRelativeXformInvTrans(), index_offset,true))
 					{
@@ -6641,10 +6605,6 @@ U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace
 						}
 					}
 				}
-				else if (no_materials)
-				{
-					registerFace(group, facep, LLRenderPass::PASS_SIMPLE);
-				}
 				else if (transparent)
 				{
 					registerFace(group, facep, LLRenderPass::PASS_ALPHA);
@@ -6709,7 +6669,7 @@ U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace
 				{
 					registerFace(group, facep, LLRenderPass::PASS_ALPHA);
 				}
-				else if (gPipeline.canUseVertexShaders()
+				else if (gPipeline.shadersLoaded()
 					&& LLPipeline::sRenderBump 
 					&& te->getShiny() 
 					&& can_be_shiny)
@@ -6744,7 +6704,7 @@ U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace
 					registerFace(group, facep, LLRenderPass::PASS_ALPHA);
 				}
 			}
-			else if (gPipeline.canUseVertexShaders()
+			else if (gPipeline.shadersLoaded()
 				&& LLPipeline::sRenderBump 
 				&& te->getShiny() 
 				&& can_be_shiny)
@@ -6825,7 +6785,7 @@ U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace
 				}
 				
 				
-				if (!gPipeline.canUseVertexShaders() && 
+				if (!gPipeline.shadersLoaded() && 
 					!is_alpha && 
 					te->getShiny() && 
 					LLPipeline::sRenderBump)
@@ -6869,16 +6829,41 @@ U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace
 	return geometryBytes;
 }
 
+void LLVolumeGeometryManager::addGeometryCount(LLSpatialGroup* group, U32& vertex_count, U32& index_count)
+{
+    //initialize to default usage for this partition
+    U32 usage = group->getSpatialPartition()->mBufferUsage;
+
+    //for each drawable
+    for (LLSpatialGroup::element_iter drawable_iter = group->getDataBegin(); drawable_iter != group->getDataEnd(); ++drawable_iter)
+    {
+        LLDrawable* drawablep = (LLDrawable*)(*drawable_iter)->getDrawable();
+
+        if (!drawablep || drawablep->isDead())
+        {
+            continue;
+        }
+
+        if (drawablep->isAnimating())
+        { //fall back to stream draw for animating verts
+            usage = GL_STREAM_DRAW_ARB;
+        }
+    }
+
+    group->mBufferUsage = usage;
+}
+
 void LLGeometryManager::addGeometryCount(LLSpatialGroup* group, U32 &vertex_count, U32 &index_count)
 {	
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME;
+
 	//initialize to default usage for this partition
 	U32 usage = group->getSpatialPartition()->mBufferUsage;
 	
-	//clear off any old faces
-	mFaceList.clear();
+    //clear off any old faces
+    mFaceList.clear();
 
 	//for each drawable
-
 	for (LLSpatialGroup::element_iter drawable_iter = group->getDataBegin(); drawable_iter != group->getDataEnd(); ++drawable_iter)
 	{
 		LLDrawable* drawablep = (LLDrawable*)(*drawable_iter)->getDrawable();
diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h
index 73eeec813cb81d50155b5185ace431a1274de181..01ad40274b8e2b35840a3dabed83edb43bcfdbb5 100644
--- a/indra/newview/llvovolume.h
+++ b/indra/newview/llvovolume.h
@@ -65,7 +65,10 @@ class LLRiggedVolume : public LLVolume
 	{
 	}
 
-	void update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, const LLVolume* src_volume);
+    using FaceIndex = S32;
+    static const FaceIndex UPDATE_ALL_FACES = -1;
+    static const FaceIndex DO_NOT_UPDATE_FACES = -2;
+    void update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, const LLVolume* src_volume, FaceIndex face_index = UPDATE_ALL_FACES, bool rebuild_face_octrees = true);
 
     std::string mExtraDebugText;
 };
@@ -232,7 +235,7 @@ class LLVOVolume : public LLViewerObject
 
 				void	updateFaceFlags();
 				void	regenFaces();
-				BOOL	genBBoxes(BOOL force_global);
+                BOOL    genBBoxes(BOOL force_global, BOOL should_update_octree_bounds = TRUE);
 				void	preRebuild();
 	virtual		void	updateSpatialExtents(LLVector4a& min, LLVector4a& max);
 	virtual		F32		getBinRadius();
@@ -295,6 +298,9 @@ class LLVOVolume : public LLViewerObject
 	BOOL setIsFlexible(BOOL is_flexible);
 
     const LLMeshSkinInfo* getSkinInfo() const;
+
+    //convenience accessor for mesh ID (which is stored in sculpt id for legacy reasons)
+    const LLUUID& getMeshID() const { return getVolume()->getParams().getSculptID(); }
     
     // Extended Mesh Properties
     U32 getExtendedMeshFlags() const;
@@ -359,8 +365,9 @@ class LLVOVolume : public LLViewerObject
 	S32 getMDCImplCount() { return mMDCImplCount; }
 	
 
-	//rigged volume update (for raycasting)
-	void updateRiggedVolume(bool force_update = false);
+    // Rigged volume update (for raycasting)
+    // By default, this updates the bounding boxes of all the faces and builds an octree for precise per-triangle raycasting
+    void updateRiggedVolume(bool force_treat_as_rigged, LLRiggedVolume::FaceIndex face_index = LLRiggedVolume::UPDATE_ALL_FACES, bool rebuild_face_octrees = true);
 	LLRiggedVolume* getRiggedVolume();
 
 	//returns true if volume should be treated as a rigged volume
@@ -383,13 +390,14 @@ class LLVOVolume : public LLViewerObject
 	static S32 mRenderComplexity_last;
 	static S32 mRenderComplexity_current;
 
+    void onDrawableUpdateFromServer();
 	void requestMediaDataUpdate(bool isNew);
 	void cleanUpMediaImpls();
 	void addMediaImpl(LLViewerMediaImpl* media_impl, S32 texture_index) ;
 	void removeMediaImpl(S32 texture_index) ;
 
 private:
-	bool lodOrSculptChanged(LLDrawable *drawable, BOOL &compiled);
+    bool lodOrSculptChanged(LLDrawable *drawable, BOOL &compiled, BOOL &shouldUpdateOctreeBounds);
 
 public:
 
@@ -410,6 +418,7 @@ class LLVOVolume : public LLViewerObject
 	S32			mLOD;
 	BOOL		mLODChanged;
 	BOOL		mSculptChanged;
+    BOOL		mColorChanged;
 	F32			mSpotLightPriority;
 	LLMatrix4	mRelativeXform;
 	LLMatrix3	mRelativeXformInvTrans;
@@ -420,6 +429,7 @@ class LLVOVolume : public LLViewerObject
 	LLPointer<LLViewerFetchedTexture> mLightTexture;
 	media_list_t mMediaImplList;
 	S32			mLastFetchedMediaVersion; // as fetched from the server, starts as -1
+    U32         mServerDrawableUpdateCount;
 	S32 mIndexInTex[LLRender::NUM_VOLUME_TEXTURE_CHANNELS];
 	S32 mMDCImplCount;
 
diff --git a/indra/newview/llvowater.cpp b/indra/newview/llvowater.cpp
index 12def24a0dd47a8685d26bab957039ff464e5aaf..089a7712c03148d6007e2243e8144c7742a4b1a5 100644
--- a/indra/newview/llvowater.cpp
+++ b/indra/newview/llvowater.cpp
@@ -114,11 +114,9 @@ LLDrawable *LLVOWater::createDrawable(LLPipeline *pipeline)
 	return mDrawable;
 }
 
-static LLTrace::BlockTimerStatHandle FTM_UPDATE_WATER("Update Water");
-
 BOOL LLVOWater::updateGeometry(LLDrawable *drawable)
 {
-	LL_RECORD_BLOCK_TIME(FTM_UPDATE_WATER);
+    LL_PROFILE_ZONE_SCOPED;
 	LLFace *face;
 
 	if (drawable->getNumFaces() < 1)
@@ -145,7 +143,7 @@ BOOL LLVOWater::updateGeometry(LLDrawable *drawable)
 	static const unsigned int vertices_per_quad = 4;
 	static const unsigned int indices_per_quad = 6;
 
-	const S32 size = LLPipeline::sRenderTransparentWater && LLGLSLShader::sNoFixedFunction ? 16 : 1;
+	const S32 size = LLPipeline::sRenderTransparentWater ? 16 : 1;
 
 	const S32 num_quads = size * size;
 	face->setSize(vertices_per_quad * num_quads,
diff --git a/indra/newview/llvowlsky.cpp b/indra/newview/llvowlsky.cpp
index d428cb15682779e6369abe6a167c1eccf483a4bb..d1f584cbca23adcfdbc2028c26e5c5aa54f5ff65 100644
--- a/indra/newview/llvowlsky.cpp
+++ b/indra/newview/llvowlsky.cpp
@@ -36,8 +36,8 @@
 #include "llenvironment.h"
 #include "llsettingssky.h"
 
-static const U32 MIN_SKY_DETAIL = 8;
-static const U32 MAX_SKY_DETAIL = 180;
+constexpr U32 MIN_SKY_DETAIL = 8;
+constexpr U32 MAX_SKY_DETAIL = 180;
 
 inline U32 LLVOWLSky::getNumStacks(void)
 {
@@ -97,13 +97,14 @@ LLDrawable * LLVOWLSky::createDrawable(LLPipeline * pipeline)
 	return mDrawable;
 }
 
-inline F32 LLVOWLSky::calcPhi(U32 i)
+// a tiny helper function for controlling the sky dome tesselation.
+inline F32 calcPhi(const U32 &i, const F32 &reciprocal_num_stacks)
 {
     // Calc: PI/8 * 1-((1-t^4)*(1-t^4))  { 0<t<1 }
     // Demos: \pi/8*\left(1-((1-x^{4})*(1-x^{4}))\right)\ \left\{0<x\le1\right\}
 
 	// i should range from [0..SKY_STACKS] so t will range from [0.f .. 1.f]
-	F32 t = float(i) / float(getNumStacks());
+	F32 t = float(i) * reciprocal_num_stacks; //SL-16127: remove: / float(getNumStacks());
 
 	// ^4 the parameter of the tesselation to bias things toward 0 (the dome's apex)
 	t *= t;
@@ -141,11 +142,9 @@ void LLVOWLSky::restoreGL()
 	gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_ALL, TRUE);
 }
 
-static LLTrace::BlockTimerStatHandle FTM_GEO_SKY("Windlight Sky Geometry");
-
 BOOL LLVOWLSky::updateGeometry(LLDrawable * drawable)
 {
-    LL_RECORD_BLOCK_TIME(FTM_GEO_SKY);
+    LL_PROFILE_ZONE_SCOPED;
 	LLStrider<LLVector3>	vertices;
 	LLStrider<LLVector2>	texCoords;
 	LLStrider<U16>			indices;
@@ -189,6 +188,8 @@ BOOL LLVOWLSky::updateGeometry(LLDrawable * drawable)
     }
 
 	{
+        const F32 dome_radius = LLEnvironment::instance().getCurrentSky()->getDomeRadius();
+
 		const U32 max_buffer_bytes = gSavedSettings.getS32("RenderMaxVBOSize")*1024;
 		const U32 data_mask = LLDrawPoolWLSky::SKY_VERTEX_DATA_MASK;
 		const U32 max_verts = max_buffer_bytes / LLVertexBuffer::calcVertexSize(data_mask);
@@ -204,12 +205,14 @@ BOOL LLVOWLSky::updateGeometry(LLDrawable * drawable)
 		// round up to a whole number of segments
 		const U32 strips_segments = (total_stacks+stacks_per_seg-1) / stacks_per_seg;
 
-		LL_INFOS() << "WL Skydome strips in " << strips_segments << " batches." << LL_ENDL;
-
 		mStripsVerts.resize(strips_segments, NULL);
 
+#if RELEASE_SHOW_DEBUG
+		LL_INFOS() << "WL Skydome strips in " << strips_segments << " batches." << LL_ENDL;
+
 		LLTimer timer;
 		timer.start();
+#endif
 
 		for (U32 i = 0; i < strips_segments ;++i)
 		{
@@ -234,34 +237,42 @@ BOOL LLVOWLSky::updateGeometry(LLDrawable * drawable)
 			const U32 num_indices_this_seg = 1+num_stacks_this_seg*(2+2*verts_per_stack);
 			llassert(num_indices_this_seg * sizeof(U16) <= max_buffer_bytes);
 
-			if (!segment->allocateBuffer(num_verts_this_seg, num_indices_this_seg, TRUE))
+			bool allocated = segment->allocateBuffer(num_verts_this_seg, num_indices_this_seg, TRUE);
+#if RELEASE_SHOW_WARNS
+			if( !allocated )
 			{
 				LL_WARNS() << "Failed to allocate Vertex Buffer on update to "
 					<< num_verts_this_seg << " vertices and "
 					<< num_indices_this_seg << " indices" << LL_ENDL;
 			}
+#else
+			(void) allocated;
+#endif
 
 			// lock the buffer
 			BOOL success = segment->getVertexStrider(vertices)
 				&& segment->getTexCoord0Strider(texCoords)
 				&& segment->getIndexStrider(indices);
 
-			if(!success) 
+#if RELEASE_SHOW_DEBUG
+			if(!success)
 			{
 				LL_ERRS() << "Failed updating WindLight sky geometry." << LL_ENDL;
 			}
-
-            U32 vertex_count = 0;
-            U32 index_count  = 0;
+#else
+			(void) success;
+#endif
 
 			// fill it
-			buildStripsBuffer(begin_stack, end_stack, vertex_count, index_count, vertices, texCoords, indices);
+			buildStripsBuffer(begin_stack, end_stack, vertices, texCoords, indices, dome_radius, verts_per_stack, total_stacks);
 
 			// and unlock the buffer
 			segment->flush();
 		}
 	
+#if RELEASE_SHOW_DEBUG
 		LL_INFOS() << "completed in " << llformat("%.2f", timer.getElapsedTimeF32().value()) << "seconds" << LL_ENDL;
+#endif
 	}
 
 	updateStarColors();
@@ -366,23 +377,16 @@ void LLVOWLSky::initStars()
 
 void LLVOWLSky::buildStripsBuffer(U32 begin_stack,
                                   U32 end_stack,
-                                  U32& vertex_count,
-                                  U32& index_count,
-								  LLStrider<LLVector3> & vertices,
-								  LLStrider<LLVector2> & texCoords,
-								  LLStrider<U16> & indices)
+                                  LLStrider<LLVector3> & vertices,
+                                  LLStrider<LLVector2> & texCoords,
+                                  LLStrider<U16> & indices,
+                                  const F32 dome_radius,
+                                  const U32& num_slices,
+                                  const U32& num_stacks)
 {
-    const F32 RADIUS = LLEnvironment::instance().getCurrentSky()->getDomeRadius();
-
-	U32 i, j, num_slices, num_stacks;
+	U32 i, j;
 	F32 phi0, theta, x0, y0, z0;
-
-	// paranoia checking for SL-55986/SL-55833
-	U32 count_verts = 0;
-	U32 count_indices = 0;
-
-	num_slices = getNumSlices();
-	num_stacks = getNumStacks();
+	const F32 reciprocal_num_stacks = 1.f / num_stacks;
 
 	llassert(end_stack <= num_stacks);
 
@@ -393,7 +397,7 @@ void LLVOWLSky::buildStripsBuffer(U32 begin_stack,
     for(i = begin_stack + 1; i <= end_stack+1; ++i) 
 #endif
 	{
-		phi0 = calcPhi(i);
+		phi0 = calcPhi(i, reciprocal_num_stacks);
 
 		for(j = 0; j < num_slices; ++j)
 		{
@@ -406,24 +410,22 @@ void LLVOWLSky::buildStripsBuffer(U32 begin_stack,
 			z0 = sin(phi0) * sin(theta);
 
 #if NEW_TESS
-            *vertices++ = LLVector3(x0 * RADIUS, y0 * RADIUS, z0 * RADIUS);
+            *vertices++ = LLVector3(x0 * dome_radius, y0 * dome_radius, z0 * dome_radius);
 #else
             if (i == num_stacks-2)
 			{
-				*vertices++ = LLVector3(x0*RADIUS, y0*RADIUS-1024.f*2.f, z0*RADIUS);
+				*vertices++ = LLVector3(x0*dome_radius, y0*dome_radius-1024.f*2.f, z0*dome_radius);
 			}
 			else if (i == num_stacks-1)
 			{
-				*vertices++ = LLVector3(0, y0*RADIUS-1024.f*2.f, 0);
+				*vertices++ = LLVector3(0, y0*dome_radius-1024.f*2.f, 0);
 			}
 			else
 			{
-				*vertices++		= LLVector3(x0 * RADIUS, y0 * RADIUS, z0 * RADIUS);
+				*vertices++		= LLVector3(x0 * dome_radius, y0 * dome_radius, z0 * dome_radius);
 			}
 #endif
 
-			++count_verts;
-
 			// generate planar uv coordinates
 			// note: x and z are transposed in order for things to animate
 			// correctly in the global coordinate system where +x is east and
@@ -434,12 +436,11 @@ void LLVOWLSky::buildStripsBuffer(U32 begin_stack,
 
 	//build triangle strip...
 	*indices++ = 0 ;
-	count_indices++ ;
+
 	S32 k = 0 ;
 	for(i = 1; i <= end_stack - begin_stack; ++i) 
 	{
 		*indices++ = i * num_slices + k ;
-		count_indices++ ;
 
 		k = (k+1) % num_slices ;
 		for(j = 0; j < num_slices ; ++j) 
@@ -447,8 +448,6 @@ void LLVOWLSky::buildStripsBuffer(U32 begin_stack,
 			*indices++ = (i-1) * num_slices + k ;
 			*indices++ = i * num_slices + k ;
 
-			count_indices += 2 ;
-
 			k = (k+1) % num_slices ;
 		}
 
@@ -458,11 +457,7 @@ void LLVOWLSky::buildStripsBuffer(U32 begin_stack,
 		}
 
 		*indices++ = i * num_slices + k ;
-		count_indices++ ;
 	}
-
-    vertex_count = count_verts;
-    index_count = count_indices;
 }
 
 void LLVOWLSky::updateStarColors()
diff --git a/indra/newview/llvowlsky.h b/indra/newview/llvowlsky.h
index 2b7ebe75dd7ef05fcb957d67cd895098db359bc6..3853dd2c7084d46ecf024adf87641bb8cb91305f 100644
--- a/indra/newview/llvowlsky.h
+++ b/indra/newview/llvowlsky.h
@@ -55,8 +55,6 @@ class LLVOWLSky : public LLStaticViewerObject {
 	void restoreGL();
 
 private:
-	// a tiny helper function for controlling the sky dome tesselation.
-	static F32 calcPhi(U32 i);
 
 	// helper function for initializing the stars.
 	void initStars();
@@ -66,11 +64,12 @@ class LLVOWLSky : public LLStaticViewerObject {
 	// begin_stack is the first stack to be included, end_stack is the first
 	// stack not to be included.
 	static void buildStripsBuffer(U32 begin_stack, U32 end_stack,
-                                  U32& vertex_count,
-                                  U32& index_count,
-								  LLStrider<LLVector3> & vertices,
-								  LLStrider<LLVector2> & texCoords,
-								  LLStrider<U16> & indices);
+                                  LLStrider<LLVector3> & vertices,
+                                  LLStrider<LLVector2> & texCoords,
+                                  LLStrider<U16> & indices,
+                                  const F32 RADIUS,
+                                  const U32& num_slices,
+                                  const U32& num_stacks);
 
 	// helper function for updating the stars colors.
 	void updateStarColors();
diff --git a/indra/newview/llweb.cpp b/indra/newview/llweb.cpp
index b8f1ec35f6dd707a296fd31dda90a554dcafa987..c4d873dd22bc42c2ec140567f070ae9c5cdc3a65 100644
--- a/indra/newview/llweb.cpp
+++ b/indra/newview/llweb.cpp
@@ -199,19 +199,16 @@ std::string LLWeb::expandURLSubstitutions(const std::string &url,
 	// find the grid
 	std::string current_grid = LLGridManager::getInstance()->getGridId();
 	std::transform(current_grid.begin(), current_grid.end(), current_grid.begin(), ::tolower);
-	if (current_grid == "agni")
+    if (current_grid == "damballah")
 	{
-		substitution["GRID"] = "secondlife.com";
-	}
-	else if (current_grid == "damballah")
-	{
-		// Staging grid has its own naming scheme.
-		substitution["GRID"] = "secondlife-staging.com";
-	}
-	else
-	{
-		substitution["GRID"] = llformat("%s.lindenlab.com", current_grid.c_str());
-	}
+      // Staging grid has its own naming scheme.
+      substitution["GRID"] = "secondlife-staging.com";
+    }
+    else
+    {
+        substitution["GRID"] = "secondlife.com";
+    }
+
 	// expand all of the substitution strings and escape the url
 	std::string expanded_url = url;
 	LLStringUtil::format(expanded_url, substitution);
diff --git a/indra/newview/llwebprofile.cpp b/indra/newview/llwebprofile.cpp
index ff899fe89538c0238af4b31a221de0511fd94450..3cc82621c49d0722c073c88c26147a79c4c74d0a 100644
--- a/indra/newview/llwebprofile.cpp
+++ b/indra/newview/llwebprofile.cpp
@@ -36,7 +36,7 @@
 #include "llstring.h"
 
 // newview
-#include "llpanelprofile.h" // for getProfileURL(). FIXME: move the method to LLAvatarActions
+#include "llavataractions.h" // for getProfileURL()
 #include "llviewermedia.h" // FIXME: don't use LLViewerMedia internals
 
 #include "llcorehttputil.h"
diff --git a/indra/newview/llworld.cpp b/indra/newview/llworld.cpp
index fb3fc55a94c2813a69b454d046551fd8cbd88dd1..aa32ef04b289723e29c5a1077da0c95c058143bb 100644
--- a/indra/newview/llworld.cpp
+++ b/indra/newview/llworld.cpp
@@ -113,7 +113,7 @@ LLWorld::LLWorld() :
 }
 
 
-void LLWorld::destroyClass()
+void LLWorld::resetClass()
 {
 	mHoleWaterObjects.clear();
 	gObjectList.destroy();
@@ -763,14 +763,13 @@ void LLWorld::updateParticles()
 void LLWorld::renderPropertyLines()
 {
 	S32 region_count = 0;
-	S32 vertex_count = 0;
 
 	for (region_list_t::iterator iter = mVisibleRegionList.begin();
 		 iter != mVisibleRegionList.end(); ++iter)
 	{
 		LLViewerRegion* regionp = *iter;
 		region_count++;
-		vertex_count += regionp->renderPropertyLines();
+		regionp->renderPropertyLines();
 	}
 }
 
@@ -778,7 +777,6 @@ void LLWorld::renderPropertyLines()
 void LLWorld::updateNetStats()
 {
 	F64Bits bits;
-	U32 packets = 0;
 
 	for (region_list_t::iterator iter = mActiveRegionList.begin();
 		 iter != mActiveRegionList.end(); ++iter)
@@ -786,7 +784,6 @@ void LLWorld::updateNetStats()
 		LLViewerRegion* regionp = *iter;
 		regionp->updateNetStats();
 		bits += regionp->mBitsReceived;
-		packets += llfloor( regionp->mPacketsReceived );
 		regionp->mBitsReceived = (F32Bits)0.f;
 		regionp->mPacketsReceived = 0.f;
 	}
@@ -884,6 +881,7 @@ void LLWorld::waterHeightRegionInfo(std::string const& sim_name, F32 water_heigh
 
 void LLWorld::precullWaterObjects(LLCamera& camera, LLCullResult* cull, bool include_void_water)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
 	if (!gAgent.getRegion())
 	{
 		return;
@@ -1077,6 +1075,7 @@ void LLWorld::updateWaterObjects()
 
 void LLWorld::shiftRegions(const LLVector3& offset)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
 	for (region_list_t::const_iterator i = getRegionList().begin(); i != getRegionList().end(); ++i)
 	{
 		LLViewerRegion* region = *i;
@@ -1147,11 +1146,9 @@ void LLWorld::disconnectRegions()
 	}
 }
 
-static LLTrace::BlockTimerStatHandle FTM_ENABLE_SIMULATOR("Enable Sim");
-
 void process_enable_simulator(LLMessageSystem *msg, void **user_data)
 {
-	LL_RECORD_BLOCK_TIME(FTM_ENABLE_SIMULATOR);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
 	// enable the appropriate circuit for this simulator and 
 	// add its values into the gSimulator structure
 	U64		handle;
@@ -1195,6 +1192,16 @@ class LLEstablishAgentCommunication : public LLHTTPNode
 	virtual void post(ResponsePtr response, const LLSD& context, const LLSD& input) const
 	{
         if (LLApp::isExiting())
+        {
+            return;
+        }
+
+        if (gDisconnected)
+        {
+            return;
+        }
+
+        if (!LLWorld::instanceExists())
         {
             return;
         }
@@ -1207,8 +1214,13 @@ class LLEstablishAgentCommunication : public LLHTTPNode
             return;
 		}
 
-		LLHost sim(input["body"]["sim-ip-and-port"].asString());
-	
+        LLHost sim(input["body"]["sim-ip-and-port"].asString());
+        if (sim.isInvalid())
+        {
+            LL_WARNS() << "Got EstablishAgentCommunication with invalid host" << LL_ENDL;
+            return;
+        }
+
 		LLViewerRegion* regionp = LLWorld::getInstance()->getRegion(sim);
 		if (!regionp)
 		{
@@ -1217,17 +1229,16 @@ class LLEstablishAgentCommunication : public LLHTTPNode
 			return;
 		}
 		LL_DEBUGS("CrossingCaps") << "Calling setSeedCapability from LLEstablishAgentCommunication::post. Seed cap == "
-				<< input["body"]["seed-capability"] << LL_ENDL;
+				<< input["body"]["seed-capability"] << " for region " << regionp->getRegionID() << LL_ENDL;
 		regionp->setSeedCapability(input["body"]["seed-capability"]);
 	}
 };
 
-static LLTrace::BlockTimerStatHandle FTM_DISABLE_REGION("Disable Region");
 // disable the circuit to this simulator
 // Called in response to "DisableSimulator" message.
 void process_disable_simulator(LLMessageSystem *mesgsys, void **user_data)
 {
-    LL_RECORD_BLOCK_TIME(FTM_DISABLE_REGION);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
 
     LLHost host = mesgsys->getSender();
 
@@ -1289,6 +1300,7 @@ void send_agent_pause()
 
 void send_agent_resume()
 {
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK
 	// Note: used to check for LLWorld initialization before it became a singleton.
 	// Rather than just remove this check I'm changing it to assure that the message 
 	// system has been initialized. -MG
diff --git a/indra/newview/llworld.h b/indra/newview/llworld.h
index 98552bc4d120187aad5254ff98830ed47557e45c..5c43cdf4e274f932a5bce44fd11c1de7ff90f932 100644
--- a/indra/newview/llworld.h
+++ b/indra/newview/llworld.h
@@ -59,11 +59,14 @@ class LLVOAvatar;
 // as simulators are connected to, viewer_regions are popped off the stack and connected as required
 // as simulators are removed, they are pushed back onto the stack
 
-class LLWorld : public LLSingleton<LLWorld>
+class LLWorld : public LLSimpleton<LLWorld>
 {
-	LLSINGLETON(LLWorld);
 public:
-	void destroyClass();
+    LLWorld();
+
+    // Clear any objects, regions
+    // Prepares class to be reused or destroyed
+    void resetClass();
 
 	LLViewerRegion*	addRegion(const U64 &region_handle, const LLHost &host);
 		// safe to call if already present, does the "right thing" if
diff --git a/indra/newview/llworldmapmessage.cpp b/indra/newview/llworldmapmessage.cpp
index 8be340de4c42ec8d95073e2b8e7ae8616502d80e..e4a9f9afdb5908dbab14f6d845a248e4eecde596 100644
--- a/indra/newview/llworldmapmessage.cpp
+++ b/indra/newview/llworldmapmessage.cpp
@@ -150,6 +150,10 @@ void LLWorldMapMessage::sendMapBlockRequest(U16 min_x, U16 min_y, U16 max_x, U16
 // public static
 void LLWorldMapMessage::processMapBlockReply(LLMessageSystem* msg, void**)
 {
+	if (gNonInteractive)
+	{
+		return;
+	}
 	U32 agent_flags;
 	msg->getU32Fast(_PREHASH_AgentData, _PREHASH_Flags, agent_flags);
 
diff --git a/indra/newview/llworldmapview.cpp b/indra/newview/llworldmapview.cpp
old mode 100644
new mode 100755
index a6df0792233581c1aabe4c1c268298b99a0003c4..6e994b4e68ad95060a476beb0b3026c1ff917ff2
--- a/indra/newview/llworldmapview.cpp
+++ b/indra/newview/llworldmapview.cpp
@@ -58,9 +58,15 @@
 
 #include "llglheaders.h"
 
+// # Constants
+static const F32 MAP_DEFAULT_SCALE = 128.f;
+static const F32 MAP_ITERP_TIME_CONSTANT = 0.75f;
+static const F32 MAP_ZOOM_ACCELERATION_TIME = 0.3f;
+static const F32 MAP_ZOOM_MAX_INTERP = 0.5f;
+static const F32 MAP_SCALE_SNAP_THRESHOLD = 0.005f;
+
 // Basically a C++ implementation of the OCEAN_COLOR defined in mapstitcher.py 
 // Please ensure consistency between those 2 files (TODO: would be better to get that color from an asset source...)
-// # Constants
 // OCEAN_COLOR = "#1D475F"
 const F32 OCEAN_RED   = (F32)(0x1D)/255.f;
 const F32 OCEAN_GREEN = (F32)(0x47)/255.f;
@@ -92,14 +98,12 @@ LLUIImagePtr LLWorldMapView::sClassifiedsImage = NULL;
 LLUIImagePtr LLWorldMapView::sForSaleImage = NULL;
 LLUIImagePtr LLWorldMapView::sForSaleAdultImage = NULL;
 
-F32 LLWorldMapView::sPanX = 0.f;
-F32 LLWorldMapView::sPanY = 0.f;
-F32 LLWorldMapView::sTargetPanX = 0.f;
-F32 LLWorldMapView::sTargetPanY = 0.f;
 S32 LLWorldMapView::sTrackingArrowX = 0;
 S32 LLWorldMapView::sTrackingArrowY = 0;
 bool LLWorldMapView::sVisibleTilesLoaded = false;
-F32 LLWorldMapView::sMapScale = 128.f;
+F32 LLWorldMapView::sMapScaleSetting = MAP_DEFAULT_SCALE;
+LLVector2 LLWorldMapView::sZoomPivot = LLVector2(0.0f, 0.0f);
+LLFrameTimer LLWorldMapView::sZoomTimer = LLFrameTimer();
 
 std::map<std::string,std::string> LLWorldMapView::sStringsMap;
 
@@ -166,20 +170,27 @@ void LLWorldMapView::cleanupClass()
 	sForSaleAdultImage = NULL;
 }
 
-LLWorldMapView::LLWorldMapView()
-:	LLPanel(),
-	mBackgroundColor( LLColor4( OCEAN_RED, OCEAN_GREEN, OCEAN_BLUE, 1.f ) ),
-	mItemPicked(FALSE),
-	mPanning( FALSE ),
-	mMouseDownPanX( 0 ),
-	mMouseDownPanY( 0 ),
-	mMouseDownX( 0 ),
-	mMouseDownY( 0 ),
-	mSelectIDStart(0)
+LLWorldMapView::LLWorldMapView() :
+    LLPanel(),
+    mBackgroundColor(LLColor4(OCEAN_RED, OCEAN_GREEN, OCEAN_BLUE, 1.f)),
+    mItemPicked(FALSE),
+    mPanX(0.f),
+    mPanY(0.f),
+    mTargetPanX(0.f),
+    mTargetPanY(0.f),
+    mPanning(FALSE),
+    mMouseDownPanX(0),
+    mMouseDownPanY(0),
+    mMouseDownX(0),
+    mMouseDownY(0),
+    mSelectIDStart(0),
+    mMapScale(0.f),
+    mTargetMapScale(0.f),
+    mMapIterpTime(MAP_ITERP_TIME_CONSTANT)
 {
-	//LL_INFOS("WorldMap") << "Creating the Map -> LLWorldMapView::LLWorldMapView()" << LL_ENDL;
+    // LL_INFOS("WorldMap") << "Creating the Map -> LLWorldMapView::LLWorldMapView()" << LL_ENDL;
 
-	clearLastClick();
+    clearLastClick();
 }
 
 BOOL LLWorldMapView::postBuild()
@@ -210,6 +221,9 @@ BOOL LLWorldMapView::postBuild()
 	mTextBoxNorthEast ->reshapeToFitText();
 	mTextBoxSouthWest->reshapeToFitText();
 	mTextBoxNorthWest ->reshapeToFitText();
+    
+    sZoomTimer.stop();
+    setScale(sMapScaleSetting, true);
 
 	return true;
 }
@@ -227,59 +241,111 @@ void LLWorldMapView::cleanupTextures()
 {
 }
 
+void LLWorldMapView::zoom(F32 zoom)
+{
+    mTargetMapScale = scaleFromZoom(zoom);
+    if (!sZoomTimer.getStarted() && mMapScale != mTargetMapScale)
+    {
+        sZoomPivot = LLVector2(0, 0);
+        sZoomTimer.start();
+    }
+}
 
-// static
-void LLWorldMapView::setScale( F32 scale )
+void LLWorldMapView::zoomWithPivot(F32 zoom, S32 x, S32 y)
 {
-	if (scale != sMapScale)
-	{
-		F32 old_scale = sMapScale;
+    mTargetMapScale = scaleFromZoom(zoom);
+    sZoomPivot      = LLVector2(x, y);
+    if (!sZoomTimer.getStarted() && mMapScale != mTargetMapScale)
+    {
+        sZoomTimer.start();
+    }
+}
 
-		sMapScale = scale;
-		if (sMapScale <= 0.f)
-		{
-			sMapScale = 0.1f;
-		}
+F32 LLWorldMapView::getZoom() { return LLWorldMapView::zoomFromScale(mMapScale); }
 
-		F32 ratio = (scale / old_scale);
-		sPanX *= ratio;
-		sPanY *= ratio;
-		sTargetPanX = sPanX;
-		sTargetPanY = sPanY;
-		sVisibleTilesLoaded = false;
-	}
-}
+F32 LLWorldMapView::getScale() { return mMapScale; }
 
+// static
+void LLWorldMapView::setScaleSetting(F32 scaleSetting) { sMapScaleSetting = scaleSetting; }
 
 // static
-void LLWorldMapView::translatePan( S32 delta_x, S32 delta_y )
+F32 LLWorldMapView::getScaleSetting() { return sMapScaleSetting; }
+
+void LLWorldMapView::setScale(F32 scale, bool snap)
+{
+    if (scale != mMapScale)
+    {
+        F32 old_scale = mMapScale;
+
+        mMapScale = scale;
+        // Set the scale used when saving the setting
+        sMapScaleSetting = scale;
+        if (mMapScale <= 0.f)
+        {
+            mMapScale = 0.1f;
+        }
+        mMapIterpTime = MAP_ITERP_TIME_CONSTANT;
+        F32 ratio = (scale / old_scale);
+        mPanX *= ratio;
+        mPanY *= ratio;
+        mTargetPanX         = mPanX;
+        mTargetPanY         = mPanY;
+        sVisibleTilesLoaded = false;
+
+        // If we are zooming relative to somewhere else rather than the center of the map, compensate for the difference in panning here
+        if (!sZoomPivot.isExactlyZero())
+        {
+            LLVector2 relative_pivot;
+            relative_pivot.mV[VX]     = sZoomPivot.mV[VX] - (getRect().getWidth() / 2.0);
+            relative_pivot.mV[VY]     = sZoomPivot.mV[VY] - (getRect().getHeight() / 2.0);
+            LLVector2 zoom_pan_offset = relative_pivot - (relative_pivot * scale / old_scale);
+            mPanX += zoom_pan_offset.mV[VX];
+            mPanY += zoom_pan_offset.mV[VY];
+            mTargetPanX += zoom_pan_offset.mV[VX];
+            mTargetPanY += zoom_pan_offset.mV[VY];
+        }
+    }
+
+    if (snap)
+    {
+        mTargetMapScale = scale;
+    }
+}
+
+// static
+void LLWorldMapView::translatePan(S32 delta_x, S32 delta_y)
 {
-	sPanX += delta_x;
-	sPanY += delta_y;
-	sTargetPanX = sPanX;
-	sTargetPanY = sPanY;
-	sVisibleTilesLoaded = false;
+    mPanX += delta_x;
+    mPanY += delta_y;
+    mTargetPanX         = mPanX;
+    mTargetPanY         = mPanY;
+    sVisibleTilesLoaded = false;
 }
 
 
 // static
-void LLWorldMapView::setPan( S32 x, S32 y, BOOL snap )
+void LLWorldMapView::setPan(S32 x, S32 y, BOOL snap)
 {
-	sTargetPanX = (F32)x;
-	sTargetPanY = (F32)y;
-	if (snap)
-	{
-		sPanX = sTargetPanX;
-		sPanY = sTargetPanY;
-	}
-	sVisibleTilesLoaded = false;
+    mMapIterpTime = MAP_ITERP_TIME_CONSTANT;
+    mTargetPanX = (F32) x;
+    mTargetPanY = (F32) y;
+    if (snap)
+    {
+        mPanX = mTargetPanX;
+        mPanY = mTargetPanY;
+    }
+    sVisibleTilesLoaded = false;
 }
 
-bool LLWorldMapView::showRegionInfo()
+// static
+void LLWorldMapView::setPanWithInterpTime(S32 x, S32 y, BOOL snap, F32 interp_time)
 {
-	return (LLWorldMipmap::scaleToLevel(sMapScale) <= DRAW_SIMINFO_THRESHOLD ? true : false);
+    setPan(x, y, snap);
+    mMapIterpTime = interp_time;
 }
 
+bool LLWorldMapView::showRegionInfo() { return (LLWorldMipmap::scaleToLevel(mMapScale) <= DRAW_SIMINFO_THRESHOLD ? true : false); }
+
 ///////////////////////////////////////////////////////////////////////////////////
 // HELPERS
 
@@ -300,9 +366,28 @@ void LLWorldMapView::draw()
 
 	mVisibleRegions.clear();
 
-	// animate pan if necessary
-	sPanX = lerp(sPanX, sTargetPanX, LLSmoothInterpolation::getInterpolant(0.1f));
-	sPanY = lerp(sPanY, sTargetPanY, LLSmoothInterpolation::getInterpolant(0.1f));
+    // animate pan if necessary
+    mPanX = lerp(mPanX, mTargetPanX, LLSmoothInterpolation::getInterpolant(mMapIterpTime));
+    mPanY = lerp(mPanY, mTargetPanY, LLSmoothInterpolation::getInterpolant(mMapIterpTime));
+    
+    //RN: snaps to zoom value because interpolation caused jitter in the text rendering
+    if (!sZoomTimer.getStarted() && mMapScale != mTargetMapScale)
+    {
+        sZoomTimer.start();
+    }
+    bool snap_scale = false;
+    F32 interp = llmin(MAP_ZOOM_MAX_INTERP, sZoomTimer.getElapsedTimeF32() / MAP_ZOOM_ACCELERATION_TIME);
+    F32 current_zoom_val = zoomFromScale(mMapScale);
+    F32 target_zoom_val = zoomFromScale(mTargetMapScale);
+    F32 new_zoom_val = lerp(current_zoom_val, target_zoom_val, interp);
+    if (abs(new_zoom_val - current_zoom_val) < MAP_SCALE_SNAP_THRESHOLD)
+    {
+        sZoomTimer.stop();
+        snap_scale = true;
+        new_zoom_val = target_zoom_val;
+    }
+    F32 map_scale = scaleFromZoom(new_zoom_val);
+    setScale(map_scale, snap_scale);
 
 	const S32 width = getRect().getWidth();
 	const S32 height = getRect().getHeight();
@@ -310,7 +395,7 @@ void LLWorldMapView::draw()
 	const F32 half_height = F32(height) / 2.0f;
 	LLVector3d camera_global = gAgentCamera.getCameraPositionGlobal();
 
-	S32 level = LLWorldMipmap::scaleToLevel(sMapScale);
+	S32 level = LLWorldMipmap::scaleToLevel(mMapScale);
 
 	LLLocalClipRect clip(getLocalRect());
 	{
@@ -321,22 +406,19 @@ void LLWorldMapView::draw()
 		// Clear the background alpha to 0
 		gGL.flush();
 		gGL.setColorMask(false, true);
-		gGL.setAlphaRejectSettings(LLRender::CF_GREATER_EQUAL, 0.f);
+        gGL.flush();
 		gGL.setSceneBlendType(LLRender::BT_REPLACE);
 		gGL.color4f(0.0f, 0.0f, 0.0f, 0.0f);
 		gl_rect_2d(0, height, width, 0);
 	}
 
 	gGL.flush();
-
-	gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
 	gGL.setColorMask(true, true);
 
 	// Draw the image tiles
 	drawMipmap(width, height);
 	gGL.flush();
 
-	gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
 	gGL.setColorMask(true, true);
 
 	// Draw per sim overlayed information (names, mature, offline...)
@@ -350,15 +432,15 @@ void LLWorldMapView::draw()
 
 		// Find x and y position relative to camera's center.
 		LLVector3d rel_region_pos = origin_global - camera_global;
-		F32 relative_x = (rel_region_pos.mdV[0] / REGION_WIDTH_METERS) * sMapScale;
-		F32 relative_y = (rel_region_pos.mdV[1] / REGION_WIDTH_METERS) * sMapScale;
+		F32 relative_x = (rel_region_pos.mdV[0] / REGION_WIDTH_METERS) * mMapScale;
+		F32 relative_y = (rel_region_pos.mdV[1] / REGION_WIDTH_METERS) * mMapScale;
 
 		// Coordinates of the sim in pixels in the UI panel
 		// When the view isn't panned, 0,0 = center of rectangle
-		F32 bottom =    sPanY + half_height + relative_y;
-		F32 left =      sPanX + half_width + relative_x;
-		F32 top =       bottom + sMapScale ;
-		F32 right =     left + sMapScale ;
+		F32 bottom =    mPanY + half_height + relative_y;
+		F32 left =      mPanX + half_width + relative_x;
+		F32 top =       bottom + mMapScale ;
+		F32 right =     left + mMapScale ;
 
 		// Discard if region is outside the screen rectangle (not visible on screen)
 		if ((top < 0.f)   || (bottom > height) ||
@@ -419,7 +501,7 @@ void LLWorldMapView::draw()
 			if (overlayimage)
 			{
 				// Inform the fetch mechanism of the size we need
-				S32 draw_size = ll_round(sMapScale);
+				S32 draw_size = ll_round(mMapScale);
 				overlayimage->setKnownDrawSize(ll_round(draw_size * LLUI::getScaleFactor().mV[VX]), ll_round(draw_size * LLUI::getScaleFactor().mV[VY]));
 				// Draw something whenever we have enough info
 				if (overlayimage->hasGLTexture())
@@ -447,7 +529,7 @@ void LLWorldMapView::draw()
 		}
 
 		// Draw the region name in the lower left corner
-		if (sMapScale >= DRAW_TEXT_THRESHOLD)
+		if (mMapScale >= DRAW_TEXT_THRESHOLD)
 		{
 			LLFontGL* font = LLFontGL::getFont(LLFontDescriptor("SansSerif", "Small", LLFontGL::BOLD));
 			std::string mesg;
@@ -467,7 +549,7 @@ void LLWorldMapView::draw()
 					LLColor4::white,
 					LLFontGL::LEFT, LLFontGL::BASELINE, LLFontGL::NORMAL, LLFontGL::DROP_SHADOW,
 					S32_MAX, //max_chars
-					sMapScale, //max_pixels
+					mMapScale, //max_pixels
 					NULL,
 					TRUE); //use ellipses
 			}
@@ -480,13 +562,13 @@ void LLWorldMapView::draw()
 	LLGLSUIDefault gls_ui;
 	{
 		gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
-		gGL.setAlphaRejectSettings(LLRender::CF_GREATER_EQUAL, 0.f);
+        gGL.flush();
 		gGL.blendFunc(LLRender::BF_ONE_MINUS_DEST_ALPHA, LLRender::BF_DEST_ALPHA);
 		gGL.color4fv( mBackgroundColor.mV );
 		gl_rect_2d(0, height, width, 0);
 	}
 
-	gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
+    gGL.flush();
 	gGL.setSceneBlendType(LLRender::BT_ALPHA);
 
 	// Draw item infos if we're not zoomed out too much and there's something to draw
@@ -594,7 +676,7 @@ void LLWorldMapView::setVisible(BOOL visible)
 void LLWorldMapView::drawMipmap(S32 width, S32 height)
 {
 	// Compute the level of the mipmap to use for the current scale level
-	S32 level = LLWorldMipmap::scaleToLevel(sMapScale);
+	S32 level = LLWorldMipmap::scaleToLevel(mMapScale);
 	// Set the tile boost level so that unused tiles get to 0
 	LLWorldMap::getInstance()->equalizeBoostLevels();
 
@@ -877,7 +959,7 @@ void LLWorldMapView::drawAgents()
 void LLWorldMapView::drawFrustum()
 {
 	// Draw frustum
-	F32 meters_to_pixels = sMapScale/ REGION_WIDTH_METERS;
+	F32 meters_to_pixels = mMapScale/ REGION_WIDTH_METERS;
 
 	F32 horiz_fov = LLViewerCamera::getInstance()->getView() * LLViewerCamera::getInstance()->getAspect();
 	F32 far_clip_meters = LLViewerCamera::getInstance()->getFar();
@@ -887,8 +969,8 @@ void LLWorldMapView::drawFrustum()
 	F32 half_width_pixels = half_width_meters * meters_to_pixels;
 	
 	// Compute the frustum coordinates. Take the UI scale into account.
-    F32 ctr_x = ((getLocalRect().getWidth() * 0.5f + sPanX)  * LLUI::getScaleFactor().mV[VX]);
-    F32 ctr_y = ((getLocalRect().getHeight() * 0.5f + sPanY) * LLUI::getScaleFactor().mV[VY]);
+    F32 ctr_x = ((getLocalRect().getWidth() * 0.5f + mPanX)  * LLUI::getScaleFactor().mV[VX]);
+    F32 ctr_y = ((getLocalRect().getHeight() * 0.5f + mPanY) * LLUI::getScaleFactor().mV[VY]);
 
 	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 
@@ -945,13 +1027,13 @@ LLVector3 LLWorldMapView::globalPosToView( const LLVector3d& global_pos )
 	LLVector3 pos_local;
 	pos_local.setVec(relative_pos_global);  // convert to floats from doubles
 
-	pos_local.mV[VX] *= sMapScale / REGION_WIDTH_METERS;
-	pos_local.mV[VY] *= sMapScale / REGION_WIDTH_METERS;
+	pos_local.mV[VX] *= mMapScale / REGION_WIDTH_METERS;
+	pos_local.mV[VY] *= mMapScale / REGION_WIDTH_METERS;
 	// leave Z component in meters
 
 
-	pos_local.mV[VX] += getRect().getWidth() / 2 + sPanX;
-	pos_local.mV[VY] += getRect().getHeight() / 2 + sPanY;
+	pos_local.mV[VX] += getRect().getWidth() / 2 + mPanX;
+	pos_local.mV[VY] += getRect().getHeight() / 2 + mPanY;
 
 	return pos_local;
 }
@@ -1022,12 +1104,12 @@ void LLWorldMapView::drawTracking(const LLVector3d& pos_global, const LLColor4&
 // If you change this, then you need to change LLTracker::getTrackedPositionGlobal() as well
 LLVector3d LLWorldMapView::viewPosToGlobal( S32 x, S32 y )
 {
-	x -= llfloor((getRect().getWidth() / 2 + sPanX));
-	y -= llfloor((getRect().getHeight() / 2 + sPanY));
+	x -= llfloor((getRect().getWidth() / 2 + mPanX));
+	y -= llfloor((getRect().getHeight() / 2 + mPanY));
 
 	LLVector3 pos_local( (F32)x, (F32)y, 0.f );
 
-	pos_local *= ( REGION_WIDTH_METERS / sMapScale );
+	pos_local *= ( REGION_WIDTH_METERS / mMapScale );
 	
 	LLVector3d pos_global;
 	pos_global.setVec( pos_local );
@@ -1484,7 +1566,7 @@ void LLWorldMapView::handleClick(S32 x, S32 y, MASK mask,
 
 	LLWorldMap::getInstance()->cancelTracking();
 
-	S32 level = LLWorldMipmap::scaleToLevel(sMapScale);
+	S32 level = LLWorldMipmap::scaleToLevel(mMapScale);
 	// If the zoom level is not too far out already, test hits
 	if (level <= DRAW_SIMINFO_THRESHOLD)
 	{
@@ -1601,8 +1683,8 @@ BOOL LLWorldMapView::handleMouseDown( S32 x, S32 y, MASK mask )
 {
 	gFocusMgr.setMouseCapture( this );
 
-	mMouseDownPanX = ll_round(sPanX);
-	mMouseDownPanY = ll_round(sPanY);
+	mMouseDownPanX = ll_round(mPanX);
+	mMouseDownPanY = ll_round(mPanY);
 	mMouseDownX = x;
 	mMouseDownY = y;
 	sHandledLastClick = TRUE;
@@ -1617,8 +1699,8 @@ BOOL LLWorldMapView::handleMouseUp( S32 x, S32 y, MASK mask )
 		{
 			// restore mouse cursor
 			S32 local_x, local_y;
-			local_x = mMouseDownX + llfloor(sPanX - mMouseDownPanX);
-			local_y = mMouseDownY + llfloor(sPanY - mMouseDownPanY);
+			local_x = mMouseDownX + llfloor(mPanX - mMouseDownPanX);
+			local_y = mMouseDownY + llfloor(mPanY - mMouseDownPanY);
 			LLRect clip_rect = getRect();
 			clip_rect.stretch(-8);
 			clip_rect.clipPointToRect(mMouseDownX, mMouseDownY, local_x, local_y);
@@ -1646,7 +1728,7 @@ BOOL LLWorldMapView::handleMouseUp( S32 x, S32 y, MASK mask )
 
 void LLWorldMapView::updateVisibleBlocks()
 {
-	if (LLWorldMipmap::scaleToLevel(sMapScale) > DRAW_SIMINFO_THRESHOLD)
+	if (LLWorldMipmap::scaleToLevel(mMapScale) > DRAW_SIMINFO_THRESHOLD)
 	{
 		// If we're zoomed out too much, we just don't load all those sim info: too much!
 		return;
@@ -1662,16 +1744,16 @@ void LLWorldMapView::updateVisibleBlocks()
 	const F32 half_height = F32(height) / 2.0f;
 
 	// Compute center into sim grid coordinates
-	S32 world_center_x = S32((-sPanX / sMapScale) + (camera_global.mdV[0] / REGION_WIDTH_METERS));
-	S32 world_center_y = S32((-sPanY / sMapScale) + (camera_global.mdV[1] / REGION_WIDTH_METERS));
+	S32 world_center_x = S32((-mPanX / mMapScale) + (camera_global.mdV[0] / REGION_WIDTH_METERS));
+	S32 world_center_y = S32((-mPanY / mMapScale) + (camera_global.mdV[1] / REGION_WIDTH_METERS));
 
 	// Compute the boundaries into sim grid coordinates
-	S32 world_left   = world_center_x - S32(half_width  / sMapScale) - 1;
-	S32 world_right  = world_center_x + S32(half_width  / sMapScale) + 1;
-	S32 world_bottom = world_center_y - S32(half_height / sMapScale) - 1;
-	S32 world_top    = world_center_y + S32(half_height / sMapScale) + 1;
+	S32 world_left   = world_center_x - S32(half_width  / mMapScale) - 1;
+	S32 world_right  = world_center_x + S32(half_width  / mMapScale) + 1;
+	S32 world_bottom = world_center_y - S32(half_height / mMapScale) - 1;
+	S32 world_top    = world_center_y + S32(half_height / mMapScale) + 1;
 
-	//LL_INFOS("WorldMap") << "LLWorldMapView::updateVisibleBlocks() : sMapScale = " << sMapScale << ", left = " << world_left << ", right = " << world_right << ", bottom  = " << world_bottom << ", top = " << world_top << LL_ENDL;
+	//LL_INFOS("WorldMap") << "LLWorldMapView::updateVisibleBlocks() : mMapScale = " << mMapScale << ", left = " << world_left << ", right = " << world_right << ", bottom  = " << world_bottom << ", top = " << world_top << LL_ENDL;
 	LLWorldMap::getInstance()->updateRegions(world_left, world_bottom, world_right, world_top);
 }
 
@@ -1692,10 +1774,10 @@ BOOL LLWorldMapView::handleHover( S32 x, S32 y, MASK mask )
 			F32 delta_y = (F32)(gViewerWindow->getCurrentMouseDY());
 
 			// Set pan to value at start of drag + offset
-			sPanX += delta_x;
-			sPanY += delta_y;
-			sTargetPanX = sPanX;
-			sTargetPanY = sPanY;
+			mPanX += delta_x;
+			mPanY += delta_y;
+			mTargetPanX = mPanX;
+			mTargetPanY = mPanY;
 
 			gViewerWindow->moveCursorToCenter();
 		}
@@ -1792,4 +1874,8 @@ BOOL LLWorldMapView::handleDoubleClick( S32 x, S32 y, MASK mask )
 	return FALSE;
 }
 
+// static
+F32 LLWorldMapView::scaleFromZoom(F32 zoom) { return exp2(zoom) * 256.0f; }
 
+// static
+F32 LLWorldMapView::zoomFromScale(F32 scale) { return log2(scale / 256.f); }
diff --git a/indra/newview/llworldmapview.h b/indra/newview/llworldmapview.h
index a2a6dc53fb5cabd412f0fcfecedefef27c0ca1f3..ce8af76a82009dcbe822bc30a77dedfddaec253e 100644
--- a/indra/newview/llworldmapview.h
+++ b/indra/newview/llworldmapview.h
@@ -67,12 +67,22 @@ class LLWorldMapView : public LLPanel
 	bool			checkItemHit(S32 x, S32 y, LLItemInfo& item, LLUUID* id, bool track);
 	void			handleClick(S32 x, S32 y, MASK mask, S32* hit_type, LLUUID* id);
 
-	// Scale and pan are shared across all instances! (i.e. Terrain and Objects maps are always registered)
-	static void		setScale( F32 scale );
-	static void		translatePan( S32 delta_x, S32 delta_y );
-	static void		setPan( S32 x, S32 y, BOOL snap = TRUE );
+    // Scale, aka zoom, is shared across all instances! (i.e. Terrain and Objects maps are always registered)
+    // Zoom is used for UI and will interpolate the map scale over multiple frames.
+    void zoom(F32 zoom);
+    void zoomWithPivot(F32 zoom, S32 x, S32 y);
+    F32 getZoom();
+    // Scale is a linear scaling factor of in-world coordinates
+    F32 getScale();
+    // setScaleSetting/getScaleSetting are for the default map setting on login
+    static void setScaleSetting(F32 scaleSetting);
+    static F32 getScaleSetting();
+    // Pan is in pixels relative to the center of the map.
+	void translatePan( S32 delta_x, S32 delta_y );
+    void setPan( S32 x, S32 y, BOOL snap = TRUE );
+    void setPanWithInterpTime(S32 x, S32 y, BOOL snap, F32 interp_time);
 	// Return true if the current scale level is above the threshold for accessing region info
-	static bool		showRegionInfo();
+    bool showRegionInfo();
 
 	LLVector3		globalPosToView(const LLVector3d& global_pos);
 	LLVector3d		viewPosToGlobal(S32 x,S32 y);
@@ -153,14 +163,12 @@ class LLWorldMapView : public LLPanel
 	static LLUIImagePtr	sForSaleImage;
 	static LLUIImagePtr	sForSaleAdultImage;
 
-	static F32		sMapScale;				// scale = size of a region in pixels
-
 	BOOL			mItemPicked;
 
-	static F32		sPanX;		// in pixels
-	static F32		sPanY;		// in pixels
-	static F32		sTargetPanX;		// in pixels
-	static F32		sTargetPanY;		// in pixels
+    F32 mPanX; // in pixels
+    F32 mPanY; // in pixels
+    F32 mTargetPanX; // in pixels
+    F32 mTargetPanY; // in pixels
 	static S32		sTrackingArrowX;
 	static S32		sTrackingArrowY;
 	static bool		sVisibleTilesLoaded;
@@ -194,6 +202,19 @@ class LLWorldMapView : public LLPanel
 
 private:
 	void drawTileOutline(S32 level, F32 top, F32 left, F32 bottom, F32 right);
+
+    void setScale(F32 scale, bool snap = true);
+
+    static F32 scaleFromZoom(F32 zoom);
+    static F32 zoomFromScale(F32 scale);
+
+    F32 mMapScale;
+    F32 mTargetMapScale;
+    static F32 sMapScaleSetting;
+    static LLVector2 sZoomPivot;
+    static LLFrameTimer sZoomTimer;
+
+    F32 mMapIterpTime;
 };
 
 #endif
diff --git a/indra/newview/llxmlrpctransaction.cpp b/indra/newview/llxmlrpctransaction.cpp
index 32c8ce66a01834353042787d838abc97725e93ed..5c56a1d34f7471c1ebfd2e4b7504a4776260799a 100644
--- a/indra/newview/llxmlrpctransaction.cpp
+++ b/indra/newview/llxmlrpctransaction.cpp
@@ -40,6 +40,7 @@
 #include "httpoptions.h"
 #include "httpheaders.h"
 #include "bufferarray.h"
+#include "llversioninfo.h"
 #include "llviewercontrol.h"
 
 // Have to include these last to avoid queue redefinition!
@@ -378,6 +379,15 @@ void LLXMLRPCTransaction::Impl::init(XMLRPC_REQUEST request, bool useGzip, const
 
 	httpHeaders->append(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_TEXT_XML);
 
+    std::string user_agent = llformat("%s %d.%d.%d (%d)",
+        LLVersionInfo::instance().getChannel().c_str(),
+        LLVersionInfo::instance().getMajor(),
+        LLVersionInfo::instance().getMinor(),
+        LLVersionInfo::instance().getPatch(),
+        LLVersionInfo::instance().getBuild());
+
+    httpHeaders->append(HTTP_OUT_HEADER_USER_AGENT, user_agent);
+
 	///* Setting the DNS cache timeout to -1 disables it completely.
 	//This might help with bug #503 */
 	//httpOpts->setDNSCacheTimeout(-1);
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index d797b64731dcc6932e226f43c4a4fbb7c7a93f23..96ba80dacc5a22ce8515d8e846c2f9324350a2c8 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -142,7 +142,6 @@
 bool gShiftFrame = false;
 
 //cached settings
-bool LLPipeline::RenderAvatarVP;
 bool LLPipeline::WindLightUseAtmosShaders;
 bool LLPipeline::RenderDeferred;
 F32 LLPipeline::RenderDeferredSunWash;
@@ -238,7 +237,6 @@ const LLMatrix4* gGLLastMatrix = NULL;
 LLTrace::BlockTimerStatHandle FTM_RENDER_GEOMETRY("Render Geometry");
 LLTrace::BlockTimerStatHandle FTM_RENDER_GRASS("Grass");
 LLTrace::BlockTimerStatHandle FTM_RENDER_INVISIBLE("Invisible");
-LLTrace::BlockTimerStatHandle FTM_RENDER_OCCLUSION("Occlusion");
 LLTrace::BlockTimerStatHandle FTM_RENDER_SHINY("Shiny");
 LLTrace::BlockTimerStatHandle FTM_RENDER_SIMPLE("Simple");
 LLTrace::BlockTimerStatHandle FTM_RENDER_TERRAIN("Terrain");
@@ -253,14 +251,12 @@ LLTrace::BlockTimerStatHandle FTM_RENDER_MATERIALS("Render Materials");
 LLTrace::BlockTimerStatHandle FTM_RENDER_FULLBRIGHT("Fullbright");
 LLTrace::BlockTimerStatHandle FTM_RENDER_GLOW("Glow");
 LLTrace::BlockTimerStatHandle FTM_GEO_UPDATE("Geo Update");
-LLTrace::BlockTimerStatHandle FTM_PIPELINE_CREATE("Pipeline Create");
 LLTrace::BlockTimerStatHandle FTM_POOLRENDER("RenderPool");
 LLTrace::BlockTimerStatHandle FTM_POOLS("Pools");
 LLTrace::BlockTimerStatHandle FTM_DEFERRED_POOLRENDER("RenderPool (Deferred)");
 LLTrace::BlockTimerStatHandle FTM_DEFERRED_POOLS("Pools (Deferred)");
 LLTrace::BlockTimerStatHandle FTM_POST_DEFERRED_POOLRENDER("RenderPool (Post)");
 LLTrace::BlockTimerStatHandle FTM_POST_DEFERRED_POOLS("Pools (Post)");
-LLTrace::BlockTimerStatHandle FTM_RENDER_BLOOM_FBO("First FBO");
 LLTrace::BlockTimerStatHandle FTM_STATESORT("Sort Draw State");
 LLTrace::BlockTimerStatHandle FTM_PIPELINE("Pipeline");
 LLTrace::BlockTimerStatHandle FTM_CLIENT_COPY("Client Copy");
@@ -269,11 +265,8 @@ LLTrace::BlockTimerStatHandle FTM_RENDER_DEFERRED("Deferred Shading");
 LLTrace::BlockTimerStatHandle FTM_RENDER_UI_HUD("HUD");
 LLTrace::BlockTimerStatHandle FTM_RENDER_UI_3D("3D");
 LLTrace::BlockTimerStatHandle FTM_RENDER_UI_2D("2D");
-LLTrace::BlockTimerStatHandle FTM_RENDER_UI_DEBUG_TEXT("Debug Text");
-LLTrace::BlockTimerStatHandle FTM_RENDER_UI_SCENE_MON("Scene Mon");
 
 static LLTrace::BlockTimerStatHandle FTM_STATESORT_DRAWABLE("Sort Drawables");
-static LLTrace::BlockTimerStatHandle FTM_STATESORT_POSTSORT("Post Sort");
 
 static LLStaticHashedString sTint("tint");
 static LLStaticHashedString sAmbiance("ambiance");
@@ -338,7 +331,6 @@ S32		LLPipeline::sUseOcclusion = 0;
 bool	LLPipeline::sDelayVBUpdate = true;
 bool	LLPipeline::sAutoMaskAlphaDeferred = true;
 bool	LLPipeline::sAutoMaskAlphaNonDeferred = false;
-bool	LLPipeline::sDisableShaders = false;
 bool	LLPipeline::sRenderTransparentWater = true;
 bool	LLPipeline::sRenderBump = true;
 bool	LLPipeline::sBakeSunlight = false;
@@ -359,7 +351,6 @@ bool	LLPipeline::sRenderAttachedLights = true;
 bool	LLPipeline::sRenderAttachedParticles = true;
 bool	LLPipeline::sRenderDeferred = false;
 S32		LLPipeline::sVisibleLightCount = 0;
-F32		LLPipeline::sMinRenderSize = 0.f;
 bool	LLPipeline::sRenderingHUDs;
 F32     LLPipeline::sDistortionWaterClipPlaneMargin = 1.0125f;
 
@@ -370,10 +361,12 @@ static LLCullResult* sCull = NULL;
 
 void validate_framebuffer_object();
 
-
-bool addDeferredAttachments(LLRenderTarget& target)
+// 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)
 {
-	return target.addColorAttachment(GL_SRGB8_ALPHA8) && //specular
+	return target.addColorAttachment(for_impostor ? GL_RGBA : GL_SRGB8_ALPHA8) && //specular
 			target.addColorAttachment(GL_RGB10_A2); //normal+z
 }
 
@@ -385,8 +378,7 @@ LLPipeline::LLPipeline() :
 	mNumVisibleFaces(0),
 
 	mInitialized(false),
-	mVertexShadersEnabled(false),
-	mVertexShadersLoaded(0),
+	mShadersLoaded(false),
 	mTransformFeedbackPrimitives(0),
 	mRenderDebugFeatureMask(0),
 	mRenderDebugMask(0),
@@ -487,6 +479,10 @@ void LLPipeline::init()
 	{
 		clearAllRenderTypes();
 	}
+	else if (gNonInteractive)
+	{
+		clearAllRenderTypes();
+	}
 	else
 	{
 		setAllRenderTypes(); // By default, all rendering types start enabled
@@ -541,7 +537,6 @@ void LLPipeline::init()
 	connectRefreshCachedSettingsSafe("RenderAvatarMaxNonImpostors");
 	connectRefreshCachedSettingsSafe("RenderDelayVBUpdate");
 	connectRefreshCachedSettingsSafe("UseOcclusion");
-	connectRefreshCachedSettingsSafe("RenderAvatarVP");
 	connectRefreshCachedSettingsSafe("WindLightUseAtmosShaders");
 	connectRefreshCachedSettingsSafe("RenderDeferred");
 	connectRefreshCachedSettingsSafe("RenderDeferredSunWash");
@@ -725,8 +720,6 @@ void LLPipeline::destroyGL()
 	}
 }
 
-static LLTrace::BlockTimerStatHandle FTM_RESIZE_SCREEN_TEXTURE("Resize Screen Texture");
-
 void LLPipeline::requestResizeScreenTexture()
 {
     gResizeScreenTexture = TRUE;
@@ -746,8 +739,7 @@ void LLPipeline::resizeShadowTexture()
 
 void LLPipeline::resizeScreenTexture()
 {
-	LL_RECORD_BLOCK_TIME(FTM_RESIZE_SCREEN_TEXTURE);
-	if (gPipeline.canUseVertexShaders() && assertInitialized())
+	if (gPipeline.shadersLoaded())
 	{
 		GLuint resX = gViewerWindow->getWorldViewWidthRaw();
 		GLuint resY = gViewerWindow->getWorldViewHeightRaw();
@@ -758,8 +750,8 @@ void LLPipeline::resizeScreenTexture()
             releaseShadowTargets();
 		    allocateScreenBuffer(resX,resY);
             gResizeScreenTexture = FALSE;
-				}
-			}
+		}
+	}
 }
 
 void LLPipeline::allocatePhysicsBuffer()
@@ -900,7 +892,7 @@ bool LLPipeline::allocateScreenBuffer(U32 resX, U32 resY, U32 samples)
 		if (!addDeferredAttachments(mDeferredScreen)) return false;
 	
 		GLuint screenFormat = GL_RGBA16;
-		if (gGLManager.mIsATI)
+		if (gGLManager.mIsAMD)
 		{
 			screenFormat = GL_RGBA12;
 		}
@@ -1054,8 +1046,6 @@ void LLPipeline::updateRenderDeferred()
                       RenderDeferred &&
                       LLRenderTarget::sUseFBO &&
                       LLPipeline::sRenderBump &&
-                      LLPipeline::sRenderTransparentWater &&
-                      RenderAvatarVP &&
                       WindLightUseAtmosShaders &&
                       (bool) LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferred");
 }
@@ -1072,12 +1062,10 @@ void LLPipeline::refreshCachedSettings()
 
 	LLPipeline::sUseOcclusion = 
 			(!gUseWireframe
-			&& LLGLSLShader::sNoFixedFunction
 			&& LLFeatureManager::getInstance()->isFeatureAvailable("UseOcclusion") 
 			&& gSavedSettings.getBOOL("UseOcclusion") 
 			&& gGLManager.mHasOcclusionQuery) ? 2 : 0;
 	
-	RenderAvatarVP = gSavedSettings.getBOOL("RenderAvatarVP");
 	WindLightUseAtmosShaders = gSavedSettings.getBOOL("WindLightUseAtmosShaders");
 	RenderDeferred = gSavedSettings.getBOOL("RenderDeferred");
 	RenderDeferredSunWash = gSavedSettings.getF32("RenderDeferredSunWash");
@@ -1153,6 +1141,12 @@ void LLPipeline::refreshCachedSettings()
 	RenderAutoHideSurfaceAreaLimit = gSavedSettings.getF32("RenderAutoHideSurfaceAreaLimit");
 	RenderSpotLight = nullptr;
 	updateRenderDeferred();
+
+	if (gNonInteractive)
+	{
+		LLVOAvatar::sMaxNonImpostors = 1;
+		LLVOAvatar::updateImpostorRendering(LLVOAvatar::sMaxNonImpostors);
+	}
 }
 
 void LLPipeline::releaseGLBuffers()
@@ -1232,7 +1226,8 @@ void LLPipeline::releaseShadowTargets()
 
 void LLPipeline::createGLBuffers()
 {
-	stop_glerror();
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
+    stop_glerror();
 	assertInitialized();
 
 	updateRenderDeferred();
@@ -1370,10 +1365,7 @@ void LLPipeline::restoreGL()
 {
 	assertInitialized();
 
-	if (mVertexShadersEnabled)
-	{
-		LLViewerShaderMgr::instance()->setShaders();
-	}
+	LLViewerShaderMgr::instance()->setShaders();
 
 	for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); 
 			iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
@@ -1385,31 +1377,19 @@ void LLPipeline::restoreGL()
 			if (part)
 			{
 				part->restoreGL();
-			}
+		}
 		}
 	}
 }
 
-
-bool LLPipeline::canUseVertexShaders()
+bool LLPipeline::shadersLoaded()
 {
-	if (sDisableShaders ||
-		!gGLManager.mHasVertexShader ||
-		!gGLManager.mHasFragmentShader ||
-		(assertInitialized() && mVertexShadersLoaded != 1) )
-	{
-		return false;
-	}
-	else
-	{
-		return true;
-	}
+    return (assertInitialized() && mShadersLoaded);
 }
 
 bool LLPipeline::canUseWindLightShaders() const
 {
-	return (!LLPipeline::sDisableShaders &&
-			gWLSkyProgram.mProgramObject != 0 &&
+	return (gWLSkyProgram.mProgramObject != 0 &&
 			LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_WINDLIGHT) > 1);
 }
 
@@ -1427,8 +1407,7 @@ bool LLPipeline::canUseAntiAliasing() const
 void LLPipeline::unloadShaders()
 {
 	LLViewerShaderMgr::instance()->unloadShaders();
-
-	mVertexShadersLoaded = 0;
+	mShadersLoaded = false;
 }
 
 void LLPipeline::assertInitializedDoError()
@@ -1514,6 +1493,7 @@ class LLOctreeDirtyTexture : public OctreeTraveler
 // Called when a texture changes # of channels (causes faces to move to alpha pool)
 void LLPipeline::dirtyPoolObjectTextures(const std::set<LLViewerFetchedTexture*>& textures)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
 	assertInitialized();
 
 	// *TODO: This is inefficient and causes frame spikes; need a better way to do this
@@ -1725,15 +1705,9 @@ void LLPipeline::allocDrawable(LLViewerObject *vobj)
 }
 
 
-static LLTrace::BlockTimerStatHandle FTM_UNLINK("Unlink");
-static LLTrace::BlockTimerStatHandle FTM_REMOVE_FROM_MOVE_LIST("Movelist");
-static LLTrace::BlockTimerStatHandle FTM_REMOVE_FROM_SPATIAL_PARTITION("Spatial Partition");
-static LLTrace::BlockTimerStatHandle FTM_REMOVE_FROM_LIGHT_SET("Light Set");
-static LLTrace::BlockTimerStatHandle FTM_REMOVE_FROM_HIGHLIGHT_SET("Highlight Set");
-
 void LLPipeline::unlinkDrawable(LLDrawable *drawable)
 {
-	LL_RECORD_BLOCK_TIME(FTM_UNLINK);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
 
 	assertInitialized();
 
@@ -1742,7 +1716,6 @@ void LLPipeline::unlinkDrawable(LLDrawable *drawable)
 	// Based on flags, remove the drawable from the queues that it's on.
 	if (drawablep->isState(LLDrawable::ON_MOVE_LIST))
 	{
-		LL_RECORD_BLOCK_TIME(FTM_REMOVE_FROM_MOVE_LIST);
 		LLDrawable::drawable_vector_t::iterator iter = std::find(mMovedList.begin(), mMovedList.end(), drawablep);
 		if (iter != mMovedList.end())
 		{
@@ -1752,7 +1725,6 @@ void LLPipeline::unlinkDrawable(LLDrawable *drawable)
 
 	if (drawablep->getSpatialGroup())
 	{
-		LL_RECORD_BLOCK_TIME(FTM_REMOVE_FROM_SPATIAL_PARTITION);
 		if (!drawablep->getSpatialGroup()->getSpatialPartition()->remove(drawablep, drawablep->getSpatialGroup()))
 		{
 #ifdef LL_RELEASE_FOR_DOWNLOAD
@@ -1763,30 +1735,24 @@ void LLPipeline::unlinkDrawable(LLDrawable *drawable)
 		}
 	}
 
-	{
-		LL_RECORD_BLOCK_TIME(FTM_REMOVE_FROM_LIGHT_SET);
-		mLights.erase(drawablep);
+	mLights.erase(drawablep);
 
-		for (light_set_t::iterator iter = mNearbyLights.begin();
-					iter != mNearbyLights.end(); iter++)
+	for (light_set_t::iterator iter = mNearbyLights.begin();
+				iter != mNearbyLights.end(); iter++)
+	{
+		if (iter->drawable == drawablep)
 		{
-			if (iter->drawable == drawablep)
-			{
-				mNearbyLights.erase(iter);
-				break;
-			}
+			mNearbyLights.erase(iter);
+			break;
 		}
 	}
 
-	{
-		LL_RECORD_BLOCK_TIME(FTM_REMOVE_FROM_HIGHLIGHT_SET);
-		HighlightItem item(drawablep);
-		mHighlightSet.erase(item);
+	HighlightItem item(drawablep);
+	mHighlightSet.erase(item);
 
-		if (mHighlightObject == drawablep)
-		{
-			mHighlightObject = NULL;
-		}
+	if (mHighlightObject == drawablep)
+	{
+		mHighlightObject = NULL;
 	}
 
 	for (U32 i = 0; i < 2; ++i)
@@ -1801,14 +1767,12 @@ void LLPipeline::unlinkDrawable(LLDrawable *drawable)
 			mTargetShadowSpotLight[i] = NULL;
 		}
 	}
-
-
 }
 
 //static
 void LLPipeline::removeMutedAVsLights(LLVOAvatar* muted_avatar)
 {
-	LL_RECORD_BLOCK_TIME(FTM_REMOVE_FROM_LIGHT_SET);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
 	for (light_set_t::iterator iter = gPipeline.mNearbyLights.begin();
 		 iter != gPipeline.mNearbyLights.end(); iter++)
 	{
@@ -1836,7 +1800,7 @@ U32 LLPipeline::addObject(LLViewerObject *vobj)
 
 void LLPipeline::createObjects(F32 max_dtime)
 {
-	LL_RECORD_BLOCK_TIME(FTM_PIPELINE_CREATE);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
 
 	LLTimer update_timer;
 
@@ -1860,6 +1824,7 @@ void LLPipeline::createObjects(F32 max_dtime)
 
 void LLPipeline::createObject(LLViewerObject* vobj)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
 	LLDrawable* drawablep = vobj->mDrawable;
 
 	if (!drawablep)
@@ -1897,6 +1862,7 @@ void LLPipeline::createObject(LLViewerObject* vobj)
 
 void LLPipeline::resetFrameStats()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
 	assertInitialized();
 
 	sCompiles        = 0;
@@ -1912,6 +1878,7 @@ void LLPipeline::resetFrameStats()
 //external functions for asynchronous updating
 void LLPipeline::updateMoveDampedAsync(LLDrawable* drawablep)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	if (FreezeTime)
 	{
 		return;
@@ -1942,6 +1909,7 @@ void LLPipeline::updateMoveDampedAsync(LLDrawable* drawablep)
 
 void LLPipeline::updateMoveNormalAsync(LLDrawable* drawablep)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	if (FreezeTime)
 	{
 		return;
@@ -1972,6 +1940,7 @@ void LLPipeline::updateMoveNormalAsync(LLDrawable* drawablep)
 
 void LLPipeline::updateMovedList(LLDrawable::drawable_vector_t& moved_list)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	for (LLDrawable::drawable_vector_t::iterator iter = moved_list.begin();
 		 iter != moved_list.end(); )
 	{
@@ -2005,14 +1974,9 @@ void LLPipeline::updateMovedList(LLDrawable::drawable_vector_t& moved_list)
 	}
 }
 
-static LLTrace::BlockTimerStatHandle FTM_OCTREE_BALANCE("Balance Octree");
-static LLTrace::BlockTimerStatHandle FTM_UPDATE_MOVE("Update Move");
-static LLTrace::BlockTimerStatHandle FTM_RETEXTURE("Retexture");
-static LLTrace::BlockTimerStatHandle FTM_MOVED_LIST("Moved List");
-
 void LLPipeline::updateMove()
 {
-	LL_RECORD_BLOCK_TIME(FTM_UPDATE_MOVE);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
 
 	if (FreezeTime)
 	{
@@ -2021,49 +1985,38 @@ void LLPipeline::updateMove()
 
 	assertInitialized();
 
+	for (LLDrawable::drawable_set_t::iterator iter = mRetexturedList.begin();
+			iter != mRetexturedList.end(); ++iter)
 	{
-		LL_RECORD_BLOCK_TIME(FTM_RETEXTURE);
-
-		for (LLDrawable::drawable_set_t::iterator iter = mRetexturedList.begin();
-			 iter != mRetexturedList.end(); ++iter)
+		LLDrawable* drawablep = *iter;
+		if (drawablep && !drawablep->isDead())
 		{
-			LLDrawable* drawablep = *iter;
-			if (drawablep && !drawablep->isDead())
-			{
-				drawablep->updateTexture();
-			}
+			drawablep->updateTexture();
 		}
-		mRetexturedList.clear();
 	}
+	mRetexturedList.clear();
 
-	{
-		LL_RECORD_BLOCK_TIME(FTM_MOVED_LIST);
-		updateMovedList(mMovedList);
-	}
+	updateMovedList(mMovedList);
 
 	//balance octrees
+	for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); 
+		iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
 	{
- 		LL_RECORD_BLOCK_TIME(FTM_OCTREE_BALANCE);
-
-		for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); 
-			iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
+		LLViewerRegion* region = *iter;
+		for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++)
 		{
-			LLViewerRegion* region = *iter;
-			for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++)
+			LLSpatialPartition* part = region->getSpatialPartition(i);
+			if (part)
 			{
-				LLSpatialPartition* part = region->getSpatialPartition(i);
-				if (part)
-				{
-					part->mOctree->balance();
-				}
+				part->mOctree->balance();
 			}
+		}
 
-			//balance the VO Cache tree
-			LLVOCachePartition* vo_part = region->getVOCachePartition();
-			if(vo_part)
-			{
-				vo_part->mOctree->balance();
-			}
+		//balance the VO Cache tree
+		LLVOCachePartition* vo_part = region->getVOCachePartition();
+		if(vo_part)
+		{
+			vo_part->mOctree->balance();
 		}
 	}
 }
@@ -2125,6 +2078,7 @@ void LLPipeline::grabReferences(LLCullResult& result)
 
 void LLPipeline::clearReferences()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
 	sCull = NULL;
 	mGroupSaveQ1.clear();
 }
@@ -2372,20 +2326,28 @@ bool LLPipeline::getVisibleExtents(LLCamera& camera, LLVector3& min, LLVector3&
 
 static LLTrace::BlockTimerStatHandle FTM_CULL("Object Culling");
 
-void LLPipeline::updateCull(LLCamera& camera, LLCullResult& result, S32 water_clip, LLPlane* planep)
+void LLPipeline::updateCull(LLCamera& camera, LLCullResult& result, LLPlane* planep)
 {
 	static LLCachedControl<bool> use_occlusion(gSavedSettings,"UseOcclusion");
-	static bool can_use_occlusion = LLGLSLShader::sNoFixedFunction
-									&& LLFeatureManager::getInstance()->isFeatureAvailable("UseOcclusion") 
+	static bool can_use_occlusion = LLFeatureManager::getInstance()->isFeatureAvailable("UseOcclusion") 
 									&& gGLManager.mHasOcclusionQuery;
 
-	LL_RECORD_BLOCK_TIME(FTM_CULL);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE; //LL_RECORD_BLOCK_TIME(FTM_CULL);
+
+    if (planep != nullptr)
+    {
+        camera.setUserClipPlane(*planep);
+    }
+    else
+    {
+        camera.disableUserClipPlane();
+    }
 
 	grabReferences(result);
 
 	sCull->clear();
 
-	bool to_texture = LLPipeline::sUseOcclusion > 1 && gPipeline.canUseVertexShaders();
+	bool to_texture = LLPipeline::sUseOcclusion > 1 && gPipeline.shadersLoaded();
 
 	if (to_texture)
 	{
@@ -2419,7 +2381,7 @@ void LLPipeline::updateCull(LLCamera& camera, LLCullResult& result, S32 water_cl
 	LLGLDepthTest depth(GL_TRUE, GL_FALSE);
 
 	bool bound_shader = false;
-	if (gPipeline.canUseVertexShaders() && LLGLSLShader::sCurBoundShader == 0)
+	if (gPipeline.shadersLoaded() && LLGLSLShader::sCurBoundShader == 0)
 	{ //if no shader is currently bound, use the occlusion shader instead of fixed function if we can
 		// (shadow render uses a special shader that clamps to clip planes)
 		bound_shader = true;
@@ -2435,11 +2397,6 @@ void LLPipeline::updateCull(LLCamera& camera, LLCullResult& result, S32 water_cl
 		mCubeVB->setBuffer(LLVertexBuffer::MAP_VERTEX);
 	}
 	
-    if (!sReflectionRender)
-    {
-        camera.disableUserClipPlane();
-    }
-
 	for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); 
 			iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
 	{
@@ -2461,8 +2418,7 @@ void LLPipeline::updateCull(LLCamera& camera, LLCullResult& result, S32 water_cl
 		LLVOCachePartition* vo_part = region->getVOCachePartition();
 		if(vo_part)
 		{
-			bool do_occlusion_cull = can_use_occlusion && use_occlusion && !gUseWireframe && 0 > water_clip /* && !gViewerWindow->getProgressView()->getVisible()*/;
-            do_occlusion_cull &= !sReflectionRender;
+            bool do_occlusion_cull = can_use_occlusion && use_occlusion && !gUseWireframe;
 			vo_part->cull(camera, do_occlusion_cull);
 		}
 	}
@@ -2546,20 +2502,6 @@ void LLPipeline::markNotCulled(LLSpatialGroup* group, LLCamera& camera)
 		group->updateDistance(camera);
 	}
 	
-	const F32 MINIMUM_PIXEL_AREA = 16.f;
-
-	if (group->mPixelArea < MINIMUM_PIXEL_AREA)
-	{
-		return;
-	}
-
-	const LLVector4a* bounds = group->getBounds();
-	if (sMinRenderSize > 0.f && 
-			llmax(llmax(bounds[1][0], bounds[1][1]), bounds[1][2]) < sMinRenderSize)
-	{
-		return;
-	}
-
 	assertInitialized();
 	
 	if (!group->getSpatialPartition()->mRenderByGroup)
@@ -2669,7 +2611,8 @@ void LLPipeline::doOcclusion(LLCamera& camera, LLRenderTarget& source, LLRenderT
 
 void LLPipeline::doOcclusion(LLCamera& camera)
 {
-	if (LLPipeline::sUseOcclusion > 1 && !LLSpatialPartition::sTeleportRequested && 
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
+    if (LLPipeline::sUseOcclusion > 1 && !LLSpatialPartition::sTeleportRequested &&
 		(sCull->hasOcclusionGroups() || LLVOCachePartition::sNeedsOcclusionCheck))
 	{
 		LLVertexBuffer::unbind();
@@ -2690,7 +2633,7 @@ void LLPipeline::doOcclusion(LLCamera& camera)
 		LLGLDisable cull(GL_CULL_FACE);
 
 		
-		bool bind_shader = LLGLSLShader::sNoFixedFunction && LLGLSLShader::sCurBoundShader == 0;
+		bool bind_shader = (LLGLSLShader::sCurBoundShader == 0);
 		if (bind_shader)
 		{
 			if (LLPipeline::sShadowRender)
@@ -2753,14 +2696,10 @@ bool LLPipeline::updateDrawableGeom(LLDrawable* drawablep, bool priority)
 	return update_complete;
 }
 
-static LLTrace::BlockTimerStatHandle FTM_SEED_VBO_POOLS("Seed VBO Pool");
-
-static LLTrace::BlockTimerStatHandle FTM_UPDATE_GL("Update GL");
-
 void LLPipeline::updateGL()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
 	{
-		LL_RECORD_BLOCK_TIME(FTM_UPDATE_GL);
 		while (!LLGLUpdate::sGLQ.empty())
 		{
 			LLGLUpdate* glu = LLGLUpdate::sGLQ.front();
@@ -2771,15 +2710,13 @@ void LLPipeline::updateGL()
 	}
 
 	{ //seed VBO Pools
-		LL_RECORD_BLOCK_TIME(FTM_SEED_VBO_POOLS);
 		LLVertexBuffer::seedPools();
 	}
 }
 
-static LLTrace::BlockTimerStatHandle FTM_REBUILD_PRIORITY_GROUPS("Rebuild Priority Groups");
-
 void LLPipeline::clearRebuildGroups()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
 	LLSpatialGroup::sg_vector_t	hudGroups;
 
 	mGroupQ1Locked = true;
@@ -2884,7 +2821,7 @@ void LLPipeline::clearRebuildDrawables()
 
 void LLPipeline::rebuildPriorityGroups()
 {
-	LL_RECORD_BLOCK_TIME(FTM_REBUILD_PRIORITY_GROUPS);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
 	LLTimer update_timer;
 	assertInitialized();
 
@@ -2906,8 +2843,6 @@ void LLPipeline::rebuildPriorityGroups()
 
 }
 
-static LLTrace::BlockTimerStatHandle FTM_REBUILD_GROUPS("Rebuild Groups");
-
 void LLPipeline::rebuildGroups()
 {
 	if (mGroupQ2.empty())
@@ -2915,7 +2850,7 @@ void LLPipeline::rebuildGroups()
 		return;
 	}
 
-	LL_RECORD_BLOCK_TIME(FTM_REBUILD_GROUPS);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
 	mGroupQ2Locked = true;
 	// Iterate through some drawables on the non-priority build queue
 	S32 size = (S32) mGroupQ2.size();
@@ -3161,12 +3096,9 @@ void LLPipeline::markShift(LLDrawable *drawablep)
 	}
 }
 
-static LLTrace::BlockTimerStatHandle FTM_SHIFT_DRAWABLE("Shift Drawable");
-static LLTrace::BlockTimerStatHandle FTM_SHIFT_OCTREE("Shift Octree");
-static LLTrace::BlockTimerStatHandle FTM_SHIFT_HUD("Shift HUD");
-
 void LLPipeline::shiftObjects(const LLVector3 &offset)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
 	assertInitialized();
 
 	glClear(GL_DEPTH_BUFFER_BIT);
@@ -3175,46 +3107,36 @@ void LLPipeline::shiftObjects(const LLVector3 &offset)
 	LLVector4a offseta;
 	offseta.load3(offset.mV);
 
+	for (LLDrawable::drawable_vector_t::iterator iter = mShiftList.begin();
+			iter != mShiftList.end(); iter++)
 	{
-		LL_RECORD_BLOCK_TIME(FTM_SHIFT_DRAWABLE);
-
-		for (LLDrawable::drawable_vector_t::iterator iter = mShiftList.begin();
-			 iter != mShiftList.end(); iter++)
+		LLDrawable *drawablep = *iter;
+		if (drawablep->isDead())
 		{
-			LLDrawable *drawablep = *iter;
-			if (drawablep->isDead())
-			{
-				continue;
-			}	
-			drawablep->shiftPos(offseta);	
-			drawablep->clearState(LLDrawable::ON_SHIFT_LIST);
-		}
-		mShiftList.resize(0);
+			continue;
+		}	
+		drawablep->shiftPos(offseta);	
+		drawablep->clearState(LLDrawable::ON_SHIFT_LIST);
 	}
-
+	mShiftList.resize(0);
 	
+	for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); 
+			iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
 	{
-		LL_RECORD_BLOCK_TIME(FTM_SHIFT_OCTREE);
-		for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); 
-				iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
+		LLViewerRegion* region = *iter;
+		for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++)
 		{
-			LLViewerRegion* region = *iter;
-			for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++)
+			LLSpatialPartition* part = region->getSpatialPartition(i);
+			if (part)
 			{
-				LLSpatialPartition* part = region->getSpatialPartition(i);
-				if (part)
-				{
-					part->shift(offseta);
-				}
+				part->shift(offseta);
 			}
 		}
 	}
 
-	{
-		LL_RECORD_BLOCK_TIME(FTM_SHIFT_HUD);
-		LLHUDText::shiftAll(offset);
-		LLHUDNameTag::shiftAll(offset);
-	}
+	LLHUDText::shiftAll(offset);
+	LLHUDNameTag::shiftAll(offset);
+
 	display_update_camera();
 }
 
@@ -3245,10 +3167,9 @@ void LLPipeline::markPartitionMove(LLDrawable* drawable)
 	}
 }
 
-static LLTrace::BlockTimerStatHandle FTM_PROCESS_PARTITIONQ("PartitionQ");
 void LLPipeline::processPartitionQ()
 {
-	LL_RECORD_BLOCK_TIME(FTM_PROCESS_PARTITIONQ);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
 	for (LLDrawable::drawable_list_t::iterator iter = mPartitionQ.begin(); iter != mPartitionQ.end(); ++iter)
 	{
 		LLDrawable* drawable = *iter;
@@ -3348,10 +3269,10 @@ void LLPipeline::markRebuild(LLDrawable *drawablep, LLDrawable::EDrawableFlags f
 	}
 }
 
-static LLTrace::BlockTimerStatHandle FTM_RESET_DRAWORDER("Reset Draw Order");
-
 void LLPipeline::stateSort(LLCamera& camera, LLCullResult &result)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
+
 	if (hasAnyRenderType(LLPipeline::RENDER_TYPE_AVATAR,
 					  LLPipeline::RENDER_TYPE_CONTROL_AV,
 					  LLPipeline::RENDER_TYPE_GROUND,
@@ -3363,12 +3284,9 @@ void LLPipeline::stateSort(LLCamera& camera, LLCullResult &result)
 					  LLPipeline::END_RENDER_TYPES))
 	{
 		//clear faces from face pools
-		LL_RECORD_BLOCK_TIME(FTM_RESET_DRAWORDER);
 		gPipeline.resetDrawOrders();
 	}
 
-	LL_RECORD_BLOCK_TIME(FTM_STATESORT);
-
 	//LLVertexBuffer::unbind();
 
 	grabReferences(result);
@@ -3453,7 +3371,7 @@ void LLPipeline::stateSort(LLCamera& camera, LLCullResult &result)
 	}
 	
 	{
-		LL_RECORD_BLOCK_TIME(FTM_STATESORT_DRAWABLE);
+		LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWABLE("stateSort"); // LL_RECORD_BLOCK_TIME(FTM_STATESORT_DRAWABLE);
 		for (LLCullResult::drawable_iterator iter = sCull->beginVisibleList();
 			 iter != sCull->endVisibleList(); ++iter)
 		{
@@ -3483,12 +3401,12 @@ void LLPipeline::stateSort(LLSpatialGroup* group, LLCamera& camera)
 			group->mLastUpdateDistance = group->mDistance;
 		}
 	}
-
 }
 
 void LLPipeline::stateSort(LLSpatialBridge* bridge, LLCamera& camera, BOOL fov_changed)
 {
-	if (bridge->getSpatialGroup()->changeLOD() || fov_changed)
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
+    if (bridge->getSpatialGroup()->changeLOD() || fov_changed)
 	{
 		bool force_update = false;
 		bridge->updateDistance(camera, force_update);
@@ -3497,7 +3415,8 @@ void LLPipeline::stateSort(LLSpatialBridge* bridge, LLCamera& camera, BOOL fov_c
 
 void LLPipeline::stateSort(LLDrawable* drawablep, LLCamera& camera)
 {
-	if (!drawablep
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
+    if (!drawablep
 		|| drawablep->isDead() 
 		|| !hasRenderType(drawablep->getRenderType()))
 	{
@@ -3790,9 +3709,36 @@ void renderSoundHighlights(LLDrawable* drawablep)
 }
 }
 
+void LLPipeline::touchTexture(LLViewerTexture* tex, F32 vsize)
+{
+    if (tex)
+    {
+        LLImageGL* gl_tex = tex->getGLTexture();
+        if (gl_tex && gl_tex->updateBindStats(gl_tex->mTextureMemory))
+        {
+            tex->setActive();
+            tex->addTextureStats(vsize);
+        }
+    }
+
+
+}
+void LLPipeline::touchTextures(LLDrawInfo* info)
+{
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
+    for (int i = 0; i < info->mTextureList.size(); ++i)
+    {
+        touchTexture(info->mTextureList[i], info->mTextureListVSize[i]);
+    }
+
+    touchTexture(info->mTexture, info->mVSize);
+    touchTexture(info->mSpecularMap, info->mVSize);
+    touchTexture(info->mNormalMap, info->mVSize);
+}
+
 void LLPipeline::postSort(LLCamera& camera)
 {
-	LL_RECORD_BLOCK_TIME(FTM_STATESORT_POSTSORT);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
 
 	assertInitialized();
 
@@ -3842,20 +3788,14 @@ void LLPipeline::postSort(LLCamera& camera)
 			
 			for (LLSpatialGroup::drawmap_elem_t::iterator k = src_vec.begin(); k != src_vec.end(); ++k)
 			{
-				if (sMinRenderSize > 0.f)
-				{
-					LLVector4a bounds;
-					bounds.setSub((*k)->mExtents[1],(*k)->mExtents[0]);
-
-					if (llmax(llmax(bounds[0], bounds[1]), bounds[2]) > sMinRenderSize)
-					{
-						sCull->pushDrawInfo(j->first, *k);
-					}
-				}
-				else
-				{
-					sCull->pushDrawInfo(j->first, *k);
-				}
+                LLDrawInfo* info = *k;
+				
+				sCull->pushDrawInfo(j->first, info);
+                if (!sShadowRender && !sReflectionRender)
+                {
+                    touchTextures(info);
+                    addTrianglesDrawn(info->mCount, info->mDrawMode);
+                }
 			}
 		}
 
@@ -3884,6 +3824,16 @@ void LLPipeline::postSort(LLCamera& camera)
 					sCull->pushAlphaGroup(group);
 				}
 			}
+
+            LLSpatialGroup::draw_map_t::iterator rigged_alpha = group->mDrawMap.find(LLRenderPass::PASS_ALPHA_RIGGED);
+
+            if (rigged_alpha != group->mDrawMap.end())
+            { //store rigged alpha groups for LLDrawPoolAlpha prepass (skip distance update, rigged attachments use depth buffer)
+                if (hasRenderType(LLDrawPool::POOL_ALPHA))
+                {
+                    sCull->pushRiggedAlphaGroup(group);
+                }
+            }
 		}
 	}
 	
@@ -3927,7 +3877,11 @@ void LLPipeline::postSort(LLCamera& camera)
 
 	if (!sShadowRender)
 	{
+        // order alpha groups by distance
 		std::sort(sCull->beginAlphaGroups(), sCull->endAlphaGroups(), LLSpatialGroup::CompareDepthGreater());
+
+        // order rigged alpha groups by avatar attachment order
+        std::sort(sCull->beginRiggedAlphaGroups(), sCull->endRiggedAlphaGroups(), LLSpatialGroup::CompareRenderOrder());
 	}
 
 	LL_PUSH_CALLSTACKS();
@@ -3985,7 +3939,7 @@ void LLPipeline::postSort(LLCamera& camera)
 	}
 	LL_PUSH_CALLSTACKS();
 	// If managing your telehub, draw beacons at telehub and currently selected spawnpoint.
-	if (LLFloaterTelehub::renderBeacons())
+	if (LLFloaterTelehub::renderBeacons() && !sShadowRender)
 	{
 		LLFloaterTelehub::addBeacons();
 	}
@@ -3994,7 +3948,10 @@ void LLPipeline::postSort(LLCamera& camera)
 	{
 		mSelectedFaces.clear();
 
-		LLPipeline::setRenderHighlightTextureChannel(gFloaterTools->getPanelFace()->getTextureChannelToEdit());
+		if (!gNonInteractive)
+		{
+			LLPipeline::setRenderHighlightTextureChannel(gFloaterTools->getPanelFace()->getTextureChannelToEdit());
+		}
 
 		// Draw face highlights for selected faces.
 		if (LLSelectMgr::getInstance()->getTEMode())
@@ -4025,8 +3982,8 @@ void LLPipeline::postSort(LLCamera& camera)
 
 void render_hud_elements()
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_UI);
-	gPipeline.disableLights();		
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; //LL_RECORD_BLOCK_TIME(FTM_RENDER_UI);
+	gPipeline.disableLights();
 	
 	LLGLDisable fog(GL_FOG);
 	LLGLSUIDefault gls_ui;
@@ -4038,10 +3995,7 @@ void render_hud_elements()
 	
 	gGL.color4f(1,1,1,1);
 	
-	if (LLGLSLShader::sNoFixedFunction)
-	{
-		gUIProgram.bind();
-	}
+	gUIProgram.bind();
 	LLGLDepthTest depth(GL_TRUE, GL_FALSE);
 
 	if (!LLPipeline::sReflectionRender && gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
@@ -4052,8 +4006,11 @@ void render_hud_elements()
 		// Draw the tracking overlays
 		LLTracker::render3D();
 		
-		// Show the property lines
-		LLWorld::getInstance()->renderPropertyLines();
+        if (LLWorld::instanceExists())
+        {
+            // Show the property lines
+            LLWorld::getInstance()->renderPropertyLines();
+        }
 		LLViewerParcelMgr::getInstance()->render();
 		LLViewerParcelMgr::getInstance()->renderParcelCollision();
 	
@@ -4070,10 +4027,7 @@ void render_hud_elements()
 		LLHUDText::renderAllHUD();
 	}
 
-	if (LLGLSLShader::sNoFixedFunction)
-	{
-		gUIProgram.unbind();
-	}
+	gUIProgram.unbind();
 	gGL.flush();
 }
 
@@ -4105,10 +4059,7 @@ void LLPipeline::renderHighlights()
 
 		gGL.setColorMask(false, false);
 
-        if (LLGLSLShader::sNoFixedFunction)
-        {
-            gHighlightProgram.bind();
-        }
+        gHighlightProgram.bind();
 
 		for (std::set<HighlightItem>::iterator iter = mHighlightSet.begin(); iter != mHighlightSet.end(); ++iter)
 		{
@@ -4310,7 +4261,7 @@ U32 LLPipeline::sCurRenderPoolType = 0 ;
 
 void LLPipeline::renderGeom(LLCamera& camera, bool forceVBOUpdate)
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_GEOMETRY);
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE; //LL_RECORD_BLOCK_TIME(FTM_RENDER_GEOMETRY);
 
 	assertInitialized();
 
@@ -4340,7 +4291,6 @@ void LLPipeline::renderGeom(LLCamera& camera, bool forceVBOUpdate)
 	// Do verification of GL state
 	LLGLState::checkStates();
 	LLGLState::checkTextureChannels();
-	LLGLState::checkClientArrays();
 	if (mRenderDebugMask & RENDER_DEBUG_VERIFY)
 	{
 		if (!verify())
@@ -4397,7 +4347,7 @@ void LLPipeline::renderGeom(LLCamera& camera, bool forceVBOUpdate)
 	}
 
 	{
-		LL_RECORD_BLOCK_TIME(FTM_POOLS);
+		LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWPOOL("pools"); //LL_RECORD_BLOCK_TIME(FTM_POOLS);
 		
 		// HACK: don't calculate local lights if we're rendering the HUD!
 		//    Removing this check will cause bad flickering when there are 
@@ -4433,7 +4383,7 @@ void LLPipeline::renderGeom(LLCamera& camera, bool forceVBOUpdate)
 			pool_set_t::iterator iter2 = iter1;
 			if (hasRenderType(poolp->getType()) && poolp->getNumPasses() > 0)
 			{
-				LL_RECORD_BLOCK_TIME(FTM_POOLRENDER);
+				LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWPOOL("pool render"); //LL_RECORD_BLOCK_TIME(FTM_POOLRENDER);
 
 				gGLLastMatrix = NULL;
 				gGL.loadMatrix(gGLModelView);
@@ -4563,98 +4513,104 @@ void LLPipeline::renderGeomDeferred(LLCamera& camera)
 {
 	LLAppViewer::instance()->pingMainloopTimeout("Pipeline:RenderGeomDeferred");
 
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_GEOMETRY);
-
-	LL_RECORD_BLOCK_TIME(FTM_DEFERRED_POOLS);
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_GEOMETRY);
+	{
+		// SL-15709 -- NOTE: Tracy only allows one ZoneScoped per function.
+		// Solutions are:
+		// 1. Use a new scope
+		// 2. Use named zones
+		// 3. Use transient zones
+		LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWPOOL("deferred pools"); //LL_RECORD_BLOCK_TIME(FTM_DEFERRED_POOLS);
 
-	LLGLEnable cull(GL_CULL_FACE);
+		LLGLEnable cull(GL_CULL_FACE);
 
-	for (pool_set_t::iterator iter = mPools.begin(); iter != mPools.end(); ++iter)
-	{
-		LLDrawPool *poolp = *iter;
-		if (hasRenderType(poolp->getType()))
+		for (pool_set_t::iterator iter = mPools.begin(); iter != mPools.end(); ++iter)
 		{
-			poolp->prerender();
+			LLDrawPool *poolp = *iter;
+			if (hasRenderType(poolp->getType()))
+			{
+				poolp->prerender();
+			}
 		}
-	}
 
-	LLGLEnable multisample(RenderFSAASamples > 0 ? GL_MULTISAMPLE_ARB : 0);
+		LLGLEnable multisample(RenderFSAASamples > 0 ? GL_MULTISAMPLE_ARB : 0);
 
-	LLVertexBuffer::unbind();
+		LLVertexBuffer::unbind();
 
-	LLGLState::checkStates();
-	LLGLState::checkTextureChannels();
-	LLGLState::checkClientArrays();
+		LLGLState::checkStates();
+		LLGLState::checkTextureChannels();
 
-	U32 cur_type = 0;
+		U32 cur_type = 0;
 
-	gGL.setColorMask(true, true);
+		gGL.setColorMask(true, true);
 	
-	pool_set_t::iterator iter1 = mPools.begin();
+		pool_set_t::iterator iter1 = mPools.begin();
 
-	while ( iter1 != mPools.end() )
-	{
-		LLDrawPool *poolp = *iter1;
+		while ( iter1 != mPools.end() )
+		{
+			LLDrawPool *poolp = *iter1;
 		
-		cur_type = poolp->getType();
+			cur_type = poolp->getType();
 
-		pool_set_t::iterator iter2 = iter1;
-		if (hasRenderType(poolp->getType()) && poolp->getNumDeferredPasses() > 0)
-		{
-			LL_RECORD_BLOCK_TIME(FTM_DEFERRED_POOLRENDER);
+			pool_set_t::iterator iter2 = iter1;
+			if (hasRenderType(poolp->getType()) && poolp->getNumDeferredPasses() > 0)
+			{
+				LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWPOOL("deferred pool render"); //LL_RECORD_BLOCK_TIME(FTM_DEFERRED_POOLRENDER);
 
-			gGLLastMatrix = NULL;
-			gGL.loadMatrix(gGLModelView);
+				gGLLastMatrix = NULL;
+				gGL.loadMatrix(gGLModelView);
 		
-			for( S32 i = 0; i < poolp->getNumDeferredPasses(); i++ )
-			{
-				LLVertexBuffer::unbind();
-				poolp->beginDeferredPass(i);
-				for (iter2 = iter1; iter2 != mPools.end(); iter2++)
+				for( S32 i = 0; i < poolp->getNumDeferredPasses(); i++ )
 				{
-					LLDrawPool *p = *iter2;
-					if (p->getType() != cur_type)
+					LLVertexBuffer::unbind();
+					poolp->beginDeferredPass(i);
+					for (iter2 = iter1; iter2 != mPools.end(); iter2++)
 					{
-						break;
+						LLDrawPool *p = *iter2;
+						if (p->getType() != cur_type)
+						{
+							break;
+						}
+
+						if ( !p->getSkipRenderFlag() ) { p->renderDeferred(i); }
 					}
-										
-					if ( !p->getSkipRenderFlag() ) { p->renderDeferred(i); }
-				}
-				poolp->endDeferredPass(i);
-				LLVertexBuffer::unbind();
+					poolp->endDeferredPass(i);
+					LLVertexBuffer::unbind();
 
-				if (gDebugGL || gDebugPipeline)
-				{
-					LLGLState::checkStates();
+					if (gDebugGL || gDebugPipeline)
+					{
+						LLGLState::checkStates();
+					}
 				}
 			}
-		}
-		else
-		{
-			// Skip all pools of this type
-			for (iter2 = iter1; iter2 != mPools.end(); iter2++)
+			else
 			{
-				LLDrawPool *p = *iter2;
-				if (p->getType() != cur_type)
+				// Skip all pools of this type
+				for (iter2 = iter1; iter2 != mPools.end(); iter2++)
 				{
-					break;
+					LLDrawPool *p = *iter2;
+					if (p->getType() != cur_type)
+					{
+						break;
+					}
 				}
 			}
+			iter1 = iter2;
+			stop_glerror();
 		}
-		iter1 = iter2;
-		stop_glerror();
-	}
 
-	gGLLastMatrix = NULL;
-    gGL.matrixMode(LLRender::MM_MODELVIEW);
-	gGL.loadMatrix(gGLModelView);
+		gGLLastMatrix = NULL;
+		gGL.matrixMode(LLRender::MM_MODELVIEW);
+		gGL.loadMatrix(gGLModelView);
 
-	gGL.setColorMask(true, false);
+		gGL.setColorMask(true, false);
+
+	} // Tracy ZoneScoped
 }
 
 void LLPipeline::renderGeomPostDeferred(LLCamera& camera, bool do_occlusion)
 {
-	LL_RECORD_BLOCK_TIME(FTM_POST_DEFERRED_POOLS);
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_POST_DEFERRED_POOLS);
 	U32 cur_type = 0;
 
 	LLGLEnable cull(GL_CULL_FACE);
@@ -4688,7 +4644,7 @@ void LLPipeline::renderGeomPostDeferred(LLCamera& camera, bool do_occlusion)
 		pool_set_t::iterator iter2 = iter1;
 		if (hasRenderType(poolp->getType()) && poolp->getNumPostDeferredPasses() > 0)
 		{
-			LL_RECORD_BLOCK_TIME(FTM_POST_DEFERRED_POOLRENDER);
+			LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWPOOL("deferred poolrender"); //LL_RECORD_BLOCK_TIME(FTM_POST_DEFERRED_POOLRENDER);
 
 			gGLLastMatrix = NULL;
 			gGL.loadMatrix(gGLModelView);
@@ -4749,7 +4705,8 @@ void LLPipeline::renderGeomPostDeferred(LLCamera& camera, bool do_occlusion)
 
 void LLPipeline::renderGeomShadow(LLCamera& camera)
 {
-	U32 cur_type = 0;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
+    U32 cur_type = 0;
 	
 	LLGLEnable cull(GL_CULL_FACE);
 
@@ -4814,6 +4771,7 @@ void LLPipeline::renderGeomShadow(LLCamera& camera)
 
 void LLPipeline::addTrianglesDrawn(S32 index_count, U32 render_type)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
 	assertInitialized();
 	S32 count = 0;
 	if (render_type == LLRender::TRIANGLE_STRIP)
@@ -4853,10 +4811,7 @@ void LLPipeline::renderPhysicsDisplay()
 
 	gGL.setColorMask(true, false);
 
-	if (LLGLSLShader::sNoFixedFunction)
-	{
-		gDebugProgram.bind();
-	}
+	gDebugProgram.bind();
 
 	for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); 
 			iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
@@ -4877,11 +4832,7 @@ void LLPipeline::renderPhysicsDisplay()
 
 	gGL.flush();
 
-	if (LLGLSLShader::sNoFixedFunction)
-	{
-		gDebugProgram.unbind();
-	}
-
+	gDebugProgram.unbind();
 	mPhysicsDisplay.flush();
 }
 
@@ -4908,13 +4859,10 @@ void LLPipeline::renderDebug()
 
 				if ( pathfindingCharacter->getVisible() || gAgentCamera.cameraMouselook() )			
 				{	
-					if (LLGLSLShader::sNoFixedFunction)
-					{					
-						gPathfindingProgram.bind();			
-						gPathfindingProgram.uniform1f(sTint, 1.f);
-						gPathfindingProgram.uniform1f(sAmbiance, 1.f);
-						gPathfindingProgram.uniform1f(sAlphaScale, 1.f);
-					}
+					gPathfindingProgram.bind();			
+					gPathfindingProgram.uniform1f(sTint, 1.f);
+					gPathfindingProgram.uniform1f(sAmbiance, 1.f);
+					gPathfindingProgram.uniform1f(sAlphaScale, 1.f);
 
 					//Requried character physics capsule render parameters
 					LLUUID id;					
@@ -4923,21 +4871,14 @@ void LLPipeline::renderDebug()
 				
 					if ( pathfindingCharacter->isPhysicsCapsuleEnabled( id, pos, rot ) )
 					{
-						if (LLGLSLShader::sNoFixedFunction)
-						{					
-							//remove blending artifacts
-							gGL.setColorMask(false, false);
-							llPathingLibInstance->renderSimpleShapeCapsuleID( gGL, id, pos, rot );				
-							gGL.setColorMask(true, false);
-							LLGLEnable blend(GL_BLEND);
-							gPathfindingProgram.uniform1f(sAlphaScale, 0.90f);
-							llPathingLibInstance->renderSimpleShapeCapsuleID( gGL, id, pos, rot );
-							gPathfindingProgram.bind();
-						}
-						else
-						{
-							llPathingLibInstance->renderSimpleShapeCapsuleID( gGL, id, pos, rot );
-						}
+						//remove blending artifacts
+						gGL.setColorMask(false, false);
+						llPathingLibInstance->renderSimpleShapeCapsuleID( gGL, id, pos, rot );				
+						gGL.setColorMask(true, false);
+						LLGLEnable blend(GL_BLEND);
+						gPathfindingProgram.uniform1f(sAlphaScale, 0.90f);
+						llPathingLibInstance->renderSimpleShapeCapsuleID( gGL, id, pos, rot );
+						gPathfindingProgram.bind();
 					}
 				}
 			}
@@ -4953,14 +4894,11 @@ void LLPipeline::renderDebug()
 				{				
 					F32 ambiance = gSavedSettings.getF32("PathfindingAmbiance");
 
-					if (LLGLSLShader::sNoFixedFunction)
-					{					
-						gPathfindingProgram.bind();
+					gPathfindingProgram.bind();
 			
-						gPathfindingProgram.uniform1f(sTint, 1.f);
-						gPathfindingProgram.uniform1f(sAmbiance, ambiance);
-						gPathfindingProgram.uniform1f(sAlphaScale, 1.f);
-					}
+					gPathfindingProgram.uniform1f(sTint, 1.f);
+					gPathfindingProgram.uniform1f(sAmbiance, ambiance);
+					gPathfindingProgram.uniform1f(sAlphaScale, 1.f);
 
 					if ( !pathfindingConsole->isRenderWorld() )
 					{
@@ -4992,18 +4930,11 @@ void LLPipeline::renderDebug()
 						}
 						
 						//render edges
-						if (LLGLSLShader::sNoFixedFunction)
-						{
-							gPathfindingNoNormalsProgram.bind();
-							gPathfindingNoNormalsProgram.uniform1f(sTint, 1.f);
-							gPathfindingNoNormalsProgram.uniform1f(sAlphaScale, 1.f);
-							llPathingLibInstance->renderNavMeshEdges();
-							gPathfindingProgram.bind();
-						}
-						else
-						{
-							llPathingLibInstance->renderNavMeshEdges();
-						}
+						gPathfindingNoNormalsProgram.bind();
+						gPathfindingNoNormalsProgram.uniform1f(sTint, 1.f);
+						gPathfindingNoNormalsProgram.uniform1f(sAlphaScale, 1.f);
+						llPathingLibInstance->renderNavMeshEdges();
+						gPathfindingProgram.bind();
 
 						gGL.flush();
 						glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );	
@@ -5014,53 +4945,31 @@ void LLPipeline::renderDebug()
 					if ( LLPathfindingPathTool::getInstance()->isRenderPath() )
 					{
 						//The path
-						if (LLGLSLShader::sNoFixedFunction)
-						{
-							gUIProgram.bind();
-							gGL.getTexUnit(0)->bind(LLViewerFetchedTexture::sWhiteImagep);
-							llPathingLibInstance->renderPath();
-							gPathfindingProgram.bind();
-						}
-						else
-						{
-							llPathingLibInstance->renderPath();
-						}
-						//The bookends
-						if (LLGLSLShader::sNoFixedFunction)
-						{
-							//remove blending artifacts
-							gGL.setColorMask(false, false);
-							llPathingLibInstance->renderPathBookend( gGL, LLPathingLib::LLPL_START );
-							llPathingLibInstance->renderPathBookend( gGL, LLPathingLib::LLPL_END );
+						gUIProgram.bind();
+						gGL.getTexUnit(0)->bind(LLViewerFetchedTexture::sWhiteImagep);
+						llPathingLibInstance->renderPath();
+						gPathfindingProgram.bind();
+
+                        //The bookends
+						//remove blending artifacts
+						gGL.setColorMask(false, false);
+						llPathingLibInstance->renderPathBookend( gGL, LLPathingLib::LLPL_START );
+						llPathingLibInstance->renderPathBookend( gGL, LLPathingLib::LLPL_END );
 						
-							gGL.setColorMask(true, false);
-							//render the bookends
-							LLGLEnable blend(GL_BLEND);
-							gPathfindingProgram.uniform1f(sAlphaScale, 0.90f);
-							llPathingLibInstance->renderPathBookend( gGL, LLPathingLib::LLPL_START );
-							llPathingLibInstance->renderPathBookend( gGL, LLPathingLib::LLPL_END );
-							gPathfindingProgram.bind();
-						}
-						else
-						{
-							llPathingLibInstance->renderPathBookend( gGL, LLPathingLib::LLPL_START );
-							llPathingLibInstance->renderPathBookend( gGL, LLPathingLib::LLPL_END );
-						}
-					
+						gGL.setColorMask(true, false);
+						//render the bookends
+						LLGLEnable blend(GL_BLEND);
+						gPathfindingProgram.uniform1f(sAlphaScale, 0.90f);
+						llPathingLibInstance->renderPathBookend( gGL, LLPathingLib::LLPL_START );
+						llPathingLibInstance->renderPathBookend( gGL, LLPathingLib::LLPL_END );
+						gPathfindingProgram.bind();
 					}
 				
 					if ( pathfindingConsole->isRenderWaterPlane() )
 					{	
-						if (LLGLSLShader::sNoFixedFunction)
-						{
-							LLGLEnable blend(GL_BLEND);
-							gPathfindingProgram.uniform1f(sAlphaScale, 0.90f);
-							llPathingLibInstance->renderSimpleShapes( gGL, gAgent.getRegion()->getWaterHeight() );
-						}
-						else
-						{
-							llPathingLibInstance->renderSimpleShapes( gGL, gAgent.getRegion()->getWaterHeight() );					
-						}
+						LLGLEnable blend(GL_BLEND);
+						gPathfindingProgram.uniform1f(sAlphaScale, 0.90f);
+						llPathingLibInstance->renderSimpleShapes( gGL, gAgent.getRegion()->getWaterHeight() );
 					}
 				//physics/exclusion shapes
 				if ( pathfindingConsole->isRenderAnyShapes() )
@@ -5191,18 +5100,11 @@ void LLPipeline::renderDebug()
 						}
 
 						//render edges
-						if (LLGLSLShader::sNoFixedFunction)
-						{
-							gPathfindingNoNormalsProgram.bind();
-							gPathfindingNoNormalsProgram.uniform1f(sTint, gSavedSettings.getF32("PathfindingXRayTint"));
-							gPathfindingNoNormalsProgram.uniform1f(sAlphaScale, gSavedSettings.getF32("PathfindingXRayOpacity"));
-							llPathingLibInstance->renderNavMeshEdges();
-							gPathfindingProgram.bind();
-						}
-						else
-						{
-							llPathingLibInstance->renderNavMeshEdges();
-						}
+						gPathfindingNoNormalsProgram.bind();
+						gPathfindingNoNormalsProgram.uniform1f(sTint, gSavedSettings.getF32("PathfindingXRayTint"));
+						gPathfindingNoNormalsProgram.uniform1f(sAlphaScale, gSavedSettings.getF32("PathfindingXRayOpacity"));
+						llPathingLibInstance->renderNavMeshEdges();
+						gPathfindingProgram.bind();
 					
 						gGL.flush();
 						glLineWidth(1.0f);	
@@ -5211,10 +5113,7 @@ void LLPipeline::renderDebug()
 					glPolygonOffset(0.f, 0.f);
 
 					gGL.flush();
-					if (LLGLSLShader::sNoFixedFunction)
-					{
-						gPathfindingProgram.unbind();
-					}
+					gPathfindingProgram.unbind();
 				}
 			}
 		}
@@ -5229,10 +5128,7 @@ void LLPipeline::renderDebug()
 	
 	if (!hud_only && !mDebugBlips.empty())
 	{ //render debug blips
-		if (LLGLSLShader::sNoFixedFunction)
-		{
-			gUIProgram.bind();
-		}
+		gUIProgram.bind();
 
 		gGL.getTexUnit(0)->bind(LLViewerFetchedTexture::sWhiteImagep, true);
 
@@ -5296,7 +5192,7 @@ void LLPipeline::renderDebug()
 		}
 	}
 
-	if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_OCCLUSION) && LLGLSLShader::sNoFixedFunction)
+	if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_OCCLUSION))
 	{ //render visible selected group occlusion geometry
 		gDebugProgram.bind();
 		LLGLDepthTest depth(GL_TRUE, GL_FALSE);
@@ -5318,44 +5214,38 @@ void LLPipeline::renderDebug()
 
 	visible_selected_groups.clear();
 
-	if (LLGLSLShader::sNoFixedFunction)
-	{
-		gUIProgram.bind();
-	}
+	gUIProgram.bind();
 
 	if (hasRenderDebugMask(LLPipeline::RENDER_DEBUG_RAYCAST) && !hud_only)
 	{ //draw crosshairs on particle intersection
 		if (gDebugRaycastParticle)
 		{
-			if (LLGLSLShader::sNoFixedFunction)
-			{ //this debug display requires shaders
-				gDebugProgram.bind();
+			gDebugProgram.bind();
 
-				gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+			gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 
-				LLVector3 center(gDebugRaycastParticleIntersection.getF32ptr());
-				LLVector3 size(0.1f, 0.1f, 0.1f);
+			LLVector3 center(gDebugRaycastParticleIntersection.getF32ptr());
+			LLVector3 size(0.1f, 0.1f, 0.1f);
 
-				LLVector3 p[6];
+			LLVector3 p[6];
 
-				p[0] = center + size.scaledVec(LLVector3(1,0,0));
-				p[1] = center + size.scaledVec(LLVector3(-1,0,0));
-				p[2] = center + size.scaledVec(LLVector3(0,1,0));
-				p[3] = center + size.scaledVec(LLVector3(0,-1,0));
-				p[4] = center + size.scaledVec(LLVector3(0,0,1));
-				p[5] = center + size.scaledVec(LLVector3(0,0,-1));
+			p[0] = center + size.scaledVec(LLVector3(1,0,0));
+			p[1] = center + size.scaledVec(LLVector3(-1,0,0));
+			p[2] = center + size.scaledVec(LLVector3(0,1,0));
+			p[3] = center + size.scaledVec(LLVector3(0,-1,0));
+			p[4] = center + size.scaledVec(LLVector3(0,0,1));
+			p[5] = center + size.scaledVec(LLVector3(0,0,-1));
 				
-				gGL.begin(LLRender::LINES);
-				gGL.diffuseColor3f(1.f, 1.f, 0.f);
-				for (U32 i = 0; i < 6; i++)
-				{
-					gGL.vertex3fv(p[i].mV);
-				}
-				gGL.end();
-				gGL.flush();
-
-				gDebugProgram.unbind();
+			gGL.begin(LLRender::LINES);
+			gGL.diffuseColor3f(1.f, 1.f, 0.f);
+			for (U32 i = 0; i < 6; i++)
+			{
+				gGL.vertex3fv(p[i].mV);
 			}
+			gGL.end();
+			gGL.flush();
+
+			gDebugProgram.unbind();
 		}
 	}
 
@@ -5588,17 +5478,12 @@ void LLPipeline::renderDebug()
 	}
 
 	gGL.flush();
-	if (LLGLSLShader::sNoFixedFunction)
-	{
-		gUIProgram.unbind();
-	}
+	gUIProgram.unbind();
 }
 
-static LLTrace::BlockTimerStatHandle FTM_REBUILD_POOLS("Rebuild Pools");
-
 void LLPipeline::rebuildPools()
 {
-	LL_RECORD_BLOCK_TIME(FTM_REBUILD_POOLS);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
 
 	assertInitialized();
 
@@ -5942,6 +5827,7 @@ void LLPipeline::removeFromQuickLookup( LLDrawPool* poolp )
 
 void LLPipeline::resetDrawOrders()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
 	assertInitialized();
 	// Iterate through all of the draw pools and rebuild them.
 	for (pool_set_t::iterator iter = mPools.begin(); iter != mPools.end(); ++iter)
@@ -6261,11 +6147,6 @@ void LLPipeline::setupHWLights(LLDrawPool* pool)
     LLEnvironment& environment = LLEnvironment::instance();
     LLSettingsSky::ptr_t psky = environment.getCurrentSky();
 
-	if (!LLGLSLShader::sNoFixedFunction)
-	{
-		gGL.syncMatrices();
-	}
-
     // Ambient
     LLColor4 ambient = psky->getTotalAmbient();
 		gGL.setAmbientLightColor(ambient);
@@ -6387,21 +6268,19 @@ void LLPipeline::setupHWLights(LLDrawPool* pool)
                 continue;
             }
 
-			LLVector3 light_pos(light->getRenderPosition());
-			LLVector4 light_pos_gl(light_pos, 1.0f);
-	
-			F32 light_radius = llmax(light->getLightRadius(), 0.001f);
-            F32 size = light_radius * (sRenderDeferred ? 1.5f : 1.0f);
+            LLVector3 light_pos(light->getRenderPosition());
+            LLVector4 light_pos_gl(light_pos, 1.0f);
 
-            if (size <= 0.001f)
+            F32 adjusted_radius = light->getLightRadius() * (sRenderDeferred ? 1.5f : 1.0f);
+            if (adjusted_radius <= 0.001f)
             {
                 continue;
             }
 
-			F32 x = (3.f * (1.f + (light->getLightFalloff() * 2.0f))); // why this magic?  probably trying to match a historic behavior.
-			F32 linatten = x / (light_radius); // % of brightness at radius
+            F32 x = (3.f * (1.f + (light->getLightFalloff() * 2.0f)));  // why this magic?  probably trying to match a historic behavior.
+            F32 linatten = x / adjusted_radius;                         // % of brightness at radius
 
-			mHWLightColors[cur_light] = light_color;
+            mHWLightColors[cur_light] = light_color;
 			LLLightState* light_state = gGL.getLight(cur_light);
 			
 			light_state->setPosition(light_pos_gl);
@@ -6410,7 +6289,7 @@ void LLPipeline::setupHWLights(LLDrawPool* pool)
 			light_state->setConstantAttenuation(0.f);
 			if (sRenderDeferred)
 			{
-				light_state->setLinearAttenuation(size);
+				light_state->setLinearAttenuation(linatten);
 				light_state->setQuadraticAttenuation(light->getLightFalloff(DEFERRED_LIGHT_FALLOFF) + 1.f); // get falloff to match for forward deferred rendering lights
 			}
 			else
@@ -6466,11 +6345,6 @@ void LLPipeline::setupHWLights(LLDrawPool* pool)
     // prev site of forward (non-deferred) character light injection, removed by SL-13522 09/20
 
 	// Init GL state
-	if (!LLGLSLShader::sNoFixedFunction)
-	{
-		glDisable(GL_LIGHTING);
-	}
-
 	for (S32 i = 0; i < 8; ++i)
 	{
 		gGL.getLight(i)->disable();
@@ -6489,13 +6363,6 @@ void LLPipeline::enableLights(U32 mask)
 	if (mLightMask != mask)
 	{
 		stop_glerror();
-		if (!mLightMask)
-		{
-			if (!LLGLSLShader::sNoFixedFunction)
-			{
-				glEnable(GL_LIGHTING);
-			}
-		}
 		if (mask)
 		{
 			stop_glerror();
@@ -6515,13 +6382,6 @@ void LLPipeline::enableLights(U32 mask)
 			}
 			stop_glerror();
 		}
-		else
-		{
-			if (!LLGLSLShader::sNoFixedFunction)
-			{
-				glDisable(GL_LIGHTING);
-			}
-		}
 		mLightMask = mask;
 		stop_glerror();
 	}
@@ -6572,11 +6432,6 @@ void LLPipeline::enableLightsPreview()
 {
 	disableLights();
 
-	if (!LLGLSLShader::sNoFixedFunction)
-	{
-		glEnable(GL_LIGHTING);
-	}
-
 	LLColor4 ambient = PreviewAmbientColor;
 	gGL.setAmbientLightColor(ambient);
 
@@ -7358,8 +7213,6 @@ void LLPipeline::resetVertexBuffers()
 	mResetVertexBuffers = true;
 }
 
-static LLTrace::BlockTimerStatHandle FTM_RESET_VB("Reset VB");
-
 void LLPipeline::doResetVertexBuffers(bool forced)
 {
 	if (!mResetVertexBuffers)
@@ -7381,10 +7234,11 @@ void LLPipeline::doResetVertexBuffers(bool forced)
 		}
 	}
 
-	LL_RECORD_BLOCK_TIME(FTM_RESET_VB);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
 	mResetVertexBuffers = false;
 
 	mCubeVB = NULL;
+    mDeferredVB = NULL;
 
 	for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); 
 			iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
@@ -7418,15 +7272,11 @@ void LLPipeline::doResetVertexBuffers(bool forced)
 		LLPathingLib::getInstance()->cleanupVBOManager();
 	}
 	LLVOPartGroup::destroyGL();
+    gGL.resetVertexBuffer();
 
 	SUBSYSTEM_CLEANUP(LLVertexBuffer);
 	
-	//delete all name pool caches
-	LLGLNamePool::cleanupPools();
-
-	
-
-	if (LLVertexBuffer::sGLCount > 0)
+	if (LLVertexBuffer::sGLCount != 0)
 	{
 		LL_WARNS() << "VBO wipe failed -- " << LLVertexBuffer::sGLCount << " buffers remaining." << LL_ENDL;
 	}
@@ -7447,36 +7297,99 @@ void LLPipeline::doResetVertexBuffers(bool forced)
 	LLPipeline::sTextureBindTest = gSavedSettings.getBOOL("RenderDebugTextureBind");
 
 	LLVertexBuffer::initClass(LLVertexBuffer::sEnableVBOs, LLVertexBuffer::sDisableVBOMapping);
+    gGL.initVertexBuffer();
+
+    mDeferredVB = new LLVertexBuffer(DEFERRED_VB_MASK, 0);
+    mDeferredVB->allocateBuffer(8, 0, true);
 
 	LLVOPartGroup::restoreGL();
 }
 
-void LLPipeline::renderObjects(U32 type, U32 mask, bool texture, bool batch_texture)
+void LLPipeline::renderObjects(U32 type, U32 mask, bool texture, bool batch_texture, bool rigged)
 {
 	assertInitialized();
 	gGL.loadMatrix(gGLModelView);
 	gGLLastMatrix = NULL;
-	mSimplePool->pushBatches(type, mask, texture, batch_texture);
+    if (rigged)
+    {
+        mSimplePool->pushRiggedBatches(type + 1, mask, texture, batch_texture);
+    }
+    else
+    {
+        mSimplePool->pushBatches(type, mask, texture, batch_texture);
+    }
 	gGL.loadMatrix(gGLModelView);
 	gGLLastMatrix = NULL;		
 }
 
-void LLPipeline::renderMaskedObjects(U32 type, U32 mask, bool texture, bool batch_texture)
+void LLPipeline::renderAlphaObjects(U32 mask, bool texture, bool batch_texture, bool rigged)
+{
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
+    assertInitialized();
+    gGL.loadMatrix(gGLModelView);
+    gGLLastMatrix = NULL;
+    U32 type = LLRenderPass::PASS_ALPHA;
+    LLVOAvatar* lastAvatar = nullptr;
+    U64 lastMeshId = 0;
+    for (LLCullResult::drawinfo_iterator i = gPipeline.beginRenderMap(type); i != gPipeline.endRenderMap(type); ++i)
+    {
+        LLDrawInfo* pparams = *i;
+        if (pparams)
+        {
+            if (rigged)
+            {
+                if (pparams->mAvatar != nullptr)
+                {
+                    if (lastAvatar != pparams->mAvatar || lastMeshId != pparams->mSkinInfo->mHash)
+                    {
+                        mSimplePool->uploadMatrixPalette(*pparams);
+                        lastAvatar = pparams->mAvatar;
+                        lastMeshId = pparams->mSkinInfo->mHash;
+                    }
+
+                    mSimplePool->pushBatch(*pparams, mask | LLVertexBuffer::MAP_WEIGHT4, texture, batch_texture);
+                }
+            }
+            else if (pparams->mAvatar == nullptr)
+            {
+                mSimplePool->pushBatch(*pparams, mask, texture, batch_texture);
+            }
+        }
+    }
+    gGL.loadMatrix(gGLModelView);
+    gGLLastMatrix = NULL;
+}
+
+void LLPipeline::renderMaskedObjects(U32 type, U32 mask, bool texture, bool batch_texture, bool rigged)
 {
 	assertInitialized();
 	gGL.loadMatrix(gGLModelView);
 	gGLLastMatrix = NULL;
-	mAlphaMaskPool->pushMaskBatches(type, mask, texture, batch_texture);
+    if (rigged)
+    {
+        mAlphaMaskPool->pushRiggedMaskBatches(type+1, mask, texture, batch_texture);
+    }
+    else
+    {
+        mAlphaMaskPool->pushMaskBatches(type, mask, texture, batch_texture);
+    }
 	gGL.loadMatrix(gGLModelView);
 	gGLLastMatrix = NULL;		
 }
 
-void LLPipeline::renderFullbrightMaskedObjects(U32 type, U32 mask, bool texture, bool batch_texture)
+void LLPipeline::renderFullbrightMaskedObjects(U32 type, U32 mask, bool texture, bool batch_texture, bool rigged)
 {
 	assertInitialized();
 	gGL.loadMatrix(gGLModelView);
 	gGLLastMatrix = NULL;
-	mFullbrightAlphaMaskPool->pushMaskBatches(type, mask, texture, batch_texture);
+    if (rigged)
+    {
+        mFullbrightAlphaMaskPool->pushRiggedMaskBatches(type+1, mask, texture, batch_texture);
+    }
+    else
+    {
+        mFullbrightAlphaMaskPool->pushMaskBatches(type, mask, texture, batch_texture);
+    }
 	gGL.loadMatrix(gGLModelView);
 	gGLLastMatrix = NULL;		
 }
@@ -7581,11 +7494,8 @@ void LLPipeline::renderFinalize()
 
     if (sRenderGlow)
     {
-        {
-            LL_RECORD_BLOCK_TIME(FTM_RENDER_BLOOM_FBO);
-            mGlow[2].bindTarget();
-            mGlow[2].clear();
-        }
+        mGlow[2].bindTarget();
+        mGlow[2].clear();
 
         gGlowExtractProgram.bind();
         F32 minLum = llmax((F32) RenderGlowMinLuminance, 0.0f);
@@ -7651,11 +7561,8 @@ void LLPipeline::renderFinalize()
 
         for (S32 i = 0; i < kernel; i++)
         {
-            {
-                LL_RECORD_BLOCK_TIME(FTM_RENDER_BLOOM_FBO);
-                mGlow[i % 2].bindTarget();
-                mGlow[i % 2].clear();
-            }
+            mGlow[i % 2].bindTarget();
+            mGlow[i % 2].clear();
 
             if (i == 0)
             {
@@ -8080,18 +7987,7 @@ void LLPipeline::renderFinalize()
 
         LLGLDisable blend(GL_BLEND);
 
-        if (LLGLSLShader::sNoFixedFunction)
-        {
-            gGlowCombineProgram.bind();
-        }
-        else
-        {
-            // tex unit 0
-            gGL.getTexUnit(0)->setTextureColorBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_TEX_COLOR);
-            // tex unit 1
-            gGL.getTexUnit(1)->setTextureColorBlend(LLTexUnit::TBO_ADD, LLTexUnit::TBS_TEX_COLOR,
-                                                    LLTexUnit::TBS_PREV_COLOR);
-        }
+        gGlowCombineProgram.bind();
 
         gGL.getTexUnit(0)->bind(&mGlow[1]);
         gGL.getTexUnit(1)->bind(&mScreen);
@@ -8101,28 +7997,14 @@ void LLPipeline::renderFinalize()
         buff->setBuffer(mask);
         buff->drawArrays(LLRender::TRIANGLE_STRIP, 0, 3);
 
-        if (LLGLSLShader::sNoFixedFunction)
-        {
-            gGlowCombineProgram.unbind();
-        }
-        else
-        {
-            gGL.getTexUnit(1)->disable();
-            gGL.getTexUnit(1)->setTextureBlendType(LLTexUnit::TB_MULT);
-
-            gGL.getTexUnit(0)->activate();
-            gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
-        }
+        gGlowCombineProgram.unbind();
     }
 
     gGL.setSceneBlendType(LLRender::BT_ALPHA);
 
     if (hasRenderDebugMask(LLPipeline::RENDER_DEBUG_PHYSICS_SHAPES))
     {
-        if (LLGLSLShader::sNoFixedFunction)
-        {
-            gSplatTextureRectProgram.bind();
-        }
+        gSplatTextureRectProgram.bind();
 
         gGL.setColorMask(true, false);
 
@@ -8148,10 +8030,7 @@ void LLPipeline::renderFinalize()
         gGL.end();
         gGL.flush();
 
-        if (LLGLSLShader::sNoFixedFunction)
-        {
-            gSplatTextureRectProgram.unbind();
-        }
+        gSplatTextureRectProgram.unbind();
     }
 
     if (LLRenderTarget::sUseFBO)
@@ -8172,11 +8051,9 @@ void LLPipeline::renderFinalize()
     LLGLState::checkTextureChannels();
 }
 
-static LLTrace::BlockTimerStatHandle FTM_BIND_DEFERRED("Bind Deferred");
-
 void LLPipeline::bindDeferredShader(LLGLSLShader& shader, LLRenderTarget* light_target)
 {
-	LL_RECORD_BLOCK_TIME(FTM_BIND_DEFERRED);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
 
     LLRenderTarget* deferred_target       = &mDeferredScreen;
     LLRenderTarget* deferred_depth_target = &mDeferredDepth;
@@ -8418,8 +8295,6 @@ void LLPipeline::bindDeferredShader(LLGLSLShader& shader, LLRenderTarget* light_
 
     LLEnvironment& environment = LLEnvironment::instance();
     LLSettingsSky::ptr_t sky = environment.getCurrentSky();
-
-    static_cast<LLSettingsVOSky*>(sky.get())->updateShader(&shader);
 }
 
 LLColor3 pow3f(LLColor3 v, F32 f)
@@ -8438,19 +8313,9 @@ LLVector4 pow4fsrgb(LLVector4 v, F32 f)
 	return v;
 }
 
-static LLTrace::BlockTimerStatHandle FTM_GI_TRACE("Trace");
-static LLTrace::BlockTimerStatHandle FTM_GI_GATHER("Gather");
-static LLTrace::BlockTimerStatHandle FTM_SUN_SHADOW("Shadow Map");
-static LLTrace::BlockTimerStatHandle FTM_SOFTEN_SHADOW("Shadow Soften");
-static LLTrace::BlockTimerStatHandle FTM_EDGE_DETECTION("Find Edges");
-static LLTrace::BlockTimerStatHandle FTM_LOCAL_LIGHTS("Local Lights");
-static LLTrace::BlockTimerStatHandle FTM_ATMOSPHERICS("Atmospherics");
-static LLTrace::BlockTimerStatHandle FTM_FULLSCREEN_LIGHTS("Fullscreen Lights");
-static LLTrace::BlockTimerStatHandle FTM_PROJECTORS("Projectors");
-static LLTrace::BlockTimerStatHandle FTM_POST("Post");
-
 void LLPipeline::renderDeferredLighting(LLRenderTarget *screen_target)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
     if (!sCull)
     {
         return;
@@ -8461,7 +8326,7 @@ void LLPipeline::renderDeferredLighting(LLRenderTarget *screen_target)
     LLRenderTarget *deferred_light_target = &mDeferredLight;
 
     {
-        LL_RECORD_BLOCK_TIME(FTM_RENDER_DEFERRED);
+        LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("deferred"); //LL_RECORD_BLOCK_TIME(FTM_RENDER_DEFERRED);
         LLViewerCamera *camera = LLViewerCamera::getInstance();
         {
             LLGLDepthTest depth(GL_TRUE);
@@ -8527,7 +8392,7 @@ void LLPipeline::renderDeferredLighting(LLRenderTarget *screen_target)
         {
             deferred_light_target->bindTarget();
             {  // paint shadow/SSAO light map (direct lighting lightmap)
-                LL_RECORD_BLOCK_TIME(FTM_SUN_SHADOW);
+                LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("renderDeferredLighting - sun shadow");
                 bindDeferredShader(gDeferredSunProgram, deferred_light_target);
                 mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX);
                 glClearColor(1, 1, 1, 1);
@@ -8573,7 +8438,7 @@ void LLPipeline::renderDeferredLighting(LLRenderTarget *screen_target)
 
         if (RenderDeferredSSAO)
         {  // soften direct lighting lightmap
-            LL_RECORD_BLOCK_TIME(FTM_SOFTEN_SHADOW);
+            LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("renderDeferredLighting - soften shadow");
             // blur lightmap
             screen_target->bindTarget();
             glClearColor(1, 1, 1, 1);
@@ -8651,7 +8516,7 @@ void LLPipeline::renderDeferredLighting(LLRenderTarget *screen_target)
         {  // apply sunlight contribution
             LLGLSLShader &soften_shader = LLPipeline::sUnderWaterRender ? gDeferredSoftenWaterProgram : gDeferredSoftenProgram;
 
-            LL_RECORD_BLOCK_TIME(FTM_ATMOSPHERICS);
+            LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("renderDeferredLighting - atmospherics");
             bindDeferredShader(soften_shader);
 
             LLEnvironment &environment = LLEnvironment::instance();
@@ -8717,6 +8582,7 @@ void LLPipeline::renderDeferredLighting(LLRenderTarget *screen_target)
             LLVertexBuffer::unbind();
 
             {
+                LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("renderDeferredLighting - local lights");
                 bindDeferredShader(gDeferredLightProgram);
 
                 if (mCubeVB.isNull())
@@ -8787,7 +8653,6 @@ void LLPipeline::renderDeferredLighting(LLRenderTarget *screen_target)
                                 continue;
                             }
 
-                            LL_RECORD_BLOCK_TIME(FTM_LOCAL_LIGHTS);
                             gDeferredLightProgram.uniform3fv(LLShaderMgr::LIGHT_CENTER, 1, c);
                             gDeferredLightProgram.uniform1f(LLShaderMgr::LIGHT_SIZE, s);
                             gDeferredLightProgram.uniform3fv(LLShaderMgr::DIFFUSE_COLOR, 1, col.mV);
@@ -8823,6 +8688,7 @@ void LLPipeline::renderDeferredLighting(LLRenderTarget *screen_target)
 
             if (!spot_lights.empty())
             {
+                LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("renderDeferredLighting - projectors");
                 LLGLDepthTest depth(GL_TRUE, GL_FALSE);
                 bindDeferredShader(gDeferredSpotLightProgram);
 
@@ -8832,7 +8698,6 @@ void LLPipeline::renderDeferredLighting(LLRenderTarget *screen_target)
 
                 for (LLDrawable::drawable_list_t::iterator iter = spot_lights.begin(); iter != spot_lights.end(); ++iter)
                 {
-                    LL_RECORD_BLOCK_TIME(FTM_PROJECTORS);
                     LLDrawable *drawablep = *iter;
 
                     LLVOVolume *volume = drawablep->getVOVolume();
@@ -8868,6 +8733,7 @@ void LLPipeline::renderDeferredLighting(LLRenderTarget *screen_target)
             vert[2].set(3, 1, 0);
 
             {
+                LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("renderDeferredLighting - fullscreen lights");
                 LLGLDepthTest depth(GL_FALSE);
 
                 // full screen blit
@@ -8887,7 +8753,6 @@ void LLPipeline::renderDeferredLighting(LLRenderTarget *screen_target)
 
                 while (!fullscreen_lights.empty())
                 {
-                    LL_RECORD_BLOCK_TIME(FTM_FULLSCREEN_LIGHTS);
                     light[count] = fullscreen_lights.front();
                     fullscreen_lights.pop_front();
                     col[count] = light_colors.front();
@@ -8919,7 +8784,6 @@ void LLPipeline::renderDeferredLighting(LLRenderTarget *screen_target)
 
                 for (LLDrawable::drawable_list_t::iterator iter = fullscreen_spot_lights.begin(); iter != fullscreen_spot_lights.end(); ++iter)
                 {
-                    LL_RECORD_BLOCK_TIME(FTM_PROJECTORS);
                     LLDrawable *drawablep           = *iter;
                     LLVOVolume *volume              = drawablep->getVOVolume();
                     LLVector3   center              = drawablep->getPositionAgent();
@@ -9263,8 +9127,19 @@ inline float sgn(float a)
 
 void LLPipeline::generateWaterReflection(LLCamera& camera_in)
 {
-    if (LLPipeline::sWaterReflections && assertInitialized() && LLDrawPoolWater::sNeedsReflectionUpdate)
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
+
+    if (!assertInitialized())
+    {
+        return;
+    }
+
+    if (LLPipeline::sWaterReflections && LLDrawPoolWater::sNeedsReflectionUpdate)
     {
+        //disable occlusion culling for reflection/refraction passes (save setting to restore later)
+        S32 occlude = LLPipeline::sUseOcclusion;
+        LLPipeline::sUseOcclusion = 0;
+
         bool skip_avatar_update = false;
         if (!isAgentAvatarValid() || gAgentCamera.getCameraAnimating() || gAgentCamera.getCameraMode() != CAMERA_MODE_MOUSELOOK || !LLVOAvatar::sVisibleInFirstPerson)
         {
@@ -9301,26 +9176,19 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in)
         //plane params
         LLPlane plane;
         LLVector3 pnorm;
-        S32 water_clip = 0;
-        if (!camera_is_underwater)
+
+        if (camera_is_underwater)
         {
-            //camera is above water, clip plane points up
-            pnorm.setVec(0,0,1);
-            plane.setVec(pnorm, -water_height);
-            water_clip = 1;
+            //camera is below water, cull above water
+            pnorm.setVec(0, 0, 1);
         }
         else
         {
-            //camera is below water, clip plane points down
-            pnorm = LLVector3(0,0,-1);
-            plane.setVec(pnorm, water_height);
-            water_clip = -1;
+            //camera is above water, cull below water
+            pnorm = LLVector3(0, 0, -1);
         }
 
-        S32 occlusion = LLPipeline::sUseOcclusion;
-
-        //disable occlusion culling for reflection map for now
-        LLPipeline::sUseOcclusion = 0;
+        plane.setVec(LLVector3(0, 0, water_height), pnorm);
 
         if (!camera_is_underwater)
         {
@@ -9419,7 +9287,7 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in)
 
                             LLGLUserClipPlane clip_plane(plane, mReflectionModelView, saved_projection);
                             LLGLDisable cull(GL_CULL_FACE);
-                            updateCull(camera, mReflectedObjects, -water_clip, &plane);
+                            updateCull(camera, mReflectedObjects, &plane);
                             stateSort(camera, mReflectedObjects);
                             renderGeom(camera);
                         }
@@ -9437,8 +9305,6 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in)
             set_current_modelview(saved_modelview);
         }
 
-        //LLPipeline::sUseOcclusion = occlusion;
-
         camera.setOrigin(camera_in.getOrigin());
         //render distortion map
         static bool last_update = true;
@@ -9477,7 +9343,11 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in)
                 LLColor3 col = LLEnvironment::instance().getCurrentWater()->getWaterFogColor();
                 glClearColor(col.mV[0], col.mV[1], col.mV[2], 0.f);
 
-                LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WATER1;
+                // HACK FIX -- pretend underwater camera is the world camera to fix weird visibility artifacts
+                // during distortion render (doesn't break main render because the camera is the same perspective
+                // as world camera and occlusion culling is disabled for this pass)
+                //LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WATER1;
+                LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD;
 
                 mWaterDis.bindTarget();
                 mWaterDis.getViewport(gGLViewport);
@@ -9486,41 +9356,47 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in)
                 mWaterDis.clear();
                 gGL.setColorMask(true, false);
 
-                F32 water_dist = water_height * LLPipeline::sDistortionWaterClipPlaneMargin;
+                F32 water_dist = water_height;
 
                 //clip out geometry on the same side of water as the camera w/ enough margin to not include the water geo itself,
                 // but not so much as to clip out parts of avatars that should be seen under the water in the distortion map
-                LLPlane plane(-pnorm, water_dist);
+                LLPlane plane;
+
+                if (camera_is_underwater)
+                {
+                    //nudge clip plane below water to avoid visible holes in objects intersecting water surface
+                    water_dist /= LLPipeline::sDistortionWaterClipPlaneMargin;
+                    //camera is below water, clip plane points up
+                    pnorm.setVec(0, 0, -1);
+                }
+                else
+                {
+                    //nudge clip plane above water to avoid visible holes in objects intersecting water surface
+                    water_dist *= LLPipeline::sDistortionWaterClipPlaneMargin;
+                    //camera is above water, clip plane points down
+                    pnorm = LLVector3(0, 0, 1);
+                }
+
+                plane.setVec(LLVector3(0, 0, water_dist), pnorm);
+
                 LLGLUserClipPlane clip_plane(plane, saved_modelview, saved_projection);
 
                 gGL.setColorMask(true, true);
                 mWaterDis.clear();
                 gGL.setColorMask(true, false);
 
-                // ignore clip plane if we're underwater and viewing distortion map of objects above waterline
-                if (camera_is_underwater)
-                {
-                    clip_plane.disable();
-                }
-
                 if (reflection_detail >= WATER_REFLECT_NONE_WATER_TRANSPARENT)
                 {
-                    updateCull(camera, mRefractedObjects, water_clip, &plane);
+                    updateCull(camera, mRefractedObjects, &plane);
                     stateSort(camera, mRefractedObjects);
                     renderGeom(camera);
                 }
 
-                if (LLGLSLShader::sNoFixedFunction)
-                {
-                    gUIProgram.bind();
-                }
+                gUIProgram.bind();
 
                 LLWorld::getInstance()->renderPropertyLines();
 
-                if (LLGLSLShader::sNoFixedFunction)
-                {
-                    gUIProgram.unbind();
-                }
+                gUIProgram.unbind();
 
                 mWaterDis.flush();
             }
@@ -9533,7 +9409,6 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in)
 
         gPipeline.popRenderTypeMask();
 
-        LLPipeline::sUseOcclusion     = occlusion;
         LLPipeline::sUnderWaterRender = false;
         LLPipeline::sReflectionRender = false;
 
@@ -9555,6 +9430,32 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in)
         }
 
         LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD;
+
+        // restore occlusion culling
+        LLPipeline::sUseOcclusion = occlude;
+    }
+    else
+    {
+        // Initial sky pass is still needed even if water reflection is not rendering
+        bool camera_is_underwater = LLViewerCamera::getInstance()->cameraUnderWater();
+        if (!camera_is_underwater)
+        {
+            gPipeline.pushRenderTypeMask();
+            {
+                gPipeline.andRenderTypeMask(
+                    LLPipeline::RENDER_TYPE_SKY,
+                    LLPipeline::RENDER_TYPE_WL_SKY,
+                    LLPipeline::END_RENDER_TYPES);
+
+                LLCamera camera = camera_in;
+                camera.setFar(camera_in.getFar() * 0.75f);
+
+                updateCull(camera, mSky);
+                stateSort(camera, mSky);
+                renderGeom(camera, TRUE);
+            }
+            gPipeline.popRenderTypeMask();
+        }
     }
 }
 
@@ -9635,204 +9536,212 @@ static LLTrace::BlockTimerStatHandle FTM_SHADOW_ALPHA_TREE("Alpha Tree");
 static LLTrace::BlockTimerStatHandle FTM_SHADOW_ALPHA_GRASS("Alpha Grass");
 static LLTrace::BlockTimerStatHandle FTM_SHADOW_FULLBRIGHT_ALPHA_MASKED("Fullbright Alpha Masked");
 
-void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera& shadow_cam, LLCullResult &result, bool use_shader, bool use_occlusion, U32 target_width)
+void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera& shadow_cam, LLCullResult& result, bool use_shader, bool use_occlusion, U32 target_width)
 {
-	LL_RECORD_BLOCK_TIME(FTM_SHADOW_RENDER);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE; //LL_RECORD_BLOCK_TIME(FTM_SHADOW_RENDER);
 
-	//clip out geometry on the same side of water as the camera
-	S32 occlude = LLPipeline::sUseOcclusion;
-	if (!use_occlusion)
-	{
-		LLPipeline::sUseOcclusion = 0;
-	}
-	LLPipeline::sShadowRender = true;
-	
-	static const U32 types[] = { 
-		LLRenderPass::PASS_SIMPLE, 
-		LLRenderPass::PASS_FULLBRIGHT, 
-		LLRenderPass::PASS_SHINY, 
-		LLRenderPass::PASS_BUMP, 
-		LLRenderPass::PASS_FULLBRIGHT_SHINY ,
-		LLRenderPass::PASS_MATERIAL,
-		LLRenderPass::PASS_MATERIAL_ALPHA_EMISSIVE,
-		LLRenderPass::PASS_SPECMAP,
-		LLRenderPass::PASS_SPECMAP_EMISSIVE,
-		LLRenderPass::PASS_NORMMAP,
-		LLRenderPass::PASS_NORMMAP_EMISSIVE,
-		LLRenderPass::PASS_NORMSPEC,
-		LLRenderPass::PASS_NORMSPEC_EMISSIVE,
-	};
+    //disable occlusion culling for shadow passes (save setting to restore later)
+    S32 occlude = LLPipeline::sUseOcclusion;
+    if (!use_occlusion)
+    {
+        LLPipeline::sUseOcclusion = 0;
+    }
+    LLPipeline::sShadowRender = true;
+
+    static const U32 types[] = {
+        LLRenderPass::PASS_SIMPLE,
+        LLRenderPass::PASS_FULLBRIGHT,
+        LLRenderPass::PASS_SHINY,
+        LLRenderPass::PASS_BUMP,
+        LLRenderPass::PASS_FULLBRIGHT_SHINY ,
+        LLRenderPass::PASS_MATERIAL,
+        LLRenderPass::PASS_MATERIAL_ALPHA_EMISSIVE,
+        LLRenderPass::PASS_SPECMAP,
+        LLRenderPass::PASS_SPECMAP_EMISSIVE,
+        LLRenderPass::PASS_NORMMAP,
+        LLRenderPass::PASS_NORMMAP_EMISSIVE,
+        LLRenderPass::PASS_NORMSPEC,
+        LLRenderPass::PASS_NORMSPEC_EMISSIVE,
+    };
+
+    LLGLEnable cull(GL_CULL_FACE);
+
+    //enable depth clamping if available
+    LLGLEnable depth_clamp(gGLManager.mHasDepthClamp ? GL_DEPTH_CLAMP : 0);
+
+    if (use_shader)
+    {
+        gDeferredShadowCubeProgram.bind();
+    }
 
-	LLGLEnable cull(GL_CULL_FACE);
+    LLRenderTarget& occlusion_target = mShadowOcclusion[LLViewerCamera::sCurCameraID - 1];
 
-	//enable depth clamping if available
-	LLGLEnable depth_clamp(gGLManager.mHasDepthClamp ? GL_DEPTH_CLAMP : 0);
+    occlusion_target.bindTarget();
+    updateCull(shadow_cam, result);
+    occlusion_target.flush();
 
-	if (use_shader)
-	{
-		gDeferredShadowCubeProgram.bind();
-	}
+    stateSort(shadow_cam, result);
 
-	LLRenderTarget& occlusion_target = mShadowOcclusion[LLViewerCamera::sCurCameraID-1];
 
-	occlusion_target.bindTarget();
-	updateCull(shadow_cam, result);
-	occlusion_target.flush();
+    //generate shadow map
+    gGL.matrixMode(LLRender::MM_PROJECTION);
+    gGL.pushMatrix();
+    gGL.loadMatrix(proj.m);
+    gGL.matrixMode(LLRender::MM_MODELVIEW);
+    gGL.pushMatrix();
+    gGL.loadMatrix(view.m);
 
-	stateSort(shadow_cam, result);
-	
-	
-	//generate shadow map
-	gGL.matrixMode(LLRender::MM_PROJECTION);
-	gGL.pushMatrix();
-	gGL.loadMatrix(proj.m);
-	gGL.matrixMode(LLRender::MM_MODELVIEW);
-	gGL.pushMatrix();
-	gGL.loadMatrix(view.m);
+    stop_glerror();
+    gGLLastMatrix = NULL;
 
-	stop_glerror();
-	gGLLastMatrix = NULL;
+    gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+
+    stop_glerror();
 
-	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
-	
-	stop_glerror();
-	
     LLEnvironment& environment = LLEnvironment::instance();
 
-	LLVertexBuffer::unbind();
+    LLVertexBuffer::unbind();
 
-	{
-		if (!use_shader)
-		{ //occlusion program is general purpose depth-only no-textures
-			gOcclusionProgram.bind();
-		}
-		else
-		{
-			gDeferredShadowProgram.bind();
-            gDeferredShadowProgram.uniform1i(LLShaderMgr::SUN_UP_FACTOR, environment.getIsSunUp() ? 1 : 0);
-		}
+    for (int j = 0; j < 2; ++j) // 0 -- static, 1 -- rigged
+    {
+        bool rigged = j == 1;
+        if (!use_shader)
+        { //occlusion program is general purpose depth-only no-textures
+            gOcclusionProgram.bind(rigged);
+        }
+        else
+        {
+            gDeferredShadowProgram.bind(rigged);
+            LLGLSLShader::sCurBoundShaderPtr->uniform1i(LLShaderMgr::SUN_UP_FACTOR, environment.getIsSunUp() ? 1 : 0);
+        }
 
-		gGL.diffuseColor4f(1,1,1,1);
+        gGL.diffuseColor4f(1, 1, 1, 1);
 
         S32 shadow_detail = gSavedSettings.getS32("RenderShadowDetail");
 
         // if not using VSM, disable color writes
         if (shadow_detail <= 2)
         {
-		gGL.setColorMask(false, false);
+            gGL.setColorMask(false, false);
         }
-	
-		LL_RECORD_BLOCK_TIME(FTM_SHADOW_SIMPLE);
-		
-		gGL.getTexUnit(0)->disable();
-		for (U32 i = 0; i < sizeof(types)/sizeof(U32); ++i)
-		{
-			renderObjects(types[i], LLVertexBuffer::MAP_VERTEX, FALSE);
-		}
-		gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE);
-		if (!use_shader)
-		{
-			gOcclusionProgram.unbind();
-		}
-	}
-	
-	if (use_shader)
-	{
-        LL_RECORD_BLOCK_TIME(FTM_SHADOW_GEOM);
 
-		gDeferredShadowProgram.unbind();
-		renderGeomShadow(shadow_cam);
-		gDeferredShadowProgram.bind();
-        gDeferredShadowProgram.uniform1i(LLShaderMgr::SUN_UP_FACTOR, environment.getIsSunUp() ? 1 : 0);
-	}
-	else
-	{
-        LL_RECORD_BLOCK_TIME(FTM_SHADOW_GEOM);
+        LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("shadow simple"); //LL_RECORD_BLOCK_TIME(FTM_SHADOW_SIMPLE);
 
-		renderGeomShadow(shadow_cam);
-	}
+        gGL.getTexUnit(0)->disable();
+        for (U32 i = 0; i < sizeof(types) / sizeof(U32); ++i)
+        {
+            renderObjects(types[i], LLVertexBuffer::MAP_VERTEX, FALSE, FALSE, rigged);
+        }
+        gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE);
+        if (!use_shader)
+        {
+            gOcclusionProgram.unbind();
+        }
 
-	{
-		LL_RECORD_BLOCK_TIME(FTM_SHADOW_ALPHA);
 
-		gDeferredShadowAlphaMaskProgram.bind();
-		gDeferredShadowAlphaMaskProgram.uniform1f(LLShaderMgr::DEFERRED_SHADOW_TARGET_WIDTH, (float)target_width);
-        gDeferredShadowAlphaMaskProgram.uniform1i(LLShaderMgr::SUN_UP_FACTOR, environment.getIsSunUp() ? 1 : 0);
+    }
 
-		U32 mask =	LLVertexBuffer::MAP_VERTEX | 
-					LLVertexBuffer::MAP_TEXCOORD0 | 
-					LLVertexBuffer::MAP_COLOR | 
-					LLVertexBuffer::MAP_TEXTURE_INDEX;
+    if (use_shader)
+    {
+        LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("shadow geom"); //LL_RECORD_BLOCK_TIME(FTM_SHADOW_GEOM);
 
-        {
-            LL_RECORD_BLOCK_TIME(FTM_SHADOW_ALPHA_MASKED);
-		renderMaskedObjects(LLRenderPass::PASS_ALPHA_MASK, mask, TRUE, TRUE);
-        }
+        gDeferredShadowProgram.unbind();
+        renderGeomShadow(shadow_cam);
+        gDeferredShadowProgram.bind();
+        gDeferredShadowProgram.uniform1i(LLShaderMgr::SUN_UP_FACTOR, environment.getIsSunUp() ? 1 : 0);
+    }
+    else
+    {
+        LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("shadow geom"); //LL_RECORD_BLOCK_TIME(FTM_SHADOW_GEOM);
 
-        {
-            LL_RECORD_BLOCK_TIME(FTM_SHADOW_ALPHA_BLEND);
-		gDeferredShadowAlphaMaskProgram.setMinimumAlpha(0.598f);
-		renderObjects(LLRenderPass::PASS_ALPHA, mask, TRUE, TRUE);
-        }
+        renderGeomShadow(shadow_cam);
+    }
+
+    {
+        LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("shadow alpha"); //LL_RECORD_BLOCK_TIME(FTM_SHADOW_ALPHA);
 
+        for (int i = 0; i < 2; ++i)
         {
-            LL_RECORD_BLOCK_TIME(FTM_SHADOW_FULLBRIGHT_ALPHA_MASKED);
-            gDeferredShadowFullbrightAlphaMaskProgram.bind();
-            gDeferredShadowFullbrightAlphaMaskProgram.uniform1f(LLShaderMgr::DEFERRED_SHADOW_TARGET_WIDTH, (float)target_width);
-            gDeferredShadowFullbrightAlphaMaskProgram.uniform1i(LLShaderMgr::SUN_UP_FACTOR, environment.getIsSunUp() ? 1 : 0);
-            renderFullbrightMaskedObjects(LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK, mask, TRUE, TRUE);
-        }
+            bool rigged = i == 1;
 
-		mask = mask & ~LLVertexBuffer::MAP_TEXTURE_INDEX;
+            gDeferredShadowAlphaMaskProgram.bind(rigged);
+            LLGLSLShader::sCurBoundShaderPtr->uniform1f(LLShaderMgr::DEFERRED_SHADOW_TARGET_WIDTH, (float)target_width);
+            LLGLSLShader::sCurBoundShaderPtr->uniform1i(LLShaderMgr::SUN_UP_FACTOR, environment.getIsSunUp() ? 1 : 0);
 
-        {
-            LL_RECORD_BLOCK_TIME(FTM_SHADOW_ALPHA_TREE);
-		gDeferredTreeShadowProgram.bind();
-            gDeferredTreeShadowProgram.uniform1i(LLShaderMgr::SUN_UP_FACTOR, environment.getIsSunUp() ? 1 : 0);
-		renderMaskedObjects(LLRenderPass::PASS_NORMSPEC_MASK, mask);
-		renderMaskedObjects(LLRenderPass::PASS_MATERIAL_ALPHA_MASK, mask);
-		renderMaskedObjects(LLRenderPass::PASS_SPECMAP_MASK, mask);
-		renderMaskedObjects(LLRenderPass::PASS_NORMMAP_MASK, mask);
+            U32 mask = LLVertexBuffer::MAP_VERTEX |
+                LLVertexBuffer::MAP_TEXCOORD0 |
+                LLVertexBuffer::MAP_COLOR |
+                LLVertexBuffer::MAP_TEXTURE_INDEX;
+
+            {
+                LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("shadow alpha masked"); //LL_RECORD_BLOCK_TIME(FTM_SHADOW_ALPHA_MASKED);
+                renderMaskedObjects(LLRenderPass::PASS_ALPHA_MASK, mask, TRUE, TRUE, rigged);
+            }
+
+            {
+                LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("shadow alpha blend"); //LL_RECORD_BLOCK_TIME(FTM_SHADOW_ALPHA_BLEND);
+                LLGLSLShader::sCurBoundShaderPtr->setMinimumAlpha(0.598f);
+                renderAlphaObjects(mask, TRUE, TRUE, rigged);
+            }
+
+
+            {
+                LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("shadow fullbright alpha masked"); //LL_RECORD_BLOCK_TIME(FTM_SHADOW_FULLBRIGHT_ALPHA_MASKED);
+                gDeferredShadowFullbrightAlphaMaskProgram.bind(rigged);
+                LLGLSLShader::sCurBoundShaderPtr->uniform1f(LLShaderMgr::DEFERRED_SHADOW_TARGET_WIDTH, (float)target_width);
+                LLGLSLShader::sCurBoundShaderPtr->uniform1i(LLShaderMgr::SUN_UP_FACTOR, environment.getIsSunUp() ? 1 : 0);
+                renderFullbrightMaskedObjects(LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK, mask, TRUE, TRUE, rigged);
+            }
+
+
+            {
+                LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("shadow alpha grass"); //LL_RECORD_BLOCK_TIME(FTM_SHADOW_ALPHA_GRASS);
+                gDeferredTreeShadowProgram.bind(rigged);
+                if (i == 0)
+                {
+                    LLGLSLShader::sCurBoundShaderPtr->setMinimumAlpha(0.598f);
+                    renderObjects(LLRenderPass::PASS_GRASS, LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0, TRUE);
+                }
+
+                U32 no_idx_mask = mask & ~LLVertexBuffer::MAP_TEXTURE_INDEX;
+                renderMaskedObjects(LLRenderPass::PASS_NORMSPEC_MASK, no_idx_mask, true, false, rigged);
+                renderMaskedObjects(LLRenderPass::PASS_MATERIAL_ALPHA_MASK, no_idx_mask, true, false, rigged);
+                renderMaskedObjects(LLRenderPass::PASS_SPECMAP_MASK, no_idx_mask, true, false, rigged);
+                renderMaskedObjects(LLRenderPass::PASS_NORMMAP_MASK, no_idx_mask, true, false, rigged);
+            }
         }
-		
-        {
-            LL_RECORD_BLOCK_TIME(FTM_SHADOW_ALPHA_GRASS);
-		gDeferredTreeShadowProgram.setMinimumAlpha(0.598f);
-		renderObjects(LLRenderPass::PASS_GRASS, LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0, TRUE);
-	}
     }
 
-	//glCullFace(GL_BACK);
+    //glCullFace(GL_BACK);
 
-	gDeferredShadowCubeProgram.bind();
-	gGLLastMatrix = NULL;
-	gGL.loadMatrix(gGLModelView);
+    gDeferredShadowCubeProgram.bind();
+    gGLLastMatrix = NULL;
+    gGL.loadMatrix(gGLModelView);
 
-	LLRenderTarget& occlusion_source = mShadow[LLViewerCamera::sCurCameraID-1];
+    LLRenderTarget& occlusion_source = mShadow[LLViewerCamera::sCurCameraID - 1];
 
-	doOcclusion(shadow_cam, occlusion_source, occlusion_target);
+    doOcclusion(shadow_cam, occlusion_source, occlusion_target);
 
-	if (use_shader)
-	{
-		gDeferredShadowProgram.unbind();
-	}
-	
-	gGL.setColorMask(true, true);
-			
-	gGL.matrixMode(LLRender::MM_PROJECTION);
-	gGL.popMatrix();
-	gGL.matrixMode(LLRender::MM_MODELVIEW);
-	gGL.popMatrix();
-	gGLLastMatrix = NULL;
+    if (use_shader)
+    {
+        gDeferredShadowProgram.unbind();
+    }
 
-	LLPipeline::sUseOcclusion = occlude;
-	LLPipeline::sShadowRender = false;
+    gGL.setColorMask(true, true);
+
+    gGL.matrixMode(LLRender::MM_PROJECTION);
+    gGL.popMatrix();
+    gGL.matrixMode(LLRender::MM_MODELVIEW);
+    gGL.popMatrix();
+    gGLLastMatrix = NULL;
+
+    LLPipeline::sUseOcclusion = occlude;
+    LLPipeline::sShadowRender = false;
 }
 
-static LLTrace::BlockTimerStatHandle FTM_VISIBLE_CLOUD("Visible Cloud");
 bool LLPipeline::getVisiblePointCloud(LLCamera& camera, LLVector3& min, LLVector3& max, std::vector<LLVector3>& fp, LLVector3 light_dir)
 {
-	LL_RECORD_BLOCK_TIME(FTM_VISIBLE_CLOUD);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
 	//get point cloud of intersection of frust and min, max
 
 	if (getVisibleExtents(camera, min, max))
@@ -10044,10 +9953,7 @@ void LLPipeline::generateHighlight(LLCamera& camera)
 		gGL.setColorMask(true, true);
 		mHighlight.clear();
 
-        if (LLGLSLShader::sNoFixedFunction)
-        {
-            gHighlightProgram.bind();
-        }
+        gHighlightProgram.bind();
 
 		gGL.getTexUnit(0)->bind(LLViewerFetchedTexture::sWhiteImagep);
 		for (std::set<HighlightItem>::iterator iter = mHighlightSet.begin(); iter != mHighlightSet.end(); )
@@ -10089,9 +9995,6 @@ LLRenderTarget* LLPipeline::getShadowTarget(U32 i)
 }
 
 static LLTrace::BlockTimerStatHandle FTM_GEN_SUN_SHADOW("Gen Sun Shadow");
-static LLTrace::BlockTimerStatHandle FTM_GEN_SUN_SHADOW_SETUP("Sun Shadow Setup");
-static LLTrace::BlockTimerStatHandle FTM_GEN_SUN_SHADOW_RENDER_DIRECTIONAL("Render Dir");
-static LLTrace::BlockTimerStatHandle FTM_GEN_SUN_SHADOW_SPOT_SETUP("Spot Shadow Setup");
 static LLTrace::BlockTimerStatHandle FTM_GEN_SUN_SHADOW_SPOT_RENDER("Spot Shadow Render");
 
 void LLPipeline::generateSunShadow(LLCamera& camera)
@@ -10101,7 +10004,7 @@ void LLPipeline::generateSunShadow(LLCamera& camera)
 		return;
 	}
 
-	LL_RECORD_BLOCK_TIME(FTM_GEN_SUN_SHADOW);
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE; //LL_RECORD_BLOCK_TIME(FTM_GEN_SUN_SHADOW);
 
 	bool skip_avatar_update = false;
 	if (!isAgentAvatarValid() || gAgentCamera.getCameraAnimating() || gAgentCamera.getCameraMode() != CAMERA_MODE_MOUSELOOK || !LLVOAvatar::sVisibleInFirstPerson)
@@ -10161,6 +10064,29 @@ void LLPipeline::generateSunShadow(LLCamera& camera)
 					LLPipeline::RENDER_TYPE_PASS_NORMSPEC_BLEND,
 					LLPipeline::RENDER_TYPE_PASS_NORMSPEC_MASK,
 					LLPipeline::RENDER_TYPE_PASS_NORMSPEC_EMISSIVE,
+                    LLPipeline::RENDER_TYPE_PASS_ALPHA_MASK_RIGGED,
+                    LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_ALPHA_MASK_RIGGED,
+                    LLPipeline::RENDER_TYPE_PASS_SIMPLE_RIGGED,
+                    LLPipeline::RENDER_TYPE_PASS_BUMP_RIGGED,
+                    LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_RIGGED,
+                    LLPipeline::RENDER_TYPE_PASS_SHINY_RIGGED,
+                    LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_SHINY_RIGGED,
+                    LLPipeline::RENDER_TYPE_PASS_MATERIAL_RIGGED,
+                    LLPipeline::RENDER_TYPE_PASS_MATERIAL_ALPHA_RIGGED,
+                    LLPipeline::RENDER_TYPE_PASS_MATERIAL_ALPHA_MASK_RIGGED,
+                    LLPipeline::RENDER_TYPE_PASS_MATERIAL_ALPHA_EMISSIVE_RIGGED,
+                    LLPipeline::RENDER_TYPE_PASS_SPECMAP_RIGGED,
+                    LLPipeline::RENDER_TYPE_PASS_SPECMAP_BLEND_RIGGED,
+                    LLPipeline::RENDER_TYPE_PASS_SPECMAP_MASK_RIGGED,
+                    LLPipeline::RENDER_TYPE_PASS_SPECMAP_EMISSIVE_RIGGED,
+                    LLPipeline::RENDER_TYPE_PASS_NORMMAP_RIGGED,
+                    LLPipeline::RENDER_TYPE_PASS_NORMMAP_BLEND_RIGGED,
+                    LLPipeline::RENDER_TYPE_PASS_NORMMAP_MASK_RIGGED,
+                    LLPipeline::RENDER_TYPE_PASS_NORMMAP_EMISSIVE_RIGGED,
+                    LLPipeline::RENDER_TYPE_PASS_NORMSPEC_RIGGED,
+                    LLPipeline::RENDER_TYPE_PASS_NORMSPEC_BLEND_RIGGED,
+                    LLPipeline::RENDER_TYPE_PASS_NORMSPEC_MASK_RIGGED,
+                    LLPipeline::RENDER_TYPE_PASS_NORMSPEC_EMISSIVE_RIGGED,
 					END_RENDER_TYPES);
 
 	gGL.setColorMask(false, false);
@@ -10887,17 +10813,28 @@ void LLPipeline::renderGroups(LLRenderPass* pass, U32 type, U32 mask, bool textu
 	}
 }
 
-static LLTrace::BlockTimerStatHandle FTM_IMPOSTOR_MARK_VISIBLE("Impostor Mark Visible");
-static LLTrace::BlockTimerStatHandle FTM_IMPOSTOR_SETUP("Impostor Setup");
-static LLTrace::BlockTimerStatHandle FTM_IMPOSTOR_BACKGROUND("Impostor Background");
-static LLTrace::BlockTimerStatHandle FTM_IMPOSTOR_ALLOCATE("Impostor Allocate");
-static LLTrace::BlockTimerStatHandle FTM_IMPOSTOR_RESIZE("Impostor Resize");
+void LLPipeline::renderRiggedGroups(LLRenderPass* pass, U32 type, U32 mask, bool texture)
+{
+    for (LLCullResult::sg_iterator i = sCull->beginVisibleGroups(); i != sCull->endVisibleGroups(); ++i)
+    {
+        LLSpatialGroup* group = *i;
+        if (!group->isDead() &&
+            (!sUseOcclusion || !group->isOcclusionState(LLSpatialGroup::OCCLUDED)) &&
+            gPipeline.hasRenderType(group->getSpatialPartition()->mDrawableType) &&
+            group->mDrawMap.find(type) != group->mDrawMap.end())
+        {
+            pass->renderRiggedGroup(group, type, mask, texture);
+        }
+    }
+}
+
+static LLTrace::BlockTimerStatHandle FTM_GENERATE_IMPOSTOR("Generate Impostor");
 
-void LLPipeline::generateImpostor(LLVOAvatar* avatar)
+void LLPipeline::generateImpostor(LLVOAvatar* avatar, bool preview_avatar)
 {
+    LL_RECORD_BLOCK_TIME(FTM_GENERATE_IMPOSTOR);
 	LLGLState::checkStates();
 	LLGLState::checkTextureChannels();
-	LLGLState::checkClientArrays();
 
 	static LLCullResult result;
 	result.clear();
@@ -10912,11 +10849,12 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar)
 
 	assertInitialized();
 
-	bool visually_muted = avatar->isVisuallyMuted();		
+    // previews can't be muted or impostered
+	bool visually_muted = !preview_avatar && avatar->isVisuallyMuted();
     LL_DEBUGS_ONCE("AvatarRenderPipeline") << "Avatar " << avatar->getID()
                               << " is " << ( visually_muted ? "" : "not ") << "visually muted"
                               << LL_ENDL;
-	bool too_complex = avatar->isTooComplex();		
+	bool too_complex = !preview_avatar && avatar->isTooComplex();
     LL_DEBUGS_ONCE("AvatarRenderPipeline") << "Avatar " << avatar->getID()
                               << " is " << ( too_complex ? "" : "not ") << "too complex"
                               << LL_ENDL;
@@ -10925,37 +10863,31 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar)
 	
 	if (visually_muted || too_complex)
 	{
+        // only show jelly doll geometry
 		andRenderTypeMask(LLPipeline::RENDER_TYPE_AVATAR,
 							LLPipeline::RENDER_TYPE_CONTROL_AV,
 							END_RENDER_TYPES);
 	}
 	else
 	{
-		andRenderTypeMask(LLPipeline::RENDER_TYPE_ALPHA,
-			LLPipeline::RENDER_TYPE_FULLBRIGHT,
-			LLPipeline::RENDER_TYPE_VOLUME,
-			LLPipeline::RENDER_TYPE_GLOW,
-						LLPipeline::RENDER_TYPE_BUMP,
-						LLPipeline::RENDER_TYPE_PASS_SIMPLE,
-						LLPipeline::RENDER_TYPE_PASS_ALPHA,
-						LLPipeline::RENDER_TYPE_PASS_ALPHA_MASK,
-			LLPipeline::RENDER_TYPE_PASS_BUMP,
-			LLPipeline::RENDER_TYPE_PASS_POST_BUMP,
-						LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT,
-						LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_ALPHA_MASK,
-						LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_SHINY,
-			LLPipeline::RENDER_TYPE_PASS_GLOW,
-			LLPipeline::RENDER_TYPE_PASS_GRASS,
-						LLPipeline::RENDER_TYPE_PASS_SHINY,
-						LLPipeline::RENDER_TYPE_PASS_INVISIBLE,
-						LLPipeline::RENDER_TYPE_PASS_INVISI_SHINY,
-			LLPipeline::RENDER_TYPE_AVATAR,
-			LLPipeline::RENDER_TYPE_CONTROL_AV,
-			LLPipeline::RENDER_TYPE_ALPHA_MASK,
-			LLPipeline::RENDER_TYPE_FULLBRIGHT_ALPHA_MASK,
-			LLPipeline::RENDER_TYPE_INVISIBLE,
-			LLPipeline::RENDER_TYPE_SIMPLE,
-						END_RENDER_TYPES);
+        //hide world geometry
+        clearRenderTypeMask(
+            RENDER_TYPE_SKY,
+            RENDER_TYPE_WL_SKY,
+            RENDER_TYPE_GROUND,
+            RENDER_TYPE_TERRAIN,
+            RENDER_TYPE_GRASS,
+            RENDER_TYPE_CONTROL_AV, // Animesh
+            RENDER_TYPE_TREE,
+            RENDER_TYPE_VOIDWATER,
+            RENDER_TYPE_WATER,
+            RENDER_TYPE_PASS_GRASS,
+            RENDER_TYPE_HUD,
+            RENDER_TYPE_PARTICLES,
+            RENDER_TYPE_CLOUDS,
+            RENDER_TYPE_HUD_PARTICLES,
+            END_RENDER_TYPES
+         );
 	}
 	
 	S32 occlusion = sUseOcclusion;
@@ -10969,25 +10901,49 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar)
 	LLViewerCamera* viewer_camera = LLViewerCamera::getInstance();
 
 	{
-		LL_RECORD_BLOCK_TIME(FTM_IMPOSTOR_MARK_VISIBLE);
 		markVisible(avatar->mDrawable, *viewer_camera);
 
-		LLVOAvatar::attachment_map_t::iterator iter;
-		for (iter = avatar->mAttachmentPoints.begin();
-			iter != avatar->mAttachmentPoints.end();
-			++iter)
-		{
-			LLViewerJointAttachment *attachment = iter->second;
-			for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin();
-				 attachment_iter != attachment->mAttachedObjects.end();
-				 ++attachment_iter)
-			{
-				if (LLViewerObject* attached_object = attachment_iter->get())
-				{
-					markVisible(attached_object->mDrawable->getSpatialBridge(), *viewer_camera);
-				}
-			}
-		}
+        if (preview_avatar)
+        {
+            // Only show rigged attachments for preview
+            LLVOAvatar::attachment_map_t::iterator iter;
+            for (iter = avatar->mAttachmentPoints.begin();
+                iter != avatar->mAttachmentPoints.end();
+                ++iter)
+            {
+                LLViewerJointAttachment *attachment = iter->second;
+                for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin();
+                    attachment_iter != attachment->mAttachedObjects.end();
+                    ++attachment_iter)
+                {
+                    LLViewerObject* attached_object = attachment_iter->get();
+                    if (attached_object && attached_object->isRiggedMesh())
+                    {
+                        markVisible(attached_object->mDrawable->getSpatialBridge(), *viewer_camera);
+                    }
+                }
+            }
+        }
+        else
+        {
+            LLVOAvatar::attachment_map_t::iterator iter;
+            for (iter = avatar->mAttachmentPoints.begin();
+                iter != avatar->mAttachmentPoints.end();
+                ++iter)
+            {
+                LLViewerJointAttachment *attachment = iter->second;
+                for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin();
+                    attachment_iter != attachment->mAttachedObjects.end();
+                    ++attachment_iter)
+                {
+                    LLViewerObject* attached_object = attachment_iter->get();
+                    if (attached_object)
+                    {
+                        markVisible(attached_object->mDrawable->getSpatialBridge(), *viewer_camera);
+                    }
+                }
+            }
+        }
 	}
 
 	stateSort(*LLViewerCamera::getInstance(), result);
@@ -10997,8 +10953,8 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar)
 	U32 resY = 0;
 	U32 resX = 0;
 
+    if (!preview_avatar)
 	{
-		LL_RECORD_BLOCK_TIME(FTM_IMPOSTOR_SETUP);
 		const LLVector4a* ext = avatar->mDrawable->getSpatialExtents();
 		LLVector3 pos(avatar->getRenderPosition()+avatar->getImpostorOffset());
 
@@ -11055,17 +11011,11 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar)
 
 		if (!avatar->mImpostor.isComplete())
 		{
-			LL_RECORD_BLOCK_TIME(FTM_IMPOSTOR_ALLOCATE);
-			
+            avatar->mImpostor.allocate(resX, resY, GL_RGBA, TRUE, FALSE);
 
 			if (LLPipeline::sRenderDeferred)
 			{
-				avatar->mImpostor.allocate(resX,resY,GL_SRGB8_ALPHA8,TRUE,FALSE);
-				addDeferredAttachments(avatar->mImpostor);
-			}
-			else
-			{
-				avatar->mImpostor.allocate(resX,resY,GL_RGBA,TRUE,FALSE);
+				addDeferredAttachments(avatar->mImpostor, true);
 			}
 		
 			gGL.getTexUnit(0)->bind(&avatar->mImpostor);
@@ -11074,7 +11024,6 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar)
 		}
 		else if(resX != avatar->mImpostor.getWidth() || resY != avatar->mImpostor.getHeight())
 		{
-			LL_RECORD_BLOCK_TIME(FTM_IMPOSTOR_RESIZE);
 			avatar->mImpostor.resize(resX,resY);
 		}
 
@@ -11088,7 +11037,20 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar)
 		LLDrawPoolAvatar::sMinimumAlpha = 0.f;
 	}
 
-	if (LLPipeline::sRenderDeferred)
+    if (preview_avatar)
+    {
+        // previews don't care about imposters
+        if (LLPipeline::sRenderDeferred)
+        {
+            renderGeomDeferred(camera);
+            renderGeomPostDeferred(camera);
+        }
+        else
+        {
+            renderGeom(camera);
+        }
+    }
+    else if (LLPipeline::sRenderDeferred)
 	{
 		avatar->mImpostor.clear();
 		renderGeomDeferred(camera);
@@ -11136,10 +11098,10 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar)
 	LLDrawPoolAvatar::sMinimumAlpha = old_alpha;
 
 	{ //create alpha mask based on depth buffer (grey out if muted)
-		LL_RECORD_BLOCK_TIME(FTM_IMPOSTOR_BACKGROUND);
 		if (LLPipeline::sRenderDeferred)
 		{
 			GLuint buff = GL_COLOR_ATTACHMENT0;
+			LL_PROFILER_GPU_ZONEC( "gl.DrawBuffersARB", 0x8000FF );
 			glDrawBuffersARB(1, &buff);
 		}
 
@@ -11168,11 +11130,7 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar)
 
 		static const F32 clip_plane = 0.99999f;
 
-		if (LLGLSLShader::sNoFixedFunction)
-		{
-			gDebugProgram.bind();
-		}
-
+		gDebugProgram.bind();
 
 		if (visually_muted)
 		{	// Visually muted avatar
@@ -11180,13 +11138,12 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar)
             LL_DEBUGS_ONCE("AvatarRenderPipeline") << "Avatar " << avatar->getID() << " MUTED set solid color " << muted_color << LL_ENDL;
 			gGL.diffuseColor4fv( muted_color.mV );
 		}
-		else
+		else if (!preview_avatar)
 		{ //grey muted avatar
             LL_DEBUGS_ONCE("AvatarRenderPipeline") << "Avatar " << avatar->getID() << " MUTED set grey" << LL_ENDL;
 			gGL.diffuseColor4fv(LLColor4::pink.mV );
 		}
 
-		{
 		gGL.begin(LLRender::QUADS);
 		gGL.vertex3f(-1, -1, clip_plane);
 		gGL.vertex3f(1, -1, clip_plane);
@@ -11194,21 +11151,19 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar)
 		gGL.vertex3f(-1, 1, clip_plane);
 		gGL.end();
 		gGL.flush();
-		}
 
-		if (LLGLSLShader::sNoFixedFunction)
-		{
-			gDebugProgram.unbind();
-		}
+		gDebugProgram.unbind();
 
 		gGL.popMatrix();
 		gGL.matrixMode(LLRender::MM_MODELVIEW);
 		gGL.popMatrix();
 	}
 
-	avatar->mImpostor.flush();
-
-	avatar->setImpostorDim(tdim);
+    if (!preview_avatar)
+    {
+        avatar->mImpostor.flush();
+        avatar->setImpostorDim(tdim);
+    }
 
 	sUseOcclusion = occlusion;
 	sReflectionRender = false;
@@ -11221,14 +11176,16 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar)
 	gGL.matrixMode(LLRender::MM_MODELVIEW);
 	gGL.popMatrix();
 
-	avatar->mNeedsImpostorUpdate = FALSE;
-	avatar->cacheImpostorValues();
-	avatar->mLastImpostorUpdateFrameTime = gFrameTimeSeconds;
+    if (!preview_avatar)
+    {
+        avatar->mNeedsImpostorUpdate = FALSE;
+        avatar->cacheImpostorValues();
+        avatar->mLastImpostorUpdateFrameTime = gFrameTimeSeconds;
+    }
 
 	LLVertexBuffer::unbind();
 	LLGLState::checkStates();
 	LLGLState::checkTextureChannels();
-	LLGLState::checkClientArrays();
 }
 
 bool LLPipeline::hasRenderBatches(const U32 type) const
@@ -11256,6 +11213,16 @@ LLCullResult::sg_iterator LLPipeline::endAlphaGroups()
 	return sCull->endAlphaGroups();
 }
 
+LLCullResult::sg_iterator LLPipeline::beginRiggedAlphaGroups()
+{
+    return sCull->beginRiggedAlphaGroups();
+}
+
+LLCullResult::sg_iterator LLPipeline::endRiggedAlphaGroups()
+{
+    return sCull->endRiggedAlphaGroups();
+}
+
 bool LLPipeline::hasRenderType(const U32 type) const
 {
     // STORM-365 : LLViewerJointAttachment::setAttachmentVisibility() is setting type to 0 to actually mean "do not render"
diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h
index 0eaa6b141d8b51d3fe68123ad6362776133c8757..62d3ae7a398884ffa2129f22892ca7258f6a73ea 100644
--- a/indra/newview/pipeline.h
+++ b/indra/newview/pipeline.h
@@ -66,7 +66,6 @@ bool setup_hud_matrices(const LLRect& screen_region); // specify portion of scre
 extern LLTrace::BlockTimerStatHandle FTM_RENDER_GEOMETRY;
 extern LLTrace::BlockTimerStatHandle FTM_RENDER_GRASS;
 extern LLTrace::BlockTimerStatHandle FTM_RENDER_INVISIBLE;
-extern LLTrace::BlockTimerStatHandle FTM_RENDER_OCCLUSION;
 extern LLTrace::BlockTimerStatHandle FTM_RENDER_SHINY;
 extern LLTrace::BlockTimerStatHandle FTM_RENDER_SIMPLE;
 extern LLTrace::BlockTimerStatHandle FTM_RENDER_TERRAIN;
@@ -87,8 +86,6 @@ extern LLTrace::BlockTimerStatHandle FTM_CLIENT_COPY;
 extern LLTrace::BlockTimerStatHandle FTM_RENDER_UI_HUD;
 extern LLTrace::BlockTimerStatHandle FTM_RENDER_UI_3D;
 extern LLTrace::BlockTimerStatHandle FTM_RENDER_UI_2D;
-extern LLTrace::BlockTimerStatHandle FTM_RENDER_UI_DEBUG_TEXT;
-extern LLTrace::BlockTimerStatHandle FTM_RENDER_UI_SCENE_MON;
 
 class LLPipeline
 {
@@ -137,7 +134,7 @@ class LLPipeline
 	void allocatePhysicsBuffer();
 	
 	void resetVertexBuffers(LLDrawable* drawable);
-	void generateImpostor(LLVOAvatar* avatar);
+	void generateImpostor(LLVOAvatar* avatar, bool preview_avatar = false);
 	void bindScreenToTexture();
 	void renderFinalize();
 
@@ -228,9 +225,7 @@ class LLPipeline
 	S32			getLightingDetail() const { return mLightingDetail; }
 	S32			getMaxLightingDetail() const;
 		
-	void		setUseVertexShaders(bool use_shaders);
-	bool		getUseVertexShaders() const { return mVertexShadersEnabled; }
-	bool		canUseVertexShaders();
+	bool		shadersLoaded();
 	bool		canUseWindLightShaders() const;
 	bool		canUseWindLightShadersOnObjects() const;
 	bool		canUseAntiAliasing() const;
@@ -245,7 +240,7 @@ class LLPipeline
 	bool visibleObjectsInFrustum(LLCamera& camera);
 	bool getVisibleExtents(LLCamera& camera, LLVector3 &min, LLVector3& max);
 	bool getVisiblePointCloud(LLCamera& camera, LLVector3 &min, LLVector3& max, std::vector<LLVector3>& fp, LLVector3 light_dir = LLVector3(0,0,0));
-	void updateCull(LLCamera& camera, LLCullResult& result, S32 water_clip = 0, LLPlane* plane = NULL);  //if water_clip is 0, ignore water plane, 1, cull to above plane, -1, cull to below plane
+	void updateCull(LLCamera& camera, LLCullResult& result, LLPlane* plane = NULL);  //if water_clip is 0, ignore water plane, 1, cull to above plane, -1, cull to below plane
 	void createObjects(F32 max_dtime);
 	void createObject(LLViewerObject* vobj);
 	void processPartitionQ();
@@ -265,13 +260,20 @@ class LLPipeline
 	void stateSort(LLSpatialBridge* bridge, LLCamera& camera, BOOL fov_changed = FALSE);
 	void stateSort(LLDrawable* drawablep, LLCamera& camera);
 	void postSort(LLCamera& camera);
+    
+    //update stats for textures in given DrawInfo
+    void touchTextures(LLDrawInfo* info);
+    void touchTexture(LLViewerTexture* tex, F32 vsize);
+
 	void forAllVisibleDrawables(void (*func)(LLDrawable*));
 
-	void renderObjects(U32 type, U32 mask, bool texture = true, bool batch_texture = false);
-	void renderMaskedObjects(U32 type, U32 mask, bool texture = true, bool batch_texture = false);
-    void renderFullbrightMaskedObjects(U32 type, U32 mask, bool texture = true, bool batch_texture = false);
+    void renderObjects(U32 type, U32 mask, bool texture = true, bool batch_texture = false, bool rigged = false);
+    void renderAlphaObjects(U32 mask, bool texture = true, bool batch_texture = false, bool rigged = false);
+	void renderMaskedObjects(U32 type, U32 mask, bool texture = true, bool batch_texture = false, bool rigged = false);
+    void renderFullbrightMaskedObjects(U32 type, U32 mask, bool texture = true, bool batch_texture = false, bool rigged = false);
 
 	void renderGroups(LLRenderPass* pass, U32 type, U32 mask, bool texture);
+    void renderRiggedGroups(LLRenderPass* pass, U32 type, U32 mask, bool texture);
 
 	void grabReferences(LLCullResult& result);
 	void clearReferences();
@@ -336,6 +338,8 @@ class LLPipeline
 	LLCullResult::drawinfo_iterator endRenderMap(U32 type);
 	LLCullResult::sg_iterator beginAlphaGroups();
 	LLCullResult::sg_iterator endAlphaGroups();
+    LLCullResult::sg_iterator beginRiggedAlphaGroups();
+    LLCullResult::sg_iterator endRiggedAlphaGroups();
 	
 
 	void addTrianglesDrawn(S32 index_count, U32 render_type = LLRender::TRIANGLES);
@@ -458,34 +462,61 @@ class LLPipeline
  		RENDER_TYPE_ALPHA						= LLDrawPool::POOL_ALPHA,
 		RENDER_TYPE_GLOW						= LLDrawPool::POOL_GLOW,
 		RENDER_TYPE_PASS_SIMPLE 				= LLRenderPass::PASS_SIMPLE,
+        RENDER_TYPE_PASS_SIMPLE_RIGGED = LLRenderPass::PASS_SIMPLE_RIGGED,
 		RENDER_TYPE_PASS_GRASS					= LLRenderPass::PASS_GRASS,
 		RENDER_TYPE_PASS_FULLBRIGHT				= LLRenderPass::PASS_FULLBRIGHT,
+        RENDER_TYPE_PASS_FULLBRIGHT_RIGGED = LLRenderPass::PASS_FULLBRIGHT,
 		RENDER_TYPE_PASS_INVISIBLE				= LLRenderPass::PASS_INVISIBLE,
+        RENDER_TYPE_PASS_INVISIBLE_RIGGED = LLRenderPass::PASS_INVISIBLE_RIGGED,
 		RENDER_TYPE_PASS_INVISI_SHINY			= LLRenderPass::PASS_INVISI_SHINY,
+        RENDER_TYPE_PASS_INVISI_SHINY_RIGGED = LLRenderPass::PASS_INVISI_SHINY_RIGGED,
 		RENDER_TYPE_PASS_FULLBRIGHT_SHINY		= LLRenderPass::PASS_FULLBRIGHT_SHINY,
+        RENDER_TYPE_PASS_FULLBRIGHT_SHINY_RIGGED = LLRenderPass::PASS_FULLBRIGHT_SHINY_RIGGED,
 		RENDER_TYPE_PASS_SHINY					= LLRenderPass::PASS_SHINY,
+        RENDER_TYPE_PASS_SHINY_RIGGED = LLRenderPass::PASS_SHINY_RIGGED,
 		RENDER_TYPE_PASS_BUMP					= LLRenderPass::PASS_BUMP,
+        RENDER_TYPE_PASS_BUMP_RIGGED = LLRenderPass::PASS_BUMP_RIGGED,
 		RENDER_TYPE_PASS_POST_BUMP				= LLRenderPass::PASS_POST_BUMP,
+        RENDER_TYPE_PASS_POST_BUMP_RIGGED = LLRenderPass::PASS_POST_BUMP_RIGGED,
 		RENDER_TYPE_PASS_GLOW					= LLRenderPass::PASS_GLOW,
+        RENDER_TYPE_PASS_GLOW_RIGGED = LLRenderPass::PASS_GLOW_RIGGED,
 		RENDER_TYPE_PASS_ALPHA					= LLRenderPass::PASS_ALPHA,
 		RENDER_TYPE_PASS_ALPHA_MASK				= LLRenderPass::PASS_ALPHA_MASK,
+        RENDER_TYPE_PASS_ALPHA_MASK_RIGGED = LLRenderPass::PASS_ALPHA_MASK_RIGGED,
 		RENDER_TYPE_PASS_FULLBRIGHT_ALPHA_MASK	= LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK,
+        RENDER_TYPE_PASS_FULLBRIGHT_ALPHA_MASK_RIGGED = LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK_RIGGED,
 		RENDER_TYPE_PASS_MATERIAL				= LLRenderPass::PASS_MATERIAL,
+        RENDER_TYPE_PASS_MATERIAL_RIGGED = LLRenderPass::PASS_MATERIAL_RIGGED,
 		RENDER_TYPE_PASS_MATERIAL_ALPHA			= LLRenderPass::PASS_MATERIAL_ALPHA,
+        RENDER_TYPE_PASS_MATERIAL_ALPHA_RIGGED = LLRenderPass::PASS_MATERIAL_ALPHA_RIGGED,
 		RENDER_TYPE_PASS_MATERIAL_ALPHA_MASK	= LLRenderPass::PASS_MATERIAL_ALPHA_MASK,
+        RENDER_TYPE_PASS_MATERIAL_ALPHA_MASK_RIGGED = LLRenderPass::PASS_MATERIAL_ALPHA_MASK_RIGGED,
 		RENDER_TYPE_PASS_MATERIAL_ALPHA_EMISSIVE= LLRenderPass::PASS_MATERIAL_ALPHA_EMISSIVE,
+        RENDER_TYPE_PASS_MATERIAL_ALPHA_EMISSIVE_RIGGED = LLRenderPass::PASS_MATERIAL_ALPHA_EMISSIVE_RIGGED,
 		RENDER_TYPE_PASS_SPECMAP				= LLRenderPass::PASS_SPECMAP,
+        RENDER_TYPE_PASS_SPECMAP_RIGGED = LLRenderPass::PASS_SPECMAP_RIGGED,
 		RENDER_TYPE_PASS_SPECMAP_BLEND			= LLRenderPass::PASS_SPECMAP_BLEND,
+        RENDER_TYPE_PASS_SPECMAP_BLEND_RIGGED = LLRenderPass::PASS_SPECMAP_BLEND_RIGGED,
 		RENDER_TYPE_PASS_SPECMAP_MASK			= LLRenderPass::PASS_SPECMAP_MASK,
+        RENDER_TYPE_PASS_SPECMAP_MASK_RIGGED = LLRenderPass::PASS_SPECMAP_MASK_RIGGED,
 		RENDER_TYPE_PASS_SPECMAP_EMISSIVE		= LLRenderPass::PASS_SPECMAP_EMISSIVE,
+        RENDER_TYPE_PASS_SPECMAP_EMISSIVE_RIGGED = LLRenderPass::PASS_SPECMAP_EMISSIVE_RIGGED,
 		RENDER_TYPE_PASS_NORMMAP				= LLRenderPass::PASS_NORMMAP,
+        RENDER_TYPE_PASS_NORMMAP_RIGGED = LLRenderPass::PASS_NORMMAP_RIGGED,
 		RENDER_TYPE_PASS_NORMMAP_BLEND			= LLRenderPass::PASS_NORMMAP_BLEND,
+        RENDER_TYPE_PASS_NORMMAP_BLEND_RIGGED = LLRenderPass::PASS_NORMMAP_BLEND_RIGGED,
 		RENDER_TYPE_PASS_NORMMAP_MASK			= LLRenderPass::PASS_NORMMAP_MASK,
+        RENDER_TYPE_PASS_NORMMAP_MASK_RIGGED = LLRenderPass::PASS_NORMMAP_MASK_RIGGED,
 		RENDER_TYPE_PASS_NORMMAP_EMISSIVE		= LLRenderPass::PASS_NORMMAP_EMISSIVE,
+        RENDER_TYPE_PASS_NORMMAP_EMISSIVE_RIGGED = LLRenderPass::PASS_NORMMAP_EMISSIVE_RIGGED,
 		RENDER_TYPE_PASS_NORMSPEC				= LLRenderPass::PASS_NORMSPEC,
+        RENDER_TYPE_PASS_NORMSPEC_RIGGED = LLRenderPass::PASS_NORMSPEC_RIGGED,
 		RENDER_TYPE_PASS_NORMSPEC_BLEND			= LLRenderPass::PASS_NORMSPEC_BLEND,
+        RENDER_TYPE_PASS_NORMSPEC_BLEND_RIGGED = LLRenderPass::PASS_NORMSPEC_BLEND_RIGGED,
 		RENDER_TYPE_PASS_NORMSPEC_MASK			= LLRenderPass::PASS_NORMSPEC_MASK,
+        RENDER_TYPE_PASS_NORMSPEC_MASK_RIGGED = LLRenderPass::PASS_NORMSPEC_MASK_RIGGED,
 		RENDER_TYPE_PASS_NORMSPEC_EMISSIVE		= LLRenderPass::PASS_NORMSPEC_EMISSIVE,
+        RENDER_TYPE_PASS_NORMSPEC_EMISSIVE_RIGGED = LLRenderPass::PASS_NORMSPEC_EMISSIVE_RIGGED,
 		// Following are object types (only used in drawable mRenderType)
 		RENDER_TYPE_HUD = LLRenderPass::NUM_RENDER_TYPES,
 		RENDER_TYPE_VOLUME,
@@ -574,7 +605,6 @@ class LLPipeline
 	static bool				sDelayVBUpdate;
 	static bool				sAutoMaskAlphaDeferred;
 	static bool				sAutoMaskAlphaNonDeferred;
-	static bool				sDisableShaders; // if true, rendering will be done without shaders
 	static bool				sRenderTransparentWater;
 	static bool				sRenderBump;
 	static bool				sBakeSunlight;
@@ -597,7 +627,6 @@ class LLPipeline
 	static bool				sRenderAttachedParticles;
 	static bool				sRenderDeferred;
 	static S32				sVisibleLightCount;
-	static F32				sMinRenderSize;
 	static bool				sRenderingHUDs;
     static F32              sDistortionWaterClipPlaneMargin;
 
@@ -676,8 +705,7 @@ class LLPipeline
     LLVector4			mTransformedMoonDir;
 
 	bool					mInitialized;
-	bool					mVertexShadersEnabled;
-	S32						mVertexShadersLoaded; // 0 = no, 1 = yes, -1 = failed
+	bool					mShadersLoaded;
 
 	U32						mTransformFeedbackPrimitives; //number of primitives expected to be generated by transform feedback
 protected:
@@ -878,7 +906,6 @@ class LLPipeline
 
 	//cached settings
 	static bool WindLightUseAtmosShaders;
-	static bool RenderAvatarVP;
 	static bool RenderDeferred;
 	static F32 RenderDeferredSunWash;
 	static U32 RenderFSAASamples;
diff --git a/indra/newview/skins/default/colors.xml b/indra/newview/skins/default/colors.xml
index 7beb013fba7ad588b93816c6c80e802d93ef08da..c3ce83e834737203daa8e5c1459aad1041d6e76c 100644
--- a/indra/newview/skins/default/colors.xml
+++ b/indra/newview/skins/default/colors.xml
@@ -514,8 +514,8 @@
      name="MapFrustumColor"
      reference="White_10" />
     <color
-     name="MapFrustumRotatingColor"
-     value="1 1 1 0.2" />
+     name="MapParcelOutlineColor"
+     value="1 1 0 0.5" />
     <color
      name="MapTrackColor"
      reference="Red" />
@@ -607,10 +607,10 @@
      value="0 0 0 1" />
     <color
      name="NetMapGroupOwnAboveWater"
-     reference="Purple" />
+     value="0.85 0 0.85 1" />
     <color
      name="NetMapGroupOwnBelowWater"
-     value="0.78 0 0.78 1" />
+     value="0.63 0 0.63 1" />
     <color
      name="NetMapOtherOwnAboveWater"
      value="0.24 0.24 0.24 1" />
@@ -619,10 +619,10 @@
      value="0.12 0.12 0.12 1" />
     <color
      name="NetMapYouOwnAboveWater"
-     value="0 1 1 1" />
+     value="0 0.85 0.85 1" />
     <color
      name="NetMapYouOwnBelowWater"
-     value="0 0.78 0.78 1" />
+     value="0 0.63 0.63 1" />
     <color
      name="NotifyBoxColor"
      value="LtGray" />
@@ -886,6 +886,22 @@
       name="PanelNotificationListItem"
       value="0.3 0.3 0.3 .3" />
 
+	<!-- profiles -->
+    <color
+        name="StatusUserOnline"
+        reference="White" />
+    <color
+        name="StatusUserOffline"
+        reference="LtGray_35" />
+    <!-- Groups visible in own profiles -->
+    <color
+        name="GroupVisibleInProfile"
+        reference="TextBgFocusColor" />
+    <color
+        name="GroupHiddenInProfile"
+        reference="Gray" />
+    
+
   <!-- Generic color names (legacy) -->
   <color
     name="white"
diff --git a/indra/newview/skins/default/textures/icons/ClipboardMenu_Disabled.png b/indra/newview/skins/default/textures/icons/ClipboardMenu_Disabled.png
new file mode 100644
index 0000000000000000000000000000000000000000..9a81c5f94b65713dcac65f5e743639162bcb8481
Binary files /dev/null and b/indra/newview/skins/default/textures/icons/ClipboardMenu_Disabled.png differ
diff --git a/indra/newview/skins/default/textures/icons/ClipboardMenu_Off.png b/indra/newview/skins/default/textures/icons/ClipboardMenu_Off.png
new file mode 100644
index 0000000000000000000000000000000000000000..88012cf8d124c6a6cb083d597fb92c689f1f9c5f
Binary files /dev/null and b/indra/newview/skins/default/textures/icons/ClipboardMenu_Off.png differ
diff --git a/indra/newview/skins/default/textures/icons/ClipboardMenu_Press.png b/indra/newview/skins/default/textures/icons/ClipboardMenu_Press.png
new file mode 100644
index 0000000000000000000000000000000000000000..ab02e7d42d798f997296e721023759f7e6600d1f
Binary files /dev/null and b/indra/newview/skins/default/textures/icons/ClipboardMenu_Press.png differ
diff --git a/indra/newview/skins/default/textures/icons/ClipboardSmallMenu_Disabled.png b/indra/newview/skins/default/textures/icons/ClipboardSmallMenu_Disabled.png
new file mode 100644
index 0000000000000000000000000000000000000000..63b4bd212739ec9a9c54b782beb31a7b70a63c73
Binary files /dev/null and b/indra/newview/skins/default/textures/icons/ClipboardSmallMenu_Disabled.png differ
diff --git a/indra/newview/skins/default/textures/icons/ClipboardSmallMenu_Off.png b/indra/newview/skins/default/textures/icons/ClipboardSmallMenu_Off.png
new file mode 100644
index 0000000000000000000000000000000000000000..4200182b0cec4c7ff7aea2bf60232207640aad9f
Binary files /dev/null and b/indra/newview/skins/default/textures/icons/ClipboardSmallMenu_Off.png differ
diff --git a/indra/newview/skins/default/textures/icons/ClipboardSmallMenu_Press.png b/indra/newview/skins/default/textures/icons/ClipboardSmallMenu_Press.png
new file mode 100644
index 0000000000000000000000000000000000000000..e12887f4891a587ad029d994844bb9c0ac766022
Binary files /dev/null and b/indra/newview/skins/default/textures/icons/ClipboardSmallMenu_Press.png differ
diff --git a/indra/newview/skins/default/textures/icons/CopyBright.png b/indra/newview/skins/default/textures/icons/CopyBright.png
new file mode 100644
index 0000000000000000000000000000000000000000..8d21c4729543bee0f1ba77f1409f53e509b904e9
Binary files /dev/null and b/indra/newview/skins/default/textures/icons/CopyBright.png differ
diff --git a/indra/newview/skins/default/textures/icons/Profile_Friend_Offline.png b/indra/newview/skins/default/textures/icons/Profile_Friend_Offline.png
new file mode 100644
index 0000000000000000000000000000000000000000..aeba6b70f785ed9b7f01bb8662710c5f31ebf48f
Binary files /dev/null and b/indra/newview/skins/default/textures/icons/Profile_Friend_Offline.png differ
diff --git a/indra/newview/skins/default/textures/icons/Profile_Friend_Online.png b/indra/newview/skins/default/textures/icons/Profile_Friend_Online.png
new file mode 100644
index 0000000000000000000000000000000000000000..d668fd8dfa0460456e5b17b80fd63aac95d1c841
Binary files /dev/null and b/indra/newview/skins/default/textures/icons/Profile_Friend_Online.png differ
diff --git a/indra/newview/skins/default/textures/icons/Profile_Perm_Find_Disabled.png b/indra/newview/skins/default/textures/icons/Profile_Perm_Find_Disabled.png
new file mode 100644
index 0000000000000000000000000000000000000000..8f8caa10d84d90e3b34c88804711d845a2f08317
Binary files /dev/null and b/indra/newview/skins/default/textures/icons/Profile_Perm_Find_Disabled.png differ
diff --git a/indra/newview/skins/default/textures/icons/Profile_Perm_Find_Enabled.png b/indra/newview/skins/default/textures/icons/Profile_Perm_Find_Enabled.png
new file mode 100644
index 0000000000000000000000000000000000000000..42a209dda51f25e0d012d202526010f7449dfe1c
Binary files /dev/null and b/indra/newview/skins/default/textures/icons/Profile_Perm_Find_Enabled.png differ
diff --git a/indra/newview/skins/default/textures/icons/Profile_Perm_Objects_Disabled.png b/indra/newview/skins/default/textures/icons/Profile_Perm_Objects_Disabled.png
new file mode 100644
index 0000000000000000000000000000000000000000..644edf0ef611607ca797b5c3636eb8daa1f820a2
Binary files /dev/null and b/indra/newview/skins/default/textures/icons/Profile_Perm_Objects_Disabled.png differ
diff --git a/indra/newview/skins/default/textures/icons/Profile_Perm_Objects_Enabled.png b/indra/newview/skins/default/textures/icons/Profile_Perm_Objects_Enabled.png
new file mode 100644
index 0000000000000000000000000000000000000000..629c05ecb83947b0ab424ce7ed867747d4f4f006
Binary files /dev/null and b/indra/newview/skins/default/textures/icons/Profile_Perm_Objects_Enabled.png differ
diff --git a/indra/newview/skins/default/textures/icons/Profile_Perm_Online_Disabled.png b/indra/newview/skins/default/textures/icons/Profile_Perm_Online_Disabled.png
new file mode 100644
index 0000000000000000000000000000000000000000..ecf66c0ee100c4e5152357429d5e471be4386f91
Binary files /dev/null and b/indra/newview/skins/default/textures/icons/Profile_Perm_Online_Disabled.png differ
diff --git a/indra/newview/skins/default/textures/icons/Profile_Perm_Online_Enabled.png b/indra/newview/skins/default/textures/icons/Profile_Perm_Online_Enabled.png
new file mode 100644
index 0000000000000000000000000000000000000000..26123938fa11d606d0f4867854120701da771cc9
Binary files /dev/null and b/indra/newview/skins/default/textures/icons/Profile_Perm_Online_Enabled.png differ
diff --git a/indra/newview/skins/default/textures/icons/avaline_default_icon.jpg b/indra/newview/skins/default/textures/icons/avaline_default_icon.jpg
deleted file mode 100644
index 3bb7f7183cd751eddcabd75da8b9f1dc9e86f0f3..0000000000000000000000000000000000000000
Binary files a/indra/newview/skins/default/textures/icons/avaline_default_icon.jpg and /dev/null differ
diff --git a/indra/newview/skins/default/textures/icons/profile_group_visibility_eye_off.png b/indra/newview/skins/default/textures/icons/profile_group_visibility_eye_off.png
new file mode 100644
index 0000000000000000000000000000000000000000..3a2ed399b228453d4101b5eb22e6f98ddb4d4941
Binary files /dev/null and b/indra/newview/skins/default/textures/icons/profile_group_visibility_eye_off.png differ
diff --git a/indra/newview/skins/default/textures/icons/profile_group_visibility_eye_off_pressed.png b/indra/newview/skins/default/textures/icons/profile_group_visibility_eye_off_pressed.png
new file mode 100644
index 0000000000000000000000000000000000000000..789f59a49109b5474aa0b86fc2c9d3fc278836f0
Binary files /dev/null and b/indra/newview/skins/default/textures/icons/profile_group_visibility_eye_off_pressed.png differ
diff --git a/indra/newview/skins/default/textures/icons/profile_group_visibility_eye_on.png b/indra/newview/skins/default/textures/icons/profile_group_visibility_eye_on.png
new file mode 100644
index 0000000000000000000000000000000000000000..4fb56c389c8e476c183c65b46b4ed3d98fa4747e
Binary files /dev/null and b/indra/newview/skins/default/textures/icons/profile_group_visibility_eye_on.png differ
diff --git a/indra/newview/skins/default/textures/icons/profile_group_visibility_eye_on_pressed.png b/indra/newview/skins/default/textures/icons/profile_group_visibility_eye_on_pressed.png
new file mode 100644
index 0000000000000000000000000000000000000000..ae04a256a4ded26470906d4140d68fdd6c7ac3a2
Binary files /dev/null and b/indra/newview/skins/default/textures/icons/profile_group_visibility_eye_on_pressed.png differ
diff --git a/indra/newview/skins/default/textures/map_ui_collapse_icon.png b/indra/newview/skins/default/textures/map_ui_collapse_icon.png
new file mode 100644
index 0000000000000000000000000000000000000000..e4de49d4af82e3a4a0952eedf81f0c58782dd0ae
Binary files /dev/null and b/indra/newview/skins/default/textures/map_ui_collapse_icon.png differ
diff --git a/indra/newview/skins/default/textures/map_ui_expand_icon.png b/indra/newview/skins/default/textures/map_ui_expand_icon.png
new file mode 100644
index 0000000000000000000000000000000000000000..08734b4cc096d3aeec81ca89e205814c94dc676c
Binary files /dev/null and b/indra/newview/skins/default/textures/map_ui_expand_icon.png differ
diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml
index a36b859b6c0e2374aea0a7aeee5c447fd931c82d..4429a1677e7cc1e7a71de6fa7afa2638f9b00e69 100644
--- a/indra/newview/skins/default/textures/textures.xml
+++ b/indra/newview/skins/default/textures/textures.xml
@@ -67,8 +67,6 @@ with the same filename but different name
   <texture name="Audio_Off" file_name="icons/Audio_Off.png" preload="false" />
   <texture name="Audio_Press" file_name="icons/Audio_Press.png" preload="false" />
 
-  <texture name="Avaline_Icon" file_name="icons/avaline_default_icon.jpg" preload="true" />
-
   <texture name="BackArrow_Off" file_name="icons/BackArrow_Off.png" preload="false" />
 
   <texture name="BackButton_Off" file_name="icons/back_arrow_off.png" preload="false" scale.left="22" scale.top="12" scale.right="25" scale.bottom="12" />
@@ -191,6 +189,7 @@ with the same filename but different name
   <texture name="Conv_log_inbox" file_name="icons/Conv_log_inbox.png" preload="false" />
 
   <texture name="Copy" file_name="icons/Copy.png" preload="false" />
+  <texture name="CopyBright" file_name="icons/CopyBright.png" preload="false" />
   
   <texture name="DisclosureArrow_Opened_Off" file_name="widgets/DisclosureArrow_Opened_Off.png" preload="true" />
 
@@ -447,6 +446,13 @@ with the same filename but different name
   <texture name="OptionsMenu_Off" file_name="icons/OptionsMenu_Off.png" preload="false" />
   <texture name="OptionsMenu_Press" file_name="icons/OptionsMenu_Press.png" preload="false" />
 
+  <texture name="ClipboardSmallMenu_Disabled" file_name="icons/ClipboardSmallMenu_Disabled.png" preload="false" />
+  <texture name="ClipboardSmallMenu_Off" file_name="icons/ClipboardSmallMenu_Off.png" preload="false" />
+  <texture name="ClipboardSmallMenu_Press" file_name="icons/ClipboardSmallMenu_Press.png" preload="false" />
+  <texture name="ClipboardMenu_Disabled" file_name="icons/ClipboardMenu_Disabled.png" preload="false" />
+  <texture name="ClipboardMenu_Off" file_name="icons/ClipboardMenu_Off.png" preload="false" />
+  <texture name="ClipboardMenu_Press" file_name="icons/ClipboardMenu_Press.png" preload="false" />
+
   <texture name="OutboxStatus_Success" file_name="green_checkmark.png" preload="false" />
   <texture name="OutboxStatus_Warning" file_name="icons/pop_up_caution.png" preload="false" />
   <texture name="OutboxStatus_Error" file_name="red_x.png" preload="false" />
@@ -505,6 +511,19 @@ with the same filename but different name
   <texture name="Play_Over" file_name="icons/Play_Over.png" preload="false" />
   <texture name="Play_Press" file_name="icons/Play_Press.png" preload="false" />
   
+  <texture name="Profile_Group_Visibility_Off" file_name="icons/profile_group_visibility_eye_off.png" preload="true"/>
+  <texture name="Profile_Group_Visibility_Off_Pressed" file_name="icons/profile_group_visibility_eye_off_pressed.png" preload="true"/>
+  <texture name="Profile_Group_Visibility_On" file_name="icons/profile_group_visibility_eye_on.png" preload="true"/>
+  <texture name="Profile_Group_Visibility_On_Pressed" file_name="icons/profile_group_visibility_eye_on_pressed.png" preload="true"/>
+  <texture name="Profile_Friend_Offline" file_name="icons/Profile_Friend_Offline.png" preload="true"/>
+  <texture name="Profile_Friend_Online" file_name="icons/Profile_Friend_Online.png" preload="true"/>
+  <texture name="Profile_Perm_Find_Disabled" file_name="icons/Profile_Perm_Find_Disabled.png" preload="true"/>
+  <texture name="Profile_Perm_Find_Enabled" file_name="icons/Profile_Perm_Find_Enabled.png" preload="true"/>
+  <texture name="Profile_Perm_Objects_Disabled" file_name="icons/Profile_Perm_Objects_Disabled.png" preload="true"/>
+  <texture name="Profile_Perm_Objects_Enabled" file_name="icons/Profile_Perm_Objects_Enabled.png" preload="true"/>
+  <texture name="Profile_Perm_Online_Disabled" file_name="icons/Profile_Perm_Online_Disabled.png" preload="true"/>
+  <texture name="Profile_Perm_Online_Enabled" file_name="icons/Profile_Perm_Online_Enabled.png" preload="true"/>
+  
   <texture name="ProgressBar" file_name="widgets/ProgressBar.png" preload="true" scale.left="4" scale.top="11" scale.right="48" scale.bottom="3" />
   <texture name="ProgressBarSolid" file_name="widgets/ProgressBarSolid.png" preload="true" scale.left="4" scale.top="11" scale.right="48" scale.bottom="3" />
   <texture name="ProgressTrack" file_name="widgets/ProgressTrack.png" preload="true" scale.left="4" scale.top="13" scale.right="148" scale.bottom="2" />
@@ -612,8 +631,7 @@ with the same filename but different name
 
   <texture name="login_sl_logo"  file_name="windows/login_sl_logo.png" preload="true" />
   <texture name="login_sl_logo_small"  file_name="windows/login_sl_logo_small.png" preload="true" />
-  <texture name="first_login_image_left"  file_name="windows/first_login_image_left.png" preload="true" />
-  <texture name="first_login_image_right"  file_name="windows/first_login_image_right.png" preload="true" />
+  <texture name="first_login_image"  file_name="windows/first_login_image.jpg" preload="true" />
 
   <texture name="Stepper_Down_Off" file_name="widgets/Stepper_Down_Off.png" preload="false" />
   <texture name="Stepper_Down_Press" file_name="widgets/Stepper_Down_Press.png" preload="false" />
@@ -804,6 +822,8 @@ with the same filename but different name
   <texture name="map_infohub.tga" />
   <texture name="map_telehub.tga" />
   <texture name="map_track_16.tga" />
+  <texture name="map_ui_collapse_icon.png" />
+  <texture name="map_ui_expand_icon.png" />
 
   <texture name="notify_caution_icon.tga" />
 
diff --git a/indra/newview/skins/default/textures/windows/first_login_image.jpg b/indra/newview/skins/default/textures/windows/first_login_image.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..30f31341edc886fa2c0b23f6b4cb442495fcff17
Binary files /dev/null and b/indra/newview/skins/default/textures/windows/first_login_image.jpg differ
diff --git a/indra/newview/skins/default/textures/windows/first_login_image_left.png b/indra/newview/skins/default/textures/windows/first_login_image_left.png
deleted file mode 100644
index 77904d7d1288e123016e1d4f4c19a3c607336a8f..0000000000000000000000000000000000000000
Binary files a/indra/newview/skins/default/textures/windows/first_login_image_left.png and /dev/null differ
diff --git a/indra/newview/skins/default/textures/windows/first_login_image_right.png b/indra/newview/skins/default/textures/windows/first_login_image_right.png
deleted file mode 100644
index 35ecce9c0703486c9f9f08378bcd0aff354c01d2..0000000000000000000000000000000000000000
Binary files a/indra/newview/skins/default/textures/windows/first_login_image_right.png and /dev/null differ
diff --git a/indra/newview/skins/default/xui/da/floater_about.xml b/indra/newview/skins/default/xui/da/floater_about.xml
index 7654f0dcd6bdc36c994ad1903809069e0afcc7e6..b322e67bb7c58a0d5ff1f462c86ac23df8c6f0f3 100644
--- a/indra/newview/skins/default/xui/da/floater_about.xml
+++ b/indra/newview/skins/default/xui/da/floater_about.xml
@@ -60,7 +60,6 @@ DBus/dbus-glib Copyright (C) 2002, 2003  CodeFactory AB / Copyright (C) 2003, 20
 expat Copyright (C) 1998, 1999, 2000 Thai Open Source Software Center Ltd.
 FreeType Copyright (C) 1996-2002, The FreeType Project (www.freetype.org).
 GL Copyright (C) 1999-2004 Brian Paul.
-GLOD Copyright (C) 2003-04 Jonathan Cohen, Nat Duca, Chris Niski, Johns Hopkins University and David Luebke, Brenden Schubert, University of Virginia.
 google-perftools Copyright (c) 2005, Google Inc.
 Havok.com(TM) Copyright (C) 1999-2001, Telekinesys Research Limited.
 jpeg2000 Copyright (C) 2001, David Taubman, The University of New South Wales (UNSW)
diff --git a/indra/newview/skins/default/xui/da/panel_me.xml b/indra/newview/skins/default/xui/da/panel_me.xml
deleted file mode 100644
index f98ced5f914cf22573528e50f1f2eae3549ad51e..0000000000000000000000000000000000000000
--- a/indra/newview/skins/default/xui/da/panel_me.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<panel label="Min profil" name="panel_me">
-	<tab_container name="tabs">
-		<panel label="MIN PROFIL" name="panel_profile"/>
-		<panel label="MINE FAVORITTER" name="panel_picks"/>
-	</tab_container>
-</panel>
diff --git a/indra/newview/skins/default/xui/da/panel_region_texture.xml b/indra/newview/skins/default/xui/da/panel_region_texture.xml
index 45946fd222a2a8aed3ee4312c695814a27a534b4..c8a3ad328ec01438320912cd0679b6a08381ec5a 100644
--- a/indra/newview/skins/default/xui/da/panel_region_texture.xml
+++ b/indra/newview/skins/default/xui/da/panel_region_texture.xml
@@ -7,8 +7,8 @@
 		ukendt
 	</text>
 	<text name="detail_texture_text">
-		Terræn teksturer (kræver 512x512, 24 bit .tga filer)
-	</text>
+    Terræn teksturer (kræver 1024x1024, 24 bit .tga filer)
+  </text>
 	<text name="height_text_lbl">
 		1 (Lav)
 	</text>
diff --git a/indra/newview/skins/default/xui/da/panel_side_tray.xml b/indra/newview/skins/default/xui/da/panel_side_tray.xml
deleted file mode 100644
index 66c3e6990487bd6997fa68eca1603e400fd8e598..0000000000000000000000000000000000000000
--- a/indra/newview/skins/default/xui/da/panel_side_tray.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<!-- Side tray cannot show background because it is always
-	partially on screen to hold tab buttons. -->
-<side_tray name="sidebar">
-	<sidetray_tab description="Ã…bn/luk sidebar" name="sidebar_openclose" tab_title="Ã…bn/luk sidebar"/>
-	<sidetray_tab description="Hjem." name="sidebar_home" tab_title="Hjem">
-		<panel label="hjem" name="panel_home"/>
-	</sidetray_tab>
-	<sidetray_tab description="Redigér din profile og favoritter." name="sidebar_me" tab_title="Min profil">
-		<panel_container name="panel_container">
-			<panel label="Mig" name="panel_me"/>
-		</panel_container>
-	</sidetray_tab>
-	<sidetray_tab description="Find venner, kontakter og personer tæt på." name="sidebar_people" tab_title="Personer">
-		<panel_container name="panel_container">
-			<panel label="Gruppe profil" name="panel_group_info_sidetray"/>
-			<panel label="Blokerede beboere og objekter" name="panel_block_list_sidetray"/>
-		</panel_container>
-	</sidetray_tab>
-	<sidetray_tab description="Find steder du vil hen og steder du har været før." label="Steder" name="sidebar_places" tab_title="Steder">
-		<panel label="Steder" name="panel_places"/>
-	</sidetray_tab>
-	<sidetray_tab description="Browse din beholdning." name="sidebar_inventory" tab_title="Min beholdning">
-		<panel label="Redigér beholdning" name="sidepanel_inventory"/>
-	</sidetray_tab>
-	<sidetray_tab description="Ændre dit nuværende udseende" name="sidebar_appearance" tab_title="Mit udseende">
-		<panel label="Redigér udseende" name="sidepanel_appearance"/>
-	</sidetray_tab>
-</side_tray>
diff --git a/indra/newview/skins/default/xui/da/strings.xml b/indra/newview/skins/default/xui/da/strings.xml
index 814305c1bc230461d41b52da57f31687bd244be6..e4f99d14e9b4b4182a171f1d6119e1e18545a3c2 100644
--- a/indra/newview/skins/default/xui/da/strings.xml
+++ b/indra/newview/skins/default/xui/da/strings.xml
@@ -106,7 +106,7 @@
 	<string name="LoginFailedNoNetwork">
 		Netværksfejl: Kunne ikke etablere forbindelse, check venligst din netværksforbindelse.
 	</string>
-	<string name="LoginFailed">
+	<string name="LoginFailedHeader">
 		Login fejlede.
 	</string>
 	<string name="Quit">
@@ -443,9 +443,6 @@ Prøv venligst om lidt igen.
 	<string name="GroupNameNone">
 		(ingen)
 	</string>
-	<string name="AvalineCaller">
-		Avaline opkalder [ORDER]
-	</string>
 	<string name="AssetErrorNone">
 		Ingen fejl
 	</string>
diff --git a/indra/newview/skins/default/xui/de/floater_about.xml b/indra/newview/skins/default/xui/de/floater_about.xml
index 42e23b208995dafc49e70ae1a2802b164bda65bc..b2708f71416b80b31ba969d1033b74e9d9934b1d 100644
--- a/indra/newview/skins/default/xui/de/floater_about.xml
+++ b/indra/newview/skins/default/xui/de/floater_about.xml
@@ -19,7 +19,6 @@ mit Open-Source-Beiträgen von:</text>
         expat Copyright (C) 1998, 1999, 2000 Thai Open Source Software Center Ltd.
         FreeType Copyright (C) 1996-2002, 2006 David Turner, Robert Wilhelm und Werner Lemberg.
         GL Copyright (C) 1999-2004 Brian Paul.
-        GLOD Copyright (C) 2003-04 Jonathan Cohen, Nat Duca, Chris Niski, Johns Hopkins University sowie David Luebke, Brenden Schubert, University of Virginia.
         google-perftools Copyright (c) 2005, Google Inc.
         Havok.com(TM) Copyright (C) 1999-2001, Telekinesys Research Limited.
         jpeg2000 Copyright (C) 2001, David Taubman, The University of New South Wales (UNSW).
diff --git a/indra/newview/skins/default/xui/de/floater_preview_texture.xml b/indra/newview/skins/default/xui/de/floater_preview_texture.xml
index eacd11c3e6b6bc508b345f15f6718e37ab0336bc..b386d0288c7f0b41043702f467664e230f385369 100644
--- a/indra/newview/skins/default/xui/de/floater_preview_texture.xml
+++ b/indra/newview/skins/default/xui/de/floater_preview_texture.xml
@@ -6,42 +6,23 @@
 	<floater.string name="Copy">
 		In Inventar kopieren
 	</floater.string>
-	<text name="desc txt">
-		Beschreibung:
-	</text>
-	<text name="dimensions">
-		[WIDTH]px x [HEIGHT]px
-	</text>
-	<text name="aspect_ratio">
-		Vorschau Seitenverhältnis
-	</text>
-	<combo_box name="combo_aspect_ratio" tool_tip="Mit einem vordefinierten Seitenverhältnis anzeigen">
-		<combo_item name="Unconstrained">
-			keines
-		</combo_item>
-		<combo_item name="1:1" tool_tip="Gruppeninsignien oder Beschreibung">
-			1:1
-		</combo_item>
-		<combo_item name="4:3" tool_tip="[SECOND_LIFE]-Profil">
-			4:3
-		</combo_item>
-		<combo_item name="10:7" tool_tip="Anzeigen und Suchergebnisse, Landmarken">
-			10:7
-		</combo_item>
-		<combo_item name="3:2" tool_tip="Ãœber Land">
-			3:2
-		</combo_item>
-		<combo_item name="16:10">
-			16:10
-		</combo_item>
-		<combo_item name="16:9" tool_tip="Profilauswahl">
-			16:9
-		</combo_item>
-		<combo_item name="2:1">
-			2:1
-		</combo_item>
-	</combo_box>
-	<button label="OK" name="Keep"/>
-	<button label="Verwerfen" name="Discard"/>
-	<button label="Speichern unter" name="save_tex_btn"/>
+	<layout_stack name="preview_stack">
+		<layout_panel name="texture_panel">
+			<text name="desc txt">
+				Beschreibung:
+			</text>
+			<text name="dimensions">
+				[WIDTH]px x [HEIGHT]px
+			</text>
+			<text name="aspect_ratio">
+				Vorschau Seitenverhältnis
+			</text>
+			<combo_box name="combo_aspect_ratio" tool_tip="Mit einem vordefinierten Seitenverhältnis anzeigen"/>
+		</layout_panel>
+		<layout_panel name="buttons_panel">
+			<button label="OK" name="Keep"/>
+			<button label="Verwerfen" name="Discard"/>
+			<button label="Speichern unter" name="save_tex_btn"/>
+		</layout_panel>
+	</layout_stack>
 </floater>
diff --git a/indra/newview/skins/default/xui/de/floater_profile.xml b/indra/newview/skins/default/xui/de/floater_profile.xml
new file mode 100644
index 0000000000000000000000000000000000000000..eb03463930a24149397a7f392cdf1a8c2442bc20
--- /dev/null
+++ b/indra/newview/skins/default/xui/de/floater_profile.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<floater name="avatarinfo" title="Profil">
+	<panel name="panel_profile_view">
+		<tab_container name="panel_profile_tabs">
+			<panel label="Second Life" name="panel_profile_secondlife"/>
+			<panel label="Web" name="panel_profile_web"/>
+			<panel label="Interessen" name="panel_profile_interests"/>
+			<panel label="Auswahlen" name="panel_profile_picks"/>
+			<panel label="Anzeige" name="panel_profile_classifieds"/>
+			<panel label="Echtes Leben" name="panel_profile_firstlife"/>
+			<panel label="Hinweise" name="panel_profile_notes"/>
+		</tab_container>
+		<button label="OK" name="ok_btn" tool_tip="Profiländerungen speichern und schließen"/>
+		<button label="Abbrechen" label_selected="Abbrechen" name="cancel_btn"/>
+	</panel>
+</floater>
diff --git a/indra/newview/skins/default/xui/de/floater_snapshot.xml b/indra/newview/skins/default/xui/de/floater_snapshot.xml
index f0152ad8cdf3e16b522a0c035408c246cc9ef8fa..636f320a952549ea8b8318ad54a82bfbcf15e10d 100644
--- a/indra/newview/skins/default/xui/de/floater_snapshot.xml
+++ b/indra/newview/skins/default/xui/de/floater_snapshot.xml
@@ -6,6 +6,9 @@
 	<string name="postcard_progress_str">
 		E-Mail senden
 	</string>
+	<string name="facebook_progress_str">
+		Auf Facebook posten
+	</string>
 	<string name="profile_progress_str">
 		Posten
 	</string>
@@ -15,6 +18,9 @@
 	<string name="local_progress_str">
 		Speichern auf Computer
 	</string>
+	<string name="facebook_succeeded_str">
+		Bild hochgeladen
+	</string>
 	<string name="profile_succeeded_str">
 		Bild hochgeladen
 	</string>
@@ -27,6 +33,9 @@
 	<string name="local_succeeded_str">
 		Auf Computer gespeichert!
 	</string>
+	<string name="facebook_failed_str">
+		Fehler beim Hochladen des Bilds in Ihre Facebook-Chronik.
+	</string>
 	<string name="profile_failed_str">
 		Fehler beim Hochladen des Bilds in Ihr Profil.
 	</string>
diff --git a/indra/newview/skins/default/xui/de/menu_name_field.xml b/indra/newview/skins/default/xui/de/menu_name_field.xml
new file mode 100644
index 0000000000000000000000000000000000000000..1d293c9361104f98e292464e9db2e1497274e957
--- /dev/null
+++ b/indra/newview/skins/default/xui/de/menu_name_field.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<toggleable_menu name="CopyMenu">
+	<menu_item_call label="Anzeigenamen kopieren" name="copy_display"/>
+	<menu_item_call label="Agent-Namen kopieren" name="copy_name"/>
+	<menu_item_call label="Agent-ID kopieren" name="copy_id"/>
+</toggleable_menu>
diff --git a/indra/newview/skins/default/xui/de/notifications.xml b/indra/newview/skins/default/xui/de/notifications.xml
index 359a8356303c27feca88486009222359c62814fe..a72784f70b99be930ca08008d3d9f9d3bed3e769 100644
--- a/indra/newview/skins/default/xui/de/notifications.xml
+++ b/indra/newview/skins/default/xui/de/notifications.xml
@@ -2698,6 +2698,9 @@ Wählen Sie eine kleinere Landfläche.
 	<notification name="SystemMessage">
 		[MESSAGE]
 	</notification>
+	<notification name="FacebookConnect">
+		[MESSAGE]
+	</notification>
 	<notification name="FlickrConnect">
 		[MESSAGE]
 	</notification>
diff --git a/indra/newview/skins/default/xui/de/panel_edit_classified.xml b/indra/newview/skins/default/xui/de/panel_edit_classified.xml
index bd270697ea0847b7bb8823b4c5614de50d07f889..8adacb4a5fe1b22c15b3ef8214d3f3a7ef3b952f 100644
--- a/indra/newview/skins/default/xui/de/panel_edit_classified.xml
+++ b/indra/newview/skins/default/xui/de/panel_edit_classified.xml
@@ -46,7 +46,7 @@
 			<layout_panel name="save_changes_btn_lp">
 				<button label="[LABEL]" name="save_changes_btn"/>
 			</layout_panel>
-			<layout_panel name="show_on_map_btn_lp">
+			<layout_panel name="cancel_btn_lp">
 				<button label="Abbrechen" name="cancel_btn"/>
 			</layout_panel>
 		</layout_stack>
diff --git a/indra/newview/skins/default/xui/de/panel_facebook_friends.xml b/indra/newview/skins/default/xui/de/panel_facebook_friends.xml
index f6a8fda23e0865c54985503472876d8faef00c7c..1a0bbc7d30125f5c689e39e22b0ab87f5a33b53f 100644
--- a/indra/newview/skins/default/xui/de/panel_facebook_friends.xml
+++ b/indra/newview/skins/default/xui/de/panel_facebook_friends.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <panel name="panel_facebook_friends">
-	<string name="facebook_friends_empty" value="Sie haben gegenwärtig keine Facebook-Freunde, die gleichzeitig Einwohner von Second Life sind. Laden Sie Ihre Facebook-Freunde ein, Second Life beizutreten!"/>
-	<string name="facebook_friends_no_connected" value="Sie sind gegenwärtig nicht mit Facebook verbunden. Um eine Verbindung herzustellen und diese Funktion zu aktivieren, gehen Sie zur Registerkarte „Status“."/>
+	<string name="facebook_friends_empty" value="Sie haben gegenwärtig keine Facebook-Freunde, die ebenfalls Second Life-Einwohner sind. Laden Sie Ihre Facebook-Freunde ein, Second Life beizutreten!"/>
+	<string name="facebook_friends_no_connected" value="Sie sind gegenwärtig nicht mit Facebook verbunden. Um eine Verbindung herzustellen und diese Funktion zu aktivieren, wechseln Sie zur Registerkarte &quot;Status&quot;."/>
 	<accordion name="friends_accordion">
 		<accordion_tab name="tab_second_life_friends" title="SL-Freunde"/>
 		<accordion_tab name="tab_suggested_friends" title="Diese Personen als SL-Freunde hinzufügen"/>
diff --git a/indra/newview/skins/default/xui/de/panel_facebook_photo.xml b/indra/newview/skins/default/xui/de/panel_facebook_photo.xml
index bc489311295b24cc5ad40c2edfdb2dee0c8f3d2b..fac9fe99848ac77f6864fe9dda609d0702b2508a 100644
--- a/indra/newview/skins/default/xui/de/panel_facebook_photo.xml
+++ b/indra/newview/skins/default/xui/de/panel_facebook_photo.xml
@@ -2,10 +2,10 @@
 <panel name="panel_facebook_photo">
 	<combo_box name="resolution_combobox" tool_tip="Bildauflösung">
 		<combo_box.item label="Aktuelles Fenster" name="CurrentWindow"/>
-		<combo_box.item label="640x480" name="640x480"/>
-		<combo_box.item label="800x600" name="800x600"/>
-		<combo_box.item label="1024x768" name="1024x768"/>
-		<combo_box.item label="1200x630" name="1200x630"/>
+		<combo_box.item label="640 x 480" name="640x480"/>
+		<combo_box.item label="800 x 600" name="800x600"/>
+		<combo_box.item label="1024 x 768" name="1024x768"/>
+		<combo_box.item label="1200 x 630" name="1200x630"/>
 	</combo_box>
 	<combo_box name="filters_combobox" tool_tip="Bildfilter">
 		<combo_box.item label="Kein Filter" name="NoFilter"/>
diff --git a/indra/newview/skins/default/xui/de/panel_facebook_status.xml b/indra/newview/skins/default/xui/de/panel_facebook_status.xml
index 23c9d3b75fc11d5f9c446751a7532b40692e2df5..1fefef548e42b35a7da58cb78fc0994b0662a042 100644
--- a/indra/newview/skins/default/xui/de/panel_facebook_status.xml
+++ b/indra/newview/skins/default/xui/de/panel_facebook_status.xml
@@ -13,7 +13,7 @@
 		</text>
 	</panel>
 	<text name="status_caption_label">
-		Was machst du gerade?
+		Was machen Sie gerade?
 	</text>
 	<button label="Posten" name="post_status_btn"/>
 	<button label="Abbrechen" name="cancel_status_btn"/>
diff --git a/indra/newview/skins/default/xui/de/panel_group_general.xml b/indra/newview/skins/default/xui/de/panel_group_general.xml
index 9fec5a242d33760765a3b39c4356138a5b16fd2e..e50124c37e8a51fb8992787dd7012bb1dc578757 100644
--- a/indra/newview/skins/default/xui/de/panel_group_general.xml
+++ b/indra/newview/skins/default/xui/de/panel_group_general.xml
@@ -46,7 +46,7 @@ Bewegen Sie die Maus über die Optionen, um weitere Informationen anzuzeigen.
 		<check_box label="Jeder kann beitreten" name="open_enrollement" tool_tip="Festlegen, ob der Gruppenbeitritt ohne Einladung zulässig ist."/>
 		<check_box label="Kosten für Beitritt" name="check_enrollment_fee" tool_tip="Festlegen, ob Neumitglieder eine Beitrittsgebühr zahlen müssen"/>
 		<spinner label="L$" name="spin_enrollment_fee" tool_tip="Wenn Beitrittsgebühr aktiviert ist, müssen neue Mitglieder diesen Betrag zahlen."/>
-		<combo_box name="group_mature_check" tool_tip="Inhaltseinstufungen kennzeichnen die in einer Gruppe zulässigen Inhalte und Verhaltensweisen">
+		<combo_box name="group_mature_check" tool_tip="Legt fest, ob Ihre Gruppe als moderat eingestufte Informationen enthält">
 			<combo_item name="select_mature">
 				- Inhaltseinstufung auswählen -
 			</combo_item>
diff --git a/indra/newview/skins/default/xui/de/panel_group_list_item_short.xml b/indra/newview/skins/default/xui/de/panel_group_list_item_short.xml
new file mode 100644
index 0000000000000000000000000000000000000000..fc911a64dff0b7ef88021bb01702ed4c4038110c
--- /dev/null
+++ b/indra/newview/skins/default/xui/de/panel_group_list_item_short.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="group_list_item">
+	<text name="group_name" value="Unbekannt"/>
+	<button name="info_btn" tool_tip="Mehr Infos"/>
+	<button name="profile_btn" tool_tip="Profil anzeigen"/>
+</panel>
diff --git a/indra/newview/skins/default/xui/de/panel_me.xml b/indra/newview/skins/default/xui/de/panel_me.xml
deleted file mode 100644
index f49446fbbf022bda93c0037e5a4276127c5fe590..0000000000000000000000000000000000000000
--- a/indra/newview/skins/default/xui/de/panel_me.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<panel label="Mein Profil" name="panel_me">
-	<panel label="MEINE AUSWAHLEN" name="panel_picks"/>
-</panel>
diff --git a/indra/newview/skins/default/xui/de/panel_people.xml b/indra/newview/skins/default/xui/de/panel_people.xml
index 81de6794290e807932c55da4277d9ad3df915451..e4a4c1033ec1fce3f760852739f5a641c67a1ab6 100644
--- a/indra/newview/skins/default/xui/de/panel_people.xml
+++ b/indra/newview/skins/default/xui/de/panel_people.xml
@@ -40,6 +40,7 @@ Sie suchen nach Leuten? Verwenden Sie die [secondlife:///app/worldmap Karte].
 			<accordion name="friends_accordion">
 				<accordion_tab name="tab_online" title="Online"/>
 				<accordion_tab name="tab_all" title="Alle"/>
+				<accordion_tab name="tab_suggested_friends" title="Potenzielle Freunde"/>
 			</accordion>
 		</panel>
 		<panel label="GRUPPEN" name="groups_panel">
diff --git a/indra/newview/skins/default/xui/de/panel_profile_classified.xml b/indra/newview/skins/default/xui/de/panel_profile_classified.xml
new file mode 100644
index 0000000000000000000000000000000000000000..5c11a01977f56c9a2a547f8b00938d6fb0d0b1d0
--- /dev/null
+++ b/indra/newview/skins/default/xui/de/panel_profile_classified.xml
@@ -0,0 +1,110 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="panel_profile_classified">
+	<panel.string name="type_mature">
+		Moderat
+	</panel.string>
+	<panel.string name="type_pg">
+		Generelle Inhalte
+	</panel.string>
+	<panel.string name="l$_price">
+		L$[PRICE]
+	</panel.string>
+	<panel.string name="click_through_text_fmt">
+		[TELEPORT] Teleportieren, [MAP] Karten, [PROFILE] Profil
+	</panel.string>
+	<panel.string name="date_fmt">
+		[mthnum,datetime,slt]/[day,datetime,slt]/[year,datetime,slt]
+	</panel.string>
+	<panel.string name="auto_renew_on">
+		Aktiviert
+	</panel.string>
+	<panel.string name="auto_renew_off">
+		Deaktiviert
+	</panel.string>
+	<panel.string name="location_notice">
+		(wird nach dem Speichern aktualisiert)
+	</panel.string>
+	<string name="publish_label">
+		Veröffentlichen
+	</string>
+	<string name="save_label">
+		Speichern
+	</string>
+	<scroll_container name="profile_scroll">
+		<panel name="info_scroll_content_panel">
+			<icon label="" name="edit_icon" tool_tip="Klicken, um ein Bild auszuwählen"/>
+			<layout_stack name="info_panel">
+				<layout_panel name="main_info_panel">
+					<text_editor name="classified_name">
+						[name]
+					</text_editor>
+					<text name="classified_location_label" value="Standort:"/>
+					<text_editor name="classified_location" value="[loading...]"/>
+					<text name="content_type_label" value="Inhaltsart:"/>
+					<text_editor name="content_type" value="[content type]"/>
+					<text name="category_label" value="Kategorie:"/>
+					<text_editor name="category" value="[category]"/>
+					<text name="creation_date_label" value="Erstellungsdatum:"/>
+					<text_editor name="creation_date" tool_tip="Erstellungsdatum" value="[date]"/>
+					<text name="price_for_listing_label" value="Preis für Auflistung:"/>
+					<text_editor name="price_for_listing" tool_tip="Preis für Auflistung.">
+						[PRICE]
+					</text_editor>
+				</layout_panel>
+				<layout_panel name="clickthrough_layout_panel">
+					<text name="click_through_label" value="Klicks:"/>
+					<text_editor name="click_through_text" tool_tip="Click-Through-Daten" value="[clicks]"/>
+				</layout_panel>
+				<layout_panel name="auto_renew_layout_panel">
+					<text name="auto_renew_label" value="Autom. erneuern:"/>
+					<text name="auto_renew" value="Aktiviert"/>
+				</layout_panel>
+				<layout_panel name="descr_layout_panel">
+					<text name="classified_desc_label" value="Beschreibung:"/>
+					<text_editor name="classified_desc" value="[description]"/>
+				</layout_panel>
+			</layout_stack>
+			<panel name="edit_panel">
+				<text name="Name:">
+					Titel:
+				</text>
+				<text name="description_label">
+					Beschreibung:
+				</text>
+				<text name="location_label">
+					Standort:
+				</text>
+				<text name="classified_location_edit">
+					Laden...
+				</text>
+				<button label="Aktuellen Standort verwenden" name="set_to_curr_location_btn"/>
+				<text name="category_label" value="Kategorie:"/>
+				<text name="content_type_label" value="Inhaltsart:"/>
+				<icons_combo_box label="Generelle Inhalte" name="content_type_edit">
+					<icons_combo_box.item label="Moderate Inhalte" name="mature_ci" value="Adult"/>
+					<icons_combo_box.item label="Generelle Inhalte" name="pg_ci" value="PG"/>
+				</icons_combo_box>
+				<check_box label="Jede Woche automatisch erneuern" name="auto_renew_edit"/>
+				<text name="price_for_listing_edit_label" value="Preis für Auflistung:"/>
+				<spinner label="L$" name="price_for_listing_edit" tool_tip="Preis für Auflistung." value="50"/>
+			</panel>
+		</panel>
+	</scroll_container>
+	<layout_stack name="edit_btns_pnl">
+		<layout_panel name="teleport_btn_lp">
+			<button label="Teleportieren" name="teleport_btn"/>
+		</layout_panel>
+		<layout_panel name="map_btn_lp">
+			<button label="Karte" name="show_on_map_btn"/>
+		</layout_panel>
+		<layout_panel name="edit_btn_lp">
+			<button label="Bearbeiten" name="edit_btn"/>
+		</layout_panel>
+		<layout_panel name="save_btn_lp">
+			<button label="[LABEL]" name="save_changes_btn"/>
+		</layout_panel>
+		<layout_panel name="cancel_btn_lp">
+			<button label="Abbrechen" name="cancel_btn"/>
+		</layout_panel>
+	</layout_stack>
+</panel>
diff --git a/indra/newview/skins/default/xui/de/panel_profile_classifieds.xml b/indra/newview/skins/default/xui/de/panel_profile_classifieds.xml
new file mode 100644
index 0000000000000000000000000000000000000000..83549cb13886ca6098445607725086242a97ca06
--- /dev/null
+++ b/indra/newview/skins/default/xui/de/panel_profile_classifieds.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel label="Anzeige" name="panel_profile_classifieds">
+	<string name="no_classifieds" value="Keine Anzeigen"/>
+	<button label="Neu..." name="new_btn"/>
+	<button label="Löschen..." name="delete_btn"/>
+	<text name="classifieds_panel_text">
+		Laden...
+	</text>
+</panel>
diff --git a/indra/newview/skins/default/xui/de/floater_picks.xml b/indra/newview/skins/default/xui/de/panel_profile_firstlife.xml
similarity index 50%
rename from indra/newview/skins/default/xui/de/floater_picks.xml
rename to indra/newview/skins/default/xui/de/panel_profile_firstlife.xml
index 2521920e83f04500d47e6b61b576d4eda53a5535..0f65090209a7dcdb8d28c2dfd86b93adbb01443b 100644
--- a/indra/newview/skins/default/xui/de/floater_picks.xml
+++ b/indra/newview/skins/default/xui/de/panel_profile_firstlife.xml
@@ -1,2 +1,2 @@
 <?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<floater name="floater_picks" title="Auswahlen"/>
+<panel label="Profil" name="panel_profile_firstlife"/>
diff --git a/indra/newview/skins/default/xui/de/panel_profile_interests.xml b/indra/newview/skins/default/xui/de/panel_profile_interests.xml
new file mode 100644
index 0000000000000000000000000000000000000000..0f36f76aa05ba1d50313c3b9f6b7c5b407f35c8d
--- /dev/null
+++ b/indra/newview/skins/default/xui/de/panel_profile_interests.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel label="Interessen" name="panel_profile_interests">
+	<text name="I Want To:">
+		Ich möchte:
+	</text>
+	<check_box label="Erstellen" name="chk0"/>
+	<check_box label="Erkunden" name="chk1"/>
+	<check_box label="Treffen" name="chk2"/>
+	<check_box label="Angestellt werden" name="chk6"/>
+	<check_box label="Gruppe" name="chk3"/>
+	<check_box label="Kaufen" name="chk4"/>
+	<check_box label="Verkaufen" name="chk5"/>
+	<check_box label="Anstellen" name="chk7"/>
+	<line_editor name="want_to_edit">
+		(wird geladen...)
+	</line_editor>
+	<text name="Skills:">
+		Fähigkeiten:
+	</text>
+	<check_box label="Texturen" name="schk0"/>
+	<check_box label="Architektur" name="schk1"/>
+	<check_box label="Modellierung" name="schk3"/>
+	<check_box label="Eventplanung" name="schk2"/>
+	<check_box label="Scripting" name="schk4"/>
+	<check_box label="Benutzerdefinierte Charaktere" name="schk5"/>
+	<line_editor name="skills_edit">
+		(wird geladen...)
+	</line_editor>
+	<text name="Languages:">
+		Sprachen:
+	</text>
+	<line_editor name="languages_edit">
+		(wird geladen...)
+	</line_editor>
+</panel>
diff --git a/indra/newview/skins/default/xui/de/panel_profile_notes.xml b/indra/newview/skins/default/xui/de/panel_profile_notes.xml
new file mode 100644
index 0000000000000000000000000000000000000000..05c46ff858ab10b077d5c5df7d38795f04f5b865
--- /dev/null
+++ b/indra/newview/skins/default/xui/de/panel_profile_notes.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel label="Anmerkungen &amp; Privatsphäre" name="panel_notes">
+	<text name="status_message" value="Private Anmerkungen zu diesem Avatar:"/>
+	<text name="status_message2" value="Dieser Avatar darf:"/>
+	<check_box label="Sehen, wenn ich online bin" name="status_check"/>
+	<check_box label="Mich auf der Weltkarte sehen" name="map_check"/>
+	<check_box label="Meine Objekte bearbeiten, löschen oder nehmen" name="objects_check"/>
+</panel>
diff --git a/indra/newview/skins/default/xui/de/panel_profile_pick.xml b/indra/newview/skins/default/xui/de/panel_profile_pick.xml
new file mode 100644
index 0000000000000000000000000000000000000000..1f44ba8b1b38a7b46443ce8466f3a48c4d6dfc20
--- /dev/null
+++ b/indra/newview/skins/default/xui/de/panel_profile_pick.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="panel_pick_info">
+	<panel.string name="location_notice">
+		(wird nach dem Speichern aktualisiert)
+	</panel.string>
+	<line_editor name="pick_location">
+		Laden...
+	</line_editor>
+	<button label="Teleportieren" name="teleport_btn"/>
+	<button label="Auf Karte anzeigen" name="show_on_map_btn"/>
+	<button label="Standort festlegen" name="set_to_curr_location_btn" tool_tip="Aktuellen Standort verwenden"/>
+	<button label="Auswahl speichern" name="save_changes_btn"/>
+</panel>
diff --git a/indra/newview/skins/default/xui/de/panel_profile_picks.xml b/indra/newview/skins/default/xui/de/panel_profile_picks.xml
new file mode 100644
index 0000000000000000000000000000000000000000..96403715e4bdda6f007c14334b21b3882ea1e735
--- /dev/null
+++ b/indra/newview/skins/default/xui/de/panel_profile_picks.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel label="Auswahlen" name="panel_picks">
+	<string name="no_picks" value="Keine Auswahl"/>
+	<text name="Tell everyone about your favorite places in Second Life.">
+		Erzählen Sie von Ihren Lieblingsorten in Second Life.
+	</text>
+	<button label="Neu..." name="new_btn"/>
+	<button label="Löschen..." name="delete_btn"/>
+	<text name="picks_panel_text">
+		Laden...
+	</text>
+</panel>
diff --git a/indra/newview/skins/default/xui/de/panel_profile_secondlife.xml b/indra/newview/skins/default/xui/de/panel_profile_secondlife.xml
new file mode 100644
index 0000000000000000000000000000000000000000..baaa58e1d752f6546bb63b25e92628de1478ecd1
--- /dev/null
+++ b/indra/newview/skins/default/xui/de/panel_profile_secondlife.xml
@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel label="Profil" name="panel_profile">
+	<string name="status_online">
+		Zurzeit online
+	</string>
+	<string name="status_offline">
+		Zurzeit offline
+	</string>
+	<string name="CaptionTextAcctInfo">
+		[ACCTTYPE]
+[PAYMENTINFO]
+	</string>
+	<string name="payment_update_link_url">
+		http://www.secondlife.com/account/billing.php?lang=de
+	</string>
+	<string name="partner_edit_link_url">
+		http://www.secondlife.com/account/partners.php?lang=de
+	</string>
+	<string name="my_account_link_url" value="http://secondlife.com/account"/>
+	<string name="no_partner_text" value="Keine"/>
+	<string name="no_group_text" value="Keine"/>
+	<string name="RegisterDateFormat">
+		[REG_DATE]
+	</string>
+	<string name="name_text_args">
+		[NAME]
+	</string>
+	<string name="display_name_text_args">
+		[DISPLAY_NAME]
+	</string>
+	<string name="FSDev" value="Entwickler"/>
+	<string name="FSSupp" value="Support"/>
+	<string name="FSQualityAssurance" value="Fehlersuche"/>
+	<string name="FSGW" value="Gateway"/>
+	<text name="name_label" value="Name:"/>
+	<button label="Name:" name="set_name" tool_tip="Anzeigenamen festlegen"/>
+	<panel name="name_holder">
+		<text_editor name="complete_name" value="(wird geladen...)"/>
+	</panel>
+	<layout_stack name="imagepositioner">
+		<layout_panel name="label_stack">
+			<text name="status" value="Status unbekannt"/>
+			<text name="label" value="Second Life-Geburtsdatum:"/>
+			<text name="label2" value="Konto:"/>
+			<text name="partner_label" value="Partner:"/>
+		</layout_panel>
+	</layout_stack>
+	<text name="Groups:" value="Gruppen:"/>
+	<button label="+" label_selected="+" name="group_invite" tool_tip="In Gruppe einladen"/>
+	<layout_stack name="aboutpositioner">
+		<layout_panel name="about_stack">
+			<text name="About:" value="Info:"/>
+		</layout_panel>
+		<layout_panel name="give_stack">
+			<text name="Give item:" value="Objekt geben:"/>
+			<text name="Give inventory" tool_tip="Legen Sie hier Inventarobjekte ab, um Sie dieser Person zu geben.">
+				Inventarobjekt hier ablegen.
+			</text>
+		</layout_panel>
+	</layout_stack>
+	<layout_stack name="buttonstack">
+		<layout_panel name="left_buttonstack">
+			<button label="Auf Karte anzeigen" label_selected="Auf Karte anzeigen" name="show_on_map_btn" tool_tip="Einwohner auf Karte lokalisieren"/>
+			<button label="Bezahlen" label_selected="Bezahlen" name="pay" tool_tip="Geld an den Einwohner zahlen"/>
+		</layout_panel>
+		<layout_panel name="middle_buttonstack">
+			<button label="Teleportation anbieten" label_selected="Teleportation anbieten" name="teleport" tool_tip="Dem Einwohner eine Teleportation anbieten"/>
+			<button label="Instant Message" label_selected="Instant Message" name="im" tool_tip="Instant Message-Sitzung öffnen"/>
+		</layout_panel>
+		<layout_panel name="right_buttonstack">
+			<button label="Freund hinzufügen" label_selected="Freund hinzufügen" name="add_friend" tool_tip="Dem Einwohner die Freundschaft anbieten"/>
+			<button label="Blockieren" name="block" tool_tip="Diesen Einwohner blockieren"/>
+			<button label="Blockierung aufheben" name="unblock" tool_tip="Diesen Einwohner nicht mehr blockieren"/>
+		</layout_panel>
+	</layout_stack>
+	<check_box label="In Suche anzeigen" name="show_in_search_checkbox"/>
+</panel>
diff --git a/indra/newview/skins/default/xui/de/panel_profile_web.xml b/indra/newview/skins/default/xui/de/panel_profile_web.xml
new file mode 100644
index 0000000000000000000000000000000000000000..a03918f4b516c6d1355617a8b0fe739a63c06123
--- /dev/null
+++ b/indra/newview/skins/default/xui/de/panel_profile_web.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel label="Web" name="panel_profile_web">
+	<panel.string name="LoadTime" value="Ladezeit: [TIME] Sekunden"/>
+	<line_editor name="url_edit">
+		(wird geladen..)
+	</line_editor>
+	<flyout_button label="Laden" name="load" tool_tip="Lädt diese Profilseite im integrierten Webbrowser.">
+		<flyout_button.item label="Im Viewer-Browser öffnen" name="open_item"/>
+		<flyout_button.item label="In externem Browser öffnen" name="home_item"/>
+	</flyout_button>
+	<button name="web_profile_popout_btn" tool_tip="Webprofil ausklappen"/>
+</panel>
diff --git a/indra/newview/skins/default/xui/de/panel_region_terrain.xml b/indra/newview/skins/default/xui/de/panel_region_terrain.xml
index 7801be30e482860200f5b456a2bdedd9cb85e2f0..42ba5b5269b20232748dfaee0f551c5ace327a0c 100644
--- a/indra/newview/skins/default/xui/de/panel_region_terrain.xml
+++ b/indra/newview/skins/default/xui/de/panel_region_terrain.xml
@@ -10,8 +10,8 @@
 	<spinner label="Obere Terraingrenze" name="terrain_raise_spin"/>
 	<spinner label="Untere Terraingrenze" name="terrain_lower_spin"/>
 	<text name="detail_texture_text">
-		Terraintexturen (erfordert 24-Bit-.tga-Dateien mit einer Größe von 512x512)
-	</text>
+    Terraintexturen (erfordert 24-Bit-.tga-Dateien mit einer Größe von 1024x1024)
+  </text>
 	<text name="height_text_lbl">
 		1 (niedrig)
 	</text>
diff --git a/indra/newview/skins/default/xui/de/strings.xml b/indra/newview/skins/default/xui/de/strings.xml
index f021e03dc759bd14927c9e0fe9ab73224d7045b4..0120f7e5bd4912ebc4477e8834d844cbdc435b48 100644
--- a/indra/newview/skins/default/xui/de/strings.xml
+++ b/indra/newview/skins/default/xui/de/strings.xml
@@ -186,7 +186,7 @@ Voice-Server-Version: [VOICE_VERSION]
 	<string name="LoginFailedNoNetwork">
 		Netzwerkfehler: Verbindung konnte nicht hergestellt werden. Bitte überprüfen Sie Ihre Netzwerkverbindung.
 	</string>
-	<string name="LoginFailed">
+	<string name="LoginFailedHeader">
 		Anmeldung fehlgeschlagen
 	</string>
 	<string name="Quit">
@@ -356,6 +356,24 @@ Warten Sie kurz und versuchen Sie dann noch einmal, sich anzumelden.
 	<string name="TestingDisconnect">
 		Verbindungsabbruch wird getestet
 	</string>
+	<string name="SocialFacebookConnecting">
+		Mit Facebook verbinden...
+	</string>
+	<string name="SocialFacebookPosting">
+		Posten...
+	</string>
+	<string name="SocialFacebookDisconnecting">
+		Facebook-Verbindung trennen...
+	</string>
+	<string name="SocialFacebookErrorConnecting">
+		Problem beim Verbinden mit Facebook
+	</string>
+	<string name="SocialFacebookErrorPosting">
+		Problem beim Posten auf Facebook
+	</string>
+	<string name="SocialFacebookErrorDisconnecting">
+		Problem beim Trennen der Facebook-Verbindung
+	</string>
 	<string name="SocialFlickrConnecting">
 		Verbinden mit Flickr...
 	</string>
@@ -673,9 +691,6 @@ nächsten Eigentümer angehängt werden.
 	<string name="GroupNameNone">
 		(keiner)
 	</string>
-	<string name="AvalineCaller">
-		Avaline-Anfrufer [ORDER]
-	</string>
 	<string name="AssetErrorNone">
 		Kein Fehler
 	</string>
@@ -2578,9 +2593,21 @@ Falls diese Meldung weiterhin angezeigt wird, wenden Sie sich unter http://suppo
 	<string name="NoPicksClassifiedsText">
 		Sie haben keine Auswahl oder Anzeigen erstelllt. Klicken Sie auf die „Plus&quot;-Schaltfläche, um eine Auswahl oder Anzeige zu erstellen.
 	</string>
+	<string name="NoPicksText">
+		Sie haben keine Auswahl erstellt. Klicken Sie auf die Schaltfläche &quot;Neu&quot;, um eine Auswahl zu erstellen.
+	</string>
+	<string name="NoClassifiedsText">
+		Sie haben keine Anzeigen erstellt. Klicken Sie auf die Schaltfläche &quot;Neu&quot;, um eine Anzeige zu erstellen.
+	</string>
 	<string name="NoAvatarPicksClassifiedsText">
 		Der Einwohner hat keine Auswahl oder Anzeigen
 	</string>
+	<string name="NoAvatarPicksText">
+		Der Einwohner hat keine Auswahl
+	</string>
+	<string name="NoAvatarClassifiedsText">
+		Der Einwohner hat keine Anzeigen
+	</string>
 	<string name="PicksClassifiedsLoadingText">
 		Wird geladen...
 	</string>
@@ -4558,6 +4585,9 @@ Falls diese Meldung weiterhin angezeigt wird, wenden Sie sich bitte an [SUPPORT_
 	<string name="share_alert">
 		Objekte aus dem Inventar hier her ziehen
 	</string>
+	<string name="facebook_post_success">
+		Sie haben auf Facebook gepostet.
+	</string>
 	<string name="flickr_post_success">
 		Sie haben auf Flickr gepostet.
 	</string>
@@ -5101,7 +5131,7 @@ Bitte überprüfen Sie http://status.secondlifegrid.net, um herauszufinden, ob e
 	<string name="PremiumMembership">
 		Premium
 	</string>
-	<string name="Premium PlusMembership">
+	<string name="Premium_PlusMembership">
 		Premium Plus
 	</string>
 	<string name="DeleteItems">
diff --git a/indra/newview/skins/default/xui/en/control_table_contents_media.xml b/indra/newview/skins/default/xui/en/control_table_contents_media.xml
index ce5d3556b612988e32fab8aa341b334b7e06d132..43e8d730cd9679460d8bf6eeb9277c0d46b3a71e 100644
--- a/indra/newview/skins/default/xui/en/control_table_contents_media.xml
+++ b/indra/newview/skins/default/xui/en/control_table_contents_media.xml
@@ -73,4 +73,14 @@
          name="lst_action"
          value="Start Gesture" />
     </rows>
+    <rows
+     name="script_trigger_lbutton"
+     value="script_trigger_lbutton">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Interact (Script LMB)" />
+    </rows>
 </contents>
diff --git a/indra/newview/skins/default/xui/en/floater_about.xml b/indra/newview/skins/default/xui/en/floater_about.xml
index 71f4d811954223ac8b6046039e85c531f75b3d9f..eb07425dfe2fe33823b1e62077ac1743a8b72979 100644
--- a/indra/newview/skins/default/xui/en/floater_about.xml
+++ b/indra/newview/skins/default/xui/en/floater_about.xml
@@ -101,11 +101,11 @@ Dummy Name replaced at run time
         expat Copyright (C) 1998, 1999, 2000 Thai Open Source Software Center Ltd.
         FreeType Copyright (C) 1996-2002, 2006 David Turner, Robert Wilhelm, and Werner Lemberg.
         GL Copyright (C) 1999-2004 Brian Paul.
-        GLOD Copyright (C) 2003-04 Jonathan Cohen, Nat Duca, Chris Niski, Johns Hopkins University and David Luebke, Brenden Schubert, University of Virginia.
         google-perftools Copyright (c) 2005, Google Inc.
         Havok.com(TM) Copyright (C) 1999-2001, Telekinesys Research Limited.
         jpeg2000 Copyright (C) 2001, David Taubman, The University of New South Wales (UNSW)
         jpeglib Copyright (C) 1991-1998, Thomas G. Lane.
+        meshoptimizer Copyright (c) 2016-2021 Arseny Kapoulkine
         ogg/vorbis Copyright (C) 2002, Xiphophorus
         OpenSSL Copyright (C) 1998-2008 The OpenSSL Project.
         PCRE Copyright (c) 1997-2012 University of Cambridge
diff --git a/indra/newview/skins/default/xui/en/floater_about_land.xml b/indra/newview/skins/default/xui/en/floater_about_land.xml
index b2d9e530398c4bcdc8cd13f4898b81f3163ab140..4678d65b85691db0426b52c0a1537e53f878dab6 100644
--- a/indra/newview/skins/default/xui/en/floater_about_land.xml
+++ b/indra/newview/skins/default/xui/en/floater_about_land.xml
@@ -164,6 +164,7 @@
              left_pad="2"
              name="Description"
              spellcheck="true"
+             parse_urls="true"
              top_delta="0"
              width="365"
              word_wrap="true" />
@@ -1892,7 +1893,29 @@ Only large parcels can be listed in search.
              left="110"
              name="parcel_enable_voice_channel_local"
              width="300" />
-        </panel>
+            <text
+             type="string"
+             length="1"
+             follows="left|top"
+             height="16"
+             layout="topleft"
+             left="10"
+             mouse_opaque="false"
+             name="media"
+             top_pad="10"
+             width="100">
+                Media:
+            </text>
+            <check_box
+             height="16"
+             label="Obscure MOAP"
+             layout="topleft"
+             left="110"
+             left_pad="0"
+             name="obscure_moap"
+             tool_tip="Media on a prim located outside the parcel should not play automatically for an agent within this parcel and vice versa."
+             width="300" />
+            </panel>
         <panel
          border="true"
          follows="all"
diff --git a/indra/newview/skins/default/xui/en/floater_associate_listing.xml b/indra/newview/skins/default/xui/en/floater_associate_listing.xml
index e019ed58ddbd9aa955f65d7e918384246154f24a..0f7ed241034e3aee0c1e1263b564be35deb3fcd5 100644
--- a/indra/newview/skins/default/xui/en/floater_associate_listing.xml
+++ b/indra/newview/skins/default/xui/en/floater_associate_listing.xml
@@ -20,9 +20,10 @@
      name="message">
         Listing ID:
     </text>
+    <!--listing_id is a positive S32-->
     <line_editor
      type="string"
-     length="1"
+     max_length_bytes="10"
      follows="top|right"
      font="SansSerif"
      height="20"
diff --git a/indra/newview/skins/default/xui/en/floater_picks.xml b/indra/newview/skins/default/xui/en/floater_classified.xml
similarity index 62%
rename from indra/newview/skins/default/xui/en/floater_picks.xml
rename to indra/newview/skins/default/xui/en/floater_classified.xml
index 984894b0165a4012b6056806ac3a813cc96d5b5a..5b14c827d018b7c34001b7853ea696981734d4c6 100644
--- a/indra/newview/skins/default/xui/en/floater_picks.xml
+++ b/indra/newview/skins/default/xui/en/floater_classified.xml
@@ -2,20 +2,19 @@
 <floater
  positioning="cascading"
  can_close="true"
- can_resize="true"
+ can_resize="false"
  height="572"
  help_topic="sidebar_me"
  min_width="333"
  min_height="440"
- name="floater_picks"
+ name="floater_classified"
  save_rect="true"
- save_visibility="true"
- reuse_instance="true"
- title="Picks"
+ save_visibility="false"
+ title="Classified"
  width="333" >
    <panel
-    class="panel_me"
+    class="panel_classified_info"
     name="main_panel"
-    filename="panel_me.xml"
+    filename="panel_classified_info.xml"
     follows="all"/>
 </floater>
diff --git a/indra/newview/skins/default/xui/en/floater_create_landmark.xml b/indra/newview/skins/default/xui/en/floater_create_landmark.xml
index bba30626b25751f028217e8208b4d496aef7a79c..632daaec7ec33badaa4b5179927d6ab9d23334aa 100644
--- a/indra/newview/skins/default/xui/en/floater_create_landmark.xml
+++ b/indra/newview/skins/default/xui/en/floater_create_landmark.xml
@@ -88,6 +88,7 @@
      spellcheck="true"
      text_readonly_color="white"
      text_type="ascii_with_newline"
+     commit_on_focus_lost="true"
      top_pad="5"
      width="290"
      wrap="true" />
diff --git a/indra/newview/skins/default/xui/en/floater_display_name.xml b/indra/newview/skins/default/xui/en/floater_display_name.xml
index 9a9fd32a773b3a07584c45368ce4f062d17bc6de..3c8f4158605579d383dfa14fdcad8c1e0fc97ecb 100644
--- a/indra/newview/skins/default/xui/en/floater_display_name.xml
+++ b/indra/newview/skins/default/xui/en/floater_display_name.xml
@@ -23,7 +23,7 @@
      use_ellipses="true"
      width="380"
      wrap="true">
-      The name you give your avatar is called your Display Name. You can change it once a week.
+      Your display name is what other people see above your head. It is different from your login name. You can change it once a week.
     </text>
 	<text
      type="string"
@@ -83,21 +83,12 @@
      tool_tip="Save your new Display Name" 
      top_pad="40"
      width="120" />
-    <button
-     height="23"
-     label="Reset"
-     layout="topleft"
-     font="SansSerif"
-     left_pad="5"
-     name="reset_btn"
-     tool_tip="Make Display Name the same as Username"
-     width="120" />
     <button
      height="23"
      label="Cancel"
      font="SansSerif"
      layout="topleft"
-     left_pad="5"
+     left_pad="125"
      name="cancel_btn"
      width="120" />
 </floater>
diff --git a/indra/newview/skins/default/xui/en/floater_map.xml b/indra/newview/skins/default/xui/en/floater_map.xml
index b8893e11d90207b5430afd4630aadccc0f57fc44..9639e70544a9161a0314451cd9745bd1b7cd0dd0 100644
--- a/indra/newview/skins/default/xui/en/floater_map.xml
+++ b/indra/newview/skins/default/xui/en/floater_map.xml
@@ -16,11 +16,35 @@
  width="200">
     <floater.string
      name="ToolTipMsg">
-        [REGION](Double-click to open Map, shift-drag to pan)
+        [PARCEL_NAME_MSG][PARCEL_SALE_PRICE_MSG][PARCEL_SALE_AREA_MSG][PARCEL_OWNER_MSG][REGION_NAME_MSG][TOOL_TIP_HINT_MSG]
+    </floater.string>
+    <floater.string
+     name="ParcelNameMsg">
+        [PARCEL_NAME]
+    </floater.string>
+    <floater.string
+     name="ParcelSalePriceMsg">
+        Price: L$[PRICE] (L$[PRICE_PER_SQM]/m²)
+    </floater.string>
+    <floater.string
+     name="ParcelSaleAreaMsg">
+        Area: [AREA]m²
+    </floater.string>
+    <floater.string
+     name="ParcelOwnerMsg">
+        Owner: [PARCEL_OWNER]
+    </floater.string>
+    <floater.string
+     name="RegionNameMsg">
+        Region: [REGION_NAME]
     </floater.string>
 	<floater.string
-     name="AltToolTipMsg">
-		[REGION](Double-click to teleport, shift-drag to pan)
+     name="ToolTipHintMsg">
+        Double-click to open map
+	</floater.string>
+	<floater.string
+     name="AltToolTipHintMsg">
+        Double-click to teleport
 	</floater.string>
 	<floater.string name="mini_map_caption">
 	Mini-map
@@ -37,105 +61,73 @@
     <text
      type="string"
      length="1"
-     bottom="218"
      label="N"
      layout="topleft"
-     left="0"
      name="floater_map_north"
-     right="10"
-     text_color="1 1 1 0.7"
-     top="189">
+     text_color="1 1 1 0.7">
         N
     </text>
     <text
      type="string"
      length="1"
-     bottom="218"
      label="E"
      layout="topleft"
-     left="0"
      name="floater_map_east"
-     right="10"
-     text_color="1 1 1 0.7"
-     top="189">
+     text_color="1 1 1 0.7">
         E
     </text>
     <text
      type="string"
      length="1"
-     bottom="205"
      label="W"
      layout="topleft"
-     left="0"
      name="floater_map_west"
-     right="11"
-     text_color="1 1 1 0.7"
-     top="175">
+     text_color="1 1 1 0.7">
         W
     </text>
     <text
      type="string"
      length="1"
-     bottom="218"
      label="S"
      layout="topleft"
-     left="0"
      name="floater_map_south"
-     right="10"
-     text_color="1 1 1 0.7"
-     top="189">
+     text_color="1 1 1 0.7">
         S
     </text>
     <text
      type="string"
      length="1"
-     bottom="218"
      label="SE"
      layout="topleft"
-     left="0"
      name="floater_map_southeast"
-     right="20"
-     text_color="1 1 1 0.7"
-     top="189">
+     text_color="1 1 1 0.7">
         SE
     </text>
     <text
      type="string"
      length="1"
-     bottom="218"
      label="NE"
      layout="topleft"
-     left="0"
      name="floater_map_northeast"
-     right="20"
-     text_color="1 1 1 0.7"
-     top="189">
+     text_color="1 1 1 0.7">
         NE
     </text>
     <text
      type="string"
      length="1"
-     bottom="218"
      label="SW"
      layout="topleft"
-     left="0"
      name="floater_map_southwest"
-     right="20"
-     text_color="1 1 1 0.7"
-     top="189">
+     text_color="1 1 1 0.7">
         SW
     </text>
     <text
      type="string"
      length="1"
-     bottom="218"
      label="NW"
      layout="topleft"
-     left="0"
      name="floater_map_northwest"
-     right="20"
-     text_color="1 1 1 0.7"
-     top="189">
+     text_color="1 1 1 0.7">
         NW
     </text>
 </floater>
diff --git a/indra/newview/skins/default/xui/en/floater_mfa.xml b/indra/newview/skins/default/xui/en/floater_mfa.xml
new file mode 100644
index 0000000000000000000000000000000000000000..a649cc6d471101fd6e9b5731c0db7c555ab47d3a
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/floater_mfa.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<floater
+ title="MFA Token Requred"
+ legacy_header_height="18"
+ can_minimize="false"
+ can_close="false"
+ height="110"
+ layout="topleft"
+ name="mfa_challenge"
+ help_topic="mfa_challenge"
+ width="550">
+    <text
+     type="string"
+     word_wrap="true"
+     length="1"
+     follows="top|left"
+     height="15"
+     layout="topleft"
+     left="10"
+     name="token_prompt_text"
+     top="20">
+        token prompt
+    </text>
+    <line_editor
+     follows="left|top|right"
+     height="19"
+     layout="topleft"
+     bottom_delta="40"
+     name="token_edit"
+     width="100" />
+    <button
+     follows="top|left"
+     height="20"
+     label="Continue"
+     layout="topleft"
+     left="10"
+     name="continue_btn"
+     bottom_delta="30"
+     width="64" />
+    <button
+     follows="top|left"
+     height="20"
+     label="Cancel"
+     layout="topleft"
+     left_pad="5"
+     name="cancel_btn"
+     bottom_delta="0"
+     width="64" />
+</floater>
diff --git a/indra/newview/skins/default/xui/en/floater_model_preview.xml b/indra/newview/skins/default/xui/en/floater_model_preview.xml
index f4cf2cb5124e06c9c310d6e8f34375dadc52945a..21c894d3afeef19e9cd40fcdb670579cf13993a1 100644
--- a/indra/newview/skins/default/xui/en/floater_model_preview.xml
+++ b/indra/newview/skins/default/xui/en/floater_model_preview.xml
@@ -34,7 +34,7 @@
   <string name="mesh_status_missing_lod">Missing required level of detail.</string>
   <string name="mesh_status_invalid_material_list">LOD materials are not a subset of reference model.</string>
   <string name="phys_status_vertex_limit_exceeded">Some physical hulls exceed vertex limitations.</string>
-  <string name="phys_status_degenerate_triangles">The physics mesh too dense remove the small thin triangles (see preview)</string>
+  <string name="phys_status_degenerate_triangles">The physics mesh is too dense or contains degenerate triangles. Use Analyze/Simplify to resolve.</string>
   <string name="layer_all">All</string> <!-- Text to display in physics layer combo box for "all layers" -->
   <string name="decomposing">Analyzing...</string>
   <string name="simplifying">Simplifying...</string>
@@ -45,7 +45,21 @@
   <string name="UnrecognizedJoint">Rigged to unrecognized joint name [NAME]</string>
   <string name="UnknownJoints">Skinning disabled due to [COUNT] unknown joints</string>
   <string name="ModelLoaded">Model [MODEL_NAME] loaded</string>
+
   <string name="IncompleteTC">Texture coordinates data is not complete.</string>
+  <string name="PositionNaN">Found NaN while loading position data from DAE-Model, invalid model.</string>
+  <string name="NormalsNaN">Found NaN while loading normals from DAE-Model, invalid model.</string>
+  <string name="NegativeScaleTrans">Negative scale detected, unsupported transform. domInstance_geometry: [LABEL]</string>
+  <string name="NegativeScaleNormTrans">Negative scale detected, unsupported post-normalization transform. domInstance_geometry: [LABEL]</string>
+  <string name="CantResolveGeometryUrl">Unable to resolve geometry URL.</string>
+  <string name="ParsingErrorBadElement">Bad element</string>
+  <string name="ParsingErrorCantParseScene">Scene could not be parsed</string>
+  <string name="ParsingErrorCorrupt">Error with dae - traditionally indicates a corrupt file.</string>
+  <string name="ParsingErrorNoController">Could not verify controller</string>
+  <string name="ParsingErrorNoDoc">Can't find internal doc</string>
+  <string name="ParsingErrorNoRoot">Document has no root</string>
+  <string name="ParsingErrorNoScene">Document has no visual_scene</string>
+  <string name="ParsingErrorPositionInvalidModel">Unable to process mesh without position data. Invalid model.</string>
 
   <panel
     follows="top|left"
@@ -173,9 +187,17 @@
                  label="Load from file"
                  value="Load from file" />
                 <item
-                 name="Generate"
-                 label="Generate"
-                 value="Generate" />
+                 name="MeshOpt Auto"
+                 label="Generate Auto"
+                 value="MeshOpt Auto" />
+                <item
+                 name="MeshOptCombine"
+                 label="Generate Precise"
+                 value="MeshOptCombine" />
+                <item
+                 name="MeshOptSloppy"
+                 label="Generate Sloppy"
+                 value="MeshOptSloppy" />
             </combo_box>
             <line_editor
              follows="left|top"
@@ -302,9 +324,17 @@
                  label="Load from file"
                  value="Load from file" />
                 <item
-                 name="Generate"
-                 label="Generate"
-                 value="Generate" />
+                 name="MeshOpt Auto"
+                 label="Generate Auto"
+                 value="MeshOpt Auto" />
+                <item
+                 name="MeshOptCombine"
+                 label="Generate Precise"
+                 value="MeshOptCombine" />
+                <item
+                 name="MeshOptSloppy"
+                 label="Generate Sloppy"
+                 value="MeshOptSloppy" />
                 <item
                  name="Use LoD above"
                  label="Use LoD above"
@@ -435,9 +465,17 @@
                  label="Load from file"
                  value="Load from file" />
                 <item
-                 name="Generate"
-                 label="Generate"
-                 value="Generate" />
+                 name="MeshOpt Auto"
+                 label="Generate Auto"
+                 value="MeshOpt Auto" />
+                <item
+                 name="MeshOptCombine"
+                 label="Generate Precise"
+                 value="MeshOptCombine" />
+                <item
+                 name="MeshOptSloppy"
+                 label="Generate Sloppy"
+                 value="MeshOptSloppy" />
                 <item
                  name="Use LoD above"
                  label="Use LoD above"
@@ -568,9 +606,17 @@
                  label="Load from file"
                  value="Load from file" />
                 <item
-                 name="Generate"
-                 label="Generate"
-                 value="Generate" />
+                 name="MeshOpt Auto"
+                 label="Generate Auto"
+                 value="MeshOpt Auto" />
+                <item
+                 name="MeshOptCombine"
+                 label="Generate Precise"
+                 value="MeshOptCombine" />
+                <item
+                 name="MeshOptSloppy"
+                 label="Generate Sloppy"
+                 value="MeshOptSloppy" />
                 <item
                  name="Use LoD above"
                  label="Use LoD above"
@@ -784,6 +830,7 @@
                         <combo_item name="physics_medium"> Medium </combo_item>
                         <combo_item name="physics_low">    Low    </combo_item>
                         <combo_item name="physics_lowest"> Lowest </combo_item>
+                        <combo_item name="physics_bounding_box"> Bounding Box </combo_item>
                         <combo_item name="load_from_file"> From file   </combo_item>
                     </combo_box>
                     <line_editor
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 7786ba8a1ce61e77192d04361bd27098acbcc54e..d1e167df64435c6e87d0aedf1b80390cad139852 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
@@ -102,6 +102,18 @@
        Low
   </text>
 
+  <check_box
+    control_name="RenderVSyncEnable"
+    height="16"
+    initial_value="true"
+    label="Enable VSync"
+    layout="topleft"
+    left="30"
+    top_delta="16"
+    name="vsync"
+    tool_tip="Synchronizes the frame rate to the refresh rate of the monitor, which results in smooth performance."
+    width="315" />
+
   <text
     type="string"
     length="1"
@@ -333,18 +345,6 @@
     top_delta="16"
     width="256" />
 
-  <check_box
-    control_name="RenderVBOEnable"
-    height="16"
-    initial_value="true"
-    label="Enable OpenGL Vertex Buffer Objects"
-    layout="topleft"
-    left="30"
-    top_delta="16"
-    name="vbo"
-    tool_tip="Enabling this on modern hardware gives a performance gain.  However, older hardware often has poor implementations of VBOs and you may get crashes when this is enabled."
-    width="315" />
-
   <check_box
     control_name="RenderCompressTextures"
     height="16"
@@ -660,20 +660,6 @@
        Low
   </text>
 
-  <check_box
-    control_name="RenderAvatarVP"
-    height="16"
-    initial_value="true"
-    label="Avatar Hardware skinning"
-    layout="topleft"
-    left="440"
-    name="AvatarVertexProgram"
-    top_delta="16"
-    width="280">
-    <check_box.commit_callback
-      function="Pref.RenderOptionUpdate" />
-  </check_box>
-
   <check_box
     control_name="RenderAvatarCloth"
     height="16"
@@ -885,7 +871,7 @@
       layout="topleft"
       left="13"
       name="horiz_border"
-      top_pad="5"
+      top_pad="21"
       top_delta="5"
       width="774"/>
   <button
diff --git a/indra/newview/skins/default/xui/en/floater_preview_texture.xml b/indra/newview/skins/default/xui/en/floater_preview_texture.xml
index e1e7e1c8c8119ac1e9962b6b04e96bbb0d80b5bf..048cf7df6262b0a26c3a40c66eff8616ae8d779e 100644
--- a/indra/newview/skins/default/xui/en/floater_preview_texture.xml
+++ b/indra/newview/skins/default/xui/en/floater_preview_texture.xml
@@ -17,94 +17,122 @@
      name="Copy">
         Copy To Inventory
     </floater.string>
-    <text
-     type="string"
-     length="1"
-     follows="left|top"
-     font="SansSerif"
-     height="19"
-     layout="topleft"
-     left="10"
-     name="desc txt"
-     top="21"
-     width="90">
-        Description:
-    </text>
-    <line_editor
-     border_style="line"
-     border_thickness="1"
-     follows="left|top|right"
-     font="SansSerif"
-     height="19"
-     layout="topleft"
-     left_pad="0"
-     max_length_bytes="127"
-     name="desc"
-     width="190" />
-    <text
-     type="string"
-     halign="right"
-     length="1"
-     follows="right|bottom"
-     height="16"
-     layout="topleft"
-     left="110"
-     name="dimensions"
-     top="255"
-     width="200">
-        [WIDTH]px x [HEIGHT]px
-    </text>
-    <text
-     type="string"
-     halign="right"
-     length="1"
-     follows="right|bottom"
-     height="16"
-     layout="topleft"
-     left_delta="-110"
-     name="aspect_ratio"
-     top_pad="5"
-     width="200">
-        Preview aspect ratio
-    </text>
-    <combo_box
-     allow_text_entry="true" 
-     top_delta="-3" 
-     follows="right|bottom" 
-     height="23"
-     left_pad="10"
-     max_chars="20"
-     mouse_opaque="true"
-     enabled="true"
-     width="108"
-     name="combo_aspect_ratio"
-     tool_tip="Preview at a fixed aspect ratio">
-	</combo_box>
-    <button
-     follows="right|bottom"
-     height="22"
-     label="OK"
-     layout="topleft"
-     left="6"
-     name="Keep"
-     top_pad="5"
-     width="110" />
-    <button
-     follows="right|bottom"
-     height="22"
-     label="Discard"
-     layout="topleft"
-     left_pad="5"
-     name="Discard"
-     top_delta="0"
-     width="110" />
-    <button
-     follows="right|bottom"
-     height="22"
-     label="Save As"
-     layout="topleft"
-     left_pad="5"
-     name="save_tex_btn"
-     top_delta="0"
-     width="110" />
+    <layout_stack
+     animate="false"
+     name="preview_stack"
+     top_pad="15"
+     left="0"
+     follows="all"
+     orientation="vertical"
+     height="350"
+     width="370"
+     layout="topleft">
+      <layout_panel
+        name="texture_panel"
+        height="305"
+        top_pad="0"
+        left="0"
+        follows="left|top"
+        layout="topleft">
+          <text
+           type="string"
+           length="1"
+           follows="left|top"
+           font="SansSerif"
+           height="19"
+           layout="topleft"
+           left="10"
+           name="desc txt"
+           top="6"
+           width="90">
+              Description:
+          </text>
+          <line_editor
+           border_style="line"
+           border_thickness="1"
+           follows="left|top|right"
+           font="SansSerif"
+           height="19"
+           layout="topleft"
+           left_pad="0"
+           max_length_bytes="127"
+           name="desc"
+           width="190" />
+          <text
+           type="string"
+           halign="right"
+           length="1"
+           follows="right|bottom"
+           height="16"
+           layout="topleft"
+           left="110"
+           name="dimensions"
+           bottom="-40"
+           width="200">
+              [WIDTH]px x [HEIGHT]px
+          </text>
+          <text
+           type="string"
+           halign="right"
+           length="1"
+           follows="right|bottom"
+           height="16"
+           layout="topleft"
+           left_delta="-110"
+           name="aspect_ratio"
+           top_pad="5"
+           width="200">
+              Preview aspect ratio
+          </text>
+          <combo_box
+           allow_text_entry="true" 
+           top_delta="-3" 
+           follows="right|bottom" 
+           height="23"
+           left_pad="10"
+           max_chars="20"
+           mouse_opaque="true"
+           enabled="true"
+           width="108"
+           name="combo_aspect_ratio"
+           tool_tip="Preview at a fixed aspect ratio">
+	      </combo_box>
+      </layout_panel>
+      <layout_panel
+        name="buttons_panel"
+        height="45"
+        bottom="-40"
+        left="0"
+        follows="right|bottom"
+        auto_resize="false"
+        layout="topleft">
+        <button
+         follows="right|bottom"
+         height="22"
+         label="OK"
+         layout="topleft"
+         left="6"
+         name="Keep"
+         top_pad="0"
+         width="110" />
+        <button
+         follows="right|bottom"
+         height="22"
+         label="Discard"
+         layout="topleft"
+         left_pad="5"
+         name="Discard"
+         top_delta="0"
+         width="110" />
+        <button
+         follows="right|bottom"
+         height="22"
+         label="Save As"
+         layout="topleft"
+         left_pad="5"
+         name="save_tex_btn"
+         top_delta="0"
+         width="110" />
+      </layout_panel>
+    </layout_stack>
 </floater>
diff --git a/indra/newview/skins/default/xui/en/floater_profile.xml b/indra/newview/skins/default/xui/en/floater_profile.xml
new file mode 100644
index 0000000000000000000000000000000000000000..32ab811a6e62f97ab93dd0e1bd5669799b54394f
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/floater_profile.xml
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<floater
+ name="avatarinfo"
+ height="510"
+ width="510"
+ layout="topleft"
+ can_close="true"
+ can_resize="true"
+ help_topic="panel_my_profile_tab"
+ min_height="510"
+ min_width="510"
+ positioning="centered"
+ save_rect="true"
+ title="Profile"
+>
+    <panel
+     name="panel_profile_view"
+     top="0"
+     left="0"
+     height="500"
+     width="505"
+     follows="all"
+     class="panel_profile"
+    >
+        <tab_container
+         name="panel_profile_tabs"
+         top_pad="5"
+         left="0"
+         height="500"
+         width="505"
+         follows="all"
+         layout="topleft"
+         halign="center"
+         tab_min_width="81"
+         tab_height="30"
+         tab_position="top"
+        >
+            <panel
+             name="panel_profile_secondlife"
+             label="BIO"
+             layout="topleft"
+             class="panel_profile_secondlife"
+             filename="panel_profile_secondlife.xml"
+             help_topic="profile_secondlife_tab"
+            />
+            <panel
+             name="panel_profile_web"
+             label="FEED"
+             layout="topleft"
+             class="panel_profile_web"
+             filename="panel_profile_web.xml"
+             help_topic="profile_web_tab"
+            />
+            <panel
+             name="panel_profile_picks"
+             label="PICKS"
+             layout="topleft"
+             class="panel_profile_picks"
+             filename="panel_profile_picks.xml"
+             help_topic="profile_picks_tab"
+            />
+            <panel
+             name="panel_profile_classifieds"
+             label="CLASSIFIEDS"
+             layout="topleft"
+             class="panel_profile_classifieds"
+             filename="panel_profile_classifieds.xml"
+             help_topic="profile_classified_tab"
+            />
+            <panel
+             name="panel_profile_firstlife"
+             label="REAL LIFE"
+             layout="topleft"
+             class="panel_profile_firstlife"
+             filename="panel_profile_firstlife.xml"
+             help_topic="profile_firstlife_tab"
+            />
+            <panel
+             name="panel_profile_notes"
+             label="MY NOTES"
+             layout="topleft"
+             class="panel_profile_notes"
+             filename="panel_profile_notes.xml"
+             help_topic="profile_notes_tab"
+            />
+        </tab_container>
+    </panel>
+</floater>
diff --git a/indra/newview/skins/default/xui/en/floater_profile_permissions.xml b/indra/newview/skins/default/xui/en/floater_profile_permissions.xml
new file mode 100644
index 0000000000000000000000000000000000000000..9f3b4d9a00b50c143c9c1f9b9e70a32bc140c7b9
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/floater_profile_permissions.xml
@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<floater
+ can_resize="false"
+ show_title="false"
+ can_minimize="false"
+ can_close="false"
+ header_height="10"
+ bg_opaque_image="Window_NoTitle_Foreground"
+ bg_alpha_image="Window_NoTitle_Background"
+ height="115"
+ layout="topleft"
+ name="profile_permissions"
+ width="300">
+  <string
+   name="description_string"
+   value="Allow [AGENT_NAME] to:" />
+  <text
+   name="perm_description"
+   value="Allow agent to:"
+   top="1"
+   left="12"
+   right="-6"
+   height="16"
+   follows="top|left"
+   layout="topleft"
+   font.style="BOLD"
+    />
+  <check_box
+   name="online_check"
+   label="See when I am online"
+   top_pad="5"
+   left="16"
+   height="16"
+   width="293"
+   follows="top|left"
+   layout="topleft"
+    />
+  <check_box
+   name="map_check"
+   label="Find me on the world map"
+   top_pad="5"
+   left="16"
+   height="16"
+   width="293"
+   follows="top|left"
+   layout="topleft"
+    />
+  <check_box
+   name="objects_check"
+   label="Edit, delete or take my objects from my land"
+   top_pad="5"
+   left="16"
+   height="16"
+   width="293"
+   follows="top|left"
+   layout="topleft"
+    />
+  <button
+   name="perms_btn_ok"
+   label="OK"
+   top_pad="5"
+   left="42"
+   height="20"
+   width="100"
+   follows="top|left"
+   layout="topleft"/>
+  <button
+   name="perms_btn_cancel"
+   label="Cancel"
+   top_delta="0"
+   left_pad="12"
+   height="20"
+   width="100"
+   follows="top|left"
+   layout="topleft"/>
+</floater>
diff --git a/indra/newview/skins/default/xui/en/floater_profile_texture.xml b/indra/newview/skins/default/xui/en/floater_profile_texture.xml
new file mode 100644
index 0000000000000000000000000000000000000000..3b351a332525b541868ca9bd50769166dbb369b5
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/floater_profile_texture.xml
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<floater
+ can_resize="false"
+ show_title="false"
+ can_minimize="false"
+ can_close="false"
+ header_height="10"
+ height="223"
+ width="200"
+ layout="topleft"
+ min_height="128"
+ min_width="128"
+ name="profile_texture">
+    <layout_stack
+     name="preview_stack"
+     top="0"
+     left="0"
+     right="-1"
+     bottom="-1"
+     follows="all"
+     orientation="vertical"
+     layout="topleft"
+     animate="false">
+      <layout_panel
+        name="texture_panel"
+        height="196"
+        follows="left|top"
+        auto_resize="true"
+        layout="topleft">
+        <icon
+         name="profile_pic"
+         image_name="Generic_Person_Large"
+         layout="topleft"
+         follows="all"
+         top="5"
+         left="5"
+         bottom="-1"
+         right="-5"/>
+      </layout_panel>
+      <layout_panel
+        name="buttons_panel"
+        height="26"
+        auto_resize="false"
+        layout="topleft">
+        <layout_stack
+         name="buttons_stack"
+         top="0"
+         left="0"
+         right="-1"
+         bottom="-1"
+         follows="all"
+         orientation="horizontal"
+         layout="topleft"
+         animate="false">
+          <layout_panel
+           follows="all"
+           layout="topleft"
+           name="resizer_left"
+           auto_resize="true"
+           width="1">
+          </layout_panel>
+          <layout_panel
+           follows="all"
+           layout="topleft"
+           name="close_panel"
+           auto_resize="false"
+           width="112">
+            <button
+             follows="top|left"
+             height="22"
+             label="Close"
+             layout="topleft"
+             left="1"
+             top="0"
+             width="110"
+             name="close_btn"/>
+          </layout_panel>
+          <layout_panel
+           follows="all"
+           layout="topleft"
+           name="resizer_right"
+           auto_resize="true"
+           width="1">
+          </layout_panel>
+        </layout_stack>
+      </layout_panel>
+    </layout_stack>
+</floater>
diff --git a/indra/newview/skins/default/xui/en/floater_report_abuse.xml b/indra/newview/skins/default/xui/en/floater_report_abuse.xml
index d07e3cb31b20a5f03571220e85c5418dfb8b4bc5..343e72f057fc0a65a3922fcdfaeadfc660e067e4 100644
--- a/indra/newview/skins/default/xui/en/floater_report_abuse.xml
+++ b/indra/newview/skins/default/xui/en/floater_report_abuse.xml
@@ -11,6 +11,11 @@
      name="Screenshot">
         Screenshot
     </floater.string>
+    <floater.string
+     name="chat_report_format">
+Time: [MSG_TIME]
+Text: [MSG_DESCRIPTION]
+    </floater.string>
     <texture_picker
      allow_no_texture="true"
      default_image_name="None"
@@ -19,7 +24,7 @@
      layout="topleft"
      left="60"
      name="screenshot"
-     top="15"
+     top="20"
      width="220" />
     <text
      type="string"
diff --git a/indra/newview/skins/default/xui/en/floater_stats.xml b/indra/newview/skins/default/xui/en/floater_stats.xml
index f9d44b2c6931d6d7592c3af5cda4cf620787b4c4..b9ca0108b6b3c4e4a262513142ce4e7632a77baa 100644
--- a/indra/newview/skins/default/xui/en/floater_stats.xml
+++ b/indra/newview/skins/default/xui/en/floater_stats.xml
@@ -35,6 +35,25 @@
                   decimal_digits="1"
                   show_bar="true"
                   show_history="true"/>
+        <stat_bar name="frame_mean"
+                  label="frame (mean)"
+                  unit_label="ms"
+                  stat="frametime"
+                  decimal_digits="1"
+                  show_bar="false"
+                  show_history="false"/>
+        <stat_bar name="frame_median"
+                  label="frame (median)"
+                  unit_label="ms"
+                  stat="frametime"
+                  show_median="true"
+                  decimal_digits="1"
+                  show_bar="false"
+                  show_history="false"/>
+        <stat_bar name="framet_jitter"
+                  label="jitter"
+                  decimal_digits="1"
+                  stat="frametimejitter"/>
        <stat_bar name="bandwidth"
                   label="UDP Data Received"
                   stat="activemessagedatareceived"
diff --git a/indra/newview/skins/default/xui/en/floater_tools.xml b/indra/newview/skins/default/xui/en/floater_tools.xml
index 0abee2ff807fa33229cd1b48155951642a3f0484..ade79b8884af31f4b5b0ec4e2b664d0c2051bdda 100644
--- a/indra/newview/skins/default/xui/en/floater_tools.xml
+++ b/indra/newview/skins/default/xui/en/floater_tools.xml
@@ -2,7 +2,7 @@
 <floater
  positioning="cascading"
  legacy_header_height="18"
- height="600"
+ height="609"
  layout="topleft"
  bg_opaque_image="Window_NoTitle_Foreground"
  bg_alpha_image="Window_NoTitle_Background"
@@ -68,7 +68,7 @@
     </floater.string>
     <floater.string
      name="status_selectcount">
-        [OBJ_COUNT] objects selected, land impact [LAND_IMPACT]
+        [OBJ_COUNT] objects selected, land impact [LAND_IMPACT] [secondlife:///app/openfloater/object_weights More info]
     </floater.string>
     <floater.string
      name="status_remaining_capacity">
@@ -763,11 +763,12 @@
 	  font="SansSerifSmall"
 	  layout="topleft"
 	  left="10"
-	  name="selection_count"
+	  name="selection_faces"
 	  top_delta="0"
 	  visible="false"
 	  width="280">
-	</text>
+    Faces selected: [FACES_STRING]
+  </text>
 	<text
 	 text_color="LtGray_50"
 	  type="string"
@@ -777,11 +778,10 @@
 	  font="SansSerifSmall"
 	  layout="topleft"
 	  left="10"
-	  name="remaining_capacity"
+	  name="selection_count"
 	  top_pad="0"
 	  visible="false"
 	  width="280">
-	  [CAPACITY_STRING] [secondlife:///app/openfloater/object_weights More info]
 	</text>
     <!-- <text -->
     <!-- text_color="LtGray_50" -->
@@ -820,7 +820,7 @@
     width="282"/>
     <tab_container
      follows="left|top"
-     height="410"
+     height="426"
      halign="center"
      left="0"
      name="Object Info Tabs"
@@ -1430,16 +1430,40 @@ even though the user gets a free copy.
              tool_tip="Causes object to not collide with other objects or avatars"
              top_pad="0"
              width="123" />
-        <text
+            <view_border
+             bevel_style="none"
+             follows="top|left"
+             height="0"
+             layout="topleft"
+             left_delta="0"
+             name="object_horizontal"
+             top_pad="10"
+             width="95" />
+            <menu_button
+             menu_filename="menu_copy_paste_pos.xml"
+             follows="top|left"
+             height="11"
+             image_disabled="ClipboardSmallMenu_Disabled"
+             image_selected="ClipboardSmallMenu_Press"
+             image_unselected="ClipboardSmallMenu_Off"
+             layout="topleft"
+             left_delta="0"
+             top_pad="13"
+             name="clipboard_pos_btn"
+             tool_tip="Paste options"
+             width="19"/>
+            <text
              type="string"
              length="1"
              follows="left|top"
              height="10"
              layout="topleft"
              name="label position"
-             top_pad="10"
+             tool_tip="Position (meters)"
+             left_pad="8"
+             top_delta="0"
              width="121">
-                Position (meters)
+                Position (m)
             </text>
             <spinner
              follows="left|top"
@@ -1449,12 +1473,12 @@ even though the user gets a free copy.
              label="X"
              label_width="10"
              layout="topleft"
-             left_delta="0"
+             left_delta="-27"
              max_val="512"
              min_val="-256"
              name="Pos X"
              text_enabled_color="1 0 0.3 .7"
-             top_pad="5"
+             top_pad="8"
              width="87" />
             <spinner
              follows="left|top"
@@ -1481,21 +1505,36 @@ even though the user gets a free copy.
              layout="topleft"
              left_delta="0"
              max_val="4096"
+             min_val="-32"
              name="Pos Z"
              text_enabled_color="0 0.8 1 .65"
              top_pad="3"
              width="87" />
+            <menu_button
+             menu_filename="menu_copy_paste_size.xml"
+             follows="top|left"
+             height="11"
+             image_disabled="ClipboardSmallMenu_Disabled"
+             image_selected="ClipboardSmallMenu_Press"
+             image_unselected="ClipboardSmallMenu_Off"
+             layout="topleft"
+             left_delta="0"
+             top_pad="13"
+             name="clipboard_size_btn"
+             tool_tip="Paste options"
+             width="19"/>
             <text
              type="string"
              length="1"
              follows="left|top"
              height="10"
              layout="topleft"
-             left_delta="0"
+             left_pad="8"
+             top_delta="0"
              name="label size"
-             top_pad="6"
+             tool_tip="Size (meters)"
              width="121">
-                Size (meters)
+                Size (m)
             </text>
             <spinner
              follows="left|top"
@@ -1505,12 +1544,12 @@ even though the user gets a free copy.
              label="X"
              label_width="10"
              layout="topleft"
-             left_delta="0"
+             left_delta="-27"
              max_val="64"
              min_val="0.01"
              name="Scale X"
              text_enabled_color="1 1 1 1"
-             top_pad="5"
+             top_pad="8"
              width="87" />
             <spinner
              follows="left|top"
@@ -1542,17 +1581,31 @@ even though the user gets a free copy.
              text_enabled_color="1 1 1 1"
              top_pad="3"
              width="87" />
+            <menu_button
+             menu_filename="menu_copy_paste_rot.xml"
+             follows="top|left"
+             height="11"
+             image_disabled="ClipboardSmallMenu_Disabled"
+             image_selected="ClipboardSmallMenu_Press"
+             image_unselected="ClipboardSmallMenu_Off"
+             layout="topleft"
+             left_delta="0"
+             top_pad="13"
+             name="clipboard_rot_btn"
+             tool_tip="Paste options"
+             width="19"/>
             <text
              type="string"
              length="1"
              follows="left|top"
              height="10"
              layout="topleft"
-             left_delta="0"
+             left_pad="8"
+             top_delta="0"
              name="label rotation"
-             top_pad="10"
+             tool_tip="Rotation (degrees)"
              width="121">
-                Rotation (degrees)
+                Rotation (°)
             </text>
             <spinner
              decimal_digits="2"
@@ -1563,12 +1616,12 @@ even though the user gets a free copy.
              label="X"
              label_width="10"
              layout="topleft"
-             left_delta="0"
+             left_delta="-27"
              max_val="9999"
              min_val="-9999"
              name="Rot X"
              text_enabled_color="1 1 1 1"
-             top_pad="5"
+             top_pad="8"
              width="87" />
             <spinner
              decimal_digits="2"
@@ -1614,13 +1667,23 @@ even though the user gets a free copy.
              width="150">
                 Prim Type
             </text>-->
+
+            <view_border
+             bevel_style="none"
+             follows="top|left"
+             layout="topleft"
+             name="object_vertical"
+             left="117"
+             top="6"
+             height="500"
+             width="0"/>
             <combo_box
              height="19"
              layout="topleft"
              name="comboBaseType"
              top="6"
              left="125"
-             width="150">
+             width="125">
                 <combo_box.item
                  label="Box"
                  name="Box"
@@ -1654,13 +1717,26 @@ even though the user gets a free copy.
                  name="Sculpted"
                  value="Sculpted" />
             </combo_box>
+            <menu_button
+              menu_filename="menu_copy_paste_object.xml"
+              follows="top|left"
+              height="15"
+              image_disabled="ClipboardMenu_Disabled"
+              image_selected="ClipboardMenu_Press"
+              image_unselected="ClipboardMenu_Off"
+              layout="topleft"
+              left_pad="8"
+              top_delta="2"
+              name="clipboard_obj_params_btn"
+              tool_tip="Paste options"
+              width="22"/>
             <text
              type="string"
              length="1"
              follows="left|top"
              height="10"
              layout="topleft"
-             left_delta="0"
+             left="125"
              name="text cut"
              top_pad="5"
              width="150">
@@ -1700,7 +1776,7 @@ even though the user gets a free copy.
              layout="topleft"
              left="125"
              name="text hollow"
-             top_pad="6"
+             top_pad="7"
              width="68">
                 Hollow
             </text>
@@ -1748,7 +1824,7 @@ even though the user gets a free copy.
              layout="topleft"
              left="125"
              name="Hollow Shape"
-             top_pad="4"
+             top_pad="7"
              width="150">
                 Hollow Shape
             </text>
@@ -1784,7 +1860,7 @@ even though the user gets a free copy.
              layout="topleft"
              left_delta="0"
              name="text twist"
-             top_pad="5"
+             top_pad="7"
              width="150">
                 Twist (begin/end)
             </text>
@@ -1826,12 +1902,12 @@ even though the user gets a free copy.
              layout="topleft"
              left="125"
              name="scale_taper"
-             top_pad="3"
+             top_pad="7"
              width="150">
                 Taper
             </text>
             <text
-			 visible="false"
+             visible="false"
              type="string"
              length="1"
              follows="left|top"
@@ -1879,7 +1955,7 @@ even though the user gets a free copy.
              layout="topleft"
              left="125"
              name="text topshear"
-             top_pad="3"
+             top_pad="5"
              width="141">
                 Top Shear
             </text>
@@ -1922,12 +1998,12 @@ even though the user gets a free copy.
              layout="topleft"
              left="125"
              name="advanced_cut"
-             top_pad="3"
+             top_pad="7"
              width="150">
                 Profile Cut (begin/end)
             </text>
             <text
-			 visible="false"
+             visible="false"
              type="string"
              length="1"
              follows="left|top"
@@ -1986,7 +2062,7 @@ even though the user gets a free copy.
              layout="topleft"
              left="125"
              name="text taper2"
-             top_pad="3"
+             top_pad="7"
              width="150">
                 Taper
             </text>
@@ -2029,7 +2105,7 @@ even though the user gets a free copy.
              layout="topleft"
              left="125"
              name="text radius delta"
-             top_pad="2"
+             top_pad="7"
              width="78">
                 Radius
             </text>
@@ -2157,6 +2233,19 @@ even though the user gets a free copy.
 	<panel.string name="None">None</panel.string>
 	<panel.string name="Prim">Prim</panel.string>
 	<panel.string name="Convex Hull">Convex Hull</panel.string>
+            <menu_button
+              menu_filename="menu_copy_paste_features.xml"
+              follows="top|left"
+              height="15"
+              image_disabled="ClipboardMenu_Disabled"
+              image_selected="ClipboardMenu_Press"
+              image_unselected="ClipboardMenu_Off"
+              layout="topleft"
+              left="258"
+              top="8"
+              name="clipboard_features_params_btn"
+              tool_tip="Paste options"
+              width="22"/>
             <text
              type="string"
              length="1"
@@ -2309,6 +2398,15 @@ even though the user gets a free copy.
              name="FlexForceZ"
              top_pad="4"
              width="128" />
+            <view_border
+             bevel_style="none"
+             follows="top|left"
+             height="0"
+             layout="topleft"
+             left="8"
+             name="object_horizontal"
+             top_pad="10"
+             width="278" />
 
             <check_box
              height="16"
@@ -2317,7 +2415,7 @@ even though the user gets a free copy.
              left="10"
              name="Light Checkbox Ctrl"
              tool_tip="Causes object to emit light"
-             top_pad="15"
+             top_pad="8"
              width="60" />
             <color_swatch
              can_apply_immediately="true"
@@ -2344,6 +2442,19 @@ even though the user gets a free copy.
             name="light texture control"
             tool_tip="Click to choose a projection image (only has effect with deferred rendering enabled)"
             width="32" />
+         <menu_button
+              menu_filename="menu_copy_paste_light.xml"
+              follows="top|left"
+              height="15"
+              image_disabled="ClipboardMenu_Disabled"
+              image_selected="ClipboardMenu_Press"
+              image_unselected="ClipboardMenu_Off"
+              layout="topleft"
+              left="258"
+              top_delta="0"
+              name="clipboard_light_params_btn"
+              tool_tip="Paste options"
+              width="22"/>
           <spinner
              follows="left|top"
              height="19"
@@ -2353,7 +2464,7 @@ even though the user gets a free copy.
              layout="topleft"
              left="10"
              name="Light Intensity"
-             top_pad="3"
+             top_pad="26"
              width="128" />
           <spinner bottom_delta="0"
                    decimal_digits="3"
@@ -2575,7 +2686,7 @@ even though the user gets a free copy.
              border_visible="true"
              bevel_style="in"
              follows="left|top|right"
-             height="325"
+             height="335"
              layout="topleft"
              left="10"
              name="contents_inventory"
diff --git a/indra/newview/skins/default/xui/en/floater_world_map.xml b/indra/newview/skins/default/xui/en/floater_world_map.xml
index 83407069d2eee1ab962a8d3381a9c897bd9c746a..c965a4427ce4c58a462709a6c57ebc1cdc834387 100644
--- a/indra/newview/skins/default/xui/en/floater_world_map.xml
+++ b/indra/newview/skins/default/xui/en/floater_world_map.xml
@@ -14,6 +14,31 @@
  single_instance="true"
  title="WORLD MAP"
  width="650">
+  <string
+   name="collapse_icon"
+   value="map_ui_collapse_icon.png"/>
+  <string
+   name="expand_icon"
+   value="map_ui_expand_icon.png"/>
+  <string
+   name="collapse_tooltip"
+   value="Hide map controls"/>
+  <string
+   name="expand_tooltip"
+   value="Show map controls"/>
+  <layout_stack
+   animate="false"
+   follows="all"
+   name="floater_map_stack"
+   tab_group="1"
+   top="16"
+   left="0"
+   right="-1"
+   bottom="-1">
+    <layout_panel
+     name="map_lp"
+     width="385"
+     height="575">
     <panel
      filename="panel_world_map.xml"
      follows="all"
@@ -21,17 +46,48 @@
      layout="topleft"
      left="10"
      name="objects_mapview"
-     top="25"
+     top="6"
      width="375" />
+      <panel
+       follows="top|right"
+       height="30"
+       layout="topleft"
+       left_pad="-29"
+       name="expand_btn_panel"
+       background_visible="true"
+       bg_opaque_color="FloaterFocusBackgroundColor"
+       bg_alpha_color="FloaterDefaultBackgroundColor"
+       background_opaque="true"
+       tool_tip="Hide map controls"
+       top="350"
+       width="30">
+        <icon
+         follows="top|right"
+         height="16"
+         width="16"
+         top="7"
+         left="7"
+         scale_image="false"
+         image_name="map_ui_collapse_icon.png"
+         layout="topleft"
+         mouse_opaque="true"
+         name="expand_collapse_icon"
+         tool_tip="Hide map controls" />
+      </panel>
+      </layout_panel>
+    <layout_panel
+      height="575"
+      width="265"
+      expanded_min_dim="265"
+      name="controls_lp">
      <panel
-     name="layout_panel_1"
-     height="22"
-     width="238"
-     follows="right|top"
-     top="25"
-     left_pad="5"
-  background_visible="true"
-  bg_alpha_color="DkGray2">
+      name="layout_panel_1"
+      height="22"
+      width="238"
+      follows="right|top"
+      top="6"     
+      background_visible="true"
+      bg_alpha_color="DkGray2">
     <text
      text_color="White"
      font="SansSerifLarge"
@@ -43,17 +99,17 @@
      layout="topleft"
      left="15"
      name="events_label"
-     top="3"
      width="215">
         Legend
     </text>
     </panel>
-<panel
- follows="right|top"
-  height="126"
-  top_pad="0"
-  width="238"
-  name="layout_panel_2">
+    <panel
+     follows="right|top"
+     height="126"
+     top_pad="4"
+     width="238"
+     left="1"
+     name="layout_panel_2">
 <button
      follows="right|top"
      height="22"
@@ -677,6 +733,7 @@
      name="zoom_icon"
      top_pad="7"
      width="16" ></icon>
+    <!-- NOTE: min_val for zoom slider is hardcoded for performance reasons -->
     <slider
      follows="left|bottom"
      height="16"
@@ -684,10 +741,12 @@
      initial_value="-2"
      left_pad="0"
      layout="topleft"
-     max_val="0"
+     max_val="4"
      min_val="-8"
      name="zoom slider"
      show_text="false"
      width="200" />
      </panel>
+      </layout_panel>
+    </layout_stack>
 </floater>
diff --git a/indra/newview/skins/default/xui/en/inspect_avatar.xml b/indra/newview/skins/default/xui/en/inspect_avatar.xml
index ef4f19cd4cdbb17e98e520bf85d5f83c511aec53..fceb9b218426432df9757b00b2ef9797b7897f6b 100644
--- a/indra/newview/skins/default/xui/en/inspect_avatar.xml
+++ b/indra/newview/skins/default/xui/en/inspect_avatar.xml
@@ -85,6 +85,8 @@
      use_ellipses="true" />
      <text
      follows="left|top|right"
+     trusted_content="false"
+     always_show_icons="true"
      height="35"
      left="8"
      name="user_details"
diff --git a/indra/newview/skins/default/xui/en/main_view.xml b/indra/newview/skins/default/xui/en/main_view.xml
index 9885e37cea6d26fe3a09b69b7b77b9b4c5638c2d..842184de883cea353f714d0ebc0f86c4eee72980 100644
--- a/indra/newview/skins/default/xui/en/main_view.xml
+++ b/indra/newview/skins/default/xui/en/main_view.xml
@@ -8,6 +8,16 @@
  tab_stop="false" 
  name="main_view"
  width="1024">
+
+  <!-- At the moment layout_stack is not an LLUICtrl,
+  but Tab requires focus_root to function and focus_root
+  functionality is implemented in LLUICtrl -->
+  <panel follows="all"
+         height="768"
+         name="menu_tab_wrapper"
+         mouse_opaque="false"
+         focus_root="true"
+         top="0">
   <layout_stack border_size="0"
                 follows="all"
                 mouse_opaque="false"
@@ -18,12 +28,12 @@
     <layout_panel mouse_opaque="true"
               follows="left|right|top"
               name="status_bar_container"
-              tab_stop="false"
               height="19"
               left="0"
               top="0"
               width="1024"
               auto_resize="false"
+              default_tab_group="1"
               visible="true">
       <view mouse_opaque="false"
             follows="all"
@@ -31,13 +41,13 @@
             left="0"
             top="0"
             width="1024"
+            tab_group="1"
             height="19"/>
     </layout_panel>
     <layout_panel auto_resize="false"
                   height="34"
                   mouse_opaque="false"
                   name="nav_bar_container"
-                  tab_stop="false"
                   width="1024"
                   visible="false"/>
     <layout_panel auto_resize="true"  
@@ -99,6 +109,7 @@
              tab_stop="false"/>
     </layout_panel>
   </layout_stack>
+  </panel> <!--menu_tab_wrapper-->
  
   <panel top="0"
         follows="all"
diff --git a/indra/newview/skins/default/xui/en/menu_attachment_self.xml b/indra/newview/skins/default/xui/en/menu_attachment_self.xml
index 26b1c86c53bab1be966053fcf0432e338eb5310f..3b91b9df7ab33c2e63e87050ca848f2682843504 100644
--- a/indra/newview/skins/default/xui/en/menu_attachment_self.xml
+++ b/indra/newview/skins/default/xui/en/menu_attachment_self.xml
@@ -33,6 +33,13 @@
          function="Object.EnableTouch"
          name="EnableTouch"/>
     </menu_item_call>
+    <menu_item_call
+     label="Show in inventory"
+     layout="topleft"
+     name="Show original">
+      <menu_item_call.on_click
+       function="Object.ShowOriginal" />
+    </menu_item_call>
     <menu_item_separator
      layout="topleft" />
 
diff --git a/indra/newview/skins/default/xui/en/menu_avatar_icon.xml b/indra/newview/skins/default/xui/en/menu_avatar_icon.xml
index 05ab4d35a0de1db0a1558565da38473b3c3f9ca3..9f394a4c74ddcaa0cd86bb77451e5c3d83cb4dd9 100644
--- a/indra/newview/skins/default/xui/en/menu_avatar_icon.xml
+++ b/indra/newview/skins/default/xui/en/menu_avatar_icon.xml
@@ -96,6 +96,13 @@
      name="Pay">
        <on_click function="AvatarIcon.Action" parameter="pay" />
     </menu_item_call>
+    <menu_item_call
+     label="Report Abuse"
+     layout="topleft"
+     name="Report Abuse">
+       <on_click function="AvatarIcon.Action" parameter="report_abuse" />
+       <on_enable function="AvatarIcon.Enable" parameter="report_abuse" />
+    </menu_item_call>
     <menu_item_check
      label="Block Voice"
      layout="topleft"
diff --git a/indra/newview/skins/default/xui/en/menu_avatar_self.xml b/indra/newview/skins/default/xui/en/menu_avatar_self.xml
index 500b6fffc264a64092db73a4c81daae34ebb31b4..20f3ad080bf7e367002943132ec8259ac7c0e472 100644
--- a/indra/newview/skins/default/xui/en/menu_avatar_self.xml
+++ b/indra/newview/skins/default/xui/en/menu_avatar_self.xml
@@ -290,4 +290,11 @@
     <menu_item_call.on_visible
      function="EnableMuteParticle" />
   </menu_item_call>
+  <menu_item_separator/>
+  <menu_item_call label="View Profile"
+       layout="topleft"
+       name="show_avatar_profile">
+    <menu_item_call.on_click
+     function="Avatar.ToggleMyProfile" />
+  </menu_item_call>
 </context_menu>
diff --git a/indra/newview/skins/default/xui/en/menu_conversation.xml b/indra/newview/skins/default/xui/en/menu_conversation.xml
index ed362b36e54ec2310581d0e90e9ef81e4d1fac36..59e6106a28a1120f085f542e2f7d0750ac9ace3c 100644
--- a/indra/newview/skins/default/xui/en/menu_conversation.xml
+++ b/indra/newview/skins/default/xui/en/menu_conversation.xml
@@ -132,6 +132,13 @@
         <on_click function="Avatar.DoToSelected" parameter="pay" />
         <on_enable function="Avatar.EnableItem" parameter="can_pay" />
     </menu_item_call>
+    <menu_item_call
+     label="Report Abuse"
+     layout="topleft"
+     name="report_abuse">
+       <on_click function="Avatar.DoToSelected" parameter="report_abuse" />
+       <on_enable function="Avatar.EnableItem" parameter="report_abuse" />
+    </menu_item_call>
     <menu_item_check
      label="Block Voice"
      layout="topleft"
diff --git a/indra/newview/skins/default/xui/en/menu_copy_paste_color.xml b/indra/newview/skins/default/xui/en/menu_copy_paste_color.xml
new file mode 100644
index 0000000000000000000000000000000000000000..4c12180daf32f53bc78324a03f636e3f449118fb
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/menu_copy_paste_color.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<toggleable_menu
+ layout="topleft"
+ name="Copy Paste Color Menu">
+    <menu_item_call
+     label="Copy"
+     layout="topleft"
+     name="params_copy"
+     visible="true">
+       <on_click function="PanelFace.menuDoToSelected" parameter="color_copy" />
+    </menu_item_call>
+    <menu_item_call
+     label="Paste"
+     layout="topleft"
+     name="params_paste"
+     visible="true">
+       <on_click function="PanelFace.menuDoToSelected" parameter="color_paste" />
+       <on_enable function="PanelFace.menuEnable" parameter="color_paste" />
+    </menu_item_call>
+</toggleable_menu>
+
diff --git a/indra/newview/skins/default/xui/en/menu_copy_paste_features.xml b/indra/newview/skins/default/xui/en/menu_copy_paste_features.xml
new file mode 100644
index 0000000000000000000000000000000000000000..4823d74a261c2ecb57d359a05b4af5708610cf53
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/menu_copy_paste_features.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<toggleable_menu
+ layout="topleft"
+ name="Copy Paste Features Menu">
+    <menu_item_call
+     label="Copy"
+     layout="topleft"
+     name="params_copy"
+     visible="true">
+       <on_click function="PanelVolume.menuDoToSelected" parameter="features_copy" />
+    </menu_item_call>
+    <menu_item_call
+     label="Paste"
+     layout="topleft"
+     name="params_paste"
+     visible="true">
+       <on_click function="PanelVolume.menuDoToSelected" parameter="features_paste" />
+       <on_enable function="PanelVolume.menuEnable" parameter="features_paste" />
+    </menu_item_call>
+</toggleable_menu>
+
diff --git a/indra/newview/skins/default/xui/en/menu_copy_paste_light.xml b/indra/newview/skins/default/xui/en/menu_copy_paste_light.xml
new file mode 100644
index 0000000000000000000000000000000000000000..5de23dfee3f9bdd0a4d57d7ea8a4ca9aa7585c22
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/menu_copy_paste_light.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<toggleable_menu
+ layout="topleft"
+ name="Copy Paste Light Menu">
+    <menu_item_call
+     label="Copy"
+     layout="topleft"
+     name="params_copy"
+     visible="true">
+       <on_click function="PanelVolume.menuDoToSelected" parameter="light_copy" />
+    </menu_item_call>
+    <menu_item_call
+     label="Paste"
+     layout="topleft"
+     name="params_paste"
+     visible="true">
+       <on_click function="PanelVolume.menuDoToSelected" parameter="light_paste" />
+       <on_enable function="PanelVolume.menuEnable" parameter="light_paste" />
+    </menu_item_call>
+</toggleable_menu>
+
diff --git a/indra/newview/skins/default/xui/en/menu_copy_paste_object.xml b/indra/newview/skins/default/xui/en/menu_copy_paste_object.xml
new file mode 100644
index 0000000000000000000000000000000000000000..bdc4537a9dc0d39c0ace17aec056fe448c589ee0
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/menu_copy_paste_object.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<toggleable_menu
+ layout="topleft"
+ name="Copy Paste Object Menu">
+    <menu_item_call
+     label="Copy"
+     layout="topleft"
+     name="params_copy"
+     visible="true">
+       <on_click function="PanelObject.menuDoToSelected" parameter="params_copy" />
+    </menu_item_call>
+    <menu_item_call
+     label="Paste"
+     layout="topleft"
+     name="params_paste"
+     visible="true">
+       <on_click function="PanelObject.menuDoToSelected" parameter="params_paste" />
+       <on_enable function="PanelObject.menuEnable" parameter="params_paste" />
+    </menu_item_call>
+</toggleable_menu>
+
diff --git a/indra/newview/skins/default/xui/en/menu_copy_paste_pos.xml b/indra/newview/skins/default/xui/en/menu_copy_paste_pos.xml
new file mode 100644
index 0000000000000000000000000000000000000000..3ea95b281f08d6e64d558cb1301d3b6b205a819d
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/menu_copy_paste_pos.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<toggleable_menu
+ layout="topleft"
+ name="Copy Paste Position Menu">
+    <menu_item_call
+     label="Copy all"
+     layout="topleft"
+     name="psr_copy"
+     visible="true">
+       <on_click function="PanelObject.menuDoToSelected" parameter="psr_copy" />
+       <on_enable function="PanelObject.menuEnable" parameter="psr_copy" />
+    </menu_item_call>
+    <menu_item_call
+     label="Copy position"
+     layout="topleft"
+     name="pos_copy"
+     visible="true">
+       <on_click function="PanelObject.menuDoToSelected" parameter="pos_copy" />
+    </menu_item_call>
+    <menu_item_call
+     label="Paste all"
+     layout="topleft"
+     name="psr_paste"
+     visible="true">
+       <on_click function="PanelObject.menuDoToSelected" parameter="psr_paste" />
+       <on_enable function="PanelObject.menuEnable" parameter="psr_paste" />
+    </menu_item_call>
+    <menu_item_call
+     label="Paste position"
+     layout="topleft"
+     name="pos_paste"
+     visible="true">
+       <on_click function="PanelObject.menuDoToSelected" parameter="pos_paste" />
+       <on_enable function="PanelObject.menuEnable" parameter="pos_paste" />
+    </menu_item_call>
+</toggleable_menu>
+
diff --git a/indra/newview/skins/default/xui/en/menu_copy_paste_rot.xml b/indra/newview/skins/default/xui/en/menu_copy_paste_rot.xml
new file mode 100644
index 0000000000000000000000000000000000000000..06ce80f8977c32488cd7b58d5f3a9cdfe09562e5
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/menu_copy_paste_rot.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<toggleable_menu
+ layout="topleft"
+ name="Copy Paste Rotation Menu">
+    <menu_item_call
+     label="Copy all"
+     layout="topleft"
+     name="psr_copy"
+     visible="true">
+       <on_click function="PanelObject.menuDoToSelected" parameter="psr_copy" />
+       <on_enable function="PanelObject.menuEnable" parameter="rot_paste" />
+    </menu_item_call>
+    <menu_item_call
+     label="Copy rotation"
+     layout="topleft"
+     name="rot_copy"
+     visible="true">
+       <on_click function="PanelObject.menuDoToSelected" parameter="rot_copy" />
+    </menu_item_call>
+    <menu_item_call
+     label="Paste all"
+     layout="topleft"
+     name="psr_paste"
+     visible="true">
+       <on_click function="PanelObject.menuDoToSelected" parameter="psr_paste" />
+       <on_enable function="PanelObject.menuEnable" parameter="psr_paste" />
+    </menu_item_call>
+    <menu_item_call
+     label="Paste rotation"
+     layout="topleft"
+     name="rot_paste"
+     visible="true">
+       <on_click function="PanelObject.menuDoToSelected" parameter="rot_paste" />
+       <on_enable function="PanelObject.menuEnable" parameter="rot_paste" />
+    </menu_item_call>
+</toggleable_menu>
+
diff --git a/indra/newview/skins/default/xui/en/menu_copy_paste_size.xml b/indra/newview/skins/default/xui/en/menu_copy_paste_size.xml
new file mode 100644
index 0000000000000000000000000000000000000000..7082a0e65b37c10df8cf24a7bf3c9f392dcb24b9
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/menu_copy_paste_size.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<toggleable_menu
+ layout="topleft"
+ name="Copy Paste Size Menu">
+    <menu_item_call
+     label="Copy all"
+     layout="topleft"
+     name="psr_copy"
+     visible="true">
+       <on_click function="PanelObject.menuDoToSelected" parameter="psr_copy" />
+       <on_enable function="PanelObject.menuEnable" parameter="psr_copy" />
+    </menu_item_call>
+    <menu_item_call
+     label="Copy size"
+     layout="topleft"
+     name="size_copy"
+     visible="true">
+       <on_click function="PanelObject.menuDoToSelected" parameter="size_copy" />
+    </menu_item_call>
+    <menu_item_call
+     label="Paste all"
+     layout="topleft"
+     name="psr_paste"
+     visible="true">
+       <on_click function="PanelObject.menuDoToSelected" parameter="psr_paste" />
+       <on_enable function="PanelObject.menuEnable" parameter="psr_paste" />
+    </menu_item_call>
+    <menu_item_call
+     label="Paste size"
+     layout="topleft"
+     name="size_paste"
+     visible="true">
+       <on_click function="PanelObject.menuDoToSelected" parameter="size_paste" />
+       <on_enable function="PanelObject.menuEnable" parameter="size_paste" />
+    </menu_item_call>
+</toggleable_menu>
+
diff --git a/indra/newview/skins/default/xui/en/menu_copy_paste_texture.xml b/indra/newview/skins/default/xui/en/menu_copy_paste_texture.xml
new file mode 100644
index 0000000000000000000000000000000000000000..f358affc23d2e32d512e8646abaa3ade304e66eb
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/menu_copy_paste_texture.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<toggleable_menu
+ layout="topleft"
+ name="Copy Paste Texture Menu">
+    <menu_item_call
+     label="Copy"
+     layout="topleft"
+     name="params_copy"
+     visible="true">
+       <on_click function="PanelFace.menuDoToSelected" parameter="texture_copy" />
+    </menu_item_call>
+    <menu_item_call
+     label="Paste"
+     layout="topleft"
+     name="params_paste"
+     visible="true">
+       <on_click function="PanelFace.menuDoToSelected" parameter="texture_paste" />
+       <on_enable function="PanelFace.menuEnable" parameter="texture_paste" />
+    </menu_item_call>
+</toggleable_menu>
+
diff --git a/indra/newview/skins/default/xui/en/menu_gesture_gear.xml b/indra/newview/skins/default/xui/en/menu_gesture_gear.xml
index 5cae643e44f5dc9475c354705d7cc08a7c47d0f5..359c093eff9fd9584318b2518b8033f2af9de82d 100644
--- a/indra/newview/skins/default/xui/en/menu_gesture_gear.xml
+++ b/indra/newview/skins/default/xui/en/menu_gesture_gear.xml
@@ -9,7 +9,7 @@
      layout="topleft"
      name="activate">
         <on_click
-         function="Gesture.Action.ToogleActiveState" />
+         function="Gesture.Action.ToggleActiveState" />
     </menu_item_call>
     <menu_item_call
      label="Rename"
diff --git a/indra/newview/skins/default/xui/en/menu_im_conversation.xml b/indra/newview/skins/default/xui/en/menu_im_conversation.xml
index 43287c6ec36e8fe6313c0f5c493d29a976232748..b38fae440412df33b961e7c7a3cf76bfbfac6a17 100644
--- a/indra/newview/skins/default/xui/en/menu_im_conversation.xml
+++ b/indra/newview/skins/default/xui/en/menu_im_conversation.xml
@@ -79,6 +79,13 @@
     </menu_item_call>
     <menu_item_separator
      layout="topleft"/>
+    <menu_item_call
+     label="Report Abuse"
+     layout="topleft"
+     name="Report Abuse">
+       <on_click function="Avatar.GearDoToSelected" parameter="report_abuse" />
+       <on_enable function="Avatar.EnableGearItem" parameter="report_abuse" />
+    </menu_item_call>
     <menu_item_check
      label="Block Voice"
      layout="topleft"
diff --git a/indra/newview/skins/default/xui/en/menu_inventory.xml b/indra/newview/skins/default/xui/en/menu_inventory.xml
index 78ca1708132e602bb09997a8f471fe0ab3c1a47c..aa3d0ae071f466bf2a1fa598530ed787ed584517 100644
--- a/indra/newview/skins/default/xui/en/menu_inventory.xml
+++ b/indra/newview/skins/default/xui/en/menu_inventory.xml
@@ -912,6 +912,25 @@
                 function="Inventory.DoToSelected"
                 parameter="apply_settings_parcel" />
     </menu_item_call>
+  <menu_item_separator
+   layout="topleft"
+   name="Subfolder Separator" />
+  <menu_item_call
+   label="Create folder from selected"
+   layout="topleft"
+   name="New folder from selected">
+    <menu_item_call.on_click
+     function="Inventory.DoToSelected"
+     parameter="new_folder_from_selected" />
+  </menu_item_call>
+  <menu_item_call
+   label="Ungroup folder items"
+   layout="topleft"
+   name="Ungroup folder items">
+    <menu_item_call.on_click
+     function="Inventory.DoToSelected"
+     parameter="ungroup_folder_items" />
+  </menu_item_call>
 	<menu_item_separator
 	 layout="topleft"
 	 name="Marketplace Separator" />
diff --git a/indra/newview/skins/default/xui/en/menu_mini_map.xml b/indra/newview/skins/default/xui/en/menu_mini_map.xml
index ea263d05ceff687978d60373687b44d8721e9c21..2715c916d42023bac768fbdf59d826c9744a558f 100644
--- a/indra/newview/skins/default/xui/en/menu_mini_map.xml
+++ b/indra/newview/skins/default/xui/en/menu_mini_map.xml
@@ -8,62 +8,108 @@
  top="724"
  visible="false"
  width="128">
-	<menu_item_call
-     label="Zoom Close"
-     name="Zoom Close">
-        <menu_item_call.on_click
-         function="Minimap.Zoom"
+    <menu_item_check
+     label="Zoom very close"
+     name="Zoom very close">
+        <menu_item_check.on_check
+         function="Minimap.Zoom.Check"
+         parameter="very close" />
+        <menu_item_check.on_click
+         function="Minimap.Zoom.Set"
+         parameter="very close" />
+    </menu_item_check>
+    <menu_item_check
+     label="Zoom close"
+     name="Zoom close">
+        <menu_item_check.on_check
+         function="Minimap.Zoom.Check"
          parameter="close" />
-    </menu_item_call>
-    <menu_item_call
-     label="Zoom Medium"
-     name="Zoom Medium">
-        <menu_item_call.on_click
-         function="Minimap.Zoom"
+        <menu_item_check.on_click
+         function="Minimap.Zoom.Set"
+         parameter="close" />
+    </menu_item_check>
+    <menu_item_check
+     label="Zoom medium"
+     name="Zoom medium">
+        <menu_item_check.on_check
+         function="Minimap.Zoom.Check"
          parameter="medium" />
-    </menu_item_call>
-    <menu_item_call
-     label="Zoom Far"
-     name="Zoom Far">
-        <menu_item_call.on_click
-         function="Minimap.Zoom"
+        <menu_item_check.on_click
+         function="Minimap.Zoom.Set"
+         parameter="medium" />
+    </menu_item_check>
+    <menu_item_check
+     label="Zoom far"
+     name="Zoom far">
+        <menu_item_check.on_check
+         function="Minimap.Zoom.Check"
          parameter="far" />
-    </menu_item_call>
-	<menu_item_call
-     label="Zoom Default"
-     name="Zoom Default">
-		<menu_item_call.on_click
-         function="Minimap.Zoom"
-         parameter="default" />
-	</menu_item_call>
+        <menu_item_check.on_click
+         function="Minimap.Zoom.Set"
+         parameter="far" />
+    </menu_item_check>
 	<menu_item_separator />
     <menu_item_check
-       label="Rotate Map"
-       name="Rotate Map">
+       label="North at top"
+       name="North at top">
           <menu_item_check.on_check
-             control="MiniMapRotate" />
+             function="Minimap.MapOrientation.Check"
+             parameter="north_at_top" />
           <menu_item_check.on_click
-             function="ToggleControl"
-             parameter="MiniMapRotate" />
+             function="Minimap.MapOrientation.Set"
+             parameter="north_at_top" />
     </menu_item_check>
     <menu_item_check
-       label="Auto Center"
-       name="Auto Center">
+       label="Camera at top"
+       name="Camera at top">
           <menu_item_check.on_check
-             control="MiniMapAutoCenter" />
+             function="Minimap.MapOrientation.Check"
+             parameter="camera_at_top" />
           <menu_item_check.on_click
-             function="ToggleControl"
-             parameter="MiniMapAutoCenter" />
+             function="Minimap.MapOrientation.Set"
+             parameter="camera_at_top" />
+    </menu_item_check>
+	<menu_item_separator />
+    <menu_item_check
+     label="Show parcel boundaries"
+     name="Show parcel boundaries">
+        <menu_item_check.on_check
+         control="MiniMapShowPropertyLines" />
+        <menu_item_check.on_click
+         function="ToggleControl"
+         parameter="MiniMapShowPropertyLines" />
     </menu_item_check>
     <menu_item_separator />
+    <menu_item_check
+     label="Auto-center map"
+     name="Auto-center map">
+        <menu_item_check.on_check
+         control="MiniMapAutoCenter" />
+        <menu_item_check.on_click
+         function="ToggleControl"
+         parameter="MiniMapAutoCenter" />
+    </menu_item_check>
+    <menu_item_separator />
+    <menu_item_call
+     label="Re-center map"
+     name="Re-center map">
+        <menu_item_call.on_click
+         function="Minimap.Center.Activate" />
+    </menu_item_call>
     <menu_item_call
-     label="Stop Tracking"
-     name="Stop Tracking">
+     label="Stop tracking"
+     name="Stop tracking">
         <menu_item_call.on_click
          function="Minimap.Tracker"
          parameter="task_properties" />
     </menu_item_call>
     <menu_item_separator />
+    <menu_item_call
+     label="About Land"
+     name="About Land">
+        <menu_item_call.on_click
+         function="Minimap.AboutLand" />
+    </menu_item_call>
     <menu_item_call
      label="World Map"
      name="World Map">
diff --git a/indra/newview/skins/default/xui/en/menu_profile_other.xml b/indra/newview/skins/default/xui/en/menu_profile_other.xml
new file mode 100644
index 0000000000000000000000000000000000000000..4db4d0922bff01021eaa54012c72ebbafc3b0f1a
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/menu_profile_other.xml
@@ -0,0 +1,171 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<toggleable_menu
+ layout="topleft"
+ name="Avatar Profile Menu">
+  <menu_item_call
+   label="IM"
+   layout="topleft"
+   name="im">
+    <menu_item_call.on_click
+     function="Profile.Commit"
+     parameter="im"/>
+  </menu_item_call>
+  <menu_item_call
+  label="Offer Teleport"
+  name="offer_teleport">
+    <menu_item_call.on_click
+     function="Profile.Commit"
+    parameter="offer_teleport"/>
+    <menu_item_call.on_enable
+    function="Profile.EnableItem"
+    parameter="offer_teleport"/>
+  </menu_item_call>
+  <menu_item_call
+  label="Request Teleport"
+  name="request_teleport">
+    <menu_item_call.on_click
+     function="Profile.Commit"
+    parameter="request_teleport"/>
+    <menu_item_call.on_enable
+    function="Profile.EnableItem"
+    parameter="request_teleport"/>
+  </menu_item_call>
+  <menu_item_call
+   label="Voice call"
+   layout="topleft"
+   name="voice_call">
+    <menu_item_call.on_click
+     function="Profile.Commit"
+     parameter="voice_call"/>
+    <menu_item_call.on_enable
+     function="Profile.EnableItem"
+     parameter="voice_call"/>
+  </menu_item_call>
+  <menu_item_separator />
+  <menu_item_call
+   label="View chat history..."
+   layout="topleft"
+   name="chat_history">
+    <menu_item_call.on_click
+     function="Profile.Commit"
+     parameter="chat_history"/>
+    <menu_item_call.on_enable
+     function="Profile.EnableItem"
+     parameter="chat_history"/>
+  </menu_item_call>
+  <menu_item_separator name="separator_chat_history"/>
+  <menu_item_call
+   label="Add Friend"
+   layout="topleft"
+   name="add_friend">
+    <menu_item_call.on_click
+     function="Profile.Commit"
+     parameter="add_friend"/>
+    <menu_item_call.on_visible
+     function="Profile.EnableItem"
+     parameter="add_friend"/>
+  </menu_item_call>
+  <menu_item_call
+   label="Remove Friend"
+   layout="topleft"
+   name="remove_friend">
+    <menu_item_call.on_click
+     function="Profile.Commit"
+     parameter="remove_friend"/>
+    <menu_item_call.on_enable
+     function="Profile.EnableItem"
+     parameter="remove_friend"/>
+  </menu_item_call>
+  <menu_item_call
+   label="Invite to group..."
+   layout="topleft"
+   name="invite_to_group">
+    <menu_item_call.on_click
+     function="Profile.Commit"
+     parameter="invite_to_group"/>
+  </menu_item_call>
+  <menu_item_separator name="separator_invite_to_group"/>
+  <menu_item_call
+   label="Permissions"
+   layout="topleft"
+   name="agent_permissions">
+    <menu_item_call.on_click
+     function="Profile.Commit"
+     parameter="agent_permissions"/>
+    <menu_item_call.on_visible
+     function="Profile.EnableItem"
+     parameter="agent_permissions"/>
+  </menu_item_call>
+  <menu_item_call
+   label="Map"
+   layout="topleft"
+   name="map">
+    <menu_item_call.on_click
+     function="Profile.Commit"
+     parameter="can_show_on_map"/>
+    <menu_item_call.on_enable
+     function="Profile.EnableItem"
+     parameter="can_show_on_map"/>
+  </menu_item_call>
+  <menu_item_call
+   label="Share"
+   layout="topleft"
+   name="share">
+    <menu_item_call.on_click
+     function="Profile.Commit"
+     parameter="share"/>
+  </menu_item_call>
+  <menu_item_call
+   label="Pay"
+   layout="topleft"
+   name="pay">
+    <menu_item_call.on_click
+     function="Profile.Commit"
+     parameter="pay"/>
+  </menu_item_call>
+  <menu_item_check
+   label="Block/Unblock"
+   layout="topleft"
+   name="block_unblock">
+    <menu_item_check.on_click
+     function="Profile.Commit"
+     parameter="toggle_block_agent"/>
+    <menu_item_check.on_check
+     function="Profile.CheckItem"
+     parameter="toggle_block_agent"/>
+    <menu_item_check.on_enable
+     function="Profile.EnableItem"
+     parameter="toggle_block_agent"/>
+  </menu_item_check>
+  <menu_item_separator name="separator_copy_options"/>
+  <menu_item_call
+   label="Copy Display Name"
+   layout="topleft"
+   name="copy_display_name">
+    <menu_item_call.on_click
+     function="Profile.Commit"
+     parameter="copy_display_name"/>
+    <menu_item_call.on_enable
+     function="Profile.EnableItem"
+     parameter="copy_display_name"/>
+  </menu_item_call>
+  <menu_item_call
+   label="Copy Agent Name"
+   layout="topleft"
+   name="copy_name">
+    <menu_item_call.on_click
+     function="Profile.Commit"
+     parameter="copy_username"/>
+    <menu_item_call.on_enable
+     function="Profile.EnableItem"
+     parameter="copy_username"/>
+  </menu_item_call>
+  <menu_item_call
+   label="Copy Agent Id"
+   layout="topleft"
+   name="copy_id">
+    <menu_item_call.on_click
+     function="Profile.Commit"
+     parameter="copy_user_id"/>
+  </menu_item_call>
+</toggleable_menu>
diff --git a/indra/newview/skins/default/xui/en/menu_profile_self.xml b/indra/newview/skins/default/xui/en/menu_profile_self.xml
new file mode 100644
index 0000000000000000000000000000000000000000..d0bd4000f853d56eb0d5c266fab2d8155958416a
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/menu_profile_self.xml
@@ -0,0 +1,85 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<toggleable_menu
+ layout="topleft"
+ name="Avatar Profile Menu Self">
+  <menu_item_call
+   label="Edit Display Name"
+   layout="topleft"
+   name="edit_display_name">
+    <on_click
+     function="Profile.Commit"
+     parameter="edit_display_name"/>
+  </menu_item_call>
+  <menu_item_call
+   label="Edit Partner"
+   layout="topleft"
+   name="edit_partner">
+    <on_click
+     function="Profile.Commit"
+     parameter="edit_partner"/>
+  </menu_item_call>
+  <menu_item_call
+   label="Upload Photo"
+   layout="topleft"
+   name="upload_photo">
+    <menu_item_call.on_click
+     function="Profile.Commit"
+     parameter="upload_photo"/>
+    <menu_item_call.on_enable
+    function="Profile.EnableItem"
+     parameter="upload_photo"/>
+  </menu_item_call>
+  <menu_item_call
+   label="Change Photo"
+   layout="topleft"
+   name="change_photo">
+    <menu_item_call.on_click
+     function="Profile.Commit"
+     parameter="change_photo"/>
+    <menu_item_call.on_enable
+    function="Profile.EnableItem"
+     parameter="change_photo"/>
+  </menu_item_call>
+  <menu_item_call
+   label="Remove Photo"
+   layout="topleft"
+   name="remove_photo">
+    <menu_item_call.on_click
+     function="Profile.Commit"
+     parameter="remove_photo"/>
+    <menu_item_call.on_enable
+     function="Profile.EnableItem"
+     parameter="remove_photo"/>
+  </menu_item_call>
+  <menu_item_separator name="separator_copy_options"/>
+  <menu_item_call
+   label="Copy Display Name"
+   layout="topleft"
+   name="copy_display_name">
+    <menu_item_call.on_click
+     function="Profile.Commit"
+     parameter="copy_display_name"/>
+    <menu_item_call.on_enable
+     function="Profile.EnableItem"
+     parameter="copy_display_name"/>
+  </menu_item_call>
+  <menu_item_call
+   label="Copy Agent Name"
+   layout="topleft"
+   name="copy_name">
+    <menu_item_call.on_click
+     function="Profile.Commit"
+     parameter="copy_username"/>
+    <menu_item_call.on_enable
+     function="Profile.EnableItem"
+     parameter="copy_username"/>
+  </menu_item_call>
+  <menu_item_call
+   label="Copy Agent Id"
+   layout="topleft"
+   name="copy_id">
+    <menu_item_call.on_click
+     function="Profile.Commit"
+     parameter="copy_user_id"/>
+  </menu_item_call>
+</toggleable_menu>
diff --git a/indra/newview/skins/default/xui/en/menu_url_agent.xml b/indra/newview/skins/default/xui/en/menu_url_agent.xml
index e8b6116026a90669a877477e5486ef19503f0963..5ca8be212306c345e2bb55a712db966810e0eca3 100644
--- a/indra/newview/skins/default/xui/en/menu_url_agent.xml
+++ b/indra/newview/skins/default/xui/en/menu_url_agent.xml
@@ -29,7 +29,14 @@
      name="remove_friend">
         <menu_item_call.on_click
          function="Url.RemoveFriend" />
-        </menu_item_call>
+    </menu_item_call>
+    <menu_item_call
+     label="Report Abuse"
+     layout="topleft"
+     name="report_abuse">
+        <menu_item_call.on_click
+         function="Url.ReportAbuse" />
+    </menu_item_call>
     <menu_item_separator
      layout="topleft" />
     <menu_item_call
diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml
index 8d7cfe1116f75079f329abb816d677c6ee1861cb..58584345a980c9f76ac2a18a26931e76e788246c 100644
--- a/indra/newview/skins/default/xui/en/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/en/menu_viewer.xml
@@ -47,8 +47,7 @@
        label="Picks..."
        name="Picks">
         <menu_item_call.on_click
-         function="Floater.ToggleOrBringToFront"
-         parameter="picks" />
+         function="ShowAgentProfilePicks" />
       </menu_item_call>
       <menu_item_call
         label="Experiences..."
@@ -423,7 +422,9 @@
         </menu_item_call>       
         <menu_item_call
          label="Stop animations"
-         name="Stop Animating My Avatar">
+         name="Stop Animating My Avatar"
+         allow_key_repeat="true"
+         shortcut="alt|shift|A">
           <menu_item_call.on_click
            function="Tools.StopAllAnimations" />
         </menu_item_call>
@@ -471,7 +472,7 @@
        layout="topleft"
        name="Reset Skeleton And Animations">
         <menu_item_call.on_click
-         function="Avatar.ResetSkeletonAndAnimations" />
+         function="Avatar.ResetSelfSkeletonAndAnimations" />
       </menu_item_call>
       <menu_item_call
        label="Attachment scripts..."
@@ -2646,6 +2647,12 @@ function="World.EnvPreset"
                 <menu_item_call.on_click
                  function="Advanced.ForceErrorBadMemoryAccess" />
             </menu_item_call>
+            <menu_item_call
+             label="Force Bad Memory Access in Coroutine"
+             name="Force Bad Memory Access in Coroutine">
+                <menu_item_call.on_click
+                 function="Advanced.ForceErrorBadMemoryAccessCoro" />
+            </menu_item_call>
             <menu_item_call
              label="Force Infinite Loop"
              name="Force Infinite Loop">
@@ -3121,14 +3128,14 @@ function="World.EnvPreset"
           <menu_item_separator />
 
           <menu_item_check
-             label="Debug GL"
+             label="Start Debug GL on next run"
              name="Debug GL">
                 <menu_item_check.on_check
                  function="CheckControl"
-                 parameter="RenderDebugGL" />
+                 parameter="RenderDebugGLSession" />
                 <menu_item_check.on_click
                  function="ToggleControl"
-                 parameter="RenderDebugGL" />
+                 parameter="RenderDebugGLSession" />
             </menu_item_check>
             <menu_item_check
              label="Debug Pipeline"
@@ -3326,6 +3333,18 @@ function="World.EnvPreset"
                  function="Advanced.DropPacket" />
             </menu_item_call>
         </menu>
+        <menu
+         create_jump_keys="true"
+         label="Cache"
+         name="Cache"
+         tear_off="true">
+            <menu_item_call
+             label="Purge Disk Cache"
+             name="Purge Disk Cache">
+                <menu_item_call.on_click
+                 function="Advanced.PurgeDiskCache" />
+            </menu_item_call>
+        </menu>
         <menu_item_call
          label="Dump Scripted Camera"
          name="Dump Scripted Camera">
diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index 2007abefd74027bb7168d8920902fc76dfdd56d9..1ddec936688ae21a5c372703b56b6d38eddd5ae3 100644
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -1496,7 +1496,19 @@ Insufficient funds to create classified.
 
   <notification
    icon="alertmodal.tga"
-   name="DeleteAvatarPick"
+   name="ProfileDeleteClassified"
+   type="alertmodal">
+Delete classified &lt;nolink&gt;[CLASSIFIED]&lt;/nolink&gt;?
+    <tag>confirm</tag>
+    <usetemplate
+     name="okcancelbuttons"
+     notext="Cancel"
+     yestext="OK"/>
+  </notification>
+
+  <notification
+   icon="alertmodal.tga"
+   name="ProfileDeletePick"
    type="alertmodal">
 Delete pick &lt;nolink&gt;[PICK]&lt;/nolink&gt;?
     <tag>confirm</tag>
@@ -1506,6 +1518,32 @@ Delete pick &lt;nolink&gt;[PICK]&lt;/nolink&gt;?
      yestext="OK"/>
   </notification>
 
+  <notification
+   icon="alert.tga"
+   name="ProfileUnpublishedClassified"
+   type="alertmodal">
+    You have unpublished classifieds. They will be lost if you close the window.
+    <tag>confirm</tag>
+    <usetemplate
+     name="okcancelbuttons"
+     notext="Cancel"
+     yestext="OK"/>
+  </notification>
+
+  <notification
+   icon="alert.tga"
+   name="ProfileUnsavedChanges"
+   type="alertmodal">
+    You have usaved changes.
+    <tag>confirm</tag>
+    <tag>save</tag>
+    <usetemplate
+     canceltext="Cancel"
+     name="yesnocancelbuttons"
+     notext="Discard"
+     yestext="Save"/>
+  </notification>
+
   <notification
    icon="alertmodal.tga"
    name="DeleteOutfits"
@@ -2309,6 +2347,7 @@ Please try again later.
   <notification
    icon="notifytip.tga"
    name="LandmarkCreated"
+   log_to_chat="false"
    type="notifytip">
 You have added "[LANDMARK_NAME]" to your [FOLDER_NAME] folder.
   </notification>
@@ -3906,7 +3945,7 @@ Are you sure you want to return objects owned by [USER_NAME]?
 Couldn&apos;t set region textures:
 Terrain texture [TEXTURE_NUM] has an invalid bit depth of [TEXTURE_BIT_DEPTH].
 
-Replace texture [TEXTURE_NUM] with a 24-bit 512x512 or smaller image then click &quot;Apply&quot; again.
+Replace texture [TEXTURE_NUM] with a 24-bit [MAX_SIZE]x[MAX_SIZE] or smaller image then click &quot;Apply&quot; again.
   <tag>fail</tag>
   </notification>
 
@@ -3917,7 +3956,7 @@ Replace texture [TEXTURE_NUM] with a 24-bit 512x512 or smaller image then click
 Couldn&apos;t set region textures:
 Terrain texture [TEXTURE_NUM] is too large at [TEXTURE_SIZE_X]x[TEXTURE_SIZE_Y].
 
-Replace texture [TEXTURE_NUM] with a 24-bit 512x512 or smaller image then click &quot;Apply&quot; again.
+Replace texture [TEXTURE_NUM] with a 24-bit [MAX_SIZE]x[MAX_SIZE] or smaller image then click &quot;Apply&quot; again.
   </notification>
 
   <notification
@@ -8786,13 +8825,6 @@ See SecondLife.log for details
     type="alert">
     Error while requesting mesh upload permissons.
   </notification>
-
-  <notification
-    name="MeshUploadProfilerError"
-    icon="alert.tga"
-    type="alert">
-Mesh uploader is incompatible with RenderGLCoreProfile, please turn RenderGLCoreProfile off in debug settings and restart the viewer.
-  </notification>
   
   <notification
     name="RegionCapabilityRequestError"
@@ -9044,6 +9076,29 @@ We cannot display a preview of this texture because it is no-copy and/or no-tran
     yestext="OK"/>
   </notification>
 
+  <notification
+   icon="alertmodal.tga"
+   name="FacePasteFailed"
+   type="alertmodal">
+Paste failed. [REASON]
+   <usetemplate
+    name="okbutton"
+    yestext="OK"/>
+  </notification>
+
+  <notification
+   icon="alertmodal.tga"
+   name="FacePasteTexturePermissions"
+   type="alertmodal">
+    You applied a texture with limited permissions, object will inherit permissions from texture.
+    <usetemplate
+     ignoretext="Paste: You applied a texture with limited permissions"
+     name="notifyignore"/>
+    <usetemplate
+     name="okbutton"
+     yestext="OK"/>
+  </notification>
+
   <notification
    icon="alertmodal.tga"
    name="ConfirmLeaveCall"
@@ -9640,18 +9695,6 @@ Do you wish to continue?
      yestext="OK"/>
   </notification>
 
-  <global name="UnsupportedShaderRequirements">
-You do not appear to meet the hardware requirements for [APP_NAME]. [APP_NAME] requires OpenGL 2.0 or later shader support. If this is the case, you may want to make sure that you have the latest drivers for your graphics card, and service packs and patches for your operating system.
-
-If you continue to have problems, please visit the [SUPPORT_SITE].
-  </global>
-
-  <global name="UnsupportedGLRequirements">
-You do not appear to have the proper hardware requirements for [APP_NAME]. [APP_NAME] requires an OpenGL graphics card that has multitexture support. If this is the case, you may want to make sure that you have the latest drivers for your graphics card, and service packs and patches for your operating system.
-
-If you continue to have problems, please visit the [SUPPORT_SITE].
-  </global>
-
   <global name="UnsupportedIntelDriver">
 The installed Intel graphics driver for [GPUNAME], version [VERSION], is significantly out of date and is known to cause excessive rates of program crashes. You are strongly advised to update to a current Intel driver
 
@@ -11658,7 +11701,7 @@ This Region does not support environmental settings.
  
   <notification
    icon="alertmodal.tga"
-   label="Save Outfit"
+   label="Save Environmental Settings"
    name="SaveSettingAs"
    type="alertmodal">
     <unique/>
@@ -11816,4 +11859,59 @@ Unpacking: [UNPACK_TIME]s [USIZE]KB
     <tag>fail</tag>
   </notification>
   
+  <notification
+   icon="alertmodal.tga"
+   label="Prompt for MFA Token"
+   name="PromptMFAToken"
+   type="alertmodal">
+    [MESSAGE]
+    <tag>confirm</tag>
+    <form name="form">
+      <input name="token" type="text" width="400" />
+      <button
+       default="true"
+       index="0"
+       name="continue"
+       text="Continue"/>
+      <button
+       index="1"
+       name="cancel"
+       text="Cancel"/>
+    </form>
+  </notification>
+
+  <notification
+   icon="alertmodal.tga"
+   label="Create subfolder"
+   name="CreateSubfolder"
+   type="alertmodal">
+    <unique/>
+    Name the new folder:
+    <tag>confirm</tag>
+    <form name="form">
+      <input name="message" type="text">
+        [DESC]
+      </input>
+      <button
+       default="true"
+       index="0"
+       name="OK"
+       text="OK"/>
+      <button
+       index="1"
+       name="Cancel"
+       text="Cancel"/>
+    </form>
+  </notification>
+  <notification
+   icon="alertmodal.tga"
+   name="SameFolderRequired"
+   type="alert">
+    Selected items must be in the same folder.
+    <tag>fail</tag>
+    <usetemplate
+      name="okbutton"
+      yestext="OK"/>
+  </notification>
+
 </notifications>
diff --git a/indra/newview/skins/default/xui/en/panel_avatar_list_item.xml b/indra/newview/skins/default/xui/en/panel_avatar_list_item.xml
index aa1b929412a8aa9cf2978d9634c0e62065848bab..54f038c24ff817f827c13d1eeff4b3b5ae457a8c 100644
--- a/indra/newview/skins/default/xui/en/panel_avatar_list_item.xml
+++ b/indra/newview/skins/default/xui/en/panel_avatar_list_item.xml
@@ -155,6 +155,7 @@
      right="-3"
      mouse_opaque="true"
      name="speaking_indicator"
+     tool_tip="Voice volume"
      visible="true"
      width="20" />
 </panel>
diff --git a/indra/newview/skins/default/xui/en/panel_classified_info.xml b/indra/newview/skins/default/xui/en/panel_classified_info.xml
index d4a2745d1d694f262b2727950f433ddd70550400..04a0bc800d8882ff2870aea6d18f1b024d4317a7 100644
--- a/indra/newview/skins/default/xui/en/panel_classified_info.xml
+++ b/indra/newview/skins/default/xui/en/panel_classified_info.xml
@@ -38,28 +38,15 @@
   name="auto_renew_off">
     Disabled
  </panel.string>
-    <button
-     follows="top|left"
-     height="24"
-     image_hover_unselected="BackButton_Over"
-     image_pressed="BackButton_Press"
-     image_unselected="BackButton_Off"
-     layout="topleft"
-     name="back_btn"
-     left="10"
-     tab_stop="false"
-     top="2"
-     width="30"
-     use_draw_context_alpha="false" />
     <text
      follows="top|left|right"
      font="SansSerifHugeBold"
      height="26"
      layout="topleft"
-     left_pad="4"
+     left="12"
      name="title"
      text_color="LtGray"
-     top="0"
+     top="2"
      value="Classified Info"
      use_ellipses="true"
      width="275" />
@@ -420,7 +407,7 @@
 		         height="23"
 		         label="Teleport"
 		         layout="topleft"
-		         left="0"
+		         left="2"
 		         name="teleport_btn"
 		         top="0"
 		         width="101" />	
@@ -443,24 +430,6 @@
 		         top="0"
 		         width="100" />
 		  </layout_panel>	  
-		  
-		  <layout_panel
-			  follows="bottom|left|right"
-			  height="23"
-			  layout="bottomleft"
-			  left_pad="3"
-			  name="edit_btn_lp"
-		      auto_resize="true"
-			  width="101">
-			  <button
-		         follows="bottom|left|right"
-		         height="23"
-		         label="Edit"
-		         layout="topleft"
-		         name="edit_btn"
-		         top="0"
-		         width="101" />
-		  </layout_panel>
 	   </layout_stack>
     </panel>
 </panel>
diff --git a/indra/newview/skins/default/xui/en/panel_edit_classified.xml b/indra/newview/skins/default/xui/en/panel_edit_classified.xml
deleted file mode 100644
index e846edf1d4b9f7beaa958c135816d3dc75277f3a..0000000000000000000000000000000000000000
--- a/indra/newview/skins/default/xui/en/panel_edit_classified.xml
+++ /dev/null
@@ -1,354 +0,0 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
-<panel
- background_visible="true"
- bevel_style="in"
- follows="left|top|right|bottom"
- height="569"
- label="Edit Classified"
- layout="topleft"
- left="0"
- min_height="350"
- name="panel_edit_classified"
- help_topic="profile_edit_classified"
- top="0"
- width="333">
- <panel.string
-  name="location_notice">
-    (will update after save)
- </panel.string>
- <string name="publish_label">
-  Publish
- </string>
- <string name="save_label">
-  Save
- </string>
-  <button
-     follows="top|left"
-     height="24"
-     image_hover_unselected="BackButton_Over"
-     image_pressed="BackButton_Press"
-     image_unselected="BackButton_Off"
-     layout="topleft"
-     name="back_btn"
-     left="10"
-     tab_stop="false"
-     top="2"
-     width="30"
-     use_draw_context_alpha="false" />
-   <text
-     type="string"
-     length="1"
-     follows="top"
-     font="SansSerifHugeBold"
-     height="26"
-     layout="topleft"
-     left_pad="4"
-     name="title"
-     text_color="LtGray"
-     top="0"
-     width="250">
-        Edit Classified
-    </text>
-   <scroll_container
-    color="DkGray2"
-    follows="all"
-    height="502"
-    layout="topleft"
-    left="8"
-    top_pad="10"
-    name="profile_scroll"
-    reserve_scroll_corner="false"
-    opaque="true"
-    width="312">
-    <panel
-     name="scroll_content_panel"
-     follows="left|top"
-     min_height="300"
-     layout="topleft"
-     top="0"
-     background_visible="false"
-     height="690"
-     left="0"
-     width="285">
-      <panel
-         name="snapshot_panel"
-         layout="topleft"
-         follows="left|top|right"
-         height="197"
-         left="10"
-         top="10"
-         width="272">
-      <texture_picker
-       fallback_image="default_land_picture.j2c"
-       follows="left|top|right"
-       height="197"
-       width="272"
-       layout="topleft"
-       top="0"
-       left="0"
-       name="classified_snapshot" />
-       <icon
-           height="197"
-           image_name="spacer24.tga"
-           layout="topleft"
-           name="edit_icon"
-           label=""
-           tool_tip="Click to select an image"
-           top="0"
-           left="0"
-           width="272" />
-       </panel>
-        <text
-         type="string"
-         length="1"
-         follows="left|top"
-         height="15"
-         font="SansSerifSmall"
-         font.style="BOLD"
-         layout="topleft"
-         left="10"
-         top="215"
-         name="Name:"
-         text_color="white"
-         width="280">
-            Title:
-        </text>
-        <line_editor
-         follows="left|top|right"
-         font="SansSerif"
-         height="20"
-         layout="topleft"
-         left="10"
-         top_pad="2"
-         max_length_bytes="30"
-         name="classified_name"
-         prevalidate_callback="ascii"
-         text_color="black"
-         width="273" />
-        <text
-         type="string"
-         length="1"
-         follows="left|top"
-         height="15"
-         font="SansSerifSmall"
-         font.style="BOLD"
-         layout="topleft"
-         left="10"
-         top_pad="20"
-         name="description_label"
-         text_color="white"
-         width="280">
-            Description:
-        </text>
-        <text_editor
-         follows="left|top|right"
-         height="100"
-         width="273"
-         layout="topleft"
-         left="10"
-         top_pad="2"
-         max_length="256"
-         name="classified_desc"
-         text_color="black"
-         word_wrap="true" />
-        <text
-         type="string"
-         length="1"
-         font="SansSerifSmall"
-         font.style="BOLD"
-         follows="left|top"
-         height="15"
-         layout="topleft"
-         left="10"
-         name="location_label"
-         text_color="white"
-         top_pad="20"
-         width="280">
-            Location:
-        </text>
-        <text
-         type="string"
-         length="1"
-         follows="left|top"
-         height="30"
-         layout="topleft"
-         left="10"
-         name="classified_location"
-         right="-10"
-         top_pad="2"
-         width="280"
-         word_wrap="true">
-            loading...
-        </text>
-        <button
-         follows="left|top"
-         height="23"
-         label="Set to Current Location"
-         layout="topleft"
-         left="10"
-         top_pad="5"
-         name="set_to_curr_location_btn"
-         width="200" />
-        <text
-         follows="left|top"
-         font.style="BOLD"
-         height="10"
-         layout="topleft"
-         left="10"
-         name="category_label"
-         text_color="white"
-         top_pad="15"
-         value="Category:"
-         width="250" />
-        <combo_box
-         follows="left|top" 
-         height="23" 
-         label=""
-	     left="10" 
-         name="category" 
-         top_pad="5"
-         width="156" />
-        <text
-         follows="left|top"
-         font.style="BOLD"
-         height="10"
-         layout="topleft"
-         left="10"
-         name="content_type_label"
-         text_color="white"
-         top_pad="15"
-         value="Content type:"
-         width="250" />
-        <icons_combo_box
-         follows="left|top"
-         height="23"
-         label="General Content"
-         layout="topleft"
-         left="10"
-         name="content_type"
-         top_pad="5"
-         width="156">
-            <icons_combo_box.drop_down_button
-             image_overlay="Parcel_PG_Light"
-             image_overlay_alignment="left"
-             imgoverlay_label_space="3"
-             pad_left="3"/>
-            <icons_combo_box.item
-             label="Moderate Content"
-             name="mature_ci"
-             value="Mature">
-                <item.columns
-                 halign="center"
-                 type="icon"
-                 value="Parcel_M_Light"
-                 width="20"/>
-            </icons_combo_box.item>
-            <icons_combo_box.item
-             label="General Content"
-             name="pg_ci"
-             value="PG">
-                <item.columns
-                 halign="center"
-                 type="icon"
-                 value="Parcel_PG_Light"
-                 width="20"/>
-            </icons_combo_box.item>
-        </icons_combo_box>
-        <check_box
-         height="16"
-         label="Auto renew each week"
-         layout="topleft"
-         left="10"
-         name="auto_renew"
-         top_pad="15"
-         width="250" />
-        <text
-         follows="left|top"
-         height="10"
-         layout="topleft"
-         left="10"
-         name="price_for_listing_label"
-         text_color="white"
-         top_pad="15"
-         value="Price for listing:"
-         width="250" />
-        <spinner
-         decimal_digits="0"
-         follows="left|top"
-         halign="left"
-         height="23"
-         increment="1"
-         label_width="20"
-         label="L$"
-         v_pad="10"
-         layout="topleft"
-         left="10"
-         value="50"
-         min_val="50"
-         max_val="99999"
-         name="price_for_listing"
-         top_pad="5"
-         tool_tip="Price for listing."
-         width="105" />
-     </panel>
-    </scroll_container>
-    <panel
-     follows="left|right|bottom"
-     height="23"
-     label="bottom_panel"
-     layout="topleft"
-     left="8"
-     name="bottom_panel"
-     top_pad="5"
-     width="303">
-     
-         <layout_stack
-		  follows="bottom|left|right"
-		  height="23"
-		  layout="topleft"
-		  name="bottom_panel_ls"
-		  left="1"
-		  orientation="horizontal"
-		  top_pad="0"
-		  width="309">
-		  
-		  <layout_panel
-			  follows="bottom|left|right"
-			  height="23"
-			  layout="bottomleft"
-			  left="0"
-			  name="save_changes_btn_lp"
-		      auto_resize="true"
-			  width="156">
-			  <button
-		         follows="bottom|left|right"
-		         height="23"
-		         label="[LABEL]"
-		         layout="topleft"
-		         name="save_changes_btn"
-		         left="1"
-		         top="0"
-		         width="155" />	
-		  </layout_panel>
-		  
-		  <layout_panel
-			  follows="bottom|left|right"
-			  height="23"
-			  layout="bottomleft"
-			  left_pad="3"
-			  name="show_on_map_btn_lp"
-		      auto_resize="true"
-			  width="157">
-			  <button
-		         follows="bottom|left|right"
-		         height="23"
-		         label="Cancel"
-		         layout="topleft"
-		         name="cancel_btn"
-		         left="1"
-		         top="0"
-		         width="156" />
-		  </layout_panel>
-	   </layout_stack>
-    </panel>
-</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_edit_pick.xml b/indra/newview/skins/default/xui/en/panel_edit_pick.xml
deleted file mode 100644
index 357a5559bf8545b347fc08ea1597ea64afff9e99..0000000000000000000000000000000000000000
--- a/indra/newview/skins/default/xui/en/panel_edit_pick.xml
+++ /dev/null
@@ -1,239 +0,0 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
-<panel
- background_visible="true"
- bevel_style="in"
- follows="left|top|right|bottom"
- height="569"
- label="Edit Pick"
- layout="topleft"
- left="0"
- min_height="350"
- name="panel_edit_pick"
- help_topic="profile_edit_pick"
- top="0"
- width="333">
- <panel.string
-  name="location_notice">
-    (will update after save)
- </panel.string>
-  <button
-     follows="top|left"
-     height="24"
-     image_hover_unselected="BackButton_Over"
-     image_pressed="BackButton_Press"
-     image_unselected="BackButton_Off"
-     layout="topleft"
-     name="back_btn"
-     left="10"
-     tab_stop="false"
-     top="4"
-     width="30"
-     use_draw_context_alpha="false" />
-   <text
-     type="string"
-     length="1"
-     follows="top"
-     font="SansSerifHugeBold"
-     height="26"
-     layout="topleft"
-     left_pad="4"
-     name="title"
-     text_color="LtGray"
-     top="4"
-     width="250">
-        Edit Pick
-    </text>
-   <scroll_container
-     color="DkGray2"
-     follows="all"
-     height="501"
-     layout="topleft"
-     left="8"
-     top_pad="9"
-     name="profile_scroll"
-     opaque="true"
-     width="312">
-    <panel
-     name="scroll_content_panel"
-     follows="left|top|right"
-     min_height="300"
-     layout="topleft"
-     top="0"
-     background_visible="false"
-     height="500"
-     left="0"
-     width="285">
-    <texture_picker
-     fallback_image="default_land_picture.j2c"
-     follows="left|top|right"
-     height="197"
-     width="272"
-     layout="topleft"
-     no_commit_on_selection="true"
-     top="10"
-     left="11"
-     name="pick_snapshot" />
-          <icon
-           height="197"
-           image_name="spacer24.tga"
-           layout="topleft"
-           name="edit_icon"
-           label=""
-           tool_tip="Click to select an image"
-           top="10"
-           left="11"
-           width="286" />
-        <text
-         type="string"
-         length="1"
-         follows="left|top|right"
-         height="15"
-         font="SansSerifSmall"
-         font.style="BOLD"
-         layout="topleft"
-         left="10"
-         top="215"
-         name="Name:"
-         text_color="white"
-         width="280">
-            Title:
-        </text>
-        <line_editor
-         follows="left|top|right"
-         font="SansSerif"
-         height="20"
-         layout="topleft"
-         left="10"
-         top_pad="2"
-         max_length_bytes="63"
-         name="pick_name"
-         text_color="black"
-         width="273" />
-        <text
-         type="string"
-         length="1"
-         follows="left|top|right"
-         height="15"
-         font="SansSerifSmall"
-         font.style="BOLD"
-         layout="topleft"
-         left="10"
-         top_pad="20"
-         name="description_label"
-         text_color="white"
-         width="280">
-            Description:
-        </text>
-        <text_editor
-         follows="left|top|right"
-         height="100"
-         width="273"
-         hide_scrollbar="false"
-         layout="topleft"
-         left="10"
-         top_pad="2"
-         max_length="1023"
-         name="pick_desc"
-         spellcheck="true"
-         text_color="black"
-         word_wrap="true" />
-        <text
-         type="string"
-         length="1"
-         font="SansSerifSmall"
-         font.style="BOLD"
-         follows="left|top|right"
-         height="15"
-         layout="topleft"
-         left="10"
-         name="location_label"
-         text_color="white"
-         top_pad="20"
-         width="280">
-            Location:
-        </text>
-        <text
-         type="string"
-         length="1"
-         follows="left|top|right"
-         height="50"
-         layout="topleft"
-         left="10"
-         name="pick_location"
-         top_pad="2"
-         width="280"
-         word_wrap="true">
-            loading...
-        </text>
-        <button
-         follows="left|top"
-         height="23"
-         label="Set to Current Location"
-         layout="topleft"
-         left="8"
-         top_pad="0"
-         name="set_to_curr_location_btn"
-         width="200" />
-    </panel>
-    </scroll_container>
-    <panel
-     follows="left|right|bottom"
-     height="23"
-     label="bottom_panel"
-     layout="topleft"
-     left="8"
-     name="bottom_panel"
-     top_pad="5"
-     width="315">
-     
-     	 <layout_stack
-		  follows="bottom|left|right"
-		  height="23"
-		  layout="topleft"
-		  name="layout_stack1"
-		  left="0"
-		  orientation="horizontal"
-		  top_pad="0"
-		  width="313">
-		  	 
-		  	 <layout_panel
-			  follows="bottom|left|right"
-			  height="23"
-			  layout="topleft"
-			  left="0"
-			  name="layout_panel1"
-		      auto_resize="true"
-			  width="150">
-		        <button
-		         follows="bottom|left|right"
-		         height="23"
-		         label="Save Pick"
-		         layout="topleft"
-		         name="save_changes_btn"
-		         top="0"
-		         left="1"
-		         width="149" />
-			  </layout_panel>
-			  
-			 <layout_panel
-			  follows="bottom|left|right"
-			  height="23"
-			  layout="topleft"
-			  left_pad="4"
-			  name="layout_panel2"
-		      auto_resize="true"
-			  width="146">
-		        <button
-		         follows="bottom|left|right"
-		         height="23"
-		         label="Cancel"
-		         layout="topleft"
-		         name="cancel_btn"
-		         top="0"
-		         left="1"
-		        width="145" />
-			  </layout_panel>
-	</layout_stack>
-		  
-    </panel>
-</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_edit_profile.xml b/indra/newview/skins/default/xui/en/panel_edit_profile.xml
deleted file mode 100644
index 2c7c8133d139125ab611f159c346a84adc25988f..0000000000000000000000000000000000000000
--- a/indra/newview/skins/default/xui/en/panel_edit_profile.xml
+++ /dev/null
@@ -1,472 +0,0 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
-<panel
- background_visible="true"
- class="edit_profile_panel"
-  follows="all"
- height="585"
- label="Profile Edit"
- layout="topleft"
- left="0"
- name="edit_profile_panel"
-  top="0"
- width="313">
-   <string
-    name="CaptionTextAcctInfo">
-       [ACCTTYPE]
-[PAYMENTINFO] [AGEVERIFICATION]
-   </string>
-   <string 
-    name="RegisterDateFormat">
-	[REG_DATE] ([AGE])
-   </string> 
-   <string
-    name="AcctTypeResident"
-    value="Resident" />
-   <string
-    name="AcctTypeTrial"
-    value="Trial" />
-   <string
-    name="AcctTypeCharterMember"
-    value="Charter Member" />
-   <string
-    name="AcctTypeEmployee"
-    value="Linden Lab Employee" />
-   <string
-    name="PaymentInfoUsed"
-    value="Payment Info Used" />
-   <string
-    name="PaymentInfoOnFile"
-    value="Payment Info On File" />
-   <string
-    name="NoPaymentInfoOnFile"
-    value="No Payment Info On File" />
-   <string
-    name="AgeVerified"
-    value="Age-verified" />
-   <string
-    name="NotAgeVerified"
-    value="Not Age-verified" />
-   <string
-    name="partner_edit_link_url">
-       http://www.secondlife.com/account/partners.php?lang=en
-   </string>
-   <string
-    name="my_account_link_url">
-       http://secondlife.com/my
-   </string>
-   <string
-    name="no_partner_text"
-    value="None" />
- <scroll_container
-     color="DkGray2"
-     follows="all"
-     height="537"
-     min_height="300"
-     layout="topleft"
-     left="8"
-     width="292"
-     name="profile_scroll"
-     reserve_scroll_corner="true"
-     opaque="true"
-     top="10">
-      <panel
-         name="scroll_content_panel"
-         follows="left|top|right"
-         layout="topleft"
-         top="0"
-     height="537"
-     min_height="300"
-         left="0"
-         width="292">
-    <panel
-     name="data_panel"
-     follows="left|top|right"
-         layout="topleft"
-         top="0"
-     height="537"
-     min_height="300"
-         left="0"
-         width="292">
-      <text
-     top="5"
-     follows="top|left"
-     height="13"
-     layout="topleft"
-     left="10"
-     name="display_name_label"
-     text_color="LtGray"
-     value="Display Name:"
-     width="80" />
-      <text
-     top="5"
-     follows="top|left"
-     height="13"
-     layout="topleft"
-     left="10"
-     name="solo_username_label"
-     text_color="LtGray"
-     value="Username:"
-     visible="false" 
-     width="80" />
-      <button
-         name="set_name"
-         layout="topleft"
-         follows="top|left"
-         image_overlay="Edit_Wrench"
-         top="21"
-         left="10"
-         height="23"
-         width="23"
-         tool_tip="Set Display Name"/>
-      <text
-       follows="top|left"
-       font="SansSerifBigBold"
-       height="20"
-       layout="topleft"
-       left="10"
-       name="solo_user_name"
-       text_color="white"
-       top_delta="3"
-       translate="false"
-       value="TestString PleaseIgnore"
-       use_ellipses="true"
-       visible="false"
-       width="275" />
-      <text
-       follows="top|left"
-       font="SansSerifBigBold"
-       height="20"
-       layout="topleft"
-       left="43"
-       name="user_name"
-       text_color="white"
-       top_delta="0"
-       translate="false"
-       value="TestString PleaseIgnore"
-       use_ellipses="true"
-       visible="true"
-       width="250" />
-      <text
-       follows="top|left"
-       font="SansSerifBold"
-       height="20"
-       layout="topleft"
-       left_delta="0"
-       name="user_name_small"
-       text_color="white"
-       top_delta="-4"
-       translate="false"
-       value="TestString PleaseIgnore"
-       use_ellipses="true"
-       visible="false"
-       wrap="true"
-       width="245" />
-      <text
-    follows="top|left"
-    height="13"
-    layout="topleft"
-    left="10"
-    name="user_label"
-    text_color="LtGray"
-    top_pad="8"
-    value="Username:"
-    width="70" />
-      <text
-       follows="top|left"
-       height="20"
-       layout="topleft"
-       left_pad="0"
-       name="user_slid"
-       text_color="EmphasisColor"
-        font="SansSerifBold"
-       top_delta="-2"
-       translate="false"
-       use_ellipses="true" 
-       value="teststring.pleaseignore"
-       wrap="true" 
-       width="205" />
-     <panel
-       name="lifes_images_panel"
-         follows="left|top|right"
-         height="244"
-         layout="topleft"
-         top="65"
-         left="0"
-         width="292">
-	 <panel
-         follows="left|top"
-         height="117"
-         layout="topleft"
-         left="10"
-         name="second_life_image_panel"
-         top="0"
-         width="282">
-          <text
-             follows="left|top|right"
-	     font.style="BOLD"
-             height="15"
-             layout="topleft"
-             left="0"
-             top="10"
-            name="second_life_photo_title_text"
-             text_color="white"
-             value="[SECOND_LIFE]:"
-             width="100" />
-            <texture_picker
-             allow_no_texture="true"
-             default_image_name="None"
-             enabled="false"
-             fallback_image="default_profile_picture.j2c" 
-             follows="top|left"
-             height="124"
-             layout="topleft"
-             left="1"
-             name="2nd_life_pic"
-             top_pad="0"
-             width="102" />
-          </panel>
-           <icon
-           height="102"
-           image_name="spacer24.tga"
-           layout="topleft"
-           name="2nd_life_edit_icon"
-           label=""
-           left="11"
-           top_pad="-92"
-           tool_tip="Click to select an image"
-           width="102" />
-      </panel>
-      <text_editor
-       type="string"
-       length="1"
-       follows="left|top|right"
-       font="SansSerifSmall"
-       height="102"
-       layout="topleft"
-       left="123"
-       top="90"
-       max_length="512"
-       name="sl_description_edit"
-       width="157"
-       word_wrap="true">
-      </text_editor>
-      <panel
-         follows="left|top"
-         height="117"
-         layout="topleft"
-	 top_pad="5"
-         left="10"
-         name="first_life_image_panel"
-         width="285">
-        <text
-             follows="left|top|right"
-	     font.style="BOLD"
-             height="15"
-             layout="topleft"
-             left="0"
-             top_pad="10"
-            name="real_world_photo_title_text"
-             text_color="white"
-             value="Real World:"
-             width="100" />
-            <texture_picker
-             allow_no_texture="true"
-             default_image_name="None"
-             enabled="false"
-             fallback_image="Generic_Person_Large"
-             follows="top|left"
-             height="124"
-             layout="topleft"
-             left="1"
-             name="real_world_pic"
-             top_pad="0"
-             width="102" />
-          </panel>
-           <icon
-           height="102"
-           image_name="spacer24.tga"
-           layout="topleft"
-           name="real_world_edit_icon"
-           label=""
-           left="11"
-           top_pad="-92"
-           tool_tip="Click to select an image"
-           width="102" />
-       <text_editor
-       type="string"
-       length="1"
-       follows="left|top|right"
-       font="SansSerifSmall"
-       height="102"
-       layout="topleft"
-       left="123"
-       max_length="512"
-       top="223"
-       name="fl_description_edit"
-       width="157"
-       word_wrap="true">
-      </text_editor>
-      <text
-       type="string"
-       length="1"
-       follows="left|top"
-       font="SansSerifSmall"
-       font.style="BOLD"
-       height="15"
-       layout="topleft"
-       left="10"
-       name="title_homepage_text"
-       text_color="white"
-       top_pad="10"
-       width="100">
-          Homepage:
-      </text>
-      <line_editor
-       follows="left|top|right"
-       font="SansSerifSmall"
-       height="20"
-       layout="topleft"
-       left="10"
-       top_pad="0"
-       value="http://"
-       name="homepage_edit"
-       width="272">
-      </line_editor>
-      <text
-         follows="left|top"
-         font="SansSerifSmall"
-	 font.style="BOLD"
-         height="15"
-         layout="topleft"
-         left="10"
-         name="title_acc_status_text"
-         text_color="white"
-         top_pad="10"
-         value="My Account:"
-         width="100" />
-        <text_editor
-         allow_scroll="false"
-         bg_visible="false"
-         follows="left|top|right"
-         h_pad="0"
-         height="28"
-         layout="topleft"
-         left="10"
-         name="acc_status_text"
-         read_only="true"
-         top_pad="5"
-         v_pad="0"
-         value="Resident. No payment info on file."
-         width="200"
-         word_wrap="true" />
-        <text
-         type="string"
-         follows="left|top"
-         font="SansSerifSmall"
-         height="15"
-         layout="topleft"
-         left="10"
-         name="my_account_link"
-         value="[[URL] Go to My Dashboard]"
-         width="200" />
-        <text
-         follows="left|top"
-         font="SansSerifSmall"
-      	 font.style="BOLD"
-         height="15"
-         layout="topleft"
-         left="10"
-         name="title_partner_text"
-         text_color="white"
-         top_pad="10"
-         value="My Partner:"
-         width="150" />
-        <panel
-         follows="left|top|right"
-         height="15"
-         layout="topleft"
-         left="10"
-         name="partner_data_panel"
-         width="200">
-          <text
-           follows="left|top|right"
-           height="12"
-           initial_value="(retrieving)"
-           layout="topleft"
-           left="0"
-           name="partner_text"
-           top="0"
-           use_ellipses="true"
-           width="280"/>
-         </panel>
-        <text
-         follows="left|top"
-         height="15"
-         layout="topleft"
-           link="true"
-         left="10"
-         name="partner_edit_link"
-         value="[[URL] Edit]"
-         width="70" />
-    </panel>
-    </panel>
-    </scroll_container>
-    <panel
-       follows="bottom|left|right"
-       height="28"
-       left="0"
-       name="profile_me_buttons_panel"
-       top_pad="0"
-       width="313">
-       
-         <layout_stack
-		  follows="bottom|left|right"
-		  height="28"
-		  layout="topleft"
-		  name="bottom_panel_ls"
-		  left="7"
-		  orientation="horizontal"
-		  top_pad="0"
-		  width="295">
-		  
-		  <layout_panel
-			  follows="bottom|left|right"
-			  height="23"
-			  layout="bottomleft"
-			  name="save_changes_btn_lp"
-			  top="0"
-		      auto_resize="true"
-			  width="153">
-        <button
-		         follows="bottom|left|right"
-         height="23"
-         label="Save Changes"
-         layout="topleft"
-		         left="1"
-         name="save_btn"
-		         top="0"
-         width="152" />
-		  </layout_panel>
-		  
-		  <layout_panel
-			  follows="bottom|left|right"
-			  height="23"
-			  layout="bottomleft"
-			  left_pad="3"
-			  name="show_on_map_btn_lp"
-			  top="0"
-		      auto_resize="true"
-			  width="154">
-        <button
-		         follows="bottom|left|right"
-         height="23"
-         label="Cancel"
-         layout="topleft"
-		         left="1"
-         name="cancel_btn"
-		         top="0"
-         width="153" />
-		  </layout_panel>
-	   </layout_stack>
-    </panel>
-</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_group_general.xml b/indra/newview/skins/default/xui/en/panel_group_general.xml
index e34335a2afcd2e7e696d3cee8805cfe3adfe4d0b..5eafb5cdf1542b20c0660a77bde220b1a6309def 100644
--- a/indra/newview/skins/default/xui/en/panel_group_general.xml
+++ b/indra/newview/skins/default/xui/en/panel_group_general.xml
@@ -95,6 +95,7 @@ Hover your mouse over the options for more help.
      layout="topleft"
      max_length="511"
      name="charter"
+     parse_urls="true"
      top="105"
      right="-4"
     bg_readonly_color="DkGray2"
diff --git a/indra/newview/skins/default/xui/en/panel_group_list_item_short.xml b/indra/newview/skins/default/xui/en/panel_group_list_item_short.xml
new file mode 100644
index 0000000000000000000000000000000000000000..b72af7221e4890c9f9767e68b07431c01e58dc5d
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/panel_group_list_item_short.xml
@@ -0,0 +1,110 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<panel
+ name="group_list_item"
+ top="0"
+ left="0"
+ height="16"
+ width="320"
+ follows="top|right|left"
+ layout="topleft"
+>
+    <icon
+     name="hovered_icon"
+     top="0"
+     left="0"
+     height="16"
+     width="320"
+     follows="top|right|left"
+     layout="topleft"
+     image_name="ListItem_Over"
+     visible="false"
+    />
+    <icon
+     name="selected_icon"
+     top="0"
+     left="0"
+     height="16"
+     width="320"
+     follows="top|right|left"
+     layout="topleft"
+     image_name="ListItem_Select"
+     visible="false"
+    />
+    <group_icon
+     name="group_icon"
+     top="2"
+     left="5"
+     height="14"
+     width="14"
+     image_name="Generic_Group"
+     mouse_opaque="true"
+     use_draw_context_alpha="false"
+    />
+    <text
+     name="group_name"
+     value="Unknown"
+     top="2"
+     left_pad="5"
+     right="-2"
+     height="16"
+     follows="left|right"
+     layout="topleft"
+     parse_urls="false"
+     text_color="ScrollUnselectedColor"
+     use_ellipses="true"
+    />
+    <button
+     name="visibility_hide_btn"
+     tool_tip="Hide group on my profile"
+     top_delta="-3"
+     left_pad="3"
+     right="-53"
+     height="20"
+     width="20"
+     follows="right"
+     image_pressed="Profile_Group_Visibility_Off_Pressed"
+     image_unselected="Profile_Group_Visibility_Off"
+     tab_stop="false"
+     visible="false"
+    />
+    <button
+     name="visibility_show_btn"
+     tool_tip="Show group on my profile"
+     top_delta="0"
+     right_delta="0"
+     height="20"
+     width="20"
+     follows="right"
+     image_pressed="Profile_Group_Visibility_On_Pressed"
+     image_unselected="Profile_Group_Visibility_On"
+     tab_stop="false"
+     visible="false"
+    />
+    <button
+     name="info_btn"
+     tool_tip="More info"
+     top_delta="2"
+     left_pad="3"
+     right="-30"
+     height="16"
+     width="16"
+     follows="right"
+     image_pressed="Info_Press"
+     image_unselected="Info_Over"
+     tab_stop="false"
+    />
+    <!--*TODO: Should only appear on rollover-->
+    <button
+     name="profile_btn"
+     tool_tip="View profile"
+     top_delta="-2"
+     left_pad="5"
+     right="-3"
+     height="20"
+     width="20"
+     follows="right"
+     layout="topleft"
+     image_overlay="Web_Profile_Off"
+     tab_stop="false"
+    />
+</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_hide_beacon.xml b/indra/newview/skins/default/xui/en/panel_hide_beacon.xml
new file mode 100644
index 0000000000000000000000000000000000000000..7cab285f77dc37e1cba722b0ad44a6652fe3b6bc
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/panel_hide_beacon.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<panel
+ height="25"
+ layout="topleft"
+ name="panel_hide_beacon"
+ mouse_opaque="false"
+ visible="true"
+ width="133">
+    <button
+     follows="left|bottom"
+     height="19"
+     label="Hide beacon"
+     layout="topleft"
+     left="10"
+     name="hide_beacon_btn"
+     tool_tip="Stop tracking and hide beacon"
+     top="2"
+     visible="false"
+     width="113" />
+</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_login.xml b/indra/newview/skins/default/xui/en/panel_login.xml
index ade004f9d0f9a1c5cf390cb6bf0960199101411c..3aba80909aa7a46da981a986f4b552b1b94e297c 100644
--- a/indra/newview/skins/default/xui/en/panel_login.xml
+++ b/indra/newview/skins/default/xui/en/panel_login.xml
@@ -145,7 +145,7 @@
     follows="left|top"
     font="SansSerifMedium"
     text_color="EmphasisColor"
-    height="16"
+    height="24"
     left="408"
     bottom_delta="0"
     label="Remember password"
diff --git a/indra/newview/skins/default/xui/en/panel_login_first.xml b/indra/newview/skins/default/xui/en/panel_login_first.xml
index 5568ccb7928635b35c67ff12868c4fcabebf83f6..d36c83d292e342c4da499cc773bce9557e49588c 100644
--- a/indra/newview/skins/default/xui/en/panel_login_first.xml
+++ b/indra/newview/skins/default/xui/en/panel_login_first.xml
@@ -98,7 +98,7 @@
           auto_resize="false"
           follows="left|right|top"
           name="widget_container"
-          width="532"
+          width="730"
           left="0"
           top="0"
           height="80">
@@ -106,7 +106,7 @@
             allow_text_entry="true"
             follows="left|bottom"
             height="32"
-            left="2"
+            left="42"
             label="Username"
             combo_editor.font="SansSerifLarge"
             max_chars="128"
@@ -126,7 +126,7 @@
             follows="left|top"
             width="200"
             height="32"
-            left="220"
+            left="262"
             max_length_chars="16"
             name="password_edit"
             label="Password"
@@ -145,42 +145,58 @@
             label_color="White"
             font="SansSerifLarge"
             name="connect_btn"
-            left="432"
-            width="100"
+  	        left_pad="15"
+            width="120"
             height="32"
             top="0" />
+          <text
+            follows="left|top"
+            font="SansSerifLarge"
+            font.style="BOLD"
+            text_color="EmphasisColor"
+            height="34"
+            name="sign_up_text"
+            left_pad="10"
+            top="0"
+            width="200"
+            valign="center">
+            Sign up
+          </text>
           <check_box
-            control_name="RememberPassword"
             follows="left|top"
             font="SansSerifLarge"
-            left="0"
+            left="42"
             top="32"
             height="24"
             label="Remember me"
+            word_wrap="down"
             check_button.bottom="3"
-            name="remember_check"
-            width="145" />
-          <text
+            name="remember_name"
+            tool_tip="Already remembered user can be forgotten from Me &gt; Preferences &gt; Advanced &gt; Remembered Usernames."
+            width="198" />
+          <check_box
+            control_name="RememberPassword"
             follows="left|top"
             font="SansSerifLarge"
             text_color="EmphasisColor"
-            height="16"
-            name="forgot_password_text"
-            left="219"
-            top="34"
-            width="200">
-            Forgotten password
-          </text>
+            height="24"
+            left="262"
+            bottom_delta="0"
+            label="Remember password"
+            word_wrap="down"
+            check_button.bottom="3"
+            name="remember_password"
+            width="198" />
           <text
             follows="left|top"
             font="SansSerifLarge"
             text_color="EmphasisColor"
             height="16"
-            name="sign_up_text"
-            left="432"
+            name="forgot_password_text"
+            left="492"
             top="34"
             width="200">
-            Sign up
+            Forgotten password
           </text>
         </layout_panel>
         <layout_panel
@@ -216,24 +232,17 @@
           auto_resize="false"
           follows="left|right|top"
           name="images_container"
-          width="832"
+          width="675"
           left="0"
           top="0"
           height="500">
           <icon
-            height="400"
-            width="400"
-            image_name="first_login_image_left"
+            height="450"
+            width="675"
+            image_name="first_login_image"
             left="0"
             name="image_left"
             top="0" />
-          <icon
-            height="400"
-            width="400"
-            image_name="first_login_image_right"
-            left_pad="32"
-            name="image_right"
-            top="0" />
         </layout_panel>
         <layout_panel
           height="100"
diff --git a/indra/newview/skins/default/xui/en/panel_me.xml b/indra/newview/skins/default/xui/en/panel_me.xml
deleted file mode 100644
index 23e7814cada591fa479954084bb2a4051c107880..0000000000000000000000000000000000000000
--- a/indra/newview/skins/default/xui/en/panel_me.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
-<panel
- background_visible="true"
- border="false"
- follows="all"
- height="570"
- label="My Profile"
- layout="topleft"
- left="0"
- name="panel_me"
- top="0"
- width="333">
-    <panel
-        class="panel_picks"
-        filename="panel_picks.xml"
-        label="MY PICKS"
-        help_topic="panel_my_picks_tab"
-        name="panel_picks"/>
-</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_navigation_bar.xml b/indra/newview/skins/default/xui/en/panel_navigation_bar.xml
index 1c9aa1eb8326cec41aa177c7781613087490cbd1..b44c19810b76c5252a150b73fe466f84c6a071bf 100644
--- a/indra/newview/skins/default/xui/en/panel_navigation_bar.xml
+++ b/indra/newview/skins/default/xui/en/panel_navigation_bar.xml
@@ -4,7 +4,6 @@
  background_visible="true"
  bg_opaque_color="MouseGray"
  follows="left|top|right"
- focus_root="true" 
  height="34"
  layout="topleft"
  name="navigation_bar"
diff --git a/indra/newview/skins/default/xui/en/panel_pick_info.xml b/indra/newview/skins/default/xui/en/panel_pick_info.xml
deleted file mode 100644
index 99c47eb8257efaf0d6f189b4d17a15c0ff01aa11..0000000000000000000000000000000000000000
--- a/indra/newview/skins/default/xui/en/panel_pick_info.xml
+++ /dev/null
@@ -1,190 +0,0 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
-<panel
- background_visible="true"
- follows="all"
- height="570"
- layout="topleft"
- left="0"
- min_height="350"
- name="panel_pick_info"
- help_topic="profile_pick_info"
- top="0"
- width="333">
-    <button
-     follows="top|left"
-     height="24"
-     image_hover_unselected="BackButton_Over"
-     image_pressed="BackButton_Press"
-     image_unselected="BackButton_Off"
-     layout="topleft"
-     name="back_btn"
-     left="10"
-     tab_stop="false"
-     top="2"
-     width="30"
-     use_draw_context_alpha="false" />
-    <text
-     follows="top|left|right"
-     font="SansSerifHugeBold"
-     height="26"
-     layout="topleft"
-     left_pad="4"
-     name="title"
-     text_color="LtGray"
-     top="2"
-     value="Pick Info"
-     use_ellipses="true"
-     width="275" />
-    <scroll_container
-     color="DkGray2"
-     opaque="true"
-     follows="all"
-     height="503"
-     layout="topleft"
-     left="8"
-     top_pad="10"
-     name="profile_scroll"
-     width="312">
-    <panel
-     name="scroll_content_panel"
-     follows="left|top|right"
-     min_height="300"
-     layout="topleft"
-     top="0"
-     background_visible="false"
-     height="400"
-     left="0"
-     width="285">
-        <texture_picker
-         fallback_image="default_land_picture.j2c"
-         enabled="false"
-         follows="left|top|right"
-         height="197"
-         layout="topleft"
-         left="11"
-         name="pick_snapshot"
-         top="10"
-         width="272" />
-        <text_editor
-         allow_scroll="false"
-         bg_visible="false"
-         follows="left|top|right"
-         h_pad="0"
-         height="35"
-         width="280"
-         layout="topleft"
-         font="SansSerifBig"
-         font.style="BOLD"
-         left="10"
-         top_pad="10"
-         name="pick_name"
-         read_only="true"
-         text_color="white"
-         v_pad="0"
-         value="[name]"
-         use_ellipses="true" />
-        <text_editor
-         allow_scroll="false"
-         bg_visible="false"
-         follows="left|top|right"
-         h_pad="0"
-         height="25"
-         layout="topleft"
-         left="10"
-         name="pick_location"
-         read_only="true"
-         width="280"
-         word_wrap="true"
-         v_pad="0"
-         value="[loading...]" />
-        <text_editor
-         bg_readonly_color="DkGray2"
-         follows="all"
-         height="100"
-         width="280"
-         parse_urls="true"	
-         layout="topleft"
-         left="10"
-         top_pad="2"
-         max_length="1023"
-         name="pick_desc"
-         read_only="true"
-         text_readonly_color="white"
-         value="[description]"
-         wrap="true" />
-    </panel>
-    </scroll_container>
-    <panel
-     follows="left|right|bottom"
-     height="23"
-     layout="topleft"
-     top_pad="5"
-     left="8"
-     name="buttons">
-       
-       <layout_stack
-		  follows="bottom|left|right"
-		  height="23"
-		  layout="topleft"
-		  name="layout_stack1"
-		  left="0"
-		  orientation="horizontal"
-		  top_pad="0"
-		  width="312">
-		  
-		  <layout_panel
-			  follows="bottom|left|right"
-			  height="23"
-			  layout="bottomleft"
-			  left="0"
-			  name="layout_panel1"
-		      auto_resize="true"
-			  width="101">
-			  <button
-			  	 follows="bottom|left|right"
-		         height="23"
-		         label="Teleport"
-		         layout="topleft"
-		         name="teleport_btn"
-		         top="0"
-		         width="101" />
-		  </layout_panel>
-		  
-		  <layout_panel
-			  follows="bottom|left|right"
-			  height="23"
-			  layout="bottomleft"
-			  left_pad="3"
-			  name="show_on_map_btn_lp"
-		      auto_resize="true"
-			  width="100">
-			  <button
-		         follows="bottom|left|right"
-		         height="23"
-		         label="Map"
-		         layout="topleft"
-		         name="show_on_map_btn"
-		         top_pad="0"
-		         width="100" />
-		  </layout_panel>	  
-		  
-		  <layout_panel
-			  follows="bottom|left|right"
-			  height="23"
-			  layout="bottomleft"
-			  left_pad="3"
-			  name="edit_btn_lp"
-		      auto_resize="true"
-			  width="101">
-			  <button
-		         follows="bottom|left|right"
-		         height="23"
-		         label="Edit"
-		         layout="topleft"
-		         name="edit_btn"
-		         top_pad="0"
-		         width="101" />
-		  </layout_panel>
-	   </layout_stack>
-    </panel>
-</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_picks.xml b/indra/newview/skins/default/xui/en/panel_picks.xml
deleted file mode 100644
index 8def96cada1d79213cd0561a9ef88e1af84d4bdc..0000000000000000000000000000000000000000
--- a/indra/newview/skins/default/xui/en/panel_picks.xml
+++ /dev/null
@@ -1,227 +0,0 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
-<panel
-bg_opaque_color="DkGray2"
-       background_visible="true"
-       background_opaque="true"
- follows="all"
- height="571"
- label="Picks"
- layout="topleft"
- left="8"
- name="panel_picks"
- top_pad="0"
- width="313">
- <string
-  name="no_picks"
-  value="No Picks" />
- <string
-  name="no_classifieds"
-  value="No Classifieds" />
- <text
-  type="string"
-  follows="all"
-  height="535"
-  layout="topleft"
-  left="6"
-  name="picks_panel_text"
-  wrap="true"
-  top="10"
-  width="313"/>
- <accordion
-  fit_parent="true" 
-  follows="all"
-  height="514"
-  layout="topleft"
-  left="0"
-  name="accordion"
-  top="0"
-  single_expansion="true"
-  width="313">
-    <accordion_tab
-     layout="topleft"
-     height="235"
-     min_height="150"
-     name="tab_picks"
-     title="Picks"
-     visible="false">
- <flat_list_view
-         color="DkGray2"
-         follows="all"
-         layout="topleft"
-         left="0"
-         name="picks_list"
-         opaque="true"
-         top="0"
-         width="313" />
-    </accordion_tab>
-    <accordion_tab
-     layout="topleft"
-     height="235"
-     name="tab_classifieds"
-     title="Classifieds"
-     visible="false">
-            <flat_list_view
-             color="DkGray2"
-             follows="all"
-             layout="topleft"
-             left="0"
-             name="classifieds_list"
-             opaque="true"
-             top="0"
-             width="313" />
-    </accordion_tab>
- </accordion>
-   <panel
-       bg_opaque_color="DkGray2"
-       background_visible="true"
-       background_opaque="true"
-       bevel_style="none"
-       enabled="false"
-       follows="bottom|left|right"
-       left="1"
-       height="27"
-       label="bottom_panel"
-       layout="topleft"
-       name="edit_panel"
-       top_pad="0"
-       width="312">
-         
-         <layout_stack
-		  follows="bottom|left|right"
-		  height="23"
-		  layout="bottomleft"
-		  name="edit_panel_ls"
-		  left="10"
-		  orientation="horizontal"
-		  top_pad="0"
-		  width="293">
-		  
-		  <layout_panel
-			  follows="bottom|left"
-			  height="18"
-			  layout="bottomleft"
-			  left="0"
-			  name="gear_menu_btn"
-		      auto_resize="true"
-			  width="51">
-				<button
-	             follows="bottom|left"
-	             height="18"
-	             image_disabled="AddItem_Disabled"
-	             image_selected="AddItem_Press"
-	             image_unselected="AddItem_Off"
-	             layout="topleft"
-	             left="0"
-	             name="new_btn"
-	             tool_tip="Create a new pick or classified at the current location"
-	             top="0"
-	             width="18" />
-		  </layout_panel>
-		  
-		  <layout_panel
-			  follows="bottom|right"
-			  height="18"
-			  layout="bottomleft"
-			  name="trash_btn_lp"
-		      auto_resize="true"
-			  width="18">
-				<button
-	             follows="bottom|right"
-	             height="18"
-	             image_disabled="TrashItem_Disabled"
-	             image_selected="TrashItem_Press"
-	             image_unselected="TrashItem_Off"
-	             layout="topleft"
-	             name="trash_btn"
-	             top="0"
-	             width="18" />
-		  </layout_panel>
-		  
-	  </layout_stack>
-	  </panel>
-	  
-	  <panel
- bg_opaque_color="DkGray"
-       background_visible="true"
-       background_opaque="true"
-         follows="bottom|left|right"
-         layout="topleft"
-         left="0"
-         height="30"
-         name="buttons_cucks"
-         top_pad="0"
-         width="313">
-      
-      <layout_stack
-		  follows="bottom|left|right"
-		  height="28"
-		  layout="topleft"
-		  left="2"
-		  name="buttons_cucks_ls"
-		  orientation="horizontal"
-		  top="0"
-		  width="313">
-		  	  
-		  <layout_panel
-			  follows="bottom|left|right"
-			  height="28"
-			  layout="topleft"
-			  left="0"
-			  name="info_btn_lp"
-		      auto_resize="true"
-			  top="0"
-			  width="95">
-		       <button
-		         enabled="false"
-		         follows="top|left|right"
-		         height="23"
-		         label="Info"
-		         layout="topleft"
-		         name="info_btn"
-		         tab_stop="false"
-		         tool_tip="Show pick information"
-		         width="95" />
-		  </layout_panel>
-		  
-		  <layout_panel
-			  follows="bottom|left|right"
-			  height="28"
-			  layout="bottomleft" 
-			  left_pad="2"
-			  name="teleport_btn_lp"
-		      auto_resize="true"
-			  width="117">
-		        <button
-		         enabled="false"
-		         follows="top|left|right"
-		         height="23"
-		         label="Teleport"
-		         layout="topleft"
-		         name="teleport_btn"
-		         tab_stop="false"
-		         tool_tip="Teleport to the corresponding area"
-		         width="117" />
-		  </layout_panel>
-		  
-		  <layout_panel
-			  follows="bottom|left|right"
-			  height="28"
-			  layout="bottomleft"
-			  name="show_on_map_btn_lp"
-		      auto_resize="true" 
-			  left_pad="2"
-			  width="90">
-		        <button
-		         enabled="false"
-		         follows="top|left|right"
-		         height="23"
-		         label="Map"
-		         layout="topleft"
-		         name="show_on_map_btn"
-		         tab_stop="false"
-		         tool_tip="Show the corresponding area on the World Map"
-		         width="88" />
-		  </layout_panel>
-	</layout_stack>
-	</panel>
-</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_preferences_sound.xml b/indra/newview/skins/default/xui/en/panel_preferences_sound.xml
index 2ea20570b18e39da29a3e874ffc58667c90b5fac..42a34d171aa352179d3c04aad6e6b5ca0bc7ebc6 100644
--- a/indra/newview/skins/default/xui/en/panel_preferences_sound.xml
+++ b/indra/newview/skins/default/xui/en/panel_preferences_sound.xml
@@ -28,7 +28,7 @@
      height="15"
      increment="0.025"
      initial_value="0.5"
-     label="Master volume"
+     label="All volume"
 	   label_width="120"
      layout="topleft"
      left="0"
@@ -386,7 +386,7 @@
      left="25"
      name="voice_chat_settings"
      width="200"
-     top_pad="7">
+     top_pad="16">
 	  Voice Chat Settings
     </text>
     <text
diff --git a/indra/newview/skins/default/xui/en/panel_profile_classified.xml b/indra/newview/skins/default/xui/en/panel_profile_classified.xml
new file mode 100644
index 0000000000000000000000000000000000000000..c9e8b242d47533d2a2fad8a0aadcbf811c16a99a
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/panel_profile_classified.xml
@@ -0,0 +1,830 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<panel
+ name="panel_profile_classified"
+ top="0"
+ left="0"
+ height="420"
+ width="315"
+ follows="all"
+ layout="topleft"
+ help_topic="panel_profile_classified"
+ min_height="250"
+>
+    <panel.string
+     name="type_mature"
+    >
+        Moderate
+    </panel.string>
+    <panel.string
+     name="type_pg"
+    >
+        General Content
+    </panel.string>
+    <panel.string
+     name="l$_price"
+    >
+        L$[PRICE]
+    </panel.string>
+    <panel.string
+     name="click_through_text_fmt"
+    >
+        [TELEPORT] teleport, [MAP] map, [PROFILE] profile
+    </panel.string>
+    <panel.string
+     name="date_fmt"
+    >
+        [mthnum,datetime,slt]/[day,datetime,slt]/[year,datetime,slt]
+    </panel.string>
+    <panel.string
+     name="auto_renew_on"
+    >
+        Enabled
+    </panel.string>
+    <panel.string
+     name="auto_renew_off"
+    >
+        Disabled
+    </panel.string>
+    <panel.string
+     name="location_notice"
+    >
+        (will update after save)
+    </panel.string>
+    <string
+     name="publish_label"
+    >
+        Publish
+    </string>
+    <string
+     name="save_label"
+    >
+        Save
+    </string>
+
+  <layout_stack
+   name="main_classifieds_stack"
+   top="0"
+   bottom="-1"
+   left="0"
+   width="310"
+   follows="all"
+   layout="topleft"
+   orientation="vertical"
+   animate="false"
+    >
+    <layout_panel
+     follows="all"
+     width="310"
+     height="300"
+     layout="topleft"
+     name="scroll_layout_panel"
+     auto_resize="true">
+      <scroll_container
+       name="profile_scroll"
+       top="0"
+       left="0"
+       height="300"
+       width="310"
+       follows="all"
+       layout="topleft"
+       color="DkGray2"
+       opaque="true"
+       reserve_scroll_corner="false"
+      >
+        <panel
+         name="info_scroll_content_panel"
+         top="0"
+         left="0"
+         height="562"
+         width="280"
+         follows="left|top|right"
+         layout="topleft"
+         background_visible="false"
+         min_height="200"
+        >
+            <texture_picker
+             name="classified_snapshot"
+             enabled="false"
+             top="0"
+             left="10"
+             height="161"
+             width="260"
+             follows="left|top"
+             layout="topleft"
+             fallback_image="default_land_picture.j2c"
+            />
+            <icon
+             name="edit_icon"
+             label=""
+             tool_tip="Click to select an image"
+             top="0"
+             left="0"
+             height="161"
+             width="260"
+             layout="topleft"
+             follows="left|top"
+             image_name="spacer24.tga"
+             visible="false"
+            />
+            <layout_stack
+             name="info_panel"
+             top="145"
+             left="0"
+             height="375"
+             width="310"
+             follows="all"
+             layout="topleft"
+             visible="true"
+             animate="false"
+             orientation="vertical"
+             >
+                <layout_panel
+                 name="main_info_panel"
+                 top="0"
+                 left="0"
+                 height="160"
+                 width="280"
+                 follows="all"
+                 layout="topleft"
+                 auto_resize="false"
+                    >
+                    <text_editor
+                     name="classified_name"
+                     top="0"
+                     left="10"
+                     height="35"
+                     width="270"
+                     follows="left|top|right"
+                     layout="topleft"
+                     allow_scroll="false"
+                     bg_visible="false"
+                     font="SansSerifBig"
+                     font.style="BOLD"
+                     h_pad="0"
+                     read_only="true"
+                     text_color="white"
+                     use_ellipses="true"
+                     v_pad="0"
+                     >
+                        [name]
+                    </text_editor>
+                    <text
+                     name="classified_location_label"
+                     value="Location:"
+                     top_pad="-2"
+                     left="10"
+                     height="10"
+                     width="250"
+                     follows="left|top"
+                     layout="topleft"
+                     font.style="BOLD"
+                     text_color="white"
+                     />
+                    <text_editor
+                     name="classified_location"
+                     value="[loading...]"
+                     top_pad="5"
+                     left="10"
+                     height="30"
+                     width="280"
+                     follows="left|top"
+                     layout="topleft"
+                     allow_scroll="false"
+                     bg_visible="false"
+                     h_pad="0"
+                     read_only="true"
+                     v_pad="0"
+                     word_wrap="true"
+                     />
+                    <text
+                     name="content_type_label"
+                     value="Content Type:"
+                     top_pad="10"
+                     left="10"
+                     height="10"
+                     width="140"
+                     follows="left|top"
+                     layout="topleft"
+                     font.style="BOLD"
+                     text_color="white"
+                     />
+                    <icon
+                     name="content_type_moderate"
+                     top_pad="-11"
+                     left_pad="0"
+                     height="16"
+                     width="18"
+                     follows="top|left"
+                     layout="topleft"
+                     image_name="Parcel_M_Light"
+                     />
+                    <icon
+                     name="content_type_general"
+                     top_delta="0"
+                     left_delta="0"
+                     height="16"
+                     width="18"
+                     follows="top|left"
+                     layout="topleft"
+                     image_name="Parcel_PG_Light"
+                     />
+                    <text_editor
+                     name="content_type"
+                     value="[content type]"
+                     top_delta="1"
+                     left_pad="2"
+                     height="18"
+                     width="130"
+                     follows="left|top|right"
+                     layout="topleft"
+                     allow_scroll="false"
+                     bg_visible="false"
+                     h_pad="0"
+                     read_only="true"
+                     v_pad="0"
+                     />
+                    <text
+                     name="category_label"
+                     value="Category:"
+                     top_pad="0"
+                     left="10"
+                     height="10"
+                     width="140"
+                     follows="left|top"
+                     layout="topleft"
+                     font.style="BOLD"
+                     text_color="white"
+                     />
+                    <text_editor
+                     name="category"
+                     value="[category]"
+                     top_pad="-10"
+                     left_pad="0"
+                     height="18"
+                     width="150"
+                     follows="left|top|right"
+                     layout="topleft"
+                     allow_scroll="false"
+                     bg_visible="false"
+                     h_pad="0"
+                     parse_urls="true"
+                     read_only="true"
+                     v_pad="0"
+                     />
+                    <text
+                     name="creation_date_label"
+                     value="Creation date:"
+                     top_pad="0"
+                     left="10"
+                     height="10"
+                     width="140"
+                     follows="left|top"
+                     layout="topleft"
+                     font.style="BOLD"
+                     text_color="white"
+                     />
+                    <text_editor
+                     name="creation_date"
+                     value="[date]"
+                     tool_tip="Creation date"
+                     top_pad="-10"
+                     left_pad="0"
+                     height="16"
+                     width="150"
+                     follows="left|top"
+                     layout="topleft"
+                     allow_scroll="false"
+                     bg_visible="false"
+                     h_pad="0"
+                     halign="left"
+                     read_only="true"
+                     v_pad="0"
+                     />
+                    <text
+                     name="price_for_listing_label"
+                     value="Price for listing:"
+                     top_pad="5"
+                     left="10"
+                     height="10"
+                     width="140"
+                     follows="left|top"
+                     layout="topleft"
+                     font.style="BOLD"
+                     text_color="white"
+                     />
+                    <text_editor
+                     name="price_for_listing"
+                     tool_tip="Price for listing."
+                     top_pad="-10"
+                     left_pad="0"
+                     height="16"
+                     width="105"
+                     follows="left|top"
+                     layout="topleft"
+                     allow_scroll="false"
+                     bg_visible="false"
+                     h_pad="0"
+                     halign="left"
+                     read_only="true"
+                     v_pad="0"
+                     >
+                     [PRICE]
+                    </text_editor>
+                </layout_panel>
+                <layout_panel
+                 name="clickthrough_layout_panel"
+                 top="0"
+                 left="0"
+                 height="16"
+                 width="290"
+                 follows="all"
+                 layout="topleft"
+                 auto_resize="false"
+                 >
+                    <text
+                     name="click_through_label"
+                     value="Clicks:"
+                     top_pad="0"
+                     left="10"
+                     height="10"
+                     width="140"
+                     follows="left|top"
+                     layout="topleft"
+                     font.style="BOLD"
+                     text_color="white"
+                     />
+                    <text_editor
+                     name="click_through_text"
+                     value="[clicks]"
+                     tool_tip="Click through data"
+                     top_pad="-10"
+                     left_pad="0"
+                     height="16"
+                     width="150"
+                     follows="left|top"
+                     layout="topleft"
+                     allow_scroll="false"
+                     bg_visible="false"
+                     h_pad="0"
+                     halign="left"
+                     read_only="true"
+                     v_pad="0"
+                     />
+                </layout_panel>
+                <layout_panel
+                 name="auto_renew_layout_panel"
+                 top="0"
+                 left="0"
+                 height="16"
+                 width="290"
+                 follows="all"
+                 layout="topleft"
+                 auto_resize="false"
+                 >
+                    <text
+                     name="auto_renew_label"
+                     value="Auto renew:"
+                     top="0"
+                     left="10"
+                     height="10"
+                     width="140"
+                     follows="left|top"
+                     layout="topleft"
+                     font.style="BOLD"
+                     text_color="white"
+                     />
+                    <text
+                     name="auto_renew"
+                     value="Enabled"
+                     top_pad="-10"
+                     left_pad="0"
+                     height="16"
+                     width="150"
+                     follows="top|left"
+                     layout="topleft"
+                     />
+                </layout_panel>
+                <layout_panel
+                 name="descr_layout_panel"
+                 top="0"
+                 left="0"
+                 height="220"
+                 width="290"
+                 follows="all"
+                 layout="topleft"
+                 auto_resize="true"
+                 >
+                    <text
+                     name="classified_desc_label"
+                     value="Description:"
+                     top="0"
+                     left="10"
+                     height="10"
+                     width="250"
+                     follows="left|top"
+                     layout="topleft"
+                     font.style="BOLD"
+                     text_color="white"
+                     />
+                    <text_editor
+                     name="classified_desc"
+                     trusted_content="false"
+                     value="[description]"
+                     top_pad="7"
+                     left="10"
+                     height="200"
+                     width="280"
+                     follows="all"
+                     layout="topleft"
+                     allow_scroll="false"
+                     bg_visible="false"
+                     h_pad="0"
+                     max_length="1023"
+                     parse_urls="true"
+                     read_only="true"
+                     v_pad="0"
+                     word_wrap="true"
+                     />
+                </layout_panel>
+            </layout_stack>
+            <panel
+             name="edit_panel"
+             top="145"
+             left="0"
+             height="420"
+             width="320"
+             follows="left|top|right"
+             layout="topleft"
+             visible="false"
+            >
+                <text
+                 name="Name:"
+                 top="0"
+                 left="10"
+                 height="15"
+                 width="280"
+                 follows="left|top"
+                 layout="topleft"
+                 font="SansSerifSmall"
+                 font.style="BOLD"
+                 length="1"
+                 text_color="white"
+                 type="string"
+                >
+                    Title:
+                </text>
+                <line_editor
+                 name="classified_name_edit"
+                 top_pad="2"
+                 left="10"
+                 height="20"
+                 width="273"
+                 follows="left|top|right"
+                 layout="topleft"
+                 font="SansSerif"
+                 max_length_bytes="30"
+                 prevalidate_callback="ascii"
+                 commit_on_focus_lost="false"
+                 text_color="black"
+                />
+                <text
+                 name="description_label"
+                 top_pad="10"
+                 left="10"
+                 height="15"
+                 width="280"
+                 follows="left|top"
+                 layout="topleft"
+                 font="SansSerifSmall"
+                 font.style="BOLD"
+                 length="1"
+                 text_color="white"
+                 type="string"
+                >
+                    Description:
+                </text>
+                <text_editor
+                 name="classified_desc_edit"
+                 top_pad="2"
+                 left="10"
+                 height="100"
+                 width="273"
+                 follows="left|top|right"
+                 layout="topleft"
+                 max_length="256"
+                 text_color="black"
+                 word_wrap="true"
+                />
+                <text
+                 name="location_label"
+                 top_pad="10"
+                 left="10"
+                 height="15"
+                 width="280"
+                 follows="left|top"
+                 layout="topleft"
+                 font="SansSerifSmall"
+                 font.style="BOLD"
+                 length="1"
+                 text_color="white"
+                 type="string"
+                >
+                    Location:
+                </text>
+                <text
+                 name="classified_location_edit"
+                 top_pad="2"
+                 left="10"
+                 right="-10"
+                 height="30"
+                 width="280"
+                 follows="left|top"
+                 layout="topleft"
+                 length="1"
+                 type="string"
+                 word_wrap="true"
+                >
+                    loading...
+                </text>
+                <button
+                 name="set_to_curr_location_btn"
+                 label="Set to Current Location"
+                 top_pad="5"
+                 left="10"
+                 height="23"
+                 width="200"
+                 follows="left|top"
+                 layout="topleft"
+                />
+                <text
+                 name="category_label"
+                 value="Category:"
+                 top_pad="10"
+                 left="10"
+                 height="10"
+                 width="120"
+                 follows="left|top"
+                 layout="topleft"
+                 font.style="BOLD"
+                 text_color="white"
+                />
+                <combo_box
+                 name="category_edit"
+                 label=""
+                 top_delta="-3"
+                 left_pad="0"
+                 height="23"
+                 width="156"
+                 follows="left|top"
+                />
+                <text
+                 name="content_type_label"
+                 value="Content type:"
+                 top_pad="15"
+                 left="10"
+                 height="10"
+                 width="120"
+                 follows="left|top"
+                 layout="topleft"
+                 font.style="BOLD"
+                 text_color="white"
+                />
+                <icons_combo_box
+                 name="content_type_edit"
+                 label="General Content"
+                 top_delta="-3"
+                 left_pad="0"
+                 height="23"
+                 width="156"
+                 follows="left|top"
+                 layout="topleft"
+                >
+                    <icons_combo_box.drop_down_button
+                     image_overlay="Parcel_PG_Light"
+                     image_overlay_alignment="left"
+                     imgoverlay_label_space="3"
+                     pad_left="3"
+                    />
+                    <icons_combo_box.item
+                     name="mature_ci"
+                     label="Moderate Content"
+                     value="Mature"
+                    >
+                        <item.columns
+                         value="Parcel_M_Light"
+                         width="20"
+                         halign="center"
+                         type="icon"
+                        />
+                    </icons_combo_box.item>
+                    <icons_combo_box.item
+                     name="pg_ci"
+                     label="General Content"
+                     value="PG"
+                    >
+                        <item.columns
+                         value="Parcel_PG_Light"
+                         width="20"
+                         halign="center"
+                         type="icon"
+                        />
+                    </icons_combo_box.item>
+                </icons_combo_box>
+                <check_box
+                 name="auto_renew_edit"
+                 label="Auto renew each week"
+                 top_pad="10"
+                 left="10"
+                 height="16"
+                 width="250"
+                 layout="topleft"
+                />
+              </panel>
+        </panel>
+      </scroll_container>
+    </layout_panel>
+
+    <layout_panel
+     follows="all"
+     width="310"
+     height="25"
+     layout="topleft"
+     name="util_buttons_lp"
+     auto_resize="true">
+      <layout_stack
+       name="util_buttons_stack"
+       bottom="-1"
+       left="1"
+       right="-1"
+       height="25"
+       follows="left|bottom|right"
+       layout="topleft"
+       orientation="horizontal"
+       animate="false"
+      >
+        <layout_panel
+         follows="all"
+         layout="topleft"
+         name="util_resizer_left"
+         auto_resize="true"
+         user_resize="false"
+         width="1"/>
+        
+        <layout_panel
+            follows="all"
+            height="25"
+            layout="topleft"
+            left="0"
+            name="teleport_btn_lp"
+            auto_resize="false"
+            top="0"
+            width="85">
+            <button
+             name="teleport_btn"
+             label="Teleport"
+             top="0"
+             left="0"
+             height="23"
+             max_width="101"
+             width="85"
+             follows="bottom|left|right"
+             layout="topleft"
+             />
+        </layout_panel>
+
+        <layout_panel
+            follows="all"
+            height="25"
+            layout="bottomleft"
+            left_pad="2"
+            name="map_btn_lp"
+            auto_resize="false"
+            max_width="101"
+            width="85">
+            <button
+             name="show_on_map_btn"
+             label="Map"
+             top="0"
+             left="0"
+             height="23"
+             width="85"
+             follows="bottom|left|right"
+             layout="topleft"
+             />
+        </layout_panel>
+
+        <layout_panel
+            follows="all"
+            height="25"
+            layout="bottomleft"
+            left_pad="2"
+            name="edit_btn_lp"
+            auto_resize="false"
+            max_width="101"
+            width="85">
+            <button
+             name="edit_btn"
+             label="Edit"
+             top="0"
+             left="0"
+             height="23"
+             width="85"
+             follows="bottom|left|right"
+             layout="topleft"
+             />
+        </layout_panel>
+
+        <layout_panel
+         follows="all"
+         layout="topleft"
+         name="util_resizer_right"
+         auto_resize="true"
+         width="1">
+        </layout_panel>
+      </layout_stack>
+    </layout_panel>
+    <layout_panel
+     follows="all"
+     width="310"
+     height="41"
+     layout="topleft"
+     name="publish_layout_panel"
+     auto_resize="false">
+      <view_border
+          bevel_style="none"
+          height="0"
+          follows="left|top|right"
+          layout="topleft"
+          left="0"
+          name="publish_emphasis_border"
+          top="5"
+          width="310"/>
+      <layout_stack
+       name="publish_stack"
+       left="1"
+       right="-1"
+       top="11"
+       height="25"
+       follows="left|top|right"
+       layout="topleft"
+       orientation="horizontal"
+       animate="false"
+      >
+        <layout_panel
+         follows="all"
+         layout="topleft"
+         name="pbl_resizer_left"
+         auto_resize="true"
+         user_resize="false"
+         width="1"/>
+        
+        <layout_panel
+         follows="all"
+         layout="topleft"
+         name="save_btn_lp"
+         auto_resize="false"
+         width="134">
+          <button
+           name="save_changes_btn"
+           label="[LABEL]"
+           top="0"
+           left="0"
+           left_pad="5"
+           height="23"
+           width="134"
+           follows="left|top"
+           layout="topleft"
+             />
+        </layout_panel>
+
+        <layout_panel
+         follows="all"
+         layout="bottomleft"
+         left_pad="2"
+         name="cancel_btn_lp"
+         auto_resize="false"
+         width="134">
+          <button
+           name="cancel_btn"
+           label="Cancel"
+           top="0"
+           left="0"
+           height="23"
+           width="134"
+           follows="left|top"
+           layout="topleft"
+             />
+        </layout_panel>
+
+        <layout_panel
+         follows="all"
+         layout="topleft"
+         name="pbl_resizer_right"
+         auto_resize="true"
+         width="1">
+        </layout_panel>
+        
+      </layout_stack>
+    </layout_panel>
+  </layout_stack>
+</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_profile_classifieds.xml b/indra/newview/skins/default/xui/en/panel_profile_classifieds.xml
new file mode 100644
index 0000000000000000000000000000000000000000..2b2f60e0c20ab4c2fada2f6e9435ccbc4e108153
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/panel_profile_classifieds.xml
@@ -0,0 +1,142 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<panel
+ name="panel_profile_classifieds"
+ label="Classified"
+ top="0"
+ left="0"
+ height="480"
+ width="420"
+ follows="all"
+ layout="topleft"
+>
+    <string
+     name="no_classifieds"
+     value="No Classifieds"
+    />
+
+  <layout_stack
+   name="main_stack"
+   top="0"
+   left="0"
+   right="-1"
+   bottom="-1"
+   follows="all"
+   layout="topleft"
+   animate="false"
+   orientation="vertical">
+    <layout_panel
+     name="buttons_header"
+     follows="all"
+     layout="topleft"
+     height="50"
+     auto_resize="false"
+     user_resize="false">
+      <button
+       name="new_btn"
+       label="New..."
+       tool_tip="Create a new classified at the current location"
+       enabled="false"
+       top="25"
+       left="5"
+       height="20"
+       width="70"
+       follows="left|top"
+       layout="topleft"
+       visible="true"
+      />
+      <button
+       name="delete_btn"
+       label="Delete..."
+       tool_tip="Delete currently selected classified"
+       enabled="false"
+       left_pad="5"
+       height="20"
+       width="70"
+       follows="left|top"
+       layout="topleft"
+       visible="true"
+      />
+    </layout_panel>
+    <layout_panel
+     name="main_body"
+     follows="all"
+     layout="topleft"
+     height="430"
+     auto_resize="true"
+     user_resize="false">
+      <tab_container
+       name="tab_classifieds"
+       top="0"
+       bottom="-1"
+       left="4"
+       right="-4"
+       follows="all"
+       layout="topleft"
+       halign="left"
+       tab_position="left"
+       tab_width="150"
+       use_ellipses="true"
+      />
+
+      <layout_stack
+       name="indicator_stack"
+       top="220"
+       left="0"
+       right="-1"
+       height="28"
+       follows="top|left|right"
+       layout="topleft"
+       animate="false"
+       orientation="horizontal">
+        <layout_panel
+         name="indicator_spacer_left"
+         follows="all"
+         layout="topleft"
+         width="100"
+         auto_resize="true"
+         user_resize="false">
+        </layout_panel>
+        <layout_panel
+         name="buttons_header"
+         follows="all"
+         layout="topleft"
+         width="25"
+         auto_resize="false"
+         user_resize="false">
+          <loading_indicator
+           name="progress_indicator"
+           top="1"
+           left="1"
+           height="23"
+           width="23"
+           follows="top|left"
+           layout="topleft"
+           visible="false"
+            />
+        </layout_panel>
+        <layout_panel
+         name="indicator_spacer_right"
+         follows="all"
+         layout="topleft"
+         width="100"
+         auto_resize="true"
+         user_resize="false">
+        </layout_panel>
+      </layout_stack>
+      <text
+       name="classifieds_panel_text"
+       top="250"
+       left="110"
+       right="-110"
+       height="25"
+       follows="left|top|right"
+       layout="topleft"
+       halign="center"
+       mouse_opaque="false"
+       wrap="true"
+      >
+          Loading...
+      </text>
+    </layout_panel>
+  </layout_stack>
+</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_profile_firstlife.xml b/indra/newview/skins/default/xui/en/panel_profile_firstlife.xml
new file mode 100644
index 0000000000000000000000000000000000000000..ca1e405a62cd5e076e6eefd0932f862aa88c0464
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/panel_profile_firstlife.xml
@@ -0,0 +1,103 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<panel
+ name="panel_profile_firstlife"
+ label="Profile"
+ top="0"
+ left="0"
+ height="480"
+ width="420"
+ follows="all"
+ layout="topleft"
+>
+    <loading_indicator
+     name="progress_indicator"
+     top="5"
+     right="-10"
+     height="23"
+     width="23"
+     follows="top|right"
+     layout="topleft"
+     visible="false"
+    />
+    <icon
+     name="real_world_pic"
+     image_name="Generic_Person_Large"
+     follows="top|left"
+     layout="topleft"
+     top="10"
+     left="8"
+     height="160"
+     width="160"/>
+    <loading_indicator
+     name="image_upload_indicator"
+     top="79"
+     left="77"
+     height="23"
+     width="23"
+     follows="top|left"
+     layout="topleft"
+     visible="false"/>
+    <button
+     name="fl_upload_image"
+     label="Upload Photo"
+     top="102"
+     left="175"
+     height="20"
+     width="120"
+     follows="top|left"
+     layout="topleft"/>
+    <button
+     name="fl_change_image"
+     label="Change Photo"
+     top_pad="5"
+     left="175"
+     height="20"
+     width="120"
+     follows="top|left"
+     layout="topleft"/>
+    <button
+     name="fl_remove_image"
+     label="Remove Photo"
+     top_pad="5"
+     left_delta="0"
+     height="20"
+     width="120"
+     follows="top|left"
+     layout="topleft"/>
+    <text_editor
+     name="fl_description_edit"
+     trusted_content="false"
+     enabled="false"
+     top="180"
+     left="6"
+     right="-6"
+     height="224"
+     follows="all"
+     layout="topleft"
+     bg_readonly_color="Transparent"
+     border_visible="true"
+     max_length="65000"
+     parse_urls="true"
+     word_wrap="true"
+    />
+    <button
+     name="fl_save_changes"
+     label="Save"
+     top_pad="5"
+     right="-108"
+     height="20"
+     width="80"
+     enabled="false"
+     follows="right|bottom"
+     layout="topleft"/>
+    <button
+     name="fl_discard_changes"
+     label="Discard"
+     top_delta="0"
+     right="-4"
+     height="20"
+     width="100"
+     enabled="false"
+     follows="right|bottom"
+     layout="topleft"/>
+</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_profile_notes.xml b/indra/newview/skins/default/xui/en/panel_profile_notes.xml
new file mode 100644
index 0000000000000000000000000000000000000000..16e7365042b05baba529f2cb8c6920049418534a
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/panel_profile_notes.xml
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<panel
+ name="panel_notes"
+ label="Notes &amp; Privacy"
+ top="0"
+ left="0"
+ height="480"
+ width="420"
+ follows="all"
+ layout="topleft"
+>
+    <loading_indicator
+     name="progress_indicator"
+     top="3"
+     right="-10"
+     height="23"
+     width="23"
+     follows="top|right"
+     layout="topleft"
+     visible="false"
+    />
+    <text
+     name="status_message"
+     value="Make notes about this person here. No one else can see your notes."
+     top="6"
+     left="6"
+     right="-6"
+     height="16"
+     follows="left|top|right"
+     layout="topleft"
+     font.style="BOLD"
+    />
+    <text_editor
+     name="notes_edit"
+     enabled="false"
+     top="28"
+     left="6"
+     right="-6"
+     bottom="-26"
+     follows="all"
+     layout="topleft"
+     max_length="65530"
+     word_wrap="true"
+    />
+    <button
+     name="notes_save_changes"
+     label="Save"
+     bottom="-1"
+     right="-108"
+     height="20"
+     width="80"
+     enabled="false"
+     follows="bottom|right"
+     layout="topleft"/>
+    <button
+     name="notes_discard_changes"
+     label="Discard"
+     bottom="-1"
+     right="-4"
+     height="20"
+     width="100"
+     enabled="false"
+     follows="bottom|right"
+     layout="topleft"/>
+</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_profile_pick.xml b/indra/newview/skins/default/xui/en/panel_profile_pick.xml
new file mode 100644
index 0000000000000000000000000000000000000000..3e91640093855a3785f3b6ec6477a90d7e3f5d48
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/panel_profile_pick.xml
@@ -0,0 +1,314 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<panel
+ name="panel_pick_info"
+ top="0"
+ left="0"
+ height="360"
+ width="310"
+ follows="all"
+ layout="topleft"
+ help_topic="profile_pick_info"
+>
+    <panel.string
+     name="location_notice"
+    >
+        (will update after save)
+    </panel.string>
+
+  <layout_stack
+   name="main_pick_stack"
+   left="1"
+   right="-1"
+   top="0"
+   bottom="-1"
+   follows="all"
+   layout="topleft"
+   orientation="vertical"
+   animate="false">
+    <layout_panel
+     follows="all"
+     layout="bottomleft"
+     left_pad="2"
+     name="main_pick_lp"
+     auto_resize="true"
+     height="314">
+      <texture_picker
+       name="pick_snapshot"
+       top="10"
+       left="10"
+       height="161"
+       width="260"
+       follows="left|top"
+       layout="topleft"
+       fallback_image="default_land_picture.j2c"
+      />
+      <text
+       name="title_label"
+       top_pad="-15"
+       left="10"
+       height="15"
+       width="280"
+       follows="left|top"
+       layout="topleft"
+       font="SansSerifSmall"
+       font.style="BOLD"
+       length="1"
+       text_color="white"
+       type="string"
+                >
+        Title:
+      </text>
+      <line_editor
+       name="pick_name"
+       enabled="false"
+       top_pad="2"
+       left="10"
+       height="20"
+       width="290"
+       follows="left|right|top"
+       layout="topleft"
+      />
+      <text
+       name="description_label"
+       top_pad="10"
+       left="10"
+       height="15"
+       width="280"
+       follows="left|top"
+       layout="topleft"
+       font="SansSerifSmall"
+       font.style="BOLD"
+       length="1"
+       text_color="white"
+       type="string"
+                >
+        Description:
+      </text>
+      <text_editor
+       name="pick_desc"
+       trusted_content="false"
+       always_show_icons="true"
+       enabled="false"
+       top_pad="2"
+       left="10"
+       height="45"
+       width="290"
+       follows="all"
+       layout="topleft"
+       allow_html="true"
+       border_visible="true"
+       h_pad="4"
+       max_length="1023"
+       v_pad="3"
+       word_wrap="true"
+      />
+      <text
+       name="location_label"
+       bottom="-25"
+       left="10"
+       height="15"
+       width="280"
+       follows="left|right|bottom"
+       layout="topleft"
+       font="SansSerifSmall"
+       font.style="BOLD"
+       length="1"
+       text_color="white"
+       type="string"
+                >
+        Location:
+      </text>
+      <line_editor
+       name="pick_location"
+       enabled="false"
+       bottom="-1"
+       left="10"
+       height="23"
+       width="290"
+       follows="left|right|bottom"
+       layout="topleft"
+       length="1"
+       type="string"
+      >
+          Loading...
+      </line_editor>
+    </layout_panel>
+
+
+    <layout_panel
+     follows="all"
+     layout="bottomleft"
+     name="save_changes_lp"
+     auto_resize="false"
+     height="25">
+      <layout_stack
+       name="save_changes_stack"
+       left="1"
+       right="-1"
+       top="0"
+       height="25"
+       follows="left|top|right"
+       layout="topleft"
+       orientation="horizontal"
+       animate="false">
+
+        <layout_panel
+         follows="all"
+         layout="topleft"
+         name="util_resizer_left"
+         auto_resize="true"
+         width="1">
+        </layout_panel>
+
+        <layout_panel
+         follows="all"
+         layout="bottomleft"
+         left_pad="2"
+         name="map_btn_lp"
+         auto_resize="false"
+         width="100">
+          <button
+           name="show_on_map_btn"
+           label="Show on Map"
+           left="0"
+           top="0"
+           height="23"
+           width="100"
+           follows="left|top"
+           layout="topleft"
+      />
+        </layout_panel>
+
+        <layout_panel
+         follows="all"
+         layout="bottomleft"
+         left_pad="2"
+         name="tp_btn_lp"
+         auto_resize="false"
+         width="100">
+          <button
+           name="teleport_btn"
+           label="Teleport"
+           left="0"
+           top="0"
+           height="23"
+           width="100"
+           follows="left|top"
+           layout="topleft"
+          />
+        </layout_panel>
+
+        <layout_panel
+         follows="all"
+         layout="topleft"
+         name="util_resizer_right"
+         auto_resize="true"
+         width="1">
+        </layout_panel>
+
+      </layout_stack>
+    </layout_panel>
+
+    <layout_panel
+     follows="all"
+     layout="bottomleft"
+     name="save_changes_lp"
+     auto_resize="false"
+     height="41">
+      <view_border
+          bevel_style="none"
+          height="0"
+          follows="left|top|right"
+          layout="topleft"
+          left="0"
+          name="save_emphasis_border"
+          top="5"
+          width="310"/>
+      <layout_stack
+       name="save_changes_stack"
+       left="1"
+       right="-1"
+       top="11"
+       height="25"
+       follows="left|top|right"
+       layout="topleft"
+       orientation="horizontal"
+       animate="false">
+
+        <layout_panel
+         follows="all"
+         layout="topleft"
+         name="save_resizer_left"
+         auto_resize="true"
+         width="1">
+        </layout_panel>
+
+        <layout_panel
+         follows="all"
+         layout="bottomleft"
+         left_pad="2"
+         name="create_btn_lp"
+         auto_resize="false"
+         width="130">
+          <button
+           name="create_changes_btn"
+           label="Create Pick"
+           left="0"
+           top="0"
+           height="23"
+           width="130"
+           follows="left|top"
+           layout="topleft"
+          />
+        </layout_panel>
+
+        <layout_panel
+         follows="all"
+         layout="bottomleft"
+         left_pad="2"
+         name="save_btn_lp"
+         auto_resize="false"
+         width="130">
+          <button
+           name="save_changes_btn"
+           label="Save Pick"
+           left="0"
+           top="0"
+           height="23"
+           width="130"
+           follows="left|top"
+           layout="topleft"
+          />
+        </layout_panel>
+
+        <layout_panel
+         follows="all"
+         layout="bottomleft"
+         left_pad="2"
+         name="cancel_btn_lp"
+         auto_resize="false"
+         width="130">
+          <button
+           name="cancel_changes_btn"
+           label="Cancel"
+           left="0"
+           top="0"
+           height="23"
+           width="130"
+           follows="left|top"
+           layout="topleft"
+          />
+        </layout_panel>
+
+        <layout_panel
+         follows="all"
+         layout="topleft"
+         name="save_resizer_right"
+         auto_resize="true"
+         width="1">
+        </layout_panel>
+
+      </layout_stack>
+    </layout_panel>
+  </layout_stack>
+</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_profile_picks.xml b/indra/newview/skins/default/xui/en/panel_profile_picks.xml
new file mode 100644
index 0000000000000000000000000000000000000000..44d5c448c00446d9512c890ac57f860324ada2f4
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/panel_profile_picks.xml
@@ -0,0 +1,154 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<panel
+ name="panel_picks"
+ label="Picks"
+ top="0"
+ left="0"
+ height="480"
+ width="420"
+ follows="all"
+ layout="topleft"
+>
+    <string
+     name="no_picks"
+     value="No Picks"
+    />
+
+  <layout_stack
+   name="main_stack"
+   top="0"
+   left="0"
+   right="-1"
+   bottom="-1"
+   follows="all"
+   layout="topleft"
+   animate="false"
+   orientation="vertical">
+    <layout_panel
+     name="buttons_header"
+     follows="all"
+     layout="topleft"
+     height="50"
+     auto_resize="false"
+     user_resize="false">
+      <text
+       name="header_text"
+       top="5"
+       left="5"
+       right="-5"
+       height="16"
+       follows="left|top|right"
+       layout="topleft"
+       halign="center"
+    >
+        Tell everyone about your favorite places in Second Life.
+      </text>
+      <button
+       name="new_btn"
+       label="New..."
+       tool_tip="Create a new pick at the current location"
+       enabled="false"
+       top_pad="4"
+       left="5"
+       height="20"
+       width="70"
+       follows="left|top"
+       layout="topleft"
+       visible="false"
+    />
+      <button
+       name="delete_btn"
+       label="Delete..."
+       tool_tip="Delete currently selected pick"
+       enabled="false"
+       left_pad="5"
+       height="20"
+       width="70"
+       follows="left|top"
+       layout="topleft"
+       visible="false"
+    />
+    </layout_panel>
+    <layout_panel
+     name="main_body"
+     follows="all"
+     layout="topleft"
+     height="430"
+     auto_resize="true"
+     user_resize="false">
+      <tab_container
+       name="tab_picks"
+       top="0"
+       bottom="-5"
+       left="4"
+       right="-4"
+       tab_width="150"
+       follows="all"
+       layout="topleft"
+       halign="left"
+       tab_position="left"
+       use_ellipses="true"
+    />
+      
+    <layout_stack
+     name="indicator_stack"
+     top="220"
+     left="0"
+     right="-1"
+     height="28"
+     follows="top|left|right"
+     layout="topleft"
+     animate="false"
+     orientation="horizontal">
+      <layout_panel
+       name="indicator_spacer_left"
+       follows="all"
+       layout="topleft"
+       width="100"
+       auto_resize="true"
+       user_resize="false">
+      </layout_panel>
+      <layout_panel
+       name="buttons_header"
+       follows="all"
+       layout="topleft"
+       width="25"
+       auto_resize="false"
+       user_resize="false">
+        <loading_indicator
+         name="progress_indicator"
+         top="1"
+         left="1"
+         height="23"
+         width="23"
+         follows="top|left"
+         layout="topleft"
+         visible="false"
+        />
+      </layout_panel>
+      <layout_panel
+       name="indicator_spacer_right"
+       follows="all"
+       layout="topleft"
+       width="100"
+       auto_resize="true"
+       user_resize="false">
+      </layout_panel>
+    </layout_stack>
+    <text
+       name="picks_panel_text"
+       top="250"
+       left="100"
+       right="-100"
+       height="25"
+       follows="left|top|right"
+       layout="topleft"
+       halign="center"
+       mouse_opaque="false"
+       wrap="true"
+    >
+        Loading...
+      </text>
+    </layout_panel>
+  </layout_stack>
+</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_profile_secondlife.xml b/indra/newview/skins/default/xui/en/panel_profile_secondlife.xml
new file mode 100644
index 0000000000000000000000000000000000000000..551b4778762a98af802aab0183462caf5684a1be
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/panel_profile_secondlife.xml
@@ -0,0 +1,549 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<panel
+ name="panel_profile"
+ label="Profile"
+ top="0"
+ left="0"
+ height="480"
+ width="420"
+ follows="all"
+ layout="topleft"
+>
+   <string 
+    name="date_format"
+    value="SL birthdate: [mth,datetime,slt] [day,datetime,slt], [year,datetime,slt]" />
+   <string
+    name="age_format"
+    value="[AGE]" />
+   <string
+    name="partner_text"
+    value="Partner: [LINK]" />
+   <string
+    name="CaptionTextAcctInfo">
+Account: [ACCTTYPE]
+[PAYMENTINFO]
+    </string>
+
+  <layout_stack
+   name="image_stack"
+   top="8"
+   left="6"
+   bottom="-1"
+   width="160"
+   border_size="0"
+   follows="left|top|bottom"
+   layout="topleft"
+   animate="false"
+   orientation="vertical">
+    <layout_panel
+     name="image_panel"
+     follows="all"
+     layout="topleft"
+     width="160"
+     height="160"
+     auto_resize="false"
+     user_resize="false">
+
+      <icon
+       name="2nd_life_pic"
+       image_name="Generic_Person_Large"
+       layout="topleft"
+       follows="all"
+       interactable="true"
+       top="0"
+       left="2"
+       bottom="-1"
+       right="-1"/>
+
+      <loading_indicator
+       name="image_upload_indicator"
+       top="69"
+       left="69"
+       height="23"
+       width="23"
+       follows="top|left"
+       layout="topleft"
+       visible="false"/>
+    </layout_panel>
+
+    <layout_panel
+     name="basics_panel"
+     follows="all"
+     layout="topleft"
+     height="54"
+     auto_resize="false"
+     user_resize="false"
+        >
+      <line_editor
+       name="user_name"
+       border_thickness="0"
+       use_bg_color="false"
+       background_image_disabled=""
+       background_image_focused=""
+       enabled="false"
+       value="(loading...)"
+       top="4"
+       left="3"
+       right="-1"
+       height="16"
+       follows="left|top|right"
+       layout="topleft"/>
+
+      <line_editor
+       name="sl_birth_date"
+       border_thickness="0"
+       use_bg_color="false"
+       background_image_disabled=""
+       background_image_focused=""
+       enabled="false"
+       value="(loading...)"
+       top_pad="0"
+       left_delta="0"
+       right="-1"
+       height="16"
+       follows="left|top|right"
+       layout="topleft"/>
+
+      <line_editor
+       name="user_age"
+       border_thickness="0"
+       use_bg_color="false"
+       background_image_disabled=""
+       background_image_focused=""
+       enabled="false"
+       value="(loading...)"
+       top_pad="0"
+       left_delta="0"
+       right="-1"
+       height="16"
+       follows="left|top|right"
+       layout="topleft"/>
+    </layout_panel>
+    <layout_panel
+     name="partner_layout"
+     follows="all"
+     layout="topleft"
+     height="30"
+     auto_resize="false"
+     user_resize="false"
+     visible="true">
+      <text
+       type="string"
+       name="partner_link"
+       value="Partner: (loading...)"
+       top="0"
+       left="5"
+       right="-1"
+       height="28"
+       follows="left|top|right"
+       layout="topleft"
+       translate="false"
+       use_ellipses="true"
+       word_wrap="true"
+       visible="true"/>
+    </layout_panel>
+
+    <layout_panel
+     name="partner_spacer_layout"
+     follows="all"
+     layout="topleft"
+     height="14"
+     auto_resize="false"
+     user_resize="false"
+     visible="true">
+    </layout_panel>
+    
+    <layout_panel
+     name="frind_layout"
+     follows="all"
+     layout="topleft"
+     height="16"
+     auto_resize="false"
+     user_resize="false"
+     visible="false">
+      <text
+       name="frind_text"
+       value="You are friends"
+       text_color="ConversationFriendColor"
+       top="0"
+       left="5"
+       right="-1"
+       height="16"
+       follows="left|top|right"
+       layout="topleft"
+       translate="false"
+       visible="true"/>
+    </layout_panel>
+    <layout_panel
+     name="online_layout"
+     follows="all"
+     layout="topleft"
+     height="16"
+     auto_resize="false"
+     user_resize="false"
+     visible="false">
+      <icon
+       name="online_icon"
+       image_name="Profile_Friend_Online"
+       layout="topleft"
+       follows="left|top"
+       top="0"
+       left="5"
+       height="10"
+       width="10"/>
+      <text
+       name="online_text"
+       value="Online"
+       top="0"
+       left="18"
+       right="-1"
+       height="16"
+       follows="left|top|right"
+       layout="topleft"
+       translate="false"
+       visible="true"/>
+    </layout_panel>
+    <layout_panel
+     name="offline_layout"
+     follows="all"
+     layout="topleft"
+     height="16"
+     auto_resize="false"
+     user_resize="false"
+     visible="false">
+      <icon
+       name="offline_icon"
+       image_name="Profile_Friend_Offline"
+       layout="topleft"
+       follows="left|top"
+       top="0"
+       left="5"
+       height="10"
+       width="10"/>
+      <text
+       name="offline_text"
+       value="Offline"
+       top="0"
+       left="18"
+       right="-1"
+       height="16"
+       follows="left|top|right"
+       layout="topleft"
+       translate="false"
+       visible="true"/>
+    </layout_panel>
+    <layout_panel
+     name="account_layout"
+     follows="all"
+     layout="topleft"
+     height="33"
+     auto_resize="false"
+     user_resize="false">
+      <text
+       name="account_info"
+       value="Account: (loading...)"
+       top="0"
+       left="5"
+       right="-1"
+       height="16"
+       follows="left|top|right"
+       layout="topleft"
+       word_wrap="true"/>
+    </layout_panel>
+    <layout_panel
+     name="indicator_stack"
+     follows="all"
+     layout="topleft"
+     height="33"
+     auto_resize="false"
+     user_resize="false">
+      <loading_indicator
+       name="progress_indicator"
+       left="67"
+       top="0"
+       height="23"
+       width="23"
+       follows="left|top"
+       layout="topleft"
+       visible="true"/>
+    </layout_panel>
+    <layout_panel
+     name="settings_panel"
+     follows="all"
+     layout="topleft"
+     height="50"
+     auto_resize="false"
+     user_resize="false">
+      <!-- only for self -->
+      <text
+       name="search_label"
+       value="Show my profile in search:"
+       top="1"
+       left="6"
+       right="-1"
+       height="16"
+       follows="left|top|right"
+       layout="topleft"/>
+      <combo_box
+       name="show_in_search"
+       tool_tip="Let people see you in search results"
+       left="1"
+       top="18"
+       height="23"
+       width="140"
+       follows="left|top"
+       layout="topleft"
+       visible="true"
+       enabled="false">
+        <combo_box.item
+           name="Hide"
+           label="Hide"
+           value="0" />
+        <combo_box.item
+           name="Show"
+           label="Show"
+           value="1" />
+      </combo_box>
+    </layout_panel>
+    
+    <layout_panel
+     name="menu_panel"
+     follows="all"
+     layout="topleft"
+     height="55"
+     auto_resize="false"
+     user_resize="false"
+        >
+      <menu_button
+       layout="topleft"
+       follows="left|top"
+       left="1"
+       top="25"
+       height="25"
+       width="140"
+       label="Actions"
+       halign="left"
+       image_unselected="DropDown_Off"
+       image_selected="DropDown_On"
+       image_pressed="DropDown_Press"
+       image_pressed_selected="DropDown_Press"
+       image_disabled="DropDown_Disabled"
+       name="agent_actions_menu" />
+    </layout_panel>
+  </layout_stack>
+
+  <layout_stack
+   name="main_stack"
+   top="8"
+   left="168"
+   bottom="-1"
+   right="-1"
+   follows="all"
+   layout="topleft"
+   animate="false"
+   orientation="vertical">
+    <layout_panel
+     name="display_name_panel"
+     follows="all"
+     layout="topleft"
+     height="24"
+     auto_resize="false"
+     user_resize="false">
+      <line_editor
+       name="display_name"
+       border_thickness="0"
+       use_bg_color="false"
+       background_image_disabled=""
+       background_image_focused=""
+       enabled="false"
+       value="(loading...)"
+       font="SansSerifBigLarge"
+       top="0"
+       left="6"
+       height="19"
+       right="-86"
+       follows="left|top|right"
+       layout="topleft"/>
+
+      <icon
+       tool_tip="Friend can see my online status"
+       mouse_opaque="true"
+       name="can_see_online"
+       image_name="Profile_Perm_Online_Enabled"
+       layout="topleft"
+       follows="right|top"
+       interactable="true"
+       top="0"
+       right="-61"
+       height="24"
+       width="24"
+       left_pad="2" />
+
+      <icon
+       tool_tip="Friend can not see my online status"
+       mouse_opaque="true"
+       name="cant_see_online"
+       image_name="Profile_Perm_Online_Disabled"
+       layout="topleft"
+       follows="right|top"
+       interactable="true"
+       top="0"
+       right="-61"
+       height="24"
+       width="24"
+       left_pad="2" />
+
+      <icon
+       tool_tip="Friend can see me on map"
+       mouse_opaque="true"
+       name="can_see_on_map"
+       image_name="Profile_Perm_Find_Enabled"
+       layout="topleft"
+       follows="right|top"
+       interactable="true"
+       top="0"
+       right="-30"
+       height="24"
+       width="24"
+       left_pad="2" />
+
+      <icon
+       tool_tip="Friend can not see me on map"
+       mouse_opaque="true"
+       name="cant_see_on_map"
+       image_name="Profile_Perm_Find_Disabled"
+       layout="topleft"
+       follows="right|top"
+       interactable="true"
+       top="0"
+       right="-30"
+       height="24"
+       width="24"
+       left_pad="2" />
+
+      <icon
+       tool_tip="Friend can edit my objects"
+       mouse_opaque="true"
+       name="can_edit_objects"
+       image_name="Profile_Perm_Objects_Enabled"
+       layout="topleft"
+       follows="right|top"
+       interactable="true"
+       top="0"
+       right="-1"
+       height="24"
+       width="24"
+       left_pad="2" />
+
+      <icon
+       tool_tip="Friend can not edit my objects"
+       mouse_opaque="true"
+       name="cant_edit_objects"
+       image_name="Profile_Perm_Objects_Disabled"
+       layout="topleft"
+       follows="right|top"
+       interactable="true"
+       top="0"
+       right="-1"
+       height="24"
+       width="24"
+       left_pad="2" />
+
+    </layout_panel>
+
+    <layout_panel
+     name="about_panel"
+     follows="all"
+     layout="topleft"
+     height="159"
+     auto_resize="true"
+     user_resize="false">
+      <text_editor
+       name="sl_description_edit"
+       trusted_content="false"
+       always_show_icons="true"
+       commit_on_focus_lost="false"
+       enabled="false"
+       top="0"
+       left="2"
+       right="-1"
+       bottom="-1"
+       follows="all"
+       layout="topleft"
+       bg_readonly_color="Transparent"
+       border_visible="true"
+       font="SansSerifSmall"
+       h_pad="2"
+       max_length="65000"
+       parse_urls="true"
+       word_wrap="true"
+        />
+    </layout_panel>
+    <layout_panel
+     name="about_buttons_panel"
+     follows="all"
+     layout="topleft"
+     height="34"
+     auto_resize="false"
+     user_resize="false">
+        <button
+         name="save_description_changes"
+         label="Save"
+         top="1"
+         right="-105"
+         height="20"
+         width="80"
+         enabled="false"
+         follows="top|right"
+         layout="topleft"/>
+        <button
+         name="discard_description_changes"
+         label="Discard"
+         top="1"
+         right="-1"
+         height="20"
+         width="100"
+         enabled="false"
+         follows="top|right"
+         layout="topleft"/>
+        <view_border
+         bevel_style="none"
+         height="0"
+         layout="topleft"
+         left="0"
+         name="cost_text_border"
+         top_pad="9"
+         width="492"/>
+    </layout_panel>
+
+    <layout_panel
+     name="groups_panel"
+     follows="all"
+     layout="topleft"
+     height="159"
+     auto_resize="true"
+     user_resize="false">
+      <text
+       name="group_label"
+       value="Group memberships"
+       top="1"
+       left="2"
+       right="-1"
+       height="16"
+       follows="left|top|right"
+       layout="topleft"/>
+      <group_list
+       name="group_list"
+       top="18"
+       left="2"
+       right="-1"
+       bottom="-1"
+       follows="all"
+       layout="topleft"
+       border_visible="true"
+       color="ScrollBgWriteableColor"
+       for_agent="false"/>
+
+    </layout_panel>
+  </layout_stack>
+</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_profile_web.xml b/indra/newview/skins/default/xui/en/panel_profile_web.xml
new file mode 100644
index 0000000000000000000000000000000000000000..e0cb4d3d06f9ec6130db17b96a39d0fc9c3fbc47
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/panel_profile_web.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<panel
+ name="panel_profile_web"
+ label="Web"
+ top="0"
+ left="0"
+ height="480"
+ width="420"
+ follows="all"
+ layout="topleft"
+>
+    <panel.string
+     name="LoadTime"
+     value="Load Time: [TIME] seconds"
+    />
+    <web_browser
+     name="profile_html"
+     top="10"
+     bottom="-18"
+     left="10"
+     right="-10"
+     follows="all"
+     layout="topleft"
+     start_url=""
+    />
+    <text
+     name="status_text"
+     bottom="-4"
+     left="110"
+     right="-110"
+     follows="bottom|left|right"
+     layout="topleft"
+     halign="center"
+     parse_urls="false"
+    />
+</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_region_terrain.xml b/indra/newview/skins/default/xui/en/panel_region_terrain.xml
index 8243c2715df910b8ff89730a8bccd242c9eb07be..2aaea04a6d306f6058c580f2d44d52c7a07e2272 100644
--- a/indra/newview/skins/default/xui/en/panel_region_terrain.xml
+++ b/indra/newview/skins/default/xui/en/panel_region_terrain.xml
@@ -86,7 +86,7 @@
      name="detail_texture_text"
      top="110"
      width="300">
-        Terrain Textures (requires 512x512, 24 bit .tga files)
+        Terrain Textures (requires 1024x1024, 24 bit .tga files)
     </text>
     <texture_picker
      follows="left|top"
diff --git a/indra/newview/skins/default/xui/en/panel_status_bar.xml b/indra/newview/skins/default/xui/en/panel_status_bar.xml
index 9023d68ea956836c7f5b251831de57150df2b097..b711ed0e1ce5dccb461871154bd5216e424593f5 100644
--- a/indra/newview/skins/default/xui/en/panel_status_bar.xml
+++ b/indra/newview/skins/default/xui/en/panel_status_bar.xml
@@ -11,7 +11,6 @@
  mouse_opaque="false"
  name="status"
  top="19"
- tab_stop="false"
  width="1000">
     <panel.string
      name="packet_loss_tooltip">
diff --git a/indra/newview/skins/default/xui/en/panel_toolbar_view.xml b/indra/newview/skins/default/xui/en/panel_toolbar_view.xml
index f5c559fe1dda158c06c33f4439980e9067918200..a3348f28c7317adf250d1de172f3a67174bd7e11 100644
--- a/indra/newview/skins/default/xui/en/panel_toolbar_view.xml
+++ b/indra/newview/skins/default/xui/en/panel_toolbar_view.xml
@@ -95,7 +95,7 @@
                tab_stop="false"
                name="state_management_buttons_container"
                visible="false"
-               width="200"/>
+               width="350"/>
       </layout_panel>
        <layout_panel name="right_toolbar_panel"
                     auto_resize="false"
diff --git a/indra/newview/skins/default/xui/en/panel_tools_texture.xml b/indra/newview/skins/default/xui/en/panel_tools_texture.xml
index 90f32ae4526b85e238b745cb279abbb6cf8f2c64..c7052bb7371e93bdd9240bc2bdb0acb606079f9c 100644
--- a/indra/newview/skins/default/xui/en/panel_tools_texture.xml
+++ b/indra/newview/skins/default/xui/en/panel_tools_texture.xml
@@ -11,6 +11,36 @@
          name="Texture"
          top="0"
          width="295">
+            <panel.string
+             name="paste_error_face_selection_mismatch">
+              When multiple faces are copied, the target object must have the same number of faces selected.
+            </panel.string>
+            <panel.string
+             name="paste_error_object_face_count_mismatch">
+              When all faces of an object are copied, the target object must have the same number of faces.
+            </panel.string>
+            <panel.string
+             name="paste_error_inventory_not_found">
+              One or more texture not found in inventory.
+            </panel.string>
+            <panel.string
+             name="paste_options">
+              Paste options
+            </panel.string>
+
+            <menu_button
+             menu_filename="menu_copy_paste_color.xml"
+             follows="top|left"
+             height="15"
+             image_disabled="ClipboardMenu_Disabled"
+             image_selected="ClipboardMenu_Press"
+             image_unselected="ClipboardMenu_Off"
+             layout="topleft"
+             left="258"
+             top="8"
+             name="clipboard_color_params_btn"
+             tool_tip="Paste options"
+             width="22"/>
             <text
              type="string"
              length="1"
@@ -36,7 +66,7 @@
              name="colorswatch"
              tool_tip="Click to open color picker"
              top="20"
-             width="64" />
+             width="54" />
             <text
              type="string"
              length="1"
@@ -84,7 +114,7 @@
              left_delta="0"
              name="glow"
              top_pad="4"
-             width="80" />
+             width="77" />
             <check_box
              height="19"
              label="Full Bright"
@@ -93,13 +123,22 @@
              name="checkbox fullbright"
              top_pad="4"
              width="81" />
+            <view_border
+             bevel_style="none"
+             follows="top|left"
+             height="0"
+             layout="topleft"
+             left="8"
+             name="object_horizontal"
+             top_pad="4"
+             width="278" />
             <combo_box
              height="23"
              layout="topleft"
              left="10"
              name="combobox matmedia"
-             top_pad="5"
-             width="100">
+             top_pad="17"
+             width="90">
                 <combo_box.item
                  label="Materials"
                  name="Materials"
@@ -113,7 +152,7 @@
             control_name="ComboMaterialType"
             height="50"
             layout="topleft"
-            left_pad="20"
+            left_pad="5"
             top_delta="-10"
             width="150"
             visible = "false"
@@ -139,7 +178,20 @@
                 layout="topleft"
                 top_pad="1"
                 value="2"/>
-            </radio_group> 
+            </radio_group>
+            <menu_button
+                menu_filename="menu_copy_paste_texture.xml"
+                follows="top|left"
+                height="15"
+                image_disabled="ClipboardMenu_Disabled"
+                image_selected="ClipboardMenu_Press"
+                image_unselected="ClipboardMenu_Off"
+                layout="topleft"
+                left="258"
+                top_delta="0"
+                name="clipboard_texture_params_btn"
+                tool_tip="Paste options"
+                width="22"/>
             <check_box
              control_name="SyncMaterialSettings"
              follows="top|left"
@@ -150,7 +202,7 @@
              left="8"
              name="checkbox_sync_settings"
              tool_tip="Adjust all maps repeats simultaneously"
-             top_pad="-16"
+             top_pad="19"
              width="160" />
             <texture_picker
              can_apply_immediately="true"
@@ -498,10 +550,7 @@
 			 top_pad="4"
 			 tool_tip="Add Media"
 			 label="Choose..."
-			 width="85">
-				<button.commit_callback
-				function="BuildTool.AddMedia"/>
-			</button>
+			 width="85"/>
 			<button
 			 follows="top|left"
 			 height="18"
@@ -511,10 +560,7 @@
 			 tool_tip="Delete this media texture"
 			 top_delta="0"
 			 label="Remove"
-			 width="85">
-				<button.commit_callback
-				function="BuildTool.DeleteMedia"/>
-			</button>
+			 width="85"/>
             <button
 			 follows="left|top"
 			 height="18"
@@ -771,14 +817,14 @@
              top_delta="16"
              width="260" />
 			<button
-			 left="10"
-			 top="222"
+       follows="left|top"
+       layout="topleft"
+			 left="9"
+			 top="204"
 			 height="20"
 			 label="Align"
 			 label_selected="Align current texture layers"
-			 layout="topleft"
 			 name="button align textures"
-			 top_delta="0"
 			 tool_tip="Align current texture layers"
 			 width="66" />
             <web_browser
diff --git a/indra/newview/skins/default/xui/en/panel_volume_pulldown.xml b/indra/newview/skins/default/xui/en/panel_volume_pulldown.xml
index 2034409111990c1550be42693801162092cb9c37..b4eb1ade9476c79fb2b551087810c1e454c0e3ae 100644
--- a/indra/newview/skins/default/xui/en/panel_volume_pulldown.xml
+++ b/indra/newview/skins/default/xui/en/panel_volume_pulldown.xml
@@ -19,7 +19,7 @@
      height="15"
      increment="0.025"
      initial_value="0.5"
-     label="Master"
+     label="All"
      label_width="60"
      left="10"
      width="160"
diff --git a/indra/newview/skins/default/xui/en/sidepanel_task_info.xml b/indra/newview/skins/default/xui/en/sidepanel_task_info.xml
index 8a3e18707fc03a265b42f6a9ecafb2b2418bbfbf..1c9d750aa638cd4b8cc2f480157248b46f22eb07 100644
--- a/indra/newview/skins/default/xui/en/sidepanel_task_info.xml
+++ b/indra/newview/skins/default/xui/en/sidepanel_task_info.xml
@@ -459,7 +459,7 @@
         label="Price: L$"
         label_width="73"				
         width="150"
-        min_val="1"
+        min_val="0"
         height="20"
         max_val="999999999"
         tool_tip="Object cost." />
diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml
index f26ee06e6bdde0f54c1f8848d4aea7be8b994096..6f95e282ca1019a654bd5ea320ad8a5626c405a8 100644
--- a/indra/newview/skins/default/xui/en/strings.xml
+++ b/indra/newview/skins/default/xui/en/strings.xml
@@ -69,6 +69,7 @@ Voice Server Version: [VOICE_VERSION]
 	</string>
 	<string name="AboutTraffic">Packets Lost: [PACKETS_LOST,number,0]/[PACKETS_IN,number,0] ([PACKETS_PCT,number,1]%)</string>
 	<string name="AboutTime">[month, datetime, slt] [day, datetime, slt] [year, datetime, slt] [hour, datetime, slt]:[min, datetime, slt]:[second,datetime,slt]</string>
+  <string name="LocalTime">[month, datetime, local] [day, datetime, local] [year, datetime, local] [hour, datetime, local]:[min, datetime, local]:[second,datetime, local]</string>
 	<string name="ErrorFetchingServerReleaseNotesURL">Error fetching server release notes URL.</string>
 	<string name="BuildConfiguration">Build Configuration</string>
 	
@@ -111,7 +112,7 @@ Voice Server Version: [VOICE_VERSION]
 	<string name="CertAllocationFailure">Failed to allocate openssl memory for certificate.</string>
 
 	<string name="LoginFailedNoNetwork">Network error: Could not establish connection, please check your network connection.</string>
-	<string name="LoginFailed">Login failed.</string>
+	<string name="LoginFailedHeader">Login failed.</string>
 	<string name="Quit">Quit</string>
 	<string name="create_account_url">http://join.secondlife.com/?sourceid=[sourceid]</string>
 	
@@ -125,6 +126,8 @@ http://secondlife.com/download
 
 For more information, see our FAQ below:
 http://secondlife.com/viewer-access-faq</string>
+	<string name="LoginFailed">Grid emergency login failure.
+If you feel this is an error, please contact support@secondlife.com.</string>
 	<string name="LoginIntermediateOptionalUpdateAvailable">Optional viewer update available: [VERSION]</string>
 	<string name="LoginFailedRequiredUpdate">Required viewer update: [VERSION]</string>
 	<string name="LoginFailedAlreadyLoggedIn">This agent is already logged in.
@@ -133,6 +136,7 @@ http://secondlife.com/viewer-access-faq</string>
 Please check to make sure you entered the right
     * Username (like bobsmith12 or steller.sunshine)
     * Password
+    * Second Factor Token (if enabled)
 Also, please make sure your Caps Lock key is off.</string>
 	<string name="LoginFailedPasswordChanged">As a security precaution your password has been changed.
 Please go to your account page at http://secondlife.com/password
@@ -151,15 +155,18 @@ People with free accounts will not be able to access Second Life during this tim
 	<string name="LoginFailedComputerProhibited">Second Life cannot be accessed from this computer.
 If you feel this is an error, please contact
 support@secondlife.com.</string>
+  <!--'Pacific time' placeholder for [TIME] in case time from server can't be decoded-->
+  <string name="PacificTime">Pacific Time</string>
 	<string name="LoginFailedAcountSuspended">Your account is not accessible until
-[TIME] Pacific Time.</string>
+[TIME].
+If you feel this is an error, please contact support@secondlife.com.</string>
 	<string name="LoginFailedAccountDisabled">We are unable to complete your request at this time.
 Please contact Second Life support for assistance at http://support.secondlife.com.</string>
 	<string name="LoginFailedTransformError">Data inconsistency found during login.
 Please contact support@secondlife.com.</string>
 	<string name="LoginFailedAccountMaintenance">Your account is undergoing minor maintenance.
 Your account is not accessible until
-[TIME] Pacific Time.
+[TIME].
 If you feel this is an error, please contact support@secondlife.com.</string>
 	<string name="LoginFailedPendingLogoutFault">Request for logout responded with a fault from simulator.</string>
 	<string name="LoginFailedPendingLogout">The system is logging you out right now.
@@ -192,7 +199,8 @@ Please try logging in again in a minute.</string>
 Please try logging in again in a minute.</string>
 	<string name="LoginFailedLoggingOutSession">The system has begun logging out your last session.
 Please try logging in again in a minute.</string>
-
+        <string name="LoginFailedAuthenticationMFARequired">To continue logging in, enter a new token from your multifactor authentication app.
+If you feel this is an error, please contact support@secondlife.com</string>
 
 	<!-- Disconnection -->
 	<string name="AgentLostConnection">This region may be experiencing trouble.  Please check your connection to the Internet.</string>
@@ -340,8 +348,6 @@ can be attached to notecards.
 	<!-- Group name: text shown for LLUUID::null -->
 	<string name="GroupNameNone">(none)</string>
 
-	<string name="AvalineCaller">Avaline Caller [ORDER]</string>
-
 	<!-- Asset errors. Used in llassetstorage.cpp, translation from error code to error message. -->
 	<string name="AssetErrorNone">No error</string>
 	<string name="AssetErrorRequestFailed">Asset request: failed</string>
@@ -2332,6 +2338,14 @@ The [[MARKETPLACE_CREATE_STORE_URL] Marketplace store] is returning errors.
 	</string>
 	<string name="InventoryMarketplaceError">
 An error occurred while opening Marketplace Listings.
+If you continue to receive this message, please contact Second Life support for assistance at http://support.secondlife.com
+	</string>
+	<string name="InventoryMarketplaceConnectionError">
+Marketplace Listings failed to connect.
+If you continue to receive this message, please contact Second Life support for assistance at http://support.secondlife.com
+	</string>
+	<string name="InventoryMarketplaceConnectionErrorReason">
+Marketplace Listings failed to connect. Reason: [REASON]
 If you continue to receive this message, please contact Second Life support for assistance at http://support.secondlife.com
 	</string>
 	<string name="InventoryMarketplaceListingsNoItemsTitle">Your Marketplace Listings folder is empty.</string>
@@ -2800,10 +2814,14 @@ If you continue to receive this message, please contact Second Life support for
 	<string name="ClassifiedClicksTxt">Clicks: [TELEPORT] teleport, [MAP] map, [PROFILE] profile</string>
 	<string name="ClassifiedUpdateAfterPublish">(will update after publish)</string>
 
-  <!-- panel picks -->
-  <string name="NoPicksClassifiedsText">You haven't created any Picks or Classifieds. Click the Plus button below to create a Pick or Classified.</string>
-  <string name="NoAvatarPicksClassifiedsText">User has no picks or classifieds</string>
-  <string name="PicksClassifiedsLoadingText">Loading...</string>
+    <!-- panel picks -->
+    <string name="NoPicksClassifiedsText">You haven't created any Picks or Classifieds. Click the Plus button below to create a Pick or Classified.</string>
+    <string name="NoPicksText">You haven't created any Picks. Click the New button to create a Pick.</string>
+    <string name="NoClassifiedsText">You haven't created any Classifieds. Click the New button to create a Classified.</string>
+    <string name="NoAvatarPicksClassifiedsText">User has no picks or classifieds</string>
+    <string name="NoAvatarPicksText">This person has no picks</string>
+    <string name="NoAvatarClassifiedsText">This person has no classifieds</string>
+    <string name="PicksClassifiedsLoadingText">Loading...</string>
 
 	<!-- Multi Preview Floater -->
 	<string name="MultiPreviewTitle">Preview</string>
@@ -3962,7 +3980,7 @@ Please check http://status.secondlifegrid.net to see if there is a known problem
   <!-- SL Membership -->
   <string name="BaseMembership">Base</string>
   <string name="PremiumMembership">Premium</string>
-  <string name="Premium PlusMembership">Premium Plus</string>
+  <string name="Premium_PlusMembership">Premium Plus</string>
   <string name="InternalMembership">Internal</string> <!-- No need to translate -->
 
   <string name="MembershipUpgradeText">Upgrade to Premium</string>
diff --git a/indra/newview/skins/default/xui/es/floater_about.xml b/indra/newview/skins/default/xui/es/floater_about.xml
index 8f143cf072ec2527bca0f75ce899f9626d83b171..f59f534908a50853753b3dd5f1ed5ba30b3627ec 100644
--- a/indra/newview/skins/default/xui/es/floater_about.xml
+++ b/indra/newview/skins/default/xui/es/floater_about.xml
@@ -19,7 +19,6 @@ con contribuciones de código abierto de:</text>
         expat Copyright (C) 1998, 1999, 2000 Thai Open Source Software Center Ltd.
         FreeType Copyright (C) 1996-2002, 2006 David Turner, Robert Wilhelm y Werner Lemberg.
         GL Copyright (C) 1999-2004 Brian Paul.
-        GLOD Copyright (C) 2003-04 Jonathan Cohen, Nat Duca, Chris Niski, Johns Hopkins University y David Luebke, Brenden Schubert, University of Virginia.
         google-perftools Copyright (c) 2005, Google Inc.
         Havok.com(TM) Copyright (C) 1999-2001, Telekinesys Research Limited.
         jpeg2000 Copyright (C) 2001, David Taubman, The University of New South Wales (UNSW)
diff --git a/indra/newview/skins/default/xui/es/floater_inventory_view_finder.xml b/indra/newview/skins/default/xui/es/floater_inventory_view_finder.xml
index 4f3c177976723d1ae44b7222033f711ea0a003b3..87f93e8fcfd50f2f45135cecea2a140d907d162a 100644
--- a/indra/newview/skins/default/xui/es/floater_inventory_view_finder.xml
+++ b/indra/newview/skins/default/xui/es/floater_inventory_view_finder.xml
@@ -6,7 +6,7 @@
 	<check_box label="Gestos" name="check_gesture"/>
 	<check_box label="Hitos" name="check_landmark"/>
 	<check_box label="Notas" name="check_notecard"/>
-	<check_box label="Redes" name="check_mesh"/>
+	<check_box label="Meshs" name="check_mesh"/>
 	<check_box label="Objetos" name="check_object"/>
 	<check_box label="Scripts" name="check_script"/>
 	<check_box label="Sonidos" name="check_sound"/>
diff --git a/indra/newview/skins/default/xui/es/floater_preview_texture.xml b/indra/newview/skins/default/xui/es/floater_preview_texture.xml
index b0afd44750e7ea9471d3ca3993a15155836353c9..2543508c4058dd34ce01dec681b1b961be40f2f5 100644
--- a/indra/newview/skins/default/xui/es/floater_preview_texture.xml
+++ b/indra/newview/skins/default/xui/es/floater_preview_texture.xml
@@ -6,42 +6,23 @@
 	<floater.string name="Copy">
 		Copiar al inventario
 	</floater.string>
-	<text name="desc txt">
-		Descripción:
-	</text>
-	<text name="dimensions">
-		[WIDTH]px x [HEIGHT]px
-	</text>
-	<text name="aspect_ratio">
-		Previsualizar la ratio de las proporciones
-	</text>
-	<combo_box name="combo_aspect_ratio" tool_tip="Vista previa en una proporción concreta">
-		<combo_item name="Unconstrained">
-			Sin restricciones
-		</combo_item>
-		<combo_item name="1:1" tool_tip="Emblema del grupo o perfil del Mundo real">
-			1:1
-		</combo_item>
-		<combo_item name="4:3" tool_tip="Perfil de [SECOND_LIFE]">
-			4:3
-		</combo_item>
-		<combo_item name="10:7" tool_tip="Clasificados (también en las listas de búsqueda), hitos">
-			10:7
-		</combo_item>
-		<combo_item name="3:2" tool_tip="Acerca del terreno">
-			3:2
-		</combo_item>
-		<combo_item name="16:10">
-			16:10
-		</combo_item>
-		<combo_item name="16:9" tool_tip="Destacados del perfil">
-			16:9
-		</combo_item>
-		<combo_item name="2:1">
-			2:1
-		</combo_item>
-	</combo_box>
-	<button label="OK" name="Keep"/>
-	<button label="Descartar" name="Discard"/>
-	<button label="Guardar como" name="save_tex_btn"/>
+	<layout_stack name="preview_stack">
+		<layout_panel name="texture_panel">
+			<text name="desc txt">
+				Descripción:
+			</text>
+			<text name="dimensions">
+				[WIDTH]px x [HEIGHT]px
+			</text>
+			<text name="aspect_ratio">
+				Previsualizar la ratio de las proporciones
+			</text>
+			<combo_box name="combo_aspect_ratio" tool_tip="Vista previa en una proporción concreta"/>
+		</layout_panel>
+		<layout_panel name="buttons_panel">
+			<button label="OK" name="Keep"/>
+			<button label="Descartar" name="Discard"/>
+			<button label="Guardar como" name="save_tex_btn"/>
+		</layout_panel>
+	</layout_stack>
 </floater>
diff --git a/indra/newview/skins/default/xui/es/floater_profile.xml b/indra/newview/skins/default/xui/es/floater_profile.xml
new file mode 100644
index 0000000000000000000000000000000000000000..c9448a0d4ede2b34bffddfd1490eecf514429a4a
--- /dev/null
+++ b/indra/newview/skins/default/xui/es/floater_profile.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<floater name="avatarinfo" title="Perfil">
+	<panel name="panel_profile_view">
+		<tab_container name="panel_profile_tabs">
+			<panel label="Second Life" name="panel_profile_secondlife"/>
+			<panel label="Web" name="panel_profile_web"/>
+			<panel label="Intereses" name="panel_profile_interests"/>
+			<panel label="Destacados" name="panel_profile_picks"/>
+			<panel label="Clasificado" name="panel_profile_classifieds"/>
+			<panel label="Vida real" name="panel_profile_firstlife"/>
+			<panel label="Notas" name="panel_profile_notes"/>
+		</tab_container>
+		<button label="OK" name="ok_btn" tool_tip="Salvar cambios en el perfil y cerrar"/>
+		<button label="Cancelar" label_selected="Cancelar" name="cancel_btn"/>
+	</panel>
+</floater>
diff --git a/indra/newview/skins/default/xui/es/floater_snapshot.xml b/indra/newview/skins/default/xui/es/floater_snapshot.xml
index c2c996aa8ae138e4146536884eae54116c35af75..2dfaecf3e3d2174d2f52c9162c4f55bf309efb2b 100644
--- a/indra/newview/skins/default/xui/es/floater_snapshot.xml
+++ b/indra/newview/skins/default/xui/es/floater_snapshot.xml
@@ -6,6 +6,9 @@
 	<string name="postcard_progress_str">
 		Enviando el correo electrónico
 	</string>
+	<string name="facebook_progress_str">
+		Publicando en Facebook
+	</string>
 	<string name="profile_progress_str">
 		Publicando
 	</string>
@@ -15,6 +18,9 @@
 	<string name="local_progress_str">
 		Guardando en el equipo
 	</string>
+	<string name="facebook_succeeded_str">
+		Imagen subida
+	</string>
 	<string name="profile_succeeded_str">
 		Imagen subida
 	</string>
@@ -27,6 +33,9 @@
 	<string name="local_succeeded_str">
 		¡Guardado en el equipo!
 	</string>
+	<string name="facebook_failed_str">
+		Error al subir la imagen a tu biografía de Facebook.
+	</string>
 	<string name="profile_failed_str">
 		Error al subir la imagen a los comentarios de tu perfil.
 	</string>
diff --git a/indra/newview/skins/default/xui/es/menu_name_field.xml b/indra/newview/skins/default/xui/es/menu_name_field.xml
new file mode 100644
index 0000000000000000000000000000000000000000..0d51fbffebcc44f83da0e9bfdb81a8c08787e565
--- /dev/null
+++ b/indra/newview/skins/default/xui/es/menu_name_field.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<toggleable_menu name="CopyMenu">
+	<menu_item_call label="Copiar Nombre mostrado" name="copy_display"/>
+	<menu_item_call label="Copiar Nombre de agente" name="copy_name"/>
+	<menu_item_call label="Copiar ID de agente" name="copy_id"/>
+</toggleable_menu>
diff --git a/indra/newview/skins/default/xui/es/notifications.xml b/indra/newview/skins/default/xui/es/notifications.xml
index 54707116d48a95e3410fc11699388cbcdc531619..36f27bc3c632e97730ba34a5a83f7137247cf66c 100644
--- a/indra/newview/skins/default/xui/es/notifications.xml
+++ b/indra/newview/skins/default/xui/es/notifications.xml
@@ -2690,6 +2690,9 @@ Inténtalo seleccionando un trozo más pequeño de terreno.
 	<notification name="SystemMessage">
 		[MESSAGE]
 	</notification>
+	<notification name="FacebookConnect">
+		[MESSAGE]
+	</notification>
 	<notification name="FlickrConnect">
 		[MESSAGE]
 	</notification>
diff --git a/indra/newview/skins/default/xui/es/panel_edit_classified.xml b/indra/newview/skins/default/xui/es/panel_edit_classified.xml
index ffad843732dd7ba2f4d4fa2269ac249966e7f9f3..09f87015cc03ddb715536f544760214ef5ec00f8 100644
--- a/indra/newview/skins/default/xui/es/panel_edit_classified.xml
+++ b/indra/newview/skins/default/xui/es/panel_edit_classified.xml
@@ -46,7 +46,7 @@
 			<layout_panel name="save_changes_btn_lp">
 				<button label="[LABEL]" name="save_changes_btn"/>
 			</layout_panel>
-			<layout_panel name="show_on_map_btn_lp">
+			<layout_panel name="cancel_btn_lp">
 				<button label="Cancelar" name="cancel_btn"/>
 			</layout_panel>
 		</layout_stack>
diff --git a/indra/newview/skins/default/xui/es/panel_facebook_place.xml b/indra/newview/skins/default/xui/es/panel_facebook_place.xml
index 5139bd1d0bee42dfb6eacea95f83a0dfc5d5d4d5..29f6147f2382b23ba78ffd53934ba44a3cbbabf9 100644
--- a/indra/newview/skins/default/xui/es/panel_facebook_place.xml
+++ b/indra/newview/skins/default/xui/es/panel_facebook_place.xml
@@ -3,7 +3,7 @@
 	<text name="place_caption_label">
 		Cuenta algo del lugar donde te encuentras:
 	</text>
-	<check_box initial_value="false" label="Incluir una vista general del lugar" name="add_place_view_cb"/>
+	<check_box initial_value="false" label="Incluye una vista general del lugar" name="add_place_view_cb"/>
 	<button label="Publicar" name="post_place_btn"/>
 	<button label="Cancelar" name="cancel_place_btn"/>
 </panel>
diff --git a/indra/newview/skins/default/xui/es/panel_group_general.xml b/indra/newview/skins/default/xui/es/panel_group_general.xml
index a17814d15df78ad2628e3b837125750b71984c2f..ef919f396e8e562c6cfb3f95c16f920cd284822a 100644
--- a/indra/newview/skins/default/xui/es/panel_group_general.xml
+++ b/indra/newview/skins/default/xui/es/panel_group_general.xml
@@ -46,7 +46,7 @@ Deja el cursor sobre las opciones para ver más ayuda.
 		<check_box label="Cualquiera puede entrar" name="open_enrollement" tool_tip="Configura si se permite la entrada de nuevos miembros sin ser invitados."/>
 		<check_box label="Cuota de entrada" name="check_enrollment_fee" tool_tip="Configura si hay que pagar una cuota para entrar al grupo"/>
 		<spinner label="L$" left_delta="130" name="spin_enrollment_fee" tool_tip="Si la opción Cuota de entrada está marcada, los nuevos miembros han de pagar esta cuota para entrar al grupo." width="60"/>
-		<combo_box bottom_delta="-38" name="group_mature_check" tool_tip="La calificación de contenido designa el tipo de contenido y conducta que se permiten en un grupo" width="150">
+		<combo_box bottom_delta="-38" name="group_mature_check" tool_tip="Establece si tu grupo contiene información clasificada como Moderada" width="150">
 			<combo_item name="select_mature">
 				- Selecciona el nivel de calificación -
 			</combo_item>
diff --git a/indra/newview/skins/default/xui/es/panel_group_list_item_short.xml b/indra/newview/skins/default/xui/es/panel_group_list_item_short.xml
new file mode 100644
index 0000000000000000000000000000000000000000..4d682068d78ecdedc09fa7756687394c9837e79c
--- /dev/null
+++ b/indra/newview/skins/default/xui/es/panel_group_list_item_short.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="group_list_item">
+	<text name="group_name" value="Desconocido"/>
+	<button name="info_btn" tool_tip="Más información"/>
+	<button name="profile_btn" tool_tip="Ver el perfil"/>
+</panel>
diff --git a/indra/newview/skins/default/xui/es/panel_me.xml b/indra/newview/skins/default/xui/es/panel_me.xml
deleted file mode 100644
index 850cd6ec7190d824cdda70c3a998bac220dd2338..0000000000000000000000000000000000000000
--- a/indra/newview/skins/default/xui/es/panel_me.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<panel label="Mi perfil" name="panel_me">
-	<panel label="MIS DESTACADOS" name="panel_picks"/>
-</panel>
diff --git a/indra/newview/skins/default/xui/es/panel_people.xml b/indra/newview/skins/default/xui/es/panel_people.xml
index 73b9af3665e5e17ad01b83780a8562e06fb7820c..2aaf7e89be16d095e4392c189168caed0e185bac 100644
--- a/indra/newview/skins/default/xui/es/panel_people.xml
+++ b/indra/newview/skins/default/xui/es/panel_people.xml
@@ -40,6 +40,7 @@
 			<accordion name="friends_accordion">
 				<accordion_tab name="tab_online" title="Conectado"/>
 				<accordion_tab name="tab_all" title="Todos"/>
+				<accordion_tab name="tab_suggested_friends" title="Personas de las que podrías querer ser amigo"/>
 			</accordion>
 		</panel>
 		<panel label="GRUPOS" name="groups_panel">
diff --git a/indra/newview/skins/default/xui/es/panel_profile_classified.xml b/indra/newview/skins/default/xui/es/panel_profile_classified.xml
new file mode 100644
index 0000000000000000000000000000000000000000..679026d350d1f625a92c21b05f1d6fc6db5a8af4
--- /dev/null
+++ b/indra/newview/skins/default/xui/es/panel_profile_classified.xml
@@ -0,0 +1,110 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="panel_profile_classified">
+	<panel.string name="type_mature">
+		Moderado
+	</panel.string>
+	<panel.string name="type_pg">
+		Contenido general
+	</panel.string>
+	<panel.string name="l$_price">
+		L$[PRICE]
+	</panel.string>
+	<panel.string name="click_through_text_fmt">
+		[TELEPORT] teleportes, [MAP] mapa, [PROFILE] perfil
+	</panel.string>
+	<panel.string name="date_fmt">
+		[mthnum,datetime,slt]/[day,datetime,slt]/[year,datetime,slt]
+	</panel.string>
+	<panel.string name="auto_renew_on">
+		Activados
+	</panel.string>
+	<panel.string name="auto_renew_off">
+		Inhabilitado
+	</panel.string>
+	<panel.string name="location_notice">
+		(se actualizará tras guardarlo)
+	</panel.string>
+	<string name="publish_label">
+		Publicar
+	</string>
+	<string name="save_label">
+		Guardar
+	</string>
+	<scroll_container name="profile_scroll">
+		<panel name="info_scroll_content_panel">
+			<icon label="" name="edit_icon" tool_tip="Pulsa para elegir una imagen"/>
+			<layout_stack name="info_panel">
+				<layout_panel name="main_info_panel">
+					<text_editor name="classified_name">
+						[name]
+					</text_editor>
+					<text name="classified_location_label" value="Ubicación:"/>
+					<text_editor name="classified_location" value="[loading...]"/>
+					<text name="content_type_label" value="Tipo de contenido:"/>
+					<text_editor name="content_type" value="[content type]"/>
+					<text name="category_label" value="Categoría:"/>
+					<text_editor name="category" value="[category]"/>
+					<text name="creation_date_label" value="Fecha de creación:"/>
+					<text_editor name="creation_date" tool_tip="Fecha de creación" value="[date]"/>
+					<text name="price_for_listing_label" value="Precio por publicarlo:"/>
+					<text_editor name="price_for_listing" tool_tip="Precio por publicarlo.">
+						[PRICE]
+					</text_editor>
+				</layout_panel>
+				<layout_panel name="clickthrough_layout_panel">
+					<text name="click_through_label" value="Clics:"/>
+					<text_editor name="click_through_text" tool_tip="Información sobre Click through" value="[clicks]"/>
+				</layout_panel>
+				<layout_panel name="auto_renew_layout_panel">
+					<text name="auto_renew_label" value="Renovación:"/>
+					<text name="auto_renew" value="Activados"/>
+				</layout_panel>
+				<layout_panel name="descr_layout_panel">
+					<text name="classified_desc_label" value="Descripción:"/>
+					<text_editor name="classified_desc" value="[description]"/>
+				</layout_panel>
+			</layout_stack>
+			<panel name="edit_panel">
+				<text name="Name:">
+					Título:
+				</text>
+				<text name="description_label">
+					Descripción:
+				</text>
+				<text name="location_label">
+					Ubicación:
+				</text>
+				<text name="classified_location_edit">
+					cargando...
+				</text>
+				<button label="Configurar en mi posición" name="set_to_curr_location_btn"/>
+				<text name="category_label" value="Categoría:"/>
+				<text name="content_type_label" value="Tipo de contenido:"/>
+				<icons_combo_box label="Contenido general" name="content_type_edit">
+					<icons_combo_box.item label="Contenido Moderado" name="mature_ci" value="Contenido para adultos"/>
+					<icons_combo_box.item label="Contenido general" name="pg_ci" value="General"/>
+				</icons_combo_box>
+				<check_box label="Renovar automáticamente cada semana" name="auto_renew_edit"/>
+				<text name="price_for_listing_edit_label" value="Precio por publicarlo:"/>
+				<spinner label="L$" name="price_for_listing_edit" tool_tip="Precio por publicarlo." value="50"/>
+			</panel>
+		</panel>
+	</scroll_container>
+	<layout_stack name="edit_btns_pnl">
+		<layout_panel name="teleport_btn_lp">
+			<button label="Teleporte" name="teleport_btn"/>
+		</layout_panel>
+		<layout_panel name="map_btn_lp">
+			<button label="Mapa" name="show_on_map_btn"/>
+		</layout_panel>
+		<layout_panel name="edit_btn_lp">
+			<button label="Editar" name="edit_btn"/>
+		</layout_panel>
+		<layout_panel name="save_btn_lp">
+			<button label="[LABEL]" name="save_changes_btn"/>
+		</layout_panel>
+		<layout_panel name="cancel_btn_lp">
+			<button label="Cancelar" name="cancel_btn"/>
+		</layout_panel>
+	</layout_stack>
+</panel>
diff --git a/indra/newview/skins/default/xui/es/panel_profile_classifieds.xml b/indra/newview/skins/default/xui/es/panel_profile_classifieds.xml
new file mode 100644
index 0000000000000000000000000000000000000000..2520348094d46d5ae8d929f87133a511ba564a92
--- /dev/null
+++ b/indra/newview/skins/default/xui/es/panel_profile_classifieds.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel label="Clasificado" name="panel_profile_classifieds">
+	<string name="no_classifieds" value="No hay clasificados"/>
+	<button label="Nuevo..." name="new_btn"/>
+	<button label="Eliminar..." name="delete_btn"/>
+	<text name="classifieds_panel_text">
+		Cargando...
+	</text>
+</panel>
diff --git a/indra/newview/skins/default/xui/fr/floater_picks.xml b/indra/newview/skins/default/xui/es/panel_profile_firstlife.xml
similarity index 50%
rename from indra/newview/skins/default/xui/fr/floater_picks.xml
rename to indra/newview/skins/default/xui/es/panel_profile_firstlife.xml
index f058ff668b7b7de1cf9b90fcf9f8262c9ffb4a20..0fb502e4419596d8de32e3a6d2180ca072dde451 100644
--- a/indra/newview/skins/default/xui/fr/floater_picks.xml
+++ b/indra/newview/skins/default/xui/es/panel_profile_firstlife.xml
@@ -1,2 +1,2 @@
 <?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<floater name="floater_picks" title="Favoris"/>
+<panel label="Perfil" name="panel_profile_firstlife"/>
diff --git a/indra/newview/skins/default/xui/es/panel_profile_interests.xml b/indra/newview/skins/default/xui/es/panel_profile_interests.xml
new file mode 100644
index 0000000000000000000000000000000000000000..86dd63390cd5f7d1d78194d9fb74dfd23f0a1c31
--- /dev/null
+++ b/indra/newview/skins/default/xui/es/panel_profile_interests.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel label="Intereses" name="panel_profile_interests">
+	<text name="I Want To:">
+		Quiero:
+	</text>
+	<check_box label="Construye" name="chk0"/>
+	<check_box label="Explora" name="chk1"/>
+	<check_box label="Conoce" name="chk2"/>
+	<check_box label="Encuentra empleo" name="chk6"/>
+	<check_box label="Agrupa" name="chk3"/>
+	<check_box label="Compra" name="chk4"/>
+	<check_box label="Vende" name="chk5"/>
+	<check_box label="Contrata" name="chk7"/>
+	<line_editor name="want_to_edit">
+		(cargando...)
+	</line_editor>
+	<text name="Skills:">
+		Habilidades:
+	</text>
+	<check_box label="Texturas" name="schk0"/>
+	<check_box label="Arquitectura" name="schk1"/>
+	<check_box label="Modelo" name="schk3"/>
+	<check_box label="Planificación de eventos" name="schk2"/>
+	<check_box label="Preparación de scripts" name="schk4"/>
+	<check_box label="Personajes personalizados" name="schk5"/>
+	<line_editor name="skills_edit">
+		(cargando...)
+	</line_editor>
+	<text name="Languages:">
+		Idiomas:
+	</text>
+	<line_editor name="languages_edit">
+		(cargando...)
+	</line_editor>
+</panel>
diff --git a/indra/newview/skins/default/xui/es/panel_profile_notes.xml b/indra/newview/skins/default/xui/es/panel_profile_notes.xml
new file mode 100644
index 0000000000000000000000000000000000000000..4cc14e14879e597a8e87223da88910fd895f12e9
--- /dev/null
+++ b/indra/newview/skins/default/xui/es/panel_profile_notes.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel label="Notas y Privacidad" name="panel_notes">
+	<text name="status_message" value="Notas privadas en este avatar:"/>
+	<text name="status_message2" value="Permitir que este avatar:"/>
+	<check_box label="Ver cuándo estoy conectado" name="status_check"/>
+	<check_box label="Encontrarme en el mapa del mundo" name="map_check"/>
+	<check_box label="Edita, borrar o tomar mis objetos" name="objects_check"/>
+</panel>
diff --git a/indra/newview/skins/default/xui/es/panel_profile_pick.xml b/indra/newview/skins/default/xui/es/panel_profile_pick.xml
new file mode 100644
index 0000000000000000000000000000000000000000..4e9f5bbdd5ee452517a6ee138976c5d99fda8e97
--- /dev/null
+++ b/indra/newview/skins/default/xui/es/panel_profile_pick.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="panel_pick_info">
+	<panel.string name="location_notice">
+		(se actualizará tras guardarlo)
+	</panel.string>
+	<line_editor name="pick_location">
+		Cargando...
+	</line_editor>
+	<button label="Teleporte" name="teleport_btn"/>
+	<button label="Mostrar en el mapa" name="show_on_map_btn"/>
+	<button label="Establecer ubicación" name="set_to_curr_location_btn" tool_tip="Configurar en mi posición"/>
+	<button label="Guardar" name="save_changes_btn"/>
+</panel>
diff --git a/indra/newview/skins/default/xui/es/panel_profile_picks.xml b/indra/newview/skins/default/xui/es/panel_profile_picks.xml
new file mode 100644
index 0000000000000000000000000000000000000000..0641b72c13d1de917151a49e2179c07af77c1622
--- /dev/null
+++ b/indra/newview/skins/default/xui/es/panel_profile_picks.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel label="Destacados" name="panel_picks">
+	<string name="no_picks" value="No hay destacados"/>
+	<text name="Tell everyone about your favorite places in Second Life.">
+		Cuéntale a todos sobre tus lugares favoritos de Second Life.
+	</text>
+	<button label="Nuevo..." name="new_btn"/>
+	<button label="Eliminar..." name="delete_btn"/>
+	<text name="picks_panel_text">
+		Cargando...
+	</text>
+</panel>
diff --git a/indra/newview/skins/default/xui/es/panel_profile_secondlife.xml b/indra/newview/skins/default/xui/es/panel_profile_secondlife.xml
new file mode 100644
index 0000000000000000000000000000000000000000..541593660dceadb9f72f05d776f7ca4fbb557a35
--- /dev/null
+++ b/indra/newview/skins/default/xui/es/panel_profile_secondlife.xml
@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel label="Perfil" name="panel_profile">
+	<string name="status_online">
+		Actualmente en línea
+	</string>
+	<string name="status_offline">
+		Actualmente sin conexión
+	</string>
+	<string name="CaptionTextAcctInfo">
+		[ACCTTYPE]
+[PAYMENTINFO]
+	</string>
+	<string name="payment_update_link_url">
+		http://www.secondlife.com/account/billing.php?lang=en
+	</string>
+	<string name="partner_edit_link_url">
+		http://www.secondlife.com/account/partners.php?lang=en
+	</string>
+	<string name="my_account_link_url" value="http://secondlife.com/account"/>
+	<string name="no_partner_text" value="Ninguno"/>
+	<string name="no_group_text" value="Ninguno"/>
+	<string name="RegisterDateFormat">
+		[REG_DATE]
+	</string>
+	<string name="name_text_args">
+		[NAME]
+	</string>
+	<string name="display_name_text_args">
+		[DISPLAY_NAME]
+	</string>
+	<string name="FSDev" value="Desarrollador"/>
+	<string name="FSSupp" value="Soporte"/>
+	<string name="FSQualityAssurance" value="Buscador de fallos"/>
+	<string name="FSGW" value="Portal"/>
+	<text name="name_label" value="Nombre:"/>
+	<button label="Nombre:" name="set_name" tool_tip="Configurar nombre mostrado"/>
+	<panel name="name_holder">
+		<text_editor name="complete_name" value="(cargando...)"/>
+	</panel>
+	<layout_stack name="imagepositioner">
+		<layout_panel name="label_stack">
+			<text name="status" value="Status Desconocido"/>
+			<text name="label" value="Fecha de nacimiento en Second Life:"/>
+			<text name="label2" value="Cuenta:"/>
+			<text name="partner_label" value="Compañero/a:"/>
+		</layout_panel>
+	</layout_stack>
+	<text name="Groups:" value="Grupos:"/>
+	<button label="+" label_selected="+" name="group_invite" tool_tip="Invitar al grupo"/>
+	<layout_stack name="aboutpositioner">
+		<layout_panel name="about_stack">
+			<text name="About:" value="Acerca de:"/>
+		</layout_panel>
+		<layout_panel name="give_stack">
+			<text name="Give item:" value="Dar objeto:"/>
+			<text name="Give inventory" tool_tip="Soltar elementos de inventario aquí para dárselos a esta persona.">
+				Soltar aquí el nuevo elemento de inventario.
+			</text>
+		</layout_panel>
+	</layout_stack>
+	<layout_stack name="buttonstack">
+		<layout_panel name="left_buttonstack">
+			<button label="Encontrar en el mapa" label_selected="Encontrar en el mapa" name="show_on_map_btn" tool_tip="Mostrar al Residente en el mapa"/>
+			<button label="Pagar" label_selected="Pagar" name="pay" tool_tip="Pagar a este Residente"/>
+		</layout_panel>
+		<layout_panel name="middle_buttonstack">
+			<button label="Ofrecer teleporte" label_selected="Ofrecer teleporte" name="teleport" tool_tip="Ofrecer teleporte al residente"/>
+			<button label="Mensaje instantáneo" label_selected="Mensaje instantáneo" name="im" tool_tip="Abrir una sesión de mensajes instantáneos"/>
+		</layout_panel>
+		<layout_panel name="right_buttonstack">
+			<button label="Añadir como amigo" label_selected="Añadir como amigo" name="add_friend" tool_tip="Ofrecer amistad a este Residente"/>
+			<button label="Bloquear" name="block" tool_tip="Bloquear al residente"/>
+			<button label="Desbloquear" name="unblock" tool_tip="Desbloquear al residente"/>
+		</layout_panel>
+	</layout_stack>
+	<check_box label="Mostrar en la búsqueda" name="show_in_search_checkbox"/>
+</panel>
diff --git a/indra/newview/skins/default/xui/es/panel_profile_web.xml b/indra/newview/skins/default/xui/es/panel_profile_web.xml
new file mode 100644
index 0000000000000000000000000000000000000000..f9a8f4b11390ccca28507fae23687941a83d2c76
--- /dev/null
+++ b/indra/newview/skins/default/xui/es/panel_profile_web.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel label="Web" name="panel_profile_web">
+	<panel.string name="LoadTime" value="Tiempo de carga: [TIME] segundos"/>
+	<line_editor name="url_edit">
+		(cargando..)
+	</line_editor>
+	<flyout_button label="Cargar" name="load" tool_tip="Cargar esta página de perfil con el navegador incorporado.">
+		<flyout_button.item label="Abrir navegador in-viewer" name="open_item"/>
+		<flyout_button.item label="Abrir navegador externo" name="home_item"/>
+	</flyout_button>
+	<button name="web_profile_popout_btn" tool_tip="Perfil web emergente"/>
+</panel>
diff --git a/indra/newview/skins/default/xui/es/panel_region_terrain.xml b/indra/newview/skins/default/xui/es/panel_region_terrain.xml
index cb6c03dbb5fa2f6d67c2fbabf4838d0883115844..9aba5299cbf1d15fdd170c781676b17cdd4fcfef 100644
--- a/indra/newview/skins/default/xui/es/panel_region_terrain.xml
+++ b/indra/newview/skins/default/xui/es/panel_region_terrain.xml
@@ -12,8 +12,8 @@ del terreno" name="terrain_raise_spin"/>
 	<spinner bottom_delta="-34" label="Límite de bajada del 
 terreno" name="terrain_lower_spin"/>
 	<text name="detail_texture_text">
-		Texturas del terreno (requiere archivos .tga de 512x512, 24 bits)
-	</text>
+    Texturas del terreno (requiere archivos .tga de 1024x1024, 24 bits)
+  </text>
 	<text name="height_text_lbl">
 		1 (bajo)
 	</text>
diff --git a/indra/newview/skins/default/xui/es/strings.xml b/indra/newview/skins/default/xui/es/strings.xml
index e5598978ce95a57984889ae2d07def8b3203ec2a..5a03e65b4997fae295f3050126e36e4187292d57 100644
--- a/indra/newview/skins/default/xui/es/strings.xml
+++ b/indra/newview/skins/default/xui/es/strings.xml
@@ -178,7 +178,7 @@ Versión del servidor de voz: [VOICE_VERSION]
 	<string name="LoginFailedNoNetwork">
 		Error de red: no se ha podido conectar; por favor, revisa tu conexión a internet.
 	</string>
-	<string name="LoginFailed">
+	<string name="LoginFailedHeader">
 		Error en el inicio de sesión.
 	</string>
 	<string name="Quit">
@@ -348,6 +348,24 @@ Intenta iniciar sesión de nuevo en unos instantes.
 	<string name="TestingDisconnect">
 		Probando la desconexión del visor
 	</string>
+	<string name="SocialFacebookConnecting">
+		Conectando con Facebook...
+	</string>
+	<string name="SocialFacebookPosting">
+		Publicando...
+	</string>
+	<string name="SocialFacebookDisconnecting">
+		Desconectando de Facebook...
+	</string>
+	<string name="SocialFacebookErrorConnecting">
+		Problema al conectar con Facebook
+	</string>
+	<string name="SocialFacebookErrorPosting">
+		Problema al publicar en Facebook
+	</string>
+	<string name="SocialFacebookErrorDisconnecting">
+		Problema al desconectar de Facebook
+	</string>
 	<string name="SocialFlickrConnecting">
 		Conectándose a Flickr...
 	</string>
@@ -662,9 +680,6 @@ pueden adjuntarse a las notas.
 	<string name="GroupNameNone">
 		(ninguno)
 	</string>
-	<string name="AvalineCaller">
-		Avaline: [ORDER]
-	</string>
 	<string name="AssetErrorNone">
 		No hay ningún error
 	</string>
@@ -2549,9 +2564,21 @@ Si sigues recibiendo el mismo mensaje, solicita ayuda al personal de asistencia
 	<string name="NoPicksClassifiedsText">
 		No has creado destacados ni clasificados. Pulsa el botón Más para crear uno.
 	</string>
+	<string name="NoPicksText">
+		No has creado destacados. Haz clic en el botón Más para crear uno.
+	</string>
+	<string name="NoClassifiedsText">
+		No has creado clasificados. Haz clic en el botón Nuevo para crear un anuncio clasificado.
+	</string>
 	<string name="NoAvatarPicksClassifiedsText">
 		El usuario no tiene clasificados ni destacados
 	</string>
+	<string name="NoAvatarPicksText">
+		El usuario no tiene destacados
+	</string>
+	<string name="NoAvatarClassifiedsText">
+		El usuario no tiene clasificados
+	</string>
 	<string name="PicksClassifiedsLoadingText">
 		Cargando...
 	</string>
@@ -4469,6 +4496,9 @@ Si sigues recibiendo este mensaje, contacta con [SUPPORT_SITE].
 	<string name="share_alert">
 		Arrastra los ítems desde el invenbtario hasta aquí
 	</string>
+	<string name="facebook_post_success">
+		Has publicado en Facebook.
+	</string>
 	<string name="flickr_post_success">
 		Has publicado en Flickr.
 	</string>
diff --git a/indra/newview/skins/default/xui/fr/floater_about.xml b/indra/newview/skins/default/xui/fr/floater_about.xml
index 1e2a14ab3e2030042a1c7bd66f239c23e39fb873..df6b61e293adfdd340aa8ef02db7aa54a66310e4 100644
--- a/indra/newview/skins/default/xui/fr/floater_about.xml
+++ b/indra/newview/skins/default/xui/fr/floater_about.xml
@@ -19,7 +19,6 @@ avec les contributions Open Source de :</text>
         expat Copyright (C) 1998, 1999, 2000 Thai Open Source Software Center Ltd.
         FreeType Copyright (C) 1996-2002, 2006 David Turner, Robert Wilhelm et Werner Lemberg.
         GL Copyright (C) 1999-2004 Brian Paul.
-        GLOD Copyright (C) 2003-04 Jonathan Cohen, Nat Duca, Chris Niski, Johns Hopkins University, et David Luebke, Brenden Schubert, University of Virginia.
         google-perftools Copyright (c) 2005, Google Inc.
         Havok.com(TM) Copyright (C) 1999-2001, Telekinesys Research Limited.
         jpeg2000 Copyright (C) 2001, David Taubman, The University of New South Wales (UNSW)
diff --git a/indra/newview/skins/default/xui/fr/floater_facebook.xml b/indra/newview/skins/default/xui/fr/floater_facebook.xml
index f5097e7a8800614b321a4fda7b6a214ca1f70c01..f6e8696e53fbfb1b0a9781a4802a42cb9c3d3ea6 100644
--- a/indra/newview/skins/default/xui/fr/floater_facebook.xml
+++ b/indra/newview/skins/default/xui/fr/floater_facebook.xml
@@ -10,6 +10,6 @@
 		Erreur
 	</text>
 	<text name="connection_loading_text">
-		Chargement...
+		En cours de chargement...
 	</text>
 </floater>
diff --git a/indra/newview/skins/default/xui/fr/floater_preview_texture.xml b/indra/newview/skins/default/xui/fr/floater_preview_texture.xml
index d63d9903ec301a92098240d7ca2547692ddba4d0..46703fe612d0f9cee78ad39716fdb5d2556f0cca 100644
--- a/indra/newview/skins/default/xui/fr/floater_preview_texture.xml
+++ b/indra/newview/skins/default/xui/fr/floater_preview_texture.xml
@@ -6,42 +6,23 @@
 	<floater.string name="Copy">
 		Copier dans l&apos;inventaire
 	</floater.string>
-	<text name="desc txt">
-		Description :
-	</text>
-	<text name="dimensions">
-		[WIDTH]px x [HEIGHT]px
-	</text>
-	<text name="aspect_ratio">
-		Rapport d&apos;aspect fixe
-	</text>
-	<combo_box name="combo_aspect_ratio" tool_tip="Prévisualiser avec un rapport d&apos;aspect fixe">
-		<combo_item name="Unconstrained">
-			Sans contraintes
-		</combo_item>
-		<combo_item name="1:1" tool_tip="Logo du groupe ou profil dans la vie réelle">
-			1:1
-		</combo_item>
-		<combo_item name="4:3" tool_tip="Profil [SECOND_LIFE]">
-			4:3
-		</combo_item>
-		<combo_item name="10:7" tool_tip="Petites annonces, repères">
-			10:7
-		</combo_item>
-		<combo_item name="3:2" tool_tip="À propos du terrain">
-			3:2
-		</combo_item>
-		<combo_item name="16:10">
-			16:10
-		</combo_item>
-		<combo_item name="16:9" tool_tip="Favoris du profil">
-			16:9
-		</combo_item>
-		<combo_item name="2:1">
-			2:1
-		</combo_item>
-	</combo_box>
-	<button label="OK" name="Keep"/>
-	<button label="Jeter" name="Discard"/>
-	<button label="Enregistrer sous" name="save_tex_btn"/>
+	<layout_stack name="preview_stack">
+		<layout_panel name="texture_panel">
+			<text name="desc txt">
+				Description :
+			</text>
+			<text name="dimensions">
+				[WIDTH]px x [HEIGHT]px
+			</text>
+			<text name="aspect_ratio">
+				Rapport d&apos;aspect fixe
+			</text>
+			<combo_box name="combo_aspect_ratio" tool_tip="Prévisualiser avec un rapport d&apos;aspect fixe"/>
+		</layout_panel>
+		<layout_panel name="buttons_panel">
+			<button label="OK" name="Keep"/>
+			<button label="Jeter" name="Discard"/>
+			<button label="Enregistrer sous" name="save_tex_btn"/>
+		</layout_panel>
+	</layout_stack>
 </floater>
diff --git a/indra/newview/skins/default/xui/fr/floater_profile.xml b/indra/newview/skins/default/xui/fr/floater_profile.xml
new file mode 100644
index 0000000000000000000000000000000000000000..c4af79e946a9049b7eb9e23cd0c2dc3b29aa9b72
--- /dev/null
+++ b/indra/newview/skins/default/xui/fr/floater_profile.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<floater name="avatarinfo" title="Profil">
+	<panel name="panel_profile_view">
+		<tab_container name="panel_profile_tabs">
+			<panel label="Second Life" name="panel_profile_secondlife"/>
+			<panel label="Web" name="panel_profile_web"/>
+			<panel label="Centres d&apos;intérêt" name="panel_profile_interests"/>
+			<panel label="Favoris" name="panel_profile_picks"/>
+			<panel label="Petite annonce" name="panel_profile_classifieds"/>
+			<panel label="Vie réelle" name="panel_profile_firstlife"/>
+			<panel label="Remarques" name="panel_profile_notes"/>
+		</tab_container>
+		<button label="OK" name="ok_btn" tool_tip="Enregistrer les changements apportés au profil et fermer"/>
+		<button label="Annuler" label_selected="Annuler" name="cancel_btn"/>
+	</panel>
+</floater>
diff --git a/indra/newview/skins/default/xui/fr/floater_snapshot.xml b/indra/newview/skins/default/xui/fr/floater_snapshot.xml
index 8eb05dd945149f6bb5bc91c82ac97b2fcc8ce1bc..adb98a68d2c26d245de1c4027da038db5df28070 100644
--- a/indra/newview/skins/default/xui/fr/floater_snapshot.xml
+++ b/indra/newview/skins/default/xui/fr/floater_snapshot.xml
@@ -6,6 +6,9 @@
 	<string name="postcard_progress_str">
 		Envoi par e-mail
 	</string>
+	<string name="facebook_progress_str">
+		Publication sur Facebook
+	</string>
 	<string name="profile_progress_str">
 		Publication
 	</string>
@@ -15,6 +18,9 @@
 	<string name="local_progress_str">
 		Enregistrement sur l&apos;ordinateur
 	</string>
+	<string name="facebook_succeeded_str">
+		Image chargée
+	</string>
 	<string name="profile_succeeded_str">
 		Image chargée
 	</string>
@@ -27,6 +33,9 @@
 	<string name="local_succeeded_str">
 		Enregistrement sur l&apos;ordinateur effectué !
 	</string>
+	<string name="facebook_failed_str">
+		Échec de chargement de l&apos;image dans votre journal Facebook.
+	</string>
 	<string name="profile_failed_str">
 		Échec de chargement de l&apos;image sur le flux de votre profil.
 	</string>
diff --git a/indra/newview/skins/default/xui/fr/menu_name_field.xml b/indra/newview/skins/default/xui/fr/menu_name_field.xml
new file mode 100644
index 0000000000000000000000000000000000000000..6c3fba41101fb108180f4c8a9fc6b416e5e6e1e8
--- /dev/null
+++ b/indra/newview/skins/default/xui/fr/menu_name_field.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<toggleable_menu name="CopyMenu">
+	<menu_item_call label="Copier le Nom d&apos;affichage" name="copy_display"/>
+	<menu_item_call label="Copier le  Nom de l&apos;agent" name="copy_name"/>
+	<menu_item_call label="Copier l&apos;ID de l&apos;agent" name="copy_id"/>
+</toggleable_menu>
diff --git a/indra/newview/skins/default/xui/fr/notifications.xml b/indra/newview/skins/default/xui/fr/notifications.xml
index e84de375d803e71039ced088751028b31c86dc60..09905f4e5d89463db5343fdae7064a3e221ae98c 100644
--- a/indra/newview/skins/default/xui/fr/notifications.xml
+++ b/indra/newview/skins/default/xui/fr/notifications.xml
@@ -2683,6 +2683,9 @@ Veuillez sélectionner un terrain plus petit.
 	<notification name="SystemMessage">
 		[MESSAGE]
 	</notification>
+	<notification name="FacebookConnect">
+		[MESSAGE]
+	</notification>
 	<notification name="FlickrConnect">
 		[MESSAGE]
 	</notification>
diff --git a/indra/newview/skins/default/xui/fr/panel_edit_classified.xml b/indra/newview/skins/default/xui/fr/panel_edit_classified.xml
index 7b58f2e82584a53d9a4617fca214927b4d743f6d..b892d25f264759d02191389a1d23636a93b27a99 100644
--- a/indra/newview/skins/default/xui/fr/panel_edit_classified.xml
+++ b/indra/newview/skins/default/xui/fr/panel_edit_classified.xml
@@ -46,7 +46,7 @@
 			<layout_panel name="save_changes_btn_lp">
 				<button label="[LABEL]" name="save_changes_btn"/>
 			</layout_panel>
-			<layout_panel name="show_on_map_btn_lp">
+			<layout_panel name="cancel_btn_lp">
 				<button label="Annuler" name="cancel_btn"/>
 			</layout_panel>
 		</layout_stack>
diff --git a/indra/newview/skins/default/xui/fr/panel_facebook_friends.xml b/indra/newview/skins/default/xui/fr/panel_facebook_friends.xml
index 319737a2afb6312b4389d3d5d908cfb3400dd60f..0e36c2092c89b231e291386940ad070680d3424a 100644
--- a/indra/newview/skins/default/xui/fr/panel_facebook_friends.xml
+++ b/indra/newview/skins/default/xui/fr/panel_facebook_friends.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <panel name="panel_facebook_friends">
-	<string name="facebook_friends_empty" value="Vous n&apos;avez actuellement aucun ami Facebook qui est également résident de Second Life. Invitez vos amis Facebook à rejoindre Second Life !"/>
+	<string name="facebook_friends_empty" value="Vous n&apos;avez actuellement aucun ami Facebook qui est également résident de Second Life. Invitez vos amis Facebook à rejoindre Second Life aujourd&apos;hui !"/>
 	<string name="facebook_friends_no_connected" value="Vous n&apos;êtes pas connecté(e) à Facebook. Allez à l&apos;onglet Statut pour vous connecter et activer cette fonctionnalité."/>
 	<accordion name="friends_accordion">
 		<accordion_tab name="tab_second_life_friends" title="Amis SL"/>
diff --git a/indra/newview/skins/default/xui/fr/panel_facebook_photo.xml b/indra/newview/skins/default/xui/fr/panel_facebook_photo.xml
index 3236f35b5586a9219f9f4fb234b7f6017532ee7f..cc4045bc740354ba7d684a5a1a06df4a36f05d10 100644
--- a/indra/newview/skins/default/xui/fr/panel_facebook_photo.xml
+++ b/indra/newview/skins/default/xui/fr/panel_facebook_photo.xml
@@ -4,14 +4,14 @@
 		<combo_box.item label="Fenêtre actuelle" name="CurrentWindow"/>
 		<combo_box.item label="640 x 480" name="640x480"/>
 		<combo_box.item label="800 x 600" name="800x600"/>
-		<combo_box.item label="1 024 x 768" name="1024x768"/>
-		<combo_box.item label="1 200 x 630" name="1200x630"/>
+		<combo_box.item label="1024 x 768" name="1024x768"/>
+		<combo_box.item label="1200 x 630" name="1200x630"/>
 	</combo_box>
-	<combo_box name="filters_combobox" tool_tip="Filtres d&apos;image">
+	<combo_box name="filters_combobox" tool_tip="Filtres d’image">
 		<combo_box.item label="Aucun filtre" name="NoFilter"/>
 	</combo_box>
 	<button label="Actualiser" name="new_snapshot_btn" tool_tip="Cliquer pour actualiser"/>
-	<button label="Aperçu" name="big_preview_btn" tool_tip="Cliquer pour activer/désactiver l&apos;aperçu"/>
+	<button label="Aperçu" name="big_preview_btn" tool_tip="Cliquer pour basculer l&apos;aperçu"/>
 	<text name="caption_label">
 		Commentaire (facultatif) :
 	</text>
diff --git a/indra/newview/skins/default/xui/fr/panel_facebook_status.xml b/indra/newview/skins/default/xui/fr/panel_facebook_status.xml
index 9afa42d2aa1a38c642a2fdf8c39abefaf809750a..dc8e4b9ecc37b2bcd3696499d44d24366c09fd68 100644
--- a/indra/newview/skins/default/xui/fr/panel_facebook_status.xml
+++ b/indra/newview/skins/default/xui/fr/panel_facebook_status.xml
@@ -6,7 +6,7 @@
 		Pas connecté(e) à Facebook.
 	</text>
 	<panel name="panel_buttons">
-		<button label="Connexion..." name="connect_btn"/>
+		<button label="Connexion en cours..." name="connect_btn"/>
 		<button label="Déconnexion" name="disconnect_btn"/>
 		<text name="account_learn_more_label">
 			[http://community.secondlife.com/t5/English-Knowledge-Base/Second-Life-Share-Facebook/ta-p/2149711 Apprenez comment publier sur Facebook]
diff --git a/indra/newview/skins/default/xui/fr/panel_group_list_item_short.xml b/indra/newview/skins/default/xui/fr/panel_group_list_item_short.xml
new file mode 100644
index 0000000000000000000000000000000000000000..b1b32af7c68d3d160c52be8c48444f5fa2af2531
--- /dev/null
+++ b/indra/newview/skins/default/xui/fr/panel_group_list_item_short.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="group_list_item">
+	<text name="group_name" value="Inconnu"/>
+	<button name="info_btn" tool_tip="En savoir plus"/>
+	<button name="profile_btn" tool_tip="Voir le profil"/>
+</panel>
diff --git a/indra/newview/skins/default/xui/fr/panel_me.xml b/indra/newview/skins/default/xui/fr/panel_me.xml
deleted file mode 100644
index 56769862280c17ecfaca1ddf7701d33d0e07725c..0000000000000000000000000000000000000000
--- a/indra/newview/skins/default/xui/fr/panel_me.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<panel label="Mon profil" name="panel_me">
-	<panel label="MES FAVORIS" name="panel_picks"/>
-</panel>
diff --git a/indra/newview/skins/default/xui/fr/panel_people.xml b/indra/newview/skins/default/xui/fr/panel_people.xml
index 3be6bae52a5958ab7934186945538b81c92a02b7..e096b5cfe0fd4bc3b1c46d9fcbc6ffb1bd2e2814 100644
--- a/indra/newview/skins/default/xui/fr/panel_people.xml
+++ b/indra/newview/skins/default/xui/fr/panel_people.xml
@@ -40,6 +40,7 @@ Pour rechercher des résidents avec qui passer du temps, utilisez [secondlife://
 			<accordion name="friends_accordion">
 				<accordion_tab name="tab_online" title="En ligne"/>
 				<accordion_tab name="tab_all" title="Tout"/>
+				<accordion_tab name="tab_suggested_friends" title="Personnes avec lesquelles vous aimeriez peut-être devenir ami(e)"/>
 			</accordion>
 		</panel>
 		<panel label="GROUPES" name="groups_panel">
diff --git a/indra/newview/skins/default/xui/fr/panel_profile_classified.xml b/indra/newview/skins/default/xui/fr/panel_profile_classified.xml
new file mode 100644
index 0000000000000000000000000000000000000000..b223684c60c1787fedb57da3ec009501b2dad55d
--- /dev/null
+++ b/indra/newview/skins/default/xui/fr/panel_profile_classified.xml
@@ -0,0 +1,110 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="panel_profile_classified">
+	<panel.string name="type_mature">
+		Modéré
+	</panel.string>
+	<panel.string name="type_pg">
+		Contenu Général
+	</panel.string>
+	<panel.string name="l$_price">
+		L$[PRICE]
+	</panel.string>
+	<panel.string name="click_through_text_fmt">
+		[TELEPORT] téléporter, [MAP] carte, [PROFILE] profile
+	</panel.string>
+	<panel.string name="date_fmt">
+		[mthnum,datetime,slt]/[day,datetime,slt]/[year,datetime,slt]
+	</panel.string>
+	<panel.string name="auto_renew_on">
+		Activé
+	</panel.string>
+	<panel.string name="auto_renew_off">
+		Désactivé
+	</panel.string>
+	<panel.string name="location_notice">
+		(mise à jour après enregistrement)
+	</panel.string>
+	<string name="publish_label">
+		Publier
+	</string>
+	<string name="save_label">
+		Enregistrer
+	</string>
+	<scroll_container name="profile_scroll">
+		<panel name="info_scroll_content_panel">
+			<icon label="" name="edit_icon" tool_tip="Cliquer pour sélectionner une image"/>
+			<layout_stack name="info_panel">
+				<layout_panel name="main_info_panel">
+					<text_editor name="classified_name">
+						[name]
+					</text_editor>
+					<text name="classified_location_label" value="Endroit :"/>
+					<text_editor name="classified_location" value="[loading...]"/>
+					<text name="content_type_label" value="Type de contenu :"/>
+					<text_editor name="content_type" value="[content type]"/>
+					<text name="category_label" value="Catégorie :"/>
+					<text_editor name="category" value="[category]"/>
+					<text name="creation_date_label" value="Date de création :"/>
+					<text_editor name="creation_date" tool_tip="Date de création" value="[date]"/>
+					<text name="price_for_listing_label" value="Coût de l&apos;annonce :"/>
+					<text_editor name="price_for_listing" tool_tip="Coût de l’annonce.">
+						[PRICE]
+					</text_editor>
+				</layout_panel>
+				<layout_panel name="clickthrough_layout_panel">
+					<text name="click_through_label" value="Clics :"/>
+					<text_editor name="click_through_text" tool_tip="Parcourir les données en cliquant" value="[clicks]"/>
+				</layout_panel>
+				<layout_panel name="auto_renew_layout_panel">
+					<text name="auto_renew_label" value="Renouv. auto :"/>
+					<text name="auto_renew" value="Activé"/>
+				</layout_panel>
+				<layout_panel name="descr_layout_panel">
+					<text name="classified_desc_label" value="Description :"/>
+					<text_editor name="classified_desc" value="[description]"/>
+				</layout_panel>
+			</layout_stack>
+			<panel name="edit_panel">
+				<text name="Name:">
+					Titre :
+				</text>
+				<text name="description_label">
+					Description :
+				</text>
+				<text name="location_label">
+					Endroit :
+				</text>
+				<text name="classified_location_edit">
+					en cours de chargement...
+				</text>
+				<button label="Définir sur l’emplacement actuel" name="set_to_curr_location_btn"/>
+				<text name="category_label" value="Catégorie :"/>
+				<text name="content_type_label" value="Type de contenu :"/>
+				<icons_combo_box label="Contenu Général" name="content_type_edit">
+					<icons_combo_box.item label="Contenu Modéré" name="mature_ci" value="Adulte"/>
+					<icons_combo_box.item label="Contenu Général" name="pg_ci" value="PG"/>
+				</icons_combo_box>
+				<check_box label="Renouvellement auto toutes les semaines" name="auto_renew_edit"/>
+				<text name="price_for_listing_edit_label" value="Coût de l&apos;annonce :"/>
+				<spinner label="L$" name="price_for_listing_edit" tool_tip="Coût de l’annonce." value="50"/>
+			</panel>
+		</panel>
+	</scroll_container>
+	<layout_stack name="edit_btns_pnl">
+		<layout_panel name="teleport_btn_lp">
+			<button label="Téléportation" name="teleport_btn"/>
+		</layout_panel>
+		<layout_panel name="map_btn_lp">
+			<button label="Carte" name="show_on_map_btn"/>
+		</layout_panel>
+		<layout_panel name="edit_btn_lp">
+			<button label="Modifier" name="edit_btn"/>
+		</layout_panel>
+		<layout_panel name="save_btn_lp">
+			<button label="[LABEL]" name="save_changes_btn"/>
+		</layout_panel>
+		<layout_panel name="cancel_btn_lp">
+			<button label="Annuler" name="cancel_btn"/>
+		</layout_panel>
+	</layout_stack>
+</panel>
diff --git a/indra/newview/skins/default/xui/fr/panel_profile_classifieds.xml b/indra/newview/skins/default/xui/fr/panel_profile_classifieds.xml
new file mode 100644
index 0000000000000000000000000000000000000000..adb3501422a260ec26d1328749912421ef2339da
--- /dev/null
+++ b/indra/newview/skins/default/xui/fr/panel_profile_classifieds.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel label="Petite annonce" name="panel_profile_classifieds">
+	<string name="no_classifieds" value="Pas de petites annonces"/>
+	<button label="Nouveau..." name="new_btn"/>
+	<button label="Supprimer..." name="delete_btn"/>
+	<text name="classifieds_panel_text">
+		En cours de chargement...
+	</text>
+</panel>
diff --git a/indra/newview/skins/default/xui/es/floater_picks.xml b/indra/newview/skins/default/xui/fr/panel_profile_firstlife.xml
similarity index 50%
rename from indra/newview/skins/default/xui/es/floater_picks.xml
rename to indra/newview/skins/default/xui/fr/panel_profile_firstlife.xml
index 255aa5dcdc1ebc1f649027a4373fa03e8ad4d0a0..0f65090209a7dcdb8d28c2dfd86b93adbb01443b 100644
--- a/indra/newview/skins/default/xui/es/floater_picks.xml
+++ b/indra/newview/skins/default/xui/fr/panel_profile_firstlife.xml
@@ -1,2 +1,2 @@
 <?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<floater name="floater_picks" title="Destacados"/>
+<panel label="Profil" name="panel_profile_firstlife"/>
diff --git a/indra/newview/skins/default/xui/fr/panel_profile_interests.xml b/indra/newview/skins/default/xui/fr/panel_profile_interests.xml
new file mode 100644
index 0000000000000000000000000000000000000000..e8212817d2168ef634decff93d4c08c6e2a3d28b
--- /dev/null
+++ b/indra/newview/skins/default/xui/fr/panel_profile_interests.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel label="Centres d&apos;intérêt" name="panel_profile_interests">
+	<text name="I Want To:">
+		Je veux :
+	</text>
+	<check_box label="Construire" name="chk0"/>
+	<check_box label="Explorer" name="chk1"/>
+	<check_box label="Rencontrer" name="chk2"/>
+	<check_box label="Être recruté" name="chk6"/>
+	<check_box label="Grouper" name="chk3"/>
+	<check_box label="Acheter" name="chk4"/>
+	<check_box label="Vendre" name="chk5"/>
+	<check_box label="Louer" name="chk7"/>
+	<line_editor name="want_to_edit">
+		(en cours de chargement...)
+	</line_editor>
+	<text name="Skills:">
+		Compétences :
+	</text>
+	<check_box label="Textures" name="schk0"/>
+	<check_box label="Architecture" name="schk1"/>
+	<check_box label="Modèle" name="schk3"/>
+	<check_box label="Planification des événements" name="schk2"/>
+	<check_box label="Langage de scripts" name="schk4"/>
+	<check_box label="Personnages personnalisés" name="schk5"/>
+	<line_editor name="skills_edit">
+		(en cours de chargement...)
+	</line_editor>
+	<text name="Languages:">
+		Langues :
+	</text>
+	<line_editor name="languages_edit">
+		(en cours de chargement...)
+	</line_editor>
+</panel>
diff --git a/indra/newview/skins/default/xui/fr/panel_profile_notes.xml b/indra/newview/skins/default/xui/fr/panel_profile_notes.xml
new file mode 100644
index 0000000000000000000000000000000000000000..03fb37d72b40fa93ee99be6e2ef2b1c489320169
--- /dev/null
+++ b/indra/newview/skins/default/xui/fr/panel_profile_notes.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel label="Notes &amp; respect de la vie privée" name="panel_notes">
+	<text name="status_message" value="Notes personnelles sur cet avatar:"/>
+	<text name="status_message2" value="Autoriser cet avatar à :"/>
+	<check_box label="Voir quand je suis en ligne" name="status_check"/>
+	<check_box label="Me trouver sur la carte du monde" name="map_check"/>
+	<check_box label="Modifier, supprimer ou prendre mes objets" name="objects_check"/>
+</panel>
diff --git a/indra/newview/skins/default/xui/fr/panel_profile_pick.xml b/indra/newview/skins/default/xui/fr/panel_profile_pick.xml
new file mode 100644
index 0000000000000000000000000000000000000000..017fcff88abfd4095c22a4d3f0cb86559eb9f8f9
--- /dev/null
+++ b/indra/newview/skins/default/xui/fr/panel_profile_pick.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="panel_pick_info">
+	<panel.string name="location_notice">
+		(mise à jour après enregistrement)
+	</panel.string>
+	<line_editor name="pick_location">
+		En cours de chargement...
+	</line_editor>
+	<button label="Téléportation" name="teleport_btn"/>
+	<button label="Voir sur la carte" name="show_on_map_btn"/>
+	<button label="Définir l&apos;emplacement" name="set_to_curr_location_btn" tool_tip="Définir sur l’emplacement actuel"/>
+	<button label="Enregistrer les favoris" name="save_changes_btn"/>
+</panel>
diff --git a/indra/newview/skins/default/xui/fr/panel_profile_picks.xml b/indra/newview/skins/default/xui/fr/panel_profile_picks.xml
new file mode 100644
index 0000000000000000000000000000000000000000..1644722813bf6e02d29820f7343e95ec2b7116a1
--- /dev/null
+++ b/indra/newview/skins/default/xui/fr/panel_profile_picks.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel label="Favoris" name="panel_picks">
+	<string name="no_picks" value="Pas de favoris"/>
+	<text name="Tell everyone about your favorite places in Second Life.">
+		Faites connaître aux autres résidents vos endroits favoris dans Second Life.
+	</text>
+	<button label="Nouveau..." name="new_btn"/>
+	<button label="Supprimer..." name="delete_btn"/>
+	<text name="picks_panel_text">
+		En cours de chargement...
+	</text>
+</panel>
diff --git a/indra/newview/skins/default/xui/fr/panel_profile_secondlife.xml b/indra/newview/skins/default/xui/fr/panel_profile_secondlife.xml
new file mode 100644
index 0000000000000000000000000000000000000000..de9cbf6dcee81f757cdfe1328bb9237f3c345315
--- /dev/null
+++ b/indra/newview/skins/default/xui/fr/panel_profile_secondlife.xml
@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel label="Profil" name="panel_profile">
+	<string name="status_online">
+		Actuellement connecté
+	</string>
+	<string name="status_offline">
+		Actuellement déconnecté
+	</string>
+	<string name="CaptionTextAcctInfo">
+		[ACCTTYPE]
+[PAYMENTINFO]
+	</string>
+	<string name="payment_update_link_url">
+		http://www.secondlife.com/account/billing.php?lang=en
+	</string>
+	<string name="partner_edit_link_url">
+		http://www.secondlife.com/account/partners.php?lang=en
+	</string>
+	<string name="my_account_link_url" value="http://secondlife.com/account"/>
+	<string name="no_partner_text" value="Aucun"/>
+	<string name="no_group_text" value="Aucun"/>
+	<string name="RegisterDateFormat">
+		[REG_DATE]
+	</string>
+	<string name="name_text_args">
+		[NAME]
+	</string>
+	<string name="display_name_text_args">
+		[DISPLAY_NAME]
+	</string>
+	<string name="FSDev" value="Développeur"/>
+	<string name="FSSupp" value="Assistance"/>
+	<string name="FSQualityAssurance" value="Suivi des anomalies"/>
+	<string name="FSGW" value="Portail"/>
+	<text name="name_label" value="Nom :"/>
+	<button label="Nom :" name="set_name" tool_tip="Définir un nom d&apos;affichage"/>
+	<panel name="name_holder">
+		<text_editor name="complete_name" value="(en cours de chargement...)"/>
+	</panel>
+	<layout_stack name="imagepositioner">
+		<layout_panel name="label_stack">
+			<text name="status" value="Statut inconnu"/>
+			<text name="label" value="Date de naissance dans Second Life :"/>
+			<text name="label2" value="Compte :"/>
+			<text name="partner_label" value="Partenaire :"/>
+		</layout_panel>
+	</layout_stack>
+	<text name="Groups:" value="Groupes :"/>
+	<button label="+" label_selected="+" name="group_invite" tool_tip="Inviter dans le groupe"/>
+	<layout_stack name="aboutpositioner">
+		<layout_panel name="about_stack">
+			<text name="About:" value="À propos :"/>
+		</layout_panel>
+		<layout_panel name="give_stack">
+			<text name="Give item:" value="Donner des objets :"/>
+			<text name="Give inventory" tool_tip="Placer les objets de l&apos;inventaire ici pour les donner à cette personne">
+				Placer les objets de l&apos;inventaire ici.
+			</text>
+		</layout_panel>
+	</layout_stack>
+	<layout_stack name="buttonstack">
+		<layout_panel name="left_buttonstack">
+			<button label="Situer sur la carte" label_selected="Situer sur la carte" name="show_on_map_btn" tool_tip="Localiser le Résident sur la carte"/>
+			<button label="Payer" label_selected="Payer" name="pay" tool_tip="Payer le résident"/>
+		</layout_panel>
+		<layout_panel name="middle_buttonstack">
+			<button label="Proposer de téléporter" label_selected="Proposer de téléporter" name="teleport" tool_tip="Proposer une téléportation au Résident"/>
+			<button label="Message instantané" label_selected="Message instantané" name="im" tool_tip="Ouvrir une session IM."/>
+		</layout_panel>
+		<layout_panel name="right_buttonstack">
+			<button label="Ajouter un ami" label_selected="Ajouter un ami" name="add_friend" tool_tip="Proposer à ce résident de devenir votre ami"/>
+			<button label="Bloquer" name="block" tool_tip="Bloquer ce Résident"/>
+			<button label="Débloquer" name="unblock" tool_tip="Débloquer ce Résident"/>
+		</layout_panel>
+	</layout_stack>
+	<check_box label="Afficher avec la recherche" name="show_in_search_checkbox"/>
+</panel>
diff --git a/indra/newview/skins/default/xui/fr/panel_profile_web.xml b/indra/newview/skins/default/xui/fr/panel_profile_web.xml
new file mode 100644
index 0000000000000000000000000000000000000000..70e145ade9ad0edc94575260d92e7af587a267b6
--- /dev/null
+++ b/indra/newview/skins/default/xui/fr/panel_profile_web.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel label="Web" name="panel_profile_web">
+	<panel.string name="LoadTime" value="Heure de chargement : [TIME] secondes"/>
+	<line_editor name="url_edit">
+		(en cours de chargement..)
+	</line_editor>
+	<flyout_button label="Charger" name="load" tool_tip="Charger ce profil avec le navigateur Web incorporé">
+		<flyout_button.item label="Ouvrir dans mon navigateur Web" name="open_item"/>
+		<flyout_button.item label="Ouvrir dans un navigateur externe" name="home_item"/>
+	</flyout_button>
+	<button name="web_profile_popout_btn" tool_tip="Profil de fenêtres web"/>
+</panel>
diff --git a/indra/newview/skins/default/xui/fr/panel_region_terrain.xml b/indra/newview/skins/default/xui/fr/panel_region_terrain.xml
index 97f486d3a3dd0969abe776f12a0c67d7d9c80b0e..bbab00ca24643f3a8f462f8e9fdcd8987796cbaa 100644
--- a/indra/newview/skins/default/xui/fr/panel_region_terrain.xml
+++ b/indra/newview/skins/default/xui/fr/panel_region_terrain.xml
@@ -12,8 +12,8 @@ terrain" name="terrain_raise_spin"/>
 	<spinner bottom_delta="-34" label="Limite d&apos;abaissement 
 du terrain" name="terrain_lower_spin"/>
 	<text name="detail_texture_text">
-		Textures du terrain (fichiers .tga 512 x 512, 24 bit requis)
-	</text>
+    Textures du terrain (fichiers .tga 1024 x 1024, 24 bit requis)
+  </text>
 	<text name="height_text_lbl">
 		1 (Bas)
 	</text>
diff --git a/indra/newview/skins/default/xui/fr/strings.xml b/indra/newview/skins/default/xui/fr/strings.xml
index 9fde703d6cd3ed105ffd77b4548f32ce9eb7b7a8..21825c6b2fd4910f5d9f0e271d89401f7d397acd 100644
--- a/indra/newview/skins/default/xui/fr/strings.xml
+++ b/indra/newview/skins/default/xui/fr/strings.xml
@@ -187,7 +187,7 @@ Voice Server Version: [VOICE_VERSION]
 	<string name="LoginFailedNoNetwork">
 		Erreur réseau : impossible d&apos;établir la connexion. Veuillez vérifier votre connexion réseau.
 	</string>
-	<string name="LoginFailed">
+	<string name="LoginFailedHeader">
 		Échec de la connexion.
 	</string>
 	<string name="Quit">
@@ -357,6 +357,24 @@ Veuillez réessayer de vous connecter dans une minute.
 	<string name="TestingDisconnect">
 		Test de déconnexion du client
 	</string>
+	<string name="SocialFacebookConnecting">
+		Connexion à Facebook…
+	</string>
+	<string name="SocialFacebookPosting">
+		Publication…
+	</string>
+	<string name="SocialFacebookDisconnecting">
+		Déconnexion de Facebook…
+	</string>
+	<string name="SocialFacebookErrorConnecting">
+		Un problème est survenu lors de la connexion à Facebook.
+	</string>
+	<string name="SocialFacebookErrorPosting">
+		Un problème est survenu lors de la publication sur Facebook.
+	</string>
+	<string name="SocialFacebookErrorDisconnecting">
+		Un problème est survenu lors de la déconnexion à Facebook.
+	</string>
 	<string name="SocialFlickrConnecting">
 		Connexion à Flickr...
 	</string>
@@ -674,9 +692,6 @@ peuvent être joints aux notes.
 	<string name="GroupNameNone">
 		(aucun)
 	</string>
-	<string name="AvalineCaller">
-		Appelant Avaline [ORDER]
-	</string>
 	<string name="AssetErrorNone">
 		Aucune erreur
 	</string>
@@ -2579,9 +2594,21 @@ Si vous continuez de recevoir ce message, contactez l’assistance Second Life 
 	<string name="NoPicksClassifiedsText">
 		Vous n&apos;avez pas créé de favoris ni de petites annonces Cliquez sur le bouton Plus pour créer un favori ou une petite annonce.
 	</string>
+	<string name="NoPicksText">
+		Vous n&apos;avez pas créé de favoris Cliquer sur le bouton Nouveau pour créer un favori
+	</string>
+	<string name="NoClassifiedsText">
+		Vous n&apos;avez pas créé de petites annonces Cliquer sur le bouton Nouveau pour créer une petite annonce.
+	</string>
 	<string name="NoAvatarPicksClassifiedsText">
 		L&apos;utilisateur n&apos;a ni favoris ni petites annonces.
 	</string>
+	<string name="NoAvatarPicksText">
+		L&apos;utilisateur n&apos;a pas de favoris
+	</string>
+	<string name="NoAvatarClassifiedsText">
+		L&apos;utilisateur n&apos;a pas de petites annonces
+	</string>
 	<string name="PicksClassifiedsLoadingText">
 		Chargement...
 	</string>
@@ -4559,6 +4586,9 @@ Si ce message persiste, veuillez aller sur la page [SUPPORT_SITE].
 	<string name="share_alert">
 		Faire glisser les objets de l&apos;inventaire ici
 	</string>
+	<string name="facebook_post_success">
+		Vous avez publié sur Facebook.
+	</string>
 	<string name="flickr_post_success">
 		Vous avez publié sur Flickr.
 	</string>
@@ -5102,7 +5132,7 @@ Veuillez vous reporter à http://status.secondlifegrid.net afin de déterminer s
 	<string name="PremiumMembership">
 		Premium
 	</string>
-	<string name="Premium PlusMembership">
+	<string name="Premium_PlusMembership">
 		Premium Plus
 	</string>
 	<string name="DeleteItems">
diff --git a/indra/newview/skins/default/xui/it/floater_about.xml b/indra/newview/skins/default/xui/it/floater_about.xml
index 9603238b66b0edf127272552ed851611c454b430..edb334e13ee83ed56959be173743a2de8f9fe579 100644
--- a/indra/newview/skins/default/xui/it/floater_about.xml
+++ b/indra/newview/skins/default/xui/it/floater_about.xml
@@ -19,7 +19,6 @@ con contributi open source da:</text>
         expat Copyright (C) 1998, 1999, 2000 Thai Open Source Software Center Ltd.
         FreeType Copyright (C) 1996-2002, 2006 David Turner, Robert Wilhelm e Werner Lemberg.
         GL Copyright (C) 1999-2004 Brian Paul.
-        GLOD Copyright (C) 2003-04 Jonathan Cohen, Nat Duca, Chris Niski, Johns Hopkins University e David Luebke, Brenden Schubert, University of Virginia.
         google-perftools Copyright (c) 2005, Google Inc.
         Havok.com(TM) Copyright (C) 1999-2001, Telekinesys Research Limited.
         jpeg2000 Copyright (C) 2001, David Taubman, The University of New South Wales (UNSW)
diff --git a/indra/newview/skins/default/xui/it/floater_preview_texture.xml b/indra/newview/skins/default/xui/it/floater_preview_texture.xml
index 8e8d020067b5ee86346ebeeecb0d190a239008c9..02f15b6b7be3c36a24286ec55b33a6e5d02d84fe 100644
--- a/indra/newview/skins/default/xui/it/floater_preview_texture.xml
+++ b/indra/newview/skins/default/xui/it/floater_preview_texture.xml
@@ -6,42 +6,23 @@
 	<floater.string name="Copy">
 		Copia nell&apos;Inventario
 	</floater.string>
-	<text name="desc txt">
-		Descrizione:
-	</text>
-	<text name="dimensions">
-		[WIDTH]px x [HEIGHT]px
-	</text>
-	<text name="aspect_ratio">
-		Antreprima rapporto di visualizzazione
-	</text>
-	<combo_box name="combo_aspect_ratio" tool_tip="Anteprima con rapporto di visualizzazione fisso">
-		<combo_item name="Unconstrained">
-			Libero
-		</combo_item>
-		<combo_item name="1:1" tool_tip="Logo del gruppo o profilo nel mondo reale">
-			1:1
-		</combo_item>
-		<combo_item name="4:3" tool_tip="Profilo [SECOND_LIFE]">
-			4:3
-		</combo_item>
-		<combo_item name="10:7" tool_tip="Annunci e inserzioni, punti di riferimento">
-			10:7
-		</combo_item>
-		<combo_item name="3:2" tool_tip="Informazioni sul terreno">
-			3:2
-		</combo_item>
-		<combo_item name="16:10">
-			16:10
-		</combo_item>
-		<combo_item name="16:9" tool_tip="Preferiti del Profilo">
-			16:9
-		</combo_item>
-		<combo_item name="2:1">
-			2:1
-		</combo_item>
-	</combo_box>
-	<button label="OK" name="Keep"/>
-	<button label="Elimina" name="Discard"/>
-	<button label="Salva con nome" name="save_tex_btn"/>
+	<layout_stack name="preview_stack">
+		<layout_panel name="texture_panel">
+			<text name="desc txt">
+				Descrizione:
+			</text>
+			<text name="dimensions">
+				[WIDTH]px x [HEIGHT]px
+			</text>
+			<text name="aspect_ratio">
+				Antreprima rapporto di visualizzazione
+			</text>
+			<combo_box name="combo_aspect_ratio" tool_tip="Anteprima con rapporto di visualizzazione fisso"/>
+		</layout_panel>
+		<layout_panel name="buttons_panel">
+			<button label="OK" name="Keep"/>
+			<button label="Elimina" name="Discard"/>
+			<button label="Salva con nome" name="save_tex_btn"/>
+		</layout_panel>
+	</layout_stack>
 </floater>
diff --git a/indra/newview/skins/default/xui/it/floater_profile.xml b/indra/newview/skins/default/xui/it/floater_profile.xml
new file mode 100644
index 0000000000000000000000000000000000000000..7e23f9bbbba960c3d0a850883914451ae289fb7c
--- /dev/null
+++ b/indra/newview/skins/default/xui/it/floater_profile.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<floater name="avatarinfo" title="Profilo">
+	<panel name="panel_profile_view">
+		<tab_container name="panel_profile_tabs">
+			<panel label="Second Life" name="panel_profile_secondlife"/>
+			<panel label="Web" name="panel_profile_web"/>
+			<panel label="Interessi" name="panel_profile_interests"/>
+			<panel label="Preferiti" name="panel_profile_picks"/>
+			<panel label="Annuncio" name="panel_profile_classifieds"/>
+			<panel label="Vita reale" name="panel_profile_firstlife"/>
+			<panel label="Note" name="panel_profile_notes"/>
+		</tab_container>
+		<button label="OK" name="ok_btn" tool_tip="Salva modifiche al profilo e chiudi"/>
+		<button label="Annulla" label_selected="Annulla" name="cancel_btn"/>
+	</panel>
+</floater>
diff --git a/indra/newview/skins/default/xui/it/floater_snapshot.xml b/indra/newview/skins/default/xui/it/floater_snapshot.xml
index d21c206f6fc11a1f7475bcfc4a22f3e8e45ce929..c9f71a167e9ee502051b056bb103dda2188b10a8 100644
--- a/indra/newview/skins/default/xui/it/floater_snapshot.xml
+++ b/indra/newview/skins/default/xui/it/floater_snapshot.xml
@@ -6,6 +6,9 @@
 	<string name="postcard_progress_str">
 		Invio e-mail in corso
 	</string>
+	<string name="facebook_progress_str">
+		Pubblicazione su Facebook in corso
+	</string>
 	<string name="profile_progress_str">
 		Caricamento post
 	</string>
@@ -15,6 +18,9 @@
 	<string name="local_progress_str">
 		Salvataggio sul computer in corso
 	</string>
+	<string name="facebook_succeeded_str">
+		Immagine caricata
+	</string>
 	<string name="profile_succeeded_str">
 		Immagine caricata
 	</string>
@@ -27,6 +33,9 @@
 	<string name="local_succeeded_str">
 		Salvato sul computer.
 	</string>
+	<string name="facebook_failed_str">
+		Caricamento immagine sul diario di Facebook non riuscito.
+	</string>
 	<string name="profile_failed_str">
 		Caricamento immagine sul feed del profilo non riuscito.
 	</string>
diff --git a/indra/newview/skins/default/xui/it/menu_name_field.xml b/indra/newview/skins/default/xui/it/menu_name_field.xml
new file mode 100644
index 0000000000000000000000000000000000000000..9ac863323c6531803952570045444e707a1bee89
--- /dev/null
+++ b/indra/newview/skins/default/xui/it/menu_name_field.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<toggleable_menu name="CopyMenu">
+	<menu_item_call label="Copia Nome Visualizzato" name="copy_display"/>
+	<menu_item_call label="Copia Nome Agente" name="copy_name"/>
+	<menu_item_call label="Copia ID Agente" name="copy_id"/>
+</toggleable_menu>
diff --git a/indra/newview/skins/default/xui/it/notifications.xml b/indra/newview/skins/default/xui/it/notifications.xml
index 1c43013255a4244289ac4a5f210b23e1d5ab14b6..a69fa07c500b8a536b9e97de09effc9b13e8495d 100644
--- a/indra/newview/skins/default/xui/it/notifications.xml
+++ b/indra/newview/skins/default/xui/it/notifications.xml
@@ -2685,6 +2685,9 @@ Prova a selezionare una parte di terreno più piccola.
 	<notification name="SystemMessage">
 		[MESSAGE]
 	</notification>
+	<notification name="FacebookConnect">
+		[MESSAGE]
+	</notification>
 	<notification name="FlickrConnect">
 		[MESSAGE]
 	</notification>
diff --git a/indra/newview/skins/default/xui/it/panel_edit_classified.xml b/indra/newview/skins/default/xui/it/panel_edit_classified.xml
index ad827696ffb3f918ae4d817130d64c85d873847c..57e422a25b4585500d2833343ec2fb141d7a9370 100644
--- a/indra/newview/skins/default/xui/it/panel_edit_classified.xml
+++ b/indra/newview/skins/default/xui/it/panel_edit_classified.xml
@@ -46,7 +46,7 @@
 			<layout_panel name="save_changes_btn_lp">
 				<button label="[LABEL]" name="save_changes_btn"/>
 			</layout_panel>
-			<layout_panel name="show_on_map_btn_lp">
+			<layout_panel name="cancel_btn_lp">
 				<button label="Annulla" name="cancel_btn"/>
 			</layout_panel>
 		</layout_stack>
diff --git a/indra/newview/skins/default/xui/it/panel_facebook_friends.xml b/indra/newview/skins/default/xui/it/panel_facebook_friends.xml
index c1c0489f884c8378f03a31def172eb685d06ed2a..28769a010f5cb002f08d7528fd383d2b6832dddd 100644
--- a/indra/newview/skins/default/xui/it/panel_facebook_friends.xml
+++ b/indra/newview/skins/default/xui/it/panel_facebook_friends.xml
@@ -1,12 +1,12 @@
 <?xml version="1.0" encoding="utf-8"?>
 <panel name="panel_facebook_friends">
-	<string name="facebook_friends_empty" value="Attualmente non hai amici su Facebook che sono anche residenti in Second Life. Invita i tuoi amici di Facebook a partecipare a Second Life!"/>
-	<string name="facebook_friends_no_connected" value="Attualmente non sei in collegamento con Facebook. Accedi alla scheda Stato per collegarti e attivare questa funzionalità."/>
+	<string name="facebook_friends_empty" value="Attualmente non hai amici su Facebook che sono anche residenti Second Life. Invita ora i tuoi amici di Facebook a unirsi a Second Life!"/>
+	<string name="facebook_friends_no_connected" value="Non sei connesso a Facebook. Accedi alla scheda Stato per collegarti e attivare questa funzionalità."/>
 	<accordion name="friends_accordion">
 		<accordion_tab name="tab_second_life_friends" title="Amici SL"/>
 		<accordion_tab name="tab_suggested_friends" title="Aggiungi queste persone come amici SL"/>
 	</accordion>
 	<text name="facebook_friends_status">
-		Non in collegamento con Facebook.
+		Non connesso a Facebook.
 	</text>
 </panel>
diff --git a/indra/newview/skins/default/xui/it/panel_facebook_photo.xml b/indra/newview/skins/default/xui/it/panel_facebook_photo.xml
index 044b8b616452fa5ce8530625053ce88bdf72e8f2..8d66f35c3c17115b0f804db026e0be6775d101c1 100644
--- a/indra/newview/skins/default/xui/it/panel_facebook_photo.xml
+++ b/indra/newview/skins/default/xui/it/panel_facebook_photo.xml
@@ -1,13 +1,13 @@
 <?xml version="1.0" encoding="utf-8"?>
 <panel name="panel_facebook_photo">
-	<combo_box name="resolution_combobox" tool_tip="Risoluzione immagini">
+	<combo_box name="resolution_combobox" tool_tip="Risoluzione immagine">
 		<combo_box.item label="Finestra attuale" name="CurrentWindow"/>
 		<combo_box.item label="640x480" name="640x480"/>
 		<combo_box.item label="800x600" name="800x600"/>
 		<combo_box.item label="1024x768" name="1024x768"/>
 		<combo_box.item label="1200x630" name="1200x630"/>
 	</combo_box>
-	<combo_box name="filters_combobox" tool_tip="Filtri immagini">
+	<combo_box name="filters_combobox" tool_tip="Filtri immagine">
 		<combo_box.item label="Nessun filtro" name="NoFilter"/>
 	</combo_box>
 	<button label="Aggiorna" name="new_snapshot_btn" tool_tip="Fai clic per aggiornare"/>
diff --git a/indra/newview/skins/default/xui/it/panel_facebook_status.xml b/indra/newview/skins/default/xui/it/panel_facebook_status.xml
index 9b5171043a00dddfe7e29ef73b25b8adc745dc02..7fb1cec78eebc4159a4ab4a68c814c0e8c5e2c5a 100644
--- a/indra/newview/skins/default/xui/it/panel_facebook_status.xml
+++ b/indra/newview/skins/default/xui/it/panel_facebook_status.xml
@@ -1,13 +1,13 @@
 <?xml version="1.0" encoding="utf-8"?>
 <panel name="panel_facebook_status">
-	<string name="facebook_connected" value="Sei in collegamento con Facebook come:"/>
-	<string name="facebook_disconnected" value="Non in collegamento con Facebook"/>
+	<string name="facebook_connected" value="Sei connesso a Facebook come:"/>
+	<string name="facebook_disconnected" value="Non connesso a Facebook"/>
 	<text name="account_caption_label">
-		Non in collegamento con Facebook.
+		Non connesso a Facebook.
 	</text>
 	<panel name="panel_buttons">
-		<button label="Collegamento..." name="connect_btn"/>
-		<button label="Interrompi collegamento" name="disconnect_btn"/>
+		<button label="Connessione in corso..." name="connect_btn"/>
+		<button label="Disconnetti" name="disconnect_btn"/>
 		<text name="account_learn_more_label">
 			[http://community.secondlife.com/t5/English-Knowledge-Base/Second-Life-Share-Facebook/ta-p/2149711 Come pubblicare su Facebook]
 		</text>
diff --git a/indra/newview/skins/default/xui/it/panel_group_general.xml b/indra/newview/skins/default/xui/it/panel_group_general.xml
index 60028e6098da188e01290c70c39a69a787afd322..168524d1ad909e0cc17d8b84707b02f11ef01e6a 100644
--- a/indra/newview/skins/default/xui/it/panel_group_general.xml
+++ b/indra/newview/skins/default/xui/it/panel_group_general.xml
@@ -46,7 +46,7 @@ Muovi il tuo mouse sopra le opzioni per maggiore aiuto.
 		<check_box label="Chiunque può aderire" name="open_enrollement" tool_tip="Imposta se questo gruppo permette ai nuovi membri di aderire senza essere invitati."/>
 		<check_box label="Quota di adesione" name="check_enrollment_fee" tool_tip="Imposta se richiedere una tassa d&apos;iscrizione per aderire al gruppo"/>
 		<spinner label="L$" left_delta="136" name="spin_enrollment_fee" tool_tip="I nuovi soci devono pagare questa tassa d&apos;iscrizione quando è selezionata." width="60"/>
-		<combo_box name="group_mature_check" tool_tip="Le categorie di accesso definiscono il tipo di contenuti e di comportamenti ammessi in un gruppo">
+		<combo_box name="group_mature_check" tool_tip="Determina se il tuo gruppo contiene informazioni contrassegnate come Moderate opppure no">
 			<combo_item name="select_mature">
 				- Seleziona categoria di accesso -
 			</combo_item>
diff --git a/indra/newview/skins/default/xui/it/panel_group_list_item_short.xml b/indra/newview/skins/default/xui/it/panel_group_list_item_short.xml
new file mode 100644
index 0000000000000000000000000000000000000000..72e644008c9f8be4eb31521682a38de96d571f3a
--- /dev/null
+++ b/indra/newview/skins/default/xui/it/panel_group_list_item_short.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="group_list_item">
+	<text name="group_name" value="Sconosciuto"/>
+	<button name="info_btn" tool_tip="Maggiori informazioni"/>
+	<button name="profile_btn" tool_tip="Vedi profilo"/>
+</panel>
diff --git a/indra/newview/skins/default/xui/it/panel_me.xml b/indra/newview/skins/default/xui/it/panel_me.xml
deleted file mode 100644
index a134f6f1decf8cb88e7169e2181dbeaa648394a4..0000000000000000000000000000000000000000
--- a/indra/newview/skins/default/xui/it/panel_me.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<panel label="Il mio profilo" name="panel_me">
-	<panel label="I MIEI PREFERITI" name="panel_picks"/>
-</panel>
diff --git a/indra/newview/skins/default/xui/it/panel_people.xml b/indra/newview/skins/default/xui/it/panel_people.xml
index 3df2368ae024a6f07ab47e6048ee7c3a1bdcf640..9eb93a26e556e1e2cc1e0b65c931f513f98c9258 100644
--- a/indra/newview/skins/default/xui/it/panel_people.xml
+++ b/indra/newview/skins/default/xui/it/panel_people.xml
@@ -40,6 +40,7 @@ Stai cercando persone da frequentare? Prova la [secondlife:///app/worldmap Mappa
 			<accordion name="friends_accordion">
 				<accordion_tab name="tab_online" title="Online"/>
 				<accordion_tab name="tab_all" title="Tutto"/>
+				<accordion_tab name="tab_suggested_friends" title="Persone che potresti voler aggiungere agli amici"/>
 			</accordion>
 		</panel>
 		<panel label="GRUPPI" name="groups_panel">
diff --git a/indra/newview/skins/default/xui/it/panel_profile_classified.xml b/indra/newview/skins/default/xui/it/panel_profile_classified.xml
new file mode 100644
index 0000000000000000000000000000000000000000..3c88fbe92fbfc90153aaaa2a80ebf66a2b82facb
--- /dev/null
+++ b/indra/newview/skins/default/xui/it/panel_profile_classified.xml
@@ -0,0 +1,110 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="panel_profile_classified">
+	<panel.string name="type_mature">
+		Moderato
+	</panel.string>
+	<panel.string name="type_pg">
+		Contenuto Generale
+	</panel.string>
+	<panel.string name="l$_price">
+		L$[PRICE]
+	</panel.string>
+	<panel.string name="click_through_text_fmt">
+		[TELEPORT] teletrasporto, [MAP] mappa, [PROFILE] profilo
+	</panel.string>
+	<panel.string name="date_fmt">
+		[mthnum,datetime,slt]/[day,datetime,slt]/[year,datetime,slt]
+	</panel.string>
+	<panel.string name="auto_renew_on">
+		Abilitato
+	</panel.string>
+	<panel.string name="auto_renew_off">
+		Disabilitato
+	</panel.string>
+	<panel.string name="location_notice">
+		(si aggiornerà dopo il salvataggio)
+	</panel.string>
+	<string name="publish_label">
+		Pubblica
+	</string>
+	<string name="save_label">
+		Salva
+	</string>
+	<scroll_container name="profile_scroll">
+		<panel name="info_scroll_content_panel">
+			<icon label="" name="edit_icon" tool_tip="Fai clic per selezionare un&apos;immagine"/>
+			<layout_stack name="info_panel">
+				<layout_panel name="main_info_panel">
+					<text_editor name="classified_name">
+						[name]
+					</text_editor>
+					<text name="classified_location_label" value="Posizione:"/>
+					<text_editor name="classified_location" value="[loading...]"/>
+					<text name="content_type_label" value="Tipo di contenuto:"/>
+					<text_editor name="content_type" value="[content type]"/>
+					<text name="category_label" value="Categoria:"/>
+					<text_editor name="category" value="[category]"/>
+					<text name="creation_date_label" value="Data di creazione:"/>
+					<text_editor name="creation_date" tool_tip="Data di creazione" value="[date]"/>
+					<text name="price_for_listing_label" value="Prezzo per inserzione:"/>
+					<text_editor name="price_for_listing" tool_tip="Prezzo per inserzione.">
+						[PRICE]
+					</text_editor>
+				</layout_panel>
+				<layout_panel name="clickthrough_layout_panel">
+					<text name="click_through_label" value="Clic:"/>
+					<text_editor name="click_through_text" tool_tip="Numero di clic" value="[clicks]"/>
+				</layout_panel>
+				<layout_panel name="auto_renew_layout_panel">
+					<text name="auto_renew_label" value="Rinnovo automatico:"/>
+					<text name="auto_renew" value="Abilitato"/>
+				</layout_panel>
+				<layout_panel name="descr_layout_panel">
+					<text name="classified_desc_label" value="Descrizione:"/>
+					<text_editor name="classified_desc" value="[description]"/>
+				</layout_panel>
+			</layout_stack>
+			<panel name="edit_panel">
+				<text name="Name:">
+					Titolo:
+				</text>
+				<text name="description_label">
+					Descrizione:
+				</text>
+				<text name="location_label">
+					Posizione:
+				</text>
+				<text name="classified_location_edit">
+					caricamento in corso...
+				</text>
+				<button label="Imposta come Luogo Attuale" name="set_to_curr_location_btn"/>
+				<text name="category_label" value="Categoria:"/>
+				<text name="content_type_label" value="Tipo di contenuto:"/>
+				<icons_combo_box label="Contenuto Generale" name="content_type_edit">
+					<icons_combo_box.item label="Contenuto Moderato" name="mature_ci" value="Per adulti"/>
+					<icons_combo_box.item label="Contenuto Generale" name="pg_ci" value="PG"/>
+				</icons_combo_box>
+				<check_box label="Rinnovo automatico ogni settimana" name="auto_renew_edit"/>
+				<text name="price_for_listing_edit_label" value="Prezzo per inserzione:"/>
+				<spinner label="L$" name="price_for_listing_edit" tool_tip="Prezzo per inserzione." value="50"/>
+			</panel>
+		</panel>
+	</scroll_container>
+	<layout_stack name="edit_btns_pnl">
+		<layout_panel name="teleport_btn_lp">
+			<button label="Teletrasporto" name="teleport_btn"/>
+		</layout_panel>
+		<layout_panel name="map_btn_lp">
+			<button label="Mappa" name="show_on_map_btn"/>
+		</layout_panel>
+		<layout_panel name="edit_btn_lp">
+			<button label="Modifica" name="edit_btn"/>
+		</layout_panel>
+		<layout_panel name="save_btn_lp">
+			<button label="[LABEL]" name="save_changes_btn"/>
+		</layout_panel>
+		<layout_panel name="cancel_btn_lp">
+			<button label="Annulla" name="cancel_btn"/>
+		</layout_panel>
+	</layout_stack>
+</panel>
diff --git a/indra/newview/skins/default/xui/it/panel_profile_classifieds.xml b/indra/newview/skins/default/xui/it/panel_profile_classifieds.xml
new file mode 100644
index 0000000000000000000000000000000000000000..6fc0fd07291c4d42154a3110def654163d9debb9
--- /dev/null
+++ b/indra/newview/skins/default/xui/it/panel_profile_classifieds.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel label="Annuncio" name="panel_profile_classifieds">
+	<string name="no_classifieds" value="Nessuno annuncio"/>
+	<button label="Nuovo..." name="new_btn"/>
+	<button label="Elimina..." name="delete_btn"/>
+	<text name="classifieds_panel_text">
+		Caricamento in corso...
+	</text>
+</panel>
diff --git a/indra/newview/skins/default/xui/it/panel_profile_firstlife.xml b/indra/newview/skins/default/xui/it/panel_profile_firstlife.xml
new file mode 100644
index 0000000000000000000000000000000000000000..bf8ccef273084f8850a8ebcee6407dd33b7b8b97
--- /dev/null
+++ b/indra/newview/skins/default/xui/it/panel_profile_firstlife.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel label="Profilo" name="panel_profile_firstlife"/>
diff --git a/indra/newview/skins/default/xui/it/panel_profile_interests.xml b/indra/newview/skins/default/xui/it/panel_profile_interests.xml
new file mode 100644
index 0000000000000000000000000000000000000000..9fe7331e5c9914fc3d4608490e6ac24a81d3b347
--- /dev/null
+++ b/indra/newview/skins/default/xui/it/panel_profile_interests.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel label="Interessi" name="panel_profile_interests">
+	<text name="I Want To:">
+		Desidero:
+	</text>
+	<check_box label="Costruire" name="chk0"/>
+	<check_box label="Esplorare" name="chk1"/>
+	<check_box label="Incontrare" name="chk2"/>
+	<check_box label="Essere assunto" name="chk6"/>
+	<check_box label="Gruppo" name="chk3"/>
+	<check_box label="Acquistare" name="chk4"/>
+	<check_box label="Vendere" name="chk5"/>
+	<check_box label="Assumere" name="chk7"/>
+	<line_editor name="want_to_edit">
+		(caricamento in corso...)
+	</line_editor>
+	<text name="Skills:">
+		Abilità:
+	</text>
+	<check_box label="Texture" name="schk0"/>
+	<check_box label="Architettura" name="schk1"/>
+	<check_box label="Realizzazione modelli 3D" name="schk3"/>
+	<check_box label="Organizzazione eventi" name="schk2"/>
+	<check_box label="Scripting" name="schk4"/>
+	<check_box label="Personaggi personalizzati" name="schk5"/>
+	<line_editor name="skills_edit">
+		(caricamento in corso...)
+	</line_editor>
+	<text name="Languages:">
+		Lingue:
+	</text>
+	<line_editor name="languages_edit">
+		(caricamento in corso...)
+	</line_editor>
+</panel>
diff --git a/indra/newview/skins/default/xui/it/panel_profile_notes.xml b/indra/newview/skins/default/xui/it/panel_profile_notes.xml
new file mode 100644
index 0000000000000000000000000000000000000000..abd5a347c3eff8bc04e4f7ed9e0f6d874665177e
--- /dev/null
+++ b/indra/newview/skins/default/xui/it/panel_profile_notes.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel label="Note e Privacy" name="panel_notes">
+	<text name="status_message" value="Annotazioni private su questo avatar:"/>
+	<text name="status_message2" value="Consenti a questo avatar di:"/>
+	<check_box label="Vedere quando sono in linea" name="status_check"/>
+	<check_box label="Trovarmi sulla mappa del mondo" name="map_check"/>
+	<check_box label="Modificare, eliminare o prendere i miei oggetti" name="objects_check"/>
+</panel>
diff --git a/indra/newview/skins/default/xui/it/panel_profile_pick.xml b/indra/newview/skins/default/xui/it/panel_profile_pick.xml
new file mode 100644
index 0000000000000000000000000000000000000000..5d2b14556583cea51c63cc98d25157f9c5474e2a
--- /dev/null
+++ b/indra/newview/skins/default/xui/it/panel_profile_pick.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="panel_pick_info">
+	<panel.string name="location_notice">
+		(si aggiornerà dopo il salvataggio)
+	</panel.string>
+	<line_editor name="pick_location">
+		Caricamento in corso...
+	</line_editor>
+	<button label="Teletrasporto" name="teleport_btn"/>
+	<button label="Mostra sulla mappa" name="show_on_map_btn"/>
+	<button label="Imposta Luogo" name="set_to_curr_location_btn" tool_tip="Imposta come Luogo Attuale"/>
+	<button label="Salva Luogo preferito" name="save_changes_btn"/>
+</panel>
diff --git a/indra/newview/skins/default/xui/it/panel_profile_picks.xml b/indra/newview/skins/default/xui/it/panel_profile_picks.xml
new file mode 100644
index 0000000000000000000000000000000000000000..37cffcf6221c4e732efbff84aebee2175b58bc20
--- /dev/null
+++ b/indra/newview/skins/default/xui/it/panel_profile_picks.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel label="Preferiti" name="panel_picks">
+	<string name="no_picks" value="Nessun preferito"/>
+	<text name="Tell everyone about your favorite places in Second Life.">
+		Comunica a tutti quali sono i tuoi posti preferiti in Second Life.
+	</text>
+	<button label="Nuovo..." name="new_btn"/>
+	<button label="Elimina..." name="delete_btn"/>
+	<text name="picks_panel_text">
+		Caricamento in corso...
+	</text>
+</panel>
diff --git a/indra/newview/skins/default/xui/it/panel_profile_secondlife.xml b/indra/newview/skins/default/xui/it/panel_profile_secondlife.xml
new file mode 100644
index 0000000000000000000000000000000000000000..47af1960a5f3d8ad62c8ea80b4d848332f5d07d7
--- /dev/null
+++ b/indra/newview/skins/default/xui/it/panel_profile_secondlife.xml
@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel label="Profilo" name="panel_profile">
+	<string name="status_online">
+		Ora in linea
+	</string>
+	<string name="status_offline">
+		Ora non in linea
+	</string>
+	<string name="CaptionTextAcctInfo">
+		[ACCTTYPE]
+[PAYMENTINFO]
+	</string>
+	<string name="payment_update_link_url">
+		http://www.secondlife.com/account/billing.php?lang=en
+	</string>
+	<string name="partner_edit_link_url">
+		http://www.secondlife.com/account/partners.php?lang=en
+	</string>
+	<string name="my_account_link_url" value="http://secondlife.com/account"/>
+	<string name="no_partner_text" value="Nessuno"/>
+	<string name="no_group_text" value="Nessuno"/>
+	<string name="RegisterDateFormat">
+		[REG_DATE]
+	</string>
+	<string name="name_text_args">
+		[NAME]
+	</string>
+	<string name="display_name_text_args">
+		[DISPLAY_NAME]
+	</string>
+	<string name="FSDev" value="Sviluppatore"/>
+	<string name="FSSupp" value="Assistenza"/>
+	<string name="FSQualityAssurance" value="Bug Hunter"/>
+	<string name="FSGW" value="Gateway"/>
+	<text name="name_label" value="Nome:"/>
+	<button label="Nome:" name="set_name" tool_tip="Imposta nome visualizzato"/>
+	<panel name="name_holder">
+		<text_editor name="complete_name" value="(caricamento in corso...)"/>
+	</panel>
+	<layout_stack name="imagepositioner">
+		<layout_panel name="label_stack">
+			<text name="status" value="Stato Sconosciuto"/>
+			<text name="label" value="Compleanno Second Life:"/>
+			<text name="label2" value="Account:"/>
+			<text name="partner_label" value="Partner:"/>
+		</layout_panel>
+	</layout_stack>
+	<text name="Groups:" value="Gruppi:"/>
+	<button label="+" label_selected="+" name="group_invite" tool_tip="Invita al gruppo:"/>
+	<layout_stack name="aboutpositioner">
+		<layout_panel name="about_stack">
+			<text name="About:" value="Informazioni generali:"/>
+		</layout_panel>
+		<layout_panel name="give_stack">
+			<text name="Give item:" value="Consegna oggetto:"/>
+			<text name="Give inventory" tool_tip="Rilascia gli oggetti dell’inventario per consegnarli a questa persona.">
+				Rilascia l’oggetto dell’inventario qui.
+			</text>
+		</layout_panel>
+	</layout_stack>
+	<layout_stack name="buttonstack">
+		<layout_panel name="left_buttonstack">
+			<button label="Trova sulla mappa" label_selected="Trova sulla mappa" name="show_on_map_btn" tool_tip="Localizza il Residente sulla mappa"/>
+			<button label="Paga" label_selected="Paga" name="pay" tool_tip="Paga del denaro al Residente"/>
+		</layout_panel>
+		<layout_panel name="middle_buttonstack">
+			<button label="Offri Teletrasporto" label_selected="Offri Teletrasporto" name="teleport" tool_tip="Offri il teletrasporto al Residente"/>
+			<button label="Messaggio istantaneo" label_selected="Messaggio istantaneo" name="im" tool_tip="Apri sessione di messaggistica istantanea"/>
+		</layout_panel>
+		<layout_panel name="right_buttonstack">
+			<button label="Aggiungi come amico" label_selected="Aggiungi come amico" name="add_friend" tool_tip="Offri amicizia al Residente"/>
+			<button label="Blocca" name="block" tool_tip="Blocca questo Residente"/>
+			<button label="Sblocca" name="unblock" tool_tip="Sblocca questo Residente"/>
+		</layout_panel>
+	</layout_stack>
+	<check_box label="Mostra nella ricerca" name="show_in_search_checkbox"/>
+</panel>
diff --git a/indra/newview/skins/default/xui/it/panel_profile_web.xml b/indra/newview/skins/default/xui/it/panel_profile_web.xml
new file mode 100644
index 0000000000000000000000000000000000000000..0c3a8ddcf55db75eed5238d0fe8259e5e838064e
--- /dev/null
+++ b/indra/newview/skins/default/xui/it/panel_profile_web.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel label="Web" name="panel_profile_web">
+	<panel.string name="LoadTime" value="Tempo di caricamento: [TIME] secondi"/>
+	<line_editor name="url_edit">
+		(caricamento in corso..)
+	</line_editor>
+	<flyout_button label="Carica" name="load" tool_tip="Carica la pagina profilo con il browser Web integrato.">
+		<flyout_button.item label="Apri browser interno" name="open_item"/>
+		<flyout_button.item label="Apri browser esterno" name="home_item"/>
+	</flyout_button>
+	<button name="web_profile_popout_btn" tool_tip="Profilo web a comparsa"/>
+</panel>
diff --git a/indra/newview/skins/default/xui/it/panel_region_terrain.xml b/indra/newview/skins/default/xui/it/panel_region_terrain.xml
index c61ac3eccecac77b4a9433210d33498e9293c366..e08c55f63bb767bf59afe07759902b8e7a5cbd41 100644
--- a/indra/newview/skins/default/xui/it/panel_region_terrain.xml
+++ b/indra/newview/skins/default/xui/it/panel_region_terrain.xml
@@ -12,8 +12,8 @@ terreno" name="terrain_raise_spin"/>
 	<spinner bottom_delta="-34" label="Limite di abbassamento 
 del terreno" name="terrain_lower_spin"/>
 	<text name="detail_texture_text">
-		Texture terreno (richiede file 512x512, 24 bit .tga)
-	</text>
+    Texture terreno (richiede file 1024x1024, 24 bit .tga)
+  </text>
 	<text name="height_text_lbl">
 		1 (basso)
 	</text>
diff --git a/indra/newview/skins/default/xui/it/strings.xml b/indra/newview/skins/default/xui/it/strings.xml
index 3049828f46e05f0855ce6cb724ed5b10f3542825..1ebdadb930554c76f1607fe0ebfdd9d088a19584 100644
--- a/indra/newview/skins/default/xui/it/strings.xml
+++ b/indra/newview/skins/default/xui/it/strings.xml
@@ -183,7 +183,7 @@ Versione server voce: [VOICE_VERSION]
 	<string name="LoginFailedNoNetwork">
 		Errore di rete: Non è stato possibile stabilire un collegamento, controlla la tua connessione.
 	</string>
-	<string name="LoginFailed">
+	<string name="LoginFailedHeader">
 		Accesso non riuscito.
 	</string>
 	<string name="Quit">
@@ -353,6 +353,24 @@ Prova ad accedere nuovamente tra un minuto.
 	<string name="TestingDisconnect">
 		Verifica scollegamento viewer
 	</string>
+	<string name="SocialFacebookConnecting">
+		Connessione a Facebook in corso...
+	</string>
+	<string name="SocialFacebookPosting">
+		Caricamento post...
+	</string>
+	<string name="SocialFacebookDisconnecting">
+		Disconnessione da Facebook in corso...
+	</string>
+	<string name="SocialFacebookErrorConnecting">
+		Problemi con la connessione a Facebook
+	</string>
+	<string name="SocialFacebookErrorPosting">
+		Problemi con la connessione a Facebook
+	</string>
+	<string name="SocialFacebookErrorDisconnecting">
+		Problemi con la disconnessione da Facebook
+	</string>
 	<string name="SocialFlickrConnecting">
 		Collegamento a Flickr...
 	</string>
@@ -667,9 +685,6 @@ possono essere allegati ai biglietti.
 	<string name="GroupNameNone">
 		(nessuno)
 	</string>
-	<string name="AvalineCaller">
-		Chiamante Avaline [ORDER]
-	</string>
 	<string name="AssetErrorNone">
 		Nessun errore
 	</string>
@@ -2557,9 +2572,21 @@ Se continui a ricevere questo messaggio, contatta l&apos;assistenza Second Life
 	<string name="NoPicksClassifiedsText">
 		Non hai creato luoghi preferiti né inserzioni. Clicca il pulsante + qui sotto per creare un luogo preferito o un&apos;inserzione.
 	</string>
+	<string name="NoPicksText">
+		Non hai creato Luoghi preferiti. Fai clic sul pulsante Nuovo per creare un Luogo preferito.
+	</string>
+	<string name="NoClassifiedsText">
+		Non hai creato Annunci. Fai clic sul pulsante Nuovo per creare un Annuncio.
+	</string>
 	<string name="NoAvatarPicksClassifiedsText">
 		L&apos;utente non ha luoghi preferiti né inserzioni
 	</string>
+	<string name="NoAvatarPicksText">
+		L&apos;utente non ha luoghi preferiti
+	</string>
+	<string name="NoAvatarClassifiedsText">
+		L&apos;utente non ha annunci
+	</string>
 	<string name="PicksClassifiedsLoadingText">
 		Caricamento in corso...
 	</string>
@@ -4474,6 +4501,9 @@ Se il messaggio persiste, contatta [SUPPORT_SITE].
 	<string name="inventory_folder_offered-im">
 		Offerta cartella di inventario &quot;[ITEM_NAME]&quot;
 	</string>
+	<string name="facebook_post_success">
+		Hai pubblicato su Facebook.
+	</string>
 	<string name="flickr_post_success">
 		Hai pubblicato su Flickr.
 	</string>
@@ -5017,7 +5047,7 @@ Consulta la pagina http://status.secondlifegrid.net per determinare se il proble
 	<string name="PremiumMembership">
 		Premium
 	</string>
-	<string name="Premium PlusMembership">
+	<string name="Premium_PlusMembership">
 		Premium Plus
 	</string>
 	<string name="DeleteItems">
diff --git a/indra/newview/skins/default/xui/ja/floater_about.xml b/indra/newview/skins/default/xui/ja/floater_about.xml
index cf5e97bd8d12bebe414ebdbcc196710a40a37828..6a39d057e21e32aa904cd872608a2f826a073327 100644
--- a/indra/newview/skins/default/xui/ja/floater_about.xml
+++ b/indra/newview/skins/default/xui/ja/floater_about.xml
@@ -19,7 +19,6 @@ DBus/dbus-glib Copyright (C) 2002, 2003  CodeFactory AB / Copyright (C) 2003, 20
 expat Copyright (C) 1998, 1999, 2000 Thai Open Source Software Center Ltd.
 FreeType Copyright (C) 1996-2002, 2006 David Turner, Robert Wilhelm, and Werner Lemberg.
 GL Copyright (C) 1999-2004 Brian Paul.
-GLOD Copyright (C) 2003-04 Jonathan Cohen, Nat Duca, Chris Niski, Johns Hopkins University and David Luebke, Brenden Schubert, University of Virginia.
 google-perftools Copyright (c) 2005, Google Inc.
 Havok.com(TM) Copyright (C) 1999-2001, Telekinesys Research Limited.
 jpeg2000 Copyright (C) 2001, David Taubman, The University of New South Wales (UNSW)
diff --git a/indra/newview/skins/default/xui/ja/floater_picks.xml b/indra/newview/skins/default/xui/ja/floater_picks.xml
deleted file mode 100644
index 359585eb86b8b27d9f6fd2c2287f093079296ac5..0000000000000000000000000000000000000000
--- a/indra/newview/skins/default/xui/ja/floater_picks.xml
+++ /dev/null
@@ -1,2 +0,0 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<floater name="floater_picks" title="ピック"/>
diff --git a/indra/newview/skins/default/xui/ja/floater_preview_texture.xml b/indra/newview/skins/default/xui/ja/floater_preview_texture.xml
index 4617fd1d92c76bbc95f90985cfcfb0d3fc7aab0c..66ef13948a4c37c789ffcd55206a38534bf0dc66 100644
--- a/indra/newview/skins/default/xui/ja/floater_preview_texture.xml
+++ b/indra/newview/skins/default/xui/ja/floater_preview_texture.xml
@@ -6,42 +6,23 @@
 	<floater.string name="Copy">
 		インベントリにコピー
 	</floater.string>
-	<text name="desc txt">
-		説明:
-	</text>
-	<text name="dimensions">
-		[WIDTH]px x [HEIGHT]px
-	</text>
-	<text name="aspect_ratio">
-		縦横比のプレビュー
-	</text>
-	<combo_box name="combo_aspect_ratio" tool_tip="固定した縦横比のプレビュー">
-		<combo_item name="Unconstrained">
-			非拘束
-		</combo_item>
-		<combo_item name="1:1" tool_tip="グループ記章か現実世界のプロフィール">
-			1:1
-		</combo_item>
-		<combo_item name="4:3" tool_tip="[SECOND_LIFE] プロフィール">
-			4:3
-		</combo_item>
-		<combo_item name="10:7" tool_tip="クラシファイド広告、検索一覧、ランドマーク">
-			10:7
-		</combo_item>
-		<combo_item name="3:2" tool_tip="土地情報">
-			3:2
-		</combo_item>
-		<combo_item name="16:10">
-			16:10
-		</combo_item>
-		<combo_item name="16:9" tool_tip="プロフィールのピック">
-			16:9
-		</combo_item>
-		<combo_item name="2:1">
-			2:1
-		</combo_item>
-	</combo_box>
-	<button label="OK" name="Keep"/>
-	<button label="処分する" name="Discard"/>
-	<button label="別名で保存" name="save_tex_btn"/>
+	<layout_stack name="preview_stack">
+		<layout_panel name="texture_panel">
+			<text name="desc txt">
+				説明:
+			</text>
+			<text name="dimensions">
+				[WIDTH]px x [HEIGHT]px
+			</text>
+			<text name="aspect_ratio">
+				縦横比のプレビュー
+			</text>
+			<combo_box name="combo_aspect_ratio" tool_tip="固定した縦横比のプレビュー"/>
+		</layout_panel>
+		<layout_panel name="buttons_panel">
+			<button label="OK" name="Keep"/>
+			<button label="処分する" name="Discard"/>
+			<button label="別名で保存" name="save_tex_btn"/>
+		</layout_panel>
+	</layout_stack>
 </floater>
diff --git a/indra/newview/skins/default/xui/ja/floater_profile.xml b/indra/newview/skins/default/xui/ja/floater_profile.xml
new file mode 100644
index 0000000000000000000000000000000000000000..e06cd6e8f6a7582b0115c691a14c90236c89bc03
--- /dev/null
+++ b/indra/newview/skins/default/xui/ja/floater_profile.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<floater name="avatarinfo" title="プロフィール">
+	<panel name="panel_profile_view">
+		<tab_container name="panel_profile_tabs">
+			<panel label="Second Life" name="panel_profile_secondlife"/>
+			<panel label="Web" name="panel_profile_web"/>
+			<panel label="趣味" name="panel_profile_interests"/>
+			<panel label="ピック" name="panel_profile_picks"/>
+			<panel label="クラシファイド広告" name="panel_profile_classifieds"/>
+			<panel label="リアルライフ(現実世界)" name="panel_profile_firstlife"/>
+			<panel label="メモ" name="panel_profile_notes"/>
+		</tab_container>
+		<button label="OK" name="ok_btn" tool_tip="プロフィールの変更を保存して閉じる"/>
+		<button label="キャンセル" label_selected="キャンセル" name="cancel_btn"/>
+	</panel>
+</floater>
diff --git a/indra/newview/skins/default/xui/ja/floater_snapshot.xml b/indra/newview/skins/default/xui/ja/floater_snapshot.xml
index f04193d034e4b5fa5400428988b36fcc3be75627..64f292c75c04f08f46fec81067e6b067fb82eff0 100644
--- a/indra/newview/skins/default/xui/ja/floater_snapshot.xml
+++ b/indra/newview/skins/default/xui/ja/floater_snapshot.xml
@@ -6,6 +6,9 @@
 	<string name="postcard_progress_str">
 		メールの送信
 	</string>
+	<string name="facebook_progress_str">
+		Facebook へ投稿中
+	</string>
 	<string name="profile_progress_str">
 		投稿
 	</string>
@@ -15,6 +18,9 @@
 	<string name="local_progress_str">
 		コンピュータに保存
 	</string>
+	<string name="facebook_succeeded_str">
+		画像がアップロードされました
+	</string>
 	<string name="profile_succeeded_str">
 		画像がアップロードされました
 	</string>
@@ -27,6 +33,9 @@
 	<string name="local_succeeded_str">
 		コンピュータに保存されました
 	</string>
+	<string name="facebook_failed_str">
+		Facebook のタイムラインに画像をアップロードできませんでした。
+	</string>
 	<string name="profile_failed_str">
 		プロフィールフィードに画像をアップロードできませんでした。
 	</string>
diff --git a/indra/newview/skins/default/xui/ja/menu_name_field.xml b/indra/newview/skins/default/xui/ja/menu_name_field.xml
new file mode 100644
index 0000000000000000000000000000000000000000..8c37d950739fd7ed7dfecf658470d38744e10a2c
--- /dev/null
+++ b/indra/newview/skins/default/xui/ja/menu_name_field.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<toggleable_menu name="CopyMenu">
+	<menu_item_call label="表示名をコピー" name="copy_display"/>
+	<menu_item_call label="エージェント名をコピー" name="copy_name"/>
+	<menu_item_call label="エージェント ID をコピー" name="copy_id"/>
+</toggleable_menu>
diff --git a/indra/newview/skins/default/xui/ja/notifications.xml b/indra/newview/skins/default/xui/ja/notifications.xml
index a66552d3fe9eddd960431742a4bfb30006de271d..92952f4c8a34abd27cd68c910f7e648d6606cccd 100644
--- a/indra/newview/skins/default/xui/ja/notifications.xml
+++ b/indra/newview/skins/default/xui/ja/notifications.xml
@@ -2727,6 +2727,9 @@ Web ページにリンクすると、他人がこの場所に簡単にアクセ
 	<notification name="SystemMessage">
 		[MESSAGE]
 	</notification>
+	<notification name="FacebookConnect">
+		[MESSAGE]
+	</notification>
 	<notification name="FlickrConnect">
 		[MESSAGE]
 	</notification>
diff --git a/indra/newview/skins/default/xui/ja/panel_edit_classified.xml b/indra/newview/skins/default/xui/ja/panel_edit_classified.xml
index cf5f2489f1ad4dae8d7f58aa744377e0fb37245a..619e9de65a7e2bda46ce6add935c4927dea313bd 100644
--- a/indra/newview/skins/default/xui/ja/panel_edit_classified.xml
+++ b/indra/newview/skins/default/xui/ja/panel_edit_classified.xml
@@ -46,7 +46,7 @@
 			<layout_panel name="save_changes_btn_lp">
 				<button label="[LABEL]" name="save_changes_btn"/>
 			</layout_panel>
-			<layout_panel name="show_on_map_btn_lp">
+			<layout_panel name="cancel_btn_lp">
 				<button label="キャンセル" name="cancel_btn"/>
 			</layout_panel>
 		</layout_stack>
diff --git a/indra/newview/skins/default/xui/ja/panel_facebook_photo.xml b/indra/newview/skins/default/xui/ja/panel_facebook_photo.xml
index c48f13456bad1b045e83d27d258db698a9f81052..ee57d178e820caa277ed3e1a9675470a2d58debb 100644
--- a/indra/newview/skins/default/xui/ja/panel_facebook_photo.xml
+++ b/indra/newview/skins/default/xui/ja/panel_facebook_photo.xml
@@ -16,5 +16,5 @@
 		コメント (オプション):
 	</text>
 	<button label="投稿" name="post_photo_btn"/>
-	<button label="取り消し" name="cancel_photo_btn"/>
+	<button label="キャンセル" name="cancel_photo_btn"/>
 </panel>
diff --git a/indra/newview/skins/default/xui/ja/panel_facebook_place.xml b/indra/newview/skins/default/xui/ja/panel_facebook_place.xml
index 61138f90c1419e9bf538734433cf2e3a862b1690..e97422a9df21ebe4885cd5f9ab9b3892661b5e2b 100644
--- a/indra/newview/skins/default/xui/ja/panel_facebook_place.xml
+++ b/indra/newview/skins/default/xui/ja/panel_facebook_place.xml
@@ -5,5 +5,5 @@
 	</text>
 	<check_box initial_value="false" label="場所の俯瞰図を含める" name="add_place_view_cb"/>
 	<button label="投稿" name="post_place_btn"/>
-	<button label="取り消し" name="cancel_place_btn"/>
+	<button label="キャンセル" name="cancel_place_btn"/>
 </panel>
diff --git a/indra/newview/skins/default/xui/ja/panel_facebook_status.xml b/indra/newview/skins/default/xui/ja/panel_facebook_status.xml
index 9d962c9d62ad09670d8e88c50bf1215e6b41c924..1f48c9c8c7ae08563880eaad5cec2dc845176843 100644
--- a/indra/newview/skins/default/xui/ja/panel_facebook_status.xml
+++ b/indra/newview/skins/default/xui/ja/panel_facebook_status.xml
@@ -9,12 +9,12 @@
 		<button label="接続..." name="connect_btn"/>
 		<button label="切断" name="disconnect_btn"/>
 		<text name="account_learn_more_label">
-			[http://community.secondlife.com/t5/English-Knowledge-Base/Second-Life-Share-Facebook/ta-p/2149711 Facebook への投稿について]]
+			[http://community.secondlife.com/t5/English-Knowledge-Base/Second-Life-Share-Facebook/ta-p/2149711 Facebook への投稿について]
 		</text>
 	</panel>
 	<text name="status_caption_label">
 		今、何を考えている?
 	</text>
 	<button label="投稿" name="post_status_btn"/>
-	<button label="取り消し" name="cancel_status_btn"/>
+	<button label="キャンセル" name="cancel_status_btn"/>
 </panel>
diff --git a/indra/newview/skins/default/xui/ja/panel_group_list_item_short.xml b/indra/newview/skins/default/xui/ja/panel_group_list_item_short.xml
new file mode 100644
index 0000000000000000000000000000000000000000..77d3d8f39164df330335110d8a8cabcfbf78bfaf
--- /dev/null
+++ b/indra/newview/skins/default/xui/ja/panel_group_list_item_short.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="group_list_item">
+	<text name="group_name" value="不明"/>
+	<button name="info_btn" tool_tip="詳細"/>
+	<button name="profile_btn" tool_tip="プロフィールの表示"/>
+</panel>
diff --git a/indra/newview/skins/default/xui/ja/panel_me.xml b/indra/newview/skins/default/xui/ja/panel_me.xml
deleted file mode 100644
index 9b1cf1c8a4d6e9ac01580888a54071372ce7ed32..0000000000000000000000000000000000000000
--- a/indra/newview/skins/default/xui/ja/panel_me.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<panel label="プロフィール" name="panel_me">
-	<panel label="マイ ピック" name="panel_picks"/>
-</panel>
diff --git a/indra/newview/skins/default/xui/ja/panel_people.xml b/indra/newview/skins/default/xui/ja/panel_people.xml
index 0a295855d05f793dc888cbb04bfced0b79882b76..be00a3c122aef7756a715cee619951349ad941e9 100644
--- a/indra/newview/skins/default/xui/ja/panel_people.xml
+++ b/indra/newview/skins/default/xui/ja/panel_people.xml
@@ -40,6 +40,7 @@
 			<accordion name="friends_accordion">
 				<accordion_tab name="tab_online" title="オンライン"/>
 				<accordion_tab name="tab_all" title="全員"/>
+				<accordion_tab name="tab_suggested_friends" title="友だちになりたくない人"/>
 			</accordion>
 		</panel>
 		<panel label="グループ" name="groups_panel">
diff --git a/indra/newview/skins/default/xui/ja/panel_profile_classified.xml b/indra/newview/skins/default/xui/ja/panel_profile_classified.xml
new file mode 100644
index 0000000000000000000000000000000000000000..2d1bc07e2c76eee142317e8b64485fe5259feb35
--- /dev/null
+++ b/indra/newview/skins/default/xui/ja/panel_profile_classified.xml
@@ -0,0 +1,110 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="panel_profile_classified">
+	<panel.string name="type_mature">
+		Moderate
+	</panel.string>
+	<panel.string name="type_pg">
+		General コンテンツ
+	</panel.string>
+	<panel.string name="l$_price">
+		L$[PRICE]
+	</panel.string>
+	<panel.string name="click_through_text_fmt">
+		[TELEPORT] テレポート、 [MAP] 地図、 [PROFILE] プロフィール
+	</panel.string>
+	<panel.string name="date_fmt">
+		[mthnum,datetime,slt]/[day,datetime,slt]/[year,datetime,slt]
+	</panel.string>
+	<panel.string name="auto_renew_on">
+		有効
+	</panel.string>
+	<panel.string name="auto_renew_off">
+		無効
+	</panel.string>
+	<panel.string name="location_notice">
+		(掲載後更新)
+	</panel.string>
+	<string name="publish_label">
+		掲載
+	</string>
+	<string name="save_label">
+		保存
+	</string>
+	<scroll_container name="profile_scroll">
+		<panel name="info_scroll_content_panel">
+			<icon label="" name="edit_icon" tool_tip="クリックして画像を選択"/>
+			<layout_stack name="info_panel">
+				<layout_panel name="main_info_panel">
+					<text_editor name="classified_name">
+						[name]
+					</text_editor>
+					<text name="classified_location_label" value="場所:"/>
+					<text_editor name="classified_location" value="[loading...]"/>
+					<text name="content_type_label" value="コンテンツの種類:"/>
+					<text_editor name="content_type" value="[content type]"/>
+					<text name="category_label" value="カテゴリ:"/>
+					<text_editor name="category" value="[category]"/>
+					<text name="creation_date_label" value="制作日:"/>
+					<text_editor name="creation_date" tool_tip="制作日" value="[date]"/>
+					<text name="price_for_listing_label" value="掲載価格:"/>
+					<text_editor name="price_for_listing" tool_tip="掲載価格。">
+						[PRICE]
+					</text_editor>
+				</layout_panel>
+				<layout_panel name="clickthrough_layout_panel">
+					<text name="click_through_label" value="クリック数:"/>
+					<text_editor name="click_through_text" tool_tip="クリックスルーデータ" value="[clicks]"/>
+				</layout_panel>
+				<layout_panel name="auto_renew_layout_panel">
+					<text name="auto_renew_label" value="自動更新:"/>
+					<text name="auto_renew" value="有効"/>
+				</layout_panel>
+				<layout_panel name="descr_layout_panel">
+					<text name="classified_desc_label" value="説明:"/>
+					<text_editor name="classified_desc" value="[description]"/>
+				</layout_panel>
+			</layout_stack>
+			<panel name="edit_panel">
+				<text name="Name:">
+					タイトル:
+				</text>
+				<text name="description_label">
+					説明:
+				</text>
+				<text name="location_label">
+					場所:
+				</text>
+				<text name="classified_location_edit">
+					ロード中...
+				</text>
+				<button label="現在地に設定" name="set_to_curr_location_btn"/>
+				<text name="category_label" value="カテゴリ:"/>
+				<text name="content_type_label" value="コンテンツの種類:"/>
+				<icons_combo_box label="General コンテンツ" name="content_type_edit">
+					<icons_combo_box.item label="Moderate コンテンツ" name="mature_ci" value="Mature"/>
+					<icons_combo_box.item label="General コンテンツ" name="pg_ci" value="PG"/>
+				</icons_combo_box>
+				<check_box label="毎週自動更新" name="auto_renew_edit"/>
+				<text name="price_for_listing_edit_label" value="掲載価格:"/>
+				<spinner label="L$" name="price_for_listing_edit" tool_tip="掲載価格。" value="50"/>
+			</panel>
+		</panel>
+	</scroll_container>
+	<layout_stack name="edit_btns_pnl">
+		<layout_panel name="teleport_btn_lp">
+			<button label="テレポート" name="teleport_btn"/>
+		</layout_panel>
+		<layout_panel name="map_btn_lp">
+			<button label="地図" name="show_on_map_btn"/>
+		</layout_panel>
+		<layout_panel name="edit_btn_lp">
+			<button label="編集" name="edit_btn"/>
+		</layout_panel>
+		<layout_panel name="save_btn_lp">
+			<button label="[LABEL]" name="save_changes_btn"/>
+		</layout_panel>
+		<layout_panel name="cancel_btn_lp">
+			<button label="キャンセル" name="cancel_btn"/>
+		</layout_panel>
+	</layout_stack>
+</panel>
diff --git a/indra/newview/skins/default/xui/ja/panel_profile_classifieds.xml b/indra/newview/skins/default/xui/ja/panel_profile_classifieds.xml
new file mode 100644
index 0000000000000000000000000000000000000000..1980c0fa62c533e9b32019762f2af7f90fec44ce
--- /dev/null
+++ b/indra/newview/skins/default/xui/ja/panel_profile_classifieds.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel label="クラシファイド広告" name="panel_profile_classifieds">
+	<string name="no_classifieds" value="クラシファイド広告なし"/>
+	<button label="新規…" name="new_btn"/>
+	<button label="削除…" name="delete_btn"/>
+	<text name="classifieds_panel_text">
+		ロード中...
+	</text>
+</panel>
diff --git a/indra/newview/skins/default/xui/ja/panel_profile_firstlife.xml b/indra/newview/skins/default/xui/ja/panel_profile_firstlife.xml
new file mode 100644
index 0000000000000000000000000000000000000000..a4ee262cb35e803e5150219b1fee901de48bf4de
--- /dev/null
+++ b/indra/newview/skins/default/xui/ja/panel_profile_firstlife.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel label="プロフィール" name="panel_profile_firstlife"/>
diff --git a/indra/newview/skins/default/xui/ja/panel_profile_interests.xml b/indra/newview/skins/default/xui/ja/panel_profile_interests.xml
new file mode 100644
index 0000000000000000000000000000000000000000..93cde6ffec62ebc4378291b4d369cd9152eb32d1
--- /dev/null
+++ b/indra/newview/skins/default/xui/ja/panel_profile_interests.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel label="趣味" name="panel_profile_interests">
+	<text name="I Want To:">
+		次の内容を実行:
+	</text>
+	<check_box label="作る" name="chk0"/>
+	<check_box label="探検" name="chk1"/>
+	<check_box label="出会う" name="chk2"/>
+	<check_box label="雇ってもらう" name="chk6"/>
+	<check_box label="グループ" name="chk3"/>
+	<check_box label="買う" name="chk4"/>
+	<check_box label="販売する" name="chk5"/>
+	<check_box label="雇う" name="chk7"/>
+	<line_editor name="want_to_edit">
+		(ロード中...)
+	</line_editor>
+	<text name="Skills:">
+		スキル:
+	</text>
+	<check_box label="テクスチャ" name="schk0"/>
+	<check_box label="建築" name="schk1"/>
+	<check_box label="モデリング" name="schk3"/>
+	<check_box label="イベント計画" name="schk2"/>
+	<check_box label="スクリプト" name="schk4"/>
+	<check_box label="キャラクターのカスタマイズ" name="schk5"/>
+	<line_editor name="skills_edit">
+		(ロード中...)
+	</line_editor>
+	<text name="Languages:">
+		言語:
+	</text>
+	<line_editor name="languages_edit">
+		(ロード中...)
+	</line_editor>
+</panel>
diff --git a/indra/newview/skins/default/xui/ja/panel_profile_notes.xml b/indra/newview/skins/default/xui/ja/panel_profile_notes.xml
new file mode 100644
index 0000000000000000000000000000000000000000..4b4e0d5e4ee5a9c02a6c10ffe6c3d78310f03892
--- /dev/null
+++ b/indra/newview/skins/default/xui/ja/panel_profile_notes.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel label="メモとプライバシー" name="panel_notes">
+	<text name="status_message" value="このアバターのプライベートメモ:"/>
+	<text name="status_message2" value="このアバターに次の許可を与える:"/>
+	<check_box label="自分のオンラインステータスを表示する" name="status_check"/>
+	<check_box label="世界地図で自分を探せるようにする" name="map_check"/>
+	<check_box label="自分のオブジェクトを編集・削除・取得できるようにする" name="objects_check"/>
+</panel>
diff --git a/indra/newview/skins/default/xui/ja/panel_profile_pick.xml b/indra/newview/skins/default/xui/ja/panel_profile_pick.xml
new file mode 100644
index 0000000000000000000000000000000000000000..0a20c04ad6d20f934c6d87c63a7d2fc6df4236b6
--- /dev/null
+++ b/indra/newview/skins/default/xui/ja/panel_profile_pick.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="panel_pick_info">
+	<panel.string name="location_notice">
+		(掲載後更新)
+	</panel.string>
+	<line_editor name="pick_location">
+		ロード中...
+	</line_editor>
+	<button label="テレポート" name="teleport_btn"/>
+	<button label="地図に表示" name="show_on_map_btn"/>
+	<button label="場所を設定" name="set_to_curr_location_btn" tool_tip="現在地に設定"/>
+	<button label="ピックを保存" name="save_changes_btn"/>
+</panel>
diff --git a/indra/newview/skins/default/xui/ja/panel_profile_picks.xml b/indra/newview/skins/default/xui/ja/panel_profile_picks.xml
new file mode 100644
index 0000000000000000000000000000000000000000..4cbfadd09d0f2dc15e0dc08f24ce72aa7afc73ba
--- /dev/null
+++ b/indra/newview/skins/default/xui/ja/panel_profile_picks.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel label="ピック" name="panel_picks">
+	<string name="no_picks" value="ピックなし"/>
+	<text name="Tell everyone about your favorite places in Second Life.">
+		Second Life のお気に入りの場所を紹介しましょう。
+	</text>
+	<button label="新規…" name="new_btn"/>
+	<button label="削除…" name="delete_btn"/>
+	<text name="picks_panel_text">
+		ロード中...
+	</text>
+</panel>
diff --git a/indra/newview/skins/default/xui/ja/panel_profile_secondlife.xml b/indra/newview/skins/default/xui/ja/panel_profile_secondlife.xml
new file mode 100644
index 0000000000000000000000000000000000000000..5470dc6c824841d352f5752a1a53fb4cbf93560a
--- /dev/null
+++ b/indra/newview/skins/default/xui/ja/panel_profile_secondlife.xml
@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel label="プロフィール" name="panel_profile">
+	<string name="status_online">
+		オンライン中
+	</string>
+	<string name="status_offline">
+		オフライン中
+	</string>
+	<string name="CaptionTextAcctInfo">
+		[ACCTTYPE]
+[PAYMENTINFO]
+	</string>
+	<string name="payment_update_link_url">
+		http://www.secondlife.com/account/billing.php?lang=en
+	</string>
+	<string name="partner_edit_link_url">
+		http://www.secondlife.com/account/partners.php?lang=en
+	</string>
+	<string name="my_account_link_url" value="http://secondlife.com/account"/>
+	<string name="no_partner_text" value="なし"/>
+	<string name="no_group_text" value="なし"/>
+	<string name="RegisterDateFormat">
+		[REG_DATE]
+	</string>
+	<string name="name_text_args">
+		[NAME]
+	</string>
+	<string name="display_name_text_args">
+		[DISPLAY_NAME]
+	</string>
+	<string name="FSDev" value="開発者"/>
+	<string name="FSSupp" value="サポート"/>
+	<string name="FSQualityAssurance" value="バグハンター"/>
+	<string name="FSGW" value="ゲートウェイ"/>
+	<text name="name_label" value="名前:"/>
+	<button label="名前:" name="set_name" tool_tip="表示名を設定"/>
+	<panel name="name_holder">
+		<text_editor name="complete_name" value="(ロード中...)"/>
+	</panel>
+	<layout_stack name="imagepositioner">
+		<layout_panel name="label_stack">
+			<text name="status" value="ステータス不明"/>
+			<text name="label" value="Second Life 生年月日:"/>
+			<text name="label2" value="アカウント:"/>
+			<text name="partner_label" value="パートナー:"/>
+		</layout_panel>
+	</layout_stack>
+	<text name="Groups:" value="グループ:"/>
+	<button label="+" label_selected="+" name="group_invite" tool_tip="グループに招待"/>
+	<layout_stack name="aboutpositioner">
+		<layout_panel name="about_stack">
+			<text name="About:" value="詳細:"/>
+		</layout_panel>
+		<layout_panel name="give_stack">
+			<text name="Give item:" value="アイテムを渡す:"/>
+			<text name="Give inventory" tool_tip="インベントリのアイテムをここにドロップしてこの人に渡します。">
+				インベントリのアイテムをここにドロップしてください。
+			</text>
+		</layout_panel>
+	</layout_stack>
+	<layout_stack name="buttonstack">
+		<layout_panel name="left_buttonstack">
+			<button label="地図上で見つける" label_selected="地図上で見つける" name="show_on_map_btn" tool_tip="住人を地図上で探す"/>
+			<button label="お金を払う" label_selected="お金を払う" name="pay" tool_tip="住人にお金を支払う"/>
+		</layout_panel>
+		<layout_panel name="middle_buttonstack">
+			<button label="テレポートを送る" label_selected="テレポートを送る" name="teleport" tool_tip="住人にテレポートを送る"/>
+			<button label="インスタントメッセージ" label_selected="インスタントメッセージ" name="im" tool_tip="インスタントメッセージを開きます"/>
+		</layout_panel>
+		<layout_panel name="right_buttonstack">
+			<button label="フレンド登録" label_selected="フレンド登録" name="add_friend" tool_tip="フレンド登録を申し出ます"/>
+			<button label="ブロック" name="block" tool_tip="この住人をブロックする"/>
+			<button label="ブロック解除" name="unblock" tool_tip="この住人のブロックを解除する"/>
+		</layout_panel>
+	</layout_stack>
+	<check_box label="検索に表示" name="show_in_search_checkbox"/>
+</panel>
diff --git a/indra/newview/skins/default/xui/ja/panel_profile_web.xml b/indra/newview/skins/default/xui/ja/panel_profile_web.xml
new file mode 100644
index 0000000000000000000000000000000000000000..4f56a7e98d04b9db19184225116b26fa77584d71
--- /dev/null
+++ b/indra/newview/skins/default/xui/ja/panel_profile_web.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel label="Web" name="panel_profile_web">
+	<panel.string name="LoadTime" value="ロード時間:[TIME] 秒"/>
+	<line_editor name="url_edit">
+		(ロード中...)
+	</line_editor>
+	<flyout_button label="ロード" name="load" tool_tip="このプロフィールページを、組み込み Web ブラウザでロードします。">
+		<flyout_button.item label="ビューワ内のブラウザを開く" name="open_item"/>
+		<flyout_button.item label="外部ブラウザを開く" name="home_item"/>
+	</flyout_button>
+	<button name="web_profile_popout_btn" tool_tip="Web プロフィールのポップアウト"/>
+</panel>
diff --git a/indra/newview/skins/default/xui/ja/panel_region_terrain.xml b/indra/newview/skins/default/xui/ja/panel_region_terrain.xml
index fb853c1925cd73f043dc941339b29ab5a96fb4cf..c1080a7d7b6d6cb931df67bbd1af952e18b635f6 100644
--- a/indra/newview/skins/default/xui/ja/panel_region_terrain.xml
+++ b/indra/newview/skins/default/xui/ja/panel_region_terrain.xml
@@ -10,8 +10,8 @@
 	<spinner label="地形の上昇限度" name="terrain_raise_spin"/>
 	<spinner label="地形の下降限度" name="terrain_lower_spin"/>
 	<text name="detail_texture_text">
-		地形テクスチャ(512x512 の 24 bit .tga ファイル)
-	</text>
+    地形テクスチャ(1024x1024 の 24 bit .tga ファイル)
+  </text>
 	<text name="height_text_lbl">
 		1(低)
 	</text>
diff --git a/indra/newview/skins/default/xui/ja/panel_snapshot_options.xml b/indra/newview/skins/default/xui/ja/panel_snapshot_options.xml
index 04dfc0176dca9b55d7c2849eb927ad558a9fc260..f222a4d61a1cf709c043e266250aa07d782f920f 100644
--- a/indra/newview/skins/default/xui/ja/panel_snapshot_options.xml
+++ b/indra/newview/skins/default/xui/ja/panel_snapshot_options.xml
@@ -3,7 +3,7 @@
 	<button label="ディスクに保存" name="save_to_computer_btn"/>
 	<button label="持ち物に保存(L$[AMOUNT])" name="save_to_inventory_btn"/>
 	<button label="プロフィールフィードで共有する" name="save_to_profile_btn"/>
-	<button label="Facebook で共有する" name="send_to_facebook_btn"/>
+	<button label="Facebook でシェア" name="send_to_facebook_btn"/>
 	<button label="Twitter で共有する" name="send_to_twitter_btn"/>
 	<button label="Flickr で共有する" name="send_to_flickr_btn"/>
 	<button label="メールにより送信" name="save_to_email_btn"/>
diff --git a/indra/newview/skins/default/xui/ja/strings.xml b/indra/newview/skins/default/xui/ja/strings.xml
index dcd6e65d34a871ac729f807b972b215141cdb517..d90772ab0a2b5be4dabfaf675811a38875c22a0e 100644
--- a/indra/newview/skins/default/xui/ja/strings.xml
+++ b/indra/newview/skins/default/xui/ja/strings.xml
@@ -186,7 +186,7 @@ LOD ä¿‚æ•°: [LOD_FACTOR]
 	<string name="LoginFailedNoNetwork">
 		ネットワークエラー:接続を確立できませんでした。お使いのネットワーク接続をご確認ください。
 	</string>
-	<string name="LoginFailed">
+	<string name="LoginFailedHeader">
 		ログインに失敗しました。
 	</string>
 	<string name="Quit">
@@ -356,6 +356,24 @@ support@secondlife.com にお問い合わせください。
 	<string name="TestingDisconnect">
 		ビューワの接続を切るテスト中
 	</string>
+	<string name="SocialFacebookConnecting">
+		Facebook に接続中...
+	</string>
+	<string name="SocialFacebookPosting">
+		投稿中...
+	</string>
+	<string name="SocialFacebookDisconnecting">
+		Facebook から切断中...
+	</string>
+	<string name="SocialFacebookErrorConnecting">
+		Facebook への接続時のエラー
+	</string>
+	<string name="SocialFacebookErrorPosting">
+		Facebook への投稿時のエラー
+	</string>
+	<string name="SocialFacebookErrorDisconnecting">
+		Facebook からの切断時のエラー
+	</string>
 	<string name="SocialFlickrConnecting">
 		Flickr に接続中...
 	</string>
@@ -673,9 +691,6 @@ support@secondlife.com にお問い合わせください。
 	<string name="GroupNameNone">
 		(なし)
 	</string>
-	<string name="AvalineCaller">
-		Avaline コール [ORDER]
-	</string>
 	<string name="AssetErrorNone">
 		エラーなし
 	</string>
@@ -2577,9 +2592,21 @@ support@secondlife.com にお問い合わせください。
 	<string name="NoPicksClassifiedsText">
 		ピックやクラシファイド広告を作成していません。 作成するには、下にある「プラス」ボタンをクリックします。
 	</string>
+	<string name="NoPicksText">
+		ピックを作成していません。[新規] ボタンをクリックしてピックを作成する。
+	</string>
+	<string name="NoClassifiedsText">
+		クラシファイド広告を作成していません。[新規] ボタンをクリックしてクラシファイド広告を作成する。
+	</string>
 	<string name="NoAvatarPicksClassifiedsText">
 		ピック、またはクラシファイド広告がありません
 	</string>
+	<string name="NoAvatarPicksText">
+		ピックがありません
+	</string>
+	<string name="NoAvatarClassifiedsText">
+		クラシファイド広告がありません
+	</string>
 	<string name="PicksClassifiedsLoadingText">
 		ローディング...
 	</string>
@@ -4557,6 +4584,9 @@ www.secondlife.com から最新バージョンをダウンロードしてくだ
 	<string name="share_alert">
 		インベントリからここにアイテムをドラッグします
 	</string>
+	<string name="facebook_post_success">
+		Facebook に投稿しました。
+	</string>
 	<string name="flickr_post_success">
 		Flickr に投稿しました。
 	</string>
@@ -5100,7 +5130,7 @@ www.secondlife.com から最新バージョンをダウンロードしてくだ
 	<string name="PremiumMembership">
 		プレミアム
 	</string>
-	<string name="Premium PlusMembership">
+	<string name="Premium_PlusMembership">
 		プレミアムプラス
 	</string>
 	<string name="DeleteItems">
diff --git a/indra/newview/skins/default/xui/pl/floater_picks.xml b/indra/newview/skins/default/xui/pl/floater_picks.xml
deleted file mode 100644
index a329e834dbd498e53b80ffa64c827ccbcd31e53a..0000000000000000000000000000000000000000
--- a/indra/newview/skins/default/xui/pl/floater_picks.xml
+++ /dev/null
@@ -1,2 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
-<floater name="floater_picks" title="Miejsca" />
diff --git a/indra/newview/skins/default/xui/pl/panel_me.xml b/indra/newview/skins/default/xui/pl/panel_me.xml
deleted file mode 100644
index 431929420aa92386b591b55df9192870f4833da7..0000000000000000000000000000000000000000
--- a/indra/newview/skins/default/xui/pl/panel_me.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
-<panel label="Mój Profil" name="panel_me">
-	<panel label="MIEJSCA" name="panel_picks" />
-</panel>
diff --git a/indra/newview/skins/default/xui/pl/panel_region_terrain.xml b/indra/newview/skins/default/xui/pl/panel_region_terrain.xml
index f086a52dcd49f5f3c7495e061c33ff8389f1750f..2d4286334f3c51c6d360048e73fa3343820532ba 100644
--- a/indra/newview/skins/default/xui/pl/panel_region_terrain.xml
+++ b/indra/newview/skins/default/xui/pl/panel_region_terrain.xml
@@ -7,7 +7,7 @@
 	<spinner label="Górny limit terenu" name="terrain_raise_spin" />
 	<spinner label="Dolny limit terenu" name="terrain_lower_spin" />
 	<text name="detail_texture_text">
-		Tekstury terenu (512x512 / 1024x1024, 24 bitowy plik .tga)
+		Tekstury terenu (1024x1024, 24 bitowy plik .tga)
 	</text>
 	<text name="height_text_lbl">
 		1 (Nisko)
diff --git a/indra/newview/skins/default/xui/pl/strings.xml b/indra/newview/skins/default/xui/pl/strings.xml
index cf033df3c9c2933b7c7e4d4a3864995f12c69fe5..90d2d86c025f4519dfa8dbeec38fab9732a497d0 100644
--- a/indra/newview/skins/default/xui/pl/strings.xml
+++ b/indra/newview/skins/default/xui/pl/strings.xml
@@ -143,7 +143,7 @@ Wersja serwera głosu (Voice Server): [VOICE_VERSION]
 	<string name="LoginFailedNoNetwork">
 		Błąd sieci: Brak połączenia z siecią, sprawdź status swojego połączenia internetowego.
 	</string>
-	<string name="LoginFailed">
+	<string name="LoginFailedHeader">
 		Logowanie nie powiodło się.
 	</string>
 	<string name="Quit">
@@ -596,9 +596,6 @@ Spróbuj zalogować się ponownie za minutę.
 	<string name="GroupNameNone">
 		(brak danych)
 	</string>
-	<string name="AvalineCaller">
-		Avaline [ORDER]
-	</string>
 	<string name="AssetErrorNone">
 		Brak błędu
 	</string>
diff --git a/indra/newview/skins/default/xui/pt/floater_about.xml b/indra/newview/skins/default/xui/pt/floater_about.xml
index 65c457f822c067360373a909b462c8e91fff3398..3c0ca332ace3f5c90f24f36a603c90b9c358d2a5 100644
--- a/indra/newview/skins/default/xui/pt/floater_about.xml
+++ b/indra/newview/skins/default/xui/pt/floater_about.xml
@@ -19,7 +19,6 @@ com contribuições de código aberto de:</text>
         expat Copyright (C) 1998, 1999, 2000 Thai Open Source Software Center Ltd.
         FreeType Copyright (C) 1996-2002, 2006 David Turner, Robert Wilhelm, and Werner Lemberg.
         GL Copyright (C) 1999-2004 Brian Paul.
-        GLOD Copyright (C) 2003-04 Jonathan Cohen, Nat Duca, Chris Niski, Johns Hopkins University e David Luebke, Brenden Schubert, University of Virginia.
         google-perftools Copyright (c) 2005, Google Inc.
         Havok.com(TM) Copyright (C) 1999-2001, Telekinesys Research Limited.
         jpeg2000 Copyright (C) 2001, David Taubman, The University of New South Wales (UNSW)
diff --git a/indra/newview/skins/default/xui/pt/floater_inventory_view_finder.xml b/indra/newview/skins/default/xui/pt/floater_inventory_view_finder.xml
index c50d7dcda0d48962f76f1f3e339a5abbb3e9f4ea..a43dec4e7b945de3d7d4ea58d310006d2238b0e3 100644
--- a/indra/newview/skins/default/xui/pt/floater_inventory_view_finder.xml
+++ b/indra/newview/skins/default/xui/pt/floater_inventory_view_finder.xml
@@ -6,7 +6,7 @@
 	<check_box label="Gestos" name="check_gesture"/>
 	<check_box label="Landmarks" name="check_landmark"/>
 	<check_box label="Anotações" name="check_notecard"/>
-	<check_box label="Meshes:" name="check_mesh"/>
+	<check_box label="Malhas" name="check_mesh"/>
 	<check_box label="Objetos" name="check_object"/>
 	<check_box label="Scripts" name="check_script"/>
 	<check_box label="Sons" name="check_sound"/>
diff --git a/indra/newview/skins/default/xui/pt/floater_picks.xml b/indra/newview/skins/default/xui/pt/floater_picks.xml
deleted file mode 100644
index 9766196319af3430471de50b0057d697b4d6de14..0000000000000000000000000000000000000000
--- a/indra/newview/skins/default/xui/pt/floater_picks.xml
+++ /dev/null
@@ -1,2 +0,0 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<floater name="floater_picks" title="Destaques"/>
diff --git a/indra/newview/skins/default/xui/pt/floater_preview_texture.xml b/indra/newview/skins/default/xui/pt/floater_preview_texture.xml
index 6f39635240e1de1f3952fc3785c7926868f13340..90102023a3d579979cf59d4fc3c8e8a065ce2258 100644
--- a/indra/newview/skins/default/xui/pt/floater_preview_texture.xml
+++ b/indra/newview/skins/default/xui/pt/floater_preview_texture.xml
@@ -6,42 +6,23 @@
 	<floater.string name="Copy">
 		Copiar para inventário
 	</floater.string>
-	<text name="desc txt">
-		Descrição:
-	</text>
-	<text name="dimensions">
-		[WIDTH]px x [HEIGHT]px
-	</text>
-	<text name="aspect_ratio">
-		Visualizar relação de aspecto
-	</text>
-	<combo_box name="combo_aspect_ratio" tool_tip="Visualizar com proporção de aspecto fixa">
-		<combo_item name="Unconstrained">
-			Sem limites
-		</combo_item>
-		<combo_item name="1:1" tool_tip="Símbolo ou perfil RW do grupo">
-			1:1
-		</combo_item>
-		<combo_item name="4:3" tool_tip="[SECOND_LIFE] perfil">
-			4:3
-		</combo_item>
-		<combo_item name="10:7" tool_tip="Procurar anúncios classificados e marcos">
-			10:7
-		</combo_item>
-		<combo_item name="3:2" tool_tip="Sobre terrenos">
-			3:2
-		</combo_item>
-		<combo_item name="16:10">
-			16:10
-		</combo_item>
-		<combo_item name="16:9" tool_tip="Perfis destacados">
-			16:9
-		</combo_item>
-		<combo_item name="2:1">
-			2:1
-		</combo_item>
-	</combo_box>
-	<button label="OK" name="Keep"/>
-	<button label="Descartar" name="Discard"/>
-	<button label="Salvar como" name="save_tex_btn"/>
+	<layout_stack name="preview_stack">
+		<layout_panel name="texture_panel">
+			<text name="desc txt">
+				Descrição:
+			</text>
+			<text name="dimensions">
+				[WIDTH]px x [HEIGHT]px
+			</text>
+			<text name="aspect_ratio">
+				Visualizar relação de aspecto
+			</text>
+			<combo_box name="combo_aspect_ratio" tool_tip="Visualizar com proporção de aspecto fixa"/>
+		</layout_panel>
+		<layout_panel name="buttons_panel">
+			<button label="OK" name="Keep"/>
+			<button label="Descartar" name="Discard"/>
+			<button label="Salvar como" name="save_tex_btn"/>
+		</layout_panel>
+	</layout_stack>
 </floater>
diff --git a/indra/newview/skins/default/xui/pt/floater_profile.xml b/indra/newview/skins/default/xui/pt/floater_profile.xml
new file mode 100644
index 0000000000000000000000000000000000000000..0327211d8f27c87c9ef52af8d258d3a264624814
--- /dev/null
+++ b/indra/newview/skins/default/xui/pt/floater_profile.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<floater name="avatarinfo" title="Perfil">
+	<panel name="panel_profile_view">
+		<tab_container name="panel_profile_tabs">
+			<panel label="Second Life" name="panel_profile_secondlife"/>
+			<panel label="Web" name="panel_profile_web"/>
+			<panel label="Interesses" name="panel_profile_interests"/>
+			<panel label="Destaques" name="panel_profile_picks"/>
+			<panel label="Anúncio" name="panel_profile_classifieds"/>
+			<panel label="Vida real" name="panel_profile_firstlife"/>
+			<panel label="Observações" name="panel_profile_notes"/>
+		</tab_container>
+		<button label="OK" name="ok_btn" tool_tip="Salvar alterações do perfil e fechar"/>
+		<button label="Cancelar" label_selected="Cancelar" name="cancel_btn"/>
+	</panel>
+</floater>
diff --git a/indra/newview/skins/default/xui/pt/floater_snapshot.xml b/indra/newview/skins/default/xui/pt/floater_snapshot.xml
index e3812ed708ec91472e0a55beb50ed9f37d793d07..89901b539f69916ddddedcd32f59d0511853a08f 100644
--- a/indra/newview/skins/default/xui/pt/floater_snapshot.xml
+++ b/indra/newview/skins/default/xui/pt/floater_snapshot.xml
@@ -6,6 +6,9 @@
 	<string name="postcard_progress_str">
 		Enviando e-mail
 	</string>
+	<string name="facebook_progress_str">
+		Como publicar no Facebook
+	</string>
 	<string name="profile_progress_str">
 		Postando
 	</string>
@@ -15,6 +18,9 @@
 	<string name="local_progress_str">
 		Salvo no computador
 	</string>
+	<string name="facebook_succeeded_str">
+		Imagem carregada
+	</string>
 	<string name="profile_succeeded_str">
 		Imagem carregada
 	</string>
@@ -27,6 +33,9 @@
 	<string name="local_succeeded_str">
 		Salvo no computador!
 	</string>
+	<string name="facebook_failed_str">
+		Falha ao carregar a imagem na sua linha do tempo no Facebook.
+	</string>
 	<string name="profile_failed_str">
 		Falha ao carregar a imagem no feed do seu perfil.
 	</string>
diff --git a/indra/newview/skins/default/xui/pt/menu_name_field.xml b/indra/newview/skins/default/xui/pt/menu_name_field.xml
new file mode 100644
index 0000000000000000000000000000000000000000..2157de9813a2d7b9ec12e6186f160c896e8d01dc
--- /dev/null
+++ b/indra/newview/skins/default/xui/pt/menu_name_field.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<toggleable_menu name="CopyMenu">
+	<menu_item_call label="Exibir Cópia do Nome" name="copy_display"/>
+	<menu_item_call label="Copiar Nome do Agente" name="copy_name"/>
+	<menu_item_call label="Copiar Id do Agente" name="copy_id"/>
+</toggleable_menu>
diff --git a/indra/newview/skins/default/xui/pt/notifications.xml b/indra/newview/skins/default/xui/pt/notifications.xml
index bd1185bdd28a45c05be9e900cbf56cd666f3c3aa..733ec2c70993faf78ea3909d252286643b70a080 100644
--- a/indra/newview/skins/default/xui/pt/notifications.xml
+++ b/indra/newview/skins/default/xui/pt/notifications.xml
@@ -2673,6 +2673,9 @@ Selecione só um objeto.
 	<notification name="SystemMessage">
 		[MESSAGE]
 	</notification>
+	<notification name="FacebookConnect">
+		[MESSAGE]
+	</notification>
 	<notification name="FlickrConnect">
 		[MESSAGE]
 	</notification>
diff --git a/indra/newview/skins/default/xui/pt/panel_edit_classified.xml b/indra/newview/skins/default/xui/pt/panel_edit_classified.xml
index 23e00bfc3adad2faf5b6e1bddc54bb47763e6deb..7b27c811f53a9a6b52b648c0c8e129669c44afde 100644
--- a/indra/newview/skins/default/xui/pt/panel_edit_classified.xml
+++ b/indra/newview/skins/default/xui/pt/panel_edit_classified.xml
@@ -46,7 +46,7 @@
 			<layout_panel name="save_changes_btn_lp">
 				<button label="[LABEL]" name="save_changes_btn"/>
 			</layout_panel>
-			<layout_panel name="show_on_map_btn_lp">
+			<layout_panel name="cancel_btn_lp">
 				<button label="Cancelar" name="cancel_btn"/>
 			</layout_panel>
 		</layout_stack>
diff --git a/indra/newview/skins/default/xui/pt/panel_group_general.xml b/indra/newview/skins/default/xui/pt/panel_group_general.xml
index 64a7d13fdb4fc999b20741ddffa772ddeb1103da..f6c6d11b87b13d206efaf34a1cb3d009ea068af9 100644
--- a/indra/newview/skins/default/xui/pt/panel_group_general.xml
+++ b/indra/newview/skins/default/xui/pt/panel_group_general.xml
@@ -46,7 +46,7 @@ Para obter mais ajuda, passe o mouse sobre as opções.
 		<check_box label="Qualquer um pode entrar" name="open_enrollement" tool_tip="Controla a entrada de novos membros, com ou sem convite."/>
 		<check_box label="Taxa de inscrição" name="check_enrollment_fee" tool_tip="Controla a cobrança de uma taxa de associação ao grupo."/>
 		<spinner label="L$" left_delta="120" name="spin_enrollment_fee" tool_tip="Se a opção &apos;Taxa de associação&apos; estiver marcada, novos membros precisam pagar o valor definido para entrar no grupo." width="60"/>
-		<combo_box name="group_mature_check" tool_tip="Os níveis de maturidade determinam o tipo de conteúdo e comportamento permitidos em um grupo" width="170">
+		<combo_box name="group_mature_check" tool_tip="Definir se o seu grupo contém informações classificadas como Moderado" width="170">
 			<combo_item name="select_mature">
 				- Selecione o nível de maturidade -
 			</combo_item>
diff --git a/indra/newview/skins/default/xui/pt/panel_group_list_item_short.xml b/indra/newview/skins/default/xui/pt/panel_group_list_item_short.xml
new file mode 100644
index 0000000000000000000000000000000000000000..0490878507727dcbf979b2441d1f28546333db49
--- /dev/null
+++ b/indra/newview/skins/default/xui/pt/panel_group_list_item_short.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="group_list_item">
+	<text name="group_name" value="Desconhecido"/>
+	<button name="info_btn" tool_tip="Mais informações"/>
+	<button name="profile_btn" tool_tip="Ver perfil"/>
+</panel>
diff --git a/indra/newview/skins/default/xui/pt/panel_me.xml b/indra/newview/skins/default/xui/pt/panel_me.xml
deleted file mode 100644
index 281c886bd490c440f1de2d63c734469a62995a17..0000000000000000000000000000000000000000
--- a/indra/newview/skins/default/xui/pt/panel_me.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<panel label="Meu perfil" name="panel_me">
-	<panel label="MEUS DESTAQUES" name="panel_picks"/>
-</panel>
diff --git a/indra/newview/skins/default/xui/pt/panel_people.xml b/indra/newview/skins/default/xui/pt/panel_people.xml
index 2ef01841c5f24e01bf6342887f86099f5e712ed5..ce50449b03a92b2892d3f480f23afe2ab12992c5 100644
--- a/indra/newview/skins/default/xui/pt/panel_people.xml
+++ b/indra/newview/skins/default/xui/pt/panel_people.xml
@@ -40,6 +40,7 @@ Em busca de alguém para conversar? Procure no [secondlife:///app/worldmap Mapa-
 			<accordion name="friends_accordion">
 				<accordion_tab name="tab_online" title="Online"/>
 				<accordion_tab name="tab_all" title="Todos"/>
+				<accordion_tab name="tab_suggested_friends" title="Pessoas que talvez você deseje adicionar"/>
 			</accordion>
 		</panel>
 		<panel label="GRUPOS" name="groups_panel">
diff --git a/indra/newview/skins/default/xui/pt/panel_profile_classified.xml b/indra/newview/skins/default/xui/pt/panel_profile_classified.xml
new file mode 100644
index 0000000000000000000000000000000000000000..b43a0ad9f2df2293c4312e2d13f6d04eecb0c750
--- /dev/null
+++ b/indra/newview/skins/default/xui/pt/panel_profile_classified.xml
@@ -0,0 +1,110 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="panel_profile_classified">
+	<panel.string name="type_mature">
+		Moderado
+	</panel.string>
+	<panel.string name="type_pg">
+		Conteúdo Geral
+	</panel.string>
+	<panel.string name="l$_price">
+		L$[PRICE]-
+	</panel.string>
+	<panel.string name="click_through_text_fmt">
+		[TELEPORT] teletransporte, [MAP] mapa, [PROFILE] perfil
+	</panel.string>
+	<panel.string name="date_fmt">
+		[mthnum,datetime,slt]/[day,datetime,slt]/[year,datetime,slt]
+	</panel.string>
+	<panel.string name="auto_renew_on">
+		Ativado
+	</panel.string>
+	<panel.string name="auto_renew_off">
+		Desativado
+	</panel.string>
+	<panel.string name="location_notice">
+		(salvar para atualizar)
+	</panel.string>
+	<string name="publish_label">
+		Publicar
+	</string>
+	<string name="save_label">
+		Salvar
+	</string>
+	<scroll_container name="profile_scroll">
+		<panel name="info_scroll_content_panel">
+			<icon label="" name="edit_icon" tool_tip="Selecione uma imagem"/>
+			<layout_stack name="info_panel">
+				<layout_panel name="main_info_panel">
+					<text_editor name="classified_name">
+						[name]
+					</text_editor>
+					<text name="classified_location_label" value="Localização:"/>
+					<text_editor name="classified_location" value="[loading...]"/>
+					<text name="content_type_label" value="Tipo de conteúdo:"/>
+					<text_editor name="content_type" value="[content type]"/>
+					<text name="category_label" value="Categoria:"/>
+					<text_editor name="category" value="[category]"/>
+					<text name="creation_date_label" value="Data de criação:"/>
+					<text_editor name="creation_date" tool_tip="Data de criação" value="[date]"/>
+					<text name="price_for_listing_label" value="Preço do anúncio:"/>
+					<text_editor name="price_for_listing" tool_tip="Preço do anúncio.">
+						[PRICE]
+					</text_editor>
+				</layout_panel>
+				<layout_panel name="clickthrough_layout_panel">
+					<text name="click_through_label" value="Cliques:"/>
+					<text_editor name="click_through_text" tool_tip="Dados de click-through" value="[clicks]"/>
+				</layout_panel>
+				<layout_panel name="auto_renew_layout_panel">
+					<text name="auto_renew_label" value="Renovação automática:"/>
+					<text name="auto_renew" value="Ativado"/>
+				</layout_panel>
+				<layout_panel name="descr_layout_panel">
+					<text name="classified_desc_label" value="Descrição:"/>
+					<text_editor name="classified_desc" value="[description]"/>
+				</layout_panel>
+			</layout_stack>
+			<panel name="edit_panel">
+				<text name="Name:">
+					Título:
+				</text>
+				<text name="description_label">
+					Descrição:
+				</text>
+				<text name="location_label">
+					Localização:
+				</text>
+				<text name="classified_location_edit">
+					Carregando...
+				</text>
+				<button label="Usar configuração local" name="set_to_curr_location_btn"/>
+				<text name="category_label" value="Categoria:"/>
+				<text name="content_type_label" value="Tipo de conteúdo:"/>
+				<icons_combo_box label="Conteúdo Geral" name="content_type_edit">
+					<icons_combo_box.item label="Conteúdo Moderado" name="mature_ci" value="Moderado"/>
+					<icons_combo_box.item label="Conteúdo Geral" name="pg_ci" value="Adequado para menores"/>
+				</icons_combo_box>
+				<check_box label="Renovar automaticamente todas as semanas" name="auto_renew_edit"/>
+				<text name="price_for_listing_edit_label" value="Preço do anúncio:"/>
+				<spinner label="L$" name="price_for_listing_edit" tool_tip="Preço do anúncio." value="50"/>
+			</panel>
+		</panel>
+	</scroll_container>
+	<layout_stack name="edit_btns_pnl">
+		<layout_panel name="teleport_btn_lp">
+			<button label="Teletransportar" name="teleport_btn"/>
+		</layout_panel>
+		<layout_panel name="map_btn_lp">
+			<button label="Mapa" name="show_on_map_btn"/>
+		</layout_panel>
+		<layout_panel name="edit_btn_lp">
+			<button label="Editar" name="edit_btn"/>
+		</layout_panel>
+		<layout_panel name="save_btn_lp">
+			<button label="[LABEL]" name="save_changes_btn"/>
+		</layout_panel>
+		<layout_panel name="cancel_btn_lp">
+			<button label="Cancelar" name="cancel_btn"/>
+		</layout_panel>
+	</layout_stack>
+</panel>
diff --git a/indra/newview/skins/default/xui/pt/panel_profile_classifieds.xml b/indra/newview/skins/default/xui/pt/panel_profile_classifieds.xml
new file mode 100644
index 0000000000000000000000000000000000000000..f8369954fd088806a16705dc503f9f4e224d184a
--- /dev/null
+++ b/indra/newview/skins/default/xui/pt/panel_profile_classifieds.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel label="Anúncio" name="panel_profile_classifieds">
+	<string name="no_classifieds" value="Nenhum classificado"/>
+	<button label="Novo..." name="new_btn"/>
+	<button label="Excluir..." name="delete_btn"/>
+	<text name="classifieds_panel_text">
+		Carregando...
+	</text>
+</panel>
diff --git a/indra/newview/skins/default/xui/it/floater_picks.xml b/indra/newview/skins/default/xui/pt/panel_profile_firstlife.xml
similarity index 50%
rename from indra/newview/skins/default/xui/it/floater_picks.xml
rename to indra/newview/skins/default/xui/pt/panel_profile_firstlife.xml
index dfc539da669fba14c7ec8688cd9c7e66b692daf1..0fb502e4419596d8de32e3a6d2180ca072dde451 100644
--- a/indra/newview/skins/default/xui/it/floater_picks.xml
+++ b/indra/newview/skins/default/xui/pt/panel_profile_firstlife.xml
@@ -1,2 +1,2 @@
 <?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<floater name="floater_picks" title="Preferiti"/>
+<panel label="Perfil" name="panel_profile_firstlife"/>
diff --git a/indra/newview/skins/default/xui/pt/panel_profile_interests.xml b/indra/newview/skins/default/xui/pt/panel_profile_interests.xml
new file mode 100644
index 0000000000000000000000000000000000000000..edf74115f2b67ecbcefae53da49e73ace97c1717
--- /dev/null
+++ b/indra/newview/skins/default/xui/pt/panel_profile_interests.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel label="Interesses" name="panel_profile_interests">
+	<text name="I Want To:">
+		Quero:
+	</text>
+	<check_box label="Crie" name="chk0"/>
+	<check_box label="Explore" name="chk1"/>
+	<check_box label="Encontrar" name="chk2"/>
+	<check_box label="Seja contratado" name="chk6"/>
+	<check_box label="Grupo" name="chk3"/>
+	<check_box label="Comprar" name="chk4"/>
+	<check_box label="Venda" name="chk5"/>
+	<check_box label="Contratar" name="chk7"/>
+	<line_editor name="want_to_edit">
+		(carregando...)
+	</line_editor>
+	<text name="Skills:">
+		Habilidades:
+	</text>
+	<check_box label="Texturas" name="schk0"/>
+	<check_box label="Arquitetura" name="schk1"/>
+	<check_box label="Modelo" name="schk3"/>
+	<check_box label="Planejamento de evento" name="schk2"/>
+	<check_box label="Scripts" name="schk4"/>
+	<check_box label="Personagens personalizados" name="schk5"/>
+	<line_editor name="skills_edit">
+		(carregando...)
+	</line_editor>
+	<text name="Languages:">
+		Idiomas:
+	</text>
+	<line_editor name="languages_edit">
+		(carregando...)
+	</line_editor>
+</panel>
diff --git a/indra/newview/skins/default/xui/pt/panel_profile_notes.xml b/indra/newview/skins/default/xui/pt/panel_profile_notes.xml
new file mode 100644
index 0000000000000000000000000000000000000000..499e371bb7d77b7bf4e244c197e93308b0b3e3b4
--- /dev/null
+++ b/indra/newview/skins/default/xui/pt/panel_profile_notes.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel label="Anotações e Privacidade" name="panel_notes">
+	<text name="status_message" value="Notas particulares neste avatar:"/>
+	<text name="status_message2" value="Permitir que esse avatar:"/>
+	<check_box label="Ver quando eu estiver conectado" name="status_check"/>
+	<check_box label="Encontre-me no mapa-múndi" name="map_check"/>
+	<check_box label="Pegar, editar ou excluir objetos meus" name="objects_check"/>
+</panel>
diff --git a/indra/newview/skins/default/xui/pt/panel_profile_pick.xml b/indra/newview/skins/default/xui/pt/panel_profile_pick.xml
new file mode 100644
index 0000000000000000000000000000000000000000..2dd37b38f9094815a1fd1320cb874a4bea08f22f
--- /dev/null
+++ b/indra/newview/skins/default/xui/pt/panel_profile_pick.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="panel_pick_info">
+	<panel.string name="location_notice">
+		(salvar para atualizar)
+	</panel.string>
+	<line_editor name="pick_location">
+		Carregando...
+	</line_editor>
+	<button label="Teletransportar" name="teleport_btn"/>
+	<button label="Mostrar no mapa" name="show_on_map_btn"/>
+	<button label="Definir Localização" name="set_to_curr_location_btn" tool_tip="Usar configuração local"/>
+	<button label="Salvar destaque" name="save_changes_btn"/>
+</panel>
diff --git a/indra/newview/skins/default/xui/pt/panel_profile_picks.xml b/indra/newview/skins/default/xui/pt/panel_profile_picks.xml
new file mode 100644
index 0000000000000000000000000000000000000000..f9ead974dc4f85798ae479589eabd294be70c88d
--- /dev/null
+++ b/indra/newview/skins/default/xui/pt/panel_profile_picks.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel label="Destaques" name="panel_picks">
+	<string name="no_picks" value="Nenhum"/>
+	<text name="Tell everyone about your favorite places in Second Life.">
+		Conte a todos sobre os seu lugares favoritos no Second Life.
+	</text>
+	<button label="Novo..." name="new_btn"/>
+	<button label="Excluir..." name="delete_btn"/>
+	<text name="picks_panel_text">
+		Carregando...
+	</text>
+</panel>
diff --git a/indra/newview/skins/default/xui/pt/panel_profile_secondlife.xml b/indra/newview/skins/default/xui/pt/panel_profile_secondlife.xml
new file mode 100644
index 0000000000000000000000000000000000000000..8723b1bf58b38c9837af10df92775549508a0e52
--- /dev/null
+++ b/indra/newview/skins/default/xui/pt/panel_profile_secondlife.xml
@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel label="Perfil" name="panel_profile">
+	<string name="status_online">
+		Atualmente Online
+	</string>
+	<string name="status_offline">
+		Atualmente Offline
+	</string>
+	<string name="CaptionTextAcctInfo">
+		[ACCTTYPE]
+[PAYMENTINFO]
+	</string>
+	<string name="payment_update_link_url">
+		http://www.secondlife.com/account/billing.php?lang=en
+	</string>
+	<string name="partner_edit_link_url">
+		http://www.secondlife.com/account/partners.php?lang=en
+	</string>
+	<string name="my_account_link_url" value="http://secondlife.com/account"/>
+	<string name="no_partner_text" value="Nenhum"/>
+	<string name="no_group_text" value="Nenhum"/>
+	<string name="RegisterDateFormat">
+		[REG_DATE]
+	</string>
+	<string name="name_text_args">
+		[NAME]
+	</string>
+	<string name="display_name_text_args">
+		[DISPLAY_NAME]
+	</string>
+	<string name="FSDev" value="Desenvolvedor"/>
+	<string name="FSSupp" value="Suporte"/>
+	<string name="FSQualityAssurance" value="Caçador de Bug"/>
+	<string name="FSGW" value="Gateway"/>
+	<text name="name_label" value="Nome:"/>
+	<button label="Nome:" name="set_name" tool_tip="Definir nome de tela"/>
+	<panel name="name_holder">
+		<text_editor name="complete_name" value="(carregando...)"/>
+	</panel>
+	<layout_stack name="imagepositioner">
+		<layout_panel name="label_stack">
+			<text name="status" value="Status desconhecido"/>
+			<text name="label" value="Aniversário Second Life:"/>
+			<text name="label2" value="Conta:"/>
+			<text name="partner_label" value="Parceiro(a):"/>
+		</layout_panel>
+	</layout_stack>
+	<text name="Groups:" value="Grupos:"/>
+	<button label="+" label_selected="+" name="group_invite" tool_tip="Convidar para entrar no grupo"/>
+	<layout_stack name="aboutpositioner">
+		<layout_panel name="about_stack">
+			<text name="About:" value="Sobre:"/>
+		</layout_panel>
+		<layout_panel name="give_stack">
+			<text name="Give item:" value="Dar o item:"/>
+			<text name="Give inventory" tool_tip="Arraste e solte o item novo do inventário aqui para dá-los a esta pessoa.">
+				Arraste e solte o item novo do inventário aqui.
+			</text>
+		</layout_panel>
+	</layout_stack>
+	<layout_stack name="buttonstack">
+		<layout_panel name="left_buttonstack">
+			<button label="Localizar no mapa" label_selected="Localizar no mapa" name="show_on_map_btn" tool_tip="Localizar o Residente no mapa"/>
+			<button label="Pagar" label_selected="Pagar" name="pay" tool_tip="Pague em dinheiro para o Residente"/>
+		</layout_panel>
+		<layout_panel name="middle_buttonstack">
+			<button label="Teletransportar?" label_selected="Teletransportar?" name="teleport" tool_tip="Oferecer teletransporte ao Residente"/>
+			<button label="Mensagem instantânea" label_selected="Mensagem instantânea" name="im" tool_tip="Abrir sessão de mensagem instantânea"/>
+		</layout_panel>
+		<layout_panel name="right_buttonstack">
+			<button label="Adicionar amigo" label_selected="Adicionar amigo" name="add_friend" tool_tip="Oferecer amizade ao residente"/>
+			<button label="Bloquear" name="block" tool_tip="Bloquear este Residente"/>
+			<button label="Desbloquear" name="unblock" tool_tip="Desbloquear este Residente"/>
+		</layout_panel>
+	</layout_stack>
+	<check_box label="Mostrar nos resultados de busca" name="show_in_search_checkbox"/>
+</panel>
diff --git a/indra/newview/skins/default/xui/pt/panel_profile_web.xml b/indra/newview/skins/default/xui/pt/panel_profile_web.xml
new file mode 100644
index 0000000000000000000000000000000000000000..0f556c7dad8fbc8042440267b75b8a1330509958
--- /dev/null
+++ b/indra/newview/skins/default/xui/pt/panel_profile_web.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel label="Web" name="panel_profile_web">
+	<panel.string name="LoadTime" value="Carregar tempo: [TIME] segundos"/>
+	<line_editor name="url_edit">
+		(carregando..)
+	</line_editor>
+	<flyout_button label="Carregar" name="load" tool_tip="Carregar esta página de perfil com navegador embutido">
+		<flyout_button.item label="Abrir no visualizador do navegador" name="open_item"/>
+		<flyout_button.item label="Abrir no navegador externo" name="home_item"/>
+	</flyout_button>
+	<button name="web_profile_popout_btn" tool_tip="Abra o perfil da web"/>
+</panel>
diff --git a/indra/newview/skins/default/xui/pt/panel_region_terrain.xml b/indra/newview/skins/default/xui/pt/panel_region_terrain.xml
index 74330a8946ee626584c145054261954f84acb626..1d312aeed94624045c39a3b86bb728362fbb1ad9 100644
--- a/indra/newview/skins/default/xui/pt/panel_region_terrain.xml
+++ b/indra/newview/skins/default/xui/pt/panel_region_terrain.xml
@@ -12,8 +12,8 @@ terreno" name="terrain_raise_spin"/>
 	<spinner bottom_delta="-34" label="Limite mais baixo do 
 terreno" name="terrain_lower_spin"/>
 	<text name="detail_texture_text">
-		Texturas de terreno (exige arquivos .tga 512x512, 24 bit)
-	</text>
+    Texturas de terreno (exige arquivos .tga 1024x1024, 24 bit)
+  </text>
 	<text name="height_text_lbl">
 		1 (Baixo)
 	</text>
diff --git a/indra/newview/skins/default/xui/pt/strings.xml b/indra/newview/skins/default/xui/pt/strings.xml
index c72a41fd3a068af80b775e765ee037fd3aa35adc..ae452d6a4d5e47c4c23e082ee5ae408927fbc23d 100644
--- a/indra/newview/skins/default/xui/pt/strings.xml
+++ b/indra/newview/skins/default/xui/pt/strings.xml
@@ -47,7 +47,7 @@ Placa de vídeo: [GRAPHICS_CARD_VENDOR]
 Placa gráfica: [GRAPHICS_CARD]
 	</string>
 	<string name="AboutDriver">
-		Versão do driver de vídeo Windows: [GRAPHICS_CARD_VENDOR]
+		Versão do driver de vídeo Windows: [GRAPHICS_DRIVER_VERSION]
 	</string>
 	<string name="AboutOGL">
 		Versão do OpenGL: [OPENGL_VERSION]
@@ -178,7 +178,7 @@ Versão do servidor de voz: [VOICE_VERSION]
 	<string name="LoginFailedNoNetwork">
 		Erro de rede: Falha de conexão: verifique sua conexão à internet.
 	</string>
-	<string name="LoginFailed">
+	<string name="LoginFailedHeader">
 		Falha do login.
 	</string>
 	<string name="Quit">
@@ -313,6 +313,24 @@ Aguarde um minuto antes que tentar logar-se novamente.
 	<string name="TestingDisconnect">
 		Teste de desconexão
 	</string>
+	<string name="SocialFacebookConnecting">
+		Conectando ao Facebook...
+	</string>
+	<string name="SocialFacebookPosting">
+		Publicando...
+	</string>
+	<string name="SocialFacebookDisconnecting">
+		Desconectando do Facebook...
+	</string>
+	<string name="SocialFacebookErrorConnecting">
+		Problema ao conectar ao Facebook
+	</string>
+	<string name="SocialFacebookErrorPosting">
+		Problema ao publicar no Facebook
+	</string>
+	<string name="SocialFacebookErrorDisconnecting">
+		Problema ao desconectar do Facebook
+	</string>
 	<string name="SocialFlickrConnecting">
 		Conectando ao Flickr...
 	</string>
@@ -627,9 +645,6 @@ ser anexado às anotações.
 	<string name="GroupNameNone">
 		(nenhum)
 	</string>
-	<string name="AvalineCaller">
-		Interlocutor Avaline [ORDER]
-	</string>
 	<string name="AssetErrorNone">
 		Nenhum erro
 	</string>
@@ -2517,9 +2532,21 @@ Se você continuar a receber essa mensagem, entre em contato com o suporte do Se
 	<string name="NoPicksClassifiedsText">
 		Você não criou nenhum Destaque ou Anúncio.  Clique no botão &quot;+&quot; para criar um Destaque ou Anúncio.
 	</string>
+	<string name="NoPicksText">
+		Você não criou nenhuma Escolha. Clique em Novo Botão para criar um Escolher
+	</string>
+	<string name="NoClassifiedsText">
+		Você criou nenhum Anúncio. Clique em Novo Botão para criar um Classificado
+	</string>
 	<string name="NoAvatarPicksClassifiedsText">
 		O usuário não tem nenhum destaque ou anúncio
 	</string>
+	<string name="NoAvatarPicksText">
+		Usuário não tem escolha
+	</string>
+	<string name="NoAvatarClassifiedsText">
+		Usuário não tem anúncio
+	</string>
 	<string name="PicksClassifiedsLoadingText">
 		Carregando...
 	</string>
@@ -4433,6 +4460,9 @@ If you continue to receive this message, contact the [SUPPORT_SITE].
 	<string name="inventory_folder_offered-im">
 		Pasta do inventário &apos;[ITEM_NAME]&apos; oferecida
 	</string>
+	<string name="facebook_post_success">
+		Você publicou no Facebook.
+	</string>
 	<string name="flickr_post_success">
 		Você publicou no Flickr.
 	</string>
diff --git a/indra/newview/skins/default/xui/ru/floater_about.xml b/indra/newview/skins/default/xui/ru/floater_about.xml
index ee9f82847d10856766b00020e4297383edfd7485..44216e04306fb6034b3a20ed3397813a1b1141ed 100644
--- a/indra/newview/skins/default/xui/ru/floater_about.xml
+++ b/indra/newview/skins/default/xui/ru/floater_about.xml
@@ -19,7 +19,6 @@
         expat (C) 1998, 1999, 2000 Thai Open Source Software Center Ltd.
         FreeType (C) 1996-2002, 2006 David Turner, Robert Wilhelm и Werner Lemberg.
         GL (C) 1999-2004 Brian Paul.
-        GLOD (C) 2003-04 Jonathan Cohen, Nat Duca, Chris Niski, Университет Джона Гопкинса и David Luebke, Brenden Schubert, Университет Вирджинии.
         google-perftools (c) 2005, Google Inc.
         Havok.com(TM) (C) 1999-2001, Telekinesys Research Limited.
         jpeg2000 (C) 2001, David Taubman, Университет Нового Южного Уэльса (UNSW)
diff --git a/indra/newview/skins/default/xui/ru/floater_inventory_view_finder.xml b/indra/newview/skins/default/xui/ru/floater_inventory_view_finder.xml
index 7c1d3b52c5f22fbcb9b1c18c71cc60f972a06863..bf90d898f90e0e8bd40585564a750de5a2d51086 100644
--- a/indra/newview/skins/default/xui/ru/floater_inventory_view_finder.xml
+++ b/indra/newview/skins/default/xui/ru/floater_inventory_view_finder.xml
@@ -6,7 +6,7 @@
 	<check_box label="Жесты" name="check_gesture"/>
 	<check_box label="Закладки" name="check_landmark"/>
 	<check_box label="Заметки" name="check_notecard"/>
-	<check_box label="Меши" name="check_mesh"/>
+	<check_box label="Полисетки" name="check_mesh"/>
 	<check_box label="Объекты" name="check_object"/>
 	<check_box label="Скрипты" name="check_script"/>
 	<check_box label="Звуки" name="check_sound"/>
diff --git a/indra/newview/skins/default/xui/ru/floater_picks.xml b/indra/newview/skins/default/xui/ru/floater_picks.xml
deleted file mode 100644
index e0ae8d6f0346c828fd2e50ca44451846f01b5519..0000000000000000000000000000000000000000
--- a/indra/newview/skins/default/xui/ru/floater_picks.xml
+++ /dev/null
@@ -1,2 +0,0 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<floater name="floater_picks" title="Подборка"/>
diff --git a/indra/newview/skins/default/xui/ru/floater_preview_texture.xml b/indra/newview/skins/default/xui/ru/floater_preview_texture.xml
index 46d2a37503f399e58352f8b0ef6a5be4437fc8f2..e3921a75ac82ea924486e2c828e01eeca99f7c9d 100644
--- a/indra/newview/skins/default/xui/ru/floater_preview_texture.xml
+++ b/indra/newview/skins/default/xui/ru/floater_preview_texture.xml
@@ -6,42 +6,23 @@
 	<floater.string name="Copy">
 		Копировать в инвентарь
 	</floater.string>
-	<text name="desc txt">
-		Описание:
-	</text>
-	<text name="dimensions">
-		[WIDTH]пикселей x [HEIGHT]пикселей
-	</text>
-	<text name="aspect_ratio">
-		Просмотр изображения с соотношением сторон
-	</text>
-	<combo_box name="combo_aspect_ratio" tool_tip="Просмотр изображения с фиксированным соотношением сторон">
-		<combo_item name="Unconstrained">
-			Без ограничения
-		</combo_item>
-		<combo_item name="1:1" tool_tip="Символ группы или профиль в реальном мире">
-			1:1
-		</combo_item>
-		<combo_item name="4:3" tool_tip="Профиль для [SECOND_LIFE]">
-			4:3
-		</combo_item>
-		<combo_item name="10:7" tool_tip="Реклама, поиск и закладки">
-			10:7
-		</combo_item>
-		<combo_item name="3:2" tool_tip="О земле">
-			3:2
-		</combo_item>
-		<combo_item name="16:10">
-			16:10
-		</combo_item>
-		<combo_item name="16:9" tool_tip="Профиль подборки">
-			16:9
-		</combo_item>
-		<combo_item name="2:1">
-			2:1
-		</combo_item>
-	</combo_box>
-	<button label="OK" name="Keep"/>
-	<button label="Отменить" name="Discard"/>
-	<button label="Сохранить как" name="save_tex_btn"/>
+	<layout_stack name="preview_stack">
+		<layout_panel name="texture_panel">
+			<text name="desc txt">
+				Описание:
+			</text>
+			<text name="dimensions">
+				[WIDTH]пикселей x [HEIGHT]пикселей
+			</text>
+			<text name="aspect_ratio">
+				Предварительный просмотр соотношения сторон
+			</text>
+			<combo_box name="combo_aspect_ratio" tool_tip="Просмотр изображения с фиксированным соотношением сторон"/>
+		</layout_panel>
+		<layout_panel name="buttons_panel">
+			<button label="OK" name="Keep"/>
+			<button label="Сбросить" name="Discard"/>
+			<button label="Сохранить как" name="save_tex_btn"/>
+		</layout_panel>
+	</layout_stack>
 </floater>
diff --git a/indra/newview/skins/default/xui/ru/floater_profile.xml b/indra/newview/skins/default/xui/ru/floater_profile.xml
new file mode 100644
index 0000000000000000000000000000000000000000..6f8daf0a628f125fcb15f34be8fce045d279cbe8
--- /dev/null
+++ b/indra/newview/skins/default/xui/ru/floater_profile.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<floater name="avatarinfo" title="Профиль">
+	<panel name="panel_profile_view">
+		<tab_container name="panel_profile_tabs">
+			<panel label="Second Life" name="panel_profile_secondlife"/>
+			<panel label="Веб" name="panel_profile_web"/>
+			<panel label="Круг интересов" name="panel_profile_interests"/>
+			<panel label="Подборка" name="panel_profile_picks"/>
+			<panel label="Объявление" name="panel_profile_classifieds"/>
+			<panel label="Реальная жизнь" name="panel_profile_firstlife"/>
+			<panel label="Примечания" name="panel_profile_notes"/>
+		</tab_container>
+		<button label="OK" name="ok_btn" tool_tip="Сохранить изменения в профиле и закрыть"/>
+		<button label="Отменить" label_selected="Отменить" name="cancel_btn"/>
+	</panel>
+</floater>
diff --git a/indra/newview/skins/default/xui/ru/floater_report_abuse.xml b/indra/newview/skins/default/xui/ru/floater_report_abuse.xml
index 3ac8cb74b4e5110f4a7ff464d89f16f0d63f9c92..89a453d9cd94d4708c13cf5eab7d24718b89f9a0 100644
--- a/indra/newview/skins/default/xui/ru/floater_report_abuse.xml
+++ b/indra/newview/skins/default/xui/ru/floater_report_abuse.xml
@@ -67,7 +67,7 @@
 		<combo_box.item label="Земля &gt; Посягательство &gt; Объекты или текстуры" name="Land__Encroachment__Objects_textures"/>
 		<combo_box.item label="Земля &gt; Посягательство &gt; Частицы" name="Land__Encroachment__Particles"/>
 		<combo_box.item label="Земля &gt; Посягательство &gt; Деревья/растения" name="Land__Encroachment__Trees_plants"/>
-		<combo_box.item label="Нарушение правил игр на ловкость" name="Wagering_gambling"/>
+		<combo_box.item label="Нарушение игровых правил" name="Wagering_gambling"/>
 		<combo_box.item label="Другое" name="Other"/>
 	</combo_box>
 	<text name="abuser_name_title">
diff --git a/indra/newview/skins/default/xui/ru/floater_snapshot.xml b/indra/newview/skins/default/xui/ru/floater_snapshot.xml
index 97de279b8f6b8a6e29c776abe1d8971036921b97..a796d942f3d62d4a9fcdf18f64c2274c181b2fc5 100644
--- a/indra/newview/skins/default/xui/ru/floater_snapshot.xml
+++ b/indra/newview/skins/default/xui/ru/floater_snapshot.xml
@@ -6,6 +6,9 @@
 	<string name="postcard_progress_str">
 		Отправка письма
 	</string>
+	<string name="facebook_progress_str">
+		Публикация в Facebook
+	</string>
 	<string name="profile_progress_str">
 		Публикация
 	</string>
@@ -15,6 +18,9 @@
 	<string name="local_progress_str">
 		Сохранение на компьютере
 	</string>
+	<string name="facebook_succeeded_str">
+		Изображение загружено
+	</string>
 	<string name="profile_succeeded_str">
 		Изображение отправлено
 	</string>
@@ -27,6 +33,9 @@
 	<string name="local_succeeded_str">
 		Сохранено на компьютере!
 	</string>
+	<string name="facebook_failed_str">
+		Не удалось передать изображение на вашу хронику Facebook.
+	</string>
 	<string name="profile_failed_str">
 		Не удалось передать изображение в ваш профиль.
 	</string>
diff --git a/indra/newview/skins/default/xui/ru/menu_name_field.xml b/indra/newview/skins/default/xui/ru/menu_name_field.xml
new file mode 100644
index 0000000000000000000000000000000000000000..889f3c37ab94203bb3eabd12422e164bd97d788d
--- /dev/null
+++ b/indra/newview/skins/default/xui/ru/menu_name_field.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<toggleable_menu name="CopyMenu">
+	<menu_item_call label="Копировать отображаемое имя" name="copy_display"/>
+	<menu_item_call label="Копировать имя агента" name="copy_name"/>
+	<menu_item_call label="Копировать Id агента" name="copy_id"/>
+</toggleable_menu>
diff --git a/indra/newview/skins/default/xui/ru/notifications.xml b/indra/newview/skins/default/xui/ru/notifications.xml
index bfcda798be4d1c2f4a0d9089df016640e8c152c0..e75fd1fd822cfe5746160d1afe1413e0bb30f3a0 100644
--- a/indra/newview/skins/default/xui/ru/notifications.xml
+++ b/indra/newview/skins/default/xui/ru/notifications.xml
@@ -2682,6 +2682,9 @@
 	<notification name="SystemMessage">
 		[MESSAGE]
 	</notification>
+	<notification name="FacebookConnect">
+		[MESSAGE]
+	</notification>
 	<notification name="FlickrConnect">
 		[MESSAGE]
 	</notification>
diff --git a/indra/newview/skins/default/xui/ru/panel_edit_classified.xml b/indra/newview/skins/default/xui/ru/panel_edit_classified.xml
index a2f06dbadfe6c31c387cc94e61f3ff9c95a2fcd2..ec457c456535a5865715eb40f4c8e90214c6ab58 100644
--- a/indra/newview/skins/default/xui/ru/panel_edit_classified.xml
+++ b/indra/newview/skins/default/xui/ru/panel_edit_classified.xml
@@ -46,8 +46,8 @@
 			<layout_panel name="save_changes_btn_lp">
 				<button label="[LABEL]" name="save_changes_btn"/>
 			</layout_panel>
-			<layout_panel name="show_on_map_btn_lp">
-				<button label="Отмена" name="cancel_btn"/>
+			<layout_panel name="cancel_btn_lp">
+				<button label="Отменить" name="cancel_btn"/>
 			</layout_panel>
 		</layout_stack>
 	</panel>
diff --git a/indra/newview/skins/default/xui/ru/panel_facebook_friends.xml b/indra/newview/skins/default/xui/ru/panel_facebook_friends.xml
index 746da8d523f517b83c1782d34e23d5300094340a..1e4d1346f7ec531d3620ad0ad6f1826ba396e4dd 100644
--- a/indra/newview/skins/default/xui/ru/panel_facebook_friends.xml
+++ b/indra/newview/skins/default/xui/ru/panel_facebook_friends.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <panel name="panel_facebook_friends">
-	<string name="facebook_friends_empty" value="Сейчас у вас нет друзей по Facebook, которые также были бы жителями Second Life. Предложите своим друзьям по Facebook присоединиться к Second Life!"/>
+	<string name="facebook_friends_empty" value="Сейчас у вас нет друзей в Facebook, которые являются также жителями Second Life. Предложите своим друзьям в Facebook присоединиться к Second Life!"/>
 	<string name="facebook_friends_no_connected" value="Сейчас вы не подключены к Facebook. Перейдите на вкладку «Статус», чтобы подключиться и включить эту функцию."/>
 	<accordion name="friends_accordion">
 		<accordion_tab name="tab_second_life_friends" title="Друзья по SL"/>
diff --git a/indra/newview/skins/default/xui/ru/panel_facebook_photo.xml b/indra/newview/skins/default/xui/ru/panel_facebook_photo.xml
index 143a57fec7fa06eaf64a91d1c6361e1fa50482ca..50296778ff2bc6da3ccec18f5455f971f613c1b8 100644
--- a/indra/newview/skins/default/xui/ru/panel_facebook_photo.xml
+++ b/indra/newview/skins/default/xui/ru/panel_facebook_photo.xml
@@ -2,19 +2,19 @@
 <panel name="panel_facebook_photo">
 	<combo_box name="resolution_combobox" tool_tip="Разрешение изображения">
 		<combo_box.item label="Текущее окно" name="CurrentWindow"/>
-		<combo_box.item label="640x480" name="640x480"/>
-		<combo_box.item label="800x600" name="800x600"/>
-		<combo_box.item label="1024x768" name="1024x768"/>
-		<combo_box.item label="1200x630" name="1200x630"/>
+		<combo_box.item label="640 x 480" name="640x480"/>
+		<combo_box.item label="800 x 600" name="800x600"/>
+		<combo_box.item label="1024 x 768" name="1024x768"/>
+		<combo_box.item label="1200 x 630" name="1200x630"/>
 	</combo_box>
 	<combo_box name="filters_combobox" tool_tip="Фильтры изображений">
 		<combo_box.item label="Без фильтра" name="NoFilter"/>
 	</combo_box>
-	<button label="Обновить" name="new_snapshot_btn" tool_tip="Щелкните для обновления"/>
-	<button label="Просмотр" name="big_preview_btn" tool_tip="Щелкните для смены вида"/>
+	<button label="Обновить" name="new_snapshot_btn" tool_tip="Щелкнуть для обновления"/>
+	<button label="Предпросмотр" name="big_preview_btn" tool_tip="Щелкнуть для смены вида"/>
 	<text name="caption_label">
 		Комментарий (не обязательно):
 	</text>
 	<button label="Опубликовать" name="post_photo_btn"/>
-	<button label="Отмена" name="cancel_photo_btn"/>
+	<button label="Отменить" name="cancel_photo_btn"/>
 </panel>
diff --git a/indra/newview/skins/default/xui/ru/panel_facebook_place.xml b/indra/newview/skins/default/xui/ru/panel_facebook_place.xml
index 7d0917a43afbf596e869c88a29800b9a146c59b5..a7fadca059ab45425ff1dd7edf435d24474aee94 100644
--- a/indra/newview/skins/default/xui/ru/panel_facebook_place.xml
+++ b/indra/newview/skins/default/xui/ru/panel_facebook_place.xml
@@ -1,9 +1,9 @@
 <?xml version="1.0" encoding="utf-8"?>
 <panel name="panel_facebook_place">
 	<text name="place_caption_label">
-		Напишите о том, где вы:
+		Сообщите, где вы находитесь:
 	</text>
 	<check_box initial_value="false" label="Включить вид места сверху" name="add_place_view_cb"/>
 	<button label="Опубликовать" name="post_place_btn"/>
-	<button label="Отмена" name="cancel_place_btn"/>
+	<button label="Отменить" name="cancel_place_btn"/>
 </panel>
diff --git a/indra/newview/skins/default/xui/ru/panel_facebook_status.xml b/indra/newview/skins/default/xui/ru/panel_facebook_status.xml
index c651a8087c704e05c83c9bbd558934ff6c8e9f66..826ac6a08c6012cb42d1bccd817d0ef7db19f8f1 100644
--- a/indra/newview/skins/default/xui/ru/panel_facebook_status.xml
+++ b/indra/newview/skins/default/xui/ru/panel_facebook_status.xml
@@ -1,20 +1,20 @@
 <?xml version="1.0" encoding="utf-8"?>
 <panel name="panel_facebook_status">
 	<string name="facebook_connected" value="Вы подключились к Facebook как:"/>
-	<string name="facebook_disconnected" value="Не подключено к Facebook"/>
+	<string name="facebook_disconnected" value="Нет подключения к Facebook"/>
 	<text name="account_caption_label">
-		Не подключено к Facebook.
+		Нет подключения к Facebook.
 	</text>
 	<panel name="panel_buttons">
-		<button label="Подключение..." name="connect_btn"/>
-		<button label="Отключить" name="disconnect_btn"/>
+		<button label="Соединение..." name="connect_btn"/>
+		<button label="Разъединить" name="disconnect_btn"/>
 		<text name="account_learn_more_label">
-			[http://community.secondlife.com/t5/English-Knowledge-Base/Second-Life-Share-Facebook/ta-p/2149711 О публикации в Facebook]
+			[http://community.secondlife.com/t5/English-Knowledge-Base/Second-Life-Share-Facebook/ta-p/2149711 Узнать о публикации в Facebook]
 		</text>
 	</panel>
 	<text name="status_caption_label">
 		О чем вы думаете?
 	</text>
 	<button label="Опубликовать" name="post_status_btn"/>
-	<button label="Отмена" name="cancel_status_btn"/>
+	<button label="Отменить" name="cancel_status_btn"/>
 </panel>
diff --git a/indra/newview/skins/default/xui/ru/panel_group_list_item_short.xml b/indra/newview/skins/default/xui/ru/panel_group_list_item_short.xml
new file mode 100644
index 0000000000000000000000000000000000000000..3408969d090522bad783d5f403e399c1a124f6d4
--- /dev/null
+++ b/indra/newview/skins/default/xui/ru/panel_group_list_item_short.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="group_list_item">
+	<text name="group_name" value="Неизвестно"/>
+	<button name="info_btn" tool_tip="Больше информации"/>
+	<button name="profile_btn" tool_tip="Посмотреть профиль"/>
+</panel>
diff --git a/indra/newview/skins/default/xui/ru/panel_me.xml b/indra/newview/skins/default/xui/ru/panel_me.xml
deleted file mode 100644
index 21a125af8762868339bb910e5b34da35bf9b36a5..0000000000000000000000000000000000000000
--- a/indra/newview/skins/default/xui/ru/panel_me.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<panel label="Мой профиль" name="panel_me">
-	<panel label="МОЯ ПОДБОРКА" name="panel_picks"/>
-</panel>
diff --git a/indra/newview/skins/default/xui/ru/panel_navigation_bar.xml b/indra/newview/skins/default/xui/ru/panel_navigation_bar.xml
index 5e3de180f92c589fa951e1902f13455482e8e295..331ba889d87a66657ea3dbb13e7fdace03ccaa1b 100644
--- a/indra/newview/skins/default/xui/ru/panel_navigation_bar.xml
+++ b/indra/newview/skins/default/xui/ru/panel_navigation_bar.xml
@@ -14,7 +14,7 @@
 				<label name="favorites_bar_label" tool_tip="Перетаскивайте сюда закладки, чтобы было удобнее переходить в любимые места в Second Life!">
 					Избранное
 				</label>
-				<more_button name="&gt;&gt;" tool_tip="Показать больше избранного">
+				<more_button name="&gt;&gt;" tool_tip="Показать больше избранного" width="60">
 					Больше ▼
 				</more_button>
 			</favorites_bar>
diff --git a/indra/newview/skins/default/xui/ru/panel_people.xml b/indra/newview/skins/default/xui/ru/panel_people.xml
index 0812eb7433c819add224d3d1c0da73fb18fecf26..8170c8d26f86c42fd62796182bacd91e3db93c16 100644
--- a/indra/newview/skins/default/xui/ru/panel_people.xml
+++ b/indra/newview/skins/default/xui/ru/panel_people.xml
@@ -40,6 +40,7 @@
 			<accordion name="friends_accordion">
 				<accordion_tab name="tab_online" title="Онлайн"/>
 				<accordion_tab name="tab_all" title="Все"/>
+				<accordion_tab name="tab_suggested_friends" title="С кем вы можете подружиться"/>
 			</accordion>
 		</panel>
 		<panel label="ГРУППЫ" name="groups_panel">
diff --git a/indra/newview/skins/default/xui/ru/panel_profile_classified.xml b/indra/newview/skins/default/xui/ru/panel_profile_classified.xml
new file mode 100644
index 0000000000000000000000000000000000000000..2d3ed685c037dcdba12d0f1e5be69f6a8651b666
--- /dev/null
+++ b/indra/newview/skins/default/xui/ru/panel_profile_classified.xml
@@ -0,0 +1,110 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="panel_profile_classified">
+	<panel.string name="type_mature">
+		Умеренная
+	</panel.string>
+	<panel.string name="type_pg">
+		Общий контент
+	</panel.string>
+	<panel.string name="l$_price">
+		L$[PRICE]
+	</panel.string>
+	<panel.string name="click_through_text_fmt">
+		Телепорт [TELEPORT], карта [MAP], профиль [PROFILE]
+	</panel.string>
+	<panel.string name="date_fmt">
+		[mthnum,datetime,slt]/[day,datetime,slt]/[year,datetime,slt]
+	</panel.string>
+	<panel.string name="auto_renew_on">
+		Включен
+	</panel.string>
+	<panel.string name="auto_renew_off">
+		Отключен
+	</panel.string>
+	<panel.string name="location_notice">
+		(будет обновлено после сохранения)
+	</panel.string>
+	<string name="publish_label">
+		Опубликовать
+	</string>
+	<string name="save_label">
+		Сохранить
+	</string>
+	<scroll_container name="profile_scroll">
+		<panel name="info_scroll_content_panel">
+			<icon label="" name="edit_icon" tool_tip="Щелкнуть для выбора изображения"/>
+			<layout_stack name="info_panel">
+				<layout_panel name="main_info_panel">
+					<text_editor name="classified_name">
+						[name]
+					</text_editor>
+					<text name="classified_location_label" value="Местоположение:"/>
+					<text_editor name="classified_location" value="[loading...]"/>
+					<text name="content_type_label" value="Тип контента:"/>
+					<text_editor name="content_type" value="[content type]"/>
+					<text name="category_label" value="Категория:"/>
+					<text_editor name="category" value="[category]"/>
+					<text name="creation_date_label" value="Дата создания:"/>
+					<text_editor name="creation_date" tool_tip="Дата создания" value="[date]"/>
+					<text name="price_for_listing_label" value="Стоимость размещения:"/>
+					<text_editor name="price_for_listing" tool_tip="Цена за размещение.">
+						[PRICE]
+					</text_editor>
+				</layout_panel>
+				<layout_panel name="clickthrough_layout_panel">
+					<text name="click_through_label" value="Клики:"/>
+					<text_editor name="click_through_text" tool_tip="Информация о переходах" value="[clicks]"/>
+				</layout_panel>
+				<layout_panel name="auto_renew_layout_panel">
+					<text name="auto_renew_label" value="Автоматическое продление:"/>
+					<text name="auto_renew" value="Включен"/>
+				</layout_panel>
+				<layout_panel name="descr_layout_panel">
+					<text name="classified_desc_label" value="Описание:"/>
+					<text_editor name="classified_desc" value="[description]"/>
+				</layout_panel>
+			</layout_stack>
+			<panel name="edit_panel">
+				<text name="Name:">
+					Название:
+				</text>
+				<text name="description_label">
+					Описание:
+				</text>
+				<text name="location_label">
+					Местоположение:
+				</text>
+				<text name="classified_location_edit">
+					загрузка...
+				</text>
+				<button label="Установить в текущее местоположение" name="set_to_curr_location_btn"/>
+				<text name="category_label" value="Категория:"/>
+				<text name="content_type_label" value="Тип контента:"/>
+				<icons_combo_box label="Общий контент" name="content_type_edit">
+					<icons_combo_box.item label="Умеренный контент" name="mature_ci" value="Возрастной"/>
+					<icons_combo_box.item label="Общий контент" name="pg_ci" value="C разрешения родителей"/>
+				</icons_combo_box>
+				<check_box label="Автоматическое обновление каждую неделю" name="auto_renew_edit"/>
+				<text name="price_for_listing_edit_label" value="Стоимость размещения:"/>
+				<spinner label="L$" name="price_for_listing_edit" tool_tip="Цена за размещение." value="50"/>
+			</panel>
+		</panel>
+	</scroll_container>
+	<layout_stack name="edit_btns_pnl">
+		<layout_panel name="teleport_btn_lp">
+			<button label="Телепорт" name="teleport_btn"/>
+		</layout_panel>
+		<layout_panel name="map_btn_lp">
+			<button label="Карта" name="show_on_map_btn"/>
+		</layout_panel>
+		<layout_panel name="edit_btn_lp">
+			<button label="Редактировать" name="edit_btn"/>
+		</layout_panel>
+		<layout_panel name="save_btn_lp">
+			<button label="[LABEL]" name="save_changes_btn"/>
+		</layout_panel>
+		<layout_panel name="cancel_btn_lp">
+			<button label="Отменить" name="cancel_btn"/>
+		</layout_panel>
+	</layout_stack>
+</panel>
diff --git a/indra/newview/skins/default/xui/ru/panel_profile_classifieds.xml b/indra/newview/skins/default/xui/ru/panel_profile_classifieds.xml
new file mode 100644
index 0000000000000000000000000000000000000000..fac494682a506c1f46d2f1a5a80e568bb00c2ec9
--- /dev/null
+++ b/indra/newview/skins/default/xui/ru/panel_profile_classifieds.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel label="Объявление" name="panel_profile_classifieds">
+	<string name="no_classifieds" value="Нет рекламы"/>
+	<button label="Новый..." name="new_btn"/>
+	<button label="Удалить..." name="delete_btn"/>
+	<text name="classifieds_panel_text">
+		Загрузка...
+	</text>
+</panel>
diff --git a/indra/newview/skins/default/xui/ru/panel_profile_firstlife.xml b/indra/newview/skins/default/xui/ru/panel_profile_firstlife.xml
new file mode 100644
index 0000000000000000000000000000000000000000..f5ac5e906a537575f77e667320cc025ef756c0f4
--- /dev/null
+++ b/indra/newview/skins/default/xui/ru/panel_profile_firstlife.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel label="Профиль" name="panel_profile_firstlife"/>
diff --git a/indra/newview/skins/default/xui/ru/panel_profile_interests.xml b/indra/newview/skins/default/xui/ru/panel_profile_interests.xml
new file mode 100644
index 0000000000000000000000000000000000000000..ba1c3d0357c68da7037fdef5ddddeec455cdfed1
--- /dev/null
+++ b/indra/newview/skins/default/xui/ru/panel_profile_interests.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel label="Круг интересов" name="panel_profile_interests">
+	<text name="I Want To:">
+		Я собираюсь:
+	</text>
+	<check_box label="Построить" name="chk0"/>
+	<check_box label="Просмотреть" name="chk1"/>
+	<check_box label="Встретить" name="chk2"/>
+	<check_box label="Получить работу" name="chk6"/>
+	<check_box label="Группа" name="chk3"/>
+	<check_box label="Купить" name="chk4"/>
+	<check_box label="Продать" name="chk5"/>
+	<check_box label="Нанять" name="chk7"/>
+	<line_editor name="want_to_edit">
+		(загрузка…)
+	</line_editor>
+	<text name="Skills:">
+		Навыки:
+	</text>
+	<check_box label="Текстуры" name="schk0"/>
+	<check_box label="Архитектура" name="schk1"/>
+	<check_box label="Моделирование" name="schk3"/>
+	<check_box label="Планирование мероприятия" name="schk2"/>
+	<check_box label="Создавать сценарии" name="schk4"/>
+	<check_box label="Пользовательские символы" name="schk5"/>
+	<line_editor name="skills_edit">
+		(загрузка…)
+	</line_editor>
+	<text name="Languages:">
+		Языки:
+	</text>
+	<line_editor name="languages_edit">
+		(загрузка…)
+	</line_editor>
+</panel>
diff --git a/indra/newview/skins/default/xui/ru/panel_profile_notes.xml b/indra/newview/skins/default/xui/ru/panel_profile_notes.xml
new file mode 100644
index 0000000000000000000000000000000000000000..41117c743a5a497e93c121eecd0340204ffbeec6
--- /dev/null
+++ b/indra/newview/skins/default/xui/ru/panel_profile_notes.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel label="Примечания и конфиденциальность" name="panel_notes">
+	<text name="status_message" value="Личные заметки об этом аватаре:"/>
+	<text name="status_message2" value="Разрешить этому аватару:"/>
+	<check_box label="Смотреть, когда я в сети" name="status_check"/>
+	<check_box label="Найти меня на карте мира" name="map_check"/>
+	<check_box label="Редактировать, удалять или брать мои объекты" name="objects_check"/>
+</panel>
diff --git a/indra/newview/skins/default/xui/ru/panel_profile_pick.xml b/indra/newview/skins/default/xui/ru/panel_profile_pick.xml
new file mode 100644
index 0000000000000000000000000000000000000000..a2ff5710eaa4b2b9bd477b2429ee9ebea10ee13d
--- /dev/null
+++ b/indra/newview/skins/default/xui/ru/panel_profile_pick.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="panel_pick_info">
+	<panel.string name="location_notice">
+		(будет обновлено после сохранения)
+	</panel.string>
+	<line_editor name="pick_location">
+		Загрузка...
+	</line_editor>
+	<button label="Телепорт" name="teleport_btn"/>
+	<button label="Показать на карте" name="show_on_map_btn"/>
+	<button label="Указать местоположение" name="set_to_curr_location_btn" tool_tip="Установить в текущее местоположение"/>
+	<button label="Сохранить подборку" name="save_changes_btn"/>
+</panel>
diff --git a/indra/newview/skins/default/xui/ru/panel_profile_picks.xml b/indra/newview/skins/default/xui/ru/panel_profile_picks.xml
new file mode 100644
index 0000000000000000000000000000000000000000..227b3f82b8988682956e63ea5457366eb0a62966
--- /dev/null
+++ b/indra/newview/skins/default/xui/ru/panel_profile_picks.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel label="Подборка" name="panel_picks">
+	<string name="no_picks" value="Нет подборки"/>
+	<text name="Tell everyone about your favorite places in Second Life.">
+		Сообщить всем о ваших избранных службах в Second Life.
+	</text>
+	<button label="Новый..." name="new_btn"/>
+	<button label="Удалить..." name="delete_btn"/>
+	<text name="picks_panel_text">
+		Загрузка...
+	</text>
+</panel>
diff --git a/indra/newview/skins/default/xui/ru/panel_profile_secondlife.xml b/indra/newview/skins/default/xui/ru/panel_profile_secondlife.xml
new file mode 100644
index 0000000000000000000000000000000000000000..e7a66ba29e2cf4a5d2dda54b4601208ed15260ea
--- /dev/null
+++ b/indra/newview/skins/default/xui/ru/panel_profile_secondlife.xml
@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel label="Профиль" name="panel_profile">
+	<string name="status_online">
+		В настоящее время в режиме онлайн
+	</string>
+	<string name="status_offline">
+		В настоящее время в режиме оффлайн
+	</string>
+	<string name="CaptionTextAcctInfo">
+		[ACCTTYPE]
+[PAYMENTINFO]
+	</string>
+	<string name="payment_update_link_url">
+		http://www.secondlife.com/account/billing.php?lang=en
+	</string>
+	<string name="partner_edit_link_url">
+		http://www.secondlife.com/account/partners.php?lang=en
+	</string>
+	<string name="my_account_link_url" value="http://secondlife.com/account"/>
+	<string name="no_partner_text" value="Никто"/>
+	<string name="no_group_text" value="Никто"/>
+	<string name="RegisterDateFormat">
+		[REG_DATE]
+	</string>
+	<string name="name_text_args">
+		[NAME]
+	</string>
+	<string name="display_name_text_args">
+		[DISPLAY_NAME]
+	</string>
+	<string name="FSDev" value="Разработчик"/>
+	<string name="FSSupp" value="Поддержка"/>
+	<string name="FSQualityAssurance" value="Отладчик"/>
+	<string name="FSGW" value="Межсетевой интерфейс"/>
+	<text name="name_label" value="Имя:"/>
+	<button label="Имя:" name="set_name" tool_tip="Задать отображаемое имя"/>
+	<panel name="name_holder">
+		<text_editor name="complete_name" value="(загрузка…)"/>
+	</panel>
+	<layout_stack name="imagepositioner">
+		<layout_panel name="label_stack">
+			<text name="status" value="Статус неизвестен"/>
+			<text name="label" value="Дата рождения в Second Life:"/>
+			<text name="label2" value="Аккаунт:"/>
+			<text name="partner_label" value="Партнер:"/>
+		</layout_panel>
+	</layout_stack>
+	<text name="Groups:" value="Группы:"/>
+	<button label="+" label_selected="+" name="group_invite" tool_tip="Пригласить в группу"/>
+	<layout_stack name="aboutpositioner">
+		<layout_panel name="about_stack">
+			<text name="About:" value="О нас:"/>
+		</layout_panel>
+		<layout_panel name="give_stack">
+			<text name="Give item:" value="Передать вещь:"/>
+			<text name="Give inventory" tool_tip="Сбросить вещи из инвентаря здесь для передачи их этому игроку.">
+				Сбросить вещь из инвентаря здесь.
+			</text>
+		</layout_panel>
+	</layout_stack>
+	<layout_stack name="buttonstack">
+		<layout_panel name="left_buttonstack">
+			<button label="Найти на карте" label_selected="Найти на карте" name="show_on_map_btn" tool_tip="Найти жителя на карте"/>
+			<button label="Оплатить" label_selected="Оплатить" name="pay" tool_tip="Выплатить деньги резиденту"/>
+		</layout_panel>
+		<layout_panel name="middle_buttonstack">
+			<button label="Предложить телепорт" label_selected="Предложить телепорт" name="teleport" tool_tip="Предложить телепорт этому жителю"/>
+			<button label="Мгновенное сообщение" label_selected="Мгновенное сообщение" name="im" tool_tip="Начать сеанс IM"/>
+		</layout_panel>
+		<layout_panel name="right_buttonstack">
+			<button label="Добавить друга" label_selected="Добавить друга" name="add_friend" tool_tip="Предложить дружбу этому жителю"/>
+			<button label="Заблокировать" name="block" tool_tip="Заблокировать этого жителя"/>
+			<button label="Разблокировать" name="unblock" tool_tip="Разблокировать этого жителя"/>
+		</layout_panel>
+	</layout_stack>
+	<check_box label="Показать в поиске" name="show_in_search_checkbox"/>
+</panel>
diff --git a/indra/newview/skins/default/xui/ru/panel_profile_web.xml b/indra/newview/skins/default/xui/ru/panel_profile_web.xml
new file mode 100644
index 0000000000000000000000000000000000000000..18a17e2586e2b9c25762f40941367b276040bb80
--- /dev/null
+++ b/indra/newview/skins/default/xui/ru/panel_profile_web.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel label="Веб" name="panel_profile_web">
+	<panel.string name="LoadTime" value="Время загрузки: [TIME] секунд"/>
+	<line_editor name="url_edit">
+		(загрузка…)
+	</line_editor>
+	<flyout_button label="Загрузить" name="load" tool_tip="Загрузить эту страницу с профилем с помощью встроенного веб-браузера.">
+		<flyout_button.item label="Открыть в просмотрщике браузера" name="open_item"/>
+		<flyout_button.item label="Открыть во внешнем браузере" name="home_item"/>
+	</flyout_button>
+	<button name="web_profile_popout_btn" tool_tip="Всплывающий веб-профиль"/>
+</panel>
diff --git a/indra/newview/skins/default/xui/ru/panel_region_terrain.xml b/indra/newview/skins/default/xui/ru/panel_region_terrain.xml
index af255652263855b21d710d6a215912e0b1a5cdf1..76b4f513a85a394d1dc66f15a66735c0e467430b 100644
--- a/indra/newview/skins/default/xui/ru/panel_region_terrain.xml
+++ b/indra/newview/skins/default/xui/ru/panel_region_terrain.xml
@@ -10,8 +10,8 @@
 	<spinner label="Верх. точка ландшафта" name="terrain_raise_spin"/>
 	<spinner label="Ниж. точка ландшафта" name="terrain_lower_spin"/>
 	<text name="detail_texture_text">
-		Текстуры ландшафта (требования: 512x512, 24-битные, TGA)
-	</text>
+    Текстуры ландшафта (требования: 1024x1024, 24-битные, TGA)
+  </text>
 	<text name="height_text_lbl">
 		1 (Низ)
 	</text>
diff --git a/indra/newview/skins/default/xui/ru/strings.xml b/indra/newview/skins/default/xui/ru/strings.xml
index 43a87b2b1863fa3ce993078074441845ee837e41..61d836a2d13e17f683c912cfd29d7318da182ba9 100644
--- a/indra/newview/skins/default/xui/ru/strings.xml
+++ b/indra/newview/skins/default/xui/ru/strings.xml
@@ -187,7 +187,7 @@ SLURL: &lt;nolink&gt;[SLURL]&lt;/nolink&gt;
 	<string name="LoginFailedNoNetwork">
 		Ошибка сети: не удалось установить соединение. Проверьте подключение к сети.
 	</string>
-	<string name="LoginFailed">
+	<string name="LoginFailedHeader">
 		Ошибка входа.
 	</string>
 	<string name="Quit">
@@ -357,6 +357,24 @@ support@secondlife.com.
 	<string name="TestingDisconnect">
 		Тестирование отключения клиента
 	</string>
+	<string name="SocialFacebookConnecting">
+		Подключение к Facebook...
+	</string>
+	<string name="SocialFacebookPosting">
+		Публикация...
+	</string>
+	<string name="SocialFacebookDisconnecting">
+		Отключение от Facebook...
+	</string>
+	<string name="SocialFacebookErrorConnecting">
+		Проблема с подключением к Facebook
+	</string>
+	<string name="SocialFacebookErrorPosting">
+		Проблемы при публикации в Facebook
+	</string>
+	<string name="SocialFacebookErrorDisconnecting">
+		Проблема с отключением от Facebook
+	</string>
 	<string name="SocialFlickrConnecting">
 		Подключение к Flickr...
 	</string>
@@ -671,9 +689,6 @@ support@secondlife.com.
 	<string name="GroupNameNone">
 		(нет)
 	</string>
-	<string name="AvalineCaller">
-		[ORDER] абонента Avaline
-	</string>
 	<string name="AssetErrorNone">
 		Ошибок нет
 	</string>
@@ -2576,9 +2591,21 @@ support@secondlife.com.
 	<string name="NoPicksClassifiedsText">
 		Вы не создали подборки или рекламы. Нажмите кнопку со знаком «плюс» ниже, чтобы создать подборку или рекламу
 	</string>
+	<string name="NoPicksText">
+		Вы не сделали никакой подборки. Нажмите кнопку Создать, чтобы сделать подборку.
+	</string>
+	<string name="NoClassifiedsText">
+		Вы не сделали никакой рекламы. Нажмите кнопку Создать, чтобы сделать рекламу.
+	</string>
 	<string name="NoAvatarPicksClassifiedsText">
 		У жителя нет подборки или рекламы
 	</string>
+	<string name="NoAvatarPicksText">
+		У пользователя нет подборки
+	</string>
+	<string name="NoAvatarClassifiedsText">
+		У пользователя нет объявлений
+	</string>
 	<string name="PicksClassifiedsLoadingText">
 		Загрузка...
 	</string>
@@ -4553,6 +4580,9 @@ support@secondlife.com.
 	<string name="share_alert">
 		Перетаскивайте вещи из инвентаря сюда
 	</string>
+	<string name="facebook_post_success">
+		Вы опубликовали сообщение в Facebook.
+	</string>
 	<string name="flickr_post_success">
 		Вы опубликовали сообщение в Flickr.
 	</string>
@@ -5096,7 +5126,7 @@ support@secondlife.com.
 	<string name="PremiumMembership">
 		Премиум
 	</string>
-	<string name="Premium PlusMembership">
+	<string name="Premium_PlusMembership">
 		Премиум Плюс
 	</string>
 	<string name="DeleteItems">
diff --git a/indra/newview/skins/default/xui/tr/floater_about.xml b/indra/newview/skins/default/xui/tr/floater_about.xml
index b91575954b3dc01b12c853b36b4a7aaae0e54233..faa504a996060c27aaee2f6f5134cd5d415c56fa 100644
--- a/indra/newview/skins/default/xui/tr/floater_about.xml
+++ b/indra/newview/skins/default/xui/tr/floater_about.xml
@@ -19,7 +19,6 @@ açık kaynak kod katkısında bulunanlar şunlardır:</text>
         expat Telif Hakkı (C) 1998, 1999, 2000 Thai Open Source Software Center Ltd.
         FreeType Telif Hakkı (C) 1996-2002, 2006 David Turner, Robert Wilhelm ve Werner Lemberg.
         GL Telif Hakkı (C) 1999-2004 Brian Paul.
-        GLOD Telif Hakkı (C) 2003-04 Jonathan Cohen, Nat Duca, Chris Niski, Johns Hopkins University ve David Luebke, Brenden Schubert, University of Virginia.
         google-perftools Telif Hakkı (c) 2005, Google Inc.
         Havok.com(TM) Telif Hakkı (C) 1999-2001, Telekinesys Research Limited.
         jpeg2000 Telif Hakkı (C) 2001, David Taubman, The University of New South Wales (UNSW)
diff --git a/indra/newview/skins/default/xui/tr/floater_facebook.xml b/indra/newview/skins/default/xui/tr/floater_facebook.xml
index 656a4a81c92082e0f6430c5d5ba967e8c62aa564..d8cbd84ed16f9491268ba4ad68212d9d89fc5b41 100644
--- a/indra/newview/skins/default/xui/tr/floater_facebook.xml
+++ b/indra/newview/skins/default/xui/tr/floater_facebook.xml
@@ -3,7 +3,7 @@
 	<tab_container name="tabs">
 		<panel label="DURUM" name="panel_facebook_status"/>
 		<panel label="FOTOÄžRAF" name="panel_facebook_photo"/>
-		<panel label="KONUMA GÄ°RÄ°Åž YAPIN" name="panel_facebook_place"/>
+		<panel label="GÄ°RÄ°Åž YAP" name="panel_facebook_place"/>
 		<panel label="ARKADAÅžLAR" name="panel_facebook_friends"/>
 	</tab_container>
 	<text name="connection_error_text">
diff --git a/indra/newview/skins/default/xui/tr/floater_inventory_view_finder.xml b/indra/newview/skins/default/xui/tr/floater_inventory_view_finder.xml
index accb1ed71c097a1868b7cfd34e949025680cd695..caa8497d3a8e1d009fcc2b40d64f830e034828cd 100644
--- a/indra/newview/skins/default/xui/tr/floater_inventory_view_finder.xml
+++ b/indra/newview/skins/default/xui/tr/floater_inventory_view_finder.xml
@@ -6,7 +6,7 @@
 	<check_box label="Mimikler" name="check_gesture"/>
 	<check_box label="Yer Ä°mleri" name="check_landmark"/>
 	<check_box label="Not Kartları" name="check_notecard"/>
-	<check_box label="Örgüler" name="check_mesh"/>
+	<check_box label="AÄŸlar" name="check_mesh"/>
 	<check_box label="Nesneler" name="check_object"/>
 	<check_box label="Komut Dosyaları" name="check_script"/>
 	<check_box label="Sesler" name="check_sound"/>
diff --git a/indra/newview/skins/default/xui/tr/floater_picks.xml b/indra/newview/skins/default/xui/tr/floater_picks.xml
deleted file mode 100644
index 5aee6ae09110fcb6934e1bdd609bc363cb6eb95c..0000000000000000000000000000000000000000
--- a/indra/newview/skins/default/xui/tr/floater_picks.xml
+++ /dev/null
@@ -1,2 +0,0 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<floater name="floater_picks" title="Seçimler"/>
diff --git a/indra/newview/skins/default/xui/tr/floater_preview_texture.xml b/indra/newview/skins/default/xui/tr/floater_preview_texture.xml
index 8302c62070568fcf60da27d57a5d06ae38588fd1..8ba9123545aca14591118a23fe913779ee0c9aaf 100644
--- a/indra/newview/skins/default/xui/tr/floater_preview_texture.xml
+++ b/indra/newview/skins/default/xui/tr/floater_preview_texture.xml
@@ -6,42 +6,23 @@
 	<floater.string name="Copy">
 		Envantere Kopyala
 	</floater.string>
-	<text name="desc txt">
-		Açıklama:
-	</text>
-	<text name="dimensions">
-		[WIDTH] pks x [HEIGHT] pks
-	</text>
-	<text name="aspect_ratio">
-		En boy oranını önizle
-	</text>
-	<combo_box name="combo_aspect_ratio" tool_tip="Sabit en boy oranında önizle">
-		<combo_item name="Unconstrained">
-			Kısıtsız
-		</combo_item>
-		<combo_item name="1:1" tool_tip="Grup iÅŸaretleri veya Real World profili">
-			1:1
-		</combo_item>
-		<combo_item name="4:3" tool_tip="[SECOND_LIFE] profili">
-			4:3
-		</combo_item>
-		<combo_item name="10:7" tool_tip="Ä°lanlar ve arama listeleri, yer imleri">
-			10:7
-		</combo_item>
-		<combo_item name="3:2" tool_tip="Arazi hakkında">
-			3:2
-		</combo_item>
-		<combo_item name="16:10">
-			16:10
-		</combo_item>
-		<combo_item name="16:9" tool_tip="Profil seçmeleri">
-			16:9
-		</combo_item>
-		<combo_item name="2:1">
-			2:1
-		</combo_item>
-	</combo_box>
-	<button label="Tamam" name="Keep"/>
-	<button label="At" name="Discard"/>
-	<button label="Farklı Kaydet" name="save_tex_btn"/>
+	<layout_stack name="preview_stack">
+		<layout_panel name="texture_panel">
+			<text name="desc txt">
+				Açıklama:
+			</text>
+			<text name="dimensions">
+				[WIDTH]pks x [HEIGHT]pks
+			</text>
+			<text name="aspect_ratio">
+				En boy oranını önizle
+			</text>
+			<combo_box name="combo_aspect_ratio" tool_tip="Sabit en boy oranında önizle"/>
+		</layout_panel>
+		<layout_panel name="buttons_panel">
+			<button label="Tamam" name="Keep"/>
+			<button label="At" name="Discard"/>
+			<button label="Farklı Kaydet" name="save_tex_btn"/>
+		</layout_panel>
+	</layout_stack>
 </floater>
diff --git a/indra/newview/skins/default/xui/tr/floater_profile.xml b/indra/newview/skins/default/xui/tr/floater_profile.xml
new file mode 100644
index 0000000000000000000000000000000000000000..bb158ddf666ab66e800f11ed0b07c972b04b6743
--- /dev/null
+++ b/indra/newview/skins/default/xui/tr/floater_profile.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<floater name="avatarinfo" title="Profil">
+	<panel name="panel_profile_view">
+		<tab_container name="panel_profile_tabs">
+			<panel label="Second Life" name="panel_profile_secondlife"/>
+			<panel label="Web" name="panel_profile_web"/>
+			<panel label="İlgi alanları" name="panel_profile_interests"/>
+			<panel label="Favoriler" name="panel_profile_picks"/>
+			<panel label="Ä°lan" name="panel_profile_classifieds"/>
+			<panel label="Gerçek Hayat" name="panel_profile_firstlife"/>
+			<panel label="Notlar" name="panel_profile_notes"/>
+		</tab_container>
+		<button label="Tamam" name="ok_btn" tool_tip="DeÄŸiÅŸiklikleri profile kaydet ve kapat"/>
+		<button label="Ä°ptal Et" label_selected="Ä°ptal Et" name="cancel_btn"/>
+	</panel>
+</floater>
diff --git a/indra/newview/skins/default/xui/tr/floater_snapshot.xml b/indra/newview/skins/default/xui/tr/floater_snapshot.xml
index be6c58e8cf2657f080dc2d9be3d786de36774613..8496194700710d9402494cc147646c29a855154d 100644
--- a/indra/newview/skins/default/xui/tr/floater_snapshot.xml
+++ b/indra/newview/skins/default/xui/tr/floater_snapshot.xml
@@ -6,6 +6,9 @@
 	<string name="postcard_progress_str">
 		E-posta Gönderiliyor
 	</string>
+	<string name="facebook_progress_str">
+		Facebook&apos;ta yayınlanıyor
+	</string>
 	<string name="profile_progress_str">
 		Yayınlanıyor
 	</string>
@@ -15,6 +18,9 @@
 	<string name="local_progress_str">
 		Bilgisayara Kaydediliyor
 	</string>
+	<string name="facebook_succeeded_str">
+		Görüntü yüklendi
+	</string>
 	<string name="profile_succeeded_str">
 		Görüntü yüklendi
 	</string>
@@ -27,6 +33,9 @@
 	<string name="local_succeeded_str">
 		Bilgisayara Kaydedildi!
 	</string>
+	<string name="facebook_failed_str">
+		Görüntü Facebook zaman tünelinize yüklenemedi.
+	</string>
 	<string name="profile_failed_str">
 		Görüntü Profil Akışınıza yüklenemedi.
 	</string>
diff --git a/indra/newview/skins/default/xui/tr/menu_name_field.xml b/indra/newview/skins/default/xui/tr/menu_name_field.xml
new file mode 100644
index 0000000000000000000000000000000000000000..b1afd737c3a66f71550b4dc193b31287bdfa9f2a
--- /dev/null
+++ b/indra/newview/skins/default/xui/tr/menu_name_field.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<toggleable_menu name="CopyMenu">
+	<menu_item_call label="Görünen Adı Kopyala" name="copy_display"/>
+	<menu_item_call label="Aracı Adını Kopyala" name="copy_name"/>
+	<menu_item_call label="Aracı Kimliğini Kopyala" name="copy_id"/>
+</toggleable_menu>
diff --git a/indra/newview/skins/default/xui/tr/notifications.xml b/indra/newview/skins/default/xui/tr/notifications.xml
index 5403a78f222ca5e0ea0a54fbff5c1fe13b5940e4..17d2969d196d12e4880271f5dde4bfb66a6b1c81 100644
--- a/indra/newview/skins/default/xui/tr/notifications.xml
+++ b/indra/newview/skins/default/xui/tr/notifications.xml
@@ -2682,6 +2682,9 @@ Daha küçük bir arazi parçası seçmeyi deneyin.
 	<notification name="SystemMessage">
 		[MESSAGE]
 	</notification>
+	<notification name="FacebookConnect">
+		[MESSAGE]
+	</notification>
 	<notification name="FlickrConnect">
 		[MESSAGE]
 	</notification>
diff --git a/indra/newview/skins/default/xui/tr/panel_edit_classified.xml b/indra/newview/skins/default/xui/tr/panel_edit_classified.xml
index fc444f21f6711b281e438fff36d9b43199ec3f23..78c34a3ac0415abf5ba716baa5fb088ad1cfa834 100644
--- a/indra/newview/skins/default/xui/tr/panel_edit_classified.xml
+++ b/indra/newview/skins/default/xui/tr/panel_edit_classified.xml
@@ -46,7 +46,7 @@
 			<layout_panel name="save_changes_btn_lp">
 				<button label="[LABEL]" name="save_changes_btn"/>
 			</layout_panel>
-			<layout_panel name="show_on_map_btn_lp">
+			<layout_panel name="cancel_btn_lp">
 				<button label="Ä°ptal Et" name="cancel_btn"/>
 			</layout_panel>
 		</layout_stack>
diff --git a/indra/newview/skins/default/xui/tr/panel_facebook_friends.xml b/indra/newview/skins/default/xui/tr/panel_facebook_friends.xml
index 8184d6d7cf92fedc17aa44de401140fb21aa9247..edbe87d74c5bd9a46d1212d75100e64c1ac4ca54 100644
--- a/indra/newview/skins/default/xui/tr/panel_facebook_friends.xml
+++ b/indra/newview/skins/default/xui/tr/panel_facebook_friends.xml
@@ -1,12 +1,12 @@
 <?xml version="1.0" encoding="utf-8"?>
 <panel name="panel_facebook_friends">
-	<string name="facebook_friends_empty" value="Şu an için aynı zamanda bir Second Life sakini olan hiçbir Facebook arkadaşınız yok. Facebook arkadaşlarınızı bugün Second Life&apos;a katılmaya davet edin!"/>
+	<string name="facebook_friends_empty" value="Şu anda aynı zamanda bir Second Life sakini olan hiçbir Facebook arkadaşınız yok. Facebook arkadaşlarınızdan bugün Second Life&apos;a katılmalarını isteyin!"/>
 	<string name="facebook_friends_no_connected" value="Şu anda Facebook&apos;a bağlı değilsiniz. Bağlanmak ve bu özelliği etkinleştirmek için lütfen Durum sekmesine gidin."/>
 	<accordion name="friends_accordion">
 		<accordion_tab name="tab_second_life_friends" title="SL arkadaşları"/>
 		<accordion_tab name="tab_suggested_friends" title="Bu kişileri SL arkadaşları olarak ekle"/>
 	</accordion>
 	<text name="facebook_friends_status">
-		Facebook&apos;a bağlanılmadı.
+		Facebook&apos;a bağlanılamadı.
 	</text>
 </panel>
diff --git a/indra/newview/skins/default/xui/tr/panel_facebook_photo.xml b/indra/newview/skins/default/xui/tr/panel_facebook_photo.xml
index d772aff937c5125279735506423e4177f7be4789..e3150f258d5da6b3d726a8104083bb5f8c403fcc 100644
--- a/indra/newview/skins/default/xui/tr/panel_facebook_photo.xml
+++ b/indra/newview/skins/default/xui/tr/panel_facebook_photo.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <panel name="panel_facebook_photo">
 	<combo_box name="resolution_combobox" tool_tip="Görüntü çözünürlüğü">
-		<combo_box.item label="Mevcut Pencere" name="CurrentWindow"/>
+		<combo_box.item label="Geçerli Pencere" name="CurrentWindow"/>
 		<combo_box.item label="640x480" name="640x480"/>
 		<combo_box.item label="800x600" name="800x600"/>
 		<combo_box.item label="1024x768" name="1024x768"/>
@@ -11,10 +11,10 @@
 		<combo_box.item label="Filtre Yok" name="NoFilter"/>
 	</combo_box>
 	<button label="Yenile" name="new_snapshot_btn" tool_tip="Yenilemek için tıklayın"/>
-	<button label="Önizleme" name="big_preview_btn" tool_tip="Önizleme ayarları arasında geçiş yapmak için tıklayın"/>
+	<button label="Önizleme" name="big_preview_btn" tool_tip="Önizlemeye geçmek için tıklayın"/>
 	<text name="caption_label">
 		Yorum (isteğe bağlı):
 	</text>
 	<button label="Yayınla" name="post_photo_btn"/>
-	<button label="Ä°ptal" name="cancel_photo_btn"/>
+	<button label="Ä°ptal Et" name="cancel_photo_btn"/>
 </panel>
diff --git a/indra/newview/skins/default/xui/tr/panel_facebook_place.xml b/indra/newview/skins/default/xui/tr/panel_facebook_place.xml
index 85b401a1a0f560c38ff1b4f27854c506ab605017..96c34d03d00b083b2abbb528cb5c6b6d59ac1223 100644
--- a/indra/newview/skins/default/xui/tr/panel_facebook_place.xml
+++ b/indra/newview/skins/default/xui/tr/panel_facebook_place.xml
@@ -5,5 +5,5 @@
 	</text>
 	<check_box initial_value="false" label="Konumun üstten görünümünü ekle" name="add_place_view_cb"/>
 	<button label="Yayınla" name="post_place_btn"/>
-	<button label="Ä°ptal" name="cancel_place_btn"/>
+	<button label="Ä°ptal Et" name="cancel_place_btn"/>
 </panel>
diff --git a/indra/newview/skins/default/xui/tr/panel_facebook_status.xml b/indra/newview/skins/default/xui/tr/panel_facebook_status.xml
index e6feff594994a98b3cd6113b6b40bcfc17f44111..f5dba088de6448e59adfdb306b6406edc350559e 100644
--- a/indra/newview/skins/default/xui/tr/panel_facebook_status.xml
+++ b/indra/newview/skins/default/xui/tr/panel_facebook_status.xml
@@ -1,9 +1,9 @@
 <?xml version="1.0" encoding="utf-8"?>
 <panel name="panel_facebook_status">
 	<string name="facebook_connected" value="Facebook&apos;a şu kimlikle bağlandınız:"/>
-	<string name="facebook_disconnected" value="Facebook&apos;a bağlanılmadı"/>
+	<string name="facebook_disconnected" value="Facebook&apos;a bağlanılamadı"/>
 	<text name="account_caption_label">
-		Facebook&apos;a bağlanılmadı.
+		Facebook&apos;a bağlanılamadı.
 	</text>
 	<panel name="panel_buttons">
 		<button label="BaÄŸlan..." name="connect_btn"/>
@@ -13,8 +13,8 @@
 		</text>
 	</panel>
 	<text name="status_caption_label">
-		Ne düşünüyorsunuz?
+		Aklınızdan ne geçiyor?
 	</text>
 	<button label="Yayınla" name="post_status_btn"/>
-	<button label="Ä°ptal" name="cancel_status_btn"/>
+	<button label="Ä°ptal Et" name="cancel_status_btn"/>
 </panel>
diff --git a/indra/newview/skins/default/xui/tr/panel_group_general.xml b/indra/newview/skins/default/xui/tr/panel_group_general.xml
index c666778c69602c5b8bc7c1e0ed905fcdbebb02b9..5578b36f3fe25e4265d46aeaf26acc00aa3acb91 100644
--- a/indra/newview/skins/default/xui/tr/panel_group_general.xml
+++ b/indra/newview/skins/default/xui/tr/panel_group_general.xml
@@ -45,7 +45,7 @@ Daha fazla yardım edinmek için farenizi seçeneklerin üzerine getirin.
 		<check_box label="Herkes katılabilir" name="open_enrollement" tool_tip="Bu grubun davet edilmeden yeni üyelerin katılmasına imkan tanıyıp tanımayacağını belirler."/>
 		<check_box label="Katılma ücreti" name="check_enrollment_fee" tool_tip="Bu gruba katılmak için bir kayıt ücretinin gerekip gerekmeyeceğini belirler"/>
 		<spinner label="L$" name="spin_enrollment_fee" tool_tip="Kayıt Ücreti işaretlendiğinde yeni üyeler gruba katılmak için bu ücreti ödemelidir."/>
-		<combo_box name="group_mature_check" tool_tip="Erişkinlik dereceleri bir grupta izin verilen içerik ve davranış türlerini belirler">
+		<combo_box name="group_mature_check" tool_tip="Grubunuzun Orta olarak sınıflandırılmış bilgiler içerip içermeyeceğini belirler">
 			<combo_item name="select_mature">
 				- Erişkinlik seviyesini seçin -
 			</combo_item>
diff --git a/indra/newview/skins/default/xui/tr/panel_group_list_item_short.xml b/indra/newview/skins/default/xui/tr/panel_group_list_item_short.xml
new file mode 100644
index 0000000000000000000000000000000000000000..0ed905ed35827389462ba524d0e227aa67e19181
--- /dev/null
+++ b/indra/newview/skins/default/xui/tr/panel_group_list_item_short.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="group_list_item">
+	<text name="group_name" value="Bilinmiyor"/>
+	<button name="info_btn" tool_tip="Ek bilgi"/>
+	<button name="profile_btn" tool_tip="Profili görüntüle"/>
+</panel>
diff --git a/indra/newview/skins/default/xui/tr/panel_me.xml b/indra/newview/skins/default/xui/tr/panel_me.xml
deleted file mode 100644
index d9e79d171cd8bed00d9f0162656d7f3b2aecf3e9..0000000000000000000000000000000000000000
--- a/indra/newview/skins/default/xui/tr/panel_me.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<panel label="Profilim" name="panel_me">
-	<panel label="SEÇTİKLERİM" name="panel_picks"/>
-</panel>
diff --git a/indra/newview/skins/default/xui/tr/panel_navigation_bar.xml b/indra/newview/skins/default/xui/tr/panel_navigation_bar.xml
index 8d43e3fb5a26afd0f5e1d78accce0fbb08f06ec5..ae9bc33bfa7e3f17ea8f826effc1b4076cf931fc 100644
--- a/indra/newview/skins/default/xui/tr/panel_navigation_bar.xml
+++ b/indra/newview/skins/default/xui/tr/panel_navigation_bar.xml
@@ -14,7 +14,7 @@
 				<label name="favorites_bar_label" tool_tip="Second Life içerisinde sık kullandığınız yerlere hızla erişmek için Yer İmlerini buraya sürükleyin!">
 					Favoriler Çubuğu
 				</label>
-				<more_button name="&gt;&gt;" tool_tip="Favorilerimden daha çok göster">
+				<more_button name="&gt;&gt;" tool_tip="Favorilerimden daha çok göster" width="65">
 					Daha Fazla â–¼
 				</more_button>
 			</favorites_bar>
diff --git a/indra/newview/skins/default/xui/tr/panel_people.xml b/indra/newview/skins/default/xui/tr/panel_people.xml
index 25d29fcbb5df07e404bce26df773f4d5c3501659..acbcd2a544b2a66fd9ff4a7aa5a1feb1798e7331 100644
--- a/indra/newview/skins/default/xui/tr/panel_people.xml
+++ b/indra/newview/skins/default/xui/tr/panel_people.xml
@@ -40,6 +40,7 @@ Birlikte takılacak kişiler mi arıyorsunuz? [secondlife:///app/worldmap Dünya
 			<accordion name="friends_accordion">
 				<accordion_tab name="tab_online" title="Çevrimiçi"/>
 				<accordion_tab name="tab_all" title="Tümü"/>
+				<accordion_tab name="tab_suggested_friends" title="ArkadaÅŸ olmak isteyebileceÄŸiniz kiÅŸiler"/>
 			</accordion>
 		</panel>
 		<panel label="GRUPLAR" name="groups_panel">
diff --git a/indra/newview/skins/default/xui/tr/panel_profile_classified.xml b/indra/newview/skins/default/xui/tr/panel_profile_classified.xml
new file mode 100644
index 0000000000000000000000000000000000000000..805de24c117c1d9b28ea2b6b13e7268853be8d32
--- /dev/null
+++ b/indra/newview/skins/default/xui/tr/panel_profile_classified.xml
@@ -0,0 +1,110 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="panel_profile_classified">
+	<panel.string name="type_mature">
+		Orta
+	</panel.string>
+	<panel.string name="type_pg">
+		Genel İçerik
+	</panel.string>
+	<panel.string name="l$_price">
+		L$[PRICE]
+	</panel.string>
+	<panel.string name="click_through_text_fmt">
+		[TELEPORT] ışınlanma, [MAP] harita, [PROFILE] profil
+	</panel.string>
+	<panel.string name="date_fmt">
+		[mthnum,datetime,slt]/[day,datetime,slt]/[year,datetime,slt]
+	</panel.string>
+	<panel.string name="auto_renew_on">
+		Etkin
+	</panel.string>
+	<panel.string name="auto_renew_off">
+		Devre dışı
+	</panel.string>
+	<panel.string name="location_notice">
+		(kaydedildikten sonra güncellenir)
+	</panel.string>
+	<string name="publish_label">
+		Yayınla
+	</string>
+	<string name="save_label">
+		Kaydet
+	</string>
+	<scroll_container name="profile_scroll">
+		<panel name="info_scroll_content_panel">
+			<icon label="" name="edit_icon" tool_tip="Bir görüntü seçmek için tıklayın"/>
+			<layout_stack name="info_panel">
+				<layout_panel name="main_info_panel">
+					<text_editor name="classified_name">
+						[name]
+					</text_editor>
+					<text name="classified_location_label" value="Konum:"/>
+					<text_editor name="classified_location" value="[loading...]"/>
+					<text name="content_type_label" value="İçerik Türü:"/>
+					<text_editor name="content_type" value="[content type]"/>
+					<text name="category_label" value="Kategori:"/>
+					<text_editor name="category" value="[category]"/>
+					<text name="creation_date_label" value="OluÅŸturma tarihi:"/>
+					<text_editor name="creation_date" tool_tip="OluÅŸturma tarihi" value="[date]"/>
+					<text name="price_for_listing_label" value="İlan fiyatı:"/>
+					<text_editor name="price_for_listing" tool_tip="İlan fiyatı.">
+						[PRICE]
+					</text_editor>
+				</layout_panel>
+				<layout_panel name="clickthrough_layout_panel">
+					<text name="click_through_label" value="Tıklama sayısı:"/>
+					<text_editor name="click_through_text" tool_tip="Tıklama verileri" value="[clicks]"/>
+				</layout_panel>
+				<layout_panel name="auto_renew_layout_panel">
+					<text name="auto_renew_label" value="Otomatik yenileme:"/>
+					<text name="auto_renew" value="Etkin"/>
+				</layout_panel>
+				<layout_panel name="descr_layout_panel">
+					<text name="classified_desc_label" value="Açıklama:"/>
+					<text_editor name="classified_desc" value="[description]"/>
+				</layout_panel>
+			</layout_stack>
+			<panel name="edit_panel">
+				<text name="Name:">
+					Başlık:
+				</text>
+				<text name="description_label">
+					Açıklama:
+				</text>
+				<text name="location_label">
+					Konum:
+				</text>
+				<text name="classified_location_edit">
+					yükleniyor...
+				</text>
+				<button label="Geçerli Konuma Ayarla" name="set_to_curr_location_btn"/>
+				<text name="category_label" value="Kategori:"/>
+				<text name="content_type_label" value="İçerik türü:"/>
+				<icons_combo_box label="Genel İçerik" name="content_type_edit">
+					<icons_combo_box.item label="Orta İçerik" name="mature_ci" value="Yetişkin"/>
+					<icons_combo_box.item label="Genel İçerik" name="pg_ci" value="PG"/>
+				</icons_combo_box>
+				<check_box label="Her hafta otomatik yenile" name="auto_renew_edit"/>
+				<text name="price_for_listing_edit_label" value="İlan fiyatı:"/>
+				<spinner label="L$" name="price_for_listing_edit" tool_tip="İlan fiyatı." value="50"/>
+			</panel>
+		</panel>
+	</scroll_container>
+	<layout_stack name="edit_btns_pnl">
+		<layout_panel name="teleport_btn_lp">
+			<button label="Işınlanma" name="teleport_btn"/>
+		</layout_panel>
+		<layout_panel name="map_btn_lp">
+			<button label="Harita" name="show_on_map_btn"/>
+		</layout_panel>
+		<layout_panel name="edit_btn_lp">
+			<button label="Düzenle" name="edit_btn"/>
+		</layout_panel>
+		<layout_panel name="save_btn_lp">
+			<button label="[LABEL]" name="save_changes_btn"/>
+		</layout_panel>
+		<layout_panel name="cancel_btn_lp">
+			<button label="Ä°ptal Et" name="cancel_btn"/>
+		</layout_panel>
+	</layout_stack>
+</panel>
diff --git a/indra/newview/skins/default/xui/tr/panel_profile_classifieds.xml b/indra/newview/skins/default/xui/tr/panel_profile_classifieds.xml
new file mode 100644
index 0000000000000000000000000000000000000000..0edae1ab2af3c7261ab853b87999e8f5bf161ef3
--- /dev/null
+++ b/indra/newview/skins/default/xui/tr/panel_profile_classifieds.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel label="Ä°lan" name="panel_profile_classifieds">
+	<string name="no_classifieds" value="Ä°lan Yok"/>
+	<button label="Yeni..." name="new_btn"/>
+	<button label="Sil..." name="delete_btn"/>
+	<text name="classifieds_panel_text">
+		Yükleniyor...
+	</text>
+</panel>
diff --git a/indra/newview/skins/default/xui/tr/panel_profile_firstlife.xml b/indra/newview/skins/default/xui/tr/panel_profile_firstlife.xml
new file mode 100644
index 0000000000000000000000000000000000000000..0f65090209a7dcdb8d28c2dfd86b93adbb01443b
--- /dev/null
+++ b/indra/newview/skins/default/xui/tr/panel_profile_firstlife.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel label="Profil" name="panel_profile_firstlife"/>
diff --git a/indra/newview/skins/default/xui/tr/panel_profile_interests.xml b/indra/newview/skins/default/xui/tr/panel_profile_interests.xml
new file mode 100644
index 0000000000000000000000000000000000000000..b068aa3dad3650d6460862d117bd3d36051f080f
--- /dev/null
+++ b/indra/newview/skins/default/xui/tr/panel_profile_interests.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel label="İlgi alanları" name="panel_profile_interests">
+	<text name="I Want To:">
+		Åžunu Yapmak Ä°stiyorum:
+	</text>
+	<check_box label="Ä°nÅŸa Et" name="chk0"/>
+	<check_box label="KeÅŸfet" name="chk1"/>
+	<check_box label="Tanış" name="chk2"/>
+	<check_box label="Ä°ÅŸe Gir" name="chk6"/>
+	<check_box label="Gruplandır" name="chk3"/>
+	<check_box label="Satın Al" name="chk4"/>
+	<check_box label="Sat" name="chk5"/>
+	<check_box label="Ä°ÅŸe Al" name="chk7"/>
+	<line_editor name="want_to_edit">
+		(yükleniyor...)
+	</line_editor>
+	<text name="Skills:">
+		Beceriler:
+	</text>
+	<check_box label="Dokular" name="schk0"/>
+	<check_box label="Mimari" name="schk1"/>
+	<check_box label="Modelleme" name="schk3"/>
+	<check_box label="Etkinlik Planlama" name="schk2"/>
+	<check_box label="Kodlama" name="schk4"/>
+	<check_box label="Özel Karakterler" name="schk5"/>
+	<line_editor name="skills_edit">
+		(yükleniyor...)
+	</line_editor>
+	<text name="Languages:">
+		Diller:
+	</text>
+	<line_editor name="languages_edit">
+		(yükleniyor...)
+	</line_editor>
+</panel>
diff --git a/indra/newview/skins/default/xui/tr/panel_profile_notes.xml b/indra/newview/skins/default/xui/tr/panel_profile_notes.xml
new file mode 100644
index 0000000000000000000000000000000000000000..fff75dd685b72ef746f43bb74dc6e09bc9c89ab2
--- /dev/null
+++ b/indra/newview/skins/default/xui/tr/panel_profile_notes.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel label="Notlar ve Gizlilik" name="panel_notes">
+	<text name="status_message" value="Bu avatar ile ilgili özel notlar:"/>
+	<text name="status_message2" value="Bu avatar için şunlara izin ver:"/>
+	<check_box label="Çevrimiçi olduğumu görme" name="status_check"/>
+	<check_box label="Beni dünya haritasında bulma" name="map_check"/>
+	<check_box label="Nesnelerimi düzenleme, silme veya alma" name="objects_check"/>
+</panel>
diff --git a/indra/newview/skins/default/xui/tr/panel_profile_pick.xml b/indra/newview/skins/default/xui/tr/panel_profile_pick.xml
new file mode 100644
index 0000000000000000000000000000000000000000..d42c1eff7f3046c1991538f41040a3826962bfa1
--- /dev/null
+++ b/indra/newview/skins/default/xui/tr/panel_profile_pick.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="panel_pick_info">
+	<panel.string name="location_notice">
+		(kaydedildikten sonra güncellenir)
+	</panel.string>
+	<line_editor name="pick_location">
+		Yükleniyor...
+	</line_editor>
+	<button label="Işınlanma" name="teleport_btn"/>
+	<button label="Haritada Göster" name="show_on_map_btn"/>
+	<button label="Konumu Ayarla" name="set_to_curr_location_btn" tool_tip="Geçerli Konuma Ayarla"/>
+	<button label="Favoriyi Kaydet" name="save_changes_btn"/>
+</panel>
diff --git a/indra/newview/skins/default/xui/tr/panel_profile_picks.xml b/indra/newview/skins/default/xui/tr/panel_profile_picks.xml
new file mode 100644
index 0000000000000000000000000000000000000000..7222a2fc2ecb4487a66ee9be90e2aedd4863b772
--- /dev/null
+++ b/indra/newview/skins/default/xui/tr/panel_profile_picks.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel label="Favoriler" name="panel_picks">
+	<string name="no_picks" value="Favori Yok"/>
+	<text name="Tell everyone about your favorite places in Second Life.">
+		Second Life&apos;ta favori yerlerinizi herkese anlatın!
+	</text>
+	<button label="Yeni..." name="new_btn"/>
+	<button label="Sil..." name="delete_btn"/>
+	<text name="picks_panel_text">
+		Yükleniyor...
+	</text>
+</panel>
diff --git a/indra/newview/skins/default/xui/tr/panel_profile_secondlife.xml b/indra/newview/skins/default/xui/tr/panel_profile_secondlife.xml
new file mode 100644
index 0000000000000000000000000000000000000000..00e81d005e32e34c2e79bda5a398ce4295f647dc
--- /dev/null
+++ b/indra/newview/skins/default/xui/tr/panel_profile_secondlife.xml
@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel label="Profil" name="panel_profile">
+	<string name="status_online">
+		Şu Anda Çevrimiçi
+	</string>
+	<string name="status_offline">
+		Şu Anda Çevrimdışı
+	</string>
+	<string name="CaptionTextAcctInfo">
+		[ACCTTYPE]
+[PAYMENTINFO]
+	</string>
+	<string name="payment_update_link_url">
+		http://www.secondlife.com/account/billing.php?lang=en
+	</string>
+	<string name="partner_edit_link_url">
+		http://www.secondlife.com/account/partners.php?lang=en
+	</string>
+	<string name="my_account_link_url" value="http://secondlife.com/account"/>
+	<string name="no_partner_text" value="Yok"/>
+	<string name="no_group_text" value="Yok"/>
+	<string name="RegisterDateFormat">
+		[REG_DATE]
+	</string>
+	<string name="name_text_args">
+		[NAME]
+	</string>
+	<string name="display_name_text_args">
+		[DISPLAY_NAME]
+	</string>
+	<string name="FSDev" value="GeliÅŸtirici"/>
+	<string name="FSSupp" value="Destek"/>
+	<string name="FSQualityAssurance" value="Böcek bilimci"/>
+	<string name="FSGW" value="Ağ geçidi"/>
+	<text name="name_label" value="Ad:"/>
+	<button label="Ad:" name="set_name" tool_tip="Görünen Adı Ayarla"/>
+	<panel name="name_holder">
+		<text_editor name="complete_name" value="(yükleniyor...)"/>
+	</panel>
+	<layout_stack name="imagepositioner">
+		<layout_panel name="label_stack">
+			<text name="status" value="Durum Bilinmiyor"/>
+			<text name="label" value="Second Life DoÄŸum Tarihi:"/>
+			<text name="label2" value="Hesap:"/>
+			<text name="partner_label" value="Ortak:"/>
+		</layout_panel>
+	</layout_stack>
+	<text name="Groups:" value="Gruplar:"/>
+	<button label="+" label_selected="+" name="group_invite" tool_tip="Gruba Davet Et"/>
+	<layout_stack name="aboutpositioner">
+		<layout_panel name="about_stack">
+			<text name="About:" value="Hakkında:"/>
+		</layout_panel>
+		<layout_panel name="give_stack">
+			<text name="Give item:" value="Öğe ver:"/>
+			<text name="Give inventory" tool_tip="Envanter öğelerini bu kişiye vermek için buraya bırakın.">
+				Envanter öğesini buraya bırakın.
+			</text>
+		</layout_panel>
+	</layout_stack>
+	<layout_stack name="buttonstack">
+		<layout_panel name="left_buttonstack">
+			<button label="Haritada Bul" label_selected="Haritada Bul" name="show_on_map_btn" tool_tip="Sakini haritada bul"/>
+			<button label="Öde" label_selected="Öde" name="pay" tool_tip="Sakine para öde"/>
+		</layout_panel>
+		<layout_panel name="middle_buttonstack">
+			<button label="Işınlanma Teklif Et" label_selected="Işınlanma Teklif Et" name="teleport" tool_tip="Sakine ışınlanma teklif et"/>
+			<button label="Anlık İleti" label_selected="Anlık İleti" name="im" tool_tip="Anlık ileti oturumu aç"/>
+		</layout_panel>
+		<layout_panel name="right_buttonstack">
+			<button label="Arkadaş Ekle" label_selected="Arkadaş Ekle" name="add_friend" tool_tip="Sakine arkadaşlık teklif et"/>
+			<button label="Engelle" name="block" tool_tip="Bu Sakini engelle"/>
+			<button label="Engellemeyi Kaldır" name="unblock" tool_tip="Bu Sakinin engellemesini kaldır"/>
+		</layout_panel>
+	</layout_stack>
+	<check_box label="Aramada göster" name="show_in_search_checkbox"/>
+</panel>
diff --git a/indra/newview/skins/default/xui/tr/panel_profile_web.xml b/indra/newview/skins/default/xui/tr/panel_profile_web.xml
new file mode 100644
index 0000000000000000000000000000000000000000..265b1fee7e8ceb6d0fa174513f10cae0150325cd
--- /dev/null
+++ b/indra/newview/skins/default/xui/tr/panel_profile_web.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel label="Web" name="panel_profile_web">
+	<panel.string name="LoadTime" value="Yükleme Süresi: [TIME] saniye"/>
+	<line_editor name="url_edit">
+		(yükleniyor..)
+	</line_editor>
+	<flyout_button label="Yükle" name="load" tool_tip="Bu profil sayfasını tümleşik web tarayıcı ile yükleyin.">
+		<flyout_button.item label="Görüntüleyici içindeki tarayıcıda aç" name="open_item"/>
+		<flyout_button.item label="Dış tarayıcıda aç" name="home_item"/>
+	</flyout_button>
+	<button name="web_profile_popout_btn" tool_tip="Açılır web profili"/>
+</panel>
diff --git a/indra/newview/skins/default/xui/tr/panel_region_terrain.xml b/indra/newview/skins/default/xui/tr/panel_region_terrain.xml
index 3226ee008e70635ca0ab4072b4c9c91d7cac040e..e25047301d729417306db8eb162732bca0078bea 100644
--- a/indra/newview/skins/default/xui/tr/panel_region_terrain.xml
+++ b/indra/newview/skins/default/xui/tr/panel_region_terrain.xml
@@ -10,8 +10,8 @@
 	<spinner label="Yüzey Yükslt. Limiti" name="terrain_raise_spin"/>
 	<spinner label="Yüzey Alçatma Limiti" name="terrain_lower_spin"/>
 	<text name="detail_texture_text">
-		Yüzey Dokuları (512x512, 24 bit .tga dosyalar gerektirir)
-	</text>
+    Yüzey Dokuları (1024x1024, 24 bit .tga dosyalar gerektirir)
+  </text>
 	<text name="height_text_lbl">
 		1 (Düşük)
 	</text>
diff --git a/indra/newview/skins/default/xui/tr/strings.xml b/indra/newview/skins/default/xui/tr/strings.xml
index 982de76a5bd91ebabdfd3aeeee9b5652e79db96f..e709a4c5d65d337b8e3c1f1933133576edcfeb88 100644
--- a/indra/newview/skins/default/xui/tr/strings.xml
+++ b/indra/newview/skins/default/xui/tr/strings.xml
@@ -187,7 +187,7 @@ Ses Sunucusu Sürümü: [VOICE_VERSION]
 	<string name="LoginFailedNoNetwork">
 		Ağ hatası: Bağlantı kurulamadı, lütfen ağ bağlantınızı kontrol edin.
 	</string>
-	<string name="LoginFailed">
+	<string name="LoginFailedHeader">
 		Oturum açılamadı.
 	</string>
 	<string name="Quit">
@@ -357,6 +357,24 @@ Lütfen bir dakika içerisinde tekrar oturum açmayı deneyin.
 	<string name="TestingDisconnect">
 		Görüntüleyici bağlantısının kesilmesi test ediliyor
 	</string>
+	<string name="SocialFacebookConnecting">
+		Facebook ile bağlantı kuruluyor...
+	</string>
+	<string name="SocialFacebookPosting">
+		Yayınlanıyor...
+	</string>
+	<string name="SocialFacebookDisconnecting">
+		Facebook bağlantısı kesiliyor...
+	</string>
+	<string name="SocialFacebookErrorConnecting">
+		Facebook ile bağlantı kurulurken sorun oluştu
+	</string>
+	<string name="SocialFacebookErrorPosting">
+		Facebook&apos;ta yayınlarken sorun oluştu
+	</string>
+	<string name="SocialFacebookErrorDisconnecting">
+		Facebook bağlantısı kesilirken sorun oluştu
+	</string>
 	<string name="SocialFlickrConnecting">
 		Flickr bağlantısı kuruluyor...
 	</string>
@@ -671,9 +689,6 @@ kartlarına eklenebilir.
 	<string name="GroupNameNone">
 		(hiçbiri)
 	</string>
-	<string name="AvalineCaller">
-		Avaline Arayanı [ORDER]
-	</string>
 	<string name="AssetErrorNone">
 		Hata yok
 	</string>
@@ -2576,9 +2591,21 @@ Bu mesaj size gelmeye devam ederse lütfen http://support.secondlife.com adresin
 	<string name="NoPicksClassifiedsText">
 		Herhangi bir Seçme veya İlan oluşturmadınız. Bir Seçme veya İlan oluşturmak için aşağıdaki Artı düğmesine tıklayın.
 	</string>
+	<string name="NoPicksText">
+		Herhangi bir Favori oluşturmadınız. Bir Favori oluşturmak için Yeni düğmesine tıklayın.
+	</string>
+	<string name="NoClassifiedsText">
+		Herhangi bir İlan oluşturmadınız. Bir İlan oluşturmak için Yeni düğmesine tıklayın.
+	</string>
 	<string name="NoAvatarPicksClassifiedsText">
 		Kullanıcının herhangi bir seçmesi veya ilanı yok
 	</string>
+	<string name="NoAvatarPicksText">
+		Kullanıcının favorisi yok
+	</string>
+	<string name="NoAvatarClassifiedsText">
+		Kullanıcının ilanı yok
+	</string>
 	<string name="PicksClassifiedsLoadingText">
 		Yükleniyor...
 	</string>
@@ -4556,6 +4583,9 @@ Bu iletiyi almaya devam ederseniz, lütfen [SUPPORT_SITE] bölümüne başvurun.
 	<string name="share_alert">
 		Envanterinizden buraya öğeler sürükleyin
 	</string>
+	<string name="facebook_post_success">
+		Facebook&apos;ta yayınladınız.
+	</string>
 	<string name="flickr_post_success">
 		Flickr&apos;da yayınladınız.
 	</string>
diff --git a/indra/newview/skins/default/xui/zh/floater_about.xml b/indra/newview/skins/default/xui/zh/floater_about.xml
index 9f6b4421a9a6b993e1f4e084c44f92696caa6ce8..d7d2a52750fee21d68b72c0fb335676a392b144e 100644
--- a/indra/newview/skins/default/xui/zh/floater_about.xml
+++ b/indra/newview/skins/default/xui/zh/floater_about.xml
@@ -19,7 +19,6 @@
         expat Copyright (C) 1998, 1999, 2000 Thai Open Source Software Center Ltd.
         FreeType Copyright (C) 1996-2002, 2006 David Turner, Robert Wilhelm, and Werner Lemberg.
         GL Copyright (C) 1999-2004 Brian Paul.
-        GLOD Copyright (C) 2003-04 Jonathan Cohen, Nat Duca, Chris Niski, Johns Hopkins University and David Luebke, Brenden Schubert, University of Virginia.
         google-perftools Copyright (c) 2005, Google Inc.
         Havok.com(TM) Copyright (C) 1999-2001, Telekinesys Research Limited.
         jpeg2000 Copyright (C) 2001, David Taubman, The University of New South Wales (UNSW)
diff --git a/indra/newview/skins/default/xui/zh/floater_picks.xml b/indra/newview/skins/default/xui/zh/floater_picks.xml
deleted file mode 100644
index a8bfcd99e3cf9ae46531130470b0412bda84d58b..0000000000000000000000000000000000000000
--- a/indra/newview/skins/default/xui/zh/floater_picks.xml
+++ /dev/null
@@ -1,2 +0,0 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<floater name="floater_picks" title="精選地點"/>
diff --git a/indra/newview/skins/default/xui/zh/floater_preview_texture.xml b/indra/newview/skins/default/xui/zh/floater_preview_texture.xml
index 2b6eac48b34dc458e493a5824bc965c9e0790d80..9213cc212d7556700f8ffe84c22b1e84b01fa19e 100644
--- a/indra/newview/skins/default/xui/zh/floater_preview_texture.xml
+++ b/indra/newview/skins/default/xui/zh/floater_preview_texture.xml
@@ -6,42 +6,23 @@
 	<floater.string name="Copy">
 		覆製到收納區
 	</floater.string>
-	<text name="desc txt">
-		描述:
-	</text>
-	<text name="dimensions">
-		[WIDTH]像素 x [HEIGHT]像素
-	</text>
-	<text name="aspect_ratio">
-		預覽長寬比
-	</text>
-	<combo_box name="combo_aspect_ratio" tool_tip="以固定長寬比預覽">
-		<combo_item name="Unconstrained">
-			不受限
-		</combo_item>
-		<combo_item name="1:1" tool_tip="群組徽章或現實世界小檔案">
-			1:1
-		</combo_item>
-		<combo_item name="4:3" tool_tip="[SECOND_LIFE] 檔案">
-			4:3
-		</combo_item>
-		<combo_item name="10:7" tool_tip="個人廣告和搜索刊登廣告、地標">
-			10:7
-		</combo_item>
-		<combo_item name="3:2" tool_tip="土地資料">
-			3:2
-		</combo_item>
-		<combo_item name="16:10">
-			16:10
-		</combo_item>
-		<combo_item name="16:9" tool_tip="個人檔案精選">
-			16:9
-		</combo_item>
-		<combo_item name="2:1">
-			2:1
-		</combo_item>
-	</combo_box>
-	<button label="確定" name="Keep"/>
-	<button label="丟棄" name="Discard"/>
-	<button label="另存為" name="save_tex_btn"/>
+	<layout_stack name="preview_stack">
+		<layout_panel name="texture_panel">
+			<text name="desc txt">
+				描述:
+			</text>
+			<text name="dimensions">
+				[WIDTH]像素 x [HEIGHT]像素
+			</text>
+			<text name="aspect_ratio">
+				預覽長寬比
+			</text>
+			<combo_box name="combo_aspect_ratio" tool_tip="以固定長寬比預覽"/>
+		</layout_panel>
+		<layout_panel name="buttons_panel">
+			<button label="確定" name="Keep"/>
+			<button label="丟棄" name="Discard"/>
+			<button label="另存為" name="save_tex_btn"/>
+		</layout_panel>
+	</layout_stack>
 </floater>
diff --git a/indra/newview/skins/default/xui/zh/floater_profile.xml b/indra/newview/skins/default/xui/zh/floater_profile.xml
new file mode 100644
index 0000000000000000000000000000000000000000..0f73f527a9e2c441fac6a23948ba147b9e109bd3
--- /dev/null
+++ b/indra/newview/skins/default/xui/zh/floater_profile.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<floater name="avatarinfo" title="簡覽">
+	<panel name="panel_profile_view">
+		<tab_container name="panel_profile_tabs">
+			<panel label="第二人生" name="panel_profile_secondlife"/>
+			<panel label="網頁" name="panel_profile_web"/>
+			<panel label="興趣" name="panel_profile_interests"/>
+			<panel label="精選地點" name="panel_profile_picks"/>
+			<panel label="分類廣告" name="panel_profile_classifieds"/>
+			<panel label="真實世界" name="panel_profile_firstlife"/>
+			<panel label="筆記" name="panel_profile_notes"/>
+		</tab_container>
+		<button label="確定" name="ok_btn" tool_tip="儲存變更到個人檔案後關閉"/>
+		<button label="取消" label_selected="取消" name="cancel_btn"/>
+	</panel>
+</floater>
diff --git a/indra/newview/skins/default/xui/zh/floater_snapshot.xml b/indra/newview/skins/default/xui/zh/floater_snapshot.xml
index 409024808308ccbcb962a167bb2d6a944f82d75d..6e1a1567624441a8ebb1846da27cf0112d8315c7 100644
--- a/indra/newview/skins/default/xui/zh/floater_snapshot.xml
+++ b/indra/newview/skins/default/xui/zh/floater_snapshot.xml
@@ -6,6 +6,9 @@
 	<string name="postcard_progress_str">
 		正在發送電郵
 	</string>
+	<string name="facebook_progress_str">
+		發佈到臉書
+	</string>
 	<string name="profile_progress_str">
 		發佈
 	</string>
@@ -15,6 +18,9 @@
 	<string name="local_progress_str">
 		正在存到電腦
 	</string>
+	<string name="facebook_succeeded_str">
+		圖像已上傳
+	</string>
 	<string name="profile_succeeded_str">
 		圖像已上傳
 	</string>
@@ -27,6 +33,9 @@
 	<string name="local_succeeded_str">
 		成功存入電腦!
 	</string>
+	<string name="facebook_failed_str">
+		上傳圖像到你的臉書時間線時失敗。
+	</string>
 	<string name="profile_failed_str">
 		上傳圖像到你的檔案訊息發佈時出錯。
 	</string>
diff --git a/indra/newview/skins/default/xui/zh/menu_name_field.xml b/indra/newview/skins/default/xui/zh/menu_name_field.xml
new file mode 100644
index 0000000000000000000000000000000000000000..5eaf3461cde9f734ca31134b7dcab94e4bea66fc
--- /dev/null
+++ b/indra/newview/skins/default/xui/zh/menu_name_field.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<toggleable_menu name="CopyMenu">
+	<menu_item_call label="複製顯示名稱" name="copy_display"/>
+	<menu_item_call label="複製代理名稱" name="copy_name"/>
+	<menu_item_call label="複製代理ID" name="copy_id"/>
+</toggleable_menu>
diff --git a/indra/newview/skins/default/xui/zh/notifications.xml b/indra/newview/skins/default/xui/zh/notifications.xml
index cfde824349bb841f52536312912872a1aab76cd9..4d0f1cb85b63d25e2a9b957b5ca0a161051d213c 100644
--- a/indra/newview/skins/default/xui/zh/notifications.xml
+++ b/indra/newview/skins/default/xui/zh/notifications.xml
@@ -2666,6 +2666,9 @@ SHA1 指紋:[MD5_DIGEST]
 	<notification name="SystemMessage">
 		[MESSAGE]
 	</notification>
+	<notification name="FacebookConnect">
+		[MESSAGE]
+	</notification>
 	<notification name="FlickrConnect">
 		[MESSAGE]
 	</notification>
diff --git a/indra/newview/skins/default/xui/zh/panel_edit_classified.xml b/indra/newview/skins/default/xui/zh/panel_edit_classified.xml
index b06ece02addf66744ccfcfab4d0ce61e1f1dd3d7..4d3248db46ab517c5036b99d299908337b13764c 100644
--- a/indra/newview/skins/default/xui/zh/panel_edit_classified.xml
+++ b/indra/newview/skins/default/xui/zh/panel_edit_classified.xml
@@ -46,7 +46,7 @@
 			<layout_panel name="save_changes_btn_lp">
 				<button label="[LABEL]" name="save_changes_btn"/>
 			</layout_panel>
-			<layout_panel name="show_on_map_btn_lp">
+			<layout_panel name="cancel_btn_lp">
 				<button label="取消" name="cancel_btn"/>
 			</layout_panel>
 		</layout_stack>
diff --git a/indra/newview/skins/default/xui/zh/panel_group_list_item_short.xml b/indra/newview/skins/default/xui/zh/panel_group_list_item_short.xml
new file mode 100644
index 0000000000000000000000000000000000000000..fec4bb572ab791ce408f4d23c30ae3ad50eed625
--- /dev/null
+++ b/indra/newview/skins/default/xui/zh/panel_group_list_item_short.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="group_list_item">
+	<text name="group_name" value="未知"/>
+	<button name="info_btn" tool_tip="詳情"/>
+	<button name="profile_btn" tool_tip="察看檔案"/>
+</panel>
diff --git a/indra/newview/skins/default/xui/zh/panel_me.xml b/indra/newview/skins/default/xui/zh/panel_me.xml
deleted file mode 100644
index aad1348e4680d265507af7e5a7b44e8a21de1c6c..0000000000000000000000000000000000000000
--- a/indra/newview/skins/default/xui/zh/panel_me.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<panel label="我的個人檔案" name="panel_me">
-	<panel label="我的精選地點" name="panel_picks"/>
-</panel>
diff --git a/indra/newview/skins/default/xui/zh/panel_people.xml b/indra/newview/skins/default/xui/zh/panel_people.xml
index b0e60218cf3971f78e99b5d8ca595f44e9efe28d..b95dd960266cd85b9111030f681e41622ec1b1ae 100644
--- a/indra/newview/skins/default/xui/zh/panel_people.xml
+++ b/indra/newview/skins/default/xui/zh/panel_people.xml
@@ -40,6 +40,7 @@
 			<accordion name="friends_accordion">
 				<accordion_tab name="tab_online" title="上線"/>
 				<accordion_tab name="tab_all" title="全部"/>
+				<accordion_tab name="tab_suggested_friends" title="你可能想要加為好友的人"/>
 			</accordion>
 		</panel>
 		<panel label="群組" name="groups_panel">
diff --git a/indra/newview/skins/default/xui/zh/panel_profile_classified.xml b/indra/newview/skins/default/xui/zh/panel_profile_classified.xml
new file mode 100644
index 0000000000000000000000000000000000000000..4eee4e8855697724ecb31b588b984ee55950d973
--- /dev/null
+++ b/indra/newview/skins/default/xui/zh/panel_profile_classified.xml
@@ -0,0 +1,110 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="panel_profile_classified">
+	<panel.string name="type_mature">
+		適度成人
+	</panel.string>
+	<panel.string name="type_pg">
+		一般普級內容
+	</panel.string>
+	<panel.string name="l$_price">
+		L$[PRICE]
+	</panel.string>
+	<panel.string name="click_through_text_fmt">
+		[TELEPORT] 瞬間傳送,[MAP] 地圖,[PROFILE] 檔案
+	</panel.string>
+	<panel.string name="date_fmt">
+		[mthnum,datetime,slt]/[day,datetime,slt]/[year,datetime,slt]
+	</panel.string>
+	<panel.string name="auto_renew_on">
+		已啟用
+	</panel.string>
+	<panel.string name="auto_renew_off">
+		已停用
+	</panel.string>
+	<panel.string name="location_notice">
+		(儲存後將會更新)
+	</panel.string>
+	<string name="publish_label">
+		發布
+	</string>
+	<string name="save_label">
+		儲存
+	</string>
+	<scroll_container name="profile_scroll">
+		<panel name="info_scroll_content_panel">
+			<icon label="" name="edit_icon" tool_tip="點按以選擇圖像"/>
+			<layout_stack name="info_panel">
+				<layout_panel name="main_info_panel">
+					<text_editor name="classified_name">
+						[name]
+					</text_editor>
+					<text name="classified_location_label" value="位置:"/>
+					<text_editor name="classified_location" value="[loading...]"/>
+					<text name="content_type_label" value="內容類型:"/>
+					<text_editor name="content_type" value="[content type]"/>
+					<text name="category_label" value="分類:"/>
+					<text_editor name="category" value="[category]"/>
+					<text name="creation_date_label" value="建立日期:"/>
+					<text_editor name="creation_date" tool_tip="建立日期" value="[date]"/>
+					<text name="price_for_listing_label" value="刊登費:"/>
+					<text_editor name="price_for_listing" tool_tip="刊登費。">
+						[PRICE]
+					</text_editor>
+				</layout_panel>
+				<layout_panel name="clickthrough_layout_panel">
+					<text name="click_through_label" value="點按狀況:"/>
+					<text_editor name="click_through_text" tool_tip="點按資料" value="[clicks]"/>
+				</layout_panel>
+				<layout_panel name="auto_renew_layout_panel">
+					<text name="auto_renew_label" value="自動續訂:"/>
+					<text name="auto_renew" value="已啟用"/>
+				</layout_panel>
+				<layout_panel name="descr_layout_panel">
+					<text name="classified_desc_label" value="描述:"/>
+					<text_editor name="classified_desc" value="[description]"/>
+				</layout_panel>
+			</layout_stack>
+			<panel name="edit_panel">
+				<text name="Name:">
+					標題:
+				</text>
+				<text name="description_label">
+					描述:
+				</text>
+				<text name="location_label">
+					位置:
+				</text>
+				<text name="classified_location_edit">
+					載入中...
+				</text>
+				<button label="設定為目前位置" name="set_to_curr_location_btn"/>
+				<text name="category_label" value="分類:"/>
+				<text name="content_type_label" value="內容類型:"/>
+				<icons_combo_box label="一般普級內容" name="content_type_edit">
+					<icons_combo_box.item label="適度成人內容" name="mature_ci" value="適度成人"/>
+					<icons_combo_box.item label="一般普級內容" name="pg_ci" value="一般普級"/>
+				</icons_combo_box>
+				<check_box label="每星期自動續訂" name="auto_renew_edit"/>
+				<text name="price_for_listing_edit_label" value="刊登費:"/>
+				<spinner label="L$" name="price_for_listing_edit" tool_tip="刊登費。" value="50"/>
+			</panel>
+		</panel>
+	</scroll_container>
+	<layout_stack name="edit_btns_pnl">
+		<layout_panel name="teleport_btn_lp">
+			<button label="瞬間傳送" name="teleport_btn"/>
+		</layout_panel>
+		<layout_panel name="map_btn_lp">
+			<button label="地圖" name="show_on_map_btn"/>
+		</layout_panel>
+		<layout_panel name="edit_btn_lp">
+			<button label="編輯" name="edit_btn"/>
+		</layout_panel>
+		<layout_panel name="save_btn_lp">
+			<button label="[LABEL]" name="save_changes_btn"/>
+		</layout_panel>
+		<layout_panel name="cancel_btn_lp">
+			<button label="取消" name="cancel_btn"/>
+		</layout_panel>
+	</layout_stack>
+</panel>
diff --git a/indra/newview/skins/default/xui/zh/panel_profile_classifieds.xml b/indra/newview/skins/default/xui/zh/panel_profile_classifieds.xml
new file mode 100644
index 0000000000000000000000000000000000000000..89b5cdf6415020d44855669f7b12f8b1883969d5
--- /dev/null
+++ b/indra/newview/skins/default/xui/zh/panel_profile_classifieds.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel label="分類廣告" name="panel_profile_classifieds">
+	<string name="no_classifieds" value="禁止個人廣告"/>
+	<button label="新增…" name="new_btn"/>
+	<button label="刪除…" name="delete_btn"/>
+	<text name="classifieds_panel_text">
+		載入中…
+	</text>
+</panel>
diff --git a/indra/newview/skins/default/xui/zh/panel_profile_firstlife.xml b/indra/newview/skins/default/xui/zh/panel_profile_firstlife.xml
new file mode 100644
index 0000000000000000000000000000000000000000..9370661d7fd0d479db624deca99c24c1689b43a0
--- /dev/null
+++ b/indra/newview/skins/default/xui/zh/panel_profile_firstlife.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel label="簡覽" name="panel_profile_firstlife"/>
diff --git a/indra/newview/skins/default/xui/zh/panel_profile_interests.xml b/indra/newview/skins/default/xui/zh/panel_profile_interests.xml
new file mode 100644
index 0000000000000000000000000000000000000000..150f3cca4fa011ea14f8b303bff847782a3500b0
--- /dev/null
+++ b/indra/newview/skins/default/xui/zh/panel_profile_interests.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel label="興趣" name="panel_profile_interests">
+	<text name="I Want To:">
+		我想要:
+	</text>
+	<check_box label="建造" name="chk0"/>
+	<check_box label="探索" name="chk1"/>
+	<check_box label="見面" name="chk2"/>
+	<check_box label="受雇" name="chk6"/>
+	<check_box label="群組" name="chk3"/>
+	<check_box label="購買" name="chk4"/>
+	<check_box label="出售" name="chk5"/>
+	<check_box label="招人" name="chk7"/>
+	<line_editor name="want_to_edit">
+		(載入中...)
+	</line_editor>
+	<text name="Skills:">
+		技能:
+	</text>
+	<check_box label="材質" name="schk0"/>
+	<check_box label="架構" name="schk1"/>
+	<check_box label="建模" name="schk3"/>
+	<check_box label="計畫活動" name="schk2"/>
+	<check_box label="建腳本" name="schk4"/>
+	<check_box label="定製角色" name="schk5"/>
+	<line_editor name="skills_edit">
+		(載入中...)
+	</line_editor>
+	<text name="Languages:">
+		語言:
+	</text>
+	<line_editor name="languages_edit">
+		(載入中...)
+	</line_editor>
+</panel>
diff --git a/indra/newview/skins/default/xui/zh/panel_profile_notes.xml b/indra/newview/skins/default/xui/zh/panel_profile_notes.xml
new file mode 100644
index 0000000000000000000000000000000000000000..17e1a997dad67e175bdbae08a3d7860035e2fc37
--- /dev/null
+++ b/indra/newview/skins/default/xui/zh/panel_profile_notes.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel label="筆記和隱私" name="panel_notes">
+	<text name="status_message" value="關於這化身的私人筆記:"/>
+	<text name="status_message2" value="允許這個化身:"/>
+	<check_box label="看見我何時上線" name="status_check"/>
+	<check_box label="在世界地圖上找到我" name="map_check"/>
+	<check_box label="邊輯,刪除或取下我的物件" name="objects_check"/>
+</panel>
diff --git a/indra/newview/skins/default/xui/zh/panel_profile_pick.xml b/indra/newview/skins/default/xui/zh/panel_profile_pick.xml
new file mode 100644
index 0000000000000000000000000000000000000000..5f8d6a2ba5ee3e4334c48bae300a231696c97619
--- /dev/null
+++ b/indra/newview/skins/default/xui/zh/panel_profile_pick.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="panel_pick_info">
+	<panel.string name="location_notice">
+		(儲存後將會更新)
+	</panel.string>
+	<line_editor name="pick_location">
+		載入中…
+	</line_editor>
+	<button label="瞬間傳送" name="teleport_btn"/>
+	<button label="顯示在地圖上" name="show_on_map_btn"/>
+	<button label="設定位置" name="set_to_curr_location_btn" tool_tip="設定為目前位置"/>
+	<button label="儲存精選地點" name="save_changes_btn"/>
+</panel>
diff --git a/indra/newview/skins/default/xui/zh/panel_profile_picks.xml b/indra/newview/skins/default/xui/zh/panel_profile_picks.xml
new file mode 100644
index 0000000000000000000000000000000000000000..8f189d13087704f410f9a71f9db57dec3774326d
--- /dev/null
+++ b/indra/newview/skins/default/xui/zh/panel_profile_picks.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel label="精選地點" name="panel_picks">
+	<string name="no_picks" value="無精選地點"/>
+	<text name="Tell everyone about your favorite places in Second Life.">
+		告訴大家你在Second Life中最愛的去處。
+	</text>
+	<button label="新增…" name="new_btn"/>
+	<button label="刪除…" name="delete_btn"/>
+	<text name="picks_panel_text">
+		載入中…
+	</text>
+</panel>
diff --git a/indra/newview/skins/default/xui/zh/panel_profile_secondlife.xml b/indra/newview/skins/default/xui/zh/panel_profile_secondlife.xml
new file mode 100644
index 0000000000000000000000000000000000000000..da4aafce556924582deb2253a934aac4797084b3
--- /dev/null
+++ b/indra/newview/skins/default/xui/zh/panel_profile_secondlife.xml
@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel label="簡覽" name="panel_profile">
+	<string name="status_online">
+		目前在線
+	</string>
+	<string name="status_offline">
+		目前離線
+	</string>
+	<string name="CaptionTextAcctInfo">
+		[ACCTTYPE]
+[PAYMENTINFO]
+	</string>
+	<string name="payment_update_link_url">
+		http://www.secondlife.com/account/billing.php?lang=en
+	</string>
+	<string name="partner_edit_link_url">
+		http://www.secondlife.com/account/partners.php?lang=en
+	</string>
+	<string name="my_account_link_url" value="http://secondlife.com/account"/>
+	<string name="no_partner_text" value="ç„¡"/>
+	<string name="no_group_text" value="ç„¡"/>
+	<string name="RegisterDateFormat">
+		[REG_DATE]
+	</string>
+	<string name="name_text_args">
+		[NAME]
+	</string>
+	<string name="display_name_text_args">
+		[DISPLAY_NAME]
+	</string>
+	<string name="FSDev" value="開發者"/>
+	<string name="FSSupp" value="支援"/>
+	<string name="FSQualityAssurance" value="除錯獵人"/>
+	<string name="FSGW" value="網關"/>
+	<text name="name_label" value="名稱:"/>
+	<button label="名稱:" name="set_name" tool_tip="設定顯示名稱"/>
+	<panel name="name_holder">
+		<text_editor name="complete_name" value="(載入中...)"/>
+	</panel>
+	<layout_stack name="imagepositioner">
+		<layout_panel name="label_stack">
+			<text name="status" value="狀態不明"/>
+			<text name="label" value="Second Life生日:"/>
+			<text name="label2" value="帳戶:"/>
+			<text name="partner_label" value="伴侶:"/>
+		</layout_panel>
+	</layout_stack>
+	<text name="Groups:" value="群組:"/>
+	<button label="+" label_selected="+" name="group_invite" tool_tip="邀請加入群組"/>
+	<layout_stack name="aboutpositioner">
+		<layout_panel name="about_stack">
+			<text name="About:" value="關於:"/>
+		</layout_panel>
+		<layout_panel name="give_stack">
+			<text name="Give item:" value="贈與物品:"/>
+			<text name="Give inventory" tool_tip="把收納區物品放到這裡,送給此人。">
+				把收納區物品放到這裡。
+			</text>
+		</layout_panel>
+	</layout_stack>
+	<layout_stack name="buttonstack">
+		<layout_panel name="left_buttonstack">
+			<button label="在地圖上查找" label_selected="在地圖上查找" name="show_on_map_btn" tool_tip="在地圖上找出這個居民"/>
+			<button label="支付" label_selected="支付" name="pay" tool_tip="付款給這個居民"/>
+		</layout_panel>
+		<layout_panel name="middle_buttonstack">
+			<button label="發出瞬間傳送邀請" label_selected="發出瞬間傳送邀請" name="teleport" tool_tip="向這個居民發出瞬間傳送邀請"/>
+			<button label="即時訊息" label_selected="即時訊息" name="im" tool_tip="開啟即時訊息會話"/>
+		</layout_panel>
+		<layout_panel name="right_buttonstack">
+			<button label="加為朋友" label_selected="加為朋友" name="add_friend" tool_tip="向這個居民發出交友邀請"/>
+			<button label="封鎖" name="block" tool_tip="封鎖這位居民"/>
+			<button label="解除封鎖" name="unblock" tool_tip="不再封鎖這位居民"/>
+		</layout_panel>
+	</layout_stack>
+	<check_box label="在搜尋結果中顯示" name="show_in_search_checkbox"/>
+</panel>
diff --git a/indra/newview/skins/default/xui/zh/panel_profile_web.xml b/indra/newview/skins/default/xui/zh/panel_profile_web.xml
new file mode 100644
index 0000000000000000000000000000000000000000..566651dceb186d04cc3c0f43707ab63385be86e8
--- /dev/null
+++ b/indra/newview/skins/default/xui/zh/panel_profile_web.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel label="網頁" name="panel_profile_web">
+	<panel.string name="LoadTime" value="載入時間:[TIME]秒"/>
+	<line_editor name="url_edit">
+		(載入中…)
+	</line_editor>
+	<flyout_button label="載入" name="load" tool_tip="用內嵌瀏覽器載入此個人檔案頁面。">
+		<flyout_button.item label="開啓内部瀏覽器" name="open_item"/>
+		<flyout_button.item label="開啓外部瀏覽器" name="home_item"/>
+	</flyout_button>
+	<button name="web_profile_popout_btn" tool_tip="彈出式個人檔案網頁"/>
+</panel>
diff --git a/indra/newview/skins/default/xui/zh/panel_region_terrain.xml b/indra/newview/skins/default/xui/zh/panel_region_terrain.xml
index 85e759e445f99d947c93cbc5772589712e8b55b0..81bce4687681eb9cb757cd962497e84e77168580 100644
--- a/indra/newview/skins/default/xui/zh/panel_region_terrain.xml
+++ b/indra/newview/skins/default/xui/zh/panel_region_terrain.xml
@@ -10,7 +10,7 @@
 	<spinner label="地形提升限制" name="terrain_raise_spin"/>
 	<spinner label="地形降低限制" name="terrain_lower_spin"/>
 	<text name="detail_texture_text">
-		地形材質(須 512x512,24 位元 .tga 檔格式)
+		地形材質(須 1024x1024,24 位元 .tga 檔格式)
 	</text>
 	<text name="height_text_lbl">
 		1(低)
diff --git a/indra/newview/skins/default/xui/zh/strings.xml b/indra/newview/skins/default/xui/zh/strings.xml
index 3221cde3b7f732cf978c0918512c0024bd6b72db..bdb16c9bf111e5afeecf864ff0e51aa5622d2645 100644
--- a/indra/newview/skins/default/xui/zh/strings.xml
+++ b/indra/newview/skins/default/xui/zh/strings.xml
@@ -187,7 +187,7 @@ LibVLC版本:[LIBVLC_VERSION]N]
 	<string name="LoginFailedNoNetwork">
 		網路錯誤:無法建立連線,請檢查網路連線是否正常。
 	</string>
-	<string name="LoginFailed">
+	<string name="LoginFailedHeader">
 		登入失敗。
 	</string>
 	<string name="Quit">
@@ -353,6 +353,24 @@ http://secondlife.com/viewer-access-faq
 	<string name="TestingDisconnect">
 		測試瀏覽器斷線
 	</string>
+	<string name="SocialFacebookConnecting">
+		連通臉書中…
+	</string>
+	<string name="SocialFacebookPosting">
+		發佈中…
+	</string>
+	<string name="SocialFacebookDisconnecting">
+		臉書連通中斷中…
+	</string>
+	<string name="SocialFacebookErrorConnecting">
+		連通臉書時出問題
+	</string>
+	<string name="SocialFacebookErrorPosting">
+		發佈到臉書時出問題
+	</string>
+	<string name="SocialFacebookErrorDisconnecting">
+		試圖中斷臉書連通時出問題
+	</string>
 	<string name="SocialFlickrConnecting">
 		連通 Flickr 中…
 	</string>
@@ -667,9 +685,6 @@ http://secondlife.com/viewer-access-faq
 	<string name="GroupNameNone">
 		(無)
 	</string>
-	<string name="AvalineCaller">
-		Avaline 通話者 [ORDER]
-	</string>
 	<string name="AssetErrorNone">
 		無錯誤
 	</string>
@@ -2569,9 +2584,21 @@ http://secondlife.com/support 求助解決問題。
 	<string name="NoPicksClassifiedsText">
 		你尚未建立任何精選地點或個人廣告。 點按下面的 + 按鈕建立精選地點或個人廣告。
 	</string>
+	<string name="NoPicksText">
+		你尚未建立任何精選地點。 點按「新增」按鈕建立精選地點。
+	</string>
+	<string name="NoClassifiedsText">
+		你尚未建立任何分類廣告。 點按「新增」按鈕建立分類廣告。
+	</string>
 	<string name="NoAvatarPicksClassifiedsText">
 		使用者無精選地點或個人廣告
 	</string>
+	<string name="NoAvatarPicksText">
+		使用者沒有精選地點
+	</string>
+	<string name="NoAvatarClassifiedsText">
+		使用者沒有分類廣告
+	</string>
 	<string name="PicksClassifiedsLoadingText">
 		載入中...
 	</string>
@@ -4549,6 +4576,9 @@ http://secondlife.com/support 求助解決問題。
 	<string name="share_alert">
 		將收納區物品拖曳到這裡
 	</string>
+	<string name="facebook_post_success">
+		成功發佈到臉書。
+	</string>
 	<string name="flickr_post_success">
 		成功發佈到 Flickr。
 	</string>
diff --git a/indra/newview/tests/lllogininstance_test.cpp b/indra/newview/tests/lllogininstance_test.cpp
index 8d1956957c7ac72a135d7aa41e018e11e793ce3e..696fe3536c834f77324dd233ef06021f72252404 100644
--- a/indra/newview/tests/lllogininstance_test.cpp
+++ b/indra/newview/tests/lllogininstance_test.cpp
@@ -186,6 +186,10 @@ std::string LLGridManager::getAppSLURLBase(const std::string& grid_name)
 {
 	return "myappslurl";
 }
+std::string LLGridManager::getGridId(const std::string& grid)
+{
+    return std::string();
+}
 
 //-----------------------------------------------------------------------------
 #include "../llviewercontrol.h"
@@ -218,6 +222,8 @@ bool llHashedUniqueID(unsigned char* id)
 //-----------------------------------------------------------------------------
 #include "../llappviewer.h"
 void LLAppViewer::forceQuit(void) {}
+bool LLAppViewer::isUpdaterMissing() { return true; }
+bool LLAppViewer::waitForUpdater() { return false; }
 LLAppViewer * LLAppViewer::sInstance = 0;
 
 //-----------------------------------------------------------------------------
@@ -226,6 +232,8 @@ LLAppViewer * LLAppViewer::sInstance = 0;
 static std::string gTOSType;
 static LLEventPump * gTOSReplyPump = NULL;
 
+LLPointer<LLSecAPIHandler> gSecAPIHandler;
+
 //static
 LLFloater* LLFloaterReg::showInstance(const std::string& name, const LLSD& key, BOOL focus)
 {
@@ -343,6 +351,7 @@ namespace tut
 			gSavedSettings.declareString("ClientSettingsFile", "test_settings.xml", "", LLControlVariable::PERSIST_NO);
 			gSavedSettings.declareString("NextLoginLocation", "", "", LLControlVariable::PERSIST_NO);
 			gSavedSettings.declareBOOL("LoginLastLocation", FALSE, "", LLControlVariable::PERSIST_NO);
+            gSavedSettings.declareBOOL("CmdLineSkipUpdater", TRUE, "", LLControlVariable::PERSIST_NO);
 
 			LLSD authenticator = LLSD::emptyMap();
 			LLSD identifier = LLSD::emptyMap();
diff --git a/indra/newview/tests/llsecapi_test.cpp b/indra/newview/tests/llsecapi_test.cpp
index 37fbbb449be47c8101593331412b1a527256fe20..7d2a9a436f5c567759492ff542e0522b27706fd4 100644
--- a/indra/newview/tests/llsecapi_test.cpp
+++ b/indra/newview/tests/llsecapi_test.cpp
@@ -62,6 +62,7 @@ LLPointer<LLCertificateStore> LLSecAPIBasicHandler::getCertificateStore(const st
 void LLSecAPIBasicHandler::setProtectedData(const std::string& data_type, const std::string& data_id, const LLSD& data) {}
 void LLSecAPIBasicHandler::addToProtectedMap(const std::string& data_type, const std::string& data_id, const std::string& map_elem, const LLSD& data) {}
 void LLSecAPIBasicHandler::removeFromProtectedMap(const std::string& data_type, const std::string& data_id, const std::string& map_elem) {}
+void LLSecAPIBasicHandler::syncProtectedMap() {}
 LLSD LLSecAPIBasicHandler::getProtectedData(const std::string& data_type, const std::string& data_id) { return LLSD(); }
 void LLSecAPIBasicHandler::deleteProtectedData(const std::string& data_type, const std::string& data_id) {}
 LLPointer<LLCredential> LLSecAPIBasicHandler::createCredential(const std::string& grid, const LLSD& identifier, const LLSD& authenticator) { return NULL; }
diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py
index ae3ed56b3db3a5f82ee7ea3829746da262f02df1..59eb18b7347eeed24de2fa3f252330b32547885f 100755
--- a/indra/newview/viewer_manifest.py
+++ b/indra/newview/viewer_manifest.py
@@ -505,14 +505,6 @@ def construct(self):
         # Get shared libs from the shared libs staging directory
         with self.prefix(src=os.path.join(self.args['build'], os.pardir,
                                           'sharedlibs', self.args['configuration'])):
-
-            # Mesh 3rd party libs needed for auto LOD and collada reading
-            try:
-                self.path("glod.dll")
-            except RuntimeError as err:
-                print(err.message)
-                print("Skipping GLOD library (assumming linked statically)")
-
             # Get fmodstudio dll if needed
             if self.args['fmodstudio'] == 'ON':
                 if(self.args['configuration'].lower() == 'debug'):
@@ -535,6 +527,7 @@ def construct(self):
             # See http://msdn.microsoft.com/en-us/library/ms235291(VS.80).aspx
             self.path("msvcp140.dll")
             self.path("vcruntime140.dll")
+            self.path_optional("vcruntime140_1.dll")
 
             # SLVoice executable
             with self.prefix(src=os.path.join(pkgdir, 'bin', 'release')):
@@ -575,6 +568,7 @@ def construct(self):
 
         self.path(src="licenses-win32.txt", dst="licenses.txt")
         self.path("featuretable.txt")
+        self.path("cube.dae")
 
         with self.prefix(src=pkgdir):
             self.path("ca-bundle.crt")
@@ -612,6 +606,7 @@ def construct(self):
                                               'sharedlibs', 'Release')):
                 self.path("msvcp140.dll")
                 self.path("vcruntime140.dll")
+                self.path_optional("vcruntime140_1.dll")
 
             # CEF files common to all configurations
             with self.prefix(src=os.path.join(pkgdir, 'resources')):
@@ -960,6 +955,7 @@ def construct(self):
 
                 self.path("licenses-mac.txt", dst="licenses.txt")
                 self.path("featuretable_mac.txt")
+                self.path("cube.dae")
                 self.path("SecondLife.nib")
 
                 with self.prefix(src=pkgdir,dst=""):
@@ -1023,7 +1019,6 @@ def path_optional(src, dst):
                                 "libapr-1.0.dylib",
                                 "libaprutil-1.0.dylib",
                                 "libexpat.1.dylib",
-                                "libGLOD.dylib",
                                 # libnghttp2.dylib is a symlink to
                                 # libnghttp2.major.dylib, which is a symlink to
                                 # libnghttp2.version.dylib. Get all of them.
@@ -1313,9 +1308,8 @@ def package_finish(self):
                         ]
                     for attempt in range(3):
                         if attempt: # second or subsequent iteration
-                            print >> sys.stderr, \
-                                ("codesign failed, waiting %d seconds before retrying" %
-                                 sign_retry_wait)
+                            print("codesign failed, waiting {:d} seconds before retrying".format(sign_retry_wait),
+                                  file=sys.stderr)
                             time.sleep(sign_retry_wait)
                             sign_retry_wait*=2
 
@@ -1345,7 +1339,7 @@ def package_finish(self):
                             # 'err' goes out of scope
                             sign_failed = err
                     else:
-                        print >> sys.stderr, "Maximum codesign attempts exceeded; giving up"
+                        print("Maximum codesign attempts exceeded; giving up", file=sys.stderr)
                         raise sign_failed
                     self.run_command(['spctl', '-a', '-texec', '-vvvv', app_in_dmg])
                     self.run_command([self.src_path_of("installers/darwin/apple-notarize.sh"), app_in_dmg])
@@ -1435,6 +1429,7 @@ def construct(self):
             print("Skipping llcommon.so (assuming llcommon was linked statically)")
 
         self.path("featuretable_linux.txt")
+        self.path("cube.dae")
 
         with self.prefix(src=pkgdir):
             self.path("ca-bundle.crt")
@@ -1501,7 +1496,6 @@ def construct(self):
             self.path("libaprutil-1.so.0.4.1")
             self.path("libdb*.so")
             self.path("libexpat.so.*")
-            self.path("libGLOD.so")
             self.path("libuuid.so*")
             self.path("libSDL-1.2.so.*")
             self.path("libdirectfb-1.*.so.*")
diff --git a/indra/test/sync.h b/indra/test/sync.h
index ca8b7262d692612c7a7f9c656ee67d9e98e59213..bd837cb73054aa1659727288dee80bd6036e0a74 100644
--- a/indra/test/sync.h
+++ b/indra/test/sync.h
@@ -89,25 +89,26 @@ class Sync
     /// suspend until "somebody else" has bumped mCond by n steps
     void yield(int n=1)
     {
-        return yield_until(STRINGIZE("Sync::yield_for(" << n << ") timed out after "
-                                     << int(mTimeout.value()) << "ms"),
-                           mCond.get() + n);
+        return yield_until("Sync::yield_for", n, mCond.get() + n);
     }
 
     /// suspend until "somebody else" has bumped mCond to a specific value
     void yield_until(int until)
     {
-        return yield_until(STRINGIZE("Sync::yield_until(" << until << ") timed out after "
-                                     << int(mTimeout.value()) << "ms"),
-                           until);
+        return yield_until("Sync::yield_until", until, until);
     }
 
 private:
-    void yield_until(const std::string& desc, int until)
+    void yield_until(const char* func, int arg, int until)
     {
         std::string name(llcoro::logname());
         LL_DEBUGS() << name << " yield_until(" << until << ") suspending" << LL_ENDL;
-        tut::ensure(name + ' ' + desc, mCond.wait_for_equal(mTimeout, until));
+        if (! mCond.wait_for_equal(mTimeout, until))
+        {
+            tut::fail(STRINGIZE(name << ' ' << func << '(' << arg << ") timed out after "
+                                << int(mTimeout.value()) << "ms (expected " << until
+                                << ", actual " << mCond.get() << ')'));
+        }
         // each time we wake up, bump mCond
         bump();
     }
diff --git a/indra/test/test.cpp b/indra/test/test.cpp
index 87c4a8d8a3235101ef3a9924184eb3d6a8ab4111..bb48216b2b388499dad917d1e2d4eb8bf3853532 100644
--- a/indra/test/test.cpp
+++ b/indra/test/test.cpp
@@ -112,6 +112,7 @@ class RecordToTempFile : public LLError::Recorder, public boost::noncopyable
 
 	virtual void recordMessage(LLError::ELevel level, const std::string& message)
 	{
+        LL_PROFILE_ZONE_SCOPED
 		mFile << message << std::endl;
 	}
 
diff --git a/indra/viewer_components/login/lllogin.cpp b/indra/viewer_components/login/lllogin.cpp
index 168880dc12d8e216000b703ebcb5236288f67ca8..5d50d1e182c789ad1d634804bacf22c542e7506d 100644
--- a/indra/viewer_components/login/lllogin.cpp
+++ b/indra/viewer_components/login/lllogin.cpp
@@ -251,20 +251,35 @@ void LLLogin::Impl::loginCoro(std::string uri, LLSD login_params)
                 // Since sSyncPoint is an LLEventMailDrop, we DEFINITELY want to
                 // consume the posted event.
                 LLCoros::OverrideConsuming oc(true);
-                // Timeout should produce the isUndefined() object passed here.
-                LL_DEBUGS("LLLogin") << "Login failure, waiting for sync from updater" << LL_ENDL;
-                LLSD updater = llcoro::suspendUntilEventOnWithTimeout(sSyncPoint, 10, LLSD());
-                if (updater.isUndefined())
-                {
-                    LL_WARNS("LLLogin") << "Failed to hear from updater, proceeding with fail.login"
-                                        << LL_ENDL;
-                }
-                else
+                LLSD responses(mAuthResponse["responses"]);
+                LLSD updater;
+
+                if (printable_params["wait_for_updater"].asBoolean())
                 {
-                    LL_DEBUGS("LLLogin") << "Got responses from updater and login.cgi" << LL_ENDL;
+                    std::string reason_response = responses["data"]["reason"].asString();
+                    // Timeout should produce the isUndefined() object passed here.
+                    if (reason_response == "update")
+                    {
+                        LL_INFOS("LLLogin") << "Login failure, waiting for sync from updater" << LL_ENDL;
+                        updater = llcoro::suspendUntilEventOnWithTimeout(sSyncPoint, 10, LLSD());
+                    }
+                    else
+                    {
+                        LL_DEBUGS("LLLogin") << "Login failure, waiting for sync from updater" << LL_ENDL;
+                        updater = llcoro::suspendUntilEventOnWithTimeout(sSyncPoint, 3, LLSD());
+                    }
+                    if (updater.isUndefined())
+                    {
+                        LL_WARNS("LLLogin") << "Failed to hear from updater, proceeding with fail.login"
+                                            << LL_ENDL;
+                    }
+                    else
+                    {
+                        LL_DEBUGS("LLLogin") << "Got responses from updater and login.cgi" << LL_ENDL;
+                    }
                 }
+
                 // Let the fail.login handler deal with empty updater response.
-                LLSD responses(mAuthResponse["responses"]);
                 responses["updater"] = updater;
                 sendProgressEvent("offline", "fail.login", responses);
             }
diff --git a/scripts/content_tools/anim_tool.py b/scripts/content_tools/anim_tool.py
index e7b86a88fa07f76f17a532c0e80b11dea0f50b52..4a0773951ecb9dfdf635badfe11a3fbcf7fe48ab 100644
--- a/scripts/content_tools/anim_tool.py
+++ b/scripts/content_tools/anim_tool.py
@@ -611,6 +611,7 @@ def main(*argv):
     parser = argparse.ArgumentParser(description="process SL animations")
     parser.add_argument("--verbose", help="verbose flag", action="store_true")
     parser.add_argument("--dump", help="dump to stdout", action="store_true")
+    parser.add_argument("--use_aliases", help="use alias names for bones", action="store_true")
     parser.add_argument("--rot", help="specify sequence of rotations", type=float_triple, nargs="+")
     parser.add_argument("--rand_pos", help="request NUM random positions (default %(default)s)",
                         metavar="NUM", type=int, default=2)
@@ -637,6 +638,7 @@ def main(*argv):
     parser.add_argument("--no_hud", help="omit hud joints from list of attachments", action="store_true")
     parser.add_argument("--base_priority", help="set base priority", type=int)
     parser.add_argument("--joint_priority", help="set joint priority for all joints", type=int)
+    parser.add_argument("--force_joints", help="don't check validity of joint names", action="store_true")
     parser.add_argument("infilename", help="name of a .anim file to input")
     parser.add_argument("outfilename", nargs="?", help="name of a .anim file to output")
     args = parser.parse_args(argv)
@@ -661,7 +663,12 @@ def main(*argv):
         if lad_tree is None:
             raise Error("failed to parse " + args.lad)
     if args.joints:
-        joints = resolve_joints(args.joints, skel_tree, lad_tree, args.no_hud)
+        if args.force_joints:
+            joints = args.joints
+        else:
+            joints = resolve_joints(args.joints, skel_tree, lad_tree, args.no_hud)
+        if args.use_aliases:
+            joints = map(lambda name: "avatar_" + name, joints)
         if args.verbose:
             print("joints resolved to",joints)
         for name in joints:
diff --git a/scripts/content_tools/skel_tool.py b/scripts/content_tools/skel_tool.py
index 449ecd6a6ce01ede5688b5b1d10e6d303150efb7..696e4e29238f030c143581df7ea02d1eaecaad71 100644
--- a/scripts/content_tools/skel_tool.py
+++ b/scripts/content_tools/skel_tool.py
@@ -72,6 +72,22 @@ def check_symmetry(name, field, vec1, vec2):
     if vec1[2] != vec2[2]:
         print(name,field,"z match fail")
 
+def enforce_alias_rules(tree, element, fix=False):
+    if element.tag != "bone":
+        return
+    alias_lis = []
+    aliases = element.get("aliases")
+    if aliases:
+        alias_lis = aliases.split(" ")
+    name = element.get("name")
+    if name:
+        std_alias = "avatar_" + name
+        if not std_alias in alias_lis:
+            print "missing expected alias",name,std_alias
+        for alias in alias_lis:
+            if alias.startswith("avatar_") and alias != std_alias:
+                print "invalid avatar_ alias",name,alias
+
 def enforce_symmetry(tree, element, field, fix=False):
     name = element.get("name")
     if not name:
@@ -209,6 +225,7 @@ def validate_skel_tree(tree, ogtree, reftree, fix=False):
                             unfixable += 1
 
         fix_name(element)
+        enforce_alias_rules(tree, element, fix)
         enforce_precision_rules(element)
         for field in ["pos","pivot"]:
             enforce_symmetry(tree, element, field, fix)
diff --git a/scripts/perf/perfbot_run.py b/scripts/perf/perfbot_run.py
new file mode 100644
index 0000000000000000000000000000000000000000..55ea2fae66dd9d25a33a336eca3718efbe6f592f
--- /dev/null
+++ b/scripts/perf/perfbot_run.py
@@ -0,0 +1,204 @@
+#!/usr/bin/env python3
+"""\
+@file perfbot_run.py
+@brief Run a number of non interactive Viewers (PerfBots) with
+       a variety of options and settings. Pass --help for details.
+
+$LicenseInfo:firstyear=2007&license=viewerlgpl$
+Second Life Viewer Source Code
+Copyright (C) 2021, Linden Research, Inc.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation;
+version 2.1 of the License only.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+$/LicenseInfo$
+"""
+
+import argparse
+import subprocess
+import os
+import math
+import time
+
+# Required parameters that are always passed in
+# Specify noninteractive mode (SL-15999 for details)
+PARAM_NON_INTERACTIVE = "--noninteractive"
+# Run multiple Viewers at once
+PARAM_MULTI = "--multiple"
+# Specify username (first and last) and password
+PARAM_LOGIN = "--login"
+# SLURL to teleport to after login
+PARAM_SLURL = "--slurl"
+
+
+def gen_niv_script(args):
+    print(f"Reading creds from {(args.creds)} folder")
+    print(f"Using the non interactive Viewer from {(args.viewer)}")
+    print(f"Sleeping for {args.sleep}ms between Viewer launches")
+
+    # Read the lines from the creds file.  Typically this will be
+    # stored in the build-secrets-git private repository but you
+    # can point to any location with the --creds parameter
+    creds_lines = []
+    with open(args.creds) as file:
+        creds_lines = file.readlines()
+        creds_lines = [line.rstrip() for line in creds_lines]
+        creds_lines = [line for line in creds_lines if not line.startswith("#") and len(line)]
+    # We cannot log in more users than we have credentials for
+    if args.num==0:
+        args.num = len(creds_lines)
+    if args.num > len(creds_lines):
+        print(
+            f"The number of agents specified ({(args.num)}) exceeds "
+            f"the number of valid entries ({(len(creds_lines))}) in "
+            f"the creds file "
+        )
+        return
+
+    print(f"Launching {(args.num)} instances of the Viewer")
+
+    # The Viewer (in dev environments at least) needs a well specified
+    # working directory to function properly. We try to guess what it
+    # might be based on the full path to the Viewer executable but
+    # you can also specify it explicitly with the --cwd parameter
+    # (required for dev builds)
+    args.viewer = os.path.abspath(args.viewer)
+    if len(args.cwd) == 0:
+        working_dir = os.path.dirname(os.path.abspath(args.viewer))
+    else:
+        working_dir = os.path.abspath(args.cwd)
+    print(f"Working directory is {working_dir}, cwd {args.cwd}")
+    os.chdir(working_dir)
+
+    if args.dryrun:
+        print("Running in dry-run mode - no Viewers will be started")
+    print("")
+
+    for inst in range(args.num):
+
+        # Format of each cred line is username_first username_last password
+        # A space is used to separate each and a # at the start of a line
+        # removes it from the pool (useful if someone else is using a subset
+        # of the available ones)
+        creds = creds_lines[inst].split(" ")
+        username_first = creds[0]
+        username_last = creds[1]
+        password = creds[2]
+
+        # The default layout is an evenly spaced circle in the
+        # center of the region.  We may extend this to allow other
+        # patterns like a square/rectangle or a spiral. (Hint: it
+        # likely won't be needed :))
+        center_x = 128
+        center_y = 128
+        if args.layout == "circle":
+            radius = 6
+            angle = (2 * math.pi / args.num) * inst
+            region_x = int(math.sin(angle) * radius + center_x)
+            region_y = int(math.cos(angle) * radius + center_y)
+            region_z = 0
+        elif args.layout == "square":
+            region_x = center_x
+            region_y = center_y
+        elif args.layout == "spiral":
+            region_x = center_x
+            region_y = center_y
+        slurl = f"secondlife://{args.region}/{region_x}/{region_y}/{region_z}"
+
+        # Build the script line
+        script_cmd = [args.viewer]
+        script_cmd.append(PARAM_NON_INTERACTIVE)
+        script_cmd.append(PARAM_MULTI)
+        script_cmd.append(PARAM_LOGIN)
+        script_cmd.append(username_first)
+        script_cmd.append(username_last)
+        script_cmd.append(password)
+        script_cmd.append(PARAM_SLURL)
+        script_cmd.append(slurl)
+
+        # Display the script we will execute.
+        cmd = ""
+        for p in script_cmd:
+            cmd = cmd + " " + p
+        print(cmd)
+
+        # If --dry-run is specified, we do everything (including, most
+        # usefully, display the script lines) but do not start the Viewer
+        if args.dryrun == False:
+            print("opening viewer session with",script_cmd)
+            viewer_session = subprocess.Popen(script_cmd)
+
+        # Sleeping a bit between launches seems to help avoid a CPU
+        # surge when N Viewers are started simulatanously. The default
+        # value can be changed with the --sleep parameter
+        time.sleep(args.sleep / 1000)
+
+
+if __name__ == "__main__":
+    parser = argparse.ArgumentParser(allow_abbrev=False)
+    parser.add_argument(
+        "--num",
+        type=int,
+        default=0,
+        dest="num",
+        help="How many avatars to add to the script",
+    )
+    parser.add_argument(
+        "--creds",
+        default="../../../build-secrets-git/perf/perfbot_creds.txt",
+        dest="creds",
+        help="Location of the text file containing user credentials",
+    )
+    parser.add_argument(
+        "--viewer",
+        default="C:/Program Files/SecondLife/SecondLifeViewer.exe",
+        dest="viewer",
+        help="Location of the non interactive Viewer build",
+    )
+    parser.add_argument(
+        "--cwd",
+        default="",
+        dest="cwd",
+        help="Location of the current working directory to use",
+    )
+    parser.add_argument(
+        "--region",
+        default="Lag Me 5",
+        dest="region",
+        help="The SLURL for the Second Life region to visit",
+    )
+    parser.add_argument(
+        "--layout",
+        default="circle",
+        dest="layout",
+        choices={"circle", "square", "spiral"},
+        help="The geometric layout of the avatar destination locations",
+    )
+    parser.add_argument(
+        "--sleep",
+        type=int,
+        default=1000,
+        dest="sleep",
+        help="Time to sleep between launches in milliseconds",
+    )
+    parser.add_argument(
+        "--dry-run",
+        action="store_true",
+        dest="dryrun",
+        help="Dryrun mode - display parameters and script lines but do not start any Viewers",
+    )
+    args = parser.parse_args()
+
+    gen_niv_script(args)