diff --git a/.gitignore b/.gitignore
index 4af34870cf621d95cb8aa4d1991d8fe993da8e19..3619681d82bd297a3967388f52897c782f3fe52a 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/autobuild.xml b/autobuild.xml
index 4768bd25c67295e05bfabb208e7de949a2e413fd..2e4397ab2014cfd092fa67f0217eb3401dbb2189 100644
--- a/autobuild.xml
+++ b/autobuild.xml
@@ -76,9 +76,9 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>9b8bcc3be6dbe40a04c9c81c313f70dc</string>
+              <string>b6357ef3a0ec37877a5831820f25094e</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/68333/658209/apr_suite-1.4.5.548882-darwin64-548882.tar.bz2</string>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/80557/759704/apr_suite-1.4.5.558565-darwin64-558565.tar.bz2</string>
             </map>
             <key>name</key>
             <string>darwin64</string>
@@ -112,9 +112,9 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>6bdf460c18ee004b41a46afc80041a92</string>
+              <string>cb48ac069440f6dcd564cfa9fd02a4c2</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/68334/658225/apr_suite-1.4.5.548882-windows-548882.tar.bz2</string>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/80556/759710/apr_suite-1.4.5.558565-windows-558565.tar.bz2</string>
             </map>
             <key>name</key>
             <string>windows</string>
@@ -124,16 +124,16 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>83104bfa4dabb77cd70d185e38a95b49</string>
+              <string>646dc3828d9c39fb1e77c4eec44ed739</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/68332/658215/apr_suite-1.4.5.548882-windows64-548882.tar.bz2</string>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/80555/759709/apr_suite-1.4.5.558565-windows64-558565.tar.bz2</string>
             </map>
             <key>name</key>
             <string>windows64</string>
           </map>
         </map>
         <key>version</key>
-        <string>1.4.5.548882</string>
+        <string>1.4.5.558565</string>
       </map>
       <key>boost</key>
       <map>
@@ -166,9 +166,9 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>3cc73623c9a976b4f8346a3837f7a916</string>
+              <string>35cc090d942b85c9126ceac9912d52d6</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/64088/601256/boost-1.72-darwin64-545361.tar.bz2</string>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/78585/744021/boost-1.72-darwin64-557045.tar.bz2</string>
             </map>
             <key>name</key>
             <string>darwin64</string>
@@ -202,9 +202,9 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>7d4b2511976449e9a4ec7be41dc8310f</string>
+              <string>9aa4ce32df5f5e36124c990e2d77b885</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/64092/601270/boost-1.72-windows-545361.tar.bz2</string>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/78586/743982/boost-1.72-windows-557045.tar.bz2</string>
             </map>
             <key>name</key>
             <string>windows</string>
@@ -214,9 +214,9 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>4ad8df0700745201cddf6b71d7b0949f</string>
+              <string>a79511c9d8b956767ebaa405155d4238</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/64091/601265/boost-1.72-windows64-545361.tar.bz2</string>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/78584/743961/boost-1.72-windows64-557045.tar.bz2</string>
             </map>
             <key>name</key>
             <string>windows64</string>
@@ -308,9 +308,9 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>02e6a8207dcdaf243dcb6da19b8c3534</string>
+              <string>1d063cf1783e7788f17486c234adb1db</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/64099/601302/colladadom-2.3.545362-darwin64-545362.tar.bz2</string>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/78635/744249/colladadom-2.3.557064-darwin64-557064.tar.bz2</string>
             </map>
             <key>name</key>
             <string>darwin64</string>
@@ -344,9 +344,9 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>8a02a10fc69c8f504dc5335644db184a</string>
+              <string>e78ecf919eee01567556787c3a358d15</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/64104/601313/colladadom-2.3.545362-windows-545362.tar.bz2</string>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/78637/744269/colladadom-2.3.557064-windows-557064.tar.bz2</string>
             </map>
             <key>name</key>
             <string>windows</string>
@@ -356,16 +356,16 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>742180324fca7ab92b6a61a36aab4f9d</string>
+              <string>7e63a212c8909a25236138422fe01298</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/64103/601314/colladadom-2.3.545362-windows64-545362.tar.bz2</string>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/78636/744273/colladadom-2.3.557064-windows64-557064.tar.bz2</string>
             </map>
             <key>name</key>
             <string>windows64</string>
           </map>
         </map>
         <key>version</key>
-        <string>2.3.545362</string>
+        <string>2.3.557064</string>
       </map>
       <key>curl</key>
       <map>
@@ -398,9 +398,9 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>f5ae57117a6518d11f49ccfbfbe0969d</string>
+              <string>13f74f43a6363ec998569f731fd869c5</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/64131/601402/curl-7.54.1.545369-darwin64-545369.tar.bz2</string>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/82637/774617/curl-7.54.1.560191-darwin64-560191.tar.bz2</string>
             </map>
             <key>name</key>
             <string>darwin64</string>
@@ -434,11 +434,11 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>2796ae7b09e730a55ac03f74ed669520</string>
+              <string>0df99bd685dc3561ca8ea347b2921987</string>
               <key>hash_algorithm</key>
               <string>md5</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/64130/601396/curl-7.54.1.545369-windows-545369.tar.bz2</string>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/82639/774610/curl-7.54.1.560191-windows-560191.tar.bz2</string>
             </map>
             <key>name</key>
             <string>windows</string>
@@ -448,16 +448,16 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>a8f96e5cdb8128b23d49ff4c3f2233a4</string>
+              <string>50db2a9e6b74ec4b0c38b1ea8f135735</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/64129/601382/curl-7.54.1.545369-windows64-545369.tar.bz2</string>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/82638/774608/curl-7.54.1.560191-windows64-560191.tar.bz2</string>
             </map>
             <key>name</key>
             <string>windows64</string>
           </map>
         </map>
         <key>version</key>
-        <string>7.54.1.545369</string>
+        <string>7.54.1.560191</string>
       </map>
       <key>db</key>
       <map>
@@ -580,9 +580,9 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>49fff41e17e06cdf9eb0c737d20df52f</string>
+              <string>45dedb5b09995cd794304150e94fcf21</string>
               <key>url</key>
-              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/83411/779825/dullahan-1.12.2.202106220202_91.1.21_g9dd45fe_chromium-91.0.4472.114-darwin64-560751.tar.bz2</string>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/87950/806969/dullahan-1.12.2.202109170444_91.1.21_g9dd45fe_chromium-91.0.4472.114-darwin64-563968.tar.bz2</string>
             </map>
             <key>name</key>
             <string>darwin64</string>
@@ -592,9 +592,9 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>f51f324d50a2461cda273e84fa65e0ad</string>
+              <string>d0fd9d7086699da4bb5ccc935622a717</string>
               <key>url</key>
-              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/83413/779836/dullahan-1.12.2.202106220213_91.1.21_g9dd45fe_chromium-91.0.4472.114-windows-560751.tar.bz2</string>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/88276/809277/dullahan-1.12.2.202109230751_91.1.21_g9dd45fe_chromium-91.0.4472.114-windows-563968.tar.bz2</string>
             </map>
             <key>name</key>
             <string>windows</string>
@@ -604,16 +604,16 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>d3df46f6592715c75df2bf520c1ad68b</string>
+              <string>7e8c3ccd420ff5aef24ff72d609ba394</string>
               <key>url</key>
-              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/83412/779840/dullahan-1.12.2.202106220213_91.1.21_g9dd45fe_chromium-91.0.4472.114-windows64-560751.tar.bz2</string>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/88275/809281/dullahan-1.12.2.202109230751_91.1.21_g9dd45fe_chromium-91.0.4472.114-windows64-563968.tar.bz2</string>
             </map>
             <key>name</key>
             <string>windows64</string>
           </map>
         </map>
         <key>version</key>
-        <string>1.12.2.202106220213_91.1.21_g9dd45fe_chromium-91.0.4472.114</string>
+        <string>1.12.2.202109230751_91.1.21_g9dd45fe_chromium-91.0.4472.114</string>
       </map>
       <key>elfio</key>
       <map>
@@ -670,9 +670,9 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>3656b7f7b655cb267fd94f089d2e145c</string>
+              <string>f4e80e0dfcab713a3da90cd8f7f23e7b</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/54860/510198/expat-2.1.1.538990-darwin64-538990.tar.bz2</string>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/76341/727265/expat-2.1.1.555519-darwin64-555519.tar.bz2</string>
             </map>
             <key>name</key>
             <string>darwin64</string>
@@ -706,9 +706,9 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>c509f8afa1e02f4c16232cce7f6855f8</string>
+              <string>cd4fe03473076c324d80ae3bd91a85bb</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/55056/512080/expat-2.1.1.538990-windows-538990.tar.bz2</string>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/76343/727273/expat-2.1.1.555519-windows-555519.tar.bz2</string>
             </map>
             <key>name</key>
             <string>windows</string>
@@ -718,16 +718,16 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>aba97cfdf44c04dbfcac89c7cb472580</string>
+              <string>d2d74d73b914150982b1883a3b96e60b</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/55054/512068/expat-2.1.1.538990-windows64-538990.tar.bz2</string>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/76344/727279/expat-2.1.1.555519-windows64-555519.tar.bz2</string>
             </map>
             <key>name</key>
             <string>windows64</string>
           </map>
         </map>
         <key>version</key>
-        <string>2.1.1.538990</string>
+        <string>2.1.1.555519</string>
       </map>
       <key>fmodstudio</key>
       <map>
@@ -748,9 +748,9 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>89c37441a806ed80c0102d380eec6fd0</string>
+              <string>d5528538e67c710387ae0c061a90cb23</string>
               <key>url</key>
-              <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/65400/612632/fmodstudio-2.00.11.546392-darwin64-546392.tar.bz2</string>
+              <string>https://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/76868/730756/fmodstudio-2.01.07.555883-darwin64-555883.tar.bz2</string>
             </map>
             <key>name</key>
             <string>darwin64</string>
@@ -784,9 +784,9 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>0f44323b0d03b7d0d8a17eec83e103ce</string>
+              <string>a2bb6eaf51f933993b26a5fe7503a761</string>
               <key>url</key>
-              <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/65401/612647/fmodstudio-2.00.11.546392-windows-546392.tar.bz2</string>
+              <string>https://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/76869/730763/fmodstudio-2.01.07.555883-windows-555883.tar.bz2</string>
             </map>
             <key>name</key>
             <string>windows</string>
@@ -796,16 +796,16 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>462d28eacf731a5d36ab031e7071c32a</string>
+              <string>138d07dd516a9ad5b9787192fe6134dd</string>
               <key>url</key>
-              <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/65402/612648/fmodstudio-2.00.11.546392-windows64-546392.tar.bz2</string>
+              <string>https://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/76867/730751/fmodstudio-2.01.07.555883-windows64-555883.tar.bz2</string>
             </map>
             <key>name</key>
             <string>windows64</string>
           </map>
         </map>
         <key>version</key>
-        <string>2.00.11.546392</string>
+        <string>2.01.07.555883</string>
       </map>
       <key>fontconfig</key>
       <map>
@@ -880,9 +880,9 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>81a2e9aca3e33c4eecf0081854540b07</string>
+              <string>3a478d6c8a10d49d9161ef864394b03c</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/56309/526711/freetype-2.4.4.539865-darwin64-539865.tar.bz2</string>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/78592/744013/freetype-2.4.4.557047-darwin64-557047.tar.bz2</string>
             </map>
             <key>name</key>
             <string>darwin64</string>
@@ -916,9 +916,9 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>1d1c7b60f71a5152ced60bee87f5bba8</string>
+              <string>7ee200d6b5fa282c7f973ade5615aa86</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/56312/526734/freetype-2.4.4.539865-windows-539865.tar.bz2</string>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/78594/744011/freetype-2.4.4.557047-windows-557047.tar.bz2</string>
             </map>
             <key>name</key>
             <string>windows</string>
@@ -928,16 +928,16 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>53e78d4a607e959637e98a82a3cf5bea</string>
+              <string>69307aaba16ac71531c9c4d930ace993</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/56310/526723/freetype-2.4.4.539865-windows64-539865.tar.bz2</string>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/78593/744010/freetype-2.4.4.557047-windows64-557047.tar.bz2</string>
             </map>
             <key>name</key>
             <string>windows64</string>
           </map>
         </map>
         <key>version</key>
-        <string>2.4.4.539865</string>
+        <string>2.4.4.557047</string>
       </map>
       <key>glext</key>
       <map>
@@ -1078,9 +1078,9 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>343913fe1434da228c2210c23d2e3a1a</string>
+              <string>a9eaa005ff9d387f946283fbcb69b3c8</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/54850/510134/glod-1.0pre3.538980-darwin64-538980.tar.bz2</string>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/76353/727324/glod-1.0pre3.555522-darwin64-555522.tar.bz2</string>
             </map>
             <key>name</key>
             <string>darwin64</string>
@@ -1139,97 +1139,7 @@
           </map>
         </map>
         <key>version</key>
-        <string>1.0pre3.538980</string>
-      </map>
-      <key>google_breakpad</key>
-      <map>
-        <key>copyright</key>
-        <string>Copyright (c) 2006, Google Inc.</string>
-        <key>description</key>
-        <string>Breakpad is a crossplatform library for capturing crash callstacks and runtime data.</string>
-        <key>license</key>
-        <string>bsd</string>
-        <key>license_file</key>
-        <string>LICENSES/google_breakpad.txt</string>
-        <key>name</key>
-        <string>google_breakpad</string>
-        <key>platforms</key>
-        <map>
-          <key>darwin</key>
-          <map>
-            <key>archive</key>
-            <map>
-              <key>hash</key>
-              <string>171b39db6d0702535b41fad5b476e39d</string>
-              <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/google-breakpad_3p-update-google-breakpad/rev/298033/arch/Darwin/installer/google_breakpad-1413.298033-darwin-298033.tar.bz2</string>
-            </map>
-            <key>name</key>
-            <string>darwin</string>
-          </map>
-          <key>darwin64</key>
-          <map>
-            <key>archive</key>
-            <map>
-              <key>hash</key>
-              <string>ca33f234aae399b9e704e262f7e15d35</string>
-              <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/56338/526869/google_breakpad-1413.539880-darwin64-539880.tar.bz2</string>
-            </map>
-            <key>name</key>
-            <string>darwin64</string>
-          </map>
-          <key>linux</key>
-          <map>
-            <key>archive</key>
-            <map>
-              <key>hash</key>
-              <string>352e673897e8f36f8470150b8ace6ce9</string>
-              <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/p64_3p-google-breakpad/rev/314225/arch/Linux/installer/google_breakpad-1413.314225-linux-314225.tar.bz2</string>
-            </map>
-            <key>name</key>
-            <string>linux</string>
-          </map>
-          <key>linux64</key>
-          <map>
-            <key>archive</key>
-            <map>
-              <key>hash</key>
-              <string>6bddcc1ac470dd5eab459220102df9e9</string>
-              <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/1835/4114/google_breakpad-1413.501824-linux64-501824.tar.bz2</string>
-            </map>
-            <key>name</key>
-            <string>linux64</string>
-          </map>
-          <key>windows</key>
-          <map>
-            <key>archive</key>
-            <map>
-              <key>hash</key>
-              <string>bfee0438617f57f02f7e8515a801cb20</string>
-              <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/56359/526982/google_breakpad-1413.539880-windows-539880.tar.bz2</string>
-            </map>
-            <key>name</key>
-            <string>windows</string>
-          </map>
-          <key>windows64</key>
-          <map>
-            <key>archive</key>
-            <map>
-              <key>hash</key>
-              <string>6f983e754bb3046f065806b510b408c5</string>
-              <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/56358/526975/google_breakpad-1413.539880-windows64-539880.tar.bz2</string>
-            </map>
-            <key>name</key>
-            <string>windows64</string>
-          </map>
-        </map>
-        <key>version</key>
-        <string>1413.539880</string>
+        <string>1.0pre3.555522</string>
       </map>
       <key>googlemock</key>
       <map>
@@ -1262,9 +1172,9 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>f9831360ced94943ab9dfb3fbf5256d3</string>
+              <string>19e925604bc1a91efb4b130e1edd8bf2</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/64101/601290/googlemock-1.7.0.545363-darwin64-545363.tar.bz2</string>
+              <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>
@@ -1298,9 +1208,9 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>8149e46b4f7abb3ac284415cfe1366e1</string>
+              <string>eed7b41d0d1f41b24f315349ef78c728</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/64102/601296/googlemock-1.7.0.545363-windows-545363.tar.bz2</string>
+              <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>
@@ -1310,16 +1220,16 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>f3851eba809ead2810d702041569d36d</string>
+              <string>a6ad6fe722d2fe4e8137495af3f374c9</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/64100/601284/googlemock-1.7.0.545363-windows64-545363.tar.bz2</string>
+              <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.545363</string>
+        <string>1.7.0.557057</string>
       </map>
       <key>gstreamer</key>
       <map>
@@ -1792,9 +1702,9 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>c327e6d6573fc0a808677de47f08acd9</string>
+              <string>2021ea3a19b81c82993e733709683303</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/54844/510092/libhunspell-1.3.2.538974-darwin64-538974.tar.bz2</string>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/76371/727419/libhunspell-1.3.2.555528-darwin64-555528.tar.bz2</string>
             </map>
             <key>name</key>
             <string>darwin64</string>
@@ -1828,9 +1738,9 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>ec22ec25160bcfd2a74f1c7bc8ff6133</string>
+              <string>2253ec09136cc7c208481030d78d9dd7</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/54986/511824/libhunspell-1.3.2.538974-windows-538974.tar.bz2</string>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/76369/727412/libhunspell-1.3.2.555528-windows-555528.tar.bz2</string>
             </map>
             <key>name</key>
             <string>windows</string>
@@ -1840,16 +1750,16 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>f470c6f3f7b0559e95e76467b808de10</string>
+              <string>858d1708f6b3a74738a3d57a5387e20f</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/54985/511817/libhunspell-1.3.2.538974-windows64-538974.tar.bz2</string>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/76370/727413/libhunspell-1.3.2.555528-windows64-555528.tar.bz2</string>
             </map>
             <key>name</key>
             <string>windows64</string>
           </map>
         </map>
         <key>version</key>
-        <string>1.3.2.538974</string>
+        <string>1.3.2.555528</string>
       </map>
       <key>libndofdev</key>
       <map>
@@ -1882,9 +1792,9 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>bf765dfe0b928ef3c531cd9618fee89b</string>
+              <string>a487fff84208a45844602c4a1f68c974</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/54843/510085/libndofdev-0.1.538973-darwin64-538973.tar.bz2</string>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/76356/727333/libndofdev-0.1.555523-darwin64-555523.tar.bz2</string>
             </map>
             <key>name</key>
             <string>darwin64</string>
@@ -1894,9 +1804,9 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>8abb7d216535009f6c0a7e43b0734b1e</string>
+              <string>4c839555bf0ed9ae60ffc3f8a7c96f9b</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/54984/511810/libndofdev-0.1.538973-windows-538973.tar.bz2</string>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/76354/727340/libndofdev-0.1.555523-windows-555523.tar.bz2</string>
             </map>
             <key>name</key>
             <string>windows</string>
@@ -1906,16 +1816,16 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>9da7aed5a914174dcb2be12ecd4a656f</string>
+              <string>cbc033ae3b034b992b59f6de1034247c</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/54983/511803/libndofdev-0.1.538973-windows64-538973.tar.bz2</string>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/76355/727341/libndofdev-0.1.555523-windows64-555523.tar.bz2</string>
             </map>
             <key>name</key>
             <string>windows64</string>
           </map>
         </map>
         <key>version</key>
-        <string>0.1.538973</string>
+        <string>0.1.555523</string>
       </map>
       <key>libpng</key>
       <map>
@@ -1948,9 +1858,9 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>0932b19bb6a8e2641706afd13d92951d</string>
+              <string>2a41acc3116ce19a443873216cb882ad</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/56313/526740/libpng-1.6.8.539868-darwin64-539868.tar.bz2</string>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/78587/743948/libpng-1.6.8.557046-darwin64-557046.tar.bz2</string>
             </map>
             <key>name</key>
             <string>darwin64</string>
@@ -1984,9 +1894,9 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>f498782698428888113b64a7505c8f7f</string>
+              <string>b935b440947f63c69700bdcf5095a8e1</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/56319/526770/libpng-1.6.8.539868-windows-539868.tar.bz2</string>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/78591/743970/libpng-1.6.8.557046-windows-557046.tar.bz2</string>
             </map>
             <key>name</key>
             <string>windows</string>
@@ -1996,16 +1906,16 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>f8ac4f690a2925418866bccf6eba3cf4</string>
+              <string>d1cc8354ac4e877eefedf16b1be3aac6</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/56317/526762/libpng-1.6.8.539868-windows64-539868.tar.bz2</string>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/78589/743991/libpng-1.6.8.557046-windows64-557046.tar.bz2</string>
             </map>
             <key>name</key>
             <string>windows64</string>
           </map>
         </map>
         <key>version</key>
-        <string>1.6.8.539868</string>
+        <string>1.6.8.557046</string>
       </map>
       <key>libuuid</key>
       <map>
@@ -2080,9 +1990,9 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>0706b9c3889d767af9f5105d9ffa9b51</string>
+              <string>6677173bbbb0ea32369b5e9b6c9aa641</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/56327/526819/libxml2-2.9.4.539866-darwin64-539866.tar.bz2</string>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/78631/744225/libxml2-2.9.4.557062-darwin64-557062.tar.bz2</string>
             </map>
             <key>name</key>
             <string>darwin64</string>
@@ -2116,9 +2026,9 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>1b7b979a8387fbb0f278dc681558b9ef</string>
+              <string>ad6a596fbf0e83a21d95762da78437bc</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/56316/526755/libxml2-2.9.4.539866-windows-539866.tar.bz2</string>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/78633/744239/libxml2-2.9.4.557062-windows-557062.tar.bz2</string>
             </map>
             <key>name</key>
             <string>windows</string>
@@ -2128,16 +2038,16 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>4f8ff97d6a9ab350306b62eec8adc810</string>
+              <string>6b5bb230684ecf28386d7c91c47bb6e1</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/56314/526748/libxml2-2.9.4.539866-windows64-539866.tar.bz2</string>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/78634/744240/libxml2-2.9.4.557062-windows64-557062.tar.bz2</string>
             </map>
             <key>name</key>
             <string>windows64</string>
           </map>
         </map>
         <key>version</key>
-        <string>2.9.4.539866</string>
+        <string>2.9.4.557062</string>
       </map>
       <key>llappearance_utility</key>
       <map>
@@ -2414,9 +2324,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>937ce1a2158c0cfff37f5989f5b24aba</string>
+              <string>e4f784d8a035c51921a1562ca7a1bab6</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/64066/601156/nghttp2-1.40.0.545354-darwin64-545354.tar.bz2</string>
+              <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>
@@ -2450,9 +2360,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>138b881bdf37dff4e626e022a50dd11f</string>
+              <string>af05aa2994c9845308fecd094b7b2d25</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/64069/601181/nghttp2-1.40.0.545354-windows-545354.tar.bz2</string>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/76359/727360/nghttp2-1.40.0.555524-windows-555524.tar.bz2</string>
             </map>
             <key>name</key>
             <string>windows</string>
@@ -2462,9 +2372,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>c23c6480c7cbea60a2bd26e257adc0a7</string>
+              <string>5a55cede40eef16b9d1e47c418a2b77a</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/64068/601177/nghttp2-1.40.0.545354-windows64-545354.tar.bz2</string>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/76358/727359/nghttp2-1.40.0.555524-windows64-555524.tar.bz2</string>
             </map>
             <key>name</key>
             <string>windows64</string>
@@ -2473,7 +2383,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
         <key>source_type</key>
         <string>hg</string>
         <key>version</key>
-        <string>1.40.0.545354</string>
+        <string>1.40.0.555524</string>
       </map>
       <key>nvapi</key>
       <map>
@@ -2828,9 +2738,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>18aef0c8fc471b6539addbdc019aea25</string>
+              <string>5503e4928bcdb0a29685b3242c4a409b</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/56325/526804/openssl-1.0.2l.539874-darwin64-539874.tar.bz2</string>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/82619/774464/openssl-1.1.1l.560177-darwin64-560177.tar.bz2</string>
             </map>
             <key>name</key>
             <string>darwin64</string>
@@ -2864,9 +2774,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>2b2f61313b1cbd2893c1ba5bf15061fa</string>
+              <string>d2153f20dc2d35c609b876a9f019a748</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/56328/526826/openssl-1.0.2l.539874-windows-539874.tar.bz2</string>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/82623/774521/openssl-1.1.1l.560177-windows-560177.tar.bz2</string>
             </map>
             <key>name</key>
             <string>windows</string>
@@ -2876,16 +2786,16 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>59aae854155bc7119e0dca25e65828c0</string>
+              <string>f40b8622ba38084b0962e273988d748f</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/56326/526811/openssl-1.0.2l.539874-windows64-539874.tar.bz2</string>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/82624/774520/openssl-1.1.1l.560177-windows64-560177.tar.bz2</string>
             </map>
             <key>name</key>
             <string>windows64</string>
           </map>
         </map>
         <key>version</key>
-        <string>1.0.2l.539874</string>
+        <string>1.1.1l.560177</string>
       </map>
       <key>pcre</key>
       <map>
@@ -3008,9 +2918,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>321a8542e7b693fbe8e44ebface06087</string>
+              <string>6ce3cbaed968a69fb7a2cca80220874d</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/55966/524403/slvoice-4.10.0000.32327.5fc3fe7c.539691-darwin64-539691.tar.bz2</string>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/80380/758537/slvoice-4.10.0000.32327.5fc3fe7c.558436-darwin64-558436.tar.bz2</string>
             </map>
             <key>name</key>
             <string>darwin64</string>
@@ -3044,9 +2954,67 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>fb1a57a1cf5e38a3d51b32307b93ffba</string>
+              <string>2eb38c5eff4d0f18fbb89d0c30c4f0a4</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>
+            </map>
+            <key>name</key>
+            <string>windows</string>
+          </map>
+          <key>windows64</key>
+          <map>
+            <key>archive</key>
+            <map>
+              <key>hash</key>
+              <string>9ee8f3cbc5369c598a998c61961ed16d</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>
+            </map>
+            <key>name</key>
+            <string>windows64</string>
+          </map>
+        </map>
+        <key>version</key>
+        <string>4.10.0000.32327.5fc3fe7c.558436</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>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/55968/524423/slvoice-4.10.0000.32327.5fc3fe7c.539691-windows-539691.tar.bz2</string>
+              <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>
@@ -3056,16 +3024,22 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>81df970eb0c97d415d7bd12049c82042</string>
+              <string>b649ee6591e67d2341e886b3fc3484a7</string>
+              <key>hash_algorithm</key>
+              <string>md5</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/55967/524409/slvoice-4.10.0000.32327.5fc3fe7c.539691-windows64-539691.tar.bz2</string>
+              <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>4.10.0000.32327.5fc3fe7c.539691</string>
+        <string>v0.7.8.563351</string>
       </map>
       <key>tut</key>
       <map>
@@ -3128,9 +3102,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>60f008c5fd31641ad4e61ac751ce15d1</string>
+              <string>c42575ac8997de979eadb082c33a578e</string>
               <key>url</key>
-              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/75748/723495/uriparser-0.9.4-darwin64-555117.tar.bz2</string>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/81322/765512/uriparser-0.9.4-darwin64-559132.tar.bz2</string>
             </map>
             <key>name</key>
             <string>darwin64</string>
@@ -3164,9 +3138,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>00aff37a6f5e1fe08456702d28706cf6</string>
+              <string>901b1063556fc6b2575e745eef2bf744</string>
               <key>url</key>
-              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/75751/723507/uriparser-0.9.4-windows-555117.tar.bz2</string>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/81323/765528/uriparser-0.9.4-windows-559132.tar.bz2</string>
             </map>
             <key>name</key>
             <string>windows</string>
@@ -3176,9 +3150,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>ff27a91f3941c7bef5e1613a064cb048</string>
+              <string>962c01d553f286c430102998129fb0d6</string>
               <key>url</key>
-              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/75750/723506/uriparser-0.9.4-windows64-555117.tar.bz2</string>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/81324/765527/uriparser-0.9.4-windows64-559132.tar.bz2</string>
             </map>
             <key>name</key>
             <string>windows64</string>
@@ -3262,9 +3236,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>5e553a4358203f283c74744aed2fcd8c</string>
+              <string>b639d0035f4a8c9b4973be428a1b7e61</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/54836/510036/vlc_bin-2.2.8.538966-darwin64-538966.tar.bz2</string>
+              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/69569/671323/vlc_bin-3.0.9.549888-darwin64-549888.tar.bz2</string>
             </map>
             <key>name</key>
             <string>darwin64</string>
@@ -3286,9 +3260,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>ca84b7c5f86e702fb35727eed8f0c8c4</string>
+              <string>4f50b0c47daa081dd4fcb83763d5b0b2</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/54958/511725/vlc_bin-2.2.8.538966-windows-538966.tar.bz2</string>
+              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/69567/671314/vlc_bin-3.0.9.549888-windows-549888.tar.bz2</string>
             </map>
             <key>name</key>
             <string>windows</string>
@@ -3298,16 +3272,16 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>93cd88d90cb8aedbed5cd90ff9262409</string>
+              <string>c2f8c01fb6c261b72beb07f0c4cd423f</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/54954/511718/vlc_bin-2.2.8.538966-windows64-538966.tar.bz2</string>
+              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/69568/671315/vlc_bin-3.0.9.549888-windows64-549888.tar.bz2</string>
             </map>
             <key>name</key>
             <string>windows64</string>
           </map>
         </map>
         <key>version</key>
-        <string>2.2.8.538966</string>
+        <string>3.0.9.549888</string>
       </map>
       <key>xmlrpc-epi</key>
       <map>
@@ -3340,9 +3314,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>99ea1808ee9f5b55029daa9fdef86776</string>
+              <string>922a0dea32266897ed1911200438e1e1</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/55063/512104/xmlrpc_epi-0.54.1.539072-darwin64-539072.tar.bz2</string>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/76372/727426/xmlrpc_epi-0.54.1.555529-darwin64-555529.tar.bz2</string>
             </map>
             <key>name</key>
             <string>darwin64</string>
@@ -3376,9 +3350,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>94643b7cebb449f049fa9e32ae682bcd</string>
+              <string>34b847e6b280048465fe7c6ce67fe05c</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/55138/512288/xmlrpc_epi-0.54.1.539072-windows-539072.tar.bz2</string>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/76374/727436/xmlrpc_epi-0.54.1.555529-windows-555529.tar.bz2</string>
             </map>
             <key>name</key>
             <string>windows</string>
@@ -3388,16 +3362,16 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>c409de1974a879291ce7daaf52348d85</string>
+              <string>8fbe7c4ea22bb7f23a93c73884ebb34c</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/55137/512279/xmlrpc_epi-0.54.1.539072-windows64-539072.tar.bz2</string>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/76373/727435/xmlrpc_epi-0.54.1.555529-windows64-555529.tar.bz2</string>
             </map>
             <key>name</key>
             <string>windows64</string>
           </map>
         </map>
         <key>version</key>
-        <string>0.54.1.539072</string>
+        <string>0.54.1.555529</string>
       </map>
       <key>zlib</key>
       <map>
@@ -3430,9 +3404,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>9785bda5b4d3b41bf391b33d0da78c9e</string>
+              <string>9181bc8229f1a8e480d2a40a2744ec28</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/54858/510190/zlib-1.2.8.538988-darwin64-538988.tar.bz2</string>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/78578/743913/zlib-1.2.11.557041-darwin64-557041.tar.bz2</string>
             </map>
             <key>name</key>
             <string>darwin64</string>
@@ -3468,9 +3442,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>ebdb07d4aaa5312005a8773f625032a4</string>
+              <string>8308cbd2ea0fe290541698b0f63482e2</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/55048/512031/zlib-1.2.8.538988-windows-538988.tar.bz2</string>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/78579/743926/zlib-1.2.11.557041-windows-557041.tar.bz2</string>
             </map>
             <key>name</key>
             <string>windows</string>
@@ -3480,16 +3454,16 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>0ac95f3dece7d575ba45cf5728f53eea</string>
+              <string>36bdc34f67d3ad3c57125dc1b16a3129</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/55047/512024/zlib-1.2.8.538988-windows64-538988.tar.bz2</string>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/78577/743920/zlib-1.2.11.557041-windows64-557041.tar.bz2</string>
             </map>
             <key>name</key>
             <string>windows64</string>
           </map>
         </map>
         <key>version</key>
-        <string>1.2.8.538988</string>
+        <string>1.2.11.557041</string>
       </map>
     </map>
     <key>package_description</key>
diff --git a/build.sh b/build.sh
index 96bcff0e8e08b22c1e3e6d0d4b8f77adf302d7bc..3f9fbfd6d7e974ab86f773ec7e4ab46c1b3b153e 100755
--- a/build.sh
+++ b/build.sh
@@ -16,6 +16,29 @@
 # * The special style in which python is invoked is intentional to permit
 #   use of a native python install on windows - which requires paths in DOS form
 
+retry_cmd()
+{
+    max_attempts="$1"; shift
+    initial_wait="$1"; shift
+    attempt_num=1
+    echo "trying" "$@"
+    until "$@"
+    do
+        if ((attempt_num==max_attempts))
+        then
+            echo "Last attempt $attempt_num failed"
+            return 1
+        else
+            wait_time=$(($attempt_num*$initial_wait))
+            echo "Attempt $attempt_num failed. Trying again in $wait_time seconds..."
+            sleep $wait_time
+            attempt_num=$(($attempt_num+1))
+        fi
+    done
+    echo "succeeded"
+    return 0
+}
+
 build_dir_Darwin()
 {
   echo build-darwin-x86_64
@@ -132,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" \
@@ -182,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"
     
@@ -447,7 +478,7 @@ then
       succeeded=$build_coverity
     else
       # Upload base package.
-      python_cmd "$helpers/codeticket.py" addoutput Installer "$package"  \
+      retry_cmd 4 30 python_cmd "$helpers/codeticket.py" addoutput Installer "$package"  \
           || fatal "Upload of installer failed"
       wait_for_codeticket
 
@@ -457,7 +488,7 @@ then
         package=$(installer_$arch "$package_id")
         if [ x"$package" != x ]
         then
-          python_cmd "$helpers/codeticket.py" addoutput "Installer $package_id" "$package" \
+          retry_cmd 4 30 python_cmd "$helpers/codeticket.py" addoutput "Installer $package_id" "$package" \
               || fatal "Upload of installer $package_id failed"
           wait_for_codeticket
         else
@@ -471,7 +502,7 @@ then
           if [ "${RELEASE_CRASH_REPORTING:-}" != "OFF" ]
           then
               # Upload crash reporter file
-              python_cmd "$helpers/codeticket.py" addoutput "Symbolfile" "$VIEWER_SYMBOL_FILE" \
+              retry_cmd 4 30 python_cmd "$helpers/codeticket.py" addoutput "Symbolfile" "$VIEWER_SYMBOL_FILE" \
                   || fatal "Upload of symbolfile failed"
               wait_for_codeticket
           fi
@@ -481,10 +512,7 @@ then
           if [ -r "$build_dir/llphysicsextensions_package" ]
           then
               llphysicsextensions_package=$(cat $build_dir/llphysicsextensions_package)
-              # This next upload is a frequent failure; see if giving the last one some time helps
-              # JJ is making changes to Codeticket that we hope will eliminate this failure soon
-              sleep 300
-              python_cmd "$helpers/codeticket.py" addoutput "Physics Extensions Package" "$llphysicsextensions_package" --private \
+              retry_cmd 4 30 python_cmd "$helpers/codeticket.py" addoutput "Physics Extensions Package" "$llphysicsextensions_package" --private \
                   || fatal "Upload of physics extensions package failed"
           fi
       fi
diff --git a/doc/contributions.txt b/doc/contributions.txt
index 20980fdacd106b58a8c40e5c84563a7fed91e454..537df59c8cdb5b9d44c2b7f0bfaa0e0cab3d9797 100755
--- a/doc/contributions.txt
+++ b/doc/contributions.txt
@@ -270,6 +270,8 @@ Beq Janus
 	SL-13583
 	SL-14766
 	SL-14927
+	SL-15709
+	SL-16021
 Beth Walcher
 Bezilon Kasei
 Biancaluce Robbiani
diff --git a/indra/CMakeLists.txt b/indra/CMakeLists.txt
index db88e441270ed4b57e89dadacfb2dea460c8c1d7..bc2ee2e6cd4263b6f8a6bfb14fd93734659f2cd0 100644
--- a/indra/CMakeLists.txt
+++ b/indra/CMakeLists.txt
@@ -95,17 +95,6 @@ if (USE_BUGSPLAT)
     endif (BUGSPLAT_DB)
 else (USE_BUGSPLAT)
     message(STATUS "Not building with BugSplat")
-    if (LINUX)
-      add_subdirectory(${VIEWER_PREFIX}linux_crash_logger)
-      add_dependencies(viewer linux-crash-logger-strip-target)
-    elseif (DARWIN)
-      add_subdirectory(${VIEWER_PREFIX}mac_crash_logger)
-      add_dependencies(viewer mac-crash-logger)
-    elseif (WINDOWS)
-      add_subdirectory(${VIEWER_PREFIX}win_crash_logger)
-      # add_dependencies(viewer windows-setup windows-crash-logger)
-      add_dependencies(viewer windows-crash-logger)
-    endif (LINUX)
 endif (USE_BUGSPLAT)
 
 add_subdirectory(${VIEWER_PREFIX}newview)
diff --git a/indra/cmake/CEFPlugin.cmake b/indra/cmake/CEFPlugin.cmake
index b8e569d3a844886581c7de916388ca5291d0d3c1..7d8bfb1b0f95b39e2fcae5955b39f85bc274d381 100644
--- a/indra/cmake/CEFPlugin.cmake
+++ b/indra/cmake/CEFPlugin.cmake
@@ -24,7 +24,7 @@ elseif (DARWIN)
         message(FATAL_ERROR "AppKit not found")
     endif()
 
-    FIND_LIBRARY(CEF_LIBRARY "Chromium Embedded Framework" ${ARCH_PREBUILT_DIRS_RELEASE})
+    set(CEF_LIBRARY "'${ARCH_PREBUILT_DIRS_RELEASE}/Chromium\ Embedded\ Framework.framework'")
     if (NOT CEF_LIBRARY)
         message(FATAL_ERROR "CEF not found")
     endif()
@@ -33,7 +33,7 @@ elseif (DARWIN)
         ${ARCH_PREBUILT_DIRS_RELEASE}/libcef_dll_wrapper.a
         ${ARCH_PREBUILT_DIRS_RELEASE}/libdullahan.a
         ${APPKIT_LIBRARY}
-        ${CEF_LIBRARY}
+        "-F ${CEF_LIBRARY}"
        )
 
 elseif (LINUX)
diff --git a/indra/cmake/CMakeLists.txt b/indra/cmake/CMakeLists.txt
index a17e37cd320bb52e8769a663323344e226eae9dc..cca305c741e1f968eb9d064e3148996fede733a3 100644
--- a/indra/cmake/CMakeLists.txt
+++ b/indra/cmake/CMakeLists.txt
@@ -28,7 +28,6 @@ set(cmake_SOURCE_FILES
     FindAutobuild.cmake
     FindBerkeleyDB.cmake
     FindGLH.cmake
-    FindGoogleBreakpad.cmake
     FindHUNSPELL.cmake
     FindJsonCpp.cmake
     FindNDOF.cmake
@@ -43,7 +42,6 @@ set(cmake_SOURCE_FILES
     GLH.cmake
     GLOD.cmake
 ##  GStreamer010Plugin.cmake
-    GoogleBreakpad.cmake
     GoogleMock.cmake
     Havok.cmake
     Hunspell.cmake
diff --git a/indra/cmake/Copy3rdPartyLibs.cmake b/indra/cmake/Copy3rdPartyLibs.cmake
index 46ddb9d15bbe57b944ade97248dfb4c5e1e00ce4..1c56f49486c84d9a52115315fdd720f4b8e6e188 100644
--- a/indra/cmake/Copy3rdPartyLibs.cmake
+++ b/indra/cmake/Copy3rdPartyLibs.cmake
@@ -56,14 +56,21 @@ if(WINDOWS)
         libapr-1.dll
         libaprutil-1.dll
         libapriconv-1.dll
-        ssleay32.dll
-        libeay32.dll
         nghttp2.dll
         glod.dll
         libhunspell.dll
         uriparser.dll
         )
 
+    # OpenSSL
+    if(ADDRESS_SIZE EQUAL 64)
+        set(release_files ${release_files} libcrypto-1_1-x64.dll)
+        set(release_files ${release_files} libssl-1_1-x64.dll)
+    else(ADDRESS_SIZE EQUAL 64)
+        set(release_files ${release_files} libcrypto-1_1.dll)
+        set(release_files ${release_files} libssl-1_1.dll)
+    endif(ADDRESS_SIZE EQUAL 64)
+
     # Filenames are different for 32/64 bit BugSplat file and we don't
     # have any control over them so need to branch.
     if (USE_BUGSPLAT)
@@ -97,6 +104,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)
@@ -158,7 +167,6 @@ elseif(DARWIN)
         libapr-1.dylib
         libaprutil-1.0.dylib
         libaprutil-1.dylib
-        libexception_handler.dylib
         ${EXPAT_COPY}
         libGLOD.dylib
         libhunspell-1.3.0.dylib
diff --git a/indra/cmake/FindGoogleBreakpad.cmake b/indra/cmake/FindGoogleBreakpad.cmake
deleted file mode 100644
index 1a0493be5ed9d782374a391f153d2a21a26a0f66..0000000000000000000000000000000000000000
--- a/indra/cmake/FindGoogleBreakpad.cmake
+++ /dev/null
@@ -1,40 +0,0 @@
-# -*- cmake -*-
-
-# - Find Google BreakPad
-# Find the Google BreakPad includes and library
-# This module defines
-#  BREAKPAD_EXCEPTION_HANDLER_INCLUDE_DIR, where to find exception_handler.h, etc.
-#  BREAKPAD_EXCEPTION_HANDLER_LIBRARIES, the libraries needed to use Google BreakPad.
-#  BREAKPAD_EXCEPTION_HANDLER_FOUND, If false, do not try to use Google BreakPad.
-# also defined, but not for general use are
-#  BREAKPAD_EXCEPTION_HANDLER_LIBRARY, where to find the Google BreakPad library.
-
-FIND_PATH(BREAKPAD_EXCEPTION_HANDLER_INCLUDE_DIR google_breakpad/exception_handler.h)
-
-SET(BREAKPAD_EXCEPTION_HANDLER_NAMES ${BREAKPAD_EXCEPTION_HANDLER_NAMES} breakpad_client)
-FIND_LIBRARY(BREAKPAD_EXCEPTION_HANDLER_LIBRARY
-  NAMES ${BREAKPAD_EXCEPTION_HANDLER_NAMES}
-  )
-
-IF (BREAKPAD_EXCEPTION_HANDLER_LIBRARY AND BREAKPAD_EXCEPTION_HANDLER_INCLUDE_DIR)
-    SET(BREAKPAD_EXCEPTION_HANDLER_LIBRARIES ${BREAKPAD_EXCEPTION_HANDLER_LIBRARY})
-    SET(BREAKPAD_EXCEPTION_HANDLER_FOUND "YES")
-ELSE (BREAKPAD_EXCEPTION_HANDLER_LIBRARY AND BREAKPAD_EXCEPTION_HANDLER_INCLUDE_DIR)
-    SET(BREAKPAD_EXCEPTION_HANDLER_FOUND "NO")
-ENDIF (BREAKPAD_EXCEPTION_HANDLER_LIBRARY AND BREAKPAD_EXCEPTION_HANDLER_INCLUDE_DIR)
-
-
-IF (BREAKPAD_EXCEPTION_HANDLER_FOUND)
-   IF (NOT BREAKPAD_EXCEPTION_HANDLER_FIND_QUIETLY)
-      MESSAGE(STATUS "Found Google BreakPad: ${BREAKPAD_EXCEPTION_HANDLER_LIBRARIES}")
-   ENDIF (NOT BREAKPAD_EXCEPTION_HANDLER_FIND_QUIETLY)
-ELSE (BREAKPAD_EXCEPTION_HANDLER_FOUND)
-   IF (BREAKPAD_EXCEPTION_HANDLER_FIND_REQUIRED)
-      MESSAGE(FATAL_ERROR "Could not find Google BreakPad library")
-   ENDIF (BREAKPAD_EXCEPTION_HANDLER_FIND_REQUIRED)
-ENDIF (BREAKPAD_EXCEPTION_HANDLER_FOUND)
-
-MARK_AS_ADVANCED(
-  BREAKPAD_EXCEPTION_HANDLER_LIBRARY
-  BREAKPAD_EXCEPTION_HANDLER_INCLUDE_DIR
-  )
diff --git a/indra/cmake/GoogleBreakpad.cmake b/indra/cmake/GoogleBreakpad.cmake
deleted file mode 100644
index 829e1ac08a8d8dbd044698a21324b377adbaebec..0000000000000000000000000000000000000000
--- a/indra/cmake/GoogleBreakpad.cmake
+++ /dev/null
@@ -1,22 +0,0 @@
-# -*- cmake -*-
-include(Prebuilt)
-
-if (USESYSTEMLIBS)
-  set(BREAKPAD_EXCEPTION_HANDLER_FIND_REQUIRED ON)
-  include(FindGoogleBreakpad)
-else (USESYSTEMLIBS)
-  use_prebuilt_binary(google_breakpad)
-  if (DARWIN)
-    set(BREAKPAD_EXCEPTION_HANDLER_LIBRARIES exception_handler)
-  endif (DARWIN)
-  if (LINUX)
-    set(BREAKPAD_EXCEPTION_HANDLER_LIBRARIES breakpad_client)
-  endif (LINUX)
-  if (WINDOWS)
-    set(BREAKPAD_EXCEPTION_HANDLER_LIBRARIES exception_handler crash_generation_client crash_generation_server common)
-  endif (WINDOWS)
-  # yes, this does look dumb, no, it's not incorrect
-  #
-  set(BREAKPAD_INCLUDE_DIRECTORIES "${LIBS_PREBUILT_DIR}/include/google_breakpad" "${LIBS_PREBUILT_DIR}/include/google_breakpad/google_breakpad")
-endif (USESYSTEMLIBS)
-
diff --git a/indra/cmake/LLCommon.cmake b/indra/cmake/LLCommon.cmake
index 8900419f9b3465e24935b773fc3cb7a1c2f70178..34499aaa3618945bcba30b302e7ee160c3d7e621 100644
--- a/indra/cmake/LLCommon.cmake
+++ b/indra/cmake/LLCommon.cmake
@@ -3,12 +3,14 @@
 include(APR)
 include(Boost)
 include(EXPAT)
+include(Tracy)
 include(ZLIB)
 
 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/OpenSSL.cmake b/indra/cmake/OpenSSL.cmake
index eb548bdcc1393d90fe9e8cdeac1f6ae32c1d3745..32400f5e4e579bdd680627434ae8231329b895ec 100644
--- a/indra/cmake/OpenSSL.cmake
+++ b/indra/cmake/OpenSSL.cmake
@@ -9,7 +9,7 @@ if (USESYSTEMLIBS)
 else (USESYSTEMLIBS)
   use_prebuilt_binary(openssl)
   if (WINDOWS)
-    set(OPENSSL_LIBRARIES ssleay32 libeay32)
+    set(OPENSSL_LIBRARIES libssl libcrypto)
   else (WINDOWS)
     set(OPENSSL_LIBRARIES ssl crypto)
   endif (WINDOWS)
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/edit-me-to-trigger-new-build.txt b/indra/edit-me-to-trigger-new-build.txt
index 5366987cff8af097af8af87892cfa26ba97f3ddf..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
\ No newline at end of file
+euclid 4/29/2021
+euclid 10/5/2021 DRTVWR-546
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/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/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/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/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt
index dd266630ea725c0753cb7ca19b4843935cc06dfb..ad6d3a5049e2097a94a997f2d4a6b0b9ac8315d9 100644
--- a/indra/llcommon/CMakeLists.txt
+++ b/indra/llcommon/CMakeLists.txt
@@ -9,18 +9,18 @@ include(Linking)
 include(Boost)
 include(LLSharedLibs)
 include(JsonCpp)
-include(GoogleBreakpad)
 include(Copy3rdPartyLibs)
 include(ZLIB)
 include(URIPARSER)
+include(Tracy)
 
 include_directories(
     ${EXPAT_INCLUDE_DIRS}
     ${LLCOMMON_INCLUDE_DIRS}
     ${JSONCPP_INCLUDE_DIR}
     ${ZLIB_INCLUDE_DIRS}
-    ${BREAKPAD_INCLUDE_DIRECTORIES}
     ${URIPARSER_INCLUDE_DIRS}
+    ${TRACY_INCLUDE_DIR}
     )
 
 # add_executable(lltreeiterators lltreeiterators.cpp)
@@ -121,12 +121,14 @@ set(llcommon_SOURCE_FILES
     llworkerthread.cpp
     timing.cpp
     u64.cpp
+    workqueue.cpp
     StackWalker.cpp
     )
     
 set(llcommon_HEADER_FILES
     CMakeLists.txt
 
+    chrono.h
     ctype_workaround.h
     fix_macros.h
     indra_constants.h
@@ -199,6 +201,7 @@ set(llcommon_HEADER_FILES
     llmortician.h
     llnametable.h
     llpointer.h
+    llprofiler.h
     llpounceable.h
     llpredicate.h
     llpreprocessor.h
@@ -253,8 +256,11 @@ set(llcommon_HEADER_FILES
     lockstatic.h
     stdtypes.h
     stringize.h
+    threadsafeschedule.h
     timer.h
+    tuple.h
     u64.h
+    workqueue.h
     StackWalker.h
     )
 
@@ -288,7 +294,6 @@ endif(LLCOMMON_LINK_SHARED)
 
 target_link_libraries(
     llcommon
-    ${BREAKPAD_EXCEPTION_HANDLER_LIBRARIES}
     ${APRUTIL_LIBRARIES}
     ${APR_LIBRARIES}
     ${EXPAT_LIBRARIES}
@@ -302,6 +307,7 @@ target_link_libraries(
     ${BOOST_SYSTEM_LIBRARY}
     ${GOOGLE_PERFTOOLS_LIBRARIES}
     ${URIPARSER_LIBRARIES}
+    ${TRACY_LIBRARY}
     )
 
 if (DARWIN)
@@ -358,6 +364,9 @@ if (LL_TESTS)
   LL_ADD_INTEGRATION_TEST(lluri "" "${test_libs}")
   LL_ADD_INTEGRATION_TEST(llunits "" "${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/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/llapp.cpp b/indra/llcommon/llapp.cpp
index 6064a843ae7985c4d7f77fd17c5d366b0ec941aa..df2a066f62aa16211e75910ab22e3ce3d61020bc 100644
--- a/indra/llcommon/llapp.cpp
+++ b/indra/llcommon/llapp.cpp
@@ -46,7 +46,6 @@
 #include "llstl.h" // for DeletePointer()
 #include "llstring.h"
 #include "lleventtimer.h"
-#include "google_breakpad/exception_handler.h"
 #include "stringize.h"
 #include "llcleanup.h"
 #include "llevents.h"
@@ -62,12 +61,6 @@
 
 LONG WINAPI default_windows_exception_handler(struct _EXCEPTION_POINTERS *exception_infop);
 BOOL ConsoleCtrlHandler(DWORD fdwCtrlType);
-bool windows_post_minidump_callback(const wchar_t* dump_path,
-									const wchar_t* minidump_id,
-									void* context,
-									EXCEPTION_POINTERS* exinfo,
-									MDRawAssertionInfo* assertion,
-									bool succeeded);
 #else
 # include <signal.h>
 # include <unistd.h> // for fork()
@@ -146,8 +139,6 @@ void LLApp::commonCtor()
 
 	// Set the application to this instance.
 	sApplication = this;
-
-	mExceptionHandler = 0;
 	
 	// initialize the buffer to write the minidump filename to
 	// (this is used to avoid allocating memory in the crash handler)
@@ -177,8 +168,6 @@ LLApp::~LLApp()
 		delete mThreadErrorp;
 		mThreadErrorp = NULL;
 	}
-	
-	if(mExceptionHandler != 0) delete mExceptionHandler;
 
 	SUBSYSTEM_CLEANUP_DBG(LLCommon);
 }
@@ -394,139 +383,18 @@ void LLApp::setupErrorHandling(bool second_instance)
 
 #if LL_WINDOWS
 
-#if LL_SEND_CRASH_REPORTS && ! defined(LL_BUGSPLAT)
-	EnableCrashingOnCrashes();
-
-	// This sets a callback to handle w32 signals to the console window.
-	// The viewer shouldn't be affected, sicne its a windowed app.
-	SetConsoleCtrlHandler( (PHANDLER_ROUTINE) ConsoleCtrlHandler, TRUE);
-
-	// Install the Google Breakpad crash handler for Windows
-	if(mExceptionHandler == 0)
-	{
-		if ( second_instance )  //BUG-5707 Firing teleport from a web browser causes second 
-		{
-			mExceptionHandler = new google_breakpad::ExceptionHandler(
-															L"C:\\Temp\\",		
-															0,		//No filter
-															windows_post_minidump_callback,
-															0,
-															google_breakpad::ExceptionHandler::HANDLER_ALL);  //No custom client info.
-		}
-		else
-		{
-			LL_WARNS() << "adding breakpad exception handler" << LL_ENDL;
-
-			std::wstring wpipe_name;
-			wpipe_name =  mCrashReportPipeStr + wstringize(getPid());
-
-			const std::wstring wdump_path(utf8str_to_utf16str(mDumpPath));
-
-			int retries = 30;
-			for (; retries > 0; --retries)
-			{
-				if (mExceptionHandler != 0) delete mExceptionHandler;
-
-				mExceptionHandler = new google_breakpad::ExceptionHandler(
-															wdump_path,		
-															NULL,		//No filter
-															windows_post_minidump_callback,
-															0,
-															google_breakpad::ExceptionHandler::HANDLER_ALL,
-															MiniDumpNormal, //Generate a 'normal' minidump.
-															wpipe_name.c_str(),
-															NULL);  //No custom client info.
-				if (mExceptionHandler->IsOutOfProcess())
-				{
-					LL_INFOS("CRASHREPORT") << "Successfully attached to Out of Process exception handler." << LL_ENDL;
-					break;
-				}
-				else
-				{
-					LL_WARNS("CRASHREPORT") << "Unable to attach to Out of Process exception handler.  " << retries << " retries remaining." << LL_ENDL; 
-					::Sleep(100);  //Wait a tick and try again.
-				}
-			}
-
-			if (retries == 0) LL_WARNS("CRASHREPORT") << "Unable to attach to Out of Process exception handler." << LL_ENDL;
-		}
-
-		if (mExceptionHandler)
-		{
-			mExceptionHandler->set_handle_debug_exceptions(true);
-		}
-	}
-#endif // LL_SEND_CRASH_REPORTS && ! defined(LL_BUGSPLAT)
 #else  // ! LL_WINDOWS
 
-#if defined(LL_BUGSPLAT)
-	// Don't install our own signal handlers -- BugSplat needs to hook them,
-	// or it's completely ineffectual.
-	bool installHandler = false;
-
-#else // ! LL_BUGSPLAT
-	//
-	// Start up signal handling.
-	//
-	// There are two different classes of signals.  Synchronous signals are delivered to a specific
-	// thread, asynchronous signals can be delivered to any thread (in theory)
-	//
-	setup_signals();
-
-	// Add google breakpad exception handler configured for Darwin/Linux.
-	bool installHandler = true;
+#if ! defined(LL_BUGSPLAT)
+    //
+    // Start up signal handling.
+    //
+    // There are two different classes of signals.  Synchronous signals are delivered to a specific
+    // thread, asynchronous signals can be delivered to any thread (in theory)
+    //
+    setup_signals();
 #endif // ! LL_BUGSPLAT
 
-#if LL_DARWIN
-	// For the special case of Darwin, we do not want to install the handler if
-	// the process is being debugged as the app will exit with value ABRT (6) if
-	// we do.  Unfortunately, the code below which performs that test relies on
-	// the structure kinfo_proc which has been tagged by apple as an unstable
-	// API.  We disable this test for shipping versions to avoid conflicts with
-	// future releases of Darwin.  This test is really only needed for developers
-	// starting the app from a debugger anyway.
-	#ifndef LL_RELEASE_FOR_DOWNLOAD
-    int mib[4];
-	mib[0] = CTL_KERN;
-	mib[1] = KERN_PROC;
-	mib[2] = KERN_PROC_PID;
-	mib[3] = getpid();
-	
-	struct kinfo_proc info;
-	memset(&info, 0, sizeof(info));
-	
-	size_t size = sizeof(info);
-	int result = sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, NULL, 0);
-	if((result == 0) || (errno == ENOMEM))
-	{
-		// P_TRACED flag is set, so this process is being debugged; do not install
-		// the handler
-		if(info.kp_proc.p_flag & P_TRACED) installHandler = false;
-	}
-	else
-	{
-		// Failed to discover if the process is being debugged; default to
-		// installing the handler.
-		installHandler = true;
-	}
-	#endif // ! LL_RELEASE_FOR_DOWNLOAD
-
-	if(installHandler && (mExceptionHandler == 0))
-	{
-		mExceptionHandler = new google_breakpad::ExceptionHandler(mDumpPath, 0, &unix_post_minidump_callback, 0, true, 0);
-	}
-#elif LL_LINUX
-	if(installHandler && (mExceptionHandler == 0))
-	{
-		if (mDumpPath.empty())
-		{
-			mDumpPath = "/tmp";
-		}
-		google_breakpad::MinidumpDescriptor desc(mDumpPath);
-	    mExceptionHandler = new google_breakpad::ExceptionHandler(desc, NULL, unix_minidump_callback, NULL, true, -1);
-	}
-#endif // LL_LINUX
-
 #endif // ! LL_WINDOWS
 
 #ifdef LL_BUGSPLAT
@@ -614,31 +482,6 @@ void LLApp::setError()
 	setStatus(APP_STATUS_ERROR);
 }
 
-void LLApp::setMiniDumpDir(const std::string &path)
-{
-	if (path.empty())
-	{
-		mDumpPath = "/tmp";
-	}
-	else
-	{
-		mDumpPath = path;
-	}
-
-	if(mExceptionHandler == 0) return;
-#ifdef LL_WINDOWS
-	std::wstring buffer(utf8str_to_utf16str(mDumpPath));
-	if (buffer.size() > MAX_MINDUMP_PATH_LENGTH) buffer.resize(MAX_MINDUMP_PATH_LENGTH);
-	mExceptionHandler->set_dump_path(buffer);
-#elif LL_LINUX
-        //google_breakpad::MinidumpDescriptor desc("/tmp");	//path works in debug fails in production inside breakpad lib so linux gets a little less stack reporting until it is patched.
-        google_breakpad::MinidumpDescriptor desc(mDumpPath);	//path works in debug fails in production inside breakpad lib so linux gets a little less stack reporting until it is patched.
-	mExceptionHandler->set_minidump_descriptor(desc);
-#else
-	mExceptionHandler->set_dump_path(mDumpPath);
-#endif
-}
-
 void LLApp::setDebugFileNames(const std::string &path)
 {
   	mStaticDebugFileName = path + "static_debug_info.log";
@@ -647,8 +490,6 @@ void LLApp::setDebugFileNames(const std::string &path)
 
 void LLApp::writeMiniDump()
 {
-	if(mExceptionHandler == 0) return;
-	mExceptionHandler->WriteMinidump();
 }
 
 // static
@@ -705,13 +546,6 @@ bool LLApp::isExiting()
 
 void LLApp::disableCrashlogger()
 {
-	// Disable Breakpad exception handler.
-	if (mExceptionHandler != 0)
-	{
-		delete mExceptionHandler;
-		mExceptionHandler = 0;
-	}
-
 	sDisableCrashlogger = TRUE;
 }
 
@@ -1105,64 +939,3 @@ bool unix_post_minidump_callback(const char *dump_dir,
 }
 #endif // !WINDOWS
 
-#ifdef LL_WINDOWS
-bool windows_post_minidump_callback(const wchar_t* dump_path,
-									const wchar_t* minidump_id,
-									void* context,
-									EXCEPTION_POINTERS* exinfo,
-									MDRawAssertionInfo* assertion,
-									bool succeeded)
-{
-	char * path = LLApp::instance()->getMiniDumpFilename();
-	S32 remaining = LLApp::MAX_MINDUMP_PATH_LENGTH;
-	size_t bytesUsed;
-
-	LL_INFOS("MINIDUMPCALLBACK") << "Dump file was generated." << LL_ENDL;
-	bytesUsed = wcstombs(path, dump_path, static_cast<size_t>(remaining));
-	remaining -= bytesUsed;
-	path += bytesUsed;
-	if(remaining > 0 && bytesUsed > 0 && path[-1] != '\\')
-	{
-		*path++ = '\\';
-		--remaining;
-	}
-	if(remaining > 0)
-	{
-		bytesUsed = wcstombs(path, minidump_id, static_cast<size_t>(remaining));
-		remaining -= bytesUsed;
-		path += bytesUsed;
-	}
-	if(remaining > 0)
-	{
-		strncpy(path, ".dmp", remaining);
-	}
-
-	LL_INFOS("CRASHREPORT") << "generated minidump: " << LLApp::instance()->getMiniDumpFilename() << LL_ENDL;
-   // *NOTE:Mani - this code is stolen from LLApp, where its never actually used.
-	//OSMessageBox("Attach Debugger Now", "Error", OSMB_OK);
-   // *TODO: Translate the signals/exceptions into cross-platform stuff
-	// Windows implementation
-	LL_INFOS() << "Entering Windows Exception Handler..." << LL_ENDL;
-
-	if (LLApp::isError())
-	{
-		LL_WARNS() << "Got another fatal signal while in the error handler, die now!" << LL_ENDL;
-	}
-
-	// Flag status to error, so thread_error starts its work
-	LLApp::setError();
-
-	// Block in the exception handler until the app has stopped
-	// This is pretty sketchy, but appears to work just fine
-	while (!LLApp::isStopped())
-	{
-		ms_sleep(10);
-	}
-
-#ifndef LL_RELEASE_FOR_DOWNLOAD
-	return false;
-#else
-	return true;
-#endif
-}
-#endif
diff --git a/indra/llcommon/llapp.h b/indra/llcommon/llapp.h
index 5fa91b8bf57d905859788f98987a8462730802c2..83f3bf3f935708c9d9fb838c343b08e3947107b5 100644
--- a/indra/llcommon/llapp.h
+++ b/indra/llcommon/llapp.h
@@ -49,10 +49,6 @@ void clear_signals();
 
 #endif
 
-namespace google_breakpad {
-	class ExceptionHandler; // See exception_handler.h
-}
-
 class LL_COMMON_API LLApp
 {
 	friend class LLErrorThread;
@@ -236,7 +232,6 @@ class LL_COMMON_API LLApp
 	static const U32 MAX_MINDUMP_PATH_LENGTH = 256;
 
 	// change the directory where Breakpad minidump files are written to
-	void setMiniDumpDir(const std::string &path);
     void setDebugFileNames(const std::string &path);
 
 	// Return the Google Breakpad minidump filename after a crash.
@@ -316,9 +311,6 @@ class LL_COMMON_API LLApp
 private:
 	// the static application instance if it was created.
 	static LLApp* sApplication;
-	
-	google_breakpad::ExceptionHandler * mExceptionHandler;
-
 
 #if !LL_WINDOWS
 	friend void default_unix_signal_handler(int signum, siginfo_t *info, void *);
diff --git a/indra/llcommon/llcommon.cpp b/indra/llcommon/llcommon.cpp
index 96be913d17a07cface3713ddf5ae95ecb8557b73..5d4a623bf6e169f0c60eecc0f16b08b504287708 100644
--- a/indra/llcommon/llcommon.cpp
+++ b/indra/llcommon/llcommon.cpp
@@ -33,6 +33,47 @@
 #include "lltracethreadrecorder.h"
 #include "llcleanup.h"
 
+#if (TRACY_ENABLE)
+// Override new/delete for tracy memory profiling
+void *operator new(size_t size)
+{
+    auto ptr = (malloc) (size);
+    if (!ptr)
+    {
+        throw std::bad_alloc();
+    }
+    TracyAlloc(ptr, size);
+    return ptr;
+}
+
+void operator delete(void *ptr) noexcept
+{
+    TracyFree(ptr);
+    (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..c08acb66a1b98b5c404dc7d5c591784dea5192af 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,14 @@ 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;
+    }
 
     /**
      * Pass update_one() an invocable accepting non-const (DATA&). The
@@ -83,7 +89,7 @@ class LLCond
     void update_one(MODIFY modify)
     {
         { // scope of lock can/should end before notify_one()
-            LLCoros::LockType lk(mMutex);
+            LockType lk(mMutex);
             modify(mData);
         }
         mCond.notify_one();
@@ -102,7 +108,7 @@ class LLCond
     void update_all(MODIFY modify)
     {
         { // scope of lock can/should end before notify_all()
-            LLCoros::LockType lk(mMutex);
+            LockType lk(mMutex);
             modify(mData);
         }
         mCond.notify_all();
@@ -118,7 +124,7 @@ class LLCond
     template <typename 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.
@@ -205,14 +211,14 @@ class LLCond
     template <typename Clock, typename Duration, typename 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)))
         {
-            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
diff --git a/indra/llcommon/llerror.cpp b/indra/llcommon/llerror.cpp
index 8355df90454588f486871460b39a5e4e8c3a5219..f7af1819274e0efed35a34fdf37d5b576a5b63bd 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
 			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
             if (LLError::getAlwaysFlush())
             {
                 mFile << message << std::endl;
@@ -208,6 +210,7 @@ namespace {
 		virtual void recordMessage(LLError::ELevel level,
 					   const std::string& message) override
 		{
+            LL_PROFILE_ZONE_SCOPED
             static std::string s_ansi_error = createANSI("31"); // red
             static std::string s_ansi_warn  = createANSI("34"); // blue
             static std::string s_ansi_debug = createANSI("35"); // magenta
@@ -220,7 +223,8 @@ namespace {
 			}
             else
             {
-                 fprintf(stderr, "%s\n", message.c_str());
+                LL_PROFILE_ZONE_NAMED("fprintf");
+                fprintf(stderr, "%s\n", message.c_str());
             }
 		}
 	
@@ -229,6 +233,7 @@ namespace {
 
         LL_FORCE_INLINE void writeANSI(const std::string& ansi_code, const std::string& message)
 		{
+            LL_PROFILE_ZONE_SCOPED
             static std::string s_ansi_bold  = createANSI("1");  // bold
             static std::string s_ansi_reset = createANSI("0");  // reset
 			// ANSI color code escape sequence, message, and reset in one fprintf call
@@ -265,6 +270,7 @@ namespace {
 		virtual void recordMessage(LLError::ELevel level,
 								   const std::string& message) override
 		{
+            LL_PROFILE_ZONE_SCOPED
 			mBuffer->addLine(message);
 		}
 	
@@ -291,6 +297,7 @@ namespace {
 		virtual void recordMessage(LLError::ELevel level,
 								   const std::string& message) override
 		{
+            LL_PROFILE_ZONE_SCOPED
 			debugger_print(message);
 		}
 	};
@@ -1178,6 +1185,7 @@ namespace
 
 	void writeToRecorders(const LLError::CallSite& site, const std::string& message)
 	{
+        LL_PROFILE_ZONE_SCOPED
 		LLError::ELevel level = site.mLevel;
 		LLError::SettingsConfigPtr s = LLError::Settings::getInstance()->getSettingsConfig();
 
@@ -1311,6 +1319,7 @@ namespace LLError
 
 	bool Log::shouldLog(CallSite& site)
 	{
+        LL_PROFILE_ZONE_SCOPED
 		LLMutexTrylock lock(getMutex<LOG_MUTEX>(), 5);
 		if (!lock.isLocked())
 		{
@@ -1354,6 +1363,7 @@ namespace LLError
 
 	void Log::flush(const std::ostringstream& out, const CallSite& site)
 	{
+        LL_PROFILE_ZONE_SCOPED
 		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/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/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..849867586acc0fad069189429c02c771118bef1b 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() ;
diff --git a/indra/llcommon/llmemory.h b/indra/llcommon/llmemory.h
index 24f86cc11ee3a7b5c9d0b567e2907539b8fee015..2704a495e085308c3816273b995d93d5ba3bafe1 100644
--- a/indra/llcommon/llmemory.h
+++ b/indra/llcommon/llmemory.h
@@ -101,6 +101,19 @@ 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);            \
+    }
+
+
 //------------------------------------------------------------------------------------------------
 //------------------------------------------------------------------------------------------------
 	// for enable buffer overrun detection predefine LL_DEBUG_BUFFER_OVERRUN in current library
diff --git a/indra/llcommon/llmutex.cpp b/indra/llcommon/llmutex.cpp
index 4d73c04d076ed565d55404790069653c3147c520..a49002b5dc95c3a6ee823fa42cb7ab0750756ea4 100644
--- a/indra/llcommon/llmutex.cpp
+++ b/indra/llcommon/llmutex.cpp
@@ -44,6 +44,7 @@ LLMutex::~LLMutex()
 
 void LLMutex::lock()
 {
+    LL_PROFILE_ZONE_SCOPED
 	if(isSelfLocked())
 	{ //redundant lock
 		mCount++;
@@ -65,6 +66,7 @@ void LLMutex::lock()
 
 void LLMutex::unlock()
 {
+    LL_PROFILE_ZONE_SCOPED
 	if (mCount > 0)
 	{ //not the root unlock
 		mCount--;
@@ -85,6 +87,7 @@ void LLMutex::unlock()
 
 bool LLMutex::isLocked()
 {
+    LL_PROFILE_ZONE_SCOPED
 	if (!mMutex.try_lock())
 	{
 		return true;
@@ -108,6 +111,7 @@ LLThread::id_t LLMutex::lockingThread() const
 
 bool LLMutex::trylock()
 {
+    LL_PROFILE_ZONE_SCOPED
 	if(isSelfLocked())
 	{ //redundant lock
 		mCount++;
@@ -146,17 +150,20 @@ LLCondition::~LLCondition()
 
 void LLCondition::wait()
 {
+    LL_PROFILE_ZONE_SCOPED
 	std::unique_lock< std::mutex > lock(mMutex);
 	mCond.wait(lock);
 }
 
 void LLCondition::signal()
 {
+    LL_PROFILE_ZONE_SCOPED
 	mCond.notify_one();
 }
 
 void LLCondition::broadcast()
 {
+    LL_PROFILE_ZONE_SCOPED
 	mCond.notify_all();
 }
 
@@ -166,6 +173,7 @@ LLMutexTrylock::LLMutexTrylock(LLMutex* mutex)
     : mMutex(mutex),
     mLocked(false)
 {
+    LL_PROFILE_ZONE_SCOPED
     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
     if (!mMutex)
         return;
 
@@ -188,6 +197,7 @@ LLMutexTrylock::LLMutexTrylock(LLMutex* mutex, U32 aTries, U32 delay_ms)
 
 LLMutexTrylock::~LLMutexTrylock()
 {
+    LL_PROFILE_ZONE_SCOPED
     if (mMutex && mLocked)
         mMutex->unlock();
 }
@@ -199,6 +209,7 @@ LLMutexTrylock::~LLMutexTrylock()
 //
 LLScopedLock::LLScopedLock(std::mutex* mutex) : mMutex(mutex)
 {
+    LL_PROFILE_ZONE_SCOPED
 	if(mutex)
 	{
 		mutex->lock();
@@ -217,6 +228,7 @@ LLScopedLock::~LLScopedLock()
 
 void LLScopedLock::unlock()
 {
+    LL_PROFILE_ZONE_SCOPED
 	if(mLocked)
 	{
 		mMutex->unlock();
diff --git a/indra/llcommon/llprofiler.h b/indra/llcommon/llprofiler.h
new file mode 100644
index 0000000000000000000000000000000000000000..49510df913ee8b161d957b42a4ed1eec03e0e14c
--- /dev/null
+++ b/indra/llcommon/llprofiler.h
@@ -0,0 +1,103 @@
+/**
+ * @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
+
+#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
+
+#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 )
+        #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
+    #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
+    #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 )
+        #define LL_RECORD_BLOCK_TIME(name)              ZoneScoped                                          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
+    #endif
+#else
+    #define LL_PROFILER_FRAME_END
+    #define LL_PROFILER_SET_THREAD_NAME( name ) (void)(name)
+#endif // LL_PROFILER
+
+#endif // LL_PROFILER_H
diff --git a/indra/llcommon/llsd.cpp b/indra/llcommon/llsd.cpp
index 57b746889d8f19ed1c2386b2f86d427c53aa9ffb..605f6bf0e3712c5d02ef2a25ae87bfad8f129f13 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;
 		if (shared())
 		{
 			ImplMap* i = new ImplMap(mData);
@@ -414,18 +415,21 @@ namespace
 	
 	bool ImplMap::has(const LLSD::String& k) const
 	{
+        LL_PROFILE_ZONE_SCOPED;
 		DataMap::const_iterator i = mData.find(k);
 		return i != mData.end();
 	}
 	
 	LLSD ImplMap::get(const LLSD::String& k) const
 	{
+        LL_PROFILE_ZONE_SCOPED;
 		DataMap::const_iterator i = mData.find(k);
 		return (i != mData.end()) ? i->second : LLSD();
 	}
 
 	LLSD ImplMap::getKeys() const
 	{ 
+        LL_PROFILE_ZONE_SCOPED;
 		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;
 		mData.insert(DataMap::value_type(k, v));
 	}
 	
 	void ImplMap::erase(const LLSD::String& k)
 	{
+        LL_PROFILE_ZONE_SCOPED;
 		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;
 	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;
+    return makeMap(impl).ref(k); 
+}
 const LLSD& LLSD::operator[](const String& k) const
-										{ return safe(impl).ref(k); }
-
+{ 
+    LL_PROFILE_ZONE_SCOPED;
+    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;
+    return makeArray(impl).ref(i); 
+}
 const LLSD& LLSD::operator[](Integer i) const
-										{ return safe(impl).ref(i); }
+{ 
+    LL_PROFILE_ZONE_SCOPED;
+    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..b8ddf2159630f77c910646e26b39449911ad70ff 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;
+            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;
+            return (*this)[String(c)]; 
+        }
 	//@}
 	
 	/** @name Array Values */
diff --git a/indra/llcommon/llsdutil.cpp b/indra/llcommon/llsdutil.cpp
index eb3a96b1333d6d6902ea277b5c46ed60905f5829..c2fe15e9b76dc345ac32e2817e79b366acf03eea 100644
--- a/indra/llcommon/llsdutil.cpp
+++ b/indra/llcommon/llsdutil.cpp
@@ -214,6 +214,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 +337,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 +533,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 +543,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 +595,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 +634,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 +768,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.
@@ -864,6 +878,8 @@ namespace llsd
 
 LLSD& drill(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 +905,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,6 +935,8 @@ LLSD& drill(LLSD& blob, const LLSD& rawPath)
 
 LLSD drill(const LLSD& blob, const LLSD& path)
 {
+    LL_PROFILE_ZONE_SCOPED
+
     // non-const drill() does exactly what we want. Temporarily cast away
     // const-ness and use that.
     return drill(const_cast<LLSD&>(blob), path);
@@ -929,6 +949,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/llsys.cpp b/indra/llcommon/llsys.cpp
index 4e61fb8a5805bce07f583e958675da0b33756a64..6d5d043e8d91bbe76f0d942b9b7c9cd77c0edb09 100644
--- a/indra/llcommon/llsys.cpp
+++ b/indra/llcommon/llsys.cpp
@@ -861,6 +861,7 @@ LLSD LLMemoryInfo::getStatsMap() const
 
 LLMemoryInfo& LLMemoryInfo::refresh()
 {
+	LL_PROFILE_ZONE_SCOPED
 	mStatsMap = loadStatsMap();
 
 	LL_DEBUGS("LLMemoryInfo") << "Populated mStatsMap:\n";
diff --git a/indra/llcommon/llthread.cpp b/indra/llcommon/llthread.cpp
index 6d531d842d83c0e091d652112a53ca9a46a5ef21..11f5a015f196f57ce93856f2d2b34df8ed15165c 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
     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
     return std::this_thread::get_id();
 }
 
 // static
 void LLThread::yield()
 {
+    LL_PROFILE_ZONE_SCOPED
     std::this_thread::yield();
 }
 
 void LLThread::wake()
 {
+    LL_PROFILE_ZONE_SCOPED
     mDataLock->lock();
     if(!shouldSleep())
     {
@@ -383,6 +389,7 @@ void LLThread::wake()
 
 void LLThread::wakeLocked()
 {
+    LL_PROFILE_ZONE_SCOPED
     if(!shouldSleep())
     {
         mRunCondition->signal();
@@ -391,11 +398,13 @@ void LLThread::wakeLocked()
 
 void LLThread::lockData()
 {
+    LL_PROFILE_ZONE_SCOPED
     mDataLock->lock();
 }
 
 void LLThread::unlockData()
 {
+    LL_PROFILE_ZONE_SCOPED
     mDataLock->unlock();
 }
 
diff --git a/indra/llcommon/llthreadsafequeue.h b/indra/llcommon/llthreadsafequeue.h
index 26e0d71d314341c4abf3b47231a12dfa3854dd96..06e8d8f6094d28417cc1710b121b7250f8bee24d 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,111 @@ 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
+	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); }
+
+	// 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); }
 
-	// Pop the element at the end of the queue (will block if the queue is
+	// 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 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 +181,152 @@ 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)
+{
+    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)
+{
+    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)
+{
+    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>
+void LLThreadSafeQueue<ElementT, QueueT>::push(T&& element)
 {
     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());
         }
 
-        if (mStorage.size() < mCapacity)
-        {
-            mStorage.push_front(element);
-            lock1.unlock();
-            mEmptyCond.notify_one();
+        if (push_(lock1, std::forward<T>(element)))
             return;
-        }
 
         // Storage Full. Wait for signal.
         mCapacityCond.wait(lock1);
@@ -175,142 +334,225 @@ 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>
+bool LLThreadSafeQueue<ElementT, QueueT>::tryPush(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;
+    return tryLock(
+        [this, element=std::move(element)](lock_t& lock)
+        {
+            if (mClosed)
+                return false;
+            return push_(lock, std::move(element));
+        });
+}
 
-    lock_t lock1(mLock, std::defer_lock);
-    if (!lock1.try_lock_until(endpoint))
-        return false;
 
-    while (true)
-    {
-        if (mClosed)
-        {
-            return false;
-        }
+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)
+{
+    // 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));
+}
 
-        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))
+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)
+{
+    return tryLockUntil(
+        until,
+        [this, until, element=std::move(element)](lock_t& lock)
         {
-            // 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.
-    }
+            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.
+            }
+        });
 }
 
 
-template<typename ElementT>
-bool LLThreadSafeQueue<ElementT>::tryPushFront(ElementT const & element)
+// 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)
 {
-    lock_t lock1(mLock, std::defer_lock);
-    if (!lock1.try_lock())
-        return false;
-
-    if (mClosed)
-        return false;
+    // If mStorage is empty, there's no head element.
+    if (mStorage.empty())
+        return mClosed? DONE : EMPTY;
 
-    if (mStorage.size() >= mCapacity)
-        return false;
+    // If there's a head element, pass it to canPop() to see if it's ready to pop. 
+    if (! canPop(mStorage.front()))
+        return WAITING;
 
-    mStorage.push_front(element);
-    lock1.unlock();
-    mEmptyCond.notify_one();
-    return true;
+    // 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)
 {
     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;
+    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)
+{
+    // 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, typename QueueT>
+template <typename Clock, typename Duration>
+bool LLThreadSafeQueue<ElementT, QueueT>::tryPopUntil(
+    const std::chrono::time_point<Clock, Duration>& until,
+    ElementT& element)
+{
+    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)
+{
+    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>
-size_t LLThreadSafeQueue<ElementT>::size(void)
+template<typename ElementT, typename QueueT>
+size_t LLThreadSafeQueue<ElementT, QueueT>::size(void)
 {
     lock_t lock(mLock);
     return mStorage.size();
 }
 
-template<typename ElementT>
-void LLThreadSafeQueue<ElementT>::close()
+
+template<typename ElementT, typename QueueT>
+void LLThreadSafeQueue<ElementT, QueueT>::close()
 {
     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()
 {
     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();
+    lock_t lock(mLock);
+    return mClosed && mStorage.empty();
 }
 
 #endif
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/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/threadsafeschedule_test.cpp b/indra/llcommon/tests/threadsafeschedule_test.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..af67b9f49247fdea378d7ef1c7ed4a713814dced
--- /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() + 20ms, "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() + 10ms, "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..d5405400fd6f693e3869c1c42cb369b2724cb3be
--- /dev/null
+++ b/indra/llcommon/tests/workqueue_test.cpp
@@ -0,0 +1,159 @@
+/**
+ * @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 "llcond.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 think we should have exhausted
+        // the iterations
+        queue.runFor(10*interval);
+        // 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.
+            [&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");
+    }
+} // namespace tut
diff --git a/indra/llcommon/threadsafeschedule.h b/indra/llcommon/threadsafeschedule.h
new file mode 100644
index 0000000000000000000000000000000000000000..c8ad23532b130f5e693faffd7b9bf8b4b78d655d
--- /dev/null
+++ b/indra/llcommon/threadsafeschedule.h
@@ -0,0 +1,373 @@
+/**
+ * @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)
+        {
+            push(tuple_cons(Clock::now(), tuple));
+        }
+
+        /// individually pass each component of the TimeTuple
+        void push(const TimePoint& time, Args&&... args)
+        {
+            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)
+        {
+            push(Clock::now(), std::forward<Args>(args)...);
+        }
+
+        /*--------------------------- tryPush() ----------------------------*/
+        /// explicit TimeTuple
+        using super::tryPush;
+
+        /// DataTuple with implicit now
+        bool tryPush(const DataTuple& tuple)
+        {
+            return tryPush(tuple_cons(Clock::now(), tuple));
+        }
+
+        /// individually pass components
+        bool tryPush(const TimePoint& time, Args&&... args)
+        {
+            return tryPush(TimeTuple(time, std::forward<Args>(args)...));
+        }
+
+        /// individually pass components with implicit now
+        bool tryPush(Args&&... args)
+        {
+            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)
+        {
+            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)
+        {
+            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)
+        {
+            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)
+        {
+            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)
+        {
+            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)
+        {
+            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()
+        {
+            return tuple_cdr(popWithTime());
+        }
+
+        /// pop TimeTuple by value
+        TimeTuple popWithTime()
+        {
+            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)
+        {
+            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)
+        {
+            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)
+        {
+            // 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)
+        {
+            // 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)
+        {
+            TimePoint adjusted = until;
+            if (! super::mStorage.empty())
+            {
+                // 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;
+            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)
+        {
+            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)
+        {
+            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
+        {
+            // 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..ffc9a97dc090a26b6845fc1ced85347aa1c2f4c0
--- /dev/null
+++ b/indra/llcommon/workqueue.cpp
@@ -0,0 +1,128 @@
+/**
+ * @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):
+    super(makeName(name))
+{
+    // TODO: register for "LLApp" events so we can implicitly close() on
+    // viewer shutdown.
+}
+
+void LL::WorkQueue::close()
+{
+    mQueue.close();
+}
+
+void LL::WorkQueue::runUntilClose()
+{
+    try
+    {
+        for (;;)
+        {
+            callWork(mQueue.pop());
+        }
+    }
+    catch (const Queue::Closed&)
+    {
+    }
+}
+
+bool LL::WorkQueue::runPending()
+{
+    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)
+{
+    // Should we subtract some slop to allow for typical Work execution time?
+    // How much slop?
+    Work work;
+    while (TimePoint::clock::now() < until && mQueue.tryPopUntil(until, 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)
+{
+    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;
+}
diff --git a/indra/llcommon/workqueue.h b/indra/llcommon/workqueue.h
new file mode 100644
index 0000000000000000000000000000000000000000..b88aef989aedb20f8ec688bad59a81998a8f18d2
--- /dev/null
+++ b/indra/llcommon/workqueue.h
@@ -0,0 +1,329 @@
+/**
+ * @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 "llinstancetracker.h"
+#include "threadsafeschedule.h"
+#include <chrono>
+#include <functional>               // std::function
+#include <queue>
+#include <string>
+#include <utility>                  // std::pair
+#include <vector>
+
+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;
+
+        /**
+         * 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());
+
+        /**
+         * 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();
+
+        /*---------------------- 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 method.
+            // 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));
+        }
+
+        /**
+         * 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);
+
+        /*------------------------- 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(WorkQueue::weak_t target,
+                    const TimePoint& time, CALLABLE&& callable, FOLLOWUP&& callback)
+        {
+            // 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)]
+                ()
+                {
+                    // Call the callable in any case -- but to minimize
+                    // copying the result, immediately bind it into a 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().
+                    auto rlambda =
+                        [result = callable(),
+                         callback = std::move(callback)]
+                        ()
+                        { callback(std::move(result)); };
+                    // Check if this originating WorkQueue still exists.
+                    // 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.
+                    // reply is a weak_ptr: have to lock it to check it.
+                    auto rptr = reply.lock();
+                    if (rptr)
+                    {
+                        // Only post reply lambda if the originating WorkQueue
+                        // still exists. If not -- who would we tell? Log it?
+                        try
+                        {
+                            rptr->post(std::move(rlambda));
+                        }
+                        catch (const Closed&)
+                        {
+                            // Originating WorkQueue might still exist, but
+                            // might be Closed. Same thing: just discard the
+                            // callback.
+                        }
+                    }
+                });
+            // looks like we were able to post()
+            return true;
+        }
+
+        /**
+         * 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(WorkQueue::weak_t target,
+                    CALLABLE&& callable, FOLLOWUP&& callback)
+        {
+            return postTo(target, TimePoint::clock::now(), std::move(callable), std::move(callback));
+        }
+
+        /*--------------------------- 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)
+        {
+            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:
+        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(WorkQueue::weak_t target,
+                 const WorkQueue::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:
+        WorkQueue::weak_t mTarget;
+        WorkQueue::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)));
+    }
+
+} // namespace LL
+
+#endif /* ! defined(LL_WORKQUEUE_H) */
diff --git a/indra/llcorehttp/CMakeLists.txt b/indra/llcorehttp/CMakeLists.txt
index 8bb6a657b10fcc8af9ea17392e624a4ee0c4297d..6a301ad50d237060c409f394321378fc3cc0e34b 100644
--- a/indra/llcorehttp/CMakeLists.txt
+++ b/indra/llcorehttp/CMakeLists.txt
@@ -177,7 +177,6 @@ if (DARWIN)
   set(copy_dylibs
     libapr-1.0.dylib
     libaprutil-1.0.dylib
-    libexception_handler.dylib
     libnghttp2*.dylib
     liburiparser*.dylib
     ${EXPAT_COPY}
diff --git a/indra/llcorehttp/httpcommon.cpp b/indra/llcorehttp/httpcommon.cpp
index e37a38b05f81a1ca1c808d2792f418aa748a261e..61ba83594e0c24ee8b8f3b95697f7ed52b62fb0f 100644
--- a/indra/llcorehttp/httpcommon.cpp
+++ b/indra/llcorehttp/httpcommon.cpp
@@ -23,13 +23,6 @@
  * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
  * $/LicenseInfo$
  */
-#if LL_WINDOWS
-#define SAFE_SSL 1
-#elif LL_DARWIN
-#define SAFE_SSL 1
-#else
-#define SAFE_SSL 1
-#endif
 
 #include "linden_common.h"		// Modifies curl/curl.h interfaces
 #include "httpcommon.h"
@@ -38,10 +31,6 @@
 #include <curl/curl.h>
 #include <string>
 #include <sstream>
-#if SAFE_SSL
-#include <openssl/crypto.h>
-#include <functional>               // std::hash
-#endif
 
 
 namespace LLCore
@@ -281,9 +270,6 @@ namespace LLHttp
 {
 namespace
 {
-typedef boost::shared_ptr<LLMutex> LLMutex_ptr;
-std::vector<LLMutex_ptr> sSSLMutex;
-
 CURL *getCurlTemplateHandle()
 {
     static CURL *curlpTemplateHandle = NULL;
@@ -348,34 +334,6 @@ void deallocateEasyCurl(CURL *curlp)
 }
 
 
-#if SAFE_SSL
-//static
-void ssl_locking_callback(int mode, int type, const char *file, int line)
-{
-    if (type >= sSSLMutex.size())
-    {
-        LL_WARNS() << "Attempt to get unknown MUTEX in SSL Lock." << LL_ENDL;
-    }
-
-    if (mode & CRYPTO_LOCK)
-    {
-        sSSLMutex[type]->lock();
-    }
-    else
-    {
-        sSSLMutex[type]->unlock();
-    }
-}
-
-//static
-unsigned long ssl_thread_id(void)
-{
-    // std::thread::id is very deliberately opaque, but we can hash it
-    return std::hash<LLThread::id_t>()(LLThread::currentID());
-}
-#endif
-
-
 }
 
 void initialize()
@@ -387,27 +345,11 @@ void initialize()
 
     check_curl_code(code, CURL_GLOBAL_ALL);
 
-#if SAFE_SSL
-    S32 mutex_count = CRYPTO_num_locks();
-    for (S32 i = 0; i < mutex_count; i++)
-    {
-        sSSLMutex.push_back(LLMutex_ptr(new LLMutex()));
-    }
-    CRYPTO_set_id_callback(&ssl_thread_id);
-    CRYPTO_set_locking_callback(&ssl_locking_callback);
-#endif
-
 }
 
 
 void cleanup()
 {
-#if SAFE_SSL
-    CRYPTO_set_id_callback(NULL);
-    CRYPTO_set_locking_callback(NULL);
-    sSSLMutex.clear();
-#endif
-
     curl_global_cleanup();
 }
 
diff --git a/indra/llimage/llimageworker.cpp b/indra/llimage/llimageworker.cpp
index 5f42fba86602ecf4df3b609ebae06b4ff947495a..33f8dce6ee67148ae805f3a270065bd9e54febd7 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;
 	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;
 	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;
 	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;
 	if (mResponder.notNull())
 	{
 		bool success = completed && mDecodedRaw && (!mNeedsAux || mDecodedAux);
diff --git a/indra/llinventory/llsettingsbase.cpp b/indra/llinventory/llsettingsbase.cpp
index 61b59e35aacd523ea90f693108896098f5b4f557..89a4eebf2683edf421a45b39bf0f1b3394fe75ff 100644
--- a/indra/llinventory/llsettingsbase.cpp
+++ b/indra/llinventory/llsettingsbase.cpp
@@ -683,6 +683,7 @@ bool LLSettingsBase::Validator::verifyStringLength(LLSD &value, S32 length)
 //=========================================================================
 void LLSettingsBlender::update(const LLSettingsBase::BlendFactor& blendf)
 {
+    LL_PROFILE_ZONE_SCOPED;
     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;
     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;
     return LLSettingsBase::BlendFactor(fmod((F64)spanpos, (F64)spanlen) / (F64)spanlen);
 }
 
 bool LLSettingsBlenderTimeDelta::applyTimeDelta(const LLSettingsBase::Seconds& timedelta)
 {
+    LL_PROFILE_ZONE_SCOPED;
     mTimeSpent += timedelta;
 
     if (mTimeSpent > mBlendSpan)
diff --git a/indra/llinventory/llsettingssky.cpp b/indra/llinventory/llsettingssky.cpp
index 81937dbda529ccbb6475e1d045e27d05274a6e81..00c1edb55a2a8b539b439154ad551b326e8ae566 100644
--- a/indra/llinventory/llsettingssky.cpp
+++ b/indra/llinventory/llsettingssky.cpp
@@ -444,6 +444,7 @@ void LLSettingsSky::replaceWithSky(LLSettingsSky::ptr_t pother)
 
 void LLSettingsSky::blend(const LLSettingsBase::ptr_t &end, F64 blendf) 
 {
+    LL_PROFILE_ZONE_SCOPED;
     llassert(getSettingsType() == end->getSettingsType());
 
     LLSettingsSky::ptr_t other = PTR_NAMESPACE::dynamic_pointer_cast<LLSettingsSky>(end);
@@ -1022,6 +1023,7 @@ LLColor3 LLSettingsSky::getLightDiffuse() const
 
 LLColor3 LLSettingsSky::getColor(const std::string& key, const LLColor3& default_value) const
 {
+    LL_PROFILE_ZONE_SCOPED;
     if (mSettings.has(SETTING_LEGACY_HAZE) && mSettings[SETTING_LEGACY_HAZE].has(key))
     {
         return LLColor3(mSettings[SETTING_LEGACY_HAZE][key]);
@@ -1035,6 +1037,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;
     if (mSettings.has(SETTING_LEGACY_HAZE) && mSettings[SETTING_LEGACY_HAZE].has(key))
     {
         return mSettings[SETTING_LEGACY_HAZE][key].asReal();
diff --git a/indra/llmath/llmatrix4a.h b/indra/llmath/llmatrix4a.h
index 7ba347062f724c99b8df1589cb5bee169daa8fa1..5291a05607b5ca6c230c2012263cd893fbc58beb 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,6 +64,14 @@ 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]);
@@ -105,7 +133,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 +179,8 @@ class LLMatrix4a
     {
         affineTransformSSE(v,res);
     }
+
+    const LLVector4a& getTranslation() const { return mMatrix[3]; }
 };
 
 inline LLVector4a rowMul(const LLVector4a &row, const LLMatrix4a &mat)
@@ -176,6 +206,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/llvector4a.h b/indra/llmath/llvector4a.h
index 27abf395376b13c0f7cb84a85a27a493382c56af..5a029283740c3172118950439b7763005c0e87f7 100644
--- a/indra/llmath/llvector4a.h
+++ b/indra/llmath/llvector4a.h
@@ -46,10 +46,9 @@ 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 LLVector4a
 {
 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
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 e085fa6ada79d8846b615314397d3091cf4dbe04..130f30bedc07408922c368784fe4f694a79948f5 100644
--- a/indra/llmath/llvolume.cpp
+++ b/indra/llmath/llvolume.cpp
@@ -383,6 +383,7 @@ class LLVolumeOctreeRebound : public LLOctreeTravelerDepthFirst<LLVolumeTriangle
 	virtual void visit(const LLOctreeNode<LLVolumeTriangle>* branch)
 	{ //this is a depth first traversal, so it's safe to assum all children have complete
 		//bounding data
+	LL_PROFILE_ZONE_SCOPED
 
 		LLVolumeOctreeListener* node = (LLVolumeOctreeListener*) branch->getListener(0);
 
@@ -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
+
 	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
+
 	// 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
+
 	if ((!mDirty) && (!is_sculpted))
 	{
 		return FALSE;
@@ -2112,6 +2119,8 @@ LLVolume::~LLVolume()
 
 BOOL LLVolume::generate()
 {
+	LL_PROFILE_ZONE_SCOPED
+
 	LL_CHECK_MEMORY
 	llassert_always(mProfilep);
 	
@@ -2370,6 +2379,8 @@ bool LLVolumeFace::VertexData::compareNormal(const LLVolumeFace::VertexData& rhs
 
 bool LLVolume::unpackVolumeFaces(std::istream& is, S32 size)
 {
+	LL_PROFILE_ZONE_SCOPED
+
 	//input stream is now pointing at a zlib compressed block of LLSD
 	//decompress block
 	LLSD mdl;
@@ -2755,6 +2766,8 @@ S32	LLVolume::getNumFaces() const
 
 void LLVolume::createVolumeFaces()
 {
+	LL_PROFILE_ZONE_SCOPED
+
 	if (mGenerateSingleFace)
 	{
 		// do nothing
@@ -3720,6 +3733,8 @@ void LLVolume::generateSilhouetteVertices(std::vector<LLVector3> &vertices,
 										  const LLMatrix3& norm_mat_in,
 										  S32 face_mask)
 {
+	LL_PROFILE_ZONE_SCOPED
+
 	LLMatrix4a mat;
 	mat.loadu(mat_in);
 
@@ -4846,6 +4861,8 @@ void LLVolumeFace::freeData()
 
 BOOL LLVolumeFace::create(LLVolume* volume, BOOL partial_build)
 {
+	LL_PROFILE_ZONE_SCOPED
+
 	//tree for this face is no longer valid
 	delete mOctree;
 	mOctree = NULL;
@@ -5514,6 +5531,8 @@ bool LLVolumeFace::cacheOptimize()
 
 void LLVolumeFace::createOctree(F32 scaler, const LLVector4a& center, const LLVector4a& size)
 {
+	LL_PROFILE_ZONE_SCOPED
+
 	if (mOctree)
 	{
 		return;
@@ -6287,6 +6306,8 @@ void CalculateTangentArray(U32 vertexCount, const LLVector4a *vertex, const LLVe
 
 void LLVolumeFace::createTangents()
 {
+	LL_PROFILE_ZONE_SCOPED
+
 	if (!mTangents)
 	{
 		allocateTangents(mNumVertices);
@@ -6482,6 +6503,8 @@ void LLVolumeFace::fillFromLegacyData(std::vector<LLVolumeFace::VertexData>& v,
 
 BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build)
 {
+	LL_PROFILE_ZONE_SCOPED
+
 	LL_CHECK_MEMORY
 	BOOL flat = mTypeMask & FLAT_MASK;
 
@@ -6974,6 +6997,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
+
     //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/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/llmessage/llblowfishcipher.cpp b/indra/llmessage/llblowfishcipher.cpp
index 0b5025a422530ca9d73798d16cd2fa09b4c75030..949d4cc0c7f50839f2d3def1423793342d65cabb 100644
--- a/indra/llmessage/llblowfishcipher.cpp
+++ b/indra/llmessage/llblowfishcipher.cpp
@@ -52,24 +52,28 @@ U32 LLBlowfishCipher::encrypt(const U8* src, U32 src_len, U8* dst, U32 dst_len)
 	if (src_len > dst_len) return 0;
 
 	// OpenSSL uses "cipher contexts" to hold encryption parameters.
-    EVP_CIPHER_CTX context;
-    EVP_CIPHER_CTX_init(&context);
+    EVP_CIPHER_CTX *context = EVP_CIPHER_CTX_new();
+    if (!context)
+    {
+        LL_WARNS() << "LLBlowfishCipher::encrypt EVP_CIPHER_CTX initiation failure" << LL_ENDL;
+        return 0;
+    }
 
 	// We want a blowfish cyclic block chain cipher, but need to set 
 	// the key length before we pass in a key, so call EncryptInit 
 	// first with NULLs.
-	EVP_EncryptInit_ex(&context, EVP_bf_cbc(), NULL, NULL, NULL);
-	EVP_CIPHER_CTX_set_key_length(&context, (int)mSecretSize);
+	EVP_EncryptInit_ex(context, EVP_bf_cbc(), NULL, NULL, NULL);
+	EVP_CIPHER_CTX_set_key_length(context, (int)mSecretSize);
 	
 	// Complete initialization.  Per EVP_EncryptInit man page, the
 	// cipher pointer must be NULL.  Apparently initial_vector must
 	// be 8 bytes for blowfish, as this is the block size.
     unsigned char initial_vector[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
-	EVP_EncryptInit_ex(&context, NULL, NULL, mSecret, initial_vector);
+	EVP_EncryptInit_ex(context, NULL, NULL, mSecret, initial_vector);
 
-    int blocksize = EVP_CIPHER_CTX_block_size(&context);
-    int keylen = EVP_CIPHER_CTX_key_length(&context);
-    int iv_length = EVP_CIPHER_CTX_iv_length(&context);
+    int blocksize = EVP_CIPHER_CTX_block_size(context);
+    int keylen = EVP_CIPHER_CTX_key_length(context);
+    int iv_length = EVP_CIPHER_CTX_iv_length(context);
     LL_DEBUGS() << "LLBlowfishCipher blocksize " << blocksize
 		<< " keylen " << keylen
 		<< " iv_len " << iv_length
@@ -77,7 +81,7 @@ U32 LLBlowfishCipher::encrypt(const U8* src, U32 src_len, U8* dst, U32 dst_len)
 
 	int output_len = 0;
 	int temp_len = 0;
-	if (!EVP_EncryptUpdate(&context,
+	if (!EVP_EncryptUpdate(context,
 			dst,
 			&output_len,
 			src,
@@ -89,18 +93,18 @@ U32 LLBlowfishCipher::encrypt(const U8* src, U32 src_len, U8* dst, U32 dst_len)
 
 	// There may be some final data left to encrypt if the input is
 	// not an exact multiple of the block size.
-	if (!EVP_EncryptFinal_ex(&context, (unsigned char*)(dst + output_len), &temp_len))
+	if (!EVP_EncryptFinal_ex(context, (unsigned char*)(dst + output_len), &temp_len))
 	{
 		LL_WARNS() << "LLBlowfishCipher::encrypt EVP_EncryptFinal failure" << LL_ENDL;
 		goto ERROR;
 	}
 	output_len += temp_len;
 
-	EVP_CIPHER_CTX_cleanup(&context);
+	EVP_CIPHER_CTX_free(context);
 	return output_len;
 
 ERROR:
-	EVP_CIPHER_CTX_cleanup(&context);
+	EVP_CIPHER_CTX_free(context);
 	return 0;
 }
 
diff --git a/indra/llprimitive/lldaeloader.cpp b/indra/llprimitive/lldaeloader.cpp
index dfa29fb539e2664d671d1355c7f8022b5ef1a9ac..8343de0cbc3f63f43fbbb9bf3642b524a6907d26 100644
--- a/indra/llprimitive/lldaeloader.cpp
+++ b/indra/llprimitive/lldaeloader.cpp
@@ -1173,17 +1173,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);
 		}
 
 
@@ -1401,7 +1403,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));
 						}
 					}
 				}
@@ -1475,9 +1477,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
 			{
diff --git a/indra/llprimitive/llmodel.cpp b/indra/llprimitive/llmodel.cpp
index 702a1b523843864d24d1f88690aed0cabfe5008d..a23b991f1d4d0896a521cde5082395526836eb52 100644
--- a/indra/llprimitive/llmodel.cpp
+++ b/indra/llprimitive/llmodel.cpp
@@ -1396,7 +1396,7 @@ void LLMeshSkinInfo::fromLLSD(LLSD& skin)
 				}
 			}
 
-			mInvBindMatrix.push_back(mat);
+			mInvBindMatrix.push_back(LLMatrix4a(mat));
 		}
 
         if (mJointNames.size() != mInvBindMatrix.size())
@@ -1410,13 +1410,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"))
@@ -1432,7 +1434,7 @@ void LLMeshSkinInfo::fromLLSD(LLSD& skin)
 				}
 			}
 			
-			mAlternateBindMatrix.push_back(mat);
+			mAlternateBindMatrix.push_back(LLMatrix4a(mat));
 		}
 	}
 
diff --git a/indra/llprimitive/llmodel.h b/indra/llprimitive/llmodel.h
index 51fa2f8079cfef5f9182df9a68e24280dce4f88b..cd2b6c6728101f0dda0822bcfaa90249771f2797 100644
--- a/indra/llprimitive/llmodel.h
+++ b/indra/llprimitive/llmodel.h
@@ -33,13 +33,17 @@
 #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);
@@ -49,18 +53,21 @@ class LLMeshSkinInfo
 	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;
 
-	LLMatrix4 mBindShapeMatrix;
+	LL_ALIGN_16(LLMatrix4a mBindShapeMatrix);
 	float mPelvisOffset;
     bool mLockScaleIfJointPosition;
     bool mInvalidJointsScrubbed;
     bool mJointNumsInitialized;
-};
+} LL_ALIGN_POSTFIX(16);
 
+LL_ALIGN_PREFIX(16)
 class LLModel : public LLVolume
 {
+    LL_ALIGN_NEW
 public:
 
 	enum
@@ -282,7 +289,7 @@ class LLModel : public LLVolume
 	EModelStatus mStatus ;
 
 	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..d7f7b2f58e84977e23d3de3cc3618efbb4b4a5ec 100644
--- a/indra/llrender/llcubemap.cpp
+++ b/indra/llrender/llcubemap.cpp
@@ -150,6 +150,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);
@@ -453,6 +454,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/llfontfreetype.cpp b/indra/llrender/llfontfreetype.cpp
index c41730ebaaacea9d369885fd04380f3821224f93..e18161e53c1d2c0396e4f5753a8ead0b277bd196 100644
--- a/indra/llrender/llfontfreetype.cpp
+++ b/indra/llrender/llfontfreetype.cpp
@@ -460,6 +460,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;
 
diff --git a/indra/llrender/llfontgl.cpp b/indra/llrender/llfontgl.cpp
index 86a4c35e6dec1ef309c370bdc2b0a40fb7dff272..266399d21266c5125cc70b6c9d386351cf3dbf56 100644
--- a/indra/llrender/llfontgl.cpp
+++ b/indra/llrender/llfontgl.cpp
@@ -547,9 +547,19 @@ F32 LLFontGL::getWidthF32(const llwchar* wchars, S32 begin_offset, S32 max_chars
 	return cur_x / sScaleX;
 }
 
+void LLFontGL::generateASCIIglyphs()
+{
+    LL_PROFILE_ZONE_SCOPED
+    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
 	if (!wchars || !wchars[0] || max_chars == 0)
 	{
 		return 0;
@@ -829,6 +839,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 +850,7 @@ void LLFontGL::initClass(F32 screen_dpi, F32 x_scale, F32 y_scale, const std::st
 // static
 bool LLFontGL::loadDefaultFonts()
 {
+	LL_PROFILE_ZONE_SCOPED
 	bool succ = true;
 	succ &= (NULL != getFontSansSerifSmall());
 	succ &= (NULL != getFontSansSerif());
@@ -845,10 +858,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
+    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 +1036,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 +1047,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 fe399ad882052bfa147c762c9644286763f28cda..a269549c4910e467e2079768ec452d9cfdf4c8f8 100644
--- a/indra/llrender/llgl.cpp
+++ b/indra/llrender/llgl.cpp
@@ -435,9 +435,6 @@ LLGLManager::LLGLManager() :
 	mHasMapBufferRange(FALSE),
 	mHasFlushBufferRange(FALSE),
 	mHasPBuffer(FALSE),
-	mHasShaderObjects(FALSE),
-	mHasVertexShader(FALSE),
-	mHasFragmentShader(FALSE),
 	mNumTextureImageUnits(0),
 	mHasOcclusionQuery(FALSE),
 	mHasTimerQuery(FALSE),
@@ -776,14 +773,9 @@ 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)
 	{
@@ -976,9 +968,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;
@@ -1084,9 +1076,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");
@@ -1144,10 +1133,6 @@ void LLGLManager::initExtensions()
 #if !LL_DARWIN
 	mHasPointParameters = !mIsATI && 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
@@ -1170,9 +1155,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 */
@@ -1185,9 +1167,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;
 	}
@@ -1209,9 +1188,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
@@ -1258,18 +1234,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;
@@ -1437,134 +1401,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)
@@ -2117,7 +2079,7 @@ void LLGLState::checkClientArrays(const std::string& msg, U32 data_mask)
 	glClientActiveTextureARB(GL_TEXTURE0_ARB);
 	gGL.getTexUnit(0)->activate();
 
-	if (gGLManager.mHasVertexShader && LLGLSLShader::sNoFixedFunction)
+	if (LLGLSLShader::sNoFixedFunction)
 	{	//make sure vertex attribs are all disabled
 		GLint count;
 		glGetIntegerv(GL_MAX_VERTEX_ATTRIBS_ARB, &count);
diff --git a/indra/llrender/llgl.h b/indra/llrender/llgl.h
index 53d077b99464fe2cda54a54830ebd544acd502d3..6e1f5e6deb777a4b6d3d03640728dec7c6bf1dcb 100644
--- a/indra/llrender/llgl.h
+++ b/indra/llrender/llgl.h
@@ -94,9 +94,6 @@ class LLGLManager
 	BOOL mHasMapBufferRange;
 	BOOL mHasFlushBufferRange;
 	BOOL mHasPBuffer;
-	BOOL mHasShaderObjects;
-	BOOL mHasVertexShader;
-	BOOL mHasFragmentShader;
 	S32  mNumTextureImageUnits;
 	BOOL mHasOcclusionQuery;
 	BOOL mHasTimerQuery;
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..0e4753fcc6c8662a1543168bfe9344e70cd23866 100644
--- a/indra/llrender/llglslshader.cpp
+++ b/indra/llrender/llglslshader.cpp
@@ -208,6 +208,7 @@ void LLGLSLShader::dumpStats()
 //static
 void LLGLSLShader::startProfile()
 {
+    LL_PROFILE_ZONE_SCOPED;
     if (sProfileEnabled && sCurBoundShaderPtr)
     {
         sCurBoundShaderPtr->placeProfileQuery();
@@ -218,6 +219,7 @@ void LLGLSLShader::startProfile()
 //static
 void LLGLSLShader::stopProfile(U32 count, U32 mode)
 {
+    LL_PROFILE_ZONE_SCOPED;
     if (sProfileEnabled && sCurBoundShaderPtr)
     {
         sCurBoundShaderPtr->readProfileQuery(count, mode);
@@ -384,6 +386,8 @@ BOOL LLGLSLShader::createShader(std::vector<LLStaticHashedString> * attributes,
                                 U32 varying_count,
                                 const char** varyings)
 {
+    LL_PROFILE_ZONE_SCOPED;
+
     unloadInternal();
 
     sInstances.insert(this);
@@ -588,6 +592,8 @@ void LLGLSLShader::attachObjects(GLhandleARB* objects, S32 count)
 
 BOOL LLGLSLShader::mapAttributes(const std::vector<LLStaticHashedString> * attributes)
 {
+    LL_PROFILE_ZONE_SCOPED;
+
     //before linking, make sure reserved attributes always have consistent locations
     for (U32 i = 0; i < LLShaderMgr::instance()->mReservedAttribs.size(); i++)
     {
@@ -649,6 +655,8 @@ BOOL LLGLSLShader::mapAttributes(const std::vector<LLStaticHashedString> * attri
 
 void LLGLSLShader::mapUniform(GLint index, const vector<LLStaticHashedString> * uniforms)
 {
+    LL_PROFILE_ZONE_SCOPED;
+
     if (index == -1)
     {
         return;
@@ -770,6 +778,8 @@ void LLGLSLShader::removePermutation(std::string name)
 
 GLint LLGLSLShader::mapUniformTextureChannel(GLint location, GLenum type)
 {
+    LL_PROFILE_ZONE_SCOPED;
+
     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 +792,9 @@ GLint LLGLSLShader::mapUniformTextureChannel(GLint location, GLenum type)
 
 BOOL LLGLSLShader::mapUniforms(const vector<LLStaticHashedString> * uniforms)
 {
-	BOOL res = TRUE;
+    LL_PROFILE_ZONE_SCOPED;
+
+    BOOL res = TRUE;
 
 	mTotalUniformSize = 0;
 	mActiveTextureChannels = 0;
@@ -925,6 +937,8 @@ BOOL LLGLSLShader::mapUniforms(const vector<LLStaticHashedString> * uniforms)
 
 BOOL LLGLSLShader::link(BOOL suppress_errors)
 {
+    LL_PROFILE_ZONE_SCOPED;
+
     BOOL success = LLShaderMgr::instance()->linkProgramObject(mProgramObject, suppress_errors);
 
     if (!success && !suppress_errors)
@@ -937,56 +951,52 @@ BOOL LLGLSLShader::link(BOOL suppress_errors)
 
 void LLGLSLShader::bind()
 {
+    LL_PROFILE_ZONE_SCOPED;
+
     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()
 {
+    LL_PROFILE_ZONE_SCOPED;
+
     gGL.flush();
-    if (gGLManager.mHasShaderObjects)
-    {
-        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();
-    }
+    stop_glerror();
+    LLVertexBuffer::unbind();
+    glUseProgramObjectARB(0);
+    sCurBoundShader = 0;
+    sCurBoundShaderPtr = NULL;
+    stop_glerror();
 }
 
 void LLGLSLShader::bindNoShader(void)
 {
+    LL_PROFILE_ZONE_SCOPED;
+
     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;
+
     S32 channel = 0;
     channel = getUniformLocation(uniform);
     
@@ -995,6 +1005,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;
+
     if (uniform < 0 || uniform >= (S32)mTexture.size())
     {
         LL_SHADER_UNIFORM_ERRS() << "Uniform out of range: " << uniform << LL_ENDL;
@@ -1005,7 +1017,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 +1026,8 @@ S32 LLGLSLShader::bindTexture(S32 uniform, LLTexture *texture, LLTexUnit::eTextu
 
 S32 LLGLSLShader::unbindTexture(const std::string &uniform, LLTexUnit::eTextureType mode)
 {
+    LL_PROFILE_ZONE_SCOPED;
+
     S32 channel = 0;
     channel = getUniformLocation(uniform);
     
@@ -1022,6 +1036,8 @@ S32 LLGLSLShader::unbindTexture(const std::string &uniform, LLTexUnit::eTextureT
 
 S32 LLGLSLShader::unbindTexture(S32 uniform, LLTexUnit::eTextureType mode)
 {
+    LL_PROFILE_ZONE_SCOPED;
+
     if (uniform < 0 || uniform >= (S32)mTexture.size())
     {
         LL_SHADER_UNIFORM_ERRS() << "Uniform out of range: " << uniform << LL_ENDL;
@@ -1032,7 +1048,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 +1056,8 @@ S32 LLGLSLShader::unbindTexture(S32 uniform, LLTexUnit::eTextureType mode)
 
 S32 LLGLSLShader::enableTexture(S32 uniform, LLTexUnit::eTextureType mode, LLTexUnit::eTextureColorSpace space)
 {
+    LL_PROFILE_ZONE_SCOPED;
+
     if (uniform < 0 || uniform >= (S32)mTexture.size())
     {
         LL_SHADER_UNIFORM_ERRS() << "Uniform out of range: " << uniform << LL_ENDL;
@@ -1057,6 +1075,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;
+
     if (uniform < 0 || uniform >= (S32)mTexture.size())
     {
         LL_SHADER_UNIFORM_ERRS() << "Uniform out of range: " << uniform << LL_ENDL;
@@ -1084,6 +1104,7 @@ S32 LLGLSLShader::disableTexture(S32 uniform, LLTexUnit::eTextureType mode, LLTe
 
 void LLGLSLShader::uniform1i(U32 index, GLint x)
 {
+    LL_PROFILE_ZONE_SCOPED
     if (mProgramObject)
     {   
         if (mUniform.size() <= index)
@@ -1094,7 +1115,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 +1127,7 @@ void LLGLSLShader::uniform1i(U32 index, GLint x)
 
 void LLGLSLShader::uniform1f(U32 index, GLfloat x)
 {
+    LL_PROFILE_ZONE_SCOPED
     if (mProgramObject)
     {   
         if (mUniform.size() <= index)
@@ -1116,7 +1138,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 +1160,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 +1183,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 +1206,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 +1229,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 +1252,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 +1275,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 +1298,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 +1321,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;
                 glUniform4fvARB(mUniform[index], count, v);
                 mValue[mUniform[index]] = vec;
             }
@@ -1346,6 +1369,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;
+
 	if (mProgramObject)
 	{	
 		if (mUniform.size() <= index)
@@ -1380,6 +1405,8 @@ void LLGLSLShader::uniformMatrix4fv(U32 index, U32 count, GLboolean transpose, c
 
 GLint LLGLSLShader::getUniformLocation(const LLStaticHashedString& uniform)
 {
+    LL_PROFILE_ZONE_SCOPED;
+
     GLint ret = -1;
     if (mProgramObject)
     {
@@ -1404,6 +1431,8 @@ GLint LLGLSLShader::getUniformLocation(const LLStaticHashedString& uniform)
 
 GLint LLGLSLShader::getUniformLocation(U32 index)
 {
+    LL_PROFILE_ZONE_SCOPED;
+
     GLint ret = -1;
     if (mProgramObject)
     {
@@ -1416,6 +1445,8 @@ GLint LLGLSLShader::getUniformLocation(U32 index)
 
 GLint LLGLSLShader::getAttribLocation(U32 attrib)
 {
+    LL_PROFILE_ZONE_SCOPED;
+
     if (attrib < mAttribute.size())
     {
         return mAttribute[attrib];
@@ -1432,7 +1463,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 +1479,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 +1496,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 +1512,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 +1529,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 +1545,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 +1561,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 +1577,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 +1594,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;
             glUniform4fvARB(location, count, v);
-            stop_glerror();
             mValue[location] = vec;
         }
     }
@@ -1608,3 +1638,27 @@ void LLGLSLShader::setMinimumAlpha(F32 minimum)
     gGL.flush();
     uniform1f(LLShaderMgr::MINIMUM_ALPHA, minimum);
 }
+
+void LLShaderUniforms::apply(LLGLSLShader* shader)
+{
+    LL_PROFILE_ZONE_SCOPED;
+    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..3b23cf1b28c53540ad3de79ad5fcba835d2c3e10 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;
@@ -190,13 +254,15 @@ 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;
diff --git a/indra/llrender/llgltexture.cpp b/indra/llrender/llgltexture.cpp
index ad501687ed54fe91f4528a00ab5d41a5ecbbff78..a279e85bae6e01444adb069c1e0128e6758e417a 100644
--- a/indra/llrender/llgltexture.cpp
+++ b/indra/llrender/llgltexture.cpp
@@ -262,6 +262,7 @@ LLTexUnit::eTextureType LLGLTexture::getTarget(void) const
 
 BOOL LLGLTexture::setSubImage(const LLImageRaw* imageraw, S32 x_pos, S32 y_pos, S32 width, S32 height)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	llassert(mGLTexturep.notNull()) ;
 
 	return mGLTexturep->setSubImage(imageraw, x_pos, y_pos, width, height) ;
@@ -269,6 +270,7 @@ BOOL LLGLTexture::setSubImage(const LLImageRaw* imageraw, S32 x_pos, S32 y_pos,
 
 BOOL LLGLTexture::setSubImage(const U8* datap, S32 data_width, S32 data_height, S32 x_pos, S32 y_pos, S32 width, S32 height)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	llassert(mGLTexturep.notNull()) ;
 
 	return mGLTexturep->setSubImage(datap, data_width, data_height, x_pos, y_pos, width, height) ;
diff --git a/indra/llrender/llgltexture.h b/indra/llrender/llgltexture.h
index 071912c2c23231080315806313c1586b95ab6fdc..028457c510174c45cbc61dc19800325ef305a86a 100644
--- a/indra/llrender/llgltexture.h
+++ b/indra/llrender/llgltexture.h
@@ -176,7 +176,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..aff29bd8577bd622b4856708d8fa534fe3701e9d 100644
--- a/indra/llrender/llimagegl.cpp
+++ b/indra/llrender/llimagegl.cpp
@@ -39,6 +39,7 @@
 #include "llgl.h"
 #include "llglslshader.h"
 #include "llrender.h"
+#include "llwindow.h"
 
 //----------------------------------------------------------------------------
 const F32 MIN_TEXTURE_LIFETIME = 10.f;
@@ -170,15 +171,32 @@ BOOL is_little_endian()
     
 	return (*c == 0x78) ;
 }
+
+LLImageGLThread* LLImageGLThread::sInstance = nullptr;
+
 //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 */)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	sSkipAnalyzeAlpha = skip_analyze_alpha;
+    LLImageGLThread::sInstance = new LLImageGLThread(window);
+    LLImageGLThread::sInstance->start();
+}
+
+//static
+void LLImageGL::updateClass()
+{
+    LL_PROFILE_ZONE_SCOPED;
+    LLImageGLThread::sInstance->executeCallbacks();
 }
 
 //static 
 void LLImageGL::cleanupClass() 
-{	
+{
+    LL_PROFILE_ZONE_SCOPED;
+    LLImageGLThread::sInstance->mFunctionQueue.close();
+    delete LLImageGLThread::sInstance;
+    LLImageGLThread::sInstance = nullptr;
 }
 
 //static
@@ -656,6 +674,7 @@ void LLImageGL::setExplicitFormat( LLGLint internal_format, LLGLenum primary_for
 
 void LLImageGL::setImage(const LLImageRaw* imageraw)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	llassert((imageraw->getWidth() == getWidth(mCurrentDiscardLevel)) &&
 			 (imageraw->getHeight() == getHeight(mCurrentDiscardLevel)) &&
 			 (imageraw->getComponents() == getComponents()));
@@ -699,9 +718,8 @@ BOOL LLImageGL::setImage(const U8* data_in, BOOL data_hasmips)
 	}
 	
 	llverify(gGL.getTexUnit(0)->bind(this));
-	
-	
-	if (mUseMipMaps)
+
+    if (mUseMipMaps)
 	{
 		if (data_hasmips)
 		{
@@ -781,7 +799,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);
@@ -878,7 +896,7 @@ BOOL LLImageGL::setImage(const U8* data_in, BOOL data_hasmips)
 							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);
@@ -1067,6 +1085,7 @@ void LLImageGL::postAddToAtlas()
 
 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)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	if (!width || !height)
 	{
 		return TRUE;
@@ -1163,6 +1182,7 @@ BOOL LLImageGL::setSubImage(const U8* datap, S32 data_width, S32 data_height, S3
 
 BOOL LLImageGL::setSubImage(const LLImageRaw* imageraw, S32 x_pos, S32 y_pos, S32 width, S32 height, BOOL force_fast_update)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	return setSubImage(imageraw->getData(), imageraw->getWidth(), imageraw->getHeight(), x_pos, y_pos, width, height, force_fast_update);
 }
 
@@ -1201,116 +1221,119 @@ 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_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];
 
-			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
+            use_scratch = true;
+            scratch = new U32[width * height];
 
-				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
+            use_scratch = true;
+            scratch = new U32[width * height];
 
-	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;
+        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
@@ -1333,6 +1356,7 @@ BOOL LLImageGL::createGLTexture()
 	if(mTexName)
 	{
 		LLImageGL::deleteTextures(1, (reinterpret_cast<GLuint*>(&mTexName))) ;
+        mTexName = 0;
 	}
 	
 
@@ -1694,7 +1718,7 @@ void LLImageGL::destroyGLTexture()
 			mTextureMemory = (S32Bytes)0;
 		}
 		
-		LLImageGL::deleteTextures(1, &mTexName);			
+		LLImageGL::deleteTextures(1, &mTexName);
 		mCurrentDiscardLevel = -1 ; //invalidate mCurrentDiscardLevel.
 		mTexName = 0;		
 		mGLTextureCreated = FALSE ;
@@ -2235,3 +2259,90 @@ void LLImageGL::resetCurTexSizebar()
 		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
 		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL,  nummips);
 */  
+
+LLImageGLThread::LLImageGLThread(LLWindow* window)
+    : LLThread("LLImageGL"), mWindow(window)
+{
+    mFinished = false;
+
+    mContext = mWindow->createSharedContext();
+}
+
+// post a function to be executed on the LLImageGL background thread
+
+bool LLImageGLThread::post(const std::function<void()>& func)
+{
+    try
+    {
+        if (mFunctionQueue.size() < mFunctionQueue.capacity())
+        {
+            //NOTE: tryPushFront will return immediately if the lock is held
+            // desired behavior here is to push and return true unless the 
+            // queue is full or closed
+            mFunctionQueue.pushFront(func);
+        }
+        else
+        {
+            return false;
+        }
+    }
+    catch (LLThreadSafeQueueInterrupt e)
+    {
+        return false;
+    }
+
+    return true;
+}
+
+//post a callback to be executed on the main thread
+
+bool LLImageGLThread::postCallback(const std::function<void()>& callback)
+{
+    try
+    {
+        mCallbackQueue.pushFront(callback);
+    }
+    catch (LLThreadSafeQueueInterrupt e)
+    {
+        //thread is closing, drop request
+        return false;
+    }
+
+    return true;
+}
+
+void LLImageGLThread::executeCallbacks()
+{
+    LL_PROFILE_ZONE_SCOPED;
+    //executed from main thread
+    std::function<void()> callback;
+    while (mCallbackQueue.tryPopBack(callback))
+    {
+        LL_PROFILE_ZONE_NAMED("iglt - callback");
+        callback();
+    }
+}
+
+void LLImageGLThread::run()
+{
+    mWindow->makeContextCurrent(mContext);
+    gGL.init();
+    try
+    {
+        while (true)
+        {
+            LL_PROFILE_ZONE_SCOPED;
+            std::function<void()> curFunc = mFunctionQueue.popBack();
+            {
+                LL_PROFILE_ZONE_NAMED("iglt - function")
+                    curFunc();
+            }
+        }
+    }
+    catch (LLThreadSafeQueueInterrupt e)
+    {
+        //queue is closed, fall out of run loop
+    }
+    gGL.shutdown();
+    mWindow->destroySharedContext(mContext);
+}
diff --git a/indra/llrender/llimagegl.h b/indra/llrender/llimagegl.h
index 61ddc8d59b7e9e63bdc0b0340f6ce68f4f4335be..8e9b483c2d070fbe8f594a63f8eba9c5845694d6 100644
--- a/indra/llrender/llimagegl.h
+++ b/indra/llrender/llimagegl.h
@@ -35,9 +35,11 @@
 #include "llrefcount.h"
 #include "v2math.h"
 #include "llunits.h"
-
+#include "llthreadsafequeue.h"
 #include "llrender.h"
 class LLTextureAtlas ;
+class LLWindow;
+
 #define BYTES_TO_MEGA_BYTES(x) ((x) >> 20)
 #define MEGA_BYTES_TO_BYTES(x) ((x) << 20)
 
@@ -102,7 +104,7 @@ 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);
@@ -265,7 +267,8 @@ 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); 
+    static void updateClass();
 	static void cleanupClass() ;
 
 private:
@@ -301,4 +304,30 @@ class LLImageGL : public LLRefCount, public LLTrace::MemTrackable<LLImageGL>
 
 };
 
+class LLImageGLThread : public LLThread
+{
+public:
+    LLImageGLThread(LLWindow* window);
+
+    // post a function to be executed on the LLImageGL background thread
+    bool post(const std::function<void()>& func);
+
+    //post a callback to be executed on the main thread
+    bool postCallback(const std::function<void()>& callback);
+
+    void executeCallbacks();
+
+    void run() override;
+
+    LLThreadSafeQueue<std::function<void()>> mFunctionQueue;
+    LLThreadSafeQueue<std::function<void()>> mCallbackQueue;
+
+    LLWindow* mWindow;
+    void* mContext;
+    LLAtomicBool mFinished;
+
+    static LLImageGLThread* sInstance;
+};
+
+
 #endif // LL_LLIMAGEGL_H
diff --git a/indra/llrender/llrender.cpp b/indra/llrender/llrender.cpp
index 03b6aac20c3d2883a4be39ef86e10549e69f68f7..669a09d3ceadfd897eeb204a7ba1c6c5235980b8 100644
--- a/indra/llrender/llrender.cpp
+++ b/indra/llrender/llrender.cpp
@@ -36,7 +36,7 @@
 #include "lltexture.h"
 #include "llshadermgr.h"
 
-LLRender gGL;
+thread_local LLRender gGL;
 
 // Handy copies of last good GL matrices
 F32	gGLModelView[16];
@@ -229,8 +229,20 @@ void LLTexUnit::disable(void)
 	}
 }
 
+void LLTexUnit::bindFast(LLTexture* texture)
+{
+    LLImageGL* gl_tex = texture->getGLTexture();
+
+    glActiveTextureARB(GL_TEXTURE0_ARB + mIndex);
+    gGL.mCurrTextureUnitIndex = mIndex;
+    mCurrTexture = gl_tex->getTexName();
+    glBindTexture(sGLTextureType[gl_tex->getTarget()], mCurrTexture);
+    mHasMipMaps = gl_tex->mHasMipMaps;
+}
+
 bool LLTexUnit::bind(LLTexture* texture, bool for_rendering, bool forceBind)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	stop_glerror();
 	if (mIndex >= 0)
 	{
@@ -459,6 +471,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;
@@ -1243,8 +1277,6 @@ void LLRender::syncLightState()
 
 void LLRender::syncMatrices()
 {
-	stop_glerror();
-
 	static const U32 name[] = 
 	{
 		LLShaderMgr::MODELVIEW_MATRIX,
@@ -1415,8 +1447,6 @@ void LLRender::syncMatrices()
 			}
 		}
 	}
-
-	stop_glerror();
 }
 
 void LLRender::translatef(const GLfloat& x, const GLfloat& y, const GLfloat& z)
@@ -1848,6 +1878,7 @@ LLLightState* LLRender::getLight(U32 index)
 
 void LLRender::setAmbientLightColor(const LLColor4& color)
 {
+	LL_PROFILE_ZONE_SCOPED
 	if (color != mAmbientLightColor)
 	{
 		++mLightHash;
@@ -1926,6 +1957,7 @@ void LLRender::flush()
 {
 	if (mCount > 0)
 	{
+        LL_PROFILE_ZONE_SCOPED;
 		if (!mUIOffset.empty())
 		{
 			sUICalls++;
diff --git a/indra/llrender/llrender.h b/indra/llrender/llrender.h
index af8568f8a3438b45c075b4390f46d05b96dd3201..6e2647a16bad3b777c2c4ce4ad5b012e434789d4 100644
--- a/indra/llrender/llrender.h
+++ b/indra/llrender/llrender.h
@@ -161,6 +161,17 @@ class LLTexUnit
 	bool bind(LLImageGL* texture, bool for_rendering = false, bool forceBind = false);
     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 +188,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.
@@ -511,7 +525,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/llrendertarget.cpp b/indra/llrender/llrendertarget.cpp
index e3c0255290fde73daac8dc5ff82493f47a4e186a..401085a00bc9dc767762a1a5e9d219c06599b91a 100644
--- a/indra/llrender/llrendertarget.cpp
+++ b/indra/llrender/llrendertarget.cpp
@@ -437,11 +437,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/lltexture.h b/indra/llrender/lltexture.h
index 41481fb8a722d23fd06e999ee9a9c7493ea02e59..256d85ce5ad808b6137810abc2f2a8dd38bf1c12 100644
--- a/indra/llrender/lltexture.h
+++ b/indra/llrender/lltexture.h
@@ -67,11 +67,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..103d5388d32e44a63df27d3a759c320167e86ddc 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
 
-	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
 	if (gGLManager.mInited)
 	{
 		LLVertexBuffer::unbind();
@@ -152,6 +159,7 @@ LLVBOPool::LLVBOPool(U32 vboUsage, U32 vboType)
 
 volatile U8* LLVBOPool::allocate(U32& name, U32 size, bool for_seed)
 {
+	LL_PROFILE_ZONE_SCOPED
 	llassert(vbo_block_size(size) == size);
 	
 	volatile U8* ret = NULL;
@@ -267,10 +275,12 @@ void LLVBOPool::release(U32 name, volatile U8* buffer, U32 size)
 
 void LLVBOPool::seedPool()
 {
+	LL_PROFILE_ZONE_SCOPED
 	U32 dummy_name = 0;
 
 	if (mFreeList.size() < LL_VBO_POOL_SEED_COUNT)
 	{
+		LL_PROFILE_ZONE_NAMED("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
 	sStreamVBOPool.seedPool();
 	sDynamicVBOPool.seedPool();
 	sDynamicCopyVBOPool.seedPool();
@@ -615,6 +626,7 @@ void LLVertexBuffer::drawArrays(U32 mode, const std::vector<LLVector3>& pos, con
 		glNormalPointer(GL_FLOAT, 0, norm[0].mV);
 	}
 	LLGLSLShader::startProfile();
+	LL_PROFILER_GPU_ZONEC( "gl.DrawArrays", 0xFF0000 )
 	glDrawArrays(sGLMode[mode], 0, count);
 	LLGLSLShader::stopProfile(count, mode);
 }
@@ -654,6 +666,7 @@ void LLVertexBuffer::drawElements(U32 mode, const LLVector4a* pos, const LLVecto
 	}
 
 	LLGLSLShader::startProfile();
+    LL_PROFILER_GPU_ZONEC( "gl.DrawElements", 0x80FF80 )
 	glDrawElements(sGLMode[mode], num_indices, GL_UNSIGNED_SHORT, indicesp);
 	LLGLSLShader::stopProfile(num_indices, mode);
 }
@@ -763,6 +776,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,6 +787,18 @@ 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*)(U8*)mAlignedIndexOffset) + 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);
@@ -814,6 +840,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);
@@ -861,6 +888,7 @@ void LLVertexBuffer::drawArrays(U32 mode, U32 first, U32 count) const
 		stop_glerror();
 		LLGLSLShader::startProfile();
 		stop_glerror();
+        LL_PROFILER_GPU_ZONEC( "gl.DrawArrays", 0xFF4040 )
 		glDrawArrays(sGLMode[mode], first, count);
 		stop_glerror();
 		LLGLSLShader::stopProfile(count, mode);
@@ -2256,6 +2284,21 @@ bool LLVertexBuffer::bindGLBuffer(bool force_bind)
 	return ret;
 }
 
+bool LLVertexBuffer::bindGLBufferFast()
+{
+    if (mGLBuffer != sGLRenderBuffer || !sVBOActive)
+    {
+        glBindBufferARB(GL_ARRAY_BUFFER_ARB, mGLBuffer);
+        sGLRenderBuffer = mGLBuffer;
+        sBindCount++;
+        sVBOActive = true;
+
+        return true;
+    }
+
+    return false;
+}
+
 static LLTrace::BlockTimerStatHandle FTM_BIND_GL_INDICES("Bind Indices");
 
 bool LLVertexBuffer::bindGLIndices(bool force_bind)
@@ -2281,6 +2324,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,6 +2529,26 @@ void LLVertexBuffer::setBuffer(U32 data_mask)
 	}
 }
 
+void LLVertexBuffer::setBufferFast(U32 data_mask)
+{
+    //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++;
+    }
+}
+
 // virtual (default)
 void LLVertexBuffer::setupVertexBuffer(U32 data_mask)
 {
@@ -2628,6 +2706,99 @@ void LLVertexBuffer::setupVertexBuffer(U32 data_mask)
 	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..51ed85510e1b1cc4ce7b31d82c7b0642f9705b1f 100644
--- a/indra/llrender/llvertexbuffer.h
+++ b/indra/llrender/llvertexbuffer.h
@@ -89,6 +89,9 @@ class LLVBOPool
 	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;
 };
 
 
@@ -127,7 +130,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;
 
@@ -207,13 +210,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();
@@ -236,6 +243,8 @@ class LLVertexBuffer : public LLRefCount, public LLTrace::MemTrackable<LLVertexB
 
 	// 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);
@@ -287,6 +296,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;
 
diff --git a/indra/llui/llnotifications.cpp b/indra/llui/llnotifications.cpp
index b791a19c2bfe4091cf37453065a3afc5e7709f36..88eda1c1729951b53a7f168c05961ed5b3413c9f 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/llstatbar.cpp b/indra/llui/llstatbar.cpp
index 6c8e63442badf14ca6498a37bad9057d2ddaadcd..8adcd664df23daed19192014c604d309f47b6814 100644
--- a/indra/llui/llstatbar.cpp
+++ b/indra/llui/llstatbar.cpp
@@ -554,29 +554,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/llwindow/llopenglview-objc.mm b/indra/llwindow/llopenglview-objc.mm
index d2c5b11c3d1899ff7b3db870eba8bb53083ab004..b647085b7e66e3f427b1785a02e0566153c87908 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]
diff --git a/indra/llwindow/llwindow.h b/indra/llwindow/llwindow.h
index 41eb1d7ee5eb0e877ab2973a623807c67214ab78..c7df72978207292c6b5b5a752c1c89781ef5358e 100644
--- a/indra/llwindow/llwindow.h
+++ b/indra/llwindow/llwindow.h
@@ -78,7 +78,18 @@ class LLWindow : public LLInstanceTracker<LLWindow>
 	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;
+
+    //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 BOOL setCursorPosition(LLCoordWindow position) = 0;
 	virtual BOOL getCursorPosition(LLCoordWindow *position) = 0;
 	virtual void showCursor() = 0;
 	virtual void hideCursor() = 0;
diff --git a/indra/llwindow/llwindowheadless.h b/indra/llwindow/llwindowheadless.h
index c692666df140d2203d35c2f2fe8c38b028efda79..a7ae28aa24b23535acd47a19da957fc0b3544073 100644
--- a/indra/llwindow/llwindowheadless.h
+++ b/indra/llwindow/llwindowheadless.h
@@ -49,6 +49,9 @@ class LLWindowHeadless : public LLWindow
 	/*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;};
+    void* createSharedContext()  { return nullptr; }
+    void makeContextCurrent(void*)  {}
+    void destroySharedContext(void*)  {}
 	/*virtual*/ BOOL setCursorPosition(LLCoordWindow position) {return FALSE;};
 	/*virtual*/ BOOL getCursorPosition(LLCoordWindow *position) {return FALSE;};
 	/*virtual*/ void showCursor() {};
diff --git a/indra/llwindow/llwindowmacosx.cpp b/indra/llwindow/llwindowmacosx.cpp
index 0d0607a0bb1e195fa3e651575f3a35ef8abb122f..23830dd24eb687242d2afc09f1f9794011da483f 100644
--- a/indra/llwindow/llwindowmacosx.cpp
+++ b/indra/llwindow/llwindowmacosx.cpp
@@ -1907,6 +1907,34 @@ 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::interruptLanguageTextInput()
 {
 	commitCurrentPreedit(mGLView);
diff --git a/indra/llwindow/llwindowmacosx.h b/indra/llwindow/llwindowmacosx.h
index bf45238c8d91bd1150108ee16e88d86faefd0506..ede2b453d5e55fe6bb31d7795d304fb20e49c75d 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 disable_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,6 +131,15 @@ 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;
+
 protected:
 	LLWindowMacOSX(LLWindowCallbacks* callbacks,
 		const std::string& title, const std::string& name, int x, int y, int width, int height, U32 flags,
@@ -141,7 +149,7 @@ class LLWindowMacOSX : public LLWindow
 		~LLWindowMacOSX();
 
 	void	initCursors();
-	BOOL	isValid();
+	BOOL	isValid() override;
 	void	moveWindow(const LLCoordScreen& position,const LLCoordScreen& size);
 
 
@@ -157,7 +165,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();
@@ -231,9 +239,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 dc3e77cc57b33be90a31b2a490354ac35f4f6f6f..e668fc1eed41ea09de8f5da329f56a0c8fd0ade4 100644
--- a/indra/llwindow/llwindowwin32.cpp
+++ b/indra/llwindow/llwindowwin32.cpp
@@ -28,6 +28,8 @@
 
 #if LL_WINDOWS && !LL_MESA_HEADLESS
 
+#define LL_WINDOW_SINGLE_THREADED 0
+
 #include "llwindowwin32.h"
 
 // LLWindow library includes
@@ -45,6 +47,7 @@
 #include "lldir.h"
 #include "llsdutil.h"
 #include "llglslshader.h"
+#include "llthreadsafequeue.h"
 
 // System includes
 #include <commdlg.h>
@@ -79,6 +82,18 @@ const F32	ICON_FLASH_TIME = 0.5f;
 
 extern BOOL gDebugWindowProc;
 
+static std::thread::id sWindowThreadId;
+static std::thread::id sMainThreadId;
+
+#if 1 || LL_WINDOW_SINGLE_THREADED
+#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;
 
@@ -294,7 +309,7 @@ LLWinImm::LLWinImm() : mHImmDll(NULL)
 
 
 // static 
-BOOL	LLWinImm::isIME(HKL hkl)															
+BOOL	LLWinImm::isIME(HKL hkl)
 { 
 	if ( sTheInstance.mImmIsIME )
 		return sTheInstance.mImmIsIME(hkl); 
@@ -326,7 +341,7 @@ BOOL		LLWinImm::getOpenStatus(HIMC himc)
 }
 
 // static 
-BOOL		LLWinImm::setOpenStatus(HIMC himc, BOOL status)									
+BOOL		LLWinImm::setOpenStatus(HIMC himc, BOOL status)
 { 
 	if ( sTheInstance.mImmSetOpenStatus )
 		return sTheInstance.mImmSetOpenStatus(himc, status); 
@@ -454,6 +469,8 @@ class LLMonitorInfo
 
 static LLMonitorInfo sMonitorInfo;
 
+
+
 LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks,
 							 const std::string& title, const std::string& name, S32 x, S32 y, S32 width,
 							 S32 height, U32 flags, 
@@ -463,7 +480,11 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks,
 							 U32 fsaa_samples)
 	: LLWindow(callbacks, fullscreen, flags)
 {
-	
+    sMainThreadId = LLThread::currentID();
+    mWindowThread = new LLWindowWin32Thread(this);
+#if !LL_WINDOW_SINGLE_THREADED
+    mWindowThread->start();
+#endif
 	//MAINT-516 -- force a load of opengl32.dll just in case windows went sideways 
 	LoadLibrary(L"opengl32.dll");
 
@@ -784,7 +805,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, disable_vsync, &windowPos))
 	{
 		return;
 	}
@@ -811,6 +832,8 @@ LLWindowWin32::~LLWindowWin32()
 
 	delete [] mWindowClassName;
 	mWindowClassName = NULL;
+    
+    delete mWindowThread;
 }
 
 void LLWindowWin32::show()
@@ -930,26 +953,35 @@ void LLWindowWin32::close()
 
 	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
+            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))
+                {
+                    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;
+
+            mWindowThread->mFinished = true;
+        });
+
+    while (!mWindowThread->isStopped())
     {
-        // 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;
+        std::this_thread::sleep_for(std::chrono::milliseconds(1));
     }
-
-	mWindowHandle = NULL;
 }
 
 BOOL LLWindowWin32::isValid()
@@ -1090,171 +1122,203 @@ BOOL LLWindowWin32::setSizeImpl(const LLCoordWindow size)
 }
 
 // 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 disable_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))
+
+    auto oldHandle = mWindowHandle;
+
+    //zero out mWindowHandle and mhDC before destroying window so window thread falls back to peekmessage
+    mWindowHandle = 0;
+    mhDC = 0;
+
+    if (oldHandle && !destroy_window_handler(oldHandle))
     {
         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);
+    }
+
+    mWindowHandle = NULL;
+    mhDC = 0;
+
+    mWindowThread->post(
+        [this, window_rect, dw_ex_style, dw_style]()
+        {
+            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);
+
+            if (mWindowHandle)
+            {
+                mhDC = GetDC(mWindowHandle);
+            }
+        }
+    );
+
+    // HACK wait for above handle to become populated
+    // TODO: use a future
+    int count = 1024;
+    while (!mhDC && count > 0)
+    {
+        Sleep(10);
+        --count;
+    }
 
 	if (mWindowHandle)
 	{
@@ -1288,7 +1352,7 @@ BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen &size, BO
 			0, 0, 0
 	};
 
-	if (!(mhDC = GetDC(mWindowHandle)))
+	if (!mhDC)
 	{
 		close();
 		OSMessageBox(mCallbacks->translateString("MBDevContextErr"),
@@ -1582,25 +1646,48 @@ const	S32   max_format  = (S32)num_formats - 1;
 			mhDC = 0;											// Zero The Device Context
 		}
 
+        auto oldHandle = mWindowHandle;
+        mWindowHandle = NULL;
+        mhDC = 0;
+
         // Destroy The Window
-        if (mWindowHandle && !destroy_window_handler(mWindowHandle))
+        if (oldHandle && !destroy_window_handler(oldHandle))
         {
             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);
+        mWindowThread->post(
+            [this, window_rect, dw_ex_style, dw_style]()
+            {
+                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);
+
+                if (mWindowHandle)
+                {
+                    mhDC = GetDC(mWindowHandle);
+                }
+            }
+        );
 
+        // HACK wait for above handle to become populated
+        // TODO: use a future
+        int count = 1024;
+        while (!mhDC && count > 0)
+        {
+            PostMessage(oldHandle, WM_USER + 8, 0x1717, 0x3b3b);
+            Sleep(10);
+            --count;
+        }
 
 		if (mWindowHandle)
 		{
@@ -1612,7 +1699,7 @@ 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);
@@ -1687,58 +1774,11 @@ const	S32   max_format  = (S32)num_formats - 1;
 	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))
@@ -1748,6 +1788,8 @@ const	S32   max_format  = (S32)num_formats - 1;
 		return FALSE;
 	}
 
+	LL_PROFILER_GPU_CONTEXT
+
 	if (!gGLManager.initGL())
 	{
 		close();
@@ -1764,6 +1806,7 @@ const	S32   max_format  = (S32)num_formats - 1;
 	else
 	{
 		LL_DEBUGS("Window") << "Keeping vertical sync" << LL_ENDL;
+        wglSwapIntervalEXT(1);
 	}
 
 	SetWindowLongPtr(mWindowHandle, GWLP_USERDATA, (LONG_PTR)this);
@@ -1790,6 +1833,75 @@ const	S32   max_format  = (S32)num_formats - 1;
 	return TRUE;
 }
 
+void* LLWindowWin32::createSharedContext()
+{
+    S32 attribs[] =
+    {
+        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
+    };
+
+    HGLRC rc = wglCreateContextAttribsARB(mhDC, mhRC, attribs);
+
+    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;
+
+            // 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 (!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::moveWindow( const LLCoordScreen& position, const LLCoordScreen& size )
 {
 	if( mIsMouseClipping )
@@ -1814,37 +1926,47 @@ void LLWindowWin32::moveWindow( const LLCoordScreen& position, const LLCoordScre
 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??)
+    // to support non-ascii usernames (and region names?)
     SetWindowTextA(mWindowHandle, title.c_str());
 }
 
 BOOL LLWindowWin32::setCursorPosition(const LLCoordWindow position)
 {
-	mMousePositionModified = TRUE;
+    ASSERT_MAIN_THREAD();
+
 	if (!mWindowHandle)
 	{
 		return FALSE;
 	}
 
-
-	// Inform the application of the new mouse position (needed for per-frame
+    // 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);
+    mMousePositionModified = TRUE;
+    LLCoordScreen screen_pos(position.convert());
+    
+    mWindowThread->post([=]
+        {
+            SetCursorPos(screen_pos.mX, screen_pos.mY);
+            // 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))
+            {
+            }
+            
+            mMousePositionModified = FALSE;
+        });
+
+    return TRUE;
 }
 
 BOOL LLWindowWin32::getCursorPosition(LLCoordWindow *position)
 {
+    ASSERT_MAIN_THREAD();
 	POINT cursor_point;
 
 	if (!mWindowHandle 
@@ -1860,21 +1982,35 @@ BOOL LLWindowWin32::getCursorPosition(LLCoordWindow *position)
 
 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;
+
+    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;
 }
@@ -1976,6 +2112,8 @@ void LLWindowWin32::initCursors()
 
 void LLWindowWin32::updateCursor()
 {
+    ASSERT_MAIN_THREAD();
+    LL_PROFILE_ZONE_SCOPED
 	if (mNextCursor == UI_CURSOR_ARROW
 		&& mBusyCount > 0)
 	{
@@ -1985,7 +2123,11 @@ void LLWindowWin32::updateCursor()
 	if( mCurrentCursor != mNextCursor )
 	{
 		mCurrentCursor = mNextCursor;
-		SetCursor( mCursor[mNextCursor] );
+        auto nextCursor = mCursor[mNextCursor];
+        mWindowThread->post([=]()
+            {
+                SetCursor(nextCursor);
+            });
 	}
 }
 
@@ -2001,13 +2143,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;
 	ReleaseCapture();
-	mCallbacks->handleResumeWatchdog(this);
 }
 
 
@@ -2016,1003 +2153,1129 @@ void LLWindowWin32::delayInputProcessing()
 	mInputProcessingPaused = TRUE;
 }
 
+
 void LLWindowWin32::gatherInput()
 {
-	MSG		msg;
-	int		msg_count = 0;
+    ASSERT_MAIN_THREAD();
+    LL_PROFILE_ZONE_SCOPED
+    MSG msg;
 
-	while ((msg_count < MAX_MESSAGE_PER_UPDATE) && PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
-	{
-		mCallbacks->handlePingWatchdog(this, "Main:TranslateGatherInput");
-		TranslateMessage(&msg);
+#if LL_WINDOW_SINGLE_THREADED
+    int	msg_count = 0;
 
-		// turn watchdog off in here to not fail if windows is doing something wacky
-		mCallbacks->handlePauseWatchdog(this);
-		DispatchMessage(&msg);
-		mCallbacks->handleResumeWatchdog(this);
-		msg_count++;
+    while ((msg_count < MAX_MESSAGE_PER_UPDATE))
+    {
+        LL_PROFILE_ZONE_NAMED("gi - loop");
+        ++msg_count;
+        {
+            LL_PROFILE_ZONE_NAMED("gi - PeekMessage");
+            if (!PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
+            {
+                break;
+            }
+        }
 
-		if ( mInputProcessingPaused )
-		{
-			break;
-		}
-		/* Attempted workaround for problem where typing fast and hitting
-		   return would result in only part of the text being sent. JC
+        {
+            LL_PROFILE_ZONE_NAMED("gi - translate");
+            TranslateMessage(&msg);
+        }
 
-		BOOL key_posted = TranslateMessage(&msg);
-		DispatchMessage(&msg);
-		msg_count++;
+        {
+            LL_PROFILE_ZONE_NAMED("gi - dispatch");
+            DispatchMessage(&msg);
+        }
 
-		// 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);
-		}
-	}
+        if (mInputProcessingPaused)
+        {
+            break;
+        }
+
+        // For async host by name support.  Really hacky.
+        if (gAsyncMsgCallback && (LL_WM_HOST_RESOLVED == msg.message))
+        {
+            LL_PROFILE_ZONE_NAMED("gi - callback");
+            gAsyncMsgCallback(msg);
+        }
+    }
+#else //multi-threaded window impl
+    {
+        if (mWindowThread->mFunctionQueue.size() > 0)
+        {
+            LL_PROFILE_ZONE_NAMED("gi - PostMessage");
+            if (mWindowHandle)
+            { // 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
+                PostMessage(mWindowHandle, WM_USER + 0x0017, 0xB0B0, 0x1337);
+            }
+        }
+        
+        while (mWindowThread->mMessageQueue.tryPopBack(msg))
+        {
+            LL_PROFILE_ZONE_NAMED("gi - message queue");
+            if (mInputProcessingPaused)
+            {
+                continue;
+            }
+
+            // For async host by name support.  Really hacky.
+            if (gAsyncMsgCallback && (LL_WM_HOST_RESOLVED == msg.message))
+            {
+                LL_PROFILE_ZONE_NAMED("gi - callback");
+                gAsyncMsgCallback(msg);
+            }
+        }
+    }
+
+    {
+        LL_PROFILE_ZONE_NAMED("gi - function queue");
+        //process any pending functions
+        std::function<void()> curFunc;
+        while (mFunctionQueue.tryPopBack(curFunc))
+        {
+            curFunc();
+        }
+    }
+#endif
 
 	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");
 
+#if LL_WINDOW_SINGLE_THREADED
+#define WINDOW_IMP_POST(x) x
+#else
+#define WINDOW_IMP_POST(x) window_imp->post([=]() { x; })
+#endif
+
 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 );
+    ASSERT_WINDOW_THREAD();
+    LL_PROFILE_ZONE_SCOPED;
 
-	bool debug_window_proc = gDebugWindowProc || debugLoggingEnabled("Window");
+    // 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;
 
-	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;
-
-		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;
-			}
-
-		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;
-
-			window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_KEYUP");
-			LL_RECORD_BLOCK_TIME(FTM_KEYHANDLER);
-
-			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;
-			}
-
-			// 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;
-
-		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;
-
-		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;
+    LLWindowWin32* window_imp = (LLWindowWin32*)GetWindowLongPtr(h_wnd, GWLP_USERDATA);
 
-		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;
+    bool debug_window_proc = false; // gDebugWindowProc || debugLoggingEnabled("Window");
 
-		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)
+    {
+        // Has user provided their own window callback?
+        if (NULL != window_imp->mWndProc)
+        {
+            LL_PROFILE_ZONE_NAMED("mwp - WndProc");
+            if (!window_imp->mWndProc(h_wnd, u_msg, w_param, l_param))
+            {
+                // user has handled window message
+                return 0;
+            }
+        }
 
-		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;
+        // 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_LBUTTONDOWN:
-			{
-				window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_LBUTTONDOWN");
-				LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER);
-				sHandleLeftMouseUp = true;
+        // This doesn't work, as LOWORD returns unsigned short.
+        //LLCoordWindow window_coord(LOWORD(l_param), HIWORD(l_param));
+        LLCoordGL gl_coord;
 
-				if (LLWinImm::isAvailable() && window_imp->mPreeditor)
-				{
-					window_imp->interruptLanguageTextInput();
-				}
+        // pass along extended flag in mask
+        MASK mask = (l_param >> 16 & KF_EXTENDED) ? MASK_EXTENDED : 0x0;
+        BOOL eat_keystroke = TRUE;
 
-				// 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;
+        switch (u_msg)
+        {
+            RECT	update_rect;
+            S32		update_width;
+            S32		update_height;
 
-		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_TIMER:
+        {
+            LL_PROFILE_ZONE_NAMED("mwp - WM_TIMER");
+            WINDOW_IMP_POST(window_imp->mCallbacks->handleTimerEvent(window_imp));
+            break;
+        }
 
-				if (!sHandleDoubleClick)
-				{
-					sHandleDoubleClick = true;
-					break;
-				}
+        case WM_DEVICECHANGE:
+        {
+            LL_PROFILE_ZONE_NAMED("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;
+        }
 
-				// 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;
+        case WM_PAINT:
+        {
+            LL_PROFILE_ZONE_NAMED("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;
+        }
 
-		case WM_LBUTTONUP:
-			{
-				window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_LBUTTONUP");
-				LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER);
+        case WM_SETCURSOR:
+        {
+            LL_PROFILE_ZONE_NAMED("mwp - WM_SETCURSOR");
+            // This message is sent whenever the cursor is moved in a window.
+            // You need to set the appropriate cursor appearance.
 
-				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;
+            // 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("mwp - WM_ENTERMENULOOP");
+            WINDOW_IMP_POST(window_imp->mCallbacks->handleWindowBlock(window_imp));
+            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_EXITMENULOOP:
+        {
+            LL_PROFILE_ZONE_NAMED("mwp - WM_EXITMENULOOP");
+            WINDOW_IMP_POST(window_imp->mCallbacks->handleWindowUnblock(window_imp));
+            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_ACTIVATEAPP:
+        {
+            LL_PROFILE_ZONE_NAMED("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("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_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_QUERYOPEN:
+            // TODO: use this to return a nice icon
+            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_SYSCOMMAND:
+        {
+            LL_PROFILE_ZONE_NAMED("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("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("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("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("mwp - WM_SYSKEYDOWN");
+            // allow system keys, such as ALT-F4 to be processed by Windows
+            eat_keystroke = FALSE;
+        }
+        case WM_KEYDOWN:
+        {
+            LL_PROFILE_ZONE_NAMED("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);
+                    }
+                });
+                return eat_keystroke;
+        }
+        case WM_SYSKEYUP:
+            eat_keystroke = FALSE;
+        case WM_KEYUP:
+        {
+            LL_PROFILE_ZONE_NAMED("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);
+                }
+            });
+            return eat_keystroke;
+        }
+        case WM_IME_SETCONTEXT:
+        {
+            LL_PROFILE_ZONE_NAMED("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("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("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("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("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("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("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("mwp - WM_LBUTTONDOWN");
+            {
+                LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER);
+                window_imp->post([=]()
+                    {
+                        auto glc = gl_coord;
+                        sHandleLeftMouseUp = true;
+
+                        if (LLWinImm::isAvailable() && window_imp->mPreeditor)
+                        {
+                            window_imp->interruptLanguageTextInput();
+                        }
+
+                        // 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);
+                            glc = cursor_coord_window.convert();
+                        }
+                        else
+                        {
+                            glc = window_coord.convert();
+                        }
+                        MASK mask = gKeyboard->currentMask(TRUE);
+                        // generate move event to update mouse coordinates
+                        window_imp->mCallbacks->handleMouseMove(window_imp, glc, mask);
+                        window_imp->mCallbacks->handleMouseDown(window_imp, glc, mask);
+                    });
+
+                return 0;
+            }
+            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_LBUTTONDBLCLK:
+        {
+            LL_PROFILE_ZONE_NAMED("mwp - WM_LBUTTONDBLCLK");
+            //RN: ignore right button double clicks for now
+            //case WM_RBUTTONDBLCLK:
+            if (!sHandleDoubleClick)
+            {
+                sHandleDoubleClick = true;
+                return 0;
+            }
 
-		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();
-				}
+            // 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->post([=]()
+                {
+                    window_imp->mCallbacks->handleMouseMove(window_imp, gl_coord, mask);
+                    window_imp->mCallbacks->handleDoubleClick(window_imp, gl_coord, mask);
+                });
+            return 0;
+        }
+        case WM_LBUTTONUP:
+        {
+            LL_PROFILE_ZONE_NAMED("mwp - WM_LBUTTONUP");
+            {
+                LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER);
+
+                if (!sHandleLeftMouseUp)
+                {
+                    sHandleLeftMouseUp = true;
+                    return 0;
+                }
+                sHandleDoubleClick = true;
+                window_imp->post([=]()
+                    {
+                        auto glc = gl_coord;
+
+                        //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);
+                            glc = cursor_coord_window.convert();
+                        }
+                        else
+                        {
+                            glc = window_coord.convert();
+                        }
+                        MASK mask = gKeyboard->currentMask(TRUE);
+                        // generate move event to update mouse coordinates
+                        window_imp->mCallbacks->handleMouseMove(window_imp, glc, mask);
+                        window_imp->mCallbacks->handleMouseUp(window_imp, glc, mask);
+                    });
+            }
+            return 0;
+        }
+        case WM_RBUTTONDBLCLK:
+        case WM_RBUTTONDOWN:
+        {
+            LL_PROFILE_ZONE_NAMED("mwp - WM_RBUTTONDOWN");
+            {
+                LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER);
+                if (LLWinImm::isAvailable() && window_imp->mPreeditor)
+                {
+                    WINDOW_IMP_POST(window_imp->interruptLanguageTextInput());
+                }
+
+                // 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->post([=]()
+                    {
+                        window_imp->mCallbacks->handleMouseMove(window_imp, gl_coord, mask);
+                        window_imp->mCallbacks->handleRightMouseDown(window_imp, gl_coord, mask);
+                    });
+            }
+            return 0;
+        }
+        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_RBUTTONUP:
+        {
+            LL_PROFILE_ZONE_NAMED("mwp - 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_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;
+        case WM_MBUTTONDOWN:
+            //		case WM_MBUTTONDBLCLK:
+        {
+            LL_PROFILE_ZONE_NAMED("mwp - WM_MBUTTONDOWN");
+            {
+                LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER);
+                if (LLWinImm::isAvailable() && window_imp->mPreeditor)
+                {
+                    window_imp->interruptLanguageTextInput();
+                }
+
+                // 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_MOUSEWHEEL:
-			{
-				window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_MOUSEWHEEL");
-				static short z_delta = 0;
+        case WM_MBUTTONUP:
+        {
+            LL_PROFILE_ZONE_NAMED("mwp - 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:
+        {
+            LL_PROFILE_ZONE_NAMED("mwp - WM_XBUTTONDOWN");
+            {
+                LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER);
+                S32 button = GET_XBUTTON_WPARAM(w_param);
+                if (LLWinImm::isAvailable() && window_imp->mPreeditor)
+                {
+                    window_imp->interruptLanguageTextInput();
+                }
+
+                // 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;
 
-				RECT	client_rect;
+        case WM_XBUTTONUP:
+        {
+            LL_PROFILE_ZONE_NAMED("mwp - WM_XBUTTONUP");
+            {
+                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;
 
-				// 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)};
+        case WM_MOUSEWHEEL:
+        {
+            LL_PROFILE_ZONE_NAMED("mwp - WM_MOUSEWHEEL");
+            static short z_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)
-				{
-					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;
+            // 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:
+        {
+            LL_PROFILE_ZONE_NAMED("mwp - 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_h_delta = HIWORD(w_param);
-				h_delta += incoming_h_delta;
+            // 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) };
 
-				// 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;
-			}
+            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;
+                }
+            }
 
-		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;
-			}
+            S16 incoming_h_delta = HIWORD(w_param);
+            h_delta += incoming_h_delta;
 
-		case WM_SIZE:
-			{
-				window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_SIZE");
-				S32 width = S32( LOWORD(l_param) );
-				S32 height = S32( HIWORD(l_param) );
+            // 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("mwp - WM_MOUSEMOVE");
+            if (!window_imp->mMousePositionModified)
+            {
+                MASK mask = gKeyboard->currentMask(TRUE);
+                WINDOW_IMP_POST(window_imp->mCallbacks->handleMouseMove(window_imp, window_coord.convert(), mask));
+            }
+            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_GETMINMAXINFO:
+        {
+            LL_PROFILE_ZONE_NAMED("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;
+        }
 
-				// 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). 
+        case WM_SIZE:
+        {
+            LL_PROFILE_ZONE_NAMED("mwp - WM_SIZE");
+            S32 width = S32(LOWORD(l_param));
+            S32 height = S32(HIWORD(l_param));
 
-				// 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);
-				}
+            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;
+            }
 
-				// 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);
-				}
+            // 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). 
 
-				// Also handle the minimization case
-				if (w_param == SIZE_MINIMIZED && window_imp->mLastSizeWParam != SIZE_MINIMIZED)
-				{
-					window_imp->mCallbacks->handleActivate(window_imp, FALSE);
-				}
+            // 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));
+            }
 
-				// 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) );
-				}
+            // 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));
+            }
 
-				window_imp->mLastSizeWParam = w_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));
+            }
 
-				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;
-			}
+            // 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)));
+            }
 
-		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;
+            window_imp->mLastSizeWParam = w_param;
 
-		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;
+            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_DPICHANGED:
+        {
+            LL_PROFILE_ZONE_NAMED("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;
+        }
 
-			break;
+        case WM_SETFOCUS:
+        {
+            LL_PROFILE_ZONE_NAMED("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;
+        }
 
-		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_KILLFOCUS:
+        {
+            LL_PROFILE_ZONE_NAMED("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;
+        }
 
-	window_imp->mCallbacks->handlePauseWatchdog(window_imp);	
-	}
+        case WM_COPYDATA:
+        {
+            LL_PROFILE_ZONE_NAMED("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("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;
+        
+        //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_MOVE:
+        case WM_WINDOWPOSCHANGING:
+        case WM_WINDOWPOSCHANGED:
+        break;
+
+        default:
+        {
+            LL_PROFILE_ZONE_NAMED("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("mwp - DefWindowProc");
+        ret = DefWindowProc(h_wnd, u_msg, w_param, l_param);
+    }
+    return ret;
 }
 
 BOOL LLWindowWin32::convertCoords(LLCoordGL from, LLCoordWindow *to)
@@ -3191,6 +3454,8 @@ BOOL LLWindowWin32::copyTextToClipboard(const LLWString& wstr)
 // Constrains the mouse to the window.
 void LLWindowWin32::setMouseClipping( BOOL b )
 {
+    LL_PROFILE_ZONE_SCOPED;
+    ASSERT_MAIN_THREAD();
 	if( b != mIsMouseClipping )
 	{
 		BOOL success = FALSE;
@@ -3267,6 +3532,7 @@ F32 LLWindowWin32::getGamma()
 
 BOOL LLWindowWin32::restoreGamma()
 {
+    ASSERT_MAIN_THREAD();
 	if (mCustomGammaSet != FALSE)
 	{
         LL_DEBUGS("Window") << "Restoring gamma" << LL_ENDL;
@@ -3278,6 +3544,7 @@ BOOL LLWindowWin32::restoreGamma()
 
 BOOL LLWindowWin32::setGamma(const F32 gamma)
 {
+    ASSERT_MAIN_THREAD();
 	mCurrentGamma = gamma;
 
 	//Get the previous gamma ramp to restore later.
@@ -3316,6 +3583,7 @@ BOOL LLWindowWin32::setGamma(const F32 gamma)
 
 void LLWindowWin32::setFSAASamples(const U32 fsaa_samples)
 {
+    ASSERT_MAIN_THREAD();
 	mFSAASamples = fsaa_samples;
 }
 
@@ -3326,6 +3594,7 @@ U32 LLWindowWin32::getFSAASamples()
 
 LLWindow::LLWindowResolution* LLWindowWin32::getSupportedResolutions(S32 &num_resolutions)
 {
+    ASSERT_MAIN_THREAD();
 	if (!mSupportedResolutions)
 	{
 		mSupportedResolutions = new LLWindowResolution[MAX_NUM_RESOLUTIONS];
@@ -3480,7 +3749,11 @@ BOOL LLWindowWin32::resetDisplayResolution()
 
 void LLWindowWin32::swapBuffers()
 {
+    LL_PROFILE_ZONE_SCOPED;
+    ASSERT_MAIN_THREAD();
 	SwapBuffers(mhDC);
+
+    LL_PROFILER_GPU_COLLECT
 }
 
 
@@ -3953,6 +4226,7 @@ void LLWindowWin32::updateLanguageTextInputArea()
 
 void LLWindowWin32::interruptLanguageTextInput()
 {
+    ASSERT_MAIN_THREAD();
 	if (mPreeditor && LLWinImm::isAvailable())
 	{
 		HIMC himc = LLWinImm::getContext(mWindowHandle);
@@ -4155,6 +4429,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 );
 }
 
@@ -4203,6 +4478,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;
@@ -4410,3 +4686,79 @@ std::vector<std::string> LLWindowWin32::getDynamicFallbackFontList()
 
 
 #endif // LL_WINDOWS
+
+inline LLWindowWin32Thread::LLWindowWin32Thread(LLWindowWin32* window)
+    : LLThread("Window Thread"), 
+    mWindow(window),
+    mFunctionQueue(MAX_QUEUE_SIZE)
+{
+
+}
+
+inline void LLWindowWin32Thread::run()
+{
+    sWindowThreadId = getID();
+    while (!mFinished)
+    {
+        LL_PROFILE_ZONE_SCOPED;
+
+
+        if (mWindow && mWindow->mWindowHandle != 0)
+        {
+            MSG msg;
+            BOOL status;
+            if (mWindow->mhDC == 0)
+            {
+                LL_PROFILE_ZONE_NAMED("w32t - PeekMessage");
+                status = PeekMessage(&msg, mWindow->mWindowHandle, 0, 0, PM_REMOVE);
+            }
+            else
+            {
+                LL_PROFILE_ZONE_NAMED("w32t - GetMessage");
+                status = GetMessage(&msg, mWindow->mWindowHandle, 0, 0);
+            }
+            if (status > 0)
+            {
+                TranslateMessage(&msg);
+                DispatchMessage(&msg);
+
+                mMessageQueue.pushFront(msg);
+            }
+        }
+
+        {
+            LL_PROFILE_ZONE_NAMED("w32t - Function Queue");
+            //process any pending functions
+            std::function<void()> curFunc;
+            while (mFunctionQueue.tryPopBack(curFunc))
+            {
+                curFunc();
+            }
+        }
+        
+#if 0
+        {
+            LL_PROFILE_ZONE_NAMED("w32t - Sleep");
+            std::this_thread::sleep_for(std::chrono::milliseconds(1));
+        }
+#endif
+    }
+}
+
+void LLWindowWin32Thread::post(const std::function<void()>& func)
+{
+#if LL_WINDOW_SINGLE_THREADED
+    func();
+#else
+    mFunctionQueue.pushFront(func);
+#endif
+}
+
+void LLWindowWin32::post(const std::function<void()>& func)
+{
+#if LL_WINDOW_SINGLE_THREADED
+    func();
+#else
+    mFunctionQueue.pushFront(func);
+#endif
+}
diff --git a/indra/llwindow/llwindowwin32.h b/indra/llwindow/llwindowwin32.h
index 34dcb7f268c86ab97aca5545e5ebedd6c2ce207c..ea1c103bcd61054d902de3bdcda9fffa0a8d0b18 100644
--- a/indra/llwindow/llwindowwin32.h
+++ b/indra/llwindow/llwindowwin32.h
@@ -33,11 +33,46 @@
 #include "llwindow.h"
 #include "llwindowcallbacks.h"
 #include "lldragdropwin32.h"
+#include "llthread.h"
+#include "llthreadsafequeue.h"
 
 // Hack for async host by name
 #define LL_WM_HOST_RESOLVED      (WM_APP + 1)
 typedef void (*LLW32MsgCallback)(const MSG &msg);
 
+class LLWindowWin32;
+
+// Thread that owns the Window Handle
+class LLWindowWin32Thread : public LLThread
+{
+public:
+    class Message
+    {
+    public:
+        LRESULT mMsg;
+    };
+
+    static const int MAX_QUEUE_SIZE = 2048;
+
+    LLThreadSafeQueue<MSG> mMessageQueue;
+    LLThreadSafeQueue<std::function<void()>> mFunctionQueue;
+
+    bool mFinished = false;
+
+    LLWindowWin32Thread(LLWindowWin32* window);
+
+    void run() override;
+
+    void post(const std::function<void()>& func);
+
+private:
+
+    // call PeekMessage and pull enqueue messages for later processing
+    void gatherInput();
+    LLWindowWin32* mWindow = nullptr;
+
+};
+
 class LLWindowWin32 : public LLWindow
 {
 public:
@@ -59,7 +94,10 @@ class LLWindowWin32 : public LLWindow
 	/*virtual*/ BOOL setSizeImpl(LLCoordWindow size);
 	/*virtual*/ BOOL switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL disable_vsync, const LLCoordScreen * const posp = NULL);
     /*virtual*/ void setTitle(const std::string title);
-    /*virtual*/ BOOL setCursorPosition(LLCoordWindow position);
+    void* createSharedContext() override;
+    void makeContextCurrent(void* context) override;
+    void destroySharedContext(void* context) override;
+	/*virtual*/ BOOL setCursorPosition(LLCoordWindow position);
 	/*virtual*/ BOOL getCursorPosition(LLCoordWindow *position);
 	/*virtual*/ void showCursor();
 	/*virtual*/ void hideCursor();
@@ -173,9 +211,9 @@ 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()
@@ -222,7 +260,12 @@ class LLWindowWin32 : public LLWindow
 
 	BOOL			mMouseVanish;
 
+    LLWindowWin32Thread* mWindowThread = nullptr;
+    LLThreadSafeQueue<std::function<void()>> mFunctionQueue;
+    void post(const std::function<void()>& func);
+
 	friend class LLWindowManager;
+    friend class LLWindowWin32Thread;
 };
 
 class LLSplashScreenWin32 : public LLSplashScreen
diff --git a/indra/llxml/llcontrol.h b/indra/llxml/llcontrol.h
index 19508becc30b4392bcdd38c5ca94d8e24e697ae7..5da13f5010bd1cbe28f950b221946cd49ea2995a 100644
--- a/indra/llxml/llcontrol.h
+++ b/indra/llxml/llcontrol.h
@@ -405,8 +405,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 +415,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/CMakeLists.txt b/indra/mac_crash_logger/CMakeLists.txt
deleted file mode 100644
index 95637c9a282bbdb9f08ef7cb97afd2e3edfcd672..0000000000000000000000000000000000000000
--- a/indra/mac_crash_logger/CMakeLists.txt
+++ /dev/null
@@ -1,95 +0,0 @@
-# -*- cmake -*-
-
-project(mac_crash_logger)
-
-include(00-Common)
-include(LLCommon)
-include(LLCoreHttp)
-include(LLCrashLogger)
-include(LLMath)
-include(LLMessage)
-include(LLVFS)
-include(LLXML)
-include(Linking)
-include(LLSharedLibs)
-include(Boost)
-
-include_directories(
-    ${LLCOREHTTP_INCLUDE_DIRS}
-    ${LLCOMMON_INCLUDE_DIRS}
-    ${LLCRASHLOGGER_INCLUDE_DIRS}
-    ${LLMATH_INCLUDE_DIRS}
-    ${LLVFS_INCLUDE_DIRS}
-    ${LLXML_INCLUDE_DIRS}
-    )
-include_directories(SYSTEM
-    ${LLCOMMON_SYSTEM_INCLUDE_DIRS}
-    ${LLXML_SYSTEM_INCLUDE_DIRS}
-    )
-
-set(mac_crash_logger_SOURCE_FILES
-    mac_crash_logger.cpp
-    llcrashloggermac.cpp
-    llcrashloggermacdelegate.mm
-    )
-
-set(mac_crash_logger_HEADER_FILES
-    CMakeLists.txt
-
-    llcrashloggermac.h
-    llcrashloggermacdelegate.h
-    )
-
-set_source_files_properties(${mac_crash_logger_HEADER_FILES}
-                            PROPERTIES HEADER_FILE_ONLY TRUE)
-list(APPEND mac_crash_logger_SOURCE_FILES ${mac_crash_logger_HEADER_FILES})
-
-set(mac_crash_logger_RESOURCE_FILES
-  CrashReporter.nib/
-  )
-set_source_files_properties(
-  ${mac_crash_logger_RESOURCE_FILES}
-  PROPERTIES
-  HEADER_FILE_ONLY TRUE
-  )
-SOURCE_GROUP("Resources" FILES ${mac_crash_logger_RESOURCE_FILES})
-list(APPEND mac_crash_logger_SOURCE_FILES ${mac_crash_logger_RESOURCE_FILES})
-
-add_executable(mac-crash-logger
-  MACOSX_BUNDLE
-  ${mac_crash_logger_SOURCE_FILES})
-
-set_target_properties(mac-crash-logger
-  PROPERTIES
-  MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist
-  )
-
-find_library(COCOA_LIBRARY Cocoa)
-
-target_link_libraries(mac-crash-logger
-    ${LLCRASHLOGGER_LIBRARIES}
-    ${LLVFS_LIBRARIES}
-    ${COCOA_LIBRARIES}
-    ${LLXML_LIBRARIES}
-    ${LLMESSAGE_LIBRARIES}
-    ${LLVFS_LIBRARIES}
-    ${LLMATH_LIBRARIES}
-    ${LLCOREHTTP_LIBRARIES}
-    ${LLCOMMON_LIBRARIES}
-    ${BOOST_CONTEXT_LIBRARY}
-    ${BOOST_FIBER_LIBRARY}
-    )
-
-add_custom_command(
-  TARGET mac-crash-logger POST_BUILD
-  COMMAND ${CMAKE_COMMAND}
-  ARGS
-    -E
-    copy_if_different
-    ${CMAKE_CURRENT_SOURCE_DIR}/CrashReporter.nib
-    ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/mac-crash-logger.app/Contents/Resources/CrashReporter.nib
-  )
-
-ll_deploy_sharedlibs_command(mac-crash-logger)
-
-
diff --git a/indra/mac_crash_logger/CrashReporter.nib b/indra/mac_crash_logger/CrashReporter.nib
deleted file mode 100755
index e9d9e059855078b54b9d1d3c382f7f241cab9e27..0000000000000000000000000000000000000000
Binary files a/indra/mac_crash_logger/CrashReporter.nib and /dev/null differ
diff --git a/indra/mac_crash_logger/CrashReporter.xib b/indra/mac_crash_logger/CrashReporter.xib
deleted file mode 100755
index f6d4776d51c742921e59b3b7a1d4ed891261a2bf..0000000000000000000000000000000000000000
--- a/indra/mac_crash_logger/CrashReporter.xib
+++ /dev/null
@@ -1,3895 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<archive type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="8.00">
-	<data>
-		<int key="IBDocument.SystemTarget">1070</int>
-		<string key="IBDocument.SystemVersion">11G63</string>
-		<string key="IBDocument.InterfaceBuilderVersion">2182</string>
-		<string key="IBDocument.AppKitVersion">1138.51</string>
-		<string key="IBDocument.HIToolboxVersion">569.00</string>
-		<object class="NSMutableDictionary" key="IBDocument.PluginVersions">
-			<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin</string>
-			<string key="NS.object.0">2182</string>
-		</object>
-		<array key="IBDocument.IntegratedClassDependencies">
-			<string>NSTextField</string>
-			<string>NSView</string>
-			<string>NSWindowTemplate</string>
-			<string>NSMenu</string>
-			<string>NSMenuItem</string>
-			<string>NSTextFieldCell</string>
-			<string>NSButtonCell</string>
-			<string>IBNSLayoutConstraint</string>
-			<string>NSButton</string>
-			<string>NSCustomObject</string>
-		</array>
-		<array key="IBDocument.PluginDependencies">
-			<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
-		</array>
-		<object class="NSMutableDictionary" key="IBDocument.Metadata">
-			<string key="NS.key.0">PluginDependencyRecalculationVersion</string>
-			<integer value="1" key="NS.object.0"/>
-		</object>
-		<array class="NSMutableArray" key="IBDocument.RootObjects" id="1048">
-			<object class="NSCustomObject" id="1021">
-				<string key="NSClassName">NSApplication</string>
-			</object>
-			<object class="NSCustomObject" id="1014">
-				<string key="NSClassName">FirstResponder</string>
-			</object>
-			<object class="NSCustomObject" id="1050">
-				<string key="NSClassName">NSApplication</string>
-			</object>
-			<object class="NSMenu" id="649796088">
-				<string key="NSTitle">AMainMenu</string>
-				<array class="NSMutableArray" key="NSMenuItems">
-					<object class="NSMenuItem" id="694149608">
-						<reference key="NSMenu" ref="649796088"/>
-						<string key="NSTitle">Second Life Crash Logger</string>
-						<string key="NSKeyEquiv"/>
-						<int key="NSKeyEquivModMask">1048576</int>
-						<int key="NSMnemonicLoc">2147483647</int>
-						<object class="NSCustomResource" key="NSOnImage" id="35465992">
-							<string key="NSClassName">NSImage</string>
-							<string key="NSResourceName">NSMenuCheckmark</string>
-						</object>
-						<object class="NSCustomResource" key="NSMixedImage" id="502551668">
-							<string key="NSClassName">NSImage</string>
-							<string key="NSResourceName">NSMenuMixedState</string>
-						</object>
-						<string key="NSAction">submenuAction:</string>
-						<object class="NSMenu" key="NSSubmenu" id="110575045">
-							<string key="NSTitle">Second Life Crash Logger</string>
-							<array class="NSMutableArray" key="NSMenuItems">
-								<object class="NSMenuItem" id="238522557">
-									<reference key="NSMenu" ref="110575045"/>
-									<string key="NSTitle">About Second Life Crash Logger</string>
-									<string key="NSKeyEquiv"/>
-									<int key="NSMnemonicLoc">2147483647</int>
-									<reference key="NSOnImage" ref="35465992"/>
-									<reference key="NSMixedImage" ref="502551668"/>
-								</object>
-								<object class="NSMenuItem" id="304266470">
-									<reference key="NSMenu" ref="110575045"/>
-									<bool key="NSIsDisabled">YES</bool>
-									<bool key="NSIsSeparator">YES</bool>
-									<string key="NSTitle"/>
-									<string key="NSKeyEquiv"/>
-									<int key="NSKeyEquivModMask">1048576</int>
-									<int key="NSMnemonicLoc">2147483647</int>
-									<reference key="NSOnImage" ref="35465992"/>
-									<reference key="NSMixedImage" ref="502551668"/>
-								</object>
-								<object class="NSMenuItem" id="609285721">
-									<reference key="NSMenu" ref="110575045"/>
-									<string key="NSTitle">Preferences…</string>
-									<string key="NSKeyEquiv">,</string>
-									<int key="NSKeyEquivModMask">1048576</int>
-									<int key="NSMnemonicLoc">2147483647</int>
-									<reference key="NSOnImage" ref="35465992"/>
-									<reference key="NSMixedImage" ref="502551668"/>
-								</object>
-								<object class="NSMenuItem" id="481834944">
-									<reference key="NSMenu" ref="110575045"/>
-									<bool key="NSIsDisabled">YES</bool>
-									<bool key="NSIsSeparator">YES</bool>
-									<string key="NSTitle"/>
-									<string key="NSKeyEquiv"/>
-									<int key="NSKeyEquivModMask">1048576</int>
-									<int key="NSMnemonicLoc">2147483647</int>
-									<reference key="NSOnImage" ref="35465992"/>
-									<reference key="NSMixedImage" ref="502551668"/>
-								</object>
-								<object class="NSMenuItem" id="1046388886">
-									<reference key="NSMenu" ref="110575045"/>
-									<string key="NSTitle">Services</string>
-									<string key="NSKeyEquiv"/>
-									<int key="NSKeyEquivModMask">1048576</int>
-									<int key="NSMnemonicLoc">2147483647</int>
-									<reference key="NSOnImage" ref="35465992"/>
-									<reference key="NSMixedImage" ref="502551668"/>
-									<string key="NSAction">submenuAction:</string>
-									<object class="NSMenu" key="NSSubmenu" id="752062318">
-										<string key="NSTitle">Services</string>
-										<array class="NSMutableArray" key="NSMenuItems"/>
-										<string key="NSName">_NSServicesMenu</string>
-									</object>
-								</object>
-								<object class="NSMenuItem" id="646227648">
-									<reference key="NSMenu" ref="110575045"/>
-									<bool key="NSIsDisabled">YES</bool>
-									<bool key="NSIsSeparator">YES</bool>
-									<string key="NSTitle"/>
-									<string key="NSKeyEquiv"/>
-									<int key="NSKeyEquivModMask">1048576</int>
-									<int key="NSMnemonicLoc">2147483647</int>
-									<reference key="NSOnImage" ref="35465992"/>
-									<reference key="NSMixedImage" ref="502551668"/>
-								</object>
-								<object class="NSMenuItem" id="755159360">
-									<reference key="NSMenu" ref="110575045"/>
-									<string key="NSTitle">Hide Second Life Crash Logger</string>
-									<string key="NSKeyEquiv">h</string>
-									<int key="NSKeyEquivModMask">1048576</int>
-									<int key="NSMnemonicLoc">2147483647</int>
-									<reference key="NSOnImage" ref="35465992"/>
-									<reference key="NSMixedImage" ref="502551668"/>
-								</object>
-								<object class="NSMenuItem" id="342932134">
-									<reference key="NSMenu" ref="110575045"/>
-									<string key="NSTitle">Hide Others</string>
-									<string key="NSKeyEquiv">h</string>
-									<int key="NSKeyEquivModMask">1572864</int>
-									<int key="NSMnemonicLoc">2147483647</int>
-									<reference key="NSOnImage" ref="35465992"/>
-									<reference key="NSMixedImage" ref="502551668"/>
-								</object>
-								<object class="NSMenuItem" id="908899353">
-									<reference key="NSMenu" ref="110575045"/>
-									<string key="NSTitle">Show All</string>
-									<string key="NSKeyEquiv"/>
-									<int key="NSKeyEquivModMask">1048576</int>
-									<int key="NSMnemonicLoc">2147483647</int>
-									<reference key="NSOnImage" ref="35465992"/>
-									<reference key="NSMixedImage" ref="502551668"/>
-								</object>
-								<object class="NSMenuItem" id="1056857174">
-									<reference key="NSMenu" ref="110575045"/>
-									<bool key="NSIsDisabled">YES</bool>
-									<bool key="NSIsSeparator">YES</bool>
-									<string key="NSTitle"/>
-									<string key="NSKeyEquiv"/>
-									<int key="NSKeyEquivModMask">1048576</int>
-									<int key="NSMnemonicLoc">2147483647</int>
-									<reference key="NSOnImage" ref="35465992"/>
-									<reference key="NSMixedImage" ref="502551668"/>
-								</object>
-								<object class="NSMenuItem" id="632727374">
-									<reference key="NSMenu" ref="110575045"/>
-									<string key="NSTitle">Quit Second Life Crash Logger</string>
-									<string key="NSKeyEquiv">q</string>
-									<int key="NSKeyEquivModMask">1048576</int>
-									<int key="NSMnemonicLoc">2147483647</int>
-									<reference key="NSOnImage" ref="35465992"/>
-									<reference key="NSMixedImage" ref="502551668"/>
-								</object>
-							</array>
-							<string key="NSName">_NSAppleMenu</string>
-						</object>
-					</object>
-					<object class="NSMenuItem" id="379814623">
-						<reference key="NSMenu" ref="649796088"/>
-						<string key="NSTitle">File</string>
-						<string key="NSKeyEquiv"/>
-						<int key="NSKeyEquivModMask">1048576</int>
-						<int key="NSMnemonicLoc">2147483647</int>
-						<reference key="NSOnImage" ref="35465992"/>
-						<reference key="NSMixedImage" ref="502551668"/>
-						<string key="NSAction">submenuAction:</string>
-						<object class="NSMenu" key="NSSubmenu" id="720053764">
-							<string key="NSTitle">File</string>
-							<array class="NSMutableArray" key="NSMenuItems">
-								<object class="NSMenuItem" id="705341025">
-									<reference key="NSMenu" ref="720053764"/>
-									<string key="NSTitle">New</string>
-									<string key="NSKeyEquiv">n</string>
-									<int key="NSKeyEquivModMask">1048576</int>
-									<int key="NSMnemonicLoc">2147483647</int>
-									<reference key="NSOnImage" ref="35465992"/>
-									<reference key="NSMixedImage" ref="502551668"/>
-								</object>
-								<object class="NSMenuItem" id="722745758">
-									<reference key="NSMenu" ref="720053764"/>
-									<string key="NSTitle">Open…</string>
-									<string key="NSKeyEquiv">o</string>
-									<int key="NSKeyEquivModMask">1048576</int>
-									<int key="NSMnemonicLoc">2147483647</int>
-									<reference key="NSOnImage" ref="35465992"/>
-									<reference key="NSMixedImage" ref="502551668"/>
-								</object>
-								<object class="NSMenuItem" id="1025936716">
-									<reference key="NSMenu" ref="720053764"/>
-									<string key="NSTitle">Open Recent</string>
-									<string key="NSKeyEquiv"/>
-									<int key="NSKeyEquivModMask">1048576</int>
-									<int key="NSMnemonicLoc">2147483647</int>
-									<reference key="NSOnImage" ref="35465992"/>
-									<reference key="NSMixedImage" ref="502551668"/>
-									<string key="NSAction">submenuAction:</string>
-									<object class="NSMenu" key="NSSubmenu" id="1065607017">
-										<string key="NSTitle">Open Recent</string>
-										<array class="NSMutableArray" key="NSMenuItems">
-											<object class="NSMenuItem" id="759406840">
-												<reference key="NSMenu" ref="1065607017"/>
-												<string key="NSTitle">Clear Menu</string>
-												<string key="NSKeyEquiv"/>
-												<int key="NSKeyEquivModMask">1048576</int>
-												<int key="NSMnemonicLoc">2147483647</int>
-												<reference key="NSOnImage" ref="35465992"/>
-												<reference key="NSMixedImage" ref="502551668"/>
-											</object>
-										</array>
-										<string key="NSName">_NSRecentDocumentsMenu</string>
-									</object>
-								</object>
-								<object class="NSMenuItem" id="425164168">
-									<reference key="NSMenu" ref="720053764"/>
-									<bool key="NSIsDisabled">YES</bool>
-									<bool key="NSIsSeparator">YES</bool>
-									<string key="NSTitle"/>
-									<string key="NSKeyEquiv"/>
-									<int key="NSKeyEquivModMask">1048576</int>
-									<int key="NSMnemonicLoc">2147483647</int>
-									<reference key="NSOnImage" ref="35465992"/>
-									<reference key="NSMixedImage" ref="502551668"/>
-								</object>
-								<object class="NSMenuItem" id="776162233">
-									<reference key="NSMenu" ref="720053764"/>
-									<string key="NSTitle">Close</string>
-									<string key="NSKeyEquiv">w</string>
-									<int key="NSKeyEquivModMask">1048576</int>
-									<int key="NSMnemonicLoc">2147483647</int>
-									<reference key="NSOnImage" ref="35465992"/>
-									<reference key="NSMixedImage" ref="502551668"/>
-								</object>
-								<object class="NSMenuItem" id="1023925487">
-									<reference key="NSMenu" ref="720053764"/>
-									<string key="NSTitle">Save…</string>
-									<string key="NSKeyEquiv">s</string>
-									<int key="NSKeyEquivModMask">1048576</int>
-									<int key="NSMnemonicLoc">2147483647</int>
-									<reference key="NSOnImage" ref="35465992"/>
-									<reference key="NSMixedImage" ref="502551668"/>
-								</object>
-								<object class="NSMenuItem" id="579971712">
-									<reference key="NSMenu" ref="720053764"/>
-									<string key="NSTitle">Revert to Saved</string>
-									<string key="NSKeyEquiv"/>
-									<int key="NSMnemonicLoc">2147483647</int>
-									<reference key="NSOnImage" ref="35465992"/>
-									<reference key="NSMixedImage" ref="502551668"/>
-								</object>
-								<object class="NSMenuItem" id="1010469920">
-									<reference key="NSMenu" ref="720053764"/>
-									<bool key="NSIsDisabled">YES</bool>
-									<bool key="NSIsSeparator">YES</bool>
-									<string key="NSTitle"/>
-									<string key="NSKeyEquiv"/>
-									<int key="NSKeyEquivModMask">1048576</int>
-									<int key="NSMnemonicLoc">2147483647</int>
-									<reference key="NSOnImage" ref="35465992"/>
-									<reference key="NSMixedImage" ref="502551668"/>
-								</object>
-								<object class="NSMenuItem" id="294629803">
-									<reference key="NSMenu" ref="720053764"/>
-									<string key="NSTitle">Page Setup...</string>
-									<string key="NSKeyEquiv">P</string>
-									<int key="NSKeyEquivModMask">1179648</int>
-									<int key="NSMnemonicLoc">2147483647</int>
-									<reference key="NSOnImage" ref="35465992"/>
-									<reference key="NSMixedImage" ref="502551668"/>
-									<string key="NSToolTip"/>
-								</object>
-								<object class="NSMenuItem" id="49223823">
-									<reference key="NSMenu" ref="720053764"/>
-									<string key="NSTitle">Print…</string>
-									<string key="NSKeyEquiv">p</string>
-									<int key="NSKeyEquivModMask">1048576</int>
-									<int key="NSMnemonicLoc">2147483647</int>
-									<reference key="NSOnImage" ref="35465992"/>
-									<reference key="NSMixedImage" ref="502551668"/>
-								</object>
-							</array>
-						</object>
-					</object>
-					<object class="NSMenuItem" id="952259628">
-						<reference key="NSMenu" ref="649796088"/>
-						<string key="NSTitle">Edit</string>
-						<string key="NSKeyEquiv"/>
-						<int key="NSKeyEquivModMask">1048576</int>
-						<int key="NSMnemonicLoc">2147483647</int>
-						<reference key="NSOnImage" ref="35465992"/>
-						<reference key="NSMixedImage" ref="502551668"/>
-						<string key="NSAction">submenuAction:</string>
-						<object class="NSMenu" key="NSSubmenu" id="789758025">
-							<string key="NSTitle">Edit</string>
-							<array class="NSMutableArray" key="NSMenuItems">
-								<object class="NSMenuItem" id="1058277027">
-									<reference key="NSMenu" ref="789758025"/>
-									<string key="NSTitle">Undo</string>
-									<string key="NSKeyEquiv">z</string>
-									<int key="NSKeyEquivModMask">1048576</int>
-									<int key="NSMnemonicLoc">2147483647</int>
-									<reference key="NSOnImage" ref="35465992"/>
-									<reference key="NSMixedImage" ref="502551668"/>
-								</object>
-								<object class="NSMenuItem" id="790794224">
-									<reference key="NSMenu" ref="789758025"/>
-									<string key="NSTitle">Redo</string>
-									<string key="NSKeyEquiv">Z</string>
-									<int key="NSKeyEquivModMask">1179648</int>
-									<int key="NSMnemonicLoc">2147483647</int>
-									<reference key="NSOnImage" ref="35465992"/>
-									<reference key="NSMixedImage" ref="502551668"/>
-								</object>
-								<object class="NSMenuItem" id="1040322652">
-									<reference key="NSMenu" ref="789758025"/>
-									<bool key="NSIsDisabled">YES</bool>
-									<bool key="NSIsSeparator">YES</bool>
-									<string key="NSTitle"/>
-									<string key="NSKeyEquiv"/>
-									<int key="NSKeyEquivModMask">1048576</int>
-									<int key="NSMnemonicLoc">2147483647</int>
-									<reference key="NSOnImage" ref="35465992"/>
-									<reference key="NSMixedImage" ref="502551668"/>
-								</object>
-								<object class="NSMenuItem" id="296257095">
-									<reference key="NSMenu" ref="789758025"/>
-									<string key="NSTitle">Cut</string>
-									<string key="NSKeyEquiv">x</string>
-									<int key="NSKeyEquivModMask">1048576</int>
-									<int key="NSMnemonicLoc">2147483647</int>
-									<reference key="NSOnImage" ref="35465992"/>
-									<reference key="NSMixedImage" ref="502551668"/>
-								</object>
-								<object class="NSMenuItem" id="860595796">
-									<reference key="NSMenu" ref="789758025"/>
-									<string key="NSTitle">Copy</string>
-									<string key="NSKeyEquiv">c</string>
-									<int key="NSKeyEquivModMask">1048576</int>
-									<int key="NSMnemonicLoc">2147483647</int>
-									<reference key="NSOnImage" ref="35465992"/>
-									<reference key="NSMixedImage" ref="502551668"/>
-								</object>
-								<object class="NSMenuItem" id="29853731">
-									<reference key="NSMenu" ref="789758025"/>
-									<string key="NSTitle">Paste</string>
-									<string key="NSKeyEquiv">v</string>
-									<int key="NSKeyEquivModMask">1048576</int>
-									<int key="NSMnemonicLoc">2147483647</int>
-									<reference key="NSOnImage" ref="35465992"/>
-									<reference key="NSMixedImage" ref="502551668"/>
-								</object>
-								<object class="NSMenuItem" id="82994268">
-									<reference key="NSMenu" ref="789758025"/>
-									<string key="NSTitle">Paste and Match Style</string>
-									<string key="NSKeyEquiv">V</string>
-									<int key="NSKeyEquivModMask">1572864</int>
-									<int key="NSMnemonicLoc">2147483647</int>
-									<reference key="NSOnImage" ref="35465992"/>
-									<reference key="NSMixedImage" ref="502551668"/>
-								</object>
-								<object class="NSMenuItem" id="437104165">
-									<reference key="NSMenu" ref="789758025"/>
-									<string key="NSTitle">Delete</string>
-									<string key="NSKeyEquiv"/>
-									<int key="NSKeyEquivModMask">1048576</int>
-									<int key="NSMnemonicLoc">2147483647</int>
-									<reference key="NSOnImage" ref="35465992"/>
-									<reference key="NSMixedImage" ref="502551668"/>
-								</object>
-								<object class="NSMenuItem" id="583158037">
-									<reference key="NSMenu" ref="789758025"/>
-									<string key="NSTitle">Select All</string>
-									<string key="NSKeyEquiv">a</string>
-									<int key="NSKeyEquivModMask">1048576</int>
-									<int key="NSMnemonicLoc">2147483647</int>
-									<reference key="NSOnImage" ref="35465992"/>
-									<reference key="NSMixedImage" ref="502551668"/>
-								</object>
-								<object class="NSMenuItem" id="212016141">
-									<reference key="NSMenu" ref="789758025"/>
-									<bool key="NSIsDisabled">YES</bool>
-									<bool key="NSIsSeparator">YES</bool>
-									<string key="NSTitle"/>
-									<string key="NSKeyEquiv"/>
-									<int key="NSKeyEquivModMask">1048576</int>
-									<int key="NSMnemonicLoc">2147483647</int>
-									<reference key="NSOnImage" ref="35465992"/>
-									<reference key="NSMixedImage" ref="502551668"/>
-								</object>
-								<object class="NSMenuItem" id="892235320">
-									<reference key="NSMenu" ref="789758025"/>
-									<string key="NSTitle">Find</string>
-									<string key="NSKeyEquiv"/>
-									<int key="NSKeyEquivModMask">1048576</int>
-									<int key="NSMnemonicLoc">2147483647</int>
-									<reference key="NSOnImage" ref="35465992"/>
-									<reference key="NSMixedImage" ref="502551668"/>
-									<string key="NSAction">submenuAction:</string>
-									<object class="NSMenu" key="NSSubmenu" id="963351320">
-										<string key="NSTitle">Find</string>
-										<array class="NSMutableArray" key="NSMenuItems">
-											<object class="NSMenuItem" id="447796847">
-												<reference key="NSMenu" ref="963351320"/>
-												<string key="NSTitle">Find…</string>
-												<string key="NSKeyEquiv">f</string>
-												<int key="NSKeyEquivModMask">1048576</int>
-												<int key="NSMnemonicLoc">2147483647</int>
-												<reference key="NSOnImage" ref="35465992"/>
-												<reference key="NSMixedImage" ref="502551668"/>
-												<int key="NSTag">1</int>
-											</object>
-											<object class="NSMenuItem" id="738670835">
-												<reference key="NSMenu" ref="963351320"/>
-												<string key="NSTitle">Find and Replace…</string>
-												<string key="NSKeyEquiv">f</string>
-												<int key="NSKeyEquivModMask">1572864</int>
-												<int key="NSMnemonicLoc">2147483647</int>
-												<reference key="NSOnImage" ref="35465992"/>
-												<reference key="NSMixedImage" ref="502551668"/>
-												<int key="NSTag">12</int>
-											</object>
-											<object class="NSMenuItem" id="326711663">
-												<reference key="NSMenu" ref="963351320"/>
-												<string key="NSTitle">Find Next</string>
-												<string key="NSKeyEquiv">g</string>
-												<int key="NSKeyEquivModMask">1048576</int>
-												<int key="NSMnemonicLoc">2147483647</int>
-												<reference key="NSOnImage" ref="35465992"/>
-												<reference key="NSMixedImage" ref="502551668"/>
-												<int key="NSTag">2</int>
-											</object>
-											<object class="NSMenuItem" id="270902937">
-												<reference key="NSMenu" ref="963351320"/>
-												<string key="NSTitle">Find Previous</string>
-												<string key="NSKeyEquiv">G</string>
-												<int key="NSKeyEquivModMask">1179648</int>
-												<int key="NSMnemonicLoc">2147483647</int>
-												<reference key="NSOnImage" ref="35465992"/>
-												<reference key="NSMixedImage" ref="502551668"/>
-												<int key="NSTag">3</int>
-											</object>
-											<object class="NSMenuItem" id="159080638">
-												<reference key="NSMenu" ref="963351320"/>
-												<string key="NSTitle">Use Selection for Find</string>
-												<string key="NSKeyEquiv">e</string>
-												<int key="NSKeyEquivModMask">1048576</int>
-												<int key="NSMnemonicLoc">2147483647</int>
-												<reference key="NSOnImage" ref="35465992"/>
-												<reference key="NSMixedImage" ref="502551668"/>
-												<int key="NSTag">7</int>
-											</object>
-											<object class="NSMenuItem" id="88285865">
-												<reference key="NSMenu" ref="963351320"/>
-												<string key="NSTitle">Jump to Selection</string>
-												<string key="NSKeyEquiv">j</string>
-												<int key="NSKeyEquivModMask">1048576</int>
-												<int key="NSMnemonicLoc">2147483647</int>
-												<reference key="NSOnImage" ref="35465992"/>
-												<reference key="NSMixedImage" ref="502551668"/>
-											</object>
-										</array>
-									</object>
-								</object>
-								<object class="NSMenuItem" id="972420730">
-									<reference key="NSMenu" ref="789758025"/>
-									<string key="NSTitle">Spelling and Grammar</string>
-									<string key="NSKeyEquiv"/>
-									<int key="NSKeyEquivModMask">1048576</int>
-									<int key="NSMnemonicLoc">2147483647</int>
-									<reference key="NSOnImage" ref="35465992"/>
-									<reference key="NSMixedImage" ref="502551668"/>
-									<string key="NSAction">submenuAction:</string>
-									<object class="NSMenu" key="NSSubmenu" id="769623530">
-										<string key="NSTitle">Spelling and Grammar</string>
-										<array class="NSMutableArray" key="NSMenuItems">
-											<object class="NSMenuItem" id="679648819">
-												<reference key="NSMenu" ref="769623530"/>
-												<string key="NSTitle">Show Spelling and Grammar</string>
-												<string key="NSKeyEquiv">:</string>
-												<int key="NSKeyEquivModMask">1048576</int>
-												<int key="NSMnemonicLoc">2147483647</int>
-												<reference key="NSOnImage" ref="35465992"/>
-												<reference key="NSMixedImage" ref="502551668"/>
-											</object>
-											<object class="NSMenuItem" id="96193923">
-												<reference key="NSMenu" ref="769623530"/>
-												<string key="NSTitle">Check Document Now</string>
-												<string key="NSKeyEquiv">;</string>
-												<int key="NSKeyEquivModMask">1048576</int>
-												<int key="NSMnemonicLoc">2147483647</int>
-												<reference key="NSOnImage" ref="35465992"/>
-												<reference key="NSMixedImage" ref="502551668"/>
-											</object>
-											<object class="NSMenuItem" id="859480356">
-												<reference key="NSMenu" ref="769623530"/>
-												<bool key="NSIsDisabled">YES</bool>
-												<bool key="NSIsSeparator">YES</bool>
-												<string key="NSTitle"/>
-												<string key="NSKeyEquiv"/>
-												<int key="NSMnemonicLoc">2147483647</int>
-												<reference key="NSOnImage" ref="35465992"/>
-												<reference key="NSMixedImage" ref="502551668"/>
-											</object>
-											<object class="NSMenuItem" id="948374510">
-												<reference key="NSMenu" ref="769623530"/>
-												<string key="NSTitle">Check Spelling While Typing</string>
-												<string key="NSKeyEquiv"/>
-												<int key="NSKeyEquivModMask">1048576</int>
-												<int key="NSMnemonicLoc">2147483647</int>
-												<reference key="NSOnImage" ref="35465992"/>
-												<reference key="NSMixedImage" ref="502551668"/>
-											</object>
-											<object class="NSMenuItem" id="967646866">
-												<reference key="NSMenu" ref="769623530"/>
-												<string key="NSTitle">Check Grammar With Spelling</string>
-												<string key="NSKeyEquiv"/>
-												<int key="NSKeyEquivModMask">1048576</int>
-												<int key="NSMnemonicLoc">2147483647</int>
-												<reference key="NSOnImage" ref="35465992"/>
-												<reference key="NSMixedImage" ref="502551668"/>
-											</object>
-											<object class="NSMenuItem" id="795346622">
-												<reference key="NSMenu" ref="769623530"/>
-												<string key="NSTitle">Correct Spelling Automatically</string>
-												<string key="NSKeyEquiv"/>
-												<int key="NSMnemonicLoc">2147483647</int>
-												<reference key="NSOnImage" ref="35465992"/>
-												<reference key="NSMixedImage" ref="502551668"/>
-											</object>
-										</array>
-									</object>
-								</object>
-								<object class="NSMenuItem" id="507821607">
-									<reference key="NSMenu" ref="789758025"/>
-									<string key="NSTitle">Substitutions</string>
-									<string key="NSKeyEquiv"/>
-									<int key="NSKeyEquivModMask">1048576</int>
-									<int key="NSMnemonicLoc">2147483647</int>
-									<reference key="NSOnImage" ref="35465992"/>
-									<reference key="NSMixedImage" ref="502551668"/>
-									<string key="NSAction">submenuAction:</string>
-									<object class="NSMenu" key="NSSubmenu" id="698887838">
-										<string key="NSTitle">Substitutions</string>
-										<array class="NSMutableArray" key="NSMenuItems">
-											<object class="NSMenuItem" id="65139061">
-												<reference key="NSMenu" ref="698887838"/>
-												<string key="NSTitle">Show Substitutions</string>
-												<string key="NSKeyEquiv"/>
-												<int key="NSMnemonicLoc">2147483647</int>
-												<reference key="NSOnImage" ref="35465992"/>
-												<reference key="NSMixedImage" ref="502551668"/>
-											</object>
-											<object class="NSMenuItem" id="19036812">
-												<reference key="NSMenu" ref="698887838"/>
-												<bool key="NSIsDisabled">YES</bool>
-												<bool key="NSIsSeparator">YES</bool>
-												<string key="NSTitle"/>
-												<string key="NSKeyEquiv"/>
-												<int key="NSMnemonicLoc">2147483647</int>
-												<reference key="NSOnImage" ref="35465992"/>
-												<reference key="NSMixedImage" ref="502551668"/>
-											</object>
-											<object class="NSMenuItem" id="605118523">
-												<reference key="NSMenu" ref="698887838"/>
-												<string key="NSTitle">Smart Copy/Paste</string>
-												<string key="NSKeyEquiv">f</string>
-												<int key="NSKeyEquivModMask">1048576</int>
-												<int key="NSMnemonicLoc">2147483647</int>
-												<reference key="NSOnImage" ref="35465992"/>
-												<reference key="NSMixedImage" ref="502551668"/>
-												<int key="NSTag">1</int>
-											</object>
-											<object class="NSMenuItem" id="197661976">
-												<reference key="NSMenu" ref="698887838"/>
-												<string key="NSTitle">Smart Quotes</string>
-												<string key="NSKeyEquiv">g</string>
-												<int key="NSKeyEquivModMask">1048576</int>
-												<int key="NSMnemonicLoc">2147483647</int>
-												<reference key="NSOnImage" ref="35465992"/>
-												<reference key="NSMixedImage" ref="502551668"/>
-												<int key="NSTag">2</int>
-											</object>
-											<object class="NSMenuItem" id="672708820">
-												<reference key="NSMenu" ref="698887838"/>
-												<string key="NSTitle">Smart Dashes</string>
-												<string key="NSKeyEquiv"/>
-												<int key="NSMnemonicLoc">2147483647</int>
-												<reference key="NSOnImage" ref="35465992"/>
-												<reference key="NSMixedImage" ref="502551668"/>
-											</object>
-											<object class="NSMenuItem" id="708854459">
-												<reference key="NSMenu" ref="698887838"/>
-												<string key="NSTitle">Smart Links</string>
-												<string key="NSKeyEquiv">G</string>
-												<int key="NSKeyEquivModMask">1179648</int>
-												<int key="NSMnemonicLoc">2147483647</int>
-												<reference key="NSOnImage" ref="35465992"/>
-												<reference key="NSMixedImage" ref="502551668"/>
-												<int key="NSTag">3</int>
-											</object>
-											<object class="NSMenuItem" id="537092702">
-												<reference key="NSMenu" ref="698887838"/>
-												<string key="NSTitle">Text Replacement</string>
-												<string key="NSKeyEquiv"/>
-												<int key="NSMnemonicLoc">2147483647</int>
-												<reference key="NSOnImage" ref="35465992"/>
-												<reference key="NSMixedImage" ref="502551668"/>
-											</object>
-										</array>
-									</object>
-								</object>
-								<object class="NSMenuItem" id="288088188">
-									<reference key="NSMenu" ref="789758025"/>
-									<string key="NSTitle">Transformations</string>
-									<string key="NSKeyEquiv"/>
-									<int key="NSMnemonicLoc">2147483647</int>
-									<reference key="NSOnImage" ref="35465992"/>
-									<reference key="NSMixedImage" ref="502551668"/>
-									<string key="NSAction">submenuAction:</string>
-									<object class="NSMenu" key="NSSubmenu" id="579392910">
-										<string key="NSTitle">Transformations</string>
-										<array class="NSMutableArray" key="NSMenuItems">
-											<object class="NSMenuItem" id="1060694897">
-												<reference key="NSMenu" ref="579392910"/>
-												<string key="NSTitle">Make Upper Case</string>
-												<string key="NSKeyEquiv"/>
-												<int key="NSMnemonicLoc">2147483647</int>
-												<reference key="NSOnImage" ref="35465992"/>
-												<reference key="NSMixedImage" ref="502551668"/>
-											</object>
-											<object class="NSMenuItem" id="879586729">
-												<reference key="NSMenu" ref="579392910"/>
-												<string key="NSTitle">Make Lower Case</string>
-												<string key="NSKeyEquiv"/>
-												<int key="NSMnemonicLoc">2147483647</int>
-												<reference key="NSOnImage" ref="35465992"/>
-												<reference key="NSMixedImage" ref="502551668"/>
-											</object>
-											<object class="NSMenuItem" id="56570060">
-												<reference key="NSMenu" ref="579392910"/>
-												<string key="NSTitle">Capitalize</string>
-												<string key="NSKeyEquiv"/>
-												<int key="NSMnemonicLoc">2147483647</int>
-												<reference key="NSOnImage" ref="35465992"/>
-												<reference key="NSMixedImage" ref="502551668"/>
-											</object>
-										</array>
-									</object>
-								</object>
-								<object class="NSMenuItem" id="676164635">
-									<reference key="NSMenu" ref="789758025"/>
-									<string key="NSTitle">Speech</string>
-									<string key="NSKeyEquiv"/>
-									<int key="NSKeyEquivModMask">1048576</int>
-									<int key="NSMnemonicLoc">2147483647</int>
-									<reference key="NSOnImage" ref="35465992"/>
-									<reference key="NSMixedImage" ref="502551668"/>
-									<string key="NSAction">submenuAction:</string>
-									<object class="NSMenu" key="NSSubmenu" id="785027613">
-										<string key="NSTitle">Speech</string>
-										<array class="NSMutableArray" key="NSMenuItems">
-											<object class="NSMenuItem" id="731782645">
-												<reference key="NSMenu" ref="785027613"/>
-												<string key="NSTitle">Start Speaking</string>
-												<string key="NSKeyEquiv"/>
-												<int key="NSKeyEquivModMask">1048576</int>
-												<int key="NSMnemonicLoc">2147483647</int>
-												<reference key="NSOnImage" ref="35465992"/>
-												<reference key="NSMixedImage" ref="502551668"/>
-											</object>
-											<object class="NSMenuItem" id="680220178">
-												<reference key="NSMenu" ref="785027613"/>
-												<string key="NSTitle">Stop Speaking</string>
-												<string key="NSKeyEquiv"/>
-												<int key="NSKeyEquivModMask">1048576</int>
-												<int key="NSMnemonicLoc">2147483647</int>
-												<reference key="NSOnImage" ref="35465992"/>
-												<reference key="NSMixedImage" ref="502551668"/>
-											</object>
-										</array>
-									</object>
-								</object>
-							</array>
-						</object>
-					</object>
-					<object class="NSMenuItem" id="302598603">
-						<reference key="NSMenu" ref="649796088"/>
-						<string key="NSTitle">Format</string>
-						<string key="NSKeyEquiv"/>
-						<int key="NSMnemonicLoc">2147483647</int>
-						<reference key="NSOnImage" ref="35465992"/>
-						<reference key="NSMixedImage" ref="502551668"/>
-						<string key="NSAction">submenuAction:</string>
-						<object class="NSMenu" key="NSSubmenu" id="941447902">
-							<string key="NSTitle">Format</string>
-							<array class="NSMutableArray" key="NSMenuItems">
-								<object class="NSMenuItem" id="792887677">
-									<reference key="NSMenu" ref="941447902"/>
-									<string key="NSTitle">Font</string>
-									<string key="NSKeyEquiv"/>
-									<int key="NSMnemonicLoc">2147483647</int>
-									<reference key="NSOnImage" ref="35465992"/>
-									<reference key="NSMixedImage" ref="502551668"/>
-									<string key="NSAction">submenuAction:</string>
-									<object class="NSMenu" key="NSSubmenu" id="786677654">
-										<string key="NSTitle">Font</string>
-										<array class="NSMutableArray" key="NSMenuItems">
-											<object class="NSMenuItem" id="159677712">
-												<reference key="NSMenu" ref="786677654"/>
-												<string key="NSTitle">Show Fonts</string>
-												<string key="NSKeyEquiv">t</string>
-												<int key="NSKeyEquivModMask">1048576</int>
-												<int key="NSMnemonicLoc">2147483647</int>
-												<reference key="NSOnImage" ref="35465992"/>
-												<reference key="NSMixedImage" ref="502551668"/>
-											</object>
-											<object class="NSMenuItem" id="305399458">
-												<reference key="NSMenu" ref="786677654"/>
-												<string key="NSTitle">Bold</string>
-												<string key="NSKeyEquiv">b</string>
-												<int key="NSKeyEquivModMask">1048576</int>
-												<int key="NSMnemonicLoc">2147483647</int>
-												<reference key="NSOnImage" ref="35465992"/>
-												<reference key="NSMixedImage" ref="502551668"/>
-												<int key="NSTag">2</int>
-											</object>
-											<object class="NSMenuItem" id="814362025">
-												<reference key="NSMenu" ref="786677654"/>
-												<string key="NSTitle">Italic</string>
-												<string key="NSKeyEquiv">i</string>
-												<int key="NSKeyEquivModMask">1048576</int>
-												<int key="NSMnemonicLoc">2147483647</int>
-												<reference key="NSOnImage" ref="35465992"/>
-												<reference key="NSMixedImage" ref="502551668"/>
-												<int key="NSTag">1</int>
-											</object>
-											<object class="NSMenuItem" id="330926929">
-												<reference key="NSMenu" ref="786677654"/>
-												<string key="NSTitle">Underline</string>
-												<string key="NSKeyEquiv">u</string>
-												<int key="NSKeyEquivModMask">1048576</int>
-												<int key="NSMnemonicLoc">2147483647</int>
-												<reference key="NSOnImage" ref="35465992"/>
-												<reference key="NSMixedImage" ref="502551668"/>
-											</object>
-											<object class="NSMenuItem" id="533507878">
-												<reference key="NSMenu" ref="786677654"/>
-												<bool key="NSIsDisabled">YES</bool>
-												<bool key="NSIsSeparator">YES</bool>
-												<string key="NSTitle"/>
-												<string key="NSKeyEquiv"/>
-												<int key="NSMnemonicLoc">2147483647</int>
-												<reference key="NSOnImage" ref="35465992"/>
-												<reference key="NSMixedImage" ref="502551668"/>
-											</object>
-											<object class="NSMenuItem" id="158063935">
-												<reference key="NSMenu" ref="786677654"/>
-												<string key="NSTitle">Bigger</string>
-												<string key="NSKeyEquiv">+</string>
-												<int key="NSKeyEquivModMask">1048576</int>
-												<int key="NSMnemonicLoc">2147483647</int>
-												<reference key="NSOnImage" ref="35465992"/>
-												<reference key="NSMixedImage" ref="502551668"/>
-												<int key="NSTag">3</int>
-											</object>
-											<object class="NSMenuItem" id="885547335">
-												<reference key="NSMenu" ref="786677654"/>
-												<string key="NSTitle">Smaller</string>
-												<string key="NSKeyEquiv">-</string>
-												<int key="NSKeyEquivModMask">1048576</int>
-												<int key="NSMnemonicLoc">2147483647</int>
-												<reference key="NSOnImage" ref="35465992"/>
-												<reference key="NSMixedImage" ref="502551668"/>
-												<int key="NSTag">4</int>
-											</object>
-											<object class="NSMenuItem" id="901062459">
-												<reference key="NSMenu" ref="786677654"/>
-												<bool key="NSIsDisabled">YES</bool>
-												<bool key="NSIsSeparator">YES</bool>
-												<string key="NSTitle"/>
-												<string key="NSKeyEquiv"/>
-												<int key="NSMnemonicLoc">2147483647</int>
-												<reference key="NSOnImage" ref="35465992"/>
-												<reference key="NSMixedImage" ref="502551668"/>
-											</object>
-											<object class="NSMenuItem" id="767671776">
-												<reference key="NSMenu" ref="786677654"/>
-												<string key="NSTitle">Kern</string>
-												<string key="NSKeyEquiv"/>
-												<int key="NSMnemonicLoc">2147483647</int>
-												<reference key="NSOnImage" ref="35465992"/>
-												<reference key="NSMixedImage" ref="502551668"/>
-												<string key="NSAction">submenuAction:</string>
-												<object class="NSMenu" key="NSSubmenu" id="175441468">
-													<string key="NSTitle">Kern</string>
-													<array class="NSMutableArray" key="NSMenuItems">
-														<object class="NSMenuItem" id="252969304">
-															<reference key="NSMenu" ref="175441468"/>
-															<string key="NSTitle">Use Default</string>
-															<string key="NSKeyEquiv"/>
-															<int key="NSMnemonicLoc">2147483647</int>
-															<reference key="NSOnImage" ref="35465992"/>
-															<reference key="NSMixedImage" ref="502551668"/>
-														</object>
-														<object class="NSMenuItem" id="766922938">
-															<reference key="NSMenu" ref="175441468"/>
-															<string key="NSTitle">Use None</string>
-															<string key="NSKeyEquiv"/>
-															<int key="NSMnemonicLoc">2147483647</int>
-															<reference key="NSOnImage" ref="35465992"/>
-															<reference key="NSMixedImage" ref="502551668"/>
-														</object>
-														<object class="NSMenuItem" id="677519740">
-															<reference key="NSMenu" ref="175441468"/>
-															<string key="NSTitle">Tighten</string>
-															<string key="NSKeyEquiv"/>
-															<int key="NSMnemonicLoc">2147483647</int>
-															<reference key="NSOnImage" ref="35465992"/>
-															<reference key="NSMixedImage" ref="502551668"/>
-														</object>
-														<object class="NSMenuItem" id="238351151">
-															<reference key="NSMenu" ref="175441468"/>
-															<string key="NSTitle">Loosen</string>
-															<string key="NSKeyEquiv"/>
-															<int key="NSMnemonicLoc">2147483647</int>
-															<reference key="NSOnImage" ref="35465992"/>
-															<reference key="NSMixedImage" ref="502551668"/>
-														</object>
-													</array>
-												</object>
-											</object>
-											<object class="NSMenuItem" id="691570813">
-												<reference key="NSMenu" ref="786677654"/>
-												<string key="NSTitle">Ligature</string>
-												<string key="NSKeyEquiv"/>
-												<int key="NSMnemonicLoc">2147483647</int>
-												<reference key="NSOnImage" ref="35465992"/>
-												<reference key="NSMixedImage" ref="502551668"/>
-												<string key="NSAction">submenuAction:</string>
-												<object class="NSMenu" key="NSSubmenu" id="1058217995">
-													<string key="NSTitle">Ligature</string>
-													<array class="NSMutableArray" key="NSMenuItems">
-														<object class="NSMenuItem" id="706297211">
-															<reference key="NSMenu" ref="1058217995"/>
-															<string key="NSTitle">Use Default</string>
-															<string key="NSKeyEquiv"/>
-															<int key="NSMnemonicLoc">2147483647</int>
-															<reference key="NSOnImage" ref="35465992"/>
-															<reference key="NSMixedImage" ref="502551668"/>
-														</object>
-														<object class="NSMenuItem" id="568384683">
-															<reference key="NSMenu" ref="1058217995"/>
-															<string key="NSTitle">Use None</string>
-															<string key="NSKeyEquiv"/>
-															<int key="NSMnemonicLoc">2147483647</int>
-															<reference key="NSOnImage" ref="35465992"/>
-															<reference key="NSMixedImage" ref="502551668"/>
-														</object>
-														<object class="NSMenuItem" id="663508465">
-															<reference key="NSMenu" ref="1058217995"/>
-															<string key="NSTitle">Use All</string>
-															<string key="NSKeyEquiv"/>
-															<int key="NSMnemonicLoc">2147483647</int>
-															<reference key="NSOnImage" ref="35465992"/>
-															<reference key="NSMixedImage" ref="502551668"/>
-														</object>
-													</array>
-												</object>
-											</object>
-											<object class="NSMenuItem" id="769124883">
-												<reference key="NSMenu" ref="786677654"/>
-												<string key="NSTitle">Baseline</string>
-												<string key="NSKeyEquiv"/>
-												<int key="NSMnemonicLoc">2147483647</int>
-												<reference key="NSOnImage" ref="35465992"/>
-												<reference key="NSMixedImage" ref="502551668"/>
-												<string key="NSAction">submenuAction:</string>
-												<object class="NSMenu" key="NSSubmenu" id="18263474">
-													<string key="NSTitle">Baseline</string>
-													<array class="NSMutableArray" key="NSMenuItems">
-														<object class="NSMenuItem" id="257962622">
-															<reference key="NSMenu" ref="18263474"/>
-															<string key="NSTitle">Use Default</string>
-															<string key="NSKeyEquiv"/>
-															<int key="NSMnemonicLoc">2147483647</int>
-															<reference key="NSOnImage" ref="35465992"/>
-															<reference key="NSMixedImage" ref="502551668"/>
-														</object>
-														<object class="NSMenuItem" id="644725453">
-															<reference key="NSMenu" ref="18263474"/>
-															<string key="NSTitle">Superscript</string>
-															<string key="NSKeyEquiv"/>
-															<int key="NSMnemonicLoc">2147483647</int>
-															<reference key="NSOnImage" ref="35465992"/>
-															<reference key="NSMixedImage" ref="502551668"/>
-														</object>
-														<object class="NSMenuItem" id="1037576581">
-															<reference key="NSMenu" ref="18263474"/>
-															<string key="NSTitle">Subscript</string>
-															<string key="NSKeyEquiv"/>
-															<int key="NSMnemonicLoc">2147483647</int>
-															<reference key="NSOnImage" ref="35465992"/>
-															<reference key="NSMixedImage" ref="502551668"/>
-														</object>
-														<object class="NSMenuItem" id="941806246">
-															<reference key="NSMenu" ref="18263474"/>
-															<string key="NSTitle">Raise</string>
-															<string key="NSKeyEquiv"/>
-															<int key="NSMnemonicLoc">2147483647</int>
-															<reference key="NSOnImage" ref="35465992"/>
-															<reference key="NSMixedImage" ref="502551668"/>
-														</object>
-														<object class="NSMenuItem" id="1045724900">
-															<reference key="NSMenu" ref="18263474"/>
-															<string key="NSTitle">Lower</string>
-															<string key="NSKeyEquiv"/>
-															<int key="NSMnemonicLoc">2147483647</int>
-															<reference key="NSOnImage" ref="35465992"/>
-															<reference key="NSMixedImage" ref="502551668"/>
-														</object>
-													</array>
-												</object>
-											</object>
-											<object class="NSMenuItem" id="739652853">
-												<reference key="NSMenu" ref="786677654"/>
-												<bool key="NSIsDisabled">YES</bool>
-												<bool key="NSIsSeparator">YES</bool>
-												<string key="NSTitle"/>
-												<string key="NSKeyEquiv"/>
-												<int key="NSMnemonicLoc">2147483647</int>
-												<reference key="NSOnImage" ref="35465992"/>
-												<reference key="NSMixedImage" ref="502551668"/>
-											</object>
-											<object class="NSMenuItem" id="1012600125">
-												<reference key="NSMenu" ref="786677654"/>
-												<string key="NSTitle">Show Colors</string>
-												<string key="NSKeyEquiv">C</string>
-												<int key="NSKeyEquivModMask">1048576</int>
-												<int key="NSMnemonicLoc">2147483647</int>
-												<reference key="NSOnImage" ref="35465992"/>
-												<reference key="NSMixedImage" ref="502551668"/>
-											</object>
-											<object class="NSMenuItem" id="214559597">
-												<reference key="NSMenu" ref="786677654"/>
-												<bool key="NSIsDisabled">YES</bool>
-												<bool key="NSIsSeparator">YES</bool>
-												<string key="NSTitle"/>
-												<string key="NSKeyEquiv"/>
-												<int key="NSMnemonicLoc">2147483647</int>
-												<reference key="NSOnImage" ref="35465992"/>
-												<reference key="NSMixedImage" ref="502551668"/>
-											</object>
-											<object class="NSMenuItem" id="596732606">
-												<reference key="NSMenu" ref="786677654"/>
-												<string key="NSTitle">Copy Style</string>
-												<string key="NSKeyEquiv">c</string>
-												<int key="NSKeyEquivModMask">1572864</int>
-												<int key="NSMnemonicLoc">2147483647</int>
-												<reference key="NSOnImage" ref="35465992"/>
-												<reference key="NSMixedImage" ref="502551668"/>
-											</object>
-											<object class="NSMenuItem" id="393423671">
-												<reference key="NSMenu" ref="786677654"/>
-												<string key="NSTitle">Paste Style</string>
-												<string key="NSKeyEquiv">v</string>
-												<int key="NSKeyEquivModMask">1572864</int>
-												<int key="NSMnemonicLoc">2147483647</int>
-												<reference key="NSOnImage" ref="35465992"/>
-												<reference key="NSMixedImage" ref="502551668"/>
-											</object>
-										</array>
-										<string key="NSName">_NSFontMenu</string>
-									</object>
-								</object>
-								<object class="NSMenuItem" id="215659978">
-									<reference key="NSMenu" ref="941447902"/>
-									<string key="NSTitle">Text</string>
-									<string key="NSKeyEquiv"/>
-									<int key="NSMnemonicLoc">2147483647</int>
-									<reference key="NSOnImage" ref="35465992"/>
-									<reference key="NSMixedImage" ref="502551668"/>
-									<string key="NSAction">submenuAction:</string>
-									<object class="NSMenu" key="NSSubmenu" id="446991534">
-										<string key="NSTitle">Text</string>
-										<array class="NSMutableArray" key="NSMenuItems">
-											<object class="NSMenuItem" id="875092757">
-												<reference key="NSMenu" ref="446991534"/>
-												<string key="NSTitle">Align Left</string>
-												<string key="NSKeyEquiv">{</string>
-												<int key="NSKeyEquivModMask">1048576</int>
-												<int key="NSMnemonicLoc">2147483647</int>
-												<reference key="NSOnImage" ref="35465992"/>
-												<reference key="NSMixedImage" ref="502551668"/>
-											</object>
-											<object class="NSMenuItem" id="630155264">
-												<reference key="NSMenu" ref="446991534"/>
-												<string key="NSTitle">Center</string>
-												<string key="NSKeyEquiv">|</string>
-												<int key="NSKeyEquivModMask">1048576</int>
-												<int key="NSMnemonicLoc">2147483647</int>
-												<reference key="NSOnImage" ref="35465992"/>
-												<reference key="NSMixedImage" ref="502551668"/>
-											</object>
-											<object class="NSMenuItem" id="945678886">
-												<reference key="NSMenu" ref="446991534"/>
-												<string key="NSTitle">Justify</string>
-												<string key="NSKeyEquiv"/>
-												<int key="NSMnemonicLoc">2147483647</int>
-												<reference key="NSOnImage" ref="35465992"/>
-												<reference key="NSMixedImage" ref="502551668"/>
-											</object>
-											<object class="NSMenuItem" id="512868991">
-												<reference key="NSMenu" ref="446991534"/>
-												<string key="NSTitle">Align Right</string>
-												<string key="NSKeyEquiv">}</string>
-												<int key="NSKeyEquivModMask">1048576</int>
-												<int key="NSMnemonicLoc">2147483647</int>
-												<reference key="NSOnImage" ref="35465992"/>
-												<reference key="NSMixedImage" ref="502551668"/>
-											</object>
-											<object class="NSMenuItem" id="163117631">
-												<reference key="NSMenu" ref="446991534"/>
-												<bool key="NSIsDisabled">YES</bool>
-												<bool key="NSIsSeparator">YES</bool>
-												<string key="NSTitle"/>
-												<string key="NSKeyEquiv"/>
-												<int key="NSMnemonicLoc">2147483647</int>
-												<reference key="NSOnImage" ref="35465992"/>
-												<reference key="NSMixedImage" ref="502551668"/>
-											</object>
-											<object class="NSMenuItem" id="31516759">
-												<reference key="NSMenu" ref="446991534"/>
-												<string key="NSTitle">Writing Direction</string>
-												<string key="NSKeyEquiv"/>
-												<int key="NSMnemonicLoc">2147483647</int>
-												<reference key="NSOnImage" ref="35465992"/>
-												<reference key="NSMixedImage" ref="502551668"/>
-												<string key="NSAction">submenuAction:</string>
-												<object class="NSMenu" key="NSSubmenu" id="956096989">
-													<string key="NSTitle">Writing Direction</string>
-													<array class="NSMutableArray" key="NSMenuItems">
-														<object class="NSMenuItem" id="257099033">
-															<reference key="NSMenu" ref="956096989"/>
-															<bool key="NSIsDisabled">YES</bool>
-															<string key="NSTitle">Paragraph</string>
-															<string key="NSKeyEquiv"/>
-															<int key="NSMnemonicLoc">2147483647</int>
-															<reference key="NSOnImage" ref="35465992"/>
-															<reference key="NSMixedImage" ref="502551668"/>
-														</object>
-														<object class="NSMenuItem" id="551969625">
-															<reference key="NSMenu" ref="956096989"/>
-															<string type="base64-UTF8" key="NSTitle">CURlZmF1bHQ</string>
-															<string key="NSKeyEquiv"/>
-															<int key="NSMnemonicLoc">2147483647</int>
-															<reference key="NSOnImage" ref="35465992"/>
-															<reference key="NSMixedImage" ref="502551668"/>
-														</object>
-														<object class="NSMenuItem" id="249532473">
-															<reference key="NSMenu" ref="956096989"/>
-															<string type="base64-UTF8" key="NSTitle">CUxlZnQgdG8gUmlnaHQ</string>
-															<string key="NSKeyEquiv"/>
-															<int key="NSMnemonicLoc">2147483647</int>
-															<reference key="NSOnImage" ref="35465992"/>
-															<reference key="NSMixedImage" ref="502551668"/>
-														</object>
-														<object class="NSMenuItem" id="607364498">
-															<reference key="NSMenu" ref="956096989"/>
-															<string type="base64-UTF8" key="NSTitle">CVJpZ2h0IHRvIExlZnQ</string>
-															<string key="NSKeyEquiv"/>
-															<int key="NSMnemonicLoc">2147483647</int>
-															<reference key="NSOnImage" ref="35465992"/>
-															<reference key="NSMixedImage" ref="502551668"/>
-														</object>
-														<object class="NSMenuItem" id="508151438">
-															<reference key="NSMenu" ref="956096989"/>
-															<bool key="NSIsDisabled">YES</bool>
-															<bool key="NSIsSeparator">YES</bool>
-															<string key="NSTitle"/>
-															<string key="NSKeyEquiv"/>
-															<int key="NSMnemonicLoc">2147483647</int>
-															<reference key="NSOnImage" ref="35465992"/>
-															<reference key="NSMixedImage" ref="502551668"/>
-														</object>
-														<object class="NSMenuItem" id="981751889">
-															<reference key="NSMenu" ref="956096989"/>
-															<bool key="NSIsDisabled">YES</bool>
-															<string key="NSTitle">Selection</string>
-															<string key="NSKeyEquiv"/>
-															<int key="NSMnemonicLoc">2147483647</int>
-															<reference key="NSOnImage" ref="35465992"/>
-															<reference key="NSMixedImage" ref="502551668"/>
-														</object>
-														<object class="NSMenuItem" id="380031999">
-															<reference key="NSMenu" ref="956096989"/>
-															<string type="base64-UTF8" key="NSTitle">CURlZmF1bHQ</string>
-															<string key="NSKeyEquiv"/>
-															<int key="NSMnemonicLoc">2147483647</int>
-															<reference key="NSOnImage" ref="35465992"/>
-															<reference key="NSMixedImage" ref="502551668"/>
-														</object>
-														<object class="NSMenuItem" id="825984362">
-															<reference key="NSMenu" ref="956096989"/>
-															<string type="base64-UTF8" key="NSTitle">CUxlZnQgdG8gUmlnaHQ</string>
-															<string key="NSKeyEquiv"/>
-															<int key="NSMnemonicLoc">2147483647</int>
-															<reference key="NSOnImage" ref="35465992"/>
-															<reference key="NSMixedImage" ref="502551668"/>
-														</object>
-														<object class="NSMenuItem" id="560145579">
-															<reference key="NSMenu" ref="956096989"/>
-															<string type="base64-UTF8" key="NSTitle">CVJpZ2h0IHRvIExlZnQ</string>
-															<string key="NSKeyEquiv"/>
-															<int key="NSMnemonicLoc">2147483647</int>
-															<reference key="NSOnImage" ref="35465992"/>
-															<reference key="NSMixedImage" ref="502551668"/>
-														</object>
-													</array>
-												</object>
-											</object>
-											<object class="NSMenuItem" id="908105787">
-												<reference key="NSMenu" ref="446991534"/>
-												<bool key="NSIsDisabled">YES</bool>
-												<bool key="NSIsSeparator">YES</bool>
-												<string key="NSTitle"/>
-												<string key="NSKeyEquiv"/>
-												<int key="NSMnemonicLoc">2147483647</int>
-												<reference key="NSOnImage" ref="35465992"/>
-												<reference key="NSMixedImage" ref="502551668"/>
-											</object>
-											<object class="NSMenuItem" id="644046920">
-												<reference key="NSMenu" ref="446991534"/>
-												<string key="NSTitle">Show Ruler</string>
-												<string key="NSKeyEquiv"/>
-												<int key="NSMnemonicLoc">2147483647</int>
-												<reference key="NSOnImage" ref="35465992"/>
-												<reference key="NSMixedImage" ref="502551668"/>
-											</object>
-											<object class="NSMenuItem" id="231811626">
-												<reference key="NSMenu" ref="446991534"/>
-												<string key="NSTitle">Copy Ruler</string>
-												<string key="NSKeyEquiv">c</string>
-												<int key="NSKeyEquivModMask">1310720</int>
-												<int key="NSMnemonicLoc">2147483647</int>
-												<reference key="NSOnImage" ref="35465992"/>
-												<reference key="NSMixedImage" ref="502551668"/>
-											</object>
-											<object class="NSMenuItem" id="883618387">
-												<reference key="NSMenu" ref="446991534"/>
-												<string key="NSTitle">Paste Ruler</string>
-												<string key="NSKeyEquiv">v</string>
-												<int key="NSKeyEquivModMask">1310720</int>
-												<int key="NSMnemonicLoc">2147483647</int>
-												<reference key="NSOnImage" ref="35465992"/>
-												<reference key="NSMixedImage" ref="502551668"/>
-											</object>
-										</array>
-									</object>
-								</object>
-							</array>
-						</object>
-					</object>
-					<object class="NSMenuItem" id="586577488">
-						<reference key="NSMenu" ref="649796088"/>
-						<string key="NSTitle">View</string>
-						<string key="NSKeyEquiv"/>
-						<int key="NSKeyEquivModMask">1048576</int>
-						<int key="NSMnemonicLoc">2147483647</int>
-						<reference key="NSOnImage" ref="35465992"/>
-						<reference key="NSMixedImage" ref="502551668"/>
-						<string key="NSAction">submenuAction:</string>
-						<object class="NSMenu" key="NSSubmenu" id="466310130">
-							<string key="NSTitle">View</string>
-							<array class="NSMutableArray" key="NSMenuItems">
-								<object class="NSMenuItem" id="102151532">
-									<reference key="NSMenu" ref="466310130"/>
-									<string key="NSTitle">Show Toolbar</string>
-									<string key="NSKeyEquiv">t</string>
-									<int key="NSKeyEquivModMask">1572864</int>
-									<int key="NSMnemonicLoc">2147483647</int>
-									<reference key="NSOnImage" ref="35465992"/>
-									<reference key="NSMixedImage" ref="502551668"/>
-								</object>
-								<object class="NSMenuItem" id="237841660">
-									<reference key="NSMenu" ref="466310130"/>
-									<string key="NSTitle">Customize Toolbar…</string>
-									<string key="NSKeyEquiv"/>
-									<int key="NSKeyEquivModMask">1048576</int>
-									<int key="NSMnemonicLoc">2147483647</int>
-									<reference key="NSOnImage" ref="35465992"/>
-									<reference key="NSMixedImage" ref="502551668"/>
-								</object>
-							</array>
-						</object>
-					</object>
-					<object class="NSMenuItem" id="713487014">
-						<reference key="NSMenu" ref="649796088"/>
-						<string key="NSTitle">Window</string>
-						<string key="NSKeyEquiv"/>
-						<int key="NSKeyEquivModMask">1048576</int>
-						<int key="NSMnemonicLoc">2147483647</int>
-						<reference key="NSOnImage" ref="35465992"/>
-						<reference key="NSMixedImage" ref="502551668"/>
-						<string key="NSAction">submenuAction:</string>
-						<object class="NSMenu" key="NSSubmenu" id="835318025">
-							<string key="NSTitle">Window</string>
-							<array class="NSMutableArray" key="NSMenuItems">
-								<object class="NSMenuItem" id="1011231497">
-									<reference key="NSMenu" ref="835318025"/>
-									<string key="NSTitle">Minimize</string>
-									<string key="NSKeyEquiv">m</string>
-									<int key="NSKeyEquivModMask">1048576</int>
-									<int key="NSMnemonicLoc">2147483647</int>
-									<reference key="NSOnImage" ref="35465992"/>
-									<reference key="NSMixedImage" ref="502551668"/>
-								</object>
-								<object class="NSMenuItem" id="575023229">
-									<reference key="NSMenu" ref="835318025"/>
-									<string key="NSTitle">Zoom</string>
-									<string key="NSKeyEquiv"/>
-									<int key="NSKeyEquivModMask">1048576</int>
-									<int key="NSMnemonicLoc">2147483647</int>
-									<reference key="NSOnImage" ref="35465992"/>
-									<reference key="NSMixedImage" ref="502551668"/>
-								</object>
-								<object class="NSMenuItem" id="299356726">
-									<reference key="NSMenu" ref="835318025"/>
-									<bool key="NSIsDisabled">YES</bool>
-									<bool key="NSIsSeparator">YES</bool>
-									<string key="NSTitle"/>
-									<string key="NSKeyEquiv"/>
-									<int key="NSKeyEquivModMask">1048576</int>
-									<int key="NSMnemonicLoc">2147483647</int>
-									<reference key="NSOnImage" ref="35465992"/>
-									<reference key="NSMixedImage" ref="502551668"/>
-								</object>
-								<object class="NSMenuItem" id="625202149">
-									<reference key="NSMenu" ref="835318025"/>
-									<string key="NSTitle">Bring All to Front</string>
-									<string key="NSKeyEquiv"/>
-									<int key="NSKeyEquivModMask">1048576</int>
-									<int key="NSMnemonicLoc">2147483647</int>
-									<reference key="NSOnImage" ref="35465992"/>
-									<reference key="NSMixedImage" ref="502551668"/>
-								</object>
-							</array>
-							<string key="NSName">_NSWindowsMenu</string>
-						</object>
-					</object>
-					<object class="NSMenuItem" id="448692316">
-						<reference key="NSMenu" ref="649796088"/>
-						<string key="NSTitle">Help</string>
-						<string key="NSKeyEquiv"/>
-						<int key="NSMnemonicLoc">2147483647</int>
-						<reference key="NSOnImage" ref="35465992"/>
-						<reference key="NSMixedImage" ref="502551668"/>
-						<string key="NSAction">submenuAction:</string>
-						<object class="NSMenu" key="NSSubmenu" id="992780483">
-							<string key="NSTitle">Help</string>
-							<array class="NSMutableArray" key="NSMenuItems">
-								<object class="NSMenuItem" id="105068016">
-									<reference key="NSMenu" ref="992780483"/>
-									<string key="NSTitle">Second Life Crash Logger Help</string>
-									<string key="NSKeyEquiv">?</string>
-									<int key="NSKeyEquivModMask">1048576</int>
-									<int key="NSMnemonicLoc">2147483647</int>
-									<reference key="NSOnImage" ref="35465992"/>
-									<reference key="NSMixedImage" ref="502551668"/>
-								</object>
-							</array>
-							<string key="NSName">_NSHelpMenu</string>
-						</object>
-					</object>
-				</array>
-				<string key="NSName">_NSMainMenu</string>
-			</object>
-			<object class="NSWindowTemplate" id="972006081">
-				<int key="NSWindowStyleMask">15</int>
-				<int key="NSWindowBacking">2</int>
-				<string key="NSWindowRect">{{335, 390}, {508, 477}}</string>
-				<int key="NSWTFlags">1954021376</int>
-				<string key="NSWindowTitle">Second Life Crash Logger</string>
-				<string key="NSWindowClass">NSWindow</string>
-				<nil key="NSViewClass"/>
-				<nil key="NSUserInterfaceItemIdentifier"/>
-				<object class="NSView" key="NSWindowView" id="439893737">
-					<reference key="NSNextResponder"/>
-					<int key="NSvFlags">256</int>
-					<array class="NSMutableArray" key="NSSubviews">
-						<object class="NSTextField" id="242877095">
-							<reference key="NSNextResponder" ref="439893737"/>
-							<int key="NSvFlags">268</int>
-							<string key="NSFrame">{{17, 228}, {474, 229}}</string>
-							<reference key="NSSuperview" ref="439893737"/>
-							<reference key="NSWindow"/>
-							<reference key="NSNextKeyView" ref="1018085422"/>
-							<string key="NSReuseIdentifierKey">_NS:9</string>
-							<string key="NSAntiCompressionPriority">{250, 750}</string>
-							<bool key="NSEnabled">YES</bool>
-							<object class="NSTextFieldCell" key="NSCell" id="502956757">
-								<int key="NSCellFlags">67239424</int>
-								<int key="NSCellFlags2">272891904</int>
-								<object class="NSMutableString" key="NSContents">
-									<bytes key="NS.bytes">U2Vjb25kIExpZmUgYXBwZWFycyB0byBoYXZlIGNyYXNoZWQgb3IgZnJvemVuIHRoZSBsYXN0IHRpbWUg
-aXQgcmFuLgoKVGhpcyBjcmFzaCByZXBvcnRlciBjb2xsZWN0cyBpbmZvcm1hdGlvbiBhYm91dCB5b3Vy
-IGNvbXB1dGVyJ3MgaGFyZHdhcmUgY29uZmlndXJhdGlvbiwgb3BlcmF0aW5nIHN5c3RlbSwgYW5kIHNv
-bWUgU2Vjb25kIExpZmUgbG9ncywgYWxsIG9mIHdoaWNoIGFyZSB1c2VkIGZvciBkZWJ1Z2dpbmcgcHVy
-cG9zZXMgb25seS4KCkluIHRoZSBzcGFjZSBiZWxvdywgcGxlYXNlIGJyaWVmbHkgZGVzY3JpYmUgd2hh
-dCB5b3Ugd2VyZSBkb2luZyBvciB0cnlpbmcgdG8gZG8ganVzdCBwcmlvciB0byB0aGUgY3Jhc2guICBU
-aGFuayB5b3UgZm9yIHlvdXIgaGVscCEKClRoaXMgcmVwb3J0IGlzIE5PVCByZWFkIGJ5IEN1c3RvbWVy
-IFN1cHBvcnQuICBJZiB5b3UgaGF2ZSBiaWxsaW5nIG9yIG90aGVyIHF1ZXN0aW9ucywgcGxlYXNlIGdv
-IHRvOiBodHRwOi8vd3d3LnNlY29uZGxpZmUuY29tL3N1cHBvcnQvCgpJZiB5b3UgZG9uJ3Qgd2lzaCB0
-byBzZW5kIExpbmRlbiBMYWIgYSBjcmFzaCByZXBvcnQsIHByZXNzIENhbmNlbC4</bytes>
-								</object>
-								<object class="NSFont" key="NSSupport" id="1010806345">
-									<string key="NSName">LucidaGrande</string>
-									<double key="NSSize">13</double>
-									<int key="NSfFlags">16</int>
-								</object>
-								<string key="NSCellIdentifier">_NS:9</string>
-								<reference key="NSControlView" ref="242877095"/>
-								<object class="NSColor" key="NSBackgroundColor">
-									<int key="NSColorSpace">6</int>
-									<string key="NSCatalogName">System</string>
-									<string key="NSColorName">controlColor</string>
-									<object class="NSColor" key="NSColor">
-										<int key="NSColorSpace">3</int>
-										<bytes key="NSWhite">MC42NjY2NjY2NjY3AA</bytes>
-									</object>
-								</object>
-								<object class="NSColor" key="NSTextColor">
-									<int key="NSColorSpace">6</int>
-									<string key="NSCatalogName">System</string>
-									<string key="NSColorName">controlTextColor</string>
-									<object class="NSColor" key="NSColor" id="355388215">
-										<int key="NSColorSpace">3</int>
-										<bytes key="NSWhite">MAA</bytes>
-									</object>
-								</object>
-							</object>
-						</object>
-						<object class="NSTextField" id="1018085422">
-							<reference key="NSNextResponder" ref="439893737"/>
-							<int key="NSvFlags">268</int>
-							<string key="NSFrame">{{20, 64}, {468, 163}}</string>
-							<reference key="NSSuperview" ref="439893737"/>
-							<reference key="NSWindow"/>
-							<reference key="NSNextKeyView" ref="688522420"/>
-							<string key="NSReuseIdentifierKey">_NS:9</string>
-							<string key="NSAntiCompressionPriority">{250, 750}</string>
-							<bool key="NSEnabled">YES</bool>
-							<object class="NSTextFieldCell" key="NSCell" id="867418359">
-								<int key="NSCellFlags">-1805517311</int>
-								<int key="NSCellFlags2">272891904</int>
-								<string key="NSContents"/>
-								<object class="NSFont" key="NSSupport">
-									<string key="NSName">LucidaGrande</string>
-									<double key="NSSize">9</double>
-									<int key="NSfFlags">3614</int>
-								</object>
-								<string key="NSCellIdentifier">_NS:9</string>
-								<reference key="NSControlView" ref="1018085422"/>
-								<bool key="NSDrawsBackground">YES</bool>
-								<object class="NSColor" key="NSBackgroundColor">
-									<int key="NSColorSpace">6</int>
-									<string key="NSCatalogName">System</string>
-									<string key="NSColorName">textBackgroundColor</string>
-									<object class="NSColor" key="NSColor">
-										<int key="NSColorSpace">3</int>
-										<bytes key="NSWhite">MQA</bytes>
-									</object>
-								</object>
-								<object class="NSColor" key="NSTextColor">
-									<int key="NSColorSpace">6</int>
-									<string key="NSCatalogName">System</string>
-									<string key="NSColorName">textColor</string>
-									<reference key="NSColor" ref="355388215"/>
-								</object>
-							</object>
-						</object>
-						<object class="NSButton" id="688522420">
-							<reference key="NSNextResponder" ref="439893737"/>
-							<int key="NSvFlags">268</int>
-							<string key="NSFrame">{{16, 18}, {189, 30}}</string>
-							<reference key="NSSuperview" ref="439893737"/>
-							<reference key="NSWindow"/>
-							<reference key="NSNextKeyView" ref="93467784"/>
-							<string key="NSReuseIdentifierKey">_NS:9</string>
-							<bool key="NSEnabled">YES</bool>
-							<object class="NSButtonCell" key="NSCell" id="445379790">
-								<int key="NSCellFlags">-2080244224</int>
-								<int key="NSCellFlags2">262144</int>
-								<string key="NSContents">Remember This Choice</string>
-								<reference key="NSSupport" ref="1010806345"/>
-								<string key="NSCellIdentifier">_NS:9</string>
-								<reference key="NSControlView" ref="688522420"/>
-								<int key="NSButtonFlags">1211912703</int>
-								<int key="NSButtonFlags2">2</int>
-								<object class="NSCustomResource" key="NSNormalImage">
-									<string key="NSClassName">NSImage</string>
-									<string key="NSResourceName">NSSwitch</string>
-								</object>
-								<object class="NSButtonImageSource" key="NSAlternateImage">
-									<string key="NSImageName">NSSwitch</string>
-								</object>
-								<string key="NSAlternateContents"/>
-								<string key="NSKeyEquivalent"/>
-								<int key="NSPeriodicDelay">200</int>
-								<int key="NSPeriodicInterval">25</int>
-							</object>
-						</object>
-						<object class="NSButton" id="93467784">
-							<reference key="NSNextResponder" ref="439893737"/>
-							<int key="NSvFlags">268</int>
-							<string key="NSFrame">{{285, 23}, {91, 17}}</string>
-							<reference key="NSSuperview" ref="439893737"/>
-							<reference key="NSWindow"/>
-							<reference key="NSNextKeyView" ref="46276252"/>
-							<string key="NSReuseIdentifierKey">_NS:9</string>
-							<bool key="NSEnabled">YES</bool>
-							<object class="NSButtonCell" key="NSCell" id="623922320">
-								<int key="NSCellFlags">-2080244224</int>
-								<int key="NSCellFlags2">134479872</int>
-								<string key="NSContents">Send Report</string>
-								<reference key="NSSupport" ref="1010806345"/>
-								<string key="NSCellIdentifier">_NS:9</string>
-								<reference key="NSControlView" ref="93467784"/>
-								<int key="NSButtonFlags">-2038152961</int>
-								<int key="NSButtonFlags2">164</int>
-								<string key="NSAlternateContents"/>
-								<string key="NSKeyEquivalent"/>
-								<int key="NSPeriodicDelay">400</int>
-								<int key="NSPeriodicInterval">75</int>
-							</object>
-						</object>
-						<object class="NSButton" id="46276252">
-							<reference key="NSNextResponder" ref="439893737"/>
-							<int key="NSvFlags">268</int>
-							<string key="NSFrame">{{388, 23}, {100, 17}}</string>
-							<reference key="NSSuperview" ref="439893737"/>
-							<reference key="NSWindow"/>
-							<reference key="NSNextKeyView"/>
-							<string key="NSReuseIdentifierKey">_NS:9</string>
-							<bool key="NSEnabled">YES</bool>
-							<object class="NSButtonCell" key="NSCell" id="398179500">
-								<int key="NSCellFlags">-2080244224</int>
-								<int key="NSCellFlags2">134479872</int>
-								<string key="NSContents">Don't Send</string>
-								<reference key="NSSupport" ref="1010806345"/>
-								<string key="NSCellIdentifier">_NS:9</string>
-								<reference key="NSControlView" ref="46276252"/>
-								<int key="NSButtonFlags">-2038152961</int>
-								<int key="NSButtonFlags2">164</int>
-								<string key="NSAlternateContents"/>
-								<string key="NSKeyEquivalent"/>
-								<int key="NSPeriodicDelay">400</int>
-								<int key="NSPeriodicInterval">75</int>
-							</object>
-						</object>
-					</array>
-					<string key="NSFrameSize">{508, 477}</string>
-					<reference key="NSSuperview"/>
-					<reference key="NSWindow"/>
-					<reference key="NSNextKeyView" ref="242877095"/>
-				</object>
-				<string key="NSScreenRect">{{0, 0}, {1680, 1028}}</string>
-				<string key="NSMaxSize">{10000000000000, 10000000000000}</string>
-				<bool key="NSWindowIsRestorable">YES</bool>
-			</object>
-			<object class="NSCustomObject" id="976324537">
-				<string key="NSClassName">LLCrashLoggerMacDelegate</string>
-			</object>
-		</array>
-		<object class="IBObjectContainer" key="IBDocument.Objects">
-			<array class="NSMutableArray" key="connectionRecords">
-				<object class="IBConnectionRecord">
-					<object class="IBActionConnection" key="connection">
-						<string key="label">terminate:</string>
-						<reference key="source" ref="1050"/>
-						<reference key="destination" ref="632727374"/>
-					</object>
-					<int key="connectionID">449</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBActionConnection" key="connection">
-						<string key="label">orderFrontStandardAboutPanel:</string>
-						<reference key="source" ref="1021"/>
-						<reference key="destination" ref="238522557"/>
-					</object>
-					<int key="connectionID">142</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBOutletConnection" key="connection">
-						<string key="label">delegate</string>
-						<reference key="source" ref="1021"/>
-						<reference key="destination" ref="976324537"/>
-					</object>
-					<int key="connectionID">495</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBActionConnection" key="connection">
-						<string key="label">performMiniaturize:</string>
-						<reference key="source" ref="1014"/>
-						<reference key="destination" ref="1011231497"/>
-					</object>
-					<int key="connectionID">37</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBActionConnection" key="connection">
-						<string key="label">arrangeInFront:</string>
-						<reference key="source" ref="1014"/>
-						<reference key="destination" ref="625202149"/>
-					</object>
-					<int key="connectionID">39</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBActionConnection" key="connection">
-						<string key="label">print:</string>
-						<reference key="source" ref="1014"/>
-						<reference key="destination" ref="49223823"/>
-					</object>
-					<int key="connectionID">86</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBActionConnection" key="connection">
-						<string key="label">runPageLayout:</string>
-						<reference key="source" ref="1014"/>
-						<reference key="destination" ref="294629803"/>
-					</object>
-					<int key="connectionID">87</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBActionConnection" key="connection">
-						<string key="label">clearRecentDocuments:</string>
-						<reference key="source" ref="1014"/>
-						<reference key="destination" ref="759406840"/>
-					</object>
-					<int key="connectionID">127</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBActionConnection" key="connection">
-						<string key="label">performClose:</string>
-						<reference key="source" ref="1014"/>
-						<reference key="destination" ref="776162233"/>
-					</object>
-					<int key="connectionID">193</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBActionConnection" key="connection">
-						<string key="label">toggleContinuousSpellChecking:</string>
-						<reference key="source" ref="1014"/>
-						<reference key="destination" ref="948374510"/>
-					</object>
-					<int key="connectionID">222</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBActionConnection" key="connection">
-						<string key="label">undo:</string>
-						<reference key="source" ref="1014"/>
-						<reference key="destination" ref="1058277027"/>
-					</object>
-					<int key="connectionID">223</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBActionConnection" key="connection">
-						<string key="label">copy:</string>
-						<reference key="source" ref="1014"/>
-						<reference key="destination" ref="860595796"/>
-					</object>
-					<int key="connectionID">224</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBActionConnection" key="connection">
-						<string key="label">checkSpelling:</string>
-						<reference key="source" ref="1014"/>
-						<reference key="destination" ref="96193923"/>
-					</object>
-					<int key="connectionID">225</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBActionConnection" key="connection">
-						<string key="label">paste:</string>
-						<reference key="source" ref="1014"/>
-						<reference key="destination" ref="29853731"/>
-					</object>
-					<int key="connectionID">226</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBActionConnection" key="connection">
-						<string key="label">stopSpeaking:</string>
-						<reference key="source" ref="1014"/>
-						<reference key="destination" ref="680220178"/>
-					</object>
-					<int key="connectionID">227</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBActionConnection" key="connection">
-						<string key="label">cut:</string>
-						<reference key="source" ref="1014"/>
-						<reference key="destination" ref="296257095"/>
-					</object>
-					<int key="connectionID">228</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBActionConnection" key="connection">
-						<string key="label">showGuessPanel:</string>
-						<reference key="source" ref="1014"/>
-						<reference key="destination" ref="679648819"/>
-					</object>
-					<int key="connectionID">230</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBActionConnection" key="connection">
-						<string key="label">redo:</string>
-						<reference key="source" ref="1014"/>
-						<reference key="destination" ref="790794224"/>
-					</object>
-					<int key="connectionID">231</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBActionConnection" key="connection">
-						<string key="label">selectAll:</string>
-						<reference key="source" ref="1014"/>
-						<reference key="destination" ref="583158037"/>
-					</object>
-					<int key="connectionID">232</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBActionConnection" key="connection">
-						<string key="label">startSpeaking:</string>
-						<reference key="source" ref="1014"/>
-						<reference key="destination" ref="731782645"/>
-					</object>
-					<int key="connectionID">233</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBActionConnection" key="connection">
-						<string key="label">delete:</string>
-						<reference key="source" ref="1014"/>
-						<reference key="destination" ref="437104165"/>
-					</object>
-					<int key="connectionID">235</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBActionConnection" key="connection">
-						<string key="label">performZoom:</string>
-						<reference key="source" ref="1014"/>
-						<reference key="destination" ref="575023229"/>
-					</object>
-					<int key="connectionID">240</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBActionConnection" key="connection">
-						<string key="label">performFindPanelAction:</string>
-						<reference key="source" ref="1014"/>
-						<reference key="destination" ref="447796847"/>
-					</object>
-					<int key="connectionID">241</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBActionConnection" key="connection">
-						<string key="label">centerSelectionInVisibleArea:</string>
-						<reference key="source" ref="1014"/>
-						<reference key="destination" ref="88285865"/>
-					</object>
-					<int key="connectionID">245</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBActionConnection" key="connection">
-						<string key="label">toggleGrammarChecking:</string>
-						<reference key="source" ref="1014"/>
-						<reference key="destination" ref="967646866"/>
-					</object>
-					<int key="connectionID">347</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBActionConnection" key="connection">
-						<string key="label">toggleSmartInsertDelete:</string>
-						<reference key="source" ref="1014"/>
-						<reference key="destination" ref="605118523"/>
-					</object>
-					<int key="connectionID">355</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBActionConnection" key="connection">
-						<string key="label">toggleAutomaticQuoteSubstitution:</string>
-						<reference key="source" ref="1014"/>
-						<reference key="destination" ref="197661976"/>
-					</object>
-					<int key="connectionID">356</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBActionConnection" key="connection">
-						<string key="label">toggleAutomaticLinkDetection:</string>
-						<reference key="source" ref="1014"/>
-						<reference key="destination" ref="708854459"/>
-					</object>
-					<int key="connectionID">357</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBActionConnection" key="connection">
-						<string key="label">saveDocument:</string>
-						<reference key="source" ref="1014"/>
-						<reference key="destination" ref="1023925487"/>
-					</object>
-					<int key="connectionID">362</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBActionConnection" key="connection">
-						<string key="label">revertDocumentToSaved:</string>
-						<reference key="source" ref="1014"/>
-						<reference key="destination" ref="579971712"/>
-					</object>
-					<int key="connectionID">364</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBActionConnection" key="connection">
-						<string key="label">runToolbarCustomizationPalette:</string>
-						<reference key="source" ref="1014"/>
-						<reference key="destination" ref="237841660"/>
-					</object>
-					<int key="connectionID">365</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBActionConnection" key="connection">
-						<string key="label">toggleToolbarShown:</string>
-						<reference key="source" ref="1014"/>
-						<reference key="destination" ref="102151532"/>
-					</object>
-					<int key="connectionID">366</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBActionConnection" key="connection">
-						<string key="label">hide:</string>
-						<reference key="source" ref="1014"/>
-						<reference key="destination" ref="755159360"/>
-					</object>
-					<int key="connectionID">367</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBActionConnection" key="connection">
-						<string key="label">hideOtherApplications:</string>
-						<reference key="source" ref="1014"/>
-						<reference key="destination" ref="342932134"/>
-					</object>
-					<int key="connectionID">368</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBActionConnection" key="connection">
-						<string key="label">unhideAllApplications:</string>
-						<reference key="source" ref="1014"/>
-						<reference key="destination" ref="908899353"/>
-					</object>
-					<int key="connectionID">370</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBActionConnection" key="connection">
-						<string key="label">newDocument:</string>
-						<reference key="source" ref="1014"/>
-						<reference key="destination" ref="705341025"/>
-					</object>
-					<int key="connectionID">373</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBActionConnection" key="connection">
-						<string key="label">openDocument:</string>
-						<reference key="source" ref="1014"/>
-						<reference key="destination" ref="722745758"/>
-					</object>
-					<int key="connectionID">374</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBActionConnection" key="connection">
-						<string key="label">raiseBaseline:</string>
-						<reference key="source" ref="1014"/>
-						<reference key="destination" ref="941806246"/>
-					</object>
-					<int key="connectionID">426</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBActionConnection" key="connection">
-						<string key="label">lowerBaseline:</string>
-						<reference key="source" ref="1014"/>
-						<reference key="destination" ref="1045724900"/>
-					</object>
-					<int key="connectionID">427</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBActionConnection" key="connection">
-						<string key="label">copyFont:</string>
-						<reference key="source" ref="1014"/>
-						<reference key="destination" ref="596732606"/>
-					</object>
-					<int key="connectionID">428</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBActionConnection" key="connection">
-						<string key="label">subscript:</string>
-						<reference key="source" ref="1014"/>
-						<reference key="destination" ref="1037576581"/>
-					</object>
-					<int key="connectionID">429</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBActionConnection" key="connection">
-						<string key="label">superscript:</string>
-						<reference key="source" ref="1014"/>
-						<reference key="destination" ref="644725453"/>
-					</object>
-					<int key="connectionID">430</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBActionConnection" key="connection">
-						<string key="label">tightenKerning:</string>
-						<reference key="source" ref="1014"/>
-						<reference key="destination" ref="677519740"/>
-					</object>
-					<int key="connectionID">431</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBActionConnection" key="connection">
-						<string key="label">underline:</string>
-						<reference key="source" ref="1014"/>
-						<reference key="destination" ref="330926929"/>
-					</object>
-					<int key="connectionID">432</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBActionConnection" key="connection">
-						<string key="label">orderFrontColorPanel:</string>
-						<reference key="source" ref="1014"/>
-						<reference key="destination" ref="1012600125"/>
-					</object>
-					<int key="connectionID">433</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBActionConnection" key="connection">
-						<string key="label">useAllLigatures:</string>
-						<reference key="source" ref="1014"/>
-						<reference key="destination" ref="663508465"/>
-					</object>
-					<int key="connectionID">434</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBActionConnection" key="connection">
-						<string key="label">loosenKerning:</string>
-						<reference key="source" ref="1014"/>
-						<reference key="destination" ref="238351151"/>
-					</object>
-					<int key="connectionID">435</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBActionConnection" key="connection">
-						<string key="label">pasteFont:</string>
-						<reference key="source" ref="1014"/>
-						<reference key="destination" ref="393423671"/>
-					</object>
-					<int key="connectionID">436</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBActionConnection" key="connection">
-						<string key="label">unscript:</string>
-						<reference key="source" ref="1014"/>
-						<reference key="destination" ref="257962622"/>
-					</object>
-					<int key="connectionID">437</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBActionConnection" key="connection">
-						<string key="label">useStandardKerning:</string>
-						<reference key="source" ref="1014"/>
-						<reference key="destination" ref="252969304"/>
-					</object>
-					<int key="connectionID">438</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBActionConnection" key="connection">
-						<string key="label">useStandardLigatures:</string>
-						<reference key="source" ref="1014"/>
-						<reference key="destination" ref="706297211"/>
-					</object>
-					<int key="connectionID">439</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBActionConnection" key="connection">
-						<string key="label">turnOffLigatures:</string>
-						<reference key="source" ref="1014"/>
-						<reference key="destination" ref="568384683"/>
-					</object>
-					<int key="connectionID">440</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBActionConnection" key="connection">
-						<string key="label">turnOffKerning:</string>
-						<reference key="source" ref="1014"/>
-						<reference key="destination" ref="766922938"/>
-					</object>
-					<int key="connectionID">441</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBActionConnection" key="connection">
-						<string key="label">toggleAutomaticSpellingCorrection:</string>
-						<reference key="source" ref="1014"/>
-						<reference key="destination" ref="795346622"/>
-					</object>
-					<int key="connectionID">456</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBActionConnection" key="connection">
-						<string key="label">orderFrontSubstitutionsPanel:</string>
-						<reference key="source" ref="1014"/>
-						<reference key="destination" ref="65139061"/>
-					</object>
-					<int key="connectionID">458</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBActionConnection" key="connection">
-						<string key="label">toggleAutomaticDashSubstitution:</string>
-						<reference key="source" ref="1014"/>
-						<reference key="destination" ref="672708820"/>
-					</object>
-					<int key="connectionID">461</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBActionConnection" key="connection">
-						<string key="label">toggleAutomaticTextReplacement:</string>
-						<reference key="source" ref="1014"/>
-						<reference key="destination" ref="537092702"/>
-					</object>
-					<int key="connectionID">463</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBActionConnection" key="connection">
-						<string key="label">uppercaseWord:</string>
-						<reference key="source" ref="1014"/>
-						<reference key="destination" ref="1060694897"/>
-					</object>
-					<int key="connectionID">464</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBActionConnection" key="connection">
-						<string key="label">capitalizeWord:</string>
-						<reference key="source" ref="1014"/>
-						<reference key="destination" ref="56570060"/>
-					</object>
-					<int key="connectionID">467</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBActionConnection" key="connection">
-						<string key="label">lowercaseWord:</string>
-						<reference key="source" ref="1014"/>
-						<reference key="destination" ref="879586729"/>
-					</object>
-					<int key="connectionID">468</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBActionConnection" key="connection">
-						<string key="label">pasteAsPlainText:</string>
-						<reference key="source" ref="1014"/>
-						<reference key="destination" ref="82994268"/>
-					</object>
-					<int key="connectionID">486</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBActionConnection" key="connection">
-						<string key="label">performFindPanelAction:</string>
-						<reference key="source" ref="1014"/>
-						<reference key="destination" ref="326711663"/>
-					</object>
-					<int key="connectionID">487</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBActionConnection" key="connection">
-						<string key="label">performFindPanelAction:</string>
-						<reference key="source" ref="1014"/>
-						<reference key="destination" ref="270902937"/>
-					</object>
-					<int key="connectionID">488</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBActionConnection" key="connection">
-						<string key="label">performFindPanelAction:</string>
-						<reference key="source" ref="1014"/>
-						<reference key="destination" ref="159080638"/>
-					</object>
-					<int key="connectionID">489</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBActionConnection" key="connection">
-						<string key="label">showHelp:</string>
-						<reference key="source" ref="1014"/>
-						<reference key="destination" ref="105068016"/>
-					</object>
-					<int key="connectionID">493</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBActionConnection" key="connection">
-						<string key="label">alignCenter:</string>
-						<reference key="source" ref="1014"/>
-						<reference key="destination" ref="630155264"/>
-					</object>
-					<int key="connectionID">518</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBActionConnection" key="connection">
-						<string key="label">pasteRuler:</string>
-						<reference key="source" ref="1014"/>
-						<reference key="destination" ref="883618387"/>
-					</object>
-					<int key="connectionID">519</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBActionConnection" key="connection">
-						<string key="label">toggleRuler:</string>
-						<reference key="source" ref="1014"/>
-						<reference key="destination" ref="644046920"/>
-					</object>
-					<int key="connectionID">520</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBActionConnection" key="connection">
-						<string key="label">alignRight:</string>
-						<reference key="source" ref="1014"/>
-						<reference key="destination" ref="512868991"/>
-					</object>
-					<int key="connectionID">521</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBActionConnection" key="connection">
-						<string key="label">copyRuler:</string>
-						<reference key="source" ref="1014"/>
-						<reference key="destination" ref="231811626"/>
-					</object>
-					<int key="connectionID">522</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBActionConnection" key="connection">
-						<string key="label">alignJustified:</string>
-						<reference key="source" ref="1014"/>
-						<reference key="destination" ref="945678886"/>
-					</object>
-					<int key="connectionID">523</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBActionConnection" key="connection">
-						<string key="label">alignLeft:</string>
-						<reference key="source" ref="1014"/>
-						<reference key="destination" ref="875092757"/>
-					</object>
-					<int key="connectionID">524</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBActionConnection" key="connection">
-						<string key="label">makeBaseWritingDirectionNatural:</string>
-						<reference key="source" ref="1014"/>
-						<reference key="destination" ref="551969625"/>
-					</object>
-					<int key="connectionID">525</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBActionConnection" key="connection">
-						<string key="label">makeBaseWritingDirectionLeftToRight:</string>
-						<reference key="source" ref="1014"/>
-						<reference key="destination" ref="249532473"/>
-					</object>
-					<int key="connectionID">526</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBActionConnection" key="connection">
-						<string key="label">makeBaseWritingDirectionRightToLeft:</string>
-						<reference key="source" ref="1014"/>
-						<reference key="destination" ref="607364498"/>
-					</object>
-					<int key="connectionID">527</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBActionConnection" key="connection">
-						<string key="label">makeTextWritingDirectionNatural:</string>
-						<reference key="source" ref="1014"/>
-						<reference key="destination" ref="380031999"/>
-					</object>
-					<int key="connectionID">528</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBActionConnection" key="connection">
-						<string key="label">makeTextWritingDirectionLeftToRight:</string>
-						<reference key="source" ref="1014"/>
-						<reference key="destination" ref="825984362"/>
-					</object>
-					<int key="connectionID">529</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBActionConnection" key="connection">
-						<string key="label">makeTextWritingDirectionRightToLeft:</string>
-						<reference key="source" ref="1014"/>
-						<reference key="destination" ref="560145579"/>
-					</object>
-					<int key="connectionID">530</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBActionConnection" key="connection">
-						<string key="label">performFindPanelAction:</string>
-						<reference key="source" ref="1014"/>
-						<reference key="destination" ref="738670835"/>
-					</object>
-					<int key="connectionID">535</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBOutletConnection" key="connection">
-						<string key="label">window</string>
-						<reference key="source" ref="976324537"/>
-						<reference key="destination" ref="972006081"/>
-					</object>
-					<int key="connectionID">532</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBActionConnection" key="connection">
-						<string key="label">remember:</string>
-						<reference key="source" ref="976324537"/>
-						<reference key="destination" ref="688522420"/>
-					</object>
-					<int key="connectionID">1176</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBActionConnection" key="connection">
-						<string key="label">send:</string>
-						<reference key="source" ref="976324537"/>
-						<reference key="destination" ref="93467784"/>
-					</object>
-					<int key="connectionID">1177</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBActionConnection" key="connection">
-						<string key="label">cancel:</string>
-						<reference key="source" ref="976324537"/>
-						<reference key="destination" ref="46276252"/>
-					</object>
-					<int key="connectionID">1178</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBOutletConnection" key="connection">
-						<string key="label">crashText</string>
-						<reference key="source" ref="976324537"/>
-						<reference key="destination" ref="1018085422"/>
-					</object>
-					<int key="connectionID">1179</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBOutletConnection" key="connection">
-						<string key="label">rememberCheck</string>
-						<reference key="source" ref="976324537"/>
-						<reference key="destination" ref="688522420"/>
-					</object>
-					<int key="connectionID">1187</int>
-				</object>
-			</array>
-			<object class="IBMutableOrderedSet" key="objectRecords">
-				<array key="orderedObjects">
-					<object class="IBObjectRecord">
-						<int key="objectID">0</int>
-						<array key="object" id="0"/>
-						<reference key="children" ref="1048"/>
-						<nil key="parent"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">-2</int>
-						<reference key="object" ref="1021"/>
-						<reference key="parent" ref="0"/>
-						<string key="objectName">File's Owner</string>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">-1</int>
-						<reference key="object" ref="1014"/>
-						<reference key="parent" ref="0"/>
-						<string key="objectName">First Responder</string>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">-3</int>
-						<reference key="object" ref="1050"/>
-						<reference key="parent" ref="0"/>
-						<string key="objectName">Application</string>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">29</int>
-						<reference key="object" ref="649796088"/>
-						<array class="NSMutableArray" key="children">
-							<reference ref="713487014"/>
-							<reference ref="694149608"/>
-							<reference ref="952259628"/>
-							<reference ref="379814623"/>
-							<reference ref="586577488"/>
-							<reference ref="302598603"/>
-							<reference ref="448692316"/>
-						</array>
-						<reference key="parent" ref="0"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">19</int>
-						<reference key="object" ref="713487014"/>
-						<array class="NSMutableArray" key="children">
-							<reference ref="835318025"/>
-						</array>
-						<reference key="parent" ref="649796088"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">56</int>
-						<reference key="object" ref="694149608"/>
-						<array class="NSMutableArray" key="children">
-							<reference ref="110575045"/>
-						</array>
-						<reference key="parent" ref="649796088"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">217</int>
-						<reference key="object" ref="952259628"/>
-						<array class="NSMutableArray" key="children">
-							<reference ref="789758025"/>
-						</array>
-						<reference key="parent" ref="649796088"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">83</int>
-						<reference key="object" ref="379814623"/>
-						<array class="NSMutableArray" key="children">
-							<reference ref="720053764"/>
-						</array>
-						<reference key="parent" ref="649796088"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">81</int>
-						<reference key="object" ref="720053764"/>
-						<array class="NSMutableArray" key="children">
-							<reference ref="1023925487"/>
-							<reference ref="49223823"/>
-							<reference ref="722745758"/>
-							<reference ref="705341025"/>
-							<reference ref="1025936716"/>
-							<reference ref="294629803"/>
-							<reference ref="776162233"/>
-							<reference ref="425164168"/>
-							<reference ref="579971712"/>
-							<reference ref="1010469920"/>
-						</array>
-						<reference key="parent" ref="379814623"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">75</int>
-						<reference key="object" ref="1023925487"/>
-						<reference key="parent" ref="720053764"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">78</int>
-						<reference key="object" ref="49223823"/>
-						<reference key="parent" ref="720053764"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">72</int>
-						<reference key="object" ref="722745758"/>
-						<reference key="parent" ref="720053764"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">82</int>
-						<reference key="object" ref="705341025"/>
-						<reference key="parent" ref="720053764"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">124</int>
-						<reference key="object" ref="1025936716"/>
-						<array class="NSMutableArray" key="children">
-							<reference ref="1065607017"/>
-						</array>
-						<reference key="parent" ref="720053764"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">77</int>
-						<reference key="object" ref="294629803"/>
-						<reference key="parent" ref="720053764"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">73</int>
-						<reference key="object" ref="776162233"/>
-						<reference key="parent" ref="720053764"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">79</int>
-						<reference key="object" ref="425164168"/>
-						<reference key="parent" ref="720053764"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">112</int>
-						<reference key="object" ref="579971712"/>
-						<reference key="parent" ref="720053764"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">74</int>
-						<reference key="object" ref="1010469920"/>
-						<reference key="parent" ref="720053764"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">125</int>
-						<reference key="object" ref="1065607017"/>
-						<array class="NSMutableArray" key="children">
-							<reference ref="759406840"/>
-						</array>
-						<reference key="parent" ref="1025936716"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">126</int>
-						<reference key="object" ref="759406840"/>
-						<reference key="parent" ref="1065607017"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">205</int>
-						<reference key="object" ref="789758025"/>
-						<array class="NSMutableArray" key="children">
-							<reference ref="437104165"/>
-							<reference ref="583158037"/>
-							<reference ref="1058277027"/>
-							<reference ref="212016141"/>
-							<reference ref="296257095"/>
-							<reference ref="29853731"/>
-							<reference ref="860595796"/>
-							<reference ref="1040322652"/>
-							<reference ref="790794224"/>
-							<reference ref="892235320"/>
-							<reference ref="972420730"/>
-							<reference ref="676164635"/>
-							<reference ref="507821607"/>
-							<reference ref="288088188"/>
-							<reference ref="82994268"/>
-						</array>
-						<reference key="parent" ref="952259628"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">202</int>
-						<reference key="object" ref="437104165"/>
-						<reference key="parent" ref="789758025"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">198</int>
-						<reference key="object" ref="583158037"/>
-						<reference key="parent" ref="789758025"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">207</int>
-						<reference key="object" ref="1058277027"/>
-						<reference key="parent" ref="789758025"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">214</int>
-						<reference key="object" ref="212016141"/>
-						<reference key="parent" ref="789758025"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">199</int>
-						<reference key="object" ref="296257095"/>
-						<reference key="parent" ref="789758025"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">203</int>
-						<reference key="object" ref="29853731"/>
-						<reference key="parent" ref="789758025"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">197</int>
-						<reference key="object" ref="860595796"/>
-						<reference key="parent" ref="789758025"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">206</int>
-						<reference key="object" ref="1040322652"/>
-						<reference key="parent" ref="789758025"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">215</int>
-						<reference key="object" ref="790794224"/>
-						<reference key="parent" ref="789758025"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">218</int>
-						<reference key="object" ref="892235320"/>
-						<array class="NSMutableArray" key="children">
-							<reference ref="963351320"/>
-						</array>
-						<reference key="parent" ref="789758025"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">216</int>
-						<reference key="object" ref="972420730"/>
-						<array class="NSMutableArray" key="children">
-							<reference ref="769623530"/>
-						</array>
-						<reference key="parent" ref="789758025"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">200</int>
-						<reference key="object" ref="769623530"/>
-						<array class="NSMutableArray" key="children">
-							<reference ref="948374510"/>
-							<reference ref="96193923"/>
-							<reference ref="679648819"/>
-							<reference ref="967646866"/>
-							<reference ref="859480356"/>
-							<reference ref="795346622"/>
-						</array>
-						<reference key="parent" ref="972420730"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">219</int>
-						<reference key="object" ref="948374510"/>
-						<reference key="parent" ref="769623530"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">201</int>
-						<reference key="object" ref="96193923"/>
-						<reference key="parent" ref="769623530"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">204</int>
-						<reference key="object" ref="679648819"/>
-						<reference key="parent" ref="769623530"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">220</int>
-						<reference key="object" ref="963351320"/>
-						<array class="NSMutableArray" key="children">
-							<reference ref="270902937"/>
-							<reference ref="88285865"/>
-							<reference ref="159080638"/>
-							<reference ref="326711663"/>
-							<reference ref="447796847"/>
-							<reference ref="738670835"/>
-						</array>
-						<reference key="parent" ref="892235320"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">213</int>
-						<reference key="object" ref="270902937"/>
-						<reference key="parent" ref="963351320"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">210</int>
-						<reference key="object" ref="88285865"/>
-						<reference key="parent" ref="963351320"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">221</int>
-						<reference key="object" ref="159080638"/>
-						<reference key="parent" ref="963351320"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">208</int>
-						<reference key="object" ref="326711663"/>
-						<reference key="parent" ref="963351320"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">209</int>
-						<reference key="object" ref="447796847"/>
-						<reference key="parent" ref="963351320"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">57</int>
-						<reference key="object" ref="110575045"/>
-						<array class="NSMutableArray" key="children">
-							<reference ref="238522557"/>
-							<reference ref="755159360"/>
-							<reference ref="908899353"/>
-							<reference ref="632727374"/>
-							<reference ref="646227648"/>
-							<reference ref="609285721"/>
-							<reference ref="481834944"/>
-							<reference ref="304266470"/>
-							<reference ref="1046388886"/>
-							<reference ref="1056857174"/>
-							<reference ref="342932134"/>
-						</array>
-						<reference key="parent" ref="694149608"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">58</int>
-						<reference key="object" ref="238522557"/>
-						<reference key="parent" ref="110575045"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">134</int>
-						<reference key="object" ref="755159360"/>
-						<reference key="parent" ref="110575045"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">150</int>
-						<reference key="object" ref="908899353"/>
-						<reference key="parent" ref="110575045"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">136</int>
-						<reference key="object" ref="632727374"/>
-						<reference key="parent" ref="110575045"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">144</int>
-						<reference key="object" ref="646227648"/>
-						<reference key="parent" ref="110575045"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">129</int>
-						<reference key="object" ref="609285721"/>
-						<reference key="parent" ref="110575045"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">143</int>
-						<reference key="object" ref="481834944"/>
-						<reference key="parent" ref="110575045"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">236</int>
-						<reference key="object" ref="304266470"/>
-						<reference key="parent" ref="110575045"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">131</int>
-						<reference key="object" ref="1046388886"/>
-						<array class="NSMutableArray" key="children">
-							<reference ref="752062318"/>
-						</array>
-						<reference key="parent" ref="110575045"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">149</int>
-						<reference key="object" ref="1056857174"/>
-						<reference key="parent" ref="110575045"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">145</int>
-						<reference key="object" ref="342932134"/>
-						<reference key="parent" ref="110575045"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">130</int>
-						<reference key="object" ref="752062318"/>
-						<reference key="parent" ref="1046388886"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">24</int>
-						<reference key="object" ref="835318025"/>
-						<array class="NSMutableArray" key="children">
-							<reference ref="299356726"/>
-							<reference ref="625202149"/>
-							<reference ref="575023229"/>
-							<reference ref="1011231497"/>
-						</array>
-						<reference key="parent" ref="713487014"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">92</int>
-						<reference key="object" ref="299356726"/>
-						<reference key="parent" ref="835318025"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">5</int>
-						<reference key="object" ref="625202149"/>
-						<reference key="parent" ref="835318025"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">239</int>
-						<reference key="object" ref="575023229"/>
-						<reference key="parent" ref="835318025"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">23</int>
-						<reference key="object" ref="1011231497"/>
-						<reference key="parent" ref="835318025"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">295</int>
-						<reference key="object" ref="586577488"/>
-						<array class="NSMutableArray" key="children">
-							<reference ref="466310130"/>
-						</array>
-						<reference key="parent" ref="649796088"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">296</int>
-						<reference key="object" ref="466310130"/>
-						<array class="NSMutableArray" key="children">
-							<reference ref="102151532"/>
-							<reference ref="237841660"/>
-						</array>
-						<reference key="parent" ref="586577488"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">297</int>
-						<reference key="object" ref="102151532"/>
-						<reference key="parent" ref="466310130"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">298</int>
-						<reference key="object" ref="237841660"/>
-						<reference key="parent" ref="466310130"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">211</int>
-						<reference key="object" ref="676164635"/>
-						<array class="NSMutableArray" key="children">
-							<reference ref="785027613"/>
-						</array>
-						<reference key="parent" ref="789758025"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">212</int>
-						<reference key="object" ref="785027613"/>
-						<array class="NSMutableArray" key="children">
-							<reference ref="680220178"/>
-							<reference ref="731782645"/>
-						</array>
-						<reference key="parent" ref="676164635"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">195</int>
-						<reference key="object" ref="680220178"/>
-						<reference key="parent" ref="785027613"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">196</int>
-						<reference key="object" ref="731782645"/>
-						<reference key="parent" ref="785027613"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">346</int>
-						<reference key="object" ref="967646866"/>
-						<reference key="parent" ref="769623530"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">348</int>
-						<reference key="object" ref="507821607"/>
-						<array class="NSMutableArray" key="children">
-							<reference ref="698887838"/>
-						</array>
-						<reference key="parent" ref="789758025"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">349</int>
-						<reference key="object" ref="698887838"/>
-						<array class="NSMutableArray" key="children">
-							<reference ref="605118523"/>
-							<reference ref="197661976"/>
-							<reference ref="708854459"/>
-							<reference ref="65139061"/>
-							<reference ref="19036812"/>
-							<reference ref="672708820"/>
-							<reference ref="537092702"/>
-						</array>
-						<reference key="parent" ref="507821607"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">350</int>
-						<reference key="object" ref="605118523"/>
-						<reference key="parent" ref="698887838"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">351</int>
-						<reference key="object" ref="197661976"/>
-						<reference key="parent" ref="698887838"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">354</int>
-						<reference key="object" ref="708854459"/>
-						<reference key="parent" ref="698887838"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">371</int>
-						<reference key="object" ref="972006081"/>
-						<array class="NSMutableArray" key="children">
-							<reference ref="439893737"/>
-						</array>
-						<reference key="parent" ref="0"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">372</int>
-						<reference key="object" ref="439893737"/>
-						<array class="NSMutableArray" key="children">
-							<reference ref="242877095"/>
-							<reference ref="1018085422"/>
-							<reference ref="688522420"/>
-							<object class="IBNSLayoutConstraint" id="109434655">
-								<reference key="firstItem" ref="242877095"/>
-								<int key="firstAttribute">3</int>
-								<int key="relation">0</int>
-								<reference key="secondItem" ref="439893737"/>
-								<int key="secondAttribute">3</int>
-								<float key="multiplier">1</float>
-								<object class="IBNSLayoutSymbolicConstant" key="constant">
-									<double key="value">20</double>
-								</object>
-								<float key="priority">1000</float>
-								<int key="scoringType">8</int>
-								<float key="scoringTypeFloat">29</float>
-								<int key="contentType">3</int>
-								<reference key="containingView" ref="439893737"/>
-							</object>
-							<reference ref="46276252"/>
-							<reference ref="93467784"/>
-							<object class="IBNSLayoutConstraint" id="166525974">
-								<reference key="firstItem" ref="439893737"/>
-								<int key="firstAttribute">6</int>
-								<int key="relation">0</int>
-								<reference key="secondItem" ref="242877095"/>
-								<int key="secondAttribute">6</int>
-								<float key="multiplier">1</float>
-								<object class="IBNSLayoutSymbolicConstant" key="constant">
-									<double key="value">20</double>
-								</object>
-								<float key="priority">1000</float>
-								<int key="scoringType">8</int>
-								<float key="scoringTypeFloat">29</float>
-								<int key="contentType">3</int>
-								<reference key="containingView" ref="439893737"/>
-							</object>
-							<object class="IBNSLayoutConstraint" id="229833409">
-								<reference key="firstItem" ref="242877095"/>
-								<int key="firstAttribute">5</int>
-								<int key="relation">0</int>
-								<reference key="secondItem" ref="439893737"/>
-								<int key="secondAttribute">5</int>
-								<float key="multiplier">1</float>
-								<object class="IBNSLayoutSymbolicConstant" key="constant">
-									<double key="value">20</double>
-								</object>
-								<float key="priority">1000</float>
-								<int key="scoringType">8</int>
-								<float key="scoringTypeFloat">29</float>
-								<int key="contentType">3</int>
-								<reference key="containingView" ref="439893737"/>
-							</object>
-							<object class="IBNSLayoutConstraint" id="992363278">
-								<reference key="firstItem" ref="439893737"/>
-								<int key="firstAttribute">6</int>
-								<int key="relation">0</int>
-								<reference key="secondItem" ref="1018085422"/>
-								<int key="secondAttribute">6</int>
-								<float key="multiplier">1</float>
-								<object class="IBNSLayoutSymbolicConstant" key="constant">
-									<double key="value">20</double>
-								</object>
-								<float key="priority">1000</float>
-								<int key="scoringType">8</int>
-								<float key="scoringTypeFloat">29</float>
-								<int key="contentType">3</int>
-								<reference key="containingView" ref="439893737"/>
-							</object>
-							<object class="IBNSLayoutConstraint" id="646866003">
-								<reference key="firstItem" ref="1018085422"/>
-								<int key="firstAttribute">5</int>
-								<int key="relation">0</int>
-								<reference key="secondItem" ref="439893737"/>
-								<int key="secondAttribute">5</int>
-								<float key="multiplier">1</float>
-								<object class="IBNSLayoutSymbolicConstant" key="constant">
-									<double key="value">20</double>
-								</object>
-								<float key="priority">1000</float>
-								<int key="scoringType">8</int>
-								<float key="scoringTypeFloat">29</float>
-								<int key="contentType">3</int>
-								<reference key="containingView" ref="439893737"/>
-							</object>
-							<object class="IBNSLayoutConstraint" id="98217052">
-								<reference key="firstItem" ref="439893737"/>
-								<int key="firstAttribute">4</int>
-								<int key="relation">0</int>
-								<reference key="secondItem" ref="1018085422"/>
-								<int key="secondAttribute">4</int>
-								<float key="multiplier">1</float>
-								<object class="IBLayoutConstant" key="constant">
-									<double key="value">64</double>
-								</object>
-								<float key="priority">1000</float>
-								<int key="scoringType">3</int>
-								<float key="scoringTypeFloat">9</float>
-								<int key="contentType">3</int>
-								<reference key="containingView" ref="439893737"/>
-							</object>
-							<object class="IBNSLayoutConstraint" id="578918264">
-								<reference key="firstItem" ref="439893737"/>
-								<int key="firstAttribute">6</int>
-								<int key="relation">0</int>
-								<reference key="secondItem" ref="46276252"/>
-								<int key="secondAttribute">6</int>
-								<float key="multiplier">1</float>
-								<object class="IBNSLayoutSymbolicConstant" key="constant">
-									<double key="value">20</double>
-								</object>
-								<float key="priority">1000</float>
-								<int key="scoringType">8</int>
-								<float key="scoringTypeFloat">29</float>
-								<int key="contentType">3</int>
-								<reference key="containingView" ref="439893737"/>
-							</object>
-							<object class="IBNSLayoutConstraint" id="591594339">
-								<reference key="firstItem" ref="688522420"/>
-								<int key="firstAttribute">5</int>
-								<int key="relation">0</int>
-								<reference key="secondItem" ref="439893737"/>
-								<int key="secondAttribute">5</int>
-								<float key="multiplier">1</float>
-								<object class="IBNSLayoutSymbolicConstant" key="constant">
-									<double key="value">20</double>
-								</object>
-								<float key="priority">1000</float>
-								<int key="scoringType">8</int>
-								<float key="scoringTypeFloat">29</float>
-								<int key="contentType">3</int>
-								<reference key="containingView" ref="439893737"/>
-							</object>
-							<object class="IBNSLayoutConstraint" id="432526715">
-								<reference key="firstItem" ref="439893737"/>
-								<int key="firstAttribute">4</int>
-								<int key="relation">0</int>
-								<reference key="secondItem" ref="688522420"/>
-								<int key="secondAttribute">4</int>
-								<float key="multiplier">1</float>
-								<object class="IBLayoutConstant" key="constant">
-									<double key="value">21</double>
-								</object>
-								<float key="priority">1000</float>
-								<int key="scoringType">3</int>
-								<float key="scoringTypeFloat">9</float>
-								<int key="contentType">3</int>
-								<reference key="containingView" ref="439893737"/>
-							</object>
-							<object class="IBNSLayoutConstraint" id="891430181">
-								<reference key="firstItem" ref="439893737"/>
-								<int key="firstAttribute">6</int>
-								<int key="relation">0</int>
-								<reference key="secondItem" ref="93467784"/>
-								<int key="secondAttribute">6</int>
-								<float key="multiplier">1</float>
-								<object class="IBLayoutConstant" key="constant">
-									<double key="value">132</double>
-								</object>
-								<float key="priority">1000</float>
-								<int key="scoringType">3</int>
-								<float key="scoringTypeFloat">9</float>
-								<int key="contentType">3</int>
-								<reference key="containingView" ref="439893737"/>
-							</object>
-							<object class="IBNSLayoutConstraint" id="833183002">
-								<reference key="firstItem" ref="93467784"/>
-								<int key="firstAttribute">11</int>
-								<int key="relation">0</int>
-								<reference key="secondItem" ref="46276252"/>
-								<int key="secondAttribute">11</int>
-								<float key="multiplier">1</float>
-								<object class="IBLayoutConstant" key="constant">
-									<double key="value">0.0</double>
-								</object>
-								<float key="priority">1000</float>
-								<int key="scoringType">6</int>
-								<float key="scoringTypeFloat">24</float>
-								<int key="contentType">2</int>
-								<reference key="containingView" ref="439893737"/>
-							</object>
-							<object class="IBNSLayoutConstraint" id="670714078">
-								<reference key="firstItem" ref="93467784"/>
-								<int key="firstAttribute">10</int>
-								<int key="relation">0</int>
-								<reference key="secondItem" ref="688522420"/>
-								<int key="secondAttribute">10</int>
-								<float key="multiplier">1</float>
-								<object class="IBLayoutConstant" key="constant">
-									<double key="value">0.0</double>
-								</object>
-								<float key="priority">1000</float>
-								<int key="scoringType">6</int>
-								<float key="scoringTypeFloat">24</float>
-								<int key="contentType">2</int>
-								<reference key="containingView" ref="439893737"/>
-							</object>
-						</array>
-						<reference key="parent" ref="972006081"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">375</int>
-						<reference key="object" ref="302598603"/>
-						<array class="NSMutableArray" key="children">
-							<reference ref="941447902"/>
-						</array>
-						<reference key="parent" ref="649796088"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">376</int>
-						<reference key="object" ref="941447902"/>
-						<array class="NSMutableArray" key="children">
-							<reference ref="792887677"/>
-							<reference ref="215659978"/>
-						</array>
-						<reference key="parent" ref="302598603"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">377</int>
-						<reference key="object" ref="792887677"/>
-						<array class="NSMutableArray" key="children">
-							<reference ref="786677654"/>
-						</array>
-						<reference key="parent" ref="941447902"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">388</int>
-						<reference key="object" ref="786677654"/>
-						<array class="NSMutableArray" key="children">
-							<reference ref="159677712"/>
-							<reference ref="305399458"/>
-							<reference ref="814362025"/>
-							<reference ref="330926929"/>
-							<reference ref="533507878"/>
-							<reference ref="158063935"/>
-							<reference ref="885547335"/>
-							<reference ref="901062459"/>
-							<reference ref="767671776"/>
-							<reference ref="691570813"/>
-							<reference ref="769124883"/>
-							<reference ref="739652853"/>
-							<reference ref="1012600125"/>
-							<reference ref="214559597"/>
-							<reference ref="596732606"/>
-							<reference ref="393423671"/>
-						</array>
-						<reference key="parent" ref="792887677"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">389</int>
-						<reference key="object" ref="159677712"/>
-						<reference key="parent" ref="786677654"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">390</int>
-						<reference key="object" ref="305399458"/>
-						<reference key="parent" ref="786677654"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">391</int>
-						<reference key="object" ref="814362025"/>
-						<reference key="parent" ref="786677654"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">392</int>
-						<reference key="object" ref="330926929"/>
-						<reference key="parent" ref="786677654"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">393</int>
-						<reference key="object" ref="533507878"/>
-						<reference key="parent" ref="786677654"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">394</int>
-						<reference key="object" ref="158063935"/>
-						<reference key="parent" ref="786677654"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">395</int>
-						<reference key="object" ref="885547335"/>
-						<reference key="parent" ref="786677654"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">396</int>
-						<reference key="object" ref="901062459"/>
-						<reference key="parent" ref="786677654"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">397</int>
-						<reference key="object" ref="767671776"/>
-						<array class="NSMutableArray" key="children">
-							<reference ref="175441468"/>
-						</array>
-						<reference key="parent" ref="786677654"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">398</int>
-						<reference key="object" ref="691570813"/>
-						<array class="NSMutableArray" key="children">
-							<reference ref="1058217995"/>
-						</array>
-						<reference key="parent" ref="786677654"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">399</int>
-						<reference key="object" ref="769124883"/>
-						<array class="NSMutableArray" key="children">
-							<reference ref="18263474"/>
-						</array>
-						<reference key="parent" ref="786677654"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">400</int>
-						<reference key="object" ref="739652853"/>
-						<reference key="parent" ref="786677654"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">401</int>
-						<reference key="object" ref="1012600125"/>
-						<reference key="parent" ref="786677654"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">402</int>
-						<reference key="object" ref="214559597"/>
-						<reference key="parent" ref="786677654"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">403</int>
-						<reference key="object" ref="596732606"/>
-						<reference key="parent" ref="786677654"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">404</int>
-						<reference key="object" ref="393423671"/>
-						<reference key="parent" ref="786677654"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">405</int>
-						<reference key="object" ref="18263474"/>
-						<array class="NSMutableArray" key="children">
-							<reference ref="257962622"/>
-							<reference ref="644725453"/>
-							<reference ref="1037576581"/>
-							<reference ref="941806246"/>
-							<reference ref="1045724900"/>
-						</array>
-						<reference key="parent" ref="769124883"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">406</int>
-						<reference key="object" ref="257962622"/>
-						<reference key="parent" ref="18263474"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">407</int>
-						<reference key="object" ref="644725453"/>
-						<reference key="parent" ref="18263474"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">408</int>
-						<reference key="object" ref="1037576581"/>
-						<reference key="parent" ref="18263474"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">409</int>
-						<reference key="object" ref="941806246"/>
-						<reference key="parent" ref="18263474"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">410</int>
-						<reference key="object" ref="1045724900"/>
-						<reference key="parent" ref="18263474"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">411</int>
-						<reference key="object" ref="1058217995"/>
-						<array class="NSMutableArray" key="children">
-							<reference ref="706297211"/>
-							<reference ref="568384683"/>
-							<reference ref="663508465"/>
-						</array>
-						<reference key="parent" ref="691570813"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">412</int>
-						<reference key="object" ref="706297211"/>
-						<reference key="parent" ref="1058217995"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">413</int>
-						<reference key="object" ref="568384683"/>
-						<reference key="parent" ref="1058217995"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">414</int>
-						<reference key="object" ref="663508465"/>
-						<reference key="parent" ref="1058217995"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">415</int>
-						<reference key="object" ref="175441468"/>
-						<array class="NSMutableArray" key="children">
-							<reference ref="252969304"/>
-							<reference ref="766922938"/>
-							<reference ref="677519740"/>
-							<reference ref="238351151"/>
-						</array>
-						<reference key="parent" ref="767671776"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">416</int>
-						<reference key="object" ref="252969304"/>
-						<reference key="parent" ref="175441468"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">417</int>
-						<reference key="object" ref="766922938"/>
-						<reference key="parent" ref="175441468"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">418</int>
-						<reference key="object" ref="677519740"/>
-						<reference key="parent" ref="175441468"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">419</int>
-						<reference key="object" ref="238351151"/>
-						<reference key="parent" ref="175441468"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">450</int>
-						<reference key="object" ref="288088188"/>
-						<array class="NSMutableArray" key="children">
-							<reference ref="579392910"/>
-						</array>
-						<reference key="parent" ref="789758025"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">451</int>
-						<reference key="object" ref="579392910"/>
-						<array class="NSMutableArray" key="children">
-							<reference ref="1060694897"/>
-							<reference ref="879586729"/>
-							<reference ref="56570060"/>
-						</array>
-						<reference key="parent" ref="288088188"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">452</int>
-						<reference key="object" ref="1060694897"/>
-						<reference key="parent" ref="579392910"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">453</int>
-						<reference key="object" ref="859480356"/>
-						<reference key="parent" ref="769623530"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">454</int>
-						<reference key="object" ref="795346622"/>
-						<reference key="parent" ref="769623530"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">457</int>
-						<reference key="object" ref="65139061"/>
-						<reference key="parent" ref="698887838"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">459</int>
-						<reference key="object" ref="19036812"/>
-						<reference key="parent" ref="698887838"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">460</int>
-						<reference key="object" ref="672708820"/>
-						<reference key="parent" ref="698887838"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">462</int>
-						<reference key="object" ref="537092702"/>
-						<reference key="parent" ref="698887838"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">465</int>
-						<reference key="object" ref="879586729"/>
-						<reference key="parent" ref="579392910"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">466</int>
-						<reference key="object" ref="56570060"/>
-						<reference key="parent" ref="579392910"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">485</int>
-						<reference key="object" ref="82994268"/>
-						<reference key="parent" ref="789758025"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">490</int>
-						<reference key="object" ref="448692316"/>
-						<array class="NSMutableArray" key="children">
-							<reference ref="992780483"/>
-						</array>
-						<reference key="parent" ref="649796088"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">491</int>
-						<reference key="object" ref="992780483"/>
-						<array class="NSMutableArray" key="children">
-							<reference ref="105068016"/>
-						</array>
-						<reference key="parent" ref="448692316"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">492</int>
-						<reference key="object" ref="105068016"/>
-						<reference key="parent" ref="992780483"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">494</int>
-						<reference key="object" ref="976324537"/>
-						<reference key="parent" ref="0"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">496</int>
-						<reference key="object" ref="215659978"/>
-						<array class="NSMutableArray" key="children">
-							<reference ref="446991534"/>
-						</array>
-						<reference key="parent" ref="941447902"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">497</int>
-						<reference key="object" ref="446991534"/>
-						<array class="NSMutableArray" key="children">
-							<reference ref="875092757"/>
-							<reference ref="630155264"/>
-							<reference ref="945678886"/>
-							<reference ref="512868991"/>
-							<reference ref="163117631"/>
-							<reference ref="31516759"/>
-							<reference ref="908105787"/>
-							<reference ref="644046920"/>
-							<reference ref="231811626"/>
-							<reference ref="883618387"/>
-						</array>
-						<reference key="parent" ref="215659978"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">498</int>
-						<reference key="object" ref="875092757"/>
-						<reference key="parent" ref="446991534"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">499</int>
-						<reference key="object" ref="630155264"/>
-						<reference key="parent" ref="446991534"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">500</int>
-						<reference key="object" ref="945678886"/>
-						<reference key="parent" ref="446991534"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">501</int>
-						<reference key="object" ref="512868991"/>
-						<reference key="parent" ref="446991534"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">502</int>
-						<reference key="object" ref="163117631"/>
-						<reference key="parent" ref="446991534"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">503</int>
-						<reference key="object" ref="31516759"/>
-						<array class="NSMutableArray" key="children">
-							<reference ref="956096989"/>
-						</array>
-						<reference key="parent" ref="446991534"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">504</int>
-						<reference key="object" ref="908105787"/>
-						<reference key="parent" ref="446991534"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">505</int>
-						<reference key="object" ref="644046920"/>
-						<reference key="parent" ref="446991534"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">506</int>
-						<reference key="object" ref="231811626"/>
-						<reference key="parent" ref="446991534"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">507</int>
-						<reference key="object" ref="883618387"/>
-						<reference key="parent" ref="446991534"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">508</int>
-						<reference key="object" ref="956096989"/>
-						<array class="NSMutableArray" key="children">
-							<reference ref="257099033"/>
-							<reference ref="551969625"/>
-							<reference ref="249532473"/>
-							<reference ref="607364498"/>
-							<reference ref="508151438"/>
-							<reference ref="981751889"/>
-							<reference ref="380031999"/>
-							<reference ref="825984362"/>
-							<reference ref="560145579"/>
-						</array>
-						<reference key="parent" ref="31516759"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">509</int>
-						<reference key="object" ref="257099033"/>
-						<reference key="parent" ref="956096989"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">510</int>
-						<reference key="object" ref="551969625"/>
-						<reference key="parent" ref="956096989"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">511</int>
-						<reference key="object" ref="249532473"/>
-						<reference key="parent" ref="956096989"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">512</int>
-						<reference key="object" ref="607364498"/>
-						<reference key="parent" ref="956096989"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">513</int>
-						<reference key="object" ref="508151438"/>
-						<reference key="parent" ref="956096989"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">514</int>
-						<reference key="object" ref="981751889"/>
-						<reference key="parent" ref="956096989"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">515</int>
-						<reference key="object" ref="380031999"/>
-						<reference key="parent" ref="956096989"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">516</int>
-						<reference key="object" ref="825984362"/>
-						<reference key="parent" ref="956096989"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">517</int>
-						<reference key="object" ref="560145579"/>
-						<reference key="parent" ref="956096989"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">534</int>
-						<reference key="object" ref="738670835"/>
-						<reference key="parent" ref="963351320"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">536</int>
-						<reference key="object" ref="242877095"/>
-						<array class="NSMutableArray" key="children">
-							<reference ref="502956757"/>
-							<object class="IBNSLayoutConstraint" id="697106875">
-								<reference key="firstItem" ref="242877095"/>
-								<int key="firstAttribute">8</int>
-								<int key="relation">0</int>
-								<nil key="secondItem"/>
-								<int key="secondAttribute">0</int>
-								<float key="multiplier">1</float>
-								<object class="IBLayoutConstant" key="constant">
-									<double key="value">229</double>
-								</object>
-								<float key="priority">1000</float>
-								<int key="scoringType">3</int>
-								<float key="scoringTypeFloat">9</float>
-								<int key="contentType">1</int>
-								<reference key="containingView" ref="242877095"/>
-							</object>
-						</array>
-						<reference key="parent" ref="439893737"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">537</int>
-						<reference key="object" ref="502956757"/>
-						<reference key="parent" ref="242877095"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">593</int>
-						<reference key="object" ref="1018085422"/>
-						<array class="NSMutableArray" key="children">
-							<reference ref="867418359"/>
-							<object class="IBNSLayoutConstraint" id="276483890">
-								<reference key="firstItem" ref="1018085422"/>
-								<int key="firstAttribute">8</int>
-								<int key="relation">0</int>
-								<nil key="secondItem"/>
-								<int key="secondAttribute">0</int>
-								<float key="multiplier">1</float>
-								<object class="IBLayoutConstant" key="constant">
-									<double key="value">163</double>
-								</object>
-								<float key="priority">1000</float>
-								<int key="scoringType">3</int>
-								<float key="scoringTypeFloat">9</float>
-								<int key="contentType">1</int>
-								<reference key="containingView" ref="1018085422"/>
-							</object>
-						</array>
-						<reference key="parent" ref="439893737"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">594</int>
-						<reference key="object" ref="867418359"/>
-						<reference key="parent" ref="1018085422"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">727</int>
-						<reference key="object" ref="688522420"/>
-						<array class="NSMutableArray" key="children">
-							<reference ref="445379790"/>
-							<object class="IBNSLayoutConstraint" id="337680523">
-								<reference key="firstItem" ref="688522420"/>
-								<int key="firstAttribute">7</int>
-								<int key="relation">0</int>
-								<nil key="secondItem"/>
-								<int key="secondAttribute">0</int>
-								<float key="multiplier">1</float>
-								<object class="IBLayoutConstant" key="constant">
-									<double key="value">183</double>
-								</object>
-								<float key="priority">1000</float>
-								<int key="scoringType">3</int>
-								<float key="scoringTypeFloat">9</float>
-								<int key="contentType">1</int>
-								<reference key="containingView" ref="688522420"/>
-							</object>
-							<object class="IBNSLayoutConstraint" id="73036966">
-								<reference key="firstItem" ref="688522420"/>
-								<int key="firstAttribute">8</int>
-								<int key="relation">0</int>
-								<nil key="secondItem"/>
-								<int key="secondAttribute">0</int>
-								<float key="multiplier">1</float>
-								<object class="IBLayoutConstant" key="constant">
-									<double key="value">22</double>
-								</object>
-								<float key="priority">1000</float>
-								<int key="scoringType">3</int>
-								<float key="scoringTypeFloat">9</float>
-								<int key="contentType">1</int>
-								<reference key="containingView" ref="688522420"/>
-							</object>
-						</array>
-						<reference key="parent" ref="439893737"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">728</int>
-						<reference key="object" ref="445379790"/>
-						<reference key="parent" ref="688522420"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">775</int>
-						<reference key="object" ref="93467784"/>
-						<array class="NSMutableArray" key="children">
-							<reference ref="623922320"/>
-						</array>
-						<reference key="parent" ref="439893737"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">776</int>
-						<reference key="object" ref="623922320"/>
-						<reference key="parent" ref="93467784"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">780</int>
-						<reference key="object" ref="46276252"/>
-						<array class="NSMutableArray" key="children">
-							<reference ref="398179500"/>
-							<object class="IBNSLayoutConstraint" id="944606221">
-								<reference key="firstItem" ref="46276252"/>
-								<int key="firstAttribute">7</int>
-								<int key="relation">0</int>
-								<nil key="secondItem"/>
-								<int key="secondAttribute">0</int>
-								<float key="multiplier">1</float>
-								<object class="IBLayoutConstant" key="constant">
-									<double key="value">100</double>
-								</object>
-								<float key="priority">1000</float>
-								<int key="scoringType">3</int>
-								<float key="scoringTypeFloat">9</float>
-								<int key="contentType">1</int>
-								<reference key="containingView" ref="46276252"/>
-							</object>
-						</array>
-						<reference key="parent" ref="439893737"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">781</int>
-						<reference key="object" ref="398179500"/>
-						<reference key="parent" ref="46276252"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">884</int>
-						<reference key="object" ref="109434655"/>
-						<reference key="parent" ref="439893737"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">981</int>
-						<reference key="object" ref="229833409"/>
-						<reference key="parent" ref="439893737"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">982</int>
-						<reference key="object" ref="992363278"/>
-						<reference key="parent" ref="439893737"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">1022</int>
-						<reference key="object" ref="98217052"/>
-						<reference key="parent" ref="439893737"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">1026</int>
-						<reference key="object" ref="276483890"/>
-						<reference key="parent" ref="1018085422"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">979</int>
-						<reference key="object" ref="166525974"/>
-						<reference key="parent" ref="439893737"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">985</int>
-						<reference key="object" ref="646866003"/>
-						<reference key="parent" ref="439893737"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">977</int>
-						<reference key="object" ref="697106875"/>
-						<reference key="parent" ref="242877095"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">1099</int>
-						<reference key="object" ref="337680523"/>
-						<reference key="parent" ref="688522420"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">1093</int>
-						<reference key="object" ref="578918264"/>
-						<reference key="parent" ref="439893737"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">1100</int>
-						<reference key="object" ref="73036966"/>
-						<reference key="parent" ref="688522420"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">1098</int>
-						<reference key="object" ref="432526715"/>
-						<reference key="parent" ref="439893737"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">1168</int>
-						<reference key="object" ref="670714078"/>
-						<reference key="parent" ref="439893737"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">1167</int>
-						<reference key="object" ref="833183002"/>
-						<reference key="parent" ref="439893737"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">1095</int>
-						<reference key="object" ref="591594339"/>
-						<reference key="parent" ref="439893737"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">1166</int>
-						<reference key="object" ref="891430181"/>
-						<reference key="parent" ref="439893737"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">1076</int>
-						<reference key="object" ref="944606221"/>
-						<reference key="parent" ref="46276252"/>
-					</object>
-				</array>
-			</object>
-			<dictionary class="NSMutableDictionary" key="flattenedProperties">
-				<string key="-1.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="-2.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="-3.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="1022.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="1026.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="1076.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="1093.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="1095.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="1098.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="1099.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="1100.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="112.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="1166.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="1167.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="1168.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="124.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="125.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="126.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="129.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="130.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="131.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="134.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="136.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="143.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="144.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="145.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="149.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="150.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="19.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="195.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="196.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="197.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="198.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="199.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="200.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="201.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="202.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="203.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="204.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="205.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="206.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="207.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="208.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="209.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="210.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="211.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="212.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="213.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="214.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="215.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="216.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="217.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="218.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="219.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="220.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="221.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="23.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="236.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="239.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="24.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="29.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="295.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="296.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="297.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="298.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="346.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="348.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="349.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="350.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="351.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="354.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="371.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="371.IBWindowTemplateEditedContentRect">{{380, 496}, {480, 360}}</string>
-				<integer value="1" key="371.NSWindowTemplate.visibleAtLaunch"/>
-				<array class="NSMutableArray" key="372.IBNSViewMetadataConstraints">
-					<reference ref="109434655"/>
-					<reference ref="166525974"/>
-					<reference ref="229833409"/>
-					<reference ref="992363278"/>
-					<reference ref="646866003"/>
-					<reference ref="98217052"/>
-					<reference ref="578918264"/>
-					<reference ref="591594339"/>
-					<reference ref="432526715"/>
-					<reference ref="891430181"/>
-					<reference ref="833183002"/>
-					<reference ref="670714078"/>
-				</array>
-				<string key="372.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<reference key="372.IBUserGuides" ref="0"/>
-				<string key="375.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="376.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="377.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="388.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="389.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="390.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="391.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="392.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="393.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="394.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="395.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="396.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="397.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="398.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="399.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="400.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="401.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="402.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="403.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="404.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="405.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="406.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="407.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="408.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="409.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="410.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="411.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="412.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="413.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="414.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="415.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="416.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="417.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="418.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="419.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="450.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="451.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="452.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="453.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="454.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="457.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="459.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="460.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="462.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="465.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="466.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="485.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="490.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="491.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="492.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="494.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="496.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="497.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="498.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="499.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="5.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="500.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="501.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="502.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="503.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="504.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="505.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="506.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="507.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="508.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="509.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="510.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="511.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="512.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="513.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="514.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="515.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="516.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="517.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="534.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<array class="NSMutableArray" key="536.IBNSViewMetadataConstraints">
-					<reference ref="697106875"/>
-				</array>
-				<boolean value="NO" key="536.IBNSViewMetadataTranslatesAutoresizingMaskIntoConstraints"/>
-				<string key="536.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="537.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="56.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="57.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="58.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<array class="NSMutableArray" key="593.IBNSViewMetadataConstraints">
-					<reference ref="276483890"/>
-				</array>
-				<boolean value="NO" key="593.IBNSViewMetadataTranslatesAutoresizingMaskIntoConstraints"/>
-				<string key="593.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="594.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="72.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<array class="NSMutableArray" key="727.IBNSViewMetadataConstraints">
-					<reference ref="337680523"/>
-					<reference ref="73036966"/>
-				</array>
-				<boolean value="NO" key="727.IBNSViewMetadataTranslatesAutoresizingMaskIntoConstraints"/>
-				<string key="727.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="728.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="73.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="74.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="75.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="77.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<boolean value="NO" key="775.IBNSViewMetadataTranslatesAutoresizingMaskIntoConstraints"/>
-				<string key="775.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="776.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="78.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<array class="NSMutableArray" key="780.IBNSViewMetadataConstraints">
-					<reference ref="944606221"/>
-				</array>
-				<boolean value="NO" key="780.IBNSViewMetadataTranslatesAutoresizingMaskIntoConstraints"/>
-				<string key="780.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="781.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="79.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="81.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="82.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="83.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="884.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="92.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="977.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="979.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="981.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="982.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-				<string key="985.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-			</dictionary>
-			<dictionary class="NSMutableDictionary" key="unlocalizedProperties"/>
-			<nil key="activeLocalization"/>
-			<dictionary class="NSMutableDictionary" key="localizations"/>
-			<nil key="sourceID"/>
-			<int key="maxID">1187</int>
-		</object>
-		<object class="IBClassDescriber" key="IBDocument.Classes">
-			<array class="NSMutableArray" key="referencedPartialClassDescriptions">
-				<object class="IBPartialClassDescription">
-					<string key="className">LLCrashLoggerMacDelegate</string>
-					<string key="superclassName">NSObject</string>
-					<dictionary class="NSMutableDictionary" key="actions">
-						<string key="cancel:">id</string>
-						<string key="remember:">id</string>
-						<string key="send:">id</string>
-					</dictionary>
-					<dictionary class="NSMutableDictionary" key="actionInfosByName">
-						<object class="IBActionInfo" key="cancel:">
-							<string key="name">cancel:</string>
-							<string key="candidateClassName">id</string>
-						</object>
-						<object class="IBActionInfo" key="remember:">
-							<string key="name">remember:</string>
-							<string key="candidateClassName">id</string>
-						</object>
-						<object class="IBActionInfo" key="send:">
-							<string key="name">send:</string>
-							<string key="candidateClassName">id</string>
-						</object>
-					</dictionary>
-					<dictionary class="NSMutableDictionary" key="outlets">
-						<string key="crashText">NSTextField</string>
-						<string key="rememberCheck">NSButton</string>
-						<string key="window">NSWindow</string>
-					</dictionary>
-					<dictionary class="NSMutableDictionary" key="toOneOutletInfosByName">
-						<object class="IBToOneOutletInfo" key="crashText">
-							<string key="name">crashText</string>
-							<string key="candidateClassName">NSTextField</string>
-						</object>
-						<object class="IBToOneOutletInfo" key="rememberCheck">
-							<string key="name">rememberCheck</string>
-							<string key="candidateClassName">NSButton</string>
-						</object>
-						<object class="IBToOneOutletInfo" key="window">
-							<string key="name">window</string>
-							<string key="candidateClassName">NSWindow</string>
-						</object>
-					</dictionary>
-					<object class="IBClassDescriptionSource" key="sourceIdentifier">
-						<string key="majorKey">IBProjectSource</string>
-						<string key="minorKey">./Classes/LLCrashLoggerMacDelegate.h</string>
-					</object>
-				</object>
-				<object class="IBPartialClassDescription">
-					<string key="className">NSLayoutConstraint</string>
-					<string key="superclassName">NSObject</string>
-					<object class="IBClassDescriptionSource" key="sourceIdentifier">
-						<string key="majorKey">IBProjectSource</string>
-						<string key="minorKey">./Classes/NSLayoutConstraint.h</string>
-					</object>
-				</object>
-			</array>
-		</object>
-		<int key="IBDocument.localizationMode">0</int>
-		<string key="IBDocument.TargetRuntimeIdentifier">IBCocoaFramework</string>
-		<object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDependencies">
-			<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin.macosx</string>
-			<integer value="1070" key="NS.object.0"/>
-		</object>
-		<bool key="IBDocument.PluginDeclaredDependenciesTrackSystemTargetVersion">YES</bool>
-		<int key="IBDocument.defaultPropertyAccessControl">3</int>
-		<dictionary class="NSMutableDictionary" key="IBDocument.LastKnownImageSizes">
-			<string key="NSMenuCheckmark">{11, 11}</string>
-			<string key="NSMenuMixedState">{10, 3}</string>
-			<string key="NSSwitch">{15, 15}</string>
-		</dictionary>
-		<bool key="IBDocument.UseAutolayout">YES</bool>
-	</data>
-</archive>
diff --git a/indra/mac_crash_logger/Info.plist b/indra/mac_crash_logger/Info.plist
deleted file mode 100644
index 2ebed11c3f972ea954fee54293be52282e776a50..0000000000000000000000000000000000000000
--- a/indra/mac_crash_logger/Info.plist
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
-	<key>CFBundleDevelopmentRegion</key>
-	<string>English</string>
-	<key>CFBundleExecutable</key>
-	<string>mac-crash-logger</string>
-	<key>CFBundleGetInfoString</key>
-	<string></string>
-	<key>CFBundleIconFile</key>
-	<string></string>
-	<key>CFBundleInfoDictionaryVersion</key>
-	<string>6.0</string>
-	<key>CFBundlePackageType</key>
-	<string>APPL</string>
-	<key>CFBundleShortVersionString</key>
-	<string></string>
-	<key>CFBundleSignature</key>
-	<string>????</string>
-	<key>CFBundleVersion</key>
-	<string>1.0.0</string>
-	<key>NSMainNibFile</key>
-	<string>CrashReporter</string>
-	<key>NSPrincipalClass</key>
-	<string>NSApplication</string>
-</dict>
-</plist>
diff --git a/indra/mac_crash_logger/llcrashloggermac.cpp b/indra/mac_crash_logger/llcrashloggermac.cpp
deleted file mode 100644
index ec3616e26a93a173c052407a62c0e46cae31b3ea..0000000000000000000000000000000000000000
--- a/indra/mac_crash_logger/llcrashloggermac.cpp
+++ /dev/null
@@ -1,91 +0,0 @@
-/** 
- * @file llcrashloggermac.cpp
- * @brief Mac OSX crash logger implementation
- *
- * $LicenseInfo:firstyear=2003&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 "llcrashloggermac.h"
-
-#include <iostream>
-
-#include "indra_constants.h"	// CRASH_BEHAVIOR_ASK, CRASH_SETTING_NAME
-#include "llerror.h"
-#include "llfile.h"
-#include "lltimer.h"
-#include "llstring.h"
-#include "lldir.h"
-#include "llsdserialize.h"
-
-// Windows Message Handlers
-
-BOOL gFirstDialog = TRUE;	
-LLFILE *gDebugFile = NULL;
-
-std::string gUserNotes = "";
-bool gSendReport = false;
-bool gRememberChoice = false;
-
-LLCrashLoggerMac::LLCrashLoggerMac(void)
-{
-}
-
-LLCrashLoggerMac::~LLCrashLoggerMac(void)
-{
-}
-
-bool LLCrashLoggerMac::init(void)
-{	
-	bool ok = LLCrashLogger::init();
-    return ok;
-}
-
-void LLCrashLoggerMac::gatherPlatformSpecificFiles()
-{
-}
-
-bool LLCrashLoggerMac::frame()
-{
-
-    if (mCrashBehavior == CRASH_BEHAVIOR_ALWAYS_SEND)
-	{
-		gSendReport = true;
-	}
-	
-	if(gSendReport)
-	{
-		setUserText(gUserNotes);
-		sendCrashLogs();
-	}	
-
-	LL_INFOS() << "Sending of logs complete" << LL_ENDL;
-		
-	return true;
-}
-
-bool LLCrashLoggerMac::cleanup()
-{
-	commonCleanup();
-    mKeyMaster.releaseMaster();
-	return true;
-}
diff --git a/indra/mac_crash_logger/llcrashloggermac.h b/indra/mac_crash_logger/llcrashloggermac.h
deleted file mode 100644
index 05ef8c9f53976161c8ac392a9ea8f095a64ac75d..0000000000000000000000000000000000000000
--- a/indra/mac_crash_logger/llcrashloggermac.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/** 
- * @file llcrashloggermac.h
- * @brief Mac OSX crash logger definition
- *
- * $LicenseInfo:firstyear=2003&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 LLCRASHLOGGERMAC_H
-#define LLCRASHLOGGERMAC_H
-
-#include "linden_common.h"
-#include "llcrashlogger.h"
-#include "llstring.h"
-
-class LLCrashLoggerMac : public LLCrashLogger
-{
-public:
-	LLCrashLoggerMac(void);
-	~LLCrashLoggerMac(void);
-	virtual bool init();
-	virtual bool frame();
-	virtual bool cleanup();
-	virtual void gatherPlatformSpecificFiles();
-};
-
-#endif
diff --git a/indra/mac_crash_logger/llcrashloggermacdelegate.h b/indra/mac_crash_logger/llcrashloggermacdelegate.h
deleted file mode 100644
index c998a8efe2444df63918693f88700204cea38372..0000000000000000000000000000000000000000
--- a/indra/mac_crash_logger/llcrashloggermacdelegate.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/** 
- * @file llcrashloggermacdelegate.h
- * @brief Mac OSX crash logger implementation
- *
- * $LicenseInfo:firstyear=2003&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$
- */
-
-/*
-#import <Cocoa/Cocoa.h>
-
-@interface LLCrashLoggerMacDelegate : NSObject <NSApplicationDelegate>
-{
-    IBOutlet NSTextField *crashText;
-    IBOutlet NSButton *rememberCheck;
-    
-    NSWindow *_window;
-    bool mRemember;
-
-}
-
-- (void)setWindow:(NSWindow *)newWindow;
-- (NSWindow *)window;
-
-- (IBAction)remember:(id)sender;
-- (IBAction)send:(id)sender;
-- (IBAction)cancel:(id)sender;
-
-@property (assign) IBOutlet NSWindow *window;
-
-@end
-*/
-
-
diff --git a/indra/mac_crash_logger/llcrashloggermacdelegate.mm b/indra/mac_crash_logger/llcrashloggermacdelegate.mm
deleted file mode 100644
index b2af76a47cc1d98f8168b482ba7122bcdf70a647..0000000000000000000000000000000000000000
--- a/indra/mac_crash_logger/llcrashloggermacdelegate.mm
+++ /dev/null
@@ -1,75 +0,0 @@
-/** 
- * @file llcrashloggermacdelegate.mm
- * @brief Mac OSX crash logger implementation
- *
- * $LicenseInfo:firstyear=2003&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$
- */
-
-
-/*
-#import "llcrashloggermacdelegate.h"
-#include <iostream>
-
-extern std::string gUserNotes;
-extern bool gSendReport;
-extern bool gRememberChoice;
-
-@implementation LLCrashLoggerMacDelegate
-
-- (void)setWindow:(NSWindow *)window
-{
-    _window = window;
-}
-
-- (NSWindow *)window
-{
-    return _window;
-}
-
-- (void)dealloc
-{
-    [super dealloc];
-}
-
-std::string* NSToString( NSString *ns_str )
-{
-    return ( new std::string([ns_str UTF8String]) );
-}
-
-- (IBAction)remember:(id)sender
-{
-    gRememberChoice = [rememberCheck state];
-}
-
-- (IBAction)send:(id)sender
-{
-    std::string* user_input = NSToString([crashText stringValue]);
-    gUserNotes = *user_input;
-    gSendReport = true;
-}
-
-- (IBAction)cancel:(id)sender
-{
-    [ _window close];
-}
-@end
-*/
\ No newline at end of file
diff --git a/indra/mac_crash_logger/mac_crash_logger.cpp b/indra/mac_crash_logger/mac_crash_logger.cpp
deleted file mode 100644
index 54e41a1954d927894dc394d2112841e2550903d0..0000000000000000000000000000000000000000
--- a/indra/mac_crash_logger/mac_crash_logger.cpp
+++ /dev/null
@@ -1,58 +0,0 @@
-/** 
- * @file mac_crash_logger.cpp
- * @brief Mac OSX crash logger implementation
- *
- * $LicenseInfo:firstyear=2003&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 "linden_common.h"
-#include "llcrashloggermac.h"
-#include "indra_constants.h"
-#include "llpidlock.h"
-
-#include <iostream>
-    
-int main(int argc, char **argv)
-{
-	LLCrashLoggerMac app;
-	app.parseCommandOptions(argc, argv);
-
-    LLSD options = LLApp::instance()->getOptionData(
-                        LLApp::PRIORITY_COMMAND_LINE);
-    
-	if (! app.init())
-	{
-		LL_WARNS() << "Unable to initialize application." << LL_ENDL;
-		return 1;
-	}
-
-    if (app.getCrashBehavior() != CRASH_BEHAVIOR_ALWAYS_SEND)
-    {
-//        return NSApplicationMain(argc, (const char **)argv);
-    }
-	app.frame();
-	app.cleanup();
-
-	LL_INFOS() << "Crash reporter finished normally." << LL_ENDL;
-    
-	return 0;
-}
diff --git a/indra/media_plugins/cef/CMakeLists.txt b/indra/media_plugins/cef/CMakeLists.txt
index ce6278963db537bc1f2498b37dd27d4fe9ae4b88..76d398576c9b43493ccedd57e06b10b9c777d337 100644
--- a/indra/media_plugins/cef/CMakeLists.txt
+++ b/indra/media_plugins/cef/CMakeLists.txt
@@ -111,9 +111,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/libvlc/media_plugin_libvlc.cpp b/indra/media_plugins/libvlc/media_plugin_libvlc.cpp
index f7d35b33c281becebf0053bbb8a550b2ea1f4f07..5d4a488e64c7b61775df0b41b1c712ecc3500a5a 100644
--- a/indra/media_plugins/libvlc/media_plugin_libvlc.cpp
+++ b/indra/media_plugins/libvlc/media_plugin_libvlc.cpp
@@ -34,6 +34,11 @@
 #include "llpluginmessageclasses.h"
 #include "media_plugin_base.h"
 
+#if defined(_MSC_VER)
+#include <basetsd.h>
+typedef SSIZE_T ssize_t;
+#endif
+
 #include "vlc/vlc.h"
 #include "vlc/libvlc_version.h"
 
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 87caca56af1d14067632cac3304742b4c1c19551..631089f6ceb323aee639224ff2306afa9054476f 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -47,6 +47,7 @@ include(OpenGL)
 include(OpenSSL)
 include(PNG)
 include(TemplateCheck)
+include(Tracy)
 include(UI)
 include(UnixInstall)
 include(ViewerMiscLibs)
@@ -92,6 +93,7 @@ include_directories(
     ${LIBS_PREBUILT_DIR}/include/collada/1.4
     ${LLAPPEARANCE_INCLUDE_DIRS}
     ${CMAKE_CURRENT_SOURCE_DIR}
+    ${TRACY_INCLUDE_DIR}
     )
 
 include_directories(SYSTEM
@@ -587,7 +589,6 @@ set(viewer_SOURCE_FILES
     llsyntaxid.cpp
     llsyswellitem.cpp
     llsyswellwindow.cpp
-    lltelemetry.cpp
     llteleporthistory.cpp
     llteleporthistorystorage.cpp
     lltextureatlas.cpp
@@ -1835,10 +1836,6 @@ if (WINDOWS)
       ${CMAKE_CURRENT_SOURCE_DIR}/licenses-win32.txt
       ${CMAKE_CURRENT_SOURCE_DIR}/featuretable.txt
       ${CMAKE_CURRENT_SOURCE_DIR}/featuretable_xp.txt
-      ${ARCH_PREBUILT_DIRS_RELEASE}/libeay32.dll
-      ${ARCH_PREBUILT_DIRS_RELEASE}/ssleay32.dll
-      ${ARCH_PREBUILT_DIRS_DEBUG}/libeay32.dll
-      ${ARCH_PREBUILT_DIRS_DEBUG}/ssleay32.dll
       ${viewer_APPSETTINGS_FILES}
       SLPlugin
       media_plugin_cef
@@ -1855,11 +1852,15 @@ if (WINDOWS)
         list(APPEND COPY_INPUT_DEPENDENCIES
             ${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/vivoxsdk_x64.dll
             ${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/ortp_x64.dll
+           ${ARCH_PREBUILT_DIRS_RELEASE}/libcrypto-1_1-x64.dll
+           ${ARCH_PREBUILT_DIRS_RELEASE}/libssl-1_1-x64.dll
             )
     else (ADDRESS_SIZE EQUAL 64)
         list(APPEND COPY_INPUT_DEPENDENCIES
             ${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/vivoxsdk.dll
             ${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/ortp.dll
+            ${ARCH_PREBUILT_DIRS_RELEASE}/libcrypto-1_1.dll
+            ${ARCH_PREBUILT_DIRS_RELEASE}/libssl-1_1.dll
             )
     endif (ADDRESS_SIZE EQUAL 64)
 
@@ -1913,11 +1914,9 @@ if (WINDOWS)
       add_dependencies(${VIEWER_BINARY_NAME} copy_win_scripts)
     endif (EXISTS ${CMAKE_SOURCE_DIR}/copy_win_scripts)
 
-    add_dependencies(${VIEWER_BINARY_NAME} SLPlugin)
-
-    if (NOT USE_BUGSPLAT)
-        add_dependencies(${VIEWER_BINARY_NAME} windows-crash-logger)
-    endif (NOT USE_BUGSPLAT)
+    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)
@@ -2067,6 +2066,7 @@ target_link_libraries(${VIEWER_BINARY_NAME}
     ${LLPHYSICS_LIBRARIES}
     ${LLPHYSICSEXTENSIONS_LIBRARIES}
     ${LLAPPEARANCE_LIBRARIES}
+    ${TRACY_LIBRARY}
     )
 
 if (USE_BUGSPLAT)
@@ -2226,10 +2226,6 @@ if (DARWIN)
 
   add_dependencies(${VIEWER_BINARY_NAME} SLPlugin media_plugin_libvlc media_plugin_cef)
 
-  if (NOT USE_BUGSPLAT)
-      add_dependencies(${VIEWER_BINARY_NAME} mac-crash-logger)
-  endif (NOT USE_BUGSPLAT)
-
   if (ENABLE_SIGNING)
       set(SIGNING_SETTING "--signature=${SIGNING_IDENTITY}")
   else (ENABLE_SIGNING)
@@ -2271,62 +2267,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 (NOT USE_BUGSPLAT)
-    # Breakpad symbol-file generation
-    set(SYMBOL_SEARCH_DIRS "")
-    if (WINDOWS)
-      list(APPEND SYMBOL_SEARCH_DIRS "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}")
-      # slplugin.exe failing symbols dump - need to debug, might have to do with updated version of google breakpad
-      # set(VIEWER_EXE_GLOBS "${VIEWER_BINARY_NAME}${CMAKE_EXECUTABLE_SUFFIX} slplugin.exe")
-      set(VIEWER_EXE_GLOBS "${VIEWER_BINARY_NAME}${CMAKE_EXECUTABLE_SUFFIX}")
-      set(VIEWER_LIB_GLOB "*${CMAKE_SHARED_MODULE_SUFFIX}")
-      set(VIEWER_COPY_MANIFEST copy_w_viewer_manifest)
-    endif (WINDOWS)
-    if (DARWIN)
-      list(APPEND SYMBOL_SEARCH_DIRS "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}")
-      # *TODO: Generate these search dirs in the cmake files related to each binary.
-      list(APPEND SYMBOL_SEARCH_DIRS "${CMAKE_BINARY_DIR}/llplugin/slplugin/${CMAKE_CFG_INTDIR}")
-      list(APPEND SYMBOL_SEARCH_DIRS "${CMAKE_BINARY_DIR}/mac_crash_logger/${CMAKE_CFG_INTDIR}")
-      list(APPEND SYMBOL_SEARCH_DIRS "${CMAKE_BINARY_DIR}/media_plugins/gstreamer010/${CMAKE_CFG_INTDIR}")
-      set(VIEWER_EXE_GLOBS "'${product}' SLPlugin")
-      set(VIEWER_EXE_GLOBS "'${product}' mac-crash-logger")
-      set(VIEWER_LIB_GLOB "*.dylib")
-    endif (DARWIN)
-    if (LINUX)
-      list(APPEND SYMBOL_SEARCH_DIRS "${CMAKE_CURRENT_BINARY_DIR}/packaged")
-      set(VIEWER_EXE_GLOBS "do-not-directly-run-secondlife-bin SLPlugin")
-      set(VIEWER_EXE_GLOBS "do-not-directly-run-secondlife-bin")
-      set(VIEWER_LIB_GLOB "*${CMAKE_SHARED_MODULE_SUFFIX}*")
-      set(VIEWER_COPY_MANIFEST copy_l_viewer_manifest)
-    endif (LINUX)
-
-    if(CMAKE_CFG_INTDIR STREQUAL ".")
-        set(LLBUILD_CONFIG ${CMAKE_BUILD_TYPE})
-    else(CMAKE_CFG_INTDIR STREQUAL ".")
-        # set LLBUILD_CONFIG to be a shell variable evaluated at build time
-        # reflecting the configuration we are currently building.
-        set(LLBUILD_CONFIG ${CMAKE_CFG_INTDIR})
-    endif(CMAKE_CFG_INTDIR STREQUAL ".")
-    add_custom_command(OUTPUT "${VIEWER_SYMBOL_FILE}"
-      COMMAND "${PYTHON_EXECUTABLE}"
-      ARGS
-        "${CMAKE_CURRENT_SOURCE_DIR}/generate_breakpad_symbols.py"
-        "${LLBUILD_CONFIG}"
-        "${SYMBOL_SEARCH_DIRS}"
-        "${VIEWER_EXE_GLOBS}"
-        "${VIEWER_LIB_GLOB}"
-        "${AUTOBUILD_INSTALL_DIR}/bin/dump_syms"
-        "${VIEWER_SYMBOL_FILE}"
-      DEPENDS generate_breakpad_symbols.py
-          VERBATIM)
-
-    add_custom_target(generate_symbols DEPENDS "${VIEWER_SYMBOL_FILE}" ${VIEWER_BINARY_NAME} "${VIEWER_COPY_MANIFEST}")
-    add_dependencies(generate_symbols ${VIEWER_BINARY_NAME})
-    if (WINDOWS OR LINUX)
-      add_dependencies(generate_symbols "${VIEWER_COPY_MANIFEST}")
-    endif (WINDOWS OR LINUX)
-
-  else (NOT USE_BUGSPLAT)
+  if (BUGSPLAT_DB)
     # BugSplat symbol-file generation
     if (WINDOWS)
       # Just pack up a tarball containing only the .pdb file for the
@@ -2410,7 +2351,7 @@ if (PACKAGE AND (RELEASE_CRASH_REPORTING OR NON_RELEASE_CRASH_REPORTING) AND VIE
     if (LINUX)
       # TBD
     endif (LINUX)
-  endif (NOT USE_BUGSPLAT)
+  endif (BUGSPLAT_DB)
 
   # for both Bugsplat and Breakpad
   add_dependencies(llpackage generate_symbols)
diff --git a/indra/newview/VIEWER_VERSION.txt b/indra/newview/VIEWER_VERSION.txt
index 4c8366c8645cc259c9a3c8622d1684ad4620c611..f186cd887440c98dd9d110fd523bb4897b1ad95a 100644
--- a/indra/newview/VIEWER_VERSION.txt
+++ b/indra/newview/VIEWER_VERSION.txt
@@ -1 +1 @@
-6.4.23
+6.4.24
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 5987bc3ddf18947a3227dce2ce7d5d52fc9ef7b4..aeeba58a686cd041b4af725bd306f2f3e76e2289 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -812,17 +812,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>
@@ -3366,13 +3355,13 @@
     <key>DisableVerticalSync</key>
     <map>
       <key>Comment</key>
-      <string>Update frames as fast as possible (FALSE = update frames between display scans)</string>
+      <string>Update frames as fast as possible (FALSE = update frames between display scans).  Requires restart.</string>
       <key>Persist</key>
       <integer>1</integer>
       <key>Type</key>
       <string>Boolean</string>
       <key>Value</key>
-      <integer>1</integer>
+      <integer>0</integer>
     </map>
     <key>EnableGroupChatPopups</key>
     <map>
@@ -9836,7 +9825,7 @@
       <key>Type</key>
       <string>Boolean</string>
       <key>Value</key>
-      <integer>0</integer>
+      <integer>1</integer>
     </map>
     <key>RenderGlow</key>
     <map>
diff --git a/indra/newview/generate_breakpad_symbols.py b/indra/newview/generate_breakpad_symbols.py
deleted file mode 100755
index d351c406bce923c8871b7442885989e87dbf0cfe..0000000000000000000000000000000000000000
--- a/indra/newview/generate_breakpad_symbols.py
+++ /dev/null
@@ -1,166 +0,0 @@
-#!/usr/bin/env python
-"""\
-@file generate_breakpad_symbols.py
-@author Brad Kittenbrink <brad@lindenlab.com>
-@brief Simple tool for generating google_breakpad symbol information
-       for the crash reporter.
-
-$LicenseInfo:firstyear=2010&license=viewerlgpl$
-Second Life Viewer Source Code
-Copyright (C) 2010-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
-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 collections
-import fnmatch
-import itertools
-import os
-import re
-import sys
-import shlex
-import subprocess
-import tarfile
-import StringIO
-import pprint
-
-DEBUG=False
-
-def usage():
-    print >>sys.stderr, "usage: %s search_dirs viewer_exes libs_suffix dump_syms_tool viewer_symbol_file" % sys.argv[0]
-
-class MissingModuleError(Exception):
-    def __init__(self, modules):
-        Exception.__init__(self, "Failed to find required modules: %r" % modules)
-        self.modules = modules
-
-def main(configuration, search_dirs, viewer_exes, libs_suffix, dump_syms_tool, viewer_symbol_file):
-    print "generate_breakpad_symbols run with args: %s" % str((configuration, search_dirs, viewer_exes, libs_suffix, dump_syms_tool, viewer_symbol_file))
-
-    if not re.match("release", configuration, re.IGNORECASE):
-        print "skipping breakpad symbol generation for non-release build."
-        return 0
-
-    # split up list of viewer_exes
-    # "'Second Life' SLPlugin" becomes ['Second Life', 'SLPlugin']
-    viewer_exes = shlex.split(viewer_exes)
-
-    found_required = dict([(module, False) for module in viewer_exes])
-
-    def matches(f):
-        if f in viewer_exes:
-            found_required[f] = True
-            return True
-        return fnmatch.fnmatch(f, libs_suffix)
-
-    search_dirs = search_dirs.split(";")
-
-    def list_files():
-        for search_dir in search_dirs:
-            for (dirname, subdirs, filenames) in os.walk(search_dir):
-                if DEBUG:
-                    print "scanning '%s' for modules..." % dirname
-                for f in itertools.ifilter(matches, filenames):
-                    yield os.path.join(dirname, f)
-
-    def dump_module(m):
-        print "dumping module '%s' with '%s'..." % (m, dump_syms_tool)
-        dsym_full_path = m
-        child = subprocess.Popen([dump_syms_tool, dsym_full_path] , stdout=subprocess.PIPE)
-        out, err = child.communicate()
-        return (m,child.returncode, out, err)
-
-    
-    modules = {}
-        
-    for m in list_files():
-        if DEBUG:
-            print "examining module '%s' ... " % m,
-        filename=os.path.basename(m)
-        if -1 != m.find("DWARF"):
-            # Just use this module; it has the symbols we want.
-            modules[filename] = m
-            if DEBUG:
-                print "found dSYM entry"
-        elif filename not in modules:
-            # Only use this if we don't already have a (possibly better) entry.
-            modules[filename] = m
-            if DEBUG:
-                print "found new entry"
-        elif DEBUG:
-            print "ignoring entry"
-
-
-    print "Found these following modules:"
-    pprint.pprint( modules )
-
-    out = tarfile.open(viewer_symbol_file, 'w:bz2')
-    for (filename,status,symbols,err) in itertools.imap(dump_module, modules.values()):
-        if status == 0:
-            module_line = symbols[:symbols.index('\n')]
-            module_line = module_line.split()
-            hash_id = module_line[3]
-            module = ' '.join(module_line[4:])
-            if sys.platform in ['win32', 'cygwin']:
-                mod_name = module[:module.rindex('.pdb')]
-            else:
-                mod_name = module
-            symbolfile = StringIO.StringIO(symbols)
-            info = tarfile.TarInfo("%(module)s/%(hash_id)s/%(mod_name)s.sym" % dict(module=module, hash_id=hash_id, mod_name=mod_name))
-            info.size = symbolfile.len
-            out.addfile(info, symbolfile)
-        else:
-            print >>sys.stderr, "warning: failed to dump symbols for '%s': %s" % (filename, err)
-
-    out.close()
-
-    missing_modules = [m for (m,_) in
-        itertools.ifilter(lambda (k,v): not v, found_required.iteritems())
-    ]
-    if missing_modules:
-        print >> sys.stderr, "failed to generate %s" % viewer_symbol_file
-        os.remove(viewer_symbol_file)
-        raise MissingModuleError(missing_modules)
-
-    symbols = tarfile.open(viewer_symbol_file, 'r:bz2')
-    tarfile_members = symbols.getnames()
-    symbols.close()
-
-    for required_module in viewer_exes:
-        def match_module_basename(m):
-            return os.path.splitext(required_module)[0].lower() \
-                   == os.path.splitext(os.path.basename(m))[0].lower()
-        # there must be at least one .sym file in tarfile_members that matches
-        # each required module (ignoring file extensions)
-        if not any(itertools.imap(match_module_basename, tarfile_members)):
-            print >> sys.stderr, "failed to find required %s in generated %s" \
-                    % (required_module, viewer_symbol_file)
-            os.remove(viewer_symbol_file)
-            raise MissingModuleError([required_module])
-
-    print "successfully generated %s including required modules '%s'" % (viewer_symbol_file, viewer_exes)
-
-    return 0
-
-if __name__ == "__main__":
-    if len(sys.argv) != 7:
-        usage()
-        sys.exit(1)
-    sys.exit(main(*sys.argv[1:]))
-
diff --git a/indra/newview/installers/darwin/apple-notarize.sh b/indra/newview/installers/darwin/apple-notarize.sh
new file mode 100755
index 0000000000000000000000000000000000000000..466898ecda609e3597253b714f844b28f1129bf7
--- /dev/null
+++ b/indra/newview/installers/darwin/apple-notarize.sh
@@ -0,0 +1,54 @@
+#!/bin/sh
+if [[ $SKIP_NOTARIZATION == "true" ]]; then
+    echo "Skipping notarization"
+    exit 0
+fi
+
+CONFIG_FILE="$build_secrets_checkout/code-signing-osx/notarize_creds.sh"
+if [ -f "$CONFIG_FILE" ]; then
+    source $CONFIG_FILE
+    app_file="$1"
+    zip_file=${app_file/app/zip}
+    ditto -c -k --keepParent "$app_file" "$zip_file"
+    if [ -f "$zip_file" ]; then
+        res=$(xcrun altool --notarize-app --primary-bundle-id "com.secondlife.viewer" \
+                                   --username $USERNAME \
+                                   --password $PASSWORD \
+                                   --asc-provider $ASC_PROVIDER \
+                                   --file "$zip_file" 2>&1)
+        requestUUID=$(echo $res | awk '/RequestUUID/ { print $NF; }')
+
+        echo "Apple Notarization RequestUUID: $requestUUID"
+
+        if [[ -n $requestUUID ]]; then
+            status="in progress"
+            while [[ "$status" == "in progress" ]]; do
+                sleep 30
+                status=$(xcrun altool --notarization-info "$requestUUID" \
+                                            --username $USERNAME \
+                                            --password $PASSWORD 2>&1 \
+                                | awk -F ': ' '/Status:/ { print $2; }' )
+                echo "$status"
+            done
+            # log results
+            xcrun altool --notarization-info "$requestUUID" \
+                        --username $USERNAME \
+                        --password $PASSWORD
+
+            #remove temporary file
+            rm "$zip_file"
+
+            if [["$status" == "success"]]; then
+                xcrun stapler staple "$app_file"
+            elif [["$status" == "invalid"]]; then
+                echo "Notarization error: failed to process the app file"
+                exit 1
+            fi
+        else
+            echo "Notarization error: couldn't get request UUID"
+            echo $res
+            exit 1
+        fi
+    fi
+fi
+
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 41a83a148460c4643f9bf1e8eee329446d60780c..8492aba2224251924230dc0d9615827c40eecfb7 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"
@@ -614,7 +613,7 @@ static void settings_modify()
 	LLPipeline::sRenderDeferred		= LLPipeline::sRenderTransparentWater && LLPipeline::sRenderBump && gSavedSettings.getBOOL("RenderDeferred");
 	LLVOSurfacePatch::sLODFactor		= gSavedSettings.getF32("RenderTerrainLODFactor");
 	LLVOSurfacePatch::sLODFactor *= LLVOSurfacePatch::sLODFactor; //square lod factor to get exponential range of [1,4]
-	gDebugGL = gSavedSettings.getBOOL("RenderDebugGL") || gDebugSession;
+    gDebugGL = gSavedSettings.getBOOL("RenderDebugGL") || gDebugSession;
 	gDebugPipeline = gSavedSettings.getBOOL("RenderDebugPipeline");
 }
 
@@ -695,8 +694,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)
 	{
@@ -739,7 +737,7 @@ LLAppViewer::LLAppViewer()
 	std::string logdir = gDirUtilp->getExpandedFilename(LL_PATH_DUMP, "");
 #   endif // ! LL_BUGSPLAT
 	mDumpPath = logdir;
-	setMiniDumpDir(logdir);
+
 	setDebugFileNames(logdir);
 }
 
@@ -1012,19 +1010,6 @@ bool LLAppViewer::init()
 		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())
 	{
@@ -1327,10 +1312,6 @@ 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();
 
@@ -1359,7 +1340,8 @@ void LLAppViewer::initMaxHeapSize()
 }
 
 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");
@@ -1421,13 +1403,17 @@ bool LLAppViewer::frame()
 
 bool LLAppViewer::doFrame()
 {
+	LL_RECORD_BLOCK_TIME(FTM_FRAME);
+
 	LLEventPump& mainloop(LLEventPumps::instance().obtain("mainloop"));
 	LLSD newFrame;
 
-	LL_RECORD_BLOCK_TIME(FTM_FRAME);
-	LLTrace::BlockTimer::processTimes();
-	LLTrace::get_frame_recording().nextPeriod();
-	LLTrace::BlockTimer::logStats();
+	{
+		LL_PROFILE_ZONE_NAMED( "df blocktimer" )
+		LLTrace::BlockTimer::processTimes();
+		LLTrace::get_frame_recording().nextPeriod();
+		LLTrace::BlockTimer::logStats();
+	}
 
 	LLTrace::get_thread_recorder()->pullFromChildren();
 
@@ -1435,6 +1421,7 @@ bool LLAppViewer::doFrame()
 	LL_CLEAR_CALLSTACKS();
 
 	{
+		LL_PROFILE_ZONE_NAMED( "df processMiscNativeEvents" )
 		pingMainloopTimeout("Main:MiscNativeWindowEvents");
 
 		if (gViewerWindow)
@@ -1443,7 +1430,10 @@ bool LLAppViewer::doFrame()
 			gViewerWindow->getWindow()->processMiscNativeEvents();
 		}
 
-		pingMainloopTimeout("Main:GatherInput");
+		{
+			LL_PROFILE_ZONE_NAMED( "df gatherInput" )
+			pingMainloopTimeout("Main:GatherInput");
+		}
 
 		if (gViewerWindow)
 		{
@@ -1467,13 +1457,21 @@ bool LLAppViewer::doFrame()
 			}
 		}
 
-		// canonical per-frame event
-		mainloop.post(newFrame);
-		// give listeners a chance to run
-		llcoro::suspend();
+		{
+			LL_PROFILE_ZONE_NAMED( "df mainloop" )
+			// canonical per-frame event
+			mainloop.post(newFrame);
+		}
+
+		{
+			LL_PROFILE_ZONE_NAMED( "df suspend" )
+			// give listeners a chance to run
+			llcoro::suspend();
+		}
 
 		if (!LLApp::isExiting())
 		{
+			LL_PROFILE_ZONE_NAMED( "df JoystickKeyboard" )
 			pingMainloopTimeout("Main:JoystickKeyboard");
 
 			// Scan keyboard for movement keys.  Command keys and typing
@@ -1494,12 +1492,18 @@ 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( "df pauseMainloopTimeout" )
+					pauseMainloopTimeout(); // *TODO: Remove. Messages shouldn't be stalling for 20+ seconds!
+				}
 
 				LL_RECORD_BLOCK_TIME(FTM_IDLE);
 				idle();
 
-				resumeMainloopTimeout();
+				{
+					LL_PROFILE_ZONE_NAMED( "df resumeMainloopTimeout" )
+					resumeMainloopTimeout();
+				}
 			}
 
 			if (gDoDisconnect && (LLStartUp::getStartupState() == STATE_STARTED))
@@ -1514,46 +1518,40 @@ bool LLAppViewer::doFrame()
 			// *TODO: Should we run display() even during gHeadlessClient?  DK 2011-02-18
 			if (!LLApp::isExiting() && !gHeadlessClient && gViewerWindow)
 			{
+				LL_PROFILE_ZONE_NAMED( "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();
-
-				pingMainloopTimeout("Main:Snapshot");
-				LLFloaterSnapshot::update(); // take snapshots
+					LL_PROFILE_ZONE_NAMED( "df Snapshot" )
+					pingMainloopTimeout("Main:Snapshot");
+					LLFloaterSnapshot::update(); // take snapshots
 					LLFloaterOutfitSnapshot::update();
-				gGLActive = FALSE;
+					gGLActive = FALSE;
+				}
 			}
 		}
 
-		pingMainloopTimeout("Main:Sleep");
+		{
+			LL_PROFILE_ZONE_NAMED( "df pauseMainloopTimeout" )
+			pingMainloopTimeout("Main:Sleep");
 
-		pauseMainloopTimeout();
+			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);
 			}
 
@@ -1572,8 +1570,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)
@@ -1624,16 +1622,22 @@ bool LLAppViewer::doFrame()
 				total_io_pending += io_pending ;
 
 			}
-			gMeshRepo.update() ;
+
+			{
+				LL_PROFILE_ZONE_NAMED( "df gMeshRepo" )
+				gMeshRepo.update() ;
+			}
 
 			if(!total_work_pending) //pause texture fetching threads if nothing to process.
 			{
+				LL_PROFILE_ZONE_NAMED( "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( "df LLVFSThread" )
 				LLVFSThread::sLocal->pause();
 				LLLFSThread::sLocal->pause();
 			}
@@ -1641,6 +1645,7 @@ bool LLAppViewer::doFrame()
 			//texture fetching debugger
 			if(LLTextureFetchDebugger::isEnabled())
 			{
+				LL_PROFILE_ZONE_NAMED( "df tex_fetch_debugger_instance" )
 				LLFloaterTextureFetchDebugger* tex_fetch_debugger_instance =
 					LLFloaterReg::findTypedInstance<LLFloaterTextureFetchDebugger>("tex_fetch_debugger");
 				if(tex_fetch_debugger_instance)
@@ -1649,8 +1654,10 @@ bool LLAppViewer::doFrame()
 				}
 			}
 
-			resumeMainloopTimeout();
-
+			{
+				LL_PROFILE_ZONE_NAMED( "df resumeMainloopTimeout" )
+				resumeMainloopTimeout();
+			}
 			pingMainloopTimeout("Main:End");
 		}
 	}
@@ -1676,7 +1683,7 @@ bool LLAppViewer::doFrame()
 		LL_INFOS() << "Exiting main_loop" << LL_ENDL;
 	}
 
-    LLPROFILE_UPDATE();
+    LL_PROFILER_FRAME_END
 
 	return ! LLApp::isRunning();
 }
@@ -2014,7 +2021,9 @@ bool LLAppViewer::cleanup()
 	if (LLConversationLog::instanceExists())
 	{
 		LLConversationLog::instance().cache();
-	}
+    }
+
+    clearSecHandler();
 
 	if (mPurgeCacheOnExit)
 	{
@@ -2344,7 +2353,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;
@@ -2454,7 +2463,7 @@ bool tempSetControl(const std::string& name, const std::string& value)
 		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);
+		auto g = LLControlGroup::getInstance(group_part);
 		if (g) control = g->getControl(name_part);
 	}
 	else
@@ -2521,12 +2530,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);
@@ -2668,10 +2672,10 @@ bool LLAppViewer::initConfiguration()
             {
                 const std::string& name = *itr;
                 const std::string& value = *(++itr);
-				if (!tempSetControl(name,value))
-				{
-					LL_WARNS() << "Failed --set " << name << ": setting name unknown." << LL_ENDL;
-				}
+                if (!tempSetControl(name,value))
+                {
+                    LL_WARNS() << "Failed --set " << name << ": setting name unknown." << LL_ENDL;
+                }
             }
         }
     }
@@ -4859,6 +4863,7 @@ void LLAppViewer::idle()
 	LLNotificationsUI::LLToast::updateClass();
 	LLSmoothInterpolation::updateInterpolants();
 	LLMortician::updateClass();
+    LLImageGL::updateClass();
 	LLFilePickerThread::clearDead();  //calls LLFilePickerThread::notify()
 	LLDirPickerThread::clearDead();
 	F32 dt_raw = idle_timer.getElapsedTimeAndResetF32();
@@ -5644,19 +5649,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 0afb70958c9c01b1170a8a17b6eae4c63e07ab51..37119aeef9bdf52291f0a2b39974db8ef3e3503d 100644
--- a/indra/newview/llappviewer.h
+++ b/indra/newview/llappviewer.h
@@ -109,7 +109,6 @@ 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.
-	virtual void initCrashReporting(bool reportFreeze = false) = 0; // What to do with crash report?
 	static void handleViewerCrash(); // Hey! The viewer crashed. Do this, soon.
     void checkForCrash();
     
@@ -262,8 +261,6 @@ class LLAppViewer : public LLApp
     void sendLogoutRequest();
     void disconnectViewer();
 
-	bool onChangeFrameLimit(LLSD const & evt);
-
 	// *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; 
@@ -319,10 +316,7 @@ class LLAppViewer : public LLApp
 	// llcorehttp library init/shutdown helper
 	LLAppCoreHttp mAppCoreHttp;
 
-        bool mIsFirstRun;
-	U64 mMinMicroSecPerFrame; // frame throttling
-
-
+    bool mIsFirstRun;
 };
 
 // consts from viewer.h
diff --git a/indra/newview/llappviewermacosx.cpp b/indra/newview/llappviewermacosx.cpp
index 42946e44155fc0e5afa5ca06e0f2038bda92d74c..aa932f9c894d5ccf4d224a34ec9dfaea8efa8988 100644
--- a/indra/newview/llappviewermacosx.cpp
+++ b/indra/newview/llappviewermacosx.cpp
@@ -222,14 +222,7 @@ LLAppViewerMacOSX::~LLAppViewerMacOSX()
 
 bool LLAppViewerMacOSX::init()
 {
-	bool success = LLAppViewer::init();
-    
-    if (success)
-    {
-        LLAppViewer* pApp = LLAppViewer::instance();
-        pApp->initCrashReporting();
-    }
-    return success;
+    return LLAppViewer::init();
 }
 
 // MacOSX may add and addition command line arguement for the process serial number.
@@ -347,28 +340,6 @@ bool LLAppViewerMacOSX::restoreErrorTrap()
 	return reset_count == 0;
 }
 
-void LLAppViewerMacOSX::initCrashReporting(bool reportFreeze)
-{
-#if defined LL_BUGSPLAT
-    LL_DEBUGS("InitOSX", "Bugsplat") << "using BugSplat crash logger" << LL_ENDL;
-#elif LL_SEND_CRASH_REPORTS
-    LL_DEBUGS("InitOSX") << "Initializing legacy crash logger" << LL_ENDL;
-	std::string command_str = "mac-crash-logger.app";
-    
-    std::stringstream pid_str;
-    pid_str <<  LLApp::getPid();
-    std::string logdir = gDirUtilp->getExpandedFilename(LL_PATH_DUMP, "");
-    std::string appname = gDirUtilp->getExecutableFilename();
-    std::string str[] = { "-pid", pid_str.str(), "-dumpdir", logdir, "-procname", appname.c_str() };
-    std::vector< std::string > args( str, str + ( sizeof ( str ) /  sizeof ( std::string ) ) );
-    LL_WARNS() << "about to launch mac-crash-logger" << pid_str.str()
-               << " " << logdir << " " << appname << LL_ENDL;
-    launchApplication(&command_str, &args);
-#else
-    LL_DEBUGS("InitOSX") << "No crash logger enabled" << LL_ENDL;    
-#endif // ! LL_BUGSPLAT
-}
-
 std::string LLAppViewerMacOSX::generateSerialNumber()
 {
 	char serial_md5[MD5HEX_STR_SIZE];		// Flawfinder: ignore
diff --git a/indra/newview/llappviewermacosx.h b/indra/newview/llappviewermacosx.h
index d5a80864be3dc0a5f0a599788f632a655806f1fc..b0e325a955bf0c8fc697dcbe3c45980939cb4fc6 100644
--- a/indra/newview/llappviewermacosx.h
+++ b/indra/newview/llappviewermacosx.h
@@ -44,7 +44,6 @@ class LLAppViewerMacOSX : public LLAppViewer
 
 protected:
 	virtual bool restoreErrorTrap();
-	virtual void initCrashReporting(bool reportFreeze);
 
 	std::string generateSerialNumber();
 	virtual bool initParseCommandLine(LLCommandLineParser& clp);
diff --git a/indra/newview/llappviewerwin32.cpp b/indra/newview/llappviewerwin32.cpp
index 9daea515e56ad4541637e15aee4db9cac27c5170..758bd73cb0b716eb7614cfad656e3aa4d75e7be0 100644
--- a/indra/newview/llappviewerwin32.cpp
+++ b/indra/newview/llappviewerwin32.cpp
@@ -323,6 +323,10 @@ 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
+
 	const S32 MAX_HEAPS = 255;
 	DWORD heap_enable_lfh_error[MAX_HEAPS];
 	S32 num_heaps = 0;
@@ -599,9 +603,6 @@ bool LLAppViewerWin32::init()
 #if ! defined(LL_BUGSPLAT)
 #pragma message("Building without BugSplat")
 
-	LLAppViewer* pApp = LLAppViewer::instance();
-	pApp->initCrashReporting();
-
 #else // LL_BUGSPLAT
 #pragma message("Building with BugSplat")
 
@@ -846,57 +847,6 @@ bool LLAppViewerWin32::restoreErrorTrap()
 	return true; // we don't check for handler collisions on windows, so just say they're ok
 }
 
-void LLAppViewerWin32::initCrashReporting(bool reportFreeze)
-{
-	if (isSecondInstance()) return; //BUG-5707 do not start another crash reporter for second instance.
-
-	const char* logger_name = "win_crash_logger.exe";
-	std::string exe_path = gDirUtilp->getExecutableDir();
-	exe_path += gDirUtilp->getDirDelimiter();
-	exe_path += logger_name;
-
-    std::string logdir = gDirUtilp->getExpandedFilename(LL_PATH_DUMP, "");
-    std::string appname = gDirUtilp->getExecutableFilename();
-
-	S32 slen = logdir.length() -1;
-	S32 end = slen;
-	while (logdir.at(end) == '/' || logdir.at(end) == '\\') end--;
-	
-	if (slen !=end)
-	{
-		logdir = logdir.substr(0,end+1);
-	}
-	//std::string arg_str = "\"" + exe_path + "\" -dumpdir \"" + logdir + "\" -procname \"" + appname + "\" -pid " + stringize(LLApp::getPid());
-	//_spawnl(_P_NOWAIT, exe_path.c_str(), arg_str.c_str(), NULL);
-	std::string arg_str =  "\"" + exe_path + "\" -dumpdir \"" + logdir + "\" -procname \"" + appname + "\" -pid " + stringize(LLApp::getPid()); 
-
-	STARTUPINFO startInfo={sizeof(startInfo)};
-	PROCESS_INFORMATION processInfo;
-
-	std::wstring exe_wstr;
-	exe_wstr = utf8str_to_utf16str(exe_path);
-
-	std::wstring arg_wstr;
-	arg_wstr = utf8str_to_utf16str(arg_str);
-
-	LL_INFOS("CrashReport") << "Creating crash reporter process " << exe_path << " with params: " << arg_str << LL_ENDL;
-    if(CreateProcess(exe_wstr.c_str(),     
-                     &arg_wstr[0],                 // Application arguments
-                     0,
-                     0,
-                     FALSE,
-                     CREATE_DEFAULT_ERROR_MODE,
-                     0,
-                     0,                              // Working directory
-                     &startInfo,
-                     &processInfo) == FALSE)
-      // Could not start application -> call 'GetLastError()'
-	{
-        LL_WARNS("CrashReport") << "CreateProcess failed " << GetLastError() << LL_ENDL;
-        return;
-    }
-}
-
 //virtual
 bool LLAppViewerWin32::sendURLToOtherInstance(const std::string& url)
 {
diff --git a/indra/newview/llappviewerwin32.h b/indra/newview/llappviewerwin32.h
index 83ae875a15162f62a66964b92d033e4c07ba691c..82b6b0c77c8089fa8ad911a481984f8b1df43273 100644
--- a/indra/newview/llappviewerwin32.h
+++ b/indra/newview/llappviewerwin32.h
@@ -51,9 +51,8 @@ class LLAppViewerWin32 : public LLAppViewer
 	bool initHardwareTest() override; // Win32 uses DX9 to test hardware.
 	bool initParseCommandLine(LLCommandLineParser& clp) override;
 
-	bool beingDebugged() override;
-	bool restoreErrorTrap() override;
-	void initCrashReporting(bool reportFreeze) override;
+	virtual bool beingDebugged();
+	virtual bool restoreErrorTrap();
 
 	bool sendURLToOtherInstance(const std::string& url) override;
 
diff --git a/indra/newview/llbrowsernotification.cpp b/indra/newview/llbrowsernotification.cpp
index 0460bff1b4859f923f7b8a584ee5a5318fcf1a9a..30ac35fff7641d976869458505fc47442d9557ea 100644
--- a/indra/newview/llbrowsernotification.cpp
+++ b/indra/newview/llbrowsernotification.cpp
@@ -43,14 +43,14 @@ LLBrowserNotification::LLBrowserNotification()
 bool LLBrowserNotification::processNotification(const LLNotificationPtr& notification)
 {
 	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/llcontrolavatar.cpp b/indra/newview/llcontrolavatar.cpp
index fab249f98807a865b7d4c21732eecd4c5443b440..606e6708053039540f7980a33f8daeae593192de 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);
diff --git a/indra/newview/lldrawable.cpp b/indra/newview/lldrawable.cpp
index 507af56cb0d2b8be0a0068a03c1276191a1cf7da..495e06b6f7e4a55d4c1f6f61bade5aa862586960 100644
--- a/indra/newview/lldrawable.cpp
+++ b/indra/newview/lldrawable.cpp
@@ -101,6 +101,8 @@ LLDrawable::LLDrawable(LLViewerObject *vobj, bool new_entry)
 
 void LLDrawable::init(bool new_entry)
 {
+	LL_PROFILE_ZONE_SCOPED
+
 	// mXform
 	mParent = NULL;
 	mRenderType = 0;
@@ -335,6 +337,7 @@ static LLTrace::BlockTimerStatHandle FTM_ALLOCATE_FACE("Allocate Face");
 
 LLFace*	LLDrawable::addFace(LLFacePool *poolp, LLViewerTexture *texturep)
 {
+	LL_PROFILE_ZONE_SCOPED
 	
 	LLFace *face;
 	{
@@ -363,6 +366,8 @@ LLFace*	LLDrawable::addFace(LLFacePool *poolp, LLViewerTexture *texturep)
 
 LLFace*	LLDrawable::addFace(const LLTextureEntry *te, LLViewerTexture *texturep)
 {
+	LL_PROFILE_ZONE_SCOPED
+
 	LLFace *face;
 
 	{
@@ -387,6 +392,8 @@ LLFace*	LLDrawable::addFace(const LLTextureEntry *te, LLViewerTexture *texturep)
 
 LLFace*	LLDrawable::addFace(const LLTextureEntry *te, LLViewerTexture *texturep, LLViewerTexture *normalp)
 {
+	LL_PROFILE_ZONE_SCOPED
+
 	LLFace *face;
 	face = new LLFace(this, mVObjp);
 	
@@ -408,6 +415,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
+
 	LLFace *face;
 	face = new LLFace(this, mVObjp);
 	
@@ -430,6 +439,8 @@ LLFace*	LLDrawable::addFace(const LLTextureEntry *te, LLViewerTexture *texturep,
 
 void LLDrawable::setNumFaces(const S32 newFaces, LLFacePool *poolp, LLViewerTexture *texturep)
 {
+	LL_PROFILE_ZONE_SCOPED
+
 	if (newFaces == (S32)mFaces.size())
 	{
 		return;
@@ -453,6 +464,8 @@ void LLDrawable::setNumFaces(const S32 newFaces, LLFacePool *poolp, LLViewerText
 
 void LLDrawable::setNumFacesFast(const S32 newFaces, LLFacePool *poolp, LLViewerTexture *texturep)
 {
+	LL_PROFILE_ZONE_SCOPED
+
 	if (newFaces <= (S32)mFaces.size() && newFaces >= (S32)mFaces.size()/2)
 	{
 		return;
@@ -476,6 +489,8 @@ void LLDrawable::setNumFacesFast(const S32 newFaces, LLFacePool *poolp, LLViewer
 
 void LLDrawable::mergeFaces(LLDrawable* src)
 {
+	LL_PROFILE_ZONE_SCOPED
+
 	U32 face_count = mFaces.size() + src->mFaces.size();
 
 	mFaces.reserve(face_count);
@@ -509,6 +524,8 @@ void LLDrawable::updateMaterial()
 
 void LLDrawable::makeActive()
 {		
+	LL_PROFILE_ZONE_SCOPED
+
 #if !LL_RELEASE_FOR_DOWNLOAD
 	if (mVObjp.notNull())
 	{
@@ -572,6 +589,8 @@ void LLDrawable::makeActive()
 
 void LLDrawable::makeStatic(BOOL warning_enabled)
 {
+	LL_PROFILE_ZONE_SCOPED
+
 	if (isState(ACTIVE) && 
 		!isState(ACTIVE_CHILD) && 
 		!mVObjp->isAttachment() && 
@@ -618,6 +637,8 @@ void LLDrawable::makeStatic(BOOL warning_enabled)
 // Returns "distance" between target destination and resulting xfrom
 F32 LLDrawable::updateXform(BOOL undamped)
 {
+	LL_PROFILE_ZONE_SCOPED
+
 	BOOL damped = !undamped;
 
 	// Position
@@ -769,6 +790,8 @@ void LLDrawable::moveUpdatePipeline(BOOL moved)
 
 void LLDrawable::movePartition()
 {
+	LL_PROFILE_ZONE_SCOPED
+
 	LLSpatialPartition* part = getSpatialPartition();
 	if (part)
 	{
@@ -813,6 +836,8 @@ BOOL LLDrawable::updateMoveUndamped()
 
 void LLDrawable::updatePartition()
 {
+	LL_PROFILE_ZONE_SCOPED
+
 	if (!getVOVolume())
 	{
 		movePartition();
@@ -830,6 +855,8 @@ void LLDrawable::updatePartition()
 
 BOOL LLDrawable::updateMoveDamped()
 {
+	LL_PROFILE_ZONE_SCOPED
+
 	F32 dist_squared = updateXform(FALSE);
 
 	mGeneration++;
@@ -853,6 +880,8 @@ BOOL LLDrawable::updateMoveDamped()
 
 void LLDrawable::updateDistance(LLCamera& camera, bool force_update)
 {
+	LL_PROFILE_ZONE_SCOPED
+
 	if (LLViewerCamera::sCurCameraID != LLViewerCamera::CAMERA_WORLD)
 	{
 		LL_WARNS() << "Attempted to update distance for non-world camera." << LL_ENDL;
@@ -957,6 +986,8 @@ void LLDrawable::updateTexture()
 
 BOOL LLDrawable::updateGeometry(BOOL priority)
 {
+	LL_PROFILE_ZONE_SCOPED
+
 	llassert(mVObjp.notNull());
 	BOOL res = mVObjp->updateGeometry(this);
 	return res;
@@ -1034,6 +1065,8 @@ const LLVector3& LLDrawable::getBounds(LLVector3& min, LLVector3& max) const
 
 void LLDrawable::updateSpatialExtents()
 {
+	LL_PROFILE_ZONE_SCOPED
+
 	if (mVObjp)
 	{
 		const LLVector4a* exts = getSpatialExtents();
@@ -1164,6 +1197,8 @@ void LLDrawable::setGroup(LLViewerOctreeGroup *groupp)
 
 LLSpatialPartition* LLDrawable::getSpatialPartition()
 { 
+	LL_PROFILE_ZONE_SCOPED
+
 	LLSpatialPartition* retval = NULL;
 	
 	if (!mVObjp || 
@@ -1247,6 +1282,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
+
 	mBridge = this;
 	mDrawable = root;
 	root->setSpatialBridge(this);
@@ -1292,6 +1329,8 @@ void LLSpatialBridge::destroyTree()
 
 void LLSpatialBridge::updateSpatialExtents()
 {
+	LL_PROFILE_ZONE_SCOPED
+
 	LLSpatialGroup* root = (LLSpatialGroup*) mOctree->getListener(0);
 	
 	{
@@ -1455,6 +1494,8 @@ class LLOctreeMarkNotCulled: public OctreeTraveler
 
 void LLSpatialBridge::setVisible(LLCamera& camera_in, std::vector<LLDrawable*>* results, BOOL for_select)
 {
+	LL_PROFILE_ZONE_SCOPED
+
 	if (!gPipeline.hasRenderType(mDrawableType))
 	{
 		return;
@@ -1552,6 +1593,8 @@ void LLSpatialBridge::setVisible(LLCamera& camera_in, std::vector<LLDrawable*>*
 
 void LLSpatialBridge::updateDistance(LLCamera& camera_in, bool force_update)
 {
+	LL_PROFILE_ZONE_SCOPED
+
 	if (mDrawable == NULL)
 	{
 		markDead();
diff --git a/indra/newview/lldrawpool.cpp b/indra/newview/lldrawpool.cpp
index d583a692f9f26d4ca398ae88baeb75f9f9604d83..3e4f97e494a74b6ce2686be8e9141e4aaf99b2c1 100644
--- a/indra/newview/lldrawpool.cpp
+++ b/indra/newview/lldrawpool.cpp
@@ -404,6 +404,7 @@ void LLRenderPass::renderTexture(U32 type, U32 mask, BOOL batch_textures)
 
 void LLRenderPass::pushBatches(U32 type, U32 mask, BOOL texture, BOOL batch_textures)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	for (LLCullResult::drawinfo_iterator i = gPipeline.beginRenderMap(type); i != gPipeline.endRenderMap(type); ++i)	
 	{
 		LLDrawInfo* pparams = *i;
@@ -452,6 +453,7 @@ void LLRenderPass::applyModelMatrix(const LLDrawInfo& params)
 
 void LLRenderPass::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture, BOOL batch_textures)
 {
+    LL_PROFILE_ZONE_SCOPED;
     if (!params.mCount)
     {
         return;
@@ -469,7 +471,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 +479,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 +491,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)
 	{
diff --git a/indra/newview/lldrawpoolalpha.cpp b/indra/newview/lldrawpoolalpha.cpp
index 4ee08e869a087c650b66dff9dd3de387e0eba16a..369d7a6bb8ea3a5d27a55b780a93afc7dfcf9bd4 100644
--- a/indra/newview/lldrawpoolalpha.cpp
+++ b/indra/newview/lldrawpoolalpha.cpp
@@ -55,19 +55,7 @@ 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");
 
 LLDrawPoolAlpha::LLDrawPoolAlpha(U32 type) :
 		LLRenderPass(type), current_shader(NULL), target_shader(NULL),
@@ -86,6 +74,10 @@ 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() 
@@ -309,7 +301,7 @@ void LLDrawPoolAlpha::render(S32 pass)
 		gGL.diffuseColor4f(1,0,0,1);
 				
 		LLViewerFetchedTexture::sSmokeImagep->addTextureStats(1024.f*1024.f);
-		gGL.getTexUnit(0)->bind(LLViewerFetchedTexture::sSmokeImagep, TRUE) ;
+		gGL.getTexUnit(0)->bindFast(LLViewerFetchedTexture::sSmokeImagep);
 		renderAlphaHighlight(LLVertexBuffer::MAP_VERTEX |
 							LLVertexBuffer::MAP_TEXCOORD0);
 
@@ -358,9 +350,8 @@ void LLDrawPoolAlpha::renderAlphaHighlight(U32 mask)
 				{
 					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);
+				params.mVertexBuffer->setBufferFast(mask);
+				params.mVertexBuffer->drawRangeFast(params.mDrawMode, params.mStart, params.mEnd, params.mCount, params.mOffset);
 			}
 		}
 	}
@@ -383,27 +374,23 @@ 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, LLGLSLShader* current_shader)
 {
-    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);
@@ -412,18 +399,16 @@ bool LLDrawPoolAlpha::TexSetup(LLDrawInfo* draw, bool use_shaders, bool use_mate
     }
     else if (current_shader == simple_shader)
     {
-        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 +416,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 +436,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,37 +454,15 @@ void LLDrawPoolAlpha::RestoreTexSetup(bool tex_setup)
 	}
 }
 
-void LLDrawPoolAlpha::renderSimples(U32 mask, std::vector<LLDrawInfo*>& simples)
-{
-    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();
-}
-
 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);
+        bool tex_setup = TexSetup(draw, 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);
@@ -511,65 +473,10 @@ void LLDrawPoolAlpha::renderFullbrights(U32 mask, std::vector<LLDrawInfo*>& full
     fullbright_shader->unbind();
 }
 
-void LLDrawPoolAlpha::renderMaterials(U32 mask, std::vector<LLDrawInfo*>& materials)
-{
-    LLGLSLShader::bindNoShader();
-    current_shader = NULL;
-
-    gPipeline.enableLightsDynamic();
-    bool use_shaders = gPipeline.canUseVertexShaders();
-    for (LLDrawInfo* draw : materials)
-    {
-        U32 mask = draw->mShaderMask;
-
-		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);
-
-        {
-            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);
-			}
-        }
-
-        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);
-    }
-}
-
 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);
+    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::drawEmissiveInline(U32 mask, LLDrawInfo* draw)
@@ -599,10 +506,10 @@ void LLDrawPoolAlpha::renderEmissives(U32 mask, std::vector<LLDrawInfo*>& emissi
     // 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)
     {
-        bool tex_setup = TexSetup(draw, use_shaders, false, emissive_shader);
+        bool tex_setup = TexSetup(draw, false, emissive_shader);
         drawEmissive(mask, draw);
         RestoreTexSetup(tex_setup);
     }
@@ -620,8 +527,6 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, S32 pass)
 	BOOL initialized_lighting = FALSE;
 	BOOL light_enabled = TRUE;
 	
-	BOOL use_shaders = gPipeline.canUseVertexShaders();
-		
 	for (LLCullResult::sg_iterator i = gPipeline.beginAlphaGroups(); i != gPipeline.endAlphaGroups(); ++i)
 	{
 		LLSpatialGroup* group = *i;
@@ -631,8 +536,10 @@ 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*> fullbrights;
+            emissives.resize(0);
+            fullbrights.resize(0);
 
 			bool is_particle_or_hud_particle = group->getSpatialPartition()->mPartitionType == LLViewerRegion::PARTITION_PARTICLE
 													  || group->getSpatialPartition()->mPartitionType == LLViewerRegion::PARTITION_HUD_PARTICLE;
@@ -649,6 +556,7 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, S32 pass)
 
 			for (LLSpatialGroup::drawmap_elem_t::iterator k = draw_info.begin(); k != draw_info.end(); ++k)	
 			{
+                LL_PROFILE_ZONE_NAMED("ra - push batch")
 				LLDrawInfo& params = **k;
                 U32 have_mask = params.mVertexBuffer->getTypeMask() & mask;
 				if (have_mask != mask)
@@ -696,34 +604,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;
 				}
 
@@ -741,7 +632,6 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, S32 pass)
 
 					if (current_shader != target_shader)
 					{
-                        LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_DEFERRED_SHADER_BINDS);
 						gPipeline.bindDeferredShader(*target_shader);
                         current_shader = target_shader;
 					}
@@ -755,25 +645,19 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, S32 pass)
 					target_shader = fullbright_shader;
 				}
 				
-				if(use_shaders && (current_shader != target_shader))
+				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).
-                    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;
-				}
 
                 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;
@@ -792,20 +676,16 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, S32 pass)
 					params.mGroup->rebuildMesh();
 				}
 
-                bool tex_setup = TexSetup(&params, use_shaders, use_shaders && (mat != nullptr), current_shader);
+                bool tex_setup = TexSetup(&params, (mat != nullptr), current_shader);
 
 				{
-					LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_PUSH);
-
 					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));
+					params.mVertexBuffer->setBufferFast(mask & ~(params.mFullbright ? (LLVertexBuffer::MAP_TANGENT | LLVertexBuffer::MAP_TEXCOORD1 | LLVertexBuffer::MAP_TEXCOORD2) : 0));
 
                     {
-                        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);
+					    params.mVertexBuffer->drawRangeFast(params.mDrawMode, params.mStart, params.mEnd, params.mCount, params.mOffset);
                     }
 				}
 
@@ -814,8 +694,6 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, S32 pass)
 					draw_glow_for_this_partition &&
 					params.mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_EMISSIVE))
 				{
-                    LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_EMISSIVE);
-
                     if (batch_emissives)
                     {
                         emissives.push_back(&params);
@@ -835,19 +713,29 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, S32 pass)
 				}
 			}
 
+
+            bool rebind = false;
             if (batch_fullbrights)
             {
-                light_enabled = false;
-                renderFullbrights(mask, fullbrights);
+                if (!fullbrights.empty())
+                {
+                    light_enabled = false;
+                    renderFullbrights(mask, fullbrights);
+                    rebind = true;
+                }
             }
 
             if (batch_emissives)
             {
-                light_enabled = true;
-                renderEmissives(mask, emissives);
+                if (!emissives.empty())
+                {
+                    light_enabled = true;
+                    renderEmissives(mask, emissives);
+                    rebind = true;
+                }
             }
 
-            if (current_shader)
+            if (current_shader && rebind)
             {
                 current_shader->bind();
             }
diff --git a/indra/newview/lldrawpoolalpha.h b/indra/newview/lldrawpoolalpha.h
index a069f805e827c4d5b175a8a2224b8fa821da6c9d..a50b1d929e40dd51d7c80d74857e2f12e11cdcb9 100644
--- a/indra/newview/lldrawpoolalpha.h
+++ b/indra/newview/lldrawpoolalpha.h
@@ -75,15 +75,13 @@ class LLDrawPoolAlpha: public LLRenderPass
 	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);
 
     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);
+    bool TexSetup(LLDrawInfo* draw, bool use_material, LLGLSLShader* current_shader);
     void RestoreTexSetup(bool tex_setup);
 
 	// our 'normal' alpha blend function for this pass
diff --git a/indra/newview/lldrawpoolavatar.cpp b/indra/newview/lldrawpoolavatar.cpp
index 687b13d2c8366d46496f27495ebbdb6709bac068..8dd8c15b876c77f0d6529080480041eaafacbc5c 100644
--- a/indra/newview/lldrawpoolavatar.cpp
+++ b/indra/newview/lldrawpoolavatar.cpp
@@ -121,6 +121,8 @@ LLDrawPoolAvatar::~LLDrawPoolAvatar()
 // virtual
 BOOL LLDrawPoolAvatar::isDead()
 {
+    LL_PROFILE_ZONE_SCOPED
+
     if (!LLFacePool::isDead())
     {
         return FALSE;
@@ -138,11 +140,15 @@ BOOL LLDrawPoolAvatar::isDead()
 
 S32 LLDrawPoolAvatar::getShaderLevel() const
 {
+    LL_PROFILE_ZONE_SCOPED
+
 	return (S32) LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_AVATAR);
 }
 
 void LLDrawPoolAvatar::prerender()
 {
+    LL_PROFILE_ZONE_SCOPED
+
 	mShaderLevel = LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_AVATAR);
 	
 	sShaderLevel = mShaderLevel;
@@ -163,12 +169,15 @@ void LLDrawPoolAvatar::prerender()
 		{
 			LLVOAvatar* avatarp = (LLVOAvatar *)facep->getDrawable()->getVObj().get();
 			updateRiggedVertexBuffers(avatarp);
+            updateSkinInfoMatrixPalettes(avatarp);
 		}
 	}
 }
 
 LLMatrix4& LLDrawPoolAvatar::getModelView()
 {
+    LL_PROFILE_ZONE_SCOPED
+
 	static LLMatrix4 ret;
 
 	ret.initRows(LLVector4(gGLModelView+0),
@@ -257,6 +266,8 @@ void LLDrawPoolAvatar::endDeferredPass(S32 pass)
 
 void LLDrawPoolAvatar::renderDeferred(S32 pass)
 {
+    LL_PROFILE_ZONE_SCOPED
+
 	render(pass);
 }
 
@@ -267,6 +278,8 @@ S32 LLDrawPoolAvatar::getNumPostDeferredPasses()
 
 void LLDrawPoolAvatar::beginPostDeferredPass(S32 pass)
 {
+    LL_PROFILE_ZONE_SCOPED
+
 	switch (pass)
 	{
 	case 0:
@@ -295,6 +308,8 @@ void LLDrawPoolAvatar::beginPostDeferredPass(S32 pass)
 
 void LLDrawPoolAvatar::beginPostDeferredAlpha()
 {
+    LL_PROFILE_ZONE_SCOPED
+
 	sSkipOpaque = TRUE;
 	sShaderLevel = mShaderLevel;
 	sVertexProgram = &gDeferredAvatarAlphaProgram;
@@ -309,6 +324,8 @@ void LLDrawPoolAvatar::beginPostDeferredAlpha()
 
 void LLDrawPoolAvatar::beginDeferredRiggedAlpha()
 {
+    LL_PROFILE_ZONE_SCOPED
+
 	sVertexProgram = &gDeferredSkinnedAlphaProgram;
 	gPipeline.bindDeferredShader(*sVertexProgram);
 	sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
@@ -317,6 +334,8 @@ void LLDrawPoolAvatar::beginDeferredRiggedAlpha()
 
 void LLDrawPoolAvatar::beginDeferredRiggedMaterialAlpha(S32 pass)
 {
+    LL_PROFILE_ZONE_SCOPED
+
 	switch (pass)
 	{
 	case 0: pass = 1; break;
@@ -343,6 +362,8 @@ void LLDrawPoolAvatar::beginDeferredRiggedMaterialAlpha(S32 pass)
 
 void LLDrawPoolAvatar::endDeferredRiggedAlpha()
 {
+    LL_PROFILE_ZONE_SCOPED
+
 	LLVertexBuffer::unbind();
 	gPipeline.unbindDeferredShader(*sVertexProgram);
 	sDiffuseChannel = 0;
@@ -353,6 +374,8 @@ void LLDrawPoolAvatar::endDeferredRiggedAlpha()
 
 void LLDrawPoolAvatar::endPostDeferredPass(S32 pass)
 {
+    LL_PROFILE_ZONE_SCOPED
+
 	switch (pass)
 	{
 	case 0:
@@ -381,6 +404,8 @@ void LLDrawPoolAvatar::endPostDeferredPass(S32 pass)
 
 void LLDrawPoolAvatar::endPostDeferredAlpha()
 {
+    LL_PROFILE_ZONE_SCOPED
+
 	// 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,6 +417,8 @@ void LLDrawPoolAvatar::endPostDeferredAlpha()
 
 void LLDrawPoolAvatar::renderPostDeferred(S32 pass)
 {
+    LL_PROFILE_ZONE_SCOPED
+
 	static const S32 actual_pass[] =
 	{ //map post deferred pass numbers to what render() expects
 		2, //skinned
@@ -428,225 +455,235 @@ S32 LLDrawPoolAvatar::getNumShadowPasses()
 void LLDrawPoolAvatar::beginShadowPass(S32 pass)
 {
 	LL_RECORD_BLOCK_TIME(FTM_SHADOW_AVATAR);
+    {
+        LL_PROFILE_ZONE_SCOPED;
 
-	if (pass == SHADOW_PASS_AVATAR_OPAQUE)
-	{
-		sVertexProgram = &gDeferredAvatarShadowProgram;
-		
-		if ((sShaderLevel > 0))  // for hardware blending
-		{
-			sRenderingSkinned = TRUE;
-			sVertexProgram->bind();
-		}
+        if (pass == SHADOW_PASS_AVATAR_OPAQUE)
+        {
+            sVertexProgram = &gDeferredAvatarShadowProgram;
 
-		gGL.diffuseColor4f(1,1,1,1);
-	}
-    else if (pass == SHADOW_PASS_AVATAR_ALPHA_BLEND)
-	{
-		sVertexProgram = &gDeferredAvatarAlphaShadowProgram;
+            if ((sShaderLevel > 0))  // for hardware blending
+            {
+                sRenderingSkinned = TRUE;
+                sVertexProgram->bind();
+            }
 
-        // bind diffuse tex so we can reference the alpha channel...
-        S32 loc = sVertexProgram->getUniformLocation(LLViewerShaderMgr::DIFFUSE_MAP);
-        sDiffuseChannel = 0;
-        if (loc != -1)
+            gGL.diffuseColor4f(1, 1, 1, 1);
+        }
+        else if (pass == SHADOW_PASS_AVATAR_ALPHA_BLEND)
         {
-            sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
-		}
+            sVertexProgram = &gDeferredAvatarAlphaShadowProgram;
 
-		if ((sShaderLevel > 0))  // for hardware blending
-		{
-			sRenderingSkinned = TRUE;
-			sVertexProgram->bind();
-		}
+            // 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);
+            }
 
-		gGL.diffuseColor4f(1,1,1,1);
-	}
-    else if (pass == SHADOW_PASS_AVATAR_ALPHA_MASK)
-	{
-		sVertexProgram = &gDeferredAvatarAlphaMaskShadowProgram;
+            if ((sShaderLevel > 0))  // for hardware blending
+            {
+                sRenderingSkinned = TRUE;
+                sVertexProgram->bind();
+            }
 
-        // bind diffuse tex so we can reference the alpha channel...
-        S32 loc = sVertexProgram->getUniformLocation(LLViewerShaderMgr::DIFFUSE_MAP);
-        sDiffuseChannel = 0;
-        if (loc != -1)
+            gGL.diffuseColor4f(1, 1, 1, 1);
+        }
+        else if (pass == SHADOW_PASS_AVATAR_ALPHA_MASK)
         {
-            sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
-		}
+            sVertexProgram = &gDeferredAvatarAlphaMaskShadowProgram;
 
-		if ((sShaderLevel > 0))  // for hardware blending
-		{
-			sRenderingSkinned = TRUE;
-			sVertexProgram->bind();
-		}
+            // 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);
+            }
 
-		gGL.diffuseColor4f(1,1,1,1);
-	}
-    else if (pass == SHADOW_PASS_ATTACHMENT_ALPHA_BLEND)
-	{
-		sVertexProgram = &gDeferredAttachmentAlphaShadowProgram;
+            if ((sShaderLevel > 0))  // for hardware blending
+            {
+                sRenderingSkinned = TRUE;
+                sVertexProgram->bind();
+            }
 
-        // bind diffuse tex so we can reference the alpha channel...
-        S32 loc = sVertexProgram->getUniformLocation(LLViewerShaderMgr::DIFFUSE_MAP);
-        sDiffuseChannel = 0;
-        if (loc != -1)
+            gGL.diffuseColor4f(1, 1, 1, 1);
+        }
+        else if (pass == SHADOW_PASS_ATTACHMENT_ALPHA_BLEND)
         {
-            sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
-		}
-		
-		if ((sShaderLevel > 0))  // for hardware blending
-		{
-			sRenderingSkinned = TRUE;
-			sVertexProgram->bind();
-		}
+            sVertexProgram = &gDeferredAttachmentAlphaShadowProgram;
 
-		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);
+            }
 
-        // bind diffuse tex so we can reference the alpha channel...
-		S32 loc = sVertexProgram->getUniformLocation(LLViewerShaderMgr::DIFFUSE_MAP);
-        sDiffuseChannel = 0;
-        if (loc != -1)
+            if ((sShaderLevel > 0))  // for hardware blending
+            {
+                sRenderingSkinned = TRUE;
+                sVertexProgram->bind();
+            }
+
+            gGL.diffuseColor4f(1, 1, 1, 1);
+        }
+        else if (pass == SHADOW_PASS_ATTACHMENT_ALPHA_MASK)
         {
-            sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
-		}
+            sVertexProgram = &gDeferredAttachmentAlphaMaskShadowProgram;
 
-		if ((sShaderLevel > 0))  // for hardware blending
-		{
-			sRenderingSkinned = TRUE;
-			sVertexProgram->bind();
-		}
+            // 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);
+            }
 
-		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)
+            if ((sShaderLevel > 0))  // for hardware blending
+            {
+                sRenderingSkinned = TRUE;
+                sVertexProgram->bind();
+            }
+
+            gGL.diffuseColor4f(1, 1, 1, 1);
+        }
+        else // SHADOW_PASS_ATTACHMENT_OPAQUE
         {
-            sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
-		}
-		sVertexProgram->bind();
-	}
+            sVertexProgram = &gDeferredAttachmentShadowProgram;
+            S32 loc = sVertexProgram->getUniformLocation(LLViewerShaderMgr::DIFFUSE_MAP);
+            sDiffuseChannel = 0;
+            if (loc != -1)
+            {
+                sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
+            }
+            sVertexProgram->bind();
+        }
+    }
 }
 
 void LLDrawPoolAvatar::endShadowPass(S32 pass)
 {
 	LL_RECORD_BLOCK_TIME(FTM_SHADOW_AVATAR);
+    {
+        LL_PROFILE_ZONE_SCOPED;
 
-	if (pass == SHADOW_PASS_ATTACHMENT_OPAQUE)
-	{
-		LLVertexBuffer::unbind();
-	}
+        if (pass == SHADOW_PASS_ATTACHMENT_OPAQUE)
+        {
+            LLVertexBuffer::unbind();
+        }
 
-    if (sShaderLevel > 0)
-	{			
-		sVertexProgram->unbind();
-	}
-    sVertexProgram = NULL;
-    sRenderingSkinned = FALSE;
-    LLDrawPoolAvatar::sShadowPass = -1;
+        if (sShaderLevel > 0)
+        {
+            sVertexProgram->unbind();
+        }
+        sVertexProgram = NULL;
+        sRenderingSkinned = FALSE;
+        LLDrawPoolAvatar::sShadowPass = -1;
+    }
 }
 
 void LLDrawPoolAvatar::renderShadow(S32 pass)
 {
-	LL_RECORD_BLOCK_TIME(FTM_SHADOW_AVATAR);
+    LL_RECORD_BLOCK_TIME(FTM_SHADOW_AVATAR);
+    {
+        LL_PROFILE_ZONE_SCOPED;
 
-	if (mDrawFace.empty())
-	{
-		return;
-	}
+        if (mDrawFace.empty())
+        {
+            return;
+        }
 
-	const LLFace *facep = mDrawFace[0];
-	if (!facep->getDrawable())
-	{
-		return;
-	}
-	LLVOAvatar *avatarp = (LLVOAvatar *)facep->getDrawable()->getVObj().get();
+        const LLFace *facep = mDrawFace[0];
+        if (!facep->getDrawable())
+        {
+            return;
+        }
+        LLVOAvatar *avatarp = (LLVOAvatar *)facep->getDrawable()->getVObj().get();
 
-	if (avatarp->isDead() || avatarp->isUIAvatar() || avatarp->mDrawable.isNull())
-	{
-		return;
-	}
-	LLVOAvatar::AvatarOverallAppearance oa = avatarp->getOverallAppearance();
-	BOOL impostor = !LLPipeline::sImpostorRender && avatarp->isImpostor();
-	if (oa == LLVOAvatar::AOA_INVISIBLE ||
-		(impostor && oa == LLVOAvatar::AOA_JELLYDOLL))
-	{
-		// No shadows for jellydolled or invisible avs.
-		return;
-	}
-	
-    LLDrawPoolAvatar::sShadowPass = pass;
+        if (avatarp->isDead() || avatarp->isUIAvatar() || avatarp->mDrawable.isNull())
+        {
+            return;
+        }
+        LLVOAvatar::AvatarOverallAppearance oa = avatarp->getOverallAppearance();
+        BOOL impostor = !LLPipeline::sImpostorRender && avatarp->isImpostor();
+        if (impostor || (oa == LLVOAvatar::AOA_INVISIBLE))
+        {
+            // No shadows for impostored (including jellydolled) or invisible avs.
+            return;
+        }
 
-	if (pass == SHADOW_PASS_AVATAR_OPAQUE)
-	{
-        LLDrawPoolAvatar::sSkipTransparent = true;
-		avatarp->renderSkinned();
-        LLDrawPoolAvatar::sSkipTransparent = false;
-	}
-    else if (pass == SHADOW_PASS_AVATAR_ALPHA_BLEND)
-	{
-        LLDrawPoolAvatar::sSkipOpaque = true;
-		avatarp->renderSkinned();
-        LLDrawPoolAvatar::sSkipOpaque = false;
-	}
-    else if (pass == SHADOW_PASS_AVATAR_ALPHA_MASK)
-	{
-        LLDrawPoolAvatar::sSkipOpaque = true;
-		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;
-	}
+        LLDrawPoolAvatar::sShadowPass = pass;
+
+        if (pass == SHADOW_PASS_AVATAR_OPAQUE)
+        {
+            LLDrawPoolAvatar::sSkipTransparent = true;
+            avatarp->renderSkinned();
+            LLDrawPoolAvatar::sSkipTransparent = false;
+        }
+        else if (pass == SHADOW_PASS_AVATAR_ALPHA_BLEND)
+        {
+            LLDrawPoolAvatar::sSkipOpaque = true;
+            avatarp->renderSkinned();
+            LLDrawPoolAvatar::sSkipOpaque = false;
+        }
+        else if (pass == SHADOW_PASS_AVATAR_ALPHA_MASK)
+        {
+            LLDrawPoolAvatar::sSkipOpaque = true;
+            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()
 {
+    LL_PROFILE_ZONE_SCOPED
+
 	if (LLPipeline::sImpostorRender)
 	{
 		return 8;
@@ -660,6 +697,8 @@ S32 LLDrawPoolAvatar::getNumPasses()
 
 S32 LLDrawPoolAvatar::getNumDeferredPasses()
 {
+    LL_PROFILE_ZONE_SCOPED
+
 	if (LLPipeline::sImpostorRender)
 	{
 		return 19;
@@ -780,6 +819,8 @@ void LLDrawPoolAvatar::endRenderPass(S32 pass)
 
 void LLDrawPoolAvatar::beginImpostor()
 {
+    LL_PROFILE_ZONE_SCOPED
+
 	if (!LLPipeline::sReflectionRender)
 	{
 		LLVOAvatar::sRenderDistance = llclamp(LLVOAvatar::sRenderDistance, 16.f, 256.f);
@@ -798,6 +839,8 @@ void LLDrawPoolAvatar::beginImpostor()
 
 void LLDrawPoolAvatar::endImpostor()
 {
+    LL_PROFILE_ZONE_SCOPED
+
 	if (LLGLSLShader::sNoFixedFunction)
 	{
 		gImpostorProgram.unbind();
@@ -807,6 +850,8 @@ void LLDrawPoolAvatar::endImpostor()
 
 void LLDrawPoolAvatar::beginRigid()
 {
+    LL_PROFILE_ZONE_SCOPED
+
 	if (gPipeline.canUseVertexShaders())
 	{
 		if (LLPipeline::sUnderWaterRender)
@@ -840,6 +885,8 @@ void LLDrawPoolAvatar::beginRigid()
 
 void LLDrawPoolAvatar::endRigid()
 {
+    LL_PROFILE_ZONE_SCOPED
+
 	sShaderLevel = mShaderLevel;
 	if (sVertexProgram != NULL)
 	{
@@ -849,6 +896,8 @@ void LLDrawPoolAvatar::endRigid()
 
 void LLDrawPoolAvatar::beginDeferredImpostor()
 {
+    LL_PROFILE_ZONE_SCOPED
+
 	if (!LLPipeline::sReflectionRender)
 	{
 		LLVOAvatar::sRenderDistance = llclamp(LLVOAvatar::sRenderDistance, 16.f, 256.f);
@@ -865,6 +914,8 @@ void LLDrawPoolAvatar::beginDeferredImpostor()
 
 void LLDrawPoolAvatar::endDeferredImpostor()
 {
+    LL_PROFILE_ZONE_SCOPED
+
 	sShaderLevel = mShaderLevel;
 	sVertexProgram->disableTexture(LLViewerShaderMgr::DEFERRED_NORMAL);
 	sVertexProgram->disableTexture(LLViewerShaderMgr::SPECULAR_MAP);
@@ -876,6 +927,8 @@ void LLDrawPoolAvatar::endDeferredImpostor()
 
 void LLDrawPoolAvatar::beginDeferredRigid()
 {
+    LL_PROFILE_ZONE_SCOPED
+
 	sVertexProgram = &gDeferredNonIndexedDiffuseAlphaMaskNoColorProgram;
 	sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
 	sVertexProgram->bind();
@@ -892,6 +945,8 @@ void LLDrawPoolAvatar::beginDeferredRigid()
 
 void LLDrawPoolAvatar::endDeferredRigid()
 {
+    LL_PROFILE_ZONE_SCOPED
+
 	sShaderLevel = mShaderLevel;
 	sVertexProgram->disableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
 	sVertexProgram->unbind();
@@ -901,6 +956,8 @@ void LLDrawPoolAvatar::endDeferredRigid()
 
 void LLDrawPoolAvatar::beginSkinned()
 {
+    LL_PROFILE_ZONE_SCOPED
+
 	if (sShaderLevel > 0)
 	{
 		if (LLPipeline::sUnderWaterRender)
@@ -967,6 +1024,8 @@ void LLDrawPoolAvatar::beginSkinned()
 
 void LLDrawPoolAvatar::endSkinned()
 {
+    LL_PROFILE_ZONE_SCOPED
+
 	// 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)
 	{
@@ -991,6 +1050,8 @@ void LLDrawPoolAvatar::endSkinned()
 
 void LLDrawPoolAvatar::beginRiggedSimple()
 {
+    LL_PROFILE_ZONE_SCOPED
+
 	if (sShaderLevel > 0)
 	{
 		if (LLPipeline::sUnderWaterRender)
@@ -1031,6 +1092,8 @@ void LLDrawPoolAvatar::beginRiggedSimple()
 
 void LLDrawPoolAvatar::endRiggedSimple()
 {
+    LL_PROFILE_ZONE_SCOPED
+
 	LLVertexBuffer::unbind();
 	if (sShaderLevel > 0 || gPipeline.canUseVertexShaders())
 	{
@@ -1041,27 +1104,37 @@ void LLDrawPoolAvatar::endRiggedSimple()
 
 void LLDrawPoolAvatar::beginRiggedAlpha()
 {
+    LL_PROFILE_ZONE_SCOPED
+
 	beginRiggedSimple();
 }
 
 void LLDrawPoolAvatar::endRiggedAlpha()
 {
+    LL_PROFILE_ZONE_SCOPED
+
 	endRiggedSimple();
 }
 
 
 void LLDrawPoolAvatar::beginRiggedFullbrightAlpha()
 {
+    LL_PROFILE_ZONE_SCOPED
+
 	beginRiggedFullbright();
 }
 
 void LLDrawPoolAvatar::endRiggedFullbrightAlpha()
 {
+    LL_PROFILE_ZONE_SCOPED
+
 	endRiggedFullbright();
 }
 
 void LLDrawPoolAvatar::beginRiggedGlow()
 {
+    LL_PROFILE_ZONE_SCOPED
+
 	if (sShaderLevel > 0)
 	{
 		if (LLPipeline::sUnderWaterRender)
@@ -1108,11 +1181,15 @@ void LLDrawPoolAvatar::beginRiggedGlow()
 
 void LLDrawPoolAvatar::endRiggedGlow()
 {
+    LL_PROFILE_ZONE_SCOPED
+
 	endRiggedFullbright();
 }
 
 void LLDrawPoolAvatar::beginRiggedFullbright()
 {
+    LL_PROFILE_ZONE_SCOPED
+
 	if (sShaderLevel > 0)
 	{
 		if (LLPipeline::sUnderWaterRender)
@@ -1170,6 +1247,8 @@ void LLDrawPoolAvatar::beginRiggedFullbright()
 
 void LLDrawPoolAvatar::endRiggedFullbright()
 {
+    LL_PROFILE_ZONE_SCOPED
+
 	LLVertexBuffer::unbind();
 	if (sShaderLevel > 0 || gPipeline.canUseVertexShaders())
 	{
@@ -1180,6 +1259,8 @@ void LLDrawPoolAvatar::endRiggedFullbright()
 
 void LLDrawPoolAvatar::beginRiggedShinySimple()
 {
+    LL_PROFILE_ZONE_SCOPED
+
 	if (sShaderLevel > 0)
 	{
 		if (LLPipeline::sUnderWaterRender)
@@ -1220,6 +1301,8 @@ void LLDrawPoolAvatar::beginRiggedShinySimple()
 
 void LLDrawPoolAvatar::endRiggedShinySimple()
 {
+    LL_PROFILE_ZONE_SCOPED
+
 	LLVertexBuffer::unbind();
 	if (sShaderLevel > 0 || gPipeline.canUseVertexShaders())
 	{
@@ -1231,6 +1314,8 @@ void LLDrawPoolAvatar::endRiggedShinySimple()
 
 void LLDrawPoolAvatar::beginRiggedFullbrightShiny()
 {
+    LL_PROFILE_ZONE_SCOPED
+
 	if (sShaderLevel > 0)
 	{
 		if (LLPipeline::sUnderWaterRender)
@@ -1296,6 +1381,8 @@ void LLDrawPoolAvatar::beginRiggedFullbrightShiny()
 
 void LLDrawPoolAvatar::endRiggedFullbrightShiny()
 {
+    LL_PROFILE_ZONE_SCOPED
+
 	LLVertexBuffer::unbind();
 	if (sShaderLevel > 0 || gPipeline.canUseVertexShaders())
 	{
@@ -1308,6 +1395,8 @@ void LLDrawPoolAvatar::endRiggedFullbrightShiny()
 
 void LLDrawPoolAvatar::beginDeferredRiggedSimple()
 {
+    LL_PROFILE_ZONE_SCOPED
+
 	sVertexProgram = &gDeferredSkinnedDiffuseProgram;
 	sDiffuseChannel = 0;
 	sVertexProgram->bind();
@@ -1323,6 +1412,8 @@ void LLDrawPoolAvatar::beginDeferredRiggedSimple()
 
 void LLDrawPoolAvatar::endDeferredRiggedSimple()
 {
+    LL_PROFILE_ZONE_SCOPED
+
 	LLVertexBuffer::unbind();
 	sVertexProgram->unbind();
 	sVertexProgram = NULL;
@@ -1330,6 +1421,8 @@ void LLDrawPoolAvatar::endDeferredRiggedSimple()
 
 void LLDrawPoolAvatar::beginDeferredRiggedBump()
 {
+    LL_PROFILE_ZONE_SCOPED
+
 	sVertexProgram = &gDeferredSkinnedBumpProgram;
 	sVertexProgram->bind();
     if (LLPipeline::sRenderingHUDs)
@@ -1346,6 +1439,8 @@ void LLDrawPoolAvatar::beginDeferredRiggedBump()
 
 void LLDrawPoolAvatar::endDeferredRiggedBump()
 {
+    LL_PROFILE_ZONE_SCOPED
+
 	LLVertexBuffer::unbind();
 	sVertexProgram->disableTexture(LLViewerShaderMgr::BUMP_MAP);
 	sVertexProgram->disableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
@@ -1357,6 +1452,8 @@ void LLDrawPoolAvatar::endDeferredRiggedBump()
 
 void LLDrawPoolAvatar::beginDeferredRiggedMaterial(S32 pass)
 {
+    LL_PROFILE_ZONE_SCOPED
+
 	if (pass == 1 ||
 		pass == 5 ||
 		pass == 9 ||
@@ -1387,6 +1484,8 @@ void LLDrawPoolAvatar::beginDeferredRiggedMaterial(S32 pass)
 
 void LLDrawPoolAvatar::endDeferredRiggedMaterial(S32 pass)
 {
+    LL_PROFILE_ZONE_SCOPED
+
 	if (pass == 1 ||
 		pass == 5 ||
 		pass == 9 ||
@@ -1407,6 +1506,8 @@ void LLDrawPoolAvatar::endDeferredRiggedMaterial(S32 pass)
 
 void LLDrawPoolAvatar::beginDeferredSkinned()
 {
+    LL_PROFILE_ZONE_SCOPED
+
 	sShaderLevel = mShaderLevel;
 	sVertexProgram = &gDeferredAvatarProgram;
 	sRenderingSkinned = TRUE;
@@ -1428,6 +1529,8 @@ void LLDrawPoolAvatar::beginDeferredSkinned()
 
 void LLDrawPoolAvatar::endDeferredSkinned()
 {
+    LL_PROFILE_ZONE_SCOPED
+
 	// 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();
@@ -1582,7 +1685,7 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass)
 				renderRigged(avatarp, RIGGED_MATERIAL_ALPHA_EMISSIVE);
 				renderRigged(avatarp, RIGGED_NORMMAP);
 				renderRigged(avatarp, RIGGED_NORMMAP_MASK);
-				renderRigged(avatarp, RIGGED_NORMMAP_EMISSIVE);	
+				renderRigged(avatarp, RIGGED_NORMMAP_EMISSIVE);
 				renderRigged(avatarp, RIGGED_SPECMAP);
 				renderRigged(avatarp, RIGGED_SPECMAP_MASK);
 				renderRigged(avatarp, RIGGED_SPECMAP_EMISSIVE);
@@ -1740,6 +1843,8 @@ void LLDrawPoolAvatar::getRiggedGeometry(
     LLVolume* volume,
     const LLVolumeFace& vol_face)
 {
+    LL_PROFILE_ZONE_SCOPED
+
     face->setGeomIndex(0);
     face->setIndicesIndex(0);
 
@@ -1794,7 +1899,7 @@ void LLDrawPoolAvatar::getRiggedGeometry(
 
 	U16 offset = 0;
 		
-	LLMatrix4 mat_vert = skin->mBindShapeMatrix;
+	LLMatrix4 mat_vert = LLMatrix4(skin->mBindShapeMatrix);
 	glh::matrix4f m((F32*) mat_vert.mMatrix);
 	m = m.inverse().transpose();
 		
@@ -1836,24 +1941,26 @@ void LLDrawPoolAvatar::getRiggedGeometry(
 void LLDrawPoolAvatar::updateRiggedFaceVertexBuffer(
     LLVOAvatar* avatar,
     LLFace* face,
-    const LLMeshSkinInfo* skin,
+    const LLVOVolume* vobj,
     LLVolume* volume,
     LLVolumeFace& vol_face)
 {
+    LL_PROFILE_ZONE_SCOPED;
+
 	LLVector4a* weights = vol_face.mWeights;
 	if (!weights)
 	{
 		return;
 	}
 
+    if (!vobj || vobj->isNoLOD())
+    {
+        return;
+    }
+
 	LLPointer<LLVertexBuffer> buffer = face->getVertexBuffer();
 	LLDrawable* drawable = face->getDrawable();
 
-	if (drawable->getVOVolume() && drawable->getVOVolume()->isNoLOD())
-	{
-		return;
-	}
-
     const U32 max_joints = LLSkinningUtil::getMaxJointCount();
 
 #if USE_SEPARATE_JOINT_INDICES_AND_WEIGHTS
@@ -1893,23 +2000,26 @@ void LLDrawPoolAvatar::updateRiggedFaceVertexBuffer(
     }
 #endif
 
-    // FIXME ugly const cast
-    LLSkinningUtil::scrubInvalidJoints(avatar, const_cast<LLMeshSkinInfo*>(skin));
-
-	U32 data_mask = face->getRiggedVertexBufferDataMask();
+    U32 data_mask = face->getRiggedVertexBufferDataMask();
+    const LLMeshSkinInfo* skin = nullptr;
 
-    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)))
 	{
+        LL_PROFILE_ZONE_NAMED("Rigged VBO Rebuild");
+        skin = vobj->getSkinInfo();
+        // FIXME ugly const cast
+        LLSkinningUtil::scrubInvalidJoints(avatar, const_cast<LLMeshSkinInfo*>(skin));
+
+        if (!vol_face.mWeightsScrubbed)
+        {
+            LLSkinningUtil::scrubSkinWeights(weights, vol_face.mNumVertices, skin);
+            vol_face.mWeightsScrubbed = TRUE;
+        }
+
 		if (drawable && drawable->isState(LLDrawable::REBUILD_ALL))
 		{
             //rebuild EVERY face in the drawable, not just this one, to avoid missing drawable wide rebuild issues
@@ -1935,18 +2045,13 @@ void LLDrawPoolAvatar::updateRiggedFaceVertexBuffer(
 		}
 	}
 
-	if (buffer.isNull() ||
-		buffer->getNumVerts() != vol_face.mNumVertices ||
-		buffer->getNumIndices() != vol_face.mNumIndices)
-	{
-		// Allocation failed
-		return;
-	}
-
-	if (!buffer.isNull() && 
-		sShaderLevel <= 0 && 
-		face->mLastSkinTime < avatar->getLastSkinTime())
+	if (sShaderLevel <= 0 && 
+        face->mLastSkinTime < avatar->getLastSkinTime() &&
+        !buffer.isNull() &&
+        buffer->getNumVerts() == vol_face.mNumVertices &&
+        buffer->getNumIndices() == vol_face.mNumIndices)
 	{
+        LL_PROFILE_ZONE_NAMED("Software Skinning");
 		//perform software vertex skinning for this face
 		LLStrider<LLVector3> position;
 		LLStrider<LLVector3> normal;
@@ -1962,54 +2067,12 @@ void LLDrawPoolAvatar::updateRiggedFaceVertexBuffer(
 		LLVector4a* pos = (LLVector4a*) position.get();
 
 		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);
+        const MatrixPaletteCache& mpc = updateSkinInfoMatrixPalette(avatar, vobj->getMeshID());
+        const LLMatrix4a* mat = &(mpc.mMatrixPalette[0]);
+        const LLMatrix4a& bind_shape_matrix = mpc.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
+        if (!mpc.mMatrixPalette.empty())
         {
             for (U32 j = 0; j < buffer->getNumVerts(); ++j)
 		    {
@@ -2038,22 +2101,25 @@ void LLDrawPoolAvatar::updateRiggedFaceVertexBuffer(
 
 void LLDrawPoolAvatar::renderRigged(LLVOAvatar* avatar, U32 type, bool glow)
 {
+    LL_PROFILE_ZONE_SCOPED
+
 	if (!avatar->shouldRenderRigged())
 	{
 		return;
 	}
 
-	stop_glerror();
+    LLUUID lastMeshId;
 
 	for (U32 i = 0; i < mRiggedFace[type].size(); ++i)
 	{
+        LL_PROFILE_ZONE_NAMED("Render Rigged Face");
 		LLFace* face = mRiggedFace[type][i];
 
         S32 offset = face->getIndicesStart();
 		U32 count = face->getIndicesCount();
 
         U16 start = face->getGeomStart();
-		U16 end = start + face->getGeomCount()-1;			
+		U16 end = start + face->getGeomCount()-1;
 
 		LLDrawable* drawable = face->getDrawable();
 		if (!drawable)
@@ -2076,19 +2142,6 @@ void LLDrawPoolAvatar::renderRigged(LLVOAvatar* avatar, U32 type, bool glow)
 			continue;
 		}
 
-		const LLMeshSkinInfo* skin = vobj->getSkinInfo();
-		if (!skin)
-		{
-			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();
@@ -2175,57 +2228,36 @@ void LLDrawPoolAvatar::renderRigged(LLVOAvatar* avatar, U32 type, bool glow)
         }
 
 		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];
+                auto& meshId = vobj->getMeshID();
+                
+                if (lastMeshId != meshId) // <== only upload matrix palette to GL if the skininfo changed
+                {
+                    // upload matrix palette to shader
+                    const MatrixPaletteCache& mpc = updateSkinInfoMatrixPalette(avatar, meshId);
+                    U32 count = mpc.mMatrixPalette.size();
 
-					mp[idx+8] = m[8];
-					mp[idx+9] = m[9];
-					mp[idx+10] = m[10];
-					mp[idx+11] = m[14];
-				}
+                    if (count == 0)
+                    {
+                        //skin info not loaded yet, don't render
+                        continue;
+                    }
 
-				LLDrawPoolAvatar::sVertexProgram->uniformMatrix3x4fv(LLViewerShaderMgr::AVATAR_MATRIX, 
-					count,
-					FALSE,
-					(GLfloat*) mp);
+                    LLDrawPoolAvatar::sVertexProgram->uniformMatrix3x4fv(LLViewerShaderMgr::AVATAR_MATRIX,
+                        count,
+                        FALSE,
+                        (GLfloat*) &(mpc.mGLMp[0]));
+                }
 
-				stop_glerror();
+                lastMeshId = meshId;
 			}
 			else
 			{
 				data_mask &= ~LLVertexBuffer::MAP_WEIGHT4;
 			}
 
-			/*if (glow)
-			{
-				gGL.diffuseColor4f(0,0,0,face->getTextureEntry()->getGlow());
-			}*/
-
 			if (mat)
 			{
 				//order is important here LLRender::DIFFUSE_MAP should be last, becouse it change 
@@ -2240,13 +2272,17 @@ void LLDrawPoolAvatar::renderRigged(LLVOAvatar* avatar, U32 type, bool glow)
                 {
                     specular = face->getTexture(LLRender::SPECULAR_MAP);
                 }
-                if (specular)
+                if (specular && specular_channel >= 0)
                 {
-                    gGL.getTexUnit(specular_channel)->bind(specular);
+                    gGL.getTexUnit(specular_channel)->bindFast(specular);
                 }
                 
-				gGL.getTexUnit(normal_channel)->bind(face->getTexture(LLRender::NORMAL_MAP));
-				gGL.getTexUnit(sDiffuseChannel)->bind(face->getTexture(LLRender::DIFFUSE_MAP), false, true);
+                if (normal_channel >= 0)
+                {
+                    gGL.getTexUnit(normal_channel)->bindFast(face->getTexture(LLRender::NORMAL_MAP));
+                }
+
+				gGL.getTexUnit(sDiffuseChannel)->bindFast(face->getTexture(LLRender::DIFFUSE_MAP));
 
 
 				LLColor4 col = mat->getSpecularLightColor();
@@ -2277,23 +2313,28 @@ void LLDrawPoolAvatar::renderRigged(LLVOAvatar* avatar, U32 type, bool glow)
 					sVertexProgram->setMinimumAlpha(0.f);
 				}
 
-				for (U32 i = 0; i < LLRender::NUM_TEXTURE_CHANNELS; ++i)
-				{
-					LLViewerTexture* tex = face->getTexture(i);
-					if (tex)
-					{
-						tex->addTextureStats(avatar->getPixelArea());
-					}
-				}
+                if (!LLPipeline::sShadowRender && !LLPipeline::sReflectionRender)
+                {
+                    for (U32 i = 0; i < LLRender::NUM_TEXTURE_CHANNELS; ++i)
+                    {
+                        LLViewerTexture* tex = face->getTexture(i);
+                        if (tex)
+                        {
+                            tex->addTextureStats(avatar->getPixelArea());
+                        }
+                    }
+                }
 			}
 			else
 			{
-				gGL.getTexUnit(sDiffuseChannel)->bind(face->getTexture());
 				sVertexProgram->setMinimumAlpha(0.f);
 				if (normal_channel > -1)
 				{
 					LLDrawPoolBump::bindBumpMap(face, normal_channel);
 				}
+
+                gGL.getTexUnit(sDiffuseChannel)->bindFast(face->getTexture());
+
 			}
 
 			if (face->mTextureMatrix && vobj->mTexAnimMode)
@@ -2307,8 +2348,8 @@ void LLDrawPoolAvatar::renderRigged(LLVOAvatar* avatar, U32 type, bool glow)
 				    gGL.loadMatrix((F32*) face->mTextureMatrix->mMatrix);
                 }
 
-				buff->setBuffer(data_mask);
-				buff->drawRange(LLRender::TRIANGLES, start, end, count, offset);
+				buff->setBufferFast(data_mask);
+				buff->drawRangeFast(LLRender::TRIANGLES, start, end, count, offset);
 
                 if (tex_index <= 1)
                 {
@@ -2319,27 +2360,31 @@ void LLDrawPoolAvatar::renderRigged(LLVOAvatar* avatar, U32 type, bool glow)
 			}
 			else
 			{
-				buff->setBuffer(data_mask);
-				buff->drawRange(LLRender::TRIANGLES, start, end, count, offset);		
+				buff->setBufferFast(data_mask);
+				buff->drawRangeFast(LLRender::TRIANGLES, start, end, count, offset);
 			}
-
-			gPipeline.addTrianglesDrawn(count, LLRender::TRIANGLES);
 		}
 	}
 }
 
 void LLDrawPoolAvatar::renderDeferredRiggedSimple(LLVOAvatar* avatar)
 {
+    LL_PROFILE_ZONE_SCOPED
+
 	renderRigged(avatar, RIGGED_DEFERRED_SIMPLE);
 }
 
 void LLDrawPoolAvatar::renderDeferredRiggedBump(LLVOAvatar* avatar)
 {
+    LL_PROFILE_ZONE_SCOPED
+
 	renderRigged(avatar, RIGGED_DEFERRED_BUMP);
 }
 
 void LLDrawPoolAvatar::renderDeferredRiggedMaterial(LLVOAvatar* avatar, S32 pass)
 {
+    LL_PROFILE_ZONE_SCOPED
+
 	renderRigged(avatar, pass);
 }
 
@@ -2352,8 +2397,10 @@ void LLDrawPoolAvatar::updateRiggedVertexBuffers(LLVOAvatar* avatar)
 	//update rigged vertex buffers
 	for (U32 type = 0; type < NUM_RIGGED_PASSES; ++type)
 	{
+        LL_PROFILE_ZONE_NAMED("Pass");
 		for (U32 i = 0; i < mRiggedFace[type].size(); ++i)
 		{
+            LL_PROFILE_ZONE_NAMED("Face");
 			LLFace* face = mRiggedFace[type][i];
 			LLDrawable* drawable = face->getDrawable();
 			if (!drawable)
@@ -2376,43 +2423,120 @@ void LLDrawPoolAvatar::updateRiggedVertexBuffers(LLVOAvatar* avatar)
 				continue;
 			}
 
-			const LLMeshSkinInfo* skin = vobj->getSkinInfo();
-			if (!skin)
-			{
-				continue;
-			}
-
-			stop_glerror();
-
 			LLVolumeFace& vol_face = volume->getVolumeFace(te);
-			updateRiggedFaceVertexBuffer(avatar, face, skin, volume, vol_face);
+			updateRiggedFaceVertexBuffer(avatar, face, vobj, volume, vol_face);
 		}
 	}
 }
 
+void LLDrawPoolAvatar::updateSkinInfoMatrixPalettes(LLVOAvatar* avatarp)
+{
+    LL_PROFILE_ZONE_SCOPED;
+    //evict matrix palettes from the cache that haven't been updated in 10 frames
+    for (matrix_palette_cache_t::iterator iter = mMatrixPaletteCache.begin(); iter != mMatrixPaletteCache.end(); )
+    {
+        if (gFrameCount - iter->second.mFrame > 10)
+        {
+            iter = mMatrixPaletteCache.erase(iter);
+        }
+        else
+        {
+            ++iter;
+        }
+    }
+}
+
+const LLDrawPoolAvatar::MatrixPaletteCache& LLDrawPoolAvatar::updateSkinInfoMatrixPalette(LLVOAvatar * avatarp, const LLUUID& meshId)
+{
+    MatrixPaletteCache& entry = mMatrixPaletteCache[meshId];
+
+    if (entry.mFrame != gFrameCount)
+    {
+        LL_PROFILE_ZONE_SCOPED;
+
+        const LLMeshSkinInfo* skin = gMeshRepo.getSkinInfo(meshId);
+        entry.mFrame = gFrameCount;
+
+        if (skin != nullptr)
+        {
+            entry.mBindShapeMatrix = skin->mBindShapeMatrix;
+
+            //build matrix palette
+            U32 count = LLSkinningUtil::getMeshJointCount(skin);
+            entry.mMatrixPalette.resize(count);
+            LLSkinningUtil::initSkinningMatrixPalette(&(entry.mMatrixPalette[0]), count, skin, avatarp);
+
+            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];
+            }
+        }
+        else
+        {
+            entry.mMatrixPalette.resize(0);
+            entry.mGLMp.resize(0);
+        }
+    }
+
+    return entry;
+}
+
 void LLDrawPoolAvatar::renderRiggedSimple(LLVOAvatar* avatar)
 {
+    LL_PROFILE_ZONE_SCOPED
+
 	renderRigged(avatar, RIGGED_SIMPLE);
 }
 
 void LLDrawPoolAvatar::renderRiggedFullbright(LLVOAvatar* avatar)
 {
+    LL_PROFILE_ZONE_SCOPED
+
 	renderRigged(avatar, RIGGED_FULLBRIGHT);
 }
 
 	
 void LLDrawPoolAvatar::renderRiggedShinySimple(LLVOAvatar* avatar)
 {
+    LL_PROFILE_ZONE_SCOPED
+
 	renderRigged(avatar, RIGGED_SHINY);
 }
 
 void LLDrawPoolAvatar::renderRiggedFullbrightShiny(LLVOAvatar* avatar)
 {
+    LL_PROFILE_ZONE_SCOPED
+
 	renderRigged(avatar, RIGGED_FULLBRIGHT_SHINY);
 }
 
 void LLDrawPoolAvatar::renderRiggedAlpha(LLVOAvatar* avatar)
 {
+    LL_PROFILE_ZONE_SCOPED
+
 	if (!mRiggedFace[RIGGED_ALPHA].empty())
 	{
 		LLGLEnable blend(GL_BLEND);
@@ -2430,6 +2554,8 @@ void LLDrawPoolAvatar::renderRiggedAlpha(LLVOAvatar* avatar)
 
 void LLDrawPoolAvatar::renderRiggedFullbrightAlpha(LLVOAvatar* avatar)
 {
+    LL_PROFILE_ZONE_SCOPED
+
 	if (!mRiggedFace[RIGGED_FULLBRIGHT_ALPHA].empty())
 	{
 		LLGLEnable blend(GL_BLEND);
@@ -2447,6 +2573,8 @@ void LLDrawPoolAvatar::renderRiggedFullbrightAlpha(LLVOAvatar* avatar)
 
 void LLDrawPoolAvatar::renderRiggedGlow(LLVOAvatar* avatar)
 {
+    LL_PROFILE_ZONE_SCOPED
+
 	if (!mRiggedFace[RIGGED_GLOW].empty())
 	{
 		LLGLEnable blend(GL_BLEND);
@@ -2474,6 +2602,8 @@ void LLDrawPoolAvatar::renderRiggedGlow(LLVOAvatar* avatar)
 //-----------------------------------------------------------------------------
 LLViewerTexture *LLDrawPoolAvatar::getDebugTexture()
 {
+    LL_PROFILE_ZONE_SCOPED
+
 	if (mReferences.empty())
 	{
 		return NULL;
@@ -2497,6 +2627,8 @@ LLColor3 LLDrawPoolAvatar::getDebugColor() const
 
 void LLDrawPoolAvatar::addRiggedFace(LLFace* facep, U32 type)
 {
+    LL_PROFILE_ZONE_SCOPED
+
     llassert (facep->isState(LLFace::RIGGED));
     llassert(getType() == LLDrawPool::POOL_AVATAR || getType() == LLDrawPool::POOL_CONTROL_AV);
     if (facep->getPool() && facep->getPool() != this)
@@ -2519,6 +2651,8 @@ void LLDrawPoolAvatar::addRiggedFace(LLFace* facep, U32 type)
 
 void LLDrawPoolAvatar::removeRiggedFace(LLFace* facep)
 {
+    LL_PROFILE_ZONE_SCOPED
+
     llassert (facep->isState(LLFace::RIGGED));
     llassert(getType() == LLDrawPool::POOL_AVATAR || getType() == LLDrawPool::POOL_CONTROL_AV);
     if (facep->getPool() != this)
@@ -2556,7 +2690,7 @@ LLVertexBufferAvatar::LLVertexBufferAvatar()
 : LLVertexBuffer(sDataMask, 
 	GL_STREAM_DRAW_ARB) //avatars are always stream draw due to morph targets
 {
-
+    LL_PROFILE_ZONE_SCOPED
 }
 
 
diff --git a/indra/newview/lldrawpoolavatar.h b/indra/newview/lldrawpoolavatar.h
index 92a85389588cb3a06c02e0bfc6f9ce14d68dba37..800bbc5f62afec6f1f5aa28f1823b8386c8369d5 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
 {
@@ -253,11 +257,13 @@ typedef enum
 	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, 
+									  const LLVOVolume* vobj,
 									  LLVolume* volume,
 									  LLVolumeFace& vol_face);
 	void updateRiggedVertexBuffers(LLVOAvatar* avatar);
 
+    void updateSkinInfoMatrixPalettes(LLVOAvatar* avatarp);
+
 	void renderRigged(LLVOAvatar* avatar, U32 type, bool glow = false);
 	void renderRiggedSimple(LLVOAvatar* avatar);
 	void renderRiggedAlpha(LLVOAvatar* avatar);
@@ -277,6 +283,27 @@ typedef enum
 
 	std::vector<LLFace*> mRiggedFace[NUM_RIGGED_PASSES];
 
+    LL_ALIGN_PREFIX(16)
+    class MatrixPaletteCache
+    {
+    public:
+        U32 mFrame;
+        LLMeshSkinInfo::matrix_list_t mMatrixPalette;
+        LL_ALIGN_16(LLMatrix4a mBindShapeMatrix);
+        // Float array ready to be sent to GL
+        std::vector<F32> mGLMp;
+
+        MatrixPaletteCache() :
+            mFrame(gFrameCount-1)
+        {
+        }
+    } LL_ALIGN_POSTFIX(16);
+    
+    const MatrixPaletteCache& updateSkinInfoMatrixPalette(LLVOAvatar* avatarp, const LLUUID& meshId);
+
+    typedef std::unordered_map<LLUUID, MatrixPaletteCache> matrix_palette_cache_t;
+    matrix_palette_cache_t mMatrixPaletteCache;
+
 	/*virtual*/ LLViewerTexture *getDebugTexture();
 	/*virtual*/ LLColor3 getDebugColor() const; // For AGP debug display
 
diff --git a/indra/newview/lldrawpoolbump.cpp b/indra/newview/lldrawpoolbump.cpp
index 14069fa6c2bbef8b940093d12efada767f464049..d75884cc1622ab9f4d1c7d5cde09d14895f18574 100644
--- a/indra/newview/lldrawpoolbump.cpp
+++ b/indra/newview/lldrawpoolbump.cpp
@@ -677,6 +677,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;
 	//Note: texture atlas does not support bump texture now.
 	LLViewerFetchedTexture* tex = LLViewerTextureManager::staticCastToFetchedTexture(texture) ;
 	if(!tex)
@@ -693,7 +694,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 +710,12 @@ 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);
+			gGL.getTexUnit(channel)->bindFast(bump);
 		}
 
 		return TRUE;
@@ -1061,6 +1062,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;
 	llassert( (bump_code == BE_BRIGHTNESS) || (bump_code == BE_DARKNESS) );
 
 	LLViewerTexture* bump = NULL;
@@ -1497,6 +1499,7 @@ void LLDrawPoolBump::renderBump(U32 type, U32 mask)
 
 void LLDrawPoolBump::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture, BOOL batch_textures)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	applyModelMatrix(params);
 
 	bool tex_setup = false;
@@ -1507,7 +1510,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 +1525,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 +1541,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 +1554,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 +1565,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);
 		}
diff --git a/indra/newview/lldrawpoolbump.h b/indra/newview/lldrawpoolbump.h
index 476b1d41b7d40d85ac08d6fb353cabe18d4773b3..bab160c34da854e4f50576aec3b9c55890ad7d2b 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;
@@ -161,7 +163,7 @@ 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;
 };
diff --git a/indra/newview/lldrawpoolmaterials.cpp b/indra/newview/lldrawpoolmaterials.cpp
index 05b0c1f1a93c6c666bee6916611e082206dccdd9..d2a8757379925f23f1cc395e6dfde7ce8ff2afb0 100644
--- a/indra/newview/lldrawpoolmaterials.cpp
+++ b/indra/newview/lldrawpoolmaterials.cpp
@@ -106,6 +106,7 @@ void LLDrawPoolMaterials::endDeferredPass(S32 pass)
 
 void LLDrawPoolMaterials::renderDeferred(S32 pass)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	static const U32 type_list[] = 
 	{
 		LLRenderPass::PASS_MATERIAL,
@@ -157,7 +158,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;
+            pushMaterialsBatch(params, mask);
+        }
 	}
 }
 
@@ -171,49 +175,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)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	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())
+		{
+			gGL.getTexUnit(diffuse_channel)->bindFast(params.mTexture);
+		}
+		else
 		{
-			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)->unbindFast(LLTexUnit::TT_TEXTURE);
 		}
 	}
 	
@@ -224,9 +216,9 @@ void LLDrawPoolMaterials::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture,
 
 	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..6e39821b0771b5e1ff249b3b4c1ed2fa20ccde85 100644
--- a/indra/newview/lldrawpoolmaterials.h
+++ b/indra/newview/lldrawpoolmaterials.h
@@ -69,7 +69,7 @@ class LLDrawPoolMaterials : public LLRenderPass
 	void bindSpecularMap(LLViewerTexture* tex);
 	void bindNormalMap(LLViewerTexture* tex);
 	
-	/*virtual*/ void pushBatch(LLDrawInfo& params, U32 mask, BOOL texture, BOOL batch_textures = FALSE);
+	/*virtual*/ void pushMaterialsBatch(LLDrawInfo& params, U32 mask);
 };
 
 #endif //LL_LLDRAWPOOLMATERIALS_H
diff --git a/indra/newview/lldrawpoolsimple.cpp b/indra/newview/lldrawpoolsimple.cpp
index f211cf6e27b6c24b981d9366d1b6f2e290f00795..843288cfb03a4cd546c7f01f93ab8bc2f4c68ee5 100644
--- a/indra/newview/lldrawpoolsimple.cpp
+++ b/indra/newview/lldrawpoolsimple.cpp
@@ -150,13 +150,6 @@ void LLDrawPoolGlow::render(S32 pass)
 	}
 }
 
-void LLDrawPoolGlow::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture, BOOL batch_textures)
-{
-	//gGL.diffuseColor4ubv(params.mGlowColor.mV);
-	LLRenderPass::pushBatch(params, mask, texture, batch_textures);
-}
-
-
 LLDrawPoolSimple::LLDrawPoolSimple() :
 	LLRenderPass(POOL_SIMPLE)
 {
@@ -199,11 +192,7 @@ void LLDrawPoolSimple::beginRenderPass(S32 pass)
 	}
 	else 
 	{
-		// don't use shaders!
-		if (gGLManager.mHasShaderObjects)
-		{
-			LLGLSLShader::bindNoShader();
-		}		
+		LLGLSLShader::bindNoShader();
 	}
 }
 
@@ -301,11 +290,7 @@ void LLDrawPoolAlphaMask::beginRenderPass(S32 pass)
 	}
 	else 
 	{
-		// don't use shaders!
-		if (gGLManager.mHasShaderObjects)
-		{
-			LLGLSLShader::bindNoShader();
-		}		
+		LLGLSLShader::bindNoShader();
 	}
 }
 
@@ -392,11 +377,7 @@ void LLDrawPoolFullbrightAlphaMask::beginRenderPass(S32 pass)
 	}
 	else 
 	{
-		// don't use shaders!
-		if (gGLManager.mHasShaderObjects)
-		{
-			LLGLSLShader::bindNoShader();
-		}		
+		LLGLSLShader::bindNoShader();
 	}
 }
 
@@ -483,6 +464,7 @@ void LLDrawPoolSimple::endDeferredPass(S32 pass)
 
 void LLDrawPoolSimple::renderDeferred(S32 pass)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	LLGLDisable blend(GL_BLEND);
 	LLGLDisable alpha_test(GL_ALPHA_TEST);
 
@@ -567,11 +549,7 @@ void LLDrawPoolGrass::beginRenderPass(S32 pass)
 	else 
 	{
 		gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.5f);
-		// don't use shaders!
-		if (gGLManager.mHasShaderObjects)
-		{
-			LLGLSLShader::bindNoShader();
-		}		
+		LLGLSLShader::bindNoShader();
 	}
 }
 
diff --git a/indra/newview/lldrawpoolsimple.h b/indra/newview/lldrawpoolsimple.h
index 608ad9e1eb0856a2095769b117f99fe070ee5cf9..b27cc4babc658caaa536785a9b50c2610d8bbc88 100644
--- a/indra/newview/lldrawpoolsimple.h
+++ b/indra/newview/lldrawpoolsimple.h
@@ -187,7 +187,6 @@ class LLDrawPoolGlow : public LLRenderPass
 	/*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..b1eefaab812c28a158c968798b7f635c329a2883 100644
--- a/indra/newview/lldrawpoolsky.cpp
+++ b/indra/newview/lldrawpoolsky.cpp
@@ -82,13 +82,7 @@ void LLDrawPoolSky::render(S32 pass)
 	}
 	else
 	{
-		// don't use shaders!
-		if (gGLManager.mHasShaderObjects)
-		{
-			// Ironically, we must support shader objects to be
-			// able to use this call.
-			LLGLSLShader::bindNoShader();
-		}
+		LLGLSLShader::bindNoShader();
 		mShader = NULL;
 	}
 	
diff --git a/indra/newview/lldrawpoolterrain.cpp b/indra/newview/lldrawpoolterrain.cpp
index 37dc80e2b7d95e9e05c577eae0e94a78ee5d2b28..34a8b6b2cc0b469be84d057f1114998a6f1177fb 100644
--- a/indra/newview/lldrawpoolterrain.cpp
+++ b/indra/newview/lldrawpoolterrain.cpp
@@ -343,8 +343,6 @@ void LLDrawPoolTerrain::renderFullShader()
 
     LLSettingsWater::ptr_t pwater = LLEnvironment::instance().getCurrentWater();
 
-    ((LLSettingsVOWater*)pwater.get())->updateShader(shader);
-
 	//
 	// detail texture 1
 	//
diff --git a/indra/newview/lldrawpooltree.cpp b/indra/newview/lldrawpooltree.cpp
index 0d5195bdbfcd67211519270c39e3d029658905ed..a1ff020068629c6933177b29797195193acf3a40 100644
--- a/indra/newview/lldrawpooltree.cpp
+++ b/indra/newview/lldrawpooltree.cpp
@@ -153,6 +153,7 @@ void LLDrawPoolTree::beginDeferredPass(S32 pass)
 
 void LLDrawPoolTree::renderDeferred(S32 pass)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	render(pass);
 }
 
diff --git a/indra/newview/lldrawpoolwlsky.cpp b/indra/newview/lldrawpoolwlsky.cpp
index 0c3d8f3098fa334bd0ef8a4c1325a3766c0b93b8..8c8dc3f3d2c480eafeb45ba652c145603a226ca3 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();
@@ -406,8 +404,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 +458,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);
 
diff --git a/indra/newview/llenvironment.cpp b/indra/newview/llenvironment.cpp
index 8881d118023c2efac9f2c77d896fe628a5cf219e..69d30759285e5e6fe0002f43bc7bef4c28c7072c 100644
--- a/indra/newview/llenvironment.cpp
+++ b/indra/newview/llenvironment.cpp
@@ -1471,6 +1471,7 @@ LLEnvironment::DayInstance::ptr_t LLEnvironment::getSharedEnvironmentInstance()
 
 void LLEnvironment::updateEnvironment(LLSettingsBase::Seconds transition, bool forced)
 {
+    LL_PROFILE_ZONE_SCOPED;
     DayInstance::ptr_t pinstance = getSelectedEnvironmentInstance();
 
     if ((mCurrentEnvironment != pinstance) || forced)
@@ -1488,6 +1489,8 @@ void LLEnvironment::updateEnvironment(LLSettingsBase::Seconds transition, bool f
         {
             mCurrentEnvironment = pinstance;
         }
+
+        updateSettingsUniforms();
     }
 }
 
@@ -1614,6 +1617,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 +1653,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);
 
+    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 +1705,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 +1718,30 @@ 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)
+{
+    LL_PROFILE_ZONE_SCOPED;
+
+    // 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::updateShaderUniforms(LLGLSLShader *shader)
+void LLEnvironment::updateSettingsUniforms()
 {
-    updateGLVariablesForSettings(shader, mCurrentEnvironment->getWater());
-    updateGLVariablesForSettings(shader, mCurrentEnvironment->getSky());
+    updateGLVariablesForSettings(mWaterUniforms, mCurrentEnvironment->getWater());
+    updateGLVariablesForSettings(mSkyUniforms, mCurrentEnvironment->getSky());
 }
 
 void LLEnvironment::recordEnvironment(S32 parcel_id, LLEnvironment::EnvironmentInfo::ptr_t envinfo, LLSettingsBase::Seconds transition)
@@ -2618,6 +2642,7 @@ LLEnvironment::DayInstance::ptr_t LLEnvironment::DayInstance::clone() const
 
 bool LLEnvironment::DayInstance::applyTimeDelta(const LLSettingsBase::Seconds& delta)
 {
+    LL_PROFILE_ZONE_SCOPED;
     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..3568fbcfd1cf68aac262e1f2c730f24b88e3f585 100644
--- a/indra/newview/llenvironment.h
+++ b/indra/newview/llenvironment.h
@@ -38,11 +38,12 @@
 
 #include "llatmosphere.h"
 
+#include "llglslshader.h"
+
 #include <boost/signals2.hpp>
 
 //-------------------------------------------------------------------------
 class LLViewerCamera;
-class LLGLSLShader;
 class LLParcel;
 
 //-------------------------------------------------------------------------
@@ -50,8 +51,8 @@ class LLEnvironment : public LLSingleton<LLEnvironment>
 {
     LLSINGLETON_C11(LLEnvironment);
     LOG_CLASS(LLEnvironment);
-
 public:
+
     static const F64Seconds     TRANSITION_INSTANT;
     static const F64Seconds     TRANSITION_FAST;
     static const F64Seconds     TRANSITION_DEFAULT;
@@ -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; }
 
@@ -234,6 +240,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 +299,7 @@ class LLEnvironment : public LLSingleton<LLEnvironment>
         LLSettingsDay::ptr_t        mDayCycle;
         LLSettingsSky::ptr_t        mSky;
         LLSettingsWater::ptr_t      mWater;
+
         S32                         mSkyTrack;
 
         bool                        mInitialized;
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 4a802ad9aa774462f5faa92d06c1f9dd7cc6567d..34448a780d95db7d559ce732279ba08f538886f6 100644
--- a/indra/newview/llface.cpp
+++ b/indra/newview/llface.cpp
@@ -241,6 +241,8 @@ void LLFace::setPool(LLFacePool* pool)
 
 void LLFace::setPool(LLFacePool* new_pool, LLViewerTexture *texturep)
 {
+	LL_PROFILE_ZONE_SCOPED
+
 	if (!new_pool)
 	{
 		LL_ERRS() << "Setting pool to null!" << LL_ENDL;
@@ -320,6 +322,8 @@ void LLFace::setSpecularMap(LLViewerTexture* tex)
 
 void LLFace::dirtyTexture()
 {
+	LL_PROFILE_ZONE_SCOPED
+
 	LLDrawable* drawablep = getDrawable();
 
 	if (mVObjp.notNull() && mVObjp->getVolume())
@@ -535,6 +539,8 @@ void LLFace::updateCenterAgent()
 
 void LLFace::renderSelected(LLViewerTexture *imagep, const LLColor4& color)
 {
+	LL_PROFILE_ZONE_SCOPED
+
 	if (mDrawablep == NULL || mDrawablep->getSpatialGroup() == NULL)
 	{
 		return;
@@ -585,6 +591,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 +612,8 @@ void LLFace::renderSelected(LLViewerTexture *imagep, const LLColor4& color)
 
 void renderFace(LLDrawable* drawable, LLFace *face)
 {
+	LL_PROFILE_ZONE_SCOPED
+
     LLVOVolume* vobj = drawable->getVOVolume();
     if (vobj)
     {
@@ -891,6 +900,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
+
 	//get bounding box
 	if (mDrawablep->isState(LLDrawable::REBUILD_VOLUME | LLDrawable::REBUILD_POSITION | LLDrawable::REBUILD_RIGGED))
 	{
@@ -2375,6 +2386,8 @@ F32 LLFace::getTextureVirtualSize()
 
 BOOL LLFace::calcPixelArea(F32& cos_angle_to_view_dir, F32& radius)
 {
+	LL_PROFILE_ZONE_SCOPED
+
 	//VECTORIZE THIS
 	//get area of circle around face
 	LLVector4a center;
@@ -2654,6 +2667,8 @@ const LLMatrix4& LLFace::getRenderMatrix() const
 
 S32 LLFace::renderElements(const U16 *index_array) const
 {
+	LL_PROFILE_ZONE_SCOPED
+
 	S32 ret = 0;
 	
 	if (isState(GLOBAL))
@@ -2673,6 +2688,8 @@ S32 LLFace::renderElements(const U16 *index_array) const
 
 S32 LLFace::renderIndexed()
 {
+	LL_PROFILE_ZONE_SCOPED
+
 	if(mDrawablep == NULL || mDrawPoolp == NULL)
 	{
 		return 0;
@@ -2683,6 +2700,8 @@ S32 LLFace::renderIndexed()
 
 S32 LLFace::renderIndexed(U32 mask)
 {
+	LL_PROFILE_ZONE_SCOPED
+
 	if (mVertexBuffer.isNull())
 	{
 		return 0;
diff --git a/indra/newview/llfeaturemanager.cpp b/indra/newview/llfeaturemanager.cpp
index e6bbe234b3e56f93aca526375adecaa83c3f78d1..98c8531cd624c6959115a34ab504ee0a307675df 100644
--- a/indra/newview/llfeaturemanager.cpp
+++ b/indra/newview/llfeaturemanager.cpp
@@ -670,11 +670,7 @@ void LLFeatureManager::applyBaseMasks()
 	}
 
 	// now all those wacky ones
-	if (!gGLManager.mHasFragmentShader)
-	{
-		maskFeatures("NoPixelShaders");
-	}
-	if (!gGLManager.mHasVertexShader || !mGPUSupported)
+	if (!mGPUSupported)
 	{
 		maskFeatures("NoVertexShaders");
 	}
diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp
index d9edd4dc30b16b6a7f3f03431c70e92c7b267edf..0e54b66ea959bd8bec32b59c3282d374b4c9e9f2 100644
--- a/indra/newview/llfloatermodelpreview.cpp
+++ b/indra/newview/llfloatermodelpreview.cpp
@@ -1357,31 +1357,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;
@@ -1390,68 +1390,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);
 
@@ -1459,38 +1459,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()
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/llglsandbox.cpp b/indra/newview/llglsandbox.cpp
index 698c15bd2d5f64c1703ae60c94608943149bfdb3..0f288e05ca602c066b8109e8df7833c11379556d 100644
--- a/indra/newview/llglsandbox.cpp
+++ b/indra/newview/llglsandbox.cpp
@@ -993,9 +993,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;
 	}
diff --git a/indra/newview/llhudnametag.cpp b/indra/newview/llhudnametag.cpp
index 9d49c30a49c2c2c6911e2b1849c2ad0d2bd4caa6..55a4b5a4572fbaf4286a3228c80dd0abb0e6a80a 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;
 	if (sDisplayText)
 	{
 		LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE);
@@ -731,6 +732,7 @@ void LLHUDNameTag::updateSize()
 
 void LLHUDNameTag::updateAll()
 {
+    LL_PROFILE_ZONE_SCOPED;
 	// 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/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp
index 2c1c1191dadd7c6ff79efa59ac25f718651106c9..a19d6d0b19309128a3c6db173a7a39b4836605e9 100644
--- a/indra/newview/llmeshrepository.cpp
+++ b/indra/newview/llmeshrepository.cpp
@@ -4045,29 +4045,28 @@ 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;
+    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;
 }
 
diff --git a/indra/newview/llmeshrepository.h b/indra/newview/llmeshrepository.h
index 81e49cb1d8d6390e6ff439f96c3431fa72d92172..c0e894fda4d5a0e2a39f22d5a3086b85f4f0c98e 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"
@@ -585,7 +586,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);
@@ -613,7 +614,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;
diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp
index a9e80ab5da107dcd7ea1ae10c3edaf030561c50a..01bddd781d2798cfd6740c925b30ec4bfffadbb0 100644
--- a/indra/newview/llmodelpreview.cpp
+++ b/indra/newview/llmodelpreview.cpp
@@ -591,7 +591,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))
                     {
@@ -3298,7 +3298,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;
@@ -3340,11 +3340,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)
                             {
diff --git a/indra/newview/llnetmap.cpp b/indra/newview/llnetmap.cpp
index 112da556825647b5d5d1ed65cd2119c8f576b1e2..111b45612e6e88d4bf118e7c05b15a58a922a69a 100644
--- a/indra/newview/llnetmap.cpp
+++ b/indra/newview/llnetmap.cpp
@@ -147,6 +147,7 @@ void LLNetMap::setScale( F32 scale )
 
 void LLNetMap::draw()
 {
+    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);
diff --git a/indra/newview/llnotificationofferhandler.cpp b/indra/newview/llnotificationofferhandler.cpp
index a9678b1e93818bc749e4af063adbb5cc230a2b83..d9359d20cfdc381784ade4f2e7b1678e8e15b778 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/llsecapi.cpp b/indra/newview/llsecapi.cpp
index b9259cb18dfd6833854d4edc8545613e8da24622..aba8ca5a4afd17decc44056659467f5012ee47ed 100644
--- a/indra/newview/llsecapi.cpp
+++ b/indra/newview/llsecapi.cpp
@@ -75,6 +75,12 @@ void initializeSecHandler()
 	}
 
 }
+
+void clearSecHandler()
+{
+    gSecAPIHandler = NULL;
+    gHandlerMap.clear();
+}
 // start using a given security api handler.  If the string is empty
 // the default is used
 LLPointer<LLSecAPIHandler> getSecHandler(const std::string& handler_type)
diff --git a/indra/newview/llsecapi.h b/indra/newview/llsecapi.h
index 14059f828a424dea7cbb8569c7d5c316046c63b7..410737b27f70bce88c45304d25a2aed2a8bc72d7 100644
--- a/indra/newview/llsecapi.h
+++ b/indra/newview/llsecapi.h
@@ -452,7 +452,7 @@ class LLSecAPIHandler : public LLThreadSafeRefCount
 	virtual LLPointer<LLCertificate> getCertificate(X509* openssl_cert)=0;
 	
 	// instantiate a chain from an X509_STORE_CTX
-	virtual LLPointer<LLCertificateChain> getCertificateChain(const X509_STORE_CTX* chain)=0;
+	virtual LLPointer<LLCertificateChain> getCertificateChain(X509_STORE_CTX* chain)=0;
 	
 	// instantiate a cert store given it's id.  if a persisted version
 	// exists, it'll be loaded.  If not, one will be created (but not
@@ -533,6 +533,8 @@ class LLSecAPIHandler : public LLThreadSafeRefCount
 };
 
 void initializeSecHandler();
+
+void clearSecHandler();
 				
 // retrieve a security api depending on the api type
 LLPointer<LLSecAPIHandler> getSecHandler(const std::string& handler_type);
diff --git a/indra/newview/llsechandler_basic.cpp b/indra/newview/llsechandler_basic.cpp
index 19db020a31373bb3d9c704c730dda61820f474aa..b4853d270adf42ad4944a05604efed0dd7440c73 100644
--- a/indra/newview/llsechandler_basic.cpp
+++ b/indra/newview/llsechandler_basic.cpp
@@ -95,7 +95,7 @@ LLBasicCertificate::LLBasicCertificate(const std::string& pem_cert,
 LLBasicCertificate::LLBasicCertificate(X509* pCert,
                                        const LLSD* validation_params) 
 {
-	if (!pCert || !pCert->cert_info)
+	if (!pCert)
 	{
 		LLTHROW(LLInvalidCertificate(LLSD::emptyMap()));
 	}	
@@ -355,8 +355,8 @@ LLSD cert_name_from_X509_NAME(X509_NAME* name)
 		char buffer[32];
 		X509_NAME_ENTRY *entry = X509_NAME_get_entry(name, entry_index);
 		
-		std::string name_value = std::string((const char*)M_ASN1_STRING_data(X509_NAME_ENTRY_get_data(entry)), 
-											 M_ASN1_STRING_length(X509_NAME_ENTRY_get_data(entry)));
+		std::string name_value = std::string((const char*)ASN1_STRING_data(X509_NAME_ENTRY_get_data(entry)), 
+											 ASN1_STRING_length(X509_NAME_ENTRY_get_data(entry)));
 
 		ASN1_OBJECT* name_obj = X509_NAME_ENTRY_get_object(entry);		
 		OBJ_obj2txt(buffer, sizeof(buffer), name_obj, 0);
@@ -683,29 +683,29 @@ std::string LLBasicCertificateStore::storeId() const
 // LLBasicCertificateChain
 // This class represents a chain of certs, each cert being signed by the next cert
 // in the chain.  Certs must be properly signed by the parent
-LLBasicCertificateChain::LLBasicCertificateChain(const X509_STORE_CTX* store)
+LLBasicCertificateChain::LLBasicCertificateChain(X509_STORE_CTX* store)
 {
 
 	// we're passed in a context, which contains a cert, and a blob of untrusted
 	// certificates which compose the chain.
-	if((store == NULL) || (store->cert == NULL))
+	if((store == NULL) || X509_STORE_CTX_get0_cert(store) == NULL)
 	{
 		LL_WARNS("SECAPI") << "An invalid store context was passed in when trying to create a certificate chain" << LL_ENDL;
 		return;
 	}
 	// grab the child cert
-	LLPointer<LLCertificate> current = new LLBasicCertificate(store->cert);
+	LLPointer<LLCertificate> current = new LLBasicCertificate(X509_STORE_CTX_get0_cert(store));
 
 	add(current);
-	if(store->untrusted != NULL)
+	if(X509_STORE_CTX_get0_untrusted(store) != NULL)
 	{
 		// if there are other certs in the chain, we build up a vector
 		// of untrusted certs so we can search for the parents of each
 		// consecutive cert.
 		LLBasicCertificateVector untrusted_certs;
-		for(int i = 0; i < sk_X509_num(store->untrusted); i++)
+		for(int i = 0; i < sk_X509_num(X509_STORE_CTX_get0_untrusted(store)); i++)
 		{
-			LLPointer<LLCertificate> cert = new LLBasicCertificate(sk_X509_value(store->untrusted, i));
+			LLPointer<LLCertificate> cert = new LLBasicCertificate(sk_X509_value(X509_STORE_CTX_get0_untrusted(store), i));
 			untrusted_certs.add(cert);
 
 		}		
@@ -1348,9 +1348,10 @@ void LLSecAPIBasicHandler::_readProtectedData()
 		
 
 		// read in the rest of the file.
-		EVP_CIPHER_CTX ctx;
-		EVP_CIPHER_CTX_init(&ctx);
-		EVP_DecryptInit(&ctx, EVP_rc4(), salt, NULL);
+		EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
+        // todo: ctx error handling
+
+		EVP_DecryptInit(ctx, EVP_rc4(), salt, NULL);
 		// allocate memory:
 		std::string decrypted_data;	
 		
@@ -1358,14 +1359,14 @@ void LLSecAPIBasicHandler::_readProtectedData()
 			// read data as a block:
 			protected_data_stream.read((char *)buffer, BUFFER_READ_SIZE);
 			
-			EVP_DecryptUpdate(&ctx, decrypted_buffer, &decrypted_length, 
+			EVP_DecryptUpdate(ctx, decrypted_buffer, &decrypted_length, 
 							  buffer, protected_data_stream.gcount());
 			decrypted_data.append((const char *)decrypted_buffer, protected_data_stream.gcount());
 		}
 		
 		// RC4 is a stream cipher, so we don't bother to EVP_DecryptFinal, as there is
 		// no block padding.
-		EVP_CIPHER_CTX_cleanup(&ctx);
+        EVP_CIPHER_CTX_free(ctx);
 		std::istringstream parse_stream(decrypted_data);
 		if (parser->parse(parse_stream, mProtectedDataMap, 
 						  LLSDSerialize::SIZE_UNLIMITED) == LLSDParser::PARSE_FAILURE)
@@ -1401,12 +1402,14 @@ void LLSecAPIBasicHandler::_writeProtectedData()
 	
 	llofstream protected_data_stream(tmp_filename.c_str(), 
                                      std::ios_base::binary);
+    EVP_CIPHER_CTX *ctx = NULL;
 	try
 	{
 		
-		EVP_CIPHER_CTX ctx;
-		EVP_CIPHER_CTX_init(&ctx);
-		EVP_EncryptInit(&ctx, EVP_rc4(), salt, NULL);
+		ctx = EVP_CIPHER_CTX_new();
+        // todo: ctx error handling
+
+		EVP_EncryptInit(ctx, EVP_rc4(), salt, NULL);
 		unsigned char unique_id[MAC_ADDRESS_BYTES];
         LLMachineID::getUniqueID(unique_id, sizeof(unique_id));
 		LLXORCipher cipher(unique_id, sizeof(unique_id));
@@ -1421,13 +1424,13 @@ void LLSecAPIBasicHandler::_writeProtectedData()
 				break;
 			}
 			int encrypted_length;
-			EVP_EncryptUpdate(&ctx, encrypted_buffer, &encrypted_length, 
+			EVP_EncryptUpdate(ctx, encrypted_buffer, &encrypted_length, 
 						  buffer, formatted_data_istream.gcount());
 			protected_data_stream.write((const char *)encrypted_buffer, encrypted_length);
 		}
 		
 		// no EVP_EncrypteFinal, as this is a stream cipher
-		EVP_CIPHER_CTX_cleanup(&ctx);
+        EVP_CIPHER_CTX_free(ctx);
 
 		protected_data_stream.close();
 	}
@@ -1439,6 +1442,11 @@ void LLSecAPIBasicHandler::_writeProtectedData()
 		// it may be, however.
 		LLFile::remove(tmp_filename);
 
+        if (ctx)
+        {
+            EVP_CIPHER_CTX_free(ctx);
+        }
+
 		// EXP-1825 crash in LLSecAPIBasicHandler::_writeProtectedData()
 		// Decided throwing an exception here was overkill until we figure out why this happens
 		//LLTHROW(LLProtectedDataException("Error writing Protected Data Store"));
@@ -1491,7 +1499,7 @@ LLPointer<LLCertificate> LLSecAPIBasicHandler::getCertificate(X509* openssl_cert
 }
 		
 // instantiate a chain from an X509_STORE_CTX
-LLPointer<LLCertificateChain> LLSecAPIBasicHandler::getCertificateChain(const X509_STORE_CTX* chain)
+LLPointer<LLCertificateChain> LLSecAPIBasicHandler::getCertificateChain(X509_STORE_CTX* chain)
 {
 	LLPointer<LLCertificateChain> result = new LLBasicCertificateChain(chain);
 	return result;
diff --git a/indra/newview/llsechandler_basic.h b/indra/newview/llsechandler_basic.h
index 0bc7f5230f8a69be187ae8b5659efce7eb98209a..82670f9083b518eea23acf4862c628f6e93e6732 100644
--- a/indra/newview/llsechandler_basic.h
+++ b/indra/newview/llsechandler_basic.h
@@ -197,7 +197,7 @@ class LLBasicCertificateChain : virtual public LLBasicCertificateVector, public
 {
 	
 public:
-	LLBasicCertificateChain(const X509_STORE_CTX * store);
+	LLBasicCertificateChain(X509_STORE_CTX * store);
 	
 	virtual ~LLBasicCertificateChain() {}
 	
@@ -241,7 +241,7 @@ class LLSecAPIBasicHandler : public LLSecAPIHandler
 	virtual LLPointer<LLCertificate> getCertificate(X509* openssl_cert);
 	
 	// instantiate a chain from an X509_STORE_CTX
-	virtual LLPointer<LLCertificateChain> getCertificateChain(const X509_STORE_CTX* chain);
+	virtual LLPointer<LLCertificateChain> getCertificateChain(X509_STORE_CTX* chain);
 	
 	// instantiate a cert store given it's id.  if a persisted version
 	// exists, it'll be loaded.  If not, one will be created (but not
diff --git a/indra/newview/llsettingsvo.cpp b/indra/newview/llsettingsvo.cpp
index 1e5b893cbc8e5c218d54284aef9e5dcc7c78b50e..6a88a8ef2c8dcb06a70076a39c68451e3bf61f41 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;
     LLSettingsSky::updateSettings();
     LLVector3 sun_direction  = getSunDirection();
     LLVector3 moon_direction = getMoonDirection();
@@ -665,55 +666,55 @@ void LLSettingsVOSky::updateSettings()
 
 void LLSettingsVOSky::applySpecial(void *ptarget, bool force)
 {
-    LLGLSLShader *shader = (LLGLSLShader *)ptarget;
-
     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 +908,11 @@ LLSD LLSettingsVOWater::convertToLegacy(const LLSettingsWater::ptr_t &pwater)
 //-------------------------------------------------------------------------
 void LLSettingsVOWater::applySpecial(void *ptarget, bool force)
 {
-    LLGLSLShader *shader = (LLGLSLShader *)ptarget;
-
     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 +936,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 +951,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;
     // base class clears dirty flag so as to not trigger recursive update
     LLSettingsBase::updateSettings();
 
diff --git a/indra/newview/llsettingsvo.h b/indra/newview/llsettingsvo.h
index 65136ad2f5ede965f256d945f2a3a66feeff011f..caa3ac18d3855453a2caa9cbc5082173f1d93bdb 100644
--- a/indra/newview/llsettingsvo.h
+++ b/indra/newview/llsettingsvo.h
@@ -102,8 +102,6 @@ class LLSettingsVOSky : public LLSettingsSky
 
     bool isAdvanced() const { return  m_isAdvanced; }
 
-    virtual void updateShader(LLGLSLShader* shader) { applySpecial(shader, true); }
-
 protected:
     LLSettingsVOSky();
 
@@ -136,8 +134,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..dc12de29fb3f1a2862e09e1c7257b122ec6a30ca 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;
+
     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;
         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..253b6b995399ede5c5b3772b47ac26bb384e27fc 100644
--- a/indra/newview/llspatialpartition.cpp
+++ b/indra/newview/llspatialpartition.cpp
@@ -503,7 +503,9 @@ LLSpatialGroup* LLSpatialGroup::getParent()
 	}
 
 BOOL LLSpatialGroup::removeObject(LLDrawable *drawablep, BOOL from_octree)
-	{
+{
+	LL_PROFILE_ZONE_SCOPED
+
 	if(!drawablep)
 	{
 		return FALSE;
@@ -591,6 +593,8 @@ class LLSpatialSetStateDiff : public LLSpatialSetState
 
 void LLSpatialGroup::setState(U32 state, S32 mode) 
 {
+	LL_PROFILE_ZONE_SCOPED
+
 	llassert(state <= LLSpatialGroup::STATE_MASK);
 	
 	if (mode > STATE_MODE_SINGLE)
@@ -638,6 +642,8 @@ class LLSpatialClearStateDiff : public LLSpatialClearState
 
 void LLSpatialGroup::clearState(U32 state, S32 mode)
 {
+	LL_PROFILE_ZONE_SCOPED
+
 	llassert(state <= LLSpatialGroup::STATE_MASK);
 
 	if (mode > STATE_MODE_SINGLE)
@@ -724,6 +730,8 @@ void LLSpatialGroup::updateDistance(LLCamera &camera)
 
 F32 LLSpatialPartition::calcDistance(LLSpatialGroup* group, LLCamera& camera)
 {
+	LL_PROFILE_ZONE_SCOPED
+
 	LLVector4a eye;
 	LLVector4a origin;
 	origin.load3(camera.getOrigin().mV);
@@ -815,6 +823,8 @@ F32 LLSpatialGroup::getUpdateUrgency() const
 
 BOOL LLSpatialGroup::changeLOD()
 {
+	LL_PROFILE_ZONE_SCOPED
+
 	if (hasState(ALPHA_DIRTY | OBJECT_DIRTY))
 	{
 		//a rebuild is going to happen, update distance and LoD
@@ -907,6 +917,8 @@ void LLSpatialGroup::handleDestruction(const TreeNode* node)
 
 void LLSpatialGroup::handleChildAddition(const OctreeNode* parent, OctreeNode* child) 
 {
+	LL_PROFILE_ZONE_SCOPED
+
 	if (child->getListenerCount() == 0)
 	{
 		new LLSpatialGroup(child, getSpatialPartition());
@@ -2700,11 +2712,17 @@ void renderPhysicsShape(LLDrawable* drawable, LLVOVolume* volume)
 			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
 		{
@@ -3222,6 +3240,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);
 					}
 					
diff --git a/indra/newview/llspatialpartition.h b/indra/newview/llspatialpartition.h
index 919f386d29b5095dd3fa1f4a34ffc8301a138e07..6ef82fac9c3078a1d52aeb4a17639ff17764f4f2 100644
--- a/indra/newview/llspatialpartition.h
+++ b/indra/newview/llspatialpartition.h
@@ -41,6 +41,7 @@
 #include "llviewercamera.h"
 #include "llvector4a.h"
 #include <queue>
+#include <unordered_map>
 
 #define SG_STATE_INHERIT_MASK (OCCLUDED)
 #define SG_INITIAL_STATE_MASK (DIRTY | GEOM_DIRTY)
@@ -216,10 +217,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
 	{
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index 124213153414253e0623749b13f5bc8dfc45de10..57c50748043e9ee437347300983a6626064eabdf 100644
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -179,7 +179,6 @@
 #include "pipeline.h"
 #include "llappviewer.h"
 #include "llfasttimerview.h"
-#include "lltelemetry.h"
 #include "llfloatermap.h"
 #include "llweb.h"
 #include "llvoiceclient.h"
@@ -530,8 +529,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");
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/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp
index 9126360eed8d0fb290c0a8cd4d2a09139685b6dc..73a25397fd7e8d412a182e7d5c6b75336e06c5af 100644
--- a/indra/newview/lltexturefetch.cpp
+++ b/indra/newview/lltexturefetch.cpp
@@ -314,6 +314,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)
 			{
@@ -338,6 +339,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)
 			{
@@ -362,6 +364,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)
 			{
@@ -1139,6 +1142,7 @@ void LLTextureFetchWorker::startWork(S32 param)
 // Threads:  Ttf
 bool LLTextureFetchWorker::doWork(S32 param)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	if (gNonInteractive)
 	{
 		return true;
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 a2f35541235ce6c541a4c8354da5013651b2ffbe..1236695e4fc5b7413a8210cea00eef8da47243f5 100644
--- a/indra/newview/llviewerdisplay.cpp
+++ b/indra/newview/llviewerdisplay.cpp
@@ -209,9 +209,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("DS - FPS");
 		F32 fps = gRecentFrameCount / fps_log_freq;
 		LL_INFOS() << llformat("FPS: %.02f", fps) << LL_ENDL;
 		gRecentFrameCount = 0;
@@ -220,6 +222,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("DS - Memory");
 		gMemoryAllocated = U64Bytes(LLMemory::getCurrentRSS());
 		U32Megabytes memory = gMemoryAllocated;
 		LL_INFOS() << "MEMORY: " << memory << LL_ENDL;
@@ -229,6 +232,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("DS - Asset Storage");
         gAssetStorageLogTime.reset();
         gAssetStorage->logAssetStorageInfo();
     }
@@ -632,6 +636,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 	
 	if (!gDisconnected)
 	{
+		LL_PROFILE_ZONE_NAMED("display - 1");
 		LLAppViewer::instance()->pingMainloopTimeout("Display:Update");
 		if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD))
 		{ //don't draw hud objects in this frame
@@ -724,6 +729,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 		LLAppViewer::instance()->pingMainloopTimeout("Display:Swap");
 		
 		{ 
+			LL_PROFILE_ZONE_NAMED("display - 2")
 			if (gResizeScreenTexture)
 			{
 				gResizeScreenTexture = FALSE;
@@ -779,6 +785,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 
 		//if (!for_snapshot)
 		{
+			LL_PROFILE_ZONE_NAMED("display - 3")
 			LLAppViewer::instance()->pingMainloopTimeout("Display:Imagery");
 			gPipeline.generateWaterReflection(*LLViewerCamera::getInstance());
 			gPipeline.generateHighlight(*LLViewerCamera::getInstance());
@@ -827,7 +834,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 				LLImageGL::deleteDeadTextures();
 				stop_glerror();
 			}*/
-			}
+		}
 
 		LLGLState::checkStates();
 		LLGLState::checkClientArrays();
@@ -842,6 +849,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 		//
 		LLAppViewer::instance()->pingMainloopTimeout("Display:StateSort");
 		{
+			LL_PROFILE_ZONE_NAMED("display - 3")
 			LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD;
 			gPipeline.stateSort(*LLViewerCamera::getInstance(), result);
 			stop_glerror();
@@ -950,6 +958,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 		if (!(LLAppViewer::instance()->logoutRequestSent() && LLAppViewer::instance()->hasSavedFinalSnapshot())
 				&& !gRestoreGL)
 		{
+			LL_PROFILE_ZONE_NAMED("display - 4")
 			LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD;
 
 			if (gSavedSettings.getBOOL("RenderDepthPrePass") && LLGLSLShader::sNoFixedFunction)
@@ -1261,7 +1270,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_RECORD_BLOCK_TIME(FTM_RENDER_UI);
 
 	LLGLState::checkStates();
 	
@@ -1276,7 +1285,7 @@ void render_ui(F32 zoom_factor, int subfield)
 	
 	if(LLSceneMonitor::getInstance()->needsUpdate())
 	{
-        LL_RECORD_BLOCK_TIME(FTM_RENDER_UI_SCENE_MON);
+		LL_RECORD_BLOCK_TIME(FTM_RENDER_UI_SCENE_MON);
 		gGL.pushMatrix();
 		gViewerWindow->setup2DRender();
 		LLSceneMonitor::getInstance()->compare();
@@ -1284,55 +1293,64 @@ void render_ui(F32 zoom_factor, int subfield)
 		gGL.popMatrix();
 	}
 
-    // Finalize scene
-    gPipeline.renderFinalize();
+	// Finalize scene
+	gPipeline.renderFinalize();
 
-    LL_RECORD_BLOCK_TIME(FTM_RENDER_HUD);
-    render_hud_elements();
-	render_hud_attachments();
-
-	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_RECORD_BLOCK_TIME(FTM_RENDER_HUD);
+		render_hud_elements();
+		render_hud_attachments();
 
-	{
-		gGL.color4f(1,1,1,1);
-		if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
+		LLGLSDefault gls_default;
+		LLGLSUIDefault gls_ui;
 		{
-			if (!gDisconnected)
+			gPipeline.disableLights();
+		}
+
+		{
+			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_RECORD_BLOCK_TIME(FTM_RENDER_UI_3D);
+					render_ui_3d();
+					LLGLState::checkStates();
+				}
+				else
+				{
+					render_disconnected_background();
+				}
+
+				LL_RECORD_BLOCK_TIME(FTM_RENDER_UI_2D);
+				render_ui_2d();
 				LLGLState::checkStates();
 			}
-			else
+			gGL.flush();
+
 			{
-				render_disconnected_background();
+				LL_RECORD_BLOCK_TIME(FTM_RENDER_UI_DEBUG_TEXT);
+				gViewerWindow->setup2DRender();
+				gViewerWindow->updateDebugText();
+				gViewerWindow->drawDebugText();
 			}
 
-            LL_RECORD_BLOCK_TIME(FTM_RENDER_UI_2D);
-			render_ui_2d();
-			LLGLState::checkStates();
+			LLVertexBuffer::unbind();
 		}
-		gGL.flush();
 
+		if (!gSnapshot)
 		{
-            LL_RECORD_BLOCK_TIME(FTM_RENDER_UI_DEBUG_TEXT);
-			gViewerWindow->setup2DRender();
-			gViewerWindow->updateDebugText();
-			gViewerWindow->drawDebugText();
+			set_current_modelview(saved_view);
+			gGL.popMatrix();
 		}
 
-		LLVertexBuffer::unbind();
-	}
-
-	if (!gSnapshot)
-	{
-		set_current_modelview(saved_view);
-		gGL.popMatrix();
-	}
+	} // Tracy integration
 }
 
 static LLTrace::BlockTimerStatHandle FTM_SWAP("Swap");
diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp
index 517e35d482cdd86f43c4a782bc9d1b2d24a96145..5e99d1320613d71a416e54efc67d67d286347269 100644
--- a/indra/newview/llviewermessage.cpp
+++ b/indra/newview/llviewermessage.cpp
@@ -3982,8 +3982,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);
@@ -4081,11 +4081,6 @@ void process_avatar_animation(LLMessageSystem *mesgsys, void **user_data)
 				gAgent.setFlying(FALSE);
 			}
 
-			if (gNonInteractive && animation_id == ANIM_AGENT_RUN)
-			{
-				LL_INFOS() << "Noninteractive, got run request for self" << LL_ENDL;
-			}
-
 			if (i < num_source_blocks)
 			{
 				mesgsys->getUUIDFast(_PREHASH_AnimationSourceList, _PREHASH_ObjectID, object_id, i);
diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp
index fbd44c198b1af3ee59c39443de873d109a1d5e1a..097b5e364599158605496da390408d749745e425 100644
--- a/indra/newview/llviewerobjectlist.cpp
+++ b/indra/newview/llviewerobjectlist.cpp
@@ -169,6 +169,8 @@ U64 LLViewerObjectList::getIndex(const U32 local_id,
 
 BOOL LLViewerObjectList::removeFromLocalIDTable(const LLViewerObject* objectp)
 {
+	LL_PROFILE_ZONE_SCOPED
+
 	if(objectp && objectp->getRegion())
 	{
 		U32 local_id = objectp->mLocalID;		
@@ -304,6 +306,8 @@ static LLTrace::BlockTimerStatHandle FTM_PROCESS_OBJECTS("Process Objects");
 
 LLViewerObject* LLViewerObjectList::processObjectUpdateFromCache(LLVOCacheEntry* entry, LLViewerRegion* regionp)
 {
+	LL_PROFILE_ZONE_SCOPED
+
 	LLDataPacker *cached_dpp = entry->getDP();
 
 	if (!cached_dpp || gNonInteractive)
@@ -849,6 +853,8 @@ static LLTrace::BlockTimerStatHandle FTM_IDLE_COPY("Idle Copy");
 
 void LLViewerObjectList::update(LLAgent &agent)
 {
+	LL_PROFILE_ZONE_SCOPED
+
 	// Update globals
 	LLViewerObject::setVelocityInterpolate( gSavedSettings.getBOOL("VelocityInterpolate") );
 	LLViewerObject::setPingInterpolate( gSavedSettings.getBOOL("PingInterpolate") );
@@ -1294,6 +1300,8 @@ void LLViewerObjectList::clearDebugText()
 
 void LLViewerObjectList::cleanupReferences(LLViewerObject *objectp)
 {
+	LL_PROFILE_ZONE_SCOPED
+
 	bool new_dead_object = true;
 	if (mDeadObjects.find(objectp->mID) != mDeadObjects.end())
 	{
@@ -1524,6 +1532,8 @@ void LLViewerObjectList::removeFromActiveList(LLViewerObject* objectp)
 
 void LLViewerObjectList::updateActive(LLViewerObject *objectp)
 {
+	LL_PROFILE_ZONE_SCOPED
+
 	if (objectp->isDead())
 	{
 		return; // We don't update dead objects!
@@ -1844,6 +1854,8 @@ void LLViewerObjectList::renderObjectBounds(const LLVector3 &center)
 
 void LLViewerObjectList::generatePickList(LLCamera &camera)
 {
+	LL_PROFILE_ZONE_SCOPED
+
 		LLViewerObject *objectp;
 		S32 i;
 		// Reset all of the GL names to zero.
@@ -2104,6 +2116,8 @@ LLViewerObject *LLViewerObjectList::replaceObject(const LLUUID &id, const LLPCod
 
 S32 LLViewerObjectList::findReferences(LLDrawable *drawablep) const
 {
+	LL_PROFILE_ZONE_SCOPED
+
 	LLViewerObject *objectp;
 	S32 num_refs = 0;
 	
@@ -2167,6 +2181,8 @@ void LLViewerObjectList::orphanize(LLViewerObject *childp, U32 parent_id, U32 ip
 
 void LLViewerObjectList::findOrphans(LLViewerObject* objectp, U32 ip, U32 port)
 {
+	LL_PROFILE_ZONE_SCOPED
+
 	if (objectp->isDead())
 	{
 		LL_WARNS() << "Trying to find orphans for dead obj " << objectp->mID 
diff --git a/indra/newview/llviewerparceloverlay.cpp b/indra/newview/llviewerparceloverlay.cpp
index 7c3dd00e1a1ad88bf5b830461e8b4950f479a8bd..02f7bbeed8e88a6a54c491315d262fb7c401df84 100644
--- a/indra/newview/llviewerparceloverlay.cpp
+++ b/indra/newview/llviewerparceloverlay.cpp
@@ -847,6 +847,7 @@ void LLViewerParcelOverlay::setDirty()
 
 void LLViewerParcelOverlay::updateGL()
 {
+	LL_PROFILE_ZONE_SCOPED
 	updateOverlayTexture();
 }
 
diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp
index be5c22e7c3a65f30155f1ead83bbc36d815065e9..7dcf29eb759a361c5350164c2b8d984f9c8e19c3 100644
--- a/indra/newview/llviewershadermgr.cpp
+++ b/indra/newview/llviewershadermgr.cpp
@@ -384,7 +384,7 @@ void LLViewerShaderMgr::initAttribsAndUniforms(void)
 
 S32 LLViewerShaderMgr::getShaderLevel(S32 type)
 {
-	return LLPipeline::sDisableShaders ? 0 : mShaderLevel[type];
+	return mShaderLevel[type];
 }
 
 //============================================================================
@@ -400,15 +400,6 @@ void LLViewerShaderMgr::setShaders()
         return;
     }
 
-    if (!gGLManager.mHasShaderObjects
-        || !gGLManager.mHasVertexShader
-        || !gGLManager.mHasFragmentShader)
-    {
-        // Viewer will show 'hardware requirements' warning later
-        LL_INFOS("ShaderLoading") << "Shaders not supported" << LL_ENDL;
-        return;
-    }
-
     static LLCachedControl<U32> max_texture_index(gSavedSettings, "RenderMaxTextureIndex", 16);
     LLGLSLShader::sIndexedTextureChannels = llmax(llmin(gGLManager.mNumTextureImageUnits, (S32) max_texture_index), 1);
 
diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp
index ca01bb46aaa3958e6f8a6b36acc0a012020179e7..949e71a4c98a886952607d8e2530be03d8bac4e2 100644
--- a/indra/newview/llviewertexture.cpp
+++ b/indra/newview/llviewertexture.cpp
@@ -184,6 +184,7 @@ void LLViewerTextureManager::findFetchedTextures(const LLUUID& id, std::vector<L
 
 void  LLViewerTextureManager::findTextures(const LLUUID& id, std::vector<LLViewerTexture*> &output)
 {
+    LL_PROFILE_ZONE_SCOPED;
     std::vector<LLViewerFetchedTexture*> fetched_output;
     gTextureList.findTexturesByID(id, fetched_output);
     std::vector<LLViewerFetchedTexture*>::iterator iter = fetched_output.begin();
@@ -208,6 +209,7 @@ void  LLViewerTextureManager::findTextures(const LLUUID& id, std::vector<LLViewe
 
 LLViewerFetchedTexture* LLViewerTextureManager::findFetchedTexture(const LLUUID& id, S32 tex_type)
 {
+    LL_PROFILE_ZONE_SCOPED;
     return gTextureList.findImage(id, (ETexListType)tex_type);
 }
 
@@ -484,6 +486,7 @@ static LLTrace::BlockTimerStatHandle FTM_TEXTURE_MEMORY_CHECK("Memory Check");
 //static 
 bool LLViewerTexture::isMemoryForTextureLow()
 {
+    LL_PROFILE_ZONE_SCOPED;
     // 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.
@@ -500,6 +503,7 @@ bool LLViewerTexture::isMemoryForTextureLow()
 //static
 bool LLViewerTexture::isMemoryForTextureSuficientlyFree()
 {
+    LL_PROFILE_ZONE_SCOPED;
     const S32Megabytes DESIRED_FREE_TEXTURE_MEMORY(50);
     const S32Megabytes DESIRED_FREE_MAIN_MEMORY(200);
 
@@ -513,6 +517,7 @@ bool LLViewerTexture::isMemoryForTextureSuficientlyFree()
 //static
 void LLViewerTexture::getGPUMemoryForTextures(S32Megabytes &gpu, S32Megabytes &physical)
 {
+    LL_PROFILE_ZONE_SCOPED;
     static LLFrameTimer timer;
     static S32Megabytes gpu_res = S32Megabytes(S32_MAX);
     static S32Megabytes physical_res = S32Megabytes(S32_MAX);
@@ -525,27 +530,29 @@ 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];
+        LL_RECORD_BLOCK_TIME(FTM_TEXTURE_MEMORY_CHECK);
 
-        //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);
-    }
+        if (gGLManager.mHasATIMemInfo)
+        {
+            S32 meminfo[4];
+            glGetIntegerv(GL_TEXTURE_FREE_MEMORY_ATI, meminfo);
+            gpu_res = (S32Megabytes)meminfo[0];
 
-    gpu = gpu_res;
-    physical = physical_res;
+            //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;
+    }
 }
 
 static LLTrace::BlockTimerStatHandle FTM_TEXTURE_UPDATE_MEDIA("Media");
@@ -554,6 +561,7 @@ static LLTrace::BlockTimerStatHandle FTM_TEXTURE_UPDATE_TEST("Test");
 //static
 void LLViewerTexture::updateClass(const F32 velocity, const F32 angular_velocity)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	sCurrentTime = gFrameTimeSeconds;
 
 	LLTexturePipelineTester* tester = (LLTexturePipelineTester*)LLMetricPerformanceTesterBasic::getTester(sTesterName);
@@ -703,6 +711,7 @@ void LLViewerTexture::cleanup()
 
 void LLViewerTexture::notifyAboutCreatingTexture()
 {
+    LL_PROFILE_ZONE_SCOPED;
 	for(U32 ch = 0; ch < LLRender::NUM_TEXTURE_CHANNELS; ++ch)
 	{
 		for(U32 f = 0; f < mNumFaces[ch]; f++)
@@ -714,6 +723,7 @@ void LLViewerTexture::notifyAboutCreatingTexture()
 
 void LLViewerTexture::notifyAboutMissingAsset()
 {
+    LL_PROFILE_ZONE_SCOPED;
 	for(U32 ch = 0; ch < LLRender::NUM_TEXTURE_CHANNELS; ++ch)
 	{
 		for(U32 f = 0; f < mNumFaces[ch]; f++)
@@ -726,6 +736,7 @@ void LLViewerTexture::notifyAboutMissingAsset()
 // virtual
 void LLViewerTexture::dump()
 {
+    LL_PROFILE_ZONE_SCOPED;
 	LLGLTexture::dump();
 
 	LL_INFOS() << "LLViewerTexture"
@@ -761,6 +772,7 @@ bool LLViewerTexture::isActiveFetching()
 
 bool LLViewerTexture::bindDebugImage(const S32 stage)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	if (stage < 0) return false;
 
 	bool res = true;
@@ -779,6 +791,7 @@ bool LLViewerTexture::bindDebugImage(const S32 stage)
 
 bool LLViewerTexture::bindDefaultImage(S32 stage) 
 {
+    LL_PROFILE_ZONE_SCOPED;
 	if (stage < 0) return false;
 
 	bool res = true;
@@ -821,6 +834,7 @@ void LLViewerTexture::forceImmediateUpdate()
 
 void LLViewerTexture::addTextureStats(F32 virtual_size, BOOL needs_gltexture) const 
 {
+    LL_PROFILE_ZONE_SCOPED;
 	if(needs_gltexture)
 	{
 		mNeedsGLTexture = TRUE;
@@ -831,14 +845,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()
@@ -863,6 +877,7 @@ void LLViewerTexture::setKnownDrawSize(S32 width, S32 height)
 //virtual
 void LLViewerTexture::addFace(U32 ch, LLFace* facep) 
 {
+    LL_PROFILE_ZONE_SCOPED;
 	llassert(ch < LLRender::NUM_TEXTURE_CHANNELS);
 
 	if(mNumFaces[ch] >= mFaceList[ch].size())
@@ -878,6 +893,7 @@ void LLViewerTexture::addFace(U32 ch, LLFace* facep)
 //virtual
 void LLViewerTexture::removeFace(U32 ch, LLFace* facep) 
 {
+    LL_PROFILE_ZONE_SCOPED;
 	llassert(ch < LLRender::NUM_TEXTURE_CHANNELS);
 
 	if(mNumFaces[ch] > 1)
@@ -918,6 +934,7 @@ S32 LLViewerTexture::getNumFaces(U32 ch) const
 //virtual
 void LLViewerTexture::addVolume(U32 ch, LLVOVolume* volumep)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	if (mNumVolumes[ch] >= mVolumeList[ch].size())
 	{
 		mVolumeList[ch].resize(2 * mNumVolumes[ch] + 1);
@@ -931,6 +948,7 @@ void LLViewerTexture::addVolume(U32 ch, LLVOVolume* volumep)
 //virtual
 void LLViewerTexture::removeVolume(U32 ch, LLVOVolume* volumep)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	if (mNumVolumes[ch] > 1)
 	{
 		S32 index = volumep->getIndexInTex(ch); 
@@ -954,6 +972,7 @@ S32 LLViewerTexture::getNumVolumes(U32 ch) const
 
 void LLViewerTexture::reorganizeFaceList()
 {
+    LL_PROFILE_ZONE_SCOPED;
 	static const F32 MAX_WAIT_TIME = 20.f; // seconds
 	static const U32 MAX_EXTRA_BUFFER_SIZE = 4;
 
@@ -977,6 +996,7 @@ void LLViewerTexture::reorganizeFaceList()
 
 void LLViewerTexture::reorganizeVolumeList()
 {
+    LL_PROFILE_ZONE_SCOPED;
 	static const F32 MAX_WAIT_TIME = 20.f; // seconds
 	static const U32 MAX_EXTRA_BUFFER_SIZE = 4;
 
@@ -1179,6 +1199,7 @@ FTType LLViewerFetchedTexture::getFTType() const
 
 void LLViewerFetchedTexture::cleanup()
 {
+    LL_PROFILE_ZONE_SCOPED;
 	for(callback_list_t::iterator iter = mLoadedCallbackList.begin();
 		iter != mLoadedCallbackList.end(); )
 	{
@@ -1204,6 +1225,7 @@ void LLViewerFetchedTexture::cleanup()
 //access the fast cache
 void LLViewerFetchedTexture::loadFromFastCache()
 {
+    LL_PROFILE_ZONE_SCOPED;
 	if(!mInFastCacheList)
 	{
 		return; //no need to access the fast cache.
@@ -1349,6 +1371,7 @@ void LLViewerFetchedTexture::dump()
 // ONLY called from LLViewerFetchedTextureList
 void LLViewerFetchedTexture::destroyTexture() 
 {
+    LL_PROFILE_ZONE_SCOPED;
 	if(LLImageGL::sGlobalTextureMemory < sMaxDesiredTextureMem * 0.95f)//not ready to release unused memory.
 	{
 		return ;
@@ -1365,6 +1388,7 @@ void LLViewerFetchedTexture::destroyTexture()
 
 void LLViewerFetchedTexture::addToCreateTexture()
 {
+    LL_PROFILE_ZONE_SCOPED;
 	bool force_update = false;
 	if (getComponents() != mRawImage->getComponents())
 	{
@@ -1406,6 +1430,7 @@ void LLViewerFetchedTexture::addToCreateTexture()
 	}
 	else
 	{	
+        LL_PROFILE_ZONE_SCOPED;
 #if 1
 		//
 		//if mRequestedDiscardLevel > mDesiredDiscardLevel, we assume the required image res keep going up,
@@ -1450,99 +1475,100 @@ 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;
+    if (!mNeedsCreateTexture)
+    {
+        destroyRawImage();
+        return FALSE;
+    }
+    mNeedsCreateTexture = FALSE;
 
-	// store original size only for locally-sourced images
-	if (mUrl.compare(0, 7, "file://") == 0)
-	{
-		mOrigWidth = mRawImage->getWidth();
-		mOrigHeight = mRawImage->getHeight();
+    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())
     {
@@ -1564,19 +1590,79 @@ 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;
+    }
 
-	return res;
+    notifyAboutCreatingTexture();
+
+    setActive();
+
+    if (!needsToSaveRawImage())
+    {
+        mNeedsAux = FALSE;
+        destroyRawImage();
+    }
+
+    mNeedsCreateTexture = FALSE;
+}
+
+void LLViewerFetchedTexture::scheduleCreateTexture()
+{
+    ref();
+    mNeedsCreateTexture = TRUE;
+    if (preCreateTexture())
+    {
+        mNeedsCreateTexture = TRUE;
+#if LL_WINDOWS //flip to 0 to revert to single-threaded OpenGL texture uploads
+        if (!LLImageGLThread::sInstance->post([this]()
+            {
+                //actually create the texture on a background thread
+                createTexture();
+                {
+                    LL_PROFILE_ZONE_NAMED("iglt - sync");
+                    if (gGLManager.mHasSync)
+                    {
+                        auto sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
+                        glClientWaitSync(sync, 0, 0);
+                        glDeleteSync(sync);
+                    }
+                    else
+                    {
+                        glFinish();
+                    }
+                }
+                LLImageGLThread::sInstance->postCallback([this]()
+                    {
+                        //finalize on main thread
+                        postCreateTexture();
+                        unref();
+                    });
+            }))
+#endif
+        {
+            gTextureList.mCreateTextureList.insert(this);
+            unref();
+        }
+    }
 }
 
 // Call with 0,0 to turn this feature off.
@@ -1868,6 +1954,7 @@ void LLViewerFetchedTexture::setAdditionalDecodePriority(F32 priority)
 
 void LLViewerFetchedTexture::updateVirtualSize() 
 {	
+    LL_PROFILE_ZONE_SCOPED;
 	if(!mMaxVirtualSizeResetCounter)
 	{
 		addTextureStats(0.f, FALSE);//reset
@@ -1959,6 +2046,7 @@ bool LLViewerFetchedTexture::isActiveFetching()
 
 bool LLViewerFetchedTexture::updateFetch()
 {
+    LL_PROFILE_ZONE_SCOPED;
 	static LLCachedControl<bool> textures_decode_disabled(gSavedSettings,"TextureDecodeDisabled", false);
 	static LLCachedControl<F32>  sCameraMotionThreshold(gSavedSettings,"TextureCameraMotionThreshold", 0.2);
 	static LLCachedControl<S32>  sCameraMotionBoost(gSavedSettings,"TextureCameraMotionBoost", 3);
@@ -2061,7 +2149,7 @@ bool LLViewerFetchedTexture::updateFetch()
 				}
 				else
 				{
-					mIsRawImageValid = TRUE;			
+					mIsRawImageValid = TRUE;
 					addToCreateTexture();
 				}
 
@@ -2889,6 +2977,7 @@ void LLViewerFetchedTexture::destroyRawImage()
 //virtual
 void LLViewerFetchedTexture::switchToCachedImage()
 {
+    LL_PROFILE_ZONE_SCOPED;
 	if(mCachedRawImage.notNull())
 	{
 		mRawImage = mCachedRawImage;
@@ -2900,12 +2989,12 @@ void LLViewerFetchedTexture::switchToCachedImage()
 			mComponents = mRawImage->getComponents();
 			mGLTexturep->setComponents(mComponents);
 			gTextureList.dirtyImage(this);
-		}			
+		}
 
 		mIsRawImageValid = TRUE;
 		mRawDiscardLevel = mCachedRawDiscardLevel;
-		gTextureList.mCreateTextureList.insert(this);
-		mNeedsCreateTexture = TRUE;		
+
+        scheduleCreateTexture();
 	}
 }
 
@@ -3179,6 +3268,7 @@ bool LLViewerLODTexture::isUpdateFrozen()
 //virtual
 void LLViewerLODTexture::processTextureStats()
 {
+    LL_PROFILE_ZONE_SCOPED;
 	updateVirtualSize();
 	
 	static LLCachedControl<bool> textures_fullres(gSavedSettings,"TextureLoadFullRes", false);
diff --git a/indra/newview/llviewertexture.h b/indra/newview/llviewertexture.h
index 69568cc8255cadf45d160a1298b00eefc126ca03..a5a1fb2c16cb8abd81d29f09094dd9dce24ba993 100644
--- a/indra/newview/llviewertexture.h
+++ b/indra/newview/llviewertexture.h
@@ -321,9 +321,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() ;
diff --git a/indra/newview/llviewertexturelist.cpp b/indra/newview/llviewertexturelist.cpp
index 561319ca5d2b4eb61e555f3b4e9bbbc4271d7c17..db740b69e9edaf1e13aff846f0806550f2928309 100644
--- a/indra/newview/llviewertexturelist.cpp
+++ b/indra/newview/llviewertexturelist.cpp
@@ -114,6 +114,7 @@ void LLViewerTextureList::init()
 
 void LLViewerTextureList::doPreloadImages()
 {
+    LL_PROFILE_ZONE_SCOPED;
 	LL_DEBUGS("ViewerImages") << "Preloading images..." << LL_ENDL;
 	
 	llassert_always(mInitialized) ;
@@ -205,6 +206,7 @@ static std::string get_texture_list_name()
 
 void LLViewerTextureList::doPrefetchImages()
 {
+    LL_PROFILE_ZONE_SCOPED;
 	if (LLAppViewer::instance()->getPurgeCache())
 	{
 		// cache was purged, no point
@@ -258,6 +260,7 @@ LLViewerTextureList::~LLViewerTextureList()
 
 void LLViewerTextureList::shutdown()
 {
+    LL_PROFILE_ZONE_SCOPED;
 	// clear out preloads
 	mImagePreloads.clear();
 
@@ -333,6 +336,7 @@ void LLViewerTextureList::shutdown()
 
 void LLViewerTextureList::dump()
 {
+    LL_PROFILE_ZONE_SCOPED;
 	LL_INFOS() << "LLViewerTextureList::dump()" << LL_ENDL;
 	for (image_priority_list_t::iterator it = mImageList.begin(); it != mImageList.end(); ++it)
 	{
@@ -377,6 +381,7 @@ LLViewerFetchedTexture* LLViewerTextureList::getImageFromFile(const std::string&
 												   LLGLenum primary_format, 
 												   const LLUUID& force_id)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	if(!mInitialized)
 	{
 		return NULL ;
@@ -404,6 +409,7 @@ LLViewerFetchedTexture* LLViewerTextureList::getImageFromUrl(const std::string&
 												   LLGLenum primary_format, 
 												   const LLUUID& force_id)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	if(!mInitialized)
 	{
 		return NULL ;
@@ -492,6 +498,7 @@ LLViewerFetchedTexture* LLViewerTextureList::getImage(const LLUUID &image_id,
 												   LLGLenum primary_format,
 												   LLHost request_from_host)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	if(!mInitialized)
 	{
 		return NULL ;
@@ -554,6 +561,7 @@ LLViewerFetchedTexture* LLViewerTextureList::createImage(const LLUUID &image_id,
 												   LLGLenum primary_format,
 												   LLHost request_from_host)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	static LLCachedControl<bool> fast_cache_fetching_enabled(gSavedSettings, "FastCacheFetchEnabled", true);
 
 	LLPointer<LLViewerFetchedTexture> imagep ;
@@ -609,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;
     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)
@@ -620,6 +629,7 @@ void LLViewerTextureList::findTexturesByID(const LLUUID &image_id, std::vector<L
 
 LLViewerFetchedTexture *LLViewerTextureList::findImage(const LLTextureKey &search_key)
 {
+    LL_PROFILE_ZONE_SCOPED;
     uuid_map_t::iterator iter = mUUIDMap.find(search_key);
     if (iter == mUUIDMap.end())
         return NULL;
@@ -633,6 +643,7 @@ LLViewerFetchedTexture *LLViewerTextureList::findImage(const LLUUID &image_id, E
 
 void LLViewerTextureList::addImageToList(LLViewerFetchedTexture *image)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	assert_main_thread();
 	llassert_always(mInitialized) ;
 	llassert(image);
@@ -652,6 +663,7 @@ void LLViewerTextureList::addImageToList(LLViewerFetchedTexture *image)
 
 void LLViewerTextureList::removeImageFromList(LLViewerFetchedTexture *image)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	assert_main_thread();
 	llassert_always(mInitialized) ;
 	llassert(image);
@@ -700,6 +712,7 @@ void LLViewerTextureList::removeImageFromList(LLViewerFetchedTexture *image)
 
 void LLViewerTextureList::addImage(LLViewerFetchedTexture *new_image, ETexListType tex_type)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	if (!new_image)
 	{
 		return;
@@ -723,6 +736,7 @@ void LLViewerTextureList::addImage(LLViewerFetchedTexture *new_image, ETexListTy
 
 void LLViewerTextureList::deleteImage(LLViewerFetchedTexture *image)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	if( image)
 	{
 		if (image->hasCallbacks())
@@ -844,6 +858,7 @@ void LLViewerTextureList::updateImages(F32 max_time)
 
 void LLViewerTextureList::clearFetchingRequests()
 {
+    LL_PROFILE_ZONE_SCOPED;
 	if (LLAppViewer::getTextureFetch()->getNumRequests() == 0)
 	{
 		return;
@@ -861,6 +876,7 @@ void LLViewerTextureList::clearFetchingRequests()
 
 void LLViewerTextureList::updateImagesDecodePriorities()
 {
+    LL_PROFILE_ZONE_SCOPED;
 	// Update the decode priority for N images each frame
 	{
 		F32 lazy_flush_timeout = 30.f; // stop decoding
@@ -976,6 +992,7 @@ void LLViewerTextureList::updateImagesDecodePriorities()
 
 void LLViewerTextureList::setDebugFetching(LLViewerFetchedTexture* tex, S32 debug_level)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	if(!tex->setDebugFetching(debug_level))
 	{
 		return;
@@ -1024,6 +1041,7 @@ void LLViewerTextureList::setDebugFetching(LLViewerFetchedTexture* tex, S32 debu
 
 F32 LLViewerTextureList::updateImagesCreateTextures(F32 max_time)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	if (gGLManager.mIsDisabled) return 0.0f;
 	
 	//
@@ -1040,6 +1058,7 @@ F32 LLViewerTextureList::updateImagesCreateTextures(F32 max_time)
 		enditer = iter;
 		LLViewerFetchedTexture *imagep = *curiter;
 		imagep->createTexture();
+        imagep->postCreateTexture();
 		if (create_timer.getElapsedTimeF32() > max_time)
 		{
 			break;
@@ -1051,6 +1070,7 @@ F32 LLViewerTextureList::updateImagesCreateTextures(F32 max_time)
 
 F32 LLViewerTextureList::updateImagesLoadingFastCache(F32 max_time)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	if (gGLManager.mIsDisabled) return 0.0f;
 	if(mFastCacheList.empty())
 	{
@@ -1081,6 +1101,7 @@ F32 LLViewerTextureList::updateImagesLoadingFastCache(F32 max_time)
 
 void LLViewerTextureList::forceImmediateUpdate(LLViewerFetchedTexture* imagep)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	if(!imagep)
 	{
 		return ;
@@ -1100,6 +1121,7 @@ void LLViewerTextureList::forceImmediateUpdate(LLViewerFetchedTexture* imagep)
 
 F32 LLViewerTextureList::updateImagesFetchTextures(F32 max_time)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	LLTimer image_op_timer;
 	
 	// Update fetch for N images each frame
@@ -1175,6 +1197,7 @@ F32 LLViewerTextureList::updateImagesFetchTextures(F32 max_time)
 
 void LLViewerTextureList::updateImagesUpdateStats()
 {
+    LL_PROFILE_ZONE_SCOPED;
 	if (mForceResetTextureStats)
 	{
 		for (image_priority_list_t::iterator iter = mImageList.begin();
@@ -1189,6 +1212,7 @@ void LLViewerTextureList::updateImagesUpdateStats()
 
 void LLViewerTextureList::decodeAllImages(F32 max_time)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	LLTimer timer;
 
 	//loading from fast cache 
@@ -1258,6 +1282,7 @@ BOOL LLViewerTextureList::createUploadFile(const std::string& filename,
 										 const std::string& out_filename,
 										 const U8 codec)
 {	
+    LL_PROFILE_ZONE_SCOPED;
 	// Load the image
 	LLPointer<LLImageFormatted> image = LLImageFormatted::createFromType(codec);
 	if (image.isNull())
@@ -1311,6 +1336,7 @@ BOOL LLViewerTextureList::createUploadFile(const std::string& filename,
 // note: modifies the argument raw_image!!!!
 LLPointer<LLImageJ2C> LLViewerTextureList::convertToUploadFile(LLPointer<LLImageRaw> raw_image)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	raw_image->biasedScaleToPowerOfTwo(LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT);
 	LLPointer<LLImageJ2C> compressedImage = new LLImageJ2C();
 	
@@ -1344,6 +1370,7 @@ LLPointer<LLImageJ2C> LLViewerTextureList::convertToUploadFile(LLPointer<LLImage
 // Returns min setting for TextureMemory (in MB)
 S32Megabytes LLViewerTextureList::getMinVideoRamSetting()
 {
+    LL_PROFILE_ZONE_SCOPED;
 	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 ;
@@ -1353,6 +1380,7 @@ S32Megabytes LLViewerTextureList::getMinVideoRamSetting()
 // Returns max setting for TextureMemory (in MB)
 S32Megabytes LLViewerTextureList::getMaxVideoRamSetting(bool get_recommended, float mem_multiplier)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	S32Megabytes max_texmem;
 	if (gGLManager.mVRAM != 0)
 	{
@@ -1406,6 +1434,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;
 	// Initialize the image pipeline VRAM settings
 	S32Megabytes cur_mem(gSavedSettings.getS32("TextureMemory"));
 	F32 mem_multiplier = gSavedSettings.getF32("RenderTextureMemoryMultiple");
@@ -1646,6 +1675,7 @@ void LLUIImageList::cleanUp()
 
 LLUIImagePtr LLUIImageList::getUIImageByID(const LLUUID& image_id, S32 priority)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	// use id as image name
 	std::string image_name = image_id.asString();
 
@@ -1664,6 +1694,7 @@ LLUIImagePtr LLUIImageList::getUIImageByID(const LLUUID& image_id, S32 priority)
 
 LLUIImagePtr LLUIImageList::getUIImage(const std::string& image_name, S32 priority)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	// look for existing image
 	uuid_ui_image_map_t::iterator found_it = mUIImages.find(image_name);
 	if (found_it != mUIImages.end())
@@ -1681,6 +1712,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;
 	if (boost_priority == LLGLTexture::BOOST_NONE)
 	{
 		boost_priority = LLGLTexture::BOOST_UI;
@@ -1693,6 +1725,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;
 	if (boost_priority == LLGLTexture::BOOST_NONE)
 	{
 		boost_priority = LLGLTexture::BOOST_UI;
@@ -1704,6 +1737,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;
 	if (!imagep) return NULL;
 
 	imagep->setAddressMode(LLTexUnit::TAM_CLAMP);
@@ -1741,6 +1775,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;
 	// look for existing image
 	uuid_ui_image_map_t::iterator found_it = mUIImages.find(name);
 	if (found_it != mUIImages.end())
@@ -1755,6 +1790,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;
 	if(!success || !user_data) 
 	{
 		return;
@@ -1856,6 +1892,7 @@ struct UIImageDeclarations : public LLInitParam::Block<UIImageDeclarations>
 
 bool LLUIImageList::initFromFile()
 {
+    LL_PROFILE_ZONE_SCOPED;
 	// 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.
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index 24cb138401fcf5d2ae652b6a0f4b285fe8f1b165..2342b6219cdc4fbfaa42c37ad20ab280b2e52810 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -1970,6 +1970,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
@@ -2011,19 +2018,11 @@ 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) ;
 	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
 	LLView::Params rvp;
 	rvp.name("root");
@@ -2109,6 +2108,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.)
@@ -5301,6 +5302,7 @@ void LLViewerWindow::setup3DRender()
 
 void LLViewerWindow::setup3DViewport(S32 x_offset, S32 y_offset)
 {
+	LL_PROFILE_ZONE_SCOPED
 	gGLViewport[0] = mWorldViewRectRaw.mLeft + x_offset;
 	gGLViewport[1] = mWorldViewRectRaw.mBottom + y_offset;
 	gGLViewport[2] = mWorldViewRectRaw.getWidth();
@@ -5519,8 +5521,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()
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 dad580de703d41a359713ef4e4482fca31b80d1e..a588d05ff726057b4e4cb2a38490e0823fbb8ad3 100644
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -3136,6 +3136,8 @@ void LLVOAvatar::idleUpdateWindEffect()
 
 void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last)
 {
+    LL_PROFILE_ZONE_SCOPED;
+
 	// update chat bubble
 	//--------------------------------------------------------------------
 	// draw text label over character's head
@@ -3807,11 +3809,6 @@ LLViewerInventoryItem* recursiveGetObjectInventoryItem(LLViewerObject *vobj, LLU
 
 void LLVOAvatar::updateAnimationDebugText()
 {
-	if (isSelf() && gNonInteractive)
-	{
-		LLVector3 vel = getVelocity();
-		addDebugText(llformat("vel %f %f %f\n",vel[0],vel[1],vel[2]));
-	}
 	for (LLMotionController::motion_list_t::iterator iter = mMotionController.getActiveMotions().begin();
 		 iter != mMotionController.getActiveMotions().end(); ++iter)
 	{
@@ -4889,6 +4886,8 @@ bool LLVOAvatar::shouldAlphaMask()
 //-----------------------------------------------------------------------------
 U32 LLVOAvatar::renderSkinned()
 {
+    LL_PROFILE_ZONE_SCOPED;
+
 	U32 num_indices = 0;
 
 	if (!mIsBuilt)
@@ -6163,27 +6162,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;
 }
@@ -6518,7 +6519,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;
@@ -7122,6 +7123,7 @@ void LLVOAvatar::updateGL()
 {
 	if (mMeshTexturesDirty)
 	{
+		LL_PROFILE_ZONE_SCOPED
 		updateMeshTextures();
 		mMeshTexturesDirty = FALSE;
 	}
@@ -7867,6 +7869,8 @@ void LLVOAvatar::onGlobalColorChanged(const LLTexGlobalColor* global_color)
 // Do rigged mesh attachments display with this av?
 bool LLVOAvatar::shouldRenderRigged() const
 {
+    LL_PROFILE_ZONE_SCOPED;
+
 	if (getOverallAppearance() == AOA_NORMAL)
 	{
 		return true;
@@ -8358,6 +8362,7 @@ void LLVOAvatar::updateMeshVisibility()
 // virtual
 void LLVOAvatar::updateMeshTextures()
 {
+	LL_PROFILE_ZONE_SCOPED
 	static S32 update_counter = 0;
 	mBakedTextureDebugText.clear();
 	
@@ -10954,6 +10959,7 @@ void LLVOAvatar::updateOverallAppearanceAnimations()
 // Based on isVisuallyMuted(), but has 3 possible results.
 LLVOAvatar::AvatarOverallAppearance LLVOAvatar::getOverallAppearance() const
 {
+    LL_PROFILE_ZONE_SCOPED;
 	AvatarOverallAppearance result = AOA_NORMAL;
 
 	// Priority order (highest priority first)
diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h
index 74ef589ca47a9532e7fc242c9d9e67fbf2acdf36..39adaab8cac366471dd5156b89cd4010e139081b 100644
--- a/indra/newview/llvoavatar.h
+++ b/indra/newview/llvoavatar.h
@@ -209,6 +209,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 					addAttachmentOverridesForObject(LLViewerObject *vo, std::set<LLUUID>* meshes_seen = NULL, bool recursive = true);
 	void					removeAttachmentOverridesForObject(const LLUUID& mesh_id);
 	void					removeAttachmentOverridesForObject(LLViewerObject *vo);
diff --git a/indra/newview/llvosurfacepatch.cpp b/indra/newview/llvosurfacepatch.cpp
index 897bace4e1ca9b0b3cc6aa8d52e9fd0f3d26f4c1..b5560d3d79080ba9b49ec1683a001e2a7a4da4df 100644
--- a/indra/newview/llvosurfacepatch.cpp
+++ b/indra/newview/llvosurfacepatch.cpp
@@ -218,6 +218,7 @@ void LLVOSurfacePatch::updateGL()
 {
 	if (mPatchp)
 	{
+		LL_PROFILE_ZONE_SCOPED
 		mPatchp->updateGL();
 	}
 }
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index f0638005870b0f16bf0e239484acccf8a91c970c..b86935b0816ccdc6d34cafb4753e11a77fbbbefb 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -3555,7 +3555,7 @@ const LLMeshSkinInfo* LLVOVolume::getSkinInfo() const
 {
     if (getVolume())
     {
-        return gMeshRepo.getSkinInfo(getVolume()->getParams().getSculptID(), this);
+        return gMeshRepo.getSkinInfo(getMeshID(), this);
     }
     else
     {
@@ -4807,7 +4807,7 @@ 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);
 
     S32 rigged_vert_count = 0;
     S32 rigged_face_count = 0;
@@ -4823,8 +4823,7 @@ 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);
+			const LLMatrix4a& bind_shape_matrix = skin->mBindShapeMatrix;
 
 			LLVector4a* pos = dst_face.mPositions;
 
@@ -6045,123 +6044,130 @@ void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* 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
+		{
+			// 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_RECORD_BLOCK_TIME(FTM_REBUILD_VOLUME_GEN_DRAW_INFO); //make sure getgeometryvolume shows up in the right place in timers
 
-		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->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->isNoLOD()) continue;
-
-				vobj->preRebuild();
-
-				if (drawablep->isState(LLDrawable::ANIMATED_CHILD))
-				{
-					vobj->updateRelativeXform(true);
-				}
+				LLDrawable* drawablep = (LLDrawable*)(*drawable_iter)->getDrawable();
 
-				LLVolume* volume = vobj->getVolume();
-				for (S32 i = 0; i < drawablep->getNumFaces(); ++i)
+				if (drawablep && !drawablep->isDead() && drawablep->isState(LLDrawable::REBUILD_ALL) && !drawablep->isState(LLDrawable::RIGGED) )
 				{
-					LLFace* face = drawablep->getFace(i);
-					if (face)
+					LLVOVolume* vobj = drawablep->getVOVolume();
+					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();
+					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;
+								llassert(!face->isState(LLFace::RIGGED));
+
+								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_RECORD_BLOCK_TIME(FTM_REBUILD_MESH_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)
-				{
-					continue;
-				}
-				for (S32 i = 0; i < drawablep->getNumFaces(); ++i)
+				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)
 				{
-					LLFace* face = drawablep->getFace(i);
-					if (face)
+					LLDrawable* drawablep = (LLDrawable*)(*drawable_iter)->getDrawable();
+					if(!drawablep)
+					{
+						continue;
+					}
+					for (S32 i = 0; i < drawablep->getNumFaces(); ++i)
 					{
-						LLVertexBuffer* buff = face->getVertexBuffer();
-						if (buff && buff->isLocked())
+						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);
 		}
 
-		group->clearState(LLSpatialGroup::MESH_DIRTY | LLSpatialGroup::NEW_DRAWINFO);
-	}
+	} // Tracy integration
 
 //	llassert(!group || !group->isState(LLSpatialGroup::NEW_DRAWINFO));
 }
diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h
index ce400a34986b8c2e56e32def745e354cfefb1a9c..b8c6f47bbdd12a0e738b431c3671d14fc1a6a093 100644
--- a/indra/newview/llvovolume.h
+++ b/indra/newview/llvovolume.h
@@ -296,6 +296,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;
diff --git a/indra/newview/llworld.cpp b/indra/newview/llworld.cpp
index a1a1db35d64f600ff2fdc1594323dd3f5b6569ca..c7b0a2bfb464e4f541bd6fc356f7b73063ff06c0 100644
--- a/indra/newview/llworld.cpp
+++ b/indra/newview/llworld.cpp
@@ -1284,6 +1284,7 @@ void send_agent_pause()
 
 void send_agent_resume()
 {
+	LL_PROFILE_ZONE_SCOPED
 	// 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/pipeline.cpp b/indra/newview/pipeline.cpp
index ad401b6db41e1047873db00acb28af0bde9ae373..7aa05fb22fa5fe3fb1adc3964a2c6b631c6926b9 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -338,7 +338,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 +358,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;
 
@@ -1403,10 +1401,7 @@ void LLPipeline::restoreGL()
 
 bool LLPipeline::canUseVertexShaders()
 {
-	if (sDisableShaders ||
-		!gGLManager.mHasVertexShader ||
-		!gGLManager.mHasFragmentShader ||
-		(assertInitialized() && mVertexShadersLoaded != 1) )
+	if ((assertInitialized() && mVertexShadersLoaded != 1) )
 	{
 		return false;
 	}
@@ -1418,8 +1413,7 @@ bool LLPipeline::canUseVertexShaders()
 
 bool LLPipeline::canUseWindLightShaders() const
 {
-	return (!LLPipeline::sDisableShaders &&
-			gWLSkyProgram.mProgramObject != 0 &&
+	return (gWLSkyProgram.mProgramObject != 0 &&
 			LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_WINDLIGHT) > 1);
 }
 
@@ -1907,6 +1901,7 @@ void LLPipeline::createObject(LLViewerObject* vobj)
 
 void LLPipeline::resetFrameStats()
 {
+	LL_PROFILE_ZONE_SCOPED
 	assertInitialized();
 
 	sCompiles        = 0;
@@ -2135,6 +2130,7 @@ void LLPipeline::grabReferences(LLCullResult& result)
 
 void LLPipeline::clearReferences()
 {
+	LL_PROFILE_ZONE_SCOPED
 	sCull = NULL;
 	mGroupSaveQ1.clear();
 }
@@ -2563,13 +2559,6 @@ void LLPipeline::markNotCulled(LLSpatialGroup* group, LLCamera& camera)
 		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)
@@ -3493,7 +3482,6 @@ void LLPipeline::stateSort(LLSpatialGroup* group, LLCamera& camera)
 			group->mLastUpdateDistance = group->mDistance;
 		}
 	}
-
 }
 
 void LLPipeline::stateSort(LLSpatialBridge* bridge, LLCamera& camera, BOOL fov_changed)
@@ -3800,6 +3788,27 @@ void renderSoundHighlights(LLDrawable* drawablep)
 }
 }
 
+void LLPipeline::touchTextures(LLDrawInfo* info)
+{
+    LL_PROFILE_ZONE_SCOPED;
+    for (auto& tex : info->mTextureList)
+    {
+        if (tex.notNull())
+        {
+            LLImageGL* gl_tex = tex->getGLTexture();
+            if (gl_tex && gl_tex->updateBindStats(gl_tex->mTextureMemory))
+            {
+                tex->setActive();
+            }
+        }
+    }
+
+    if (info->mTexture.notNull())
+    {
+        info->mTexture->addTextureStats(info->mVSize);
+    }
+}
+
 void LLPipeline::postSort(LLCamera& camera)
 {
 	LL_RECORD_BLOCK_TIME(FTM_STATESORT_POSTSORT);
@@ -3852,20 +3861,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);
+                }
 			}
 		}
 
@@ -4577,92 +4580,99 @@ void LLPipeline::renderGeomDeferred(LLCamera& camera)
 	LLAppViewer::instance()->pingMainloopTimeout("Pipeline:RenderGeomDeferred");
 
 	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_RECORD_BLOCK_TIME(FTM_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();
+		LLGLState::checkClientArrays();
 
-	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_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)
@@ -8430,8 +8440,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)
@@ -11152,6 +11160,7 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar)
 		if (LLPipeline::sRenderDeferred)
 		{
 			GLuint buff = GL_COLOR_ATTACHMENT0;
+			LL_PROFILER_GPU_ZONEC( "gl.DrawBuffersARB", 0x8000FF );
 			glDrawBuffersARB(1, &buff);
 		}
 
diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h
index 0eaa6b141d8b51d3fe68123ad6362776133c8757..8ffbddca210883f7d6891c41cdee5294f216bb56 100644
--- a/indra/newview/pipeline.h
+++ b/indra/newview/pipeline.h
@@ -265,6 +265,8 @@ 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 forAllVisibleDrawables(void (*func)(LLDrawable*));
 
 	void renderObjects(U32 type, U32 mask, bool texture = true, bool batch_texture = false);
@@ -574,7 +576,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 +598,6 @@ class LLPipeline
 	static bool				sRenderAttachedParticles;
 	static bool				sRenderDeferred;
 	static S32				sVisibleLightCount;
-	static F32				sMinRenderSize;
 	static bool				sRenderingHUDs;
     static F32              sDistortionWaterClipPlaneMargin;
 
diff --git a/indra/newview/slplugin.entitlements b/indra/newview/slplugin.entitlements
new file mode 100644
index 0000000000000000000000000000000000000000..a1c430a57ab6b81d2eee387c16fe4e9f83a3835d
--- /dev/null
+++ b/indra/newview/slplugin.entitlements
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
+	<true/>
+</dict>
+</plist>
diff --git a/indra/newview/tests/llsecapi_test.cpp b/indra/newview/tests/llsecapi_test.cpp
index caa3016d2e9e92f0eb061ea2b89c8c0761dff90c..37fbbb449be47c8101593331412b1a527256fe20 100644
--- a/indra/newview/tests/llsecapi_test.cpp
+++ b/indra/newview/tests/llsecapi_test.cpp
@@ -57,7 +57,7 @@ void LLSecAPIBasicHandler::init() {}
 LLSecAPIBasicHandler::~LLSecAPIBasicHandler() {}
 LLPointer<LLCertificate> LLSecAPIBasicHandler::getCertificate(const std::string& pem_cert) { return NULL; }
 LLPointer<LLCertificate> LLSecAPIBasicHandler::getCertificate(X509* openssl_cert) { return NULL; }
-LLPointer<LLCertificateChain> LLSecAPIBasicHandler::getCertificateChain(const X509_STORE_CTX* chain) { return NULL; }
+LLPointer<LLCertificateChain> LLSecAPIBasicHandler::getCertificateChain(X509_STORE_CTX* chain) { return NULL; }
 LLPointer<LLCertificateStore> LLSecAPIBasicHandler::getCertificateStore(const std::string& store_id) { return NULL; }
 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) {}
diff --git a/indra/newview/tests/llsechandler_basic_test.cpp b/indra/newview/tests/llsechandler_basic_test.cpp
index e5d226a2a4966cea58d25fca2939073d71e424f6..4c8d6c51b09e55c51376c0e910ff9fea724447f6 100644
--- a/indra/newview/tests/llsechandler_basic_test.cpp
+++ b/indra/newview/tests/llsechandler_basic_test.cpp
@@ -1217,8 +1217,8 @@ namespace tut
 
 		// Single cert in the chain.
 		X509_STORE_CTX *test_store = X509_STORE_CTX_new();
-		test_store->cert = mX509ChildCert;		
-		test_store->untrusted = NULL;
+        X509_STORE_CTX_set_cert(test_store, mX509ChildCert);
+        X509_STORE_CTX_set0_untrusted(test_store, NULL);
 		test_chain = new LLBasicCertificateChain(test_store);
 		X509_STORE_CTX_free(test_store);
 		ensure_equals("two elements in store", test_chain->size(), 1);		
@@ -1229,9 +1229,9 @@ namespace tut
 		// cert + CA
 		
 		test_store = X509_STORE_CTX_new();
-		test_store->cert = mX509ChildCert;
-		test_store->untrusted = sk_X509_new_null();
-		sk_X509_push(test_store->untrusted, mX509IntermediateCert);
+        X509_STORE_CTX_set_cert(test_store, mX509ChildCert);
+        X509_STORE_CTX_set0_untrusted(test_store, sk_X509_new_null());
+		sk_X509_push(X509_STORE_CTX_get0_untrusted(test_store), mX509IntermediateCert);
 		test_chain = new LLBasicCertificateChain(test_store);
 		X509_STORE_CTX_free(test_store);
 		ensure_equals("two elements in store", test_chain->size(), 2);	
@@ -1245,9 +1245,9 @@ namespace tut
 		// cert + nonrelated
 		
 		test_store = X509_STORE_CTX_new();
-		test_store->cert = mX509ChildCert;
-		test_store->untrusted = sk_X509_new_null();
-		sk_X509_push(test_store->untrusted, mX509TestCert);
+        X509_STORE_CTX_set_cert(test_store, mX509ChildCert);
+        X509_STORE_CTX_set0_untrusted(test_store, sk_X509_new_null());
+		sk_X509_push(X509_STORE_CTX_get0_untrusted(test_store), mX509TestCert);
 		test_chain = new LLBasicCertificateChain(test_store);
 		X509_STORE_CTX_free(test_store);
 		ensure_equals("two elements in store", test_chain->size(), 1);	
@@ -1257,10 +1257,10 @@ namespace tut
 		
 		// cert + CA + nonrelated
 		test_store = X509_STORE_CTX_new();
-		test_store->cert = mX509ChildCert;
-		test_store->untrusted = sk_X509_new_null();
-		sk_X509_push(test_store->untrusted, mX509IntermediateCert);
-		sk_X509_push(test_store->untrusted, mX509TestCert);
+        X509_STORE_CTX_set_cert(test_store, mX509ChildCert);
+        X509_STORE_CTX_set0_untrusted(test_store, sk_X509_new_null());
+		sk_X509_push(X509_STORE_CTX_get0_untrusted(test_store), mX509IntermediateCert);
+		sk_X509_push(X509_STORE_CTX_get0_untrusted(test_store), mX509TestCert);
 		test_chain = new LLBasicCertificateChain(test_store);
 		X509_STORE_CTX_free(test_store);
 		ensure_equals("two elements in store", test_chain->size(), 2);	
@@ -1273,10 +1273,10 @@ namespace tut
 
 		// cert + intermediate + CA 
 		test_store = X509_STORE_CTX_new();
-		test_store->cert = mX509ChildCert;
-		test_store->untrusted = sk_X509_new_null();
-		sk_X509_push(test_store->untrusted, mX509IntermediateCert);
-		sk_X509_push(test_store->untrusted, mX509RootCert);
+        X509_STORE_CTX_set_cert(test_store, mX509ChildCert);
+        X509_STORE_CTX_set0_untrusted(test_store, sk_X509_new_null());
+		sk_X509_push(X509_STORE_CTX_get0_untrusted(test_store), mX509IntermediateCert);
+		sk_X509_push(X509_STORE_CTX_get0_untrusted(test_store), mX509RootCert);
 		test_chain = new LLBasicCertificateChain(test_store);
 		X509_STORE_CTX_free(test_store);
 		ensure_equals("three elements in store", test_chain->size(), 3);	
diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py
index 41da8fa3287e482f5a30361897d123f1b0eeb4cb..b932f431412900740b46d6be13ba26918f2a93f6 100755
--- a/indra/newview/viewer_manifest.py
+++ b/indra/newview/viewer_manifest.py
@@ -553,9 +553,13 @@ def construct(self):
                 self.path("vivoxsdk.dll")
                 self.path("ortp.dll")
             
-            # Security
-            self.path("ssleay32.dll")
-            self.path("libeay32.dll")
+            # OpenSSL
+            if (self.address_size == 64):
+                self.path("libcrypto-1_1-x64.dll")
+                self.path("libssl-1_1-x64.dll")
+            else:
+                self.path("libcrypto-1_1.dll")
+                self.path("libssl-1_1.dll")
 
             # HTTP/2
             self.path("nghttp2.dll")
@@ -1025,7 +1029,6 @@ def path_optional(src, dst):
                                 "libapr-1.0.dylib",
                                 "libaprutil-1.0.dylib",
                                 "libexpat.1.dylib",
-                                "libexception_handler.dylib",
                                 "libGLOD.dylib",
                                 # libnghttp2.dylib is a symlink to
                                 # libnghttp2.major.dylib, which is a symlink to
@@ -1294,14 +1297,19 @@ def package_finish(self):
                     signed=False
                     sign_attempts=3
                     sign_retry_wait=15
+                    libvlc_path = app_in_dmg + "/Contents/Resources/llplugin/media_plugin_libvlc.dylib"
+                    cef_path = app_in_dmg + "/Contents/Resources/llplugin/media_plugin_cef.dylib"
+                    slplugin_path = app_in_dmg + "/Contents/Resources/SLPlugin.app/Contents/MacOS/SLPlugin"
+                    greenlet_path = app_in_dmg + "/Contents/Resources/updater/greenlet/_greenlet.so"
                     while (not signed) and (sign_attempts > 0):
                         try:
-                            sign_attempts-=1;
-                            self.run_command(
-                                # Note: See blurb above about names of keychains
-                               ['codesign', '--verbose', '--deep', '--force',
-                                '--keychain', viewer_keychain, '--sign', identity,
-                                app_in_dmg])
+                            sign_attempts-=1
+                            # Note: See blurb above about names of keychains
+                            self.run_command(['codesign', '--force', '--timestamp','--keychain', viewer_keychain, '--sign', identity, libvlc_path])
+                            self.run_command(['codesign', '--force', '--timestamp', '--keychain', viewer_keychain, '--sign', identity, cef_path])
+                            self.run_command(['codesign', '--force', '--timestamp', '--keychain', viewer_keychain, '--sign', identity, greenlet_path])
+                            self.run_command(['codesign', '--verbose', '--deep', '--force', '--entitlements', self.src_path_of("slplugin.entitlements"), '--options', 'runtime', '--keychain', viewer_keychain, '--sign', identity, slplugin_path])
+                            self.run_command(['codesign', '--verbose', '--deep', '--force', '--options', 'runtime', '--keychain', viewer_keychain, '--sign', identity, app_in_dmg])
                             signed=True # if no exception was raised, the codesign worked
                         except ManifestError as err:
                             if sign_attempts:
@@ -1312,6 +1320,7 @@ def package_finish(self):
                                 print >> sys.stderr, "Maximum codesign attempts exceeded; giving up"
                                 raise
                     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])
 
         finally:
             # Unmount the image even if exceptions from any of the above 
@@ -1364,7 +1373,7 @@ def construct(self):
         with self.prefix(dst="bin"):
             self.path("secondlife-bin","do-not-directly-run-secondlife-bin")
             self.path("../linux_crash_logger/linux-crash-logger","linux-crash-logger.bin")
-            self.path2basename("../llplugin/slplugin", "SLPlugin") 
+            self.path2basename("../llplugin/slplugin", "SLPlugin")
             #this copies over the python wrapper script, associated utilities and required libraries, see SL-321, SL-322 and SL-323
             with self.prefix(src="../viewer_components/manager", dst=""):
                 self.path("*.py")
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/win_crash_logger/CMakeLists.txt b/indra/win_crash_logger/CMakeLists.txt
deleted file mode 100644
index 86aa655f03443dc99e5187e7c50c07e40e9860bb..0000000000000000000000000000000000000000
--- a/indra/win_crash_logger/CMakeLists.txt
+++ /dev/null
@@ -1,105 +0,0 @@
-# -*- cmake -*-
-
-project(win_crash_logger)
-
-include(00-Common)
-include(LLCommon)
-include(LLCoreHttp)
-include(LLCrashLogger)
-include(LLMath)
-include(LLMessage)
-include(LLVFS)
-include(LLWindow)
-include(LLXML)
-include(Linking)
-include(LLSharedLibs)
-include(GoogleBreakpad)
-include(Boost)
-
-include_directories(
-    ${LLCOREHTTP_INCLUDE_DIRS}
-    ${LLCOMMON_INCLUDE_DIRS}
-    ${LLCRASHLOGGER_INCLUDE_DIRS}
-    ${LLMATH_INCLUDE_DIRS}
-    ${LLWINDOW_INCLUDE_DIRS}
-    ${LLXML_INCLUDE_DIRS}
-    ${LLVFS_INCLUDE_DIRS}
-    ${BREAKPAD_INCLUDE_DIRECTORIES}
-    )
-include_directories(SYSTEM
-    ${LLCOMMON_SYSTEM_INCLUDE_DIRS}
-    ${LLXML_SYSTEM_INCLUDE_DIRS}
-    )
-
-set(win_crash_logger_SOURCE_FILES
-    win_crash_logger.cpp
-    llcrashloggerwindows.cpp
-    )
-
-set(win_crash_logger_HEADER_FILES
-    CMakeLists.txt
-
-    llcrashloggerwindows.h
-    resource.h
-    StdAfx.h
-    win_crash_logger.h
-    )
-
-set_source_files_properties(${win_crash_logger_HEADER_FILES}
-                            PROPERTIES HEADER_FILE_ONLY TRUE)
-
-set(win_crash_logger_RESOURCE_FILES
-    ll_icon.ico
-    )
-
-set_source_files_properties(${win_crash_logger_RESOURCE_FILES}
-                            PROPERTIES HEADER_FILE_ONLY TRUE)
-
-set(win_crash_logger_RESOURCE_FILES 
-    win_crash_logger.rc
-    ${win_crash_logger_RESOURCE_FILES}
-    )
-
-SOURCE_GROUP("Resource Files" FILES ${win_crash_logger_RESOURCE_FILES})
-
-list(APPEND 
-    win_crash_logger_SOURCE_FILES 
-    ${win_crash_logger_HEADER_FILES} 
-    ${win_crash_logger_RESOURCE_FILES}
-    )
-
-add_executable(windows-crash-logger WIN32 ${win_crash_logger_SOURCE_FILES})
-
-
-target_link_libraries(windows-crash-logger
-    ${LEGACY_STDIO_LIBS}
-    ${BREAKPAD_EXCEPTION_HANDLER_LIBRARIES}
-    ${LLCRASHLOGGER_LIBRARIES}
-    ${LLWINDOW_LIBRARIES}
-    ${LLVFS_LIBRARIES}
-    ${LLXML_LIBRARIES}
-    ${LLMESSAGE_LIBRARIES}
-    ${LLMATH_LIBRARIES}
-    ${LLCOREHTTP_LIBRARIES}
-    ${LLCOMMON_LIBRARIES}
-    ${BOOST_CONTEXT_LIBRARY}
-    ${BOOST_FIBER_LIBRARY}
-    ${WINDOWS_LIBRARIES}
-    dxguid
-    ${GOOGLE_PERFTOOLS_LIBRARIES}
-    user32
-    gdi32
-    oleaut32
-    wininet
-    Wldap32
-    )
-    
-if (WINDOWS)
-    set_target_properties(windows-crash-logger
-        PROPERTIES 
-        LINK_FLAGS "/NODEFAULTLIB:LIBCMT"
-        LINK_FLAGS_DEBUG "/NODEFAULTLIB:\"LIBCMT;LIBCMTD;MSVCRT\""
-        )
-endif (WINDOWS)
-
-ll_deploy_sharedlibs_command(windows-crash-logger)
diff --git a/indra/win_crash_logger/StdAfx.cpp b/indra/win_crash_logger/StdAfx.cpp
deleted file mode 100644
index f56711af73ea327dc25692afe48a47cea400bbd0..0000000000000000000000000000000000000000
--- a/indra/win_crash_logger/StdAfx.cpp
+++ /dev/null
@@ -1,34 +0,0 @@
-/** 
- * @file StdAfx.cpp
- * @brief windows crash logger source file for includes
- *
- * $LicenseInfo:firstyear=2003&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$
- */
-
-// stdafx.cpp : source file that includes just the standard includes
-//	win_crash_logger.pch will be the pre-compiled header
-//	stdafx.obj will contain the pre-compiled type information
-
-#include "stdafx.h"
-
-// TODO: reference any additional headers you need in STDAFX.H
-// and not in this file
diff --git a/indra/win_crash_logger/StdAfx.h b/indra/win_crash_logger/StdAfx.h
deleted file mode 100644
index 35976658acb9b525c45d8a75842ac8bb6d8e92d9..0000000000000000000000000000000000000000
--- a/indra/win_crash_logger/StdAfx.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/** 
- * @file StdAfx.h
- * @brief standard system includes
- *
- * $LicenseInfo:firstyear=2003&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$
- */
-
-// stdafx.h : include file for standard system include files,
-//  or project specific include files that are used frequently, but
-//      are changed infrequently
-//
-
-#if !defined(AFX_STDAFX_H__A9DB83DB_A9FD_11D0_BFD1_444553540000__INCLUDED_)
-#define AFX_STDAFX_H__A9DB83DB_A9FD_11D0_BFD1_444553540000__INCLUDED_
-
-#if _MSC_VER > 1000
-#pragma once
-#endif // _MSC_VER > 1000
-
-#define WIN32_LEAN_AND_MEAN		// Exclude rarely-used stuff from Windows headers
-
-// Windows Header Files:
-#include <windows.h>
-
-// C RunTime Header Files
-#include <stdlib.h>
-#include <malloc.h>
-#include <memory.h>
-
-// Local Header Files
-
-// TODO: reference additional headers your program requires here
-
-//{{AFX_INSERT_LOCATION}}
-// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
-
-#endif // !defined(AFX_STDAFX_H__A9DB83DB_A9FD_11D0_BFD1_444553540000__INCLUDED_)
diff --git a/indra/win_crash_logger/ll_icon.ico b/indra/win_crash_logger/ll_icon.ico
deleted file mode 100644
index 566346dfe301eec04d1fb819ecec2f2dd8d2483c..0000000000000000000000000000000000000000
Binary files a/indra/win_crash_logger/ll_icon.ico and /dev/null differ
diff --git a/indra/win_crash_logger/llcrashloggerwindows.cpp b/indra/win_crash_logger/llcrashloggerwindows.cpp
deleted file mode 100644
index 0cbe0b0d170c06bffbffb251edd022d5726edd6a..0000000000000000000000000000000000000000
--- a/indra/win_crash_logger/llcrashloggerwindows.cpp
+++ /dev/null
@@ -1,536 +0,0 @@
-/** 
-* @file llcrashloggerwindows.cpp
-* @brief Windows crash logger implementation
-*
-* $LicenseInfo:firstyear=2003&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 "linden_common.h"
-
-#include "stdafx.h"
-#include "resource.h"
-#include "llcrashloggerwindows.h"
-
-#include <sstream>
-
-#include "boost/tokenizer.hpp"
-
-#include "indra_constants.h"	// CRASH_BEHAVIOR_ASK, CRASH_SETTING_NAME
-#include "llerror.h"
-#include "llfile.h"
-#include "lltimer.h"
-#include "llstring.h"
-#include "lldxhardware.h"
-#include "lldir.h"
-#include "llsdserialize.h"
-#include "llsdutil.h"
-#include "stringize.h"
-
-#include <client/windows/crash_generation/crash_generation_server.h>
-#include <client/windows/crash_generation/client_info.h>
-
-#define MAX_LOADSTRING 100
-#define MAX_STRING 2048
-const char* const SETTINGS_FILE_HEADER = "version";
-const S32 SETTINGS_FILE_VERSION = 101;
-
-// Windows Message Handlers
-
-// Global Variables:
-HINSTANCE hInst= NULL;					// current instance
-TCHAR szTitle[MAX_LOADSTRING];				/* Flawfinder: ignore */		// The title bar text
-TCHAR szWindowClass[MAX_LOADSTRING];		/* Flawfinder: ignore */		// The title bar text
-
-std::string gProductName;
-HWND gHwndReport = NULL;	// Send/Don't Send dialog
-HWND gHwndProgress = NULL;	// Progress window
-HCURSOR gCursorArrow = NULL;
-HCURSOR gCursorWait = NULL;
-BOOL gFirstDialog = TRUE;	// Are we currently handling the Send/Don't Send dialog?
-std::stringstream gDXInfo;
-bool gSendLogs = false;
-
-LLCrashLoggerWindows* LLCrashLoggerWindows::sInstance = NULL;
-
-//Conversion from char* to wchar*
-//Replacement for ATL macros, doesn't allocate memory
-//For more info see: http://www.codeguru.com/forum/showthread.php?t=337247
-void ConvertLPCSTRToLPWSTR (const char* pCstring, WCHAR* outStr)
-{
-    if (pCstring != NULL)
-    {
-        int nInputStrLen = strlen (pCstring);
-        // Double NULL Termination
-        int nOutputStrLen = MultiByteToWideChar(CP_ACP, 0, pCstring, nInputStrLen, NULL, 0) + 2;
-        if (outStr)
-        {
-            memset (outStr, 0x00, sizeof (WCHAR)*nOutputStrLen);
-            MultiByteToWideChar (CP_ACP, 0, pCstring, nInputStrLen, outStr, nInputStrLen);
-        }
-    }
-}
-
-void write_debug(const char *str)
-{
-	gDXInfo << str;		/* Flawfinder: ignore */
-}
-
-void write_debug(std::string& str)
-{
-	write_debug(str.c_str());
-}
-
-void show_progress(const std::string& message)
-{
-	std::wstring msg = wstring_to_utf16str(utf8str_to_wstring(message));
-	if (gHwndProgress)
-	{
-		SendDlgItemMessage(gHwndProgress,       // handle to destination window 
-							IDC_LOG,
-							WM_SETTEXT,			// message to send
-							FALSE,				// undo option
-							(LPARAM)msg.c_str());
-	}
-}
-
-void update_messages()
-{
-	MSG msg;
-	while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
-	{
-		if (msg.message == WM_QUIT)
-		{
-			exit(0);
-		}
-		TranslateMessage(&msg);
-		DispatchMessage(&msg);
-	}
-}
-
-void sleep_and_pump_messages( U32 seconds )
-{
-	const U32 CYCLES_PER_SECOND = 10;
-	U32 cycles = seconds * CYCLES_PER_SECOND;
-	while( cycles-- )
-	{
-		update_messages();
-		ms_sleep(1000 / CYCLES_PER_SECOND);
-	}
-}
-
-// Include product name in the window caption.
-void LLCrashLoggerWindows::ProcessCaption(HWND hWnd)
-{
-	TCHAR templateText[MAX_STRING];		/* Flawfinder: ignore */
-	TCHAR header[MAX_STRING];
-	std::string final;
-	GetWindowText(hWnd, templateText, sizeof(templateText));
-	final = llformat(ll_convert_wide_to_string(templateText, CP_ACP).c_str(), gProductName.c_str());
-	ConvertLPCSTRToLPWSTR(final.c_str(), header);
-	SetWindowText(hWnd, header);
-}
-
-
-// Include product name in the diaog item text.
-void LLCrashLoggerWindows::ProcessDlgItemText(HWND hWnd, int nIDDlgItem)
-{
-	TCHAR templateText[MAX_STRING];		/* Flawfinder: ignore */
-	TCHAR header[MAX_STRING];
-	std::string final;
-	GetDlgItemText(hWnd, nIDDlgItem, templateText, sizeof(templateText));
-	final = llformat(ll_convert_wide_to_string(templateText, CP_ACP).c_str(), gProductName.c_str());
-	ConvertLPCSTRToLPWSTR(final.c_str(), header);
-	SetDlgItemText(hWnd, nIDDlgItem, header);
-}
-
-bool handle_button_click(WORD button_id)
-{
-	// Is this something other than Send or Don't Send?
-	if (button_id != IDOK
-		&& button_id != IDCANCEL)
-	{
-		return false;
-	}
-
-	// We're done with this dialog.
-	gFirstDialog = FALSE;
-
-	// Send the crash report if requested
-	if (button_id == IDOK)
-	{
-		gSendLogs = TRUE;
-		WCHAR wbuffer[20000];
-		GetDlgItemText(gHwndReport, // handle to dialog box
-						IDC_EDIT1,  // control identifier
-						wbuffer, // pointer to buffer for text
-						20000 // maximum size of string
-						);
-		std::string user_text(ll_convert_wide_to_string(wbuffer, CP_ACP));
-		// Activate and show the window.
-		ShowWindow(gHwndProgress, SW_SHOW); 
-		// Try doing this second to make the progress window go frontmost.
-		ShowWindow(gHwndReport, SW_HIDE);
-		((LLCrashLoggerWindows*)LLCrashLogger::instance())->setUserText(user_text);
-		((LLCrashLoggerWindows*)LLCrashLogger::instance())->sendCrashLogs();
-	}
-	// Quit the app
-	LLApp::setQuitting();
-	return true;
-}
-
-
-LRESULT CALLBACK WndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam )
-{
-	switch( message )
-	{
-	case WM_CREATE:
-		return 0;
-
-	case WM_COMMAND:
-		if( gFirstDialog )
-		{
-			WORD button_id = LOWORD(wParam);
-			bool handled = handle_button_click(button_id);
-			if (handled)
-			{
-				return 0;
-			}
-		}
-		break;
-
-	case WM_DESTROY:
-		// Closing the window cancels
-		LLApp::setQuitting();
-		PostQuitMessage(0);
-		return 0;
-	}
-
-	return DefWindowProc(hwnd, message, wParam, lParam);
-}
-
-
-LLCrashLoggerWindows::LLCrashLoggerWindows(void)
-{
-	if (LLCrashLoggerWindows::sInstance==NULL)
-	{
-		sInstance = this; 
-	}
-}
-
-LLCrashLoggerWindows::~LLCrashLoggerWindows(void)
-{
-	sInstance = NULL;
-}
-
-bool LLCrashLoggerWindows::getMessageWithTimeout(MSG *msg, UINT to)
-{
-    bool res;
-	UINT_PTR timerID = SetTimer(NULL, NULL, to, NULL);
-    res = GetMessage(msg, NULL, 0, 0);
-    KillTimer(NULL, timerID);
-    if (!res)
-        return false;
-    if (msg->message == WM_TIMER && msg->hwnd == NULL && msg->wParam == 1)
-        return false; //TIMEOUT! You could call SetLastError() or something...
-    return true;
-}
-
-int LLCrashLoggerWindows::processingLoop() {
-	const int millisecs=1000;
-	int retries = 0;
-	const int max_retries = 60;
-
-	LL_DEBUGS("CRASHREPORT") << "Entering processing loop for OOP server" << LL_ENDL;
-
-	LLSD options = getOptionData( LLApp::PRIORITY_COMMAND_LINE );
-
-	MSG msg;
-	
-	bool result;
-
-    while (1) 
-	{
-		result = getMessageWithTimeout(&msg, millisecs);
-		if ( result ) 
-		{
-			TranslateMessage(&msg);
-			DispatchMessage(&msg);
-		}
-
-		if ( retries < max_retries )  //Wait up to 1 minute for the viewer to say hello.
-		{
-			if (mClientsConnected == 0) 
-			{
-				LL_DEBUGS("CRASHREPORT") << "Waiting for client to connect." << LL_ENDL;
-				++retries;
-			}
-			else
-			{
-				LL_INFOS("CRASHREPORT") << "Client has connected!" << LL_ENDL;
-				retries = max_retries;
-			}
-		} 
-		else 
-		{
-			if (mClientsConnected == 0)
-			{
-				break;
-			}
-			if (!mKeyMaster.isProcessAlive(mPID, mProcName) )
-			{
-				break;
-			}
-		} 
-    }
-    
-    LL_INFOS() << "session ending.." << LL_ENDL;
-    
-    std::string per_run_dir = options["dumpdir"].asString();
-	std::string per_run_file = per_run_dir + "\\SecondLife.log";
-    std::string log_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"SecondLife.log");
-
-	if (gDirUtilp->fileExists(per_run_dir))  
-	{
-		LL_INFOS ("CRASHREPORT") << "Copying " << log_file << " to " << per_run_file << LL_ENDL;
-	    LLFile::copy(log_file, per_run_file);
-	}
-	return 0;
-}
-
-
-void LLCrashLoggerWindows::OnClientConnected(void* context,
-				const google_breakpad::ClientInfo* client_info) 
-{
-	sInstance->mClientsConnected++;
-	LL_INFOS("CRASHREPORT") << "Client connected. pid = " << client_info->pid() << " total clients " << sInstance->mClientsConnected << LL_ENDL;
-}
-
-void LLCrashLoggerWindows::OnClientExited(void* context,
-		const google_breakpad::ClientInfo* client_info) 
-{
-	sInstance->mClientsConnected--;
-	LL_INFOS("CRASHREPORT") << "Client disconnected. pid = " << client_info->pid() << " total clients " << sInstance->mClientsConnected << LL_ENDL;
-}
-
-
-void LLCrashLoggerWindows::OnClientDumpRequest(void* context,
-	const google_breakpad::ClientInfo* client_info,
-	const std::wstring* file_path) 
-{
-	if (!file_path) 
-	{
-		LL_WARNS() << "dump with no file path" << LL_ENDL;
-		return;
-	}
-	if (!client_info) 
-	{
-		LL_WARNS() << "dump with no client info" << LL_ENDL;
-		return;
-	}
-
-	LLCrashLoggerWindows* self = static_cast<LLCrashLoggerWindows*>(context);
-	if (!self) 
-	{
-		LL_WARNS() << "dump with no context" << LL_ENDL;
-		return;
-	}
-
-	//DWORD pid = client_info->pid();
-}
-
-
-bool LLCrashLoggerWindows::initCrashServer()
-{
-	//For Breakpad on Windows we need a full Out of Process service to get good data.
-	//This routine starts up the service on a named pipe that the viewer will then
-	//communicate with. 
-	using namespace google_breakpad;
-
-	LLSD options = getOptionData( LLApp::PRIORITY_COMMAND_LINE );
-	std::string dump_path = options["dumpdir"].asString();
-	mClientsConnected = 0;
-	mPID = options["pid"].asInteger();
-	mProcName = options["procname"].asString();
-
-	//Generate a quasi-uniq name for the named pipe.  For our purposes
-	//this is unique-enough with least hassle.  Worst case for duplicate name
-	//is a second instance of the viewer will not do crash reporting. 
-	std::wstring wpipe_name;
-	wpipe_name = mCrashReportPipeStr + std::wstring(wstringize(mPID));
-
-	std::wstring wdump_path(utf8str_to_utf16str(dump_path));
-		
-	//Pipe naming conventions:  http://msdn.microsoft.com/en-us/library/aa365783%28v=vs.85%29.aspx
-	mCrashHandler = new CrashGenerationServer( wpipe_name,
-		NULL, 
- 		&LLCrashLoggerWindows::OnClientConnected, this,
-		/*NULL, NULL,    */ &LLCrashLoggerWindows::OnClientDumpRequest, this,
- 		&LLCrashLoggerWindows::OnClientExited, this,
- 		NULL, NULL,
- 		true, &wdump_path);
-	
- 	if (!mCrashHandler) {
-		//Failed to start the crash server.
- 		LL_WARNS() << "Failed to init crash server." << LL_ENDL;
-		return false; 
- 	}
-
-	// Start servicing clients.
-    if (!mCrashHandler->Start()) {
-		LL_WARNS() << "Failed to start crash server." << LL_ENDL;
-		return false;
-	}
-
-	LL_INFOS("CRASHREPORT") << "Initialized OOP server with pipe named " << stringize(wpipe_name) << LL_ENDL;
-	return true;
-}
-
-bool LLCrashLoggerWindows::init(void)
-{	
-	bool ok = LLCrashLogger::init();
-	if(!ok) return false;
-
-	initCrashServer();
-
-	/*
-	mbstowcs( gProductName, mProductName.c_str(), LL_ARRAY_SIZE(gProductName) );
-	gProductName[ LL_ARRY_SIZE(gProductName) - 1 ] = 0;
-	swprintf(gProductName, L"Second Life"); 
-	*/
-
-	LL_INFOS() << "Loading dialogs" << LL_ENDL;
-
-	// Initialize global strings
-	LoadString(mhInst, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
-	LoadString(mhInst, IDC_WIN_CRASH_LOGGER, szWindowClass, MAX_LOADSTRING);
-
-	gCursorArrow = LoadCursor(NULL, IDC_ARROW);
-	gCursorWait = LoadCursor(NULL, IDC_WAIT);
-
-	// Register a window class that will be used by our dialogs
-	WNDCLASS wndclass;
-	wndclass.style = CS_HREDRAW | CS_VREDRAW;
-	wndclass.lpfnWndProc = WndProc;
-	wndclass.cbClsExtra = 0;
-	wndclass.cbWndExtra = DLGWINDOWEXTRA;  // Required, since this is used for dialogs!
-	wndclass.hInstance = mhInst;
-	wndclass.hIcon = LoadIcon(hInst, MAKEINTRESOURCE( IDI_WIN_CRASH_LOGGER ) );
-	wndclass.hCursor = gCursorArrow;
-	wndclass.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1);
-	wndclass.lpszMenuName = NULL;
-	wndclass.lpszClassName = szWindowClass;
-	RegisterClass( &wndclass );
-	
-	return true;
-}
-
-void LLCrashLoggerWindows::gatherPlatformSpecificFiles()
-{
-	updateApplication("Gathering hardware information. App may appear frozen.");
-	// DX hardware probe blocks, so we can't cancel during it
-	//Generate our dx_info.log file 
-	SetCursor(gCursorWait);
-	// At this point we're responsive enough the user could click the close button
-	SetCursor(gCursorArrow);
-	//mDebugLog["DisplayDeviceInfo"] = gDXHardware.getDisplayInfo();  //Not initialized.
-}
-
-bool LLCrashLoggerWindows::frame()
-{	
-	LL_INFOS() << "CrashSubmitBehavior is " << mCrashBehavior << LL_ENDL;
-
-	// Note: parent hwnd is 0 (the desktop).  No dlg proc.  See Petzold (5th ed) HexCalc example, Chapter 11, p529
-	// win_crash_logger.rc has been edited by hand.
-	// Dialogs defined with CLASS "WIN_CRASH_LOGGER" (must be same as szWindowClass)
-	gProductName = mProductName;
-	gHwndProgress = CreateDialog(hInst, MAKEINTRESOURCE(IDD_PROGRESS), 0, NULL);
-	ProcessCaption(gHwndProgress);
-	ShowWindow(gHwndProgress, SW_HIDE );
-
-	if (mCrashBehavior == CRASH_BEHAVIOR_ALWAYS_SEND)
-	{
-		LL_INFOS() << "Showing crash report submit progress window." << LL_ENDL;
-		//ShowWindow(gHwndProgress, SW_SHOW );   Maint-5707
-		sendCrashLogs();
-	}
-	else if (mCrashBehavior == CRASH_BEHAVIOR_ASK)
-	{
-		gHwndReport = CreateDialog(hInst, MAKEINTRESOURCE(IDD_PREVREPORTBOX), 0, NULL);
-		// Ignore result
-		(void) SendDlgItemMessage(gHwndReport, IDC_CHECK_AUTO, BM_SETCHECK, 0, 0);
-		// Include the product name in the caption and various dialog items.
-		ProcessCaption(gHwndReport);
-		ProcessDlgItemText(gHwndReport, IDC_STATIC_MSG);
-
-		// Update the header to include whether or not we crashed on the last run.
-		std::string headerStr;
-		TCHAR header[MAX_STRING];
-		if (mCrashInPreviousExec)
-		{
-			headerStr = llformat("%s appears to have crashed or frozen the last time it ran.", mProductName.c_str());
-		}
-		else
-		{
-			headerStr = llformat("%s appears to have crashed.", mProductName.c_str());
-		}
-		ConvertLPCSTRToLPWSTR(headerStr.c_str(), header);
-		SetDlgItemText(gHwndReport, IDC_STATIC_HEADER, header);		
-		ShowWindow(gHwndReport, SW_SHOW );
-		
-		MSG msg;
-		memset(&msg, 0, sizeof(msg));
-		while (!LLApp::isExiting() && GetMessage(&msg, NULL, 0, 0))
-		{
-			TranslateMessage(&msg);
-			DispatchMessage(&msg);
-		}
-		return true; // msg.wParam;
-	}
-	else
-	{
-		LL_WARNS() << "Unknown crash behavior " << mCrashBehavior << LL_ENDL;
-		return true; // 1;
-	}
-	return true; // 0;
-}
-
-void LLCrashLoggerWindows::updateApplication(const std::string& message)
-{
-	LLCrashLogger::updateApplication(message);
-	if(!message.empty()) show_progress(message);
-	update_messages();
-}
-
-bool LLCrashLoggerWindows::cleanup()
-{
-	if(gSendLogs)
-	{
-		if(mSentCrashLogs) show_progress("Done");
-		else show_progress("Could not connect to servers, logs not sent");
-		sleep_and_pump_messages(3);
-	}
-	PostQuitMessage(0);
-	commonCleanup();
-	mKeyMaster.releaseMaster();
-	return true;
-}
-
diff --git a/indra/win_crash_logger/llcrashloggerwindows.h b/indra/win_crash_logger/llcrashloggerwindows.h
deleted file mode 100644
index f89b8708dc9386567547b875c518a0ef07522e36..0000000000000000000000000000000000000000
--- a/indra/win_crash_logger/llcrashloggerwindows.h
+++ /dev/null
@@ -1,86 +0,0 @@
-/** 
-* @file llcrashloggerwindows.h
-* @brief Windows crash logger definition
-*
-* $LicenseInfo:firstyear=2003&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 LLCRASHLOGGERWINDOWS_H
-#define LLCRASHLOGGERWINDOWS_H
-
-#include "llcrashlogger.h"
-#include "windows.h"
-#include "llstring.h"
-
-class LLSD;
-
-namespace google_breakpad {
-	class CrashGenerationServer; 
-	class ClientInfo;
-}
-
-class LLCrashLoggerWindows : public LLCrashLogger
-{
-public:
-	LLCrashLoggerWindows(void);
-	~LLCrashLoggerWindows(void);
-	static LLCrashLoggerWindows* sInstance; 
-
-	virtual bool init();
-	virtual bool frame();
-	virtual void updateApplication(const std::string& message = LLStringUtil::null);
-	virtual bool cleanup();
-	virtual void gatherPlatformSpecificFiles();
-	void setHandle(HINSTANCE hInst) { mhInst = hInst; }
-    int clients_connected() const {
-        return mClientsConnected;
-    }
-	bool getMessageWithTimeout(MSG *msg, UINT to);
-    
-    // Starts the processing loop. This function does not return unless the
-    // user is logging off or the user closes the crash service window. The
-    // return value is a good number to pass in ExitProcess().
-    int processingLoop();
-private:
-	void ProcessDlgItemText(HWND hWnd, int nIDDlgItem);
-	void ProcessCaption(HWND hWnd);
-	bool initCrashServer();
-	google_breakpad::CrashGenerationServer* mCrashHandler;
-	static void OnClientConnected(void* context,
- 					const google_breakpad::ClientInfo* client_info);
- 	
- 	static void OnClientDumpRequest(
- 					void* context,
- 					const google_breakpad::ClientInfo* client_info,
- 					const std::wstring* file_path);
- 	
- 	static void OnClientExited(void* context,
-		 			const google_breakpad::ClientInfo* client_info);
-    int mClientsConnected;
-	int mPID;
-	std::string mProcName;
-    
-	HINSTANCE mhInst;
-
-};
-
-#endif
diff --git a/indra/win_crash_logger/resource.h b/indra/win_crash_logger/resource.h
deleted file mode 100644
index 37a387275ed4c98000907ace53a1d4e9fc64fb95..0000000000000000000000000000000000000000
--- a/indra/win_crash_logger/resource.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/** 
-* @file resource.h
-* @brief Windows crash logger windows resources
-*
-* $LicenseInfo:firstyear=2003&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$
-*/
-
-//{{NO_DEPENDENCIES}}
-// Microsoft Visual C++ generated include file.
-// Used by win_crash_logger.rc
-//
-#define IDC_MYICON                      2
-#define IDD_REPORT                      9
-#define IDD_WIN_CRASH_LOGGER_DIALOG     102
-#define IDD_ABOUTBOX                    103
-#define IDS_APP_TITLE                   103
-#define IDM_ABOUT                       104
-#define IDM_EXIT                        105
-#define IDS_HELLO                       106
-#define IDI_WIN_CRASH_LOGGER            107
-#define IDI_SMALL                       108
-#define IDC_WIN_CRASH_LOGGER            109
-#define IDR_MAINFRAME                   128
-#define IDD_PROGRESS                    129
-#define IDD_PREVREPORTBOX               130
-#define IDC_EDIT1                       1000
-#define IDC_LOG                         1004
-#define IDC_CHECK_AUTO                  1006
-#define IDC_STATIC_HEADER               1007
-#define IDC_STATIC_WHATINFO             1008
-#define IDC_STATIC_MOTIVATION           1009
-#define IDC_STATIC_MSG                  1010
-#define IDC_STATIC                      -1
-
-// Next default values for new objects
-// 
-#ifdef APSTUDIO_INVOKED
-#ifndef APSTUDIO_READONLY_SYMBOLS
-#define _APS_NEXT_RESOURCE_VALUE        131
-#define _APS_NEXT_COMMAND_VALUE         32771
-#define _APS_NEXT_CONTROL_VALUE         1011
-#define _APS_NEXT_SYMED_VALUE           110
-#endif
-#endif
diff --git a/indra/win_crash_logger/win_crash_logger.cpp b/indra/win_crash_logger/win_crash_logger.cpp
deleted file mode 100644
index 58746eba02559fc9becbb21d1c620bd2ff381a17..0000000000000000000000000000000000000000
--- a/indra/win_crash_logger/win_crash_logger.cpp
+++ /dev/null
@@ -1,70 +0,0 @@
-/** 
- * @file win_crash_logger.cpp
- * @brief Windows crash logger implementation
- *
- * $LicenseInfo:firstyear=2003&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 "linden_common.h"
-#include "stdafx.h"
-#include <stdlib.h>
-#include "llcrashloggerwindows.h"
-
-#ifdef _UNICODE
-int APIENTRY wWinMain(HINSTANCE hInstance,
-                      HINSTANCE hPrevInstance,
-                      LPWSTR    lpCmdLine,
-                      int       nCmdShow)
-#else
-int APIENTRY WinMain(HINSTANCE hInstance,
-                     HINSTANCE hPrevInstance,
-                     LPSTR     lpCmdLine,
-                     int       nCmdShow)
-#endif //_UNICODE
-{
-	LL_INFOS() << "Starting crash reporter with args" << &lpCmdLine << LL_ENDL;
-	LLCrashLoggerWindows app;
-	app.setHandle(hInstance);
-#ifdef _UNICODE
-	app.parseCommandOptions(__argc, __wargv);
-#else
-	app.parseCommandOptions(__argc, __argv);
-#endif //_UNICODE
-
-	LLSD options = LLApp::instance()->getOptionData(
-                   LLApp::PRIORITY_COMMAND_LINE);
-    if (!(options.has("pid") && options.has("dumpdir")))
-    {
-        LL_WARNS() << "Insufficient parameters to crash report." << LL_ENDL; 
-    }
-	if (! app.init())
-	{
-		LL_WARNS() << "Unable to initialize application." << LL_ENDL;
-		return -1;
-	}
-
-	app.processingLoop();
-	app.frame();
-	app.cleanup();
-	LL_INFOS() << "Crash reporter finished normally." << LL_ENDL;
-	return 0;
-}
diff --git a/indra/win_crash_logger/win_crash_logger.h b/indra/win_crash_logger/win_crash_logger.h
deleted file mode 100644
index 2cc2cf3dcfce62563ae4e4e0d977d60f5c4a0b2d..0000000000000000000000000000000000000000
--- a/indra/win_crash_logger/win_crash_logger.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/** 
- * @file win_crash_logger.h
- * @brief Windows crash logger project includes
- *
- * $LicenseInfo:firstyear=2003&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$
- */
-
-
-#if !defined(AFX_WIN_CRASH_LOGGER_H__79802F4B_7C37_4F63_A2BB_0768788C3A27__INCLUDED_)
-#define AFX_WIN_CRASH_LOGGER_H__79802F4B_7C37_4F63_A2BB_0768788C3A27__INCLUDED_
-
-#if _MSC_VER > 1000
-#pragma once
-#endif // _MSC_VER > 1000
-
-#include "resource.h"
-
-
-#endif // !defined(AFX_WIN_CRASH_LOGGER_H__79802F4B_7C37_4F63_A2BB_0768788C3A27__INCLUDED_)
diff --git a/indra/win_crash_logger/win_crash_logger.ico b/indra/win_crash_logger/win_crash_logger.ico
deleted file mode 100644
index 386883523bcc032db77b69b047cbc5c15ae3b7fe..0000000000000000000000000000000000000000
Binary files a/indra/win_crash_logger/win_crash_logger.ico and /dev/null differ
diff --git a/indra/win_crash_logger/win_crash_logger.rc b/indra/win_crash_logger/win_crash_logger.rc
deleted file mode 100755
index 2819722f6365732f75f83b6111bbce2cc7bc994f..0000000000000000000000000000000000000000
--- a/indra/win_crash_logger/win_crash_logger.rc
+++ /dev/null
@@ -1,188 +0,0 @@
-// Microsoft Visual C++ generated resource script.
-//
-#include "resource.h"
-
-#define APSTUDIO_READONLY_SYMBOLS
-/////////////////////////////////////////////////////////////////////////////
-//
-// Generated from the TEXTINCLUDE 2 resource.
-//
-#define APSTUDIO_HIDDEN_SYMBOLS
-#include "windows.h"
-#undef APSTUDIO_HIDDEN_SYMBOLS
-#include "resource.h"
-
-/////////////////////////////////////////////////////////////////////////////
-#undef APSTUDIO_READONLY_SYMBOLS
-
-/////////////////////////////////////////////////////////////////////////////
-// English (U.S.) resources
-
-#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
-#ifdef _WIN32
-LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
-#pragma code_page(1252)
-#endif //_WIN32
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// Icon
-//
-
-// Icon with lowest ID value placed first to ensure application icon
-// remains consistent on all systems.
-IDI_WIN_CRASH_LOGGER    ICON                    "ll_icon.ico"
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// Menu
-//
-
-IDC_WIN_CRASH_LOGGER MENU 
-BEGIN
-    POPUP "&File"
-    BEGIN
-        MENUITEM "E&xit",                       IDM_EXIT
-    END
-    POPUP "&Help"
-    BEGIN
-        MENUITEM "&About ...",                  IDM_ABOUT
-    END
-END
-
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// Dialog
-//
-
-IDD_PROGRESS DIALOGEX 100, 100, 234, 33
-STYLE DS_SETFONT | DS_SETFOREGROUND | WS_CAPTION | WS_SYSMENU
-CAPTION "%s Crash Logger"
-CLASS "WIN_CRASH_LOGGER"
-FONT 8, "MS Sans Serif", 0, 0, 0x0
-BEGIN
-    LTEXT           "Static",IDC_LOG,7,7,220,8
-END
-
-IDD_REPORT DIALOGEX 100, 100, 297, 125
-STYLE DS_SETFONT | DS_SETFOREGROUND | WS_CAPTION | WS_SYSMENU
-CAPTION "%s Crash Logger"
-CLASS "WIN_CRASH_LOGGER"
-FONT 8, "MS Sans Serif", 0, 0, 0x0
-BEGIN
-    DEFPUSHBUTTON   "Send",IDOK,198,104,45,15,WS_GROUP
-    PUSHBUTTON      "Don't Send",IDCANCEL,247,104,45,15,WS_GROUP
-    LTEXT           "%s appears to have crashed.",IDC_STATIC_HEADER,4,4,288,14
-    LTEXT           "This crash reporter collects information about your computer's hardware, operating system, and some %s logs, which are used for debugging purposes only.",IDC_STATIC_WHATINFO,4,23,288,19,NOT WS_GROUP
-    CONTROL         "Remember this choice",IDC_CHECK_AUTO,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,4,106,89,13
-    LTEXT           "Sending crash reports is the best way to help us improve the quality of %s.",IDC_STATIC_MOTIVATION,4,43,288,8
-    LTEXT           "If you continue to experience this problem, please try:",IDC_STATIC,4,57,251,8
-    LTEXT           "- Contacting support by visiting http://www.secondlife.com/support",IDC_STATIC,4,67,231,8
-END
-
-IDD_PREVREPORTBOX DIALOGEX 100, 100, 232, 213
-STYLE DS_SETFONT | DS_SETFOREGROUND | WS_CAPTION | WS_SYSMENU
-CAPTION "%s Crash Logger"
-CLASS "WIN_CRASH_LOGGER"
-FONT 8, "MS Sans Serif", 0, 0, 0x0
-BEGIN
-    DEFPUSHBUTTON   "Send Report",IDOK,131,193,45,15,WS_GROUP
-    EDITTEXT        IDC_EDIT1,3,100,223,89,ES_MULTILINE | ES_WANTRETURN | WS_VSCROLL
-    PUSHBUTTON      "Don't Send",IDCANCEL,181,193,45,15,WS_GROUP
-    LTEXT           "%s appears to have crashed or frozen the last time it ran.",IDC_STATIC_HEADER,4,4,214,8
-    LTEXT           "This crash reporter collects information about your computer's",IDC_STATIC,4,17,201,8
-    LTEXT           "hardware configuration, operating system, and some %s",IDC_STATIC_MSG,4,25,212,8
-    LTEXT           "logs, all of which are used for debugging purposes only.",IDC_STATIC,4,33,210,8
-    LTEXT           "In the space below, please briefly describe what you were doing",IDC_STATIC,3,48,208,8
-    LTEXT           "or trying to do just prior to the crash.",IDC_STATIC,3,56,204,8
-    LTEXT           "If you don't wish to send Linden Lab a crash report, press Don't Send.",IDC_STATIC,3,90,223,8
-    LTEXT           "This report is NOT read by customer support.  If you have billing or",IDC_STATIC,3,68,208,8
-    LTEXT           "other questions, please go to: www.secondlife.com/support",IDC_STATIC,3,76,206,8
-    CONTROL         "Remember this choice",IDC_CHECK_AUTO,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,3,193,89,13
-END
-
-
-#ifdef APSTUDIO_INVOKED
-/////////////////////////////////////////////////////////////////////////////
-//
-// TEXTINCLUDE
-//
-
-2 TEXTINCLUDE 
-BEGIN
-    "#define APSTUDIO_HIDDEN_SYMBOLS\r\n"
-    "#include ""windows.h""\r\n"
-    "#undef APSTUDIO_HIDDEN_SYMBOLS\r\n"
-    "#include ""resource.h""\r\n"
-    "\0"
-END
-
-3 TEXTINCLUDE 
-BEGIN
-    "\r\n"
-    "\0"
-END
-
-1 TEXTINCLUDE 
-BEGIN
-    "resource.h\0"
-END
-
-#endif    // APSTUDIO_INVOKED
-
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// DESIGNINFO
-//
-
-#ifdef APSTUDIO_INVOKED
-GUIDELINES DESIGNINFO 
-BEGIN
-    IDD_PROGRESS, DIALOG
-    BEGIN
-        LEFTMARGIN, 7
-        RIGHTMARGIN, 227
-        TOPMARGIN, 7
-        BOTTOMMARGIN, 26
-    END
-
-    IDD_REPORT, DIALOG
-    BEGIN
-        RIGHTMARGIN, 292
-        VERTGUIDE, 4
-        BOTTOMMARGIN, 119
-        HORZGUIDE, 4
-    END
-END
-#endif    // APSTUDIO_INVOKED
-
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// String Table
-//
-
-STRINGTABLE 
-BEGIN
-    IDS_APP_TITLE           "win_crash_logger"
-    IDS_HELLO               "Hello World!"
-    IDC_WIN_CRASH_LOGGER    "WIN_CRASH_LOGGER"
-END
-
-#endif    // English (U.S.) resources
-/////////////////////////////////////////////////////////////////////////////
-
-
-
-#ifndef APSTUDIO_INVOKED
-/////////////////////////////////////////////////////////////////////////////
-//
-// Generated from the TEXTINCLUDE 3 resource.
-//
-
-
-/////////////////////////////////////////////////////////////////////////////
-#endif    // not APSTUDIO_INVOKED
-
diff --git a/scripts/perf/perfbot_run.py b/scripts/perf/perfbot_run.py
index 4219b7bcda1a9d7d551627c823db150b50f06214..006d5f8934bcbd12d5cf286a8021b61df81535d2 100644
--- a/scripts/perf/perfbot_run.py
+++ b/scripts/perf/perfbot_run.py
@@ -78,7 +78,7 @@ def gen_niv_script(args):
     working_dir = args.cwd
     if len(args.cwd) == 0:
         working_dir = os.path.dirname(os.path.abspath(args.viewer))
-    print(f"Working directory is {working_dir}")
+    print(f"Working directory is {working_dir} {args.cwd=}")
     environ = os.environ
     environ["cwd"] = working_dir