From 10f84d8244d01728338f1eb20b0b25271fc7db63 Mon Sep 17 00:00:00 2001
From: Dave Houlton <euclid@lindenlab.com>
Date: Tue, 20 Apr 2021 10:49:33 -0600
Subject: DRTVWR-528 remove wrapper code for RAD telemetry library

---
 indra/newview/CMakeLists.txt  |   1 -
 indra/newview/llappviewer.cpp |   3 -
 indra/newview/llstartup.cpp   |   3 -
 indra/newview/lltelemetry.cpp | 145 ------------------------------------------
 indra/newview/lltelemetry.h   |  81 -----------------------
 5 files changed, 233 deletions(-)
 delete mode 100644 indra/newview/lltelemetry.cpp
 delete mode 100644 indra/newview/lltelemetry.h

(limited to 'indra')

diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 424fd17707..e8e5b83957 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -589,7 +589,6 @@ set(viewer_SOURCE_FILES
     llsyntaxid.cpp
     llsyswellitem.cpp
     llsyswellwindow.cpp
-    lltelemetry.cpp
     llteleporthistory.cpp
     llteleporthistorystorage.cpp
     lltextureatlas.cpp
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index c0971ba943..bc651188e0 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"
@@ -1679,8 +1678,6 @@ bool LLAppViewer::doFrame()
 		LL_INFOS() << "Exiting main_loop" << LL_ENDL;
 	}
 
-    LLPROFILE_UPDATE();
-
 	return ! LLApp::isRunning();
 }
 
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index c5d5be3509..55048b03be 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/lltelemetry.cpp b/indra/newview/lltelemetry.cpp
deleted file mode 100644
index 0c63e2fede..0000000000
--- 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 a73e5fcfa2..0000000000
--- 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
-- 
cgit v1.2.3


From 97c954dd84d50ec7b739d2dd3adb7365589f3034 Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Tue, 6 Jul 2021 21:26:15 +0300
Subject: SL-15522 Initial addition of meshoptimizer

---
 indra/CMakeLists.txt                      |  1 +
 indra/cmake/CMakeLists.txt                |  1 +
 indra/cmake/LLMeshOptimizer.cmake         |  7 +++++
 indra/cmake/MESHOPTIMIZER.cmake           | 16 ++++++++++++
 indra/llmeshoptimizer/CMakeLists.txt      | 41 +++++++++++++++++++++++++++++
 indra/llmeshoptimizer/llmeshoptimizer.cpp | 43 +++++++++++++++++++++++++++++++
 indra/llmeshoptimizer/llmeshoptimizer.h   | 37 ++++++++++++++++++++++++++
 indra/newview/CMakeLists.txt              |  3 +++
 8 files changed, 149 insertions(+)
 create mode 100644 indra/cmake/LLMeshOptimizer.cmake
 create mode 100644 indra/cmake/MESHOPTIMIZER.cmake
 create mode 100644 indra/llmeshoptimizer/CMakeLists.txt
 create mode 100644 indra/llmeshoptimizer/llmeshoptimizer.cpp
 create mode 100644 indra/llmeshoptimizer/llmeshoptimizer.h

(limited to 'indra')

diff --git a/indra/CMakeLists.txt b/indra/CMakeLists.txt
index 53e5d7b6a5..c504ca3b02 100644
--- a/indra/CMakeLists.txt
+++ b/indra/CMakeLists.txt
@@ -37,6 +37,7 @@ add_subdirectory(${LIBS_OPEN_PREFIX}llkdu)
 add_subdirectory(${LIBS_OPEN_PREFIX}llimagej2coj)
 add_subdirectory(${LIBS_OPEN_PREFIX}llinventory)
 add_subdirectory(${LIBS_OPEN_PREFIX}llmath)
+add_subdirectory(${LIBS_OPEN_PREFIX}llmeshoptimizer)
 add_subdirectory(${LIBS_OPEN_PREFIX}llmessage)
 add_subdirectory(${LIBS_OPEN_PREFIX}llprimitive)
 add_subdirectory(${LIBS_OPEN_PREFIX}llrender)
diff --git a/indra/cmake/CMakeLists.txt b/indra/cmake/CMakeLists.txt
index a17e37cd32..7795aa7db1 100644
--- a/indra/cmake/CMakeLists.txt
+++ b/indra/cmake/CMakeLists.txt
@@ -61,6 +61,7 @@ set(cmake_SOURCE_FILES
     LLKDU.cmake
     LLLogin.cmake
     LLMath.cmake
+    LLMeshOptimizer.cmake
     LLMessage.cmake
     LLPhysicsExtensions.cmake
     LLPlugin.cmake
diff --git a/indra/cmake/LLMeshOptimizer.cmake b/indra/cmake/LLMeshOptimizer.cmake
new file mode 100644
index 0000000000..b79944f618
--- /dev/null
+++ b/indra/cmake/LLMeshOptimizer.cmake
@@ -0,0 +1,7 @@
+# -*- cmake -*-
+
+set(LLMESHOPTIMIZER_INCLUDE_DIRS
+    ${LIBS_OPEN_DIR}/llmeshoptimizer
+    )
+
+set(LLMESHOPTIMIZER_LIBRARIES llmeshoptimizer)
diff --git a/indra/cmake/MESHOPTIMIZER.cmake b/indra/cmake/MESHOPTIMIZER.cmake
new file mode 100644
index 0000000000..7600a56999
--- /dev/null
+++ b/indra/cmake/MESHOPTIMIZER.cmake
@@ -0,0 +1,16 @@
+# -*- cmake -*-
+
+include(Prebuilt)
+
+use_prebuilt_binary(meshoptimizer)
+
+if (WINDOWS)
+  set(MESHOPTIMIZER_LIBRARIES
+    debug meshoptimizer
+    optimized meshoptimizer)
+elseif (LINUX)
+  set(MESHOPTIMIZER_LIBRARIES meshoptimizer)
+elseif (DARWIN)
+  set(MESHOPTIMIZER_LIBRARIES libmeshoptimizer.o)
+endif (WINDOWS)
+set(MESHOPTIMIZER_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/include/meshoptimizer)
diff --git a/indra/llmeshoptimizer/CMakeLists.txt b/indra/llmeshoptimizer/CMakeLists.txt
new file mode 100644
index 0000000000..1eea19de66
--- /dev/null
+++ b/indra/llmeshoptimizer/CMakeLists.txt
@@ -0,0 +1,41 @@
+# -*- cmake -*-
+
+project(llmeshoptimizer)
+
+include(MESHOPTIMIZER)
+
+include(00-Common)
+include(LLCommon)
+
+include_directories(
+    ${LLCOMMON_INCLUDE_DIRS}
+    ${LLMESHOPTIMIZER_INCLUDE_DIR}
+    ${MESHOPTIMIZER_INCLUDE_DIRS}
+    ${LIBS_PREBUILT_DIR}/include  #access to boost headers, needed for LLError
+    )
+
+set(llmeshoptimizer_SOURCE_FILES
+    llmeshoptimizer.cpp
+    )
+
+set(llmeshoptimizer_HEADER_FILES
+    CMakeLists.txt
+
+    llmeshoptimizer.h
+    )
+
+set_source_files_properties(${llmeshoptimizer_HEADER_FILES}
+                            PROPERTIES HEADER_FILE_ONLY TRUE)
+
+list(APPEND llmeshoptimizer_SOURCE_FILES ${llmeshoptimizer_HEADER_FILES})
+
+#if (USE_MESHOPT)
+  add_library (llmeshoptimizer ${llmeshoptimizer_SOURCE_FILES})
+
+  target_link_libraries(llmeshoptimizer
+    ${LLCOMMON_LIBRARIES}
+    ${MESHOPTIMIZER_LIBRARY})
+  
+  # Add tests
+
+#endif (USE_MESHOPT)
diff --git a/indra/llmeshoptimizer/llmeshoptimizer.cpp b/indra/llmeshoptimizer/llmeshoptimizer.cpp
new file mode 100644
index 0000000000..770cd5aa3c
--- /dev/null
+++ b/indra/llmeshoptimizer/llmeshoptimizer.cpp
@@ -0,0 +1,43 @@
+ /** 
+* @file llmeshoptimizer.cpp
+* @brief Wrapper around meshoptimizer
+*
+* $LicenseInfo:firstyear=2021&license=viewerlgpl$
+* Second Life Viewer Source Code
+* Copyright (C) 2021, Linden Research, Inc.
+* 
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Lesser General Public
+* License as published by the Free Software Foundation;
+* version 2.1 of the License only.
+* 
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+* Lesser General Public License for more details.
+* 
+* You should have received a copy of the GNU Lesser General Public
+* License along with this library; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+* 
+* Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+* $/LicenseInfo$
+*/
+
+#include "llmeshoptimizer.h"
+
+#include "linden_common.h"
+
+#include "meshoptimizer.h"
+#include "llmath.h"
+
+
+LLMeshOptimizer::LLMeshOptimizer()
+{
+
+}
+
+LLMeshOptimizer::~LLMeshOptimizer()
+{
+
+}
diff --git a/indra/llmeshoptimizer/llmeshoptimizer.h b/indra/llmeshoptimizer/llmeshoptimizer.h
new file mode 100644
index 0000000000..edce4edf05
--- /dev/null
+++ b/indra/llmeshoptimizer/llmeshoptimizer.h
@@ -0,0 +1,37 @@
+/** 
+* @file llmeshoptimizer.h
+* @brief Wrapper around meshoptimizer
+*
+* $LicenseInfo:firstyear=2021&license=viewerlgpl$
+* Second Life Viewer Source Code
+* Copyright (C) 2021, Linden Research, Inc.
+* 
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Lesser General Public
+* License as published by the Free Software Foundation;
+* version 2.1 of the License only.
+* 
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+* Lesser General Public License for more details.
+* 
+* You should have received a copy of the GNU Lesser General Public
+* License along with this library; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+* 
+* Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+* $/LicenseInfo$
+*/
+#ifndef LLMESHOPTIMIZER_H
+#define LLMESHOPTIMIZER_H
+
+class LLMeshOptimizer
+{
+public:
+    LLMeshOptimizer();
+    ~LLMeshOptimizer();
+private:
+};
+
+#endif //LLMESHOPTIMIZER_H
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 424fd17707..72d01b264c 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -33,6 +33,7 @@ include(LLInventory)
 include(LLKDU)
 include(LLLogin)
 include(LLMath)
+include(LLMeshOptimizer)
 include(LLMessage)
 include(LLPhysicsExtensions)
 include(LLPlugin)
@@ -79,6 +80,7 @@ include_directories(
     ${LLKDU_INCLUDE_DIRS}
     ${LLINVENTORY_INCLUDE_DIRS}
     ${LLMATH_INCLUDE_DIRS}
+    ${LLMESHOPTIMIZER_INCLUDE_DIRS}
     ${LLMESSAGE_INCLUDE_DIRS}
     ${LLPLUGIN_INCLUDE_DIRS}
     ${LLPRIMITIVE_INCLUDE_DIRS}
@@ -2027,6 +2029,7 @@ target_link_libraries(${VIEWER_BINARY_NAME}
     ${LLCHARACTER_LIBRARIES}
     ${LLIMAGE_LIBRARIES}
     ${LLINVENTORY_LIBRARIES}
+    ${LLMESHOPTIMIZER_LIBRARIES}
     ${LLMESSAGE_LIBRARIES}
     ${LLPLUGIN_LIBRARIES}
     ${LLPRIMITIVE_LIBRARIES}
-- 
cgit v1.2.3


From 7b7b8a8da8f3a7e726b7de2b152cd00c67df0f18 Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Wed, 7 Jul 2021 22:34:26 +0300
Subject: DRTVWR-542 WIP

---
 indra/llmeshoptimizer/llmeshoptimizer.cpp          |  14 +-
 indra/llmeshoptimizer/llmeshoptimizer.h            |   5 +
 indra/newview/llfloatermodelpreview.cpp            |  19 +-
 indra/newview/llmodelpreview.cpp                   | 203 ++++++++++++++++++++-
 indra/newview/llmodelpreview.h                     |  12 +-
 .../skins/default/xui/en/floater_model_preview.xml |  16 ++
 6 files changed, 255 insertions(+), 14 deletions(-)

(limited to 'indra')

diff --git a/indra/llmeshoptimizer/llmeshoptimizer.cpp b/indra/llmeshoptimizer/llmeshoptimizer.cpp
index 770cd5aa3c..c46fa8dcf3 100644
--- a/indra/llmeshoptimizer/llmeshoptimizer.cpp
+++ b/indra/llmeshoptimizer/llmeshoptimizer.cpp
@@ -26,18 +26,24 @@
 
 #include "llmeshoptimizer.h"
 
-#include "linden_common.h"
-
 #include "meshoptimizer.h"
-#include "llmath.h"
 
 
 LLMeshOptimizer::LLMeshOptimizer()
 {
-
+    // Todo: Looks like for memory management, we can add allocator and deallocator callbacks
+    // Should be one time
+    // meshopt_setAllocator(allocate, deallocate);
 }
 
 LLMeshOptimizer::~LLMeshOptimizer()
 {
 
 }
+
+//static
+U32 LLMeshOptimizer::simplifyModel()
+{
+    LL_WARNS() << "NOT IMPLEMENTED" << LL_ENDL;
+    return 0;
+}
diff --git a/indra/llmeshoptimizer/llmeshoptimizer.h b/indra/llmeshoptimizer/llmeshoptimizer.h
index edce4edf05..d53ec2e24c 100644
--- a/indra/llmeshoptimizer/llmeshoptimizer.h
+++ b/indra/llmeshoptimizer/llmeshoptimizer.h
@@ -26,11 +26,16 @@
 #ifndef LLMESHOPTIMIZER_H
 #define LLMESHOPTIMIZER_H
 
+#include "linden_common.h"
+
 class LLMeshOptimizer
 {
 public:
     LLMeshOptimizer();
     ~LLMeshOptimizer();
+
+    // returns state
+    static U32 simplifyModel();
 private:
 };
 
diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp
index d9edd4dc30..d8f3021fb2 100644
--- a/indra/newview/llfloatermodelpreview.cpp
+++ b/indra/newview/llfloatermodelpreview.cpp
@@ -722,7 +722,20 @@ void LLFloaterModelPreview::onAutoFillCommit(LLUICtrl* ctrl, void* userdata)
 
 void LLFloaterModelPreview::onLODParamCommit(S32 lod, bool enforce_tri_limit)
 {
-	mModelPreview->onLODParamCommit(lod, enforce_tri_limit);
+    LLComboBox* lod_source_combo = getChild<LLComboBox>("lod_source_" + lod_name[lod]);
+    S32 mode = lod_source_combo->getCurrentIndex();
+    switch (mode)
+    {
+    case LLModelPreview::GENERATE:
+        mModelPreview->onLODGenerateParamCommit(lod, enforce_tri_limit);
+        break;
+    case LLModelPreview::MESH_OPTIMIZER:
+        mModelPreview->onLODMeshOptimizerParamCommit(lod, enforce_tri_limit);
+        break;
+    default:
+        LL_ERRS() << "Only supposed to be called to generate models" << LL_ENDL;
+        break;
+    }
 
 	//refresh LoDs that reference this one
 	for (S32 i = lod - 1; i >= 0; --i)
@@ -1721,7 +1734,9 @@ void LLFloaterModelPreview::onLoDSourceCommit(S32 lod)
 	refresh();
 
 	LLComboBox* lod_source_combo = getChild<LLComboBox>("lod_source_" + lod_name[lod]);
-	if (lod_source_combo->getCurrentIndex() == LLModelPreview::GENERATE)
+    S32 index = lod_source_combo->getCurrentIndex();
+	if (index == LLModelPreview::GENERATE
+        || index == LLModelPreview::MESH_OPTIMIZER)
 	{ //rebuild LoD to update triangle counts
 		onLODParamCommit(lod, true);
 	}
diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp
index a9e80ab5da..a6eef74cdc 100644
--- a/indra/newview/llmodelpreview.cpp
+++ b/indra/newview/llmodelpreview.cpp
@@ -41,6 +41,7 @@
 #include "lliconctrl.h"
 #include "llmatrix4a.h"
 #include "llmeshrepository.h"
+#include "llmeshoptimizer.h"
 #include "llrender.h"
 #include "llsdutil_math.h"
 #include "llskinningutil.h"
@@ -1339,7 +1340,7 @@ void LLModelPreview::restoreNormals()
     updateStatusMessages();
 }
 
-void LLModelPreview::genLODs(S32 which_lod, U32 decimation, bool enforce_tri_limit)
+void LLModelPreview::genGlodLODs(S32 which_lod, U32 decimation, bool enforce_tri_limit)
 {
     // Allow LoD from -1 to LLModel::LOD_PHYSICS
     if (which_lod < -1 || which_lod > LLModel::NUM_LODS - 1)
@@ -1424,7 +1425,7 @@ void LLModelPreview::genLODs(S32 which_lod, U32 decimation, bool enforce_tri_lim
         mRequestedLoDMode[which_lod] = lod_mode;
     }
 
-    if (lod_mode == 0)
+    if (lod_mode == LIMIT_TRIANGLES)
     {
         lod_mode = GLOD_TRIANGLE_BUDGET;
 
@@ -2957,7 +2958,7 @@ BOOL LLModelPreview::render()
     {
         genBuffers(-1, skin_weight);
         //genBuffers(3);
-        //genLODs();
+        //genGlodLODs();
     }
 
     if (!mModel[mPreviewLOD].empty())
@@ -3544,7 +3545,7 @@ bool LLModelPreview::lodQueryCallback()
         {
             S32 lod = preview->mLodsQuery.back();
             preview->mLodsQuery.pop_back();
-            preview->genLODs(lod);
+            preview->genGlodLODs(lod);
 
             if (preview->mLookUpLodFiles && (lod == LLModel::LOD_HIGH))
             {
@@ -3559,12 +3560,202 @@ bool LLModelPreview::lodQueryCallback()
     return true;
 }
 
-void LLModelPreview::onLODParamCommit(S32 lod, bool enforce_tri_limit)
+void LLModelPreview::onLODGenerateParamCommit(S32 lod, bool enforce_tri_limit)
 {
     if (!mLODFrozen)
     {
-        genLODs(lod, 3, enforce_tri_limit);
+        genGlodLODs(lod, 3, enforce_tri_limit);
         refresh();
     }
 }
 
+void LLModelPreview::onLODMeshOptimizerParamCommit(S32 lod, bool enforce_tri_limit)
+{
+    if (mLODFrozen)
+    {
+        return;
+    }
+
+    // Allow LoD from -1 to LLModel::LOD_PHYSICS
+    if (lod < -1 || lod > LLModel::NUM_LODS - 1)
+    {
+        std::ostringstream out;
+        out << "Invalid level of detail: " << lod;
+        LL_WARNS() << out.str() << LL_ENDL;
+        LLFloaterModelPreview::addStringToLog(out, false);
+        assert(lod >= -1 && lod < LLModel::NUM_LODS);
+        return;
+    }
+
+    if (mBaseModel.empty())
+    {
+        return;
+    }
+
+
+    U32 triangle_count = 0;
+    U32 instanced_triangle_count = 0;
+
+    //get the triangle count for the whole scene
+    for (LLModelLoader::scene::iterator iter = mBaseScene.begin(), endIter = mBaseScene.end(); iter != endIter; ++iter)
+    {
+        for (LLModelLoader::model_instance_list::iterator instance = iter->second.begin(), end_instance = iter->second.end(); instance != end_instance; ++instance)
+        {
+            LLModel* mdl = instance->mModel;
+            if (mdl)
+            {
+                instanced_triangle_count += mdl->getNumTriangles();
+            }
+        }
+    }
+
+    //get the triangle count for the non-instanced set of models
+    for (U32 i = 0; i < mBaseModel.size(); ++i)
+    {
+        triangle_count += mBaseModel[i]->getNumTriangles();
+    }
+
+    //get ratio of uninstanced triangles to instanced triangles
+    F32 triangle_ratio = (F32)triangle_count / (F32)instanced_triangle_count;
+    U32 base_triangle_count = triangle_count;
+    U32 lod_mode = 0;
+    F32 lod_error_threshold = 0;
+
+
+    // Urgh...
+    // TODO: add interface to mFMP to get error treshold or let mFMP write one into LLModelPreview
+    // We should not be accesing views from other class!
+    LLCtrlSelectionInterface* iface = mFMP->childGetSelectionInterface("lod_mode_" + lod_name[lod]);
+    if (iface)
+    {
+        lod_mode = iface->getFirstSelectedIndex();
+    }
+
+    lod_error_threshold = mFMP->childGetValue("lod_error_threshold_" + lod_name[lod]).asReal();
+
+    if (lod != -1)
+    {
+        mRequestedLoDMode[lod] = lod_mode;
+    }
+
+    S32 limit = -1;
+    if (lod_mode == LIMIT_TRIANGLES)
+    {
+        limit = mFMP->childGetValue("lod_triangle_limit_" + lod_name[lod]).asInteger();
+        //convert from "scene wide" to "non-instanced" triangle limit
+        limit = (S32)((F32)limit*triangle_ratio);
+    }
+
+    // Glod regenerates vertex buffer at this stage
+
+    // Build models
+
+    S32 start = LLModel::LOD_HIGH;
+    S32 end = 0;
+    S32 decimation = 3;
+
+    if (lod != -1)
+    {
+        start  = lod;
+        end = lod;
+    }
+
+    mMaxTriangleLimit = base_triangle_count;
+
+    for (S32 lod = start; lod >= end; --lod)
+    {
+        if (lod == -1)
+        {
+            if (lod < start)
+            {
+                triangle_count /= decimation;
+            }
+        }
+        else
+        {
+            if (enforce_tri_limit)
+            {
+                triangle_count = limit;
+            }
+            else
+            {
+                for (S32 j = LLModel::LOD_HIGH; j > lod; --j)
+                {
+                    triangle_count /= decimation;
+                }
+            }
+        }
+
+        mModel[lod].clear();
+        mModel[lod].resize(mBaseModel.size());
+        mVertexBuffer[lod].clear();
+
+        mRequestedTriangleCount[lod] = (S32)((F32)triangle_count / triangle_ratio);
+        mRequestedErrorThreshold[lod] = lod_error_threshold;
+
+        for (U32 mdl_idx = 0; mdl_idx < mBaseModel.size(); ++mdl_idx)
+        {
+            LLModel* base = mBaseModel[mdl_idx];
+            
+            LLVolumeParams volume_params;
+            volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE);
+            mModel[lod][mdl_idx] = new LLModel(volume_params, 0.f);
+
+            std::string name = base->mLabel + getLodSuffix(lod);
+
+            mModel[lod][mdl_idx]->mLabel = name;
+            mModel[lod][mdl_idx]->mSubmodelID = base->mSubmodelID;
+            //mModel[lod][mdl_idx]->setNumVolumeFaces(   );
+
+            LLModel* target_model = mModel[lod][mdl_idx];
+
+
+            //
+            LLMeshOptimizer::simplifyModel(/*Some params*/);
+
+            //blind copy skin weights and just take closest skin weight to point on
+            //decimated mesh for now (auto-generating LODs with skin weights is still a bit
+            //of an open problem).
+            target_model->mPosition = base->mPosition;
+            target_model->mSkinWeights = base->mSkinWeights;
+            target_model->mSkinInfo = base->mSkinInfo;
+            //copy material list
+            target_model->mMaterialList = base->mMaterialList;
+
+            if (!validate_model(target_model))
+            {
+                LL_ERRS() << "Invalid model generated when creating LODs" << LL_ENDL;
+            }
+        }
+
+        //rebuild scene based on mBaseScene
+        mScene[lod].clear();
+        mScene[lod] = mBaseScene;
+
+        for (U32 i = 0; i < mBaseModel.size(); ++i)
+        {
+            LLModel* mdl = mBaseModel[i];
+            LLModel* target = mModel[lod][i];
+            if (target)
+            {
+                for (LLModelLoader::scene::iterator iter = mScene[lod].begin(); iter != mScene[lod].end(); ++iter)
+                {
+                    for (U32 j = 0; j < iter->second.size(); ++j)
+                    {
+                        if (iter->second[j].mModel == mdl)
+                        {
+                            iter->second[j].mModel = target;
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    mResourceCost = calcResourceCost();
+
+
+    LLMeshOptimizer::simplifyModel();
+    refresh();
+}
+
diff --git a/indra/newview/llmodelpreview.h b/indra/newview/llmodelpreview.h
index 3664a27a72..df66d79b7b 100644
--- a/indra/newview/llmodelpreview.h
+++ b/indra/newview/llmodelpreview.h
@@ -125,9 +125,16 @@ public:
     {
         LOD_FROM_FILE = 0,
         GENERATE,
+        MESH_OPTIMIZER,
         USE_LOD_ABOVE,
     } eLoDMode;
 
+    typedef enum
+    {
+        LIMIT_TRIANGLES = 0,
+        LIMIT_ERROR_TRESHOLD,
+    } eLoDLimit;
+
 public:
     // Todo: model preview shouldn't need floater dependency, it
     // should just expose data to floater, not control flaoter like it does
@@ -155,7 +162,7 @@ public:
     void loadModelCallback(S32 lod);
     bool lodsReady() { return !mGenLOD && mLodsQuery.empty(); }
     void queryLODs() { mGenLOD = true; };
-    void genLODs(S32 which_lod = -1, U32 decimation = 3, bool enforce_tri_limit = false);
+    void genGlodLODs(S32 which_lod = -1, U32 decimation = 3, bool enforce_tri_limit = false);
     void generateNormals();
     void restoreNormals();
     U32 calcResourceCost();
@@ -166,7 +173,8 @@ public:
     void updateStatusMessages();
     void updateLodControls(S32 lod);
     void clearGLODGroup();
-    void onLODParamCommit(S32 lod, bool enforce_tri_limit);
+    void onLODGenerateParamCommit(S32 lod, bool enforce_tri_limit);
+    void onLODMeshOptimizerParamCommit(S32 lod, bool enforce_tri_limit);
     void addEmptyFace(LLModel* pTarget);
 
     const bool getModelPivot(void) const { return mHasPivot; }
diff --git a/indra/newview/skins/default/xui/en/floater_model_preview.xml b/indra/newview/skins/default/xui/en/floater_model_preview.xml
index 7f863756eb..96bda42316 100644
--- a/indra/newview/skins/default/xui/en/floater_model_preview.xml
+++ b/indra/newview/skins/default/xui/en/floater_model_preview.xml
@@ -176,6 +176,10 @@
                  name="Generate"
                  label="Generate"
                  value="Generate" />
+                <item
+                 name="MeshOpt"
+                 label="MeshOpt"
+                 value="MeshOpt" />
             </combo_box>
             <line_editor
              follows="left|top"
@@ -305,6 +309,10 @@
                  name="Generate"
                  label="Generate"
                  value="Generate" />
+                <item
+                 name="MeshOpt"
+                 label="MeshOpt"
+                 value="MeshOpt" />
                 <item
                  name="Use LoD above"
                  label="Use LoD above"
@@ -438,6 +446,10 @@
                  name="Generate"
                  label="Generate"
                  value="Generate" />
+                <item
+                 name="MeshOpt"
+                 label="MeshOpt"
+                 value="MeshOpt" />
                 <item
                  name="Use LoD above"
                  label="Use LoD above"
@@ -571,6 +583,10 @@
                  name="Generate"
                  label="Generate"
                  value="Generate" />
+                <item
+                 name="MeshOpt"
+                 label="MeshOpt"
+                 value="MeshOpt" />
                 <item
                  name="Use LoD above"
                  label="Use LoD above"
-- 
cgit v1.2.3


From 1a17e19a610b598650624fb0ae3e67352f00e499 Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Thu, 8 Jul 2021 20:29:28 +0300
Subject: DRTVWR-542 WIP #2

---
 indra/cmake/CMakeLists.txt                |  1 +
 indra/cmake/MESHOPTIMIZER.cmake           |  8 ++++----
 indra/llmeshoptimizer/CMakeLists.txt      |  5 ++++-
 indra/llmeshoptimizer/llmeshoptimizer.cpp | 24 +++++++++++++++++++-----
 indra/llmeshoptimizer/llmeshoptimizer.h   | 12 +++++++++++-
 indra/newview/llmodelpreview.cpp          | 27 +++++++++++++++++++++++----
 6 files changed, 62 insertions(+), 15 deletions(-)

(limited to 'indra')

diff --git a/indra/cmake/CMakeLists.txt b/indra/cmake/CMakeLists.txt
index 7795aa7db1..527a9cba43 100644
--- a/indra/cmake/CMakeLists.txt
+++ b/indra/cmake/CMakeLists.txt
@@ -75,6 +75,7 @@ set(cmake_SOURCE_FILES
     LLXML.cmake
     Linking.cmake
     MediaPluginBase.cmake
+    MESHOPTIMIZER.cmake
     NDOF.cmake
     OPENAL.cmake
     OpenGL.cmake
diff --git a/indra/cmake/MESHOPTIMIZER.cmake b/indra/cmake/MESHOPTIMIZER.cmake
index 7600a56999..6a31dc5569 100644
--- a/indra/cmake/MESHOPTIMIZER.cmake
+++ b/indra/cmake/MESHOPTIMIZER.cmake
@@ -1,16 +1,16 @@
 # -*- cmake -*-
 
+include(Linking)
 include(Prebuilt)
 
 use_prebuilt_binary(meshoptimizer)
 
 if (WINDOWS)
-  set(MESHOPTIMIZER_LIBRARIES
-    debug meshoptimizer
-    optimized meshoptimizer)
+  set(MESHOPTIMIZER_LIBRARIES meshoptimizer.lib)
 elseif (LINUX)
-  set(MESHOPTIMIZER_LIBRARIES meshoptimizer)
+  set(MESHOPTIMIZER_LIBRARIES meshoptimizer.o)
 elseif (DARWIN)
   set(MESHOPTIMIZER_LIBRARIES libmeshoptimizer.o)
 endif (WINDOWS)
+
 set(MESHOPTIMIZER_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/include/meshoptimizer)
diff --git a/indra/llmeshoptimizer/CMakeLists.txt b/indra/llmeshoptimizer/CMakeLists.txt
index 1eea19de66..016794cfad 100644
--- a/indra/llmeshoptimizer/CMakeLists.txt
+++ b/indra/llmeshoptimizer/CMakeLists.txt
@@ -6,9 +6,11 @@ include(MESHOPTIMIZER)
 
 include(00-Common)
 include(LLCommon)
+include(LLMath)
 
 include_directories(
     ${LLCOMMON_INCLUDE_DIRS}
+    ${LLMATH_INCLUDE_DIRS}
     ${LLMESHOPTIMIZER_INCLUDE_DIR}
     ${MESHOPTIMIZER_INCLUDE_DIRS}
     ${LIBS_PREBUILT_DIR}/include  #access to boost headers, needed for LLError
@@ -34,7 +36,8 @@ list(APPEND llmeshoptimizer_SOURCE_FILES ${llmeshoptimizer_HEADER_FILES})
 
   target_link_libraries(llmeshoptimizer
     ${LLCOMMON_LIBRARIES}
-    ${MESHOPTIMIZER_LIBRARY})
+    ${LLMATH_LIBRARIES}
+    ${MESHOPTIMIZER_LIBRARIES})
   
   # Add tests
 
diff --git a/indra/llmeshoptimizer/llmeshoptimizer.cpp b/indra/llmeshoptimizer/llmeshoptimizer.cpp
index c46fa8dcf3..02e97ef984 100644
--- a/indra/llmeshoptimizer/llmeshoptimizer.cpp
+++ b/indra/llmeshoptimizer/llmeshoptimizer.cpp
@@ -28,7 +28,6 @@
 
 #include "meshoptimizer.h"
 
-
 LLMeshOptimizer::LLMeshOptimizer()
 {
     // Todo: Looks like for memory management, we can add allocator and deallocator callbacks
@@ -38,12 +37,27 @@ LLMeshOptimizer::LLMeshOptimizer()
 
 LLMeshOptimizer::~LLMeshOptimizer()
 {
-
 }
 
 //static
-U32 LLMeshOptimizer::simplifyModel()
+U64 LLMeshOptimizer::simplify(U16 *destination,
+                              const U16 *indices,
+                              U64 index_count,
+                              const LLVector4a *vertex_positions,
+                              U64 vertex_count,
+                              U64 target_index_count,
+                              F32 target_error,
+                              F32* result_error
+    )
 {
-    LL_WARNS() << "NOT IMPLEMENTED" << LL_ENDL;
-    return 0;
+    return meshopt_simplify<unsigned short>(destination,
+                                 indices,
+                                 index_count,
+                                 (const float*)vertex_positions, // verify that it is correct to convert to float
+                                 vertex_count,
+                                 sizeof(LLVector4a), // should be either 0 or 4
+                                 target_index_count,
+                                 target_error,
+                                 result_error
+                                 );
 }
diff --git a/indra/llmeshoptimizer/llmeshoptimizer.h b/indra/llmeshoptimizer/llmeshoptimizer.h
index d53ec2e24c..a0c53ed9e1 100644
--- a/indra/llmeshoptimizer/llmeshoptimizer.h
+++ b/indra/llmeshoptimizer/llmeshoptimizer.h
@@ -28,6 +28,8 @@
 
 #include "linden_common.h"
 
+#include "llmath.h"
+
 class LLMeshOptimizer
 {
 public:
@@ -35,7 +37,15 @@ public:
     ~LLMeshOptimizer();
 
     // returns state
-    static U32 simplifyModel();
+    static U64 simplify(
+        U16 *destination,
+        const U16 *indices,
+        U64 index_count,
+        const LLVector4a *vertex_positions,
+        U64 vertex_count,
+        U64 target_index_count,
+        F32 target_error,
+        F32* result_error);
 private:
 };
 
diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp
index a6eef74cdc..f23143e3fa 100644
--- a/indra/newview/llmodelpreview.cpp
+++ b/indra/newview/llmodelpreview.cpp
@@ -3705,13 +3705,33 @@ void LLModelPreview::onLODMeshOptimizerParamCommit(S32 lod, bool enforce_tri_lim
 
             mModel[lod][mdl_idx]->mLabel = name;
             mModel[lod][mdl_idx]->mSubmodelID = base->mSubmodelID;
-            //mModel[lod][mdl_idx]->setNumVolumeFaces(   );
+            mModel[lod][mdl_idx]->setNumVolumeFaces(base->getNumVolumeFaces());
 
             LLModel* target_model = mModel[lod][mdl_idx];
 
+            // Run meshoptimizer for each face
+            for (U32 face_idx = 0; face_idx < base->getNumVolumeFaces(); ++face_idx)
+            {
+                const LLVolumeFace &face = base->getVolumeFace(face_idx);
+                S32 num_indices = face.mNumIndices;
+                std::vector<U16> output(num_indices); //todo: do not allocate per each face, add one large buffer somewhere
+
+                // todo: run generateShadowIndexBuffer, at some stage, potentially inside simplify
+
+                F32 error_code = 0;
+                LLMeshOptimizer::simplify(&output[0],
+                                          &face.mIndices[0],
+                                          num_indices,
+                                          &face.mPositions[0],
+                                          face.mNumVertices,
+                                          triangle_count * 3, //todo: indices limit, not triangles limit*3
+                                          lod_error_threshold,
+                                          &error_code);
+
+                // todo: copy result into face
+            }
 
-            //
-            LLMeshOptimizer::simplifyModel(/*Some params*/);
+            LL_WARNS() << "WORK IN PROGRESS" << LL_ENDL;
 
             //blind copy skin weights and just take closest skin weight to point on
             //decimated mesh for now (auto-generating LODs with skin weights is still a bit
@@ -3755,7 +3775,6 @@ void LLModelPreview::onLODMeshOptimizerParamCommit(S32 lod, bool enforce_tri_lim
     mResourceCost = calcResourceCost();
 
 
-    LLMeshOptimizer::simplifyModel();
     refresh();
 }
 
-- 
cgit v1.2.3


From 6047b7c4383be53718fc72d7058a7435ccda7785 Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Fri, 9 Jul 2021 23:42:37 +0300
Subject: DRTVWR-542 WIP #3

First functional meshoptimizer
---
 indra/llmeshoptimizer/llmeshoptimizer.h |   3 +-
 indra/newview/llmodelpreview.cpp        | 180 ++++++++++++++++++--------------
 2 files changed, 101 insertions(+), 82 deletions(-)

(limited to 'indra')

diff --git a/indra/llmeshoptimizer/llmeshoptimizer.h b/indra/llmeshoptimizer/llmeshoptimizer.h
index a0c53ed9e1..157de0251d 100644
--- a/indra/llmeshoptimizer/llmeshoptimizer.h
+++ b/indra/llmeshoptimizer/llmeshoptimizer.h
@@ -36,7 +36,8 @@ public:
     LLMeshOptimizer();
     ~LLMeshOptimizer();
 
-    // returns state
+    // returns amount of indices in destiantion
+    // result_error returns how far from original the model is in % if not NULL
     static U64 simplify(
         U16 *destination,
         const U16 *indices,
diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp
index f23143e3fa..0cf44ca1cb 100644
--- a/indra/newview/llmodelpreview.cpp
+++ b/indra/newview/llmodelpreview.cpp
@@ -1404,7 +1404,7 @@ void LLModelPreview::genGlodLODs(S32 which_lod, U32 decimation, bool enforce_tri
 
     U32 type_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0;
 
-    U32 lod_mode = 0;
+    U32 lod_mode = LIMIT_TRIANGLES;
 
     F32 lod_error_threshold = 0;
 
@@ -3569,7 +3569,7 @@ void LLModelPreview::onLODGenerateParamCommit(S32 lod, bool enforce_tri_limit)
     }
 }
 
-void LLModelPreview::onLODMeshOptimizerParamCommit(S32 lod, bool enforce_tri_limit)
+void LLModelPreview::onLODMeshOptimizerParamCommit(S32 requested_lod, bool enforce_tri_limit)
 {
     if (mLODFrozen)
     {
@@ -3577,10 +3577,10 @@ void LLModelPreview::onLODMeshOptimizerParamCommit(S32 lod, bool enforce_tri_lim
     }
 
     // Allow LoD from -1 to LLModel::LOD_PHYSICS
-    if (lod < -1 || lod > LLModel::NUM_LODS - 1)
+    if (requested_lod < -1 || requested_lod > LLModel::NUM_LODS - 1)
     {
         std::ostringstream out;
-        out << "Invalid level of detail: " << lod;
+        out << "Invalid level of detail: " << requested_lod;
         LL_WARNS() << out.str() << LL_ENDL;
         LLFloaterModelPreview::addStringToLog(out, false);
         assert(lod >= -1 && lod < LLModel::NUM_LODS);
@@ -3592,106 +3592,108 @@ void LLModelPreview::onLODMeshOptimizerParamCommit(S32 lod, bool enforce_tri_lim
         return;
     }
 
-
-    U32 triangle_count = 0;
-    U32 instanced_triangle_count = 0;
-
-    //get the triangle count for the whole scene
-    for (LLModelLoader::scene::iterator iter = mBaseScene.begin(), endIter = mBaseScene.end(); iter != endIter; ++iter)
-    {
-        for (LLModelLoader::model_instance_list::iterator instance = iter->second.begin(), end_instance = iter->second.end(); instance != end_instance; ++instance)
-        {
-            LLModel* mdl = instance->mModel;
-            if (mdl)
-            {
-                instanced_triangle_count += mdl->getNumTriangles();
-            }
-        }
-    }
-
-    //get the triangle count for the non-instanced set of models
-    for (U32 i = 0; i < mBaseModel.size(); ++i)
+    //get the triangle count for all base models
+    S32 base_triangle_count = 0;
+    for (S32 i = 0; i < mBaseModel.size(); ++i)
     {
-        triangle_count += mBaseModel[i]->getNumTriangles();
+        base_triangle_count += mBaseModel[i]->getNumTriangles();
     }
 
-    //get ratio of uninstanced triangles to instanced triangles
-    F32 triangle_ratio = (F32)triangle_count / (F32)instanced_triangle_count;
-    U32 base_triangle_count = triangle_count;
-    U32 lod_mode = 0;
-    F32 lod_error_threshold = 0;
-
-
     // Urgh...
     // TODO: add interface to mFMP to get error treshold or let mFMP write one into LLModelPreview
     // We should not be accesing views from other class!
-    LLCtrlSelectionInterface* iface = mFMP->childGetSelectionInterface("lod_mode_" + lod_name[lod]);
-    if (iface)
+    U32 lod_mode = LIMIT_TRIANGLES;
+    F32 indices_ratio = 0;
+    F32 triangle_limit = 0;
+    F32 lod_error_threshold = 100;
+    F32 decimation = 3.f;
+
+    // If requesting a single lod
+    if (requested_lod > -1 && requested_lod < NUM_LOD)
     {
-        lod_mode = iface->getFirstSelectedIndex();
-    }
+        LLCtrlSelectionInterface* iface = mFMP->childGetSelectionInterface("lod_mode_" + lod_name[requested_lod]);
+        if (iface)
+        {
+            lod_mode = iface->getFirstSelectedIndex();
+        }
 
-    lod_error_threshold = mFMP->childGetValue("lod_error_threshold_" + lod_name[lod]).asReal();
+        if (lod_mode == LIMIT_TRIANGLES)
+        {
+            if (!enforce_tri_limit && lod_mode == LIMIT_TRIANGLES)
+            {
+                triangle_limit = base_triangle_count;
+                // reset to default value for this lod
+                for (S32 j = LLModel::LOD_HIGH; j > requested_lod; --j)
+                {
+                    triangle_limit /= decimation;
+                    indices_ratio /= decimation;
+                }
+            }
+            else
+            {
+                // meshoptimizer doesn't use triangle limit, it uses indices limit, so convert it to ratio
 
-    if (lod != -1)
-    {
-        mRequestedLoDMode[lod] = lod_mode;
-    }
+                // UI spacifies limit for all models of single lod
+                triangle_limit = mFMP->childGetValue("lod_triangle_limit_" + lod_name[requested_lod]).asInteger();
 
-    S32 limit = -1;
-    if (lod_mode == LIMIT_TRIANGLES)
+                // calculate aproximate ratio
+                indices_ratio = (F32)triangle_limit / (F32)base_triangle_count;
+            }
+        }
+        else
+        {
+            lod_error_threshold = mFMP->childGetValue("lod_error_threshold_" + lod_name[requested_lod]).asReal();
+        }
+    }
+    else
     {
-        limit = mFMP->childGetValue("lod_triangle_limit_" + lod_name[lod]).asInteger();
-        //convert from "scene wide" to "non-instanced" triangle limit
-        limit = (S32)((F32)limit*triangle_ratio);
+        // we are genrating all lods and each lod will get own indices_ratio
+        indices_ratio = 1;
+        triangle_limit = base_triangle_count;
     }
 
-    // Glod regenerates vertex buffer at this stage
+    mMaxTriangleLimit = base_triangle_count;
+
+    // TODO: Glod regenerates vertex buffer at this stage
+    // check why, it might be needed to regenerate buffer as well
 
     // Build models
 
     S32 start = LLModel::LOD_HIGH;
     S32 end = 0;
-    S32 decimation = 3;
 
-    if (lod != -1)
+    if (requested_lod != -1)
     {
-        start  = lod;
-        end = lod;
+        start  = requested_lod;
+        end = requested_lod;
     }
 
-    mMaxTriangleLimit = base_triangle_count;
+    LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
+    if (shader)
+    {
+        shader->unbind();
+    }
 
     for (S32 lod = start; lod >= end; --lod)
     {
-        if (lod == -1)
+        if (requested_lod == -1)
         {
+            // we are genrating all lods and each lod gets own indices_ratio
             if (lod < start)
             {
-                triangle_count /= decimation;
-            }
-        }
-        else
-        {
-            if (enforce_tri_limit)
-            {
-                triangle_count = limit;
-            }
-            else
-            {
-                for (S32 j = LLModel::LOD_HIGH; j > lod; --j)
-                {
-                    triangle_count /= decimation;
-                }
+                indices_ratio /= decimation;
+                triangle_limit /= decimation;
             }
         }
 
+        mRequestedTriangleCount[lod] = triangle_limit;
+        mRequestedErrorThreshold[lod] = lod_error_threshold;
+        mRequestedLoDMode[requested_lod] = lod_mode;
+
         mModel[lod].clear();
         mModel[lod].resize(mBaseModel.size());
         mVertexBuffer[lod].clear();
 
-        mRequestedTriangleCount[lod] = (S32)((F32)triangle_count / triangle_ratio);
-        mRequestedErrorThreshold[lod] = lod_error_threshold;
 
         for (U32 mdl_idx = 0; mdl_idx < mBaseModel.size(); ++mdl_idx)
         {
@@ -3718,20 +3720,30 @@ void LLModelPreview::onLODMeshOptimizerParamCommit(S32 lod, bool enforce_tri_lim
 
                 // todo: run generateShadowIndexBuffer, at some stage, potentially inside simplify
 
-                F32 error_code = 0;
-                LLMeshOptimizer::simplify(&output[0],
-                                          &face.mIndices[0],
-                                          num_indices,
-                                          &face.mPositions[0],
-                                          face.mNumVertices,
-                                          triangle_count * 3, //todo: indices limit, not triangles limit*3
-                                          lod_error_threshold,
-                                          &error_code);
+                F32 result_code = 0; // how far from original the model is
+                S32 new_indices = LLMeshOptimizer::simplify(&output[0],
+                                                            face.mIndices,
+                                                            num_indices,
+                                                            &face.mPositions[0],
+                                                            face.mNumVertices,
+                                                            num_indices * indices_ratio,
+                                                            lod_error_threshold,
+                                                            &result_code);
 
-                // todo: copy result into face
-            }
+                LLVolumeFace &new_face = target_model->getVolumeFace(face_idx);
+
+                // Copy old values
+                // todo: no point copying faces?
+                new_face = face;
 
-            LL_WARNS() << "WORK IN PROGRESS" << LL_ENDL;
+                // Assign new values
+                S32 idx_size = (new_indices * sizeof(U16) + 0xF) & ~0xF;
+                LLVector4a::memcpyNonAliased16((F32*)new_face.mIndices, (F32*)(&output[0]), idx_size);
+                new_face.mNumIndices = new_indices;
+
+                // clear unused values
+                new_face.optimize();
+            }
 
             //blind copy skin weights and just take closest skin weight to point on
             //decimated mesh for now (auto-generating LODs with skin weights is still a bit
@@ -3739,6 +3751,7 @@ void LLModelPreview::onLODMeshOptimizerParamCommit(S32 lod, bool enforce_tri_lim
             target_model->mPosition = base->mPosition;
             target_model->mSkinWeights = base->mSkinWeights;
             target_model->mSkinInfo = base->mSkinInfo;
+
             //copy material list
             target_model->mMaterialList = base->mMaterialList;
 
@@ -3774,6 +3787,11 @@ void LLModelPreview::onLODMeshOptimizerParamCommit(S32 lod, bool enforce_tri_lim
 
     mResourceCost = calcResourceCost();
 
+    LLVertexBuffer::unbind();
+    if (shader)
+    {
+        shader->bind();
+    }
 
     refresh();
 }
-- 
cgit v1.2.3


From 17131ac20336b5561b574a9c121c6a5876be2d53 Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Sun, 11 Jul 2021 22:39:30 +0300
Subject: DRTVWR-542 WIP #4

Made meshoptimizer into default generation mechanism
Ensured that at least one triangle will remain of any face
---
 indra/newview/llfloatermodelpreview.cpp |   4 +-
 indra/newview/llmodelpreview.cpp        | 460 +++++++++++++++++---------------
 indra/newview/llmodelpreview.h          |   1 +
 3 files changed, 241 insertions(+), 224 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp
index d8f3021fb2..85250abefc 100644
--- a/indra/newview/llfloatermodelpreview.cpp
+++ b/indra/newview/llfloatermodelpreview.cpp
@@ -139,7 +139,7 @@ mAvatarTabIndex(0)
 	mLODMode[LLModel::LOD_HIGH] = 0;
 	for (U32 i = 0; i < LLModel::LOD_HIGH; i++)
 	{
-		mLODMode[i] = 1;
+		mLODMode[i] = LLModelPreview::MESH_OPTIMIZER;
 	}
 }
 
@@ -1767,7 +1767,7 @@ void LLFloaterModelPreview::resetUploadOptions()
 	getChild<LLComboBox>("lod_source_" + lod_name[NUM_LOD - 1])->setCurrentByIndex(LLModelPreview::LOD_FROM_FILE);
 	for (S32 lod = 0; lod < NUM_LOD - 1; ++lod)
 	{
-		getChild<LLComboBox>("lod_source_" + lod_name[lod])->setCurrentByIndex(LLModelPreview::GENERATE);
+		getChild<LLComboBox>("lod_source_" + lod_name[lod])->setCurrentByIndex(LLModelPreview::MESH_OPTIMIZER);
 		childSetValue("lod_file_" + lod_name[lod], "");
 	}
 
diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp
index 0cf44ca1cb..27341eff3c 100644
--- a/indra/newview/llmodelpreview.cpp
+++ b/indra/newview/llmodelpreview.cpp
@@ -1342,6 +1342,7 @@ void LLModelPreview::restoreNormals()
 
 void LLModelPreview::genGlodLODs(S32 which_lod, U32 decimation, bool enforce_tri_limit)
 {
+    LL_INFOS() << "Generating lod " << which_lod << " using glod" << LL_ENDL;
     // Allow LoD from -1 to LLModel::LOD_PHYSICS
     if (which_lod < -1 || which_lod > LLModel::NUM_LODS - 1)
     {
@@ -1705,6 +1706,239 @@ void LLModelPreview::genGlodLODs(S32 which_lod, U32 decimation, bool enforce_tri
     }
 }
 
+void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, U32 decimation, bool enforce_tri_limit)
+{
+    LL_INFOS() << "Generating lod " << which_lod << " using meshoptimizer" << LL_ENDL;
+    // Allow LoD from -1 to LLModel::LOD_PHYSICS
+    if (which_lod < -1 || which_lod > LLModel::NUM_LODS - 1)
+    {
+        std::ostringstream out;
+        out << "Invalid level of detail: " << which_lod;
+        LL_WARNS() << out.str() << LL_ENDL;
+        LLFloaterModelPreview::addStringToLog(out, false);
+        assert(lod >= -1 && lod < LLModel::NUM_LODS);
+        return;
+    }
+
+    if (mBaseModel.empty())
+    {
+        return;
+    }
+
+    //get the triangle count for all base models
+    S32 base_triangle_count = 0;
+    for (S32 i = 0; i < mBaseModel.size(); ++i)
+    {
+        base_triangle_count += mBaseModel[i]->getNumTriangles();
+    }
+
+    // Urgh...
+    // TODO: add interface to mFMP to get error treshold or let mFMP write one into LLModelPreview
+    // We should not be accesing views from other class!
+    U32 lod_mode = LIMIT_TRIANGLES;
+    F32 indices_ratio = 0;
+    F32 triangle_limit = 0;
+    F32 lod_error_threshold = 1; //100%
+
+    // If requesting a single lod
+    if (which_lod > -1 && which_lod < NUM_LOD)
+    {
+        LLCtrlSelectionInterface* iface = mFMP->childGetSelectionInterface("lod_mode_" + lod_name[which_lod]);
+        if (iface)
+        {
+            lod_mode = iface->getFirstSelectedIndex();
+        }
+
+        if (lod_mode == LIMIT_TRIANGLES)
+        {
+            if (!enforce_tri_limit)
+            {
+                triangle_limit = base_triangle_count;
+                // reset to default value for this lod
+                F32 pw = pow((F32)decimation, (F32)(LLModel::LOD_HIGH - which_lod));
+
+                triangle_limit /= pw; //indices_ratio can be 1/pw
+            }
+            else
+            {
+
+                // UI spacifies limit for all models of single lod
+                triangle_limit = mFMP->childGetValue("lod_triangle_limit_" + lod_name[which_lod]).asInteger();
+
+            }
+            // meshoptimizer doesn't use triangle limit, it uses indices limit, so convert it to aproximate ratio
+            indices_ratio = (F32)triangle_limit / (F32)base_triangle_count;
+        }
+        else
+        {
+            lod_error_threshold = mFMP->childGetValue("lod_error_threshold_" + lod_name[which_lod]).asReal();
+        }
+    }
+    else
+    {
+        // we are genrating all lods and each lod will get own indices_ratio
+        indices_ratio = 1;
+        triangle_limit = base_triangle_count;
+    }
+
+    mMaxTriangleLimit = base_triangle_count;
+
+    // TODO: Glod regenerates vertex buffer at this stage
+    // check why, it might be needed to regenerate buffer as well
+
+    // Build models
+
+    S32 start = LLModel::LOD_HIGH;
+    S32 end = 0;
+
+    if (which_lod != -1)
+    {
+        start = which_lod;
+        end = which_lod;
+    }
+
+    LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
+    if (shader)
+    {
+        shader->unbind();
+    }
+
+    for (S32 lod = start; lod >= end; --lod)
+    {
+        if (which_lod == -1)
+        {
+            // we are genrating all lods and each lod gets own indices_ratio
+            if (lod < start)
+            {
+                indices_ratio /= decimation;
+                triangle_limit /= decimation;
+            }
+        }
+
+        mRequestedTriangleCount[lod] = triangle_limit;
+        mRequestedErrorThreshold[lod] = lod_error_threshold;
+        mRequestedLoDMode[lod] = lod_mode;
+
+        mModel[lod].clear();
+        mModel[lod].resize(mBaseModel.size());
+        mVertexBuffer[lod].clear();
+
+
+        for (U32 mdl_idx = 0; mdl_idx < mBaseModel.size(); ++mdl_idx)
+        {
+            LLModel* base = mBaseModel[mdl_idx];
+
+            LLVolumeParams volume_params;
+            volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE);
+            mModel[lod][mdl_idx] = new LLModel(volume_params, 0.f);
+
+            std::string name = base->mLabel + getLodSuffix(lod);
+
+            mModel[lod][mdl_idx]->mLabel = name;
+            mModel[lod][mdl_idx]->mSubmodelID = base->mSubmodelID;
+            mModel[lod][mdl_idx]->setNumVolumeFaces(base->getNumVolumeFaces());
+
+            LLModel* target_model = mModel[lod][mdl_idx];
+
+            // Run meshoptimizer for each face
+            for (U32 face_idx = 0; face_idx < base->getNumVolumeFaces(); ++face_idx)
+            {
+                const LLVolumeFace &face = base->getVolumeFace(face_idx);
+                S32 num_indices = face.mNumIndices;
+                std::vector<U16> output(num_indices); //todo: do not allocate per each face, add one large buffer somewhere
+
+                // todo: run generateShadowIndexBuffer, at some stage, potentially inside simplify
+
+                F32 target_indices = llmax((F32)3, num_indices * indices_ratio); // leave at least one triangle
+                F32 result_code = 0; // how far from original the model is
+                S32 new_indices = LLMeshOptimizer::simplify(&output[0],
+                    face.mIndices,
+                    num_indices,
+                    &face.mPositions[0],
+                    face.mNumVertices,
+                    target_indices,
+                    lod_error_threshold,
+                    &result_code);
+
+                if (result_code < 0)
+                {
+                    LL_WARNS() << "Negative result from meshoptimizer" << LL_ENDL;
+                }
+
+                LLVolumeFace &new_face = target_model->getVolumeFace(face_idx);
+
+                // Copy old values
+                // todo: no point copying faces?
+                new_face = face;
+
+                if (new_indices == 0)
+                {
+                    LL_WARNS() << "No indices generated for face " << face_idx
+                               << " of model " << target_model->mLabel
+                               << " target Indices: " << target_indices
+                               << " original count: "  << num_indices << LL_ENDL;
+                }
+                else
+                {
+                    // Assign new values
+                    S32 idx_size = (new_indices * sizeof(U16) + 0xF) & ~0xF;
+                    LLVector4a::memcpyNonAliased16((F32*)new_face.mIndices, (F32*)(&output[0]), idx_size);
+                    new_face.mNumIndices = new_indices;
+
+                    // clear unused values
+                    new_face.optimize();
+                }
+            }
+
+            //blind copy skin weights and just take closest skin weight to point on
+            //decimated mesh for now (auto-generating LODs with skin weights is still a bit
+            //of an open problem).
+            target_model->mPosition = base->mPosition;
+            target_model->mSkinWeights = base->mSkinWeights;
+            target_model->mSkinInfo = base->mSkinInfo;
+
+            //copy material list
+            target_model->mMaterialList = base->mMaterialList;
+
+            if (!validate_model(target_model))
+            {
+                LL_ERRS() << "Invalid model generated when creating LODs" << LL_ENDL;
+            }
+        }
+
+        //rebuild scene based on mBaseScene
+        mScene[lod].clear();
+        mScene[lod] = mBaseScene;
+
+        for (U32 i = 0; i < mBaseModel.size(); ++i)
+        {
+            LLModel* mdl = mBaseModel[i];
+            LLModel* target = mModel[lod][i];
+            if (target)
+            {
+                for (LLModelLoader::scene::iterator iter = mScene[lod].begin(); iter != mScene[lod].end(); ++iter)
+                {
+                    for (U32 j = 0; j < iter->second.size(); ++j)
+                    {
+                        if (iter->second[j].mModel == mdl)
+                        {
+                            iter->second[j].mModel = target;
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    mResourceCost = calcResourceCost();
+
+    LLVertexBuffer::unbind();
+    if (shader)
+    {
+        shader->bind();
+    }
+}
+
 void LLModelPreview::updateStatusMessages()
 {
     // bit mask values for physics errors. used to prevent overwrite of single line status
@@ -3545,7 +3779,7 @@ bool LLModelPreview::lodQueryCallback()
         {
             S32 lod = preview->mLodsQuery.back();
             preview->mLodsQuery.pop_back();
-            preview->genGlodLODs(lod);
+            preview->genMeshOptimizerLODs(lod);
 
             if (preview->mLookUpLodFiles && (lod == LLModel::LOD_HIGH))
             {
@@ -3571,228 +3805,10 @@ void LLModelPreview::onLODGenerateParamCommit(S32 lod, bool enforce_tri_limit)
 
 void LLModelPreview::onLODMeshOptimizerParamCommit(S32 requested_lod, bool enforce_tri_limit)
 {
-    if (mLODFrozen)
-    {
-        return;
-    }
-
-    // Allow LoD from -1 to LLModel::LOD_PHYSICS
-    if (requested_lod < -1 || requested_lod > LLModel::NUM_LODS - 1)
-    {
-        std::ostringstream out;
-        out << "Invalid level of detail: " << requested_lod;
-        LL_WARNS() << out.str() << LL_ENDL;
-        LLFloaterModelPreview::addStringToLog(out, false);
-        assert(lod >= -1 && lod < LLModel::NUM_LODS);
-        return;
-    }
-
-    if (mBaseModel.empty())
-    {
-        return;
-    }
-
-    //get the triangle count for all base models
-    S32 base_triangle_count = 0;
-    for (S32 i = 0; i < mBaseModel.size(); ++i)
-    {
-        base_triangle_count += mBaseModel[i]->getNumTriangles();
-    }
-
-    // Urgh...
-    // TODO: add interface to mFMP to get error treshold or let mFMP write one into LLModelPreview
-    // We should not be accesing views from other class!
-    U32 lod_mode = LIMIT_TRIANGLES;
-    F32 indices_ratio = 0;
-    F32 triangle_limit = 0;
-    F32 lod_error_threshold = 100;
-    F32 decimation = 3.f;
-
-    // If requesting a single lod
-    if (requested_lod > -1 && requested_lod < NUM_LOD)
-    {
-        LLCtrlSelectionInterface* iface = mFMP->childGetSelectionInterface("lod_mode_" + lod_name[requested_lod]);
-        if (iface)
-        {
-            lod_mode = iface->getFirstSelectedIndex();
-        }
-
-        if (lod_mode == LIMIT_TRIANGLES)
-        {
-            if (!enforce_tri_limit && lod_mode == LIMIT_TRIANGLES)
-            {
-                triangle_limit = base_triangle_count;
-                // reset to default value for this lod
-                for (S32 j = LLModel::LOD_HIGH; j > requested_lod; --j)
-                {
-                    triangle_limit /= decimation;
-                    indices_ratio /= decimation;
-                }
-            }
-            else
-            {
-                // meshoptimizer doesn't use triangle limit, it uses indices limit, so convert it to ratio
-
-                // UI spacifies limit for all models of single lod
-                triangle_limit = mFMP->childGetValue("lod_triangle_limit_" + lod_name[requested_lod]).asInteger();
-
-                // calculate aproximate ratio
-                indices_ratio = (F32)triangle_limit / (F32)base_triangle_count;
-            }
-        }
-        else
-        {
-            lod_error_threshold = mFMP->childGetValue("lod_error_threshold_" + lod_name[requested_lod]).asReal();
-        }
-    }
-    else
-    {
-        // we are genrating all lods and each lod will get own indices_ratio
-        indices_ratio = 1;
-        triangle_limit = base_triangle_count;
-    }
-
-    mMaxTriangleLimit = base_triangle_count;
-
-    // TODO: Glod regenerates vertex buffer at this stage
-    // check why, it might be needed to regenerate buffer as well
-
-    // Build models
-
-    S32 start = LLModel::LOD_HIGH;
-    S32 end = 0;
-
-    if (requested_lod != -1)
-    {
-        start  = requested_lod;
-        end = requested_lod;
-    }
-
-    LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
-    if (shader)
-    {
-        shader->unbind();
-    }
-
-    for (S32 lod = start; lod >= end; --lod)
-    {
-        if (requested_lod == -1)
-        {
-            // we are genrating all lods and each lod gets own indices_ratio
-            if (lod < start)
-            {
-                indices_ratio /= decimation;
-                triangle_limit /= decimation;
-            }
-        }
-
-        mRequestedTriangleCount[lod] = triangle_limit;
-        mRequestedErrorThreshold[lod] = lod_error_threshold;
-        mRequestedLoDMode[requested_lod] = lod_mode;
-
-        mModel[lod].clear();
-        mModel[lod].resize(mBaseModel.size());
-        mVertexBuffer[lod].clear();
-
-
-        for (U32 mdl_idx = 0; mdl_idx < mBaseModel.size(); ++mdl_idx)
-        {
-            LLModel* base = mBaseModel[mdl_idx];
-            
-            LLVolumeParams volume_params;
-            volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE);
-            mModel[lod][mdl_idx] = new LLModel(volume_params, 0.f);
-
-            std::string name = base->mLabel + getLodSuffix(lod);
-
-            mModel[lod][mdl_idx]->mLabel = name;
-            mModel[lod][mdl_idx]->mSubmodelID = base->mSubmodelID;
-            mModel[lod][mdl_idx]->setNumVolumeFaces(base->getNumVolumeFaces());
-
-            LLModel* target_model = mModel[lod][mdl_idx];
-
-            // Run meshoptimizer for each face
-            for (U32 face_idx = 0; face_idx < base->getNumVolumeFaces(); ++face_idx)
-            {
-                const LLVolumeFace &face = base->getVolumeFace(face_idx);
-                S32 num_indices = face.mNumIndices;
-                std::vector<U16> output(num_indices); //todo: do not allocate per each face, add one large buffer somewhere
-
-                // todo: run generateShadowIndexBuffer, at some stage, potentially inside simplify
-
-                F32 result_code = 0; // how far from original the model is
-                S32 new_indices = LLMeshOptimizer::simplify(&output[0],
-                                                            face.mIndices,
-                                                            num_indices,
-                                                            &face.mPositions[0],
-                                                            face.mNumVertices,
-                                                            num_indices * indices_ratio,
-                                                            lod_error_threshold,
-                                                            &result_code);
-
-                LLVolumeFace &new_face = target_model->getVolumeFace(face_idx);
-
-                // Copy old values
-                // todo: no point copying faces?
-                new_face = face;
-
-                // Assign new values
-                S32 idx_size = (new_indices * sizeof(U16) + 0xF) & ~0xF;
-                LLVector4a::memcpyNonAliased16((F32*)new_face.mIndices, (F32*)(&output[0]), idx_size);
-                new_face.mNumIndices = new_indices;
-
-                // clear unused values
-                new_face.optimize();
-            }
-
-            //blind copy skin weights and just take closest skin weight to point on
-            //decimated mesh for now (auto-generating LODs with skin weights is still a bit
-            //of an open problem).
-            target_model->mPosition = base->mPosition;
-            target_model->mSkinWeights = base->mSkinWeights;
-            target_model->mSkinInfo = base->mSkinInfo;
-
-            //copy material list
-            target_model->mMaterialList = base->mMaterialList;
-
-            if (!validate_model(target_model))
-            {
-                LL_ERRS() << "Invalid model generated when creating LODs" << LL_ENDL;
-            }
-        }
-
-        //rebuild scene based on mBaseScene
-        mScene[lod].clear();
-        mScene[lod] = mBaseScene;
-
-        for (U32 i = 0; i < mBaseModel.size(); ++i)
-        {
-            LLModel* mdl = mBaseModel[i];
-            LLModel* target = mModel[lod][i];
-            if (target)
-            {
-                for (LLModelLoader::scene::iterator iter = mScene[lod].begin(); iter != mScene[lod].end(); ++iter)
-                {
-                    for (U32 j = 0; j < iter->second.size(); ++j)
-                    {
-                        if (iter->second[j].mModel == mdl)
-                        {
-                            iter->second[j].mModel = target;
-                        }
-                    }
-                }
-            }
-        }
-    }
-
-    mResourceCost = calcResourceCost();
-
-    LLVertexBuffer::unbind();
-    if (shader)
+    if (!mLODFrozen)
     {
-        shader->bind();
+        genMeshOptimizerLODs(requested_lod, 3, enforce_tri_limit);
+        refresh();
     }
-
-    refresh();
 }
 
diff --git a/indra/newview/llmodelpreview.h b/indra/newview/llmodelpreview.h
index df66d79b7b..f6f4ce580d 100644
--- a/indra/newview/llmodelpreview.h
+++ b/indra/newview/llmodelpreview.h
@@ -163,6 +163,7 @@ public:
     bool lodsReady() { return !mGenLOD && mLodsQuery.empty(); }
     void queryLODs() { mGenLOD = true; };
     void genGlodLODs(S32 which_lod = -1, U32 decimation = 3, bool enforce_tri_limit = false);
+    void genMeshOptimizerLODs(S32 which_lod = -1, U32 decimation = 3, bool enforce_tri_limit = false);
     void generateNormals();
     void restoreNormals();
     U32 calcResourceCost();
-- 
cgit v1.2.3


From eb13133e3e0020c73399414cea4d9b39ef526cd3 Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Mon, 12 Jul 2021 16:47:45 +0300
Subject: DRTVWR-542 WIP #5

---
 indra/cmake/MESHOPTIMIZER.cmake           |  2 +-
 indra/llmeshoptimizer/llmeshoptimizer.cpp |  7 ++++++-
 indra/newview/llmodelpreview.cpp          | 23 ++++++++++-------------
 3 files changed, 17 insertions(+), 15 deletions(-)

(limited to 'indra')

diff --git a/indra/cmake/MESHOPTIMIZER.cmake b/indra/cmake/MESHOPTIMIZER.cmake
index 6a31dc5569..1c5b47b9bd 100644
--- a/indra/cmake/MESHOPTIMIZER.cmake
+++ b/indra/cmake/MESHOPTIMIZER.cmake
@@ -10,7 +10,7 @@ if (WINDOWS)
 elseif (LINUX)
   set(MESHOPTIMIZER_LIBRARIES meshoptimizer.o)
 elseif (DARWIN)
-  set(MESHOPTIMIZER_LIBRARIES libmeshoptimizer.o)
+  set(MESHOPTIMIZER_LIBRARIES libmeshoptimizer.a)
 endif (WINDOWS)
 
 set(MESHOPTIMIZER_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/include/meshoptimizer)
diff --git a/indra/llmeshoptimizer/llmeshoptimizer.cpp b/indra/llmeshoptimizer/llmeshoptimizer.cpp
index 02e97ef984..dbf8e5b631 100644
--- a/indra/llmeshoptimizer/llmeshoptimizer.cpp
+++ b/indra/llmeshoptimizer/llmeshoptimizer.cpp
@@ -50,12 +50,17 @@ U64 LLMeshOptimizer::simplify(U16 *destination,
                               F32* result_error
     )
 {
+    const size_t vertex_stride = 4; // should be either 0 or 4
+
+    // Consider running meshopt_generateShadowIndexBuffer<unsigned short> first.
+    // meshopt_generateShadowIndexBuffer is only needed if models don't use some of the vertices,
+    // but since we call optimize() in a lot of cases, it likely isn't needed
     return meshopt_simplify<unsigned short>(destination,
                                  indices,
                                  index_count,
                                  (const float*)vertex_positions, // verify that it is correct to convert to float
                                  vertex_count,
-                                 sizeof(LLVector4a), // should be either 0 or 4
+                                 vertex_stride, 
                                  target_index_count,
                                  target_error,
                                  result_error
diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp
index 27341eff3c..5eb49ee938 100644
--- a/indra/newview/llmodelpreview.cpp
+++ b/indra/newview/llmodelpreview.cpp
@@ -1767,7 +1767,7 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, U32 decimation, bool en
 
             }
             // meshoptimizer doesn't use triangle limit, it uses indices limit, so convert it to aproximate ratio
-            indices_ratio = (F32)triangle_limit / (F32)base_triangle_count;
+            indices_ratio = triangle_limit / (F32)base_triangle_count;
         }
         else
         {
@@ -1849,7 +1849,7 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, U32 decimation, bool en
 
                 // todo: run generateShadowIndexBuffer, at some stage, potentially inside simplify
 
-                F32 target_indices = llmax((F32)3, num_indices * indices_ratio); // leave at least one triangle
+                S32 target_indices = llmax(3, llfloor(num_indices * indices_ratio)); // leave at least one triangle
                 F32 result_code = 0; // how far from original the model is
                 S32 new_indices = LLMeshOptimizer::simplify(&output[0],
                     face.mIndices,
@@ -1868,9 +1868,16 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, U32 decimation, bool en
                 LLVolumeFace &new_face = target_model->getVolumeFace(face_idx);
 
                 // Copy old values
-                // todo: no point copying faces?
                 new_face = face;
 
+                // Assign new values
+                S32 idx_size = (new_indices * sizeof(U16) + 0xF) & ~0xF;
+                LLVector4a::memcpyNonAliased16((F32*)new_face.mIndices, (F32*)(&output[0]), idx_size);
+                new_face.mNumIndices = new_indices;
+
+                // clear unused values
+                new_face.optimize();
+
                 if (new_indices == 0)
                 {
                     LL_WARNS() << "No indices generated for face " << face_idx
@@ -1878,16 +1885,6 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, U32 decimation, bool en
                                << " target Indices: " << target_indices
                                << " original count: "  << num_indices << LL_ENDL;
                 }
-                else
-                {
-                    // Assign new values
-                    S32 idx_size = (new_indices * sizeof(U16) + 0xF) & ~0xF;
-                    LLVector4a::memcpyNonAliased16((F32*)new_face.mIndices, (F32*)(&output[0]), idx_size);
-                    new_face.mNumIndices = new_indices;
-
-                    // clear unused values
-                    new_face.optimize();
-                }
             }
 
             //blind copy skin weights and just take closest skin weight to point on
-- 
cgit v1.2.3


From 938969c811732a3e2faf0229301de286bd12c1a5 Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Mon, 12 Jul 2021 19:18:25 +0300
Subject: DRTVWR-542 WIP #6

Trying out 'sloppy' variant
---
 indra/llmeshoptimizer/llmeshoptimizer.cpp          | 24 +++++++++++++
 indra/llmeshoptimizer/llmeshoptimizer.h            | 12 +++++++
 indra/newview/llfloatermodelpreview.cpp            |  8 +++--
 indra/newview/llmodelpreview.cpp                   | 42 ++++++++++++++++------
 indra/newview/llmodelpreview.h                     |  5 +--
 .../skins/default/xui/en/floater_model_preview.xml | 16 +++++++++
 6 files changed, 92 insertions(+), 15 deletions(-)

(limited to 'indra')

diff --git a/indra/llmeshoptimizer/llmeshoptimizer.cpp b/indra/llmeshoptimizer/llmeshoptimizer.cpp
index dbf8e5b631..2f3d2491c2 100644
--- a/indra/llmeshoptimizer/llmeshoptimizer.cpp
+++ b/indra/llmeshoptimizer/llmeshoptimizer.cpp
@@ -66,3 +66,27 @@ U64 LLMeshOptimizer::simplify(U16 *destination,
                                  result_error
                                  );
 }
+
+//static
+U64 LLMeshOptimizer::simplifySloppy(U16 *destination,
+                              const U16 *indices,
+                              U64 index_count,
+                              const LLVector4a *vertex_positions,
+                              U64 vertex_count,
+                              U64 target_index_count,
+                              F32 target_error,
+                              F32* result_error
+    )
+{
+    const size_t vertex_stride = 4; // should be either 0 or 4
+    return meshopt_simplifySloppy<unsigned short>(destination,
+                                 indices,
+                                 index_count,
+                                 (const float*)vertex_positions, // verify that it is correct to convert to float
+                                 vertex_count,
+                                 vertex_stride, 
+                                 target_index_count,
+                                 target_error,
+                                 result_error
+                                 );
+}
diff --git a/indra/llmeshoptimizer/llmeshoptimizer.h b/indra/llmeshoptimizer/llmeshoptimizer.h
index 157de0251d..c4250c537d 100644
--- a/indra/llmeshoptimizer/llmeshoptimizer.h
+++ b/indra/llmeshoptimizer/llmeshoptimizer.h
@@ -47,6 +47,18 @@ public:
         U64 target_index_count,
         F32 target_error,
         F32* result_error);
+
+    // returns amount of indices in destiantion
+    // result_error returns how far from original the model is in % if not NULL
+    static U64 simplifySloppy(
+        U16 *destination,
+        const U16 *indices,
+        U64 index_count,
+        const LLVector4a *vertex_positions,
+        U64 vertex_count,
+        U64 target_index_count,
+        F32 target_error,
+        F32* result_error);
 private:
 };
 
diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp
index 85250abefc..d61311d610 100644
--- a/indra/newview/llfloatermodelpreview.cpp
+++ b/indra/newview/llfloatermodelpreview.cpp
@@ -730,7 +730,10 @@ void LLFloaterModelPreview::onLODParamCommit(S32 lod, bool enforce_tri_limit)
         mModelPreview->onLODGenerateParamCommit(lod, enforce_tri_limit);
         break;
     case LLModelPreview::MESH_OPTIMIZER:
-        mModelPreview->onLODMeshOptimizerParamCommit(lod, enforce_tri_limit);
+        mModelPreview->onLODMeshOptimizerParamCommit(lod, enforce_tri_limit, false);
+        break;
+    case LLModelPreview::MESH_OPTIMIZER_SLOPPY:
+        mModelPreview->onLODMeshOptimizerParamCommit(lod, enforce_tri_limit, true);
         break;
     default:
         LL_ERRS() << "Only supposed to be called to generate models" << LL_ENDL;
@@ -1736,7 +1739,8 @@ void LLFloaterModelPreview::onLoDSourceCommit(S32 lod)
 	LLComboBox* lod_source_combo = getChild<LLComboBox>("lod_source_" + lod_name[lod]);
     S32 index = lod_source_combo->getCurrentIndex();
 	if (index == LLModelPreview::GENERATE
-        || index == LLModelPreview::MESH_OPTIMIZER)
+        || index == LLModelPreview::MESH_OPTIMIZER
+        || index == LLModelPreview::MESH_OPTIMIZER_SLOPPY)
 	{ //rebuild LoD to update triangle counts
 		onLODParamCommit(lod, true);
 	}
diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp
index 5eb49ee938..c33b48c16e 100644
--- a/indra/newview/llmodelpreview.cpp
+++ b/indra/newview/llmodelpreview.cpp
@@ -1706,7 +1706,7 @@ void LLModelPreview::genGlodLODs(S32 which_lod, U32 decimation, bool enforce_tri
     }
 }
 
-void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, U32 decimation, bool enforce_tri_limit)
+void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, U32 decimation, bool enforce_tri_limit, bool sloppy)
 {
     LL_INFOS() << "Generating lod " << which_lod << " using meshoptimizer" << LL_ENDL;
     // Allow LoD from -1 to LLModel::LOD_PHYSICS
@@ -1851,14 +1851,34 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, U32 decimation, bool en
 
                 S32 target_indices = llmax(3, llfloor(num_indices * indices_ratio)); // leave at least one triangle
                 F32 result_code = 0; // how far from original the model is
-                S32 new_indices = LLMeshOptimizer::simplify(&output[0],
-                    face.mIndices,
-                    num_indices,
-                    &face.mPositions[0],
-                    face.mNumVertices,
-                    target_indices,
-                    lod_error_threshold,
-                    &result_code);
+                S32 new_indices = 0;
+
+                if (sloppy)
+                {
+                    new_indices = LLMeshOptimizer::simplifySloppy(
+                        &output[0],
+                        face.mIndices,
+                        num_indices,
+                        &face.mPositions[0],
+                        face.mNumVertices,
+                        target_indices,
+                        lod_error_threshold,
+                        &result_code);
+                }
+                
+                if (new_indices <= 0)
+                {
+                    new_indices = LLMeshOptimizer::simplify(
+                        &output[0],
+                        face.mIndices,
+                        num_indices,
+                        &face.mPositions[0],
+                        face.mNumVertices,
+                        target_indices,
+                        lod_error_threshold,
+                        &result_code);
+                }
+
 
                 if (result_code < 0)
                 {
@@ -3800,11 +3820,11 @@ void LLModelPreview::onLODGenerateParamCommit(S32 lod, bool enforce_tri_limit)
     }
 }
 
-void LLModelPreview::onLODMeshOptimizerParamCommit(S32 requested_lod, bool enforce_tri_limit)
+void LLModelPreview::onLODMeshOptimizerParamCommit(S32 requested_lod, bool enforce_tri_limit, bool sloppy)
 {
     if (!mLODFrozen)
     {
-        genMeshOptimizerLODs(requested_lod, 3, enforce_tri_limit);
+        genMeshOptimizerLODs(requested_lod, 3, enforce_tri_limit, sloppy);
         refresh();
     }
 }
diff --git a/indra/newview/llmodelpreview.h b/indra/newview/llmodelpreview.h
index f6f4ce580d..9f38156ca2 100644
--- a/indra/newview/llmodelpreview.h
+++ b/indra/newview/llmodelpreview.h
@@ -126,6 +126,7 @@ public:
         LOD_FROM_FILE = 0,
         GENERATE,
         MESH_OPTIMIZER,
+        MESH_OPTIMIZER_SLOPPY,
         USE_LOD_ABOVE,
     } eLoDMode;
 
@@ -163,7 +164,7 @@ public:
     bool lodsReady() { return !mGenLOD && mLodsQuery.empty(); }
     void queryLODs() { mGenLOD = true; };
     void genGlodLODs(S32 which_lod = -1, U32 decimation = 3, bool enforce_tri_limit = false);
-    void genMeshOptimizerLODs(S32 which_lod = -1, U32 decimation = 3, bool enforce_tri_limit = false);
+    void genMeshOptimizerLODs(S32 which_lod = -1, U32 decimation = 3, bool enforce_tri_limit = false, bool sloppy = false);
     void generateNormals();
     void restoreNormals();
     U32 calcResourceCost();
@@ -175,7 +176,7 @@ public:
     void updateLodControls(S32 lod);
     void clearGLODGroup();
     void onLODGenerateParamCommit(S32 lod, bool enforce_tri_limit);
-    void onLODMeshOptimizerParamCommit(S32 lod, bool enforce_tri_limit);
+    void onLODMeshOptimizerParamCommit(S32 lod, bool enforce_tri_limit, bool sloppy);
     void addEmptyFace(LLModel* pTarget);
 
     const bool getModelPivot(void) const { return mHasPivot; }
diff --git a/indra/newview/skins/default/xui/en/floater_model_preview.xml b/indra/newview/skins/default/xui/en/floater_model_preview.xml
index 96bda42316..230284555c 100644
--- a/indra/newview/skins/default/xui/en/floater_model_preview.xml
+++ b/indra/newview/skins/default/xui/en/floater_model_preview.xml
@@ -180,6 +180,10 @@
                  name="MeshOpt"
                  label="MeshOpt"
                  value="MeshOpt" />
+                <item
+                 name="MeshOptSloppy"
+                 label="MeshOptSloppy"
+                 value="MeshOptSloppy" />
             </combo_box>
             <line_editor
              follows="left|top"
@@ -313,6 +317,10 @@
                  name="MeshOpt"
                  label="MeshOpt"
                  value="MeshOpt" />
+                <item
+                 name="MeshOptSloppy"
+                 label="MeshOptSloppy"
+                 value="MeshOptSloppy" />
                 <item
                  name="Use LoD above"
                  label="Use LoD above"
@@ -450,6 +458,10 @@
                  name="MeshOpt"
                  label="MeshOpt"
                  value="MeshOpt" />
+                <item
+                 name="MeshOptSloppy"
+                 label="MeshOptSloppy"
+                 value="MeshOptSloppy" />
                 <item
                  name="Use LoD above"
                  label="Use LoD above"
@@ -587,6 +599,10 @@
                  name="MeshOpt"
                  label="MeshOpt"
                  value="MeshOpt" />
+                <item
+                 name="MeshOptSloppy"
+                 label="MeshOptSloppy"
+                 value="MeshOptSloppy" />
                 <item
                  name="Use LoD above"
                  label="Use LoD above"
-- 
cgit v1.2.3


From 833a82f8593c513b12b59c489760f77d5a806668 Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Mon, 12 Jul 2021 23:23:08 +0300
Subject: DRTVWR-542 WIP #7

---
 indra/llmeshoptimizer/llmeshoptimizer.cpp | 23 ++++++++++++++++++++---
 indra/llmeshoptimizer/llmeshoptimizer.h   |  7 +++++++
 indra/newview/llmodelpreview.cpp          | 16 ++++++++++++----
 3 files changed, 39 insertions(+), 7 deletions(-)

(limited to 'indra')

diff --git a/indra/llmeshoptimizer/llmeshoptimizer.cpp b/indra/llmeshoptimizer/llmeshoptimizer.cpp
index 2f3d2491c2..0ddaa82c3d 100644
--- a/indra/llmeshoptimizer/llmeshoptimizer.cpp
+++ b/indra/llmeshoptimizer/llmeshoptimizer.cpp
@@ -39,6 +39,26 @@ LLMeshOptimizer::~LLMeshOptimizer()
 {
 }
 
+//static
+void LLMeshOptimizer::generateShadowIndexBuffer(U16 *destination,
+    const U16 *indices,
+    U64 index_count,
+    const LLVector4a *vertex_positions,
+    U64 vertex_count
+)
+{
+    const size_t vertex_stride = 4; // should be either 0 or 4
+
+    meshopt_generateShadowIndexBuffer<unsigned short>(destination,
+        indices,
+        index_count,
+        (const float*)vertex_positions, // verify that it is correct to convert to float
+        vertex_count,
+        sizeof(LLVector4a),
+        vertex_stride
+        );
+}
+
 //static
 U64 LLMeshOptimizer::simplify(U16 *destination,
                               const U16 *indices,
@@ -52,9 +72,6 @@ U64 LLMeshOptimizer::simplify(U16 *destination,
 {
     const size_t vertex_stride = 4; // should be either 0 or 4
 
-    // Consider running meshopt_generateShadowIndexBuffer<unsigned short> first.
-    // meshopt_generateShadowIndexBuffer is only needed if models don't use some of the vertices,
-    // but since we call optimize() in a lot of cases, it likely isn't needed
     return meshopt_simplify<unsigned short>(destination,
                                  indices,
                                  index_count,
diff --git a/indra/llmeshoptimizer/llmeshoptimizer.h b/indra/llmeshoptimizer/llmeshoptimizer.h
index c4250c537d..744856361c 100644
--- a/indra/llmeshoptimizer/llmeshoptimizer.h
+++ b/indra/llmeshoptimizer/llmeshoptimizer.h
@@ -36,6 +36,13 @@ public:
     LLMeshOptimizer();
     ~LLMeshOptimizer();
 
+    static void LLMeshOptimizer::generateShadowIndexBuffer(
+        U16 *destination,
+        const U16 *indices,
+        U64 index_count,
+        const LLVector4a *vertex_positions,
+        U64 vertex_count);
+
     // returns amount of indices in destiantion
     // result_error returns how far from original the model is in % if not NULL
     static U64 simplify(
diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp
index c33b48c16e..471b29d850 100644
--- a/indra/newview/llmodelpreview.cpp
+++ b/indra/newview/llmodelpreview.cpp
@@ -1847,10 +1847,18 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, U32 decimation, bool en
                 S32 num_indices = face.mNumIndices;
                 std::vector<U16> output(num_indices); //todo: do not allocate per each face, add one large buffer somewhere
 
-                // todo: run generateShadowIndexBuffer, at some stage, potentially inside simplify
+                /*
+                generateShadowIndexBuffer appears to deform model
+                LLMeshOptimizer::generateShadowIndexBuffer(
+                    &shadow[0],
+                    face.mIndices,
+                    num_indices,
+                    &face.mPositions[0],
+                    face.mNumVertices);
+                */
 
                 S32 target_indices = llmax(3, llfloor(num_indices * indices_ratio)); // leave at least one triangle
-                F32 result_code = 0; // how far from original the model is
+                F32 result_code = 0; // how far from original the model is, 1 == 100%
                 S32 new_indices = 0;
 
                 if (sloppy)
@@ -1859,7 +1867,7 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, U32 decimation, bool en
                         &output[0],
                         face.mIndices,
                         num_indices,
-                        &face.mPositions[0],
+                        face.mPositions,
                         face.mNumVertices,
                         target_indices,
                         lod_error_threshold,
@@ -1872,7 +1880,7 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, U32 decimation, bool en
                         &output[0],
                         face.mIndices,
                         num_indices,
-                        &face.mPositions[0],
+                        face.mPositions,
                         face.mNumVertices,
                         target_indices,
                         lod_error_threshold,
-- 
cgit v1.2.3


From 66ba1c4c8e840bb5e9da23e2b5772cd24b23714f Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Tue, 13 Jul 2021 02:14:16 +0300
Subject: DRTVWR-542 WIP Fixed Stride

---
 indra/llmeshoptimizer/llmeshoptimizer.cpp | 19 +++++++++----------
 indra/llmeshoptimizer/llmeshoptimizer.h   |  7 +++++--
 indra/newview/llmodelpreview.cpp          |  2 ++
 3 files changed, 16 insertions(+), 12 deletions(-)

(limited to 'indra')

diff --git a/indra/llmeshoptimizer/llmeshoptimizer.cpp b/indra/llmeshoptimizer/llmeshoptimizer.cpp
index 0ddaa82c3d..09fa7cb235 100644
--- a/indra/llmeshoptimizer/llmeshoptimizer.cpp
+++ b/indra/llmeshoptimizer/llmeshoptimizer.cpp
@@ -44,18 +44,17 @@ void LLMeshOptimizer::generateShadowIndexBuffer(U16 *destination,
     const U16 *indices,
     U64 index_count,
     const LLVector4a *vertex_positions,
-    U64 vertex_count
+    U64 vertex_count,
+    U64 vertex_positions_stride
 )
 {
-    const size_t vertex_stride = 4; // should be either 0 or 4
-
     meshopt_generateShadowIndexBuffer<unsigned short>(destination,
         indices,
         index_count,
         (const float*)vertex_positions, // verify that it is correct to convert to float
         vertex_count,
         sizeof(LLVector4a),
-        vertex_stride
+        vertex_positions_stride
         );
 }
 
@@ -65,19 +64,19 @@ U64 LLMeshOptimizer::simplify(U16 *destination,
                               U64 index_count,
                               const LLVector4a *vertex_positions,
                               U64 vertex_count,
+                              U64 vertex_positions_stride,
                               U64 target_index_count,
                               F32 target_error,
                               F32* result_error
     )
 {
-    const size_t vertex_stride = 4; // should be either 0 or 4
 
     return meshopt_simplify<unsigned short>(destination,
                                  indices,
                                  index_count,
-                                 (const float*)vertex_positions, // verify that it is correct to convert to float
+                                 (const float*)vertex_positions,
                                  vertex_count,
-                                 vertex_stride, 
+                                 vertex_positions_stride, 
                                  target_index_count,
                                  target_error,
                                  result_error
@@ -90,18 +89,18 @@ U64 LLMeshOptimizer::simplifySloppy(U16 *destination,
                               U64 index_count,
                               const LLVector4a *vertex_positions,
                               U64 vertex_count,
+    U64 vertex_positions_stride,
                               U64 target_index_count,
                               F32 target_error,
                               F32* result_error
     )
 {
-    const size_t vertex_stride = 4; // should be either 0 or 4
     return meshopt_simplifySloppy<unsigned short>(destination,
                                  indices,
                                  index_count,
-                                 (const float*)vertex_positions, // verify that it is correct to convert to float
+                                 (const float*)vertex_positions,
                                  vertex_count,
-                                 vertex_stride, 
+                                 vertex_positions_stride, 
                                  target_index_count,
                                  target_error,
                                  result_error
diff --git a/indra/llmeshoptimizer/llmeshoptimizer.h b/indra/llmeshoptimizer/llmeshoptimizer.h
index 744856361c..1aa02372fa 100644
--- a/indra/llmeshoptimizer/llmeshoptimizer.h
+++ b/indra/llmeshoptimizer/llmeshoptimizer.h
@@ -36,12 +36,13 @@ public:
     LLMeshOptimizer();
     ~LLMeshOptimizer();
 
-    static void LLMeshOptimizer::generateShadowIndexBuffer(
+    static void generateShadowIndexBuffer(
         U16 *destination,
         const U16 *indices,
         U64 index_count,
         const LLVector4a *vertex_positions,
-        U64 vertex_count);
+        U64 vertex_count,
+        U64 vertex_positions_stride);
 
     // returns amount of indices in destiantion
     // result_error returns how far from original the model is in % if not NULL
@@ -51,6 +52,7 @@ public:
         U64 index_count,
         const LLVector4a *vertex_positions,
         U64 vertex_count,
+        U64 vertex_positions_stride,
         U64 target_index_count,
         F32 target_error,
         F32* result_error);
@@ -63,6 +65,7 @@ public:
         U64 index_count,
         const LLVector4a *vertex_positions,
         U64 vertex_count,
+        U64 vertex_positions_stride,
         U64 target_index_count,
         F32 target_error,
         F32* result_error);
diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp
index 471b29d850..aa065edf92 100644
--- a/indra/newview/llmodelpreview.cpp
+++ b/indra/newview/llmodelpreview.cpp
@@ -1869,6 +1869,7 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, U32 decimation, bool en
                         num_indices,
                         face.mPositions,
                         face.mNumVertices,
+                        LLVertexBuffer::sTypeSize[LLVertexBuffer::TYPE_VERTEX],
                         target_indices,
                         lod_error_threshold,
                         &result_code);
@@ -1882,6 +1883,7 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, U32 decimation, bool en
                         num_indices,
                         face.mPositions,
                         face.mNumVertices,
+                        LLVertexBuffer::sTypeSize[LLVertexBuffer::TYPE_VERTEX],
                         target_indices,
                         lod_error_threshold,
                         &result_code);
-- 
cgit v1.2.3


From 33819e157e9a9638d4869e90601f7b7011804e08 Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Tue, 13 Jul 2021 11:32:59 +0300
Subject: DRTVWR-542 Fixed size of indices array

---
 indra/newview/llmodelpreview.cpp | 27 ++++++++++++++++-----------
 1 file changed, 16 insertions(+), 11 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp
index aa065edf92..26eac71281 100644
--- a/indra/newview/llmodelpreview.cpp
+++ b/indra/newview/llmodelpreview.cpp
@@ -1874,7 +1874,9 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, U32 decimation, bool en
                         lod_error_threshold,
                         &result_code);
                 }
-                
+
+                // todo: instead of checking (new_indices <= 0)
+                // create a dummy triangle if simplifySloppy returns nothing
                 if (new_indices <= 0)
                 {
                     new_indices = LLMeshOptimizer::simplify(
@@ -1892,7 +1894,18 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, U32 decimation, bool en
 
                 if (result_code < 0)
                 {
-                    LL_WARNS() << "Negative result from meshoptimizer" << LL_ENDL;
+                    LL_WARNS() << "Negative result code from meshoptimizer for face " << face_idx
+                        << " of model " << target_model->mLabel
+                        << " target Indices: " << target_indices
+                        << " new Indices: " << new_indices
+                        << " original count: " << num_indices << LL_ENDL;
+                }
+                if (new_indices == 0)
+                {
+                    LL_WARNS() << "No indices generated by meshoptimizer for face " << face_idx
+                        << " of model " << target_model->mLabel
+                        << " target Indices: " << target_indices
+                        << " original count: " << num_indices << LL_ENDL;
                 }
 
                 LLVolumeFace &new_face = target_model->getVolumeFace(face_idx);
@@ -1901,20 +1914,12 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, U32 decimation, bool en
                 new_face = face;
 
                 // Assign new values
+                new_face.resizeIndices(new_indices); // will wipe out mIndices, so new_face can't substitute output
                 S32 idx_size = (new_indices * sizeof(U16) + 0xF) & ~0xF;
                 LLVector4a::memcpyNonAliased16((F32*)new_face.mIndices, (F32*)(&output[0]), idx_size);
-                new_face.mNumIndices = new_indices;
 
                 // clear unused values
                 new_face.optimize();
-
-                if (new_indices == 0)
-                {
-                    LL_WARNS() << "No indices generated for face " << face_idx
-                               << " of model " << target_model->mLabel
-                               << " target Indices: " << target_indices
-                               << " original count: "  << num_indices << LL_ENDL;
-                }
             }
 
             //blind copy skin weights and just take closest skin weight to point on
-- 
cgit v1.2.3


From a607e7642071690dcab9a1fdf5453fcf83480982 Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Tue, 13 Jul 2021 20:07:28 +0300
Subject: DRTVWR-542 output buffer should be indentical in size to indices
 array

---
 indra/newview/llmodelpreview.cpp | 13 +++++++++----
 1 file changed, 9 insertions(+), 4 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp
index 26eac71281..93186657ce 100644
--- a/indra/newview/llmodelpreview.cpp
+++ b/indra/newview/llmodelpreview.cpp
@@ -1845,7 +1845,10 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, U32 decimation, bool en
             {
                 const LLVolumeFace &face = base->getVolumeFace(face_idx);
                 S32 num_indices = face.mNumIndices;
-                std::vector<U16> output(num_indices); //todo: do not allocate per each face, add one large buffer somewhere
+                // todo: do not allocate per each face, add one large buffer somewhere
+                // faces have limited amount of indices
+                S32 size = (num_indices * sizeof(U16) + 0xF) & ~0xF;
+                U16* output = (U16*)ll_aligned_malloc_16(size);
 
                 /*
                 generateShadowIndexBuffer appears to deform model
@@ -1864,7 +1867,7 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, U32 decimation, bool en
                 if (sloppy)
                 {
                     new_indices = LLMeshOptimizer::simplifySloppy(
-                        &output[0],
+                        output,
                         face.mIndices,
                         num_indices,
                         face.mPositions,
@@ -1880,7 +1883,7 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, U32 decimation, bool en
                 if (new_indices <= 0)
                 {
                     new_indices = LLMeshOptimizer::simplify(
-                        &output[0],
+                        output,
                         face.mIndices,
                         num_indices,
                         face.mPositions,
@@ -1916,7 +1919,9 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, U32 decimation, bool en
                 // Assign new values
                 new_face.resizeIndices(new_indices); // will wipe out mIndices, so new_face can't substitute output
                 S32 idx_size = (new_indices * sizeof(U16) + 0xF) & ~0xF;
-                LLVector4a::memcpyNonAliased16((F32*)new_face.mIndices, (F32*)(&output[0]), idx_size);
+                LLVector4a::memcpyNonAliased16((F32*)new_face.mIndices, (F32*)output, idx_size);
+
+                ll_aligned_free_16(output);
 
                 // clear unused values
                 new_face.optimize();
-- 
cgit v1.2.3


From d3d0711f1da33665df63be41758fbc1480244811 Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Thu, 15 Jul 2021 17:30:21 +0300
Subject: SL-443 Keybindings: Restored default fails to save

---
 indra/newview/llkeyconflict.cpp | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

(limited to 'indra')

diff --git a/indra/newview/llkeyconflict.cpp b/indra/newview/llkeyconflict.cpp
index b6107eeedf..d7a17b237e 100644
--- a/indra/newview/llkeyconflict.cpp
+++ b/indra/newview/llkeyconflict.cpp
@@ -730,13 +730,19 @@ void LLKeyConflictHandler::resetToDefault(const std::string &control_name, U32 i
     {
         return;
     }
+    LLKeyConflict &type_data = mControlsMap[control_name];
+    if (!type_data.mAssignable)
+    {
+        return;
+    }
     LLKeyData data = getDefaultControl(control_name, index);
 
-    if (data != mControlsMap[control_name].getKeyData(index))
+    if (data != type_data.getKeyData(index))
     {
         // reset controls that might have been switched to our current control
         removeConflicts(data, mControlsMap[control_name].mConflictMask);
         mControlsMap[control_name].setKeyData(data, index);
+        mHasUnsavedChanges = true;
     }
 }
 
-- 
cgit v1.2.3


From a5675bedbb2bd34ce03dd16651dc74d8078efea9 Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Thu, 15 Jul 2021 17:34:16 +0300
Subject: SL-443 Keybindings: Support reassigment of script interaction button

---
 indra/newview/app_settings/key_bindings.xml        |  8 +++
 indra/newview/llkeyconflict.cpp                    | 58 ++++++++++++++--
 indra/newview/llkeyconflict.h                      |  4 +-
 indra/newview/lltoolcomp.cpp                       | 10 ++-
 indra/newview/lltoolpie.cpp                        |  2 +-
 indra/newview/llviewerinput.cpp                    | 81 +++++++++++++++++++---
 indra/newview/llviewerinput.h                      |  5 +-
 .../xui/en/control_table_contents_media.xml        | 10 +++
 8 files changed, 158 insertions(+), 20 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/app_settings/key_bindings.xml b/indra/newview/app_settings/key_bindings.xml
index 4f6deb1f98..ffc1b2e7cc 100644
--- a/indra/newview/app_settings/key_bindings.xml
+++ b/indra/newview/app_settings/key_bindings.xml
@@ -33,6 +33,8 @@
     <binding key="DIVIDE" mask="NONE" command="start_gesture"/>
 
     <binding key="" mask="NONE" mouse="MMB" command="toggle_voice"/>
+
+    <binding key="" mask="NONE" mouse="LMB" command="sript_trigger_lbutton"/>
   </first_person>
   <third_person>
     <binding key="A" mask="NONE" command="turn_left"/>
@@ -127,6 +129,8 @@
 
     <binding key="" mask="NONE" mouse="MMB" command="toggle_voice"/>
     <binding key="" mask="NONE" mouse="LMB" command="walk_to"/>
+
+    <binding key="" mask="NONE" mouse="LMB" command="sript_trigger_lbutton"/>
   </third_person>
   <sitting>
     <binding key="A" mask="ALT" command="spin_around_cw"/>
@@ -224,6 +228,8 @@
     <binding key="DIVIDE" mask="NONE" command="start_gesture"/>
 
     <binding key="" mask="NONE" mouse="MMB" command="toggle_voice"/>
+
+    <binding key="" mask="NONE" mouse="LMB" command="sript_trigger_lbutton"/>
   </sitting>
   <edit_avatar>
     <!--Avatar editing camera controls-->
@@ -251,5 +257,7 @@
     <binding key="PAD_DIVIDE" mask="NONE" command="start_gesture"/>
 
     <binding key="" mask="NONE" mouse="MMB" command="toggle_voice"/>
+
+    <binding key="" mask="NONE" mouse="LMB" command="sript_trigger_lbutton"/>
   </edit_avatar>
 </keys>
diff --git a/indra/newview/llkeyconflict.cpp b/indra/newview/llkeyconflict.cpp
index d7a17b237e..58a740e16a 100644
--- a/indra/newview/llkeyconflict.cpp
+++ b/indra/newview/llkeyconflict.cpp
@@ -868,7 +868,7 @@ void LLKeyConflictHandler::resetKeyboardBindings()
 
 void LLKeyConflictHandler::generatePlaceholders(ESourceMode load_mode)
 {
-    // These controls are meant to cause conflicts when user tries to assign same control somewhere else
+    // These placeholds are meant to cause conflict resolution when user tries to assign same control somewhere else
     // also this can be used to pre-record controls that should not conflict or to assign conflict groups/masks
 
     if (load_mode == MODE_FIRST_PERSON)
@@ -928,25 +928,73 @@ void LLKeyConflictHandler::generatePlaceholders(ESourceMode load_mode)
         registerTemporaryControl("spin_around_ccw_sitting");
         registerTemporaryControl("spin_around_cw_sitting");
     }
+
+
+    // Special case, mouse clicks passed to scripts have 'lowest' piority
+    // thus do not conflict, everything else has a chance before them
+    // also in ML they have highest priority, but only when script-grabbed,
+    // thus do not conflict
+    // (see AGENT_CONTROL_ML_LBUTTON_DOWN and CONTROL_LBUTTON_DOWN_INDEX)
+    LLKeyConflict *type_data = &mControlsMap[script_mouse_handler_name];
+    type_data->mAssignable = true;
+    type_data->mConflictMask = U32_MAX - CONFLICT_LMOUSE;
 }
 
-bool LLKeyConflictHandler::removeConflicts(const LLKeyData &data, const U32 &conlict_mask)
+bool LLKeyConflictHandler::removeConflicts(const LLKeyData &data, U32 conlict_mask)
 {
     if (conlict_mask == CONFLICT_NOTHING)
     {
         // Can't conflict
         return true;
     }
+
+    if (data.mMouse == CLICK_LEFT
+        && data.mMask == MASK_NONE
+        && data.mKey == KEY_NONE)
+    {
+        if ((conlict_mask & CONFLICT_LMOUSE) == 0)
+        {
+            // Can't conflict
+            return true;
+        }
+        else
+        {
+            // simplify conflict mask
+            conlict_mask = CONFLICT_LMOUSE;
+        }
+    }
+    else
+    {
+        // simplify conflict mask
+        conlict_mask &= ~CONFLICT_LMOUSE;
+    }
+
     std::map<std::string, S32> conflict_list;
     control_map_t::iterator cntrl_iter = mControlsMap.begin();
     control_map_t::iterator cntrl_end = mControlsMap.end();
     for (; cntrl_iter != cntrl_end; ++cntrl_iter)
     {
+        const U32 cmp_mask = cntrl_iter->second.mConflictMask;
+        if ((cmp_mask & conlict_mask) == 0)
+        {
+            // can't conflict
+            continue;
+        }
         S32 index = cntrl_iter->second.mKeyBind.findKeyData(data);
-        if (index >= 0
-            && cntrl_iter->second.mConflictMask != CONFLICT_NOTHING
-            && (cntrl_iter->second.mConflictMask & conlict_mask) != 0)
+        if (index >= 0)
         {
+            if (cmp_mask != U32_MAX)
+            {
+                const LLKeyData cmp_data = cntrl_iter->second.mKeyBind.getKeyData(index);
+                if ((cmp_mask & CONFLICT_LMOUSE) == 0
+                    && cmp_data.mMouse == CLICK_LEFT
+                    && cmp_data.mMask == MASK_NONE
+                    && cmp_data.mKey == KEY_NONE)
+                {
+                    // Does not conflict
+                    continue;
+                }
+            }
             if (cntrl_iter->second.mAssignable)
             {
                 // Potentially we can have multiple conflict flags conflicting
diff --git a/indra/newview/llkeyconflict.h b/indra/newview/llkeyconflict.h
index 2926ca3aeb..e78d2fa33b 100644
--- a/indra/newview/llkeyconflict.h
+++ b/indra/newview/llkeyconflict.h
@@ -66,6 +66,7 @@ public:
     };
 
     const U32 CONFLICT_NOTHING = 0;
+    const U32 CONFLICT_LMOUSE = 0x1 << 1;
     // at the moment this just means that key will conflict with everything that is identical
     const U32 CONFLICT_ANY = U32_MAX;
 
@@ -145,6 +146,7 @@ private:
 
     // at the moment these kind of control is not savable, but takes part in conflict resolution
     void registerTemporaryControl(const std::string &control_name, EMouseClickType mouse_ind, KEY key, MASK mask, U32 conflict_mask);
+    // conflict mask 0 means that any conflicts will be ignored
     void registerTemporaryControl(const std::string &control_name, U32 conflict_mask = 0);
 
     typedef std::map<std::string, LLKeyConflict> control_map_t;
@@ -152,7 +154,7 @@ private:
     bool loadFromSettings(const ESourceMode &load_mode, const std::string &filename, control_map_t *destination);
     void generatePlaceholders(ESourceMode load_mode); //E.x. non-assignable values
     // returns false in case user is trying to reuse control that can't be reassigned
-    bool removeConflicts(const LLKeyData &data, const U32 &conlict_mask);
+    bool removeConflicts(const LLKeyData &data, U32 conlict_mask);
 
     // removes flags and removes temporary file, returns 'true' if file was removed
     bool clearUnsavedChanges();
diff --git a/indra/newview/lltoolcomp.cpp b/indra/newview/lltoolcomp.cpp
index f9c327b46e..9ac1810964 100644
--- a/indra/newview/lltoolcomp.cpp
+++ b/indra/newview/lltoolcomp.cpp
@@ -44,6 +44,7 @@
 #include "lltoolmgr.h"
 #include "lltoolselectrect.h"
 #include "lltoolplacer.h"
+#include "llviewerinput.h"
 #include "llviewermenu.h"
 #include "llviewerobject.h"
 #include "llviewerwindow.h"
@@ -743,7 +744,7 @@ BOOL LLToolCompGun::handleHover(S32 x, S32 y, MASK mask)
 BOOL LLToolCompGun::handleMouseDown(S32 x, S32 y, MASK mask)
 { 
 	// if the left button is grabbed, don't put up the pie menu
-	if (gAgent.leftButtonGrabbed())
+	if (gAgent.leftButtonGrabbed() && gViewerInput.isLMouseHandlingDefault(MODE_FIRST_PERSON))
 	{
 		gAgent.setControlFlags(AGENT_CONTROL_ML_LBUTTON_DOWN);
 		return FALSE;
@@ -760,7 +761,7 @@ BOOL LLToolCompGun::handleMouseDown(S32 x, S32 y, MASK mask)
 BOOL LLToolCompGun::handleDoubleClick(S32 x, S32 y, MASK mask)
 {
 	// if the left button is grabbed, don't put up the pie menu
-	if (gAgent.leftButtonGrabbed())
+	if (gAgent.leftButtonGrabbed() && gViewerInput.isLMouseHandlingDefault(MODE_FIRST_PERSON))
 	{
 		gAgent.setControlFlags(AGENT_CONTROL_ML_LBUTTON_DOWN);
 		return FALSE;
@@ -794,7 +795,10 @@ BOOL LLToolCompGun::handleRightMouseDown(S32 x, S32 y, MASK mask)
 
 BOOL LLToolCompGun::handleMouseUp(S32 x, S32 y, MASK mask)
 {
-	gAgent.setControlFlags(AGENT_CONTROL_ML_LBUTTON_UP);
+    if (gViewerInput.isLMouseHandlingDefault(MODE_FIRST_PERSON))
+    {
+        gAgent.setControlFlags(AGENT_CONTROL_ML_LBUTTON_UP);
+    }
 	setCurrentTool( (LLTool*) mGun );
 	return TRUE;
 }
diff --git a/indra/newview/lltoolpie.cpp b/indra/newview/lltoolpie.cpp
index 322d0bc727..543a93bf9b 100644
--- a/indra/newview/lltoolpie.cpp
+++ b/indra/newview/lltoolpie.cpp
@@ -746,7 +746,7 @@ BOOL LLToolPie::handleHover(S32 x, S32 y, MASK mask)
 	else if (!mMouseOutsideSlop 
 		&& mMouseButtonDown
 		// disable camera steering if click on land is not used for moving
-		&& gViewerInput.isMouseBindUsed(CLICK_LEFT))
+		&& gViewerInput.isMouseBindUsed(CLICK_LEFT, MASK_NONE, MODE_THIRD_PERSON))
 	{
 		S32 delta_x = x - mMouseDownX;
 		S32 delta_y = y - mMouseDownY;
diff --git a/indra/newview/llviewerinput.cpp b/indra/newview/llviewerinput.cpp
index c0eaa88f54..8b3d406b78 100644
--- a/indra/newview/llviewerinput.cpp
+++ b/indra/newview/llviewerinput.cpp
@@ -61,7 +61,7 @@ const F32 ORBIT_NUDGE_RATE = 0.05f;  // fraction of normal speed
 const LLKeyData agent_control_lbutton(CLICK_LEFT, KEY_NONE, MASK_NONE, true);
 
 struct LLKeyboardActionRegistry 
-:	public LLRegistrySingleton<std::string, boost::function<bool (EKeystate keystate)>, LLKeyboardActionRegistry>
+:	public LLRegistrySingleton<const std::string, boost::function<bool (EKeystate keystate)>, LLKeyboardActionRegistry>
 {
 	LLSINGLETON_EMPTY_CTOR(LLKeyboardActionRegistry);
 };
@@ -836,7 +836,49 @@ bool voice_follow_key(EKeystate s)
     return false;
 }
 
-bool agen_control_lbutton_handle(EKeystate s)
+bool sript_trigger_lbutton(EKeystate s)
+{
+    // Check for script overriding/expecting left mouse button.
+    // Note that this does not pass event further and depends onto mouselook.
+    // Checks CONTROL_ML_LBUTTON_DOWN_INDEX for mouselook,
+    // CONTROL_LBUTTON_DOWN_INDEX for normal camera
+    if (gAgent.leftButtonGrabbed())
+    {
+        bool mouselook = gAgentCamera.cameraMouselook();
+        switch (s)
+        {
+        case KEYSTATE_DOWN:
+            // at the moment sript_trigger_lbutton is only intended for mouselook
+            // but handling other modes just in case
+            if (mouselook)
+            {
+                gAgent.setControlFlags(AGENT_CONTROL_ML_LBUTTON_DOWN);
+            }
+            else
+            {
+                gAgent.setControlFlags(AGENT_CONTROL_LBUTTON_DOWN);
+            }
+            return true;
+        case KEYSTATE_UP:
+            if (mouselook)
+            {
+                gAgent.setControlFlags(AGENT_CONTROL_ML_LBUTTON_UP);
+            }
+            else
+            {
+                gAgent.setControlFlags(AGENT_CONTROL_LBUTTON_UP);
+            }
+            return true;
+        default:
+            break;
+        }
+    }
+    return false;
+}
+
+// Used by scripts, for overriding/handling left mouse button
+// see mControlsTakenCount
+bool agent_control_lbutton_handle(EKeystate s)
 {
     switch (s)
     {
@@ -905,6 +947,7 @@ REGISTER_KEYBOARD_ACTION("teleport_to", teleport_to);
 REGISTER_KEYBOARD_ACTION("walk_to", walk_to);
 REGISTER_KEYBOARD_ACTION("toggle_voice", toggle_voice);
 REGISTER_KEYBOARD_ACTION("voice_follow_key", voice_follow_key);
+REGISTER_KEYBOARD_ACTION(script_mouse_handler_name, sript_trigger_lbutton);
 #undef REGISTER_KEYBOARD_ACTION
 
 LLViewerInput::LLViewerInput()
@@ -1104,6 +1147,20 @@ BOOL LLViewerInput::bindMouse(const S32 mode, const EMouseClickType mouse, const
     typedef boost::function<bool(EKeystate)> function_t;
     function_t function = NULL;
 
+    if (mouse == CLICK_LEFT
+        && mask == MASK_NONE
+        && function_name == script_mouse_handler_name)
+    {
+        // Special case
+        // Left click has script overrides and by default
+        // is handled via agent_control_lbutton as last option
+        // In case of mouselook and present overrides it has highest
+        // priority even over UI and is handled in LLToolCompGun::handleMouseDown
+        // so just mark it as having default handler
+        mLMouseDefaultHandling[mode] = true;
+        return TRUE;
+    }
+
     function_t* result = LLKeyboardActionRegistry::getValue(function_name);
     if (result)
     {
@@ -1164,6 +1221,7 @@ void LLViewerInput::resetBindings()
     {
         mKeyBindings[i].clear();
         mMouseBindings[i].clear();
+        mLMouseDefaultHandling[i] = false;
     }
 }
 
@@ -1355,13 +1413,14 @@ bool LLViewerInput::scanKey(KEY key, BOOL key_down, BOOL key_up, BOOL key_level)
 
     if (!res && agent_control_lbutton.canHandle(CLICK_NONE, key, mask))
     {
+        // pass mouse left button press to script
         if (key_down && !repeat)
         {
-            res = agen_control_lbutton_handle(KEYSTATE_DOWN);
+            res = agent_control_lbutton_handle(KEYSTATE_DOWN);
         }
         if (key_up)
         {
-            res = agen_control_lbutton_handle(KEYSTATE_UP);
+            res = agent_control_lbutton_handle(KEYSTATE_UP);
         }
     }
     return res;
@@ -1481,24 +1540,28 @@ bool LLViewerInput::scanMouse(EMouseClickType click, EMouseState state) const
     S32 mode = getMode();
     MASK mask = gKeyboard->currentMask(TRUE);
     res = scanMouse(mMouseBindings[mode], mMouseBindings[mode].size(), click, mask, state);
+
     // no user defined actions found or those actions can't handle the key/button, handle control if nessesary
-    if (!res && agent_control_lbutton.canHandle(click, KEY_NONE, mask))
+    // This will pass AGENT_CONTROL_LBUTTON_DOWN to server, no idea why it doesn't do mouselook variant _ML_
+    // but it was set this way forever (moved as is from LLTool::handleMouseDown) so lots of scripts probably
+    // rely on this.
+    if (!res && mLMouseDefaultHandling[mode] && agent_control_lbutton.canHandle(click, KEY_NONE, mask))
     {
         switch (state)
         {
         case MOUSE_STATE_DOWN:
-            agen_control_lbutton_handle(KEYSTATE_DOWN);
+            agent_control_lbutton_handle(KEYSTATE_DOWN);
             res = true;
             break;
         case MOUSE_STATE_CLICK:
             // might not work best with some functions,
             // but some function need specific states too specifically
-            agen_control_lbutton_handle(KEYSTATE_DOWN);
-            agen_control_lbutton_handle(KEYSTATE_UP);
+            agent_control_lbutton_handle(KEYSTATE_DOWN);
+            agent_control_lbutton_handle(KEYSTATE_UP);
             res = true;
             break;
         case MOUSE_STATE_UP:
-            agen_control_lbutton_handle(KEYSTATE_UP);
+            agent_control_lbutton_handle(KEYSTATE_UP);
             res = true;
             break;
         default:
diff --git a/indra/newview/llviewerinput.h b/indra/newview/llviewerinput.h
index 281a209896..32dd3c0e28 100644
--- a/indra/newview/llviewerinput.h
+++ b/indra/newview/llviewerinput.h
@@ -31,6 +31,7 @@
 #include "llinitparam.h"
 
 const S32 MAX_KEY_BINDINGS = 128; // was 60
+const std::string script_mouse_handler_name = "sript_trigger_lbutton";
 
 class LLNamedFunction
 {
@@ -124,7 +125,8 @@ public:
     BOOL            handleMouse(LLWindow *window_impl, LLCoordGL pos, MASK mask, EMouseClickType clicktype, BOOL down);
     void            scanMouse();
 
-    bool            isMouseBindUsed(const EMouseClickType mouse, const MASK mask = MASK_NONE, const S32 mode = MODE_THIRD_PERSON);
+    bool            isMouseBindUsed(const EMouseClickType mouse, const MASK mask, const S32 mode);
+    bool            isLMouseHandlingDefault(const S32 mode) { return mLMouseDefaultHandling[mode]; }
 
 private:
     bool            scanKey(const std::vector<LLKeyboardBinding> &binding,
@@ -163,6 +165,7 @@ private:
     // to send what we think function wants based on collection of bools (mKeyRepeated, mKeyLevel, mKeyDown)
     std::vector<LLKeyboardBinding>	mKeyBindings[MODE_COUNT];
     std::vector<LLMouseBinding>		mMouseBindings[MODE_COUNT];
+    bool							mLMouseDefaultHandling[MODE_COUNT]; // Due to having special priority
 
 	typedef std::map<U32, U32> key_remap_t;
 	key_remap_t		mRemapKeys[MODE_COUNT];
diff --git a/indra/newview/skins/default/xui/en/control_table_contents_media.xml b/indra/newview/skins/default/xui/en/control_table_contents_media.xml
index ce5d3556b6..a97c45dd6f 100644
--- a/indra/newview/skins/default/xui/en/control_table_contents_media.xml
+++ b/indra/newview/skins/default/xui/en/control_table_contents_media.xml
@@ -73,4 +73,14 @@
          name="lst_action"
          value="Start Gesture" />
     </rows>
+    <rows
+     name="sript_trigger_lbutton"
+     value="sript_trigger_lbutton">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Interact (Script LMB)" />
+    </rows>
 </contents>
-- 
cgit v1.2.3


From d5857b376f1da9ad4fe25ced1a4785a40a82a709 Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Tue, 20 Jul 2021 21:51:43 +0300
Subject: DRTVWR-542 Generate placehodler triangles when face got optimized
 away like glod does

---
 indra/newview/llmodelpreview.cpp | 55 ++++++++++++++++++++++++++--------------
 1 file changed, 36 insertions(+), 19 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp
index 93186657ce..f21b05f9dc 100644
--- a/indra/newview/llmodelpreview.cpp
+++ b/indra/newview/llmodelpreview.cpp
@@ -1860,12 +1860,13 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, U32 decimation, bool en
                     face.mNumVertices);
                 */
 
-                S32 target_indices = llmax(3, llfloor(num_indices * indices_ratio)); // leave at least one triangle
+                S32 target_indices = 0;
                 F32 result_code = 0; // how far from original the model is, 1 == 100%
                 S32 new_indices = 0;
 
                 if (sloppy)
                 {
+                    target_indices = llfloor(num_indices * indices_ratio);
                     new_indices = LLMeshOptimizer::simplifySloppy(
                         output,
                         face.mIndices,
@@ -1877,11 +1878,9 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, U32 decimation, bool en
                         lod_error_threshold,
                         &result_code);
                 }
-
-                // todo: instead of checking (new_indices <= 0)
-                // create a dummy triangle if simplifySloppy returns nothing
-                if (new_indices <= 0)
+                else
                 {
+                    target_indices = llmax(3, llfloor(num_indices * indices_ratio)); // leave at least one triangle
                     new_indices = LLMeshOptimizer::simplify(
                         output,
                         face.mIndices,
@@ -1903,28 +1902,46 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, U32 decimation, bool en
                         << " new Indices: " << new_indices
                         << " original count: " << num_indices << LL_ENDL;
                 }
-                if (new_indices == 0)
-                {
-                    LL_WARNS() << "No indices generated by meshoptimizer for face " << face_idx
-                        << " of model " << target_model->mLabel
-                        << " target Indices: " << target_indices
-                        << " original count: " << num_indices << LL_ENDL;
-                }
 
                 LLVolumeFace &new_face = target_model->getVolumeFace(face_idx);
 
                 // Copy old values
                 new_face = face;
 
-                // Assign new values
-                new_face.resizeIndices(new_indices); // will wipe out mIndices, so new_face can't substitute output
-                S32 idx_size = (new_indices * sizeof(U16) + 0xF) & ~0xF;
-                LLVector4a::memcpyNonAliased16((F32*)new_face.mIndices, (F32*)output, idx_size);
 
-                ll_aligned_free_16(output);
+                if (new_indices == 0)
+                {
+                    if (!sloppy)
+                    {
+                        // optimizeSloppy() can optimize triangles away even if target_indices is > 2,
+                        // but optimize() isn't supposed to
+                        LL_INFOS() << "No indices generated by meshoptimizer for face " << face_idx
+                            << " of model " << target_model->mLabel
+                            << " target Indices: " << target_indices
+                            << " original count: " << num_indices << LL_ENDL;
+                    }
+
+                    // Face got optimized away
+                    // Generate empty triangle
+                    new_face.resizeIndices(3);
+                    new_face.resizeVertices(1);
+                    memset(new_face.mIndices, 0, sizeof(U16) * 3);
+                    new_face.mPositions[0].clear(); // set first vertice to 0
+                    new_face.mNormals[0].clear();
+                    new_face.mTexCoords[0].setZero();
+                }
+                else
+                {
+                    // Assign new values
+                    new_face.resizeIndices(new_indices); // will wipe out mIndices, so new_face can't substitute output
+                    S32 idx_size = (new_indices * sizeof(U16) + 0xF) & ~0xF;
+                    LLVector4a::memcpyNonAliased16((F32*)new_face.mIndices, (F32*)output, idx_size);
 
-                // clear unused values
-                new_face.optimize();
+                    // clear unused values
+                    new_face.optimize();
+                }
+
+                ll_aligned_free_16(output);
             }
 
             //blind copy skin weights and just take closest skin weight to point on
-- 
cgit v1.2.3


From 9aaac1bb985f5bd65f9b0fe985c47cd30dcfd166 Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Fri, 23 Jul 2021 21:30:13 +0300
Subject: DRTVWR-542 Attempt to simplify all faces of an object as a whole and
 split back into faces

---
 indra/llmeshoptimizer/llmeshoptimizer.cpp          |  25 +-
 indra/llmeshoptimizer/llmeshoptimizer.h            |  13 +
 indra/newview/llfloatermodelpreview.cpp            |   8 +-
 indra/newview/llmodelpreview.cpp                   | 323 +++++++++++++++------
 indra/newview/llmodelpreview.h                     |   5 +-
 .../skins/default/xui/en/floater_model_preview.xml |  16 +
 6 files changed, 302 insertions(+), 88 deletions(-)

(limited to 'indra')

diff --git a/indra/llmeshoptimizer/llmeshoptimizer.cpp b/indra/llmeshoptimizer/llmeshoptimizer.cpp
index 09fa7cb235..8097a05511 100644
--- a/indra/llmeshoptimizer/llmeshoptimizer.cpp
+++ b/indra/llmeshoptimizer/llmeshoptimizer.cpp
@@ -58,6 +58,30 @@ void LLMeshOptimizer::generateShadowIndexBuffer(U16 *destination,
         );
 }
 
+//static
+U64 LLMeshOptimizer::simplifyU32(U32 *destination,
+    const U32 *indices,
+    U64 index_count,
+    const LLVector4a *vertex_positions,
+    U64 vertex_count,
+    U64 vertex_positions_stride,
+    U64 target_index_count,
+    F32 target_error,
+    F32* result_error
+)
+{
+    return meshopt_simplify<unsigned int>(destination,
+        indices,
+        index_count,
+        (const float*)vertex_positions,
+        vertex_count,
+        vertex_positions_stride,
+        target_index_count,
+        target_error,
+        result_error
+        );
+}
+
 //static
 U64 LLMeshOptimizer::simplify(U16 *destination,
                               const U16 *indices,
@@ -70,7 +94,6 @@ U64 LLMeshOptimizer::simplify(U16 *destination,
                               F32* result_error
     )
 {
-
     return meshopt_simplify<unsigned short>(destination,
                                  indices,
                                  index_count,
diff --git a/indra/llmeshoptimizer/llmeshoptimizer.h b/indra/llmeshoptimizer/llmeshoptimizer.h
index 1aa02372fa..2696733eb2 100644
--- a/indra/llmeshoptimizer/llmeshoptimizer.h
+++ b/indra/llmeshoptimizer/llmeshoptimizer.h
@@ -44,6 +44,19 @@ public:
         U64 vertex_count,
         U64 vertex_positions_stride);
 
+    // returns amount of indices in destiantion
+    // result_error returns how far from original the model is in % if not NULL
+    static U64 simplifyU32(
+        U32 *destination,
+        const U32 *indices,
+        U64 index_count,
+        const LLVector4a *vertex_positions,
+        U64 vertex_count,
+        U64 vertex_positions_stride,
+        U64 target_index_count,
+        F32 target_error,
+        F32* result_error);
+
     // returns amount of indices in destiantion
     // result_error returns how far from original the model is in % if not NULL
     static U64 simplify(
diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp
index d61311d610..3f2fcb148c 100644
--- a/indra/newview/llfloatermodelpreview.cpp
+++ b/indra/newview/llfloatermodelpreview.cpp
@@ -730,10 +730,9 @@ void LLFloaterModelPreview::onLODParamCommit(S32 lod, bool enforce_tri_limit)
         mModelPreview->onLODGenerateParamCommit(lod, enforce_tri_limit);
         break;
     case LLModelPreview::MESH_OPTIMIZER:
-        mModelPreview->onLODMeshOptimizerParamCommit(lod, enforce_tri_limit, false);
-        break;
     case LLModelPreview::MESH_OPTIMIZER_SLOPPY:
-        mModelPreview->onLODMeshOptimizerParamCommit(lod, enforce_tri_limit, true);
+    case LLModelPreview::MESH_OPTIMIZER_COMBINE:
+        mModelPreview->onLODMeshOptimizerParamCommit(lod, enforce_tri_limit, mode);
         break;
     default:
         LL_ERRS() << "Only supposed to be called to generate models" << LL_ENDL;
@@ -1740,7 +1739,8 @@ void LLFloaterModelPreview::onLoDSourceCommit(S32 lod)
     S32 index = lod_source_combo->getCurrentIndex();
 	if (index == LLModelPreview::GENERATE
         || index == LLModelPreview::MESH_OPTIMIZER
-        || index == LLModelPreview::MESH_OPTIMIZER_SLOPPY)
+        || index == LLModelPreview::MESH_OPTIMIZER_SLOPPY
+        || index == LLModelPreview::MESH_OPTIMIZER_COMBINE)
 	{ //rebuild LoD to update triangle counts
 		onLODParamCommit(lod, true);
 	}
diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp
index f21b05f9dc..6542ac9090 100644
--- a/indra/newview/llmodelpreview.cpp
+++ b/indra/newview/llmodelpreview.cpp
@@ -1706,7 +1706,7 @@ void LLModelPreview::genGlodLODs(S32 which_lod, U32 decimation, bool enforce_tri
     }
 }
 
-void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, U32 decimation, bool enforce_tri_limit, bool sloppy)
+void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 decimation, bool enforce_tri_limit)
 {
     LL_INFOS() << "Generating lod " << which_lod << " using meshoptimizer" << LL_ENDL;
     // Allow LoD from -1 to LLModel::LOD_PHYSICS
@@ -1840,108 +1840,269 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, U32 decimation, bool en
 
             LLModel* target_model = mModel[lod][mdl_idx];
 
-            // Run meshoptimizer for each face
-            for (U32 face_idx = 0; face_idx < base->getNumVolumeFaces(); ++face_idx)
-            {
-                const LLVolumeFace &face = base->getVolumeFace(face_idx);
-                S32 num_indices = face.mNumIndices;
-                // todo: do not allocate per each face, add one large buffer somewhere
-                // faces have limited amount of indices
-                S32 size = (num_indices * sizeof(U16) + 0xF) & ~0xF;
-                U16* output = (U16*)ll_aligned_malloc_16(size);
-
-                /*
-                generateShadowIndexBuffer appears to deform model
-                LLMeshOptimizer::generateShadowIndexBuffer(
-                    &shadow[0],
-                    face.mIndices,
-                    num_indices,
-                    &face.mPositions[0],
-                    face.mNumVertices);
-                */
-
-                S32 target_indices = 0;
-                F32 result_code = 0; // how far from original the model is, 1 == 100%
-                S32 new_indices = 0;
+            if (meshopt_mode == MESH_OPTIMIZER_COMBINE)
+            {
+                // Figure out buffer size
+                S32 size_indices = 0;
+                S32 size_vertices = 0;
 
-                if (sloppy)
+                for (U32 face_idx = 0; face_idx < base->getNumVolumeFaces(); ++face_idx)
                 {
-                    target_indices = llfloor(num_indices * indices_ratio);
-                    new_indices = LLMeshOptimizer::simplifySloppy(
-                        output,
-                        face.mIndices,
-                        num_indices,
-                        face.mPositions,
-                        face.mNumVertices,
-                        LLVertexBuffer::sTypeSize[LLVertexBuffer::TYPE_VERTEX],
-                        target_indices,
-                        lod_error_threshold,
-                        &result_code);
+                    const LLVolumeFace &face = base->getVolumeFace(face_idx);
+                    size_indices += face.mNumIndices;
+                    size_vertices += face.mNumVertices;
                 }
-                else
+
+                // Allocate buffers, note that we are using U32 buffer instead of U16
+                U32* combined_indices = (U32*)ll_aligned_malloc_32(size_indices * sizeof(U32));
+                U32* output_indices = (U32*)ll_aligned_malloc_32(size_indices * sizeof(U32));
+
+                // extra space for normals and text coords, is it needed?
+                S32 size = ((size_vertices * sizeof(LLVector2)) + 0xF) & ~0xF;
+                LLVector4a* combined_positions = (LLVector4a*)ll_aligned_malloc<64>(sizeof(LLVector4a) * 2 * size_vertices + size);
+
+                // copy indices and vertices into new buffers
+                S32 vertices_copied = 0;
+                S32 indices_shift = 0;
+                S32 indices_copied = 0;
+                for (U32 face_idx = 0; face_idx < base->getNumVolumeFaces(); ++face_idx)
                 {
-                    target_indices = llmax(3, llfloor(num_indices * indices_ratio)); // leave at least one triangle
-                    new_indices = LLMeshOptimizer::simplify(
-                        output,
-                        face.mIndices,
-                        num_indices,
-                        face.mPositions,
-                        face.mNumVertices,
-                        LLVertexBuffer::sTypeSize[LLVertexBuffer::TYPE_VERTEX],
-                        target_indices,
-                        lod_error_threshold,
-                        &result_code);
+                    const LLVolumeFace &face = base->getVolumeFace(face_idx);
+
+                    // vertices
+                    S32 copy_bytes = face.mNumVertices * sizeof(LLVector4a);
+                    LLVector4a* dest = combined_positions + vertices_copied;
+                    LLVector4a::memcpyNonAliased16((F32*)dest, (F32*)face.mPositions, copy_bytes);
+                    vertices_copied += face.mNumVertices;
+
+                    // todo: figure if need to copy normals and text coords
+
+                    // indices, sadly can't do dumb memcpy for indices, we need to adjust each value
+                    for (S32 i = 0; i < face.mNumIndices; ++i)
+                    {
+                        U16 idx = face.mIndices[i];
+
+                        combined_indices[indices_copied] = idx + indices_shift;
+                        indices_copied++;
+                    }
+                    indices_shift += face.mNumVertices;
                 }
 
+                // Now that we have buffers, optimize
+                S32 target_indices = 0;
+                F32 result_code = 0; // how far from original the model is, 1 == 100%
+                S32 new_indices = 0;
+
+                target_indices = llmax(3, llfloor(size_indices * indices_ratio)); // leave at least one triangle
+                new_indices = LLMeshOptimizer::simplifyU32(
+                    output_indices,
+                    combined_indices,
+                    size_indices,
+                    combined_positions,
+                    size_vertices,
+                    LLVertexBuffer::sTypeSize[LLVertexBuffer::TYPE_VERTEX],
+                    target_indices,
+                    lod_error_threshold,
+                    &result_code);
+
 
                 if (result_code < 0)
                 {
-                    LL_WARNS() << "Negative result code from meshoptimizer for face " << face_idx
-                        << " of model " << target_model->mLabel
+                    LL_WARNS() << "Negative result code from meshoptimizer for model " << target_model->mLabel
                         << " target Indices: " << target_indices
                         << " new Indices: " << new_indices
-                        << " original count: " << num_indices << LL_ENDL;
+                        << " original count: " << size_indices << LL_ENDL;
                 }
 
-                LLVolumeFace &new_face = target_model->getVolumeFace(face_idx);
+                // repack back into individual faces
+                indices_shift = 0;
+                for (U32 face_idx = 0; face_idx < base->getNumVolumeFaces(); ++face_idx)
+                {
+                    const LLVolumeFace &face = base->getVolumeFace(face_idx);
+                    LLVolumeFace &new_face = target_model->getVolumeFace(face_idx);
+
+                    S32 size = (face.mNumIndices * sizeof(U16) + 0xF) & ~0xF;
+                    U16* output = (U16*)ll_aligned_malloc_16(size);
 
-                // Copy old values
-                new_face = face;
+                    // Copy old values
+                    new_face = face;
 
+                    // Fow now crude method to copy indices back into face
+                    // Should have been done in reverse - cycle by indices and figure out target face from id's size
+                    // Experiment
+                    S32 indices_copied = 0;
+                    for (S32 i = 0; i < new_indices / 3; ++i)
+                    {
+                        U32 position = i * 3;
+                        U32 idx1 = output_indices[position];
+                        U32 idx2 = output_indices[position+1];
+                        U32 idx3 = output_indices[position+2];
+
+                        bool copy = false;
+                        S32 range = indices_shift + face.mNumVertices;
+
+                        if (idx1 >= indices_shift && idx1 < range)
+                        {
+                            output[indices_copied] = idx1 - indices_shift;
+                            copy = true;
+                        }
+                        if (copy)
+                        {
+                            if (idx2 >= indices_shift && idx2 < range)
+                            {
+                                output[indices_copied + 1] = idx2 - indices_shift;
+                            }
+                            else
+                            {
+                                // todo: extend size of face's vertices list and add new vertices
+                                LL_WARNS_ONCE() << "incomplete code, dropped triangle" << LL_ENDL;
+                                output[indices_copied + 1] = 0;
+                            }
 
-                if (new_indices == 0)
+                            if (idx3 < face.mNumVertices)
+                            {
+                                output[indices_copied + 2] = idx3 - indices_shift;
+                            }
+                            else
+                            {
+                                // todo: extend size of face's vertices list and add new vertices
+                                LL_WARNS_ONCE() << "incomplete code, dropped triangle" << LL_ENDL;
+                                output[indices_copied + 2] = 0;
+                            }
+                        }
+                        if (copy)
+                        {
+                            indices_copied += 3;
+                        }
+
+                        new_face.resizeIndices(indices_copied);
+                        S32 idx_size = (indices_copied * sizeof(U16) + 0xF) & ~0xF;
+                        LLVector4a::memcpyNonAliased16((F32*)new_face.mIndices, (F32*)output, idx_size);
+
+                    }
+                    indices_shift += face.mNumVertices;
+
+                    if (indices_copied == 0)
+                    {
+                        new_face.resizeIndices(3);
+                        new_face.resizeVertices(1);
+                        memset(new_face.mIndices, 0, sizeof(U16) * 3);
+                        new_face.mPositions[0].clear(); // set first vertice to 0
+                        new_face.mNormals[0].clear();
+                        new_face.mTexCoords[0].setZero();
+                    }
+                }
+
+                ll_aligned_free<64>(combined_positions);
+                ll_aligned_free_32(output_indices);
+                ll_aligned_free_32(combined_indices);
+            }
+            else
+            {
+                // Run meshoptimizer for each face
+                for (U32 face_idx = 0; face_idx < base->getNumVolumeFaces(); ++face_idx)
                 {
-                    if (!sloppy)
+                    const LLVolumeFace &face = base->getVolumeFace(face_idx);
+                    S32 num_indices = face.mNumIndices;
+                    // todo: do not allocate per each face, add one large buffer somewhere
+                    // faces have limited amount of indices
+                    S32 size = (num_indices * sizeof(U16) + 0xF) & ~0xF;
+                    U16* output = (U16*)ll_aligned_malloc_16(size);
+
+                    /*
+                    generateShadowIndexBuffer appears to deform model
+                    LLMeshOptimizer::generateShadowIndexBuffer(
+                        &shadow[0],
+                        face.mIndices,
+                        num_indices,
+                        &face.mPositions[0],
+                        face.mNumVertices);
+                    */
+
+                    S32 target_indices = 0;
+                    F32 result_code = 0; // how far from original the model is, 1 == 100%
+                    S32 new_indices = 0;
+
+                    if (meshopt_mode == MESH_OPTIMIZER_SLOPPY)
+                    {
+                        target_indices = llfloor(num_indices * indices_ratio);
+                        new_indices = LLMeshOptimizer::simplifySloppy(
+                            output,
+                            face.mIndices,
+                            num_indices,
+                            face.mPositions,
+                            face.mNumVertices,
+                            LLVertexBuffer::sTypeSize[LLVertexBuffer::TYPE_VERTEX],
+                            target_indices,
+                            lod_error_threshold,
+                            &result_code);
+                    }
+
+                    if (meshopt_mode == MESH_OPTIMIZER)
                     {
-                        // optimizeSloppy() can optimize triangles away even if target_indices is > 2,
-                        // but optimize() isn't supposed to
-                        LL_INFOS() << "No indices generated by meshoptimizer for face " << face_idx
+                        target_indices = llmax(3, llfloor(num_indices * indices_ratio)); // leave at least one triangle
+                        new_indices = LLMeshOptimizer::simplify(
+                            output,
+                            face.mIndices,
+                            num_indices,
+                            face.mPositions,
+                            face.mNumVertices,
+                            LLVertexBuffer::sTypeSize[LLVertexBuffer::TYPE_VERTEX],
+                            target_indices,
+                            lod_error_threshold,
+                            &result_code);
+                    }
+
+
+                    if (result_code < 0)
+                    {
+                        LL_WARNS() << "Negative result code from meshoptimizer for face " << face_idx
                             << " of model " << target_model->mLabel
                             << " target Indices: " << target_indices
+                            << " new Indices: " << new_indices
                             << " original count: " << num_indices << LL_ENDL;
                     }
 
-                    // Face got optimized away
-                    // Generate empty triangle
-                    new_face.resizeIndices(3);
-                    new_face.resizeVertices(1);
-                    memset(new_face.mIndices, 0, sizeof(U16) * 3);
-                    new_face.mPositions[0].clear(); // set first vertice to 0
-                    new_face.mNormals[0].clear();
-                    new_face.mTexCoords[0].setZero();
-                }
-                else
-                {
-                    // Assign new values
-                    new_face.resizeIndices(new_indices); // will wipe out mIndices, so new_face can't substitute output
-                    S32 idx_size = (new_indices * sizeof(U16) + 0xF) & ~0xF;
-                    LLVector4a::memcpyNonAliased16((F32*)new_face.mIndices, (F32*)output, idx_size);
+                    LLVolumeFace &new_face = target_model->getVolumeFace(face_idx);
 
-                    // clear unused values
-                    new_face.optimize();
-                }
+                    // Copy old values
+                    new_face = face;
+
+
+                    if (new_indices == 0)
+                    {
+                        if (meshopt_mode != MESH_OPTIMIZER_SLOPPY)
+                        {
+                            // optimizeSloppy() can optimize triangles away even if target_indices is > 2,
+                            // but optimize() isn't supposed to
+                            LL_INFOS() << "No indices generated by meshoptimizer for face " << face_idx
+                                << " of model " << target_model->mLabel
+                                << " target Indices: " << target_indices
+                                << " original count: " << num_indices << LL_ENDL;
+                        }
+
+                        // Face got optimized away
+                        // Generate empty triangle
+                        new_face.resizeIndices(3);
+                        new_face.resizeVertices(1);
+                        memset(new_face.mIndices, 0, sizeof(U16) * 3);
+                        new_face.mPositions[0].clear(); // set first vertice to 0
+                        new_face.mNormals[0].clear();
+                        new_face.mTexCoords[0].setZero();
+                    }
+                    else
+                    {
+                        // Assign new values
+                        new_face.resizeIndices(new_indices); // will wipe out mIndices, so new_face can't substitute output
+                        S32 idx_size = (new_indices * sizeof(U16) + 0xF) & ~0xF;
+                        LLVector4a::memcpyNonAliased16((F32*)new_face.mIndices, (F32*)output, idx_size);
 
-                ll_aligned_free_16(output);
+                        // clear unused values
+                        new_face.optimize();
+                    }
+
+                    ll_aligned_free_16(output);
+                }
             }
 
             //blind copy skin weights and just take closest skin weight to point on
@@ -3833,7 +3994,7 @@ bool LLModelPreview::lodQueryCallback()
         {
             S32 lod = preview->mLodsQuery.back();
             preview->mLodsQuery.pop_back();
-            preview->genMeshOptimizerLODs(lod);
+            preview->genMeshOptimizerLODs(lod, MESH_OPTIMIZER);
 
             if (preview->mLookUpLodFiles && (lod == LLModel::LOD_HIGH))
             {
@@ -3857,11 +4018,11 @@ void LLModelPreview::onLODGenerateParamCommit(S32 lod, bool enforce_tri_limit)
     }
 }
 
-void LLModelPreview::onLODMeshOptimizerParamCommit(S32 requested_lod, bool enforce_tri_limit, bool sloppy)
+void LLModelPreview::onLODMeshOptimizerParamCommit(S32 requested_lod, bool enforce_tri_limit, S32 mode)
 {
     if (!mLODFrozen)
     {
-        genMeshOptimizerLODs(requested_lod, 3, enforce_tri_limit, sloppy);
+        genMeshOptimizerLODs(requested_lod, mode, 3, enforce_tri_limit);
         refresh();
     }
 }
diff --git a/indra/newview/llmodelpreview.h b/indra/newview/llmodelpreview.h
index 9f38156ca2..b784345b5a 100644
--- a/indra/newview/llmodelpreview.h
+++ b/indra/newview/llmodelpreview.h
@@ -127,6 +127,7 @@ public:
         GENERATE,
         MESH_OPTIMIZER,
         MESH_OPTIMIZER_SLOPPY,
+        MESH_OPTIMIZER_COMBINE,
         USE_LOD_ABOVE,
     } eLoDMode;
 
@@ -164,7 +165,7 @@ public:
     bool lodsReady() { return !mGenLOD && mLodsQuery.empty(); }
     void queryLODs() { mGenLOD = true; };
     void genGlodLODs(S32 which_lod = -1, U32 decimation = 3, bool enforce_tri_limit = false);
-    void genMeshOptimizerLODs(S32 which_lod = -1, U32 decimation = 3, bool enforce_tri_limit = false, bool sloppy = false);
+    void genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 decimation = 3, bool enforce_tri_limit = false);
     void generateNormals();
     void restoreNormals();
     U32 calcResourceCost();
@@ -176,7 +177,7 @@ public:
     void updateLodControls(S32 lod);
     void clearGLODGroup();
     void onLODGenerateParamCommit(S32 lod, bool enforce_tri_limit);
-    void onLODMeshOptimizerParamCommit(S32 lod, bool enforce_tri_limit, bool sloppy);
+    void onLODMeshOptimizerParamCommit(S32 lod, bool enforce_tri_limit, S32 mode);
     void addEmptyFace(LLModel* pTarget);
 
     const bool getModelPivot(void) const { return mHasPivot; }
diff --git a/indra/newview/skins/default/xui/en/floater_model_preview.xml b/indra/newview/skins/default/xui/en/floater_model_preview.xml
index 230284555c..5c78ef55d1 100644
--- a/indra/newview/skins/default/xui/en/floater_model_preview.xml
+++ b/indra/newview/skins/default/xui/en/floater_model_preview.xml
@@ -184,6 +184,10 @@
                  name="MeshOptSloppy"
                  label="MeshOptSloppy"
                  value="MeshOptSloppy" />
+                <item
+                 name="MeshOptCombine"
+                 label="MeshOptCombine"
+                 value="MeshOptCombine" />
             </combo_box>
             <line_editor
              follows="left|top"
@@ -321,6 +325,10 @@
                  name="MeshOptSloppy"
                  label="MeshOptSloppy"
                  value="MeshOptSloppy" />
+                <item
+                 name="MeshOptCombine"
+                 label="MeshOptCombine"
+                 value="MeshOptCombine" />
                 <item
                  name="Use LoD above"
                  label="Use LoD above"
@@ -462,6 +470,10 @@
                  name="MeshOptSloppy"
                  label="MeshOptSloppy"
                  value="MeshOptSloppy" />
+                <item
+                 name="MeshOptCombine"
+                 label="MeshOptCombine"
+                 value="MeshOptCombine" />
                 <item
                  name="Use LoD above"
                  label="Use LoD above"
@@ -603,6 +615,10 @@
                  name="MeshOptSloppy"
                  label="MeshOptSloppy"
                  value="MeshOptSloppy" />
+                <item
+                 name="MeshOptCombine"
+                 label="MeshOptCombine"
+                 value="MeshOptCombine" />
                 <item
                  name="Use LoD above"
                  label="Use LoD above"
-- 
cgit v1.2.3


From 8e725e74aa4cebdc472844252adf5b2952f7e3ff Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Mon, 26 Jul 2021 21:20:53 +0300
Subject: DRTVWR-542 Attempt to simplify all faces of an object as a whole and
 split back into faces #2

---
 indra/llmath/llvolume.cpp        |   4 +-
 indra/newview/llmodelpreview.cpp | 111 ++++++++++++++++++++++++++++-----------
 2 files changed, 82 insertions(+), 33 deletions(-)

(limited to 'indra')

diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp
index e085fa6ada..b036ece71e 100644
--- a/indra/llmath/llvolume.cpp
+++ b/indra/llmath/llvolume.cpp
@@ -6327,9 +6327,9 @@ void LLVolumeFace::resizeVertices(S32 num_verts)
 	if (num_verts)
 	{
 		//pad texture coordinate block end to allow for QWORD reads
-		S32 size = ((num_verts*sizeof(LLVector2)) + 0xF) & ~0xF;
+		S32 tc_size = ((num_verts*sizeof(LLVector2)) + 0xF) & ~0xF;
 
-		mPositions = (LLVector4a*) ll_aligned_malloc<64>(sizeof(LLVector4a)*2*num_verts+size);
+		mPositions = (LLVector4a*) ll_aligned_malloc<64>(sizeof(LLVector4a)*2*num_verts+tc_size);
 		mNormals = mPositions+num_verts;
 		mTexCoords = (LLVector2*) (mNormals+num_verts);
 
diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp
index 6542ac9090..b68162e374 100644
--- a/indra/newview/llmodelpreview.cpp
+++ b/indra/newview/llmodelpreview.cpp
@@ -1857,12 +1857,14 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d
                 U32* combined_indices = (U32*)ll_aligned_malloc_32(size_indices * sizeof(U32));
                 U32* output_indices = (U32*)ll_aligned_malloc_32(size_indices * sizeof(U32));
 
-                // extra space for normals and text coords, is it needed?
-                S32 size = ((size_vertices * sizeof(LLVector2)) + 0xF) & ~0xF;
-                LLVector4a* combined_positions = (LLVector4a*)ll_aligned_malloc<64>(sizeof(LLVector4a) * 2 * size_vertices + size);
+                // extra space for normals and text coords
+                S32 tc_bytes_size = ((size_vertices * sizeof(LLVector2)) + 0xF) & ~0xF;
+                LLVector4a* combined_positions = (LLVector4a*)ll_aligned_malloc<64>(sizeof(LLVector4a) * 2 * size_vertices + tc_bytes_size);
+                LLVector4a* combined_normals = combined_positions + size_vertices;
+                LLVector2* combined_tex_coords = (LLVector2*)(combined_normals + size_vertices);
 
                 // copy indices and vertices into new buffers
-                S32 vertices_copied = 0;
+                S32 positions_copied = 0;
                 S32 indices_shift = 0;
                 S32 indices_copied = 0;
                 for (U32 face_idx = 0; face_idx < base->getNumVolumeFaces(); ++face_idx)
@@ -1871,13 +1873,18 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d
 
                     // vertices
                     S32 copy_bytes = face.mNumVertices * sizeof(LLVector4a);
-                    LLVector4a* dest = combined_positions + vertices_copied;
-                    LLVector4a::memcpyNonAliased16((F32*)dest, (F32*)face.mPositions, copy_bytes);
-                    vertices_copied += face.mNumVertices;
+                    LLVector4a::memcpyNonAliased16((F32*)(combined_positions + positions_copied), (F32*)face.mPositions, copy_bytes);
 
-                    // todo: figure if need to copy normals and text coords
+                    // normals
+                    LLVector4a::memcpyNonAliased16((F32*)(combined_normals + positions_copied), (F32*)face.mNormals, copy_bytes);
 
-                    // indices, sadly can't do dumb memcpy for indices, we need to adjust each value
+                    // tex coords
+                    copy_bytes = (face.mNumVertices * sizeof(LLVector2) + 0xF) & ~0xF;
+                    LLVector4a::memcpyNonAliased16((F32*)(combined_tex_coords + positions_copied), (F32*)face.mTexCoords, copy_bytes);
+
+                    positions_copied += face.mNumVertices;
+
+                    // indices, sadly can't do dumb memcpy for indices, need to adjust each value
                     for (S32 i = 0; i < face.mNumIndices; ++i)
                     {
                         U16 idx = face.mIndices[i];
@@ -1916,20 +1923,31 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d
 
                 // repack back into individual faces
                 indices_shift = 0;
+
+                LLVector4a* buffer_positions = (LLVector4a*)ll_aligned_malloc<64>(sizeof(LLVector4a) * 2 * size_vertices + tc_bytes_size);
+                LLVector4a* buffer_normals = buffer_positions + size_vertices;
+                LLVector2* buffer_tex_coords = (LLVector2*)(buffer_normals + size_vertices);
+                S32 position_buffer_known_size = 0;
+
+                U16* buffer_indices = (U16*)ll_aligned_malloc_16(U16_MAX * sizeof(U16));
+
+                // Crude method to copy indices back into face
+                // Should have been done in reverse - cycle by indices and figure out target face from ids
                 for (U32 face_idx = 0; face_idx < base->getNumVolumeFaces(); ++face_idx)
                 {
                     const LLVolumeFace &face = base->getVolumeFace(face_idx);
-                    LLVolumeFace &new_face = target_model->getVolumeFace(face_idx);
 
-                    S32 size = (face.mNumIndices * sizeof(U16) + 0xF) & ~0xF;
-                    U16* output = (U16*)ll_aligned_malloc_16(size);
+                    // copy face's original data
+                    S32 copy_bytes = face.mNumVertices * sizeof(LLVector4a);
+                    LLVector4a::memcpyNonAliased16((F32*)buffer_positions, (F32*)face.mPositions, copy_bytes);
+                    LLVector4a::memcpyNonAliased16((F32*)buffer_normals, (F32*)face.mNormals, copy_bytes);
 
-                    // Copy old values
-                    new_face = face;
+                    copy_bytes = (face.mNumVertices * sizeof(LLVector2) + 0xF) & ~0xF;
+                    LLVector4a::memcpyNonAliased16((F32*)buffer_tex_coords, (F32*)face.mTexCoords, copy_bytes);
 
-                    // Fow now crude method to copy indices back into face
-                    // Should have been done in reverse - cycle by indices and figure out target face from id's size
-                    // Experiment
+                    position_buffer_known_size = face.mNumVertices;
+
+                    // Copy indices
                     S32 indices_copied = 0;
                     for (S32 i = 0; i < new_indices / 3; ++i)
                     {
@@ -1941,49 +1959,60 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d
                         bool copy = false;
                         S32 range = indices_shift + face.mNumVertices;
 
+                        // todo: we should not copy more than U16_MAX items per face
                         if (idx1 >= indices_shift && idx1 < range)
                         {
-                            output[indices_copied] = idx1 - indices_shift;
+                            buffer_indices[indices_copied] = idx1 - indices_shift;
                             copy = true;
                         }
                         if (copy)
                         {
                             if (idx2 >= indices_shift && idx2 < range)
                             {
-                                output[indices_copied + 1] = idx2 - indices_shift;
+                                buffer_indices[indices_copied + 1] = idx2 - indices_shift;
                             }
                             else
                             {
-                                // todo: extend size of face's vertices list and add new vertices
-                                LL_WARNS_ONCE() << "incomplete code, dropped triangle" << LL_ENDL;
-                                output[indices_copied + 1] = 0;
+                                // Extend size of face's positions list
+                                buffer_indices[indices_copied + 1] = (U16)position_buffer_known_size;
+                                buffer_positions[position_buffer_known_size] = combined_positions[idx2];
+                                buffer_normals[position_buffer_known_size] = combined_normals[idx2];
+                                buffer_tex_coords[position_buffer_known_size] = combined_tex_coords[idx2];
+                                position_buffer_known_size++;
+
+                                LL_WARNS_ONCE() << "Merged triangle into different face" << LL_ENDL;
                             }
 
                             if (idx3 < face.mNumVertices)
                             {
-                                output[indices_copied + 2] = idx3 - indices_shift;
+                                buffer_indices[indices_copied + 2] = idx3 - indices_shift;
                             }
                             else
                             {
-                                // todo: extend size of face's vertices list and add new vertices
-                                LL_WARNS_ONCE() << "incomplete code, dropped triangle" << LL_ENDL;
-                                output[indices_copied + 2] = 0;
+                                // Extend size of face's positions list
+                                buffer_indices[indices_copied + 2] = position_buffer_known_size;
+                                buffer_positions[position_buffer_known_size] = combined_positions[idx3];
+                                buffer_normals[position_buffer_known_size] = combined_normals[idx3];
+                                buffer_tex_coords[position_buffer_known_size] = combined_tex_coords[idx3];
+                                position_buffer_known_size++;
+
+                                LL_WARNS_ONCE() << "Merged triangle into different face" << LL_ENDL;
                             }
                         }
+
                         if (copy)
                         {
                             indices_copied += 3;
                         }
 
-                        new_face.resizeIndices(indices_copied);
-                        S32 idx_size = (indices_copied * sizeof(U16) + 0xF) & ~0xF;
-                        LLVector4a::memcpyNonAliased16((F32*)new_face.mIndices, (F32*)output, idx_size);
-
                     }
-                    indices_shift += face.mNumVertices;
+
+                    LLVolumeFace &new_face = target_model->getVolumeFace(face_idx);
+                    //new_face = face; //temp
 
                     if (indices_copied == 0)
                     {
+                        // face was optimized away
                         new_face.resizeIndices(3);
                         new_face.resizeVertices(1);
                         memset(new_face.mIndices, 0, sizeof(U16) * 3);
@@ -1991,10 +2020,30 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d
                         new_face.mNormals[0].clear();
                         new_face.mTexCoords[0].setZero();
                     }
+                    else
+                    {
+                        new_face.resizeIndices(indices_copied);
+                        new_face.resizeVertices(position_buffer_known_size);
+
+                        S32 idx_size = (indices_copied * sizeof(U16) + 0xF) & ~0xF;
+                        LLVector4a::memcpyNonAliased16((F32*)new_face.mIndices, (F32*)buffer_indices, idx_size);
+
+                        LLVector4a::memcpyNonAliased16((F32*)new_face.mPositions, (F32*)buffer_positions, position_buffer_known_size * sizeof(LLVector4a));
+                        LLVector4a::memcpyNonAliased16((F32*)new_face.mNormals, (F32*)buffer_normals, position_buffer_known_size * sizeof(LLVector4a));
+
+                        U32 tex_size = (position_buffer_known_size * sizeof(LLVector2) + 0xF)&~0xF;
+                        LLVector4a::memcpyNonAliased16((F32*)new_face.mTexCoords, (F32*)buffer_tex_coords, tex_size);
+
+                        new_face.optimize();
+                    }
+
+                    indices_shift += face.mNumVertices;
                 }
 
                 ll_aligned_free<64>(combined_positions);
+                ll_aligned_free<64>(buffer_positions);
                 ll_aligned_free_32(output_indices);
+                ll_aligned_free_32(buffer_indices);
                 ll_aligned_free_32(combined_indices);
             }
             else
-- 
cgit v1.2.3


From 61d2717cfc58ade1f0a4647698603c146ee9e012 Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Tue, 27 Jul 2021 18:54:44 +0300
Subject: DRTVWR-542 Attempt to simplify all faces of an object as a whole and
 split back into faces #3

---
 indra/newview/llmodelpreview.cpp | 141 +++++++++++++++++++--------------------
 1 file changed, 67 insertions(+), 74 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp
index b68162e374..f005eb0436 100644
--- a/indra/newview/llmodelpreview.cpp
+++ b/indra/newview/llmodelpreview.cpp
@@ -1864,35 +1864,35 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d
                 LLVector2* combined_tex_coords = (LLVector2*)(combined_normals + size_vertices);
 
                 // copy indices and vertices into new buffers
-                S32 positions_copied = 0;
-                S32 indices_shift = 0;
-                S32 indices_copied = 0;
+                S32 combined_positions_shift = 0;
+                S32 indices_idx_shift = 0;
+                S32 combined_indices_shift = 0;
                 for (U32 face_idx = 0; face_idx < base->getNumVolumeFaces(); ++face_idx)
                 {
                     const LLVolumeFace &face = base->getVolumeFace(face_idx);
 
                     // vertices
                     S32 copy_bytes = face.mNumVertices * sizeof(LLVector4a);
-                    LLVector4a::memcpyNonAliased16((F32*)(combined_positions + positions_copied), (F32*)face.mPositions, copy_bytes);
+                    LLVector4a::memcpyNonAliased16((F32*)(combined_positions + combined_positions_shift), (F32*)face.mPositions, copy_bytes);
 
                     // normals
-                    LLVector4a::memcpyNonAliased16((F32*)(combined_normals + positions_copied), (F32*)face.mNormals, copy_bytes);
+                    LLVector4a::memcpyNonAliased16((F32*)(combined_normals + combined_positions_shift), (F32*)face.mNormals, copy_bytes);
 
                     // tex coords
                     copy_bytes = (face.mNumVertices * sizeof(LLVector2) + 0xF) & ~0xF;
-                    LLVector4a::memcpyNonAliased16((F32*)(combined_tex_coords + positions_copied), (F32*)face.mTexCoords, copy_bytes);
+                    LLVector4a::memcpyNonAliased16((F32*)(combined_tex_coords + combined_positions_shift), (F32*)face.mTexCoords, copy_bytes);
 
-                    positions_copied += face.mNumVertices;
+                    combined_positions_shift += face.mNumVertices;
 
                     // indices, sadly can't do dumb memcpy for indices, need to adjust each value
                     for (S32 i = 0; i < face.mNumIndices; ++i)
                     {
                         U16 idx = face.mIndices[i];
 
-                        combined_indices[indices_copied] = idx + indices_shift;
-                        indices_copied++;
+                        combined_indices[combined_indices_shift] = idx + indices_idx_shift;
+                        combined_indices_shift++;
                     }
-                    indices_shift += face.mNumVertices;
+                    indices_idx_shift += face.mNumVertices;
                 }
 
                 // Now that we have buffers, optimize
@@ -1922,95 +1922,87 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d
                 }
 
                 // repack back into individual faces
-                indices_shift = 0;
 
                 LLVector4a* buffer_positions = (LLVector4a*)ll_aligned_malloc<64>(sizeof(LLVector4a) * 2 * size_vertices + tc_bytes_size);
                 LLVector4a* buffer_normals = buffer_positions + size_vertices;
                 LLVector2* buffer_tex_coords = (LLVector2*)(buffer_normals + size_vertices);
-                S32 position_buffer_known_size = 0;
-
                 U16* buffer_indices = (U16*)ll_aligned_malloc_16(U16_MAX * sizeof(U16));
+                S32* old_to_new_positions_map = new S32[size_vertices];
+
+                S32 buf_positions_copied = 0;
+                S32 buf_indices_copied = 0;
+                indices_idx_shift = 0;
 
                 // Crude method to copy indices back into face
-                // Should have been done in reverse - cycle by indices and figure out target face from ids
                 for (U32 face_idx = 0; face_idx < base->getNumVolumeFaces(); ++face_idx)
                 {
                     const LLVolumeFace &face = base->getVolumeFace(face_idx);
 
-                    // copy face's original data
-                    S32 copy_bytes = face.mNumVertices * sizeof(LLVector4a);
-                    LLVector4a::memcpyNonAliased16((F32*)buffer_positions, (F32*)face.mPositions, copy_bytes);
-                    LLVector4a::memcpyNonAliased16((F32*)buffer_normals, (F32*)face.mNormals, copy_bytes);
-
-                    copy_bytes = (face.mNumVertices * sizeof(LLVector2) + 0xF) & ~0xF;
-                    LLVector4a::memcpyNonAliased16((F32*)buffer_tex_coords, (F32*)face.mTexCoords, copy_bytes);
-
-                    position_buffer_known_size = face.mNumVertices;
+                    // reset data for new run
+                    buf_positions_copied = 0;
+                    buf_indices_copied = 0;
+                    bool copy_triangle = false;
+                    S32 range = indices_idx_shift + face.mNumVertices;
 
-                    // Copy indices
-                    S32 indices_copied = 0;
-                    for (S32 i = 0; i < new_indices / 3; ++i)
+                    for (S32 i = 0; i < size_vertices; i++)
                     {
-                        U32 position = i * 3;
-                        U32 idx1 = output_indices[position];
-                        U32 idx2 = output_indices[position+1];
-                        U32 idx3 = output_indices[position+2];
+                        old_to_new_positions_map[i] = -1;
+                    }
 
-                        bool copy = false;
-                        S32 range = indices_shift + face.mNumVertices;
+                    // Copy relevant indices and vertices
+                    for (S32 i = 0; i < new_indices; ++i)
+                    {
+                        U32 idx = output_indices[i];
 
-                        // todo: we should not copy more than U16_MAX items per face
-                        if (idx1 >= indices_shift && idx1 < range)
+                        if ((i % 3) == 0)
                         {
-                            buffer_indices[indices_copied] = idx1 - indices_shift;
-                            copy = true;
+                            copy_triangle = idx >= indices_idx_shift && idx < range;
                         }
-                        if (copy)
+
+                        if (copy_triangle)
                         {
-                            if (idx2 >= indices_shift && idx2 < range)
+                            if (idx >= U16_MAX)
                             {
-                                buffer_indices[indices_copied + 1] = idx2 - indices_shift;
-                            }
-                            else
-                            {
-                                // Extend size of face's positions list
-                                buffer_indices[indices_copied + 1] = (U16)position_buffer_known_size;
-                                buffer_positions[position_buffer_known_size] = combined_positions[idx2];
-                                buffer_normals[position_buffer_known_size] = combined_normals[idx2];
-                                buffer_tex_coords[position_buffer_known_size] = combined_tex_coords[idx2];
-                                position_buffer_known_size++;
-
-                                LL_WARNS_ONCE() << "Merged triangle into different face" << LL_ENDL;
+                                // Shouldn't happen due to simplification?
+                                // Todo: add a fallback?
+                                LL_ERRS() << "Over triangle limit" << LL_ENDL;
+                                break;
                             }
 
-                            if (idx3 < face.mNumVertices)
+                            if (old_to_new_positions_map[idx] == -1)
                             {
-                                buffer_indices[indices_copied + 2] = idx3 - indices_shift;
+                                // New position, need to copy it
+                                // Validate size
+                                if (buf_positions_copied >= U16_MAX)
+                                {
+                                    // Shouldn't happen due to simplification?
+                                    LL_ERRS() << "Over triangle limit" << LL_ENDL;
+                                    break;
+                                }
+
+                                // Copy vertice, normals, tcs
+                                buffer_positions[buf_positions_copied] = combined_positions[idx];
+                                buffer_normals[buf_positions_copied] = combined_normals[idx];
+                                buffer_tex_coords[buf_positions_copied] = combined_tex_coords[idx];
+
+                                old_to_new_positions_map[idx] = buf_positions_copied;
+
+                                buffer_indices[buf_indices_copied] = (U16)buf_positions_copied;
+                                buf_positions_copied++;
                             }
                             else
                             {
-                                // Extend size of face's positions list
-                                buffer_indices[indices_copied + 2] = position_buffer_known_size;
-                                buffer_positions[position_buffer_known_size] = combined_positions[idx3];
-                                buffer_normals[position_buffer_known_size] = combined_normals[idx3];
-                                buffer_tex_coords[position_buffer_known_size] = combined_tex_coords[idx3];
-                                position_buffer_known_size++;
-
-                                LL_WARNS_ONCE() << "Merged triangle into different face" << LL_ENDL;
+                                // existing position
+                                buffer_indices[buf_indices_copied] = (U16)old_to_new_positions_map[idx];
                             }
+                            buf_indices_copied++;
                         }
-
-                        if (copy)
-                        {
-                            indices_copied += 3;
-                        }
-
                     }
 
                     LLVolumeFace &new_face = target_model->getVolumeFace(face_idx);
                     //new_face = face; //temp
 
-                    if (indices_copied == 0)
+                    if (buf_indices_copied < 3)
                     {
                         // face was optimized away
                         new_face.resizeIndices(3);
@@ -2022,24 +2014,25 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d
                     }
                     else
                     {
-                        new_face.resizeIndices(indices_copied);
-                        new_face.resizeVertices(position_buffer_known_size);
+                        new_face.resizeIndices(buf_indices_copied);
+                        new_face.resizeVertices(buf_positions_copied);
 
-                        S32 idx_size = (indices_copied * sizeof(U16) + 0xF) & ~0xF;
+                        S32 idx_size = (buf_indices_copied * sizeof(U16) + 0xF) & ~0xF;
                         LLVector4a::memcpyNonAliased16((F32*)new_face.mIndices, (F32*)buffer_indices, idx_size);
 
-                        LLVector4a::memcpyNonAliased16((F32*)new_face.mPositions, (F32*)buffer_positions, position_buffer_known_size * sizeof(LLVector4a));
-                        LLVector4a::memcpyNonAliased16((F32*)new_face.mNormals, (F32*)buffer_normals, position_buffer_known_size * sizeof(LLVector4a));
+                        LLVector4a::memcpyNonAliased16((F32*)new_face.mPositions, (F32*)buffer_positions, buf_positions_copied * sizeof(LLVector4a));
+                        LLVector4a::memcpyNonAliased16((F32*)new_face.mNormals, (F32*)buffer_normals, buf_positions_copied * sizeof(LLVector4a));
 
-                        U32 tex_size = (position_buffer_known_size * sizeof(LLVector2) + 0xF)&~0xF;
+                        U32 tex_size = (buf_positions_copied * sizeof(LLVector2) + 0xF)&~0xF;
                         LLVector4a::memcpyNonAliased16((F32*)new_face.mTexCoords, (F32*)buffer_tex_coords, tex_size);
 
                         new_face.optimize();
                     }
 
-                    indices_shift += face.mNumVertices;
+                    indices_idx_shift += face.mNumVertices;
                 }
 
+                delete []old_to_new_positions_map;
                 ll_aligned_free<64>(combined_positions);
                 ll_aligned_free<64>(buffer_positions);
                 ll_aligned_free_32(output_indices);
-- 
cgit v1.2.3


From d64b1bded9a0ff05d90f00d72b031a8c04715af7 Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Tue, 27 Jul 2021 20:14:39 +0300
Subject: DRTVWR-542 Already optimized

---
 indra/newview/llmodelpreview.cpp | 2 --
 1 file changed, 2 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp
index f005eb0436..3704cc2ea5 100644
--- a/indra/newview/llmodelpreview.cpp
+++ b/indra/newview/llmodelpreview.cpp
@@ -2025,8 +2025,6 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d
 
                         U32 tex_size = (buf_positions_copied * sizeof(LLVector2) + 0xF)&~0xF;
                         LLVector4a::memcpyNonAliased16((F32*)new_face.mTexCoords, (F32*)buffer_tex_coords, tex_size);
-
-                        new_face.optimize();
                     }
 
                     indices_idx_shift += face.mNumVertices;
-- 
cgit v1.2.3


From 1a782ed690e56bf81ec9073041c7559e1762855d Mon Sep 17 00:00:00 2001
From: Dave Houlton <euclid@lindenlab.com>
Date: Mon, 19 Jul 2021 16:26:33 -0600
Subject: SL-15595 update viewer autobuild to import tracy lib

---
 indra/cmake/Tracy.cmake       | 17 +++++++++++++++++
 indra/llcommon/CMakeLists.txt |  2 ++
 indra/newview/CMakeLists.txt  |  3 +++
 3 files changed, 22 insertions(+)
 create mode 100644 indra/cmake/Tracy.cmake

(limited to 'indra')

diff --git a/indra/cmake/Tracy.cmake b/indra/cmake/Tracy.cmake
new file mode 100644
index 0000000000..bf09bccd4b
--- /dev/null
+++ b/indra/cmake/Tracy.cmake
@@ -0,0 +1,17 @@
+# -*- cmake -*-
+include(Prebuilt)
+
+set(TRACY ON CACHE BOOL "Use Tracy profiler.")
+
+if (TRACY)
+  set(TRACY_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include/tracy) 
+  if (WINDOWS)
+    use_prebuilt_binary(tracy)
+    set(TRACY_LIBRARY tracy)
+  else (WINDOWS)
+    set(TRACY_LIBRARY "")
+  endif (WINDOWS)
+else (TRACY)
+  set(TRACY_LIBRARY "")
+endif (TRACY)
+
diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt
index dd266630ea..f1b0506659 100644
--- a/indra/llcommon/CMakeLists.txt
+++ b/indra/llcommon/CMakeLists.txt
@@ -13,6 +13,7 @@ include(GoogleBreakpad)
 include(Copy3rdPartyLibs)
 include(ZLIB)
 include(URIPARSER)
+include(Tracy)
 
 include_directories(
     ${EXPAT_INCLUDE_DIRS}
@@ -21,6 +22,7 @@ include_directories(
     ${ZLIB_INCLUDE_DIRS}
     ${BREAKPAD_INCLUDE_DIRECTORIES}
     ${URIPARSER_INCLUDE_DIRS}
+    ${TRACY_INCLUDE_DIR}
     )
 
 # add_executable(lltreeiterators lltreeiterators.cpp)
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 2995a006ac..fbe75af712 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
@@ -2066,6 +2068,7 @@ target_link_libraries(${VIEWER_BINARY_NAME}
     ${LLPHYSICS_LIBRARIES}
     ${LLPHYSICSEXTENSIONS_LIBRARIES}
     ${LLAPPEARANCE_LIBRARIES}
+    ${TRACY_LIBRARY}
     )
 
 if (USE_BUGSPLAT)
-- 
cgit v1.2.3


From 1531a31cd9907e5294df5cedbda2b9d1e3adb68b Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Wed, 28 Jul 2021 21:25:18 +0300
Subject: DRTVWR-542 Rename simplification methods in UI and add a fallback

---
 indra/llmeshoptimizer/llmeshoptimizer.h            |  6 ++-
 indra/newview/llmodelpreview.cpp                   | 56 ++++++++++++----------
 .../skins/default/xui/en/floater_model_preview.xml | 24 +++++-----
 3 files changed, 46 insertions(+), 40 deletions(-)

(limited to 'indra')

diff --git a/indra/llmeshoptimizer/llmeshoptimizer.h b/indra/llmeshoptimizer/llmeshoptimizer.h
index 2696733eb2..e881ec26c5 100644
--- a/indra/llmeshoptimizer/llmeshoptimizer.h
+++ b/indra/llmeshoptimizer/llmeshoptimizer.h
@@ -46,6 +46,7 @@ public:
 
     // returns amount of indices in destiantion
     // result_error returns how far from original the model is in % if not NULL
+    // Works with U32 indices (LLFace uses U16 indices)
     static U64 simplifyU32(
         U32 *destination,
         const U32 *indices,
@@ -57,8 +58,9 @@ public:
         F32 target_error,
         F32* result_error);
 
-    // returns amount of indices in destiantion
-    // result_error returns how far from original the model is in % if not NULL
+    // Returns amount of indices in destiantion
+    // Result_error returns how far from original the model is in % if not NULL
+    // Meant for U16 indices (LLFace uses U16 indices)
     static U64 simplify(
         U16 *destination,
         const U16 *indices,
diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp
index 3704cc2ea5..96eb9340f5 100644
--- a/indra/newview/llmodelpreview.cpp
+++ b/indra/newview/llmodelpreview.cpp
@@ -1840,7 +1840,9 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d
 
             LLModel* target_model = mModel[lod][mdl_idx];
 
-            if (meshopt_mode == MESH_OPTIMIZER_COMBINE)
+            S32 model_meshopt_mode = meshopt_mode;
+
+            if (model_meshopt_mode == MESH_OPTIMIZER_COMBINE)
             {
                 // Figure out buffer size
                 S32 size_indices = 0;
@@ -1961,22 +1963,23 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d
 
                         if (copy_triangle)
                         {
-                            if (idx >= U16_MAX)
-                            {
-                                // Shouldn't happen due to simplification?
-                                // Todo: add a fallback?
-                                LL_ERRS() << "Over triangle limit" << LL_ENDL;
-                                break;
-                            }
-
                             if (old_to_new_positions_map[idx] == -1)
                             {
                                 // New position, need to copy it
                                 // Validate size
                                 if (buf_positions_copied >= U16_MAX)
                                 {
-                                    // Shouldn't happen due to simplification?
-                                    LL_ERRS() << "Over triangle limit" << LL_ENDL;
+                                    // Normally this shouldn't happen since the whole point is to reduce amount of vertices
+                                    // but it might happen if user tries to run optimization with too large triangle or error value
+                                    // so fallback to 'per face' mode or verify requested limits and copy base model as is.
+                                    LL_WARNS() << "Over triangle limit. Failed to optimize in 'per object' mode, falling back to per face variant for"
+                                               << " model " << target_model->mLabel
+                                               << " target Indices: " << target_indices
+                                               << " new Indices: " << new_indices
+                                               << " original count: " << size_indices
+                                               << " error treshold: " << lod_error_threshold
+                                               << LL_ENDL;
+                                    model_meshopt_mode = MESH_OPTIMIZER;
                                     break;
                                 }
 
@@ -1999,6 +2002,11 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d
                         }
                     }
 
+                    if (buf_positions_copied >= U16_MAX)
+                    {
+                        break;
+                    }
+
                     LLVolumeFace &new_face = target_model->getVolumeFace(face_idx);
                     //new_face = face; //temp
 
@@ -2037,7 +2045,9 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d
                 ll_aligned_free_32(buffer_indices);
                 ll_aligned_free_32(combined_indices);
             }
-            else
+            
+            if (model_meshopt_mode == MESH_OPTIMIZER
+                || model_meshopt_mode == MESH_OPTIMIZER_SLOPPY)
             {
                 // Run meshoptimizer for each face
                 for (U32 face_idx = 0; face_idx < base->getNumVolumeFaces(); ++face_idx)
@@ -2049,21 +2059,11 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d
                     S32 size = (num_indices * sizeof(U16) + 0xF) & ~0xF;
                     U16* output = (U16*)ll_aligned_malloc_16(size);
 
-                    /*
-                    generateShadowIndexBuffer appears to deform model
-                    LLMeshOptimizer::generateShadowIndexBuffer(
-                        &shadow[0],
-                        face.mIndices,
-                        num_indices,
-                        &face.mPositions[0],
-                        face.mNumVertices);
-                    */
-
                     S32 target_indices = 0;
                     F32 result_code = 0; // how far from original the model is, 1 == 100%
                     S32 new_indices = 0;
 
-                    if (meshopt_mode == MESH_OPTIMIZER_SLOPPY)
+                    if (model_meshopt_mode == MESH_OPTIMIZER_SLOPPY)
                     {
                         target_indices = llfloor(num_indices * indices_ratio);
                         new_indices = LLMeshOptimizer::simplifySloppy(
@@ -2078,7 +2078,7 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d
                             &result_code);
                     }
 
-                    if (meshopt_mode == MESH_OPTIMIZER)
+                    if (model_meshopt_mode == MESH_OPTIMIZER)
                     {
                         target_indices = llmax(3, llfloor(num_indices * indices_ratio)); // leave at least one triangle
                         new_indices = LLMeshOptimizer::simplify(
@@ -2100,7 +2100,9 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d
                             << " of model " << target_model->mLabel
                             << " target Indices: " << target_indices
                             << " new Indices: " << new_indices
-                            << " original count: " << num_indices << LL_ENDL;
+                            << " original count: " << num_indices
+                            << " error treshold: " << lod_error_threshold
+                            << LL_ENDL;
                     }
 
                     LLVolumeFace &new_face = target_model->getVolumeFace(face_idx);
@@ -2118,7 +2120,9 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d
                             LL_INFOS() << "No indices generated by meshoptimizer for face " << face_idx
                                 << " of model " << target_model->mLabel
                                 << " target Indices: " << target_indices
-                                << " original count: " << num_indices << LL_ENDL;
+                                << " original count: " << num_indices
+                                << " error treshold: " << lod_error_threshold
+                                << LL_ENDL;
                         }
 
                         // Face got optimized away
diff --git a/indra/newview/skins/default/xui/en/floater_model_preview.xml b/indra/newview/skins/default/xui/en/floater_model_preview.xml
index 5c78ef55d1..cd67adf42a 100644
--- a/indra/newview/skins/default/xui/en/floater_model_preview.xml
+++ b/indra/newview/skins/default/xui/en/floater_model_preview.xml
@@ -178,15 +178,15 @@
                  value="Generate" />
                 <item
                  name="MeshOpt"
-                 label="MeshOpt"
+                 label="Simplify per face"
                  value="MeshOpt" />
                 <item
                  name="MeshOptSloppy"
-                 label="MeshOptSloppy"
+                 label="Simplify sloppy"
                  value="MeshOptSloppy" />
                 <item
                  name="MeshOptCombine"
-                 label="MeshOptCombine"
+                 label="Simplify per object"
                  value="MeshOptCombine" />
             </combo_box>
             <line_editor
@@ -319,15 +319,15 @@
                  value="Generate" />
                 <item
                  name="MeshOpt"
-                 label="MeshOpt"
+                 label="Simplify per face"
                  value="MeshOpt" />
                 <item
                  name="MeshOptSloppy"
-                 label="MeshOptSloppy"
+                 label="Simplify sloppy"
                  value="MeshOptSloppy" />
                 <item
                  name="MeshOptCombine"
-                 label="MeshOptCombine"
+                 label="Simplify per object"
                  value="MeshOptCombine" />
                 <item
                  name="Use LoD above"
@@ -464,15 +464,15 @@
                  value="Generate" />
                 <item
                  name="MeshOpt"
-                 label="MeshOpt"
+                 label="Simplify per face"
                  value="MeshOpt" />
                 <item
                  name="MeshOptSloppy"
-                 label="MeshOptSloppy"
+                 label="Simplify sloppy"
                  value="MeshOptSloppy" />
                 <item
                  name="MeshOptCombine"
-                 label="MeshOptCombine"
+                 label="Simplify per object"
                  value="MeshOptCombine" />
                 <item
                  name="Use LoD above"
@@ -609,15 +609,15 @@
                  value="Generate" />
                 <item
                  name="MeshOpt"
-                 label="MeshOpt"
+                 label="Simplify per face"
                  value="MeshOpt" />
                 <item
                  name="MeshOptSloppy"
-                 label="MeshOptSloppy"
+                 label="Simplify sloppy"
                  value="MeshOptSloppy" />
                 <item
                  name="MeshOptCombine"
-                 label="MeshOptCombine"
+                 label="Simplify per object"
                  value="MeshOptCombine" />
                 <item
                  name="Use LoD above"
-- 
cgit v1.2.3


From 2d2ed85c56c0aa47e6909becaf60b71f1daaf46f Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Wed, 28 Jul 2021 21:30:49 +0300
Subject: DRTVWR-542 Fix malfunctioning warning

---
 indra/llmath/llvolume.h           | 16 +++++++++++-----
 indra/llprimitive/lldaeloader.cpp |  7 ++++++-
 2 files changed, 17 insertions(+), 6 deletions(-)

(limited to 'indra')

diff --git a/indra/llmath/llvolume.h b/indra/llmath/llvolume.h
index a77e8c08c6..c0b224b1ff 100644
--- a/indra/llmath/llvolume.h
+++ b/indra/llmath/llvolume.h
@@ -936,17 +936,23 @@ public:
 	LLVector4a* mCenter;
 	LLVector2   mTexCoordExtents[2]; //minimum and maximum of texture coordinates of the face.
 
-	S32 mNumVertices;
+	S32 mNumVertices; // num vertices == num normals == num texcoords
 	S32 mNumAllocatedVertices;
 	S32 mNumIndices;
 
-	LLVector4a* mPositions;
-	LLVector4a* mNormals;
+	LLVector4a* mPositions; // Contains vertices, nortmals and texcoords
+	LLVector4a* mNormals; // pointer into mPositions
 	LLVector4a* mTangents;
-	LLVector2*  mTexCoords;
+	LLVector2*  mTexCoords; // pointer into mPositions
+
+	// mIndices contains mNumIndices amount of elements.
+	// It contains triangles, each 3 indices describe one triangle.
+    // If mIndices contains {0, 2, 3, 1, 2, 4}, it means there
+    // are two triangles {0, 2, 3} and {1, 2, 4} with values being
+    // indexes for mPositions/mNormals/mTexCoords
 	U16* mIndices;
 
-	//vertex buffer filled in by LLFace to cache this volume face geometry in vram 
+	// vertex buffer filled in by LLFace to cache this volume face geometry in vram 
 	// (declared as a LLPointer to LLRefCount to avoid dependency on LLVertexBuffer)
 	mutable LLPointer<LLRefCount> mVertexBuffer; 
 
diff --git a/indra/llprimitive/lldaeloader.cpp b/indra/llprimitive/lldaeloader.cpp
index dfa29fb539..d3acd44f06 100644
--- a/indra/llprimitive/lldaeloader.cpp
+++ b/indra/llprimitive/lldaeloader.cpp
@@ -787,7 +787,12 @@ LLModel::EModelStatus load_face_from_dom_polygons(std::vector<LLVolumeFace>& fac
 	for (U32 i = 0; i < verts.size(); ++i)
 	{
 		indices[i] = vert_idx[verts[i]];
-		llassert(!i || (indices[i-1] != indices[i]));
+        if (i % 3 != 0) // assumes GL_TRIANGLES, compare 0-1, 1-2, 3-4, 4-5 but not 2-3 or 5-6
+        {
+            // A faulty degenerate triangle detection (triangle with 0 area),
+            // probably should be a warning and not an assert
+            llassert(!i || (indices[i-1] != indices[i]));
+        }
 	}
 
 	// DEBUG just build an expanded triangle list
-- 
cgit v1.2.3


From 7d5cd52498e3da2b2438ad82fe450c923541e798 Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Tue, 27 Jul 2021 15:31:15 -0700
Subject: SL-15709: Add Tracy support to viewer

---
 indra/cmake/LLCommon.cmake        |   2 +-
 indra/llcommon/CMakeLists.txt     |   1 +
 indra/llcommon/linden_common.h    |   2 +
 indra/llcommon/llfasttimer.h      |   3 +
 indra/llcommon/llprofiler.h       |  64 ++++++++++++++
 indra/llcommon/llthread.cpp       |   2 +
 indra/newview/llappviewer.cpp     |   2 +
 indra/newview/llviewerdisplay.cpp |  81 ++++++++++--------
 indra/newview/llvovolume.cpp      | 175 ++++++++++++++++++++------------------
 indra/newview/pipeline.cpp        | 123 ++++++++++++++-------------
 10 files changed, 276 insertions(+), 179 deletions(-)
 create mode 100644 indra/llcommon/llprofiler.h

(limited to 'indra')

diff --git a/indra/cmake/LLCommon.cmake b/indra/cmake/LLCommon.cmake
index 8900419f9b..c1cfa51cfb 100644
--- a/indra/cmake/LLCommon.cmake
+++ b/indra/cmake/LLCommon.cmake
@@ -30,7 +30,7 @@ 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/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt
index f1b0506659..28bf5d0c39 100644
--- a/indra/llcommon/CMakeLists.txt
+++ b/indra/llcommon/CMakeLists.txt
@@ -201,6 +201,7 @@ set(llcommon_HEADER_FILES
     llmortician.h
     llnametable.h
     llpointer.h
+    llprofiler.h
     llpounceable.h
     llpredicate.h
     llpreprocessor.h
diff --git a/indra/llcommon/linden_common.h b/indra/llcommon/linden_common.h
index e5a913a6a9..45ac43910c 100644
--- a/indra/llcommon/linden_common.h
+++ b/indra/llcommon/linden_common.h
@@ -60,4 +60,6 @@
 #include "llerror.h"
 #include "llfile.h"
 
+#include "llprofiler.h" // must be before fast timer; needed due to LLThreads potentially needing access to tracy
+
 #endif
diff --git a/indra/llcommon/llfasttimer.h b/indra/llcommon/llfasttimer.h
index dfc63d08a2..c7d5bb3761 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) // defined(LL_PROFILER_CONFIGURATION) && (LL_PROFILER_CONFIGURATION == LL_PROFILER_CONFIG_FAST_TIMER)
 #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/llprofiler.h b/indra/llcommon/llprofiler.h
new file mode 100644
index 0000000000..75954b9a79
--- /dev/null
+++ b/indra/llcommon/llprofiler.h
@@ -0,0 +1,64 @@
+/**
+ * @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
+
+#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
+        #define TRACY_NO_BROADCAST   1
+        #define TRACY_ONLY_LOCALHOST 1
+        #define TRACY_ONLY_IPV4      1
+        #include "Tracy.hpp"
+    #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)          ZoneNamedN( ___tracy_scoped_zone, #name, true );
+    #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__);
+    #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)          ZoneNamedN( ___tracy_scoped_zone, #timer_stat, true )   const LLTrace::BlockTimer& LL_GLUE_TOKENS(block_time_recorder, __LINE__)(LLTrace::timeThisBlock(name)); (void)LL_GLUE_TOKENS(block_time_recorder, __LINE__);
+    #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/llthread.cpp b/indra/llcommon/llthread.cpp
index 6d531d842d..a8cc750437 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();
 
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 79f1cc0e8f..94f0b31ecd 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -1667,6 +1667,8 @@ bool LLAppViewer::doFrame()
 		LL_INFOS() << "Exiting main_loop" << LL_ENDL;
 	}
 
+    LL_PROFILER_FRAME_END
+
 	return ! LLApp::isRunning();
 }
 
diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp
index 109dc93261..a590237440 100644
--- a/indra/newview/llviewerdisplay.cpp
+++ b/indra/newview/llviewerdisplay.cpp
@@ -1259,7 +1259,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();
 	
@@ -1274,7 +1274,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();
@@ -1282,55 +1282,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();
+
+		LLGLSDefault gls_default;
+		LLGLSUIDefault gls_ui;
+		{
+			gPipeline.disableLights();
+		}
 
-	{
-		gGL.color4f(1,1,1,1);
-		if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
 		{
-			if (!gDisconnected)
+			gGL.color4f(1,1,1,1);
+			if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
 			{
-                LL_RECORD_BLOCK_TIME(FTM_RENDER_UI_3D);
-				render_ui_3d();
+				if (!gDisconnected)
+				{
+					LL_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/llvovolume.cpp b/indra/newview/llvovolume.cpp
index f063800587..f9b2285989 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -6045,123 +6045,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/pipeline.cpp b/indra/newview/pipeline.cpp
index cd1b9c7c69..e7c2d4db39 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -4564,92 +4564,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)
-- 
cgit v1.2.3


From 908ce721792c7b549227e1ee23ae8b7b064ad439 Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Fri, 30 Jul 2021 09:36:38 -0700
Subject: SL-15709: Default to old fast timers

---
 indra/llcommon/llprofiler.h | 2 ++
 1 file changed, 2 insertions(+)

(limited to 'indra')

diff --git a/indra/llcommon/llprofiler.h b/indra/llcommon/llprofiler.h
index 75954b9a79..29331d35bf 100644
--- a/indra/llcommon/llprofiler.h
+++ b/indra/llcommon/llprofiler.h
@@ -32,6 +32,8 @@
 #define LL_PROFILER_CONFIG_TRACY            2  // Profiling on: Only Tracy
 #define LL_PROFILER_CONFIG_TRACY_FAST_TIMER 3  // Profiling on: Fast Timers + Tracy
 
+#define LL_PROFILER_CONFIGURATION           LL_PROFILER_CONFIG_FAST_TIMER
+
 #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
-- 
cgit v1.2.3


From 7235d333ea24388fc13a6d01dbafc707b658a0d4 Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Wed, 4 Aug 2021 00:15:49 +0300
Subject: DRTVWR-542 Fix incorect dropbox state

---
 indra/llprimitive/lldaeloader.cpp       | 1 +
 indra/llprimitive/llmodel.h             | 2 ++
 indra/newview/llfloatermodelpreview.cpp | 2 +-
 indra/newview/llfloatermodelpreview.h   | 4 +---
 indra/newview/llmodelpreview.cpp        | 8 +++++---
 5 files changed, 10 insertions(+), 7 deletions(-)

(limited to 'indra')

diff --git a/indra/llprimitive/lldaeloader.cpp b/indra/llprimitive/lldaeloader.cpp
index d3acd44f06..17e9e05edd 100644
--- a/indra/llprimitive/lldaeloader.cpp
+++ b/indra/llprimitive/lldaeloader.cpp
@@ -289,6 +289,7 @@ LLModel::EModelStatus load_face_from_dom_triangles(std::vector<LLVolumeFace>& fa
 				material = std::string(tri->getMaterial());
 			}
 
+            // Todo: mark model in some way as having generated(split) faces  
 			materials.push_back(material);
 			face_list.push_back(face);
 			face_list.rbegin()->fillFromLegacyData(verts, indices);
diff --git a/indra/llprimitive/llmodel.h b/indra/llprimitive/llmodel.h
index 51fa2f8079..96368d64e5 100644
--- a/indra/llprimitive/llmodel.h
+++ b/indra/llprimitive/llmodel.h
@@ -281,6 +281,8 @@ public:
 
 	EModelStatus mStatus ;
 
+    // A model/object can only have 8 faces, spillover faces will
+    // be moved to new model/object and assigned a submodel id.
 	int mSubmodelID;
 };
 
diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp
index 3f2fcb148c..e5d451e909 100644
--- a/indra/newview/llfloatermodelpreview.cpp
+++ b/indra/newview/llfloatermodelpreview.cpp
@@ -136,7 +136,7 @@ mAvatarTabIndex(0)
 	mStatusLock = new LLMutex();
 	mModelPreview = NULL;
 
-	mLODMode[LLModel::LOD_HIGH] = 0;
+	mLODMode[LLModel::LOD_HIGH] = LLModelPreview::LOD_FROM_FILE;
 	for (U32 i = 0; i < LLModel::LOD_HIGH; i++)
 	{
 		mLODMode[i] = LLModelPreview::MESH_OPTIMIZER;
diff --git a/indra/newview/llfloatermodelpreview.h b/indra/newview/llfloatermodelpreview.h
index 8a01b0c307..51f9b3a0e2 100644
--- a/indra/newview/llfloatermodelpreview.h
+++ b/indra/newview/llfloatermodelpreview.h
@@ -196,9 +196,7 @@ protected:
 	std::map<std::string, bool> mViewOptionDisabled;
 	
 	//store which lod mode each LOD is using
-	// 0 - load from file
-	// 1 - auto generate
-	// 2 - use LoD above
+	// See eLoDMode
 	S32 mLODMode[4];
 
 	LLMutex* mStatusLock;
diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp
index 96eb9340f5..11a536473c 100644
--- a/indra/newview/llmodelpreview.cpp
+++ b/indra/newview/llmodelpreview.cpp
@@ -1842,6 +1842,8 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d
 
             S32 model_meshopt_mode = meshopt_mode;
 
+            // Ideally this should run not per model,
+            // but combine all submodels with origin model as well
             if (model_meshopt_mode == MESH_OPTIMIZER_COMBINE)
             {
                 // Figure out buffer size
@@ -2758,7 +2760,7 @@ void LLModelPreview::updateLodControls(S32 lod)
     S32 lod_mode = lod_combo->getCurrentIndex();
     if (lod_mode == LOD_FROM_FILE) // LoD from file
     {
-        fmp->mLODMode[lod] = 0;
+        fmp->mLODMode[lod] = LOD_FROM_FILE;
         for (U32 i = 0; i < num_file_controls; ++i)
         {
             mFMP->childSetVisible(file_controls[i] + lod_name[lod], true);
@@ -2771,7 +2773,7 @@ void LLModelPreview::updateLodControls(S32 lod)
     }
     else if (lod_mode == USE_LOD_ABOVE) // use LoD above
     {
-        fmp->mLODMode[lod] = 2;
+        fmp->mLODMode[lod] = USE_LOD_ABOVE;
         for (U32 i = 0; i < num_file_controls; ++i)
         {
             mFMP->childSetVisible(file_controls[i] + lod_name[lod], false);
@@ -2797,7 +2799,7 @@ void LLModelPreview::updateLodControls(S32 lod)
     }
     else // auto generate, the default case for all LoDs except High
     {
-        fmp->mLODMode[lod] = 1;
+        fmp->mLODMode[lod] = MESH_OPTIMIZER;
 
         //don't actually regenerate lod when refreshing UI
         mLODFrozen = true;
-- 
cgit v1.2.3


From 1a1793244002effe46cedf63180de60f4bc69a9a Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Wed, 4 Aug 2021 21:14:00 +0300
Subject: DRTVWR-542 Automated method selection

Normally simplification methods apply for whole upload, but this one selects methods per model or per face.
---
 indra/llmeshoptimizer/llmeshoptimizer.cpp          |  97 ++--
 indra/llmeshoptimizer/llmeshoptimizer.h            |  21 +-
 indra/llprimitive/lldaeloader.cpp                  |  32 +-
 indra/llprimitive/llmodel.cpp                      |   3 +-
 indra/llprimitive/llmodel.h                        |   5 +
 indra/newview/llfloatermodelpreview.cpp            |   6 +-
 indra/newview/llmodelpreview.cpp                   | 631 +++++++++++----------
 indra/newview/llmodelpreview.h                     |   7 +-
 .../skins/default/xui/en/floater_model_preview.xml |  48 +-
 9 files changed, 481 insertions(+), 369 deletions(-)

(limited to 'indra')

diff --git a/indra/llmeshoptimizer/llmeshoptimizer.cpp b/indra/llmeshoptimizer/llmeshoptimizer.cpp
index 8097a05511..a879389c5a 100644
--- a/indra/llmeshoptimizer/llmeshoptimizer.cpp
+++ b/indra/llmeshoptimizer/llmeshoptimizer.cpp
@@ -67,19 +67,36 @@ U64 LLMeshOptimizer::simplifyU32(U32 *destination,
     U64 vertex_positions_stride,
     U64 target_index_count,
     F32 target_error,
+    bool sloppy,
     F32* result_error
 )
 {
-    return meshopt_simplify<unsigned int>(destination,
-        indices,
-        index_count,
-        (const float*)vertex_positions,
-        vertex_count,
-        vertex_positions_stride,
-        target_index_count,
-        target_error,
-        result_error
-        );
+    if (sloppy)
+    {
+        return meshopt_simplifySloppy<unsigned int>(destination,
+            indices,
+            index_count,
+            (const float*)vertex_positions,
+            vertex_count,
+            vertex_positions_stride,
+            target_index_count,
+            target_error,
+            result_error
+            );
+    }
+    else
+    {
+        return meshopt_simplify<unsigned int>(destination,
+            indices,
+            index_count,
+            (const float*)vertex_positions,
+            vertex_count,
+            vertex_positions_stride,
+            target_index_count,
+            target_error,
+            result_error
+            );
+    }
 }
 
 //static
@@ -91,41 +108,35 @@ U64 LLMeshOptimizer::simplify(U16 *destination,
                               U64 vertex_positions_stride,
                               U64 target_index_count,
                               F32 target_error,
+                              bool sloppy,
                               F32* result_error
     )
 {
-    return meshopt_simplify<unsigned short>(destination,
-                                 indices,
-                                 index_count,
-                                 (const float*)vertex_positions,
-                                 vertex_count,
-                                 vertex_positions_stride, 
-                                 target_index_count,
-                                 target_error,
-                                 result_error
-                                 );
+    if (sloppy)
+    {
+        return meshopt_simplifySloppy<unsigned short>(destination,
+            indices,
+            index_count,
+            (const float*)vertex_positions,
+            vertex_count,
+            vertex_positions_stride,
+            target_index_count,
+            target_error,
+            result_error
+            );
+    }
+    else
+    {
+        return meshopt_simplify<unsigned short>(destination,
+            indices,
+            index_count,
+            (const float*)vertex_positions,
+            vertex_count,
+            vertex_positions_stride,
+            target_index_count,
+            target_error,
+            result_error
+            );
+    }
 }
 
-//static
-U64 LLMeshOptimizer::simplifySloppy(U16 *destination,
-                              const U16 *indices,
-                              U64 index_count,
-                              const LLVector4a *vertex_positions,
-                              U64 vertex_count,
-    U64 vertex_positions_stride,
-                              U64 target_index_count,
-                              F32 target_error,
-                              F32* result_error
-    )
-{
-    return meshopt_simplifySloppy<unsigned short>(destination,
-                                 indices,
-                                 index_count,
-                                 (const float*)vertex_positions,
-                                 vertex_count,
-                                 vertex_positions_stride, 
-                                 target_index_count,
-                                 target_error,
-                                 result_error
-                                 );
-}
diff --git a/indra/llmeshoptimizer/llmeshoptimizer.h b/indra/llmeshoptimizer/llmeshoptimizer.h
index e881ec26c5..e8dd16dae9 100644
--- a/indra/llmeshoptimizer/llmeshoptimizer.h
+++ b/indra/llmeshoptimizer/llmeshoptimizer.h
@@ -45,6 +45,8 @@ public:
         U64 vertex_positions_stride);
 
     // returns amount of indices in destiantion
+    // sloppy engages a variant of a mechanizm that does not respect topology as much
+    // but is much more efective for simpler models
     // result_error returns how far from original the model is in % if not NULL
     // Works with U32 indices (LLFace uses U16 indices)
     static U64 simplifyU32(
@@ -56,10 +58,13 @@ public:
         U64 vertex_positions_stride,
         U64 target_index_count,
         F32 target_error,
+        bool sloppy,
         F32* result_error);
 
     // Returns amount of indices in destiantion
-    // Result_error returns how far from original the model is in % if not NULL
+    // sloppy engages a variant of a mechanizm that does not respect topology as much
+    // but is much better for simpler models
+    // result_error returns how far from original the model is in % if not NULL
     // Meant for U16 indices (LLFace uses U16 indices)
     static U64 simplify(
         U16 *destination,
@@ -70,19 +75,7 @@ public:
         U64 vertex_positions_stride,
         U64 target_index_count,
         F32 target_error,
-        F32* result_error);
-
-    // returns amount of indices in destiantion
-    // result_error returns how far from original the model is in % if not NULL
-    static U64 simplifySloppy(
-        U16 *destination,
-        const U16 *indices,
-        U64 index_count,
-        const LLVector4a *vertex_positions,
-        U64 vertex_count,
-        U64 vertex_positions_stride,
-        U64 target_index_count,
-        F32 target_error,
+        bool sloppy,
         F32* result_error);
 private:
 };
diff --git a/indra/llprimitive/lldaeloader.cpp b/indra/llprimitive/lldaeloader.cpp
index 17e9e05edd..dcf3b5fa0e 100644
--- a/indra/llprimitive/lldaeloader.cpp
+++ b/indra/llprimitive/lldaeloader.cpp
@@ -149,7 +149,11 @@ bool get_dom_sources(const domInputLocalOffset_Array& inputs, S32& pos_offset, S
 	return true;
 }
 
-LLModel::EModelStatus load_face_from_dom_triangles(std::vector<LLVolumeFace>& face_list, std::vector<std::string>& materials, domTrianglesRef& tri)
+LLModel::EModelStatus load_face_from_dom_triangles(
+    std::vector<LLVolumeFace>& face_list,
+    std::vector<std::string>& materials,
+    domTrianglesRef& tri,
+    bool &generated_additional_faces)
 {
 	LLVolumeFace face;
 	std::vector<LLVolumeFace::VertexData> verts;
@@ -282,6 +286,8 @@ LLModel::EModelStatus load_face_from_dom_triangles(std::vector<LLVolumeFace>& fa
 
 		if (indices.size()%3 == 0 && verts.size() >= 65532)
 		{
+            generated_additional_faces = true;
+
 			std::string material;
 
 			if (tri->getMaterial())
@@ -289,7 +295,6 @@ LLModel::EModelStatus load_face_from_dom_triangles(std::vector<LLVolumeFace>& fa
 				material = std::string(tri->getMaterial());
 			}
 
-            // Todo: mark model in some way as having generated(split) faces  
 			materials.push_back(material);
 			face_list.push_back(face);
 			face_list.rbegin()->fillFromLegacyData(verts, indices);
@@ -344,7 +349,12 @@ LLModel::EModelStatus load_face_from_dom_triangles(std::vector<LLVolumeFace>& fa
 	return LLModel::NO_ERRORS ;
 }
 
-LLModel::EModelStatus load_face_from_dom_polylist(std::vector<LLVolumeFace>& face_list, std::vector<std::string>& materials, domPolylistRef& poly, LLSD& log_msg)
+LLModel::EModelStatus load_face_from_dom_polylist(
+    std::vector<LLVolumeFace>& face_list,
+    std::vector<std::string>& materials,
+    domPolylistRef& poly,
+    bool& generated_additional_faces,
+    LLSD& log_msg)
 {
 	domPRef p = poly->getP();
 	domListOfUInts& idx = p->getValue();
@@ -546,6 +556,8 @@ LLModel::EModelStatus load_face_from_dom_polylist(std::vector<LLVolumeFace>& fac
 
 			if (indices.size()%3 == 0 && indices.size() >= 65532)
 			{
+                generated_additional_faces = true;
+
 				std::string material;
 
 				if (poly->getMaterial())
@@ -771,6 +783,9 @@ LLModel::EModelStatus load_face_from_dom_polygons(std::vector<LLVolumeFace>& fac
 		}
 	}
 
+    // Viewer can only fit U16 vertices, shouldn't we do some checks here and return overflow if result has more?
+    llassert(vert_idx.size() < U16_MAX);
+
 	//build vertex array from map
 	std::vector<LLVolumeFace::VertexData> new_verts;
 	new_verts.resize(vert_idx.size());
@@ -2390,11 +2405,13 @@ bool LLDAELoader::addVolumeFacesFromDomMesh(LLModel* pModel,domMesh* mesh, LLSD&
 	LLModel::EModelStatus status = LLModel::NO_ERRORS;
 	domTriangles_Array& tris = mesh->getTriangles_array();
 
+    pModel->mHasGeneratedFaces = false;
+
 	for (U32 i = 0; i < tris.getCount(); ++i)
 	{
 		domTrianglesRef& tri = tris.get(i);
 
-		status = load_face_from_dom_triangles(pModel->getVolumeFaces(), pModel->getMaterialList(), tri);
+		status = load_face_from_dom_triangles(pModel->getVolumeFaces(), pModel->getMaterialList(), tri, pModel->mHasGeneratedFaces);
 		pModel->mStatus = status;
 		if(status != LLModel::NO_ERRORS)
 		{
@@ -2407,7 +2424,7 @@ bool LLDAELoader::addVolumeFacesFromDomMesh(LLModel* pModel,domMesh* mesh, LLSD&
 	for (U32 i = 0; i < polys.getCount(); ++i)
 	{
 		domPolylistRef& poly = polys.get(i);
-		status = load_face_from_dom_polylist(pModel->getVolumeFaces(), pModel->getMaterialList(), poly, log_msg);
+		status = load_face_from_dom_polylist(pModel->getVolumeFaces(), pModel->getMaterialList(), poly, pModel->mHasGeneratedFaces, log_msg);
 
 		if(status != LLModel::NO_ERRORS)
 		{
@@ -2421,6 +2438,10 @@ bool LLDAELoader::addVolumeFacesFromDomMesh(LLModel* pModel,domMesh* mesh, LLSD&
 	for (U32 i = 0; i < polygons.getCount(); ++i)
 	{
 		domPolygonsRef& poly = polygons.get(i);
+
+        // Due to how poligons work, assume that face was 'generated' by default
+        pModel->mHasGeneratedFaces = true;
+
 		status = load_face_from_dom_polygons(pModel->getVolumeFaces(), pModel->getMaterialList(), poly);
 
 		if(status != LLModel::NO_ERRORS)
@@ -2520,6 +2541,7 @@ bool LLDAELoader::loadModelsFromDomMesh(domMesh* mesh, std::vector<LLModel*>& mo
 		{
 			LLModel* next = new LLModel(volume_params, 0.f);
 			next->mSubmodelID = ++submodelID;
+			next->mHasGeneratedFaces = ret->mHasGeneratedFaces;
 			next->mLabel = model_name + (char)((int)'a' + next->mSubmodelID) + lod_suffix[mLod];
 			next->getVolumeFaces() = remainder;
 			next->mNormalizedScale = ret->mNormalizedScale;
diff --git a/indra/llprimitive/llmodel.cpp b/indra/llprimitive/llmodel.cpp
index 702a1b5238..8b8fde0ea0 100644
--- a/indra/llprimitive/llmodel.cpp
+++ b/indra/llprimitive/llmodel.cpp
@@ -55,7 +55,8 @@ LLModel::LLModel(LLVolumeParams& params, F32 detail)
       mNormalizedTranslation(0,0,0), 
       mPelvisOffset( 0.0f ), 
       mStatus(NO_ERRORS), 
-      mSubmodelID(0)
+      mSubmodelID(0),
+      mHasGeneratedFaces(false)
 {
 	mDecompID = -1;
 	mLocalID = -1;
diff --git a/indra/llprimitive/llmodel.h b/indra/llprimitive/llmodel.h
index 96368d64e5..87a47dcb36 100644
--- a/indra/llprimitive/llmodel.h
+++ b/indra/llprimitive/llmodel.h
@@ -284,6 +284,11 @@ public:
     // A model/object can only have 8 faces, spillover faces will
     // be moved to new model/object and assigned a submodel id.
 	int mSubmodelID;
+    // A .dae face can have more than 65K vertices, but viewer
+    // is limited to U16 for indices, in such case spilower will
+    // be moved into new face and this will be set to true.
+    // Also true in case faces were generated from polygons
+    bool mHasGeneratedFaces;
 };
 
 typedef std::vector<LLPointer<LLModel> >	model_list;
diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp
index e5d451e909..6795ea8f53 100644
--- a/indra/newview/llfloatermodelpreview.cpp
+++ b/indra/newview/llfloatermodelpreview.cpp
@@ -139,7 +139,7 @@ mAvatarTabIndex(0)
 	mLODMode[LLModel::LOD_HIGH] = LLModelPreview::LOD_FROM_FILE;
 	for (U32 i = 0; i < LLModel::LOD_HIGH; i++)
 	{
-		mLODMode[i] = LLModelPreview::MESH_OPTIMIZER;
+		mLODMode[i] = LLModelPreview::MESH_OPTIMIZER_AUTO;
 	}
 }
 
@@ -729,6 +729,7 @@ void LLFloaterModelPreview::onLODParamCommit(S32 lod, bool enforce_tri_limit)
     case LLModelPreview::GENERATE:
         mModelPreview->onLODGenerateParamCommit(lod, enforce_tri_limit);
         break;
+    case LLModelPreview::MESH_OPTIMIZER_AUTO:
     case LLModelPreview::MESH_OPTIMIZER:
     case LLModelPreview::MESH_OPTIMIZER_SLOPPY:
     case LLModelPreview::MESH_OPTIMIZER_COMBINE:
@@ -1738,6 +1739,7 @@ void LLFloaterModelPreview::onLoDSourceCommit(S32 lod)
 	LLComboBox* lod_source_combo = getChild<LLComboBox>("lod_source_" + lod_name[lod]);
     S32 index = lod_source_combo->getCurrentIndex();
 	if (index == LLModelPreview::GENERATE
+        || index == LLModelPreview::MESH_OPTIMIZER_AUTO
         || index == LLModelPreview::MESH_OPTIMIZER
         || index == LLModelPreview::MESH_OPTIMIZER_SLOPPY
         || index == LLModelPreview::MESH_OPTIMIZER_COMBINE)
@@ -1771,7 +1773,7 @@ void LLFloaterModelPreview::resetUploadOptions()
 	getChild<LLComboBox>("lod_source_" + lod_name[NUM_LOD - 1])->setCurrentByIndex(LLModelPreview::LOD_FROM_FILE);
 	for (S32 lod = 0; lod < NUM_LOD - 1; ++lod)
 	{
-		getChild<LLComboBox>("lod_source_" + lod_name[lod])->setCurrentByIndex(LLModelPreview::MESH_OPTIMIZER);
+		getChild<LLComboBox>("lod_source_" + lod_name[lod])->setCurrentByIndex(LLModelPreview::MESH_OPTIMIZER_AUTO);
 		childSetValue("lod_file_" + lod_name[lod], "");
 	}
 
diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp
index 11a536473c..3a8676d7b9 100644
--- a/indra/newview/llmodelpreview.cpp
+++ b/indra/newview/llmodelpreview.cpp
@@ -1706,6 +1706,307 @@ void LLModelPreview::genGlodLODs(S32 which_lod, U32 decimation, bool enforce_tri
     }
 }
 
+// Runs per object, but likely it is a better way to run per model+submodels
+// returns a ratio of base model indices to resulting indices
+F32 LLModelPreview::genMeshOptimizerPerModel(LLModel *base_model, LLModel *target_model, F32 indices_decimator, F32 error_threshold, bool sloppy)
+{
+    // Figure out buffer size
+    S32 size_indices = 0;
+    S32 size_vertices = 0;
+
+    for (U32 face_idx = 0; face_idx < base_model->getNumVolumeFaces(); ++face_idx)
+    {
+        const LLVolumeFace &face = base_model->getVolumeFace(face_idx);
+        size_indices += face.mNumIndices;
+        size_vertices += face.mNumVertices;
+    }
+
+    // Allocate buffers, note that we are using U32 buffer instead of U16
+    U32* combined_indices = (U32*)ll_aligned_malloc_32(size_indices * sizeof(U32));
+    U32* output_indices = (U32*)ll_aligned_malloc_32(size_indices * sizeof(U32));
+
+    // extra space for normals and text coords
+    S32 tc_bytes_size = ((size_vertices * sizeof(LLVector2)) + 0xF) & ~0xF;
+    LLVector4a* combined_positions = (LLVector4a*)ll_aligned_malloc<64>(sizeof(LLVector4a) * 2 * size_vertices + tc_bytes_size);
+    LLVector4a* combined_normals = combined_positions + size_vertices;
+    LLVector2* combined_tex_coords = (LLVector2*)(combined_normals + size_vertices);
+
+    // copy indices and vertices into new buffers
+    S32 combined_positions_shift = 0;
+    S32 indices_idx_shift = 0;
+    S32 combined_indices_shift = 0;
+    for (U32 face_idx = 0; face_idx < base_model->getNumVolumeFaces(); ++face_idx)
+    {
+        const LLVolumeFace &face = base_model->getVolumeFace(face_idx);
+
+        // vertices
+        S32 copy_bytes = face.mNumVertices * sizeof(LLVector4a);
+        LLVector4a::memcpyNonAliased16((F32*)(combined_positions + combined_positions_shift), (F32*)face.mPositions, copy_bytes);
+
+        // normals
+        LLVector4a::memcpyNonAliased16((F32*)(combined_normals + combined_positions_shift), (F32*)face.mNormals, copy_bytes);
+
+        // tex coords
+        copy_bytes = (face.mNumVertices * sizeof(LLVector2) + 0xF) & ~0xF;
+        LLVector4a::memcpyNonAliased16((F32*)(combined_tex_coords + combined_positions_shift), (F32*)face.mTexCoords, copy_bytes);
+
+        combined_positions_shift += face.mNumVertices;
+
+        // indices, sadly can't do dumb memcpy for indices, need to adjust each value
+        for (S32 i = 0; i < face.mNumIndices; ++i)
+        {
+            U16 idx = face.mIndices[i];
+
+            combined_indices[combined_indices_shift] = idx + indices_idx_shift;
+            combined_indices_shift++;
+        }
+        indices_idx_shift += face.mNumVertices;
+    }
+
+    // Now that we have buffers, optimize
+    S32 target_indices = 0;
+    F32 result_code = 0; // how far from original the model is, 1 == 100%
+    S32 new_indices = 0;
+
+    target_indices = llmax(3, llfloor(size_indices / indices_decimator)); // leave at least one triangle
+    new_indices = LLMeshOptimizer::simplifyU32(
+        output_indices,
+        combined_indices,
+        size_indices,
+        combined_positions,
+        size_vertices,
+        LLVertexBuffer::sTypeSize[LLVertexBuffer::TYPE_VERTEX],
+        target_indices,
+        error_threshold,
+        sloppy,
+        &result_code);
+
+
+    if (result_code < 0)
+    {
+        LL_WARNS() << "Negative result code from meshoptimizer for model " << target_model->mLabel
+            << " target Indices: " << target_indices
+            << " new Indices: " << new_indices
+            << " original count: " << size_indices << LL_ENDL;
+    }
+
+    // repack back into individual faces
+
+    LLVector4a* buffer_positions = (LLVector4a*)ll_aligned_malloc<64>(sizeof(LLVector4a) * 2 * size_vertices + tc_bytes_size);
+    LLVector4a* buffer_normals = buffer_positions + size_vertices;
+    LLVector2* buffer_tex_coords = (LLVector2*)(buffer_normals + size_vertices);
+    U16* buffer_indices = (U16*)ll_aligned_malloc_16(U16_MAX * sizeof(U16));
+    S32* old_to_new_positions_map = new S32[size_vertices];
+
+    S32 buf_positions_copied = 0;
+    S32 buf_indices_copied = 0;
+    indices_idx_shift = 0;
+
+    // Crude method to copy indices back into face
+    for (U32 face_idx = 0; face_idx < base_model->getNumVolumeFaces(); ++face_idx)
+    {
+        const LLVolumeFace &face = base_model->getVolumeFace(face_idx);
+
+        // reset data for new run
+        buf_positions_copied = 0;
+        buf_indices_copied = 0;
+        bool copy_triangle = false;
+        S32 range = indices_idx_shift + face.mNumVertices;
+
+        for (S32 i = 0; i < size_vertices; i++)
+        {
+            old_to_new_positions_map[i] = -1;
+        }
+
+        // Copy relevant indices and vertices
+        for (S32 i = 0; i < new_indices; ++i)
+        {
+            U32 idx = output_indices[i];
+
+            if ((i % 3) == 0)
+            {
+                copy_triangle = idx >= indices_idx_shift && idx < range;
+            }
+
+            if (copy_triangle)
+            {
+                if (old_to_new_positions_map[idx] == -1)
+                {
+                    // New position, need to copy it
+                    // Validate size
+                    if (buf_positions_copied >= U16_MAX)
+                    {
+                        // Normally this shouldn't happen since the whole point is to reduce amount of vertices
+                        // but it might happen if user tries to run optimization with too large triangle or error value
+                        // so fallback to 'per face' mode or verify requested limits and copy base model as is.
+                        LL_WARNS() << "Over triangle limit. Failed to optimize in 'per object' mode, falling back to per face variant for"
+                            << " model " << target_model->mLabel
+                            << " target Indices: " << target_indices
+                            << " new Indices: " << new_indices
+                            << " original count: " << size_indices
+                            << " error treshold: " << error_threshold
+                            << LL_ENDL;
+                        return -1;
+                    }
+
+                    // Copy vertice, normals, tcs
+                    buffer_positions[buf_positions_copied] = combined_positions[idx];
+                    buffer_normals[buf_positions_copied] = combined_normals[idx];
+                    buffer_tex_coords[buf_positions_copied] = combined_tex_coords[idx];
+
+                    old_to_new_positions_map[idx] = buf_positions_copied;
+
+                    buffer_indices[buf_indices_copied] = (U16)buf_positions_copied;
+                    buf_positions_copied++;
+                }
+                else
+                {
+                    // existing position
+                    buffer_indices[buf_indices_copied] = (U16)old_to_new_positions_map[idx];
+                }
+                buf_indices_copied++;
+            }
+        }
+
+        if (buf_positions_copied >= U16_MAX)
+        {
+            break;
+        }
+
+        LLVolumeFace &new_face = target_model->getVolumeFace(face_idx);
+        //new_face = face; //temp
+
+        if (buf_indices_copied < 3)
+        {
+            // face was optimized away
+            new_face.resizeIndices(3);
+            new_face.resizeVertices(1);
+            memset(new_face.mIndices, 0, sizeof(U16) * 3);
+            new_face.mPositions[0].clear(); // set first vertice to 0
+            new_face.mNormals[0].clear();
+            new_face.mTexCoords[0].setZero();
+        }
+        else
+        {
+            new_face.resizeIndices(buf_indices_copied);
+            new_face.resizeVertices(buf_positions_copied);
+
+            S32 idx_size = (buf_indices_copied * sizeof(U16) + 0xF) & ~0xF;
+            LLVector4a::memcpyNonAliased16((F32*)new_face.mIndices, (F32*)buffer_indices, idx_size);
+
+            LLVector4a::memcpyNonAliased16((F32*)new_face.mPositions, (F32*)buffer_positions, buf_positions_copied * sizeof(LLVector4a));
+            LLVector4a::memcpyNonAliased16((F32*)new_face.mNormals, (F32*)buffer_normals, buf_positions_copied * sizeof(LLVector4a));
+
+            U32 tex_size = (buf_positions_copied * sizeof(LLVector2) + 0xF)&~0xF;
+            LLVector4a::memcpyNonAliased16((F32*)new_face.mTexCoords, (F32*)buffer_tex_coords, tex_size);
+        }
+
+        indices_idx_shift += face.mNumVertices;
+    }
+
+    delete[]old_to_new_positions_map;
+    ll_aligned_free<64>(combined_positions);
+    ll_aligned_free<64>(buffer_positions);
+    ll_aligned_free_32(output_indices);
+    ll_aligned_free_32(buffer_indices);
+    ll_aligned_free_32(combined_indices);
+
+    if (new_indices <= 0)
+    {
+        return -1;
+    }
+
+    return (F32)size_indices / (F32)new_indices;
+}
+
+F32 LLModelPreview::genMeshOptimizerPerFace(LLModel *base_model, LLModel *target_model, U32 face_idx, F32 indices_decimator, F32 error_threshold, bool sloppy)
+{
+    const LLVolumeFace &face = base_model->getVolumeFace(face_idx);
+    S32 size_indices = face.mNumIndices;
+    // todo: do not allocate per each face, add one large buffer somewhere
+    // faces have limited amount of indices
+    S32 size = (size_indices * sizeof(U16) + 0xF) & ~0xF;
+    U16* output = (U16*)ll_aligned_malloc_16(size);
+
+    S32 target_indices = 0;
+    F32 result_code = 0; // how far from original the model is, 1 == 100%
+    S32 new_indices = 0;
+
+    target_indices = llmax(3, llfloor(size_indices / indices_decimator)); // leave at least one triangle
+    new_indices = LLMeshOptimizer::simplify(
+        output,
+        face.mIndices,
+        size_indices,
+        face.mPositions,
+        face.mNumVertices,
+        LLVertexBuffer::sTypeSize[LLVertexBuffer::TYPE_VERTEX],
+        target_indices,
+        error_threshold,
+        sloppy,
+        &result_code);
+
+
+    if (result_code < 0)
+    {
+        LL_WARNS() << "Negative result code from meshoptimizer for face " << face_idx
+            << " of model " << target_model->mLabel
+            << " target Indices: " << target_indices
+            << " new Indices: " << new_indices
+            << " original count: " << size_indices
+            << " error treshold: " << error_threshold
+            << LL_ENDL;
+    }
+
+    LLVolumeFace &new_face = target_model->getVolumeFace(face_idx);
+
+    // Copy old values
+    new_face = face;
+
+
+    if (new_indices == 0)
+    {
+        if (!sloppy)
+        {
+            // meshopt_optimizeSloppy() can optimize triangles away even if target_indices is > 2,
+            // but optimize() isn't supposed to
+            LL_INFOS() << "No indices generated by meshoptimizer for face " << face_idx
+                << " of model " << target_model->mLabel
+                << " target Indices: " << target_indices
+                << " original count: " << size_indices
+                << " error treshold: " << error_threshold
+                << LL_ENDL;
+        }
+
+        // Face got optimized away
+        // Generate empty triangle
+        new_face.resizeIndices(3);
+        new_face.resizeVertices(1);
+        memset(new_face.mIndices, 0, sizeof(U16) * 3);
+        new_face.mPositions[0].clear(); // set first vertice to 0
+        new_face.mNormals[0].clear();
+        new_face.mTexCoords[0].setZero();
+    }
+    else
+    {
+        // Assign new values
+        new_face.resizeIndices(new_indices); // will wipe out mIndices, so new_face can't substitute output
+        S32 idx_size = (new_indices * sizeof(U16) + 0xF) & ~0xF;
+        LLVector4a::memcpyNonAliased16((F32*)new_face.mIndices, (F32*)output, idx_size);
+
+        // clear unused values
+        new_face.optimize();
+    }
+
+    ll_aligned_free_16(output);
+     
+    if (new_indices <= 0)
+    {
+        return -1;
+    }
+
+    return (F32)size_indices / (F32)new_indices;
+}
+
 void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 decimation, bool enforce_tri_limit)
 {
     LL_INFOS() << "Generating lod " << which_lod << " using meshoptimizer" << LL_ENDL;
@@ -1736,7 +2037,7 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d
     // TODO: add interface to mFMP to get error treshold or let mFMP write one into LLModelPreview
     // We should not be accesing views from other class!
     U32 lod_mode = LIMIT_TRIANGLES;
-    F32 indices_ratio = 0;
+    F32 indices_decimator = 0;
     F32 triangle_limit = 0;
     F32 lod_error_threshold = 1; //100%
 
@@ -1767,7 +2068,7 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d
 
             }
             // meshoptimizer doesn't use triangle limit, it uses indices limit, so convert it to aproximate ratio
-            indices_ratio = triangle_limit / (F32)base_triangle_count;
+            indices_decimator = (F32)base_triangle_count / triangle_limit;
         }
         else
         {
@@ -1776,8 +2077,8 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d
     }
     else
     {
-        // we are genrating all lods and each lod will get own indices_ratio
-        indices_ratio = 1;
+        // we are genrating all lods and each lod will get own indices_decimator
+        indices_decimator = 1;
         triangle_limit = base_triangle_count;
     }
 
@@ -1810,7 +2111,7 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d
             // we are genrating all lods and each lod gets own indices_ratio
             if (lod < start)
             {
-                indices_ratio /= decimation;
+                indices_decimator *= decimation;
                 triangle_limit /= decimation;
             }
         }
@@ -1846,308 +2147,64 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d
             // but combine all submodels with origin model as well
             if (model_meshopt_mode == MESH_OPTIMIZER_COMBINE)
             {
-                // Figure out buffer size
-                S32 size_indices = 0;
-                S32 size_vertices = 0;
+                // Run meshoptimizer for each model/object, up to 8 faces in one model
 
+                // Ideally this should run not per model,
+                // but combine all submodels with origin model as well
+                genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, false);
+            }
+            
+            if (model_meshopt_mode == MESH_OPTIMIZER)
+            {
+                // Run meshoptimizer for each face
                 for (U32 face_idx = 0; face_idx < base->getNumVolumeFaces(); ++face_idx)
                 {
-                    const LLVolumeFace &face = base->getVolumeFace(face_idx);
-                    size_indices += face.mNumIndices;
-                    size_vertices += face.mNumVertices;
+                    genMeshOptimizerPerFace(base, target_model, face_idx, indices_decimator, lod_error_threshold, false);
                 }
+            }
 
-                // Allocate buffers, note that we are using U32 buffer instead of U16
-                U32* combined_indices = (U32*)ll_aligned_malloc_32(size_indices * sizeof(U32));
-                U32* output_indices = (U32*)ll_aligned_malloc_32(size_indices * sizeof(U32));
-
-                // extra space for normals and text coords
-                S32 tc_bytes_size = ((size_vertices * sizeof(LLVector2)) + 0xF) & ~0xF;
-                LLVector4a* combined_positions = (LLVector4a*)ll_aligned_malloc<64>(sizeof(LLVector4a) * 2 * size_vertices + tc_bytes_size);
-                LLVector4a* combined_normals = combined_positions + size_vertices;
-                LLVector2* combined_tex_coords = (LLVector2*)(combined_normals + size_vertices);
-
-                // copy indices and vertices into new buffers
-                S32 combined_positions_shift = 0;
-                S32 indices_idx_shift = 0;
-                S32 combined_indices_shift = 0;
+            if (model_meshopt_mode == MESH_OPTIMIZER_SLOPPY)
+            {
+                // Run meshoptimizer for each face
                 for (U32 face_idx = 0; face_idx < base->getNumVolumeFaces(); ++face_idx)
                 {
-                    const LLVolumeFace &face = base->getVolumeFace(face_idx);
-
-                    // vertices
-                    S32 copy_bytes = face.mNumVertices * sizeof(LLVector4a);
-                    LLVector4a::memcpyNonAliased16((F32*)(combined_positions + combined_positions_shift), (F32*)face.mPositions, copy_bytes);
-
-                    // normals
-                    LLVector4a::memcpyNonAliased16((F32*)(combined_normals + combined_positions_shift), (F32*)face.mNormals, copy_bytes);
-
-                    // tex coords
-                    copy_bytes = (face.mNumVertices * sizeof(LLVector2) + 0xF) & ~0xF;
-                    LLVector4a::memcpyNonAliased16((F32*)(combined_tex_coords + combined_positions_shift), (F32*)face.mTexCoords, copy_bytes);
-
-                    combined_positions_shift += face.mNumVertices;
-
-                    // indices, sadly can't do dumb memcpy for indices, need to adjust each value
-                    for (S32 i = 0; i < face.mNumIndices; ++i)
-                    {
-                        U16 idx = face.mIndices[i];
-
-                        combined_indices[combined_indices_shift] = idx + indices_idx_shift;
-                        combined_indices_shift++;
-                    }
-                    indices_idx_shift += face.mNumVertices;
-                }
-
-                // Now that we have buffers, optimize
-                S32 target_indices = 0;
-                F32 result_code = 0; // how far from original the model is, 1 == 100%
-                S32 new_indices = 0;
-
-                target_indices = llmax(3, llfloor(size_indices * indices_ratio)); // leave at least one triangle
-                new_indices = LLMeshOptimizer::simplifyU32(
-                    output_indices,
-                    combined_indices,
-                    size_indices,
-                    combined_positions,
-                    size_vertices,
-                    LLVertexBuffer::sTypeSize[LLVertexBuffer::TYPE_VERTEX],
-                    target_indices,
-                    lod_error_threshold,
-                    &result_code);
-
-
-                if (result_code < 0)
-                {
-                    LL_WARNS() << "Negative result code from meshoptimizer for model " << target_model->mLabel
-                        << " target Indices: " << target_indices
-                        << " new Indices: " << new_indices
-                        << " original count: " << size_indices << LL_ENDL;
+                    genMeshOptimizerPerFace(base, target_model, face_idx, indices_decimator, lod_error_threshold, true);
                 }
+            }
 
-                // repack back into individual faces
-
-                LLVector4a* buffer_positions = (LLVector4a*)ll_aligned_malloc<64>(sizeof(LLVector4a) * 2 * size_vertices + tc_bytes_size);
-                LLVector4a* buffer_normals = buffer_positions + size_vertices;
-                LLVector2* buffer_tex_coords = (LLVector2*)(buffer_normals + size_vertices);
-                U16* buffer_indices = (U16*)ll_aligned_malloc_16(U16_MAX * sizeof(U16));
-                S32* old_to_new_positions_map = new S32[size_vertices];
-
-                S32 buf_positions_copied = 0;
-                S32 buf_indices_copied = 0;
-                indices_idx_shift = 0;
-
-                // Crude method to copy indices back into face
-                for (U32 face_idx = 0; face_idx < base->getNumVolumeFaces(); ++face_idx)
+            if (model_meshopt_mode == MESH_OPTIMIZER_AUTO)
+            {
+                F32 allowed_ratio_drift = 2.f;
+                S32 res = 0;
+                if (base->mHasGeneratedFaces)
                 {
-                    const LLVolumeFace &face = base->getVolumeFace(face_idx);
-
-                    // reset data for new run
-                    buf_positions_copied = 0;
-                    buf_indices_copied = 0;
-                    bool copy_triangle = false;
-                    S32 range = indices_idx_shift + face.mNumVertices;
-
-                    for (S32 i = 0; i < size_vertices; i++)
-                    {
-                        old_to_new_positions_map[i] = -1;
-                    }
-
-                    // Copy relevant indices and vertices
-                    for (S32 i = 0; i < new_indices; ++i)
-                    {
-                        U32 idx = output_indices[i];
-
-                        if ((i % 3) == 0)
-                        {
-                            copy_triangle = idx >= indices_idx_shift && idx < range;
-                        }
-
-                        if (copy_triangle)
-                        {
-                            if (old_to_new_positions_map[idx] == -1)
-                            {
-                                // New position, need to copy it
-                                // Validate size
-                                if (buf_positions_copied >= U16_MAX)
-                                {
-                                    // Normally this shouldn't happen since the whole point is to reduce amount of vertices
-                                    // but it might happen if user tries to run optimization with too large triangle or error value
-                                    // so fallback to 'per face' mode or verify requested limits and copy base model as is.
-                                    LL_WARNS() << "Over triangle limit. Failed to optimize in 'per object' mode, falling back to per face variant for"
-                                               << " model " << target_model->mLabel
-                                               << " target Indices: " << target_indices
-                                               << " new Indices: " << new_indices
-                                               << " original count: " << size_indices
-                                               << " error treshold: " << lod_error_threshold
-                                               << LL_ENDL;
-                                    model_meshopt_mode = MESH_OPTIMIZER;
-                                    break;
-                                }
-
-                                // Copy vertice, normals, tcs
-                                buffer_positions[buf_positions_copied] = combined_positions[idx];
-                                buffer_normals[buf_positions_copied] = combined_normals[idx];
-                                buffer_tex_coords[buf_positions_copied] = combined_tex_coords[idx];
-
-                                old_to_new_positions_map[idx] = buf_positions_copied;
-
-                                buffer_indices[buf_indices_copied] = (U16)buf_positions_copied;
-                                buf_positions_copied++;
-                            }
-                            else
-                            {
-                                // existing position
-                                buffer_indices[buf_indices_copied] = (U16)old_to_new_positions_map[idx];
-                            }
-                            buf_indices_copied++;
-                        }
-                    }
-
-                    if (buf_positions_copied >= U16_MAX)
-                    {
-                        break;
-                    }
-
-                    LLVolumeFace &new_face = target_model->getVolumeFace(face_idx);
-                    //new_face = face; //temp
+                    res = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, false);
 
-                    if (buf_indices_copied < 3)
+                    if (res * allowed_ratio_drift < indices_decimator)
                     {
-                        // face was optimized away
-                        new_face.resizeIndices(3);
-                        new_face.resizeVertices(1);
-                        memset(new_face.mIndices, 0, sizeof(U16) * 3);
-                        new_face.mPositions[0].clear(); // set first vertice to 0
-                        new_face.mNormals[0].clear();
-                        new_face.mTexCoords[0].setZero();
+                        res = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, true);
+                        LL_INFOS() << "Model " << target_model->getName()
+                                   << " lod " << which_lod
+                                   << " sloppily simplified using per model method." << LL_ENDL;
                     }
                     else
                     {
-                        new_face.resizeIndices(buf_indices_copied);
-                        new_face.resizeVertices(buf_positions_copied);
-
-                        S32 idx_size = (buf_indices_copied * sizeof(U16) + 0xF) & ~0xF;
-                        LLVector4a::memcpyNonAliased16((F32*)new_face.mIndices, (F32*)buffer_indices, idx_size);
-
-                        LLVector4a::memcpyNonAliased16((F32*)new_face.mPositions, (F32*)buffer_positions, buf_positions_copied * sizeof(LLVector4a));
-                        LLVector4a::memcpyNonAliased16((F32*)new_face.mNormals, (F32*)buffer_normals, buf_positions_copied * sizeof(LLVector4a));
-
-                        U32 tex_size = (buf_positions_copied * sizeof(LLVector2) + 0xF)&~0xF;
-                        LLVector4a::memcpyNonAliased16((F32*)new_face.mTexCoords, (F32*)buffer_tex_coords, tex_size);
+                        LL_INFOS() << "Model " << target_model->getName()
+                            << " lod " << which_lod
+                            << " simplified using per model method." << LL_ENDL;
                     }
-
-                    indices_idx_shift += face.mNumVertices;
                 }
-
-                delete []old_to_new_positions_map;
-                ll_aligned_free<64>(combined_positions);
-                ll_aligned_free<64>(buffer_positions);
-                ll_aligned_free_32(output_indices);
-                ll_aligned_free_32(buffer_indices);
-                ll_aligned_free_32(combined_indices);
-            }
-            
-            if (model_meshopt_mode == MESH_OPTIMIZER
-                || model_meshopt_mode == MESH_OPTIMIZER_SLOPPY)
-            {
-                // Run meshoptimizer for each face
-                for (U32 face_idx = 0; face_idx < base->getNumVolumeFaces(); ++face_idx)
+                else
                 {
-                    const LLVolumeFace &face = base->getVolumeFace(face_idx);
-                    S32 num_indices = face.mNumIndices;
-                    // todo: do not allocate per each face, add one large buffer somewhere
-                    // faces have limited amount of indices
-                    S32 size = (num_indices * sizeof(U16) + 0xF) & ~0xF;
-                    U16* output = (U16*)ll_aligned_malloc_16(size);
-
-                    S32 target_indices = 0;
-                    F32 result_code = 0; // how far from original the model is, 1 == 100%
-                    S32 new_indices = 0;
-
-                    if (model_meshopt_mode == MESH_OPTIMIZER_SLOPPY)
-                    {
-                        target_indices = llfloor(num_indices * indices_ratio);
-                        new_indices = LLMeshOptimizer::simplifySloppy(
-                            output,
-                            face.mIndices,
-                            num_indices,
-                            face.mPositions,
-                            face.mNumVertices,
-                            LLVertexBuffer::sTypeSize[LLVertexBuffer::TYPE_VERTEX],
-                            target_indices,
-                            lod_error_threshold,
-                            &result_code);
-                    }
-
-                    if (model_meshopt_mode == MESH_OPTIMIZER)
-                    {
-                        target_indices = llmax(3, llfloor(num_indices * indices_ratio)); // leave at least one triangle
-                        new_indices = LLMeshOptimizer::simplify(
-                            output,
-                            face.mIndices,
-                            num_indices,
-                            face.mPositions,
-                            face.mNumVertices,
-                            LLVertexBuffer::sTypeSize[LLVertexBuffer::TYPE_VERTEX],
-                            target_indices,
-                            lod_error_threshold,
-                            &result_code);
-                    }
-
-
-                    if (result_code < 0)
+                    for (U32 face_idx = 0; face_idx < base->getNumVolumeFaces(); ++face_idx)
                     {
-                        LL_WARNS() << "Negative result code from meshoptimizer for face " << face_idx
-                            << " of model " << target_model->mLabel
-                            << " target Indices: " << target_indices
-                            << " new Indices: " << new_indices
-                            << " original count: " << num_indices
-                            << " error treshold: " << lod_error_threshold
-                            << LL_ENDL;
-                    }
-
-                    LLVolumeFace &new_face = target_model->getVolumeFace(face_idx);
-
-                    // Copy old values
-                    new_face = face;
-
-
-                    if (new_indices == 0)
-                    {
-                        if (meshopt_mode != MESH_OPTIMIZER_SLOPPY)
+                        res = genMeshOptimizerPerFace(base, target_model, face_idx, indices_decimator, lod_error_threshold, false);
+                        
+                        if (res * allowed_ratio_drift < indices_decimator)
                         {
-                            // optimizeSloppy() can optimize triangles away even if target_indices is > 2,
-                            // but optimize() isn't supposed to
-                            LL_INFOS() << "No indices generated by meshoptimizer for face " << face_idx
-                                << " of model " << target_model->mLabel
-                                << " target Indices: " << target_indices
-                                << " original count: " << num_indices
-                                << " error treshold: " << lod_error_threshold
-                                << LL_ENDL;
+                            res = genMeshOptimizerPerFace(base, target_model, face_idx, indices_decimator, lod_error_threshold, true);
                         }
-
-                        // Face got optimized away
-                        // Generate empty triangle
-                        new_face.resizeIndices(3);
-                        new_face.resizeVertices(1);
-                        memset(new_face.mIndices, 0, sizeof(U16) * 3);
-                        new_face.mPositions[0].clear(); // set first vertice to 0
-                        new_face.mNormals[0].clear();
-                        new_face.mTexCoords[0].setZero();
                     }
-                    else
-                    {
-                        // Assign new values
-                        new_face.resizeIndices(new_indices); // will wipe out mIndices, so new_face can't substitute output
-                        S32 idx_size = (new_indices * sizeof(U16) + 0xF) & ~0xF;
-                        LLVector4a::memcpyNonAliased16((F32*)new_face.mIndices, (F32*)output, idx_size);
-
-                        // clear unused values
-                        new_face.optimize();
-                    }
-
-                    ll_aligned_free_16(output);
                 }
             }
 
@@ -2799,7 +2856,7 @@ void LLModelPreview::updateLodControls(S32 lod)
     }
     else // auto generate, the default case for all LoDs except High
     {
-        fmp->mLODMode[lod] = MESH_OPTIMIZER;
+        fmp->mLODMode[lod] = MESH_OPTIMIZER_AUTO;
 
         //don't actually regenerate lod when refreshing UI
         mLODFrozen = true;
@@ -4040,7 +4097,7 @@ bool LLModelPreview::lodQueryCallback()
         {
             S32 lod = preview->mLodsQuery.back();
             preview->mLodsQuery.pop_back();
-            preview->genMeshOptimizerLODs(lod, MESH_OPTIMIZER);
+            preview->genMeshOptimizerLODs(lod, MESH_OPTIMIZER_AUTO);
 
             if (preview->mLookUpLodFiles && (lod == LLModel::LOD_HIGH))
             {
diff --git a/indra/newview/llmodelpreview.h b/indra/newview/llmodelpreview.h
index b784345b5a..b3296fecf6 100644
--- a/indra/newview/llmodelpreview.h
+++ b/indra/newview/llmodelpreview.h
@@ -125,9 +125,10 @@ public:
     {
         LOD_FROM_FILE = 0,
         GENERATE,
+        MESH_OPTIMIZER_AUTO, // automatically selects method based on model or face
+        MESH_OPTIMIZER_COMBINE,
         MESH_OPTIMIZER,
         MESH_OPTIMIZER_SLOPPY,
-        MESH_OPTIMIZER_COMBINE,
         USE_LOD_ABOVE,
     } eLoDMode;
 
@@ -229,6 +230,10 @@ private:
     // Count amount of original models, excluding sub-models
     static U32 countRootModels(LLModelLoader::model_list models);
 
+    // functions for meshoptimizer, return reached simplification ratio
+    F32 genMeshOptimizerPerModel(LLModel *base_model, LLModel *target_model, F32 indices_ratio, F32 error_threshold, bool sloppy);
+    F32 genMeshOptimizerPerFace(LLModel *base_model, LLModel *target_model, U32 face_idx, F32 indices_ratio, F32 error_threshold, bool sloppy);
+
 protected:
     friend class LLModelLoader;
     friend class LLFloaterModelPreview;
diff --git a/indra/newview/skins/default/xui/en/floater_model_preview.xml b/indra/newview/skins/default/xui/en/floater_model_preview.xml
index cd67adf42a..db9d296fa5 100644
--- a/indra/newview/skins/default/xui/en/floater_model_preview.xml
+++ b/indra/newview/skins/default/xui/en/floater_model_preview.xml
@@ -176,6 +176,14 @@
                  name="Generate"
                  label="Generate"
                  value="Generate" />
+                <item
+                 name="MeshOpt"
+                 label="Simplify (auto)"
+                 value="MeshOpt" />
+                <item
+                 name="MeshOptCombine"
+                 label="Simplify per object"
+                 value="MeshOptCombine" />
                 <item
                  name="MeshOpt"
                  label="Simplify per face"
@@ -184,10 +192,6 @@
                  name="MeshOptSloppy"
                  label="Simplify sloppy"
                  value="MeshOptSloppy" />
-                <item
-                 name="MeshOptCombine"
-                 label="Simplify per object"
-                 value="MeshOptCombine" />
             </combo_box>
             <line_editor
              follows="left|top"
@@ -317,6 +321,14 @@
                  name="Generate"
                  label="Generate"
                  value="Generate" />
+                <item
+                 name="MeshOpt"
+                 label="Simplify (auto)"
+                 value="MeshOpt" />
+                <item
+                 name="MeshOptCombine"
+                 label="Simplify per object"
+                 value="MeshOptCombine" />
                 <item
                  name="MeshOpt"
                  label="Simplify per face"
@@ -325,10 +337,6 @@
                  name="MeshOptSloppy"
                  label="Simplify sloppy"
                  value="MeshOptSloppy" />
-                <item
-                 name="MeshOptCombine"
-                 label="Simplify per object"
-                 value="MeshOptCombine" />
                 <item
                  name="Use LoD above"
                  label="Use LoD above"
@@ -462,6 +470,14 @@
                  name="Generate"
                  label="Generate"
                  value="Generate" />
+                <item
+                 name="MeshOpt"
+                 label="Simplify (auto)"
+                 value="MeshOpt" />
+                <item
+                 name="MeshOptCombine"
+                 label="Simplify per object"
+                 value="MeshOptCombine" />
                 <item
                  name="MeshOpt"
                  label="Simplify per face"
@@ -470,10 +486,6 @@
                  name="MeshOptSloppy"
                  label="Simplify sloppy"
                  value="MeshOptSloppy" />
-                <item
-                 name="MeshOptCombine"
-                 label="Simplify per object"
-                 value="MeshOptCombine" />
                 <item
                  name="Use LoD above"
                  label="Use LoD above"
@@ -607,6 +619,14 @@
                  name="Generate"
                  label="Generate"
                  value="Generate" />
+                <item
+                 name="MeshOpt"
+                 label="Simplify (auto)"
+                 value="MeshOpt" />
+                <item
+                 name="MeshOptCombine"
+                 label="Simplify per object"
+                 value="MeshOptCombine" />
                 <item
                  name="MeshOpt"
                  label="Simplify per face"
@@ -615,10 +635,6 @@
                  name="MeshOptSloppy"
                  label="Simplify sloppy"
                  value="MeshOptSloppy" />
-                <item
-                 name="MeshOptCombine"
-                 label="Simplify per object"
-                 value="MeshOptCombine" />
                 <item
                  name="Use LoD above"
                  label="Use LoD above"
-- 
cgit v1.2.3


From 17ce44e24af77708ddd53b1f38447f5e8ed03786 Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Fri, 6 Aug 2021 09:46:11 +0300
Subject: DRTVWR-542 Automated method selection #2

---
 indra/newview/llmodelpreview.cpp | 25 ++++++++++++++++++++++---
 1 file changed, 22 insertions(+), 3 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp
index 3a8676d7b9..3ee435fb5f 100644
--- a/indra/newview/llmodelpreview.cpp
+++ b/indra/newview/llmodelpreview.cpp
@@ -2151,7 +2151,15 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d
 
                 // Ideally this should run not per model,
                 // but combine all submodels with origin model as well
-                genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, false);
+                F32 res = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, false);
+                if (res < 0)
+                {
+                    // U16 vertices overflow, shouldn't happen, but just in case
+                    for (U32 face_idx = 0; face_idx < base->getNumVolumeFaces(); ++face_idx)
+                    {
+                        genMeshOptimizerPerFace(base, target_model, face_idx, indices_decimator, lod_error_threshold, false);
+                    }
+                }
             }
             
             if (model_meshopt_mode == MESH_OPTIMIZER)
@@ -2175,12 +2183,23 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d
             if (model_meshopt_mode == MESH_OPTIMIZER_AUTO)
             {
                 F32 allowed_ratio_drift = 2.f;
-                S32 res = 0;
+                F32 res = 0;
                 if (base->mHasGeneratedFaces)
                 {
                     res = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, false);
 
-                    if (res * allowed_ratio_drift < indices_decimator)
+                    if (res < 0) 
+                    {
+                        // U16 vertices overflow, shouldn't happen, but just in case
+                        for (U32 face_idx = 0; face_idx < base->getNumVolumeFaces(); ++face_idx)
+                        {
+                            genMeshOptimizerPerFace(base, target_model, face_idx, indices_decimator, lod_error_threshold, false);
+                        }
+                        LL_INFOS() << "Model " << target_model->getName()
+                            << " lod " << which_lod
+                            << " per model method overflow, defaulting to per face." << LL_ENDL;
+                    }
+                    else if (res * allowed_ratio_drift < indices_decimator)
                     {
                         res = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, true);
                         LL_INFOS() << "Model " << target_model->getName()
-- 
cgit v1.2.3


From 574b05531ce3a0e535264937d299e5580fb31cdc Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Thu, 26 Aug 2021 22:50:08 -0700
Subject: SL-15709: Default Tracy to off

---
 indra/cmake/Tracy.cmake | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'indra')

diff --git a/indra/cmake/Tracy.cmake b/indra/cmake/Tracy.cmake
index bf09bccd4b..f4be4f72b3 100644
--- a/indra/cmake/Tracy.cmake
+++ b/indra/cmake/Tracy.cmake
@@ -1,7 +1,7 @@
 # -*- cmake -*-
 include(Prebuilt)
 
-set(TRACY ON CACHE BOOL "Use Tracy profiler.")
+set(TRACY OFF CACHE BOOL "Use Tracy profiler.")
 
 if (TRACY)
   set(TRACY_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include/tracy) 
-- 
cgit v1.2.3


From bb601196ddbe7d37584468f611ada67647a050d3 Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Thu, 26 Aug 2021 22:52:07 -0700
Subject: SL-15709: IF Tracy is enabled default to using only Tracy instead of
 Fast Timers; also print Tracy include directory

---
 indra/cmake/Tracy.cmake | 19 ++++++++++++++++---
 1 file changed, 16 insertions(+), 3 deletions(-)

(limited to 'indra')

diff --git a/indra/cmake/Tracy.cmake b/indra/cmake/Tracy.cmake
index f4be4f72b3..4750bdc349 100644
--- a/indra/cmake/Tracy.cmake
+++ b/indra/cmake/Tracy.cmake
@@ -5,12 +5,25 @@ set(TRACY OFF CACHE BOOL "Use Tracy profiler.")
 
 if (TRACY)
   set(TRACY_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include/tracy) 
+
+# See: indra/llcommon/llprofiler.h
+  add_definitions(-DLL_PROFILER_CONFIGURATION=2)
+  use_prebuilt_binary(tracy)
+
   if (WINDOWS)
-    use_prebuilt_binary(tracy)
+    MESSAGE(STATUS "Including Tracy for Windows: '${TRACY_INCLUDE_DIR}'")
     set(TRACY_LIBRARY tracy)
-  else (WINDOWS)
-    set(TRACY_LIBRARY "")
   endif (WINDOWS)
+
+  if (DARWIN)
+    MESSAGE(STATUS "Including Tracy for Darwin: '${TRACY_INCLUDE_DIR}'")
+    set(TRACY_LIBRARY "")
+  endif (DARWIN)
+
+  if (LINUX)
+    MESSAGE(STATUS "Including Tracy for Linux: '${TRACY_INCLUDE_DIR}'")
+    set(TRACY_LIBRARY "")
+  endif (LINUX)
 else (TRACY)
   set(TRACY_LIBRARY "")
 endif (TRACY)
-- 
cgit v1.2.3


From c443dc51e48d34a00b61468514dab8209ee214ea Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Thu, 26 Aug 2021 22:52:49 -0700
Subject: SL-15709: Cleanup

---
 indra/llcommon/llfasttimer.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'indra')

diff --git a/indra/llcommon/llfasttimer.h b/indra/llcommon/llfasttimer.h
index c7d5bb3761..9bd93d7240 100644
--- a/indra/llcommon/llfasttimer.h
+++ b/indra/llcommon/llfasttimer.h
@@ -39,7 +39,7 @@
 #define LL_FASTTIMER_USE_RDTSC 1
 
 // NOTE: Also see llprofiler.h
-#if !defined(LL_PROFILER_CONFIGURATION) // defined(LL_PROFILER_CONFIGURATION) && (LL_PROFILER_CONFIGURATION == LL_PROFILER_CONFIG_FAST_TIMER)
+#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
 
-- 
cgit v1.2.3


From cdf2bdafd394a97b917cc0a71b2bc8531cce40c7 Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Thu, 26 Aug 2021 23:58:45 -0700
Subject: SL-15709: Add Darwin support

---
 indra/llcommon/llframetimer.cpp | 8 ++++++++
 indra/llcommon/llprofiler.h     | 2 ++
 2 files changed, 10 insertions(+)

(limited to 'indra')

diff --git a/indra/llcommon/llframetimer.cpp b/indra/llcommon/llframetimer.cpp
index 1e9920746b..e293a557c0 100644
--- a/indra/llcommon/llframetimer.cpp
+++ b/indra/llcommon/llframetimer.cpp
@@ -29,6 +29,14 @@
 
 #include "llframetimer.h"
 
+// On Windows we build a static lib and link with that
+// On macOS we don't bother building a stand alone lib, just include the one source file we need for Tracy support
+#if LL_DARWIN
+	#if LL_PROFILER_CONFIGURATION == LL_PROFILER_CONFIG_TRACY || LL_PROFILER_CONFIGURATION == LL_PROFILER_CONFIG_TRACY_FAST_TIMER
+		#include "TracyClient.cpp"
+	#endif // LL_PROFILER_CONFIGURATION
+#endif // LL_DARWIN
+
 // Static members
 //LLTimer	LLFrameTimer::sInternalTimer;
 U64 LLFrameTimer::sStartTotalTime = totalTime();
diff --git a/indra/llcommon/llprofiler.h b/indra/llcommon/llprofiler.h
index 29331d35bf..4674985e06 100644
--- a/indra/llcommon/llprofiler.h
+++ b/indra/llcommon/llprofiler.h
@@ -32,7 +32,9 @@
 #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
-- 
cgit v1.2.3


From 240000c01cb6dc43203584809eb63452b3c80b75 Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Tue, 31 Aug 2021 21:23:10 -0700
Subject: SL-15709: Use standardized autobuild name; set TRACY_INCLUDE_DIR if
 Tracy not enabled

---
 indra/cmake/Tracy.cmake | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

(limited to 'indra')

diff --git a/indra/cmake/Tracy.cmake b/indra/cmake/Tracy.cmake
index 4750bdc349..dfa3e83039 100644
--- a/indra/cmake/Tracy.cmake
+++ b/indra/cmake/Tracy.cmake
@@ -1,9 +1,9 @@
 # -*- cmake -*-
 include(Prebuilt)
 
-set(TRACY OFF CACHE BOOL "Use Tracy profiler.")
+set(USE_TRACY OFF CACHE BOOL "Use Tracy profiler.")
 
-if (TRACY)
+if (USE_TRACY)
   set(TRACY_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include/tracy) 
 
 # See: indra/llcommon/llprofiler.h
@@ -24,7 +24,9 @@ if (TRACY)
     MESSAGE(STATUS "Including Tracy for Linux: '${TRACY_INCLUDE_DIR}'")
     set(TRACY_LIBRARY "")
   endif (LINUX)
-else (TRACY)
+else (USE_TRACY)
+  # Tracy.cmake should not set LLCOMMON_INCLUDE_DIRS, let LLCommon.cmake do that
+  set(TRACY_INCLUDE_DIR "")
   set(TRACY_LIBRARY "")
-endif (TRACY)
+endif (USE_TRACY)
 
-- 
cgit v1.2.3


From 3176136686adb58f4add432b017a7017a3f405a5 Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Tue, 31 Aug 2021 21:41:03 -0700
Subject: SL-15709: Fix LLCommon not setting Tracy include directory and not
 linking to tracy.lib

---
 indra/cmake/LLCommon.cmake    | 6 +++++-
 indra/llcommon/CMakeLists.txt | 1 +
 2 files changed, 6 insertions(+), 1 deletion(-)

(limited to 'indra')

diff --git a/indra/cmake/LLCommon.cmake b/indra/cmake/LLCommon.cmake
index c1cfa51cfb..b6f310fe12 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,9 @@ else (LINUX)
         ${BOOST_FIBER_LIBRARY} 
         ${BOOST_CONTEXT_LIBRARY} 
         ${BOOST_THREAD_LIBRARY} 
-        ${BOOST_SYSTEM_LIBRARY})
+        ${BOOST_SYSTEM_LIBRARY}
+        ${TRACY_LIBRARY}
+        )
 endif (LINUX)
 
 set(LLCOMMON_LINK_SHARED OFF CACHE BOOL "Build the llcommon target as a static library.")
diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt
index 28bf5d0c39..066d0404ac 100644
--- a/indra/llcommon/CMakeLists.txt
+++ b/indra/llcommon/CMakeLists.txt
@@ -305,6 +305,7 @@ target_link_libraries(
     ${BOOST_SYSTEM_LIBRARY}
     ${GOOGLE_PERFTOOLS_LIBRARIES}
     ${URIPARSER_LIBRARIES}
+    ${TRACY_LIBRARY}
     )
 
 if (DARWIN)
-- 
cgit v1.2.3


From 3772249c2f1fd101e06c1be8c1601b58fd6f04ba Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Thu, 2 Sep 2021 21:55:06 +0300
Subject: SL-15756 Falback in case no triangles were generated

---
 indra/newview/llmodelpreview.cpp | 60 ++++++++++++++++++++++++++++++++--------
 1 file changed, 49 insertions(+), 11 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp
index 3ee435fb5f..e54045d811 100644
--- a/indra/newview/llmodelpreview.cpp
+++ b/indra/newview/llmodelpreview.cpp
@@ -1708,6 +1708,7 @@ void LLModelPreview::genGlodLODs(S32 which_lod, U32 decimation, bool enforce_tri
 
 // Runs per object, but likely it is a better way to run per model+submodels
 // returns a ratio of base model indices to resulting indices
+// returns -1 in case of failure
 F32 LLModelPreview::genMeshOptimizerPerModel(LLModel *base_model, LLModel *target_model, F32 indices_decimator, F32 error_threshold, bool sloppy)
 {
     // Figure out buffer size
@@ -1911,8 +1912,23 @@ F32 LLModelPreview::genMeshOptimizerPerModel(LLModel *base_model, LLModel *targe
     ll_aligned_free_32(buffer_indices);
     ll_aligned_free_32(combined_indices);
 
-    if (new_indices <= 0)
+    if (new_indices < 3)
     {
+        // Model should have at least one visible triangle
+
+        if (!sloppy)
+        {
+            // Should only happen with sloppy
+            // non sloppy shouldn't be capable of optimizing mesh away
+            LL_WARNS() << "Failed to generate triangles"
+                << " model " << target_model->mLabel
+                << " target Indices: " << target_indices
+                << " new Indices: " << new_indices
+                << " original count: " << size_indices
+                << " error treshold: " << error_threshold
+                << LL_ENDL;
+        }
+
         return -1;
     }
 
@@ -1963,7 +1979,7 @@ F32 LLModelPreview::genMeshOptimizerPerFace(LLModel *base_model, LLModel *target
     new_face = face;
 
 
-    if (new_indices == 0)
+    if (new_indices < 3)
     {
         if (!sloppy)
         {
@@ -1999,8 +2015,9 @@ F32 LLModelPreview::genMeshOptimizerPerFace(LLModel *base_model, LLModel *target
 
     ll_aligned_free_16(output);
      
-    if (new_indices <= 0)
+    if (new_indices < 3)
     {
+        // At least one triangle is needed
         return -1;
     }
 
@@ -2183,12 +2200,12 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d
             if (model_meshopt_mode == MESH_OPTIMIZER_AUTO)
             {
                 F32 allowed_ratio_drift = 2.f;
-                F32 res = 0;
+                F32 res_ratio = 0;
                 if (base->mHasGeneratedFaces)
                 {
-                    res = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, false);
+                    res_ratio = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, false);
 
-                    if (res < 0) 
+                    if (res_ratio < 0)
                     {
                         // U16 vertices overflow, shouldn't happen, but just in case
                         for (U32 face_idx = 0; face_idx < base->getNumVolumeFaces(); ++face_idx)
@@ -2199,12 +2216,22 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d
                             << " lod " << which_lod
                             << " per model method overflow, defaulting to per face." << LL_ENDL;
                     }
-                    else if (res * allowed_ratio_drift < indices_decimator)
+                    else if (res_ratio * allowed_ratio_drift < indices_decimator)
                     {
-                        res = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, true);
+                        // Try sloppy variant if normal one failed to simplify model enough.
+                        res_ratio = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, true);
                         LL_INFOS() << "Model " << target_model->getName()
                                    << " lod " << which_lod
                                    << " sloppily simplified using per model method." << LL_ENDL;
+
+
+                        if (res_ratio < 0)
+                        {
+                            // Sloppy variant failed to generate triangles.
+                            // Can happen with models that are too simple as is.
+                            // Fallback to normal method.
+                            genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, false);
+                        }
                     }
                     else
                     {
@@ -2217,13 +2244,24 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d
                 {
                     for (U32 face_idx = 0; face_idx < base->getNumVolumeFaces(); ++face_idx)
                     {
-                        res = genMeshOptimizerPerFace(base, target_model, face_idx, indices_decimator, lod_error_threshold, false);
+                        res_ratio = genMeshOptimizerPerFace(base, target_model, face_idx, indices_decimator, lod_error_threshold, false);
                         
-                        if (res * allowed_ratio_drift < indices_decimator)
+                        if (res_ratio * allowed_ratio_drift < indices_decimator)
                         {
-                            res = genMeshOptimizerPerFace(base, target_model, face_idx, indices_decimator, lod_error_threshold, true);
+                            // normal method failed to sufficiently simplify, try sloppy
+                            res_ratio = genMeshOptimizerPerFace(base, target_model, face_idx, indices_decimator, lod_error_threshold, true);
+                            if (res_ratio < 0)
+                            {
+                                // Sloppy failed to generate triangles.
+                                // Can happen with models that are too simple as is.
+                                // Fallback to normal method.
+                                genMeshOptimizerPerFace(base, target_model, face_idx, indices_decimator, lod_error_threshold, false);
+                            }
                         }
                     }
+                    LL_INFOS() << "Model " << target_model->getName()
+                        << " lod " << which_lod
+                        << " simplified using per face methods." << LL_ENDL;
                 }
             }
 
-- 
cgit v1.2.3


From bac30c9ba5fc9f947788b4fbb468d3259a20fc2e Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Fri, 3 Sep 2021 21:15:00 +0300
Subject: SL-15940 Limit wasn't adjusting for a model with less than 30
 triangles

---
 indra/newview/llmodelpreview.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'indra')

diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp
index e54045d811..bf661d39b2 100644
--- a/indra/newview/llmodelpreview.cpp
+++ b/indra/newview/llmodelpreview.cpp
@@ -2945,7 +2945,7 @@ void LLModelPreview::updateLodControls(S32 lod)
             threshold->setVisible(false);
 
             limit->setMaxValue(mMaxTriangleLimit);
-            limit->setIncrement(mMaxTriangleLimit / 32);
+            limit->setIncrement(llmax((U32)1, mMaxTriangleLimit / 32));
         }
         else
         {
-- 
cgit v1.2.3


From c37cc7c3a4888fdca132613d627d7ad90517332a Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Fri, 3 Sep 2021 17:20:22 -0700
Subject: SL-15709: Windows: Include Tracy source directly; don't use a library

---
 indra/cmake/LLCommon.cmake      |  1 -
 indra/cmake/Tracy.cmake         |  3 ---
 indra/llcommon/llframetimer.cpp | 11 ++++-------
 indra/llcommon/llprofiler.h     |  6 ++++--
 4 files changed, 8 insertions(+), 13 deletions(-)

(limited to 'indra')

diff --git a/indra/cmake/LLCommon.cmake b/indra/cmake/LLCommon.cmake
index b6f310fe12..34499aaa36 100644
--- a/indra/cmake/LLCommon.cmake
+++ b/indra/cmake/LLCommon.cmake
@@ -33,7 +33,6 @@ else (LINUX)
         ${BOOST_CONTEXT_LIBRARY} 
         ${BOOST_THREAD_LIBRARY} 
         ${BOOST_SYSTEM_LIBRARY}
-        ${TRACY_LIBRARY}
         )
 endif (LINUX)
 
diff --git a/indra/cmake/Tracy.cmake b/indra/cmake/Tracy.cmake
index dfa3e83039..1b8c3db2e2 100644
--- a/indra/cmake/Tracy.cmake
+++ b/indra/cmake/Tracy.cmake
@@ -12,17 +12,14 @@ if (USE_TRACY)
 
   if (WINDOWS)
     MESSAGE(STATUS "Including Tracy for Windows: '${TRACY_INCLUDE_DIR}'")
-    set(TRACY_LIBRARY tracy)
   endif (WINDOWS)
 
   if (DARWIN)
     MESSAGE(STATUS "Including Tracy for Darwin: '${TRACY_INCLUDE_DIR}'")
-    set(TRACY_LIBRARY "")
   endif (DARWIN)
 
   if (LINUX)
     MESSAGE(STATUS "Including Tracy for Linux: '${TRACY_INCLUDE_DIR}'")
-    set(TRACY_LIBRARY "")
   endif (LINUX)
 else (USE_TRACY)
   # Tracy.cmake should not set LLCOMMON_INCLUDE_DIRS, let LLCommon.cmake do that
diff --git a/indra/llcommon/llframetimer.cpp b/indra/llcommon/llframetimer.cpp
index e293a557c0..c54029e8b4 100644
--- a/indra/llcommon/llframetimer.cpp
+++ b/indra/llcommon/llframetimer.cpp
@@ -29,13 +29,10 @@
 
 #include "llframetimer.h"
 
-// On Windows we build a static lib and link with that
-// On macOS we don't bother building a stand alone lib, just include the one source file we need for Tracy support
-#if LL_DARWIN
-	#if LL_PROFILER_CONFIGURATION == LL_PROFILER_CONFIG_TRACY || LL_PROFILER_CONFIGURATION == LL_PROFILER_CONFIG_TRACY_FAST_TIMER
-		#include "TracyClient.cpp"
-	#endif // LL_PROFILER_CONFIGURATION
-#endif // LL_DARWIN
+// 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;
diff --git a/indra/llcommon/llprofiler.h b/indra/llcommon/llprofiler.h
index 4674985e06..062c9360dd 100644
--- a/indra/llcommon/llprofiler.h
+++ b/indra/llcommon/llprofiler.h
@@ -39,8 +39,10 @@
 #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
-        #define TRACY_NO_BROADCAST   1
-        #define TRACY_ONLY_LOCALHOST 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"
     #endif
-- 
cgit v1.2.3


From aa358035a3553e382128c62d24755b7dce2a8278 Mon Sep 17 00:00:00 2001
From: Dave Houlton <euclid@lindenlab.com>
Date: Tue, 20 Apr 2021 10:49:33 -0600
Subject: DRTVWR-528 remove wrapper code for RAD telemetry library

---
 indra/newview/CMakeLists.txt  |   1 -
 indra/newview/llappviewer.cpp |   3 -
 indra/newview/llstartup.cpp   |   3 -
 indra/newview/lltelemetry.cpp | 145 ------------------------------------------
 indra/newview/lltelemetry.h   |  81 -----------------------
 5 files changed, 233 deletions(-)
 delete mode 100644 indra/newview/lltelemetry.cpp
 delete mode 100644 indra/newview/lltelemetry.h

(limited to 'indra')

diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 87caca56af..2995a006ac 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -587,7 +587,6 @@ set(viewer_SOURCE_FILES
     llsyntaxid.cpp
     llsyswellitem.cpp
     llsyswellwindow.cpp
-    lltelemetry.cpp
     llteleporthistory.cpp
     llteleporthistorystorage.cpp
     lltextureatlas.cpp
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 891722e1bd..79f1cc0e8f 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"
@@ -1668,8 +1667,6 @@ bool LLAppViewer::doFrame()
 		LL_INFOS() << "Exiting main_loop" << LL_ENDL;
 	}
 
-    LLPROFILE_UPDATE();
-
 	return ! LLApp::isRunning();
 }
 
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index 1242131534..57c5074804 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/lltelemetry.cpp b/indra/newview/lltelemetry.cpp
deleted file mode 100644
index 0c63e2fede..0000000000
--- 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 a73e5fcfa2..0000000000
--- 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
-- 
cgit v1.2.3


From 2e88a3266529714efcf8ae092819a25393540c8a Mon Sep 17 00:00:00 2001
From: Dave Houlton <euclid@lindenlab.com>
Date: Mon, 19 Jul 2021 16:26:33 -0600
Subject: SL-15595 update viewer autobuild to import tracy lib

---
 indra/cmake/Tracy.cmake       | 17 +++++++++++++++++
 indra/llcommon/CMakeLists.txt |  2 ++
 indra/newview/CMakeLists.txt  |  3 +++
 3 files changed, 22 insertions(+)
 create mode 100644 indra/cmake/Tracy.cmake

(limited to 'indra')

diff --git a/indra/cmake/Tracy.cmake b/indra/cmake/Tracy.cmake
new file mode 100644
index 0000000000..bf09bccd4b
--- /dev/null
+++ b/indra/cmake/Tracy.cmake
@@ -0,0 +1,17 @@
+# -*- cmake -*-
+include(Prebuilt)
+
+set(TRACY ON CACHE BOOL "Use Tracy profiler.")
+
+if (TRACY)
+  set(TRACY_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include/tracy) 
+  if (WINDOWS)
+    use_prebuilt_binary(tracy)
+    set(TRACY_LIBRARY tracy)
+  else (WINDOWS)
+    set(TRACY_LIBRARY "")
+  endif (WINDOWS)
+else (TRACY)
+  set(TRACY_LIBRARY "")
+endif (TRACY)
+
diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt
index dd266630ea..f1b0506659 100644
--- a/indra/llcommon/CMakeLists.txt
+++ b/indra/llcommon/CMakeLists.txt
@@ -13,6 +13,7 @@ include(GoogleBreakpad)
 include(Copy3rdPartyLibs)
 include(ZLIB)
 include(URIPARSER)
+include(Tracy)
 
 include_directories(
     ${EXPAT_INCLUDE_DIRS}
@@ -21,6 +22,7 @@ include_directories(
     ${ZLIB_INCLUDE_DIRS}
     ${BREAKPAD_INCLUDE_DIRECTORIES}
     ${URIPARSER_INCLUDE_DIRS}
+    ${TRACY_INCLUDE_DIR}
     )
 
 # add_executable(lltreeiterators lltreeiterators.cpp)
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 2995a006ac..fbe75af712 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
@@ -2066,6 +2068,7 @@ target_link_libraries(${VIEWER_BINARY_NAME}
     ${LLPHYSICS_LIBRARIES}
     ${LLPHYSICSEXTENSIONS_LIBRARIES}
     ${LLAPPEARANCE_LIBRARIES}
+    ${TRACY_LIBRARY}
     )
 
 if (USE_BUGSPLAT)
-- 
cgit v1.2.3


From df5127136f9f520aa31c06ddb37ac79b6a8dc16d Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Tue, 27 Jul 2021 15:31:15 -0700
Subject: SL-15709: Add Tracy support to viewer

---
 indra/cmake/LLCommon.cmake        |   2 +-
 indra/llcommon/CMakeLists.txt     |   1 +
 indra/llcommon/linden_common.h    |   2 +
 indra/llcommon/llfasttimer.h      |   3 +
 indra/llcommon/llprofiler.h       |  64 ++++++++++++++
 indra/llcommon/llthread.cpp       |   2 +
 indra/newview/llappviewer.cpp     |   2 +
 indra/newview/llviewerdisplay.cpp |  81 ++++++++++--------
 indra/newview/llvovolume.cpp      | 175 ++++++++++++++++++++------------------
 indra/newview/pipeline.cpp        | 123 ++++++++++++++-------------
 10 files changed, 276 insertions(+), 179 deletions(-)
 create mode 100644 indra/llcommon/llprofiler.h

(limited to 'indra')

diff --git a/indra/cmake/LLCommon.cmake b/indra/cmake/LLCommon.cmake
index 8900419f9b..c1cfa51cfb 100644
--- a/indra/cmake/LLCommon.cmake
+++ b/indra/cmake/LLCommon.cmake
@@ -30,7 +30,7 @@ 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/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt
index f1b0506659..28bf5d0c39 100644
--- a/indra/llcommon/CMakeLists.txt
+++ b/indra/llcommon/CMakeLists.txt
@@ -201,6 +201,7 @@ set(llcommon_HEADER_FILES
     llmortician.h
     llnametable.h
     llpointer.h
+    llprofiler.h
     llpounceable.h
     llpredicate.h
     llpreprocessor.h
diff --git a/indra/llcommon/linden_common.h b/indra/llcommon/linden_common.h
index e5a913a6a9..45ac43910c 100644
--- a/indra/llcommon/linden_common.h
+++ b/indra/llcommon/linden_common.h
@@ -60,4 +60,6 @@
 #include "llerror.h"
 #include "llfile.h"
 
+#include "llprofiler.h" // must be before fast timer; needed due to LLThreads potentially needing access to tracy
+
 #endif
diff --git a/indra/llcommon/llfasttimer.h b/indra/llcommon/llfasttimer.h
index dfc63d08a2..c7d5bb3761 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) // defined(LL_PROFILER_CONFIGURATION) && (LL_PROFILER_CONFIGURATION == LL_PROFILER_CONFIG_FAST_TIMER)
 #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/llprofiler.h b/indra/llcommon/llprofiler.h
new file mode 100644
index 0000000000..75954b9a79
--- /dev/null
+++ b/indra/llcommon/llprofiler.h
@@ -0,0 +1,64 @@
+/**
+ * @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
+
+#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
+        #define TRACY_NO_BROADCAST   1
+        #define TRACY_ONLY_LOCALHOST 1
+        #define TRACY_ONLY_IPV4      1
+        #include "Tracy.hpp"
+    #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)          ZoneNamedN( ___tracy_scoped_zone, #name, true );
+    #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__);
+    #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)          ZoneNamedN( ___tracy_scoped_zone, #timer_stat, true )   const LLTrace::BlockTimer& LL_GLUE_TOKENS(block_time_recorder, __LINE__)(LLTrace::timeThisBlock(name)); (void)LL_GLUE_TOKENS(block_time_recorder, __LINE__);
+    #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/llthread.cpp b/indra/llcommon/llthread.cpp
index 6d531d842d..a8cc750437 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();
 
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 79f1cc0e8f..94f0b31ecd 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -1667,6 +1667,8 @@ bool LLAppViewer::doFrame()
 		LL_INFOS() << "Exiting main_loop" << LL_ENDL;
 	}
 
+    LL_PROFILER_FRAME_END
+
 	return ! LLApp::isRunning();
 }
 
diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp
index 109dc93261..a590237440 100644
--- a/indra/newview/llviewerdisplay.cpp
+++ b/indra/newview/llviewerdisplay.cpp
@@ -1259,7 +1259,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();
 	
@@ -1274,7 +1274,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();
@@ -1282,55 +1282,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();
+
+		LLGLSDefault gls_default;
+		LLGLSUIDefault gls_ui;
+		{
+			gPipeline.disableLights();
+		}
 
-	{
-		gGL.color4f(1,1,1,1);
-		if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
 		{
-			if (!gDisconnected)
+			gGL.color4f(1,1,1,1);
+			if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
 			{
-                LL_RECORD_BLOCK_TIME(FTM_RENDER_UI_3D);
-				render_ui_3d();
+				if (!gDisconnected)
+				{
+					LL_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/llvovolume.cpp b/indra/newview/llvovolume.cpp
index f063800587..f9b2285989 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -6045,123 +6045,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/pipeline.cpp b/indra/newview/pipeline.cpp
index cd1b9c7c69..e7c2d4db39 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -4564,92 +4564,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)
-- 
cgit v1.2.3


From 6d74ae649c6a05403f7ddc01a41d8def694e00e1 Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Fri, 30 Jul 2021 09:36:38 -0700
Subject: SL-15709: Default to old fast timers

---
 indra/llcommon/llprofiler.h | 2 ++
 1 file changed, 2 insertions(+)

(limited to 'indra')

diff --git a/indra/llcommon/llprofiler.h b/indra/llcommon/llprofiler.h
index 75954b9a79..29331d35bf 100644
--- a/indra/llcommon/llprofiler.h
+++ b/indra/llcommon/llprofiler.h
@@ -32,6 +32,8 @@
 #define LL_PROFILER_CONFIG_TRACY            2  // Profiling on: Only Tracy
 #define LL_PROFILER_CONFIG_TRACY_FAST_TIMER 3  // Profiling on: Fast Timers + Tracy
 
+#define LL_PROFILER_CONFIGURATION           LL_PROFILER_CONFIG_FAST_TIMER
+
 #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
-- 
cgit v1.2.3


From 61175cfa018eba460d4f836dee5fabbe78799442 Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Thu, 26 Aug 2021 22:50:08 -0700
Subject: SL-15709: Default Tracy to off

---
 indra/cmake/Tracy.cmake | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'indra')

diff --git a/indra/cmake/Tracy.cmake b/indra/cmake/Tracy.cmake
index bf09bccd4b..f4be4f72b3 100644
--- a/indra/cmake/Tracy.cmake
+++ b/indra/cmake/Tracy.cmake
@@ -1,7 +1,7 @@
 # -*- cmake -*-
 include(Prebuilt)
 
-set(TRACY ON CACHE BOOL "Use Tracy profiler.")
+set(TRACY OFF CACHE BOOL "Use Tracy profiler.")
 
 if (TRACY)
   set(TRACY_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include/tracy) 
-- 
cgit v1.2.3


From a783f7c74abc3a5afc8dbd1af63b74e281f02308 Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Thu, 26 Aug 2021 22:52:07 -0700
Subject: SL-15709: IF Tracy is enabled default to using only Tracy instead of
 Fast Timers; also print Tracy include directory

---
 indra/cmake/Tracy.cmake | 19 ++++++++++++++++---
 1 file changed, 16 insertions(+), 3 deletions(-)

(limited to 'indra')

diff --git a/indra/cmake/Tracy.cmake b/indra/cmake/Tracy.cmake
index f4be4f72b3..4750bdc349 100644
--- a/indra/cmake/Tracy.cmake
+++ b/indra/cmake/Tracy.cmake
@@ -5,12 +5,25 @@ set(TRACY OFF CACHE BOOL "Use Tracy profiler.")
 
 if (TRACY)
   set(TRACY_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include/tracy) 
+
+# See: indra/llcommon/llprofiler.h
+  add_definitions(-DLL_PROFILER_CONFIGURATION=2)
+  use_prebuilt_binary(tracy)
+
   if (WINDOWS)
-    use_prebuilt_binary(tracy)
+    MESSAGE(STATUS "Including Tracy for Windows: '${TRACY_INCLUDE_DIR}'")
     set(TRACY_LIBRARY tracy)
-  else (WINDOWS)
-    set(TRACY_LIBRARY "")
   endif (WINDOWS)
+
+  if (DARWIN)
+    MESSAGE(STATUS "Including Tracy for Darwin: '${TRACY_INCLUDE_DIR}'")
+    set(TRACY_LIBRARY "")
+  endif (DARWIN)
+
+  if (LINUX)
+    MESSAGE(STATUS "Including Tracy for Linux: '${TRACY_INCLUDE_DIR}'")
+    set(TRACY_LIBRARY "")
+  endif (LINUX)
 else (TRACY)
   set(TRACY_LIBRARY "")
 endif (TRACY)
-- 
cgit v1.2.3


From 92e53622ea33cf1558d7079e9341038dd242c3a5 Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Thu, 26 Aug 2021 22:52:49 -0700
Subject: SL-15709: Cleanup

---
 indra/llcommon/llfasttimer.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'indra')

diff --git a/indra/llcommon/llfasttimer.h b/indra/llcommon/llfasttimer.h
index c7d5bb3761..9bd93d7240 100644
--- a/indra/llcommon/llfasttimer.h
+++ b/indra/llcommon/llfasttimer.h
@@ -39,7 +39,7 @@
 #define LL_FASTTIMER_USE_RDTSC 1
 
 // NOTE: Also see llprofiler.h
-#if !defined(LL_PROFILER_CONFIGURATION) // defined(LL_PROFILER_CONFIGURATION) && (LL_PROFILER_CONFIGURATION == LL_PROFILER_CONFIG_FAST_TIMER)
+#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
 
-- 
cgit v1.2.3


From 13ff2cba5365474fe53809968f66cc2fa20be4cc Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Thu, 26 Aug 2021 23:58:45 -0700
Subject: SL-15709: Add Darwin support

---
 indra/llcommon/llframetimer.cpp | 8 ++++++++
 indra/llcommon/llprofiler.h     | 2 ++
 2 files changed, 10 insertions(+)

(limited to 'indra')

diff --git a/indra/llcommon/llframetimer.cpp b/indra/llcommon/llframetimer.cpp
index 1e9920746b..e293a557c0 100644
--- a/indra/llcommon/llframetimer.cpp
+++ b/indra/llcommon/llframetimer.cpp
@@ -29,6 +29,14 @@
 
 #include "llframetimer.h"
 
+// On Windows we build a static lib and link with that
+// On macOS we don't bother building a stand alone lib, just include the one source file we need for Tracy support
+#if LL_DARWIN
+	#if LL_PROFILER_CONFIGURATION == LL_PROFILER_CONFIG_TRACY || LL_PROFILER_CONFIGURATION == LL_PROFILER_CONFIG_TRACY_FAST_TIMER
+		#include "TracyClient.cpp"
+	#endif // LL_PROFILER_CONFIGURATION
+#endif // LL_DARWIN
+
 // Static members
 //LLTimer	LLFrameTimer::sInternalTimer;
 U64 LLFrameTimer::sStartTotalTime = totalTime();
diff --git a/indra/llcommon/llprofiler.h b/indra/llcommon/llprofiler.h
index 29331d35bf..4674985e06 100644
--- a/indra/llcommon/llprofiler.h
+++ b/indra/llcommon/llprofiler.h
@@ -32,7 +32,9 @@
 #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
-- 
cgit v1.2.3


From 91f4d7f7a04839bb9c5e320dcb5f90314586624f Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Tue, 31 Aug 2021 21:23:10 -0700
Subject: SL-15709: Use standardized autobuild name; set TRACY_INCLUDE_DIR if
 Tracy not enabled

---
 indra/cmake/Tracy.cmake | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

(limited to 'indra')

diff --git a/indra/cmake/Tracy.cmake b/indra/cmake/Tracy.cmake
index 4750bdc349..dfa3e83039 100644
--- a/indra/cmake/Tracy.cmake
+++ b/indra/cmake/Tracy.cmake
@@ -1,9 +1,9 @@
 # -*- cmake -*-
 include(Prebuilt)
 
-set(TRACY OFF CACHE BOOL "Use Tracy profiler.")
+set(USE_TRACY OFF CACHE BOOL "Use Tracy profiler.")
 
-if (TRACY)
+if (USE_TRACY)
   set(TRACY_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include/tracy) 
 
 # See: indra/llcommon/llprofiler.h
@@ -24,7 +24,9 @@ if (TRACY)
     MESSAGE(STATUS "Including Tracy for Linux: '${TRACY_INCLUDE_DIR}'")
     set(TRACY_LIBRARY "")
   endif (LINUX)
-else (TRACY)
+else (USE_TRACY)
+  # Tracy.cmake should not set LLCOMMON_INCLUDE_DIRS, let LLCommon.cmake do that
+  set(TRACY_INCLUDE_DIR "")
   set(TRACY_LIBRARY "")
-endif (TRACY)
+endif (USE_TRACY)
 
-- 
cgit v1.2.3


From 6d2cad965c63cd352f617537b73506790fd8f4a4 Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Tue, 31 Aug 2021 21:41:03 -0700
Subject: SL-15709: Fix LLCommon not setting Tracy include directory and not
 linking to tracy.lib

---
 indra/cmake/LLCommon.cmake    | 6 +++++-
 indra/llcommon/CMakeLists.txt | 1 +
 2 files changed, 6 insertions(+), 1 deletion(-)

(limited to 'indra')

diff --git a/indra/cmake/LLCommon.cmake b/indra/cmake/LLCommon.cmake
index c1cfa51cfb..b6f310fe12 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,9 @@ else (LINUX)
         ${BOOST_FIBER_LIBRARY} 
         ${BOOST_CONTEXT_LIBRARY} 
         ${BOOST_THREAD_LIBRARY} 
-        ${BOOST_SYSTEM_LIBRARY})
+        ${BOOST_SYSTEM_LIBRARY}
+        ${TRACY_LIBRARY}
+        )
 endif (LINUX)
 
 set(LLCOMMON_LINK_SHARED OFF CACHE BOOL "Build the llcommon target as a static library.")
diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt
index 28bf5d0c39..066d0404ac 100644
--- a/indra/llcommon/CMakeLists.txt
+++ b/indra/llcommon/CMakeLists.txt
@@ -305,6 +305,7 @@ target_link_libraries(
     ${BOOST_SYSTEM_LIBRARY}
     ${GOOGLE_PERFTOOLS_LIBRARIES}
     ${URIPARSER_LIBRARIES}
+    ${TRACY_LIBRARY}
     )
 
 if (DARWIN)
-- 
cgit v1.2.3


From b45c0e3ed926270e100271f33885b8d31085a858 Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Mon, 6 Sep 2021 21:29:51 +0300
Subject: SL-15940 Remove ability to set zero triangle limit

Setting lod to zero triangles doesn't work and shouldn't work, so UI shouldn't allow setting less then one triangle per model as well.
---
 indra/newview/llmodelpreview.cpp | 10 ++++++++--
 indra/newview/llmodelpreview.h   |  6 ++++++
 2 files changed, 14 insertions(+), 2 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp
index bf661d39b2..b17aa960ce 100644
--- a/indra/newview/llmodelpreview.cpp
+++ b/indra/newview/llmodelpreview.cpp
@@ -194,6 +194,7 @@ LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloater* fmp)
     mPreviewLOD = 0;
     mModelLoader = NULL;
     mMaxTriangleLimit = 0;
+    mMinTriangleLimit = 0;
     mDirty = false;
     mGenLOD = false;
     mLoading = false;
@@ -1508,6 +1509,7 @@ void LLModelPreview::genGlodLODs(S32 which_lod, U32 decimation, bool enforce_tri
     }
 
     mMaxTriangleLimit = base_triangle_count;
+    mMinTriangleLimit = mBaseModel.size();
 
     for (S32 lod = start; lod >= end; --lod)
     {
@@ -1541,7 +1543,7 @@ void LLModelPreview::genGlodLODs(S32 which_lod, U32 decimation, bool enforce_tri
         U32 actual_verts = 0;
         U32 submeshes = 0;
 
-        mRequestedTriangleCount[lod] = (S32)((F32)triangle_count / triangle_ratio);
+        mRequestedTriangleCount[lod] = llmax(mMinTriangleLimit, (S32)((F32)triangle_count / triangle_ratio));
         mRequestedErrorThreshold[lod] = lod_error_threshold;
 
         glodGroupParameteri(mGroup, GLOD_ADAPT_MODE, lod_mode);
@@ -2100,6 +2102,7 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d
     }
 
     mMaxTriangleLimit = base_triangle_count;
+    mMinTriangleLimit = mBaseModel.size();
 
     // TODO: Glod regenerates vertex buffer at this stage
     // check why, it might be needed to regenerate buffer as well
@@ -2133,7 +2136,7 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d
             }
         }
 
-        mRequestedTriangleCount[lod] = triangle_limit;
+        mRequestedTriangleCount[lod] = llmax(mMinTriangleLimit, (S32)triangle_limit);
         mRequestedErrorThreshold[lod] = lod_error_threshold;
         mRequestedLoDMode[lod] = lod_mode;
 
@@ -2431,6 +2434,7 @@ void LLModelPreview::updateStatusMessages()
     if (mMaxTriangleLimit == 0)
     {
         mMaxTriangleLimit = total_tris[LLModel::LOD_HIGH];
+        mMinTriangleLimit = mUploadData.size();
     }
 
     mHasDegenerate = false;
@@ -2933,6 +2937,7 @@ void LLModelPreview::updateLodControls(S32 lod)
         LLSpinCtrl* limit = mFMP->getChild<LLSpinCtrl>("lod_triangle_limit_" + lod_name[lod]);
 
         limit->setMaxValue(mMaxTriangleLimit);
+        limit->setMinValue(mMinTriangleLimit);
         limit->forceSetValue(mRequestedTriangleCount[lod]);
 
         threshold->forceSetValue(mRequestedErrorThreshold[lod]);
@@ -2945,6 +2950,7 @@ void LLModelPreview::updateLodControls(S32 lod)
             threshold->setVisible(false);
 
             limit->setMaxValue(mMaxTriangleLimit);
+            limit->setMinValue(mMinTriangleLimit);
             limit->setIncrement(llmax((U32)1, mMaxTriangleLimit / 32));
         }
         else
diff --git a/indra/newview/llmodelpreview.h b/indra/newview/llmodelpreview.h
index b3296fecf6..49032f0dbf 100644
--- a/indra/newview/llmodelpreview.h
+++ b/indra/newview/llmodelpreview.h
@@ -296,8 +296,14 @@ protected:
 
     U32 mGroup;
     std::map<LLPointer<LLModel>, U32> mObject;
+
+    // Amount of triangles in original(base) model
     U32 mMaxTriangleLimit;
 
+    // Minimum amount of allowed triangles in lod for spin cntrl.
+    // Leave at least one triangle per model.
+    S32 mMinTriangleLimit;
+
     LLMeshUploadThread::instance_list mUploadData;
     std::set<LLViewerFetchedTexture * > mTextureSet;
 
-- 
cgit v1.2.3


From 396c8bb9fe52e86a857a49020bc0feb33503a6a1 Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Mon, 6 Sep 2021 23:48:04 +0300
Subject: Revert "SL-443 Keybindings: Support reassigment of script interaction
 button"

This reverts commit a5675bedbb2bd34ce03dd16651dc74d8078efea9.
Commit slipped in by accident
---
 indra/newview/app_settings/key_bindings.xml        |  8 ---
 indra/newview/llkeyconflict.cpp                    | 58 ++--------------
 indra/newview/llkeyconflict.h                      |  4 +-
 indra/newview/lltoolcomp.cpp                       | 10 +--
 indra/newview/lltoolpie.cpp                        |  2 +-
 indra/newview/llviewerinput.cpp                    | 81 +++-------------------
 indra/newview/llviewerinput.h                      |  5 +-
 .../xui/en/control_table_contents_media.xml        | 10 ---
 8 files changed, 20 insertions(+), 158 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/app_settings/key_bindings.xml b/indra/newview/app_settings/key_bindings.xml
index ffc1b2e7cc..4f6deb1f98 100644
--- a/indra/newview/app_settings/key_bindings.xml
+++ b/indra/newview/app_settings/key_bindings.xml
@@ -33,8 +33,6 @@
     <binding key="DIVIDE" mask="NONE" command="start_gesture"/>
 
     <binding key="" mask="NONE" mouse="MMB" command="toggle_voice"/>
-
-    <binding key="" mask="NONE" mouse="LMB" command="sript_trigger_lbutton"/>
   </first_person>
   <third_person>
     <binding key="A" mask="NONE" command="turn_left"/>
@@ -129,8 +127,6 @@
 
     <binding key="" mask="NONE" mouse="MMB" command="toggle_voice"/>
     <binding key="" mask="NONE" mouse="LMB" command="walk_to"/>
-
-    <binding key="" mask="NONE" mouse="LMB" command="sript_trigger_lbutton"/>
   </third_person>
   <sitting>
     <binding key="A" mask="ALT" command="spin_around_cw"/>
@@ -228,8 +224,6 @@
     <binding key="DIVIDE" mask="NONE" command="start_gesture"/>
 
     <binding key="" mask="NONE" mouse="MMB" command="toggle_voice"/>
-
-    <binding key="" mask="NONE" mouse="LMB" command="sript_trigger_lbutton"/>
   </sitting>
   <edit_avatar>
     <!--Avatar editing camera controls-->
@@ -257,7 +251,5 @@
     <binding key="PAD_DIVIDE" mask="NONE" command="start_gesture"/>
 
     <binding key="" mask="NONE" mouse="MMB" command="toggle_voice"/>
-
-    <binding key="" mask="NONE" mouse="LMB" command="sript_trigger_lbutton"/>
   </edit_avatar>
 </keys>
diff --git a/indra/newview/llkeyconflict.cpp b/indra/newview/llkeyconflict.cpp
index 58a740e16a..d7a17b237e 100644
--- a/indra/newview/llkeyconflict.cpp
+++ b/indra/newview/llkeyconflict.cpp
@@ -868,7 +868,7 @@ void LLKeyConflictHandler::resetKeyboardBindings()
 
 void LLKeyConflictHandler::generatePlaceholders(ESourceMode load_mode)
 {
-    // These placeholds are meant to cause conflict resolution when user tries to assign same control somewhere else
+    // These controls are meant to cause conflicts when user tries to assign same control somewhere else
     // also this can be used to pre-record controls that should not conflict or to assign conflict groups/masks
 
     if (load_mode == MODE_FIRST_PERSON)
@@ -928,73 +928,25 @@ void LLKeyConflictHandler::generatePlaceholders(ESourceMode load_mode)
         registerTemporaryControl("spin_around_ccw_sitting");
         registerTemporaryControl("spin_around_cw_sitting");
     }
-
-
-    // Special case, mouse clicks passed to scripts have 'lowest' piority
-    // thus do not conflict, everything else has a chance before them
-    // also in ML they have highest priority, but only when script-grabbed,
-    // thus do not conflict
-    // (see AGENT_CONTROL_ML_LBUTTON_DOWN and CONTROL_LBUTTON_DOWN_INDEX)
-    LLKeyConflict *type_data = &mControlsMap[script_mouse_handler_name];
-    type_data->mAssignable = true;
-    type_data->mConflictMask = U32_MAX - CONFLICT_LMOUSE;
 }
 
-bool LLKeyConflictHandler::removeConflicts(const LLKeyData &data, U32 conlict_mask)
+bool LLKeyConflictHandler::removeConflicts(const LLKeyData &data, const U32 &conlict_mask)
 {
     if (conlict_mask == CONFLICT_NOTHING)
     {
         // Can't conflict
         return true;
     }
-
-    if (data.mMouse == CLICK_LEFT
-        && data.mMask == MASK_NONE
-        && data.mKey == KEY_NONE)
-    {
-        if ((conlict_mask & CONFLICT_LMOUSE) == 0)
-        {
-            // Can't conflict
-            return true;
-        }
-        else
-        {
-            // simplify conflict mask
-            conlict_mask = CONFLICT_LMOUSE;
-        }
-    }
-    else
-    {
-        // simplify conflict mask
-        conlict_mask &= ~CONFLICT_LMOUSE;
-    }
-
     std::map<std::string, S32> conflict_list;
     control_map_t::iterator cntrl_iter = mControlsMap.begin();
     control_map_t::iterator cntrl_end = mControlsMap.end();
     for (; cntrl_iter != cntrl_end; ++cntrl_iter)
     {
-        const U32 cmp_mask = cntrl_iter->second.mConflictMask;
-        if ((cmp_mask & conlict_mask) == 0)
-        {
-            // can't conflict
-            continue;
-        }
         S32 index = cntrl_iter->second.mKeyBind.findKeyData(data);
-        if (index >= 0)
+        if (index >= 0
+            && cntrl_iter->second.mConflictMask != CONFLICT_NOTHING
+            && (cntrl_iter->second.mConflictMask & conlict_mask) != 0)
         {
-            if (cmp_mask != U32_MAX)
-            {
-                const LLKeyData cmp_data = cntrl_iter->second.mKeyBind.getKeyData(index);
-                if ((cmp_mask & CONFLICT_LMOUSE) == 0
-                    && cmp_data.mMouse == CLICK_LEFT
-                    && cmp_data.mMask == MASK_NONE
-                    && cmp_data.mKey == KEY_NONE)
-                {
-                    // Does not conflict
-                    continue;
-                }
-            }
             if (cntrl_iter->second.mAssignable)
             {
                 // Potentially we can have multiple conflict flags conflicting
diff --git a/indra/newview/llkeyconflict.h b/indra/newview/llkeyconflict.h
index e78d2fa33b..2926ca3aeb 100644
--- a/indra/newview/llkeyconflict.h
+++ b/indra/newview/llkeyconflict.h
@@ -66,7 +66,6 @@ public:
     };
 
     const U32 CONFLICT_NOTHING = 0;
-    const U32 CONFLICT_LMOUSE = 0x1 << 1;
     // at the moment this just means that key will conflict with everything that is identical
     const U32 CONFLICT_ANY = U32_MAX;
 
@@ -146,7 +145,6 @@ private:
 
     // at the moment these kind of control is not savable, but takes part in conflict resolution
     void registerTemporaryControl(const std::string &control_name, EMouseClickType mouse_ind, KEY key, MASK mask, U32 conflict_mask);
-    // conflict mask 0 means that any conflicts will be ignored
     void registerTemporaryControl(const std::string &control_name, U32 conflict_mask = 0);
 
     typedef std::map<std::string, LLKeyConflict> control_map_t;
@@ -154,7 +152,7 @@ private:
     bool loadFromSettings(const ESourceMode &load_mode, const std::string &filename, control_map_t *destination);
     void generatePlaceholders(ESourceMode load_mode); //E.x. non-assignable values
     // returns false in case user is trying to reuse control that can't be reassigned
-    bool removeConflicts(const LLKeyData &data, U32 conlict_mask);
+    bool removeConflicts(const LLKeyData &data, const U32 &conlict_mask);
 
     // removes flags and removes temporary file, returns 'true' if file was removed
     bool clearUnsavedChanges();
diff --git a/indra/newview/lltoolcomp.cpp b/indra/newview/lltoolcomp.cpp
index 9ac1810964..f9c327b46e 100644
--- a/indra/newview/lltoolcomp.cpp
+++ b/indra/newview/lltoolcomp.cpp
@@ -44,7 +44,6 @@
 #include "lltoolmgr.h"
 #include "lltoolselectrect.h"
 #include "lltoolplacer.h"
-#include "llviewerinput.h"
 #include "llviewermenu.h"
 #include "llviewerobject.h"
 #include "llviewerwindow.h"
@@ -744,7 +743,7 @@ BOOL LLToolCompGun::handleHover(S32 x, S32 y, MASK mask)
 BOOL LLToolCompGun::handleMouseDown(S32 x, S32 y, MASK mask)
 { 
 	// if the left button is grabbed, don't put up the pie menu
-	if (gAgent.leftButtonGrabbed() && gViewerInput.isLMouseHandlingDefault(MODE_FIRST_PERSON))
+	if (gAgent.leftButtonGrabbed())
 	{
 		gAgent.setControlFlags(AGENT_CONTROL_ML_LBUTTON_DOWN);
 		return FALSE;
@@ -761,7 +760,7 @@ BOOL LLToolCompGun::handleMouseDown(S32 x, S32 y, MASK mask)
 BOOL LLToolCompGun::handleDoubleClick(S32 x, S32 y, MASK mask)
 {
 	// if the left button is grabbed, don't put up the pie menu
-	if (gAgent.leftButtonGrabbed() && gViewerInput.isLMouseHandlingDefault(MODE_FIRST_PERSON))
+	if (gAgent.leftButtonGrabbed())
 	{
 		gAgent.setControlFlags(AGENT_CONTROL_ML_LBUTTON_DOWN);
 		return FALSE;
@@ -795,10 +794,7 @@ BOOL LLToolCompGun::handleRightMouseDown(S32 x, S32 y, MASK mask)
 
 BOOL LLToolCompGun::handleMouseUp(S32 x, S32 y, MASK mask)
 {
-    if (gViewerInput.isLMouseHandlingDefault(MODE_FIRST_PERSON))
-    {
-        gAgent.setControlFlags(AGENT_CONTROL_ML_LBUTTON_UP);
-    }
+	gAgent.setControlFlags(AGENT_CONTROL_ML_LBUTTON_UP);
 	setCurrentTool( (LLTool*) mGun );
 	return TRUE;
 }
diff --git a/indra/newview/lltoolpie.cpp b/indra/newview/lltoolpie.cpp
index 0693775622..75a5fabdc2 100644
--- a/indra/newview/lltoolpie.cpp
+++ b/indra/newview/lltoolpie.cpp
@@ -746,7 +746,7 @@ BOOL LLToolPie::handleHover(S32 x, S32 y, MASK mask)
 	else if (!mMouseOutsideSlop 
 		&& mMouseButtonDown
 		// disable camera steering if click on land is not used for moving
-		&& gViewerInput.isMouseBindUsed(CLICK_LEFT, MASK_NONE, MODE_THIRD_PERSON))
+		&& gViewerInput.isMouseBindUsed(CLICK_LEFT))
 	{
 		S32 delta_x = x - mMouseDownX;
 		S32 delta_y = y - mMouseDownY;
diff --git a/indra/newview/llviewerinput.cpp b/indra/newview/llviewerinput.cpp
index 8b3d406b78..c0eaa88f54 100644
--- a/indra/newview/llviewerinput.cpp
+++ b/indra/newview/llviewerinput.cpp
@@ -61,7 +61,7 @@ const F32 ORBIT_NUDGE_RATE = 0.05f;  // fraction of normal speed
 const LLKeyData agent_control_lbutton(CLICK_LEFT, KEY_NONE, MASK_NONE, true);
 
 struct LLKeyboardActionRegistry 
-:	public LLRegistrySingleton<const std::string, boost::function<bool (EKeystate keystate)>, LLKeyboardActionRegistry>
+:	public LLRegistrySingleton<std::string, boost::function<bool (EKeystate keystate)>, LLKeyboardActionRegistry>
 {
 	LLSINGLETON_EMPTY_CTOR(LLKeyboardActionRegistry);
 };
@@ -836,49 +836,7 @@ bool voice_follow_key(EKeystate s)
     return false;
 }
 
-bool sript_trigger_lbutton(EKeystate s)
-{
-    // Check for script overriding/expecting left mouse button.
-    // Note that this does not pass event further and depends onto mouselook.
-    // Checks CONTROL_ML_LBUTTON_DOWN_INDEX for mouselook,
-    // CONTROL_LBUTTON_DOWN_INDEX for normal camera
-    if (gAgent.leftButtonGrabbed())
-    {
-        bool mouselook = gAgentCamera.cameraMouselook();
-        switch (s)
-        {
-        case KEYSTATE_DOWN:
-            // at the moment sript_trigger_lbutton is only intended for mouselook
-            // but handling other modes just in case
-            if (mouselook)
-            {
-                gAgent.setControlFlags(AGENT_CONTROL_ML_LBUTTON_DOWN);
-            }
-            else
-            {
-                gAgent.setControlFlags(AGENT_CONTROL_LBUTTON_DOWN);
-            }
-            return true;
-        case KEYSTATE_UP:
-            if (mouselook)
-            {
-                gAgent.setControlFlags(AGENT_CONTROL_ML_LBUTTON_UP);
-            }
-            else
-            {
-                gAgent.setControlFlags(AGENT_CONTROL_LBUTTON_UP);
-            }
-            return true;
-        default:
-            break;
-        }
-    }
-    return false;
-}
-
-// Used by scripts, for overriding/handling left mouse button
-// see mControlsTakenCount
-bool agent_control_lbutton_handle(EKeystate s)
+bool agen_control_lbutton_handle(EKeystate s)
 {
     switch (s)
     {
@@ -947,7 +905,6 @@ REGISTER_KEYBOARD_ACTION("teleport_to", teleport_to);
 REGISTER_KEYBOARD_ACTION("walk_to", walk_to);
 REGISTER_KEYBOARD_ACTION("toggle_voice", toggle_voice);
 REGISTER_KEYBOARD_ACTION("voice_follow_key", voice_follow_key);
-REGISTER_KEYBOARD_ACTION(script_mouse_handler_name, sript_trigger_lbutton);
 #undef REGISTER_KEYBOARD_ACTION
 
 LLViewerInput::LLViewerInput()
@@ -1147,20 +1104,6 @@ BOOL LLViewerInput::bindMouse(const S32 mode, const EMouseClickType mouse, const
     typedef boost::function<bool(EKeystate)> function_t;
     function_t function = NULL;
 
-    if (mouse == CLICK_LEFT
-        && mask == MASK_NONE
-        && function_name == script_mouse_handler_name)
-    {
-        // Special case
-        // Left click has script overrides and by default
-        // is handled via agent_control_lbutton as last option
-        // In case of mouselook and present overrides it has highest
-        // priority even over UI and is handled in LLToolCompGun::handleMouseDown
-        // so just mark it as having default handler
-        mLMouseDefaultHandling[mode] = true;
-        return TRUE;
-    }
-
     function_t* result = LLKeyboardActionRegistry::getValue(function_name);
     if (result)
     {
@@ -1221,7 +1164,6 @@ void LLViewerInput::resetBindings()
     {
         mKeyBindings[i].clear();
         mMouseBindings[i].clear();
-        mLMouseDefaultHandling[i] = false;
     }
 }
 
@@ -1413,14 +1355,13 @@ bool LLViewerInput::scanKey(KEY key, BOOL key_down, BOOL key_up, BOOL key_level)
 
     if (!res && agent_control_lbutton.canHandle(CLICK_NONE, key, mask))
     {
-        // pass mouse left button press to script
         if (key_down && !repeat)
         {
-            res = agent_control_lbutton_handle(KEYSTATE_DOWN);
+            res = agen_control_lbutton_handle(KEYSTATE_DOWN);
         }
         if (key_up)
         {
-            res = agent_control_lbutton_handle(KEYSTATE_UP);
+            res = agen_control_lbutton_handle(KEYSTATE_UP);
         }
     }
     return res;
@@ -1540,28 +1481,24 @@ bool LLViewerInput::scanMouse(EMouseClickType click, EMouseState state) const
     S32 mode = getMode();
     MASK mask = gKeyboard->currentMask(TRUE);
     res = scanMouse(mMouseBindings[mode], mMouseBindings[mode].size(), click, mask, state);
-
     // no user defined actions found or those actions can't handle the key/button, handle control if nessesary
-    // This will pass AGENT_CONTROL_LBUTTON_DOWN to server, no idea why it doesn't do mouselook variant _ML_
-    // but it was set this way forever (moved as is from LLTool::handleMouseDown) so lots of scripts probably
-    // rely on this.
-    if (!res && mLMouseDefaultHandling[mode] && agent_control_lbutton.canHandle(click, KEY_NONE, mask))
+    if (!res && agent_control_lbutton.canHandle(click, KEY_NONE, mask))
     {
         switch (state)
         {
         case MOUSE_STATE_DOWN:
-            agent_control_lbutton_handle(KEYSTATE_DOWN);
+            agen_control_lbutton_handle(KEYSTATE_DOWN);
             res = true;
             break;
         case MOUSE_STATE_CLICK:
             // might not work best with some functions,
             // but some function need specific states too specifically
-            agent_control_lbutton_handle(KEYSTATE_DOWN);
-            agent_control_lbutton_handle(KEYSTATE_UP);
+            agen_control_lbutton_handle(KEYSTATE_DOWN);
+            agen_control_lbutton_handle(KEYSTATE_UP);
             res = true;
             break;
         case MOUSE_STATE_UP:
-            agent_control_lbutton_handle(KEYSTATE_UP);
+            agen_control_lbutton_handle(KEYSTATE_UP);
             res = true;
             break;
         default:
diff --git a/indra/newview/llviewerinput.h b/indra/newview/llviewerinput.h
index 32dd3c0e28..281a209896 100644
--- a/indra/newview/llviewerinput.h
+++ b/indra/newview/llviewerinput.h
@@ -31,7 +31,6 @@
 #include "llinitparam.h"
 
 const S32 MAX_KEY_BINDINGS = 128; // was 60
-const std::string script_mouse_handler_name = "sript_trigger_lbutton";
 
 class LLNamedFunction
 {
@@ -125,8 +124,7 @@ public:
     BOOL            handleMouse(LLWindow *window_impl, LLCoordGL pos, MASK mask, EMouseClickType clicktype, BOOL down);
     void            scanMouse();
 
-    bool            isMouseBindUsed(const EMouseClickType mouse, const MASK mask, const S32 mode);
-    bool            isLMouseHandlingDefault(const S32 mode) { return mLMouseDefaultHandling[mode]; }
+    bool            isMouseBindUsed(const EMouseClickType mouse, const MASK mask = MASK_NONE, const S32 mode = MODE_THIRD_PERSON);
 
 private:
     bool            scanKey(const std::vector<LLKeyboardBinding> &binding,
@@ -165,7 +163,6 @@ private:
     // to send what we think function wants based on collection of bools (mKeyRepeated, mKeyLevel, mKeyDown)
     std::vector<LLKeyboardBinding>	mKeyBindings[MODE_COUNT];
     std::vector<LLMouseBinding>		mMouseBindings[MODE_COUNT];
-    bool							mLMouseDefaultHandling[MODE_COUNT]; // Due to having special priority
 
 	typedef std::map<U32, U32> key_remap_t;
 	key_remap_t		mRemapKeys[MODE_COUNT];
diff --git a/indra/newview/skins/default/xui/en/control_table_contents_media.xml b/indra/newview/skins/default/xui/en/control_table_contents_media.xml
index a97c45dd6f..ce5d3556b6 100644
--- a/indra/newview/skins/default/xui/en/control_table_contents_media.xml
+++ b/indra/newview/skins/default/xui/en/control_table_contents_media.xml
@@ -73,14 +73,4 @@
          name="lst_action"
          value="Start Gesture" />
     </rows>
-    <rows
-     name="sript_trigger_lbutton"
-     value="sript_trigger_lbutton">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Interact (Script LMB)" />
-    </rows>
 </contents>
-- 
cgit v1.2.3


From 0bcf150d4e25f701fbed7ea0141fb580d698ee4d Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Thu, 15 Jul 2021 18:37:02 +0300
Subject: SL-443 keybindings: Do not error on unknown function

It is likely be from newer viewer / Preparations for SL-443 deloyment.
---
 indra/newview/llviewerinput.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llviewerinput.cpp b/indra/newview/llviewerinput.cpp
index c0eaa88f54..f269be035e 100644
--- a/indra/newview/llviewerinput.cpp
+++ b/indra/newview/llviewerinput.cpp
@@ -1070,7 +1070,7 @@ BOOL LLViewerInput::bindKey(const S32 mode, const KEY key, const MASK mask, cons
 
 	if (!function)
 	{
-		LL_ERRS() << "Can't bind key to function " << function_name << ", no function with this name found" << LL_ENDL;
+		LL_WARNS() << "Can't bind key to function " << function_name << ", no function with this name found" << LL_ENDL;
 		return FALSE;
 	}
 
@@ -1112,7 +1112,7 @@ BOOL LLViewerInput::bindMouse(const S32 mode, const EMouseClickType mouse, const
 
     if (!function)
     {
-        LL_ERRS() << "Can't bind key to function " << function_name << ", no function with this name found" << LL_ENDL;
+        LL_WARNS() << "Can't bind mouse key to function " << function_name << ", no function with this name found" << LL_ENDL;
         return FALSE;
     }
 
-- 
cgit v1.2.3


From e7373ff2f52f375ba9b6ffbf4d3b9f1996d2007e Mon Sep 17 00:00:00 2001
From: Andrey Lihatskiy <alihatskiy@productengine.com>
Date: Mon, 2 Aug 2021 23:56:24 +0300
Subject: SL-15201 Increased the viewer version to 6.5 for new-feature viewer

---
 indra/newview/VIEWER_VERSION.txt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'indra')

diff --git a/indra/newview/VIEWER_VERSION.txt b/indra/newview/VIEWER_VERSION.txt
index 4c8366c864..f22d756da3 100644
--- a/indra/newview/VIEWER_VERSION.txt
+++ b/indra/newview/VIEWER_VERSION.txt
@@ -1 +1 @@
-6.4.23
+6.5.0
-- 
cgit v1.2.3


From ca629c362c5ed248547f9df057703079c95331e7 Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Thu, 9 Sep 2021 20:59:21 +0300
Subject: SL-15965 Support wider range of parsing errors

---
 indra/llprimitive/lldaeloader.cpp                  | 56 ++++++++++++++++++++--
 .../skins/default/xui/en/floater_model_preview.xml | 14 ++++++
 2 files changed, 66 insertions(+), 4 deletions(-)

(limited to 'indra')

diff --git a/indra/llprimitive/lldaeloader.cpp b/indra/llprimitive/lldaeloader.cpp
index dcf3b5fa0e..73a0b3d673 100644
--- a/indra/llprimitive/lldaeloader.cpp
+++ b/indra/llprimitive/lldaeloader.cpp
@@ -153,7 +153,8 @@ LLModel::EModelStatus load_face_from_dom_triangles(
     std::vector<LLVolumeFace>& face_list,
     std::vector<std::string>& materials,
     domTrianglesRef& tri,
-    bool &generated_additional_faces)
+    bool &generated_additional_faces,
+    LLSD& log_msg)
 {
 	LLVolumeFace face;
 	std::vector<LLVolumeFace::VertexData> verts;
@@ -173,12 +174,18 @@ LLModel::EModelStatus load_face_from_dom_triangles(
 
 	if ( !get_dom_sources(inputs, pos_offset, tc_offset, norm_offset, idx_stride, pos_source, tc_source, norm_source))
 	{
+        LLSD args;
+        args["Message"] = "ParsingErrorBadElement";
+        log_msg.append(args);
 		return LLModel::BAD_ELEMENT;
 	}
 
 	if (!pos_source || !pos_source->getFloat_array())
 	{
 		LL_WARNS() << "Unable to process mesh without position data; invalid model;  invalid model." << LL_ENDL;
+        LLSD args;
+        args["Message"] = "ParsingErrorPositionInvalidModel";
+        log_msg.append(args);
 		return LLModel::BAD_ELEMENT;
 	}
 
@@ -381,6 +388,10 @@ LLModel::EModelStatus load_face_from_dom_polylist(
 
 	if (!get_dom_sources(inputs, pos_offset, tc_offset, norm_offset, idx_stride, pos_source, tc_source, norm_source))
 	{
+        LL_WARNS() << "Bad element." << LL_ENDL;
+        LLSD args;
+        args["Message"] = "ParsingErrorBadElement";
+        log_msg.append(args);
 		return LLModel::BAD_ELEMENT;
 	}
 
@@ -432,6 +443,9 @@ LLModel::EModelStatus load_face_from_dom_polylist(
 				if (!cv.getPosition().isFinite3())
 				{
 					LL_WARNS() << "Found NaN while loading position data from DAE-Model, invalid model." << LL_ENDL;
+                    LLSD args;
+                    args["Message"] = "PositionNaN";
+                    log_msg.append(args);
 					return LLModel::BAD_ELEMENT;
 				}
 			}
@@ -464,6 +478,10 @@ LLModel::EModelStatus load_face_from_dom_polylist(
 				if (!cv.getNormal().isFinite3())
 				{
 					LL_WARNS() << "Found NaN while loading normals from DAE-Model, invalid model." << LL_ENDL;
+                    LLSD args;
+                    args["Message"] = "NormalsNaN";
+                    log_msg.append(args);
+
 					return LLModel::BAD_ELEMENT;
 				}
 			}
@@ -928,6 +946,9 @@ bool LLDAELoader::OpenFile(const std::string& filename)
 	if (!dom)
 	{
 		LL_INFOS() <<" Error with dae - traditionally indicates a corrupt file."<<LL_ENDL;
+        LLSD args;
+        args["Message"] = "ParsingErrorCorrupt";
+        mWarningsArray.append(args);
 		setLoadState( ERROR_PARSING );
 		return false;
 	}
@@ -955,6 +976,9 @@ bool LLDAELoader::OpenFile(const std::string& filename)
 	if (!doc)
 	{
 		LL_WARNS() << "can't find internal doc" << LL_ENDL;
+        LLSD args;
+        args["Message"] = "ParsingErrorNoDoc";
+        mWarningsArray.append(args);
 		return false;
 	}
 	
@@ -962,6 +986,9 @@ bool LLDAELoader::OpenFile(const std::string& filename)
 	if (!root)
 	{
 		LL_WARNS() << "document has no root" << LL_ENDL;
+        LLSD args;
+        args["Message"] = "ParsingErrorNoRoot";
+        mWarningsArray.append(args);
 		return false;
 	}
 	
@@ -977,6 +1004,9 @@ bool LLDAELoader::OpenFile(const std::string& filename)
 		if (!result)
 		{
 			LL_INFOS() << "Could not verify controller" << LL_ENDL;
+            LLSD args;
+            args["Message"] = "ParsingErrorBadElement";
+            mWarningsArray.append(args);
 			setLoadState( ERROR_PARSING );
 			return true;
 		}
@@ -1110,6 +1140,9 @@ bool LLDAELoader::OpenFile(const std::string& filename)
 	if (!scene)
 	{
 		LL_WARNS() << "document has no visual_scene" << LL_ENDL;
+        LLSD args;
+        args["Message"] = "ParsingErrorNoScene";
+        mWarningsArray.append(args);
 		setLoadState( ERROR_PARSING );
 		return true;
 	}
@@ -1118,11 +1151,14 @@ bool LLDAELoader::OpenFile(const std::string& filename)
 
 	bool badElement = false;
 	
-	processElement( scene, badElement, &dae );
+	processElement( scene, badElement, &dae);
 	
 	if ( badElement )
 	{
 		LL_INFOS()<<"Scene could not be parsed"<<LL_ENDL;
+        LLSD args;
+        args["Message"] = "ParsingErrorCantParseScene";
+        mWarningsArray.append(args);
 		setLoadState( ERROR_PARSING );
 	}
 	
@@ -1961,7 +1997,7 @@ daeElement* LLDAELoader::getChildFromElement( daeElement* pElement, std::string
     return NULL;
 }
 
-void LLDAELoader::processElement( daeElement* element, bool& badElement, DAE* dae )
+void LLDAELoader::processElement( daeElement* element, bool& badElement, DAE* dae)
 {
 	LLMatrix4 saved_transform;
 	bool pushed_mat = false;
@@ -2055,6 +2091,11 @@ void LLDAELoader::processElement( daeElement* element, bool& badElement, DAE* da
 					if (mTransform.determinant() < 0)
 					{ //negative scales are not supported
 						LL_INFOS() << "Negative scale detected, unsupported transform.  domInstance_geometry: " << getElementLabel(instance_geo) << LL_ENDL;
+                        LLSD args;
+                        args["Message"] = "NegativeScaleTrans";
+                        args["LABEL"] = getElementLabel(instance_geo);
+                        mWarningsArray.append(args);
+
 						badElement = true;
 					}
 
@@ -2078,6 +2119,10 @@ void LLDAELoader::processElement( daeElement* element, bool& badElement, DAE* da
 					if (transformation.determinant() < 0)
 					{ //negative scales are not supported
 						LL_INFOS() << "Negative scale detected, unsupported post-normalization transform.  domInstance_geometry: " << getElementLabel(instance_geo) << LL_ENDL;
+                        LLSD args;
+                        args["Message"] = "NegativeScaleNormTrans";
+                        args["LABEL"] = getElementLabel(instance_geo);
+                        mWarningsArray.append(args);
 						badElement = true;
 					}
 
@@ -2119,6 +2164,9 @@ void LLDAELoader::processElement( daeElement* element, bool& badElement, DAE* da
 		else 
 		{
 			LL_INFOS()<<"Unable to resolve geometry URL."<<LL_ENDL;
+            LLSD args;
+            args["Message"] = "CantResolveGeometryUrl";
+            mWarningsArray.append(args);
 			badElement = true;			
 		}
 
@@ -2411,7 +2459,7 @@ bool LLDAELoader::addVolumeFacesFromDomMesh(LLModel* pModel,domMesh* mesh, LLSD&
 	{
 		domTrianglesRef& tri = tris.get(i);
 
-		status = load_face_from_dom_triangles(pModel->getVolumeFaces(), pModel->getMaterialList(), tri, pModel->mHasGeneratedFaces);
+		status = load_face_from_dom_triangles(pModel->getVolumeFaces(), pModel->getMaterialList(), tri, pModel->mHasGeneratedFaces, log_msg);
 		pModel->mStatus = status;
 		if(status != LLModel::NO_ERRORS)
 		{
diff --git a/indra/newview/skins/default/xui/en/floater_model_preview.xml b/indra/newview/skins/default/xui/en/floater_model_preview.xml
index db9d296fa5..05990e28d8 100644
--- a/indra/newview/skins/default/xui/en/floater_model_preview.xml
+++ b/indra/newview/skins/default/xui/en/floater_model_preview.xml
@@ -45,7 +45,21 @@
   <string name="UnrecognizedJoint">Rigged to unrecognized joint name [NAME]</string>
   <string name="UnknownJoints">Skinning disabled due to [COUNT] unknown joints</string>
   <string name="ModelLoaded">Model [MODEL_NAME] loaded</string>
+
   <string name="IncompleteTC">Texture coordinates data is not complete.</string>
+  <string name="PositionNaN">Found NaN while loading position data from DAE-Model, invalid model.</string>
+  <string name="NormalsNaN">Found NaN while loading normals from DAE-Model, invalid model.</string>
+  <string name="NegativeScaleTrans">Negative scale detected, unsupported transform. domInstance_geometry: [LABEL]</string>
+  <string name="NegativeScaleNormTrans">Negative scale detected, unsupported post-normalization transform. domInstance_geometry: [LABEL]</string>
+  <string name="CantResolveGeometryUrl">Unable to resolve geometry URL.</string>
+  <string name="ParsingErrorBadElement">Bad element</string>
+  <string name="ParsingErrorCantParseScene">Scene could not be parsed</string>
+  <string name="ParsingErrorCorrupt">Error with dae - traditionally indicates a corrupt file.</string>
+  <string name="ParsingErrorNoController">Could not verify controller</string>
+  <string name="ParsingErrorNoDoc">Can't find internal doc</string>
+  <string name="ParsingErrorNoRoot">Document has no root</string>
+  <string name="ParsingErrorNoScene">Document has no visual_scene</string>
+  <string name="ParsingErrorPositionInvalidModel">Unable to process mesh without position data. Invalid model.</string>
 
   <panel
     follows="top|left"
-- 
cgit v1.2.3


From f2d4f83931f77282d6cdeba582def46b51c22b89 Mon Sep 17 00:00:00 2001
From: Dave Houlton <euclid@lindenlab.com>
Date: Wed, 15 Sep 2021 10:11:25 -0600
Subject: SL-15962 Add hooks for tracy memory profiling

---
 indra/llcommon/linden_common.h |  8 ++++++++
 indra/llcommon/llcommon.cpp    | 42 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 50 insertions(+)

(limited to 'indra')

diff --git a/indra/llcommon/linden_common.h b/indra/llcommon/linden_common.h
index 45ac43910c..b2c5be6b76 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)  // 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/llcommon.cpp b/indra/llcommon/llcommon.cpp
index 96be913d17..da61e7539a 100644
--- a/indra/llcommon/llcommon.cpp
+++ b/indra/llcommon/llcommon.cpp
@@ -33,6 +33,48 @@
 #include "lltracethreadrecorder.h"
 #include "llcleanup.h"
 
+#if (TRACY_ENABLE)
+// Override new/delet for tracy memory profiling
+void *operator new(size_t size)
+{
+    auto ptr = (malloc) (size);
+    if (!ptr)
+    {
+        throw std::bad_alloc();
+        return nullptr;
+    }
+    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 = (_aligned_malloc) (size, alignment);
+    if (ptr) TracyAlloc(ptr, size);
+    return ptr;
+}
+
+void tracy_aligned_free(void *memblock)
+{
+    TracyFree(memblock);
+    (_aligned_free)(memblock);
+}
+
+#endif
+
 //static
 BOOL LLCommon::sAprInitialized = FALSE;
 
-- 
cgit v1.2.3


From 7fe2856516d9e0de0fda6ff389ad3cc977b2d309 Mon Sep 17 00:00:00 2001
From: Runitai Linden <davep@lindenlab.com>
Date: Mon, 13 Sep 2021 12:41:57 -0500
Subject: SL-15975 Add Tracy-only profile macros that are no-ops when Tracy is
 disabled.

---
 indra/llcommon/llprofiler.h        | 6 ++++++
 indra/newview/lldrawpoolavatar.cpp | 4 ++++
 2 files changed, 10 insertions(+)

(limited to 'indra')

diff --git a/indra/llcommon/llprofiler.h b/indra/llcommon/llprofiler.h
index 062c9360dd..62e649913b 100644
--- a/indra/llcommon/llprofiler.h
+++ b/indra/llcommon/llprofiler.h
@@ -51,16 +51,22 @@
         #define LL_PROFILER_FRAME_END               FrameMark
         #define LL_PROFILER_SET_THREAD_NAME( name ) tracy::SetThreadName( name )
         #define LL_RECORD_BLOCK_TIME(name)          ZoneNamedN( ___tracy_scoped_zone, #name, true );
+        #define LL_PROFILE_ZONE_NAMED(name)          ZoneNamedN( ___tracy_scoped_zone, name, true );  
+        #define LL_PROFILE_ZONE_SCOPED              ZoneScoped
     #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
     #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)          ZoneNamedN( ___tracy_scoped_zone, #timer_stat, true )   const LLTrace::BlockTimer& LL_GLUE_TOKENS(block_time_recorder, __LINE__)(LLTrace::timeThisBlock(name)); (void)LL_GLUE_TOKENS(block_time_recorder, __LINE__);
+        #define LL_PROFILE_ZONE_NAMED(name)         ZoneNamedN( ___tracy_scoped_zone, #name, true );
+        #define LL_PROFILE_ZONE_SCOPED              ZoneScoped
     #endif
 #else
     #define LL_PROFILER_FRAME_END
diff --git a/indra/newview/lldrawpoolavatar.cpp b/indra/newview/lldrawpoolavatar.cpp
index 687b13d2c8..c04142ab47 100644
--- a/indra/newview/lldrawpoolavatar.cpp
+++ b/indra/newview/lldrawpoolavatar.cpp
@@ -1840,6 +1840,8 @@ void LLDrawPoolAvatar::updateRiggedFaceVertexBuffer(
     LLVolume* volume,
     LLVolumeFace& vol_face)
 {
+    LL_PROFILE_ZONE_SCOPED;
+
 	LLVector4a* weights = vol_face.mWeights;
 	if (!weights)
 	{
@@ -2352,8 +2354,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)
-- 
cgit v1.2.3


From 04e1962d48e36f9055f0d893fc1b7a97d9e334c6 Mon Sep 17 00:00:00 2001
From: "Brad Payne (Vir Linden)" <vir@lindenlab.com>
Date: Wed, 15 Sep 2021 20:06:56 +0100
Subject: SL-15742 - python 3 support for integration test script

---
 indra/llcommon/tests/llprocess_test.cpp | 32 ++++++++++++++++++++------------
 1 file changed, 20 insertions(+), 12 deletions(-)

(limited to 'indra')

diff --git a/indra/llcommon/tests/llprocess_test.cpp b/indra/llcommon/tests/llprocess_test.cpp
index f0eafa8201..447c7f50f2 100644
--- a/indra/llcommon/tests/llprocess_test.cpp
+++ b/indra/llcommon/tests/llprocess_test.cpp
@@ -356,14 +356,15 @@ namespace tut
 
         // Create a script file in a temporary place.
         NamedTempFile script("py",
+			"from __future__ import print_function" EOL
             "import sys" EOL
             "import time" EOL
             EOL
             "time.sleep(2)" EOL
-            "print >>sys.stdout, 'stdout after wait'" EOL
+            "print('stdout after wait',file=sys.stdout)" EOL
             "sys.stdout.flush()" EOL
             "time.sleep(2)" EOL
-            "print >>sys.stderr, 'stderr after wait'" EOL
+            "print('stderr after wait',file=sys.stderr)" EOL
             "sys.stderr.flush()" EOL
             );
 
@@ -568,12 +569,12 @@ namespace tut
     {
         set_test_name("arguments");
         PythonProcessLauncher py(get_test_name(),
-                                 "from __future__ import with_statement\n"
+                                 "from __future__ import with_statement, print_function\n"
                                  "import sys\n"
                                  // note nonstandard output-file arg!
                                  "with open(sys.argv[3], 'w') as f:\n"
                                  "    for arg in sys.argv[1:]:\n"
-                                 "        print >>f, arg\n");
+                                 "        print(arg,file=f)\n");
         // We expect that PythonProcessLauncher has already appended
         // its own NamedTempFile to mParams.args (sys.argv[0]).
         py.mParams.args.add("first arg");          // sys.argv[1]
@@ -857,7 +858,8 @@ namespace tut
         set_test_name("'bogus' test");
         CaptureLog recorder;
         PythonProcessLauncher py(get_test_name(),
-                                 "print 'Hello world'\n");
+                                 "from __future__ import print_function\n"
+                                 "print('Hello world')\n");
         py.mParams.files.add(LLProcess::FileParam("bogus"));
         py.mPy = LLProcess::create(py.mParams);
         ensure("should have rejected 'bogus'", ! py.mPy);
@@ -872,7 +874,8 @@ namespace tut
         // Replace this test with one or more real 'file' tests when we
         // implement 'file' support
         PythonProcessLauncher py(get_test_name(),
-                                 "print 'Hello world'\n");
+                                 "from __future__ import print_function\n"
+                                 "print('Hello world')\n");
         py.mParams.files.add(LLProcess::FileParam());
         py.mParams.files.add(LLProcess::FileParam("file"));
         py.mPy = LLProcess::create(py.mParams);
@@ -887,7 +890,8 @@ namespace tut
         // implement 'tpipe' support
         CaptureLog recorder;
         PythonProcessLauncher py(get_test_name(),
-                                 "print 'Hello world'\n");
+                                 "from __future__ import print_function\n"
+                                 "print('Hello world')\n");
         py.mParams.files.add(LLProcess::FileParam());
         py.mParams.files.add(LLProcess::FileParam("tpipe"));
         py.mPy = LLProcess::create(py.mParams);
@@ -904,7 +908,8 @@ namespace tut
         // implement 'npipe' support
         CaptureLog recorder;
         PythonProcessLauncher py(get_test_name(),
-                                 "print 'Hello world'\n");
+                                 "from __future__ import print_function\n"
+                                 "print('Hello world')\n");
         py.mParams.files.add(LLProcess::FileParam());
         py.mParams.files.add(LLProcess::FileParam());
         py.mParams.files.add(LLProcess::FileParam("npipe"));
@@ -980,7 +985,8 @@ namespace tut
     {
         set_test_name("get*Pipe() validation");
         PythonProcessLauncher py(get_test_name(),
-                                 "print 'this output is expected'\n");
+                                 "from __future__ import print_function\n"
+                                 "print('this output is expected')\n");
         py.mParams.files.add(LLProcess::FileParam("pipe")); // pipe for  stdin
         py.mParams.files.add(LLProcess::FileParam());       // inherit stdout
         py.mParams.files.add(LLProcess::FileParam("pipe")); // pipe for stderr
@@ -1000,14 +1006,15 @@ namespace tut
     {
         set_test_name("talk to stdin/stdout");
         PythonProcessLauncher py(get_test_name(),
+                                 "from __future__ import print_function\n"
                                  "import sys, time\n"
-                                 "print 'ok'\n"
+                                 "print('ok')\n"
                                  "sys.stdout.flush()\n"
                                  "# wait for 'go' from test program\n"
                                  "go = sys.stdin.readline()\n"
                                  "if go != 'go\\n':\n"
                                  "    sys.exit('expected \"go\", saw %r' % go)\n"
-                                 "print 'ack'\n");
+                                 "print('ack')\n");
         py.mParams.files.add(LLProcess::FileParam("pipe")); // stdin
         py.mParams.files.add(LLProcess::FileParam("pipe")); // stdout
         py.launch();
@@ -1118,7 +1125,8 @@ namespace tut
     {
         set_test_name("ReadPipe \"eof\" event");
         PythonProcessLauncher py(get_test_name(),
-                                 "print 'Hello from Python!'\n");
+                                 "from __future__ import print_function\n"
+                                 "print('Hello from Python!')\n");
         py.mParams.files.add(LLProcess::FileParam()); // stdin
         py.mParams.files.add(LLProcess::FileParam("pipe")); // stdout
         py.launch();
-- 
cgit v1.2.3


From d343313f3f0dc8eba75c939cac3e02fe020cb165 Mon Sep 17 00:00:00 2001
From: "Brad Payne (Vir Linden)" <vir@lindenlab.com>
Date: Wed, 15 Sep 2021 20:06:56 +0100
Subject: SL-15742 - python 3 support for integration test script

---
 indra/llcommon/tests/llprocess_test.cpp | 32 ++++++++++++++++++++------------
 1 file changed, 20 insertions(+), 12 deletions(-)

(limited to 'indra')

diff --git a/indra/llcommon/tests/llprocess_test.cpp b/indra/llcommon/tests/llprocess_test.cpp
index f0eafa8201..447c7f50f2 100644
--- a/indra/llcommon/tests/llprocess_test.cpp
+++ b/indra/llcommon/tests/llprocess_test.cpp
@@ -356,14 +356,15 @@ namespace tut
 
         // Create a script file in a temporary place.
         NamedTempFile script("py",
+			"from __future__ import print_function" EOL
             "import sys" EOL
             "import time" EOL
             EOL
             "time.sleep(2)" EOL
-            "print >>sys.stdout, 'stdout after wait'" EOL
+            "print('stdout after wait',file=sys.stdout)" EOL
             "sys.stdout.flush()" EOL
             "time.sleep(2)" EOL
-            "print >>sys.stderr, 'stderr after wait'" EOL
+            "print('stderr after wait',file=sys.stderr)" EOL
             "sys.stderr.flush()" EOL
             );
 
@@ -568,12 +569,12 @@ namespace tut
     {
         set_test_name("arguments");
         PythonProcessLauncher py(get_test_name(),
-                                 "from __future__ import with_statement\n"
+                                 "from __future__ import with_statement, print_function\n"
                                  "import sys\n"
                                  // note nonstandard output-file arg!
                                  "with open(sys.argv[3], 'w') as f:\n"
                                  "    for arg in sys.argv[1:]:\n"
-                                 "        print >>f, arg\n");
+                                 "        print(arg,file=f)\n");
         // We expect that PythonProcessLauncher has already appended
         // its own NamedTempFile to mParams.args (sys.argv[0]).
         py.mParams.args.add("first arg");          // sys.argv[1]
@@ -857,7 +858,8 @@ namespace tut
         set_test_name("'bogus' test");
         CaptureLog recorder;
         PythonProcessLauncher py(get_test_name(),
-                                 "print 'Hello world'\n");
+                                 "from __future__ import print_function\n"
+                                 "print('Hello world')\n");
         py.mParams.files.add(LLProcess::FileParam("bogus"));
         py.mPy = LLProcess::create(py.mParams);
         ensure("should have rejected 'bogus'", ! py.mPy);
@@ -872,7 +874,8 @@ namespace tut
         // Replace this test with one or more real 'file' tests when we
         // implement 'file' support
         PythonProcessLauncher py(get_test_name(),
-                                 "print 'Hello world'\n");
+                                 "from __future__ import print_function\n"
+                                 "print('Hello world')\n");
         py.mParams.files.add(LLProcess::FileParam());
         py.mParams.files.add(LLProcess::FileParam("file"));
         py.mPy = LLProcess::create(py.mParams);
@@ -887,7 +890,8 @@ namespace tut
         // implement 'tpipe' support
         CaptureLog recorder;
         PythonProcessLauncher py(get_test_name(),
-                                 "print 'Hello world'\n");
+                                 "from __future__ import print_function\n"
+                                 "print('Hello world')\n");
         py.mParams.files.add(LLProcess::FileParam());
         py.mParams.files.add(LLProcess::FileParam("tpipe"));
         py.mPy = LLProcess::create(py.mParams);
@@ -904,7 +908,8 @@ namespace tut
         // implement 'npipe' support
         CaptureLog recorder;
         PythonProcessLauncher py(get_test_name(),
-                                 "print 'Hello world'\n");
+                                 "from __future__ import print_function\n"
+                                 "print('Hello world')\n");
         py.mParams.files.add(LLProcess::FileParam());
         py.mParams.files.add(LLProcess::FileParam());
         py.mParams.files.add(LLProcess::FileParam("npipe"));
@@ -980,7 +985,8 @@ namespace tut
     {
         set_test_name("get*Pipe() validation");
         PythonProcessLauncher py(get_test_name(),
-                                 "print 'this output is expected'\n");
+                                 "from __future__ import print_function\n"
+                                 "print('this output is expected')\n");
         py.mParams.files.add(LLProcess::FileParam("pipe")); // pipe for  stdin
         py.mParams.files.add(LLProcess::FileParam());       // inherit stdout
         py.mParams.files.add(LLProcess::FileParam("pipe")); // pipe for stderr
@@ -1000,14 +1006,15 @@ namespace tut
     {
         set_test_name("talk to stdin/stdout");
         PythonProcessLauncher py(get_test_name(),
+                                 "from __future__ import print_function\n"
                                  "import sys, time\n"
-                                 "print 'ok'\n"
+                                 "print('ok')\n"
                                  "sys.stdout.flush()\n"
                                  "# wait for 'go' from test program\n"
                                  "go = sys.stdin.readline()\n"
                                  "if go != 'go\\n':\n"
                                  "    sys.exit('expected \"go\", saw %r' % go)\n"
-                                 "print 'ack'\n");
+                                 "print('ack')\n");
         py.mParams.files.add(LLProcess::FileParam("pipe")); // stdin
         py.mParams.files.add(LLProcess::FileParam("pipe")); // stdout
         py.launch();
@@ -1118,7 +1125,8 @@ namespace tut
     {
         set_test_name("ReadPipe \"eof\" event");
         PythonProcessLauncher py(get_test_name(),
-                                 "print 'Hello from Python!'\n");
+                                 "from __future__ import print_function\n"
+                                 "print('Hello from Python!')\n");
         py.mParams.files.add(LLProcess::FileParam()); // stdin
         py.mParams.files.add(LLProcess::FileParam("pipe")); // stdout
         py.launch();
-- 
cgit v1.2.3


From a4c9fb003f36955cecb0b987b5ddf9a04edd0f90 Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Fri, 3 Sep 2021 17:20:22 -0700
Subject: SL-15709: Windows: Include Tracy source directly; don't use a library

---
 indra/cmake/LLCommon.cmake      |  1 -
 indra/cmake/Tracy.cmake         |  3 ---
 indra/llcommon/llframetimer.cpp | 11 ++++-------
 indra/llcommon/llprofiler.h     |  6 ++++--
 4 files changed, 8 insertions(+), 13 deletions(-)

(limited to 'indra')

diff --git a/indra/cmake/LLCommon.cmake b/indra/cmake/LLCommon.cmake
index b6f310fe12..34499aaa36 100644
--- a/indra/cmake/LLCommon.cmake
+++ b/indra/cmake/LLCommon.cmake
@@ -33,7 +33,6 @@ else (LINUX)
         ${BOOST_CONTEXT_LIBRARY} 
         ${BOOST_THREAD_LIBRARY} 
         ${BOOST_SYSTEM_LIBRARY}
-        ${TRACY_LIBRARY}
         )
 endif (LINUX)
 
diff --git a/indra/cmake/Tracy.cmake b/indra/cmake/Tracy.cmake
index dfa3e83039..1b8c3db2e2 100644
--- a/indra/cmake/Tracy.cmake
+++ b/indra/cmake/Tracy.cmake
@@ -12,17 +12,14 @@ if (USE_TRACY)
 
   if (WINDOWS)
     MESSAGE(STATUS "Including Tracy for Windows: '${TRACY_INCLUDE_DIR}'")
-    set(TRACY_LIBRARY tracy)
   endif (WINDOWS)
 
   if (DARWIN)
     MESSAGE(STATUS "Including Tracy for Darwin: '${TRACY_INCLUDE_DIR}'")
-    set(TRACY_LIBRARY "")
   endif (DARWIN)
 
   if (LINUX)
     MESSAGE(STATUS "Including Tracy for Linux: '${TRACY_INCLUDE_DIR}'")
-    set(TRACY_LIBRARY "")
   endif (LINUX)
 else (USE_TRACY)
   # Tracy.cmake should not set LLCOMMON_INCLUDE_DIRS, let LLCommon.cmake do that
diff --git a/indra/llcommon/llframetimer.cpp b/indra/llcommon/llframetimer.cpp
index e293a557c0..c54029e8b4 100644
--- a/indra/llcommon/llframetimer.cpp
+++ b/indra/llcommon/llframetimer.cpp
@@ -29,13 +29,10 @@
 
 #include "llframetimer.h"
 
-// On Windows we build a static lib and link with that
-// On macOS we don't bother building a stand alone lib, just include the one source file we need for Tracy support
-#if LL_DARWIN
-	#if LL_PROFILER_CONFIGURATION == LL_PROFILER_CONFIG_TRACY || LL_PROFILER_CONFIGURATION == LL_PROFILER_CONFIG_TRACY_FAST_TIMER
-		#include "TracyClient.cpp"
-	#endif // LL_PROFILER_CONFIGURATION
-#endif // LL_DARWIN
+// 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;
diff --git a/indra/llcommon/llprofiler.h b/indra/llcommon/llprofiler.h
index 4674985e06..062c9360dd 100644
--- a/indra/llcommon/llprofiler.h
+++ b/indra/llcommon/llprofiler.h
@@ -39,8 +39,10 @@
 #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
-        #define TRACY_NO_BROADCAST   1
-        #define TRACY_ONLY_LOCALHOST 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"
     #endif
-- 
cgit v1.2.3


From fc612fd8a0057daa7436c8d2285ccee0c634378a Mon Sep 17 00:00:00 2001
From: Runitai Linden <davep@lindenlab.com>
Date: Mon, 13 Sep 2021 12:41:57 -0500
Subject: SL-15975 Add Tracy-only profile macros that are no-ops when Tracy is
 disabled.

---
 indra/llcommon/llprofiler.h        | 6 ++++++
 indra/newview/lldrawpoolavatar.cpp | 4 ++++
 2 files changed, 10 insertions(+)

(limited to 'indra')

diff --git a/indra/llcommon/llprofiler.h b/indra/llcommon/llprofiler.h
index 062c9360dd..62e649913b 100644
--- a/indra/llcommon/llprofiler.h
+++ b/indra/llcommon/llprofiler.h
@@ -51,16 +51,22 @@
         #define LL_PROFILER_FRAME_END               FrameMark
         #define LL_PROFILER_SET_THREAD_NAME( name ) tracy::SetThreadName( name )
         #define LL_RECORD_BLOCK_TIME(name)          ZoneNamedN( ___tracy_scoped_zone, #name, true );
+        #define LL_PROFILE_ZONE_NAMED(name)          ZoneNamedN( ___tracy_scoped_zone, name, true );  
+        #define LL_PROFILE_ZONE_SCOPED              ZoneScoped
     #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
     #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)          ZoneNamedN( ___tracy_scoped_zone, #timer_stat, true )   const LLTrace::BlockTimer& LL_GLUE_TOKENS(block_time_recorder, __LINE__)(LLTrace::timeThisBlock(name)); (void)LL_GLUE_TOKENS(block_time_recorder, __LINE__);
+        #define LL_PROFILE_ZONE_NAMED(name)         ZoneNamedN( ___tracy_scoped_zone, #name, true );
+        #define LL_PROFILE_ZONE_SCOPED              ZoneScoped
     #endif
 #else
     #define LL_PROFILER_FRAME_END
diff --git a/indra/newview/lldrawpoolavatar.cpp b/indra/newview/lldrawpoolavatar.cpp
index 687b13d2c8..c04142ab47 100644
--- a/indra/newview/lldrawpoolavatar.cpp
+++ b/indra/newview/lldrawpoolavatar.cpp
@@ -1840,6 +1840,8 @@ void LLDrawPoolAvatar::updateRiggedFaceVertexBuffer(
     LLVolume* volume,
     LLVolumeFace& vol_face)
 {
+    LL_PROFILE_ZONE_SCOPED;
+
 	LLVector4a* weights = vol_face.mWeights;
 	if (!weights)
 	{
@@ -2352,8 +2354,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)
-- 
cgit v1.2.3


From 84da92663aad221db19927de26922417e7cb45c6 Mon Sep 17 00:00:00 2001
From: Runitai Linden <davep@lindenlab.com>
Date: Tue, 14 Sep 2021 20:18:58 -0500
Subject: SL-15961 Convert LLMeshRepository::mSkinMap into unordered_map and
 reduce number of per-frame lookups to said map.

---
 indra/llcommon/lluuid.h            | 11 +++++++
 indra/newview/lldrawpoolavatar.cpp | 65 ++++++++++++++++++--------------------
 indra/newview/lldrawpoolavatar.h   |  3 +-
 indra/newview/llmeshrepository.cpp | 40 +++++++++++------------
 indra/newview/llmeshrepository.h   |  3 +-
 5 files changed, 65 insertions(+), 57 deletions(-)

(limited to 'indra')

diff --git a/indra/llcommon/lluuid.h b/indra/llcommon/lluuid.h
index fe7482ba29..86a396ab06 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/newview/lldrawpoolavatar.cpp b/indra/newview/lldrawpoolavatar.cpp
index c04142ab47..6c4844f9ee 100644
--- a/indra/newview/lldrawpoolavatar.cpp
+++ b/indra/newview/lldrawpoolavatar.cpp
@@ -1836,7 +1836,7 @@ void LLDrawPoolAvatar::getRiggedGeometry(
 void LLDrawPoolAvatar::updateRiggedFaceVertexBuffer(
     LLVOAvatar* avatar,
     LLFace* face,
-    const LLMeshSkinInfo* skin,
+    const LLVOVolume* vobj,
     LLVolume* volume,
     LLVolumeFace& vol_face)
 {
@@ -1848,14 +1848,14 @@ void LLDrawPoolAvatar::updateRiggedFaceVertexBuffer(
 		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
@@ -1895,23 +1895,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
@@ -1937,18 +1940,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;
@@ -1965,6 +1963,11 @@ void LLDrawPoolAvatar::updateRiggedFaceVertexBuffer(
 
 		LLVector4a* norm = has_normal ? (LLVector4a*) normal.get() : NULL;
 		
+        if (skin == nullptr)
+        {
+            skin = vobj->getSkinInfo();
+        }
+
 		//build matrix palette
 		LLMatrix4a mat[LL_MAX_JOINTS_PER_MESH_OBJECT];
         U32 count = LLSkinningUtil::getMeshJointCount(skin);
@@ -2380,16 +2383,10 @@ 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);
 		}
 	}
 }
diff --git a/indra/newview/lldrawpoolavatar.h b/indra/newview/lldrawpoolavatar.h
index 92a8538958..9b26266ced 100644
--- a/indra/newview/lldrawpoolavatar.h
+++ b/indra/newview/lldrawpoolavatar.h
@@ -30,6 +30,7 @@
 #include "lldrawpool.h"
 
 class LLVOAvatar;
+class LLVOVolume;
 class LLGLSLShader;
 class LLFace;
 class LLMeshSkinInfo;
@@ -253,7 +254,7 @@ 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);
diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp
index 2c1c1191da..8ac64dbd15 100644
--- a/indra/newview/llmeshrepository.cpp
+++ b/indra/newview/llmeshrepository.cpp
@@ -4046,28 +4046,26 @@ 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);
+        }
 
-	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());
-		}
-	}
-
+        //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());
+        }
+    }
 	return NULL;
 }
 
diff --git a/indra/newview/llmeshrepository.h b/indra/newview/llmeshrepository.h
index 81e49cb1d8..c1698194cb 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"
@@ -613,7 +614,7 @@ public:
 	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;
-- 
cgit v1.2.3


From 6f03dc8d048ca82e49592b3358f7b1f2a74137ec Mon Sep 17 00:00:00 2001
From: Runitai Linden <davep@lindenlab.com>
Date: Tue, 14 Sep 2021 20:50:55 -0500
Subject: SL-15038 Added Tracy instrumentation to name tags and chat bubbles.

---
 indra/newview/llhudnametag.cpp | 2 ++
 indra/newview/llvoavatar.cpp   | 2 ++
 2 files changed, 4 insertions(+)

(limited to 'indra')

diff --git a/indra/newview/llhudnametag.cpp b/indra/newview/llhudnametag.cpp
index 9d49c30a49..55a4b5a457 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/llvoavatar.cpp b/indra/newview/llvoavatar.cpp
index e085a945a8..ba9f8d14cb 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
-- 
cgit v1.2.3


From 6c6eb59e947631275b2149208e4b46977dfa0309 Mon Sep 17 00:00:00 2001
From: Dave Houlton <euclid@lindenlab.com>
Date: Wed, 15 Sep 2021 10:11:25 -0600
Subject: SL-15962 Add hooks for tracy memory profiling

---
 indra/llcommon/linden_common.h |  8 ++++++++
 indra/llcommon/llcommon.cpp    | 42 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 50 insertions(+)

(limited to 'indra')

diff --git a/indra/llcommon/linden_common.h b/indra/llcommon/linden_common.h
index 45ac43910c..b2c5be6b76 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)  // 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/llcommon.cpp b/indra/llcommon/llcommon.cpp
index 96be913d17..da61e7539a 100644
--- a/indra/llcommon/llcommon.cpp
+++ b/indra/llcommon/llcommon.cpp
@@ -33,6 +33,48 @@
 #include "lltracethreadrecorder.h"
 #include "llcleanup.h"
 
+#if (TRACY_ENABLE)
+// Override new/delet for tracy memory profiling
+void *operator new(size_t size)
+{
+    auto ptr = (malloc) (size);
+    if (!ptr)
+    {
+        throw std::bad_alloc();
+        return nullptr;
+    }
+    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 = (_aligned_malloc) (size, alignment);
+    if (ptr) TracyAlloc(ptr, size);
+    return ptr;
+}
+
+void tracy_aligned_free(void *memblock)
+{
+    TracyFree(memblock);
+    (_aligned_free)(memblock);
+}
+
+#endif
+
 //static
 BOOL LLCommon::sAprInitialized = FALSE;
 
-- 
cgit v1.2.3


From 6d2714ac85815699599501538a397ccba109c6c6 Mon Sep 17 00:00:00 2001
From: "Brad Payne (Vir Linden)" <vir@lindenlab.com>
Date: Thu, 16 Sep 2021 14:22:28 +0100
Subject: SL-15999 - added --noninteractive command line option

---
 indra/newview/app_settings/cmd_line.xml |  8 ++++++++
 indra/newview/app_settings/settings.xml | 11 +++++++++++
 2 files changed, 19 insertions(+)

(limited to 'indra')

diff --git a/indra/newview/app_settings/cmd_line.xml b/indra/newview/app_settings/cmd_line.xml
index 4e186292f7..7514913d13 100644
--- a/indra/newview/app_settings/cmd_line.xml
+++ b/indra/newview/app_settings/cmd_line.xml
@@ -217,6 +217,14 @@
       <string>NoInventoryLibrary</string>
     </map>
 
+    <key>noninteractive</key>
+    <map>
+      <key>desc</key>
+      <string>Run in semi-headless mode where only login and logout need to work.</string>
+      <key>map-to</key>
+      <string>NonInteractive</string>
+    </map>
+
     <key>nonotifications</key>
     <map>
       <key>desc</key>
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index b1120c18b2..6ff94e1afd 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -7026,6 +7026,17 @@
       <key>Value</key>
       <integer>0</integer>
     </map>
+    <key>NonInteractive</key>
+    <map>
+      <key>Comment</key>
+      <string>Run in a semi-headless mode where only logging in and logging out needs to work.</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>Boolean</string>
+      <key>Value</key>
+	  <integer>0</integer>
+    </map>
     <key>NonvisibleObjectsInMemoryTime</key>
     <map>
       <key>Comment</key>
-- 
cgit v1.2.3


From 411c9aa485e1d6e260a261257f64aeac9f244963 Mon Sep 17 00:00:00 2001
From: "Brad Payne (Vir Linden)" <vir@lindenlab.com>
Date: Thu, 16 Sep 2021 14:29:39 +0100
Subject: SL-15999 - skip plugins in NonInteractive mode

---
 indra/newview/llviewermedia.cpp | 5 +++++
 1 file changed, 5 insertions(+)

(limited to 'indra')

diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp
index d35dbda907..82152a6cf5 100644
--- a/indra/newview/llviewermedia.cpp
+++ b/indra/newview/llviewermedia.cpp
@@ -1687,6 +1687,11 @@ void LLViewerMediaImpl::setMediaType(const std::string& media_type)
 /*static*/
 LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_type, LLPluginClassMediaOwner *owner /* may be NULL */, S32 default_width, S32 default_height, F64 zoom_factor, const std::string target, bool clean_browser)
 {
+    if (gSavedSettings.getBOOL("NonInteractive"))
+    {
+        return NULL;
+    }
+
 	std::string plugin_basename = LLMIMETypes::implType(media_type);
 	LLPluginClassMedia* media_source = NULL;
 
-- 
cgit v1.2.3


From 4ab77cdb60465d655a05cf7f1e9de73867284ac1 Mon Sep 17 00:00:00 2001
From: "Brad Payne (Vir Linden)" <vir@lindenlab.com>
Date: Thu, 16 Sep 2021 18:39:02 +0100
Subject: SL-15999 - throttle frame rate even more when noninteractive

---
 indra/newview/llappviewer.cpp |  9 +++++++++
 indra/newview/pipeline.cpp    | 11 +++++++++++
 2 files changed, 20 insertions(+)

(limited to 'indra')

diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 891722e1bd..6ff9b2b2eb 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -1557,6 +1557,15 @@ bool LLAppViewer::doFrame()
 				ms_sleep(yield_time);
 			}
 
+			static LLCachedControl<bool> s_non_interactive(gSavedSettings, "NonInteractive", false);
+			if (s_non_interactive)
+			{
+				S32 non_interactive_ms_sleep_time = 1000;
+				LLAppViewer::getTextureCache()->pause();
+				LLAppViewer::getImageDecodeThread()->pause();
+				ms_sleep(non_interactive_ms_sleep_time);
+			}
+
 			// yield cooperatively when not running as foreground window
 			// and when not quiting (causes trouble at mac's cleanup stage)
 			if (!LLApp::isExiting()
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index cd1b9c7c69..6d2eafd7c0 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -487,6 +487,10 @@ void LLPipeline::init()
 	{
 		clearAllRenderTypes();
 	}
+	else if (gSavedSettings.getBOOL("NonInteractive"))
+	{
+		clearAllRenderTypes();
+	}
 	else
 	{
 		setAllRenderTypes(); // By default, all rendering types start enabled
@@ -1153,6 +1157,13 @@ void LLPipeline::refreshCachedSettings()
 	RenderAutoHideSurfaceAreaLimit = gSavedSettings.getF32("RenderAutoHideSurfaceAreaLimit");
 	RenderSpotLight = nullptr;
 	updateRenderDeferred();
+
+	bool non_interactive = gSavedSettings.getBOOL("NonInteractive");
+	if (non_interactive)
+	{
+		LLVOAvatar::sMaxNonImpostors = 1;
+		LLVOAvatar::updateImpostorRendering(LLVOAvatar::sMaxNonImpostors);
+	}
 }
 
 void LLPipeline::releaseGLBuffers()
-- 
cgit v1.2.3


From 0918958507c9140cca0f4026ecef210eac9aef3a Mon Sep 17 00:00:00 2001
From: "Brad Payne (Vir Linden)" <vir@lindenlab.com>
Date: Fri, 17 Sep 2021 16:45:56 +0100
Subject: SL-15999 - disable various types of loading in noninteractive mode

---
 indra/newview/llviewerobject.cpp     | 19 +++++++++++++++----
 indra/newview/llviewerobjectlist.cpp |  5 +++--
 indra/newview/pipeline.cpp           |  8 ++++----
 3 files changed, 22 insertions(+), 10 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp
index b88baf6aa7..1852d4980f 100644
--- a/indra/newview/llviewerobject.cpp
+++ b/indra/newview/llviewerobject.cpp
@@ -153,13 +153,21 @@ LLViewerObject *LLViewerObject::createObject(const LLUUID &id, const LLPCode pco
     LL_DEBUGS("ObjectUpdate") << "creating " << id << LL_ENDL;
     dumpStack("ObjectUpdateStack");
     
+	static LLCachedControl<bool> s_non_interactive(gSavedSettings, "NonInteractive", false);
+	
 	LLViewerObject *res = NULL;
 	LL_RECORD_BLOCK_TIME(FTM_CREATE_OBJECT);
 	
 	switch (pcode)
 	{
 	case LL_PCODE_VOLUME:
-	  res = new LLVOVolume(id, pcode, regionp); break;
+	{
+		if (!s_non_interactive)
+		{
+			res = new LLVOVolume(id, pcode, regionp); break;
+		}
+		break;
+	}
 	case LL_PCODE_LEGACY_AVATAR:
 	{
 		if (id == gAgentID)
@@ -193,9 +201,12 @@ LLViewerObject *LLViewerObject::createObject(const LLUUID &id, const LLPCode pco
         }
 		else
 		{
-			LLVOAvatar *avatar = new LLVOAvatar(id, pcode, regionp); 
-			avatar->initInstance();
-			res = avatar;
+			if (!s_non_interactive)
+			{
+				LLVOAvatar *avatar = new LLVOAvatar(id, pcode, regionp); 
+				avatar->initInstance();
+				res = avatar;
+			}
 		}
 		break;
 	}
diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp
index 63e48d1dd0..9fe80b38d6 100644
--- a/indra/newview/llviewerobjectlist.cpp
+++ b/indra/newview/llviewerobjectlist.cpp
@@ -80,6 +80,7 @@
 #include "llfloaterperms.h"
 #include "llvocache.h"
 #include "llcorehttputil.h"
+#include "llstartup.h"
 
 #include <algorithm>
 #include <iterator>
@@ -303,9 +304,10 @@ static LLTrace::BlockTimerStatHandle FTM_PROCESS_OBJECTS("Process Objects");
 
 LLViewerObject* LLViewerObjectList::processObjectUpdateFromCache(LLVOCacheEntry* entry, LLViewerRegion* regionp)
 {
+	static LLCachedControl<bool> s_non_interactive(gSavedSettings, "NonInteractive", false);
 	LLDataPacker *cached_dpp = entry->getDP();
 
-	if (!cached_dpp)
+	if (!cached_dpp || s_non_interactive)
 	{
 		return NULL; //nothing cached.
 	}
@@ -2051,7 +2053,6 @@ LLViewerObject *LLViewerObjectList::createObjectFromCache(const LLPCode pcode, L
 LLViewerObject *LLViewerObjectList::createObject(const LLPCode pcode, LLViewerRegion *regionp,
 												 const LLUUID &uuid, const U32 local_id, const LLHost &sender)
 {
-	
 	LLUUID fullid;
 	if (uuid == LLUUID::null)
 	{
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index 6d2eafd7c0..43ae0c2e76 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -487,10 +487,10 @@ void LLPipeline::init()
 	{
 		clearAllRenderTypes();
 	}
-	else if (gSavedSettings.getBOOL("NonInteractive"))
-	{
-		clearAllRenderTypes();
-	}
+	//else if (gSavedSettings.getBOOL("NonInteractive"))
+//	{
+	//	clearAllRenderTypes();
+	//}
 	else
 	{
 		setAllRenderTypes(); // By default, all rendering types start enabled
-- 
cgit v1.2.3


From c10d601ce8d2a6ca7e354772a217a998cd9865b3 Mon Sep 17 00:00:00 2001
From: "Brad Payne (Vir Linden)" <vir@lindenlab.com>
Date: Mon, 20 Sep 2021 13:19:20 +0100
Subject: SL-15999 - track --noninteractive state with gNonInteractive flag

---
 indra/llrender/llgl.cpp              | 1 +
 indra/llrender/llgl.h                | 1 +
 indra/newview/llappviewer.cpp        | 4 ++--
 indra/newview/llviewermedia.cpp      | 2 +-
 indra/newview/llviewerobject.cpp     | 7 +++----
 indra/newview/llviewerobjectlist.cpp | 3 +--
 indra/newview/pipeline.cpp           | 3 +--
 7 files changed, 10 insertions(+), 11 deletions(-)

(limited to 'indra')

diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp
index 43fedeca64..fe399ad882 100644
--- a/indra/llrender/llgl.cpp
+++ b/indra/llrender/llgl.cpp
@@ -62,6 +62,7 @@
 BOOL gDebugSession = FALSE;
 BOOL gClothRipple = FALSE;
 BOOL gHeadlessClient = FALSE;
+BOOL gNonInteractive = FALSE;
 BOOL gGLActive = FALSE;
 BOOL gGLDebugLoggingEnabled = TRUE;
 
diff --git a/indra/llrender/llgl.h b/indra/llrender/llgl.h
index a07e2d9bb0..53d077b994 100644
--- a/indra/llrender/llgl.h
+++ b/indra/llrender/llgl.h
@@ -488,6 +488,7 @@ void parse_gl_version( S32* major, S32* minor, S32* release, std::string* vendor
 
 extern BOOL gClothRipple;
 extern BOOL gHeadlessClient;
+extern BOOL gNonInteractive;
 extern BOOL gGLActive;
 
 // Deal with changing glext.h definitions for newer SDK versions, specifically
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 6ff9b2b2eb..970bc0a83d 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -1557,8 +1557,7 @@ bool LLAppViewer::doFrame()
 				ms_sleep(yield_time);
 			}
 
-			static LLCachedControl<bool> s_non_interactive(gSavedSettings, "NonInteractive", false);
-			if (s_non_interactive)
+			if (gNonInteractive)
 			{
 				S32 non_interactive_ms_sleep_time = 1000;
 				LLAppViewer::getTextureCache()->pause();
@@ -2979,6 +2978,7 @@ bool LLAppViewer::initWindow()
 
 	// store setting in a global for easy access and modification
 	gHeadlessClient = gSavedSettings.getBOOL("HeadlessClient");
+	gNonInteractive = gSavedSettings.getBOOL("NonInteractive");
 
 	// always start windowed
 	BOOL ignorePixelDepth = gSavedSettings.getBOOL("IgnorePixelDepth");
diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp
index 82152a6cf5..8064e998f1 100644
--- a/indra/newview/llviewermedia.cpp
+++ b/indra/newview/llviewermedia.cpp
@@ -1687,7 +1687,7 @@ void LLViewerMediaImpl::setMediaType(const std::string& media_type)
 /*static*/
 LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_type, LLPluginClassMediaOwner *owner /* may be NULL */, S32 default_width, S32 default_height, F64 zoom_factor, const std::string target, bool clean_browser)
 {
-    if (gSavedSettings.getBOOL("NonInteractive"))
+	if (gNonInteractive)
     {
         return NULL;
     }
diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp
index 1852d4980f..528448c477 100644
--- a/indra/newview/llviewerobject.cpp
+++ b/indra/newview/llviewerobject.cpp
@@ -107,6 +107,7 @@
 #include "llcleanup.h"
 #include "llcallstack.h"
 #include "llmeshrepository.h"
+#include "llgl.h"
 
 //#define DEBUG_UPDATE_TYPE
 
@@ -153,8 +154,6 @@ LLViewerObject *LLViewerObject::createObject(const LLUUID &id, const LLPCode pco
     LL_DEBUGS("ObjectUpdate") << "creating " << id << LL_ENDL;
     dumpStack("ObjectUpdateStack");
     
-	static LLCachedControl<bool> s_non_interactive(gSavedSettings, "NonInteractive", false);
-	
 	LLViewerObject *res = NULL;
 	LL_RECORD_BLOCK_TIME(FTM_CREATE_OBJECT);
 	
@@ -162,7 +161,7 @@ LLViewerObject *LLViewerObject::createObject(const LLUUID &id, const LLPCode pco
 	{
 	case LL_PCODE_VOLUME:
 	{
-		if (!s_non_interactive)
+		if (!gNonInteractive)
 		{
 			res = new LLVOVolume(id, pcode, regionp); break;
 		}
@@ -201,7 +200,7 @@ LLViewerObject *LLViewerObject::createObject(const LLUUID &id, const LLPCode pco
         }
 		else
 		{
-			if (!s_non_interactive)
+			if (!gNonInteractive)
 			{
 				LLVOAvatar *avatar = new LLVOAvatar(id, pcode, regionp); 
 				avatar->initInstance();
diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp
index 9fe80b38d6..fbd44c198b 100644
--- a/indra/newview/llviewerobjectlist.cpp
+++ b/indra/newview/llviewerobjectlist.cpp
@@ -304,10 +304,9 @@ static LLTrace::BlockTimerStatHandle FTM_PROCESS_OBJECTS("Process Objects");
 
 LLViewerObject* LLViewerObjectList::processObjectUpdateFromCache(LLVOCacheEntry* entry, LLViewerRegion* regionp)
 {
-	static LLCachedControl<bool> s_non_interactive(gSavedSettings, "NonInteractive", false);
 	LLDataPacker *cached_dpp = entry->getDP();
 
-	if (!cached_dpp || s_non_interactive)
+	if (!cached_dpp || gNonInteractive)
 	{
 		return NULL; //nothing cached.
 	}
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index 43ae0c2e76..30703426ce 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -1158,8 +1158,7 @@ void LLPipeline::refreshCachedSettings()
 	RenderSpotLight = nullptr;
 	updateRenderDeferred();
 
-	bool non_interactive = gSavedSettings.getBOOL("NonInteractive");
-	if (non_interactive)
+	if (gNonInteractive)
 	{
 		LLVOAvatar::sMaxNonImpostors = 1;
 		LLVOAvatar::updateImpostorRendering(LLVOAvatar::sMaxNonImpostors);
-- 
cgit v1.2.3


From 9bb566ea26c7fd5d93b5b42a9ee3f4aba92ebf7a Mon Sep 17 00:00:00 2001
From: "Brad Payne (Vir Linden)" <vir@lindenlab.com>
Date: Mon, 20 Sep 2021 14:03:19 +0100
Subject: SL-15999 - support for temporarily changing other settings while
 noninteractive, including a fix for unwanted SLURL redirects

---
 indra/newview/llappviewer.cpp | 68 ++++++++++++++++++++++++++-----------------
 1 file changed, 41 insertions(+), 27 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 970bc0a83d..eab91f5d02 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -2439,6 +2439,37 @@ namespace
     }
 } // anonymous namespace
 
+// Set a named control temporarily for this session, as when set via the command line --set option.
+bool tempSetControl(const std::string& name, const std::string& value)
+{
+	std::string name_part;
+	std::string group_part;
+	LLControlVariable* control = NULL;
+
+	// Name can be further split into ControlGroup.Name, with the default control group being Global
+	size_t pos = name.find('.');
+	if (pos != std::string::npos)
+	{
+		group_part = name.substr(0, pos);
+		name_part = name.substr(pos+1);
+		LL_INFOS() << "Setting " << group_part << "." << name_part << " to " << value << LL_ENDL;
+		LLControlGroup* g = LLControlGroup::getInstance(group_part);
+		if (g) control = g->getControl(name_part);
+	}
+	else
+	{
+		LL_INFOS() << "Setting Global." << name << " to " << value << LL_ENDL;
+		control = gSavedSettings.getControl(name);
+	}
+
+	if (control)
+	{
+		control->setValue(value, false);
+		return true;
+	}
+	return false;
+}
+
 bool LLAppViewer::initConfiguration()
 {
 	//Load settings files list
@@ -2635,34 +2666,10 @@ bool LLAppViewer::initConfiguration()
             {
                 const std::string& name = *itr;
                 const std::string& value = *(++itr);
-                std::string name_part;
-                std::string group_part;
-				LLControlVariable* control = NULL;
-
-				// Name can be further split into ControlGroup.Name, with the default control group being Global
-				size_t pos = name.find('.');
-				if (pos != std::string::npos)
+				if (!tempSetControl(name,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);
-					if (g) control = g->getControl(name_part);
-				}
-				else
-				{
-					LL_INFOS() << "Setting Global." << name << " to " << value << LL_ENDL;
-					control = gSavedSettings.getControl(name);
-				}
-
-                if (control)
-                {
-                    control->setValue(value, false);
-                }
-                else
-                {
 					LL_WARNS() << "Failed --set " << name << ": setting name unknown." << LL_ENDL;
-                }
+				}
             }
         }
     }
@@ -2747,6 +2754,14 @@ bool LLAppViewer::initConfiguration()
 		}
 	}
 
+	gNonInteractive = gSavedSettings.getBOOL("NonInteractive");
+	if (gNonInteractive)
+	{
+		tempSetControl("SLURLPassToOtherInstance", "FALSE");
+		llassert_always(!gSavedSettings.getBOOL("SLURLPassToOtherInstance"));
+	}
+
+
 	// Handle slurl use. NOTE: Don't let SL-55321 reappear.
 	// This initial-SLURL logic, up through the call to
 	// sendURLToOtherInstance(), must precede LLSplashScreen::show() --
@@ -2978,7 +2993,6 @@ bool LLAppViewer::initWindow()
 
 	// store setting in a global for easy access and modification
 	gHeadlessClient = gSavedSettings.getBOOL("HeadlessClient");
-	gNonInteractive = gSavedSettings.getBOOL("NonInteractive");
 
 	// always start windowed
 	BOOL ignorePixelDepth = gSavedSettings.getBOOL("IgnorePixelDepth");
-- 
cgit v1.2.3


From f79890669dcf8e44b5ec3ce1abbd1d1fdd34eb3b Mon Sep 17 00:00:00 2001
From: Dave Parks <davep@lindenlab.com>
Date: Mon, 20 Sep 2021 18:58:09 +0000
Subject: SL-16006 and SL-16009 Rigged mesh rendering optimization pass

---
 indra/llcharacter/lljoint.cpp           |   8 +
 indra/llcharacter/lljoint.h             |   4 +
 indra/llmath/llmatrix4a.h               |  41 ++-
 indra/llmath/llvector4a.h               |   7 +-
 indra/llmath/llvector4a.inl             |   4 +-
 indra/llmath/m4math.cpp                 |   9 +-
 indra/llmath/m4math.h                   |   2 +
 indra/llmath/v3math.cpp                 |   6 +
 indra/llmath/v3math.h                   |   5 +-
 indra/llprimitive/lldaeloader.cpp       |  16 +-
 indra/llprimitive/llmodel.cpp           |   8 +-
 indra/llprimitive/llmodel.h             |   9 +-
 indra/llrender/llglslshader.cpp         |   1 +
 indra/newview/llcontrolavatar.cpp       |   2 +-
 indra/newview/lldrawpoolavatar.cpp      | 508 ++++++++++++++++++--------------
 indra/newview/lldrawpoolavatar.h        |  27 +-
 indra/newview/llfloatermodelpreview.cpp |  88 +++---
 indra/newview/llmodelpreview.cpp        |   9 +-
 indra/newview/llskinningutil.cpp        |  62 ++--
 indra/newview/llskinningutil.h          |   4 +-
 indra/newview/llviewertexture.cpp       |   1 +
 indra/newview/llviewertexturelist.cpp   |   1 +
 indra/newview/llvoavatar.cpp            |  43 +--
 indra/newview/llvoavatar.h              |   5 +
 indra/newview/llvovolume.cpp            |   5 +-
 25 files changed, 521 insertions(+), 354 deletions(-)

(limited to 'indra')

diff --git a/indra/llcharacter/lljoint.cpp b/indra/llcharacter/lljoint.cpp
index dee642310e..d72282ab42 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 1b646b641f..ba821667c7 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,
@@ -123,6 +124,7 @@ protected:
 
 	// explicit transformation members
 	LLXformMatrix		mXform;
+    LLMatrix4a          mWorldMatrix;
 
     LLVector3       mDefaultPosition;
     LLVector3       mDefaultScale;
@@ -259,6 +261,8 @@ public:
 	const LLMatrix4 &getWorldMatrix();
 	void setWorldMatrix( const LLMatrix4& mat );
 
+    const LLMatrix4a& getWorldMatrix4a();
+
 	void updateWorldMatrixChildren();
 	void updateWorldMatrixParent();
 
diff --git a/indra/llmath/llmatrix4a.h b/indra/llmath/llmatrix4a.h
index 7ba347062f..5291a05607 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 @@ public:
 		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 @@ public:
 		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 @@ public:
     {
         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 27abf39537..5a02928374 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 @@ public:
 	// 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 69d3d01efe..8be1c1b114 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/m4math.cpp b/indra/llmath/m4math.cpp
index 3baf1bad18..6e40dae30b 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 bf60adb9b6..b9da970cde 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 @@ public:
 	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 b04c67d926..93010d2250 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 6f857d7061..068f489020 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/llprimitive/lldaeloader.cpp b/indra/llprimitive/lldaeloader.cpp
index dfa29fb539..8343de0cbc 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 702a1b5238..a23b991f1d 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 51fa2f8079..96d4582b4f 100644
--- a/indra/llprimitive/llmodel.h
+++ b/indra/llprimitive/llmodel.h
@@ -33,6 +33,8 @@
 #include "m4math.h"
 #include <queue>
 
+#include <boost/align/aligned_allocator.hpp>
+
 class daeElement;
 class domMesh;
 
@@ -49,10 +51,11 @@ public:
 	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;
+	LLMatrix4a mBindShapeMatrix;
 	float mPelvisOffset;
     bool mLockScaleIfJointPosition;
     bool mInvalidJointsScrubbed;
diff --git a/indra/llrender/llglslshader.cpp b/indra/llrender/llglslshader.cpp
index 4351f6e2c8..8bd9dbf9b8 100644
--- a/indra/llrender/llglslshader.cpp
+++ b/indra/llrender/llglslshader.cpp
@@ -1346,6 +1346,7 @@ 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)
diff --git a/indra/newview/llcontrolavatar.cpp b/indra/newview/llcontrolavatar.cpp
index fab249f988..606e670805 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/lldrawpoolavatar.cpp b/indra/newview/lldrawpoolavatar.cpp
index 6c4844f9ee..c7aa104ca5 100644
--- a/indra/newview/lldrawpoolavatar.cpp
+++ b/indra/newview/lldrawpoolavatar.cpp
@@ -163,6 +163,7 @@ void LLDrawPoolAvatar::prerender()
 		{
 			LLVOAvatar* avatarp = (LLVOAvatar *)facep->getDrawable()->getVObj().get();
 			updateRiggedVertexBuffers(avatarp);
+            updateSkinInfoMatrixPalettes(avatarp);
 		}
 	}
 }
@@ -428,221 +429,230 @@ 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);
+            }
+
+            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_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 (oa == LLVOAvatar::AOA_INVISIBLE ||
+            (impostor && oa == LLVOAvatar::AOA_JELLYDOLL))
+        {
+            // No shadows for 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()
@@ -1794,7 +1804,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();
 		
@@ -1968,14 +1978,11 @@ void LLDrawPoolAvatar::updateRiggedFaceVertexBuffer(
             skin = vobj->getSkinInfo();
         }
 
-		//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);
+        const MatrixPaletteCache& mpc = updateSkinInfoMatrixPalette(avatar, skin);
+        const LLMatrix4a* mat = &(mpc.mMatrixPalette[0]);
 
-		LLMatrix4a bind_shape_matrix;
-		bind_shape_matrix.loadu(skin->mBindShapeMatrix);
+        LLSkinningUtil::checkSkinWeights(weights, buffer->getNumVerts(), skin);
+		const LLMatrix4a& bind_shape_matrix = skin->mBindShapeMatrix;
 
 #if USE_SEPARATE_JOINT_INDICES_AND_WEIGHTS
         U8* joint_indices_cursor = vol_face.mJointIndices;
@@ -2043,6 +2050,8 @@ void LLDrawPoolAvatar::updateRiggedFaceVertexBuffer(
 
 void LLDrawPoolAvatar::renderRigged(LLVOAvatar* avatar, U32 type, bool glow)
 {
+    LL_PROFILE_ZONE_SCOPED;
+
 	if (!avatar->shouldRenderRigged())
 	{
 		return;
@@ -2050,15 +2059,18 @@ void LLDrawPoolAvatar::renderRigged(LLVOAvatar* avatar, U32 type, bool glow)
 
 	stop_glerror();
 
+    const LLMeshSkinInfo* lastSkin = nullptr;
+
 	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)
@@ -2180,52 +2192,32 @@ 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];
+                if (lastSkin != skin) // <== only upload matrix palette to GL if the skininfo changed
+                {
+                    // upload matrix palette to shader
+                    const MatrixPaletteCache& mpc = updateSkinInfoMatrixPalette(avatar, skin);
+                    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];
-				}
+                    stop_glerror();
 
-				LLDrawPoolAvatar::sVertexProgram->uniformMatrix3x4fv(LLViewerShaderMgr::AVATAR_MATRIX, 
-					count,
-					FALSE,
-					(GLfloat*) mp);
+                    LLDrawPoolAvatar::sVertexProgram->uniformMatrix3x4fv(LLViewerShaderMgr::AVATAR_MATRIX,
+                        count,
+                        FALSE,
+                        (GLfloat*) &(mpc.mGLMp[0]));
 
-				stop_glerror();
+                    stop_glerror();
+                }
 			}
 			else
 			{
 				data_mask &= ~LLVertexBuffer::MAP_WEIGHT4;
 			}
 
+            lastSkin = skin;
+
 			/*if (glow)
 			{
 				gGL.diffuseColor4f(0,0,0,face->getTextureEntry()->getGlow());
@@ -2391,6 +2383,70 @@ void LLDrawPoolAvatar::updateRiggedVertexBuffers(LLVOAvatar* avatar)
 	}
 }
 
+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 LLMeshSkinInfo* skin)
+{
+    MatrixPaletteCache& entry = mMatrixPaletteCache[skin];
+
+    if (entry.mFrame != gFrameCount)
+    {
+        LL_PROFILE_ZONE_SCOPED;
+        entry.mFrame = gFrameCount;
+        //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]);
+
+        stop_glerror();
+        
+        entry.mGLMp.resize(count * 12);
+
+        F32* mp = &(entry.mGLMp[0]);
+        
+        for (U32 i = 0; i < count; ++i)
+        {
+            F32* m = (F32*)mat[i].mMatrix[0].getF32ptr();
+
+            U32 idx = i * 12;
+
+            mp[idx + 0] = m[0];
+            mp[idx + 1] = m[1];
+            mp[idx + 2] = m[2];
+            mp[idx + 3] = m[12];
+
+            mp[idx + 4] = m[4];
+            mp[idx + 5] = m[5];
+            mp[idx + 6] = m[6];
+            mp[idx + 7] = m[13];
+
+            mp[idx + 8] = m[8];
+            mp[idx + 9] = m[9];
+            mp[idx + 10] = m[10];
+            mp[idx + 11] = m[14];
+        }
+    }
+
+    return entry;
+}
+
 void LLDrawPoolAvatar::renderRiggedSimple(LLVOAvatar* avatar)
 {
 	renderRigged(avatar, RIGGED_SIMPLE);
diff --git a/indra/newview/lldrawpoolavatar.h b/indra/newview/lldrawpoolavatar.h
index 9b26266ced..0c1ee2cced 100644
--- a/indra/newview/lldrawpoolavatar.h
+++ b/indra/newview/lldrawpoolavatar.h
@@ -28,15 +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
 {
@@ -259,6 +262,8 @@ typedef enum
 									  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);
@@ -278,6 +283,26 @@ typedef enum
 
 	std::vector<LLFace*> mRiggedFace[NUM_RIGGED_PASSES];
 
+    class MatrixPaletteCache
+    {
+    public:
+        U32 mFrame;
+        LLMeshSkinInfo::matrix_list_t mMatrixPalette;
+        
+        // Float array ready to be sent to GL
+        std::vector<F32> mGLMp;
+
+        MatrixPaletteCache() :
+            mFrame(gFrameCount-1)
+        {
+        }
+    };
+    
+    const MatrixPaletteCache& updateSkinInfoMatrixPalette(LLVOAvatar* avatarp, const LLMeshSkinInfo* skin);
+
+    typedef std::unordered_map<const LLMeshSkinInfo*, 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/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp
index d9edd4dc30..0e54b66ea9 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/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp
index a9e80ab5da..01bddd781d 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/llskinningutil.cpp b/indra/newview/llskinningutil.cpp
index e02b21f036..dc12de29fb 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 efe7c85997..807418f983 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/llviewertexture.cpp b/indra/newview/llviewertexture.cpp
index ca01bb46aa..af55f68cd2 100644
--- a/indra/newview/llviewertexture.cpp
+++ b/indra/newview/llviewertexture.cpp
@@ -208,6 +208,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);
 }
 
diff --git a/indra/newview/llviewertexturelist.cpp b/indra/newview/llviewertexturelist.cpp
index 561319ca5d..12495078e9 100644
--- a/indra/newview/llviewertexturelist.cpp
+++ b/indra/newview/llviewertexturelist.cpp
@@ -620,6 +620,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;
diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp
index ba9f8d14cb..f260e4f750 100644
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -4886,6 +4886,8 @@ bool LLVOAvatar::shouldAlphaMask()
 //-----------------------------------------------------------------------------
 U32 LLVOAvatar::renderSkinned()
 {
+    LL_PROFILE_ZONE_SCOPED;
+
 	U32 num_indices = 0;
 
 	if (!mIsBuilt)
@@ -6160,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;
 }
@@ -6515,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;
@@ -7864,6 +7868,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;
@@ -10951,6 +10957,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 74ef589ca4..39adaab8ca 100644
--- a/indra/newview/llvoavatar.h
+++ b/indra/newview/llvoavatar.h
@@ -209,6 +209,11 @@ public:
 	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/llvovolume.cpp b/indra/newview/llvovolume.cpp
index f9b2285989..e5a4b0f374 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -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;
 
-- 
cgit v1.2.3


From 014dd037dde0a93f6c591618e4c111c6b598b60e Mon Sep 17 00:00:00 2001
From: Dave Parks <davep@lindenlab.com>
Date: Mon, 20 Sep 2021 21:22:17 +0000
Subject: SL-16043 Fix DisableVerticalSync, default DisableVerticalSync to off,
 remove broken frame limiter code (use vsync if you want to limit framerate).

---
 indra/llwindow/llwindowwin32.cpp        |  3 ++-
 indra/newview/app_settings/settings.xml | 15 ++------------
 indra/newview/llappviewer.cpp           | 35 +--------------------------------
 indra/newview/llappviewer.h             |  7 +------
 4 files changed, 6 insertions(+), 54 deletions(-)

(limited to 'indra')

diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp
index b2b123f0da..585905893b 100644
--- a/indra/llwindow/llwindowwin32.cpp
+++ b/indra/llwindow/llwindowwin32.cpp
@@ -784,7 +784,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;
 	}
@@ -1764,6 +1764,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);
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index b1120c18b2..05c3fc3bfe 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>
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 94f0b31ecd..a71ef69512 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -694,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)
 	{
@@ -1326,10 +1325,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();
 
@@ -1518,21 +1513,6 @@ bool LLAppViewer::doFrame()
 
 				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
 					LLFloaterOutfitSnapshot::update();
@@ -5613,19 +5593,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 0afb70958c..64e7caa36b 100644
--- a/indra/newview/llappviewer.h
+++ b/indra/newview/llappviewer.h
@@ -262,8 +262,6 @@ private:
     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 +317,7 @@ private:
 	// llcorehttp library init/shutdown helper
 	LLAppCoreHttp mAppCoreHttp;
 
-        bool mIsFirstRun;
-	U64 mMinMicroSecPerFrame; // frame throttling
-
-
+    bool mIsFirstRun;
 };
 
 // consts from viewer.h
-- 
cgit v1.2.3


From a0157baf08ab5a4ac3f667520e18a796a11b9ad7 Mon Sep 17 00:00:00 2001
From: "Brad Payne (Vir Linden)" <vir@lindenlab.com>
Date: Tue, 21 Sep 2021 17:01:57 +0100
Subject: SL-15999 - try to force non-interactive agents to always start out
 standing

---
 indra/newview/llappviewer.cpp     |  1 +
 indra/newview/llviewermessage.cpp | 16 ++++++++++++++++
 2 files changed, 17 insertions(+)

(limited to 'indra')

diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index eab91f5d02..b6446e40ac 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -2440,6 +2440,7 @@ namespace
 } // anonymous namespace
 
 // Set a named control temporarily for this session, as when set via the command line --set option.
+// Name can be specified as "<control_group>.<control_name>", with default group being Global.
 bool tempSetControl(const std::string& name, const std::string& value)
 {
 	std::string name_part;
diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp
index 39c891c9c1..c99232eba0 100644
--- a/indra/newview/llviewermessage.cpp
+++ b/indra/newview/llviewermessage.cpp
@@ -4049,6 +4049,7 @@ void process_avatar_animation(LLMessageSystem *mesgsys, void **user_data)
 
 	S32 num_blocks = mesgsys->getNumberOfBlocksFast(_PREHASH_AnimationList);
 	S32 num_source_blocks = mesgsys->getNumberOfBlocksFast(_PREHASH_AnimationSourceList);
+	bool non_interactive_got_run = false;
 
 	LL_DEBUGS("Messaging", "Motion") << "Processing " << num_blocks << " Animations" << LL_ENDL;
 
@@ -4064,6 +4065,14 @@ void process_avatar_animation(LLMessageSystem *mesgsys, void **user_data)
 			mesgsys->getUUIDFast(_PREHASH_AnimationList, _PREHASH_AnimID, animation_id, i);
 			mesgsys->getS32Fast(_PREHASH_AnimationList, _PREHASH_AnimSequenceID, anim_sequence_id, i);
 
+			if (gNonInteractive && (animation_id == ANIM_AGENT_RUN))
+			{
+				// RUN requests get sent at startup for unclear
+				// reasons. Same avatar may get requests one run and
+				// not another. At least in the non-interactive case,
+				// we want to override these.
+				non_interactive_got_run = true;
+			}
 			avatarp->mSignaledAnimations[animation_id] = anim_sequence_id;
 
 			// *HACK: Disabling flying mode if it has been enabled shortly before the agent
@@ -4127,6 +4136,13 @@ void process_avatar_animation(LLMessageSystem *mesgsys, void **user_data)
 	{
 		avatarp->processAnimationStateChanges();
 	}
+
+	if (non_interactive_got_run)
+	{
+		// Total kluge alert.
+		LL_INFOS("Messaging","Motion") << "non-interactive mode, resetting animations" << LL_ENDL;
+		gAgent.stopCurrentAnimations();
+	}
 }
 
 
-- 
cgit v1.2.3


From a35544c701b223ba08f0607c872d8afbb08114f5 Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Tue, 21 Sep 2021 15:56:18 -0700
Subject: SL-16027: Add Tracy OpenGL support

---
 indra/llcommon/linden_common.h       |  4 +---
 indra/llcommon/llprofiler.h          |  3 +++
 indra/llrender/llglheaders.h         | 19 +++++++++++++++++++
 indra/llrender/llrendertarget.cpp    |  2 ++
 indra/llrender/llvertexbuffer.cpp    |  5 +++++
 indra/llwindow/llwindowwin32.cpp     |  4 ++++
 indra/newview/llappviewerwin32.cpp   |  4 ++++
 indra/newview/llface.cpp             |  1 +
 indra/newview/llspatialpartition.cpp | 11 +++++++++--
 indra/newview/pipeline.cpp           |  1 +
 10 files changed, 49 insertions(+), 5 deletions(-)

(limited to 'indra')

diff --git a/indra/llcommon/linden_common.h b/indra/llcommon/linden_common.h
index b2c5be6b76..a228fd22be 100644
--- a/indra/llcommon/linden_common.h
+++ b/indra/llcommon/linden_common.h
@@ -28,7 +28,7 @@
 #define LL_LINDEN_COMMON_H
 
 #include "llprofiler.h"
-#if (TRACY_ENABLE)  // hooks for memory profiling
+#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))
@@ -68,6 +68,4 @@ void  tracy_aligned_free(void *memblock);
 #include "llerror.h"
 #include "llfile.h"
 
-#include "llprofiler.h" // must be before fast timer; needed due to LLThreads potentially needing access to tracy
-
 #endif
diff --git a/indra/llcommon/llprofiler.h b/indra/llcommon/llprofiler.h
index 62e649913b..62ec20fa44 100644
--- a/indra/llcommon/llprofiler.h
+++ b/indra/llcommon/llprofiler.h
@@ -45,6 +45,9 @@
 //      #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
diff --git a/indra/llrender/llglheaders.h b/indra/llrender/llglheaders.h
index 6bca3623e0..e7f9315d11 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 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/llrendertarget.cpp b/indra/llrender/llrendertarget.cpp
index e3c0255290..401085a00b 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/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp
index 7d2b09ca4a..b69b644ebc 100644
--- a/indra/llrender/llvertexbuffer.cpp
+++ b/indra/llrender/llvertexbuffer.cpp
@@ -615,6 +615,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 +655,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 +765,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);
@@ -814,6 +817,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 +865,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);
diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp
index b2b123f0da..1b8881cc86 100644
--- a/indra/llwindow/llwindowwin32.cpp
+++ b/indra/llwindow/llwindowwin32.cpp
@@ -1748,6 +1748,8 @@ const	S32   max_format  = (S32)num_formats - 1;
 		return FALSE;
 	}
 
+	LL_PROFILER_GPU_CONTEXT
+
 	if (!gGLManager.initGL())
 	{
 		close();
@@ -3474,6 +3476,8 @@ BOOL LLWindowWin32::resetDisplayResolution()
 void LLWindowWin32::swapBuffers()
 {
 	SwapBuffers(mhDC);
+
+    LL_PROFILER_GPU_COLLECT
 }
 
 
diff --git a/indra/newview/llappviewerwin32.cpp b/indra/newview/llappviewerwin32.cpp
index 9daea515e5..fb53a7648d 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;
diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp
index 4a802ad9aa..6e55d8f66a 100644
--- a/indra/newview/llface.cpp
+++ b/indra/newview/llface.cpp
@@ -585,6 +585,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);
 				}
diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp
index efa4a7fd66..0adf58a0bf 100644
--- a/indra/newview/llspatialpartition.cpp
+++ b/indra/newview/llspatialpartition.cpp
@@ -2700,11 +2700,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 +3228,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/pipeline.cpp b/indra/newview/pipeline.cpp
index e7c2d4db39..4e28c8c493 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -11146,6 +11146,7 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar)
 		if (LLPipeline::sRenderDeferred)
 		{
 			GLuint buff = GL_COLOR_ATTACHMENT0;
+			LL_PROFILER_GPU_ZONEC( "gl.DrawBuffersARB", 0x8000FF );
 			glDrawBuffersARB(1, &buff);
 		}
 
-- 
cgit v1.2.3


From d03ade68d36525a8b7abc0a783636cebda006ef4 Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Tue, 21 Sep 2021 17:46:11 -0700
Subject: SL-16027: Only enable Tracy OpengL macros if Tracy is enabled

---
 indra/llrender/llglheaders.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'indra')

diff --git a/indra/llrender/llglheaders.h b/indra/llrender/llglheaders.h
index e7f9315d11..3d93cc0762 100644
--- a/indra/llrender/llglheaders.h
+++ b/indra/llrender/llglheaders.h
@@ -812,7 +812,7 @@ extern void glGetBufferPointervARB (GLenum, GLenum, GLvoid* *);
 #define GL_RENDERBUFFER_FREE_MEMORY_ATI            0x87FD
 #endif
 
-#if LL_PROFILER_ENABLE_TRACY_OPENGL
+#if defined(TRACY_ENABLE) && LL_PROFILER_ENABLE_TRACY_OPENGL
     // Tracy uses the following:
     //    glGenQueries
     //    glGetQueryiv
-- 
cgit v1.2.3


From a68ca665ade56d21a8c939a7e26332f1de413698 Mon Sep 17 00:00:00 2001
From: Mnikolenko Productengine <mnikolenko@productengine.com>
Date: Fri, 17 Sep 2021 15:29:00 +0300
Subject: SL-15958 Stop impostored avatars from casting shadows

---
 indra/newview/lldrawpoolavatar.cpp | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/lldrawpoolavatar.cpp b/indra/newview/lldrawpoolavatar.cpp
index c7aa104ca5..d8491d60ee 100644
--- a/indra/newview/lldrawpoolavatar.cpp
+++ b/indra/newview/lldrawpoolavatar.cpp
@@ -583,10 +583,9 @@ void LLDrawPoolAvatar::renderShadow(S32 pass)
         }
         LLVOAvatar::AvatarOverallAppearance oa = avatarp->getOverallAppearance();
         BOOL impostor = !LLPipeline::sImpostorRender && avatarp->isImpostor();
-        if (oa == LLVOAvatar::AOA_INVISIBLE ||
-            (impostor && oa == LLVOAvatar::AOA_JELLYDOLL))
+        if (impostor || (oa == LLVOAvatar::AOA_INVISIBLE))
         {
-            // No shadows for jellydolled or invisible avs.
+            // No shadows for impostored (including jellydolled) or invisible avs.
             return;
         }
 
-- 
cgit v1.2.3


From b4bb74c5def3175d99d672b0b26f941b756f5f45 Mon Sep 17 00:00:00 2001
From: Dave Parks <davep@lindenlab.com>
Date: Wed, 22 Sep 2021 21:37:01 +0000
Subject: SL-16031 Add support for VS 2019 (requires autobuild 1.2-alpha)

---
 indra/cmake/Copy3rdPartyLibs.cmake | 2 ++
 indra/newview/llexperiencelog.cpp  | 4 ----
 2 files changed, 2 insertions(+), 4 deletions(-)

(limited to 'indra')

diff --git a/indra/cmake/Copy3rdPartyLibs.cmake b/indra/cmake/Copy3rdPartyLibs.cmake
index 46ddb9d15b..75601ddfcb 100644
--- a/indra/cmake/Copy3rdPartyLibs.cmake
+++ b/indra/cmake/Copy3rdPartyLibs.cmake
@@ -97,6 +97,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)
diff --git a/indra/newview/llexperiencelog.cpp b/indra/newview/llexperiencelog.cpp
index ee5d561927..c441fbc09f 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())
-- 
cgit v1.2.3


From 25089265699afe6c2a035f81259e8fd1e4b7008f Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Wed, 15 Sep 2021 15:39:48 -0700
Subject: SL-16014 Add Tracy logging to lldrawpoolavatar.cpp

---
 indra/newview/lldrawpoolavatar.cpp | 126 ++++++++++++++++++++++++++++++++++++-
 1 file changed, 125 insertions(+), 1 deletion(-)

(limited to 'indra')

diff --git a/indra/newview/lldrawpoolavatar.cpp b/indra/newview/lldrawpoolavatar.cpp
index c04142ab47..4f615d6107 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;
@@ -169,6 +175,8 @@ void LLDrawPoolAvatar::prerender()
 
 LLMatrix4& LLDrawPoolAvatar::getModelView()
 {
+    LL_PROFILE_ZONE_SCOPED
+
 	static LLMatrix4 ret;
 
 	ret.initRows(LLVector4(gGLModelView+0),
@@ -257,6 +265,8 @@ void LLDrawPoolAvatar::endDeferredPass(S32 pass)
 
 void LLDrawPoolAvatar::renderDeferred(S32 pass)
 {
+    LL_PROFILE_ZONE_SCOPED
+
 	render(pass);
 }
 
@@ -267,6 +277,8 @@ S32 LLDrawPoolAvatar::getNumPostDeferredPasses()
 
 void LLDrawPoolAvatar::beginPostDeferredPass(S32 pass)
 {
+    LL_PROFILE_ZONE_SCOPED
+
 	switch (pass)
 	{
 	case 0:
@@ -295,6 +307,8 @@ void LLDrawPoolAvatar::beginPostDeferredPass(S32 pass)
 
 void LLDrawPoolAvatar::beginPostDeferredAlpha()
 {
+    LL_PROFILE_ZONE_SCOPED
+
 	sSkipOpaque = TRUE;
 	sShaderLevel = mShaderLevel;
 	sVertexProgram = &gDeferredAvatarAlphaProgram;
@@ -309,6 +323,8 @@ void LLDrawPoolAvatar::beginPostDeferredAlpha()
 
 void LLDrawPoolAvatar::beginDeferredRiggedAlpha()
 {
+    LL_PROFILE_ZONE_SCOPED
+
 	sVertexProgram = &gDeferredSkinnedAlphaProgram;
 	gPipeline.bindDeferredShader(*sVertexProgram);
 	sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
@@ -317,6 +333,8 @@ void LLDrawPoolAvatar::beginDeferredRiggedAlpha()
 
 void LLDrawPoolAvatar::beginDeferredRiggedMaterialAlpha(S32 pass)
 {
+    LL_PROFILE_ZONE_SCOPED
+
 	switch (pass)
 	{
 	case 0: pass = 1; break;
@@ -343,6 +361,8 @@ void LLDrawPoolAvatar::beginDeferredRiggedMaterialAlpha(S32 pass)
 
 void LLDrawPoolAvatar::endDeferredRiggedAlpha()
 {
+    LL_PROFILE_ZONE_SCOPED
+
 	LLVertexBuffer::unbind();
 	gPipeline.unbindDeferredShader(*sVertexProgram);
 	sDiffuseChannel = 0;
@@ -353,6 +373,8 @@ void LLDrawPoolAvatar::endDeferredRiggedAlpha()
 
 void LLDrawPoolAvatar::endPostDeferredPass(S32 pass)
 {
+    LL_PROFILE_ZONE_SCOPED
+
 	switch (pass)
 	{
 	case 0:
@@ -381,6 +403,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 +416,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
@@ -647,6 +673,8 @@ void LLDrawPoolAvatar::renderShadow(S32 pass)
 
 S32 LLDrawPoolAvatar::getNumPasses()
 {
+    LL_PROFILE_ZONE_SCOPED
+
 	if (LLPipeline::sImpostorRender)
 	{
 		return 8;
@@ -660,6 +688,8 @@ S32 LLDrawPoolAvatar::getNumPasses()
 
 S32 LLDrawPoolAvatar::getNumDeferredPasses()
 {
+    LL_PROFILE_ZONE_SCOPED
+
 	if (LLPipeline::sImpostorRender)
 	{
 		return 19;
@@ -780,6 +810,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 +830,8 @@ void LLDrawPoolAvatar::beginImpostor()
 
 void LLDrawPoolAvatar::endImpostor()
 {
+    LL_PROFILE_ZONE_SCOPED
+
 	if (LLGLSLShader::sNoFixedFunction)
 	{
 		gImpostorProgram.unbind();
@@ -807,6 +841,8 @@ void LLDrawPoolAvatar::endImpostor()
 
 void LLDrawPoolAvatar::beginRigid()
 {
+    LL_PROFILE_ZONE_SCOPED
+
 	if (gPipeline.canUseVertexShaders())
 	{
 		if (LLPipeline::sUnderWaterRender)
@@ -840,6 +876,8 @@ void LLDrawPoolAvatar::beginRigid()
 
 void LLDrawPoolAvatar::endRigid()
 {
+    LL_PROFILE_ZONE_SCOPED
+
 	sShaderLevel = mShaderLevel;
 	if (sVertexProgram != NULL)
 	{
@@ -849,6 +887,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 +905,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 +918,8 @@ void LLDrawPoolAvatar::endDeferredImpostor()
 
 void LLDrawPoolAvatar::beginDeferredRigid()
 {
+    LL_PROFILE_ZONE_SCOPED
+
 	sVertexProgram = &gDeferredNonIndexedDiffuseAlphaMaskNoColorProgram;
 	sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
 	sVertexProgram->bind();
@@ -892,6 +936,8 @@ void LLDrawPoolAvatar::beginDeferredRigid()
 
 void LLDrawPoolAvatar::endDeferredRigid()
 {
+    LL_PROFILE_ZONE_SCOPED
+
 	sShaderLevel = mShaderLevel;
 	sVertexProgram->disableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
 	sVertexProgram->unbind();
@@ -901,6 +947,8 @@ void LLDrawPoolAvatar::endDeferredRigid()
 
 void LLDrawPoolAvatar::beginSkinned()
 {
+    LL_PROFILE_ZONE_SCOPED
+
 	if (sShaderLevel > 0)
 	{
 		if (LLPipeline::sUnderWaterRender)
@@ -967,6 +1015,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 +1041,8 @@ void LLDrawPoolAvatar::endSkinned()
 
 void LLDrawPoolAvatar::beginRiggedSimple()
 {
+    LL_PROFILE_ZONE_SCOPED
+
 	if (sShaderLevel > 0)
 	{
 		if (LLPipeline::sUnderWaterRender)
@@ -1031,6 +1083,8 @@ void LLDrawPoolAvatar::beginRiggedSimple()
 
 void LLDrawPoolAvatar::endRiggedSimple()
 {
+    LL_PROFILE_ZONE_SCOPED
+
 	LLVertexBuffer::unbind();
 	if (sShaderLevel > 0 || gPipeline.canUseVertexShaders())
 	{
@@ -1041,27 +1095,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 +1172,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 +1238,8 @@ void LLDrawPoolAvatar::beginRiggedFullbright()
 
 void LLDrawPoolAvatar::endRiggedFullbright()
 {
+    LL_PROFILE_ZONE_SCOPED
+
 	LLVertexBuffer::unbind();
 	if (sShaderLevel > 0 || gPipeline.canUseVertexShaders())
 	{
@@ -1180,6 +1250,8 @@ void LLDrawPoolAvatar::endRiggedFullbright()
 
 void LLDrawPoolAvatar::beginRiggedShinySimple()
 {
+    LL_PROFILE_ZONE_SCOPED
+
 	if (sShaderLevel > 0)
 	{
 		if (LLPipeline::sUnderWaterRender)
@@ -1220,6 +1292,8 @@ void LLDrawPoolAvatar::beginRiggedShinySimple()
 
 void LLDrawPoolAvatar::endRiggedShinySimple()
 {
+    LL_PROFILE_ZONE_SCOPED
+
 	LLVertexBuffer::unbind();
 	if (sShaderLevel > 0 || gPipeline.canUseVertexShaders())
 	{
@@ -1231,6 +1305,8 @@ void LLDrawPoolAvatar::endRiggedShinySimple()
 
 void LLDrawPoolAvatar::beginRiggedFullbrightShiny()
 {
+    LL_PROFILE_ZONE_SCOPED
+
 	if (sShaderLevel > 0)
 	{
 		if (LLPipeline::sUnderWaterRender)
@@ -1296,6 +1372,8 @@ void LLDrawPoolAvatar::beginRiggedFullbrightShiny()
 
 void LLDrawPoolAvatar::endRiggedFullbrightShiny()
 {
+    LL_PROFILE_ZONE_SCOPED
+
 	LLVertexBuffer::unbind();
 	if (sShaderLevel > 0 || gPipeline.canUseVertexShaders())
 	{
@@ -1308,6 +1386,8 @@ void LLDrawPoolAvatar::endRiggedFullbrightShiny()
 
 void LLDrawPoolAvatar::beginDeferredRiggedSimple()
 {
+    LL_PROFILE_ZONE_SCOPED
+
 	sVertexProgram = &gDeferredSkinnedDiffuseProgram;
 	sDiffuseChannel = 0;
 	sVertexProgram->bind();
@@ -1323,6 +1403,8 @@ void LLDrawPoolAvatar::beginDeferredRiggedSimple()
 
 void LLDrawPoolAvatar::endDeferredRiggedSimple()
 {
+    LL_PROFILE_ZONE_SCOPED
+
 	LLVertexBuffer::unbind();
 	sVertexProgram->unbind();
 	sVertexProgram = NULL;
@@ -1330,6 +1412,8 @@ void LLDrawPoolAvatar::endDeferredRiggedSimple()
 
 void LLDrawPoolAvatar::beginDeferredRiggedBump()
 {
+    LL_PROFILE_ZONE_SCOPED
+
 	sVertexProgram = &gDeferredSkinnedBumpProgram;
 	sVertexProgram->bind();
     if (LLPipeline::sRenderingHUDs)
@@ -1346,6 +1430,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 +1443,8 @@ void LLDrawPoolAvatar::endDeferredRiggedBump()
 
 void LLDrawPoolAvatar::beginDeferredRiggedMaterial(S32 pass)
 {
+    LL_PROFILE_ZONE_SCOPED
+
 	if (pass == 1 ||
 		pass == 5 ||
 		pass == 9 ||
@@ -1387,6 +1475,8 @@ void LLDrawPoolAvatar::beginDeferredRiggedMaterial(S32 pass)
 
 void LLDrawPoolAvatar::endDeferredRiggedMaterial(S32 pass)
 {
+    LL_PROFILE_ZONE_SCOPED
+
 	if (pass == 1 ||
 		pass == 5 ||
 		pass == 9 ||
@@ -1407,6 +1497,8 @@ void LLDrawPoolAvatar::endDeferredRiggedMaterial(S32 pass)
 
 void LLDrawPoolAvatar::beginDeferredSkinned()
 {
+    LL_PROFILE_ZONE_SCOPED
+
 	sShaderLevel = mShaderLevel;
 	sVertexProgram = &gDeferredAvatarProgram;
 	sRenderingSkinned = TRUE;
@@ -1428,6 +1520,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();
@@ -1740,6 +1834,8 @@ void LLDrawPoolAvatar::getRiggedGeometry(
     LLVolume* volume,
     const LLVolumeFace& vol_face)
 {
+    LL_PROFILE_ZONE_SCOPED
+
     face->setGeomIndex(0);
     face->setIndicesIndex(0);
 
@@ -2040,6 +2136,8 @@ void LLDrawPoolAvatar::updateRiggedFaceVertexBuffer(
 
 void LLDrawPoolAvatar::renderRigged(LLVOAvatar* avatar, U32 type, bool glow)
 {
+    LL_PROFILE_ZONE_SCOPED
+
 	if (!avatar->shouldRenderRigged())
 	{
 		return;
@@ -2332,16 +2430,22 @@ void LLDrawPoolAvatar::renderRigged(LLVOAvatar* avatar, U32 type, bool glow)
 
 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);
 }
 
@@ -2396,27 +2500,37 @@ void LLDrawPoolAvatar::updateRiggedVertexBuffers(LLVOAvatar* avatar)
 
 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);
@@ -2434,6 +2548,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);
@@ -2451,6 +2567,8 @@ void LLDrawPoolAvatar::renderRiggedFullbrightAlpha(LLVOAvatar* avatar)
 
 void LLDrawPoolAvatar::renderRiggedGlow(LLVOAvatar* avatar)
 {
+    LL_PROFILE_ZONE_SCOPED
+
 	if (!mRiggedFace[RIGGED_GLOW].empty())
 	{
 		LLGLEnable blend(GL_BLEND);
@@ -2478,6 +2596,8 @@ void LLDrawPoolAvatar::renderRiggedGlow(LLVOAvatar* avatar)
 //-----------------------------------------------------------------------------
 LLViewerTexture *LLDrawPoolAvatar::getDebugTexture()
 {
+    LL_PROFILE_ZONE_SCOPED
+
 	if (mReferences.empty())
 	{
 		return NULL;
@@ -2501,6 +2621,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)
@@ -2523,6 +2645,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)
@@ -2560,7 +2684,7 @@ LLVertexBufferAvatar::LLVertexBufferAvatar()
 : LLVertexBuffer(sDataMask, 
 	GL_STREAM_DRAW_ARB) //avatars are always stream draw due to morph targets
 {
-
+    LL_PROFILE_ZONE_SCOPED
 }
 
 
-- 
cgit v1.2.3


From c0eadc87e8bc8ce5658f49a960af4868a0865ddc Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Wed, 15 Sep 2021 17:44:09 -0700
Subject: SL-16014: Add Tracy logging to doFrame()

---
 indra/newview/llappviewer.cpp | 74 ++++++++++++++++++++++++++++++++-----------
 1 file changed, 56 insertions(+), 18 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 94f0b31ecd..ab2b846c09 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -1424,9 +1424,13 @@ bool LLAppViewer::doFrame()
 	LLSD newFrame;
 
 	LL_RECORD_BLOCK_TIME(FTM_FRAME);
-	LLTrace::BlockTimer::processTimes();
-	LLTrace::get_frame_recording().nextPeriod();
-	LLTrace::BlockTimer::logStats();
+
+	{
+		LL_PROFILE_ZONE_NAMED( ":blocktimer" )
+		LLTrace::BlockTimer::processTimes();
+		LLTrace::get_frame_recording().nextPeriod();
+		LLTrace::BlockTimer::logStats();
+	}
 
 	LLTrace::get_thread_recorder()->pullFromChildren();
 
@@ -1434,6 +1438,7 @@ bool LLAppViewer::doFrame()
 	LL_CLEAR_CALLSTACKS();
 
 	{
+		LL_PROFILE_ZONE_NAMED( ":processMiscNativeEvents" )
 		pingMainloopTimeout("Main:MiscNativeWindowEvents");
 
 		if (gViewerWindow)
@@ -1442,7 +1447,10 @@ bool LLAppViewer::doFrame()
 			gViewerWindow->getWindow()->processMiscNativeEvents();
 		}
 
-		pingMainloopTimeout("Main:GatherInput");
+		{
+			LL_PROFILE_ZONE_NAMED( ":gatherInput" )
+			pingMainloopTimeout("Main:GatherInput");
+		}
 
 		if (gViewerWindow)
 		{
@@ -1466,13 +1474,21 @@ bool LLAppViewer::doFrame()
 			}
 		}
 
-		// canonical per-frame event
-		mainloop.post(newFrame);
-		// give listeners a chance to run
-		llcoro::suspend();
+		{
+			LL_PROFILE_ZONE_NAMED( ":mainloop" )
+			// canonical per-frame event
+			mainloop.post(newFrame);
+		}
+
+		{
+			LL_PROFILE_ZONE_NAMED( ":suspend" )
+			// give listeners a chance to run
+			llcoro::suspend();
+		}
 
 		if (!LLApp::isExiting())
 		{
+			LL_PROFILE_ZONE_NAMED( ":JoystickKeyboard" )
 			pingMainloopTimeout("Main:JoystickKeyboard");
 
 			// Scan keyboard for movement keys.  Command keys and typing
@@ -1493,12 +1509,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( ":pauseMainloopTimeout" )
+					pauseMainloopTimeout(); // *TODO: Remove. Messages shouldn't be stalling for 20+ seconds!
+				}
 
 				LL_RECORD_BLOCK_TIME(FTM_IDLE);
 				idle();
 
-				resumeMainloopTimeout();
+				{
+					LL_PROFILE_ZONE_NAMED( ":resumeMainloopTimeout" )
+					resumeMainloopTimeout();
+				}
 			}
 
 			if (gDoDisconnect && (LLStartUp::getStartupState() == STATE_STARTED))
@@ -1513,6 +1535,7 @@ bool LLAppViewer::doFrame()
 			// *TODO: Should we run display() even during gHeadlessClient?  DK 2011-02-18
 			if (!LLApp::isExiting() && !gHeadlessClient && gViewerWindow)
 			{
+				LL_PROFILE_ZONE_NAMED( ":Display" )
 				pingMainloopTimeout("Main:Display");
 				gGLActive = TRUE;
 
@@ -1533,16 +1556,22 @@ bool LLAppViewer::doFrame()
 				}
 				last_call = LLTimer::getTotalTime();
 
-				pingMainloopTimeout("Main:Snapshot");
-				LLFloaterSnapshot::update(); // take snapshots
+				{
+					LL_PROFILE_ZONE_NAMED( ":Snapshot" )
+					pingMainloopTimeout("Main:Snapshot");
+					LLFloaterSnapshot::update(); // take snapshots
 					LLFloaterOutfitSnapshot::update();
-				gGLActive = FALSE;
+					gGLActive = FALSE;
+				}
 			}
 		}
 
-		pingMainloopTimeout("Main:Sleep");
+		{
+			LL_PROFILE_ZONE_NAMED( ":pauseMainloopTimeout" )
+			pingMainloopTimeout("Main:Sleep");
 
-		pauseMainloopTimeout();
+			pauseMainloopTimeout();
+		}
 
 		// Sleep and run background threads
 		{
@@ -1615,16 +1644,22 @@ bool LLAppViewer::doFrame()
 				total_io_pending += io_pending ;
 
 			}
-			gMeshRepo.update() ;
+
+			{
+				LL_PROFILE_ZONE_NAMED( ":gMeshRepo" )
+				gMeshRepo.update() ;
+			}
 
 			if(!total_work_pending) //pause texture fetching threads if nothing to process.
 			{
+				LL_PROFILE_ZONE_NAMED( ":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( ":LLVFSThread" )
 				LLVFSThread::sLocal->pause();
 				LLLFSThread::sLocal->pause();
 			}
@@ -1632,6 +1667,7 @@ bool LLAppViewer::doFrame()
 			//texture fetching debugger
 			if(LLTextureFetchDebugger::isEnabled())
 			{
+				LL_PROFILE_ZONE_NAMED( ":tex_fetch_debugger_instance" )
 				LLFloaterTextureFetchDebugger* tex_fetch_debugger_instance =
 					LLFloaterReg::findTypedInstance<LLFloaterTextureFetchDebugger>("tex_fetch_debugger");
 				if(tex_fetch_debugger_instance)
@@ -1640,8 +1676,10 @@ bool LLAppViewer::doFrame()
 				}
 			}
 
-			resumeMainloopTimeout();
-
+			{
+				LL_PROFILE_ZONE_NAMED( ":resumeMainloopTimeout" )
+				resumeMainloopTimeout();
+			}
 			pingMainloopTimeout("Main:End");
 		}
 	}
-- 
cgit v1.2.3


From b9ad51981eb992ebe77b8ffbde48b2797ff55cef Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Mon, 20 Sep 2021 08:33:41 -0700
Subject: SL-16014: Add macros for better markup in Tracy

---
 indra/llcommon/llprofiler.h | 50 +++++++++++++++++++++++++++++++++------------
 1 file changed, 37 insertions(+), 13 deletions(-)

(limited to 'indra')

diff --git a/indra/llcommon/llprofiler.h b/indra/llcommon/llprofiler.h
index 62ec20fa44..59e7dc02c6 100644
--- a/indra/llcommon/llprofiler.h
+++ b/indra/llcommon/llprofiler.h
@@ -51,25 +51,49 @@
     #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)          ZoneNamedN( ___tracy_scoped_zone, #name, true );
-        #define LL_PROFILE_ZONE_NAMED(name)          ZoneNamedN( ___tracy_scoped_zone, name, true );  
-        #define LL_PROFILE_ZONE_SCOPED              ZoneScoped
+        #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_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_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_PRPFILE_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)          ZoneNamedN( ___tracy_scoped_zone, #timer_stat, true )   const LLTrace::BlockTimer& LL_GLUE_TOKENS(block_time_recorder, __LINE__)(LLTrace::timeThisBlock(name)); (void)LL_GLUE_TOKENS(block_time_recorder, __LINE__);
-        #define LL_PROFILE_ZONE_NAMED(name)         ZoneNamedN( ___tracy_scoped_zone, #name, true );
-        #define LL_PROFILE_ZONE_SCOPED              ZoneScoped
+        #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
-- 
cgit v1.2.3


From 6c53fbfb4700b40893cd69377999d29c7ba96099 Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Mon, 20 Sep 2021 09:43:38 -0700
Subject: SL-16014: Add Tracy markup for lldrawable

---
 indra/newview/lldrawable.cpp | 45 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 45 insertions(+)

(limited to 'indra')

diff --git a/indra/newview/lldrawable.cpp b/indra/newview/lldrawable.cpp
index 507af56cb0..30c4a21e1c 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;
@@ -232,6 +234,8 @@ void LLDrawable::markDead()
 
 LLVOVolume* LLDrawable::getVOVolume() const
 {
+	LL_PROFILE_ZONE_SCOPED
+
 	LLViewerObject* objectp = mVObjp;
 	if ( !isDead() && objectp && (objectp->getPCode() == LL_PCODE_VOLUME))
 	{
@@ -335,6 +339,7 @@ static LLTrace::BlockTimerStatHandle FTM_ALLOCATE_FACE("Allocate Face");
 
 LLFace*	LLDrawable::addFace(LLFacePool *poolp, LLViewerTexture *texturep)
 {
+	LL_PROFILE_ZONE_SCOPED
 	
 	LLFace *face;
 	{
@@ -363,6 +368,8 @@ LLFace*	LLDrawable::addFace(LLFacePool *poolp, LLViewerTexture *texturep)
 
 LLFace*	LLDrawable::addFace(const LLTextureEntry *te, LLViewerTexture *texturep)
 {
+	LL_PROFILE_ZONE_SCOPED
+
 	LLFace *face;
 
 	{
@@ -387,6 +394,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 +417,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 +441,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 +466,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 +491,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 +526,8 @@ void LLDrawable::updateMaterial()
 
 void LLDrawable::makeActive()
 {		
+	LL_PROFILE_ZONE_SCOPED
+
 #if !LL_RELEASE_FOR_DOWNLOAD
 	if (mVObjp.notNull())
 	{
@@ -572,6 +591,8 @@ void LLDrawable::makeActive()
 
 void LLDrawable::makeStatic(BOOL warning_enabled)
 {
+	LL_PROFILE_ZONE_SCOPED
+
 	if (isState(ACTIVE) && 
 		!isState(ACTIVE_CHILD) && 
 		!mVObjp->isAttachment() && 
@@ -618,6 +639,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 +792,8 @@ void LLDrawable::moveUpdatePipeline(BOOL moved)
 
 void LLDrawable::movePartition()
 {
+	LL_PROFILE_ZONE_SCOPED
+
 	LLSpatialPartition* part = getSpatialPartition();
 	if (part)
 	{
@@ -813,6 +838,8 @@ BOOL LLDrawable::updateMoveUndamped()
 
 void LLDrawable::updatePartition()
 {
+	LL_PROFILE_ZONE_SCOPED
+
 	if (!getVOVolume())
 	{
 		movePartition();
@@ -830,6 +857,8 @@ void LLDrawable::updatePartition()
 
 BOOL LLDrawable::updateMoveDamped()
 {
+	LL_PROFILE_ZONE_SCOPED
+
 	F32 dist_squared = updateXform(FALSE);
 
 	mGeneration++;
@@ -853,6 +882,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 +988,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 +1067,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 +1199,8 @@ void LLDrawable::setGroup(LLViewerOctreeGroup *groupp)
 
 LLSpatialPartition* LLDrawable::getSpatialPartition()
 { 
+	LL_PROFILE_ZONE_SCOPED
+
 	LLSpatialPartition* retval = NULL;
 	
 	if (!mVObjp || 
@@ -1247,6 +1284,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 +1331,8 @@ void LLSpatialBridge::destroyTree()
 
 void LLSpatialBridge::updateSpatialExtents()
 {
+	LL_PROFILE_ZONE_SCOPED
+
 	LLSpatialGroup* root = (LLSpatialGroup*) mOctree->getListener(0);
 	
 	{
@@ -1455,6 +1496,8 @@ public:
 
 void LLSpatialBridge::setVisible(LLCamera& camera_in, std::vector<LLDrawable*>* results, BOOL for_select)
 {
+	LL_PROFILE_ZONE_SCOPED
+
 	if (!gPipeline.hasRenderType(mDrawableType))
 	{
 		return;
@@ -1552,6 +1595,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();
-- 
cgit v1.2.3


From dd3fc66b51e8a979a6f6bf8f7e1cfedb952d0d49 Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Mon, 20 Sep 2021 09:44:34 -0700
Subject: SL-16014: Add Tracy markup to LLFace

---
 indra/newview/llface.cpp | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

(limited to 'indra')

diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp
index 6e55d8f66a..34448a780d 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;
@@ -606,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)
     {
@@ -892,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))
 	{
@@ -2376,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;
@@ -2655,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))
@@ -2674,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;
@@ -2684,6 +2700,8 @@ S32 LLFace::renderIndexed()
 
 S32 LLFace::renderIndexed(U32 mask)
 {
+	LL_PROFILE_ZONE_SCOPED
+
 	if (mVertexBuffer.isNull())
 	{
 		return 0;
-- 
cgit v1.2.3


From 584a7f05df9b067c3e57b52c61d5e94fcfce6a19 Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Mon, 20 Sep 2021 09:45:17 -0700
Subject: SL-16014: Add Tracy markup to LLSpatialGroup

---
 indra/newview/llspatialpartition.cpp | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

(limited to 'indra')

diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp
index 0adf58a0bf..253b6b9953 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 @@ public:
 
 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 @@ public:
 
 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());
-- 
cgit v1.2.3


From b78db5ae5c308f3a895e15a109d2814ca7f9ea94 Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Mon, 20 Sep 2021 09:45:52 -0700
Subject: SL-16014: Add Tracy markup to LLViewerObjectList

---
 indra/newview/llviewerobjectlist.cpp | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

(limited to 'indra')

diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp
index 63e48d1dd0..0b20556104 100644
--- a/indra/newview/llviewerobjectlist.cpp
+++ b/indra/newview/llviewerobjectlist.cpp
@@ -168,6 +168,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;		
@@ -303,6 +305,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)
@@ -848,6 +852,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") );
@@ -1293,6 +1299,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())
 	{
@@ -1523,6 +1531,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!
@@ -1843,6 +1853,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 
-- 
cgit v1.2.3


From 51a887a51c4d86775006fea1d9522031142ec79d Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Mon, 20 Sep 2021 09:46:43 -0700
Subject: SL-16014: Add Tracy markup for LLSD

---
 indra/llcommon/llsdutil.cpp | 22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)

(limited to 'indra')

diff --git a/indra/llcommon/llsdutil.cpp b/indra/llcommon/llsdutil.cpp
index eb3a96b133..c2fe15e9b7 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 @@ public:
 
     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());
 
-- 
cgit v1.2.3


From 8e4907beeea1ca0474dd124c7f6b4bf5dba45c3e Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Mon, 20 Sep 2021 09:47:26 -0700
Subject: SL-16014: Add Tracy markup for LLVolumeFace

---
 indra/llmath/llvolume.cpp | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

(limited to 'indra')

diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp
index e085fa6ada..130f30bedc 100644
--- a/indra/llmath/llvolume.cpp
+++ b/indra/llmath/llvolume.cpp
@@ -383,6 +383,7 @@ public:
 	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;
-- 
cgit v1.2.3


From 2b19015f4394de59244c78f88c5c5df172632de6 Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Mon, 20 Sep 2021 09:48:16 -0700
Subject: SL-16014: Add Tracy markup for LLEventFilter

---
 indra/llcommon/lleventfilter.h | 2 ++
 1 file changed, 2 insertions(+)

(limited to 'indra')

diff --git a/indra/llcommon/lleventfilter.h b/indra/llcommon/lleventfilter.h
index 48c2570732..7613850fb2 100644
--- a/indra/llcommon/lleventfilter.h
+++ b/indra/llcommon/lleventfilter.h
@@ -429,6 +429,8 @@ public:
     // 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
-- 
cgit v1.2.3


From 5fa9b510293fc3a36776f75fa6e88aefe3233a94 Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Mon, 20 Sep 2021 09:54:32 -0700
Subject: SL-16014: Add Tracy markup to doFrame()

---
 indra/newview/llappviewer.cpp | 48 ++++++++++++++++++++++++-------------------
 1 file changed, 27 insertions(+), 21 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index ab2b846c09..879cc6fc85 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -1358,7 +1358,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");
@@ -1420,13 +1421,13 @@ 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);
-
 	{
-		LL_PROFILE_ZONE_NAMED( ":blocktimer" )
+		LL_PROFILE_ZONE_NAMED( "df blocktimer" )
 		LLTrace::BlockTimer::processTimes();
 		LLTrace::get_frame_recording().nextPeriod();
 		LLTrace::BlockTimer::logStats();
@@ -1438,7 +1439,7 @@ bool LLAppViewer::doFrame()
 	LL_CLEAR_CALLSTACKS();
 
 	{
-		LL_PROFILE_ZONE_NAMED( ":processMiscNativeEvents" )
+		LL_PROFILE_ZONE_NAMED( "df processMiscNativeEvents" )
 		pingMainloopTimeout("Main:MiscNativeWindowEvents");
 
 		if (gViewerWindow)
@@ -1448,7 +1449,7 @@ bool LLAppViewer::doFrame()
 		}
 
 		{
-			LL_PROFILE_ZONE_NAMED( ":gatherInput" )
+			LL_PROFILE_ZONE_NAMED( "df gatherInput" )
 			pingMainloopTimeout("Main:GatherInput");
 		}
 
@@ -1475,20 +1476,20 @@ bool LLAppViewer::doFrame()
 		}
 
 		{
-			LL_PROFILE_ZONE_NAMED( ":mainloop" )
+			LL_PROFILE_ZONE_NAMED( "df mainloop" )
 			// canonical per-frame event
 			mainloop.post(newFrame);
 		}
 
 		{
-			LL_PROFILE_ZONE_NAMED( ":suspend" )
+			LL_PROFILE_ZONE_NAMED( "df suspend" )
 			// give listeners a chance to run
 			llcoro::suspend();
 		}
 
 		if (!LLApp::isExiting())
 		{
-			LL_PROFILE_ZONE_NAMED( ":JoystickKeyboard" )
+			LL_PROFILE_ZONE_NAMED( "df JoystickKeyboard" )
 			pingMainloopTimeout("Main:JoystickKeyboard");
 
 			// Scan keyboard for movement keys.  Command keys and typing
@@ -1510,7 +1511,7 @@ bool LLAppViewer::doFrame()
 			// Update state based on messages, user input, object idle.
 			{
 				{
-					LL_PROFILE_ZONE_NAMED( ":pauseMainloopTimeout" )
+					LL_PROFILE_ZONE_NAMED( "df pauseMainloopTimeout" )
 					pauseMainloopTimeout(); // *TODO: Remove. Messages shouldn't be stalling for 20+ seconds!
 				}
 
@@ -1518,7 +1519,7 @@ bool LLAppViewer::doFrame()
 				idle();
 
 				{
-					LL_PROFILE_ZONE_NAMED( ":resumeMainloopTimeout" )
+					LL_PROFILE_ZONE_NAMED( "df resumeMainloopTimeout" )
 					resumeMainloopTimeout();
 				}
 			}
@@ -1535,7 +1536,7 @@ bool LLAppViewer::doFrame()
 			// *TODO: Should we run display() even during gHeadlessClient?  DK 2011-02-18
 			if (!LLApp::isExiting() && !gHeadlessClient && gViewerWindow)
 			{
-				LL_PROFILE_ZONE_NAMED( ":Display" )
+				LL_PROFILE_ZONE_NAMED( "df Display" )
 				pingMainloopTimeout("Main:Display");
 				gGLActive = TRUE;
 
@@ -1548,16 +1549,19 @@ bool LLAppViewer::doFrame()
 					U64 elapsed_time = LLTimer::getTotalTime() - last_call;
 					if (elapsed_time < mMinMicroSecPerFrame)
 					{
-						LL_RECORD_BLOCK_TIME(FTM_SLEEP);
+						//LL_RECORD_BLOCK_TIME(FTM_SLEEP1);
+						LL_PROFILE_ZONE_WARN( "Sleep1" )
 						// llclamp for when time function gets funky
 						U64 sleep_time = llclamp(mMinMicroSecPerFrame - elapsed_time, (U64)1, (U64)1e6);
+
+						LL_PROFILE_ZONE_NUM( sleep_time )
 						micro_sleep(sleep_time, 0);
 					}
 				}
 				last_call = LLTimer::getTotalTime();
 
 				{
-					LL_PROFILE_ZONE_NAMED( ":Snapshot" )
+					LL_PROFILE_ZONE_NAMED( "df Snapshot" )
 					pingMainloopTimeout("Main:Snapshot");
 					LLFloaterSnapshot::update(); // take snapshots
 					LLFloaterOutfitSnapshot::update();
@@ -1567,7 +1571,7 @@ bool LLAppViewer::doFrame()
 		}
 
 		{
-			LL_PROFILE_ZONE_NAMED( ":pauseMainloopTimeout" )
+			LL_PROFILE_ZONE_NAMED( "df pauseMainloopTimeout" )
 			pingMainloopTimeout("Main:Sleep");
 
 			pauseMainloopTimeout();
@@ -1575,13 +1579,15 @@ bool LLAppViewer::doFrame()
 
 		// 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);
 			}
 
@@ -1646,20 +1652,20 @@ bool LLAppViewer::doFrame()
 			}
 
 			{
-				LL_PROFILE_ZONE_NAMED( ":gMeshRepo" )
+				LL_PROFILE_ZONE_NAMED( "df gMeshRepo" )
 				gMeshRepo.update() ;
 			}
 
 			if(!total_work_pending) //pause texture fetching threads if nothing to process.
 			{
-				LL_PROFILE_ZONE_NAMED( ":getTextureCache" )
+				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( ":LLVFSThread" )
+				LL_PROFILE_ZONE_NAMED( "df LLVFSThread" )
 				LLVFSThread::sLocal->pause();
 				LLLFSThread::sLocal->pause();
 			}
@@ -1667,7 +1673,7 @@ bool LLAppViewer::doFrame()
 			//texture fetching debugger
 			if(LLTextureFetchDebugger::isEnabled())
 			{
-				LL_PROFILE_ZONE_NAMED( ":tex_fetch_debugger_instance" )
+				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)
@@ -1677,7 +1683,7 @@ bool LLAppViewer::doFrame()
 			}
 
 			{
-				LL_PROFILE_ZONE_NAMED( ":resumeMainloopTimeout" )
+				LL_PROFILE_ZONE_NAMED( "df resumeMainloopTimeout" )
 				resumeMainloopTimeout();
 			}
 			pingMainloopTimeout("Main:End");
-- 
cgit v1.2.3


From 43bca9e85d7fb1e6907fbe17f527e5bc8f543411 Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Wed, 22 Sep 2021 14:58:36 -0700
Subject: SL-16014: Fix typo

---
 indra/llcommon/llprofiler.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'indra')

diff --git a/indra/llcommon/llprofiler.h b/indra/llcommon/llprofiler.h
index 59e7dc02c6..49510df913 100644
--- a/indra/llcommon/llprofiler.h
+++ b/indra/llcommon/llprofiler.h
@@ -71,7 +71,7 @@
         #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_PRPFILE_ZONE_COLOR(name,color)       // LL_RECORD_BLOCK_TIME(name)
+        #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
-- 
cgit v1.2.3


From dc48e174c43edb770f3c2de0ac16adee5841d7ec Mon Sep 17 00:00:00 2001
From: Callum Linden <callum@lindenlab.com>
Date: Fri, 24 Sep 2021 11:46:19 -0700
Subject: SL-15999 (SL-16055) Turn off voice in non-interactive mode

---
 indra/newview/llvoicevivox.cpp | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

(limited to 'indra')

diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp
index 4d2eac8c09..86fe7c19bd 100644
--- a/indra/newview/llvoicevivox.cpp
+++ b/indra/newview/llvoicevivox.cpp
@@ -5358,7 +5358,9 @@ void LLVivoxVoiceClient::setVoiceEnabled(bool enabled)
 
 bool LLVivoxVoiceClient::voiceEnabled()
 {
-	return gSavedSettings.getBOOL("EnableVoiceChat") && !gSavedSettings.getBOOL("CmdLineDisableVoice");
+    return gSavedSettings.getBOOL("EnableVoiceChat") &&
+          !gSavedSettings.getBOOL("CmdLineDisableVoice") &&
+          !gNonInteractive;
 }
 
 void LLVivoxVoiceClient::setLipSyncEnabled(BOOL enabled)
-- 
cgit v1.2.3


From 628b9dfe0639a7dfccd05533671cbbf1d93d5ba0 Mon Sep 17 00:00:00 2001
From: "Brad Payne (Vir Linden)" <vir@lindenlab.com>
Date: Mon, 27 Sep 2021 13:53:04 +0100
Subject: SL-15999 - removed kludgy run disablement, needs better fix

---
 indra/newview/llviewermessage.cpp | 16 ----------------
 1 file changed, 16 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp
index c99232eba0..39c891c9c1 100644
--- a/indra/newview/llviewermessage.cpp
+++ b/indra/newview/llviewermessage.cpp
@@ -4049,7 +4049,6 @@ void process_avatar_animation(LLMessageSystem *mesgsys, void **user_data)
 
 	S32 num_blocks = mesgsys->getNumberOfBlocksFast(_PREHASH_AnimationList);
 	S32 num_source_blocks = mesgsys->getNumberOfBlocksFast(_PREHASH_AnimationSourceList);
-	bool non_interactive_got_run = false;
 
 	LL_DEBUGS("Messaging", "Motion") << "Processing " << num_blocks << " Animations" << LL_ENDL;
 
@@ -4065,14 +4064,6 @@ void process_avatar_animation(LLMessageSystem *mesgsys, void **user_data)
 			mesgsys->getUUIDFast(_PREHASH_AnimationList, _PREHASH_AnimID, animation_id, i);
 			mesgsys->getS32Fast(_PREHASH_AnimationList, _PREHASH_AnimSequenceID, anim_sequence_id, i);
 
-			if (gNonInteractive && (animation_id == ANIM_AGENT_RUN))
-			{
-				// RUN requests get sent at startup for unclear
-				// reasons. Same avatar may get requests one run and
-				// not another. At least in the non-interactive case,
-				// we want to override these.
-				non_interactive_got_run = true;
-			}
 			avatarp->mSignaledAnimations[animation_id] = anim_sequence_id;
 
 			// *HACK: Disabling flying mode if it has been enabled shortly before the agent
@@ -4136,13 +4127,6 @@ void process_avatar_animation(LLMessageSystem *mesgsys, void **user_data)
 	{
 		avatarp->processAnimationStateChanges();
 	}
-
-	if (non_interactive_got_run)
-	{
-		// Total kluge alert.
-		LL_INFOS("Messaging","Motion") << "non-interactive mode, resetting animations" << LL_ENDL;
-		gAgent.stopCurrentAnimations();
-	}
 }
 
 
-- 
cgit v1.2.3


From 502d37913d3df8abb4e8e103c446e24ded2996a6 Mon Sep 17 00:00:00 2001
From: "Brad Payne (Vir Linden)" <vir@lindenlab.com>
Date: Mon, 27 Sep 2021 21:23:49 +0100
Subject: SL-15999 - noninteractive: debugging run issues, suppress AFK/Away
 pose

---
 indra/newview/llagent.cpp         | 2 +-
 indra/newview/llappviewer.cpp     | 2 +-
 indra/newview/llviewermessage.cpp | 5 +++++
 indra/newview/llvoavatar.cpp      | 5 +++++
 4 files changed, 12 insertions(+), 2 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp
index 389448654a..b35eef20f7 100644
--- a/indra/newview/llagent.cpp
+++ b/indra/newview/llagent.cpp
@@ -1481,7 +1481,7 @@ void LLAgent::resetControlFlags()
 //-----------------------------------------------------------------------------
 void LLAgent::setAFK()
 {
-	if (!gAgent.getRegion())
+	if (gNonInteractive || !gAgent.getRegion())
 	{
 		// Don't set AFK if we're not talking to a region yet.
 		return;
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index b6446e40ac..fb69f46bc5 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -1559,7 +1559,7 @@ bool LLAppViewer::doFrame()
 
 			if (gNonInteractive)
 			{
-				S32 non_interactive_ms_sleep_time = 1000;
+				S32 non_interactive_ms_sleep_time = 100;
 				LLAppViewer::getTextureCache()->pause();
 				LLAppViewer::getImageDecodeThread()->pause();
 				ms_sleep(non_interactive_ms_sleep_time);
diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp
index 39c891c9c1..ab65d747ba 100644
--- a/indra/newview/llviewermessage.cpp
+++ b/indra/newview/llviewermessage.cpp
@@ -4077,6 +4077,11 @@ 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/llvoavatar.cpp b/indra/newview/llvoavatar.cpp
index e085a945a8..dad580de70 100644
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -3807,6 +3807,11 @@ 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)
 	{
-- 
cgit v1.2.3


From 78007d2592290582e3b3fbff002376ad0561779f Mon Sep 17 00:00:00 2001
From: Dave Parks <davep@lindenlab.com>
Date: Mon, 27 Sep 2021 22:35:50 +0000
Subject: SL-16088 Fix for stall from many calls to glGenBuffers.

---
 indra/llrender/llvertexbuffer.cpp       | 19 +++++++++++++++----
 indra/llrender/llvertexbuffer.h         |  5 ++++-
 indra/newview/llsurface.cpp             |  1 +
 indra/newview/llsurfacepatch.cpp        |  1 +
 indra/newview/llviewerparceloverlay.cpp |  1 +
 indra/newview/llvlcomposition.cpp       |  1 +
 indra/newview/llvoavatar.cpp            |  2 ++
 indra/newview/llvosurfacepatch.cpp      |  1 +
 8 files changed, 26 insertions(+), 5 deletions(-)

(limited to 'indra')

diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp
index b69b644ebc..0449ac392c 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();
diff --git a/indra/llrender/llvertexbuffer.h b/indra/llrender/llvertexbuffer.h
index dbe1a3687f..1d60970df4 100644
--- a/indra/llrender/llvertexbuffer.h
+++ b/indra/llrender/llvertexbuffer.h
@@ -89,6 +89,9 @@ public:
 	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 @@ public:
 	static LLVBOPool sDynamicCopyVBOPool;
 	static LLVBOPool sStreamIBOPool;
 	static LLVBOPool sDynamicIBOPool;
-	
+
 	static std::list<U32> sAvailableVAOName;
 	static U32 sCurVAOName;
 
diff --git a/indra/newview/llsurface.cpp b/indra/newview/llsurface.cpp
index cb356726e6..ea36e1d7be 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 5e056944e9..aeefcd6fb8 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/llviewerparceloverlay.cpp b/indra/newview/llviewerparceloverlay.cpp
index 7c3dd00e1a..02f7bbeed8 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/llvlcomposition.cpp b/indra/newview/llvlcomposition.cpp
index c63c5f6b23..46beac8255 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 f260e4f750..a588d05ff7 100644
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -7123,6 +7123,7 @@ void LLVOAvatar::updateGL()
 {
 	if (mMeshTexturesDirty)
 	{
+		LL_PROFILE_ZONE_SCOPED
 		updateMeshTextures();
 		mMeshTexturesDirty = FALSE;
 	}
@@ -8361,6 +8362,7 @@ void LLVOAvatar::updateMeshVisibility()
 // virtual
 void LLVOAvatar::updateMeshTextures()
 {
+	LL_PROFILE_ZONE_SCOPED
 	static S32 update_counter = 0;
 	mBakedTextureDebugText.clear();
 	
diff --git a/indra/newview/llvosurfacepatch.cpp b/indra/newview/llvosurfacepatch.cpp
index 897bace4e1..b5560d3d79 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();
 	}
 }
-- 
cgit v1.2.3


From 675514bdb372c25b50dd2c42b06633895c86b8ce Mon Sep 17 00:00:00 2001
From: Dave Parks <davep@lindenlab.com>
Date: Mon, 27 Sep 2021 23:56:06 +0000
Subject: SL-16093 Don't force the console window to be open on developer
 builds because it causes frame stalls while logging.

---
 indra/llcommon/llerror.cpp        | 12 +++++++++++-
 indra/llcommon/llerror.h          |  5 ++++-
 indra/llcommon/llerrorcontrol.h   |  1 +
 indra/llcommon/llmemory.cpp       |  2 ++
 indra/llcommon/llmutex.cpp        | 12 ++++++++++++
 indra/llcommon/llsys.cpp          |  1 +
 indra/llcommon/llthread.cpp       |  7 +++++++
 indra/llrender/llglslshader.cpp   |  1 +
 indra/llrender/llimagegl.cpp      |  5 ++++-
 indra/llrender/llrender.cpp       |  1 +
 indra/newview/llappviewer.cpp     |  7 +------
 indra/newview/llviewerdisplay.cpp | 11 ++++++++++-
 indra/newview/llviewerwindow.cpp  |  1 +
 indra/newview/llworld.cpp         |  1 +
 indra/newview/pipeline.cpp        |  2 ++
 indra/test/test.cpp               |  1 +
 16 files changed, 60 insertions(+), 10 deletions(-)

(limited to 'indra')

diff --git a/indra/llcommon/llerror.cpp b/indra/llcommon/llerror.cpp
index 8355df9045..f7af181927 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 d439136ca8..d06c0e2132 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 e87bb7bf35..57f10b7895 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/llmemory.cpp b/indra/llcommon/llmemory.cpp
index ea84e4c1ea..849867586a 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/llmutex.cpp b/indra/llcommon/llmutex.cpp
index 4d73c04d07..a49002b5dc 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/llsys.cpp b/indra/llcommon/llsys.cpp
index 4e61fb8a58..6d5d043e8d 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 a8cc750437..11f5a015f1 100644
--- a/indra/llcommon/llthread.cpp
+++ b/indra/llcommon/llthread.cpp
@@ -333,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.
@@ -364,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())
     {
@@ -385,6 +389,7 @@ void LLThread::wake()
 
 void LLThread::wakeLocked()
 {
+    LL_PROFILE_ZONE_SCOPED
     if(!shouldSleep())
     {
         mRunCondition->signal();
@@ -393,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/llrender/llglslshader.cpp b/indra/llrender/llglslshader.cpp
index 8bd9dbf9b8..9ab38d25a9 100644
--- a/indra/llrender/llglslshader.cpp
+++ b/indra/llrender/llglslshader.cpp
@@ -126,6 +126,7 @@ struct LLGLSLShaderCompareTimeElapsed
 //static
 void LLGLSLShader::finishProfile(bool emit_report)
 {
+    LL_PROFILE_ZONE_SCOPED
     sProfileEnabled = false;
 
     if (emit_report)
diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp
index 0151d20128..276fa55e15 100644
--- a/indra/llrender/llimagegl.cpp
+++ b/indra/llrender/llimagegl.cpp
@@ -1304,7 +1304,10 @@ void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 widt
 	}
 
 	stop_glerror();
-	glTexImage2D(target, miplevel, intformat, width, height, 0, pixformat, pixtype, use_scratch ? scratch : pixels);
+	{
+		LL_PROFILE_ZONE_NAMED("glTexImage2D");
+		glTexImage2D(target, miplevel, intformat, width, height, 0, pixformat, pixtype, use_scratch ? scratch : pixels);
+	}
 	stop_glerror();
 
 	if (use_scratch)
diff --git a/indra/llrender/llrender.cpp b/indra/llrender/llrender.cpp
index 03b6aac20c..43b4441ea8 100644
--- a/indra/llrender/llrender.cpp
+++ b/indra/llrender/llrender.cpp
@@ -1848,6 +1848,7 @@ LLLightState* LLRender::getLight(U32 index)
 
 void LLRender::setAmbientLightColor(const LLColor4& color)
 {
+	LL_PROFILE_ZONE_SCOPED
 	if (color != mAmbientLightColor)
 	{
 		++mLightHash;
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index fc35590667..3d49a9eb78 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -2501,12 +2501,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);
diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp
index a590237440..33842497d1 100644
--- a/indra/newview/llviewerdisplay.cpp
+++ b/indra/newview/llviewerdisplay.cpp
@@ -208,9 +208,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;
@@ -219,6 +221,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;
@@ -228,6 +231,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();
     }
@@ -630,6 +634,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
@@ -722,6 +727,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;
@@ -777,6 +783,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());
@@ -825,7 +832,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 				LLImageGL::deleteDeadTextures();
 				stop_glerror();
 			}*/
-			}
+		}
 
 		LLGLState::checkStates();
 		LLGLState::checkClientArrays();
@@ -840,6 +847,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();
@@ -948,6 +956,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)
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index 1d13a306ef..2157585364 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -5280,6 +5280,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();
diff --git a/indra/newview/llworld.cpp b/indra/newview/llworld.cpp
index a1a1db35d6..c7b0a2bfb4 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 4e28c8c493..d7acf2ec0e 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -1897,6 +1897,7 @@ void LLPipeline::createObject(LLViewerObject* vobj)
 
 void LLPipeline::resetFrameStats()
 {
+	LL_PROFILE_ZONE_SCOPED
 	assertInitialized();
 
 	sCompiles        = 0;
@@ -2125,6 +2126,7 @@ void LLPipeline::grabReferences(LLCullResult& result)
 
 void LLPipeline::clearReferences()
 {
+	LL_PROFILE_ZONE_SCOPED
 	sCull = NULL;
 	mGroupSaveQ1.clear();
 }
diff --git a/indra/test/test.cpp b/indra/test/test.cpp
index 87c4a8d8a3..bb48216b2b 100644
--- a/indra/test/test.cpp
+++ b/indra/test/test.cpp
@@ -112,6 +112,7 @@ public:
 
 	virtual void recordMessage(LLError::ELevel level, const std::string& message)
 	{
+        LL_PROFILE_ZONE_SCOPED
 		mFile << message << std::endl;
 	}
 
-- 
cgit v1.2.3


From a184a0fbeea8a9dea855dc6e4fd29d81803fa738 Mon Sep 17 00:00:00 2001
From: "Brad Payne (Vir Linden)" <vir@lindenlab.com>
Date: Tue, 28 Sep 2021 20:10:06 +0100
Subject: SL-15999 - noninteractive mode: create minimal objects,load no
 textures

---
 indra/newview/llappviewer.cpp    |  2 ++
 indra/newview/lltexturefetch.cpp |  4 ++++
 indra/newview/llviewerobject.cpp | 29 ++++++++++++++++++-----------
 3 files changed, 24 insertions(+), 11 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index fb69f46bc5..1f59134679 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -2759,6 +2759,8 @@ bool LLAppViewer::initConfiguration()
 	if (gNonInteractive)
 	{
 		tempSetControl("SLURLPassToOtherInstance", "FALSE");
+		tempSetControl("RenderWater", "FALSE");
+		tempSetControl("FlyingAtExit", "FALSE");
 		llassert_always(!gSavedSettings.getBOOL("SLURLPassToOtherInstance"));
 	}
 
diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp
index f64db7beb5..9126360eed 100644
--- a/indra/newview/lltexturefetch.cpp
+++ b/indra/newview/lltexturefetch.cpp
@@ -1139,6 +1139,10 @@ void LLTextureFetchWorker::startWork(S32 param)
 // Threads:  Ttf
 bool LLTextureFetchWorker::doWork(S32 param)
 {
+	if (gNonInteractive)
+	{
+		return true;
+	}
 	static const LLCore::HttpStatus http_not_found(HTTP_NOT_FOUND);						// 404
 	static const LLCore::HttpStatus http_service_unavail(HTTP_SERVICE_UNAVAILABLE);		// 503
 	static const LLCore::HttpStatus http_not_sat(HTTP_REQUESTED_RANGE_NOT_SATISFIABLE);	// 416;
diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp
index 528448c477..0832415e1e 100644
--- a/indra/newview/llviewerobject.cpp
+++ b/indra/newview/llviewerobject.cpp
@@ -156,15 +156,25 @@ LLViewerObject *LLViewerObject::createObject(const LLUUID &id, const LLPCode pco
     
 	LLViewerObject *res = NULL;
 	LL_RECORD_BLOCK_TIME(FTM_CREATE_OBJECT);
-	
+
+	if (gNonInteractive
+		&& pcode != LL_PCODE_LEGACY_AVATAR
+		&& pcode != LL_VO_SURFACE_PATCH
+		&& pcode != LL_VO_WATER
+		&& pcode != LL_VO_VOID_WATER
+		&& pcode != LL_VO_WL_SKY
+		&& pcode != LL_VO_SKY
+		&& pcode != LL_VO_GROUND
+		&& pcode != LL_VO_PART_GROUP
+		)
+	{
+		return res;
+	}
 	switch (pcode)
 	{
 	case LL_PCODE_VOLUME:
 	{
-		if (!gNonInteractive)
-		{
-			res = new LLVOVolume(id, pcode, regionp); break;
-		}
+		res = new LLVOVolume(id, pcode, regionp); break;
 		break;
 	}
 	case LL_PCODE_LEGACY_AVATAR:
@@ -200,12 +210,9 @@ LLViewerObject *LLViewerObject::createObject(const LLUUID &id, const LLPCode pco
         }
 		else
 		{
-			if (!gNonInteractive)
-			{
-				LLVOAvatar *avatar = new LLVOAvatar(id, pcode, regionp); 
-				avatar->initInstance();
-				res = avatar;
-			}
+			LLVOAvatar *avatar = new LLVOAvatar(id, pcode, regionp); 
+			avatar->initInstance();
+			res = avatar;
 		}
 		break;
 	}
-- 
cgit v1.2.3


From 542f1917e9e963862088936b819fd9f0c1425541 Mon Sep 17 00:00:00 2001
From: "Brad Payne (Vir Linden)" <vir@lindenlab.com>
Date: Tue, 28 Sep 2021 20:20:23 +0100
Subject: SL-15999 - draw no objects when noninteractive

---
 indra/newview/llappviewer.cpp | 1 +
 indra/newview/pipeline.cpp    | 8 ++++----
 2 files changed, 5 insertions(+), 4 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 1f59134679..a146f72dde 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -2761,6 +2761,7 @@ bool LLAppViewer::initConfiguration()
 		tempSetControl("SLURLPassToOtherInstance", "FALSE");
 		tempSetControl("RenderWater", "FALSE");
 		tempSetControl("FlyingAtExit", "FALSE");
+		gPipeline.clearAllRenderTypes();
 		llassert_always(!gSavedSettings.getBOOL("SLURLPassToOtherInstance"));
 	}
 
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index 30703426ce..1730753eb1 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -487,10 +487,10 @@ void LLPipeline::init()
 	{
 		clearAllRenderTypes();
 	}
-	//else if (gSavedSettings.getBOOL("NonInteractive"))
-//	{
-	//	clearAllRenderTypes();
-	//}
+	else if (gNonInteractive)
+	{
+		clearAllRenderTypes();
+	}
 	else
 	{
 		setAllRenderTypes(); // By default, all rendering types start enabled
-- 
cgit v1.2.3


From 187d5862398820e28a8935ce9058f444f4963153 Mon Sep 17 00:00:00 2001
From: "Brad Payne (Vir Linden)" <vir@lindenlab.com>
Date: Tue, 28 Sep 2021 21:24:38 +0100
Subject: SL-15999 - noninteractive sessions disable logging

---
 indra/newview/llappviewer.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'indra')

diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index a146f72dde..5413045e7a 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -2761,7 +2761,7 @@ bool LLAppViewer::initConfiguration()
 		tempSetControl("SLURLPassToOtherInstance", "FALSE");
 		tempSetControl("RenderWater", "FALSE");
 		tempSetControl("FlyingAtExit", "FALSE");
-		gPipeline.clearAllRenderTypes();
+		LLError::setEnabledLogTypesMask(0);
 		llassert_always(!gSavedSettings.getBOOL("SLURLPassToOtherInstance"));
 	}
 
-- 
cgit v1.2.3


From 548bfda290b556d3ab29cc8c2f810f4cc349c9d8 Mon Sep 17 00:00:00 2001
From: Nat Goodspeed <nat@lindenlab.com>
Date: Tue, 28 Sep 2021 16:53:04 -0400
Subject: SL-16040: operator new() must never return nullptr.

---
 indra/llcommon/llcommon.cpp | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

(limited to 'indra')

diff --git a/indra/llcommon/llcommon.cpp b/indra/llcommon/llcommon.cpp
index da61e7539a..92f4d569b1 100644
--- a/indra/llcommon/llcommon.cpp
+++ b/indra/llcommon/llcommon.cpp
@@ -34,14 +34,13 @@
 #include "llcleanup.h"
 
 #if (TRACY_ENABLE)
-// Override new/delet for tracy memory profiling
+// Override new/delete for tracy memory profiling
 void *operator new(size_t size)
 {
     auto ptr = (malloc) (size);
     if (!ptr)
     {
         throw std::bad_alloc();
-        return nullptr;
     }
     TracyAlloc(ptr, size);
     return ptr;
-- 
cgit v1.2.3


From 851fef680164e3472b0516e7237bbcc4a35bc5a3 Mon Sep 17 00:00:00 2001
From: Callum Linden <callum@lindenlab.com>
Date: Tue, 28 Sep 2021 15:24:42 -0700
Subject: SL-16102 Set window title to agent name (child of SL-15999 Support
 for low overhead, non interactive viewer sessions)

---
 indra/llwindow/llwindow.cpp             |  6 ++++++
 indra/llwindow/llwindow.h               |  7 +++++++
 indra/llwindow/llwindowwin32.cpp        |  7 +++++++
 indra/llwindow/llwindowwin32.h          |  3 ++-
 indra/newview/app_settings/settings.xml | 11 +++++++++++
 indra/newview/llteleporthistory.cpp     | 27 +++++++++++++++++++++++++++
 6 files changed, 60 insertions(+), 1 deletion(-)

(limited to 'indra')

diff --git a/indra/llwindow/llwindow.cpp b/indra/llwindow/llwindow.cpp
index 30bc743e72..67ef98d7b3 100644
--- a/indra/llwindow/llwindow.cpp
+++ b/indra/llwindow/llwindow.cpp
@@ -137,6 +137,12 @@ BOOL LLWindow::canDelete()
 	return TRUE;
 }
 
+//virtual
+void LLWindow::setTitle(const std::string title)
+{
+    // the action happens in the platform specific impl
+}
+
 // virtual
 void LLWindow::incBusyCount()
 {
diff --git a/indra/llwindow/llwindow.h b/indra/llwindow/llwindow.h
index d4d5b76937..41eb1d7ee5 100644
--- a/indra/llwindow/llwindow.h
+++ b/indra/llwindow/llwindow.h
@@ -86,6 +86,13 @@ public:
 	virtual void showCursorFromMouseMove() = 0;
 	virtual void hideCursorUntilMouseMove() = 0;
 
+    // Provide a way to set the Viewer window title after the
+    // windows has been created. The initial use case for this
+    // is described in SL-16102 (update window title with agent 
+    // name, location etc. for non-interactive viewer) but it
+    // may also be useful in other cases.
+    virtual void setTitle(const std::string title);
+
 	// These two functions create a way to make a busy cursor instead
 	// of an arrow when someone's busy doing something. Draw an
 	// arrow/hour if busycount > 0.
diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp
index b2b123f0da..dc3e77cc57 100644
--- a/indra/llwindow/llwindowwin32.cpp
+++ b/indra/llwindow/llwindowwin32.cpp
@@ -1811,6 +1811,13 @@ void LLWindowWin32::moveWindow( const LLCoordScreen& position, const LLCoordScre
 	MoveWindow(mWindowHandle, position.mX, position.mY, size.mX, size.mY, TRUE);
 }
 
+void LLWindowWin32::setTitle(const std::string title)
+{
+    // TODO: Do we need to use the wide string version of this call
+    // to support non-ascii usernames (and region names??)
+    SetWindowTextA(mWindowHandle, title.c_str());
+}
+
 BOOL LLWindowWin32::setCursorPosition(const LLCoordWindow position)
 {
 	mMousePositionModified = TRUE;
diff --git a/indra/llwindow/llwindowwin32.h b/indra/llwindow/llwindowwin32.h
index 0b3d14fb16..34dcb7f268 100644
--- a/indra/llwindow/llwindowwin32.h
+++ b/indra/llwindow/llwindowwin32.h
@@ -58,7 +58,8 @@ public:
 	/*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*/ void setTitle(const std::string title);
+    /*virtual*/ BOOL setCursorPosition(LLCoordWindow position);
 	/*virtual*/ BOOL getCursorPosition(LLCoordWindow *position);
 	/*virtual*/ void showCursor();
 	/*virtual*/ void hideCursor();
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 6ff94e1afd..5987bc3ddf 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -16666,6 +16666,17 @@
       <key>Value</key>
       <integer>1</integer>        
     </map>
+    <key>UpdateAppWindowTitleBar</key>
+    <map>
+      <key>Comment</key>
+      <string>Updates the application window title bar with brief information about user/location</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>Boolean</string>
+      <key>Value</key>
+      <integer>0</integer>
+    </map>
 </map>
 </llsd>
 
diff --git a/indra/newview/llteleporthistory.cpp b/indra/newview/llteleporthistory.cpp
index 3c3c1c96ef..b872053d3f 100644
--- a/indra/newview/llteleporthistory.cpp
+++ b/indra/newview/llteleporthistory.cpp
@@ -39,6 +39,11 @@
 #include "llviewerregion.h"
 #include "llworldmap.h"
 #include "llagentui.h"
+#include "llwindow.h"
+#include "llviewerwindow.h"
+#include "llavatarname.h"
+#include "llavatarnamecache.h"
+
 
 //////////////////////////////////////////////////////////////////////////////
 // LLTeleportHistoryItem
@@ -174,6 +179,28 @@ void LLTeleportHistory::updateCurrentLocation(const LLVector3d& new_pos)
 	if (!mGotInitialUpdate)
 		mGotInitialUpdate = true;
 
+    // update Viewer window title with username and region name
+    // if we are in "non-interactive mode" (SL-15999) or the debug 
+    // setting to allow it is enabled (may be useful in other situations)
+    if (gNonInteractive || gSavedSettings.getBOOL("UpdateAppWindowTitleBar"))
+    {
+        LLAvatarName av_name;
+        if (LLAvatarNameCache::get(gAgent.getID(), &av_name))
+        {
+            if (gAgent.getRegion() && gViewerWindow && gViewerWindow->getWindow())
+            {
+                std::string region = gAgent.getRegion()->getName();
+                std::string username = av_name.getUserName();
+
+                // this first pass simply displays username and region name
+                // but could easily be extended to include other details like
+                // X/Y/Z location within a region etc.
+                std::string new_title = STRINGIZE(username << " @ " << region);
+                gViewerWindow->getWindow()->setTitle(new_title);
+            }
+        }
+    }
+
 	// Signal the interesting party that we've changed. 
 	onHistoryChanged();
 }
-- 
cgit v1.2.3


From db86ec9176dcbfabe5fddb3603da4132443f8b7f Mon Sep 17 00:00:00 2001
From: Nat Goodspeed <nat@lindenlab.com>
Date: Tue, 28 Sep 2021 22:09:02 -0400
Subject: SL-16040: _aligned_malloc() and _aligned_free() are Microsoft only.

Fortunately we already have platform-independent wrappers in llmemory.h.
---
 indra/llcommon/llcommon.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

(limited to 'indra')

diff --git a/indra/llcommon/llcommon.cpp b/indra/llcommon/llcommon.cpp
index 92f4d569b1..5d4a623bf6 100644
--- a/indra/llcommon/llcommon.cpp
+++ b/indra/llcommon/llcommon.cpp
@@ -61,7 +61,7 @@ void operator delete(void *ptr) noexcept
 
 void *tracy_aligned_malloc(size_t size, size_t alignment)
 {
-    auto ptr = (_aligned_malloc) (size, alignment);
+    auto ptr = ll_aligned_malloc_fallback(size, alignment);
     if (ptr) TracyAlloc(ptr, size);
     return ptr;
 }
@@ -69,7 +69,7 @@ void *tracy_aligned_malloc(size_t size, size_t alignment)
 void tracy_aligned_free(void *memblock)
 {
     TracyFree(memblock);
-    (_aligned_free)(memblock);
+    ll_aligned_free_fallback(memblock);
 }
 
 #endif
-- 
cgit v1.2.3


From 391500b5f7f2fb251acdd192d80e1da7eea02c4c Mon Sep 17 00:00:00 2001
From: Mnikolenko Productengine <mnikolenko@productengine.com>
Date: Wed, 29 Sep 2021 12:37:57 +0300
Subject: SL-16034 Disable all displays and UI in noninteractive mode

---
 indra/newview/llappviewer.cpp     | 4 ++--
 indra/newview/llviewerdisplay.cpp | 6 ++++--
 indra/newview/llviewerwindow.cpp  | 7 +++++++
 3 files changed, 13 insertions(+), 4 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 5413045e7a..9a8b773a66 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -2632,9 +2632,10 @@ bool LLAppViewer::initConfiguration()
 		disableCrashlogger();
 	}
 
+	gNonInteractive = gSavedSettings.getBOOL("NonInteractive");
 	// Handle initialization from settings.
 	// Start up the debugging console before handling other options.
-	if (gSavedSettings.getBOOL("ShowConsoleWindow"))
+	if (gSavedSettings.getBOOL("ShowConsoleWindow") && !gNonInteractive)
 	{
 		initConsole();
 	}
@@ -2755,7 +2756,6 @@ bool LLAppViewer::initConfiguration()
 		}
 	}
 
-	gNonInteractive = gSavedSettings.getBOOL("NonInteractive");
 	if (gNonInteractive)
 	{
 		tempSetControl("SLURLPassToOtherInstance", "FALSE");
diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp
index 109dc93261..a2f3554123 100644
--- a/indra/newview/llviewerdisplay.cpp
+++ b/indra/newview/llviewerdisplay.cpp
@@ -124,7 +124,8 @@ void display_startup()
 	if (   !gViewerWindow
 		|| !gViewerWindow->getActive()
 		|| !gViewerWindow->getWindow()->getVisible() 
-		|| gViewerWindow->getWindow()->getMinimized() )
+		|| gViewerWindow->getWindow()->getMinimized()
+		|| gNonInteractive)
 	{
 		return; 
 	}
@@ -309,7 +310,8 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 	// Attempting to draw into a minimized window causes a GL error. JC
 	if (   !gViewerWindow->getActive()
 		|| !gViewerWindow->getWindow()->getVisible() 
-		|| gViewerWindow->getWindow()->getMinimized() )
+		|| gViewerWindow->getWindow()->getMinimized() 
+		|| gNonInteractive)
 	{
 		// Clean up memory the pools may have allocated
 		if (rebuild)
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index 1d13a306ef..86ef4e66fb 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -2188,6 +2188,13 @@ void LLViewerWindow::initBase()
 
 void LLViewerWindow::initWorldUI()
 {
+	if (gNonInteractive)
+	{
+		gIMMgr = LLIMMgr::getInstance();
+		gFloaterView->pushVisibleAll(FALSE);
+		return;
+	}
+	
 	S32 height = mRootView->getRect().getHeight();
 	S32 width = mRootView->getRect().getWidth();
 	LLRect full_window(0, height, width, 0);
-- 
cgit v1.2.3


From e16105cab07047cadf0f5a4eae9335c066b5053c Mon Sep 17 00:00:00 2001
From: "Brad Payne (Vir Linden)" <vir@lindenlab.com>
Date: Wed, 29 Sep 2021 12:14:51 +0100
Subject: SL-15999 - don't create floaters in noninteractive mode

---
 indra/newview/llviewerfloaterreg.cpp |  4 ++++
 indra/newview/llviewermedia.cpp      |  2 +-
 indra/newview/llviewerwindow.cpp     | 46 ++++++++++++++++++++----------------
 indra/newview/pipeline.cpp           |  5 +++-
 4 files changed, 35 insertions(+), 22 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp
index 5a05f89758..98b76328de 100644
--- a/indra/newview/llviewerfloaterreg.cpp
+++ b/indra/newview/llviewerfloaterreg.cpp
@@ -192,6 +192,10 @@ LLFloaterOpenHandler gFloaterOpenHandler;
 
 void LLViewerFloaterReg::registerFloaters()
 {
+	if (gNonInteractive)
+	{
+		return;
+	}
 	// *NOTE: Please keep these alphabetized for easier merges
 
 	LLFloaterAboutUtil::registerFloater();
diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp
index 8064e998f1..c347e0eb76 100644
--- a/indra/newview/llviewermedia.cpp
+++ b/indra/newview/llviewermedia.cpp
@@ -1216,7 +1216,7 @@ LLCore::HttpHeaders::ptr_t LLViewerMedia::getHttpHeaders()
 /////////////////////////////////////////////////////////////////////////////////////////
 void LLViewerMedia::setOpenIDCookie(const std::string& url)
 {
-	if(!mOpenIDCookie.empty())
+	if(!gNonInteractive && !mOpenIDCookie.empty())
 	{
         std::string profileUrl = getProfileURL("");
 
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index 1d13a306ef..20bb65760c 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -2198,12 +2198,15 @@ void LLViewerWindow::initWorldUI()
 	//getRootView()->sendChildToFront(gFloaterView);
 	//getRootView()->sendChildToFront(gSnapshotFloaterView);
 
-	LLPanel* chiclet_container = getRootView()->getChild<LLPanel>("chiclet_container");
-	LLChicletBar* chiclet_bar = LLChicletBar::getInstance();
-	chiclet_bar->setShape(chiclet_container->getLocalRect());
-	chiclet_bar->setFollowsAll();
-	chiclet_container->addChild(chiclet_bar);
-	chiclet_container->setVisible(TRUE);
+	if (!gNonInteractive)
+	{
+		LLPanel* chiclet_container = getRootView()->getChild<LLPanel>("chiclet_container");
+		LLChicletBar* chiclet_bar = LLChicletBar::getInstance();
+		chiclet_bar->setShape(chiclet_container->getLocalRect());
+		chiclet_bar->setFollowsAll();
+		chiclet_container->addChild(chiclet_bar);
+		chiclet_container->setVisible(TRUE);
+	}
 
 	LLRect morph_view_rect = full_window;
 	morph_view_rect.stretch( -STATUS_BAR_HEIGHT );
@@ -2292,21 +2295,24 @@ void LLViewerWindow::initWorldUI()
 		gToolBarView->setVisible(TRUE);
 	}
 
-	LLMediaCtrl* destinations = LLFloaterReg::getInstance("destinations")->getChild<LLMediaCtrl>("destination_guide_contents");
-	if (destinations)
-	{
-		destinations->setErrorPageURL(gSavedSettings.getString("GenericErrorPageURL"));
-		std::string url = gSavedSettings.getString("DestinationGuideURL");
-		url = LLWeb::expandURLSubstitutions(url, LLSD());
-		destinations->navigateTo(url, HTTP_CONTENT_TEXT_HTML);
-	}
-	LLMediaCtrl* avatar_picker = LLFloaterReg::getInstance("avatar")->findChild<LLMediaCtrl>("avatar_picker_contents");
-	if (avatar_picker)
+	if (!gNonInteractive)
 	{
-		avatar_picker->setErrorPageURL(gSavedSettings.getString("GenericErrorPageURL"));
-		std::string url = gSavedSettings.getString("AvatarPickerURL");
-		url = LLWeb::expandURLSubstitutions(url, LLSD());
-		avatar_picker->navigateTo(url, HTTP_CONTENT_TEXT_HTML);
+		LLMediaCtrl* destinations = LLFloaterReg::getInstance("destinations")->getChild<LLMediaCtrl>("destination_guide_contents");
+		if (destinations)
+		{
+			destinations->setErrorPageURL(gSavedSettings.getString("GenericErrorPageURL"));
+			std::string url = gSavedSettings.getString("DestinationGuideURL");
+			url = LLWeb::expandURLSubstitutions(url, LLSD());
+			destinations->navigateTo(url, HTTP_CONTENT_TEXT_HTML);
+		}
+		LLMediaCtrl* avatar_picker = LLFloaterReg::getInstance("avatar")->findChild<LLMediaCtrl>("avatar_picker_contents");
+		if (avatar_picker)
+		{
+			avatar_picker->setErrorPageURL(gSavedSettings.getString("GenericErrorPageURL"));
+			std::string url = gSavedSettings.getString("AvatarPickerURL");
+			url = LLWeb::expandURLSubstitutions(url, LLSD());
+			avatar_picker->navigateTo(url, HTTP_CONTENT_TEXT_HTML);
+		}
 	}
 }
 
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index 1730753eb1..ad401b6db4 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -4004,7 +4004,10 @@ void LLPipeline::postSort(LLCamera& camera)
 	{
 		mSelectedFaces.clear();
 
-		LLPipeline::setRenderHighlightTextureChannel(gFloaterTools->getPanelFace()->getTextureChannelToEdit());
+		if (!gNonInteractive)
+		{
+			LLPipeline::setRenderHighlightTextureChannel(gFloaterTools->getPanelFace()->getTextureChannelToEdit());
+		}
 
 		// Draw face highlights for selected faces.
 		if (LLSelectMgr::getInstance()->getTEMode())
-- 
cgit v1.2.3


From 3c4198e4b50de0221020f3b5bbf7d3f7ff7cf984 Mon Sep 17 00:00:00 2001
From: "Brad Payne (Vir Linden)" <vir@lindenlab.com>
Date: Wed, 29 Sep 2021 16:50:32 +0100
Subject: SL-15999 - noninteractive sessions should quit cleanly when they get
 a close message. Removed some possible crashes

---
 indra/newview/llappviewer.cpp       |  2 ++
 indra/newview/lldynamictexture.cpp  |  7 +++++--
 indra/newview/llviewermessage.cpp   |  4 ++++
 indra/newview/llviewerwindow.cpp    | 13 ++++++++++---
 indra/newview/llworldmapmessage.cpp |  4 ++++
 5 files changed, 25 insertions(+), 5 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 5413045e7a..bd1b30b4a1 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -2761,6 +2761,8 @@ bool LLAppViewer::initConfiguration()
 		tempSetControl("SLURLPassToOtherInstance", "FALSE");
 		tempSetControl("RenderWater", "FALSE");
 		tempSetControl("FlyingAtExit", "FALSE");
+		tempSetControl("WindowWidth", "1024");
+		tempSetControl("WindowHeight", "200");
 		LLError::setEnabledLogTypesMask(0);
 		llassert_always(!gSavedSettings.getBOOL("SLURLPassToOtherInstance"));
 	}
diff --git a/indra/newview/lldynamictexture.cpp b/indra/newview/lldynamictexture.cpp
index 8b8273d183..31ca2531ba 100644
--- a/indra/newview/lldynamictexture.cpp
+++ b/indra/newview/lldynamictexture.cpp
@@ -119,8 +119,11 @@ BOOL LLViewerDynamicTexture::render()
 void LLViewerDynamicTexture::preRender(BOOL clear_depth)
 {
 	gPipeline.allocatePhysicsBuffer();
-	llassert(mFullWidth <= static_cast<S32>(gPipeline.mPhysicsDisplay.getWidth()));
-	llassert(mFullHeight <= static_cast<S32>(gPipeline.mPhysicsDisplay.getHeight()));
+	if (!gNonInteractive)
+	{
+		llassert(mFullWidth <= static_cast<S32>(gPipeline.mPhysicsDisplay.getWidth()));
+		llassert(mFullHeight <= static_cast<S32>(gPipeline.mPhysicsDisplay.getHeight()));
+	}
 
 	if (gGLManager.mHasFramebufferObject && gPipeline.mPhysicsDisplay.isComplete() && !gGLManager.mIsATI)
 	{ //using offscreen render target, just use the bottom left corner
diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp
index ab65d747ba..517e35d482 100644
--- a/indra/newview/llviewermessage.cpp
+++ b/indra/newview/llviewermessage.cpp
@@ -2423,6 +2423,10 @@ void translateFailure(LLChat chat, LLSD toastArgs, int status, const std::string
 
 void process_chat_from_simulator(LLMessageSystem *msg, void **user_data)
 {
+	if (gNonInteractive)
+	{
+		return;
+	}
 	LLChat	chat;
 	std::string		mesg;
 	std::string		from_name;
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index 20bb65760c..22279d0bf0 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -1516,8 +1516,15 @@ BOOL LLViewerWindow::handleCloseRequest(LLWindow *window)
 
 void LLViewerWindow::handleQuit(LLWindow *window)
 {
-	LL_INFOS() << "Window forced quit" << LL_ENDL;
-	LLAppViewer::instance()->forceQuit();
+	if (gNonInteractive)
+	{
+		LLAppViewer::instance()->requestQuit();
+	}
+	else
+	{
+		LL_INFOS() << "Window forced quit" << LL_ENDL;
+		LLAppViewer::instance()->forceQuit();
+	}
 }
 
 void LLViewerWindow::handleResize(LLWindow *window,  S32 width,  S32 height)
@@ -2556,7 +2563,7 @@ void LLViewerWindow::reshape(S32 width, S32 height)
 			mWindow->setMinSize(min_window_width, min_window_height);
 
 			LLCoordScreen window_rect;
-			if (mWindow->getSize(&window_rect))
+			if (!gNonInteractive && mWindow->getSize(&window_rect))
 			{
 			// Only save size if not maximized
 				gSavedSettings.setU32("WindowWidth", window_rect.mX);
diff --git a/indra/newview/llworldmapmessage.cpp b/indra/newview/llworldmapmessage.cpp
index 8be340de4c..e4a9f9afdb 100644
--- a/indra/newview/llworldmapmessage.cpp
+++ b/indra/newview/llworldmapmessage.cpp
@@ -150,6 +150,10 @@ void LLWorldMapMessage::sendMapBlockRequest(U16 min_x, U16 min_y, U16 max_x, U16
 // public static
 void LLWorldMapMessage::processMapBlockReply(LLMessageSystem* msg, void**)
 {
+	if (gNonInteractive)
+	{
+		return;
+	}
 	U32 agent_flags;
 	msg->getU32Fast(_PREHASH_AgentData, _PREHASH_Flags, agent_flags);
 
-- 
cgit v1.2.3


From a0881ccb272e90d5472e00d8883fcf3b69c7ee10 Mon Sep 17 00:00:00 2001
From: Mnikolenko Productengine <mnikolenko@productengine.com>
Date: Wed, 29 Sep 2021 21:04:46 +0300
Subject: SL-16034 init LLNavigationBar to allow setting title with location
 info later

---
 indra/newview/llviewerwindow.cpp | 1 +
 1 file changed, 1 insertion(+)

(limited to 'indra')

diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index bd22127a45..24cb138401 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -2198,6 +2198,7 @@ void LLViewerWindow::initWorldUI()
 	if (gNonInteractive)
 	{
 		gIMMgr = LLIMMgr::getInstance();
+		LLNavigationBar::getInstance();
 		gFloaterView->pushVisibleAll(FALSE);
 		return;
 	}
-- 
cgit v1.2.3


From 9561e986ce879833def4243700971fc53bd878d4 Mon Sep 17 00:00:00 2001
From: "Brad Payne (Vir Linden)" <vir@lindenlab.com>
Date: Wed, 29 Sep 2021 19:47:23 +0100
Subject: SL-15999 - force multiple viewers support for noninteractive mode

---
 indra/newview/llappviewer.cpp | 1 +
 1 file changed, 1 insertion(+)

(limited to 'indra')

diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index e1fbbf6ce5..41a83a1484 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -2758,6 +2758,7 @@ bool LLAppViewer::initConfiguration()
 
 	if (gNonInteractive)
 	{
+		tempSetControl("AllowMultipleViewers", "TRUE");
 		tempSetControl("SLURLPassToOtherInstance", "FALSE");
 		tempSetControl("RenderWater", "FALSE");
 		tempSetControl("FlyingAtExit", "FALSE");
-- 
cgit v1.2.3


From f3743b8e3092daabf5c5324626c4f04f36ff5bd7 Mon Sep 17 00:00:00 2001
From: Mnikolenko Productengine <mnikolenko@productengine.com>
Date: Fri, 1 Oct 2021 16:39:56 +0300
Subject: SL-15999 use callback for updating window title

---
 indra/newview/llteleporthistory.cpp | 30 +++++++++++++++---------------
 1 file changed, 15 insertions(+), 15 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llteleporthistory.cpp b/indra/newview/llteleporthistory.cpp
index b872053d3f..3ece12931c 100644
--- a/indra/newview/llteleporthistory.cpp
+++ b/indra/newview/llteleporthistory.cpp
@@ -118,6 +118,20 @@ void LLTeleportHistory::handleLoginComplete()
 	updateCurrentLocation(gAgent.getPositionGlobal());
 }
 
+static void on_avatar_name_update_title(const LLAvatarName& av_name)
+{
+	if (gAgent.getRegion() && gViewerWindow && gViewerWindow->getWindow())
+	{
+		std::string region = gAgent.getRegion()->getName();
+		std::string username = av_name.getUserName();
+
+		// this first pass simply displays username and region name
+		// but could easily be extended to include other details like
+		// X/Y/Z location within a region etc.
+		std::string new_title = STRINGIZE(username << " @ " << region);
+		gViewerWindow->getWindow()->setTitle(new_title);
+	}	
+}
 
 void LLTeleportHistory::updateCurrentLocation(const LLVector3d& new_pos)
 {
@@ -184,21 +198,7 @@ void LLTeleportHistory::updateCurrentLocation(const LLVector3d& new_pos)
     // setting to allow it is enabled (may be useful in other situations)
     if (gNonInteractive || gSavedSettings.getBOOL("UpdateAppWindowTitleBar"))
     {
-        LLAvatarName av_name;
-        if (LLAvatarNameCache::get(gAgent.getID(), &av_name))
-        {
-            if (gAgent.getRegion() && gViewerWindow && gViewerWindow->getWindow())
-            {
-                std::string region = gAgent.getRegion()->getName();
-                std::string username = av_name.getUserName();
-
-                // this first pass simply displays username and region name
-                // but could easily be extended to include other details like
-                // X/Y/Z location within a region etc.
-                std::string new_title = STRINGIZE(username << " @ " << region);
-                gViewerWindow->getWindow()->setTitle(new_title);
-            }
-        }
+		LLAvatarNameCache::get(gAgent.getID(), boost::bind(&on_avatar_name_update_title, _2));
     }
 
 	// Signal the interesting party that we've changed. 
-- 
cgit v1.2.3


From 2148e4c731e1c0926c32fedb3e7047c96cd9eebf Mon Sep 17 00:00:00 2001
From: Dave Parks <davep@lindenlab.com>
Date: Fri, 1 Oct 2021 15:51:12 +0000
Subject: SL-16094 Move LLWindowWin32::mainWindowProc and Windows message
 handling to a background thread to prevent  frame stalls in
 LLWindowWin32::gatherInput

---
 indra/llwindow/llwindowwin32.cpp | 2580 +++++++++++++++++++++-----------------
 indra/llwindow/llwindowwin32.h   |   46 +-
 2 files changed, 1495 insertions(+), 1131 deletions(-)

(limited to 'indra')

diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp
index 714e07da31..4ce7c30bef 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 @@ private:
 
 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");
 
@@ -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);
@@ -1816,31 +1903,41 @@ void LLWindowWin32::moveWindow( const LLCoordScreen& position, const LLCoordScre
 
 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 
@@ -1856,21 +1953,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;
 }
@@ -1972,6 +2083,8 @@ void LLWindowWin32::initCursors()
 
 void LLWindowWin32::updateCursor()
 {
+    ASSERT_MAIN_THREAD();
+    LL_PROFILE_ZONE_SCOPED
 	if (mNextCursor == UI_CURSOR_ARROW
 		&& mBusyCount > 0)
 	{
@@ -1981,7 +2094,11 @@ void LLWindowWin32::updateCursor()
 	if( mCurrentCursor != mNextCursor )
 	{
 		mCurrentCursor = mNextCursor;
-		SetCursor( mCursor[mNextCursor] );
+        auto nextCursor = mCursor[mNextCursor];
+        mWindowThread->post([=]()
+            {
+                SetCursor(nextCursor);
+            });
 	}
 }
 
@@ -1997,13 +2114,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);
 }
 
 
@@ -2012,1003 +2124,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;
+
+    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;
+            }
+        }
 
-		// turn watchdog off in here to not fail if windows is doing something wacky
-		mCallbacks->handlePauseWatchdog(this);
-		DispatchMessage(&msg);
-		mCallbacks->handleResumeWatchdog(this);
-		msg_count++;
+        {
+            LL_PROFILE_ZONE_NAMED("gi - translate");
+            TranslateMessage(&msg);
+        }
 
-		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 - dispatch");
+            DispatchMessage(&msg);
+        }
 
-		BOOL key_posted = TranslateMessage(&msg);
-		DispatchMessage(&msg);
-		msg_count++;
+        if (mInputProcessingPaused)
+        {
+            break;
+        }
 
-		// If a key was translated, a WM_CHAR might have been posted to the end
-		// of the event queue.  We need it immediately.
-		if (key_posted && msg.message == WM_KEYDOWN)
-		{
-			if (PeekMessage(&msg, NULL, WM_CHAR, WM_CHAR, PM_REMOVE))
-			{
-				TranslateMessage(&msg);
-				DispatchMessage(&msg);
-				msg_count++;
-			}
-		}
-		*/
-		mCallbacks->handlePingWatchdog(this, "Main:AsyncCallbackGatherInput");
-		// For async host by name support.  Really hacky.
-		if (gAsyncMsgCallback && (LL_WM_HOST_RESOLVED == msg.message))
-		{
-			gAsyncMsgCallback(msg);
-		}
-	}
+        // For async host by name support.  Really hacky.
+        if (gAsyncMsgCallback && (LL_WM_HOST_RESOLVED == msg.message))
+        {
+            LL_PROFILE_ZONE_NAMED("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;
+    ASSERT_WINDOW_THREAD();
+    LL_PROFILE_ZONE_SCOPED;
 
-	// 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;
+    // 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;
 
-	LLWindowWin32 *window_imp = (LLWindowWin32 *)GetWindowLongPtr( h_wnd, GWLP_USERDATA );
+    // 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;
 
-	bool debug_window_proc = gDebugWindowProc || debugLoggingEnabled("Window");
+    LLWindowWin32* window_imp = (LLWindowWin32*)GetWindowLongPtr(h_wnd, GWLP_USERDATA);
 
+    bool debug_window_proc = false; // gDebugWindowProc || debugLoggingEnabled("Window");
 
-	if (NULL != window_imp)
-	{
-		window_imp->mCallbacks->handleResumeWatchdog(window_imp);
-		window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:StartWndProc");
-		// Has user provided their own window callback?
-		if (NULL != window_imp->mWndProc)
-		{
-			if (!window_imp->mWndProc(h_wnd, u_msg, w_param, l_param))
-			{
-				// user has handled window message
-				return 0;
-			}
-		}
+    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;
+            }
+        }
 
-		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));
+        // 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;
+        // 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;
+        // 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;
+        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_TIMER:
+        {
+            LL_PROFILE_ZONE_NAMED("mwp - WM_TIMER");
+            WINDOW_IMP_POST(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;
-
-		case WM_IME_REQUEST:
-			window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_IME_REQUEST");
-			if (debug_window_proc)
-			{
-				LL_INFOS() << "WM_IME_REQUEST" << LL_ENDL;
-			}
-			if (LLWinImm::isAvailable() && window_imp->mPreeditor)
-			{
-				LRESULT result = 0;
-				if (window_imp->handleImeRequests(w_param, l_param, &result))
-				{
-					return result;
-				}
-			}
-			break;
-
-		case WM_CHAR:
-			window_imp->mKeyCharCode = w_param;
-			window_imp->mRawMsg = u_msg;
-			window_imp->mRawWParam = w_param;
-			window_imp->mRawLParam = l_param;
-
-			// Should really use WM_UNICHAR eventually, but it requires a specific Windows version and I need
-			// to figure out how that works. - Doug
-			//
-			// ... Well, I don't think so.
-			// How it works is explained in Win32 API document, but WM_UNICHAR didn't work
-			// as specified at least on Windows XP SP1 Japanese version.  I have never used
-			// it since then, and I'm not sure whether it has been fixed now, but I don't think
-			// it is worth trying.  The good old WM_CHAR works just fine even for supplementary
-			// characters.  We just need to take care of surrogate pairs sent as two WM_CHAR's
-			// by ourselves.  It is not that tough.  -- Alissa Sabre @ SL
-			window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_CHAR");
-			if (debug_window_proc)
-			{
-				LL_INFOS("Window") << "Debug WindowProc WM_CHAR "
-					<< " key " << S32(w_param) 
-					<< LL_ENDL;
-			}
-			// Even if LLWindowCallbacks::handleUnicodeChar(llwchar, BOOL) returned FALSE,
-			// we *did* processed the event, so I believe we should not pass it to DefWindowProc...
-			window_imp->handleUnicodeUTF16((U16)w_param, gKeyboard->currentMask(FALSE));
-			return 0;
+        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;
+        }
 
-		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;
+        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_LBUTTONDOWN:
-			{
-				window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_LBUTTONDOWN");
-				LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER);
-				sHandleLeftMouseUp = true;
+        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 (LLWinImm::isAvailable() && window_imp->mPreeditor)
-				{
-					window_imp->interruptLanguageTextInput();
-				}
+            // 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;
+        }
 
-				// Because we move the cursor position in the app, we need to query
-				// to find out where the cursor at the time the event is handled.
-				// If we don't do this, many clicks could get buffered up, and if the
-				// first click changes the cursor position, all subsequent clicks
-				// will occur at the wrong location.  JC
-				if (window_imp->mMousePositionModified)
-				{
-					LLCoordWindow cursor_coord_window;
-					window_imp->getCursorPosition(&cursor_coord_window);
-					gl_coord = cursor_coord_window.convert();
-				}
-				else
-				{
-					gl_coord = window_coord.convert();
-				}
-				MASK mask = gKeyboard->currentMask(TRUE);
-				// generate move event to update mouse coordinates
-				window_imp->mCallbacks->handleMouseMove(window_imp, gl_coord, mask);
-				if (window_imp->mCallbacks->handleMouseDown(window_imp, gl_coord, mask))
-				{
-					return 0;
-				}
-			}
-			break;
+        case WM_EXITMENULOOP:
+        {
+            LL_PROFILE_ZONE_NAMED("mwp - WM_EXITMENULOOP");
+            WINDOW_IMP_POST(window_imp->mCallbacks->handleWindowUnblock(window_imp));
+            break;
+        }
 
-		case WM_LBUTTONDBLCLK:
-		//RN: ignore right button double clicks for now
-		//case WM_RBUTTONDBLCLK:
-			{
-				window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_LBUTTONDBLCLK");
+        case WM_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;
+        }
 
-				if (!sHandleDoubleClick)
-				{
-					sHandleDoubleClick = true;
-					break;
-				}
+        case WM_QUERYOPEN:
+            // TODO: use this to return a nice icon
+            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_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;
+        }
 
-		case WM_LBUTTONUP:
-			{
-				window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_LBUTTONUP");
-				LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER);
+        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;
+            }
 
-				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;
+            // 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;
 
-		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_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;
 
-				// 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_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_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_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;
 
-		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_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;
 
-				// 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:
+        {
+            LL_PROFILE_ZONE_NAMED("mwp - WM_MOUSEWHEEL");
+            static short z_delta = 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();
-				}
+            RECT	client_rect;
 
-				// 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;
+            // 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_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;
+            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_MOUSEWHEEL:
-			{
-				window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_MOUSEWHEEL");
-				static short z_delta = 0;
+            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;
 
-				RECT	client_rect;
+            RECT	client_rect;
 
-				// 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)};
+            // 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 (ScreenToClient(window_imp->mWindowHandle, &mouse_coord)
-					&& GetClientRect(window_imp->mWindowHandle, &client_rect))
-				{
-					// we have a valid mouse point and client rect
-					if (mouse_coord.x < client_rect.left || client_rect.right < mouse_coord.x
-						|| mouse_coord.y < client_rect.top || client_rect.bottom < mouse_coord.y)
-					{
-						// mouse is outside of client rect, so don't do anything
-						return 0;
-					}
-				}
+            if (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;
+                }
+            }
 
-				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;
+            S16 incoming_h_delta = HIWORD(w_param);
+            h_delta += incoming_h_delta;
 
-				RECT	client_rect;
+            // 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;
+        }
 
-				// 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_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;
+        }
 
-				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_SIZE:
+        {
+            LL_PROFILE_ZONE_NAMED("mwp - WM_SIZE");
+            S32 width = S32(LOWORD(l_param));
+            S32 height = S32(HIWORD(l_param));
 
-				S16 incoming_h_delta = HIWORD(w_param);
-				h_delta += incoming_h_delta;
+            if (debug_window_proc)
+            {
+                BOOL maximized = (w_param == SIZE_MAXIMIZED);
+                BOOL restored = (w_param == SIZE_RESTORED);
+                BOOL minimized = (w_param == SIZE_MINIMIZED);
+
+                LL_INFOS("Window") << "WINDOWPROC Size "
+                    << width << "x" << height
+                    << " max " << S32(maximized)
+                    << " min " << S32(minimized)
+                    << " rest " << S32(restored)
+                    << LL_ENDL;
+            }
 
-				// If 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;
-			}
+            // 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_GETMINMAXINFO:
-			{
-				LPMINMAXINFO min_max = (LPMINMAXINFO)l_param;
-				min_max->ptMinTrackSize.x = window_imp->mMinWindowWidth;
-				min_max->ptMinTrackSize.y = window_imp->mMinWindowHeight;
-				return 0;
-			}
+            // 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));
+            }
 
-		case WM_SIZE:
-			{
-				window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_SIZE");
-				S32 width = S32( LOWORD(l_param) );
-				S32 height = S32( 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));
+            }
 
-				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;
-				}
+            // 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));
+            }
 
-				// 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). 
+            // 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)));
+            }
 
-				// 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);
-				}
+            window_imp->mLastSizeWParam = w_param;
 
-				// 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);
-				}
+            return 0;
+        }
 
-				// Also handle the minimization case
-				if (w_param == SIZE_MINIMIZED && window_imp->mLastSizeWParam != SIZE_MINIMIZED)
-				{
-					window_imp->mCallbacks->handleActivate(window_imp, FALSE);
-				}
+        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;
+        }
 
-				// 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) );
-				}
+        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;
+        }
 
-				window_imp->mLastSizeWParam = w_param;
+        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;
+        }
 
-				return 0;
-			}
+        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;
         
-		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;
-			}
-
-		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;
-
-		case WM_KILLFOCUS:
-			if (debug_window_proc)
-			{
-				LL_INFOS("Window") << "WINDOWPROC KillFocus" << LL_ENDL;
-			}
-			window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_KILLFOCUS");
-			window_imp->mCallbacks->handleFocusLost(window_imp);
-			return 0;
-
-		case WM_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;			
-
-			break;
-
-		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;
-		}
-
-	window_imp->mCallbacks->handlePauseWatchdog(window_imp);	
-	}
+        //list of messages we get often that we don't care to log about
+        case WM_NCHITTEST:
+        case WM_NCMOUSEMOVE:
+        case WM_NCMOUSELEAVE:
+        case WM_MOVING:
+        case WM_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)
@@ -3187,6 +3425,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;
@@ -3263,6 +3503,7 @@ F32 LLWindowWin32::getGamma()
 
 BOOL LLWindowWin32::restoreGamma()
 {
+    ASSERT_MAIN_THREAD();
 	if (mCustomGammaSet != FALSE)
 	{
         LL_DEBUGS("Window") << "Restoring gamma" << LL_ENDL;
@@ -3274,6 +3515,7 @@ BOOL LLWindowWin32::restoreGamma()
 
 BOOL LLWindowWin32::setGamma(const F32 gamma)
 {
+    ASSERT_MAIN_THREAD();
 	mCurrentGamma = gamma;
 
 	//Get the previous gamma ramp to restore later.
@@ -3312,6 +3554,7 @@ BOOL LLWindowWin32::setGamma(const F32 gamma)
 
 void LLWindowWin32::setFSAASamples(const U32 fsaa_samples)
 {
+    ASSERT_MAIN_THREAD();
 	mFSAASamples = fsaa_samples;
 }
 
@@ -3322,6 +3565,7 @@ U32 LLWindowWin32::getFSAASamples()
 
 LLWindow::LLWindowResolution* LLWindowWin32::getSupportedResolutions(S32 &num_resolutions)
 {
+    ASSERT_MAIN_THREAD();
 	if (!mSupportedResolutions)
 	{
 		mSupportedResolutions = new LLWindowResolution[MAX_NUM_RESOLUTIONS];
@@ -3476,6 +3720,7 @@ BOOL LLWindowWin32::resetDisplayResolution()
 
 void LLWindowWin32::swapBuffers()
 {
+    ASSERT_MAIN_THREAD();
 	SwapBuffers(mhDC);
 
     LL_PROFILER_GPU_COLLECT
@@ -3951,6 +4196,7 @@ void LLWindowWin32::updateLanguageTextInputArea()
 
 void LLWindowWin32::interruptLanguageTextInput()
 {
+    ASSERT_MAIN_THREAD();
 	if (mPreeditor && LLWinImm::isAvailable())
 	{
 		HIMC himc = LLWinImm::getContext(mWindowHandle);
@@ -4153,6 +4399,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 );
 }
 
@@ -4201,6 +4448,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;
@@ -4408,3 +4656,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
+}
\ No newline at end of file
diff --git a/indra/llwindow/llwindowwin32.h b/indra/llwindow/llwindowwin32.h
index 0b3d14fb16..66647459b2 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:
@@ -172,9 +207,9 @@ protected:
 	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()
@@ -221,7 +256,12 @@ protected:
 
 	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
-- 
cgit v1.2.3


From 7c9aeed97d4ba3641971b9a1a92d334ec0adbb09 Mon Sep 17 00:00:00 2001
From: Nat Goodspeed <nat@lindenlab.com>
Date: Fri, 1 Oct 2021 16:05:23 -0400
Subject: SL-16024: Enhance LLThreadSafeQueue for use with WorkQueue.

First, parameterize LLThreadSafeQueue's queue type. This allows us to
substitute (e.g.) a std::priority_queue for a particular instance.

Use std::queue for the default queue type, changing the operations invoked on
the queue type from std::deque methods to std::queue methods.

Rename published methods from (e.g.) pushFront() and popBack() to simple
push() and pop(), retaining legacy names as aliases. Not only are the overt
Front and Back unnecessary; they're the opposite of how std::queue uses
std::deque or std::list, so they only confuse the reader.

Break out tryPushUntil() method. We already use that logic internally to
tryPushFor(), so it's just as easy to publish it as its own entry point.

Add tryPopFor() and tryPopUntil() to allow limiting the time we'll wait for a
queue item to become available.
---
 indra/llcommon/llthreadsafequeue.h | 229 ++++++++++++++++++++++++++-----------
 1 file changed, 163 insertions(+), 66 deletions(-)

(limited to 'indra')

diff --git a/indra/llcommon/llthreadsafequeue.h b/indra/llcommon/llthreadsafequeue.h
index 26e0d71d31..04f51816d7 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,15 +27,15 @@
 #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>
 
 //
 // A general queue exception.
@@ -66,61 +66,95 @@ public:
 	}
 };
 
-//
-// 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.
 	LLThreadSafeQueue(U32 capacity = 1024);
-	
-	// Add an element to the front of queue (will block if the queue has
+
+	// 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
+	void push(ElementT const& 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);
+	bool tryPush(ElementT const& 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>
+	bool tryPushFor(const std::chrono::duration<Rep, Period>& timeout,
+					ElementT const & element);
+	// legacy name
+	template <typename Rep, typename Period>
 	bool tryPushFrontFor(const std::chrono::duration<Rep, Period>& timeout,
-						 ElementT const & element);
+						 ElementT const & element) { return tryPushFor(timeout, element); }
+
+	// Try to add an element to the queue, blocking if full but with
+	// timeout at specified time_point. Returns true if the element was added.
+	template <typename Clock, typename Duration>
+	bool tryPushUntil(const std::chrono::time_point<Clock, Duration>& timeout,
+					  ElementT const& element);
+	// no legacy name because this is a newer method
 
-	// Pop the element at the end of the queue (will block if the queue is
+	// Pop the element at the head of the queue (will block if the queue is
 	// empty).
 	//
 	// This call will raise an interrupt error if the queue is closed while
 	// the caller is blocked.
-	ElementT popBack(void);
-	
-	// Pop an element from the end of the queue if there is one available.
+	ElementT pop(void);
+	// legacy name
+	ElementT popBack(void) { return pop(); }
+
+	// Pop an element from the head of the queue if there is one available.
 	// Returns true only if an element was popped.
-	bool tryPopBack(ElementT & element);
-	
+	bool tryPop(ElementT & element);
+	// legacy name
+	bool tryPopBack(ElementT & element) { return tryPop(element); }
+
+	// Pop the element at the head of the queue, blocking if empty, with
+	// timeout after specified duration. Returns true if an element was popped.
+	template <typename Rep, typename Period>
+	bool tryPopFor(const std::chrono::duration<Rep, Period>& timeout, ElementT& element);
+	// no legacy name because this is a newer method
+
+	// Pop the element at the head of the queue, blocking if empty, with
+	// timeout at specified time_point. Returns true if an element was popped.
+	template <typename Clock, typename Duration>
+	bool tryPopUntil(const std::chrono::time_point<Clock, Duration>& timeout,
+					 ElementT& element);
+	// no legacy name because this is a newer method
+
 	// Returns the size of the queue.
 	size_t size();
 
 	// 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
@@ -128,8 +162,9 @@ public:
 	// inverse of isClosed()
 	explicit operator bool();
 
-private:
-	std::deque< ElementT > mStorage;
+protected:
+	typedef QueueT queue_type;
+	QueueT mStorage;
 	U32 mCapacity;
 	bool mClosed;
 
@@ -142,16 +177,16 @@ private:
 // LLThreadSafeQueue
 //-----------------------------------------------------------------------------
 
-template<typename ElementT>
-LLThreadSafeQueue<ElementT>::LLThreadSafeQueue(U32 capacity) :
+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)
+template<typename ElementT, typename QueueT>
+void LLThreadSafeQueue<ElementT, QueueT>::push(ElementT const & element)
 {
     lock_t lock1(mLock);
     while (true)
@@ -163,7 +198,7 @@ void LLThreadSafeQueue<ElementT>::pushFront(ElementT const & element)
 
         if (mStorage.size() < mCapacity)
         {
-            mStorage.push_front(element);
+            mStorage.push(element);
             lock1.unlock();
             mEmptyCond.notify_one();
             return;
@@ -175,15 +210,24 @@ void LLThreadSafeQueue<ElementT>::pushFront(ElementT const & element)
 }
 
 
-template <typename ElementT>
+template <typename ElementT, typename QueueT>
 template <typename Rep, typename Period>
-bool LLThreadSafeQueue<ElementT>::tryPushFrontFor(const std::chrono::duration<Rep, Period>& timeout,
-                                                  ElementT const & element)
+bool LLThreadSafeQueue<ElementT, QueueT>::tryPushFor(
+    const std::chrono::duration<Rep, Period>& timeout,
+    ElementT const & 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 tryPushUntil(std::chrono::steady_clock::now() + timeout, element);
+}
 
+
+template <typename ElementT, typename QueueT>
+template <typename Clock, typename Duration>
+bool LLThreadSafeQueue<ElementT, QueueT>::tryPushUntil(
+    const std::chrono::time_point<Clock, Duration>& endpoint,
+    ElementT const& element)
+{
     lock_t lock1(mLock, std::defer_lock);
     if (!lock1.try_lock_until(endpoint))
         return false;
@@ -197,7 +241,7 @@ bool LLThreadSafeQueue<ElementT>::tryPushFrontFor(const std::chrono::duration<Re
 
         if (mStorage.size() < mCapacity)
         {
-            mStorage.push_front(element);
+            mStorage.push(element);
             lock1.unlock();
             mEmptyCond.notify_one();
             return true;
@@ -215,8 +259,8 @@ bool LLThreadSafeQueue<ElementT>::tryPushFrontFor(const std::chrono::duration<Re
 }
 
 
-template<typename ElementT>
-bool LLThreadSafeQueue<ElementT>::tryPushFront(ElementT const & element)
+template<typename ElementT, typename QueueT>
+bool LLThreadSafeQueue<ElementT, QueueT>::tryPush(ElementT const & element)
 {
     lock_t lock1(mLock, std::defer_lock);
     if (!lock1.try_lock())
@@ -228,23 +272,24 @@ bool LLThreadSafeQueue<ElementT>::tryPushFront(ElementT const & element)
     if (mStorage.size() >= mCapacity)
         return false;
 
-    mStorage.push_front(element);
+    mStorage.push(element);
     lock1.unlock();
     mEmptyCond.notify_one();
     return true;
 }
 
 
-template<typename ElementT>
-ElementT LLThreadSafeQueue<ElementT>::popBack(void)
+template<typename ElementT, typename QueueT>
+ElementT LLThreadSafeQueue<ElementT, QueueT>::pop(void)
 {
     lock_t lock1(mLock);
     while (true)
     {
         if (!mStorage.empty())
         {
-            ElementT value = mStorage.back();
-            mStorage.pop_back();
+            // std::queue::front() is the element about to pop()
+            ElementT value = mStorage.front();
+            mStorage.pop();
             lock1.unlock();
             mCapacityCond.notify_one();
             return value;
@@ -261,54 +306,106 @@ ElementT LLThreadSafeQueue<ElementT>::popBack(void)
 }
 
 
-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;
 
-    // no need to check mClosed: tryPopBack() behavior when the queue is
+    // no need to check mClosed: tryPop() 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();
+    // std::queue::front() is the element about to pop()
+    element = mStorage.front();
+    mStorage.pop();
     lock1.unlock();
     mCapacityCond.notify_one();
     return true;
 }
 
 
-template<typename ElementT>
-size_t LLThreadSafeQueue<ElementT>::size(void)
+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>& endpoint,
+    ElementT& element)
+{
+    lock_t lock1(mLock, std::defer_lock);
+    if (!lock1.try_lock_until(endpoint))
+        return false;
+
+    while (true)
+    {
+        if (!mStorage.empty())
+        {
+            // std::queue::front() is the element about to pop()
+            element = mStorage.front();
+            mStorage.pop();
+            lock1.unlock();
+            mCapacityCond.notify_one();
+            return true;
+        }
+
+        if (mClosed)
+        {
+            return false;
+        }
+
+        // Storage empty. Wait for signal.
+        if (LLCoros::cv_status::timeout == mEmptyCond.wait_until(lock1, endpoint))
+        {
+            // timed out -- formally we might recheck both conditions above
+            return false;
+        }
+        // If we didn't time out, we were notified for some reason. Loop back
+        // to check.
+    }
+}
+
+
+template<typename ElementT, typename QueueT>
+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;
 }
 
-template<typename ElementT>
-LLThreadSafeQueue<ElementT>::operator bool()
+template<typename ElementT, typename QueueT>
+LLThreadSafeQueue<ElementT, QueueT>::operator bool()
 {
     return ! isClosed();
 }
-- 
cgit v1.2.3


From 1b1ebdf183e50c6a751493570ee6e643c33c4eda Mon Sep 17 00:00:00 2001
From: Nat Goodspeed <nat@lindenlab.com>
Date: Mon, 4 Oct 2021 11:48:58 -0400
Subject: SL-16024: Introduce tuple.h with tuple_cons(), tuple_cdr().

These functions allow prepending or removing an item at the left end of an
arbitrary tuple -- for instance, to add a sequence key to a caller's data,
then remove it again when delivering the original tuple.
---
 indra/llcommon/CMakeLists.txt       |  2 +
 indra/llcommon/tests/tuple_test.cpp | 47 +++++++++++++++++++++
 indra/llcommon/tuple.h              | 84 +++++++++++++++++++++++++++++++++++++
 3 files changed, 133 insertions(+)
 create mode 100644 indra/llcommon/tests/tuple_test.cpp
 create mode 100644 indra/llcommon/tuple.h

(limited to 'indra')

diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt
index dd266630ea..6558219462 100644
--- a/indra/llcommon/CMakeLists.txt
+++ b/indra/llcommon/CMakeLists.txt
@@ -254,6 +254,7 @@ set(llcommon_HEADER_FILES
     stdtypes.h
     stringize.h
     timer.h
+    tuple.h
     u64.h
     StackWalker.h
     )
@@ -358,6 +359,7 @@ 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(tuple "" "${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/tests/tuple_test.cpp b/indra/llcommon/tests/tuple_test.cpp
new file mode 100644
index 0000000000..af94e2086c
--- /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/tuple.h b/indra/llcommon/tuple.h
new file mode 100644
index 0000000000..bfe7e3c2ba
--- /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) */
-- 
cgit v1.2.3


From ca60fbe72ce086fbdf0821043ad3be6aad06857c Mon Sep 17 00:00:00 2001
From: Nat Goodspeed <nat@lindenlab.com>
Date: Mon, 4 Oct 2021 16:19:59 -0400
Subject: SL-16024: LLThreadSafeQueue enhancements

Add LL::PriorityQueueAdapter, a wrapper for std::priority_queue to make its
API more closely resemble std::queue for drop-in use as LLThreadSafeQueue's
underlying QueueT container.

Support move-only element types.

Factor out some implementation redundancy: wrap actual push semantics as
push_(), actual pop semantics as pop_(). push(), tryPush() and tryPushUntil()
now call push_(); pop(), tryPop() and tryPopUntil() now call pop_().

Break out tryLock() and tryLockUntil() methods that, if they can lock, run the
passed callable. Then tryPush(), tryPushUntil(), tryPop() and tryPopUntil()
pass lambdas containing the meat of the original method body to tryLock() or
tryLockUntil(), as appropriate.
---
 indra/llcommon/llthreadsafequeue.h | 358 ++++++++++++++++++++++++-------------
 1 file changed, 235 insertions(+), 123 deletions(-)

(limited to 'indra')

diff --git a/indra/llcommon/llthreadsafequeue.h b/indra/llcommon/llthreadsafequeue.h
index 04f51816d7..c57520c01f 100644
--- a/indra/llcommon/llthreadsafequeue.h
+++ b/indra/llcommon/llthreadsafequeue.h
@@ -37,6 +37,9 @@
 #include <queue>
 #include <string>
 
+/*****************************************************************************
+*   LLThreadSafeQueue
+*****************************************************************************/
 //
 // A general queue exception.
 //
@@ -77,8 +80,8 @@ 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 queue (will block if the queue has
@@ -86,13 +89,15 @@ public:
 	//
 	// This call will raise an interrupt error if the queue is closed while
 	// the caller is blocked.
-	void push(ElementT const& element);
+	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 tryPush(ElementT const& element);
+	template <typename T>
+	bool tryPush(T&& element);
 	// legacy name
 	bool tryPushFront(ElementT const & element) { return tryPush(element); }
 
@@ -102,9 +107,9 @@ public:
 	// 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>
+	template <typename Rep, typename Period, typename T>
 	bool tryPushFor(const std::chrono::duration<Rep, Period>& timeout,
-					ElementT const & element);
+					T&& element);
 	// legacy name
 	template <typename Rep, typename Period>
 	bool tryPushFrontFor(const std::chrono::duration<Rep, Period>& timeout,
@@ -112,9 +117,9 @@ public:
 
 	// 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>
-	bool tryPushUntil(const std::chrono::time_point<Clock, Duration>& timeout,
-					  ElementT const& element);
+	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
@@ -141,7 +146,7 @@ public:
 	// 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>& timeout,
+	bool tryPopUntil(const std::chrono::time_point<Clock, Duration>& until,
 					 ElementT& element);
 	// no legacy name because this is a newer method
 
@@ -172,11 +177,74 @@ protected:
 	typedef std::unique_lock<decltype(mLock)> lock_t;
 	boost::fibers::condition_variable_any mCapacityCond;
 	boost::fibers::condition_variable_any mEmptyCond;
-};
 
-// LLThreadSafeQueue
-//-----------------------------------------------------------------------------
+	// 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
+	template <typename PRED>
+	bool pop_(lock_t& lock, ElementT& element,
+			  PRED&& pred=[](const ElementT&){ return true; });
+};
 
+/*****************************************************************************
+*   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),
@@ -185,24 +253,69 @@ LLThreadSafeQueue<ElementT, QueueT>::LLThreadSafeQueue(U32 capacity) :
 }
 
 
-template<typename ElementT, typename QueueT>
-void LLThreadSafeQueue<ElementT, QueueT>::push(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(element);
-            lock1.unlock();
-            mEmptyCond.notify_one();
+        if (push_(lock1, std::forward<T>(element)))
             return;
-        }
 
         // Storage Full. Wait for signal.
         mCapacityCond.wait(lock1);
@@ -210,71 +323,85 @@ void LLThreadSafeQueue<ElementT, QueueT>::push(ElementT const & element)
 }
 
 
+template<typename ElementT, typename QueueT>
+template<typename T>
+bool LLThreadSafeQueue<ElementT, QueueT>::tryPush(T&& element)
+{
+    return tryLock(
+        [this, element=std::move(element)](lock_t& lock)
+        {
+            if (mClosed)
+                return false;
+            return push_(lock, std::move(element));
+        });
+}
+
+
 template <typename ElementT, typename QueueT>
-template <typename Rep, typename Period>
+template <typename Rep, typename Period, typename T>
 bool LLThreadSafeQueue<ElementT, QueueT>::tryPushFor(
     const std::chrono::duration<Rep, Period>& timeout,
-    ElementT const & element)
+    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, element);
+    return tryPushUntil(std::chrono::steady_clock::now() + timeout,
+                        std::forward<T>(element));
 }
 
 
 template <typename ElementT, typename QueueT>
-template <typename Clock, typename Duration>
+template <typename Clock, typename Duration, typename T>
 bool LLThreadSafeQueue<ElementT, QueueT>::tryPushUntil(
-    const std::chrono::time_point<Clock, Duration>& endpoint,
-    ElementT const& element)
+    const std::chrono::time_point<Clock, Duration>& until,
+    T&& element)
 {
-    lock_t lock1(mLock, std::defer_lock);
-    if (!lock1.try_lock_until(endpoint))
-        return false;
-
-    while (true)
-    {
-        if (mClosed)
+    return tryLockUntil(
+        until,
+        [this, until, element=std::move(element)](lock_t& lock)
         {
-            return false;
-        }
-
-        if (mStorage.size() < mCapacity)
-        {
-            mStorage.push(element);
-            lock1.unlock();
-            mEmptyCond.notify_one();
-            return true;
-        }
-
-        // Storage Full. Wait for signal.
-        if (LLCoros::cv_status::timeout == mCapacityCond.wait_until(lock1, endpoint))
-        {
-            // timed out -- formally we might recheck both conditions above
-            return false;
-        }
-        // If we didn't time out, we were notified for some reason. Loop back
-        // to check.
-    }
+            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, typename QueueT>
-bool LLThreadSafeQueue<ElementT, QueueT>::tryPush(ElementT const & element)
+// while lock is locked, really pop the head element, if we can
+template <typename ElementT, typename QueueT>
+template <typename PRED>
+bool LLThreadSafeQueue<ElementT, QueueT>::pop_(
+    lock_t& lock, ElementT& element, PRED&& pred)
 {
-    lock_t lock1(mLock, std::defer_lock);
-    if (!lock1.try_lock())
-        return false;
-
-    if (mClosed)
-        return false;
-
-    if (mStorage.size() >= mCapacity)
+    // If mStorage is empty, there's no head element.
+    // If there's a head element, pass it to the predicate to see if caller
+    // considers it ready to pop.
+    // Unless both are satisfied, no point in continuing.
+    if (mStorage.empty() || ! std::forward<PRED>(pred)(mStorage.front()))
         return false;
 
-    mStorage.push(element);
-    lock1.unlock();
-    mEmptyCond.notify_one();
+    // 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 true;
 }
 
@@ -285,22 +412,20 @@ ElementT LLThreadSafeQueue<ElementT, QueueT>::pop(void)
     lock_t lock1(mLock);
     while (true)
     {
-        if (!mStorage.empty())
-        {
-            // std::queue::front() is the element about to pop()
-            ElementT value = mStorage.front();
-            mStorage.pop();
-            lock1.unlock();
-            mCapacityCond.notify_one();
-            return value;
-        }
-
+        // On the consumer side, we always try to pop before checking mClosed
+        // so we can finish draining the queue.
+        ElementT value;
+        if (pop_(lock1, value))
+            return std::move(value);
+
+        // Once the queue is empty, mClosed lets us know if there will ever be
+        // any more coming.
         if (mClosed)
         {
             LLTHROW(LLThreadSafeQueueInterrupt());
         }
 
-        // Storage empty. Wait for signal.
+        // Storage empty, queue still open. Wait for signal.
         mEmptyCond.wait(lock1);
     }
 }
@@ -309,21 +434,14 @@ ElementT LLThreadSafeQueue<ElementT, QueueT>::pop(void)
 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;
-
-    // no need to check mClosed: tryPop() behavior when the queue is
-    // closed is implemented by simple inability to push any new elements
-    if (mStorage.empty())
-        return false;
-
-    // std::queue::front() is the element about to pop()
-    element = mStorage.front();
-    mStorage.pop();
-    lock1.unlock();
-    mCapacityCond.notify_one();
-    return true;
+    return tryLock(
+        [this, &element](lock_t& lock)
+        {
+            // no need to check mClosed: tryPop() behavior when the queue is
+            // closed is implemented by simple inability to push any new
+            // elements
+            return pop_(lock, element);
+        });
 }
 
 
@@ -342,39 +460,33 @@ bool LLThreadSafeQueue<ElementT, QueueT>::tryPopFor(
 template <typename ElementT, typename QueueT>
 template <typename Clock, typename Duration>
 bool LLThreadSafeQueue<ElementT, QueueT>::tryPopUntil(
-    const std::chrono::time_point<Clock, Duration>& endpoint,
+    const std::chrono::time_point<Clock, Duration>& until,
     ElementT& element)
 {
-    lock_t lock1(mLock, std::defer_lock);
-    if (!lock1.try_lock_until(endpoint))
-        return false;
-
-    while (true)
-    {
-        if (!mStorage.empty())
+    return tryLockUntil(
+        until,
+        [this, until, &element](lock_t& lock)
         {
-            // std::queue::front() is the element about to pop()
-            element = mStorage.front();
-            mStorage.pop();
-            lock1.unlock();
-            mCapacityCond.notify_one();
-            return true;
-        }
-
-        if (mClosed)
-        {
-            return false;
-        }
-
-        // Storage empty. Wait for signal.
-        if (LLCoros::cv_status::timeout == mEmptyCond.wait_until(lock1, endpoint))
-        {
-            // timed out -- formally we might recheck both conditions above
-            return false;
-        }
-        // If we didn't time out, we were notified for some reason. Loop back
-        // to check.
-    }
+            while (true)
+            {
+                if (pop_(lock, element))
+                    return true;
+
+                if (mClosed)
+                {
+                    return false;
+                }
+
+                // Storage empty. Wait for signal.
+                if (LLCoros::cv_status::timeout == mEmptyCond.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.
+            }
+        });
 }
 
 
-- 
cgit v1.2.3


From a35e266547e4d2c8dbd6b003c64b719d91eaaf87 Mon Sep 17 00:00:00 2001
From: Nat Goodspeed <nat@lindenlab.com>
Date: Mon, 4 Oct 2021 17:21:39 -0400
Subject: SL-16024: Don't use a lambda as default arg for universal reference.

Instead, break out a separate pop_() method that explicitly provides the
lambda to the real pop_() implementation.
---
 indra/llcommon/llthreadsafequeue.h | 16 ++++++++++++++--
 1 file changed, 14 insertions(+), 2 deletions(-)

(limited to 'indra')

diff --git a/indra/llcommon/llthreadsafequeue.h b/indra/llcommon/llthreadsafequeue.h
index c57520c01f..1dffad6b89 100644
--- a/indra/llcommon/llthreadsafequeue.h
+++ b/indra/llcommon/llthreadsafequeue.h
@@ -191,9 +191,11 @@ protected:
 	template <typename T>
 	bool push_(lock_t& lock, T&& element);
 	// while lock is locked, really pop the head element, if we can
+	bool pop_(lock_t& lock, ElementT& element);
+	// pop_() with an explicit predicate indicating whether the head element
+	// is ready to be popped
 	template <typename PRED>
-	bool pop_(lock_t& lock, ElementT& element,
-			  PRED&& pred=[](const ElementT&){ return true; });
+	bool pop_(lock_t& lock, ElementT& element, PRED&& pred);
 };
 
 /*****************************************************************************
@@ -385,6 +387,16 @@ bool LLThreadSafeQueue<ElementT, QueueT>::tryPushUntil(
 
 // while lock is locked, really pop the head element, if we can
 template <typename ElementT, typename QueueT>
+bool LLThreadSafeQueue<ElementT, QueueT>::pop_(lock_t& lock, ElementT& element)
+{
+    // default predicate: head element, if present, is always ready to pop
+    return pop_(lock, element, [](const ElementT&){ return true; });
+}
+
+
+// pop_() with an explicit predicate indicating whether the head element
+// is ready to be popped
+template <typename ElementT, typename QueueT>
 template <typename PRED>
 bool LLThreadSafeQueue<ElementT, QueueT>::pop_(
     lock_t& lock, ElementT& element, PRED&& pred)
-- 
cgit v1.2.3


From 4778f9497ec8b871c297b4efc4c0a44ee5726af1 Mon Sep 17 00:00:00 2001
From: Dave Houlton <euclid@lindenlab.com>
Date: Tue, 5 Oct 2021 10:05:22 -0600
Subject: DRTVWR-546 trigger

---
 indra/edit-me-to-trigger-new-build.txt | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

(limited to 'indra')

diff --git a/indra/edit-me-to-trigger-new-build.txt b/indra/edit-me-to-trigger-new-build.txt
index 5366987cff..eab7c17b71 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
-- 
cgit v1.2.3


From f0e31b6c82d38706acbad22abc3946c2579870cd Mon Sep 17 00:00:00 2001
From: Dave Houlton <euclid@lindenlab.com>
Date: Tue, 5 Oct 2021 13:29:46 -0600
Subject: SL-16138 Avoid re-binding a shader which is already bound

---
 indra/llrender/llglslshader.cpp | 53 ++++++++++++++++++-----------------------
 1 file changed, 23 insertions(+), 30 deletions(-)

(limited to 'indra')

diff --git a/indra/llrender/llglslshader.cpp b/indra/llrender/llglslshader.cpp
index 9ab38d25a9..46b9c69faa 100644
--- a/indra/llrender/llglslshader.cpp
+++ b/indra/llrender/llglslshader.cpp
@@ -938,52 +938,45 @@ BOOL LLGLSLShader::link(BOOL suppress_errors)
 
 void LLGLSLShader::bind()
 {
-    gGL.flush();
-    if (gGLManager.mHasShaderObjects)
+    LL_PROFILE_ZONE_SCOPED;
+
+    if (sCurBoundShader != mProgramObject)  // Don't re-bind current shader
     {
+        gGL.flush();
         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)
-- 
cgit v1.2.3


From 955b967623983cb50ba09f7b82e5f01f2c6bcebb Mon Sep 17 00:00:00 2001
From: Nat Goodspeed <nat@lindenlab.com>
Date: Tue, 5 Oct 2021 17:31:53 -0400
Subject: SL-16024: Add ThreadSafeSchedule, a timestamped LLThreadSafeQueue.

ThreadSafeSchedule orders its items by timestamp, which can be passed either
implicitly or explicitly. The timestamp specifies earliest delivery time: an
item cannot be popped until that time.

Add initial tests.

Tweak the LLThreadSafeQueue base class to support ThreadSafeSchedule:
introduce virtual canPop() method to report whether the current head item is
available to pop. The base class unconditionally says yes, ThreadSafeSchedule
says it depends on whether its timestamp is still in the future.

This replaces the protected pop_() overload accepting a predicate. Rather than
explicitly passing a predicate through a couple levels of function call, use
canPop() at the level it matters. Runtime behavior that varies depending on
an object's leaf class is what virtual functions were invented for.

Give pop_() a three-state enum return so pop() can distinguish between "closed
and empty" (throws exception) versus "closed, not yet drained because we're
not yet ready to pop the head item" (waits).

Also break out protected tryPopUntil_() method, the body logic of
tryPopUntil(). The public method locks the data structure, the protected
method requires that its caller has already done so.

Add chrono.h with a more full-featured LL::time_point_cast() function than the
one found in <chrono>, which only converts between time_point durations, not
between time_points based on different clocks.
---
 indra/llcommon/CMakeLists.txt                    |   3 +
 indra/llcommon/chrono.h                          |  65 +++++
 indra/llcommon/llthreadsafequeue.h               | 121 ++++----
 indra/llcommon/tests/threadsafeschedule_test.cpp |  65 +++++
 indra/llcommon/threadsafeschedule.h              | 334 +++++++++++++++++++++++
 5 files changed, 535 insertions(+), 53 deletions(-)
 create mode 100644 indra/llcommon/chrono.h
 create mode 100644 indra/llcommon/tests/threadsafeschedule_test.cpp
 create mode 100644 indra/llcommon/threadsafeschedule.h

(limited to 'indra')

diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt
index 6558219462..5efcfabf24 100644
--- a/indra/llcommon/CMakeLists.txt
+++ b/indra/llcommon/CMakeLists.txt
@@ -127,6 +127,7 @@ set(llcommon_SOURCE_FILES
 set(llcommon_HEADER_FILES
     CMakeLists.txt
 
+    chrono.h
     ctype_workaround.h
     fix_macros.h
     indra_constants.h
@@ -253,6 +254,7 @@ set(llcommon_HEADER_FILES
     lockstatic.h
     stdtypes.h
     stringize.h
+    threadsafeschedule.h
     timer.h
     tuple.h
     u64.h
@@ -359,6 +361,7 @@ 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}")
 
 ## llexception_test.cpp isn't a regression test, and doesn't need to be run
diff --git a/indra/llcommon/chrono.h b/indra/llcommon/chrono.h
new file mode 100644
index 0000000000..806e871892
--- /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/llthreadsafequeue.h b/indra/llcommon/llthreadsafequeue.h
index 1dffad6b89..bd2d82d4c3 100644
--- a/indra/llcommon/llthreadsafequeue.h
+++ b/indra/llcommon/llthreadsafequeue.h
@@ -83,6 +83,7 @@ public:
 	// Limiting the number of pending items prevents unbounded growth of the
 	// underlying queue.
 	LLThreadSafeQueue(U32 capacity = 1024);
+	virtual ~LLThreadSafeQueue() {}
 
 	// Add an element to the queue (will block if the queue has
 	// reached capacity).
@@ -162,10 +163,10 @@ public:
 	//   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();
 
 protected:
 	typedef QueueT queue_type;
@@ -178,6 +179,11 @@ protected:
 	boost::fibers::condition_variable_any mCapacityCond;
 	boost::fibers::condition_variable_any mEmptyCond;
 
+	// implementation logic, suitable for passing to tryLockUntil()
+	template <typename Clock, typename Duration>
+	bool 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>
@@ -191,11 +197,11 @@ protected:
 	template <typename T>
 	bool push_(lock_t& lock, T&& element);
 	// while lock is locked, really pop the head element, if we can
-	bool pop_(lock_t& lock, ElementT& element);
-	// pop_() with an explicit predicate indicating whether the head element
-	// is ready to be popped
-	template <typename PRED>
-	bool pop_(lock_t& lock, ElementT& element, PRED&& pred);
+	enum pop_result { EMPTY, WAITING, POPPED };
+	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; }
 };
 
 /*****************************************************************************
@@ -387,26 +393,16 @@ bool LLThreadSafeQueue<ElementT, QueueT>::tryPushUntil(
 
 // while lock is locked, really pop the head element, if we can
 template <typename ElementT, typename QueueT>
-bool LLThreadSafeQueue<ElementT, QueueT>::pop_(lock_t& lock, ElementT& element)
-{
-    // default predicate: head element, if present, is always ready to pop
-    return pop_(lock, element, [](const ElementT&){ return true; });
-}
-
-
-// pop_() with an explicit predicate indicating whether the head element
-// is ready to be popped
-template <typename ElementT, typename QueueT>
-template <typename PRED>
-bool LLThreadSafeQueue<ElementT, QueueT>::pop_(
-    lock_t& lock, ElementT& element, PRED&& pred)
+typename LLThreadSafeQueue<ElementT, QueueT>::pop_result
+LLThreadSafeQueue<ElementT, QueueT>::pop_(lock_t& lock, ElementT& element)
 {
     // If mStorage is empty, there's no head element.
-    // If there's a head element, pass it to the predicate to see if caller
-    // considers it ready to pop.
-    // Unless both are satisfied, no point in continuing.
-    if (mStorage.empty() || ! std::forward<PRED>(pred)(mStorage.front()))
-        return false;
+    if (mStorage.empty())
+        return EMPTY;
+
+    // If there's a head element, pass it to canPop() to see if it's ready to pop. 
+    if (! canPop(mStorage.front()))
+        return WAITING;
 
     // std::queue::front() is the element about to pop()
     element = mStorage.front();
@@ -414,7 +410,7 @@ bool LLThreadSafeQueue<ElementT, QueueT>::pop_(
     lock.unlock();
     // now that we've popped, if somebody's been waiting to push, signal them
     mCapacityCond.notify_one();
-    return true;
+    return POPPED;
 }
 
 
@@ -422,17 +418,20 @@ template<typename ElementT, typename QueueT>
 ElementT LLThreadSafeQueue<ElementT, QueueT>::pop(void)
 {
     lock_t lock1(mLock);
+    ElementT value;
     while (true)
     {
         // On the consumer side, we always try to pop before checking mClosed
         // so we can finish draining the queue.
-        ElementT value;
-        if (pop_(lock1, value))
+        pop_result popped = pop_(lock1, value);
+        if (popped == POPPED)
             return std::move(value);
 
         // Once the queue is empty, mClosed lets us know if there will ever be
-        // any more coming.
-        if (mClosed)
+        // any more coming. 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.
+        if (popped == EMPTY && mClosed)
         {
             LLTHROW(LLThreadSafeQueueInterrupt());
         }
@@ -452,7 +451,7 @@ bool LLThreadSafeQueue<ElementT, QueueT>::tryPop(ElementT & element)
             // no need to check mClosed: tryPop() behavior when the queue is
             // closed is implemented by simple inability to push any new
             // elements
-            return pop_(lock, element);
+            return pop_(lock, element) == POPPED;
         });
 }
 
@@ -479,26 +478,38 @@ bool LLThreadSafeQueue<ElementT, QueueT>::tryPopUntil(
         until,
         [this, until, &element](lock_t& lock)
         {
-            while (true)
-            {
-                if (pop_(lock, element))
-                    return true;
+            return tryPopUntil_(lock, until, element);
+        });
+}
 
-                if (mClosed)
-                {
-                    return false;
-                }
 
-                // Storage empty. Wait for signal.
-                if (LLCoros::cv_status::timeout == mEmptyCond.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.
-            }
-        });
+// body of tryPopUntil(), called once we have the lock
+template <typename ElementT, typename QueueT>
+template <typename Clock, typename Duration>
+bool LLThreadSafeQueue<ElementT, QueueT>::tryPopUntil_(
+    lock_t& lock,
+    const std::chrono::time_point<Clock, Duration>& until,
+    ElementT& element)
+{
+    while (true)
+    {
+        if (pop_(lock, element) == POPPED)
+            return true;
+
+        if (mClosed)
+        {
+            return false;
+        }
+
+        // Storage empty. Wait for signal.
+        if (LLCoros::cv_status::timeout == mEmptyCond.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.
+    }
 }
 
 
@@ -509,6 +520,7 @@ size_t LLThreadSafeQueue<ElementT, QueueT>::size(void)
     return mStorage.size();
 }
 
+
 template<typename ElementT, typename QueueT>
 void LLThreadSafeQueue<ElementT, QueueT>::close()
 {
@@ -521,17 +533,20 @@ void LLThreadSafeQueue<ElementT, QueueT>::close()
     mCapacityCond.notify_all();
 }
 
+
 template<typename ElementT, typename QueueT>
 bool LLThreadSafeQueue<ElementT, QueueT>::isClosed()
 {
     lock_t lock(mLock);
-    return mClosed && mStorage.size() == 0;
+    return mClosed;
 }
 
+
 template<typename ElementT, typename QueueT>
-LLThreadSafeQueue<ElementT, QueueT>::operator bool()
+bool LLThreadSafeQueue<ElementT, QueueT>::done()
 {
-    return ! isClosed();
+    lock_t lock(mLock);
+    return mClosed && mStorage.size() == 0;
 }
 
 #endif
diff --git a/indra/llcommon/tests/threadsafeschedule_test.cpp b/indra/llcommon/tests/threadsafeschedule_test.cpp
new file mode 100644
index 0000000000..ec0fa0c928
--- /dev/null
+++ b/indra/llcommon/tests/threadsafeschedule_test.cpp
@@ -0,0 +1,65 @@
+/**
+ * @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"));
+        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());
+        entry = queue.pop();
+        ensure_equals("failed to pop third", std::get<0>(entry), "ghi"s);
+        bool popped = queue.tryPop(entry);
+        ensure("queue not empty", ! popped);
+        ensure("queue not done", queue.done());
+    }
+} // namespace tut
diff --git a/indra/llcommon/threadsafeschedule.h b/indra/llcommon/threadsafeschedule.h
new file mode 100644
index 0000000000..545c820f53
--- /dev/null
+++ b/indra/llcommon/threadsafeschedule.h
@@ -0,0 +1,334 @@
+/**
+ * @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;
+        using super::pop_;
+        using super::push_;
+        using super::mClosed;
+        using super::mEmptyCond;
+        using super::mCapacityCond;
+
+    public:
+        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
+        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) -- 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
+        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);
+                if (tryPopUntil_(lock, until, tt))
+                    return std::move(tt);
+
+                // empty and closed: throw, just as super::pop() does
+                if (super::mStorage.empty() && super::mClosed)
+                {
+                    LLTHROW(LLThreadSafeQueueInterrupt());
+                }
+                // If not empty, we've still got items to drain.
+                // If not closed, 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;
+        }
+
+        /// 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 tryPopUntil_(lock, time_point_cast<TimePoint>(until), tuple);
+                });
+        }
+
+        bool 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_()
+            return super::tryPopUntil_(lock, adjusted, tuple);
+        }
+
+        /// 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;
+        }
+
+        /*------------------------------ 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) */
-- 
cgit v1.2.3


From cf70766b4504f7ee745822926c526ed9c86c9339 Mon Sep 17 00:00:00 2001
From: Nat Goodspeed <nat@lindenlab.com>
Date: Wed, 6 Oct 2021 12:54:29 -0400
Subject: SL-16024: Fix ThreadSafeSchedule::tryPopFor(), tryPopUntil().

ThreadSafeSchedule::tryPopUntil() (and therefore tryPopFor()) was simply
delegating to LLThreadSafeQueue::tryPopUntil(), with an adjusted timeout since
we want to wake up as soon as the head item, if any, becomes ready. But then
we have to loop back to retry the pop to actually deal with that head item.

In addition, ThreadSafeSchedule::popWithTime() was spinning rather than
properly blocking on a timed condition variable. Fixed.
---
 indra/llcommon/llthreadsafequeue.h               | 51 +++++++++--------
 indra/llcommon/tests/threadsafeschedule_test.cpp | 10 +++-
 indra/llcommon/threadsafeschedule.h              | 72 ++++++++++++++++++------
 3 files changed, 88 insertions(+), 45 deletions(-)

(limited to 'indra')

diff --git a/indra/llcommon/llthreadsafequeue.h b/indra/llcommon/llthreadsafequeue.h
index bd2d82d4c3..719edcd579 100644
--- a/indra/llcommon/llthreadsafequeue.h
+++ b/indra/llcommon/llthreadsafequeue.h
@@ -179,11 +179,12 @@ protected:
 	boost::fibers::condition_variable_any mCapacityCond;
 	boost::fibers::condition_variable_any mEmptyCond;
 
+	enum pop_result { EMPTY, DONE, WAITING, POPPED };
 	// implementation logic, suitable for passing to tryLockUntil()
 	template <typename Clock, typename Duration>
-	bool tryPopUntil_(lock_t& lock,
-					  const std::chrono::time_point<Clock, Duration>& until,
-					  ElementT& element);
+	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>
@@ -197,7 +198,6 @@ protected:
 	template <typename T>
 	bool push_(lock_t& lock, T&& element);
 	// while lock is locked, really pop the head element, if we can
-	enum pop_result { EMPTY, WAITING, POPPED };
 	pop_result pop_(lock_t& lock, ElementT& element);
 	// Is the current head element ready to pop? We say yes; subclass can
 	// override as needed.
@@ -398,7 +398,7 @@ LLThreadSafeQueue<ElementT, QueueT>::pop_(lock_t& lock, ElementT& element)
 {
     // If mStorage is empty, there's no head element.
     if (mStorage.empty())
-        return EMPTY;
+        return mClosed? DONE : EMPTY;
 
     // If there's a head element, pass it to canPop() to see if it's ready to pop. 
     if (! canPop(mStorage.front()))
@@ -427,16 +427,16 @@ ElementT LLThreadSafeQueue<ElementT, QueueT>::pop(void)
         if (popped == POPPED)
             return std::move(value);
 
-        // Once the queue is empty, mClosed lets us know if there will ever be
-        // any more coming. 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.
-        if (popped == EMPTY && mClosed)
+        // Once the queue is DONE, there will never be any more coming.
+        if (popped == DONE)
         {
             LLTHROW(LLThreadSafeQueueInterrupt());
         }
 
-        // Storage empty, queue still open. 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);
     }
 }
@@ -448,8 +448,8 @@ bool LLThreadSafeQueue<ElementT, QueueT>::tryPop(ElementT & element)
     return tryLock(
         [this, &element](lock_t& lock)
         {
-            // no need to check mClosed: tryPop() behavior when the queue is
-            // closed is implemented by simple inability to push any new
+            // 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;
         });
@@ -478,7 +478,8 @@ bool LLThreadSafeQueue<ElementT, QueueT>::tryPopUntil(
         until,
         [this, until, &element](lock_t& lock)
         {
-            return tryPopUntil_(lock, until, element);
+            // conflate EMPTY, DONE, WAITING
+            return tryPopUntil_(lock, until, element) == POPPED;
         });
 }
 
@@ -486,26 +487,28 @@ bool LLThreadSafeQueue<ElementT, QueueT>::tryPopUntil(
 // body of tryPopUntil(), called once we have the lock
 template <typename ElementT, typename QueueT>
 template <typename Clock, typename Duration>
-bool LLThreadSafeQueue<ElementT, QueueT>::tryPopUntil_(
+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)
     {
-        if (pop_(lock, element) == POPPED)
-            return true;
-
-        if (mClosed)
+        pop_result popped = pop_(lock, element);
+        if (popped == POPPED || popped == DONE)
         {
-            return false;
+            // If we succeeded, great! If we've drained the last item, so be
+            // it. Either way, break the loop and tell caller.
+            return popped;
         }
 
-        // Storage empty. Wait for signal.
+        // EMPTY or WAITING: wait for signal.
         if (LLCoros::cv_status::timeout == mEmptyCond.wait_until(lock, until))
         {
-            // timed out -- formally we might recheck both conditions above
-            return false;
+            // 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.
@@ -546,7 +549,7 @@ template<typename ElementT, typename QueueT>
 bool LLThreadSafeQueue<ElementT, QueueT>::done()
 {
     lock_t lock(mLock);
-    return mClosed && mStorage.size() == 0;
+    return mClosed && mStorage.empty();
 }
 
 #endif
diff --git a/indra/llcommon/tests/threadsafeschedule_test.cpp b/indra/llcommon/tests/threadsafeschedule_test.cpp
index ec0fa0c928..af67b9f492 100644
--- a/indra/llcommon/tests/threadsafeschedule_test.cpp
+++ b/indra/llcommon/tests/threadsafeschedule_test.cpp
@@ -47,6 +47,8 @@ namespace tut
         // 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();
@@ -56,9 +58,11 @@ namespace tut
         ensure_equals("failed to pop second", std::get<0>(entry), "def"s);
         ensure("queue not closed", queue.isClosed());
         ensure("queue prematurely done", ! queue.done());
-        entry = queue.pop();
-        ensure_equals("failed to pop third", std::get<0>(entry), "ghi"s);
-        bool popped = queue.tryPop(entry);
+        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());
     }
diff --git a/indra/llcommon/threadsafeschedule.h b/indra/llcommon/threadsafeschedule.h
index 545c820f53..8ab4311ca1 100644
--- a/indra/llcommon/threadsafeschedule.h
+++ b/indra/llcommon/threadsafeschedule.h
@@ -73,11 +73,7 @@ namespace LL
     private:
         using super = LLThreadSafeQueue<TimeTuple, ThreadSafeSchedulePrivate::TimedQueue<Args...>>;
         using lock_t = typename super::lock_t;
-        using super::pop_;
-        using super::push_;
-        using super::mClosed;
-        using super::mEmptyCond;
-        using super::mCapacityCond;
+        using pop_result = typename super::pop_result;
 
     public:
         using TimePoint = ThreadSafeSchedulePrivate::TimePoint;
@@ -92,6 +88,11 @@ namespace LL
         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));
@@ -103,11 +104,11 @@ namespace LL
             push(TimeTuple(time, std::forward<Args>(args)...));
         }
 
-        /// individually pass every component except the TimePoint (implies
-        /// now) -- 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
+        /// 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)...);
@@ -199,6 +200,10 @@ namespace LL
         // 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());
@@ -224,16 +229,17 @@ namespace LL
             {
                 // Pick a point suitably far into the future.
                 TimePoint until = TimePoint::clock::now() + std::chrono::hours(24);
-                if (tryPopUntil_(lock, until, tt))
+                pop_result popped = tryPopUntil_(lock, until, tt);
+                if (popped == super::POPPED)
                     return std::move(tt);
 
-                // empty and closed: throw, just as super::pop() does
-                if (super::mStorage.empty() && super::mClosed)
+                // DONE: throw, just as super::pop() does
+                if (popped == super::DONE)
                 {
                     LLTHROW(LLThreadSafeQueueInterrupt());
                 }
-                // If not empty, we've still got items to drain.
-                // If not closed, it's worth waiting for more items.
+                // 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.
             }
         }
@@ -252,6 +258,16 @@ namespace LL
             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)
@@ -278,11 +294,12 @@ namespace LL
                 {
                     // Use our time_point_cast to allow for 'until' that's a
                     // time_point type other than TimePoint.
-                    return tryPopUntil_(lock, time_point_cast<TimePoint>(until), tuple);
+                    return super::POPPED ==
+                        tryPopUntil_(lock, LL::time_point_cast<TimePoint>(until), tuple);
                 });
         }
 
-        bool tryPopUntil_(lock_t& lock, const TimePoint& until, TimeTuple& tuple)
+        pop_result tryPopUntil_(lock_t& lock, const TimePoint& until, TimeTuple& tuple)
         {
             TimePoint adjusted = until;
             if (! super::mStorage.empty())
@@ -292,7 +309,14 @@ namespace LL
                 adjusted = min(std::get<0>(super::mStorage.front()), adjusted);
             }
             // now delegate to base-class tryPopUntil_()
-            return super::tryPopUntil_(lock, adjusted, tuple);
+            pop_result popped;
+            while ((popped = super::tryPopUntil_(lock, adjusted, tuple)) == super::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&)
@@ -307,6 +331,18 @@ namespace LL
             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
-- 
cgit v1.2.3


From 4c07eaa560c24303126057b7cf43441d87d520e5 Mon Sep 17 00:00:00 2001
From: Dave Houlton <euclid@lindenlab.com>
Date: Tue, 5 Oct 2021 14:11:29 -0600
Subject: SL-16138 Add timing mark-up to shader fxns

---
 indra/llrender/llglslshader.cpp | 37 ++++++++++++++++++++++++++++++++++---
 1 file changed, 34 insertions(+), 3 deletions(-)

(limited to 'indra')

diff --git a/indra/llrender/llglslshader.cpp b/indra/llrender/llglslshader.cpp
index 46b9c69faa..2fb3b8257d 100644
--- a/indra/llrender/llglslshader.cpp
+++ b/indra/llrender/llglslshader.cpp
@@ -126,7 +126,6 @@ struct LLGLSLShaderCompareTimeElapsed
 //static
 void LLGLSLShader::finishProfile(bool emit_report)
 {
-    LL_PROFILE_ZONE_SCOPED
     sProfileEnabled = false;
 
     if (emit_report)
@@ -385,6 +384,8 @@ BOOL LLGLSLShader::createShader(std::vector<LLStaticHashedString> * attributes,
                                 U32 varying_count,
                                 const char** varyings)
 {
+    LL_PROFILE_ZONE_SCOPED;
+
     unloadInternal();
 
     sInstances.insert(this);
@@ -589,6 +590,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++)
     {
@@ -650,6 +653,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;
@@ -771,6 +776,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
@@ -783,7 +790,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;
@@ -926,6 +935,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)
@@ -940,9 +951,10 @@ void LLGLSLShader::bind()
 {
     LL_PROFILE_ZONE_SCOPED;
 
+    gGL.flush();
+
     if (sCurBoundShader != mProgramObject)  // Don't re-bind current shader
     {
-        gGL.flush();
         LLVertexBuffer::unbind();
         glUseProgramObjectARB(mProgramObject);
         sCurBoundShader = mProgramObject;
@@ -981,6 +993,8 @@ void LLGLSLShader::bindNoShader(void)
 
 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);
     
@@ -989,6 +1003,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;
@@ -1008,6 +1024,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);
     
@@ -1016,6 +1034,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;
@@ -1034,6 +1054,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;
@@ -1051,6 +1073,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;
@@ -1341,6 +1365,7 @@ 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)
@@ -1375,6 +1400,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)
     {
@@ -1399,6 +1426,8 @@ GLint LLGLSLShader::getUniformLocation(const LLStaticHashedString& uniform)
 
 GLint LLGLSLShader::getUniformLocation(U32 index)
 {
+    LL_PROFILE_ZONE_SCOPED;
+
     GLint ret = -1;
     if (mProgramObject)
     {
@@ -1411,6 +1440,8 @@ GLint LLGLSLShader::getUniformLocation(U32 index)
 
 GLint LLGLSLShader::getAttribLocation(U32 attrib)
 {
+    LL_PROFILE_ZONE_SCOPED;
+
     if (attrib < mAttribute.size())
     {
         return mAttribute[attrib];
-- 
cgit v1.2.3


From 3e99853b2984a40093ff6b504abfcabe065b251b Mon Sep 17 00:00:00 2001
From: Dave Houlton <euclid@lindenlab.com>
Date: Tue, 5 Oct 2021 15:59:21 -0600
Subject: SL-16138 remove checks for now-mandatory capabilities

---
 indra/llrender/llgl.cpp             | 300 ++++++++++++++++--------------------
 indra/llrender/llgl.h               |   3 -
 indra/newview/llappviewer.cpp       |  13 --
 indra/newview/lldrawpoolsimple.cpp  |  24 +--
 indra/newview/lldrawpoolsky.cpp     |   8 +-
 indra/newview/llfeaturemanager.cpp  |   6 +-
 indra/newview/llglsandbox.cpp       |   5 +-
 indra/newview/llviewershadermgr.cpp |  11 +-
 indra/newview/pipeline.cpp          |   9 +-
 indra/newview/pipeline.h            |   1 -
 10 files changed, 142 insertions(+), 238 deletions(-)

(limited to 'indra')

diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp
index 43fedeca64..673f6cb6df 100644
--- a/indra/llrender/llgl.cpp
+++ b/indra/llrender/llgl.cpp
@@ -434,9 +434,6 @@ LLGLManager::LLGLManager() :
 	mHasMapBufferRange(FALSE),
 	mHasFlushBufferRange(FALSE),
 	mHasPBuffer(FALSE),
-	mHasShaderObjects(FALSE),
-	mHasVertexShader(FALSE),
-	mHasFragmentShader(FALSE),
 	mNumTextureImageUnits(0),
 	mHasOcclusionQuery(FALSE),
 	mHasTimerQuery(FALSE),
@@ -775,14 +772,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)
 	{
@@ -975,9 +967,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;
@@ -1083,9 +1075,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");
@@ -1143,10 +1132,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
@@ -1169,9 +1154,6 @@ void LLGLManager::initExtensions()
 		mHasCubeMap = FALSE;
 		mHasOcclusionQuery = FALSE;
 		mHasPointParameters = FALSE;
-		mHasShaderObjects = FALSE;
-		mHasVertexShader = FALSE;
-		mHasFragmentShader = FALSE;
 		LL_WARNS("RenderInit") << "GL extension support DISABLED via LL_GL_NOEXT" << LL_ENDL;
 	}
 	else if (getenv("LL_GL_BASICEXT"))	/* Flawfinder: ignore */
@@ -1184,9 +1166,6 @@ void LLGLManager::initExtensions()
 		mHasAnisotropic = FALSE;
 		//mHasCubeMap = FALSE; // apparently fatal on Intel 915 & similar
 		//mHasOcclusionQuery = FALSE; // source of many ATI system hangs
-		mHasShaderObjects = FALSE;
-		mHasVertexShader = FALSE;
-		mHasFragmentShader = FALSE;
 		mHasBlendFuncSeparate = FALSE;
 		LL_WARNS("RenderInit") << "GL extension support forced to SIMPLE level via LL_GL_BASICEXT" << LL_ENDL;
 	}
@@ -1208,9 +1187,6 @@ void LLGLManager::initExtensions()
 		if (strchr(blacklist,'j')) mHasCubeMap = FALSE;//S
 // 		if (strchr(blacklist,'k')) mHasATIVAO = FALSE;//S
 		if (strchr(blacklist,'l')) mHasOcclusionQuery = FALSE;
-		if (strchr(blacklist,'m')) mHasShaderObjects = FALSE;//S
-		if (strchr(blacklist,'n')) mHasVertexShader = FALSE;//S
-		if (strchr(blacklist,'o')) mHasFragmentShader = FALSE;//S
 		if (strchr(blacklist,'p')) mHasPointParameters = FALSE;//S
 		if (strchr(blacklist,'q')) mHasFramebufferObject = FALSE;//S
 		if (strchr(blacklist,'r')) mHasDrawBuffers = FALSE;//S
@@ -1257,18 +1233,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;
@@ -1436,134 +1400,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)
@@ -2116,7 +2078,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 a07e2d9bb0..a03d5352be 100644
--- a/indra/llrender/llgl.h
+++ b/indra/llrender/llgl.h
@@ -94,9 +94,6 @@ public:
 	BOOL mHasMapBufferRange;
 	BOOL mHasFlushBufferRange;
 	BOOL mHasPBuffer;
-	BOOL mHasShaderObjects;
-	BOOL mHasVertexShader;
-	BOOL mHasFragmentShader;
 	S32  mNumTextureImageUnits;
 	BOOL mHasOcclusionQuery;
 	BOOL mHasTimerQuery;
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 3d49a9eb78..98409106a1 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -1010,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())
 	{
diff --git a/indra/newview/lldrawpoolsimple.cpp b/indra/newview/lldrawpoolsimple.cpp
index f211cf6e27..74e6665a96 100644
--- a/indra/newview/lldrawpoolsimple.cpp
+++ b/indra/newview/lldrawpoolsimple.cpp
@@ -199,11 +199,7 @@ void LLDrawPoolSimple::beginRenderPass(S32 pass)
 	}
 	else 
 	{
-		// don't use shaders!
-		if (gGLManager.mHasShaderObjects)
-		{
-			LLGLSLShader::bindNoShader();
-		}		
+		LLGLSLShader::bindNoShader();
 	}
 }
 
@@ -301,11 +297,7 @@ void LLDrawPoolAlphaMask::beginRenderPass(S32 pass)
 	}
 	else 
 	{
-		// don't use shaders!
-		if (gGLManager.mHasShaderObjects)
-		{
-			LLGLSLShader::bindNoShader();
-		}		
+		LLGLSLShader::bindNoShader();
 	}
 }
 
@@ -392,11 +384,7 @@ void LLDrawPoolFullbrightAlphaMask::beginRenderPass(S32 pass)
 	}
 	else 
 	{
-		// don't use shaders!
-		if (gGLManager.mHasShaderObjects)
-		{
-			LLGLSLShader::bindNoShader();
-		}		
+		LLGLSLShader::bindNoShader();
 	}
 }
 
@@ -567,11 +555,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/lldrawpoolsky.cpp b/indra/newview/lldrawpoolsky.cpp
index b6f55e800a..b1eefaab81 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/llfeaturemanager.cpp b/indra/newview/llfeaturemanager.cpp
index e6bbe234b3..98c8531cd6 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/llglsandbox.cpp b/indra/newview/llglsandbox.cpp
index 698c15bd2d..0f288e05ca 100644
--- a/indra/newview/llglsandbox.cpp
+++ b/indra/newview/llglsandbox.cpp
@@ -993,9 +993,8 @@ private:
 //-----------------------------------------------------------------------------
 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/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp
index be5c22e7c3..7dcf29eb75 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/pipeline.cpp b/indra/newview/pipeline.cpp
index d7acf2ec0e..c0b469af81 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;
@@ -1393,10 +1392,7 @@ void LLPipeline::restoreGL()
 
 bool LLPipeline::canUseVertexShaders()
 {
-	if (sDisableShaders ||
-		!gGLManager.mHasVertexShader ||
-		!gGLManager.mHasFragmentShader ||
-		(assertInitialized() && mVertexShadersLoaded != 1) )
+	if ((assertInitialized() && mVertexShadersLoaded != 1) )
 	{
 		return false;
 	}
@@ -1408,8 +1404,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);
 }
 
diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h
index 0eaa6b141d..5605d26410 100644
--- a/indra/newview/pipeline.h
+++ b/indra/newview/pipeline.h
@@ -574,7 +574,6 @@ public:
 	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;
-- 
cgit v1.2.3


From 1ef78e2afa9e8424dd5d84b2b104b31e72e9e95a Mon Sep 17 00:00:00 2001
From: Nat Goodspeed <nat@lindenlab.com>
Date: Wed, 6 Oct 2021 15:28:58 -0400
Subject: SL-16024: Work around VS bug regarding base-class enum.

---
 indra/llcommon/threadsafeschedule.h | 12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)

(limited to 'indra')

diff --git a/indra/llcommon/threadsafeschedule.h b/indra/llcommon/threadsafeschedule.h
index 8ab4311ca1..0e70d30714 100644
--- a/indra/llcommon/threadsafeschedule.h
+++ b/indra/llcommon/threadsafeschedule.h
@@ -73,7 +73,9 @@ namespace LL
     private:
         using super = LLThreadSafeQueue<TimeTuple, ThreadSafeSchedulePrivate::TimedQueue<Args...>>;
         using lock_t = typename super::lock_t;
-        using pop_result = typename super::pop_result;
+        // 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 TimePoint = ThreadSafeSchedulePrivate::TimePoint;
@@ -230,11 +232,11 @@ namespace LL
                 // 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 == super::POPPED)
+                if (popped == POPPED)
                     return std::move(tt);
 
                 // DONE: throw, just as super::pop() does
-                if (popped == super::DONE)
+                if (popped == DONE)
                 {
                     LLTHROW(LLThreadSafeQueueInterrupt());
                 }
@@ -294,7 +296,7 @@ namespace LL
                 {
                     // Use our time_point_cast to allow for 'until' that's a
                     // time_point type other than TimePoint.
-                    return super::POPPED ==
+                    return POPPED ==
                         tryPopUntil_(lock, LL::time_point_cast<TimePoint>(until), tuple);
                 });
         }
@@ -310,7 +312,7 @@ namespace LL
             }
             // now delegate to base-class tryPopUntil_()
             pop_result popped;
-            while ((popped = super::tryPopUntil_(lock, adjusted, tuple)) == super::WAITING)
+            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
-- 
cgit v1.2.3


From 2cb09dd4a828756dce6180505c63851aa9875187 Mon Sep 17 00:00:00 2001
From: Nat Goodspeed <nat@lindenlab.com>
Date: Thu, 7 Oct 2021 11:53:45 -0400
Subject: SL-16024: Return shared_ptr from LLInstanceTracker::getInstance().

It feels wrong to return a dumb LLInstanceTracker subclass* from getInstance()
when we use std::shared_ptr and std::weak_ptr internally. But tweak consumers
to use 'auto' or LLInstanceTracker::ptr_t in case we later revisit this
decision.

We did add a couple get() calls where it's important to obtain a dumb pointer.
---
 indra/llcommon/llinstancetracker.h           | 59 ++++++++++++++++++++--------
 indra/llcommon/llleaplistener.cpp            |  2 +-
 indra/llui/llnotifications.cpp               |  2 +-
 indra/llui/llstatbar.cpp                     | 20 ++++------
 indra/llxml/llcontrol.h                      |  8 ++--
 indra/newview/llappviewer.cpp                |  4 +-
 indra/newview/llbrowsernotification.cpp      |  4 +-
 indra/newview/llfloaterwebcontent.cpp        |  4 +-
 indra/newview/llnotificationofferhandler.cpp |  4 +-
 indra/newview/llviewercontrollistener.cpp    |  8 ++--
 indra/newview/llviewermessage.cpp            |  4 +-
 11 files changed, 71 insertions(+), 48 deletions(-)

(limited to 'indra')

diff --git a/indra/llcommon/llinstancetracker.h b/indra/llcommon/llinstancetracker.h
index 402333cca7..02535a59e7 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 @@ public:
         // 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 @@ public:
         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 @@ protected:
         // 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 @@ private:
     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 @@ private:
             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 @@ private:
     }
 
 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 @@ public:
      * 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 @@ public:
         // 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 @@ protected:
 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 3e6ce9092c..11bfec1b31 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/llui/llnotifications.cpp b/indra/llui/llnotifications.cpp
index b791a19c2b..88eda1c172 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 6c8e63442b..8adcd664df 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/llxml/llcontrol.h b/indra/llxml/llcontrol.h
index 19508becc3..5da13f5010 100644
--- a/indra/llxml/llcontrol.h
+++ b/indra/llxml/llcontrol.h
@@ -405,8 +405,8 @@ public:
 					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 @@ public:
 	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/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 891722e1bd..4a9a1ad0d4 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -2336,7 +2336,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;
@@ -2638,7 +2638,7 @@ bool LLAppViewer::initConfiguration()
 					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
diff --git a/indra/newview/llbrowsernotification.cpp b/indra/newview/llbrowsernotification.cpp
index 0460bff1b4..30ac35fff7 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/llfloaterwebcontent.cpp b/indra/newview/llfloaterwebcontent.cpp
index 23fd6d9c8e..ceab472c55 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/llnotificationofferhandler.cpp b/indra/newview/llnotificationofferhandler.cpp
index a9678b1e93..d9359d20cf 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/llviewercontrollistener.cpp b/indra/newview/llviewercontrollistener.cpp
index 3443bb644a..8820f9ec56 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/llviewermessage.cpp b/indra/newview/llviewermessage.cpp
index 39c891c9c1..94d2d216b9 100644
--- a/indra/newview/llviewermessage.cpp
+++ b/indra/newview/llviewermessage.cpp
@@ -3978,8 +3978,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);
-- 
cgit v1.2.3


From b554c9eaf45c83500e6b65e295cc507b9a3d537b Mon Sep 17 00:00:00 2001
From: Nat Goodspeed <nat@lindenlab.com>
Date: Thu, 7 Oct 2021 14:00:39 -0400
Subject: SL-16024: Adapt llinstancetracker_test.cpp to getInstance() change.

---
 indra/llcommon/tests/llinstancetracker_test.cpp | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

(limited to 'indra')

diff --git a/indra/llcommon/tests/llinstancetracker_test.cpp b/indra/llcommon/tests/llinstancetracker_test.cpp
index 9b89159625..5daa29adf4 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);
     }
-- 
cgit v1.2.3


From 6e06d1db6045df2e4961243f379c4d7695a8190d Mon Sep 17 00:00:00 2001
From: Nat Goodspeed <nat@lindenlab.com>
Date: Thu, 7 Oct 2021 15:32:19 -0400
Subject: SL-16024: Make LLCond::get() lock and return by value.

Its previous behavior, returning a const reference without locking, was wrong:
it could return a reference to an object in an inconsistent state if it was
concurrently being modified on another thread.

Locking the mutex and returning a copy by value is the correct behavior.
---
 indra/llcommon/llcond.h | 24 +++++++++++++++---------
 1 file changed, 15 insertions(+), 9 deletions(-)

(limited to 'indra')

diff --git a/indra/llcommon/llcond.h b/indra/llcommon/llcond.h
index e31b67d893..c08acb66a1 100644
--- a/indra/llcommon/llcond.h
+++ b/indra/llcommon/llcond.h
@@ -53,6 +53,8 @@ private:
     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 @@ public:
     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 @@ public:
     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 @@ public:
     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 @@ public:
     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 @@ private:
     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
-- 
cgit v1.2.3


From 623ac79120a417ec445ce5c106a907fe46734309 Mon Sep 17 00:00:00 2001
From: Nat Goodspeed <nat@lindenlab.com>
Date: Thu, 7 Oct 2021 15:32:51 -0400
Subject: SL-16024: Add LL::WorkQueue for passing work items between threads.

A typical WorkQueue has a string name, which can be used to find it to post
work to it. "Work" is a nullary callable.

WorkQueue is a multi-producer, multi-consumer thread-safe queue: multiple
threads can service the WorkQueue, multiple threads can post work to it.

Work can be scheduled in the future by submitting with a timestamp. In
addition, a given work item can be scheduled to run on a recurring basis.

A requesting thread servicing a WorkQueue of its own, such as the viewer's
main thread, can submit work to another WorkQueue along with a callback to be
passed the result (of arbitrary type) of the first work item. The callback is
posted to the originating WorkQueue, permitting safe data exchange between
participating threads.

Methods are provided for different kinds of servicing threads. runUntilClose()
is useful for a simple worker thread. runFor(duration) devotes no more than a
specified time slice to that WorkQueue, e.g. for use by the main thread.
---
 indra/llcommon/CMakeLists.txt           |   3 +
 indra/llcommon/tests/workqueue_test.cpp | 158 ++++++++++++++++
 indra/llcommon/threadsafeschedule.h     |   1 +
 indra/llcommon/workqueue.cpp            | 114 +++++++++++
 indra/llcommon/workqueue.h              | 325 ++++++++++++++++++++++++++++++++
 5 files changed, 601 insertions(+)
 create mode 100644 indra/llcommon/tests/workqueue_test.cpp
 create mode 100644 indra/llcommon/workqueue.cpp
 create mode 100644 indra/llcommon/workqueue.h

(limited to 'indra')

diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt
index 5efcfabf24..a3dbb6d9d0 100644
--- a/indra/llcommon/CMakeLists.txt
+++ b/indra/llcommon/CMakeLists.txt
@@ -121,6 +121,7 @@ set(llcommon_SOURCE_FILES
     llworkerthread.cpp
     timing.cpp
     u64.cpp
+    workqueue.cpp
     StackWalker.cpp
     )
     
@@ -258,6 +259,7 @@ set(llcommon_HEADER_FILES
     timer.h
     tuple.h
     u64.h
+    workqueue.h
     StackWalker.h
     )
 
@@ -363,6 +365,7 @@ if (LL_TESTS)
   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/tests/workqueue_test.cpp b/indra/llcommon/tests/workqueue_test.cpp
new file mode 100644
index 0000000000..ab1cae6c14
--- /dev/null
+++ b/indra/llcommon/tests/workqueue_test.cpp
@@ -0,0 +1,158 @@
+/**
+ * @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.
+        // Inject a fake start time that's (interval) earlier than that, to
+        // make our too early/too late tests uniform for all entries.
+        result.push_front(start - interval);
+        for (size_t i = 1; i < result.size(); ++i)
+        {
+            auto diff = (result[i] - result[i-1]);
+            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
index 0e70d30714..c8ad23532b 100644
--- a/indra/llcommon/threadsafeschedule.h
+++ b/indra/llcommon/threadsafeschedule.h
@@ -78,6 +78,7 @@ namespace LL
         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;
 
diff --git a/indra/llcommon/workqueue.cpp b/indra/llcommon/workqueue.cpp
new file mode 100644
index 0000000000..15e292fb43
--- /dev/null
+++ b/indra/llcommon/workqueue.cpp
@@ -0,0 +1,114 @@
+/**
+ * @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 "llerror.h"
+#include "llexception.h"
+#include "stringize.h"
+
+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 thread_local U32 discriminator = 0;
+    return STRINGIZE("WorkQueue" << discriminator++);
+}
+
+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 0000000000..a52f7b0e26
--- /dev/null
+++ b/indra/llcommon/workqueue.h
@@ -0,0 +1,325 @@
+/**
+ * @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.
+         */
+        template <typename CALLABLE, typename CALLBACK>
+        bool postTo(std::weak_ptr<WorkQueue> target,
+                    const TimePoint& time, CALLABLE&& callable, CALLBACK&& 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 CALLBACK>
+        bool postTo(std::weak_ptr<WorkQueue> target,
+                    CALLABLE&& callable, CALLBACK&& 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(std::weak_ptr<WorkQueue> 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:
+        std::weak_ptr<WorkQueue> 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) */
-- 
cgit v1.2.3


From c585ddb75e383cdd994d0d99fed8f2de8f955e3c Mon Sep 17 00:00:00 2001
From: Nat Goodspeed <nat@lindenlab.com>
Date: Thu, 7 Oct 2021 16:45:15 -0400
Subject: SL-16024: Defend against two threads making "anonymous" WorkQueues.

Also make workqueue_test.cpp more robust.
---
 indra/llcommon/tests/workqueue_test.cpp | 11 ++++++-----
 indra/llcommon/workqueue.cpp            | 18 ++++++++++++++++--
 2 files changed, 22 insertions(+), 7 deletions(-)

(limited to 'indra')

diff --git a/indra/llcommon/tests/workqueue_test.cpp b/indra/llcommon/tests/workqueue_test.cpp
index ab1cae6c14..d5405400fd 100644
--- a/indra/llcommon/tests/workqueue_test.cpp
+++ b/indra/llcommon/tests/workqueue_test.cpp
@@ -103,12 +103,13 @@ namespace tut
         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.
-        // Inject a fake start time that's (interval) earlier than that, to
-        // make our too early/too late tests uniform for all entries.
-        result.push_front(start - interval);
-        for (size_t i = 1; i < result.size(); ++i)
+        // 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] - result[i-1]);
+            auto diff = result[i] - start;
+            start += interval;
             try
             {
                 ensure(STRINGIZE("call " << i << " too soon"), diff >= interval);
diff --git a/indra/llcommon/workqueue.cpp b/indra/llcommon/workqueue.cpp
index 15e292fb43..ffc9a97dc0 100644
--- a/indra/llcommon/workqueue.cpp
+++ b/indra/llcommon/workqueue.cpp
@@ -17,10 +17,15 @@
 // 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))
 {
@@ -83,8 +88,17 @@ std::string LL::WorkQueue::makeName(const std::string& name)
     if (! name.empty())
         return name;
 
-    static thread_local U32 discriminator = 0;
-    return STRINGIZE("WorkQueue" << discriminator++);
+    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)
-- 
cgit v1.2.3


From 54d874b1233586844f87e79ae8f211af0a1cb7a6 Mon Sep 17 00:00:00 2001
From: Nat Goodspeed <nat@lindenlab.com>
Date: Fri, 8 Oct 2021 11:52:09 -0400
Subject: SL-16024: Resolve bizarre VS compile error. Thanks Callum!

It seems CALLBACK is a macro in some Microsoft header file. Bleah.
---
 indra/llcommon/workqueue.h | 20 ++++++++++++--------
 1 file changed, 12 insertions(+), 8 deletions(-)

(limited to 'indra')

diff --git a/indra/llcommon/workqueue.h b/indra/llcommon/workqueue.h
index a52f7b0e26..b88aef989a 100644
--- a/indra/llcommon/workqueue.h
+++ b/indra/llcommon/workqueue.h
@@ -104,9 +104,13 @@ namespace LL
          * Returns true if able to post, false if the other WorkQueue is
          * inaccessible.
          */
-        template <typename CALLABLE, typename CALLBACK>
-        bool postTo(std::weak_ptr<WorkQueue> target,
-                    const TimePoint& time, CALLABLE&& callable, CALLBACK&& callback)
+        // 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.
@@ -170,9 +174,9 @@ namespace LL
          * Returns true if able to post, false if the other WorkQueue is
          * inaccessible.
          */
-        template <typename CALLABLE, typename CALLBACK>
-        bool postTo(std::weak_ptr<WorkQueue> target,
-                    CALLABLE&& callable, CALLBACK&& callback)
+        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));
         }
@@ -243,7 +247,7 @@ namespace LL
     {
     public:
         // bind the desired data
-        BackJack(std::weak_ptr<WorkQueue> target,
+        BackJack(WorkQueue::weak_t target,
                  const WorkQueue::TimePoint& start,
                  const std::chrono::duration<Rep, Period>& interval,
                  CALLABLE&& callable):
@@ -291,7 +295,7 @@ namespace LL
         }
 
     private:
-        std::weak_ptr<WorkQueue> mTarget;
+        WorkQueue::weak_t mTarget;
         WorkQueue::TimePoint mStart;
         std::chrono::duration<Rep, Period> mInterval;
         CALLABLE mCallable;
-- 
cgit v1.2.3


From 2238f89db70a754614b01bb85adc5f16a63e7eb4 Mon Sep 17 00:00:00 2001
From: Mnikolenko Productengine <mnikolenko@productengine.com>
Date: Mon, 11 Oct 2021 18:05:27 +0300
Subject: SL-16141 Load fonts and generate glyphs on startup

---
 indra/llrender/llfontgl.cpp       | 31 +++++++++++++++++++++++--------
 indra/llrender/llfontgl.h         |  4 +++-
 indra/llrender/llfontregistry.cpp |  5 +++++
 indra/newview/llviewerwindow.cpp  | 19 +++++++++----------
 4 files changed, 40 insertions(+), 19 deletions(-)

(limited to 'indra')

diff --git a/indra/llrender/llfontgl.cpp b/indra/llrender/llfontgl.cpp
index 86a4c35e6d..266399d212 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 10891faed9..3b58a37d33 100644
--- a/indra/llrender/llfontgl.h
+++ b/indra/llrender/llfontgl.h
@@ -160,12 +160,15 @@ public:
 
 	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 @@ public:
 	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 33a33af160..bc1a2f8887 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/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index 2157585364..c52a4e98d3 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -1963,6 +1963,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
@@ -2009,14 +2016,6 @@ LLViewerWindow::LLViewerWindow(const Params& p)
 	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");
@@ -2102,6 +2101,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.)
@@ -5499,8 +5500,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()
-- 
cgit v1.2.3


From d00272e0cc9974f35a46f0c313ee2c0e11cddbda Mon Sep 17 00:00:00 2001
From: Dave Parks <davep@lindenlab.com>
Date: Mon, 11 Oct 2021 16:03:40 +0000
Subject: SL-16099 Multi-threaded OpenGL usage on Windows, enable Core Profile
 and VAOs by default.

---
 indra/llcommon/llthreadsafequeue.h      |   3 +
 indra/llimage/llimageworker.cpp         |   4 +
 indra/llrender/llcubemap.cpp            |   2 +
 indra/llrender/llfontfreetype.cpp       |   1 +
 indra/llrender/llglslshader.cpp         |   2 +
 indra/llrender/llgltexture.cpp          |   2 +
 indra/llrender/llimagegl.cpp            | 330 +++++++++++++++++++++-----------
 indra/llrender/llimagegl.h              |  35 +++-
 indra/llrender/llrender.cpp             |   2 +-
 indra/llrender/llrender.h               |   2 +-
 indra/llwindow/llopenglview-objc.mm     |   3 +-
 indra/llwindow/llwindow.h               |  12 +-
 indra/llwindow/llwindowheadless.h       |   3 +
 indra/llwindow/llwindowmacosx.cpp       |  28 +++
 indra/llwindow/llwindowmacosx.h         | 144 +++++++-------
 indra/llwindow/llwindowwin32.cpp        | 129 ++++++++-----
 indra/llwindow/llwindowwin32.h          |   3 +
 indra/newview/app_settings/settings.xml |   4 +-
 indra/newview/llappviewer.cpp           |   3 +-
 indra/newview/llnetmap.cpp              |   1 +
 indra/newview/lltexturefetch.cpp        |   4 +
 indra/newview/llviewertexture.cpp       | 311 +++++++++++++++++++-----------
 indra/newview/llviewertexture.h         |   8 +-
 indra/newview/llviewertexturelist.cpp   |  36 ++++
 indra/newview/llviewerwindow.cpp        |   2 +-
 25 files changed, 718 insertions(+), 356 deletions(-)

(limited to 'indra')

diff --git a/indra/llcommon/llthreadsafequeue.h b/indra/llcommon/llthreadsafequeue.h
index 719edcd579..06e8d8f609 100644
--- a/indra/llcommon/llthreadsafequeue.h
+++ b/indra/llcommon/llthreadsafequeue.h
@@ -154,6 +154,9 @@ public:
 	// Returns the size of the queue.
 	size_t size();
 
+    //Returns the capacity of the queue.
+    U32 capacity() { return mCapacity; }
+
 	// closes the queue:
 	// - every subsequent push() call will throw LLThreadSafeQueueInterrupt
 	// - every subsequent tryPush() call will return false
diff --git a/indra/llimage/llimageworker.cpp b/indra/llimage/llimageworker.cpp
index 5f42fba866..33f8dce6ee 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/llrender/llcubemap.cpp b/indra/llrender/llcubemap.cpp
index 5947bca670..d7f7b2f58e 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 c41730ebaa..e18161e53c 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/llglslshader.cpp b/indra/llrender/llglslshader.cpp
index 2fb3b8257d..394fcd2b2f 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);
diff --git a/indra/llrender/llgltexture.cpp b/indra/llrender/llgltexture.cpp
index ad501687ed..a279e85bae 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/llimagegl.cpp b/indra/llrender/llimagegl.cpp
index 276fa55e15..aff29bd857 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,119 +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();
-	{
-		LL_PROFILE_ZONE_NAMED("glTexImage2D");
-		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
@@ -1336,6 +1356,7 @@ BOOL LLImageGL::createGLTexture()
 	if(mTexName)
 	{
 		LLImageGL::deleteTextures(1, (reinterpret_cast<GLuint*>(&mTexName))) ;
+        mTexName = 0;
 	}
 	
 
@@ -1697,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 ;
@@ -2238,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 61ddc8d59b..8e9b483c2d 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 @@ public:
 	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 @@ public:
 #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 @@ public:
 
 };
 
+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 43b4441ea8..b6711e44e3 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];
diff --git a/indra/llrender/llrender.h b/indra/llrender/llrender.h
index af8568f8a3..c08c2d6881 100644
--- a/indra/llrender/llrender.h
+++ b/indra/llrender/llrender.h
@@ -511,7 +511,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/llwindow/llopenglview-objc.mm b/indra/llwindow/llopenglview-objc.mm
index d2c5b11c3d..b647085b7e 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 d4d5b76937..10c0b6a424 100644
--- a/indra/llwindow/llwindow.h
+++ b/indra/llwindow/llwindow.h
@@ -78,7 +78,17 @@ public:
 	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 c692666df1..a7ae28aa24 100644
--- a/indra/llwindow/llwindowheadless.h
+++ b/indra/llwindow/llwindowheadless.h
@@ -49,6 +49,9 @@ public:
 	/*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 0d0607a0bb..23830dd24e 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 bf45238c8d..ede2b453d5 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 @@ public:
     
     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 @@ protected:
 		~LLWindowMacOSX();
 
 	void	initCursors();
-	BOOL	isValid();
+	BOOL	isValid() override;
 	void	moveWindow(const LLCoordScreen& position,const LLCoordScreen& size);
 
 
@@ -157,7 +165,7 @@ protected:
 	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 @@ public:
 	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 4ce7c30bef..12d4c6c30e 100644
--- a/indra/llwindow/llwindowwin32.cpp
+++ b/indra/llwindow/llwindowwin32.cpp
@@ -1774,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))
@@ -1880,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 )
@@ -3720,6 +3742,7 @@ BOOL LLWindowWin32::resetDisplayResolution()
 
 void LLWindowWin32::swapBuffers()
 {
+    LL_PROFILE_ZONE_SCOPED;
     ASSERT_MAIN_THREAD();
 	SwapBuffers(mhDC);
 
@@ -4731,4 +4754,4 @@ void LLWindowWin32::post(const std::function<void()>& func)
 #else
     mFunctionQueue.pushFront(func);
 #endif
-}
\ No newline at end of file
+}
diff --git a/indra/llwindow/llwindowwin32.h b/indra/llwindow/llwindowwin32.h
index 66647459b2..5f253b5df3 100644
--- a/indra/llwindow/llwindowwin32.h
+++ b/indra/llwindow/llwindowwin32.h
@@ -93,6 +93,9 @@ public:
 	/*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);
+    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();
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 05c3fc3bfe..d05d100ddf 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -9814,7 +9814,7 @@
       <key>Type</key>
       <string>Boolean</string>
       <key>Value</key>
-      <integer>0</integer>
+      <integer>1</integer>
     </map>
     <key>RenderGlow</key>
     <map>
@@ -10599,7 +10599,7 @@
       <key>Type</key>
       <string>Boolean</string>
       <key>Value</key>
-      <integer>0</integer>
+      <integer>1</integer>
     </map>
   <key>RenderUseTransformFeedback</key>
   <map>
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 722a6caa65..e46e8feb14 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -613,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");
 }
 
@@ -4831,6 +4831,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();
diff --git a/indra/newview/llnetmap.cpp b/indra/newview/llnetmap.cpp
index 112da55682..111b45612e 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/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp
index f64db7beb5..63e561147d 100644
--- a/indra/newview/lltexturefetch.cpp
+++ b/indra/newview/lltexturefetch.cpp
@@ -314,6 +314,7 @@ private:
 		// Threads:  Ttc
 		virtual void completed(bool success)
 		{
+            LL_PROFILE_ZONE_SCOPED;
 			LLTextureFetchWorker* worker = mFetcher->getWorker(mID);
 			if (worker)
 			{
@@ -338,6 +339,7 @@ private:
 		// Threads:  Ttc
 		virtual void completed(bool success)
 		{
+            LL_PROFILE_ZONE_SCOPED;
 			LLTextureFetchWorker* worker = mFetcher->getWorker(mID);
 			if (worker)
 			{
@@ -362,6 +364,7 @@ private:
 		// 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;
 	static const LLCore::HttpStatus http_not_found(HTTP_NOT_FOUND);						// 404
 	static const LLCore::HttpStatus http_service_unavail(HTTP_SERVICE_UNAVAILABLE);		// 503
 	static const LLCore::HttpStatus http_not_sat(HTTP_REQUESTED_RANGE_NOT_SATISFIABLE);	// 416;
diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp
index af55f68cd2..274f53a160 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();
@@ -485,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.
@@ -501,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);
 
@@ -514,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);
@@ -526,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");
@@ -555,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);
@@ -704,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++)
@@ -715,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++)
@@ -727,6 +736,7 @@ void LLViewerTexture::notifyAboutMissingAsset()
 // virtual
 void LLViewerTexture::dump()
 {
+    LL_PROFILE_ZONE_SCOPED;
 	LLGLTexture::dump();
 
 	LL_INFOS() << "LLViewerTexture"
@@ -762,6 +772,7 @@ bool LLViewerTexture::isActiveFetching()
 
 bool LLViewerTexture::bindDebugImage(const S32 stage)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	if (stage < 0) return false;
 
 	bool res = true;
@@ -780,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;
@@ -822,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;
@@ -864,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())
@@ -879,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)
@@ -919,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);
@@ -932,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); 
@@ -955,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;
 
@@ -978,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;
 
@@ -1180,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(); )
 	{
@@ -1205,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.
@@ -1350,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 ;
@@ -1366,6 +1388,7 @@ void LLViewerFetchedTexture::destroyTexture()
 
 void LLViewerFetchedTexture::addToCreateTexture()
 {
+    LL_PROFILE_ZONE_SCOPED;
 	bool force_update = false;
 	if (getComponents() != mRawImage->getComponents())
 	{
@@ -1407,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,
@@ -1451,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())
     {
@@ -1565,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.
@@ -1869,6 +1954,7 @@ void LLViewerFetchedTexture::setAdditionalDecodePriority(F32 priority)
 
 void LLViewerFetchedTexture::updateVirtualSize() 
 {	
+    LL_PROFILE_ZONE_SCOPED;
 	if(!mMaxVirtualSizeResetCounter)
 	{
 		addTextureStats(0.f, FALSE);//reset
@@ -1960,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);
@@ -2062,7 +2149,7 @@ bool LLViewerFetchedTexture::updateFetch()
 				}
 				else
 				{
-					mIsRawImageValid = TRUE;			
+					mIsRawImageValid = TRUE;
 					addToCreateTexture();
 				}
 
@@ -2890,6 +2977,7 @@ void LLViewerFetchedTexture::destroyRawImage()
 //virtual
 void LLViewerFetchedTexture::switchToCachedImage()
 {
+    LL_PROFILE_ZONE_SCOPED;
 	if(mCachedRawImage.notNull())
 	{
 		mRawImage = mCachedRawImage;
@@ -2901,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();
 	}
 }
 
@@ -3180,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 69568cc825..a5a1fb2c16 100644
--- a/indra/newview/llviewertexture.h
+++ b/indra/newview/llviewertexture.h
@@ -321,9 +321,13 @@ public:
 
 	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 12495078e9..db740b69e9 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)
@@ -634,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);
@@ -653,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);
@@ -701,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;
@@ -724,6 +736,7 @@ void LLViewerTextureList::addImage(LLViewerFetchedTexture *new_image, ETexListTy
 
 void LLViewerTextureList::deleteImage(LLViewerFetchedTexture *image)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	if( image)
 	{
 		if (image->hasCallbacks())
@@ -845,6 +858,7 @@ void LLViewerTextureList::updateImages(F32 max_time)
 
 void LLViewerTextureList::clearFetchingRequests()
 {
+    LL_PROFILE_ZONE_SCOPED;
 	if (LLAppViewer::getTextureFetch()->getNumRequests() == 0)
 	{
 		return;
@@ -862,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
@@ -977,6 +992,7 @@ void LLViewerTextureList::updateImagesDecodePriorities()
 
 void LLViewerTextureList::setDebugFetching(LLViewerFetchedTexture* tex, S32 debug_level)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	if(!tex->setDebugFetching(debug_level))
 	{
 		return;
@@ -1025,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;
 	
 	//
@@ -1041,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;
@@ -1052,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())
 	{
@@ -1082,6 +1101,7 @@ F32 LLViewerTextureList::updateImagesLoadingFastCache(F32 max_time)
 
 void LLViewerTextureList::forceImmediateUpdate(LLViewerFetchedTexture* imagep)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	if(!imagep)
 	{
 		return ;
@@ -1101,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
@@ -1176,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();
@@ -1190,6 +1212,7 @@ void LLViewerTextureList::updateImagesUpdateStats()
 
 void LLViewerTextureList::decodeAllImages(F32 max_time)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	LLTimer timer;
 
 	//loading from fast cache 
@@ -1259,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())
@@ -1312,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();
 	
@@ -1345,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 ;
@@ -1354,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)
 	{
@@ -1407,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");
@@ -1647,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();
 
@@ -1665,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())
@@ -1682,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;
@@ -1694,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;
@@ -1705,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);
@@ -1742,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())
@@ -1756,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;
@@ -1857,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 c52a4e98d3..82ece85c1b 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -2011,7 +2011,7 @@ 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();
-- 
cgit v1.2.3


From 75cf90723f63d1d80b2a3b4b8aa9536cadcda8cb Mon Sep 17 00:00:00 2001
From: Runitai Linden <davep@lindenlab.com>
Date: Mon, 11 Oct 2021 11:48:43 -0500
Subject: SL-16099 Followup -- disable VAOs since they still run like garbage
 in busy scenes.

---
 indra/newview/app_settings/settings.xml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'indra')

diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index d05d100ddf..eeadea76a2 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -10599,7 +10599,7 @@
       <key>Type</key>
       <string>Boolean</string>
       <key>Value</key>
-      <integer>1</integer>
+      <integer>0</integer>
     </map>
   <key>RenderUseTransformFeedback</key>
   <map>
-- 
cgit v1.2.3


From 52e1a45659341df68eca01822f189e0883afe66d Mon Sep 17 00:00:00 2001
From: Runitai Linden <davep@lindenlab.com>
Date: Tue, 12 Oct 2021 14:46:19 -0500
Subject: SL-16166 Optimization pass on LLRenderPass::pushBatch

---
 indra/llrender/llgltexture.h          |   2 +-
 indra/llrender/llrender.cpp           |  18 +++-
 indra/llrender/llrender.h             |  11 +++
 indra/llrender/lltexture.h            |   4 +-
 indra/llrender/llvertexbuffer.cpp     | 155 ++++++++++++++++++++++++++++++++++
 indra/llrender/llvertexbuffer.h       |  11 ++-
 indra/newview/lldrawpool.cpp          |  29 +++----
 indra/newview/lldrawpoolmaterials.cpp |   1 +
 indra/newview/lldrawpoolsimple.cpp    |   1 +
 indra/newview/lldrawpooltree.cpp      |   1 +
 indra/newview/llspatialpartition.h    |   7 +-
 indra/newview/llviewertexture.cpp     |   6 +-
 indra/newview/pipeline.cpp            |  52 +++++++-----
 indra/newview/pipeline.h              |   3 +-
 14 files changed, 247 insertions(+), 54 deletions(-)

(limited to 'indra')

diff --git a/indra/llrender/llgltexture.h b/indra/llrender/llgltexture.h
index 071912c2c2..028457c510 100644
--- a/indra/llrender/llgltexture.h
+++ b/indra/llrender/llgltexture.h
@@ -176,7 +176,7 @@ private:
 protected:
 	void setTexelsPerImage();
 
-	//note: do not make this function public.
+public:
 	/*virtual*/ LLImageGL* getGLTexture() const ;
 
 protected:
diff --git a/indra/llrender/llrender.cpp b/indra/llrender/llrender.cpp
index b6711e44e3..34c5b77944 100644
--- a/indra/llrender/llrender.cpp
+++ b/indra/llrender/llrender.cpp
@@ -169,6 +169,7 @@ void LLTexUnit::refreshState(void)
 
 void LLTexUnit::activate(void)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	if (mIndex < 0) return;
 
 	if ((S32)gGL.mCurrTextureUnitIndex != mIndex || gGL.mDirty)
@@ -229,8 +230,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)
 	{
@@ -1243,8 +1256,6 @@ void LLRender::syncLightState()
 
 void LLRender::syncMatrices()
 {
-	stop_glerror();
-
 	static const U32 name[] = 
 	{
 		LLShaderMgr::MODELVIEW_MATRIX,
@@ -1415,8 +1426,6 @@ void LLRender::syncMatrices()
 			}
 		}
 	}
-
-	stop_glerror();
 }
 
 void LLRender::translatef(const GLfloat& x, const GLfloat& y, const GLfloat& z)
@@ -1925,6 +1934,7 @@ void LLRender::end()
 }
 void LLRender::flush()
 {
+    LL_PROFILE_ZONE_SCOPED;
 	if (mCount > 0)
 	{
 		if (!mUIOffset.empty())
diff --git a/indra/llrender/llrender.h b/indra/llrender/llrender.h
index c08c2d6881..658cdda504 100644
--- a/indra/llrender/llrender.h
+++ b/indra/llrender/llrender.h
@@ -161,6 +161,17 @@ public:
 	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);
diff --git a/indra/llrender/lltexture.h b/indra/llrender/lltexture.h
index 41481fb8a7..256d85ce5a 100644
--- a/indra/llrender/lltexture.h
+++ b/indra/llrender/lltexture.h
@@ -67,11 +67,9 @@ public:
 	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 0449ac392c..7b9388123f 100644
--- a/indra/llrender/llvertexbuffer.cpp
+++ b/indra/llrender/llvertexbuffer.cpp
@@ -787,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);
@@ -2272,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)
@@ -2297,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())
@@ -2487,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)
+    {
+        setupVertexBuffer(data_mask); // subclass specific setup (virtual function)
+        sSetCount++;
+    }
+}
+
 // virtual (default)
 void LLVertexBuffer::setupVertexBuffer(U32 data_mask)
 {
@@ -2644,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 1d60970df4..51ed85510e 100644
--- a/indra/llrender/llvertexbuffer.h
+++ b/indra/llrender/llvertexbuffer.h
@@ -210,13 +210,17 @@ protected:
 
 	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();
@@ -239,6 +243,8 @@ public:
 
 	// 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);
@@ -290,6 +296,9 @@ public:
 	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/newview/lldrawpool.cpp b/indra/newview/lldrawpool.cpp
index d583a692f9..01dd307187 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;
@@ -495,19 +496,17 @@ void LLRenderPass::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture, BOOL ba
 		}
 	}
 	
-	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/lldrawpoolmaterials.cpp b/indra/newview/lldrawpoolmaterials.cpp
index 05b0c1f1a9..d45e387e10 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,
diff --git a/indra/newview/lldrawpoolsimple.cpp b/indra/newview/lldrawpoolsimple.cpp
index 74e6665a96..ba8549904b 100644
--- a/indra/newview/lldrawpoolsimple.cpp
+++ b/indra/newview/lldrawpoolsimple.cpp
@@ -471,6 +471,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);
 
diff --git a/indra/newview/lldrawpooltree.cpp b/indra/newview/lldrawpooltree.cpp
index 0d5195bdbf..a1ff020068 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/llspatialpartition.h b/indra/newview/llspatialpartition.h
index 919f386d29..6ef82fac9c 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 @@ public:
 	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/llviewertexture.cpp b/indra/newview/llviewertexture.cpp
index 274f53a160..949e71a4c9 100644
--- a/indra/newview/llviewertexture.cpp
+++ b/indra/newview/llviewertexture.cpp
@@ -845,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()
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index c0b469af81..5ef3819de4 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -358,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;
 
@@ -2550,13 +2549,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)
@@ -3480,7 +3472,6 @@ void LLPipeline::stateSort(LLSpatialGroup* group, LLCamera& camera)
 			group->mLastUpdateDistance = group->mDistance;
 		}
 	}
-
 }
 
 void LLPipeline::stateSort(LLSpatialBridge* bridge, LLCamera& camera, BOOL fov_changed)
@@ -3787,6 +3778,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);
@@ -3839,20 +3851,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);
+                }
 			}
 		}
 
diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h
index 5605d26410..8ffbddca21 100644
--- a/indra/newview/pipeline.h
+++ b/indra/newview/pipeline.h
@@ -265,6 +265,8 @@ public:
 	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);
@@ -596,7 +598,6 @@ public:
 	static bool				sRenderAttachedParticles;
 	static bool				sRenderDeferred;
 	static S32				sVisibleLightCount;
-	static F32				sMinRenderSize;
 	static bool				sRenderingHUDs;
     static F32              sDistortionWaterClipPlaneMargin;
 
-- 
cgit v1.2.3


From 74a2354353813db529ae123858bafba86cd12110 Mon Sep 17 00:00:00 2001
From: Runitai Linden <davep@lindenlab.com>
Date: Wed, 13 Oct 2021 09:37:04 -0500
Subject: SL-16166 Don't use setupVertexBuffer where setupVertexBufferFast is
 called for (thank you, Henri!)

---
 indra/llrender/llvertexbuffer.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'indra')

diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp
index 7b9388123f..103d5388d3 100644
--- a/indra/llrender/llvertexbuffer.cpp
+++ b/indra/llrender/llvertexbuffer.cpp
@@ -2544,7 +2544,7 @@ void LLVertexBuffer::setBufferFast(U32 data_mask)
   
     if (data_mask && setup)
     {
-        setupVertexBuffer(data_mask); // subclass specific setup (virtual function)
+        setupVertexBufferFast(data_mask);
         sSetCount++;
     }
 }
-- 
cgit v1.2.3


From a1e6cbe4a802f92182163171e6743e7f63d89ace Mon Sep 17 00:00:00 2001
From: Runitai Linden <davep@lindenlab.com>
Date: Wed, 13 Oct 2021 10:35:39 -0500
Subject: SL-16166 Apply LLRenderPass::pushBatch optimizations to
 LLDrawPoolBump::pushBatch

---
 indra/llrender/llrender.cpp      | 22 ++++++++++++++++++++++
 indra/llrender/llrender.h        |  3 +++
 indra/newview/lldrawpool.cpp     | 14 ++++++--------
 indra/newview/lldrawpoolbump.cpp | 28 ++++++++--------------------
 4 files changed, 39 insertions(+), 28 deletions(-)

(limited to 'indra')

diff --git a/indra/llrender/llrender.cpp b/indra/llrender/llrender.cpp
index 34c5b77944..91d3c96fbe 100644
--- a/indra/llrender/llrender.cpp
+++ b/indra/llrender/llrender.cpp
@@ -472,6 +472,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;
diff --git a/indra/llrender/llrender.h b/indra/llrender/llrender.h
index 658cdda504..6e2647a16b 100644
--- a/indra/llrender/llrender.h
+++ b/indra/llrender/llrender.h
@@ -188,6 +188,9 @@ public:
 	// (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.
diff --git a/indra/newview/lldrawpool.cpp b/indra/newview/lldrawpool.cpp
index 01dd307187..75d569ffbb 100644
--- a/indra/newview/lldrawpool.cpp
+++ b/indra/newview/lldrawpool.cpp
@@ -496,17 +496,15 @@ void LLRenderPass::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture, BOOL ba
 		}
 	}
 	
+    if (params.mGroup)
     {
-        if (params.mGroup)
-        {
-            params.mGroup->rebuildMesh();
-        }
+        params.mGroup->rebuildMesh();
+    }
 
-        LLGLEnableFunc stencil_test(GL_STENCIL_TEST, params.mSelected, &LLGLCommonFunc::selected_stencil_test);
+    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);
-    }
+    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/lldrawpoolbump.cpp b/indra/newview/lldrawpoolbump.cpp
index 14069fa6c2..7e2dfbfda1 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)
@@ -1497,6 +1498,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 +1509,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 +1524,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 +1540,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 +1553,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 +1564,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);
 		}
-- 
cgit v1.2.3


From 4dedd706ae07c4a1aeedfe9ca0c03b7c905d0b57 Mon Sep 17 00:00:00 2001
From: Runitai Linden <davep@lindenlab.com>
Date: Wed, 13 Oct 2021 11:02:00 -0500
Subject: SL-16189 Optimize bindBumpMap

---
 indra/newview/lldrawpoolbump.cpp | 8 ++++----
 indra/newview/lldrawpoolbump.h   | 4 +++-
 2 files changed, 7 insertions(+), 5 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/lldrawpoolbump.cpp b/indra/newview/lldrawpoolbump.cpp
index 7e2dfbfda1..f316d121ab 100644
--- a/indra/newview/lldrawpoolbump.cpp
+++ b/indra/newview/lldrawpoolbump.cpp
@@ -694,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:
@@ -710,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;
diff --git a/indra/newview/lldrawpoolbump.h b/indra/newview/lldrawpoolbump.h
index 476b1d41b7..bab160c34d 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 @@ private:
 	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;
 };
-- 
cgit v1.2.3


From 6a0b728bd9e75cbee62752033e6460a76e8b0ed6 Mon Sep 17 00:00:00 2001
From: Runitai Linden <davep@lindenlab.com>
Date: Wed, 13 Oct 2021 13:49:24 -0500
Subject: SL-16166 Optimize LLDrawPoolMaterials::pushBatch

---
 indra/newview/lldrawpool.cpp          |  2 +-
 indra/newview/lldrawpoolmaterials.cpp | 61 +++++++++++++++--------------------
 indra/newview/lldrawpoolmaterials.h   |  2 +-
 3 files changed, 28 insertions(+), 37 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/lldrawpool.cpp b/indra/newview/lldrawpool.cpp
index 75d569ffbb..3e4f97e494 100644
--- a/indra/newview/lldrawpool.cpp
+++ b/indra/newview/lldrawpool.cpp
@@ -491,7 +491,7 @@ 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);
 			}
 		}
 	}
diff --git a/indra/newview/lldrawpoolmaterials.cpp b/indra/newview/lldrawpoolmaterials.cpp
index d45e387e10..d2a8757379 100644
--- a/indra/newview/lldrawpoolmaterials.cpp
+++ b/indra/newview/lldrawpoolmaterials.cpp
@@ -158,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);
+        }
 	}
 }
 
@@ -172,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);
 		}
 	}
 	
@@ -225,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 eae1aba87c..6e39821b07 100644
--- a/indra/newview/lldrawpoolmaterials.h
+++ b/indra/newview/lldrawpoolmaterials.h
@@ -69,7 +69,7 @@ public:
 	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
-- 
cgit v1.2.3


From aa2169aa372492b3a5367997536fb6dfa89b74cf Mon Sep 17 00:00:00 2001
From: Runitai Linden <davep@lindenlab.com>
Date: Wed, 13 Oct 2021 13:57:56 -0500
Subject: SL-16166 Remove LLDrawPoolGlow::pushBatch non-specialization

---
 indra/newview/lldrawpoolsimple.cpp | 7 -------
 indra/newview/lldrawpoolsimple.h   | 1 -
 2 files changed, 8 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/lldrawpoolsimple.cpp b/indra/newview/lldrawpoolsimple.cpp
index ba8549904b..843288cfb0 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)
 {
diff --git a/indra/newview/lldrawpoolsimple.h b/indra/newview/lldrawpoolsimple.h
index 608ad9e1eb..b27cc4babc 100644
--- a/indra/newview/lldrawpoolsimple.h
+++ b/indra/newview/lldrawpoolsimple.h
@@ -187,7 +187,6 @@ public:
 	/*virtual*/ S32 getNumPasses();
 
 	void render(S32 pass = 0);
-	void pushBatch(LLDrawInfo& params, U32 mask, BOOL texture = TRUE, BOOL batch_textures = FALSE);
 
 };
 
-- 
cgit v1.2.3


From 851767b808c3cb05d718538389ccc1ed3c95d1a1 Mon Sep 17 00:00:00 2001
From: Dave Parks <davep@lindenlab.com>
Date: Thu, 14 Oct 2021 17:41:38 +0000
Subject: SL-16131 Fix for alignment warnings on Win32 builds.

---
 indra/llcharacter/lleditingmotion.h       |   18 +-
 indra/llcharacter/lljoint.h               |   14 +-
 indra/llcharacter/llkeyframestandmotion.h |   28 +-
 indra/llcharacter/llpose.h                |    6 +-
 indra/llcommon/llmemory.h                 |   13 +
 indra/llprimitive/llmodel.h               |   10 +-
 indra/llwindow/llwindow.h                 |    1 +
 indra/media_plugins/cef/CMakeLists.txt    |    3 -
 indra/newview/llviewertexture.h           | 1592 ++++++++++++++---------------
 9 files changed, 854 insertions(+), 831 deletions(-)

(limited to 'indra')

diff --git a/indra/llcharacter/lleditingmotion.h b/indra/llcharacter/lleditingmotion.h
index 7b1c8bb059..80c1717a70 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 @@ public:
 	//-------------------------------------------------------------------------
 	// 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 @@ public:
 	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.h b/indra/llcharacter/lljoint.h
index ba821667c7..63d99b9209 100644
--- a/indra/llcharacter/lljoint.h
+++ b/indra/llcharacter/lljoint.h
@@ -86,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
@@ -115,17 +117,17 @@ public:
         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;
-    LLMatrix4a          mWorldMatrix;
-
     LLVector3       mDefaultPosition;
     LLVector3       mDefaultScale;
     
@@ -300,6 +302,6 @@ public:
     // 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 c2634ecd6d..1aa5b187ba 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 @@ public:
 	//-------------------------------------------------------------------------
 	// 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 @@ public:
 	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 @@ public:
 	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 c004a0f3b7..1405f1e053 100644
--- a/indra/llcharacter/llpose.h
+++ b/indra/llcharacter/llpose.h
@@ -80,8 +80,10 @@ public:
 
 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 @@ public:
 	void resetCachedJoint();
 
 public:
-	LLJoint mJointCache;
-};
+	LL_ALIGN_16(LLJoint mJointCache);
+} LL_ALIGN_POSTFIX(16);
 
 class LLMotion;
 
diff --git a/indra/llcommon/llmemory.h b/indra/llcommon/llmemory.h
index 24f86cc11e..2704a495e0 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/llprimitive/llmodel.h b/indra/llprimitive/llmodel.h
index 96d4582b4f..cd2b6c6728 100644
--- a/indra/llprimitive/llmodel.h
+++ b/indra/llprimitive/llmodel.h
@@ -40,8 +40,10 @@ class domMesh;
 
 #define MAX_MODEL_FACES 8
 
+LL_ALIGN_PREFIX(16)
 class LLMeshSkinInfo 
 {
+    LL_ALIGN_NEW
 public:
 	LLMeshSkinInfo();
 	LLMeshSkinInfo(LLSD& data);
@@ -55,15 +57,17 @@ public:
 	matrix_list_t mInvBindMatrix;
 	matrix_list_t mAlternateBindMatrix;
 
-	LLMatrix4a 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
@@ -285,7 +289,7 @@ public:
 	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/llwindow/llwindow.h b/indra/llwindow/llwindow.h
index 10c0b6a424..0100c3bf0a 100644
--- a/indra/llwindow/llwindow.h
+++ b/indra/llwindow/llwindow.h
@@ -88,6 +88,7 @@ public:
     //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;
diff --git a/indra/media_plugins/cef/CMakeLists.txt b/indra/media_plugins/cef/CMakeLists.txt
index ce6278963d..76d398576c 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/newview/llviewertexture.h b/indra/newview/llviewertexture.h
index a5a1fb2c16..b6b4d1e41f 100644
--- a/indra/newview/llviewertexture.h
+++ b/indra/newview/llviewertexture.h
@@ -1,796 +1,796 @@
-/** 
- * @file llviewertexture.h
- * @brief Object for managing images and their textures
- *
- * $LicenseInfo:firstyear=2000&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- * 
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- * 
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
- * $/LicenseInfo$
- */
-
-#ifndef LL_LLVIEWERTEXTURE_H					
-#define LL_LLVIEWERTEXTURE_H
-
-#include "llgltexture.h"
-#include "lltimer.h"
-#include "llframetimer.h"
-#include "llhost.h"
-#include "llgltypes.h"
-#include "llrender.h"
-#include "llmetricperformancetester.h"
-#include "httpcommon.h"
-
-#include <map>
-#include <list>
-
-extern const S32Megabytes gMinVideoRam;
-extern const S32Megabytes gMaxVideoRam;
-
-class LLFace;
-class LLImageGL ;
-class LLImageRaw;
-class LLViewerObject;
-class LLViewerTexture;
-class LLViewerFetchedTexture ;
-class LLViewerMediaTexture ;
-class LLTexturePipelineTester ;
-
-
-typedef	void	(*loaded_callback_func)( BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* src_aux, S32 discard_level, BOOL final, void* userdata );
-
-class LLVFile;
-class LLMessageSystem;
-class LLViewerMediaImpl ;
-class LLVOVolume ;
-struct LLTextureKey;
-
-class LLLoadedCallbackEntry
-{
-public:
-    typedef std::set< LLTextureKey > source_callback_list_t;
-
-public:
-	LLLoadedCallbackEntry(loaded_callback_func cb,
-						  S32 discard_level,
-						  BOOL need_imageraw, // Needs image raw for the callback
-						  void* userdata,
-						  source_callback_list_t* src_callback_list,
-						  LLViewerFetchedTexture* target,
-						  BOOL pause);
-	~LLLoadedCallbackEntry();
-	void removeTexture(LLViewerFetchedTexture* tex) ;
-
-	loaded_callback_func	mCallback;
-	S32						mLastUsedDiscard;
-	S32						mDesiredDiscard;
-	BOOL					mNeedsImageRaw;
-	BOOL                    mPaused;
-	void*					mUserData;
-	source_callback_list_t* mSourceCallbackList;
-	
-public:
-	static void cleanUpCallbackList(LLLoadedCallbackEntry::source_callback_list_t* callback_list) ;
-};
-
-class LLTextureBar;
-
-class LLViewerTexture : public LLGLTexture
-{
-public:
-	enum
-	{
-		LOCAL_TEXTURE,		
-		MEDIA_TEXTURE,
-		DYNAMIC_TEXTURE,
-		FETCHED_TEXTURE,
-		LOD_TEXTURE,
-		ATLAS_TEXTURE,
-		INVALID_TEXTURE_TYPE
-	};
-
-	typedef std::vector<class LLFace*> ll_face_list_t;
-	typedef std::vector<LLVOVolume*> ll_volume_list_t;
-
-
-protected:
-	virtual ~LLViewerTexture();
-	LOG_CLASS(LLViewerTexture);
-
-public:	
-	static void initClass();
-	static void updateClass(const F32 velocity, const F32 angular_velocity) ;
-	
-	LLViewerTexture(BOOL usemipmaps = TRUE);
-	LLViewerTexture(const LLUUID& id, BOOL usemipmaps) ;
-	LLViewerTexture(const LLImageRaw* raw, BOOL usemipmaps) ;
-	LLViewerTexture(const U32 width, const U32 height, const U8 components, BOOL usemipmaps) ;
-
-	virtual S8 getType() const;
-	virtual BOOL isMissingAsset() const ;
-	virtual void dump();	// debug info to LL_INFOS()
-	
-    virtual bool isViewerMediaTexture() const { return false; }
-
-	/*virtual*/ bool bindDefaultImage(const S32 stage = 0) ;
-	/*virtual*/ bool bindDebugImage(const S32 stage = 0) ;
-	/*virtual*/ void forceImmediateUpdate() ;
-	/*virtual*/ bool isActiveFetching();
-	
-	/*virtual*/ const LLUUID& getID() const { return mID; }
-	void setBoostLevel(S32 level);
-	S32  getBoostLevel() { return mBoostLevel; }
-	void setTextureListType(S32 tex_type) { mTextureListType = tex_type; }
-	S32 getTextureListType() { return mTextureListType; }
-
-	void addTextureStats(F32 virtual_size, BOOL needs_gltexture = TRUE) const;
-	void resetTextureStats();	
-	void setMaxVirtualSizeResetInterval(S32 interval)const {mMaxVirtualSizeResetInterval = interval;}
-	void resetMaxVirtualSizeResetCounter()const {mMaxVirtualSizeResetCounter = mMaxVirtualSizeResetInterval;}
-	S32 getMaxVirtualSizeResetCounter() const { return mMaxVirtualSizeResetCounter; }
-
-	virtual F32  getMaxVirtualSize() ;
-
-	LLFrameTimer* getLastReferencedTimer() {return &mLastReferencedTimer ;}
-	
-	S32 getFullWidth() const { return mFullWidth; }
-	S32 getFullHeight() const { return mFullHeight; }	
-	/*virtual*/ void setKnownDrawSize(S32 width, S32 height);
-
-	virtual void addFace(U32 channel, LLFace* facep) ;
-	virtual void removeFace(U32 channel, LLFace* facep) ; 
-	S32 getTotalNumFaces() const;
-	S32 getNumFaces(U32 ch) const;
-	const ll_face_list_t* getFaceList(U32 channel) const {llassert(channel < LLRender::NUM_TEXTURE_CHANNELS); return &mFaceList[channel];}
-
-	virtual void addVolume(U32 channel, LLVOVolume* volumep);
-	virtual void removeVolume(U32 channel, LLVOVolume* volumep);
-	S32 getNumVolumes(U32 channel) const;
-	const ll_volume_list_t* getVolumeList(U32 channel) const { return &mVolumeList[channel]; }
-
-	
-	virtual void setCachedRawImage(S32 discard_level, LLImageRaw* imageraw) ;
-	BOOL isLargeImage() ;	
-	
-	void setParcelMedia(LLViewerMediaTexture* media) {mParcelMedia = media;}
-	BOOL hasParcelMedia() const { return mParcelMedia != NULL;}
-	LLViewerMediaTexture* getParcelMedia() const { return mParcelMedia;}
-
-	/*virtual*/ void updateBindStatsForTester() ;
-protected:
-	void cleanup() ;
-	void init(bool firstinit) ;
-	void reorganizeFaceList() ;
-	void reorganizeVolumeList() ;
-
-	void notifyAboutMissingAsset();
-	void notifyAboutCreatingTexture();
-
-private:
-	friend class LLBumpImageList;
-	friend class LLUIImageList;
-
-	virtual void switchToCachedImage();
-	
-	static bool isMemoryForTextureLow() ;
-	static bool isMemoryForTextureSuficientlyFree();
-	static void getGPUMemoryForTextures(S32Megabytes &gpu, S32Megabytes &physical);
-
-protected:
-	LLUUID mID;
-	S32 mTextureListType; // along with mID identifies where to search for this texture in TextureList
-
-	F32 mSelectedTime;				// time texture was last selected
-	mutable F32 mMaxVirtualSize;	// The largest virtual size of the image, in pixels - how much data to we need?	
-	mutable S32  mMaxVirtualSizeResetCounter ;
-	mutable S32  mMaxVirtualSizeResetInterval;
-	mutable F32 mAdditionalDecodePriority;  // priority add to mDecodePriority.
-	LLFrameTimer mLastReferencedTimer;	
-
-	ll_face_list_t    mFaceList[LLRender::NUM_TEXTURE_CHANNELS]; //reverse pointer pointing to the faces using this image as texture
-	U32               mNumFaces[LLRender::NUM_TEXTURE_CHANNELS];
-	LLFrameTimer      mLastFaceListUpdateTimer ;
-
-	ll_volume_list_t  mVolumeList[LLRender::NUM_VOLUME_TEXTURE_CHANNELS];
-	U32					mNumVolumes[LLRender::NUM_VOLUME_TEXTURE_CHANNELS];
-	LLFrameTimer	  mLastVolumeListUpdateTimer;
-
-	//do not use LLPointer here.
-	LLViewerMediaTexture* mParcelMedia ;
-
-	static F32 sTexelPixelRatio;
-public:
-	static const U32 sCurrentFileVersion;	
-	static S32 sImageCount;
-	static S32 sRawCount;
-	static S32 sAuxCount;
-	static LLFrameTimer sEvaluationTimer;
-	static F32 sDesiredDiscardBias;
-	static F32 sDesiredDiscardScale;
-	static S32Bytes sBoundTextureMemory;
-	static S32Bytes sTotalTextureMemory;
-	static S32Megabytes sMaxBoundTextureMemory;
-	static S32Megabytes sMaxTotalTextureMem;
-	static S32Bytes sMaxDesiredTextureMem ;
-	static S8  sCameraMovingDiscardBias;
-	static F32 sCameraMovingBias;
-	static S32 sMaxSculptRez ;
-	static U32 sMinLargeImageSize ;
-	static U32 sMaxSmallImageSize ;
-	static bool sFreezeImageUpdates;
-	static F32  sCurrentTime ;
-
-	enum EDebugTexels
-	{
-		DEBUG_TEXELS_OFF,
-		DEBUG_TEXELS_CURRENT,
-		DEBUG_TEXELS_DESIRED,
-		DEBUG_TEXELS_FULL
-	};
-
-	static EDebugTexels sDebugTexelsMode;
-
-	static LLPointer<LLViewerTexture> sNullImagep; // Null texture for non-textured objects.
-	static LLPointer<LLViewerTexture> sBlackImagep;	// Texture to show NOTHING (pure black)
-	static LLPointer<LLViewerTexture> sCheckerBoardImagep;	// Texture to show NOTHING (pure black)
-};
-
-
-enum FTType
-{
-	FTT_UNKNOWN = -1,
-	FTT_DEFAULT = 0, // standard texture fetched by id.
-	FTT_SERVER_BAKE, // texture produced by appearance service and fetched from there.
-	FTT_HOST_BAKE, // old-style baked texture uploaded by viewer and fetched from avatar's host.
-	FTT_MAP_TILE, // tiles are fetched from map server directly.
-	FTT_LOCAL_FILE // fetch directly from a local file.
-};
-
-const std::string& fttype_to_string(const FTType& fttype);
-
-//
-//textures are managed in gTextureList.
-//raw image data is fetched from remote or local cache
-//but the raw image this texture pointing to is fixed.
-//
-class LLViewerFetchedTexture : public LLViewerTexture
-{
-	friend class LLTextureBar; // debug info only
-	friend class LLTextureView; // debug info only
-
-protected:
-	/*virtual*/ ~LLViewerFetchedTexture();
-public:
-	LLViewerFetchedTexture(const LLUUID& id, FTType f_type, const LLHost& host = LLHost(), BOOL usemipmaps = TRUE);
-	LLViewerFetchedTexture(const LLImageRaw* raw, FTType f_type, BOOL usemipmaps);
-	LLViewerFetchedTexture(const std::string& url, FTType f_type, const LLUUID& id, BOOL usemipmaps = TRUE);
-
-public:
-	static F32 maxDecodePriority();
-	
-	struct Compare
-	{
-		// lhs < rhs
-		bool operator()(const LLPointer<LLViewerFetchedTexture> &lhs, const LLPointer<LLViewerFetchedTexture> &rhs) const
-		{
-			const LLViewerFetchedTexture* lhsp = (const LLViewerFetchedTexture*)lhs;
-			const LLViewerFetchedTexture* rhsp = (const LLViewerFetchedTexture*)rhs;
-			// greater priority is "less"
-			const F32 lpriority = lhsp->getDecodePriority();
-			const F32 rpriority = rhsp->getDecodePriority();
-			if (lpriority > rpriority) // higher priority
-				return true;
-			if (lpriority < rpriority)
-				return false;
-			return lhsp < rhsp;
-		}
-	};
-
-public:
-	/*virtual*/ S8 getType() const ;
-	FTType getFTType() const;
-	/*virtual*/ void forceImmediateUpdate() ;
-	/*virtual*/ void dump() ;
-
-	// Set callbacks to get called when the image gets updated with higher 
-	// resolution versions.
-	void setLoadedCallback(loaded_callback_func cb,
-						   S32 discard_level, BOOL keep_imageraw, BOOL needs_aux,
-						   void* userdata, LLLoadedCallbackEntry::source_callback_list_t* src_callback_list, BOOL pause = FALSE);
-	bool hasCallbacks() { return mLoadedCallbackList.empty() ? false : true; }	
-	void pauseLoadedCallbacks(const LLLoadedCallbackEntry::source_callback_list_t* callback_list);
-	void unpauseLoadedCallbacks(const LLLoadedCallbackEntry::source_callback_list_t* callback_list);
-	bool doLoadedCallbacks();
-	void deleteCallbackEntry(const LLLoadedCallbackEntry::source_callback_list_t* callback_list);
-	void clearCallbackEntryList() ;
-
-	void addToCreateTexture();
-
-    //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() ;
-	F32  calcDecodePriority() ;
-
-	BOOL needsAux() const { return mNeedsAux; }
-
-	// Host we think might have this image, used for baked av textures.
-	void setTargetHost(LLHost host)			{ mTargetHost = host; }
-	LLHost getTargetHost() const			{ return mTargetHost; }
-	
-	// Set the decode priority for this image...
-	// DON'T CALL THIS UNLESS YOU KNOW WHAT YOU'RE DOING, it can mess up
-	// the priority list, and cause horrible things to happen.
-	void setDecodePriority(F32 priority = -1.0f);
-	F32 getDecodePriority() const { return mDecodePriority; };
-	F32 getAdditionalDecodePriority() const { return mAdditionalDecodePriority; };
-
-	void setAdditionalDecodePriority(F32 priority) ;
-	
-	void updateVirtualSize() ;
-
-	S32  getDesiredDiscardLevel()			 { return mDesiredDiscardLevel; }
-	void setMinDiscardLevel(S32 discard) 	{ mMinDesiredDiscardLevel = llmin(mMinDesiredDiscardLevel,(S8)discard); }
-
-	bool updateFetch();
-	bool setDebugFetching(S32 debug_level);
-	bool isInDebug() const { return mInDebug; }
-
-	void setUnremovable(BOOL value) { mUnremovable = value; }
-	bool isUnremovable() const { return mUnremovable; }
-	
-	void clearFetchedResults(); //clear all fetched results, for debug use.
-
-	// Override the computation of discard levels if we know the exact output
-	// size of the image.  Used for UI textures to not decode, even if we have
-	// more data.
-	/*virtual*/ void setKnownDrawSize(S32 width, S32 height);
-
-	void setIsMissingAsset(BOOL is_missing = true);
-	/*virtual*/ BOOL isMissingAsset() const { return mIsMissingAsset; }
-
-	// returns dimensions of original image for local files (before power of two scaling)
-	// and returns 0 for all asset system images
-	S32 getOriginalWidth() { return mOrigWidth; }
-	S32 getOriginalHeight() { return mOrigHeight; }
-
-	BOOL isInImageList() const {return mInImageList ;}
-	void setInImageList(BOOL flag) {mInImageList = flag ;}
-
-	LLFrameTimer* getLastPacketTimer() {return &mLastPacketTimer;}
-
-	U32 getFetchPriority() const { return mFetchPriority ;}
-	F32 getDownloadProgress() const {return mDownloadProgress ;}
-
-	LLImageRaw* reloadRawImage(S8 discard_level) ;
-	void destroyRawImage();
-	bool needsToSaveRawImage();
-
-	const std::string& getUrl() const {return mUrl;}
-	//---------------
-	BOOL isDeleted() ;
-	BOOL isInactive() ;
-	BOOL isDeletionCandidate();
-	void setDeletionCandidate() ;
-	void setInactive() ;
-	BOOL getUseDiscard() const { return mUseMipMaps && !mDontDiscard; }	
-	//---------------
-
-	void setForSculpt();
-	BOOL forSculpt() const {return mForSculpt;}
-	BOOL isForSculptOnly() const;
-
-	//raw image management	
-	void        checkCachedRawSculptImage() ;
-	LLImageRaw* getRawImage()const { return mRawImage ;}
-	S32         getRawImageLevel() const {return mRawDiscardLevel;}
-	LLImageRaw* getCachedRawImage() const { return mCachedRawImage ;}
-	S32         getCachedRawImageLevel() const {return mCachedRawDiscardLevel;}
-	BOOL        isCachedRawImageReady() const {return mCachedRawImageReady ;}
-	BOOL        isRawImageValid()const { return mIsRawImageValid ; }	
-	void        forceToSaveRawImage(S32 desired_discard = 0, F32 kept_time = 0.f) ;
-	void        forceToRefetchTexture(S32 desired_discard = 0, F32 kept_time = 60.f);
-	/*virtual*/ void setCachedRawImage(S32 discard_level, LLImageRaw* imageraw) ;
-	void        destroySavedRawImage() ;
-	LLImageRaw* getSavedRawImage() ;
-	BOOL        hasSavedRawImage() const ;
-	F32         getElapsedLastReferencedSavedRawImageTime() const ;
-	BOOL		isFullyLoaded() const;
-
-	BOOL        hasFetcher() const { return mHasFetcher;}
-	void        setCanUseHTTP(bool can_use_http) {mCanUseHTTP = can_use_http;}
-
-	void        forceToDeleteRequest();
-	void        loadFromFastCache();
-	void        setInFastCacheList(bool in_list) { mInFastCacheList = in_list; }
-	bool        isInFastCacheList() { return mInFastCacheList; }
-
-	/*virtual*/bool  isActiveFetching(); //is actively in fetching by the fetching pipeline.
-
-protected:
-	/*virtual*/ void switchToCachedImage();
-	S32 getCurrentDiscardLevelForFetching() ;
-
-private:
-	void init(bool firstinit) ;	
-	void cleanup() ;
-
-	void saveRawImage() ;
-	void setCachedRawImage() ;
-
-	//for atlas
-	void resetFaceAtlas() ;
-	void invalidateAtlas(BOOL rebuild_geom) ;
-	BOOL insertToAtlas() ;
-
-private:
-	BOOL  mFullyLoaded;
-	BOOL  mInDebug;
-	BOOL  mUnremovable;
-	BOOL  mInFastCacheList;
-	BOOL  mForceCallbackFetch;
-
-protected:		
-	std::string mLocalFileName;
-
-	S32 mOrigWidth;
-	S32 mOrigHeight;
-
-	// Override the computation of discard levels if we know the exact output size of the image.
-	// Used for UI textures to not decode, even if we have more data.
-	S32 mKnownDrawWidth;
-	S32	mKnownDrawHeight;
-	BOOL mKnownDrawSizeChanged ;
-	std::string mUrl;
-	
-	S32 mRequestedDiscardLevel;
-	F32 mRequestedDownloadPriority;
-	S32 mFetchState;
-	U32 mFetchPriority;
-	F32 mDownloadProgress;
-	F32 mFetchDeltaTime;
-	F32 mRequestDeltaTime;
-	F32 mDecodePriority;			// The priority for decoding this image.
-	S32	mMinDiscardLevel;
-	S8  mDesiredDiscardLevel;			// The discard level we'd LIKE to have - if we have it and there's space	
-	S8  mMinDesiredDiscardLevel;	// The minimum discard level we'd like to have
-
-	S8  mNeedsAux;					// We need to decode the auxiliary channels
-	S8  mHasAux;                    // We have aux channels
-	S8  mDecodingAux;				// Are we decoding high components
-	S8  mIsRawImageValid;
-	S8  mHasFetcher;				// We've made a fecth request
-	S8  mIsFetching;				// Fetch request is active
-	bool mCanUseHTTP;              //This texture can be fetched through http if true.
-	LLCore::HttpStatus mLastHttpGetStatus; // Result of the most recently completed http request for this texture.
-
-	FTType mFTType; // What category of image is this - map tile, server bake, etc?
-	mutable S8 mIsMissingAsset;		// True if we know that there is no image asset with this image id in the database.		
-
-	typedef std::list<LLLoadedCallbackEntry*> callback_list_t;
-	S8              mLoadedCallbackDesiredDiscardLevel;
-	BOOL            mPauseLoadedCallBacks;
-	callback_list_t mLoadedCallbackList;
-	F32             mLastCallBackActiveTime;
-
-	LLPointer<LLImageRaw> mRawImage;
-	S32 mRawDiscardLevel;
-
-	// Used ONLY for cloth meshes right now.  Make SURE you know what you're 
-	// doing if you use it for anything else! - djs
-	LLPointer<LLImageRaw> mAuxRawImage;
-
-	//keep a copy of mRawImage for some special purposes
-	//when mForceToSaveRawImage is set.
-	BOOL mForceToSaveRawImage ;
-	BOOL mSaveRawImage;
-	LLPointer<LLImageRaw> mSavedRawImage;
-	S32 mSavedRawDiscardLevel;
-	S32 mDesiredSavedRawDiscardLevel;
-	F32 mLastReferencedSavedRawImageTime ;
-	F32 mKeptSavedRawImageTime ;
-
-	//a small version of the copy of the raw image (<= 64 * 64)
-	LLPointer<LLImageRaw> mCachedRawImage;
-	S32 mCachedRawDiscardLevel;
-	BOOL mCachedRawImageReady; //the rez of the mCachedRawImage reaches the upper limit.	
-
-	LLHost mTargetHost;	// if invalid, just request from agent's simulator
-
-	// Timers
-	LLFrameTimer mLastPacketTimer;		// Time since last packet.
-	LLFrameTimer mStopFetchingTimer;	// Time since mDecodePriority == 0.f.
-
-	BOOL  mInImageList;				// TRUE if image is in list (in which case don't reset priority!)
-	BOOL  mNeedsCreateTexture;	
-
-	BOOL   mForSculpt ; //a flag if the texture is used as sculpt data.
-	BOOL   mIsFetched ; //is loaded from remote or from cache, not generated locally.
-
-public:
-	static LLPointer<LLViewerFetchedTexture> sMissingAssetImagep;	// Texture to show for an image asset that is not in the database
-	static LLPointer<LLViewerFetchedTexture> sWhiteImagep;	// Texture to show NOTHING (whiteness)
-	static LLPointer<LLViewerFetchedTexture> sDefaultImagep; // "Default" texture for error cases, the only case of fetched texture which is generated in local.
-	static LLPointer<LLViewerFetchedTexture> sSmokeImagep; // Old "Default" translucent texture
-	static LLPointer<LLViewerFetchedTexture> sFlatNormalImagep; // Flat normal map denoting no bumpiness on a surface
-};
-
-//
-//the image data is fetched from remote or from local cache
-//the resolution of the texture is adjustable: depends on the view-dependent parameters.
-//
-class LLViewerLODTexture : public LLViewerFetchedTexture
-{
-protected:
-	/*virtual*/ ~LLViewerLODTexture(){}
-
-public:
-	LLViewerLODTexture(const LLUUID& id, FTType f_type, const LLHost& host = LLHost(), BOOL usemipmaps = TRUE);
-	LLViewerLODTexture(const std::string& url, FTType f_type, const LLUUID& id, BOOL usemipmaps = TRUE);
-
-	/*virtual*/ S8 getType() const;
-	// Process image stats to determine priority/quality requirements.
-	/*virtual*/ void processTextureStats();
-	bool isUpdateFrozen() ;
-
-private:
-	void init(bool firstinit) ;
-	bool scaleDown() ;		
-
-private:
-	F32 mDiscardVirtualSize;		// Virtual size used to calculate desired discard	
-	F32 mCalculatedDiscardLevel;    // Last calculated discard level
-};
-
-//
-//the image data is fetched from the media pipeline periodically
-//the resolution of the texture is also adjusted by the media pipeline
-//
-class LLViewerMediaTexture : public LLViewerTexture
-{
-protected:
-	/*virtual*/ ~LLViewerMediaTexture() ;
-
-public:
-	LLViewerMediaTexture(const LLUUID& id, BOOL usemipmaps = TRUE, LLImageGL* gl_image = NULL) ;
-
-	/*virtual*/ S8 getType() const;
-	void reinit(BOOL usemipmaps = TRUE);	
-
-	BOOL  getUseMipMaps() {return mUseMipMaps ; }
-	void  setUseMipMaps(BOOL mipmap) ;	
-	
-	void setPlaying(BOOL playing) ;
-	BOOL isPlaying() const {return mIsPlaying;}
-	void setMediaImpl() ;
-
-    virtual bool isViewerMediaTexture() const { return true; }
-
-	void initVirtualSize() ;	
-	void invalidateMediaImpl() ;
-
-	void addMediaToFace(LLFace* facep) ;
-	void removeMediaFromFace(LLFace* facep) ;
-
-	/*virtual*/ void addFace(U32 ch, LLFace* facep) ;
-	/*virtual*/ void removeFace(U32 ch, LLFace* facep) ; 
-
-	/*virtual*/ F32  getMaxVirtualSize() ;
-private:
-	void switchTexture(U32 ch, LLFace* facep) ;
-	BOOL findFaces() ;
-	void stopPlaying() ;
-
-private:
-	//
-	//an instant list, recording all faces referencing or can reference to this media texture.
-	//NOTE: it is NOT thread safe. 
-	//
-	std::list< LLFace* > mMediaFaceList ; 
-
-	//an instant list keeping all textures which are replaced by the current media texture,
-	//is only used to avoid the removal of those textures from memory.
-	std::list< LLPointer<LLViewerTexture> > mTextureList ;
-
-	LLViewerMediaImpl* mMediaImplp ;	
-	BOOL mIsPlaying ;
-	U32  mUpdateVirtualSizeTime ;
-
-public:
-	static void updateClass() ;
-	static void cleanUpClass() ;	
-
-	static LLViewerMediaTexture* findMediaTexture(const LLUUID& media_id) ;
-	static void removeMediaImplFromTexture(const LLUUID& media_id) ;
-
-private:
-	typedef std::map< LLUUID, LLPointer<LLViewerMediaTexture> > media_map_t ;
-	static media_map_t sMediaMap ;	
-};
-
-//just an interface class, do not create instance from this class.
-class LLViewerTextureManager
-{
-private:
-	//make the constructor private to preclude creating instances from this class.
-	LLViewerTextureManager(){}
-
-public:
-    //texture pipeline tester
-	static LLTexturePipelineTester* sTesterp ;
-
-	//returns NULL if tex is not a LLViewerFetchedTexture nor derived from LLViewerFetchedTexture.
-	static LLViewerFetchedTexture*    staticCastToFetchedTexture(LLTexture* tex, BOOL report_error = FALSE) ;
-
-	//
-	//"find-texture" just check if the texture exists, if yes, return it, otherwise return null.
-	//
-	static void                       findFetchedTextures(const LLUUID& id, std::vector<LLViewerFetchedTexture*> &output);
-	static void                       findTextures(const LLUUID& id, std::vector<LLViewerTexture*> &output);
-	static LLViewerFetchedTexture*    findFetchedTexture(const LLUUID& id, S32 tex_type);
-	static LLViewerMediaTexture*      findMediaTexture(const LLUUID& id) ;
-	
-	static LLViewerMediaTexture*      createMediaTexture(const LLUUID& id, BOOL usemipmaps = TRUE, LLImageGL* gl_image = NULL) ;
-
-	//
-	//"get-texture" will create a new texture if the texture does not exist.
-	//
-	static LLViewerMediaTexture*      getMediaTexture(const LLUUID& id, BOOL usemipmaps = TRUE, LLImageGL* gl_image = NULL) ;
-	
-	static LLPointer<LLViewerTexture> getLocalTexture(BOOL usemipmaps = TRUE, BOOL generate_gl_tex = TRUE);
-	static LLPointer<LLViewerTexture> getLocalTexture(const LLUUID& id, BOOL usemipmaps, BOOL generate_gl_tex = TRUE) ;
-	static LLPointer<LLViewerTexture> getLocalTexture(const LLImageRaw* raw, BOOL usemipmaps) ;
-	static LLPointer<LLViewerTexture> getLocalTexture(const U32 width, const U32 height, const U8 components, BOOL usemipmaps, BOOL generate_gl_tex = TRUE) ;
-
-	static LLViewerFetchedTexture* getFetchedTexture(const LLUUID &image_id,									 
-									 FTType f_type = FTT_DEFAULT,
-									 BOOL usemipmap = TRUE,
-									 LLViewerTexture::EBoostLevel boost_priority = LLGLTexture::BOOST_NONE,		// Get the requested level immediately upon creation.
-									 S8 texture_type = LLViewerTexture::FETCHED_TEXTURE,
-									 LLGLint internal_format = 0,
-									 LLGLenum primary_format = 0,
-									 LLHost request_from_host = LLHost()
-									 );
-	
-	static LLViewerFetchedTexture* getFetchedTextureFromFile(const std::string& filename,									 
-									 FTType f_type = FTT_LOCAL_FILE,
-									 BOOL usemipmap = TRUE,
-									 LLViewerTexture::EBoostLevel boost_priority = LLGLTexture::BOOST_NONE,
-									 S8 texture_type = LLViewerTexture::FETCHED_TEXTURE,
-									 LLGLint internal_format = 0,
-									 LLGLenum primary_format = 0,
-									 const LLUUID& force_id = LLUUID::null
-									 );
-
-	static LLViewerFetchedTexture* getFetchedTextureFromUrl(const std::string& url,									 
-									 FTType f_type,
-									 BOOL usemipmap = TRUE,
-									 LLViewerTexture::EBoostLevel boost_priority = LLGLTexture::BOOST_NONE,
-									 S8 texture_type = LLViewerTexture::FETCHED_TEXTURE,
-									 LLGLint internal_format = 0,
-									 LLGLenum primary_format = 0,
-									 const LLUUID& force_id = LLUUID::null
-									 );
-
-	static LLViewerFetchedTexture* getFetchedTextureFromHost(const LLUUID& image_id, FTType f_type, LLHost host) ;
-
-	static void init() ;
-	static void cleanup() ;
-};
-//
-//this class is used for test/debug only
-//it tracks the activities of the texture pipeline
-//records them, and outputs them to log files
-//
-class LLTexturePipelineTester : public LLMetricPerformanceTesterWithSession
-{
-	enum
-	{
-		MIN_LARGE_IMAGE_AREA = 262144  //512 * 512
-	};
-public:
-	LLTexturePipelineTester() ;
-	~LLTexturePipelineTester() ;
-
-	void update();		
-	void updateTextureBindingStats(const LLViewerTexture* imagep) ;
-	void updateTextureLoadingStats(const LLViewerFetchedTexture* imagep, const LLImageRaw* raw_imagep, BOOL from_cache) ;
-	void updateGrayTextureBinding() ;
-	void setStablizingTime() ;
-
-private:
-	void reset() ;
-	void updateStablizingTime() ;
-
-	/*virtual*/ void outputTestRecord(LLSD* sd) ;
-
-private:
-	BOOL mPause ;
-private:
-	BOOL mUsingDefaultTexture;            //if set, some textures are still gray.
-
-	U32Bytes mTotalBytesUsed ;                     //total bytes of textures bound/used for the current frame.
-	U32Bytes mTotalBytesUsedForLargeImage ;        //total bytes of textures bound/used for the current frame for images larger than 256 * 256.
-	U32Bytes mLastTotalBytesUsed ;                 //total bytes of textures bound/used for the previous frame.
-	U32Bytes mLastTotalBytesUsedForLargeImage ;    //total bytes of textures bound/used for the previous frame for images larger than 256 * 256.
-		
-	//
-	//data size
-	//
-	U32Bytes mTotalBytesLoaded ;               //total bytes fetched by texture pipeline
-	U32Bytes mTotalBytesLoadedFromCache ;      //total bytes fetched by texture pipeline from local cache	
-	U32Bytes mTotalBytesLoadedForLargeImage ;  //total bytes fetched by texture pipeline for images larger than 256 * 256. 
-	U32Bytes mTotalBytesLoadedForSculpties ;   //total bytes fetched by texture pipeline for sculpties
-
-	//
-	//time
-	//NOTE: the error tolerances of the following timers is one frame time.
-	//
-	F32 mStartFetchingTime ;
-	F32 mTotalGrayTime ;                  //total loading time when no gray textures.
-	F32 mTotalStablizingTime ;            //total stablizing time when texture memory overflows
-	F32 mStartTimeLoadingSculpties ;      //the start moment of loading sculpty images.
-	F32 mEndTimeLoadingSculpties ;        //the end moment of loading sculpty images.
-	F32 mStartStablizingTime ;
-	F32 mEndStablizingTime ;
-
-private:
-	//
-	//The following members are used for performance analyzing
-	//
-	class LLTextureTestSession : public LLTestSession
-	{
-	public:
-		LLTextureTestSession() ;
-		/*virtual*/ ~LLTextureTestSession() ;
-
-		void reset() ;
-
-		F32 mTotalFetchingTime ;
-		F32 mTotalGrayTime ;
-		F32 mTotalStablizingTime ;
-		F32 mStartTimeLoadingSculpties ; 
-		F32 mTotalTimeLoadingSculpties ;
-
-		S32 mTotalBytesLoaded ; 
-		S32 mTotalBytesLoadedFromCache ;
-		S32 mTotalBytesLoadedForLargeImage ;
-		S32 mTotalBytesLoadedForSculpties ; 
-
-		typedef struct _texture_instant_preformance_t
-		{
-			S32 mAverageBytesUsedPerSecond ;         
-			S32 mAverageBytesUsedForLargeImagePerSecond ;
-			F32 mAveragePercentageBytesUsedPerSecond ;
-			F32 mTime ;
-		}texture_instant_preformance_t ;
-		std::vector<texture_instant_preformance_t> mInstantPerformanceList ;
-		S32 mInstantPerformanceListCounter ;
-	};
-
-	/*virtual*/ LLMetricPerformanceTesterWithSession::LLTestSession* loadTestSession(LLSD* log) ;
-	/*virtual*/ void compareTestSessions(llofstream* os) ;
-};
-
-#endif
+/** 
+ * @file llviewertexture.h
+ * @brief Object for managing images and their textures
+ *
+ * $LicenseInfo:firstyear=2000&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLVIEWERTEXTURE_H					
+#define LL_LLVIEWERTEXTURE_H
+
+#include "llgltexture.h"
+#include "lltimer.h"
+#include "llframetimer.h"
+#include "llhost.h"
+#include "llgltypes.h"
+#include "llrender.h"
+#include "llmetricperformancetester.h"
+#include "httpcommon.h"
+
+#include <map>
+#include <list>
+
+extern const S32Megabytes gMinVideoRam;
+extern const S32Megabytes gMaxVideoRam;
+
+class LLFace;
+class LLImageGL ;
+class LLImageRaw;
+class LLViewerObject;
+class LLViewerTexture;
+class LLViewerFetchedTexture ;
+class LLViewerMediaTexture ;
+class LLTexturePipelineTester ;
+
+
+typedef	void	(*loaded_callback_func)( BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* src_aux, S32 discard_level, BOOL final, void* userdata );
+
+class LLVFile;
+class LLMessageSystem;
+class LLViewerMediaImpl ;
+class LLVOVolume ;
+struct LLTextureKey;
+
+class LLLoadedCallbackEntry
+{
+public:
+    typedef std::set< LLTextureKey > source_callback_list_t;
+
+public:
+	LLLoadedCallbackEntry(loaded_callback_func cb,
+						  S32 discard_level,
+						  BOOL need_imageraw, // Needs image raw for the callback
+						  void* userdata,
+						  source_callback_list_t* src_callback_list,
+						  LLViewerFetchedTexture* target,
+						  BOOL pause);
+	~LLLoadedCallbackEntry();
+	void removeTexture(LLViewerFetchedTexture* tex) ;
+
+	loaded_callback_func	mCallback;
+	S32						mLastUsedDiscard;
+	S32						mDesiredDiscard;
+	BOOL					mNeedsImageRaw;
+	BOOL                    mPaused;
+	void*					mUserData;
+	source_callback_list_t* mSourceCallbackList;
+	
+public:
+	static void cleanUpCallbackList(LLLoadedCallbackEntry::source_callback_list_t* callback_list) ;
+};
+
+class LLTextureBar;
+
+class LLViewerTexture : public LLGLTexture
+{
+public:
+	enum
+	{
+		LOCAL_TEXTURE,		
+		MEDIA_TEXTURE,
+		DYNAMIC_TEXTURE,
+		FETCHED_TEXTURE,
+		LOD_TEXTURE,
+		ATLAS_TEXTURE,
+		INVALID_TEXTURE_TYPE
+	};
+
+	typedef std::vector<class LLFace*> ll_face_list_t;
+	typedef std::vector<LLVOVolume*> ll_volume_list_t;
+
+
+protected:
+	virtual ~LLViewerTexture();
+	LOG_CLASS(LLViewerTexture);
+
+public:	
+	static void initClass();
+	static void updateClass(const F32 velocity, const F32 angular_velocity) ;
+	
+	LLViewerTexture(BOOL usemipmaps = TRUE);
+	LLViewerTexture(const LLUUID& id, BOOL usemipmaps) ;
+	LLViewerTexture(const LLImageRaw* raw, BOOL usemipmaps) ;
+	LLViewerTexture(const U32 width, const U32 height, const U8 components, BOOL usemipmaps) ;
+
+	virtual S8 getType() const;
+	virtual BOOL isMissingAsset() const ;
+	virtual void dump();	// debug info to LL_INFOS()
+	
+    virtual bool isViewerMediaTexture() const { return false; }
+
+	/*virtual*/ bool bindDefaultImage(const S32 stage = 0) ;
+	/*virtual*/ bool bindDebugImage(const S32 stage = 0) ;
+	/*virtual*/ void forceImmediateUpdate() ;
+	/*virtual*/ bool isActiveFetching();
+	
+	/*virtual*/ const LLUUID& getID() const { return mID; }
+	void setBoostLevel(S32 level);
+	S32  getBoostLevel() { return mBoostLevel; }
+	void setTextureListType(S32 tex_type) { mTextureListType = tex_type; }
+	S32 getTextureListType() { return mTextureListType; }
+
+	void addTextureStats(F32 virtual_size, BOOL needs_gltexture = TRUE) const;
+	void resetTextureStats();	
+	void setMaxVirtualSizeResetInterval(S32 interval)const {mMaxVirtualSizeResetInterval = interval;}
+	void resetMaxVirtualSizeResetCounter()const {mMaxVirtualSizeResetCounter = mMaxVirtualSizeResetInterval;}
+	S32 getMaxVirtualSizeResetCounter() const { return mMaxVirtualSizeResetCounter; }
+
+	virtual F32  getMaxVirtualSize() ;
+
+	LLFrameTimer* getLastReferencedTimer() {return &mLastReferencedTimer ;}
+	
+	S32 getFullWidth() const { return mFullWidth; }
+	S32 getFullHeight() const { return mFullHeight; }	
+	/*virtual*/ void setKnownDrawSize(S32 width, S32 height);
+
+	virtual void addFace(U32 channel, LLFace* facep) ;
+	virtual void removeFace(U32 channel, LLFace* facep) ; 
+	S32 getTotalNumFaces() const;
+	S32 getNumFaces(U32 ch) const;
+	const ll_face_list_t* getFaceList(U32 channel) const {llassert(channel < LLRender::NUM_TEXTURE_CHANNELS); return &mFaceList[channel];}
+
+	virtual void addVolume(U32 channel, LLVOVolume* volumep);
+	virtual void removeVolume(U32 channel, LLVOVolume* volumep);
+	S32 getNumVolumes(U32 channel) const;
+	const ll_volume_list_t* getVolumeList(U32 channel) const { return &mVolumeList[channel]; }
+
+	
+	virtual void setCachedRawImage(S32 discard_level, LLImageRaw* imageraw) ;
+	BOOL isLargeImage() ;	
+	
+	void setParcelMedia(LLViewerMediaTexture* media) {mParcelMedia = media;}
+	BOOL hasParcelMedia() const { return mParcelMedia != NULL;}
+	LLViewerMediaTexture* getParcelMedia() const { return mParcelMedia;}
+
+	/*virtual*/ void updateBindStatsForTester() ;
+protected:
+	void cleanup() ;
+	void init(bool firstinit) ;
+	void reorganizeFaceList() ;
+	void reorganizeVolumeList() ;
+
+	void notifyAboutMissingAsset();
+	void notifyAboutCreatingTexture();
+
+private:
+	friend class LLBumpImageList;
+	friend class LLUIImageList;
+
+	virtual void switchToCachedImage();
+	
+	static bool isMemoryForTextureLow() ;
+	static bool isMemoryForTextureSuficientlyFree();
+	static void getGPUMemoryForTextures(S32Megabytes &gpu, S32Megabytes &physical);
+
+protected:
+	LLUUID mID;
+	S32 mTextureListType; // along with mID identifies where to search for this texture in TextureList
+
+	F32 mSelectedTime;				// time texture was last selected
+	mutable F32 mMaxVirtualSize;	// The largest virtual size of the image, in pixels - how much data to we need?	
+	mutable S32  mMaxVirtualSizeResetCounter ;
+	mutable S32  mMaxVirtualSizeResetInterval;
+	mutable F32 mAdditionalDecodePriority;  // priority add to mDecodePriority.
+	LLFrameTimer mLastReferencedTimer;	
+
+	ll_face_list_t    mFaceList[LLRender::NUM_TEXTURE_CHANNELS]; //reverse pointer pointing to the faces using this image as texture
+	U32               mNumFaces[LLRender::NUM_TEXTURE_CHANNELS];
+	LLFrameTimer      mLastFaceListUpdateTimer ;
+
+	ll_volume_list_t  mVolumeList[LLRender::NUM_VOLUME_TEXTURE_CHANNELS];
+	U32					mNumVolumes[LLRender::NUM_VOLUME_TEXTURE_CHANNELS];
+	LLFrameTimer	  mLastVolumeListUpdateTimer;
+
+	//do not use LLPointer here.
+	LLViewerMediaTexture* mParcelMedia ;
+
+	static F32 sTexelPixelRatio;
+public:
+	static const U32 sCurrentFileVersion;	
+	static S32 sImageCount;
+	static S32 sRawCount;
+	static S32 sAuxCount;
+	static LLFrameTimer sEvaluationTimer;
+	static F32 sDesiredDiscardBias;
+	static F32 sDesiredDiscardScale;
+	static S32Bytes sBoundTextureMemory;
+	static S32Bytes sTotalTextureMemory;
+	static S32Megabytes sMaxBoundTextureMemory;
+	static S32Megabytes sMaxTotalTextureMem;
+	static S32Bytes sMaxDesiredTextureMem ;
+	static S8  sCameraMovingDiscardBias;
+	static F32 sCameraMovingBias;
+	static S32 sMaxSculptRez ;
+	static U32 sMinLargeImageSize ;
+	static U32 sMaxSmallImageSize ;
+	static bool sFreezeImageUpdates;
+	static F32  sCurrentTime ;
+
+	enum EDebugTexels
+	{
+		DEBUG_TEXELS_OFF,
+		DEBUG_TEXELS_CURRENT,
+		DEBUG_TEXELS_DESIRED,
+		DEBUG_TEXELS_FULL
+	};
+
+	static EDebugTexels sDebugTexelsMode;
+
+	static LLPointer<LLViewerTexture> sNullImagep; // Null texture for non-textured objects.
+	static LLPointer<LLViewerTexture> sBlackImagep;	// Texture to show NOTHING (pure black)
+	static LLPointer<LLViewerTexture> sCheckerBoardImagep;	// Texture to show NOTHING (pure black)
+};
+
+
+enum FTType
+{
+	FTT_UNKNOWN = -1,
+	FTT_DEFAULT = 0, // standard texture fetched by id.
+	FTT_SERVER_BAKE, // texture produced by appearance service and fetched from there.
+	FTT_HOST_BAKE, // old-style baked texture uploaded by viewer and fetched from avatar's host.
+	FTT_MAP_TILE, // tiles are fetched from map server directly.
+	FTT_LOCAL_FILE // fetch directly from a local file.
+};
+
+const std::string& fttype_to_string(const FTType& fttype);
+
+//
+//textures are managed in gTextureList.
+//raw image data is fetched from remote or local cache
+//but the raw image this texture pointing to is fixed.
+//
+class LLViewerFetchedTexture : public LLViewerTexture
+{
+	friend class LLTextureBar; // debug info only
+	friend class LLTextureView; // debug info only
+
+protected:
+	/*virtual*/ ~LLViewerFetchedTexture();
+public:
+	LLViewerFetchedTexture(const LLUUID& id, FTType f_type, const LLHost& host = LLHost(), BOOL usemipmaps = TRUE);
+	LLViewerFetchedTexture(const LLImageRaw* raw, FTType f_type, BOOL usemipmaps);
+	LLViewerFetchedTexture(const std::string& url, FTType f_type, const LLUUID& id, BOOL usemipmaps = TRUE);
+
+public:
+	static F32 maxDecodePriority();
+	
+	struct Compare
+	{
+		// lhs < rhs
+		bool operator()(const LLPointer<LLViewerFetchedTexture> &lhs, const LLPointer<LLViewerFetchedTexture> &rhs) const
+		{
+			const LLViewerFetchedTexture* lhsp = (const LLViewerFetchedTexture*)lhs;
+			const LLViewerFetchedTexture* rhsp = (const LLViewerFetchedTexture*)rhs;
+			// greater priority is "less"
+			const F32 lpriority = lhsp->getDecodePriority();
+			const F32 rpriority = rhsp->getDecodePriority();
+			if (lpriority > rpriority) // higher priority
+				return true;
+			if (lpriority < rpriority)
+				return false;
+			return lhsp < rhsp;
+		}
+	};
+
+public:
+	/*virtual*/ S8 getType() const ;
+	FTType getFTType() const;
+	/*virtual*/ void forceImmediateUpdate() ;
+	/*virtual*/ void dump() ;
+
+	// Set callbacks to get called when the image gets updated with higher 
+	// resolution versions.
+	void setLoadedCallback(loaded_callback_func cb,
+						   S32 discard_level, BOOL keep_imageraw, BOOL needs_aux,
+						   void* userdata, LLLoadedCallbackEntry::source_callback_list_t* src_callback_list, BOOL pause = FALSE);
+	bool hasCallbacks() { return mLoadedCallbackList.empty() ? false : true; }	
+	void pauseLoadedCallbacks(const LLLoadedCallbackEntry::source_callback_list_t* callback_list);
+	void unpauseLoadedCallbacks(const LLLoadedCallbackEntry::source_callback_list_t* callback_list);
+	bool doLoadedCallbacks();
+	void deleteCallbackEntry(const LLLoadedCallbackEntry::source_callback_list_t* callback_list);
+	void clearCallbackEntryList() ;
+
+	void addToCreateTexture();
+
+    //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() ;
+	F32  calcDecodePriority() ;
+
+	BOOL needsAux() const { return mNeedsAux; }
+
+	// Host we think might have this image, used for baked av textures.
+	void setTargetHost(LLHost host)			{ mTargetHost = host; }
+	LLHost getTargetHost() const			{ return mTargetHost; }
+	
+	// Set the decode priority for this image...
+	// DON'T CALL THIS UNLESS YOU KNOW WHAT YOU'RE DOING, it can mess up
+	// the priority list, and cause horrible things to happen.
+	void setDecodePriority(F32 priority = -1.0f);
+	F32 getDecodePriority() const { return mDecodePriority; };
+	F32 getAdditionalDecodePriority() const { return mAdditionalDecodePriority; };
+
+	void setAdditionalDecodePriority(F32 priority) ;
+	
+	void updateVirtualSize() ;
+
+	S32  getDesiredDiscardLevel()			 { return mDesiredDiscardLevel; }
+	void setMinDiscardLevel(S32 discard) 	{ mMinDesiredDiscardLevel = llmin(mMinDesiredDiscardLevel,(S8)discard); }
+
+	bool updateFetch();
+	bool setDebugFetching(S32 debug_level);
+	bool isInDebug() const { return mInDebug; }
+
+	void setUnremovable(BOOL value) { mUnremovable = value; }
+	bool isUnremovable() const { return mUnremovable; }
+	
+	void clearFetchedResults(); //clear all fetched results, for debug use.
+
+	// Override the computation of discard levels if we know the exact output
+	// size of the image.  Used for UI textures to not decode, even if we have
+	// more data.
+	/*virtual*/ void setKnownDrawSize(S32 width, S32 height);
+
+	void setIsMissingAsset(BOOL is_missing = true);
+	/*virtual*/ BOOL isMissingAsset() const { return mIsMissingAsset; }
+
+	// returns dimensions of original image for local files (before power of two scaling)
+	// and returns 0 for all asset system images
+	S32 getOriginalWidth() { return mOrigWidth; }
+	S32 getOriginalHeight() { return mOrigHeight; }
+
+	BOOL isInImageList() const {return mInImageList ;}
+	void setInImageList(BOOL flag) {mInImageList = flag ;}
+
+	LLFrameTimer* getLastPacketTimer() {return &mLastPacketTimer;}
+
+	U32 getFetchPriority() const { return mFetchPriority ;}
+	F32 getDownloadProgress() const {return mDownloadProgress ;}
+
+	LLImageRaw* reloadRawImage(S8 discard_level) ;
+	void destroyRawImage();
+	bool needsToSaveRawImage();
+
+	const std::string& getUrl() const {return mUrl;}
+	//---------------
+	BOOL isDeleted() ;
+	BOOL isInactive() ;
+	BOOL isDeletionCandidate();
+	void setDeletionCandidate() ;
+	void setInactive() ;
+	BOOL getUseDiscard() const { return mUseMipMaps && !mDontDiscard; }	
+	//---------------
+
+	void setForSculpt();
+	BOOL forSculpt() const {return mForSculpt;}
+	BOOL isForSculptOnly() const;
+
+	//raw image management	
+	void        checkCachedRawSculptImage() ;
+	LLImageRaw* getRawImage()const { return mRawImage ;}
+	S32         getRawImageLevel() const {return mRawDiscardLevel;}
+	LLImageRaw* getCachedRawImage() const { return mCachedRawImage ;}
+	S32         getCachedRawImageLevel() const {return mCachedRawDiscardLevel;}
+	BOOL        isCachedRawImageReady() const {return mCachedRawImageReady ;}
+	BOOL        isRawImageValid()const { return mIsRawImageValid ; }	
+	void        forceToSaveRawImage(S32 desired_discard = 0, F32 kept_time = 0.f) ;
+	void        forceToRefetchTexture(S32 desired_discard = 0, F32 kept_time = 60.f);
+	/*virtual*/ void setCachedRawImage(S32 discard_level, LLImageRaw* imageraw) ;
+	void        destroySavedRawImage() ;
+	LLImageRaw* getSavedRawImage() ;
+	BOOL        hasSavedRawImage() const ;
+	F32         getElapsedLastReferencedSavedRawImageTime() const ;
+	BOOL		isFullyLoaded() const;
+
+	BOOL        hasFetcher() const { return mHasFetcher;}
+	void        setCanUseHTTP(bool can_use_http) {mCanUseHTTP = can_use_http;}
+
+	void        forceToDeleteRequest();
+	void        loadFromFastCache();
+	void        setInFastCacheList(bool in_list) { mInFastCacheList = in_list; }
+	bool        isInFastCacheList() { return mInFastCacheList; }
+
+	/*virtual*/bool  isActiveFetching(); //is actively in fetching by the fetching pipeline.
+
+protected:
+	/*virtual*/ void switchToCachedImage();
+	S32 getCurrentDiscardLevelForFetching() ;
+
+private:
+	void init(bool firstinit) ;	
+	void cleanup() ;
+
+	void saveRawImage() ;
+	void setCachedRawImage() ;
+
+	//for atlas
+	void resetFaceAtlas() ;
+	void invalidateAtlas(BOOL rebuild_geom) ;
+	BOOL insertToAtlas() ;
+
+private:
+	BOOL  mFullyLoaded;
+	BOOL  mInDebug;
+	BOOL  mUnremovable;
+	BOOL  mInFastCacheList;
+	BOOL  mForceCallbackFetch;
+
+protected:		
+	std::string mLocalFileName;
+
+	S32 mOrigWidth;
+	S32 mOrigHeight;
+
+	// Override the computation of discard levels if we know the exact output size of the image.
+	// Used for UI textures to not decode, even if we have more data.
+	S32 mKnownDrawWidth;
+	S32	mKnownDrawHeight;
+	BOOL mKnownDrawSizeChanged ;
+	std::string mUrl;
+	
+	S32 mRequestedDiscardLevel;
+	F32 mRequestedDownloadPriority;
+	S32 mFetchState;
+	U32 mFetchPriority;
+	F32 mDownloadProgress;
+	F32 mFetchDeltaTime;
+	F32 mRequestDeltaTime;
+	F32 mDecodePriority;			// The priority for decoding this image.
+	S32	mMinDiscardLevel;
+	S8  mDesiredDiscardLevel;			// The discard level we'd LIKE to have - if we have it and there's space	
+	S8  mMinDesiredDiscardLevel;	// The minimum discard level we'd like to have
+
+	S8  mNeedsAux;					// We need to decode the auxiliary channels
+	S8  mHasAux;                    // We have aux channels
+	S8  mDecodingAux;				// Are we decoding high components
+	S8  mIsRawImageValid;
+	S8  mHasFetcher;				// We've made a fecth request
+	S8  mIsFetching;				// Fetch request is active
+	bool mCanUseHTTP;              //This texture can be fetched through http if true.
+	LLCore::HttpStatus mLastHttpGetStatus; // Result of the most recently completed http request for this texture.
+
+	FTType mFTType; // What category of image is this - map tile, server bake, etc?
+	mutable S8 mIsMissingAsset;		// True if we know that there is no image asset with this image id in the database.		
+
+	typedef std::list<LLLoadedCallbackEntry*> callback_list_t;
+	S8              mLoadedCallbackDesiredDiscardLevel;
+	BOOL            mPauseLoadedCallBacks;
+	callback_list_t mLoadedCallbackList;
+	F32             mLastCallBackActiveTime;
+
+	LLPointer<LLImageRaw> mRawImage;
+	S32 mRawDiscardLevel;
+
+	// Used ONLY for cloth meshes right now.  Make SURE you know what you're 
+	// doing if you use it for anything else! - djs
+	LLPointer<LLImageRaw> mAuxRawImage;
+
+	//keep a copy of mRawImage for some special purposes
+	//when mForceToSaveRawImage is set.
+	BOOL mForceToSaveRawImage ;
+	BOOL mSaveRawImage;
+	LLPointer<LLImageRaw> mSavedRawImage;
+	S32 mSavedRawDiscardLevel;
+	S32 mDesiredSavedRawDiscardLevel;
+	F32 mLastReferencedSavedRawImageTime ;
+	F32 mKeptSavedRawImageTime ;
+
+	//a small version of the copy of the raw image (<= 64 * 64)
+	LLPointer<LLImageRaw> mCachedRawImage;
+	S32 mCachedRawDiscardLevel;
+	BOOL mCachedRawImageReady; //the rez of the mCachedRawImage reaches the upper limit.	
+
+	LLHost mTargetHost;	// if invalid, just request from agent's simulator
+
+	// Timers
+	LLFrameTimer mLastPacketTimer;		// Time since last packet.
+	LLFrameTimer mStopFetchingTimer;	// Time since mDecodePriority == 0.f.
+
+	BOOL  mInImageList;				// TRUE if image is in list (in which case don't reset priority!)
+	BOOL  mNeedsCreateTexture;	
+
+	BOOL   mForSculpt ; //a flag if the texture is used as sculpt data.
+	BOOL   mIsFetched ; //is loaded from remote or from cache, not generated locally.
+
+public:
+	static LLPointer<LLViewerFetchedTexture> sMissingAssetImagep;	// Texture to show for an image asset that is not in the database
+	static LLPointer<LLViewerFetchedTexture> sWhiteImagep;	// Texture to show NOTHING (whiteness)
+	static LLPointer<LLViewerFetchedTexture> sDefaultImagep; // "Default" texture for error cases, the only case of fetched texture which is generated in local.
+	static LLPointer<LLViewerFetchedTexture> sSmokeImagep; // Old "Default" translucent texture
+	static LLPointer<LLViewerFetchedTexture> sFlatNormalImagep; // Flat normal map denoting no bumpiness on a surface
+};
+
+//
+//the image data is fetched from remote or from local cache
+//the resolution of the texture is adjustable: depends on the view-dependent parameters.
+//
+class LLViewerLODTexture : public LLViewerFetchedTexture
+{
+protected:
+	/*virtual*/ ~LLViewerLODTexture(){}
+
+public:
+	LLViewerLODTexture(const LLUUID& id, FTType f_type, const LLHost& host = LLHost(), BOOL usemipmaps = TRUE);
+	LLViewerLODTexture(const std::string& url, FTType f_type, const LLUUID& id, BOOL usemipmaps = TRUE);
+
+	/*virtual*/ S8 getType() const;
+	// Process image stats to determine priority/quality requirements.
+	/*virtual*/ void processTextureStats();
+	bool isUpdateFrozen() ;
+
+private:
+	void init(bool firstinit) ;
+	bool scaleDown() ;		
+
+private:
+	F32 mDiscardVirtualSize;		// Virtual size used to calculate desired discard	
+	F32 mCalculatedDiscardLevel;    // Last calculated discard level
+};
+
+//
+//the image data is fetched from the media pipeline periodically
+//the resolution of the texture is also adjusted by the media pipeline
+//
+class LLViewerMediaTexture : public LLViewerTexture
+{
+protected:
+	/*virtual*/ ~LLViewerMediaTexture() ;
+
+public:
+	LLViewerMediaTexture(const LLUUID& id, BOOL usemipmaps = TRUE, LLImageGL* gl_image = NULL) ;
+
+	/*virtual*/ S8 getType() const;
+	void reinit(BOOL usemipmaps = TRUE);	
+
+	BOOL  getUseMipMaps() {return mUseMipMaps ; }
+	void  setUseMipMaps(BOOL mipmap) ;	
+	
+	void setPlaying(BOOL playing) ;
+	BOOL isPlaying() const {return mIsPlaying;}
+	void setMediaImpl() ;
+
+    virtual bool isViewerMediaTexture() const { return true; }
+
+	void initVirtualSize() ;	
+	void invalidateMediaImpl() ;
+
+	void addMediaToFace(LLFace* facep) ;
+	void removeMediaFromFace(LLFace* facep) ;
+
+	/*virtual*/ void addFace(U32 ch, LLFace* facep) ;
+	/*virtual*/ void removeFace(U32 ch, LLFace* facep) ; 
+
+	/*virtual*/ F32  getMaxVirtualSize() ;
+private:
+	void switchTexture(U32 ch, LLFace* facep) ;
+	BOOL findFaces() ;
+	void stopPlaying() ;
+
+private:
+	//
+	//an instant list, recording all faces referencing or can reference to this media texture.
+	//NOTE: it is NOT thread safe. 
+	//
+	std::list< LLFace* > mMediaFaceList ; 
+
+	//an instant list keeping all textures which are replaced by the current media texture,
+	//is only used to avoid the removal of those textures from memory.
+	std::list< LLPointer<LLViewerTexture> > mTextureList ;
+
+	LLViewerMediaImpl* mMediaImplp ;	
+	BOOL mIsPlaying ;
+	U32  mUpdateVirtualSizeTime ;
+
+public:
+	static void updateClass() ;
+	static void cleanUpClass() ;	
+
+	static LLViewerMediaTexture* findMediaTexture(const LLUUID& media_id) ;
+	static void removeMediaImplFromTexture(const LLUUID& media_id) ;
+
+private:
+	typedef std::map< LLUUID, LLPointer<LLViewerMediaTexture> > media_map_t ;
+	static media_map_t sMediaMap ;	
+};
+
+//just an interface class, do not create instance from this class.
+class LLViewerTextureManager
+{
+private:
+	//make the constructor private to preclude creating instances from this class.
+	LLViewerTextureManager(){}
+
+public:
+    //texture pipeline tester
+	static LLTexturePipelineTester* sTesterp ;
+
+	//returns NULL if tex is not a LLViewerFetchedTexture nor derived from LLViewerFetchedTexture.
+	static LLViewerFetchedTexture*    staticCastToFetchedTexture(LLTexture* tex, BOOL report_error = FALSE) ;
+
+	//
+	//"find-texture" just check if the texture exists, if yes, return it, otherwise return null.
+	//
+	static void                       findFetchedTextures(const LLUUID& id, std::vector<LLViewerFetchedTexture*> &output);
+	static void                       findTextures(const LLUUID& id, std::vector<LLViewerTexture*> &output);
+	static LLViewerFetchedTexture*    findFetchedTexture(const LLUUID& id, S32 tex_type);
+	static LLViewerMediaTexture*      findMediaTexture(const LLUUID& id) ;
+	
+	static LLViewerMediaTexture*      createMediaTexture(const LLUUID& id, BOOL usemipmaps = TRUE, LLImageGL* gl_image = NULL) ;
+
+	//
+	//"get-texture" will create a new texture if the texture does not exist.
+	//
+	static LLViewerMediaTexture*      getMediaTexture(const LLUUID& id, BOOL usemipmaps = TRUE, LLImageGL* gl_image = NULL) ;
+	
+	static LLPointer<LLViewerTexture> getLocalTexture(BOOL usemipmaps = TRUE, BOOL generate_gl_tex = TRUE);
+	static LLPointer<LLViewerTexture> getLocalTexture(const LLUUID& id, BOOL usemipmaps, BOOL generate_gl_tex = TRUE) ;
+	static LLPointer<LLViewerTexture> getLocalTexture(const LLImageRaw* raw, BOOL usemipmaps) ;
+	static LLPointer<LLViewerTexture> getLocalTexture(const U32 width, const U32 height, const U8 components, BOOL usemipmaps, BOOL generate_gl_tex = TRUE) ;
+
+	static LLViewerFetchedTexture* getFetchedTexture(const LLUUID &image_id,									 
+									 FTType f_type = FTT_DEFAULT,
+									 BOOL usemipmap = TRUE,
+									 LLViewerTexture::EBoostLevel boost_priority = LLGLTexture::BOOST_NONE,		// Get the requested level immediately upon creation.
+									 S8 texture_type = LLViewerTexture::FETCHED_TEXTURE,
+									 LLGLint internal_format = 0,
+									 LLGLenum primary_format = 0,
+									 LLHost request_from_host = LLHost()
+									 );
+	
+	static LLViewerFetchedTexture* getFetchedTextureFromFile(const std::string& filename,									 
+									 FTType f_type = FTT_LOCAL_FILE,
+									 BOOL usemipmap = TRUE,
+									 LLViewerTexture::EBoostLevel boost_priority = LLGLTexture::BOOST_NONE,
+									 S8 texture_type = LLViewerTexture::FETCHED_TEXTURE,
+									 LLGLint internal_format = 0,
+									 LLGLenum primary_format = 0,
+									 const LLUUID& force_id = LLUUID::null
+									 );
+
+	static LLViewerFetchedTexture* getFetchedTextureFromUrl(const std::string& url,									 
+									 FTType f_type,
+									 BOOL usemipmap = TRUE,
+									 LLViewerTexture::EBoostLevel boost_priority = LLGLTexture::BOOST_NONE,
+									 S8 texture_type = LLViewerTexture::FETCHED_TEXTURE,
+									 LLGLint internal_format = 0,
+									 LLGLenum primary_format = 0,
+									 const LLUUID& force_id = LLUUID::null
+									 );
+
+	static LLViewerFetchedTexture* getFetchedTextureFromHost(const LLUUID& image_id, FTType f_type, LLHost host) ;
+
+	static void init() ;
+	static void cleanup() ;
+};
+//
+//this class is used for test/debug only
+//it tracks the activities of the texture pipeline
+//records them, and outputs them to log files
+//
+class LLTexturePipelineTester : public LLMetricPerformanceTesterWithSession
+{
+	enum
+	{
+		MIN_LARGE_IMAGE_AREA = 262144  //512 * 512
+	};
+public:
+	LLTexturePipelineTester() ;
+	~LLTexturePipelineTester() ;
+
+	void update();		
+	void updateTextureBindingStats(const LLViewerTexture* imagep) ;
+	void updateTextureLoadingStats(const LLViewerFetchedTexture* imagep, const LLImageRaw* raw_imagep, BOOL from_cache) ;
+	void updateGrayTextureBinding() ;
+	void setStablizingTime() ;
+
+private:
+	void reset() ;
+	void updateStablizingTime() ;
+
+	/*virtual*/ void outputTestRecord(LLSD* sd) ;
+
+private:
+	BOOL mPause ;
+private:
+	BOOL mUsingDefaultTexture;            //if set, some textures are still gray.
+
+	U32Bytes mTotalBytesUsed ;                     //total bytes of textures bound/used for the current frame.
+	U32Bytes mTotalBytesUsedForLargeImage ;        //total bytes of textures bound/used for the current frame for images larger than 256 * 256.
+	U32Bytes mLastTotalBytesUsed ;                 //total bytes of textures bound/used for the previous frame.
+	U32Bytes mLastTotalBytesUsedForLargeImage ;    //total bytes of textures bound/used for the previous frame for images larger than 256 * 256.
+		
+	//
+	//data size
+	//
+	U32Bytes mTotalBytesLoaded ;               //total bytes fetched by texture pipeline
+	U32Bytes mTotalBytesLoadedFromCache ;      //total bytes fetched by texture pipeline from local cache	
+	U32Bytes mTotalBytesLoadedForLargeImage ;  //total bytes fetched by texture pipeline for images larger than 256 * 256. 
+	U32Bytes mTotalBytesLoadedForSculpties ;   //total bytes fetched by texture pipeline for sculpties
+
+	//
+	//time
+	//NOTE: the error tolerances of the following timers is one frame time.
+	//
+	F32 mStartFetchingTime ;
+	F32 mTotalGrayTime ;                  //total loading time when no gray textures.
+	F32 mTotalStablizingTime ;            //total stablizing time when texture memory overflows
+	F32 mStartTimeLoadingSculpties ;      //the start moment of loading sculpty images.
+	F32 mEndTimeLoadingSculpties ;        //the end moment of loading sculpty images.
+	F32 mStartStablizingTime ;
+	F32 mEndStablizingTime ;
+
+private:
+	//
+	//The following members are used for performance analyzing
+	//
+	class LLTextureTestSession : public LLTestSession
+	{
+	public:
+		LLTextureTestSession() ;
+		/*virtual*/ ~LLTextureTestSession() ;
+
+		void reset() ;
+
+		F32 mTotalFetchingTime ;
+		F32 mTotalGrayTime ;
+		F32 mTotalStablizingTime ;
+		F32 mStartTimeLoadingSculpties ; 
+		F32 mTotalTimeLoadingSculpties ;
+
+		S32 mTotalBytesLoaded ; 
+		S32 mTotalBytesLoadedFromCache ;
+		S32 mTotalBytesLoadedForLargeImage ;
+		S32 mTotalBytesLoadedForSculpties ; 
+
+		typedef struct _texture_instant_preformance_t
+		{
+			S32 mAverageBytesUsedPerSecond ;         
+			S32 mAverageBytesUsedForLargeImagePerSecond ;
+			F32 mAveragePercentageBytesUsedPerSecond ;
+			F32 mTime ;
+		}texture_instant_preformance_t ;
+		std::vector<texture_instant_preformance_t> mInstantPerformanceList ;
+		S32 mInstantPerformanceListCounter ;
+	};
+
+	/*virtual*/ LLMetricPerformanceTesterWithSession::LLTestSession* loadTestSession(LLSD* log) ;
+	/*virtual*/ void compareTestSessions(llofstream* os) ;
+};
+
+#endif
-- 
cgit v1.2.3


From e7227afe0249806ceb1c8eef2dd6ca909eb394d3 Mon Sep 17 00:00:00 2001
From: Runitai Linden <davep@lindenlab.com>
Date: Thu, 14 Oct 2021 13:02:40 -0500
Subject: SL-16166 Apply optimizations from pushBatch to other render call
 sites.  Optimize out a map lookup in rigged face rendering.

---
 indra/llrender/llglslshader.cpp    |   4 +-
 indra/llrender/llrender.cpp        |   3 +-
 indra/newview/lldrawable.cpp       |   2 -
 indra/newview/lldrawpoolalpha.cpp  | 218 +++++++++----------------------------
 indra/newview/lldrawpoolalpha.h    |   4 +-
 indra/newview/lldrawpoolavatar.cpp | 206 ++++++++++++++---------------------
 indra/newview/lldrawpoolavatar.h   |   9 +-
 indra/newview/llmeshrepository.cpp |   3 +-
 indra/newview/llmeshrepository.h   |   2 +-
 indra/newview/llvovolume.cpp       |   2 +-
 indra/newview/llvovolume.h         |   3 +
 11 files changed, 150 insertions(+), 306 deletions(-)

(limited to 'indra')

diff --git a/indra/llrender/llglslshader.cpp b/indra/llrender/llglslshader.cpp
index 394fcd2b2f..84eac00c65 100644
--- a/indra/llrender/llglslshader.cpp
+++ b/indra/llrender/llglslshader.cpp
@@ -1017,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);
     }
     
@@ -1048,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;
diff --git a/indra/llrender/llrender.cpp b/indra/llrender/llrender.cpp
index 91d3c96fbe..669a09d3ce 100644
--- a/indra/llrender/llrender.cpp
+++ b/indra/llrender/llrender.cpp
@@ -169,7 +169,6 @@ void LLTexUnit::refreshState(void)
 
 void LLTexUnit::activate(void)
 {
-    LL_PROFILE_ZONE_SCOPED;
 	if (mIndex < 0) return;
 
 	if ((S32)gGL.mCurrTextureUnitIndex != mIndex || gGL.mDirty)
@@ -1956,9 +1955,9 @@ void LLRender::end()
 }
 void LLRender::flush()
 {
-    LL_PROFILE_ZONE_SCOPED;
 	if (mCount > 0)
 	{
+        LL_PROFILE_ZONE_SCOPED;
 		if (!mUIOffset.empty())
 		{
 			sUICalls++;
diff --git a/indra/newview/lldrawable.cpp b/indra/newview/lldrawable.cpp
index 30c4a21e1c..495e06b6f7 100644
--- a/indra/newview/lldrawable.cpp
+++ b/indra/newview/lldrawable.cpp
@@ -234,8 +234,6 @@ void LLDrawable::markDead()
 
 LLVOVolume* LLDrawable::getVOVolume() const
 {
-	LL_PROFILE_ZONE_SCOPED
-
 	LLViewerObject* objectp = mVObjp;
 	if ( !isDead() && objectp && (objectp->getPCode() == LL_PCODE_VOLUME))
 	{
diff --git a/indra/newview/lldrawpoolalpha.cpp b/indra/newview/lldrawpoolalpha.cpp
index 4ee08e869a..369d7a6bb8 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 a069f805e8..a50b1d929e 100644
--- a/indra/newview/lldrawpoolalpha.h
+++ b/indra/newview/lldrawpoolalpha.h
@@ -75,15 +75,13 @@ private:
 	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 02ab316256..8dd8c15b87 100644
--- a/indra/newview/lldrawpoolavatar.cpp
+++ b/indra/newview/lldrawpoolavatar.cpp
@@ -1685,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);
@@ -2067,56 +2067,12 @@ void LLDrawPoolAvatar::updateRiggedFaceVertexBuffer(
 		LLVector4a* pos = (LLVector4a*) position.get();
 
 		LLVector4a* norm = has_normal ? (LLVector4a*) normal.get() : NULL;
-		
-        if (skin == nullptr)
-        {
-            skin = vobj->getSkinInfo();
-        }
 
-        const MatrixPaletteCache& mpc = updateSkinInfoMatrixPalette(avatar, skin);
+        const MatrixPaletteCache& mpc = updateSkinInfoMatrixPalette(avatar, vobj->getMeshID());
         const LLMatrix4a* mat = &(mpc.mMatrixPalette[0]);
+        const LLMatrix4a& bind_shape_matrix = mpc.mBindShapeMatrix;
 
-        LLSkinningUtil::checkSkinWeights(weights, buffer->getNumVerts(), skin);
-		const LLMatrix4a& bind_shape_matrix = skin->mBindShapeMatrix;
-
-#if USE_SEPARATE_JOINT_INDICES_AND_WEIGHTS
-        U8* joint_indices_cursor = vol_face.mJointIndices;
-        // fast path with joint indices separate from weights
-        if (joint_indices_cursor)
-        {
-            LLMatrix4a src[4];
-		    for (U32 j = 0; j < buffer->getNumVerts(); ++j)
-		    {
-			    LLMatrix4a final_mat;
-                //LLMatrix4a final_mat_correct;
-
-                F32* jw = just_weights[j].getF32ptr();
-
-                LLSkinningUtil::getPerVertexSkinMatrixWithIndices(jw, joint_indices_cursor, mat, final_mat, src);                
-
-                joint_indices_cursor += 4;
-
-			    LLVector4a& v = vol_face.mPositions[j];
-
-			    LLVector4a t;
-			    LLVector4a dst;
-			    bind_shape_matrix.affineTransform(v, t);
-			    final_mat.affineTransform(t, dst);
-			    pos[j] = dst;
-
-			    if (norm)
-			    {
-				    LLVector4a& n = vol_face.mNormals[j];
-				    bind_shape_matrix.rotate(n, t);
-				    final_mat.rotate(t, dst);
-				    dst.normalize3fast();
-				    norm[j] = dst;
-			    }
-		    }
-        }
-        // slow path with joint indices calculated from weights
-        else
-#endif
+        if (!mpc.mMatrixPalette.empty())
         {
             for (U32 j = 0; j < buffer->getNumVerts(); ++j)
 		    {
@@ -2152,9 +2108,7 @@ void LLDrawPoolAvatar::renderRigged(LLVOAvatar* avatar, U32 type, bool glow)
 		return;
 	}
 
-	stop_glerror();
-
-    const LLMeshSkinInfo* lastSkin = nullptr;
+    LLUUID lastMeshId;
 
 	for (U32 i = 0; i < mRiggedFace[type].size(); ++i)
 	{
@@ -2188,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();
@@ -2290,34 +2231,33 @@ void LLDrawPoolAvatar::renderRigged(LLVOAvatar* avatar, U32 type, bool glow)
 		{
 			if (sShaderLevel > 0)
 			{
-                if (lastSkin != skin) // <== only upload matrix palette to GL if the skininfo changed
+                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, skin);
+                    const MatrixPaletteCache& mpc = updateSkinInfoMatrixPalette(avatar, meshId);
                     U32 count = mpc.mMatrixPalette.size();
 
-                    stop_glerror();
+                    if (count == 0)
+                    {
+                        //skin info not loaded yet, don't render
+                        continue;
+                    }
 
                     LLDrawPoolAvatar::sVertexProgram->uniformMatrix3x4fv(LLViewerShaderMgr::AVATAR_MATRIX,
                         count,
                         FALSE,
                         (GLfloat*) &(mpc.mGLMp[0]));
-
-                    stop_glerror();
                 }
+
+                lastMeshId = meshId;
 			}
 			else
 			{
 				data_mask &= ~LLVertexBuffer::MAP_WEIGHT4;
 			}
 
-            lastSkin = skin;
-
-			/*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 
@@ -2332,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();
@@ -2369,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)
@@ -2399,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)
                 {
@@ -2411,11 +2360,9 @@ 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);
 		}
 	}
 }
@@ -2476,8 +2423,6 @@ void LLDrawPoolAvatar::updateRiggedVertexBuffers(LLVOAvatar* avatar)
 				continue;
 			}
 
-			stop_glerror();
-
 			LLVolumeFace& vol_face = volume->getVolumeFace(te);
 			updateRiggedFaceVertexBuffer(avatar, face, vobj, volume, vol_face);
 		}
@@ -2501,47 +2446,58 @@ void LLDrawPoolAvatar::updateSkinInfoMatrixPalettes(LLVOAvatar* avatarp)
     }
 }
 
-const LLDrawPoolAvatar::MatrixPaletteCache& LLDrawPoolAvatar::updateSkinInfoMatrixPalette(LLVOAvatar * avatarp, const LLMeshSkinInfo* skin)
+const LLDrawPoolAvatar::MatrixPaletteCache& LLDrawPoolAvatar::updateSkinInfoMatrixPalette(LLVOAvatar * avatarp, const LLUUID& meshId)
 {
-    MatrixPaletteCache& entry = mMatrixPaletteCache[skin];
+    MatrixPaletteCache& entry = mMatrixPaletteCache[meshId];
 
     if (entry.mFrame != gFrameCount)
     {
         LL_PROFILE_ZONE_SCOPED;
+
+        const LLMeshSkinInfo* skin = gMeshRepo.getSkinInfo(meshId);
         entry.mFrame = gFrameCount;
-        //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]);
+        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);
 
-        stop_glerror();
-        
-        entry.mGLMp.resize(count * 12);
+            const LLMatrix4a* mat = &(entry.mMatrixPalette[0]);
 
-        F32* mp = &(entry.mGLMp[0]);
-        
-        for (U32 i = 0; i < count; ++i)
-        {
-            F32* m = (F32*)mat[i].mMatrix[0].getF32ptr();
+            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;
+                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 + 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 + 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];
+                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);
         }
     }
 
diff --git a/indra/newview/lldrawpoolavatar.h b/indra/newview/lldrawpoolavatar.h
index 0c1ee2cced..800bbc5f62 100644
--- a/indra/newview/lldrawpoolavatar.h
+++ b/indra/newview/lldrawpoolavatar.h
@@ -283,12 +283,13 @@ 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;
 
@@ -296,11 +297,11 @@ typedef enum
             mFrame(gFrameCount-1)
         {
         }
-    };
+    } LL_ALIGN_POSTFIX(16);
     
-    const MatrixPaletteCache& updateSkinInfoMatrixPalette(LLVOAvatar* avatarp, const LLMeshSkinInfo* skin);
+    const MatrixPaletteCache& updateSkinInfoMatrixPalette(LLVOAvatar* avatarp, const LLUUID& meshId);
 
-    typedef std::unordered_map<const LLMeshSkinInfo*, MatrixPaletteCache> matrix_palette_cache_t;
+    typedef std::unordered_map<LLUUID, MatrixPaletteCache> matrix_palette_cache_t;
     matrix_palette_cache_t mMatrixPaletteCache;
 
 	/*virtual*/ LLViewerTexture *getDebugTexture();
diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp
index 8ac64dbd15..a19d6d0b19 100644
--- a/indra/newview/llmeshrepository.cpp
+++ b/indra/newview/llmeshrepository.cpp
@@ -4045,7 +4045,7 @@ 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);
+    LL_PROFILE_ZONE_SCOPED;
     if (mesh_id.notNull())
     {
         skin_map::iterator iter = mSkinMap.find(mesh_id);
@@ -4055,6 +4055,7 @@ const LLMeshSkinInfo* LLMeshRepository::getSkinInfo(const LLUUID& mesh_id, const
         }
 
         //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
diff --git a/indra/newview/llmeshrepository.h b/indra/newview/llmeshrepository.h
index c1698194cb..c0e894fda4 100644
--- a/indra/newview/llmeshrepository.h
+++ b/indra/newview/llmeshrepository.h
@@ -586,7 +586,7 @@ public:
 
 	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);
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index e5a4b0f374..b86935b081 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
     {
diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h
index ce400a3498..b8c6f47bbd 100644
--- a/indra/newview/llvovolume.h
+++ b/indra/newview/llvovolume.h
@@ -296,6 +296,9 @@ public:
 	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;
-- 
cgit v1.2.3


From d2dce17803a545378407d6b7c62fdcd3007a92bc Mon Sep 17 00:00:00 2001
From: Dave Parks <davep@lindenlab.com>
Date: Tue, 19 Oct 2021 02:26:41 +0000
Subject: SL-16197 Optimize LLEnvironment handling of shader uniforms. 
 Instrument LLSD.  Enable Fast Timers when Tracy is enabled to catch Fast
 Timer overhead.

---
 indra/cmake/Tracy.cmake              |  2 +-
 indra/llcommon/llsd.cpp              | 32 +++++++++++---
 indra/llcommon/llsd.h                | 12 +++++-
 indra/llinventory/llsettingsbase.cpp |  4 ++
 indra/llinventory/llsettingssky.cpp  |  3 ++
 indra/llrender/llglslshader.cpp      | 68 +++++++++++++++++++++---------
 indra/llrender/llglslshader.h        | 82 ++++++++++++++++++++++++++++++++----
 indra/newview/lldrawpoolbump.cpp     |  1 +
 indra/newview/lldrawpoolterrain.cpp  |  2 -
 indra/newview/lldrawpoolwlsky.cpp    |  6 ---
 indra/newview/llenvironment.cpp      | 39 ++++++++++++++---
 indra/newview/llenvironment.h        | 18 ++++++--
 indra/newview/llsettingsvo.cpp       | 68 +++++++++++++++---------------
 indra/newview/llsettingsvo.h         |  4 --
 indra/newview/pipeline.cpp           |  2 -
 15 files changed, 247 insertions(+), 96 deletions(-)

(limited to 'indra')

diff --git a/indra/cmake/Tracy.cmake b/indra/cmake/Tracy.cmake
index 1b8c3db2e2..cfff956bcf 100644
--- a/indra/cmake/Tracy.cmake
+++ b/indra/cmake/Tracy.cmake
@@ -7,7 +7,7 @@ if (USE_TRACY)
   set(TRACY_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include/tracy) 
 
 # See: indra/llcommon/llprofiler.h
-  add_definitions(-DLL_PROFILER_CONFIGURATION=2)
+  add_definitions(-DLL_PROFILER_CONFIGURATION=3)
   use_prebuilt_binary(tracy)
 
   if (WINDOWS)
diff --git a/indra/llcommon/llsd.cpp b/indra/llcommon/llsd.cpp
index 57b746889d..605f6bf0e3 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 5b6d5545af..b8ddf21596 100644
--- a/indra/llcommon/llsd.h
+++ b/indra/llcommon/llsd.h
@@ -290,9 +290,17 @@ public:
 		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/llinventory/llsettingsbase.cpp b/indra/llinventory/llsettingsbase.cpp
index 61b59e35aa..89a4eebf26 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 81937dbda5..00c1edb55a 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/llrender/llglslshader.cpp b/indra/llrender/llglslshader.cpp
index 84eac00c65..0e4753fcc6 100644
--- a/indra/llrender/llglslshader.cpp
+++ b/indra/llrender/llglslshader.cpp
@@ -1104,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)
@@ -1114,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);
@@ -1126,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)
@@ -1136,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);
@@ -1158,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))
             {
@@ -1181,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))
             {
@@ -1204,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))
             {
@@ -1227,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)
             {
@@ -1250,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)
             {
@@ -1273,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)
             {
@@ -1296,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)
             {
@@ -1319,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;
             }
@@ -1460,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))
         {
@@ -1476,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))
         {
@@ -1493,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))
         {
@@ -1509,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))
         {
@@ -1526,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))
         {
@@ -1542,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)
         {
@@ -1558,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)
         {
@@ -1574,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)
         {
@@ -1591,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;
         }
     }
@@ -1636,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 7cf6d3c941..3b23cf1b28 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 @@ public:
 	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 @@ public:
 	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/newview/lldrawpoolbump.cpp b/indra/newview/lldrawpoolbump.cpp
index f316d121ab..d75884cc16 100644
--- a/indra/newview/lldrawpoolbump.cpp
+++ b/indra/newview/lldrawpoolbump.cpp
@@ -1062,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;
diff --git a/indra/newview/lldrawpoolterrain.cpp b/indra/newview/lldrawpoolterrain.cpp
index 37dc80e2b7..34a8b6b2cc 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/lldrawpoolwlsky.cpp b/indra/newview/lldrawpoolwlsky.cpp
index 0c3d8f3098..8c8dc3f3d2 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 8881d11802..69d3075928 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 7cbf2d25bb..3568fbcfd1 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 @@ public:
 
     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 @@ public:
 
     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 @@ public:
         LLSettingsDay::ptr_t        mDayCycle;
         LLSettingsSky::ptr_t        mSky;
         LLSettingsWater::ptr_t      mWater;
+
         S32                         mSkyTrack;
 
         bool                        mInitialized;
diff --git a/indra/newview/llsettingsvo.cpp b/indra/newview/llsettingsvo.cpp
index 1e5b893cbc..6a88a8ef2c 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 65136ad2f5..caa3ac18d3 100644
--- a/indra/newview/llsettingsvo.h
+++ b/indra/newview/llsettingsvo.h
@@ -102,8 +102,6 @@ public:
 
     bool isAdvanced() const { return  m_isAdvanced; }
 
-    virtual void updateShader(LLGLSLShader* shader) { applySpecial(shader, true); }
-
 protected:
     LLSettingsVOSky();
 
@@ -136,8 +134,6 @@ public:
 
     static LLSD     convertToLegacy(const ptr_t &);
 
-    virtual void    updateShader(LLGLSLShader* shader) { applySpecial(shader, true); }
-
 protected:
     LLSettingsVOWater();
 
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index 5ef3819de4..c4976c4bbc 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -8427,8 +8427,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)
-- 
cgit v1.2.3


From 6ecf8f2c01dc90c26a8a0ccbd11abc2241debfa9 Mon Sep 17 00:00:00 2001
From: Mnikolenko Productengine <mnikolenko@productengine.com>
Date: Wed, 20 Oct 2021 14:53:55 +0300
Subject: SL-16184 FIXED Frame stall when friend comes online.

---
 indra/newview/llcallingcard.cpp               |  5 ++---
 indra/newview/llimview.cpp                    |  1 -
 indra/newview/llinventorybridge.cpp           | 25 +++++++++++++------------
 indra/newview/llnotificationscripthandler.cpp |  3 ++-
 indra/newview/llscreenchannel.cpp             |  3 ++-
 indra/newview/lltoastpanel.cpp                |  3 ++-
 6 files changed, 21 insertions(+), 19 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llcallingcard.cpp b/indra/newview/llcallingcard.cpp
index 6d20b23e9f..9ee9900eba 100644
--- a/indra/newview/llcallingcard.cpp
+++ b/indra/newview/llcallingcard.cpp
@@ -257,7 +257,6 @@ S32 LLAvatarTracker::addBuddyList(const LLAvatarTracker::buddy_map_t& buds)
 			LLAvatarName av_name;
 			LLAvatarNameCache::get(agent_id, &av_name);
 
-			addChangedMask(LLFriendObserver::ADD, agent_id);
 			LL_DEBUGS() << "Added buddy " << agent_id
 					<< ", " << (mBuddyInfo[agent_id]->isOnline() ? "Online" : "Offline")
 					<< ", TO: " << mBuddyInfo[agent_id]->getRightsGrantedTo()
@@ -493,6 +492,7 @@ void LLAvatarTracker::notifyObservers()
 		// new masks and ids will be processed later from idle.
 		return;
 	}
+	LL_PROFILE_ZONE_SCOPED
 	mIsNotifyObservers = TRUE;
 
 	observer_list_t observers(mObservers);
@@ -678,6 +678,7 @@ void LLAvatarTracker::processChangeUserRights(LLMessageSystem* msg, void**)
 
 void LLAvatarTracker::processNotify(LLMessageSystem* msg, bool online)
 {
+	LL_PROFILE_ZONE_SCOPED
 	S32 count = msg->getNumberOfBlocksFast(_PREHASH_AgentBlock);
 	BOOL chat_notify = gSavedSettings.getBOOL("ChatOnlineNotification");
 
@@ -712,8 +713,6 @@ void LLAvatarTracker::processNotify(LLMessageSystem* msg, bool online)
 				// we were tracking someone who went offline
 				deleteTrackingData();
 			}
-			// *TODO: get actual inventory id
-			gInventory.addChangedMask(LLInventoryObserver::CALLING_CARD, LLUUID::null);
 		}
 		if(chat_notify)
 		{
diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp
index 1059324a16..f5358ba5f2 100644
--- a/indra/newview/llimview.cpp
+++ b/indra/newview/llimview.cpp
@@ -1229,7 +1229,6 @@ LLIMModel::LLIMSession* LLIMModel::addMessageSilently(const LLUUID& session_id,
 
 	if (!session)
 	{
-		LL_WARNS() << "session " << session_id << "does not exist " << LL_ENDL;
 		return NULL;
 	}
 
diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp
index fc8179f3b4..844d544e16 100644
--- a/indra/newview/llinventorybridge.cpp
+++ b/indra/newview/llinventorybridge.cpp
@@ -5714,14 +5714,14 @@ class LLCallingCardObserver : public LLFriendObserver
 public:
 	LLCallingCardObserver(LLCallingCardBridge* bridge) : mBridgep(bridge) {}
 	virtual ~LLCallingCardObserver() { mBridgep = NULL; }
-	virtual void changed(U32 mask)
-	{
-		mBridgep->refreshFolderViewItem();
-		if (mask & LLFriendObserver::ONLINE)
-		{
-			mBridgep->checkSearchBySuffixChanges();
-		}
-	}
+    virtual void changed(U32 mask)
+    {
+        if (mask & LLFriendObserver::ONLINE)
+        {
+            mBridgep->refreshFolderViewItem();
+            mBridgep->checkSearchBySuffixChanges();
+        }
+    }
 protected:
 	LLCallingCardBridge* mBridgep;
 };
@@ -5735,14 +5735,15 @@ LLCallingCardBridge::LLCallingCardBridge(LLInventoryPanel* inventory,
 										 const LLUUID& uuid ) :
 	LLItemBridge(inventory, root, uuid)
 {
-	mObserver = new LLCallingCardObserver(this);
-	LLAvatarTracker::instance().addObserver(mObserver);
+    mObserver = new LLCallingCardObserver(this);
+    LLAvatarTracker::instance().addParticularFriendObserver(getItem()->getCreatorUUID(), mObserver);
 }
 
 LLCallingCardBridge::~LLCallingCardBridge()
 {
-	LLAvatarTracker::instance().removeObserver(mObserver);
-	delete mObserver;
+    LLAvatarTracker::instance().removeParticularFriendObserver(getItem()->getCreatorUUID(), mObserver);
+
+    delete mObserver;
 }
 
 void LLCallingCardBridge::refreshFolderViewItem()
diff --git a/indra/newview/llnotificationscripthandler.cpp b/indra/newview/llnotificationscripthandler.cpp
index ba831ab2ed..d896c409d7 100644
--- a/indra/newview/llnotificationscripthandler.cpp
+++ b/indra/newview/llnotificationscripthandler.cpp
@@ -69,7 +69,8 @@ void LLScriptHandler::initChannel()
 //--------------------------------------------------------------------------
 void LLScriptHandler::addToastWithNotification(const LLNotificationPtr& notification)
 {
-	LLToastPanel* notify_box = LLToastPanel::buidPanelFromNotification(notification);
+    LL_PROFILE_ZONE_SCOPED
+    LLToastPanel* notify_box = LLToastPanel::buidPanelFromNotification(notification);
 
 	LLToast::Params p;
 	p.notif_id = notification->getID();
diff --git a/indra/newview/llscreenchannel.cpp b/indra/newview/llscreenchannel.cpp
index 681787bcbe..ca48c9d58c 100644
--- a/indra/newview/llscreenchannel.cpp
+++ b/indra/newview/llscreenchannel.cpp
@@ -259,7 +259,8 @@ void LLScreenChannel::updatePositionAndSize(LLRect new_world_rect)
 //--------------------------------------------------------------------------
 void LLScreenChannel::addToast(const LLToast::Params& p)
 {
-	bool store_toast = false, show_toast = false;
+    LL_PROFILE_ZONE_SCOPED
+    bool store_toast = false, show_toast = false;
 
 	if (mDisplayToastsAlways)
 	{
diff --git a/indra/newview/lltoastpanel.cpp b/indra/newview/lltoastpanel.cpp
index 100d5ee713..d43da93c61 100644
--- a/indra/newview/lltoastpanel.cpp
+++ b/indra/newview/lltoastpanel.cpp
@@ -114,7 +114,8 @@ void LLToastPanel::snapToMessageHeight(LLTextBase* message, S32 maxLineCount)
 LLToastPanel* LLToastPanel::buidPanelFromNotification(
 		const LLNotificationPtr& notification)
 {
-	LLToastPanel* res = NULL;
+    LL_PROFILE_ZONE_SCOPED
+    LLToastPanel* res = NULL;
 
 	//process tip toast panels
 	if ("notifytip" == notification->getType())
-- 
cgit v1.2.3


From eda264c2821a86505b4ec2a898ff3169ab82f895 Mon Sep 17 00:00:00 2001
From: Nat Goodspeed <nat@lindenlab.com>
Date: Wed, 20 Oct 2021 18:38:36 -0400
Subject: SL-16220: Add a WorkQueue to be serviced by mainloop.

Make LLAppViewer::idle() call LL::WorkQueue::runFor() to dequeue and run some
or all of the pending responses from worker threads.

Add a MainWorkTime setting to specify the time slice the main loop may devote
each frame to servicing such responses.
---
 indra/newview/app_settings/settings.xml | 11 +++++++++++
 indra/newview/llappviewer.cpp           | 18 ++++++++++++++++++
 2 files changed, 29 insertions(+)

(limited to 'indra')

diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 05c3fc3bfe..802453d508 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -3858,6 +3858,17 @@
         <key>Value</key>
         <integer>1</integer>
     </map>
+    <key>MainWorkTime</key>
+    <map>
+        <key>Comment</key>
+        <string>Max time per frame devoted to mainloop work queue (in milliseconds)</string>
+        <key>Persist</key>
+        <integer>1</integer>
+        <key>Type</key>
+        <string>F32</string>
+        <key>Value</key>
+        <real>0.1</real>
+    </map>
     <key>QueueInventoryFetchTimeout</key>
     <map>
         <key>Comment</key>
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 722a6caa65..7c932a3959 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -233,6 +233,8 @@
 #include "llavatariconctrl.h"
 #include "llgroupiconctrl.h"
 #include "llviewerassetstats.h"
+#include "workqueue.h"
+using namespace LL;
 
 // Include for security api initialization
 #include "llsecapi.h"
@@ -366,6 +368,8 @@ BOOL gLogoutInProgress = FALSE;
 
 BOOL gSimulateMemLeak = FALSE;
 
+WorkQueue gMainloopWork("mainloop");
+
 ////////////////////////////////////////////////////////////
 // Internal globals... that should be removed.
 static std::string gArgs;
@@ -5210,6 +5214,20 @@ void LLAppViewer::idle()
 	// Execute deferred tasks.
 	LLDeferredTaskList::instance().run();
 
+	// Service the WorkQueue we use for replies from worker threads.
+	// Use function statics for the timeslice setting so we only have to fetch
+	// and convert MainWorkTime once.
+	static F32 MainWorkTimeRaw = gSavedSettings.getF32("MainWorkTime");
+	static F32Milliseconds MainWorkTimeMs(MainWorkTimeRaw);
+	// MainWorkTime is specified in fractional milliseconds, but std::chrono
+	// uses integer representations. What if we want less than a microsecond?
+	// Use nanoseconds. We're very sure we will never need to specify a
+	// MainWorkTime that would be larger than we could express in
+	// std::chrono::nanoseconds.
+	static std::chrono::nanoseconds MainWorkTimeNanoSec{
+		std::chrono::nanoseconds::rep(MainWorkTimeMs.value() * 1000000)};
+	gMainloopWork.runFor(MainWorkTimeNanoSec);
+
 	// Handle shutdown process, for example,
 	// wait for floaters to close, send quit message,
 	// forcibly quit if it has taken too long
-- 
cgit v1.2.3


From a448846ca3bcaf73da428c5ef28d3f130bf128fc Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Thu, 21 Oct 2021 18:46:06 +0300
Subject: SL-16226 Crash at genMeshOptimizerPerModel

---
 indra/newview/llmodelpreview.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'indra')

diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp
index b17aa960ce..4f759446f1 100644
--- a/indra/newview/llmodelpreview.cpp
+++ b/indra/newview/llmodelpreview.cpp
@@ -1911,7 +1911,7 @@ F32 LLModelPreview::genMeshOptimizerPerModel(LLModel *base_model, LLModel *targe
     ll_aligned_free<64>(combined_positions);
     ll_aligned_free<64>(buffer_positions);
     ll_aligned_free_32(output_indices);
-    ll_aligned_free_32(buffer_indices);
+    ll_aligned_free_16(buffer_indices);
     ll_aligned_free_32(combined_indices);
 
     if (new_indices < 3)
-- 
cgit v1.2.3


From fd5e1f0b97adf17469023d81908554890af5d24b Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Thu, 21 Oct 2021 18:54:35 +0300
Subject: SL-15521 Fix license file not mentioning meshoptimizer

---
 indra/newview/licenses-mac.txt   | 26 ++++++++++++++++++++++++++
 indra/newview/licenses-win32.txt | 26 ++++++++++++++++++++++++++
 2 files changed, 52 insertions(+)

(limited to 'indra')

diff --git a/indra/newview/licenses-mac.txt b/indra/newview/licenses-mac.txt
index af80bff5d9..1a3a59d2f5 100644
--- a/indra/newview/licenses-mac.txt
+++ b/indra/newview/licenses-mac.txt
@@ -693,3 +693,29 @@ From Vivox:
      Attn: customer support 
      40 Speen Street Suite 402 
      Framingham, MA 01701 
+
+
+=============
+meshoptimizer
+=============
+MIT License
+
+Copyright (c) 2016-2021 Arseny Kapoulkine
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/indra/newview/licenses-win32.txt b/indra/newview/licenses-win32.txt
index 8736626907..3e337851d7 100644
--- a/indra/newview/licenses-win32.txt
+++ b/indra/newview/licenses-win32.txt
@@ -838,3 +838,29 @@ Although NOT REQUIRED, we would appreciate it if active users of GLOD
 put a link on their web site to the GLOD web site when possible.
 
 
+=============
+meshoptimizer
+=============
+MIT License
+
+Copyright (c) 2016-2021 Arseny Kapoulkine
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+
-- 
cgit v1.2.3


From e774bffb28a71730792931aeb1ed6a46d3cfe67b Mon Sep 17 00:00:00 2001
From: Dave Parks <davep@lindenlab.com>
Date: Thu, 21 Oct 2021 21:19:48 +0000
Subject: SL-16202 Fix for textures appearing black or flashing white due to
 optimization bugs.

---
 indra/llcommon/workqueue.cpp      |   2 +
 indra/llrender/llimagegl.cpp      | 241 ++++++++++++++++++--------------------
 indra/llrender/llimagegl.h        |  16 ++-
 indra/llrender/llrender.cpp       |  14 ++-
 indra/llrender/llrender.h         |   2 +-
 indra/newview/llglsandbox.cpp     |   3 +-
 indra/newview/llviewertexture.cpp |  13 --
 7 files changed, 141 insertions(+), 150 deletions(-)

(limited to 'indra')

diff --git a/indra/llcommon/workqueue.cpp b/indra/llcommon/workqueue.cpp
index ffc9a97dc0..b32357e832 100644
--- a/indra/llcommon/workqueue.cpp
+++ b/indra/llcommon/workqueue.cpp
@@ -54,6 +54,7 @@ void LL::WorkQueue::runUntilClose()
 
 bool LL::WorkQueue::runPending()
 {
+    LL_PROFILE_ZONE_SCOPED;
     for (Work work; mQueue.tryPop(work); )
     {
         callWork(work);
@@ -110,6 +111,7 @@ void LL::WorkQueue::callWork(const Queue::DataTuple& work)
 
 void LL::WorkQueue::callWork(const Work& work)
 {
+    LL_PROFILE_ZONE_SCOPED;
     try
     {
         work();
diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp
index aff29bd857..b5e1910242 100644
--- a/indra/llrender/llimagegl.cpp
+++ b/indra/llrender/llimagegl.cpp
@@ -683,7 +683,7 @@ void LLImageGL::setImage(const LLImageRaw* imageraw)
 }
 
 static LLTrace::BlockTimerStatHandle FTM_SET_IMAGE("setImage");
-BOOL LLImageGL::setImage(const U8* data_in, BOOL data_hasmips)
+BOOL LLImageGL::setImage(const U8* data_in, BOOL data_hasmips, S32 usename)
 {
 	LL_RECORD_BLOCK_TIME(FTM_SET_IMAGE);
 	bool is_compressed = false;
@@ -702,12 +702,11 @@ BOOL LLImageGL::setImage(const U8* data_in, BOOL data_hasmips)
         break;
     }
 	
-	
-	
 	if (mUseMipMaps)
 	{
 		//set has mip maps to true before binding image so tex parameters get set properly
-		gGL.getTexUnit(0)->unbind(mBindTarget);
+        gGL.getTexUnit(0)->unbind(mBindTarget);
+        
 		mHasMipMaps = true;
 		mTexOptionsDirty = true;
 		setFilteringOption(LLTexUnit::TFO_ANISOTROPIC);
@@ -717,7 +716,8 @@ BOOL LLImageGL::setImage(const U8* data_in, BOOL data_hasmips)
 		mHasMipMaps = false;
 	}
 	
-	llverify(gGL.getTexUnit(0)->bind(this));
+    gGL.getTexUnit(0)->bind(this, false, false, usename);
+
 
     if (mUseMipMaps)
 	{
@@ -1211,7 +1211,7 @@ void LLImageGL::generateTextures(S32 numTextures, U32 *textures)
 }
 
 // static
-void LLImageGL::deleteTextures(S32 numTextures, U32 *textures)
+void LLImageGL::deleteTextures(S32 numTextures, const U32 *textures)
 {
 	if (gGLManager.mInited)
 	{
@@ -1381,13 +1381,13 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S
 		return FALSE;
 	}
 
-	mGLTextureCreated = false ;
 	llassert(gGLManager.mInited);
 	stop_glerror();
 
 	if (!imageraw || imageraw->isBufferInvalid())
 	{
 		LL_WARNS() << "Trying to create a texture from invalid image data" << LL_ENDL;
+        mGLTextureCreated = false;
 		return FALSE;
 	}
 
@@ -1407,6 +1407,7 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S
 	if (!setSize(w, h, imageraw->getComponents(), discard_level))
 	{
 		LL_WARNS() << "Trying to create a texture with incorrect dimensions!" << LL_ENDL;
+        mGLTextureCreated = false;
 		return FALSE;
 	}
 
@@ -1475,6 +1476,7 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S
 		destroyGLTexture();
 		mCurrentDiscardLevel = discard_level;	
 		mLastBindTime = sLastFrameTime;
+        mGLTextureCreated = false;
 		return TRUE ;
 	}
 
@@ -1486,104 +1488,123 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S
 static LLTrace::BlockTimerStatHandle FTM_CREATE_GL_TEXTURE3("createGLTexture3(data)");
 BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_hasmips, S32 usename)
 {
-	LL_RECORD_BLOCK_TIME(FTM_CREATE_GL_TEXTURE3);
-	llassert(data_in);
-	stop_glerror();
-
-	if (discard_level < 0)
-	{
-		llassert(mCurrentDiscardLevel >= 0);
-		discard_level = mCurrentDiscardLevel;
-	}
-	discard_level = llclamp(discard_level, 0, (S32)mMaxDiscardLevel);
+    LL_RECORD_BLOCK_TIME(FTM_CREATE_GL_TEXTURE3);
+    llassert(data_in);
+    stop_glerror();
 
-	if (mTexName != 0 && discard_level == mCurrentDiscardLevel)
-	{
-		// This will only be true if the size has not changed
-		return setImage(data_in, data_hasmips);
-	}
-	
-	U32 old_name = mTexName;
-// 	S32 old_discard = mCurrentDiscardLevel;
-	
-	if (usename != 0)
-	{
-		mTexName = usename;
-	}
-	else
-	{
-		LLImageGL::generateTextures(1, &mTexName);
-		stop_glerror();
-		{
-			llverify(gGL.getTexUnit(0)->bind(this));
-			stop_glerror();
-			glTexParameteri(LLTexUnit::getInternalType(mBindTarget), GL_TEXTURE_BASE_LEVEL, 0);
-			stop_glerror();
-			glTexParameteri(LLTexUnit::getInternalType(mBindTarget), GL_TEXTURE_MAX_LEVEL,  mMaxDiscardLevel-discard_level);
-			stop_glerror();
-		}
-	}
-	if (!mTexName)
-	{
-		if (old_name)
-		{
-			sGlobalTextureMemory -= mTextureMemory;
-			LLImageGL::deleteTextures(1, &old_name);
-			disclaimMem(mTextureMemory);
-			stop_glerror();
-		}
+    if (discard_level < 0)
+    {
+        llassert(mCurrentDiscardLevel >= 0);
+        discard_level = mCurrentDiscardLevel;
+    }
+    discard_level = llclamp(discard_level, 0, (S32)mMaxDiscardLevel);
 
-		LL_WARNS() << "LLImageGL::createGLTexture failed to make texture" << LL_ENDL;
-		return FALSE;
-	}
+    if (mTexName != 0 && discard_level == mCurrentDiscardLevel)
+    {
+        // This will only be true if the size has not changed
+        return setImage(data_in, data_hasmips);
+    }
 
-	if (mUseMipMaps)
-	{
-		mAutoGenMips = gGLManager.mHasMipMapGeneration;
+    GLuint old_texname = mTexName;
+    
+    if (usename != 0)
+    {
+        mNewTexName = usename;
+    }
+    else
+    {
+        LLImageGL::generateTextures(1, &mNewTexName);
+        {
+            gGL.getTexUnit(0)->bind(this, false, false, mNewTexName);
+            glTexParameteri(LLTexUnit::getInternalType(mBindTarget), GL_TEXTURE_BASE_LEVEL, 0);
+            glTexParameteri(LLTexUnit::getInternalType(mBindTarget), GL_TEXTURE_MAX_LEVEL, mMaxDiscardLevel - discard_level);
+        }
+    }
+    
+    if (mUseMipMaps)
+    {
+        mAutoGenMips = gGLManager.mHasMipMapGeneration;
 #if LL_DARWIN
-		// On the Mac GF2 and GF4MX drivers, auto mipmap generation doesn't work right with alpha-only textures.
-		if(gGLManager.mIsGF2or4MX && (mFormatInternal == GL_ALPHA8) && (mFormatPrimary == GL_ALPHA))
-		{
-			mAutoGenMips = FALSE;
-		}
+        // On the Mac GF2 and GF4MX drivers, auto mipmap generation doesn't work right with alpha-only textures.
+        if (gGLManager.mIsGF2or4MX && (mFormatInternal == GL_ALPHA8) && (mFormatPrimary == GL_ALPHA))
+        {
+            mAutoGenMips = FALSE;
+        }
 #endif
-	}
+    }
 
-	mCurrentDiscardLevel = discard_level;	
+    mCurrentDiscardLevel = discard_level;
 
-	if (!setImage(data_in, data_hasmips))
-	{
-		stop_glerror();
-		return FALSE;
-	}
+    if (!setImage(data_in, data_hasmips, mNewTexName))
+    {
+        return FALSE;
+    }
 
-	// Set texture options to our defaults.
-	gGL.getTexUnit(0)->setHasMipMaps(mHasMipMaps);
-	gGL.getTexUnit(0)->setTextureAddressMode(mAddressMode);
-	gGL.getTexUnit(0)->setTextureFilteringOption(mFilterOption);
+    // Set texture options to our defaults.
+    gGL.getTexUnit(0)->setHasMipMaps(mHasMipMaps);
+    gGL.getTexUnit(0)->setTextureAddressMode(mAddressMode);
+    gGL.getTexUnit(0)->setTextureFilteringOption(mFilterOption);
 
-	// things will break if we don't unbind after creation
-	gGL.getTexUnit(0)->unbind(mBindTarget);
-	stop_glerror();
+    // things will break if we don't unbind after creation
+    gGL.getTexUnit(0)->unbind(mBindTarget);
 
-	if (old_name != 0)
-	{
-		sGlobalTextureMemory -= mTextureMemory;
+    if (old_texname != 0)
+    {
+        sGlobalTextureMemory -= mTextureMemory;
+    }
 
-		LLImageGL::deleteTextures(1, &old_name);
+    //if we're on the image loading thread, be sure to delete old_texname and update mTexName on the main thread
+    if (LLImageGLThread::sInstance != nullptr && 
+        LLThread::currentID() == LLImageGLThread::sInstance->getID())
+    {
+        {
+            LL_PROFILE_ZONE_NAMED("cglt - sync");
+            if (gGLManager.mHasSync)
+            {
+                auto sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
+                glClientWaitSync(sync, 0, 0);
+                glDeleteSync(sync);
+            }
+            else
+            {
+                glFinish();
+            }
+        }
 
-		stop_glerror();
-	}
+        ref();
+        LLImageGLThread::sInstance->postCallback([=]()
+            {
+                LL_PROFILE_ZONE_NAMED("cglt - delete callback");
+                if (old_texname != 0)
+                {
+                    LLImageGL::deleteTextures(1, &old_texname);
+                }
+                mTexName = mNewTexName;
+                mNewTexName = 0;
+                unref();
+            });
+    }
+    else 
+    {
+        //not on background thread, immediately set mTexName
+        if (old_texname != 0)
+        {
+            LLImageGL::deleteTextures(1, &old_texname);
+        }
+        mTexName = mNewTexName;
+        mNewTexName = 0;
+    }
+    
+    disclaimMem(mTextureMemory);
+    mTextureMemory = (S32Bytes)getMipBytes(mCurrentDiscardLevel);
+    claimMem(mTextureMemory);
+    sGlobalTextureMemory += mTextureMemory;
+    mTexelsInGLTexture = getWidth() * getHeight();
 
-	disclaimMem(mTextureMemory);
-	mTextureMemory = (S32Bytes)getMipBytes(discard_level);
-	claimMem(mTextureMemory);
-	sGlobalTextureMemory += mTextureMemory;
-	mTexelsInGLTexture = getWidth() * getHeight() ;
+    // mark this as bound at this point, so we don't throw it out immediately
+    mLastBindTime = sLastFrameTime;
 
-	// mark this as bound at this point, so we don't throw it out immediately
-	mLastBindTime = sLastFrameTime;
-	return TRUE;
+    return TRUE;
 }
 
 BOOL LLImageGL::readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool compressed_ok) const
@@ -2274,17 +2295,7 @@ 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;
-        }
+        mFunctionQueue.post(func);
     }
     catch (LLThreadSafeQueueInterrupt e)
     {
@@ -2300,7 +2311,7 @@ bool LLImageGLThread::postCallback(const std::function<void()>& callback)
 {
     try
     {
-        mCallbackQueue.pushFront(callback);
+        mCallbackQueue.post(callback);
     }
     catch (LLThreadSafeQueueInterrupt e)
     {
@@ -2315,34 +2326,14 @@ 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();
-    }
+    mCallbackQueue.runPending();
 }
 
 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
-    }
+    mFunctionQueue.runUntilClose();
     gGL.shutdown();
     mWindow->destroySharedContext(mContext);
 }
diff --git a/indra/llrender/llimagegl.h b/indra/llrender/llimagegl.h
index 8e9b483c2d..da626a1093 100644
--- a/indra/llrender/llimagegl.h
+++ b/indra/llrender/llimagegl.h
@@ -37,6 +37,8 @@
 #include "llunits.h"
 #include "llthreadsafequeue.h"
 #include "llrender.h"
+#include "workqueue.h"
+
 class LLTextureAtlas ;
 class LLWindow;
 
@@ -50,7 +52,7 @@ class LLImageGL : public LLRefCount, public LLTrace::MemTrackable<LLImageGL>
 public:
 	// These 2 functions replace glGenTextures() and glDeleteTextures()
 	static void generateTextures(S32 numTextures, U32 *textures);
-	static void deleteTextures(S32 numTextures, U32 *textures);
+	static void deleteTextures(S32 numTextures, const U32 *textures);
 	static void deleteDeadTextures();
 
 	// Size calculation
@@ -110,7 +112,7 @@ public:
 		S32 category = sMaxCategories-1);
 	BOOL createGLTexture(S32 discard_level, const U8* data, BOOL data_hasmips = FALSE, S32 usename = 0);
 	void setImage(const LLImageRaw* imageraw);
-	BOOL setImage(const U8* data_in, BOOL data_hasmips = FALSE);
+	BOOL setImage(const U8* data_in, BOOL data_hasmips = FALSE, S32 usename = 0);
 	BOOL setSubImage(const LLImageRaw* imageraw, S32 x_pos, S32 y_pos, S32 width, S32 height, BOOL force_fast_update = FALSE);
 	BOOL setSubImage(const U8* datap, S32 data_width, S32 data_height, S32 x_pos, S32 y_pos, S32 width, S32 height, BOOL force_fast_update = FALSE);
 	BOOL setSubImageFromFrameBuffer(S32 fb_x, S32 fb_y, S32 x_pos, S32 y_pos, S32 width, S32 height);
@@ -210,8 +212,9 @@ private:
 
 	bool     mGLTextureCreated ;
 	LLGLuint mTexName;
+    LLGLuint mNewTexName = 0; // tex name set by background thread to be applied in main thread
 	U16      mWidth;
-	U16      mHeight;	
+	U16      mHeight;
 	S8       mCurrentDiscardLevel;
 	
 	S8       mDiscardLevelInAtlas;
@@ -319,8 +322,11 @@ public:
 
     void run() override;
 
-    LLThreadSafeQueue<std::function<void()>> mFunctionQueue;
-    LLThreadSafeQueue<std::function<void()>> mCallbackQueue;
+    // Work Queue for background thread
+    LL::WorkQueue mFunctionQueue;
+
+    // Work Queue for main thread (run from updateClass)
+    LL::WorkQueue mCallbackQueue;
 
     LLWindow* mWindow;
     void* mContext;
diff --git a/indra/llrender/llrender.cpp b/indra/llrender/llrender.cpp
index 669a09d3ce..aad04beea2 100644
--- a/indra/llrender/llrender.cpp
+++ b/indra/llrender/llrender.cpp
@@ -236,6 +236,10 @@ void LLTexUnit::bindFast(LLTexture* texture)
     glActiveTextureARB(GL_TEXTURE0_ARB + mIndex);
     gGL.mCurrTextureUnitIndex = mIndex;
     mCurrTexture = gl_tex->getTexName();
+    if (!mCurrTexture)
+    {
+        mCurrTexture = LLImageGL::sDefaultGLTexture->getTexName();
+    }
     glBindTexture(sGLTextureType[gl_tex->getTarget()], mCurrTexture);
     mHasMipMaps = gl_tex->mHasMipMaps;
 }
@@ -306,18 +310,20 @@ bool LLTexUnit::bind(LLTexture* texture, bool for_rendering, bool forceBind)
 	return true;
 }
 
-bool LLTexUnit::bind(LLImageGL* texture, bool for_rendering, bool forceBind)
+bool LLTexUnit::bind(LLImageGL* texture, bool for_rendering, bool forceBind, S32 usename)
 {
 	stop_glerror();
 	if (mIndex < 0) return false;
 
+    U32 texname = usename ? usename : texture->getTexName();
+
 	if(!texture)
 	{
 		LL_DEBUGS() << "NULL LLTexUnit::bind texture" << LL_ENDL;
 		return false;
 	}
 
-	if(!texture->getTexName())
+	if(!texname)
 	{
 		if(LLImageGL::sDefaultGLTexture && LLImageGL::sDefaultGLTexture->getTexName())
 		{
@@ -327,7 +333,7 @@ bool LLTexUnit::bind(LLImageGL* texture, bool for_rendering, bool forceBind)
 		return false ;
 	}
 
-	if ((mCurrTexture != texture->getTexName()) || forceBind)
+	if ((mCurrTexture != texname) || forceBind)
 	{
 		gGL.flush();
 		stop_glerror();
@@ -335,7 +341,7 @@ bool LLTexUnit::bind(LLImageGL* texture, bool for_rendering, bool forceBind)
 		stop_glerror();
 		enable(texture->getTarget());
 		stop_glerror();
-		mCurrTexture = texture->getTexName();
+		mCurrTexture = texname;
 		glBindTexture(sGLTextureType[texture->getTarget()], mCurrTexture);
 		stop_glerror();
 		texture->updateBindStats(texture->mTextureMemory);		
diff --git a/indra/llrender/llrender.h b/indra/llrender/llrender.h
index 6e2647a16b..7f19a45410 100644
--- a/indra/llrender/llrender.h
+++ b/indra/llrender/llrender.h
@@ -158,7 +158,7 @@ public:
 	
 	// Binds the LLImageGL to this texture unit 
 	// (automatically enables the unit for the LLImageGL's texture type)
-	bool bind(LLImageGL* texture, bool for_rendering = false, bool forceBind = false);
+	bool bind(LLImageGL* texture, bool for_rendering = false, bool forceBind = false, S32 usename = 0);
     bool bind(LLTexture* texture, bool for_rendering = false, bool forceBind = false);
 
     // bind implementation for inner loops
diff --git a/indra/newview/llglsandbox.cpp b/indra/newview/llglsandbox.cpp
index 0f288e05ca..91f314c115 100644
--- a/indra/newview/llglsandbox.cpp
+++ b/indra/newview/llglsandbox.cpp
@@ -1090,7 +1090,7 @@ F32 gpu_benchmark()
     delete [] pixels;
 
 	//make a dummy triangle to draw with
-	LLPointer<LLVertexBuffer> buff = new LLVertexBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0, GL_STREAM_DRAW_ARB);
+	LLPointer<LLVertexBuffer> buff = new LLVertexBuffer(LLVertexBuffer::MAP_VERTEX, GL_STREAM_DRAW_ARB);
 
 	if (!buff->allocateBuffer(3, 0, true))
 	{
@@ -1100,7 +1100,6 @@ F32 gpu_benchmark()
 	}
 
 	LLStrider<LLVector3> v;
-	LLStrider<LLVector2> tc;
 
 	if (! buff->getVertexStrider(v))
 	{
diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp
index 949e71a4c9..34847d8618 100644
--- a/indra/newview/llviewertexture.cpp
+++ b/indra/newview/llviewertexture.cpp
@@ -1637,19 +1637,6 @@ void LLViewerFetchedTexture::scheduleCreateTexture()
             {
                 //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
-- 
cgit v1.2.3


From a172c9d9cf358c3d9329a1777e30f627f50d5aaa Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Thu, 21 Oct 2021 16:46:06 -0700
Subject: SL-16127: Replace slow getLightTransmittance with faster version

---
 indra/llinventory/llsettingssky.cpp    | 8 ++++++++
 indra/llinventory/llsettingssky.h      | 1 +
 indra/newview/lllegacyatmospherics.cpp | 2 +-
 3 files changed, 10 insertions(+), 1 deletion(-)

(limited to 'indra')

diff --git a/indra/llinventory/llsettingssky.cpp b/indra/llinventory/llsettingssky.cpp
index 81937dbda5..69b4a4929d 100644
--- a/indra/llinventory/llsettingssky.cpp
+++ b/indra/llinventory/llsettingssky.cpp
@@ -1206,6 +1206,14 @@ LLColor3 LLSettingsSky::getLightTransmittance(F32 distance) const
     return transmittance;
 }
 
+// SL-16127: getTotalDensity() and getDensityMultiplier() call LLSettingsSky::getColor() and LLSettingsSky::getFloat() respectively which are S-L-O-W
+LLColor3 LLSettingsSky::getLightTransmittanceFast( const LLColor3& total_density, const F32 density_multiplier, const F32 distance ) const
+{
+    // Transparency (-> density) from Beer's law
+    LLColor3 transmittance = componentExp(total_density * -(density_multiplier * distance));
+    return transmittance;
+}
+
 // performs soft scale clip and gamma correction ala the shader implementation
 // scales colors down to 0 - 1 range preserving relative ratios
 LLColor3 LLSettingsSky::gammaCorrect(const LLColor3& in) const
diff --git a/indra/llinventory/llsettingssky.h b/indra/llinventory/llsettingssky.h
index 4127911643..77d9d8e87c 100644
--- a/indra/llinventory/llsettingssky.h
+++ b/indra/llinventory/llsettingssky.h
@@ -252,6 +252,7 @@ public:
 
     LLColor3 getLightAttenuation(F32 distance) const;
     LLColor3 getLightTransmittance(F32 distance) const;
+    LLColor3 getLightTransmittanceFast(const LLColor3& total_density, const F32 density_multiplier, const F32 distance) const;
     LLColor3 getTotalDensity() const;
     LLColor3 gammaCorrect(const LLColor3& in) const;
 
diff --git a/indra/newview/lllegacyatmospherics.cpp b/indra/newview/lllegacyatmospherics.cpp
index a2acb3efe2..71482c3261 100644
--- a/indra/newview/lllegacyatmospherics.cpp
+++ b/indra/newview/lllegacyatmospherics.cpp
@@ -313,7 +313,7 @@ void LLAtmospherics::calcSkyColorWLVert(const LLSettingsSky::ptr_t &psky, LLVect
 	// Sunlight attenuation effect (hue and brightness) due to atmosphere
 	// this is used later for sunlight modulation at various altitudes
 	LLColor3 light_atten = vars.light_atten;
-    LLColor3 light_transmittance = psky->getLightTransmittance(Plen);
+    LLColor3 light_transmittance = psky->getLightTransmittanceFast(vars.total_density, vars.density_multiplier, Plen);
     (void)light_transmittance; // silence Clang warn-error
 
 	// Calculate relative weights
-- 
cgit v1.2.3


From d84a08379e01ca755bafb68ef58c6d2fe8c95780 Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Thu, 21 Oct 2021 16:47:48 -0700
Subject: SL-16127: Remove unused functions

---
 indra/newview/llvosky.h | 3 ---
 1 file changed, 3 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llvosky.h b/indra/newview/llvosky.h
index 39e42bbb24..ddcb3b1742 100644
--- a/indra/newview/llvosky.h
+++ b/indra/newview/llvosky.h
@@ -214,7 +214,6 @@ public:
 	// Initialize/delete data that's only inited once per class.
 	void init();
 	void initCubeMap();
-	void initEmpty();
 	
 	void cleanupGL();
 	void restoreGL();
@@ -253,8 +252,6 @@ public:
     LLColor4 getSkyFogColor() const                        { return m_legacyAtmospherics.getFogColor(); }
     LLColor4 getGLFogColor() const                      { return m_legacyAtmospherics.getGLFogColor(); }
 
-    LLColor4U getFadeColor() const;
-
 	void setCloudDensity(F32 cloud_density)				{ mCloudDensity = cloud_density; }
 	void setWind ( const LLVector3& wind )				{ mWind = wind.length(); }
 
-- 
cgit v1.2.3


From 6339eb7393e6c84a1651f71ebea6be4ce44ccbcf Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Thu, 21 Oct 2021 16:50:09 -0700
Subject: SL-16127: Cleanup trailing whitespace

---
 indra/newview/llvosky.cpp | 28 ++++++++++++++--------------
 1 file changed, 14 insertions(+), 14 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llvosky.cpp b/indra/newview/llvosky.cpp
index 878d7287ed..8a4958ac06 100644
--- a/indra/newview/llvosky.cpp
+++ b/indra/newview/llvosky.cpp
@@ -1,25 +1,25 @@
-/** 
+/**
  * @file llvosky.cpp
  * @brief LLVOSky class implementation
  *
  * $LicenseInfo:firstyear=2001&license=viewerlgpl$
  * Second Life Viewer Source Code
  * Copyright (C) 2010, Linden Research, Inc.
- * 
+ *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  * License as published by the Free Software Foundation;
  * version 2.1 of the License only.
- * 
+ *
  * This library is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * Lesser General Public License for more details.
- * 
+ *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- * 
+ *
  * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
  * $/LicenseInfo$
  */
@@ -468,7 +468,7 @@ void LLVOSky::init()
     LLSettingsSky::ptr_t psky = LLEnvironment::instance().getCurrentSky();
 
     // invariants across whole sky tex process...
-    m_atmosphericsVars.blue_density = psky->getBlueDensity();    
+    m_atmosphericsVars.blue_density = psky->getBlueDensity();
     m_atmosphericsVars.blue_horizon = psky->getBlueHorizon();
     m_atmosphericsVars.haze_density = psky->getHazeDensity();
     m_atmosphericsVars.haze_horizon = psky->getHazeHorizon();
@@ -476,7 +476,7 @@ void LLVOSky::init()
     m_atmosphericsVars.max_y = psky->getMaxY();
     m_atmosphericsVars.sun_norm = LLEnvironment::instance().getClampedSunNorm();
     m_atmosphericsVars.sunlight = psky->getIsSunUp() ? psky->getSunlightColor() : psky->getMoonlightColor();
-    m_atmosphericsVars.ambient = psky->getAmbientColor();    
+    m_atmosphericsVars.ambient = psky->getAmbientColor();
     m_atmosphericsVars.glow = psky->getGlow();
     m_atmosphericsVars.cloud_shadow = psky->getCloudShadow();
     m_atmosphericsVars.dome_radius = psky->getDomeRadius();
@@ -514,7 +514,7 @@ void LLVOSky::calc()
     LLSettingsSky::ptr_t psky = LLEnvironment::instance().getCurrentSky();
 
     // invariants across whole sky tex process...
-    m_atmosphericsVars.blue_density = psky->getBlueDensity();    
+    m_atmosphericsVars.blue_density = psky->getBlueDensity();
     m_atmosphericsVars.blue_horizon = psky->getBlueHorizon();
     m_atmosphericsVars.haze_density = psky->getHazeDensity();
     m_atmosphericsVars.haze_horizon = psky->getHazeHorizon();
@@ -523,7 +523,7 @@ void LLVOSky::calc()
     m_atmosphericsVars.max_y = psky->getMaxY();
     m_atmosphericsVars.sun_norm = LLEnvironment::instance().getClampedSunNorm();
     m_atmosphericsVars.sunlight = psky->getIsSunUp() ? psky->getSunlightColor() : psky->getMoonlightColor();
-    m_atmosphericsVars.ambient = psky->getAmbientColor();    
+    m_atmosphericsVars.ambient = psky->getAmbientColor();
     m_atmosphericsVars.glow = psky->getGlow();
     m_atmosphericsVars.cloud_shadow = psky->getCloudShadow();
     m_atmosphericsVars.dome_radius = psky->getDomeRadius();
@@ -541,7 +541,7 @@ void LLVOSky::calc()
 	mMoon.renewColor();
 }
 
-void LLVOSky::initCubeMap() 
+void LLVOSky::initCubeMap()
 {
 	std::vector<LLPointer<LLImageRaw> > images;
 	for (S32 side = 0; side < NUM_CUBEMAP_FACES; side++)
@@ -925,7 +925,7 @@ void LLVOSky::setSunTextures(const LLUUID& sun_texture, const LLUUID& sun_textur
         {
             if (mSunTexturep[1])
 						{
-	            mSunTexturep[1]->setAddressMode(LLTexUnit::TAM_CLAMP);            
+	            mSunTexturep[1]->setAddressMode(LLTexUnit::TAM_CLAMP);
 						}
             mFace[FACE_SUN]->setTexture(LLRender::ALTERNATE_DIFFUSE_MAP, mSunTexturep[1]);
 					}
@@ -1033,7 +1033,7 @@ BOOL LLVOSky::updateGeometry(LLDrawable *drawable)
 
 	for (S32 side = 0; side < NUM_CUBEMAP_FACES; ++side)
 	{
-		face = mFace[FACE_SIDE0 + side]; 
+		face = mFace[FACE_SIDE0 + side];
 
 		if (!face->getVertexBuffer())
 		{
@@ -1164,7 +1164,7 @@ bool LLVOSky::updateHeavenlyBodyGeometry(LLDrawable *drawable, F32 scale, const
 
 	hb.setVisible(TRUE);
 
-	facep = mFace[f]; 
+	facep = mFace[f];
 
 	if (!facep->getVertexBuffer())
 	{
@@ -1402,7 +1402,7 @@ void LLVOSky::updateReflectionGeometry(LLDrawable *drawable, F32 H,
 		dt_clip = -0.1f;
 	}
 
-	LLFace *face = mFace[FACE_REFLECTION]; 
+	LLFace *face = mFace[FACE_REFLECTION];
 
     if (face)
     {
-- 
cgit v1.2.3


From 76487ce707d042cdb937dc1fe610896ef9421e80 Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Thu, 21 Oct 2021 17:10:51 -0700
Subject: SL-16127: Use cache psky when possible

---
 indra/newview/llvosky.cpp | 62 +++++++++++++++++++++++------------------------
 indra/newview/llvosky.h   |  2 +-
 2 files changed, 32 insertions(+), 32 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llvosky.cpp b/indra/newview/llvosky.cpp
index 8a4958ac06..0799d63cbb 100644
--- a/indra/newview/llvosky.cpp
+++ b/indra/newview/llvosky.cpp
@@ -461,11 +461,10 @@ void LLVOSky::init()
     llassert(!mInitialized);
 
     // Update sky at least once to get correct initial sun/moon directions and lighting calcs performed
-    LLEnvironment::instance().getCurrentSky()->update();
-
-	updateDirections();
-
     LLSettingsSky::ptr_t psky = LLEnvironment::instance().getCurrentSky();
+    psky->update();
+
+    updateDirections(psky);
 
     // invariants across whole sky tex process...
     m_atmosphericsVars.blue_density = psky->getBlueDensity();
@@ -592,7 +591,7 @@ void LLVOSky::restoreGL()
         setMoonTextures(psky->getMoonTextureId(), psky->getNextMoonTextureId());
     }
 
-	updateDirections();
+	updateDirections(psky);
 
 	if (gSavedSettings.getBOOL("RenderWater") && gGLManager.mHasCubeMap && LLCubeMap::sUseCubeMaps)
 		{
@@ -661,16 +660,14 @@ void LLVOSky::createSkyTexture(AtmosphericsVars& vars, const S32 side, const S32
 	}
 }
 
-void LLVOSky::updateDirections(void)
+void LLVOSky::updateDirections(LLSettingsSky::ptr_t psky)
 {
-    LLSettingsSky::ptr_t psky = LLEnvironment::instance().getCurrentSky();
-
     mSun.setDirection(psky->getSunDirection());
-	mMoon.setDirection(psky->getMoonDirection());
+    mMoon.setDirection(psky->getMoonDirection());
     mSun.setRotation(psky->getSunRotation());
-	mMoon.setRotation(psky->getMoonRotation());
-	mSun.renewDirection();
-	mMoon.renewDirection();
+    mMoon.setRotation(psky->getMoonRotation());
+    mSun.renewDirection();
+    mMoon.renewDirection();
 }
 
 void LLVOSky::idleUpdate(LLAgent &agent, const F64 &time)
@@ -717,7 +714,7 @@ bool LLVOSky::updateSky()
 
 	mInterpVal = (!mInitialized) ? 1 : (F32)next_frame / cycle_frame_no;
 	LLHeavenBody::setInterpVal( mInterpVal );
-	updateDirections();
+	updateDirections(psky);
 
     if (!mCubeMap)
 	{
@@ -1579,16 +1576,17 @@ void LLVOSky::setSunAndMoonDirectionsCFR(const LLVector3 &sun_dir_cfr, const LLV
 	    F32 sunDot = llmax(0.f, sun_dir_cfr.mV[2]);
 	    sunDot *= sunDot;	
 
-	    // Create normalized vector that has the sunDir pushed south about an hour and change.
-	    LLVector3 adjustedDir = (sun_dir_cfr + LLVector3(0.f, -0.70711f, 0.70711f)) * 0.5f;
-		
-	    // Blend between normal sun dir and adjusted sun dir based on how close we are
-	    // to having the sun overhead.
-	    mBumpSunDir = adjustedDir * sunDot + sun_dir_cfr * (1.0f - sunDot);
-	    mBumpSunDir.normalize();
-		}
-	updateDirections();
-	}
+    // Create normalized vector that has the sunDir pushed south about an hour and change.
+    LLVector3 adjustedDir = (sun_dir_cfr + LLVector3(0.f, -0.70711f, 0.70711f)) * 0.5f;
+
+    // Blend between normal sun dir and adjusted sun dir based on how close we are
+    // to having the sun overhead.
+    mBumpSunDir = adjustedDir * sunDot + sun_dir_cfr * (1.0f - sunDot);
+    mBumpSunDir.normalize();
+
+    LLSettingsSky::ptr_t psky = LLEnvironment::instance().getCurrentSky();
+    updateDirections(psky);
+}
 
 void LLVOSky::setSunDirectionCFR(const LLVector3 &sun_dir_cfr)
 	{
@@ -1604,16 +1602,18 @@ void LLVOSky::setSunDirectionCFR(const LLVector3 &sun_dir_cfr)
 	// Create normalized vector that has the sunDir pushed south about an hour and change.
 	    LLVector3 adjustedDir = (sun_dir_cfr + LLVector3(0.f, -0.70711f, 0.70711f)) * 0.5f;
 
-	// Blend between normal sun dir and adjusted sun dir based on how close we are
-	// to having the sun overhead.
-	    mBumpSunDir = adjustedDir * sunDot + sun_dir_cfr * (1.0f - sunDot);
-	mBumpSunDir.normalize();
-    }
-	updateDirections();
+    // Blend between normal sun dir and adjusted sun dir based on how close we are
+    // to having the sun overhead.
+    mBumpSunDir = adjustedDir * sunDot + sun_dir_cfr * (1.0f - sunDot);
+    mBumpSunDir.normalize();
+
+    LLSettingsSky::ptr_t psky = LLEnvironment::instance().getCurrentSky();
+    updateDirections(psky);
 }
 
 void LLVOSky::setMoonDirectionCFR(const LLVector3 &moon_dir_cfr)
 {
-	mMoon.setDirection(moon_dir_cfr);
-	updateDirections();
+    mMoon.setDirection(moon_dir_cfr);
+    LLSettingsSky::ptr_t psky = LLEnvironment::instance().getCurrentSky();
+    updateDirections(psky);
 }
diff --git a/indra/newview/llvosky.h b/indra/newview/llvosky.h
index ddcb3b1742..efa45a3cc5 100644
--- a/indra/newview/llvosky.h
+++ b/indra/newview/llvosky.h
@@ -296,7 +296,7 @@ public:
 protected:
 	~LLVOSky();
 
-	void updateDirections(void);
+	void updateDirections(LLSettingsSky::ptr_t psky);
 
 	void initSkyTextureDirs(const S32 side, const S32 tile);
 	void createSkyTexture(AtmosphericsVars& vars, const S32 side, const S32 tile);
-- 
cgit v1.2.3


From ee724fecdc1c3285cfa1a260a2fdf8f2355a68fa Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Thu, 21 Oct 2021 17:11:42 -0700
Subject: SL-16127: Cleanup indentation and whitespace to match coding style

---
 indra/newview/llvosky.cpp | 118 +++++++++++++++++++++++-----------------------
 1 file changed, 58 insertions(+), 60 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llvosky.cpp b/indra/newview/llvosky.cpp
index 0799d63cbb..cb2b2e8dfb 100644
--- a/indra/newview/llvosky.cpp
+++ b/indra/newview/llvosky.cpp
@@ -113,7 +113,7 @@ void LLSkyTex::init(bool isShiny)
 		mTexture[i] = LLViewerTextureManager::getLocalTexture(FALSE);
 		mTexture[i]->setAddressMode(LLTexUnit::TAM_CLAMP);
 		mImageRaw[i] = new LLImageRaw(sResolution, sResolution, sComponents);
-		
+
 		initEmpty(i);
 	}
 }
@@ -208,7 +208,7 @@ void LLSkyTex::create()
 }
 
 void LLSkyTex::createGLImage(S32 which)
-{	
+{
 	mTexture[which]->setExplicitFormat(GL_RGBA8, GL_RGBA);
 	mTexture[which]->createGLTexture(0, mImageRaw[which], 0, TRUE, LLGLTexture::LOCAL);
 	mTexture[which]->setAddressMode(LLTexUnit::TAM_CLAMP);
@@ -433,7 +433,7 @@ LLVOSky::LLVOSky(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp)
 	{
 		mFace[i] = NULL;
 	}
-	
+
 	mCameraPosAgent = gAgentCamera.getCameraPositionAgent();
 	mAtmHeight = ATM_HEIGHT;
 	mEarthCenter = LLVector3(mCameraPosAgent.mV[0], mCameraPosAgent.mV[1], -EARTH_RADIUS);
@@ -547,7 +547,7 @@ void LLVOSky::initCubeMap()
 	{
 		images.push_back(mShinyTex[side].getImageRaw());
 	}
-	
+
 	if (!mCubeMap && gSavedSettings.getBOOL("RenderWater") && gGLManager.mHasCubeMap && LLCubeMap::sUseCubeMaps)
 	{
         mCubeMap = new LLCubeMap(false);
@@ -594,9 +594,9 @@ void LLVOSky::restoreGL()
 	updateDirections(psky);
 
 	if (gSavedSettings.getBOOL("RenderWater") && gGLManager.mHasCubeMap && LLCubeMap::sUseCubeMaps)
-		{
+	{
 		initCubeMap();
-		}
+	}
 
     forceSkyUpdate();
 
@@ -706,7 +706,7 @@ bool LLVOSky::updateSky()
 	static S32 next_frame = 0;
 	const S32 total_no_tiles = NUM_CUBEMAP_FACES * NUM_TILES;
 	const S32 cycle_frame_no = total_no_tiles + 1;
-	
+
     mNeedUpdate = mForceUpdate;
 
 	++next_frame;
@@ -722,7 +722,7 @@ bool LLVOSky::updateSky()
         mForceUpdate = FALSE;
         return TRUE;
 	}
-	
+
     if (mCubeMapUpdateStage < 0)
     {
         LL_RECORD_BLOCK_TIME(FTM_VOSKY_CALC);
@@ -886,10 +886,10 @@ void LLVOSky::setSunScale(F32 sun_scale)
 void LLVOSky::setMoonScale(F32 moon_scale)
 {
     mMoonScale = moon_scale;
-	}
-	
+}
+
 void LLVOSky::setSunTextures(const LLUUID& sun_texture, const LLUUID& sun_texture_next)
-	{
+{
     // We test the UUIDs here because we explicitly do not want the default image returned by getFetchedTexture in that case...
     mSunTexturep[0] = sun_texture.isNull() ? nullptr : LLViewerTextureManager::getFetchedTexture(sun_texture, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_UI);
     mSunTexturep[1] = sun_texture_next.isNull() ? nullptr : LLViewerTextureManager::getFetchedTexture(sun_texture_next, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_UI);
@@ -907,32 +907,32 @@ void LLVOSky::setSunTextures(const LLUUID& sun_texture, const LLUUID& sun_textur
         LLViewerTexture* current_tex1 = mFace[FACE_SUN]->getTexture(LLRender::ALTERNATE_DIFFUSE_MAP);
 
         if (current_tex0 && (mSunTexturep[0] != current_tex0) && current_tex0->isViewerMediaTexture())
-			{
+        {
             static_cast<LLViewerMediaTexture*>(current_tex0)->removeMediaFromFace(mFace[FACE_SUN]);
         }
 
         if (current_tex1 && (mSunTexturep[1] != current_tex1) && current_tex1->isViewerMediaTexture())
-				{
+        {
             static_cast<LLViewerMediaTexture*>(current_tex1)->removeMediaFromFace(mFace[FACE_SUN]);
-						}
+        }
 
         mFace[FACE_SUN]->setTexture(LLRender::DIFFUSE_MAP, mSunTexturep[0]);
 
         if (can_use_wl)
         {
             if (mSunTexturep[1])
-						{
-	            mSunTexturep[1]->setAddressMode(LLTexUnit::TAM_CLAMP);
-						}
+            {
+                mSunTexturep[1]->setAddressMode(LLTexUnit::TAM_CLAMP);
+            }
             mFace[FACE_SUN]->setTexture(LLRender::ALTERNATE_DIFFUSE_MAP, mSunTexturep[1]);
-					}
-				}
-			}
+        }
+    }
+}
 
 void LLVOSky::setMoonTextures(const LLUUID& moon_texture, const LLUUID& moon_texture_next)
-			{
+{
     LLSettingsSky::ptr_t psky = LLEnvironment::instance().getCurrentSky();
-			
+
     bool can_use_wl = gPipeline.canUseWindLightShaders();
 
     mMoonTexturep[0] = moon_texture.isNull()      ? nullptr : LLViewerTextureManager::getFetchedTexture(moon_texture, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_UI);
@@ -941,17 +941,17 @@ void LLVOSky::setMoonTextures(const LLUUID& moon_texture, const LLUUID& moon_tex
     if (mFace[FACE_MOON])
     {
         if (mMoonTexturep[0])
-		{
-	        mMoonTexturep[0]->setAddressMode(LLTexUnit::TAM_CLAMP);
-	}
+        {
+            mMoonTexturep[0]->setAddressMode(LLTexUnit::TAM_CLAMP);
+        }
         mFace[FACE_MOON]->setTexture(LLRender::DIFFUSE_MAP, mMoonTexturep[0]);
 
         if (mMoonTexturep[1] && can_use_wl)
-	{
-	        mMoonTexturep[1]->setAddressMode(LLTexUnit::TAM_CLAMP);
+        {
+            mMoonTexturep[1]->setAddressMode(LLTexUnit::TAM_CLAMP);
             mFace[FACE_MOON]->setTexture(LLRender::ALTERNATE_DIFFUSE_MAP, mMoonTexturep[1]);
-	}
-	}
+        }
+    }
 }
 
 void LLVOSky::setCloudNoiseTextures(const LLUUID& cloud_noise_texture, const LLUUID& cloud_noise_texture_next)
@@ -960,7 +960,7 @@ void LLVOSky::setCloudNoiseTextures(const LLUUID& cloud_noise_texture, const LLU
 
     mCloudNoiseTexturep[0] = cloud_noise_texture.isNull() ? nullptr : LLViewerTextureManager::getFetchedTexture(cloud_noise_texture, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_UI);
     mCloudNoiseTexturep[1] = cloud_noise_texture_next.isNull() ? nullptr : LLViewerTextureManager::getFetchedTexture(cloud_noise_texture_next, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_UI);
-	
+
     if (mCloudNoiseTexturep[0])
 	{
 	    mCloudNoiseTexturep[0]->setAddressMode(LLTexUnit::TAM_WRAP);
@@ -983,15 +983,15 @@ void LLVOSky::setBloomTextures(const LLUUID& bloom_texture, const LLUUID& bloom_
     mBloomTexturep[1] = bloom_tex_next.isNull() ? nullptr : LLViewerTextureManager::getFetchedTexture(bloom_tex_next, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_UI);
 
     if (mBloomTexturep[0])
-{	
-	    mBloomTexturep[0]->setAddressMode(LLTexUnit::TAM_CLAMP);
+    {
+        mBloomTexturep[0]->setAddressMode(LLTexUnit::TAM_CLAMP);
     }
 
     if (mBloomTexturep[1])
-	{
-	    mBloomTexturep[1]->setAddressMode(LLTexUnit::TAM_CLAMP);
+    {
+        mBloomTexturep[1]->setAddressMode(LLTexUnit::TAM_CLAMP);
     }
-	}
+}
 
 static LLTrace::BlockTimerStatHandle FTM_GEO_SKY("Sky Geometry");
 
@@ -1026,7 +1026,7 @@ BOOL LLVOSky::updateGeometry(LLDrawable *drawable)
 	LLStrider<LLVector2> texCoordsp;
 	LLStrider<U16> indicesp;
 	U16 index_offset;
-	LLFace *face;	
+	LLFace *face;
 
 	for (S32 side = 0; side < NUM_CUBEMAP_FACES; ++side)
 	{
@@ -1042,7 +1042,7 @@ BOOL LLVOSky::updateGeometry(LLDrawable *drawable)
 			face->setVertexBuffer(buff);
 
 			index_offset = face->getGeometry(verticesp,normalsp,texCoordsp, indicesp);
-			
+
 			S32 vtx = 0;
 			S32 curr_bit = side >> 1; // 0/1 = Z axis, 2/3 = Y, 4/5 = X
 			S32 side_dir = side & 1;  // even - 0, odd - 1
@@ -1165,7 +1165,7 @@ bool LLVOSky::updateHeavenlyBodyGeometry(LLDrawable *drawable, F32 scale, const
 
 	if (!facep->getVertexBuffer())
 	{
-		facep->setSize(4, 6);	
+		facep->setSize(4, 6);
 		LLVertexBuffer* buff = new LLVertexBuffer(LLDrawPoolSky::VERTEX_DATA_MASK, GL_STREAM_DRAW_ARB);
 		if (!buff->allocateBuffer(facep->getGeomCount(), facep->getIndicesCount(), TRUE))
 		{
@@ -1417,13 +1417,13 @@ void LLVOSky::updateReflectionGeometry(LLDrawable *drawable, F32 H,
 		face->setGeomIndex(0);
 		face->setVertexBuffer(buff);
 	}
-	
+
 	LLStrider<LLVector3> verticesp;
 	LLStrider<LLVector3> normalsp;
 	LLStrider<LLVector2> texCoordsp;
 	LLStrider<U16> indicesp;
 	S32 index_offset;
-	
+
 	index_offset = face->getGeometry(verticesp,normalsp,texCoordsp, indicesp);
 	if (-1 == index_offset)
 	{
@@ -1441,7 +1441,7 @@ void LLVOSky::updateReflectionGeometry(LLDrawable *drawable, F32 H,
 
         LLColor4 hb_refl_col = (1 - attenuation) * hb_col + attenuation * getSkyFogColor();
 	face->setFaceColor(hb_refl_col);
-	
+
 	LLVector3 v_far[2];
 	v_far[0] = v_refl_corner[1];
 	v_far[1] = v_refl_corner[3];
@@ -1565,16 +1565,15 @@ void LLVOSky::updateFog(const F32 distance)
 	}
 
 void LLVOSky::setSunAndMoonDirectionsCFR(const LLVector3 &sun_dir_cfr, const LLVector3 &moon_dir_cfr)
-	{
-    mSun.setDirection(sun_dir_cfr);	
-	mMoon.setDirection(moon_dir_cfr);
+{
+    mSun.setDirection(sun_dir_cfr);
+    mMoon.setDirection(moon_dir_cfr);
 
-	// Push the sun "South" as it approaches directly overhead so that we can always see bump mapping
-	// on the upward facing faces of cubes.
-	{
-	    // Same as dot product with the up direction + clamp.
-	    F32 sunDot = llmax(0.f, sun_dir_cfr.mV[2]);
-	    sunDot *= sunDot;	
+    // Push the sun "South" as it approaches directly overhead so that we can always see bump mapping
+    // on the upward facing faces of cubes.
+    // Same as dot product with the up direction + clamp.
+    F32 sunDot = llmax(0.f, sun_dir_cfr.mV[2]);
+    sunDot *= sunDot;
 
     // Create normalized vector that has the sunDir pushed south about an hour and change.
     LLVector3 adjustedDir = (sun_dir_cfr + LLVector3(0.f, -0.70711f, 0.70711f)) * 0.5f;
@@ -1589,18 +1588,17 @@ void LLVOSky::setSunAndMoonDirectionsCFR(const LLVector3 &sun_dir_cfr, const LLV
 }
 
 void LLVOSky::setSunDirectionCFR(const LLVector3 &sun_dir_cfr)
-	{
-    mSun.setDirection(sun_dir_cfr);	
+{
+    mSun.setDirection(sun_dir_cfr);
 
-	// Push the sun "South" as it approaches directly overhead so that we can always see bump mapping
-	// on the upward facing faces of cubes.
-    {
-	// Same as dot product with the up direction + clamp.
-	    F32 sunDot = llmax(0.f, sun_dir_cfr.mV[2]);
-	sunDot *= sunDot;	
+    // Push the sun "South" as it approaches directly overhead so that we can always see bump mapping
+    // on the upward facing faces of cubes.
+    // Same as dot product with the up direction + clamp.
+    F32 sunDot = llmax(0.f, sun_dir_cfr.mV[2]);
+    sunDot *= sunDot;
 
-	// Create normalized vector that has the sunDir pushed south about an hour and change.
-	    LLVector3 adjustedDir = (sun_dir_cfr + LLVector3(0.f, -0.70711f, 0.70711f)) * 0.5f;
+    // Create normalized vector that has the sunDir pushed south about an hour and change.
+    LLVector3 adjustedDir = (sun_dir_cfr + LLVector3(0.f, -0.70711f, 0.70711f)) * 0.5f;
 
     // Blend between normal sun dir and adjusted sun dir based on how close we are
     // to having the sun overhead.
-- 
cgit v1.2.3


From 94d08a13d5737f072231584d9f135dc44e8c6750 Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Thu, 21 Oct 2021 18:40:24 -0700
Subject: SL-16127: Use cached sky

---
 indra/newview/llvosky.cpp | 8 +++-----
 indra/newview/llvosky.h   | 2 +-
 2 files changed, 4 insertions(+), 6 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llvosky.cpp b/indra/newview/llvosky.cpp
index cb2b2e8dfb..1fd10a231a 100644
--- a/indra/newview/llvosky.cpp
+++ b/indra/newview/llvosky.cpp
@@ -491,7 +491,7 @@ void LLVOSky::init()
 		for (S32 tile = 0; tile < NUM_TILES; ++tile)
 		{
 			initSkyTextureDirs(side, tile);
-            createSkyTexture(m_atmosphericsVars, side, tile);
+            createSkyTexture(psky, m_atmosphericsVars, side, tile);
 		}
         mSkyTex[side].create();
         mShinyTex[side].create();
@@ -639,10 +639,8 @@ void LLVOSky::initSkyTextureDirs(const S32 side, const S32 tile)
 	}
 }
 
-void LLVOSky::createSkyTexture(AtmosphericsVars& vars, const S32 side, const S32 tile)
+void LLVOSky::createSkyTexture(LLSettingsSky::ptr_t psky, AtmosphericsVars& vars, const S32 side, const S32 tile)
 {
-	LLSettingsSky::ptr_t psky = LLEnvironment::instance().getCurrentSky();
-
 	S32 tile_x = tile % NUM_TILES_X;
 	S32 tile_y = tile / NUM_TILES_X;
 
@@ -812,7 +810,7 @@ bool LLVOSky::updateSky()
         // instead of executing per face, or may be can be moved to shaders)
         for (S32 tile = 0; tile < NUM_TILES; tile++)
         {
-            createSkyTexture(m_atmosphericsVars, side, tile);
+            createSkyTexture(psky, m_atmosphericsVars, side, tile);
         }
         mCubeMapUpdateStage++;
     }
diff --git a/indra/newview/llvosky.h b/indra/newview/llvosky.h
index efa45a3cc5..0b313a9a61 100644
--- a/indra/newview/llvosky.h
+++ b/indra/newview/llvosky.h
@@ -299,7 +299,7 @@ protected:
 	void updateDirections(LLSettingsSky::ptr_t psky);
 
 	void initSkyTextureDirs(const S32 side, const S32 tile);
-	void createSkyTexture(AtmosphericsVars& vars, const S32 side, const S32 tile);
+	void createSkyTexture(LLSettingsSky::ptr_t psky, AtmosphericsVars& vars, const S32 side, const S32 tile);
 
 	LLPointer<LLViewerFetchedTexture> mSunTexturep[2];
 	LLPointer<LLViewerFetchedTexture> mMoonTexturep[2];
-- 
cgit v1.2.3


From de2c6826073ab1fbc83ac8a486157c177aa1f5dc Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Thu, 21 Oct 2021 18:43:35 -0700
Subject: SL-16127: Fix bug in int() not calling getDistanceMultiplier(),
 calc() not calling getTotalDensity()

---
 indra/newview/llvosky.cpp | 62 +++++++++++++++++++----------------------------
 indra/newview/llvosky.h   |  1 +
 2 files changed, 26 insertions(+), 37 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llvosky.cpp b/indra/newview/llvosky.cpp
index 1fd10a231a..882bfe6f7d 100644
--- a/indra/newview/llvosky.cpp
+++ b/indra/newview/llvosky.cpp
@@ -466,24 +466,7 @@ void LLVOSky::init()
 
     updateDirections(psky);
 
-    // invariants across whole sky tex process...
-    m_atmosphericsVars.blue_density = psky->getBlueDensity();
-    m_atmosphericsVars.blue_horizon = psky->getBlueHorizon();
-    m_atmosphericsVars.haze_density = psky->getHazeDensity();
-    m_atmosphericsVars.haze_horizon = psky->getHazeHorizon();
-    m_atmosphericsVars.density_multiplier = psky->getDensityMultiplier();
-    m_atmosphericsVars.max_y = psky->getMaxY();
-    m_atmosphericsVars.sun_norm = LLEnvironment::instance().getClampedSunNorm();
-    m_atmosphericsVars.sunlight = psky->getIsSunUp() ? psky->getSunlightColor() : psky->getMoonlightColor();
-    m_atmosphericsVars.ambient = psky->getAmbientColor();
-    m_atmosphericsVars.glow = psky->getGlow();
-    m_atmosphericsVars.cloud_shadow = psky->getCloudShadow();
-    m_atmosphericsVars.dome_radius = psky->getDomeRadius();
-    m_atmosphericsVars.dome_offset = psky->getDomeOffset();
-    m_atmosphericsVars.light_atten = psky->getLightAttenuation(m_atmosphericsVars.max_y);
-    m_atmosphericsVars.light_transmittance = psky->getLightTransmittance(m_atmosphericsVars.max_y);
-    m_atmosphericsVars.total_density = psky->getTotalDensity();
-    m_atmosphericsVars.gamma = psky->getGamma();
+    cacheEnvironment(psky,m_atmosphericsVars);
 
 	// Initialize the cached normalized direction vectors
 	for (S32 side = 0; side < NUM_CUBEMAP_FACES; ++side)
@@ -508,28 +491,33 @@ void LLVOSky::init()
 }
 
 
+void LLVOSky::cacheEnvironment(LLSettingsSky::ptr_t psky,AtmosphericsVars& atmosphericsVars)
+{
+    // invariants across whole sky tex process...
+    atmosphericsVars.blue_density = psky->getBlueDensity();
+    atmosphericsVars.blue_horizon = psky->getBlueHorizon();
+    atmosphericsVars.haze_density = psky->getHazeDensity();
+    atmosphericsVars.haze_horizon = psky->getHazeHorizon();
+    atmosphericsVars.density_multiplier = psky->getDensityMultiplier();
+    atmosphericsVars.distance_multiplier = psky->getDistanceMultiplier();
+    atmosphericsVars.max_y = psky->getMaxY();
+    atmosphericsVars.sun_norm = LLEnvironment::instance().getClampedSunNorm();
+    atmosphericsVars.sunlight = psky->getIsSunUp() ? psky->getSunlightColor() : psky->getMoonlightColor();
+    atmosphericsVars.ambient = psky->getAmbientColor();
+    atmosphericsVars.glow = psky->getGlow();
+    atmosphericsVars.cloud_shadow = psky->getCloudShadow();
+    atmosphericsVars.dome_radius = psky->getDomeRadius();
+    atmosphericsVars.dome_offset = psky->getDomeOffset();
+    atmosphericsVars.light_atten = psky->getLightAttenuation(atmosphericsVars.max_y);
+    atmosphericsVars.light_transmittance = psky->getLightTransmittance(atmosphericsVars.max_y);
+    atmosphericsVars.total_density = psky->getTotalDensity();
+    atmosphericsVars.gamma = psky->getGamma();
+}
+
 void LLVOSky::calc()
 {
     LLSettingsSky::ptr_t psky = LLEnvironment::instance().getCurrentSky();
-
-    // invariants across whole sky tex process...
-    m_atmosphericsVars.blue_density = psky->getBlueDensity();
-    m_atmosphericsVars.blue_horizon = psky->getBlueHorizon();
-    m_atmosphericsVars.haze_density = psky->getHazeDensity();
-    m_atmosphericsVars.haze_horizon = psky->getHazeHorizon();
-    m_atmosphericsVars.density_multiplier = psky->getDensityMultiplier();
-    m_atmosphericsVars.distance_multiplier = psky->getDistanceMultiplier();
-    m_atmosphericsVars.max_y = psky->getMaxY();
-    m_atmosphericsVars.sun_norm = LLEnvironment::instance().getClampedSunNorm();
-    m_atmosphericsVars.sunlight = psky->getIsSunUp() ? psky->getSunlightColor() : psky->getMoonlightColor();
-    m_atmosphericsVars.ambient = psky->getAmbientColor();
-    m_atmosphericsVars.glow = psky->getGlow();
-    m_atmosphericsVars.cloud_shadow = psky->getCloudShadow();
-    m_atmosphericsVars.dome_radius = psky->getDomeRadius();
-    m_atmosphericsVars.dome_offset = psky->getDomeOffset();
-    m_atmosphericsVars.light_atten = psky->getLightAttenuation(m_atmosphericsVars.max_y);
-    m_atmosphericsVars.light_transmittance = psky->getLightTransmittance(m_atmosphericsVars.max_y);
-    m_atmosphericsVars.gamma = psky->getGamma();
+    cacheEnvironment(psky,m_atmosphericsVars);
 
 	mSun.setColor(psky->getSunDiffuse());
 	mMoon.setColor(LLColor3(1.0f, 1.0f, 1.0f));
diff --git a/indra/newview/llvosky.h b/indra/newview/llvosky.h
index 0b313a9a61..793dcf4cbf 100644
--- a/indra/newview/llvosky.h
+++ b/indra/newview/llvosky.h
@@ -219,6 +219,7 @@ public:
 	void restoreGL();
 
     void calc();
+    void cacheEnvironment(LLSettingsSky::ptr_t psky, AtmosphericsVars& atmosphericsVars);
 
 	/*virtual*/ void idleUpdate(LLAgent &agent, const F64 &time);
 	bool updateSky();
-- 
cgit v1.2.3


From de3568f1fdab50b3bdbbb1a6b67d552c97c86464 Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Thu, 21 Oct 2021 18:46:31 -0700
Subject: SL-16127: Cleanup consts

---
 indra/newview/llvosky.cpp | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llvosky.cpp b/indra/newview/llvosky.cpp
index 882bfe6f7d..9b929cda8c 100644
--- a/indra/newview/llvosky.cpp
+++ b/indra/newview/llvosky.cpp
@@ -64,7 +64,9 @@ namespace
     const S32 NUM_TILES_X = 8;
     const S32 NUM_TILES_Y = 4;
     const S32 NUM_TILES = NUM_TILES_X * NUM_TILES_Y;
-    const S32 NUM_CUBEMAP_FACES = 6;
+    const S32 NUM_CUBEMAP_FACES = 6; // See sResolution for face dimensions
+    const S32 TOTAL_TILES = NUM_CUBEMAP_FACES * NUM_TILES;
+    const S32 MAX_TILES = TOTAL_TILES + 1;
 
 // Heavenly body constants
     const F32 SUN_DISK_RADIUS	= 0.5f;
@@ -690,15 +692,13 @@ bool LLVOSky::updateSky()
 	}
 
 	static S32 next_frame = 0;
-	const S32 total_no_tiles = NUM_CUBEMAP_FACES * NUM_TILES;
-	const S32 cycle_frame_no = total_no_tiles + 1;
 
     mNeedUpdate = mForceUpdate;
 
 	++next_frame;
-	next_frame = next_frame % cycle_frame_no;
+	next_frame = next_frame % MAX_TILES;
 
-	mInterpVal = (!mInitialized) ? 1 : (F32)next_frame / cycle_frame_no;
+	mInterpVal = (!mInitialized) ? 1 : (F32)next_frame / MAX_TILES;
 	LLHeavenBody::setInterpVal( mInterpVal );
 	updateDirections(psky);
 
-- 
cgit v1.2.3


From 4463d01aa96712ed41d5d8b074a19d892e2d1480 Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Thu, 21 Oct 2021 18:46:55 -0700
Subject: SL-16127: More cleanup

---
 indra/newview/llvosky.cpp | 9 ++-------
 1 file changed, 2 insertions(+), 7 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llvosky.cpp b/indra/newview/llvosky.cpp
index 9b929cda8c..edf8c40bd3 100644
--- a/indra/newview/llvosky.cpp
+++ b/indra/newview/llvosky.cpp
@@ -642,8 +642,8 @@ void LLVOSky::createSkyTexture(LLSettingsSky::ptr_t psky, AtmosphericsVars& vars
 	{
 		for (x = tile_x_pos; x < (tile_x_pos + sTileResX); ++x)
 		{
-			mSkyTex[side].setPixel(m_legacyAtmospherics.calcSkyColorInDir(psky, vars, mSkyTex[side].getDir(x, y), false), x, y);
-			mShinyTex[side].setPixel(m_legacyAtmospherics.calcSkyColorInDir(psky, vars, mShinyTex[side].getDir(x, y), true), x, y);
+			mSkyTex  [side].setPixel(m_legacyAtmospherics.calcSkyColorInDir(psky, vars, mSkyTex  [side].getDir(x, y), false), x, y);
+			mShinyTex[side].setPixel(m_legacyAtmospherics.calcSkyColorInDir(psky, vars, mShinyTex[side].getDir(x, y), true ), x, y);
 		}
 	}
 }
@@ -676,11 +676,6 @@ bool LLVOSky::updateSky()
     LLSettingsSky::ptr_t psky = LLEnvironment::instance().getCurrentSky();
 
 	if (mDead || !(gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_SKY)))
-	{
-		return TRUE;
-	}
-
-	if (mDead)
 	{
 		// It's dead.  Don't update it.
 		return TRUE;
-- 
cgit v1.2.3


From 26e8d2d8c7328878cb6bc83eb6b3b7b5b1462f17 Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Thu, 21 Oct 2021 18:50:28 -0700
Subject: SL-16127: Const cleanup

---
 indra/newview/lllegacyatmospherics.cpp | 15 ++++++++-------
 1 file changed, 8 insertions(+), 7 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/lllegacyatmospherics.cpp b/indra/newview/lllegacyatmospherics.cpp
index 71482c3261..9eda254b25 100644
--- a/indra/newview/lllegacyatmospherics.cpp
+++ b/indra/newview/lllegacyatmospherics.cpp
@@ -211,8 +211,8 @@ LLColor4 LLAtmospherics::calcSkyColorInDir(AtmosphericsVars& vars, const LLVecto
 // This cubemap is used as "environmentMap" in indra/newview/app_settings/shaders/class2/deferred/softenLightF.glsl
 LLColor4 LLAtmospherics::calcSkyColorInDir(const LLSettingsSky::ptr_t &psky, AtmosphericsVars& vars, const LLVector3 &dir, bool isShiny)
 {
-	F32 sky_saturation = 0.25f;
-	F32 land_saturation = 0.1f;
+	const F32 sky_saturation = 0.25f;
+	const F32 land_saturation = 0.1f;
 
 	if (isShiny && dir.mV[VZ] < -0.02f)
 	{
@@ -270,11 +270,12 @@ LLColor4 LLAtmospherics::calcSkyColorInDir(const LLSettingsSky::ptr_t &psky, Atm
 //       indra\newview\lllegacyatmospherics.cpp
 void LLAtmospherics::calcSkyColorWLVert(const LLSettingsSky::ptr_t &psky, LLVector3 & Pn, AtmosphericsVars& vars)
 {
-    LLColor3    blue_density = vars.blue_density;
-    LLColor3    blue_horizon = vars.blue_horizon;
-    F32         haze_horizon = vars.haze_horizon;
-    F32         haze_density = vars.haze_density;
-    F32         density_multiplier = vars.density_multiplier;
+    const LLColor3    blue_density = vars.blue_density;
+    const LLColor3    blue_horizon = vars.blue_horizon;
+    const F32         haze_horizon = vars.haze_horizon;
+    const F32         haze_density = vars.haze_density;
+    const F32         density_multiplier = vars.density_multiplier;
+
     F32         max_y = vars.max_y;
     LLVector4   sun_norm = vars.sun_norm;
 
-- 
cgit v1.2.3


From f2eba1909d5d02553c1f6b456a424b384f110fdf Mon Sep 17 00:00:00 2001
From: Mnikolenko Productengine <mnikolenko@productengine.com>
Date: Fri, 22 Oct 2021 16:09:41 +0300
Subject: SL-16234 FIXED Frame stall caused by unnecessary building the floater
 when exiting viewer

---
 indra/llui/llfloater.h                 | 2 ++
 indra/newview/llfloaterimcontainer.cpp | 8 +++++++-
 2 files changed, 9 insertions(+), 1 deletion(-)

(limited to 'indra')

diff --git a/indra/llui/llfloater.h b/indra/llui/llfloater.h
index 2672d600c6..306760b7fb 100644
--- a/indra/llui/llfloater.h
+++ b/indra/llui/llfloater.h
@@ -346,6 +346,8 @@ public:
 	// handle refocusing.
 	static void		closeFrontmostFloater();
 
+    static bool     isQuitRequested() { return sQuitting; }
+
 //	LLNotification::Params contextualNotification(const std::string& name) 
 //	{ 
 //	    return LLNotification::Params(name).context(mNotificationContext); 
diff --git a/indra/newview/llfloaterimcontainer.cpp b/indra/newview/llfloaterimcontainer.cpp
index 9c84fa1991..2ccb9ab074 100644
--- a/indra/newview/llfloaterimcontainer.cpp
+++ b/indra/newview/llfloaterimcontainer.cpp
@@ -723,7 +723,13 @@ void LLFloaterIMContainer::setMinimized(BOOL b)
 }
 
 void LLFloaterIMContainer::setVisible(BOOL visible)
-{	LLFloaterIMNearbyChat* nearby_chat;
+{
+    if (LLFloater::isQuitRequested())
+    {
+        return;
+    }
+
+    LLFloaterIMNearbyChat* nearby_chat;
 	if (visible)
 	{
 		// Make sure we have the Nearby Chat present when showing the conversation container
-- 
cgit v1.2.3


From 11afa09ea3f56c0e20eb195ae1520a88602ceaca Mon Sep 17 00:00:00 2001
From: Nat Goodspeed <nat@lindenlab.com>
Date: Fri, 22 Oct 2021 11:36:31 -0400
Subject: SL-16220: Add LL::ThreadPool class and a "General" instance.

ThreadPool bundles a WorkQueue with the specified number of worker threads to
service it. Each ThreadPool has a name that can be used to locate its
WorkQueue.

Each worker thread calls WorkQueue::runUntilClose().

ThreadPool listens on the "LLApp" LLEventPump for shutdown notification. On
receiving that, it closes its WorkQueue and then join()s each of its worker
threads for orderly shutdown.

Add a settings.xml entry "ThreadPoolSizes", the first LLSD-valued settings
entry to expect a map: pool name->size. The expectation is that usually code
instantiating a particular ThreadPool will have a default size in mind, but it
should check "ThreadPoolSizes" for a user override.

Make idle_startup()'s STATE_SEED_CAP_GRANTED state instantiate a "General"
ThreadPool. This is function-static for lazy initialization.

Eliminate LLMainLoopRepeater, which is completely unreferenced. Any potential
future use cases are better addressed by posting to the main loop's WorkQueue.

Eliminate llappviewer.cpp's private LLDeferredTaskList class, which
implemented LLAppViewer::addOnIdleCallback(). Make addOnIdleCallback() post
work to the main loop's WorkQueue instead.
---
 indra/llcommon/CMakeLists.txt           |  3 +-
 indra/llcommon/threadpool.cpp           | 75 ++++++++++++++++++++++++++++
 indra/llcommon/threadpool.h             | 46 +++++++++++++++++
 indra/llcommon/timing.cpp               | 25 ----------
 indra/llcommon/workqueue.cpp            | 10 ++++
 indra/llcommon/workqueue.h              |  5 ++
 indra/newview/CMakeLists.txt            |  2 -
 indra/newview/app_settings/settings.xml | 14 ++++++
 indra/newview/llappviewer.cpp           | 47 +-----------------
 indra/newview/llmainlooprepeater.cpp    | 88 ---------------------------------
 indra/newview/llmainlooprepeater.h      | 64 ------------------------
 indra/newview/llstartup.cpp             | 18 +++++++
 12 files changed, 171 insertions(+), 226 deletions(-)
 create mode 100644 indra/llcommon/threadpool.cpp
 create mode 100644 indra/llcommon/threadpool.h
 delete mode 100644 indra/llcommon/timing.cpp
 delete mode 100644 indra/newview/llmainlooprepeater.cpp
 delete mode 100644 indra/newview/llmainlooprepeater.h

(limited to 'indra')

diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt
index fda43dd24c..c374f1135c 100644
--- a/indra/llcommon/CMakeLists.txt
+++ b/indra/llcommon/CMakeLists.txt
@@ -121,8 +121,8 @@ set(llcommon_SOURCE_FILES
     lluriparser.cpp
     lluuid.cpp
     llworkerthread.cpp
-    timing.cpp
     u64.cpp
+    threadpool.cpp
     workqueue.cpp
     StackWalker.cpp
     )
@@ -258,6 +258,7 @@ set(llcommon_HEADER_FILES
     lockstatic.h
     stdtypes.h
     stringize.h
+    threadpool.h
     threadsafeschedule.h
     timer.h
     tuple.h
diff --git a/indra/llcommon/threadpool.cpp b/indra/llcommon/threadpool.cpp
new file mode 100644
index 0000000000..aa7d4179a2
--- /dev/null
+++ b/indra/llcommon/threadpool.cpp
@@ -0,0 +1,75 @@
+/**
+ * @file   threadpool.cpp
+ * @author Nat Goodspeed
+ * @date   2021-10-21
+ * @brief  Implementation for threadpool.
+ * 
+ * $LicenseInfo:firstyear=2021&license=viewerlgpl$
+ * Copyright (c) 2021, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+// Precompiled header
+#include "linden_common.h"
+// associated header
+#include "threadpool.h"
+// STL headers
+// std headers
+// external library headers
+// other Linden headers
+#include "llerror.h"
+#include "llevents.h"
+#include "stringize.h"
+
+LL::ThreadPool::ThreadPool(const std::string& name, size_t threads):
+    mQueue(name),
+    mName("ThreadPool:" + name)
+{
+    for (size_t i = 0; i < threads; ++i)
+    {
+        std::string tname{ STRINGIZE(mName << ':' << (i+i) << '/' << threads) };
+        mThreads.emplace_back(tname, [this, tname](){ run(tname); });
+    }
+    // Listen on "LLApp", and when the app is shutting down, close the queue
+    // and join the workers.
+    LLEventPumps::instance().obtain("LLApp").listen(
+        mName,
+        [this](const LLSD& stat)
+        {
+            std::string status(stat["status"]);
+            if (status != "running")
+            {
+                // viewer is starting shutdown -- proclaim the end is nigh!
+                LL_DEBUGS("ThreadPool") << mName << " saw " << status << LL_ENDL;
+                close();
+            }
+            return false;
+        });
+}
+
+LL::ThreadPool::~ThreadPool()
+{
+    close();
+}
+
+void LL::ThreadPool::close()
+{
+    if (! mQueue.isClosed())
+    {
+        LL_DEBUGS("ThreadPool") << mName << " closing queue and joining threads" << LL_ENDL;
+        mQueue.close();
+        for (auto& pair: mThreads)
+        {
+            LL_DEBUGS("ThreadPool") << mName << " waiting on thread " << pair.first << LL_ENDL;
+            pair.second.join();
+        }
+        LL_DEBUGS("ThreadPool") << mName << " shutdown complete" << LL_ENDL;
+    }
+}
+
+void LL::ThreadPool::run(const std::string& name)
+{
+    LL_DEBUGS("ThreadPool") << name << " starting" << LL_ENDL;
+    mQueue.runUntilClose();
+    LL_DEBUGS("ThreadPool") << name << " stopping" << LL_ENDL;
+}
diff --git a/indra/llcommon/threadpool.h b/indra/llcommon/threadpool.h
new file mode 100644
index 0000000000..8f3c8514b5
--- /dev/null
+++ b/indra/llcommon/threadpool.h
@@ -0,0 +1,46 @@
+/**
+ * @file   threadpool.h
+ * @author Nat Goodspeed
+ * @date   2021-10-21
+ * @brief  ThreadPool configures a WorkQueue along with a pool of threads to
+ *         service it.
+ * 
+ * $LicenseInfo:firstyear=2021&license=viewerlgpl$
+ * Copyright (c) 2021, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+#if ! defined(LL_THREADPOOL_H)
+#define LL_THREADPOOL_H
+
+#include "workqueue.h"
+#include <string>
+#include <thread>
+#include <utility>                  // std::pair
+#include <vector>
+
+namespace LL
+{
+
+    class ThreadPool
+    {
+    public:
+        /**
+         * Pass ThreadPool a string name. This can be used to look up the
+         * relevant WorkQueue.
+         */
+        ThreadPool(const std::string& name, size_t threads=1);
+        ~ThreadPool();
+        void close();
+
+    private:
+        void run(const std::string& name);
+
+        WorkQueue mQueue;
+        std::string mName;
+        std::vector<std::pair<std::string, std::thread>> mThreads;
+    };
+
+} // namespace LL
+
+#endif /* ! defined(LL_THREADPOOL_H) */
diff --git a/indra/llcommon/timing.cpp b/indra/llcommon/timing.cpp
deleted file mode 100644
index c2dc695ef3..0000000000
--- a/indra/llcommon/timing.cpp
+++ /dev/null
@@ -1,25 +0,0 @@
-/** 
- * @file timing.cpp
- * @brief This file will be deprecated in the future.
- *
- * $LicenseInfo:firstyear=2000&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$
- */
diff --git a/indra/llcommon/workqueue.cpp b/indra/llcommon/workqueue.cpp
index ffc9a97dc0..114aeea1f3 100644
--- a/indra/llcommon/workqueue.cpp
+++ b/indra/llcommon/workqueue.cpp
@@ -38,6 +38,16 @@ void LL::WorkQueue::close()
     mQueue.close();
 }
 
+bool LL::WorkQueue::isClosed()
+{
+    return mQueue.isClosed();
+}
+
+bool LL::WorkQueue::done()
+{
+    return mQueue.done();
+}
+
 void LL::WorkQueue::runUntilClose()
 {
     try
diff --git a/indra/llcommon/workqueue.h b/indra/llcommon/workqueue.h
index b88aef989a..cfae2019dc 100644
--- a/indra/llcommon/workqueue.h
+++ b/indra/llcommon/workqueue.h
@@ -59,6 +59,11 @@ namespace LL
          */
         void close();
 
+        /// producer end: are we prevented from pushing any additional items?
+        bool isClosed();
+        /// consumer end: are we done, is the queue entirely drained?
+        bool done();
+
         /*---------------------- fire and forget API -----------------------*/
 
         /// fire-and-forget, but at a particular (future?) time
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index fbe75af712..bad36505d1 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -393,7 +393,6 @@ set(viewer_SOURCE_FILES
     llloginhandler.cpp
     lllogininstance.cpp
     llmachineid.cpp
-    llmainlooprepeater.cpp
     llmanip.cpp
     llmaniprotate.cpp
     llmanipscale.cpp
@@ -1032,7 +1031,6 @@ set(viewer_HEADER_FILES
     llloginhandler.h
     lllogininstance.h
     llmachineid.h
-    llmainlooprepeater.h
     llmanip.h
     llmaniprotate.h
     llmanipscale.h
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 802453d508..3c7fe174fd 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -12663,6 +12663,20 @@
       <key>Value</key>
       <integer>50</integer>
     </map>
+    <key>ThreadPoolSizes</key>
+    <map>
+      <key>Comment</key>
+      <string>Map of size overrides for specific thread pools.</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>LLSD</string>
+      <key>Value</key>
+      <map>
+        <key>General</key>
+        <integer>4</integer>
+      </map>
+    </map>
     <key>ThrottleBandwidthKBPS</key>
     <map>
       <key>Comment</key>
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 7c932a3959..7c363eea5e 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -239,7 +239,6 @@ using namespace LL;
 // Include for security api initialization
 #include "llsecapi.h"
 #include "llmachineid.h"
-#include "llmainlooprepeater.h"
 #include "llcleanup.h"
 
 #include "llcoproceduremanager.h"
@@ -385,42 +384,6 @@ static std::string gLaunchFileOnQuit;
 // Used on Win32 for other apps to identify our window (eg, win_setup)
 const char* const VIEWER_WINDOW_CLASSNAME = "Second Life";
 
-//-- LLDeferredTaskList ------------------------------------------------------
-
-/**
- * A list of deferred tasks.
- *
- * We sometimes need to defer execution of some code until the viewer gets idle,
- * e.g. removing an inventory item from within notifyObservers() may not work out.
- *
- * Tasks added to this list will be executed in the next LLAppViewer::idle() iteration.
- * All tasks are executed only once.
- */
-class LLDeferredTaskList: public LLSingleton<LLDeferredTaskList>
-{
-	LLSINGLETON_EMPTY_CTOR(LLDeferredTaskList);
-	LOG_CLASS(LLDeferredTaskList);
-
-	friend class LLAppViewer;
-	typedef boost::signals2::signal<void()> signal_t;
-
-	void addTask(const signal_t::slot_type& cb)
-	{
-		mSignal.connect(cb);
-	}
-
-	void run()
-	{
-		if (!mSignal.empty())
-		{
-			mSignal();
-			mSignal.disconnect_all_slots();
-		}
-	}
-
-	signal_t mSignal;
-};
-
 //----------------------------------------------------------------------------
 
 // List of entries from strings.xml to always replace
@@ -980,9 +943,6 @@ bool LLAppViewer::init()
 	}
 	LL_INFOS("InitInfo") << "Cache initialization is done." << LL_ENDL ;
 
-	// Initialize the repeater service.
-	LLMainLoopRepeater::instance().start();
-
 	//
 	// Initialize the window
 	//
@@ -2171,8 +2131,6 @@ bool LLAppViewer::cleanup()
 	SUBSYSTEM_CLEANUP(LLProxy);
     LLCore::LLHttp::cleanup();
 
-	LLMainLoopRepeater::instance().stop();
-
 	ll_close_fail_log();
 
 	LLError::LLCallStacks::cleanup();
@@ -4437,7 +4395,7 @@ bool LLAppViewer::initCache()
 
 void LLAppViewer::addOnIdleCallback(const boost::function<void()>& cb)
 {
-	LLDeferredTaskList::instance().addTask(cb);
+	gMainloopWork.post(cb);
 }
 
 void LLAppViewer::loadKeyBindings()
@@ -5211,9 +5169,6 @@ void LLAppViewer::idle()
 		}
 	}
 
-	// Execute deferred tasks.
-	LLDeferredTaskList::instance().run();
-
 	// Service the WorkQueue we use for replies from worker threads.
 	// Use function statics for the timeslice setting so we only have to fetch
 	// and convert MainWorkTime once.
diff --git a/indra/newview/llmainlooprepeater.cpp b/indra/newview/llmainlooprepeater.cpp
deleted file mode 100644
index 6736e9a950..0000000000
--- a/indra/newview/llmainlooprepeater.cpp
+++ /dev/null
@@ -1,88 +0,0 @@
-/** 
- * @file llmachineid.cpp
- * @brief retrieves unique machine ids
- *
- * $LicenseInfo:firstyear=2009&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- * 
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- * 
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
- * $/LicenseInfo$
- */
-
-#include "llviewerprecompiledheaders.h"
-#include "llapr.h"
-#include "llevents.h"
-#include "llmainlooprepeater.h"
-
-
-
-// LLMainLoopRepeater
-//-----------------------------------------------------------------------------
-
-
-LLMainLoopRepeater::LLMainLoopRepeater(void):
-	mQueue(0)
-{
-	; // No op.
-}
-
-
-void LLMainLoopRepeater::start(void)
-{
-	if(mQueue != 0) return;
-
-	mQueue = new LLThreadSafeQueue<LLSD>(1024);
-	mMainLoopConnection = LLEventPumps::instance().
-		obtain("mainloop").listen(LLEventPump::inventName(), boost::bind(&LLMainLoopRepeater::onMainLoop, this, _1));
-	mRepeaterConnection = LLEventPumps::instance().
-		obtain("mainlooprepeater").listen(LLEventPump::inventName(), boost::bind(&LLMainLoopRepeater::onMessage, this, _1));
-}
-
-
-void LLMainLoopRepeater::stop(void)
-{
-	mMainLoopConnection.release();
-	mRepeaterConnection.release();
-
-	delete mQueue;
-	mQueue = 0;
-}
-
-
-bool LLMainLoopRepeater::onMainLoop(LLSD const &)
-{
-	LLSD message;
-	while(mQueue->tryPopBack(message)) {
-		std::string pump = message["pump"].asString();
-		if(pump.length() == 0 ) continue; // No pump.
-		LLEventPumps::instance().obtain(pump).post(message["payload"]);
-	}
-	return false;
-}
-
-
-bool LLMainLoopRepeater::onMessage(LLSD const & event)
-{
-	try {
-		mQueue->pushFront(event);
-	} catch(LLThreadSafeQueueError & e) {
-		LL_WARNS() << "could not repeat message (" << e.what() << ")" << 
-			event.asString() << LL_ENDL;
-	}
-	return false;
-}
diff --git a/indra/newview/llmainlooprepeater.h b/indra/newview/llmainlooprepeater.h
deleted file mode 100644
index 2ec3a74e4a..0000000000
--- a/indra/newview/llmainlooprepeater.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/** 
- * @file llmainlooprepeater.h
- * @brief a service for repeating messages on the main loop.
- *
- * $LicenseInfo:firstyear=2010&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- * 
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- * 
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
- * $/LicenseInfo$
- */
-
-#ifndef LL_LLMAINLOOPREPEATER_H
-#define LL_LLMAINLOOPREPEATER_H
-
-
-#include "llsd.h"
-#include "llthreadsafequeue.h"
-
-
-//
-// A service which creates the pump 'mainlooprepeater' to which any thread can
-// post a message that will be re-posted on the main loop.
-//
-// The posted message should contain two map elements: pump and payload.  The
-// pump value is a string naming the pump to which the message should be
-// re-posted.  The payload value is what will be posted to the designated pump.
-//
-class LLMainLoopRepeater:
-	public LLSingleton<LLMainLoopRepeater>
-{
-	LLSINGLETON(LLMainLoopRepeater);
-public:
-	// Start the repeater service.
-	void start(void);
-	
-	// Stop the repeater service.
-	void stop(void);
-	
-private:
-	LLTempBoundListener mMainLoopConnection;
-	LLTempBoundListener mRepeaterConnection;
-	LLThreadSafeQueue<LLSD> * mQueue;
-	
-	bool onMainLoop(LLSD const &);
-	bool onMessage(LLSD const & event);
-};
-
-
-#endif
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index 57c5074804..13e7fcb6e4 100644
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -205,6 +205,9 @@
 
 #include "llstacktrace.h"
 
+#include "threadpool.h"
+
+
 #if LL_WINDOWS
 #include "lldxhardware.h"
 #endif
@@ -301,6 +304,18 @@ void callback_cache_name(const LLUUID& id, const std::string& full_name, bool is
 // local classes
 //
 
+void launchThreadPool()
+{
+    LLSD poolSizes{ gSavedSettings.getLLSD("ThreadPoolSizes") };
+    LLSD sizeSpec{ poolSizes["General"] };
+    LLSD::Integer size{ sizeSpec.isInteger()? sizeSpec.asInteger() : 3 };
+    LL_DEBUGS("ThreadPool") << "Instantiating General pool with "
+                            << size << " threads" << LL_ENDL;
+    // Use a function-static ThreadPool: static duration, but instantiated
+    // only on demand.
+    static LL::ThreadPool pool("General", size);
+}
+
 void update_texture_fetch()
 {
 	LLAppViewer::getTextureCache()->update(1); // unpauses the texture cache thread
@@ -1489,6 +1504,9 @@ bool idle_startup()
 		gAgentCamera.resetCamera();
 		display_startup();
 
+		// start up the ThreadPool we'll use for textures et al.
+		launchThreadPool();
+
 		// Initialize global class data needed for surfaces (i.e. textures)
 		LL_DEBUGS("AppInit") << "Initializing sky..." << LL_ENDL;
 		// Initialize all of the viewer object classes for the first time (doing things like texture fetches.
-- 
cgit v1.2.3


From 5553d614211998b5a10529f6b3ec68d2b25dc07a Mon Sep 17 00:00:00 2001
From: Dave Parks <davep@lindenlab.com>
Date: Fri, 22 Oct 2021 17:01:33 +0000
Subject: SL-16203 Fix for wonky handling of mouse deltas.

---
 indra/llcommon/llsingleton.h       |   1 +
 indra/llwindow/llwindow.h          |   3 +
 indra/llwindow/llwindowheadless.h  |   3 +
 indra/llwindow/llwindowwin32.cpp   | 530 ++++++++++++++-----------------------
 indra/llwindow/llwindowwin32.h     |  13 +-
 indra/newview/lldrawpoolavatar.cpp |  10 +-
 indra/newview/llviewerwindow.cpp   |   7 +
 7 files changed, 230 insertions(+), 337 deletions(-)

(limited to 'indra')

diff --git a/indra/llcommon/llsingleton.h b/indra/llcommon/llsingleton.h
index 7c81d65a8b..2e43a3cbed 100644
--- a/indra/llcommon/llsingleton.h
+++ b/indra/llcommon/llsingleton.h
@@ -455,6 +455,7 @@ public:
 
     static DERIVED_TYPE* getInstance()
     {
+        LL_PROFILE_ZONE_SCOPED;
         // We know the viewer has LLSingleton dependency circularities. If you
         // feel strongly motivated to eliminate them, cheers and good luck.
         // (At that point we could consider a much simpler locking mechanism.)
diff --git a/indra/llwindow/llwindow.h b/indra/llwindow/llwindow.h
index 0100c3bf0a..1384ddfd82 100644
--- a/indra/llwindow/llwindow.h
+++ b/indra/llwindow/llwindow.h
@@ -91,6 +91,9 @@ public:
 
     virtual BOOL setCursorPosition(LLCoordWindow position) = 0;
 	virtual BOOL getCursorPosition(LLCoordWindow *position) = 0;
+#if LL_WINDOWS
+    virtual BOOL getCursorDelta(LLCoordCommon* delta) = 0;
+#endif
 	virtual void showCursor() = 0;
 	virtual void hideCursor() = 0;
 	virtual BOOL isCursorHidden() = 0;
diff --git a/indra/llwindow/llwindowheadless.h b/indra/llwindow/llwindowheadless.h
index a7ae28aa24..f8ba9bbed4 100644
--- a/indra/llwindow/llwindowheadless.h
+++ b/indra/llwindow/llwindowheadless.h
@@ -54,6 +54,9 @@ public:
     void destroySharedContext(void*)  {}
 	/*virtual*/ BOOL setCursorPosition(LLCoordWindow position) {return FALSE;};
 	/*virtual*/ BOOL getCursorPosition(LLCoordWindow *position) {return FALSE;};
+#if LL_WINDOWS
+    /*virtual*/ BOOL getCursorDelta(LLCoordCommon* delta) { return FALSE; }
+#endif
 	/*virtual*/ void showCursor() {};
 	/*virtual*/ void hideCursor() {};
 	/*virtual*/ void showCursorFromMouseMove() {};
diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp
index 12d4c6c30e..bf78bcba29 100644
--- a/indra/llwindow/llwindowwin32.cpp
+++ b/indra/llwindow/llwindowwin32.cpp
@@ -28,8 +28,6 @@
 
 #if LL_WINDOWS && !LL_MESA_HEADLESS
 
-#define LL_WINDOW_SINGLE_THREADED 0
-
 #include "llwindowwin32.h"
 
 // LLWindow library includes
@@ -85,7 +83,7 @@ extern BOOL gDebugWindowProc;
 static std::thread::id sWindowThreadId;
 static std::thread::id sMainThreadId;
 
-#if 1 || LL_WINDOW_SINGLE_THREADED
+#if 1 // flip to zero to enable assertions for functions being called from wrong thread
 #define ASSERT_MAIN_THREAD()
 #define ASSERT_WINDOW_THREAD()
 #else
@@ -482,9 +480,7 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks,
 {
     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");
 
@@ -492,7 +488,6 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks,
 	mIconResource = gIconResource;
 	mOverrideAspectRatio = 0.f;
 	mNativeAspectRatio = 0.f;
-	mMousePositionModified = FALSE;
 	mInputProcessingPaused = FALSE;
 	mPreeditor = NULL;
 	mKeyCharCode = 0;
@@ -814,6 +809,13 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks,
 	initCursors();
 	setCursor( UI_CURSOR_ARROW );
 
+    mRawMouse.usUsagePage = 0x01;          // HID_USAGE_PAGE_GENERIC
+    mRawMouse.usUsage = 0x02;              // HID_USAGE_GENERIC_MOUSE
+    mRawMouse.dwFlags = 0;    // adds mouse and also ignores legacy mouse messages
+    mRawMouse.hwndTarget = 0;
+
+    RegisterRawInputDevices(&mRawMouse, 1, sizeof(mRawMouse));
+
 	// Initialize (boot strap) the Language text input management,
 	// based on the system's (or user's) default settings.
 	allowLanguageTextInput(NULL, FALSE);
@@ -1927,31 +1929,26 @@ BOOL LLWindowWin32::setCursorPosition(const LLCoordWindow position)
 {
     ASSERT_MAIN_THREAD();
 
-	if (!mWindowHandle)
-	{
-		return FALSE;
-	}
+    if (!mWindowHandle)
+    {
+        return FALSE;
+    }
 
-    // Inform the application of the new mouse position (needed for per-frame
-	// hover/picking to function).
-	mCallbacks->handleMouseMove(this, position.convert(), (MASK)0);
-	
-    mMousePositionModified = TRUE;
     LLCoordScreen screen_pos(position.convert());
-    
-    mWindowThread->post([=]
+
+    // instantly set the cursor position from the app's point of view
+    mCursorPosition = position;
+    mLastCursorPosition = position;
+
+    // Inform the application of the new mouse position (needed for per-frame
+    // hover/picking to function).
+    mCallbacks->handleMouseMove(this, position.convert(), (MASK)0);
+
+    // actually set the cursor position on the window thread
+    mWindowThread->post([=]()
         {
+            // actually set the OS cursor position
             SetCursorPos(screen_pos.mX, screen_pos.mY);
-            // 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;
@@ -1960,19 +1957,27 @@ BOOL LLWindowWin32::setCursorPosition(const LLCoordWindow position)
 BOOL LLWindowWin32::getCursorPosition(LLCoordWindow *position)
 {
     ASSERT_MAIN_THREAD();
-	POINT cursor_point;
-
-	if (!mWindowHandle 
-		|| !GetCursorPos(&cursor_point)
-		|| !position)
-	{
-		return FALSE;
-	}
+    if (!position)
+    {
+        return FALSE;
+    }
 
-	*position = LLCoordScreen(cursor_point.x, cursor_point.y).convert();
+    *position = mCursorPosition;
 	return TRUE;
 }
 
+BOOL LLWindowWin32::getCursorDelta(LLCoordCommon* delta)
+{
+    if (delta == nullptr)
+    {
+        return FALSE;
+    }
+
+    *delta = mMouseFrameDelta;
+
+    return TRUE;
+}
+
 void LLWindowWin32::hideCursor()
 {
     ASSERT_MAIN_THREAD();
@@ -2153,34 +2158,31 @@ void LLWindowWin32::gatherInput()
     LL_PROFILE_ZONE_SCOPED
     MSG msg;
 
-#if LL_WINDOW_SINGLE_THREADED
-    int	msg_count = 0;
-
-    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;
-            }
-        }
+        LLMutexLock lock(&mRawMouseMutex);
+        mMouseFrameDelta = mRawMouseDelta;
 
-        {
-            LL_PROFILE_ZONE_NAMED("gi - translate");
-            TranslateMessage(&msg);
-        }
+        mRawMouseDelta.mX = 0;
+        mRawMouseDelta.mY = 0;
+    }
 
-        {
-            LL_PROFILE_ZONE_NAMED("gi - dispatch");
-            DispatchMessage(&msg);
-        }
 
+    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)
         {
-            break;
+            continue;
         }
 
         // For async host by name support.  Really hacky.
@@ -2190,45 +2192,35 @@ void LLWindowWin32::gatherInput()
             gAsyncMsgCallback(msg);
         }
     }
-#else //multi-threaded window impl
+
     {
-        if (mWindowThread->mFunctionQueue.size() > 0)
+        LL_PROFILE_ZONE_NAMED("gi - function queue");
+        //process any pending functions
+        std::function<void()> curFunc;
+        while (mFunctionQueue.tryPopBack(curFunc))
         {
-            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);
-            }
+            curFunc();
         }
-        
-        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);
-            }
-        }
+    // send one and only one mouse move event per frame BEFORE handling mouse button presses
+    if (mLastCursorPosition != mCursorPosition)
+    {
+        LL_PROFILE_ZONE_NAMED("gi - mouse move");
+        mCallbacks->handleMouseMove(this, mCursorPosition.convert(), mMouseMask);
     }
+    
+    mLastCursorPosition = mCursorPosition;
 
     {
-        LL_PROFILE_ZONE_NAMED("gi - function queue");
-        //process any pending functions
+        LL_PROFILE_ZONE_NAMED("gi - mouse queue");
+        // handle mouse button presses AFTER updating mouse cursor position
         std::function<void()> curFunc;
-        while (mFunctionQueue.tryPopBack(curFunc))
+        while (mMouseQueue.tryPopBack(curFunc))
         {
             curFunc();
         }
     }
-#endif
 
 	mInputProcessingPaused = FALSE;
 
@@ -2238,11 +2230,7 @@ void LLWindowWin32::gatherInput()
 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)
 {
@@ -2278,10 +2266,6 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
         // 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;
@@ -2665,35 +2649,19 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
             LL_PROFILE_ZONE_NAMED("mwp - WM_LBUTTONDOWN");
             {
                 LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER);
-                window_imp->post([=]()
+                window_imp->postMouseButtonEvent([=]()
                     {
-                        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);
+                        auto gl_coord = window_imp->mCursorPosition.convert();
+                        window_imp->mCallbacks->handleMouseMove(window_imp, gl_coord, mask);
+                        window_imp->mCallbacks->handleMouseDown(window_imp, gl_coord, mask);
                     });
 
                 return 0;
@@ -2704,77 +2672,43 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
         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;
-            }
-
-            // 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->postMouseButtonEvent([=]()
                 {
-                    window_imp->mCallbacks->handleMouseMove(window_imp, gl_coord, mask);
-                    window_imp->mCallbacks->handleDoubleClick(window_imp, gl_coord, mask);
+                    //RN: ignore right button double clicks for now
+                    //case WM_RBUTTONDBLCLK:
+                    if (!sHandleDoubleClick)
+                    {
+                        sHandleDoubleClick = true;
+                        return;
+                    }
+                    MASK mask = gKeyboard->currentMask(TRUE);
+
+                    // generate move event to update mouse coordinates
+                    window_imp->mCursorPosition = window_coord;
+                    window_imp->mCallbacks->handleDoubleClick(window_imp, window_imp->mCursorPosition.convert(), mask);
                 });
+
             return 0;
         }
         case WM_LBUTTONUP:
         {
             LL_PROFILE_ZONE_NAMED("mwp - WM_LBUTTONUP");
             {
-                LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER);
-
-                if (!sHandleLeftMouseUp)
-                {
-                    sHandleLeftMouseUp = true;
-                    return 0;
-                }
-                sHandleDoubleClick = true;
-                window_imp->post([=]()
+                window_imp->postMouseButtonEvent([=]()
                     {
-                        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)
+                        LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER);
+                        if (!sHandleLeftMouseUp)
                         {
-                            LLCoordWindow cursor_coord_window;
-                            window_imp->getCursorPosition(&cursor_coord_window);
-                            glc = cursor_coord_window.convert();
-                        }
-                        else
-                        {
-                            glc = window_coord.convert();
+                            sHandleLeftMouseUp = true;
+                            return;
                         }
+                        sHandleDoubleClick = true;
+
+                        
                         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);
+                        window_imp->mCursorPosition = window_coord;
+                        window_imp->mCallbacks->handleMouseUp(window_imp, window_imp->mCursorPosition.convert(), mask);
                     });
             }
             return 0;
@@ -2785,30 +2719,16 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
             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([=]()
                     {
+                        if (LLWinImm::isAvailable() && window_imp->mPreeditor)
+                        {
+                            WINDOW_IMP_POST(window_imp->interruptLanguageTextInput());
+                        }
+
+                        MASK mask = gKeyboard->currentMask(TRUE);
+                        // generate move event to update mouse coordinates
+                        auto gl_coord = window_imp->mCursorPosition.convert();
                         window_imp->mCallbacks->handleMouseMove(window_imp, gl_coord, mask);
                         window_imp->mCallbacks->handleRightMouseDown(window_imp, gl_coord, mask);
                     });
@@ -2822,28 +2742,11 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
             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;
-                }
+                window_imp->postMouseButtonEvent([=]()
+                    {
+                        MASK mask = gKeyboard->currentMask(TRUE);
+                        window_imp->mCallbacks->handleRightMouseUp(window_imp, window_imp->mCursorPosition.convert(), mask);
+                    });
             }
         }
         break;
@@ -2854,33 +2757,16 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
             LL_PROFILE_ZONE_NAMED("mwp - WM_MBUTTONDOWN");
             {
                 LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER);
-                if (LLWinImm::isAvailable() && window_imp->mPreeditor)
-                {
-                    window_imp->interruptLanguageTextInput();
-                }
+                window_imp->postMouseButtonEvent([=]()
+                    {
+                        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;
-                }
+                        MASK mask = gKeyboard->currentMask(TRUE);
+                        window_imp->mCallbacks->handleMiddleMouseDown(window_imp, window_imp->mCursorPosition.convert(), mask);
+                    });
             }
         }
         break;
@@ -2890,99 +2776,47 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
             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;
-                }
+                window_imp->postMouseButtonEvent([=]()
+                    {
+                        MASK mask = gKeyboard->currentMask(TRUE);
+                        window_imp->mCallbacks->handleMiddleMouseUp(window_imp, window_imp->mCursorPosition.convert(), mask);
+                    });
             }
         }
         break;
         case WM_XBUTTONDOWN:
         {
             LL_PROFILE_ZONE_NAMED("mwp - WM_XBUTTONDOWN");
-            {
-                LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER);
-                S32 button = GET_XBUTTON_WPARAM(w_param);
-                if (LLWinImm::isAvailable() && window_imp->mPreeditor)
+            window_imp->postMouseButtonEvent([=]()
                 {
-                    window_imp->interruptLanguageTextInput();
-                }
+                    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;
-                }
-            }
+                    MASK mask = gKeyboard->currentMask(TRUE);
+                    // Windows uses numbers 1 and 2 for buttons, remap to 4, 5
+                    window_imp->mCallbacks->handleOtherMouseDown(window_imp, window_imp->mCursorPosition.convert(), mask, button + 3);
+                });
+            
         }
         break;
 
         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)
+            window_imp->postMouseButtonEvent([=]()
                 {
-                    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;
-                }
-            }
+
+                    LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER);
+
+                    S32 button = GET_XBUTTON_WPARAM(w_param);
+                    MASK mask = gKeyboard->currentMask(TRUE);
+                    // Windows uses numbers 1 and 2 for buttons, remap to 4, 5
+                    window_imp->mCallbacks->handleOtherMouseUp(window_imp, window_imp->mCursorPosition.convert(), mask, button + 3);
+                });
         }
         break;
 
@@ -3022,7 +2856,8 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
             // 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);
+                short clicks = -z_delta / WHEEL_DELTA;
+                WINDOW_IMP_POST(window_imp->mCallbacks->handleScrollWheel(window_imp, clicks));
                 z_delta = 0;
             }
             return 0;
@@ -3082,11 +2917,16 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
         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));
-            }
+            // DO NOT use mouse event queue for move events to ensure cursor position is updated 
+            // when button events are handled
+            WINDOW_IMP_POST(
+                {
+                    LL_PROFILE_ZONE_NAMED("mwp - WM_MOUSEMOVE lambda");
+
+                    MASK mask = gKeyboard->currentMask(TRUE);
+                    window_imp->mMouseMask = mask;
+                    window_imp->mCursorPosition = window_coord;
+                });
             return 0;
         }
 
@@ -3235,6 +3075,28 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
         }
         break;
         
+        case WM_INPUT:
+        {
+            LL_PROFILE_ZONE_NAMED("MWP - WM_INPUT");
+            
+            UINT dwSize = 0;
+            GetRawInputData((HRAWINPUT)l_param, RID_INPUT, NULL, &dwSize, sizeof(RAWINPUTHEADER));
+            llassert(dwSize < 1024);
+
+            U8 lpb[1024];
+            
+            if (GetRawInputData((HRAWINPUT)l_param, RID_INPUT, (void*)lpb, &dwSize, sizeof(RAWINPUTHEADER)) == dwSize)
+            {
+                RAWINPUT* raw = (RAWINPUT*)lpb;
+
+                if (raw->header.dwType == RIM_TYPEMOUSE)
+                {
+                    LLMutexLock lock(&window_imp->mRawMouseMutex);
+                    window_imp->mRawMouseDelta.mX += raw->data.mouse.lLastX;
+                    window_imp->mRawMouseDelta.mY -= raw->data.mouse.lLastY;
+                }
+            }
+        }
         //list of messages we get often that we don't care to log about
         case WM_NCHITTEST:
         case WM_NCMOUSEMOVE:
@@ -4740,18 +4602,16 @@ inline void LLWindowWin32Thread::run()
 
 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
 }
+
+void LLWindowWin32::postMouseButtonEvent(const std::function<void()>& func)
+{
+    mMouseQueue.pushFront(func);
+}
+
diff --git a/indra/llwindow/llwindowwin32.h b/indra/llwindow/llwindowwin32.h
index 5f253b5df3..b44d458fc6 100644
--- a/indra/llwindow/llwindowwin32.h
+++ b/indra/llwindow/llwindowwin32.h
@@ -35,6 +35,7 @@
 #include "lldragdropwin32.h"
 #include "llthread.h"
 #include "llthreadsafequeue.h"
+#include "llmutex.h"
 
 // Hack for async host by name
 #define LL_WM_HOST_RESOLVED      (WM_APP + 1)
@@ -98,6 +99,7 @@ public:
     void destroySharedContext(void* context) override;
 	/*virtual*/ BOOL setCursorPosition(LLCoordWindow position);
 	/*virtual*/ BOOL getCursorPosition(LLCoordWindow *position);
+    /*virtual*/ BOOL getCursorDelta(LLCoordCommon* delta);
 	/*virtual*/ void showCursor();
 	/*virtual*/ void hideCursor();
 	/*virtual*/ void showCursorFromMouseMove();
@@ -221,6 +223,14 @@ protected:
 	F32			mNativeAspectRatio;
 
 	HCURSOR		mCursor[ UI_CURSOR_COUNT ];  // Array of all mouse cursors
+    LLCoordWindow mCursorPosition;  // mouse cursor position, should only be mutated on main thread
+    LLMutex mRawMouseMutex;
+    RAWINPUTDEVICE mRawMouse;
+    LLCoordWindow mLastCursorPosition; // mouse cursor position from previous frame
+    LLCoordCommon mRawMouseDelta; // raw mouse delta according to window thread
+    LLCoordCommon mMouseFrameDelta; // how much the mouse moved between the last two calls to gatherInput
+
+    MASK        mMouseMask;
 
 	static BOOL sIsClassRegistered; // has the window class been registered?
 
@@ -231,7 +241,6 @@ protected:
 	BOOL		mCustomGammaSet;
 
 	LPWSTR		mIconResource;
-	BOOL		mMousePositionModified;
 	BOOL		mInputProcessingPaused;
 
 	// The following variables are for Language Text Input control.
@@ -261,7 +270,9 @@ protected:
 
     LLWindowWin32Thread* mWindowThread = nullptr;
     LLThreadSafeQueue<std::function<void()>> mFunctionQueue;
+    LLThreadSafeQueue<std::function<void()>> mMouseQueue;
     void post(const std::function<void()>& func);
+    void postMouseButtonEvent(const std::function<void()>& func);
 
 	friend class LLWindowManager;
     friend class LLWindowWin32Thread;
diff --git a/indra/newview/lldrawpoolavatar.cpp b/indra/newview/lldrawpoolavatar.cpp
index 8dd8c15b87..52d308f6bd 100644
--- a/indra/newview/lldrawpoolavatar.cpp
+++ b/indra/newview/lldrawpoolavatar.cpp
@@ -2279,7 +2279,15 @@ void LLDrawPoolAvatar::renderRigged(LLVOAvatar* avatar, U32 type, bool glow)
                 
                 if (normal_channel >= 0)
                 {
-                    gGL.getTexUnit(normal_channel)->bindFast(face->getTexture(LLRender::NORMAL_MAP));
+                    auto* texture = face->getTexture(LLRender::NORMAL_MAP);
+                    if (texture)
+                    {
+                        gGL.getTexUnit(normal_channel)->bindFast(texture);
+                    }
+                    //else
+                    //{
+                        // TODO handle missing normal map
+                    //}
                 }
 
 				gGL.getTexUnit(sDiffuseChannel)->bindFast(face->getTexture(LLRender::DIFFUSE_MAP));
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index 82ece85c1b..ce73037006 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -3781,8 +3781,15 @@ void LLViewerWindow::updateLayout()
 
 void LLViewerWindow::updateMouseDelta()
 {
+#if LL_WINDOWS
+    LLCoordCommon delta; 
+    mWindow->getCursorDelta(&delta);
+    S32 dx = delta.mX;
+    S32 dy = delta.mY;
+#else
 	S32 dx = lltrunc((F32) (mCurrentMousePoint.mX - mLastMousePoint.mX) * LLUI::getScaleFactor().mV[VX]);
 	S32 dy = lltrunc((F32) (mCurrentMousePoint.mY - mLastMousePoint.mY) * LLUI::getScaleFactor().mV[VY]);
+#endif
 
 	//RN: fix for asynchronous notification of mouse leaving window not working
 	LLCoordWindow mouse_pos;
-- 
cgit v1.2.3


From 3efd4c50a031ce0c1cb3d2fcc43e403136277e1f Mon Sep 17 00:00:00 2001
From: Runitai Linden <davep@lindenlab.com>
Date: Fri, 22 Oct 2021 16:56:20 -0500
Subject: SL-16222 Don't use bindFast for legacy bump maps (weird loading path
 sometimes has stale texture state).

---
 indra/newview/lldrawpoolbump.cpp | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

(limited to 'indra')

diff --git a/indra/newview/lldrawpoolbump.cpp b/indra/newview/lldrawpoolbump.cpp
index d75884cc16..b08fbcbd89 100644
--- a/indra/newview/lldrawpoolbump.cpp
+++ b/indra/newview/lldrawpoolbump.cpp
@@ -715,7 +715,8 @@ BOOL LLDrawPoolBump::bindBumpMap(U8 bump_code, LLViewerTexture* texture, F32 vsi
 		}
 		else
 		{
-			gGL.getTexUnit(channel)->bindFast(bump);
+            // NOTE: do not use bindFast here (see SL-16222)
+            gGL.getTexUnit(channel)->bind(bump);
 		}
 
 		return TRUE;
-- 
cgit v1.2.3


From d2763897f22e3d7789f97fe68000662ecd4a3548 Mon Sep 17 00:00:00 2001
From: Nat Goodspeed <nat@lindenlab.com>
Date: Fri, 22 Oct 2021 21:51:44 -0400
Subject: SL-16220: Fix thread name expression.

---
 indra/llcommon/threadpool.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'indra')

diff --git a/indra/llcommon/threadpool.cpp b/indra/llcommon/threadpool.cpp
index aa7d4179a2..1899f9a20a 100644
--- a/indra/llcommon/threadpool.cpp
+++ b/indra/llcommon/threadpool.cpp
@@ -27,7 +27,7 @@ LL::ThreadPool::ThreadPool(const std::string& name, size_t threads):
 {
     for (size_t i = 0; i < threads; ++i)
     {
-        std::string tname{ STRINGIZE(mName << ':' << (i+i) << '/' << threads) };
+        std::string tname{ STRINGIZE(mName << ':' << (i+1) << '/' << threads) };
         mThreads.emplace_back(tname, [this, tname](){ run(tname); });
     }
     // Listen on "LLApp", and when the app is shutting down, close the queue
-- 
cgit v1.2.3


From a5b1c013542d93be3b4cac820f32000fa5e3cfd4 Mon Sep 17 00:00:00 2001
From: Mnikolenko Productengine <mnikolenko@productengine.com>
Date: Mon, 25 Oct 2021 21:23:26 +0300
Subject: SL-16234 handle closing floater correctly

---
 indra/newview/llfloaterimcontainer.cpp | 40 ++++++++++++++++------------------
 1 file changed, 19 insertions(+), 21 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llfloaterimcontainer.cpp b/indra/newview/llfloaterimcontainer.cpp
index 2ccb9ab074..112ece0fbf 100644
--- a/indra/newview/llfloaterimcontainer.cpp
+++ b/indra/newview/llfloaterimcontainer.cpp
@@ -724,11 +724,6 @@ void LLFloaterIMContainer::setMinimized(BOOL b)
 
 void LLFloaterIMContainer::setVisible(BOOL visible)
 {
-    if (LLFloater::isQuitRequested())
-    {
-        return;
-    }
-
     LLFloaterIMNearbyChat* nearby_chat;
 	if (visible)
 	{
@@ -764,22 +759,25 @@ void LLFloaterIMContainer::setVisible(BOOL visible)
 		LLFloaterIMSessionTab::addToHost(LLUUID());
 	}
 
-	// We need to show/hide all the associated conversations that have been torn off
-	// (and therefore, are not longer managed by the multifloater),
-	// so that they show/hide with the conversations manager.
-	conversations_widgets_map::iterator widget_it = mConversationsWidgets.begin();
-	for (;widget_it != mConversationsWidgets.end(); ++widget_it)
-	{
-		LLConversationViewSession* widget = dynamic_cast<LLConversationViewSession*>(widget_it->second);
-		if (widget)
-		{
-			LLFloater* session_floater = widget->getSessionFloater();
-			if (session_floater != nearby_chat)
-			{
-		    widget->setVisibleIfDetached(visible);
-		}
-	}
-	}
+    if (!LLFloater::isQuitRequested())
+    {
+        // We need to show/hide all the associated conversations that have been torn off
+        // (and therefore, are not longer managed by the multifloater),
+        // so that they show/hide with the conversations manager.
+        conversations_widgets_map::iterator widget_it = mConversationsWidgets.begin();
+        for (; widget_it != mConversationsWidgets.end(); ++widget_it)
+        {
+            LLConversationViewSession* widget = dynamic_cast<LLConversationViewSession*>(widget_it->second);
+            if (widget)
+            {
+                LLFloater* session_floater = widget->getSessionFloater();
+                if (session_floater != nearby_chat)
+                {
+                    widget->setVisibleIfDetached(visible);
+                }
+            }
+        }
+    }
 	
 	// Now, do the normal multifloater show/hide
 	LLMultiFloater::setVisible(visible);
-- 
cgit v1.2.3


From e7b8c27741201528bf78f95c96ba820833923dab Mon Sep 17 00:00:00 2001
From: Nat Goodspeed <nat@lindenlab.com>
Date: Mon, 25 Oct 2021 15:55:49 -0400
Subject: SL-16220: Specialize WorkQueue for callable with void return.

Add a test exercising this feature.
---
 indra/llcommon/tests/threadsafeschedule_test.cpp |   4 +-
 indra/llcommon/tests/workqueue_test.cpp          |  23 +++-
 indra/llcommon/workqueue.h                       | 167 +++++++++++++++--------
 3 files changed, 134 insertions(+), 60 deletions(-)

(limited to 'indra')

diff --git a/indra/llcommon/tests/threadsafeschedule_test.cpp b/indra/llcommon/tests/threadsafeschedule_test.cpp
index af67b9f492..c421cc7b1c 100644
--- a/indra/llcommon/tests/threadsafeschedule_test.cpp
+++ b/indra/llcommon/tests/threadsafeschedule_test.cpp
@@ -46,11 +46,11 @@ namespace tut
         // 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"));
+        queue.push(Queue::TimeTuple(Queue::Clock::now() + 200ms, "ghi"));
         // Given the various push() overloads, you have to match the type
         // exactly: conversions are ambiguous.
         queue.push("abc"s);
-        queue.push(Queue::Clock::now() + 10ms, "def");
+        queue.push(Queue::Clock::now() + 100ms, "def");
         queue.close();
         auto entry = queue.pop();
         ensure_equals("failed to pop first", std::get<0>(entry), "abc"s);
diff --git a/indra/llcommon/tests/workqueue_test.cpp b/indra/llcommon/tests/workqueue_test.cpp
index d5405400fd..b69df49d33 100644
--- a/indra/llcommon/tests/workqueue_test.cpp
+++ b/indra/llcommon/tests/workqueue_test.cpp
@@ -138,7 +138,8 @@ namespace tut
             [](){ 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.
+            // on the invoking thread. (Of course the bound variable must
+            // survive until the callback is called.)
             [&result](int i){ result = i; });
         // this should post the callback to main
         qptr->runOne();
@@ -156,4 +157,24 @@ namespace tut
         main.runPending();
         ensure_equals("failed to run string callback", alpha, "abc");
     }
+
+    template<> template<>
+    void object::test<5>()
+    {
+        set_test_name("postTo with void return");
+        WorkQueue main("main");
+        auto qptr = WorkQueue::getInstance("queue");
+        std::string observe;
+        main.postTo(
+            qptr,
+            // The ONLY reason we can get away with binding a reference to
+            // 'observe' in our work callable is because we're directly
+            // calling qptr->runOne() on this same thread. It would be a
+            // mistake to do that if some other thread were servicing 'queue'.
+            [&observe](){ observe = "queue"; },
+            [&observe](){ observe.append(";main"); });
+        qptr->runOne();
+        main.runOne();
+        ensure_equals("failed to run both lambdas", observe, "queue;main");
+    }
 } // namespace tut
diff --git a/indra/llcommon/workqueue.h b/indra/llcommon/workqueue.h
index cfae2019dc..deef3c8e84 100644
--- a/indra/llcommon/workqueue.h
+++ b/indra/llcommon/workqueue.h
@@ -115,62 +115,7 @@ namespace LL
         // 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;
-        }
+                    const TimePoint& time, CALLABLE&& callable, FOLLOWUP&& callback);
 
         /**
          * Post work to another WorkQueue, requesting a specific callback to
@@ -183,7 +128,8 @@ namespace LL
         bool postTo(WorkQueue::weak_t target,
                     CALLABLE&& callable, FOLLOWUP&& callback)
         {
-            return postTo(target, TimePoint::clock::now(), std::move(callable), std::move(callback));
+            return postTo(target, TimePoint::clock::now(),
+                          std::move(callable), std::move(callback));
         }
 
         /*--------------------------- worker API ---------------------------*/
@@ -231,6 +177,17 @@ namespace LL
         bool runUntil(const TimePoint& until);
 
     private:
+        template <typename CALLABLE, typename FOLLOWUP>
+        static auto makeReplyLambda(CALLABLE&& callable, FOLLOWUP&& callback);
+
+        /// general case: arbitrary C++ return type
+        template <typename CALLABLE, typename FOLLOWUP, typename RETURNTYPE>
+        struct MakeReplyLambda;
+
+        /// specialize for CALLABLE returning void
+        template <typename CALLABLE, typename FOLLOWUP>
+        struct MakeReplyLambda<CALLABLE, FOLLOWUP, void>;
+
         static void error(const std::string& msg);
         static std::string makeName(const std::string& name);
         void callWork(const Queue::DataTuple& work);
@@ -329,6 +286,102 @@ namespace LL
                  getWeak(), TimePoint::clock::now(), interval, std::move(callable)));
     }
 
+    template <typename CALLABLE, typename FOLLOWUP, typename RETURNTYPE>
+    struct WorkQueue::MakeReplyLambda
+    {
+        auto operator()(CALLABLE&& callable, FOLLOWUP&& callback)
+        {
+            // Call the callable in any case -- but to minimize
+            // copying the result, immediately bind it into the reply
+            // lambda. The reply lambda also binds the original
+            // callback, so that when we, the originating WorkQueue,
+            // finally receive and process the reply lambda, we'll
+            // call the bound callback with the bound result -- on the
+            // same thread that originally called postTo().
+            return
+                [result = std::forward<CALLABLE>(callable)(),
+                 callback = std::move(callback)]
+                ()
+                { callback(std::move(result)); };
+        }
+    };
+
+    /// specialize for CALLABLE returning void
+    template <typename CALLABLE, typename FOLLOWUP>
+    struct WorkQueue::MakeReplyLambda<CALLABLE, FOLLOWUP, void>
+    {
+        auto operator()(CALLABLE&& callable, FOLLOWUP&& callback)
+        {
+            // Call the callable, which produces no result.
+            std::forward<CALLABLE>(callable)();
+            // This reply lambda binds the original callback, so
+            // that when we, the originating WorkQueue, finally
+            // receive and process the reply lambda, we'll call
+            // the bound callback -- on the same thread that
+            // originally called postTo().
+            return [callback = std::move(callback)](){ callback(); };
+        }
+    };
+
+    template <typename CALLABLE, typename FOLLOWUP>
+    auto WorkQueue::makeReplyLambda(CALLABLE&& callable, FOLLOWUP&& callback)
+    {
+        return MakeReplyLambda<CALLABLE, FOLLOWUP,
+                               decltype(std::forward<CALLABLE>(callable)())>()
+            (std::move(callable), std::move(callback));
+    }
+
+    template <typename CALLABLE, typename FOLLOWUP>
+    bool WorkQueue::postTo(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)]
+            ()
+            {
+                // Make a reply lambda to repost to THIS WorkQueue.
+                // Delegate to makeReplyLambda() so we can partially
+                // specialize on void return.
+                auto rlambda = makeReplyLambda(std::move(callable), std::move(callback));
+                // 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;
+    }
+
 } // namespace LL
 
 #endif /* ! defined(LL_WORKQUEUE_H) */
-- 
cgit v1.2.3


From 647d0224d321c706ba5936905db4265becde9d8e Mon Sep 17 00:00:00 2001
From: Dave Parks <davep@lindenlab.com>
Date: Mon, 25 Oct 2021 21:11:03 +0000
Subject: SL-16243 Add Tracy timers to global new/delete overrides.

---
 indra/llcommon/llcommon.cpp        | 24 ++++++++++++++++++++++--
 indra/llcommon/llprofiler.h        |  6 ++++--
 indra/newview/llappviewerwin32.cpp |  3 ++-
 3 files changed, 28 insertions(+), 5 deletions(-)

(limited to 'indra')

diff --git a/indra/llcommon/llcommon.cpp b/indra/llcommon/llcommon.cpp
index 5d4a623bf6..abc6af2cfc 100644
--- a/indra/llcommon/llcommon.cpp
+++ b/indra/llcommon/llcommon.cpp
@@ -33,11 +33,22 @@
 #include "lltracethreadrecorder.h"
 #include "llcleanup.h"
 
+thread_local bool gProfilerEnabled = false;
+
 #if (TRACY_ENABLE)
 // Override new/delete for tracy memory profiling
 void *operator new(size_t size)
 {
-    auto ptr = (malloc) (size);
+    void* ptr;
+    if (gProfilerEnabled)
+    {
+        LL_PROFILE_ZONE_SCOPED;
+        ptr = (malloc)(size);
+    }
+    else
+    {
+        ptr = (malloc)(size);
+    }
     if (!ptr)
     {
         throw std::bad_alloc();
@@ -49,7 +60,16 @@ void *operator new(size_t size)
 void operator delete(void *ptr) noexcept
 {
     TracyFree(ptr);
-    (free)(ptr);
+
+    if (gProfilerEnabled)
+    {
+        LL_PROFILE_ZONE_SCOPED;
+        (free)(ptr);
+    }
+    else
+    {
+        (free)(ptr);
+    }
 }
 
 // C-style malloc/free can't be so easily overridden, so we define tracy versions and use
diff --git a/indra/llcommon/llprofiler.h b/indra/llcommon/llprofiler.h
index 49510df913..e36f693dd3 100644
--- a/indra/llcommon/llprofiler.h
+++ b/indra/llcommon/llprofiler.h
@@ -36,6 +36,8 @@
 #define LL_PROFILER_CONFIGURATION           LL_PROFILER_CONFIG_FAST_TIMER
 #endif
 
+extern thread_local bool gProfilerEnabled;
+
 #if defined(LL_PROFILER_CONFIGURATION) && (LL_PROFILER_CONFIGURATION > LL_PROFILER_CONFIG_NONE)
     #if LL_PROFILER_CONFIGURATION == LL_PROFILER_CONFIG_TRACY || LL_PROFILER_CONFIGURATION == LL_PROFILER_CONFIG_TRACY_FAST_TIMER
         #define TRACY_ENABLE         1
@@ -52,7 +54,7 @@
 
     #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_PROFILER_SET_THREAD_NAME( name )     tracy::SetThreadName( name );    gProfilerEnabled = true;
         #define LL_RECORD_BLOCK_TIME(name)              ZoneScoped // Want descriptive names; was: ZoneNamedN( ___tracy_scoped_zone, #name, true );
         #define LL_PROFILE_ZONE_NAMED(name)             ZoneNamedN( ___tracy_scoped_zone, name, true );
         #define LL_PROFILE_ZONE_NAMED_COLOR(name,color) ZoneNamedNC( ___tracy_scopped_zone, name, color, true ) // RGB
@@ -82,7 +84,7 @@
     #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_PROFILER_SET_THREAD_NAME( name )     tracy::SetThreadName( name );    gProfilerEnabled = true;
         #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
diff --git a/indra/newview/llappviewerwin32.cpp b/indra/newview/llappviewerwin32.cpp
index 758bd73cb0..9074e6a6cf 100644
--- a/indra/newview/llappviewerwin32.cpp
+++ b/indra/newview/llappviewerwin32.cpp
@@ -325,7 +325,8 @@ int APIENTRY WINMAIN(HINSTANCE hInstance,
 {
     // Call Tracy first thing to have it allocate memory
     // https://github.com/wolfpld/tracy/issues/196
-    LL_PROFILER_FRAME_END
+    LL_PROFILER_FRAME_END;
+    LL_PROFILER_SET_THREAD_NAME("App");
 
 	const S32 MAX_HEAPS = 255;
 	DWORD heap_enable_lfh_error[MAX_HEAPS];
-- 
cgit v1.2.3


From 023d39963e850356e1af6eec7f857e2534ce8d38 Mon Sep 17 00:00:00 2001
From: Nat Goodspeed <nat@lindenlab.com>
Date: Mon, 25 Oct 2021 17:31:27 -0400
Subject: SL-16220: WorkQueue::runOn() methods submit work, wait for result.

The idea is that you can call runOn(target, callable) from a (non-default)
coroutine and block that coroutine until the result becomes available.

As a safety check, we forbid calling runOn() from a thread's default
coroutine, assuming that a given thread's default coroutine is the one
servicing the relevant WorkQueue.
---
 indra/llcommon/workqueue.cpp |  15 +++++
 indra/llcommon/workqueue.h   | 150 +++++++++++++++++++++++++++++++++++++++----
 2 files changed, 154 insertions(+), 11 deletions(-)

(limited to 'indra')

diff --git a/indra/llcommon/workqueue.cpp b/indra/llcommon/workqueue.cpp
index 114aeea1f3..f7ffc8233c 100644
--- a/indra/llcommon/workqueue.cpp
+++ b/indra/llcommon/workqueue.cpp
@@ -26,6 +26,11 @@
 using Mutex = LLCoros::Mutex;
 using Lock  = LLCoros::LockType;
 
+struct NotOnDftCoro: public LLException
+{
+    NotOnDftCoro(const std::string& what): LLException(what) {}
+};
+
 LL::WorkQueue::WorkQueue(const std::string& name):
     super(makeName(name))
 {
@@ -136,3 +141,13 @@ void LL::WorkQueue::error(const std::string& msg)
 {
     LL_ERRS("WorkQueue") << msg << LL_ENDL;
 }
+
+void LL::WorkQueue::checkCoroutine(const std::string& method)
+{
+    // By convention, the default coroutine on each thread has an empty name
+    // string. See also LLCoros::logname().
+    if (LLCoros::getName().empty())
+    {
+        LLTHROW(NotOnDftCoro("Do not call " + method + " from a thread's default coroutine"));
+    }
+}
diff --git a/indra/llcommon/workqueue.h b/indra/llcommon/workqueue.h
index deef3c8e84..b17c666172 100644
--- a/indra/llcommon/workqueue.h
+++ b/indra/llcommon/workqueue.h
@@ -12,11 +12,18 @@
 #if ! defined(LL_WORKQUEUE_H)
 #define LL_WORKQUEUE_H
 
+#include "llcoros.h"
 #include "llinstancetracker.h"
 #include "threadsafeschedule.h"
 #include <chrono>
 #include <functional>               // std::function
-#include <queue>
+#if __cplusplus >= 201703
+#include <optional>
+namespace stdopt = std;
+#else
+#include <boost/optional.hpp>
+namespace stdopt = boost;
+#endif
 #include <string>
 #include <utility>                  // std::pair
 #include <vector>
@@ -44,6 +51,8 @@ namespace LL
         using TimePoint = Queue::TimePoint;
         using TimedWork = Queue::TimeTuple;
         using Closed    = Queue::Closed;
+        template <typename T>
+        using optional  = stdopt::optional<T>;
 
         /**
          * You may omit the WorkQueue name, in which case a unique name is
@@ -114,7 +123,7 @@ namespace LL
         // Studio compile errors that seem utterly unrelated to this source
         // code.
         template <typename CALLABLE, typename FOLLOWUP>
-        bool postTo(WorkQueue::weak_t target,
+        bool postTo(weak_t target,
                     const TimePoint& time, CALLABLE&& callable, FOLLOWUP&& callback);
 
         /**
@@ -125,13 +134,62 @@ namespace LL
          * inaccessible.
          */
         template <typename CALLABLE, typename FOLLOWUP>
-        bool postTo(WorkQueue::weak_t target,
-                    CALLABLE&& callable, FOLLOWUP&& callback)
+        bool postTo(weak_t target, CALLABLE&& callable, FOLLOWUP&& callback)
         {
             return postTo(target, TimePoint::clock::now(),
                           std::move(callable), std::move(callback));
         }
 
+        /**
+         * Post work to another WorkQueue to be run at a specified time,
+         * blocking the calling coroutine until then, returning the result to
+         * caller on completion.
+         *
+         * REQUIRED:
+         *
+         * * The calling thread is the thread servicing 'this' WorkQueue.
+         * * The calling coroutine is not the @em coroutine servicing this
+         *   WorkQueue. We block the calling coroutine until the result is
+         *   available. If this same coroutine is responsible for checking the
+         *   local WorkQueue, the result will never be dequeued. In practice,
+         *   to try to prevent mistakes, we forbid calling runOn() from a
+         *   thread's default coroutine.
+         *
+         * Returns result if able to post, empty optional if the other
+         * WorkQueue is inaccessible.
+         *
+         * If the passed callable has void return, runOn() returns bool true
+         * if able to post, false if the other WorkQueue is inaccessible.
+         */
+        template <typename CALLABLE>
+        auto runOn(weak_t target, const TimePoint& time, CALLABLE&& callable);
+
+        /**
+         * Post work to another WorkQueue, blocking the calling coroutine
+         * until then, returning the result to caller on completion.
+         *
+         * REQUIRED:
+         *
+         * * The calling thread is the thread servicing 'this' WorkQueue.
+         * * The calling coroutine is not the @em coroutine servicing this
+         *   WorkQueue. We block the calling coroutine until the result is
+         *   available. If this same coroutine is responsible for checking the
+         *   local WorkQueue, the result will never be dequeued. In practice,
+         *   to try to prevent mistakes, we forbid calling runOn() from a
+         *   thread's default coroutine.
+         *
+         * Returns result if able to post, empty optional if the other
+         * WorkQueue is inaccessible.
+         *
+         * If the passed callable has void return, runOn() returns bool true
+         * if able to post, false if the other WorkQueue is inaccessible.
+         */
+        template <typename CALLABLE>
+        auto runOn(weak_t target, CALLABLE&& callable)
+        {
+            return runOn(target, TimePoint::clock::now(), std::move(callable));
+        }
+
         /*--------------------------- worker API ---------------------------*/
 
         /**
@@ -179,15 +237,21 @@ namespace LL
     private:
         template <typename CALLABLE, typename FOLLOWUP>
         static auto makeReplyLambda(CALLABLE&& callable, FOLLOWUP&& callback);
-
         /// general case: arbitrary C++ return type
         template <typename CALLABLE, typename FOLLOWUP, typename RETURNTYPE>
         struct MakeReplyLambda;
-
         /// specialize for CALLABLE returning void
         template <typename CALLABLE, typename FOLLOWUP>
         struct MakeReplyLambda<CALLABLE, FOLLOWUP, void>;
 
+        /// general case: arbitrary C++ return type
+        template <typename CALLABLE, typename RETURNTYPE>
+        struct RunOn;
+        /// specialize for CALLABLE returning void
+        template <typename CALLABLE>
+        struct RunOn<CALLABLE, void>;
+
+        static void checkCoroutine(const std::string& method);
         static void error(const std::string& msg);
         static std::string makeName(const std::string& name);
         void callWork(const Queue::DataTuple& work);
@@ -209,8 +273,8 @@ namespace LL
     {
     public:
         // bind the desired data
-        BackJack(WorkQueue::weak_t target,
-                 const WorkQueue::TimePoint& start,
+        BackJack(weak_t target,
+                 const TimePoint& start,
                  const std::chrono::duration<Rep, Period>& interval,
                  CALLABLE&& callable):
             mTarget(target),
@@ -257,8 +321,8 @@ namespace LL
         }
 
     private:
-        WorkQueue::weak_t mTarget;
-        WorkQueue::TimePoint mStart;
+        weak_t mTarget;
+        TimePoint mStart;
         std::chrono::duration<Rep, Period> mInterval;
         CALLABLE mCallable;
     };
@@ -286,6 +350,7 @@ namespace LL
                  getWeak(), TimePoint::clock::now(), interval, std::move(callable)));
     }
 
+    /// general case: arbitrary C++ return type
     template <typename CALLABLE, typename FOLLOWUP, typename RETURNTYPE>
     struct WorkQueue::MakeReplyLambda
     {
@@ -332,7 +397,7 @@ namespace LL
     }
 
     template <typename CALLABLE, typename FOLLOWUP>
-    bool WorkQueue::postTo(WorkQueue::weak_t target,
+    bool WorkQueue::postTo(weak_t target,
                            const TimePoint& time, CALLABLE&& callable, FOLLOWUP&& callback)
     {
         // We're being asked to post to the WorkQueue at target.
@@ -382,6 +447,69 @@ namespace LL
         return true;
     }
 
+    /// general case: arbitrary C++ return type
+    template <typename CALLABLE, typename RETURNTYPE>
+    struct WorkQueue::RunOn
+    {
+        optional<RETURNTYPE> operator()(WorkQueue* self, weak_t target,
+                                        const TimePoint& time, CALLABLE&& callable)
+        {
+            LLCoros::Promise<RETURNTYPE> promise;
+            if (! self->postTo(
+                    target,
+                    time,
+                    std::forward<CALLABLE>(callable),
+                    // We dare to bind a reference to Promise because it's
+                    // specifically intended for cross-thread synchronization.
+                    [&promise]
+                    (RETURNTYPE&& result)
+                    {
+                        promise.set_value(std::forward<RETURNTYPE>(result));
+                    }))
+            {
+                // we couldn't even postTo(): return empty optional
+                return {};
+            }
+            // we were able to post
+            auto future{ LLCoros::getFuture(promise) };
+            return { future.get(); }
+        }
+    };
+
+    /// specialize for CALLABLE returning void
+    template <typename CALLABLE>
+    struct WorkQueue::RunOn<CALLABLE, void>
+    {
+        bool operator()(WorkQueue* self, weak_t target,
+                        const TimePoint& time, CALLABLE&& callable)
+        {
+            LLCoros::Promise<void> promise;
+            if (! self->postTo(
+                    target,
+                    time,
+                    std::forward<CALLABLE>(callable),
+                    // &promise is designed for cross-thread access
+                    [&promise](){ promise.set_value(); }))
+            {
+                // we couldn't postTo()
+                return false;
+            }
+            // we were able to post
+            auto future{ LLCoros::getFuture(promise) };
+            // block until set_value()
+            future.get();
+            return true;
+        }
+    };
+
+    template <typename CALLABLE>
+    auto WorkQueue::runOn(weak_t target, const TimePoint& time, CALLABLE&& callable)
+    {
+        checkCoroutine("runOn()");
+        return RunOn<CALLABLE, decltype(std::forward<CALLABLE>(callable)())>()
+            (this, target, time, std::forward<CALLABLE>(callable));
+    }
+
 } // namespace LL
 
 #endif /* ! defined(LL_WORKQUEUE_H) */
-- 
cgit v1.2.3


From 081ae57831b40d46acfe8f70e727ab804597ae58 Mon Sep 17 00:00:00 2001
From: Dave Houlton <euclid@lindenlab.com>
Date: Mon, 25 Oct 2021 15:51:35 -0600
Subject: SL-16246 protect null deference

---
 indra/newview/llappviewer.cpp | 20 ++++++++++++--------
 1 file changed, 12 insertions(+), 8 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 8492aba222..400a6a722b 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -864,8 +864,6 @@ bool LLAppViewer::init()
 	LLNotifications::instance();
 	LL_INFOS("InitInfo") << "Notifications initialized." << LL_ENDL ;
 
-    writeSystemInfo();
-
 	//////////////////////////////////////////////////////////////////////////////
 	//////////////////////////////////////////////////////////////////////////////
 	//////////////////////////////////////////////////////////////////////////////
@@ -986,6 +984,9 @@ bool LLAppViewer::init()
 	initWindow();
 	LL_INFOS("InitInfo") << "Window is initialized." << LL_ENDL ;
 
+    // writeSystemInfo can be called after window is initialized (gViewerWindow non-null)
+    writeSystemInfo();
+
 	// initWindow also initializes the Feature List, so now we can initialize this global.
 	LLCubeMap::sUseCubeMaps = LLFeatureManager::getInstance()->isFeatureAvailable("RenderCubeMap");
 
@@ -3540,12 +3541,15 @@ void LLAppViewer::writeSystemInfo()
 	gDebugInfo["FirstLogin"] = LLSD::Boolean(gAgent.isFirstLogin());
 	gDebugInfo["FirstRunThisInstall"] = gSavedSettings.getBOOL("FirstRunThisInstall");
     gDebugInfo["StartupState"] = LLStartUp::getStartupStateString();
-
-	std::vector<std::string> resolutions = gViewerWindow->getWindow()->getDisplaysResolutionList();
-	for (auto res_iter : resolutions)
-	{
-		gDebugInfo["DisplayInfo"].append(res_iter);
-	}
+    
+    if (gViewerWindow)
+    {
+        std::vector<std::string> resolutions = gViewerWindow->getWindow()->getDisplaysResolutionList();
+        for (auto res_iter : resolutions)
+        {
+            gDebugInfo["DisplayInfo"].append(res_iter);
+        }
+    }
 
 	writeDebugInfo(); // Save out debug_info.log early, in case of crash.
 }
-- 
cgit v1.2.3


From 4e8cd9437bed90b3468b1bf12f545de16faefb67 Mon Sep 17 00:00:00 2001
From: Dave Parks <davep@lindenlab.com>
Date: Tue, 26 Oct 2021 14:07:00 +0000
Subject: SL-16193 Fix for mesh selection outline not rendering correctly (and
 broken physics shapes display).

---
 indra/llcommon/llcommon.cpp          |   5 +-
 indra/llrender/llgl.cpp              |   2 +
 indra/llrender/llvertexbuffer.cpp    | 185 ++++++++++++++---------------------
 indra/llrender/llvertexbuffer.h      |   3 +-
 indra/newview/llface.h               |   4 +-
 indra/newview/llmodelpreview.cpp     |   2 +-
 indra/newview/llspatialpartition.cpp |  26 +++--
 7 files changed, 95 insertions(+), 132 deletions(-)

(limited to 'indra')

diff --git a/indra/llcommon/llcommon.cpp b/indra/llcommon/llcommon.cpp
index abc6af2cfc..04872564bf 100644
--- a/indra/llcommon/llcommon.cpp
+++ b/indra/llcommon/llcommon.cpp
@@ -44,6 +44,7 @@ void *operator new(size_t size)
     {
         LL_PROFILE_ZONE_SCOPED;
         ptr = (malloc)(size);
+        TracyAlloc(ptr, size);
     }
     else
     {
@@ -53,17 +54,15 @@ void *operator new(size_t size)
     {
         throw std::bad_alloc();
     }
-    TracyAlloc(ptr, size);
     return ptr;
 }
 
 void operator delete(void *ptr) noexcept
 {
-    TracyFree(ptr);
-
     if (gProfilerEnabled)
     {
         LL_PROFILE_ZONE_SCOPED;
+        TracyFree(ptr);
         (free)(ptr);
     }
     else
diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp
index a269549c49..b66521132c 100644
--- a/indra/llrender/llgl.cpp
+++ b/indra/llrender/llgl.cpp
@@ -2117,6 +2117,7 @@ void LLGLState::checkClientArrays(const std::string& msg, U32 data_mask)
 LLGLState::LLGLState(LLGLenum state, S32 enabled) :
 	mState(state), mWasEnabled(FALSE), mIsEnabled(FALSE)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	if (LLGLSLShader::sNoFixedFunction)
 	{ //always ignore state that's deprecated post GL 3.0
 		switch (state)
@@ -2175,6 +2176,7 @@ void LLGLState::setEnabled(S32 enabled)
 
 LLGLState::~LLGLState() 
 {
+    LL_PROFILE_ZONE_SCOPED;
 	stop_glerror();
 	if (mState)
 	{
diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp
index 103d5388d3..7e726df907 100644
--- a/indra/llrender/llvertexbuffer.cpp
+++ b/indra/llrender/llvertexbuffer.cpp
@@ -577,63 +577,22 @@ void LLVertexBuffer::setupClientArrays(U32 data_mask)
 }
 
 //static
-static LLTrace::BlockTimerStatHandle FTM_VB_DRAW_ARRAYS("drawArrays");
-void LLVertexBuffer::drawArrays(U32 mode, const std::vector<LLVector3>& pos, const std::vector<LLVector3>& norm)
+void LLVertexBuffer::drawArrays(U32 mode, const std::vector<LLVector3>& pos)
 {
-	LL_RECORD_BLOCK_TIME(FTM_VB_DRAW_ARRAYS);
-	llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShaderPtr != NULL);
-	gGL.syncMatrices();
-
-	U32 count = pos.size();
-	
-	llassert(norm.size() >= pos.size());
-	llassert(count > 0);
-
-	if( count == 0 )
-	{
-		LL_WARNS() << "Called drawArrays with 0 vertices" << LL_ENDL;
-		return;
-	}
-
-	if( norm.size() < pos.size() )
-	{
-		LL_WARNS() << "Called drawArrays with #" << norm.size() << " normals and #" << pos.size() << " vertices" << LL_ENDL;
-		return;
-	}
-
-	unbind();
-	
-	setupClientArrays(MAP_VERTEX | MAP_NORMAL);
-
-	LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
-
-	if (shader)
-	{
-		S32 loc = LLVertexBuffer::TYPE_VERTEX;
-		if (loc > -1)
-		{
-			glVertexAttribPointerARB(loc, 3, GL_FLOAT, GL_FALSE, 0, pos[0].mV);
-		}
-		loc = LLVertexBuffer::TYPE_NORMAL;
-		if (loc > -1)
-		{
-			glVertexAttribPointerARB(loc, 3, GL_FLOAT, GL_FALSE, 0, norm[0].mV);
-		}
-	}
-	else
-	{
-		glVertexPointer(3, GL_FLOAT, 0, pos[0].mV);
-		glNormalPointer(GL_FLOAT, 0, norm[0].mV);
-	}
-	LLGLSLShader::startProfile();
-	LL_PROFILER_GPU_ZONEC( "gl.DrawArrays", 0xFF0000 )
-	glDrawArrays(sGLMode[mode], 0, count);
-	LLGLSLShader::stopProfile(count, mode);
+    LL_PROFILE_ZONE_SCOPED;
+    gGL.begin(mode);
+    for (auto& v : pos)
+    {
+        gGL.vertex3fv(v.mV);
+    }
+    gGL.end();
+    gGL.flush();
 }
 
 //static
 void LLVertexBuffer::drawElements(U32 mode, const LLVector4a* pos, const LLVector2* tc, S32 num_indices, const U16* indicesp)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShaderPtr != NULL);
 
 	gGL.syncMatrices();
@@ -646,29 +605,27 @@ void LLVertexBuffer::drawElements(U32 mode, const LLVector4a* pos, const LLVecto
 
 	unbind();
 	
-	setupClientArrays(mask);
+    gGL.begin(mode);
 
-	if (LLGLSLShader::sNoFixedFunction)
-	{
-		S32 loc = LLVertexBuffer::TYPE_VERTEX;
-		glVertexAttribPointerARB(loc, 3, GL_FLOAT, GL_FALSE, 16, pos);
-
-		if (tc)
-		{
-			loc = LLVertexBuffer::TYPE_TEXCOORD0;
-			glVertexAttribPointerARB(loc, 2, GL_FLOAT, GL_FALSE, 0, tc);
-		}
-	}
-	else
-	{
-		glTexCoordPointer(2, GL_FLOAT, 0, tc);
-		glVertexPointer(3, GL_FLOAT, 16, pos);
-	}
-
-	LLGLSLShader::startProfile();
-    LL_PROFILER_GPU_ZONEC( "gl.DrawElements", 0x80FF80 )
-	glDrawElements(sGLMode[mode], num_indices, GL_UNSIGNED_SHORT, indicesp);
-	LLGLSLShader::stopProfile(num_indices, mode);
+    if (tc != nullptr)
+    {
+        for (int i = 0; i < num_indices; ++i)
+        {
+            U16 idx = indicesp[i];
+            gGL.texCoord2fv(tc[idx].mV);
+            gGL.vertex3fv(pos[idx].getF32ptr());
+        }
+    }
+    else
+    {
+        for (int i = 0; i < num_indices; ++i)
+        {
+            U16 idx = indicesp[i];
+            gGL.vertex3fv(pos[idx].getF32ptr());
+        }
+    }
+    gGL.end();
+    gGL.flush();
 }
 
 void LLVertexBuffer::validateRange(U32 start, U32 end, U32 count, U32 indices_offset) const
@@ -851,51 +808,51 @@ void LLVertexBuffer::draw(U32 mode, U32 count, U32 indices_offset) const
 static LLTrace::BlockTimerStatHandle FTM_GL_DRAW_ARRAYS("GL draw arrays");
 void LLVertexBuffer::drawArrays(U32 mode, U32 first, U32 count) const
 {
-	llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShaderPtr != NULL);
-	mMappable = false;
-	gGL.syncMatrices();
-	
-	llassert(mNumVerts >= 0);
-	if (first >= (U32) mNumVerts ||
-	    first + count > (U32) mNumVerts)
-	{
-		LL_ERRS() << "Bad vertex buffer draw range: [" << first << ", " << first+count << "]" << LL_ENDL;
-	}
+    llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShaderPtr != NULL);
+    mMappable = false;
+    gGL.syncMatrices();
 
-	if (mGLArray)
-	{
-		if (mGLArray != sGLRenderArray)
-		{
-			LL_ERRS() << "Wrong vertex array bound." << LL_ENDL;
-		}
-	}
-	else
-	{
-		if (mGLBuffer != sGLRenderBuffer || useVBOs() != sVBOActive)
-		{
-			LL_ERRS() << "Wrong vertex buffer bound." << LL_ENDL;
-		}
-	}
+    llassert(mNumVerts >= 0);
+    if (first >= (U32)mNumVerts ||
+        first + count > (U32)mNumVerts)
+    {
+        LL_ERRS() << "Bad vertex buffer draw range: [" << first << ", " << first + count << "]" << LL_ENDL;
+    }
 
-	if (mode >= LLRender::NUM_MODES)
-	{
-		LL_ERRS() << "Invalid draw mode: " << mode << LL_ENDL;
-		return;
-	}
+    if (mGLArray)
+    {
+        if (mGLArray != sGLRenderArray)
+        {
+            LL_ERRS() << "Wrong vertex array bound." << LL_ENDL;
+        }
+    }
+    else
+    {
+        if (mGLBuffer != sGLRenderBuffer || useVBOs() != sVBOActive)
+        {
+            LL_ERRS() << "Wrong vertex buffer bound." << LL_ENDL;
+        }
+    }
 
-	{
-		LL_RECORD_BLOCK_TIME(FTM_GL_DRAW_ARRAYS);
-		stop_glerror();
-		LLGLSLShader::startProfile();
-		stop_glerror();
-        LL_PROFILER_GPU_ZONEC( "gl.DrawArrays", 0xFF4040 )
-		glDrawArrays(sGLMode[mode], first, count);
-		stop_glerror();
-		LLGLSLShader::stopProfile(count, mode);
-	}
+    if (mode >= LLRender::NUM_MODES)
+    {
+        LL_ERRS() << "Invalid draw mode: " << mode << LL_ENDL;
+        return;
+    }
 
-	stop_glerror();
-	placeFence();
+    {
+        LL_RECORD_BLOCK_TIME(FTM_GL_DRAW_ARRAYS);
+        stop_glerror();
+        LLGLSLShader::startProfile();
+        stop_glerror();
+        LL_PROFILER_GPU_ZONEC("gl.DrawArrays", 0xFF4040)
+            glDrawArrays(sGLMode[mode], first, count);
+        stop_glerror();
+        LLGLSLShader::stopProfile(count, mode);
+    }
+
+    stop_glerror();
+    placeFence();
 }
 
 //static
diff --git a/indra/llrender/llvertexbuffer.h b/indra/llrender/llvertexbuffer.h
index 51ed85510e..fad474a143 100644
--- a/indra/llrender/llvertexbuffer.h
+++ b/indra/llrender/llvertexbuffer.h
@@ -146,8 +146,7 @@ public:
 	static void initClass(bool use_vbo, bool no_vbo_mapping);
 	static void cleanupClass();
 	static void setupClientArrays(U32 data_mask);
-	static void pushPositions(U32 mode, const LLVector4a* pos, U32 count);
-	static void drawArrays(U32 mode, const std::vector<LLVector3>& pos, const std::vector<LLVector3>& norm);
+	static void drawArrays(U32 mode, const std::vector<LLVector3>& pos);
 	static void drawElements(U32 mode, const LLVector4a* pos, const LLVector2* tc, S32 num_indices, const U16* indicesp);
 
  	static void unbind(); //unbind any bound vertex buffer
diff --git a/indra/newview/llface.h b/indra/newview/llface.h
index 3611539ff8..9dd365e3dc 100644
--- a/indra/newview/llface.h
+++ b/indra/newview/llface.h
@@ -271,10 +271,10 @@ private:
 	LLColor4	mFaceColor;			// overrides material color if state |= USE_FACE_COLOR
 	
 	U16			mGeomCount;			// vertex count for this face
-	U16			mGeomIndex;			// index into draw pool
+	U16			mGeomIndex;			// starting index into mVertexBuffer's vertex array
 	U8			mTextureIndex;		// index of texture channel to use for pseudo-atlasing
 	U32			mIndicesCount;
-	U32			mIndicesIndex;		// index into draw pool for indices (yeah, I know!)
+	U32			mIndicesIndex;		// index into mVertexBuffer's index array
 	S32         mIndexInTex[LLRender::NUM_TEXTURE_CHANNELS];
 
 	LLXformMatrix* mXform;
diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp
index 01bddd781d..4fce6735e0 100644
--- a/indra/newview/llmodelpreview.cpp
+++ b/indra/newview/llmodelpreview.cpp
@@ -3126,7 +3126,7 @@ BOOL LLModelPreview::render()
                                         }
 
                                         gGL.diffuseColor4ubv(hull_colors[i].mV);
-                                        LLVertexBuffer::drawArrays(LLRender::TRIANGLES, physics.mMesh[i].mPositions, physics.mMesh[i].mNormals);
+                                        LLVertexBuffer::drawArrays(LLRender::TRIANGLES, physics.mMesh[i].mPositions);
 
                                         if (explode > 0.f)
                                         {
diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp
index 253b6b9953..5cac9cd7ae 100644
--- a/indra/newview/llspatialpartition.cpp
+++ b/indra/newview/llspatialpartition.cpp
@@ -2386,7 +2386,12 @@ void renderMeshBaseHull(LLVOVolume* volume, U32 data_mask, LLColor4& color, LLCo
 		if (!decomp->mBaseHullMesh.empty())
 		{
 			gGL.diffuseColor4fv(color.mV);
-			LLVertexBuffer::drawArrays(LLRender::TRIANGLES, decomp->mBaseHullMesh.mPositions, decomp->mBaseHullMesh.mNormals);
+			LLVertexBuffer::drawArrays(LLRender::TRIANGLES, decomp->mBaseHullMesh.mPositions);
+
+            glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+            gGL.diffuseColor4fv(line_color.mV);
+            LLVertexBuffer::drawArrays(LLRender::TRIANGLES, decomp->mBaseHullMesh.mPositions);
+            glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
 		}
 		else
 		{
@@ -2406,13 +2411,11 @@ void renderMeshBaseHull(LLVOVolume* volume, U32 data_mask, LLColor4& color, LLCo
 void render_hull(LLModel::PhysicsMesh& mesh, const LLColor4& color, const LLColor4& line_color)
 {
 	gGL.diffuseColor4fv(color.mV);
-	LLVertexBuffer::drawArrays(LLRender::TRIANGLES, mesh.mPositions, mesh.mNormals);
-	LLGLEnable offset(GL_POLYGON_OFFSET_LINE);
+	LLVertexBuffer::drawArrays(LLRender::TRIANGLES, mesh.mPositions);
 	glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
-	glPolygonOffset(3.f, 3.f);
 	glLineWidth(3.f);
 	gGL.diffuseColor4fv(line_color.mV);
-	LLVertexBuffer::drawArrays(LLRender::TRIANGLES, mesh.mPositions, mesh.mNormals);
+	LLVertexBuffer::drawArrays(LLRender::TRIANGLES, mesh.mPositions);
 	glLineWidth(1.f);
 	glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
 }
@@ -2467,6 +2470,9 @@ void renderPhysicsShape(LLDrawable* drawable, LLVOVolume* volume)
 	gGL.pushMatrix();
 	gGL.multMatrix((F32*) volume->getRelativeXform().mMatrix);
 		
+    LLGLEnable(GL_POLYGON_OFFSET_LINE);
+    glPolygonOffset(3.f, 3.f);
+
 	if (type == LLPhysicsShapeBuilderUtil::PhysicsShapeSpecification::USER_MESH)
 	{
 		LLUUID mesh_id = volume->getVolume()->getParams().getSculptID();
@@ -2494,12 +2500,12 @@ void renderPhysicsShape(LLDrawable* drawable, LLVOVolume* volume)
 			{ 
 				//decomp has physics mesh, render that mesh
 				gGL.diffuseColor4fv(color.mV);
-				LLVertexBuffer::drawArrays(LLRender::TRIANGLES, decomp->mPhysicsShapeMesh.mPositions, decomp->mPhysicsShapeMesh.mNormals);
+				LLVertexBuffer::drawArrays(LLRender::TRIANGLES, decomp->mPhysicsShapeMesh.mPositions);
 								
 				glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
 				gGL.diffuseColor4fv(line_color.mV);
-				LLVertexBuffer::drawArrays(LLRender::TRIANGLES, decomp->mPhysicsShapeMesh.mPositions, decomp->mPhysicsShapeMesh.mNormals);
-				glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+                LLVertexBuffer::drawArrays(LLRender::TRIANGLES, decomp->mPhysicsShapeMesh.mPositions);
+                glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
 			}
 			else
 			{ //no mesh or decomposition, render base hull
@@ -2626,8 +2632,8 @@ void renderPhysicsShape(LLDrawable* drawable, LLVOVolume* volume)
 				LLVertexBuffer::unbind();
 
 				llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShader != 0);
-							
-				LLVertexBuffer::drawElements(LLRender::TRIANGLES, phys_volume->mHullPoints, NULL, phys_volume->mNumHullIndices, phys_volume->mHullIndices);
+				
+                LLVertexBuffer::drawElements(LLRender::TRIANGLES, phys_volume->mHullPoints, NULL, phys_volume->mNumHullIndices, phys_volume->mHullIndices);
 				
 				gGL.diffuseColor4fv(color.mV);
 				glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
-- 
cgit v1.2.3


From c907d067f41930bd6a4bbef9903febfab1090982 Mon Sep 17 00:00:00 2001
From: Runitai Linden <davep@lindenlab.com>
Date: Tue, 26 Oct 2021 09:23:17 -0500
Subject: SL-16243 Followup -- fix for inconsistently calling
 TracyAlloc/TracyFree

---
 indra/llcommon/llcommon.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

(limited to 'indra')

diff --git a/indra/llcommon/llcommon.cpp b/indra/llcommon/llcommon.cpp
index 04872564bf..25a809dad2 100644
--- a/indra/llcommon/llcommon.cpp
+++ b/indra/llcommon/llcommon.cpp
@@ -44,7 +44,6 @@ void *operator new(size_t size)
     {
         LL_PROFILE_ZONE_SCOPED;
         ptr = (malloc)(size);
-        TracyAlloc(ptr, size);
     }
     else
     {
@@ -54,15 +53,16 @@ void *operator new(size_t size)
     {
         throw std::bad_alloc();
     }
+    TracyAlloc(ptr, size);
     return ptr;
 }
 
 void operator delete(void *ptr) noexcept
 {
+    TracyFree(ptr);
     if (gProfilerEnabled)
     {
         LL_PROFILE_ZONE_SCOPED;
-        TracyFree(ptr);
         (free)(ptr);
     }
     else
-- 
cgit v1.2.3


From e6eebea8da545350f6684c191c633dd2fbc6f6f1 Mon Sep 17 00:00:00 2001
From: Nat Goodspeed <nat@lindenlab.com>
Date: Tue, 26 Oct 2021 11:49:53 -0400
Subject: SL-16220: Change WorkQueue::runOn() to waitForResult().

In addition to the name making the blocking explicit, we changed the
signature: instead of specifying a target WorkQueue on which to run,
waitForResult() runs the passed callable on its own WorkQueue.

Why is that? Because, unlike postTo(), we do not require a handshake between
two different WorkQueues. postTo() allows running arbitrary callback code,
setting variables or whatever, on the originating WorkQueue (presumably on the
originating thread). waitForResult() synchronizes using Promise/Future, which
are explicitly designed for cross-thread communication. We need not call
set_value() on the originating thread, so we don't need a postTo() callback
lambda.
---
 indra/llcommon/workqueue.cpp |   7 +--
 indra/llcommon/workqueue.h   | 145 ++++++++++++++++++-------------------------
 2 files changed, 62 insertions(+), 90 deletions(-)

(limited to 'indra')

diff --git a/indra/llcommon/workqueue.cpp b/indra/llcommon/workqueue.cpp
index f7ffc8233c..ac3086aac5 100644
--- a/indra/llcommon/workqueue.cpp
+++ b/indra/llcommon/workqueue.cpp
@@ -26,11 +26,6 @@
 using Mutex = LLCoros::Mutex;
 using Lock  = LLCoros::LockType;
 
-struct NotOnDftCoro: public LLException
-{
-    NotOnDftCoro(const std::string& what): LLException(what) {}
-};
-
 LL::WorkQueue::WorkQueue(const std::string& name):
     super(makeName(name))
 {
@@ -148,6 +143,6 @@ void LL::WorkQueue::checkCoroutine(const std::string& method)
     // string. See also LLCoros::logname().
     if (LLCoros::getName().empty())
     {
-        LLTHROW(NotOnDftCoro("Do not call " + method + " from a thread's default coroutine"));
+        LLTHROW(Error("Do not call " + method + " from a thread's default coroutine"));
     }
 }
diff --git a/indra/llcommon/workqueue.h b/indra/llcommon/workqueue.h
index b17c666172..869f5d9a82 100644
--- a/indra/llcommon/workqueue.h
+++ b/indra/llcommon/workqueue.h
@@ -13,20 +13,13 @@
 #define LL_WORKQUEUE_H
 
 #include "llcoros.h"
+#include "llexception.h"
 #include "llinstancetracker.h"
 #include "threadsafeschedule.h"
 #include <chrono>
+#include <exception>                // std::current_exception
 #include <functional>               // std::function
-#if __cplusplus >= 201703
-#include <optional>
-namespace stdopt = std;
-#else
-#include <boost/optional.hpp>
-namespace stdopt = boost;
-#endif
 #include <string>
-#include <utility>                  // std::pair
-#include <vector>
 
 namespace LL
 {
@@ -51,8 +44,11 @@ namespace LL
         using TimePoint = Queue::TimePoint;
         using TimedWork = Queue::TimeTuple;
         using Closed    = Queue::Closed;
-        template <typename T>
-        using optional  = stdopt::optional<T>;
+
+        struct Error: public LLException
+        {
+            Error(const std::string& what): LLException(what) {}
+        };
 
         /**
          * You may omit the WorkQueue name, in which case a unique name is
@@ -145,49 +141,25 @@ namespace LL
          * blocking the calling coroutine until then, returning the result to
          * caller on completion.
          *
-         * REQUIRED:
-         *
-         * * The calling thread is the thread servicing 'this' WorkQueue.
-         * * The calling coroutine is not the @em coroutine servicing this
-         *   WorkQueue. We block the calling coroutine until the result is
-         *   available. If this same coroutine is responsible for checking the
-         *   local WorkQueue, the result will never be dequeued. In practice,
-         *   to try to prevent mistakes, we forbid calling runOn() from a
-         *   thread's default coroutine.
-         *
-         * Returns result if able to post, empty optional if the other
-         * WorkQueue is inaccessible.
-         *
-         * If the passed callable has void return, runOn() returns bool true
-         * if able to post, false if the other WorkQueue is inaccessible.
+         * In general, we assume that each thread's default coroutine is busy
+         * servicing its WorkQueue or whatever. To try to prevent mistakes, we
+         * forbid calling waitForResult() from a thread's default coroutine.
          */
         template <typename CALLABLE>
-        auto runOn(weak_t target, const TimePoint& time, CALLABLE&& callable);
+        auto waitForResult(const TimePoint& time, CALLABLE&& callable);
 
         /**
          * Post work to another WorkQueue, blocking the calling coroutine
          * until then, returning the result to caller on completion.
          *
-         * REQUIRED:
-         *
-         * * The calling thread is the thread servicing 'this' WorkQueue.
-         * * The calling coroutine is not the @em coroutine servicing this
-         *   WorkQueue. We block the calling coroutine until the result is
-         *   available. If this same coroutine is responsible for checking the
-         *   local WorkQueue, the result will never be dequeued. In practice,
-         *   to try to prevent mistakes, we forbid calling runOn() from a
-         *   thread's default coroutine.
-         *
-         * Returns result if able to post, empty optional if the other
-         * WorkQueue is inaccessible.
-         *
-         * If the passed callable has void return, runOn() returns bool true
-         * if able to post, false if the other WorkQueue is inaccessible.
+         * In general, we assume that each thread's default coroutine is busy
+         * servicing its WorkQueue or whatever. To try to prevent mistakes, we
+         * forbid calling waitForResult() from a thread's default coroutine.
          */
         template <typename CALLABLE>
-        auto runOn(weak_t target, CALLABLE&& callable)
+        auto waitForResult(CALLABLE&& callable)
         {
-            return runOn(target, TimePoint::clock::now(), std::move(callable));
+            return waitForResult(TimePoint::clock::now(), std::move(callable));
         }
 
         /*--------------------------- worker API ---------------------------*/
@@ -246,10 +218,10 @@ namespace LL
 
         /// general case: arbitrary C++ return type
         template <typename CALLABLE, typename RETURNTYPE>
-        struct RunOn;
+        struct WaitForResult;
         /// specialize for CALLABLE returning void
         template <typename CALLABLE>
-        struct RunOn<CALLABLE, void>;
+        struct WaitForResult<CALLABLE, void>;
 
         static void checkCoroutine(const std::string& method);
         static void error(const std::string& msg);
@@ -449,65 +421,70 @@ namespace LL
 
     /// general case: arbitrary C++ return type
     template <typename CALLABLE, typename RETURNTYPE>
-    struct WorkQueue::RunOn
+    struct WorkQueue::WaitForResult
     {
-        optional<RETURNTYPE> operator()(WorkQueue* self, weak_t target,
-                                        const TimePoint& time, CALLABLE&& callable)
+        auto operator()(WorkQueue* self, const TimePoint& time, CALLABLE&& callable)
         {
             LLCoros::Promise<RETURNTYPE> promise;
-            if (! self->postTo(
-                    target,
-                    time,
-                    std::forward<CALLABLE>(callable),
-                    // We dare to bind a reference to Promise because it's
-                    // specifically intended for cross-thread synchronization.
-                    [&promise]
-                    (RETURNTYPE&& result)
+            self->post(
+                time,
+                // We dare to bind a reference to Promise because it's
+                // specifically designed for cross-thread communication.
+                [&promise, callable = std::move(callable)]()
+                {
+                    try
                     {
-                        promise.set_value(std::forward<RETURNTYPE>(result));
-                    }))
-            {
-                // we couldn't even postTo(): return empty optional
-                return {};
-            }
-            // we were able to post
+                        // call the caller's callable and trigger promise with result
+                        promise.set_value(callable());
+                    }
+                    catch (...)
+                    {
+                        promise.set_exception(std::current_exception());
+                    }
+                });
             auto future{ LLCoros::getFuture(promise) };
-            return { future.get(); }
+            // now, on the calling thread, wait for that result
+            LLCoros::TempStatus st("waiting for WorkQueue::waitForResult()");
+            return future.get();
         }
     };
 
     /// specialize for CALLABLE returning void
     template <typename CALLABLE>
-    struct WorkQueue::RunOn<CALLABLE, void>
+    struct WorkQueue::WaitForResult<CALLABLE, void>
     {
-        bool operator()(WorkQueue* self, weak_t target,
-                        const TimePoint& time, CALLABLE&& callable)
+        void operator()(WorkQueue* self, const TimePoint& time, CALLABLE&& callable)
         {
             LLCoros::Promise<void> promise;
-            if (! self->postTo(
-                    target,
-                    time,
-                    std::forward<CALLABLE>(callable),
-                    // &promise is designed for cross-thread access
-                    [&promise](){ promise.set_value(); }))
-            {
-                // we couldn't postTo()
-                return false;
-            }
-            // we were able to post
+            self->post(
+                time,
+                // &promise is designed for cross-thread access
+                [&promise, callable = std::move(callable)]()
+                {
+                    try
+                    {
+                        callable();
+                        promise.set_value();
+                    }
+                    catch (...)
+                    {
+                        promise.set_exception(std::current_exception());
+                    }
+                });
             auto future{ LLCoros::getFuture(promise) };
             // block until set_value()
+            LLCoros::TempStatus st("waiting for void WorkQueue::waitForResult()");
             future.get();
-            return true;
         }
     };
 
     template <typename CALLABLE>
-    auto WorkQueue::runOn(weak_t target, const TimePoint& time, CALLABLE&& callable)
+    auto WorkQueue::waitForResult(const TimePoint& time, CALLABLE&& callable)
     {
-        checkCoroutine("runOn()");
-        return RunOn<CALLABLE, decltype(std::forward<CALLABLE>(callable)())>()
-            (this, target, time, std::forward<CALLABLE>(callable));
+        checkCoroutine("waitForResult()");
+        // derive callable's return type so we can specialize for void
+        return WaitForResult<CALLABLE, decltype(std::forward<CALLABLE>(callable)())>()
+            (this, time, std::forward<CALLABLE>(callable));
     }
 
 } // namespace LL
-- 
cgit v1.2.3


From f06765cba868679492934452354d16f9f3af9ade Mon Sep 17 00:00:00 2001
From: Nat Goodspeed <nat@lindenlab.com>
Date: Tue, 26 Oct 2021 12:29:49 -0400
Subject: SL-16220: Make WorkQueue::postTo() return exception to caller.

postTo() sets up two-way communication: the caller asks to run work on some
other WorkQueue, expecting an eventual callback on the originating WorkQueue.
That permits us to transport any exception thrown by the work callable back to
rethrow on the originating WorkQueue.
---
 indra/llcommon/workqueue.h | 93 +++++++++++++++++++++++++++++++---------------
 1 file changed, 64 insertions(+), 29 deletions(-)

(limited to 'indra')

diff --git a/indra/llcommon/workqueue.h b/indra/llcommon/workqueue.h
index 869f5d9a82..42f5d78ba3 100644
--- a/indra/llcommon/workqueue.h
+++ b/indra/llcommon/workqueue.h
@@ -136,6 +136,25 @@ namespace LL
                           std::move(callable), std::move(callback));
         }
 
+        /**
+         * Post work to be run at a specified time to another WorkQueue, which
+         * may or may not still exist and be open. Return true if we were able
+         * to post.
+         */
+        template <typename CALLABLE>
+        static bool postMaybe(weak_t target, const TimePoint& time, CALLABLE&& callable);
+
+        /**
+         * Post work to another WorkQueue, which may or may not still exist
+         * and be open. Return true if we were able to post.
+         */
+        template <typename CALLABLE>
+        static bool postMaybe(weak_t target, CALLABLE&& callable)
+        {
+            return postMaybe(target, TimePoint::clock::now(),
+                             std::forward<CALLABLE>(callable));
+        }
+
         /**
          * Post work to another WorkQueue to be run at a specified time,
          * blocking the calling coroutine until then, returning the result to
@@ -351,12 +370,8 @@ namespace LL
         {
             // Call the callable, which produces no result.
             std::forward<CALLABLE>(callable)();
-            // This reply lambda binds the original callback, so
-            // that when we, the originating WorkQueue, finally
-            // receive and process the reply lambda, we'll call
-            // the bound callback -- on the same thread that
-            // originally called postTo().
-            return [callback = std::move(callback)](){ callback(); };
+            // Our completion callback is simply the caller's callback.
+            return std::move(callback);
         }
     };
 
@@ -389,36 +404,56 @@ namespace LL
              callback = std::move(callback)]
             ()
             {
-                // Make a reply lambda to repost to THIS WorkQueue.
-                // Delegate to makeReplyLambda() so we can partially
-                // specialize on void return.
-                auto rlambda = makeReplyLambda(std::move(callable), std::move(callback));
-                // 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)
+                // Use postMaybe() below in case this originating WorkQueue
+                // has been closed or destroyed. Remember, the outer lambda is
+                // now running on a thread servicing the target WorkQueue, and
+                // real time has elapsed since postTo()'s tptr->post() call.
+                try
                 {
-                    // 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.
-                    }
+                    // Make a reply lambda to repost to THIS WorkQueue.
+                    // Delegate to makeReplyLambda() so we can partially
+                    // specialize on void return.
+                    postMaybe(reply, makeReplyLambda(std::move(callable), std::move(callback)));
+                }
+                catch (...)
+                {
+                    // Either variant of makeReplyLambda() is responsible for
+                    // calling the caller's callable. If that throws, return
+                    // the exception to the originating thread.
+                    postMaybe(
+                        reply,
+                        // Bind the current exception to transport back to the
+                        // originating WorkQueue. Once there, rethrow it.
+                        [exc = std::current_exception()](){ std::rethrow_exception(exc); });
                 }
             });
+
         // looks like we were able to post()
         return true;
     }
 
+    template <typename CALLABLE>
+    bool WorkQueue::postMaybe(weak_t target, const TimePoint& time, CALLABLE&& callable)
+    {
+        // target is a weak_ptr: have to lock it to check it
+        auto tptr = target.lock();
+        if (tptr)
+        {
+            try
+            {
+                tptr->post(time, std::forward<CALLABLE>(callable));
+                // we were able to post()
+                return true;
+            }
+            catch (const Closed&)
+            {
+                // target WorkQueue still exists, but is Closed
+            }
+        }
+        // either target no longer exists, or its WorkQueue is Closed
+        return false;
+    }
+
     /// general case: arbitrary C++ return type
     template <typename CALLABLE, typename RETURNTYPE>
     struct WorkQueue::WaitForResult
-- 
cgit v1.2.3


From af5c5a994b90a27e16ef6f2f5044e096269e4217 Mon Sep 17 00:00:00 2001
From: Nat Goodspeed <nat@lindenlab.com>
Date: Wed, 27 Oct 2021 13:01:37 -0400
Subject: SL-16207: Update llstring.h handling of different string types.

In llpreprocessor.h, consider the case of clang on Windows: #define
LL_WCHAR_T_NATIVE there as well as for the Microsoft compiler with /Zc:wchar_t
switch.

In stdtypes.h, inject a LLWCHAR_IS_WCHAR_T symbol to allow the preprocessor to
make decisions about when the types are identical.

llstring.h's conversion logic deals with three types of wide strings
(LLWString, std::wstring and utf16string) based on three types of wide char
(llwchar, wchar_t and U16, respectively). Sometimes they're three distinct
types, sometimes wchar_t is identical to llwchar and sometimes wchar_t is
identical to U16. Rationalize the three cases using ll_convert_u16_alias() and
new ll_convert_wstr_alias() macros.

stringize.h was directly calling wstring_to_utf8str() and utf8str_to_wstring(),
which was producing errors with VS 2019 clang since there isn't actually a
wstring_to_utf8str(std::wstring) overload. Use ll_convert<std::string>()
instead, since that redirects to the relevant ll_convert_wide_to_string()
function. (And now you see why we've been trying to migrate to the uniform
ll_convert<target>() wrapper!) Similarly, call ll_convert<std::wstring>()
instead of a two-step conversion from utf8str_to_wstring(), producing LLWString,
then a character-by-character copy from LLWString to std::wstring. That
isn't even correct: on Windows, we should be encoding from UTF32 to UTF16.
---
 indra/llcommon/llpreprocessor.h |  4 ++-
 indra/llcommon/llstring.h       | 65 ++++++++++++++++++++++-------------------
 indra/llcommon/stdtypes.h       |  7 +++++
 indra/llcommon/stringize.h      | 13 ++++-----
 4 files changed, 50 insertions(+), 39 deletions(-)

(limited to 'indra')

diff --git a/indra/llcommon/llpreprocessor.h b/indra/llcommon/llpreprocessor.h
index b17a8e761a..dc586b0008 100644
--- a/indra/llcommon/llpreprocessor.h
+++ b/indra/llcommon/llpreprocessor.h
@@ -171,7 +171,9 @@
 #define LL_DLLIMPORT
 #endif // LL_WINDOWS
 
-#if ! defined(LL_WINDOWS)
+#if __clang__ || ! defined(LL_WINDOWS)
+// Only on Windows, and only with the Microsoft compiler (vs. clang) is
+// wchar_t potentially not a distinct type.
 #define LL_WCHAR_T_NATIVE 1
 #else  // LL_WINDOWS
 // https://docs.microsoft.com/en-us/cpp/preprocessor/predefined-macros
diff --git a/indra/llcommon/llstring.h b/indra/llcommon/llstring.h
index 4263122f36..89e95ef40a 100644
--- a/indra/llcommon/llstring.h
+++ b/indra/llcommon/llstring.h
@@ -535,6 +535,11 @@ struct ll_convert_impl<TO, FROM>                            \
     TO operator()(const FROM& in) const { return EXPR; }    \
 }
 
+// If all we're doing is copying characters, pass this as EXPR. Since it
+// expands into the 'return EXPR' slot in the ll_convert_impl specialization
+// above, it implies TO{ in.begin(), in.end() }.
+#define LL_CONVERT_COPY_CHARS { in.begin(), in.end() }
+
 // Make the incoming string a utf8 string. Replaces any unknown glyph
 // with the UNKNOWN_CHARACTER. Once any unknown glyph is found, the rest
 // of the data may not be recovered.
@@ -571,30 +576,31 @@ LL_COMMON_API std::string rawstr_to_utf8(const std::string& raw);
 // LL_WCHAR_T_NATIVE.
 typedef std::basic_string<U16> llutf16string;
 
-#if ! defined(LL_WCHAR_T_NATIVE)
-// wchar_t is identical to U16, and std::wstring is identical to llutf16string.
-// Defining an ll_convert alias involving llutf16string would collide with the
-// comparable preferred alias involving std::wstring. (In this scenario, if
-// you pass llutf16string, it will engage the std::wstring specialization.)
-#define ll_convert_u16_alias(TO, FROM, EXPR) // nothing
-#else  // defined(LL_WCHAR_T_NATIVE)
-// wchar_t is a distinct native type, so llutf16string is also a distinct
-// type, and there IS a point to converting separately to/from llutf16string.
-// (But why? Windows APIs are still defined in terms of wchar_t, and
-// in this scenario llutf16string won't work for them!)
-#define ll_convert_u16_alias(TO, FROM, EXPR) ll_convert_alias(TO, FROM, EXPR)
-
-#if LL_WINDOWS
-// LL_WCHAR_T_NATIVE is defined on non-Windows systems because, in fact,
-// wchar_t is native. Everywhere but Windows, we use it for llwchar (see
-// stdtypes.h). That makes LLWString identical to std::wstring, so these
-// aliases for std::wstring would collide with those for LLWString. Only
-// define on Windows, where converting between std::wstring and llutf16string
-// means copying chars.
-ll_convert_alias(llutf16string, std::wstring, llutf16string(in.begin(), in.end()));
-ll_convert_alias(std::wstring, llutf16string,  std::wstring(in.begin(), in.end()));
-#endif // LL_WINDOWS
-#endif // defined(LL_WCHAR_T_NATIVE)
+// Considering wchar_t, llwchar and U16, there are three relevant cases:
+#if LLWCHAR_IS_WCHAR_T         // every which way but Windows
+// llwchar is identical to wchar_t, LLWString is identical to std::wstring.
+// U16 is distinct, llutf16string is distinct (though pretty useless).
+// Given conversions to/from LLWString and to/from llutf16string, conversions
+// involving std::wstring would collide.
+#define ll_convert_wstr_alias(TO, FROM, EXPR) // nothing
+// but we can define conversions involving llutf16string without collisions
+#define  ll_convert_u16_alias(TO, FROM, EXPR) ll_convert_alias(TO, FROM, EXPR)
+
+#elif defined(LL_WCHAR_T_NATIVE)    // Windows, either clang or MS /Zc:wchar_t
+// llwchar (32-bit), wchar_t (16-bit) and U16 are all different types.
+// Conversions to/from LLWString, to/from std::wstring and to/from llutf16string
+// can all be defined.
+#define ll_convert_wstr_alias(TO, FROM, EXPR) ll_convert_alias(TO, FROM, EXPR)
+#define  ll_convert_u16_alias(TO, FROM, EXPR) ll_convert_alias(TO, FROM, EXPR)
+
+#else  // ! LL_WCHAR_T_NATIVE: Windows with MS /Zc:wchar_t-
+// wchar_t is identical to U16, std::wstring is identical to llutf16string.
+// Given conversions to/from LLWString and to/from std::wstring, conversions
+// involving llutf16string would collide.
+#define  ll_convert_u16_alias(TO, FROM, EXPR) // nothing
+// but we can define conversions involving std::wstring without collisions
+#define ll_convert_wstr_alias(TO, FROM, EXPR) ll_convert_alias(TO, FROM, EXPR)
+#endif
 
 LL_COMMON_API LLWString utf16str_to_wstring(const llutf16string &utf16str, S32 len);
 LL_COMMON_API LLWString utf16str_to_wstring(const llutf16string &utf16str);
@@ -625,9 +631,8 @@ LL_COMMON_API std::string utf16str_to_utf8str(const llutf16string &utf16str, S32
 LL_COMMON_API std::string utf16str_to_utf8str(const llutf16string &utf16str);
 ll_convert_u16_alias(std::string, llutf16string, utf16str_to_utf8str(in));
 
-#if LL_WINDOWS
+// an older alias for utf16str_to_utf8str(llutf16string)
 inline std::string wstring_to_utf8str(const llutf16string &utf16str) { return utf16str_to_utf8str(utf16str);}
-#endif
 
 // Length of this UTF32 string in bytes when transformed to UTF8
 LL_COMMON_API S32 wstring_utf8_length(const LLWString& wstr); 
@@ -715,7 +720,7 @@ inline std::string ll_convert_wide_to_string(const std::wstring& in)
 {
     return ll_convert_wide_to_string(in.c_str());
 }
-ll_convert_alias(std::string, std::wstring, ll_convert_wide_to_string(in));
+ll_convert_wstr_alias(std::string, std::wstring, ll_convert_wide_to_string(in));
 
 /**
  * Converts a string to wide string.
@@ -724,19 +729,19 @@ LL_COMMON_API std::wstring ll_convert_string_to_wide(const std::string& in,
                                                      unsigned int code_page);
 LL_COMMON_API std::wstring ll_convert_string_to_wide(const std::string& in);
                                                      // default CP_UTF8
-ll_convert_alias(std::wstring, std::string, ll_convert_string_to_wide(in));
+ll_convert_wstr_alias(std::wstring, std::string, ll_convert_string_to_wide(in));
 
 /**
  * Convert a Windows wide string to our LLWString
  */
 LL_COMMON_API LLWString ll_convert_wide_to_wstring(const std::wstring& in);
-ll_convert_alias(LLWString, std::wstring, ll_convert_wide_to_wstring(in));
+ll_convert_wstr_alias(LLWString, std::wstring, ll_convert_wide_to_wstring(in));
 
 /**
  * Convert LLWString to Windows wide string
  */
 LL_COMMON_API std::wstring ll_convert_wstring_to_wide(const LLWString& in);
-ll_convert_alias(std::wstring, LLWString, ll_convert_wstring_to_wide(in));
+ll_convert_wstr_alias(std::wstring, LLWString, ll_convert_wstring_to_wide(in));
 
 /**
  * Converts incoming string into utf8 string
diff --git a/indra/llcommon/stdtypes.h b/indra/llcommon/stdtypes.h
index 887f6ab733..b07805b628 100644
--- a/indra/llcommon/stdtypes.h
+++ b/indra/llcommon/stdtypes.h
@@ -42,10 +42,17 @@ typedef unsigned int			U32;
 // Windows wchar_t is 16-bit, whichever way /Zc:wchar_t is set. In effect,
 // Windows wchar_t is always a typedef, either for unsigned short or __wchar_t.
 // (__wchar_t, available either way, is Microsoft's native 2-byte wchar_t type.)
+// The version of clang available with VS 2019 also defines wchar_t as __wchar_t
+// which is also 16 bits.
 // In any case, llwchar should be a UTF-32 type.
 typedef U32				llwchar;
 #else
 typedef wchar_t				llwchar;
+// What we'd actually want is a simple module-scope 'if constexpr' to test
+// std::is_same<wchar_t, llwchar>::value and use that to define, or not
+// define, string conversion specializations. Since we don't have that, we'll
+// have to rely on #if instead. Sorry, Dr. Stroustrup.
+#define LLWCHAR_IS_WCHAR_T 1
 #endif
 
 #if LL_WINDOWS
diff --git a/indra/llcommon/stringize.h b/indra/llcommon/stringize.h
index 38dd198ad3..31a114f167 100644
--- a/indra/llcommon/stringize.h
+++ b/indra/llcommon/stringize.h
@@ -52,7 +52,7 @@ std::basic_string<CHARTYPE> gstringize(const T& item)
  */
 inline std::string stringize(const std::wstring& item)
 {
-    return wstring_to_utf8str(item);
+    return ll_convert<std::string>(item);
 }
 
 /**
@@ -72,8 +72,7 @@ inline std::wstring wstringize(const std::string& item)
 {
     // utf8str_to_wstring() returns LLWString, which isn't necessarily the
     // same as std::wstring
-    LLWString s(utf8str_to_wstring(item));
-    return std::wstring(s.begin(), s.end());
+    return ll_convert<std::wstring>(item);
 }
 
 /**
@@ -146,11 +145,9 @@ void destringize_f(std::basic_string<CHARTYPE> const & str, Functor const & f)
  * std::istringstream in(str);
  * in >> item1 >> item2 >> item3 ... ;
  * @endcode
- * @NOTE - once we get generic lambdas, we shouldn't need DEWSTRINGIZE() any
- * more since DESTRINGIZE() should do the right thing with a std::wstring. But
- * until then, the lambda we pass must accept the right std::basic_istream.
  */
-#define DESTRINGIZE(STR, EXPRESSION) (destringize_f((STR), [&](std::istream& in){in >> EXPRESSION;}))
-#define DEWSTRINGIZE(STR, EXPRESSION) (destringize_f((STR), [&](std::wistream& in){in >> EXPRESSION;}))
+#define DESTRINGIZE(STR, EXPRESSION) (destringize_f((STR), [&](auto& in){in >> EXPRESSION;}))
+// legacy name, just use DESTRINGIZE() going forward
+#define DEWSTRINGIZE(STR, EXPRESSION) DESTRINGIZE(STR, EXPRESSION)
 
 #endif /* ! defined(LL_STRINGIZE_H) */
-- 
cgit v1.2.3


From ad91d0fd92bdcb6b4dcd24fda1cdb08d4b9ad97e Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Tue, 26 Oct 2021 22:09:27 -0700
Subject: SL-16127: Make another pass removing redundant LLSD op [] calls,
 unused vars, and use atmospheric already calculated

---
 indra/llinventory/llsettingssky.cpp    |  4 +-
 indra/llinventory/llsettingssky.h      |  2 +-
 indra/newview/lllegacyatmospherics.cpp | 27 +++++-------
 indra/newview/lllegacyatmospherics.h   |  6 +--
 indra/newview/llvosky.cpp              | 63 +++++++++++++-------------
 indra/newview/llvosky.h                | 17 +++----
 indra/newview/llvowlsky.cpp            | 81 ++++++++++++++++------------------
 indra/newview/llvowlsky.h              | 13 +++---
 8 files changed, 102 insertions(+), 111 deletions(-)

(limited to 'indra')

diff --git a/indra/llinventory/llsettingssky.cpp b/indra/llinventory/llsettingssky.cpp
index 82c67a1066..bdcf35faae 100644
--- a/indra/llinventory/llsettingssky.cpp
+++ b/indra/llinventory/llsettingssky.cpp
@@ -1219,9 +1219,9 @@ LLColor3 LLSettingsSky::getLightTransmittanceFast( const LLColor3& total_density
 
 // performs soft scale clip and gamma correction ala the shader implementation
 // scales colors down to 0 - 1 range preserving relative ratios
-LLColor3 LLSettingsSky::gammaCorrect(const LLColor3& in) const
+LLColor3 LLSettingsSky::gammaCorrect(const LLColor3& in,const F32 &gamma) const
 {
-    F32 gamma = getGamma();
+    //F32 gamma = getGamma(); // SL-16127: Use cached gamma from atmospheric vars
 
     LLColor3 v(in);
     // scale down to 0 to 1 range preserving relative ratio (aka homegenize)
diff --git a/indra/llinventory/llsettingssky.h b/indra/llinventory/llsettingssky.h
index 77d9d8e87c..fa9326f006 100644
--- a/indra/llinventory/llsettingssky.h
+++ b/indra/llinventory/llsettingssky.h
@@ -254,7 +254,7 @@ public:
     LLColor3 getLightTransmittance(F32 distance) const;
     LLColor3 getLightTransmittanceFast(const LLColor3& total_density, const F32 density_multiplier, const F32 distance) const;
     LLColor3 getTotalDensity() const;
-    LLColor3 gammaCorrect(const LLColor3& in) const;
+    LLColor3 gammaCorrect(const LLColor3& in,const F32 &gamma) const;
 
     LLColor3 getBlueDensity() const;
     LLColor3 getBlueHorizon() const;
diff --git a/indra/newview/lllegacyatmospherics.cpp b/indra/newview/lllegacyatmospherics.cpp
index 9eda254b25..238e9fe0e1 100644
--- a/indra/newview/lllegacyatmospherics.cpp
+++ b/indra/newview/lllegacyatmospherics.cpp
@@ -202,14 +202,8 @@ void LLAtmospherics::init()
 	mInitialized = true;
 }
 
-LLColor4 LLAtmospherics::calcSkyColorInDir(AtmosphericsVars& vars, const LLVector3 &dir, bool isShiny)
-{
-    LLSettingsSky::ptr_t psky = LLEnvironment::instance().getCurrentSky();
-    return calcSkyColorInDir(psky, vars, dir, isShiny);
-}
-
 // This cubemap is used as "environmentMap" in indra/newview/app_settings/shaders/class2/deferred/softenLightF.glsl
-LLColor4 LLAtmospherics::calcSkyColorInDir(const LLSettingsSky::ptr_t &psky, AtmosphericsVars& vars, const LLVector3 &dir, bool isShiny)
+LLColor4 LLAtmospherics::calcSkyColorInDir(const LLSettingsSky::ptr_t &psky, AtmosphericsVars& vars, const LLVector3 &dir, bool isShiny, bool low_end)
 {
 	const F32 sky_saturation = 0.25f;
 	const F32 land_saturation = 0.1f;
@@ -227,7 +221,7 @@ LLColor4 LLAtmospherics::calcSkyColorInDir(const LLSettingsSky::ptr_t &psky, Atm
 		}
 		F32 greyscale_sat = brightness * (1.0f - land_saturation);
 		desat_fog = desat_fog * land_saturation + smear(greyscale_sat);
-		if (!gPipeline.canUseWindLightShaders())
+		if (low_end)
 		{
 			col = LLColor4(desat_fog, 0.f);
 		}
@@ -258,8 +252,7 @@ LLColor4 LLAtmospherics::calcSkyColorInDir(const LLSettingsSky::ptr_t &psky, Atm
 		return LLColor4(sky_color, 0.0f);
 	}
 
-	bool low_end = !gPipeline.canUseWindLightShaders();
-	LLColor3 sky_color = low_end ? vars.hazeColor * 2.0f : psky->gammaCorrect(vars.hazeColor * 2.0f);
+	LLColor3 sky_color = low_end ? vars.hazeColor * 2.0f : psky->gammaCorrect(vars.hazeColor * 2.0f, vars.gamma);
 
 	return LLColor4(sky_color, 0.0f);
 }
@@ -437,12 +430,16 @@ void LLAtmospherics::updateFog(const F32 distance, const LLVector3& tosun_in)
 
     LLSettingsSky::ptr_t psky = LLEnvironment::instance().getCurrentSky();
 
+    // NOTE: This is very similar to LLVOSky::cacheEnvironment()
+    // Differences:
+    //     vars.sun_norm
+    //     vars.sunlight
     // invariants across whole sky tex process...
-    vars.blue_density = psky->getBlueDensity();    
+    vars.blue_density = psky->getBlueDensity();
     vars.blue_horizon = psky->getBlueHorizon();
     vars.haze_density = psky->getHazeDensity();
     vars.haze_horizon = psky->getHazeHorizon();
-    vars.density_multiplier = psky->getDensityMultiplier();    
+    vars.density_multiplier = psky->getDensityMultiplier();
     vars.distance_multiplier = psky->getDistanceMultiplier();
     vars.max_y = psky->getMaxY();
     vars.sun_norm = LLEnvironment::instance().getSunDirectionCFR();
@@ -457,9 +454,9 @@ void LLAtmospherics::updateFog(const F32 distance, const LLVector3& tosun_in)
     vars.total_density = psky->getTotalDensity();
     vars.gamma = psky->getGamma();
 
-	res_color[0] = calcSkyColorInDir(vars, tosun);
-	res_color[1] = calcSkyColorInDir(vars, perp_tosun);
-	res_color[2] = calcSkyColorInDir(vars, tosun_45);
+    res_color[0] = calcSkyColorInDir(psky, vars, tosun);
+    res_color[1] = calcSkyColorInDir(psky, vars, perp_tosun);
+    res_color[2] = calcSkyColorInDir(psky, vars, tosun_45);
 
 	sky_fog_color = color_norm(res_color[0] + res_color[1] + res_color[2]);
 
diff --git a/indra/newview/lllegacyatmospherics.h b/indra/newview/lllegacyatmospherics.h
index 03c8efb91a..d48f3040c3 100644
--- a/indra/newview/lllegacyatmospherics.h
+++ b/indra/newview/lllegacyatmospherics.h
@@ -257,13 +257,11 @@ public:
     void setCloudDensity(F32 cloud_density)          { mCloudDensity = cloud_density; }
     void setWind ( const LLVector3& wind )           { mWind = wind.length(); }
 
-    LLColor4 calcSkyColorInDir(AtmosphericsVars& vars, const LLVector3& dir, bool isShiny = false);
-    LLColor4 calcSkyColorInDir(const LLSettingsSky::ptr_t &psky, AtmosphericsVars& vars, const LLVector3& dir, bool isShiny = false);
+    LLColor4 calcSkyColorInDir(const LLSettingsSky::ptr_t &psky, AtmosphericsVars& vars, const LLVector3& dir, bool isShiny = false, const bool low_end = false);
 
-protected:    
+protected:
 
     void     calcSkyColorWLVert(const LLSettingsSky::ptr_t &psky, LLVector3 & Pn, AtmosphericsVars& vars);
-    LLColor3 getHazeColor(LLSettingsSky::ptr_t psky, AtmosphericsVars& vars, F32 costheta, F32 cloud_shadow);
 
     LLHaze              mHaze;
     F32                 mHazeConcentration;
diff --git a/indra/newview/llvosky.cpp b/indra/newview/llvosky.cpp
index edf8c40bd3..322e4f110a 100644
--- a/indra/newview/llvosky.cpp
+++ b/indra/newview/llvosky.cpp
@@ -64,7 +64,7 @@ namespace
     const S32 NUM_TILES_X = 8;
     const S32 NUM_TILES_Y = 4;
     const S32 NUM_TILES = NUM_TILES_X * NUM_TILES_Y;
-    const S32 NUM_CUBEMAP_FACES = 6; // See sResolution for face dimensions
+    const S32 NUM_CUBEMAP_FACES = 6; // See SKYTEX_RESOLUTION for face dimensions
     const S32 TOTAL_TILES = NUM_CUBEMAP_FACES * NUM_TILES;
     const S32 MAX_TILES = TOTAL_TILES + 1;
 
@@ -92,8 +92,6 @@ namespace
 		SkyTex
 ***************************************/
 
-S32 LLSkyTex::sComponents = 4;
-S32 LLSkyTex::sResolution = 64;
 S32 LLSkyTex::sCurrent = 0;
 
 
@@ -107,14 +105,14 @@ LLSkyTex::LLSkyTex() :
 void LLSkyTex::init(bool isShiny)
 {
     mIsShiny = isShiny;
-	mSkyData = new LLColor4[sResolution * sResolution];
-	mSkyDirs = new LLVector3[sResolution * sResolution];
+	mSkyData = new LLColor4[SKYTEX_RESOLUTION * SKYTEX_RESOLUTION];
+	mSkyDirs = new LLVector3[SKYTEX_RESOLUTION * SKYTEX_RESOLUTION];
 
 	for (S32 i = 0; i < 2; ++i)
 	{
 		mTexture[i] = LLViewerTextureManager::getLocalTexture(FALSE);
 		mTexture[i]->setAddressMode(LLTexUnit::TAM_CLAMP);
-		mImageRaw[i] = new LLImageRaw(sResolution, sResolution, sComponents);
+		mImageRaw[i] = new LLImageRaw(SKYTEX_RESOLUTION, SKYTEX_RESOLUTION, SKYTEX_COMPONENTS);
 
 		initEmpty(i);
 	}
@@ -146,7 +144,7 @@ LLSkyTex::~LLSkyTex()
 
 S32 LLSkyTex::getResolution()
 {
-    return sResolution;
+    return SKYTEX_RESOLUTION;
 }
 
 S32 LLSkyTex::getCurrent()
@@ -174,12 +172,12 @@ S32 LLSkyTex::getWhich(const BOOL curr)
 void LLSkyTex::initEmpty(const S32 tex)
 {
 	U8* data = mImageRaw[tex]->getData();
-	for (S32 i = 0; i < sResolution; ++i)
+	for (S32 i = 0; i < SKYTEX_RESOLUTION; ++i)
 	{
-		for (S32 j = 0; j < sResolution; ++j)
+		for (S32 j = 0; j < SKYTEX_RESOLUTION; ++j)
 		{
-			const S32 basic_offset = (i * sResolution + j);
-			S32 offset = basic_offset * sComponents;
+			const S32 basic_offset = (i * SKYTEX_RESOLUTION + j);
+			S32 offset = basic_offset * SKYTEX_COMPONENTS;
 			data[offset] = 0;
 			data[offset+1] = 0;
 			data[offset+2] = 0;
@@ -195,12 +193,12 @@ void LLSkyTex::initEmpty(const S32 tex)
 void LLSkyTex::create()
 {
 	U8* data = mImageRaw[sCurrent]->getData();
-	for (S32 i = 0; i < sResolution; ++i)
+	for (S32 i = 0; i < SKYTEX_RESOLUTION; ++i)
 	{
-		for (S32 j = 0; j < sResolution; ++j)
+		for (S32 j = 0; j < SKYTEX_RESOLUTION; ++j)
 		{
-			const S32 basic_offset = (i * sResolution + j);
-			S32 offset = basic_offset * sComponents;
+			const S32 basic_offset = (i * SKYTEX_RESOLUTION + j);
+			S32 offset = basic_offset * SKYTEX_COMPONENTS;
 			U32* pix = (U32*)(data + offset);
 			LLColor4U temp = LLColor4U(mSkyData[basic_offset]);
 			*pix = temp.asRGBA();
@@ -397,10 +395,8 @@ const LLVector3* LLHeavenBody::corners() const
 		Sky
 ***************************************/
 
-
-S32 LLVOSky::sResolution = LLSkyTex::getResolution();
-S32 LLVOSky::sTileResX = sResolution/NUM_TILES_X;
-S32 LLVOSky::sTileResY = sResolution/NUM_TILES_Y;
+const S32 SKYTEX_TILE_RES_X = SKYTEX_RESOLUTION / NUM_TILES_X;
+const S32 SKYTEX_TILE_RES_Y = SKYTEX_RESOLUTION / NUM_TILES_Y;
 
 LLVOSky::LLVOSky(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp)
 :	LLStaticViewerObject(id, pcode, regionp, TRUE),
@@ -495,6 +491,7 @@ void LLVOSky::init()
 
 void LLVOSky::cacheEnvironment(LLSettingsSky::ptr_t psky,AtmosphericsVars& atmosphericsVars)
 {
+    // NOTE: Also see: LLAtmospherics::updateFog()
     // invariants across whole sky tex process...
     atmosphericsVars.blue_density = psky->getBlueDensity();
     atmosphericsVars.blue_horizon = psky->getBlueHorizon();
@@ -602,8 +599,8 @@ void LLVOSky::initSkyTextureDirs(const S32 side, const S32 tile)
 	S32 tile_x = tile % NUM_TILES_X;
 	S32 tile_y = tile / NUM_TILES_X;
 
-	S32 tile_x_pos = tile_x * sTileResX;
-	S32 tile_y_pos = tile_y * sTileResY;
+	S32 tile_x_pos = tile_x * SKYTEX_TILE_RES_X;
+	S32 tile_y_pos = tile_y * SKYTEX_TILE_RES_Y;
 
 	F32 coeff[3] = {0, 0, 0};
 	const S32 curr_coef = side >> 1; // 0/1 = Z axis, 2/3 = Y, 4/5 = X
@@ -613,11 +610,11 @@ void LLVOSky::initSkyTextureDirs(const S32 side, const S32 tile)
 
 	coeff[curr_coef] = (F32)side_dir;
 
-	F32 inv_res = 1.f/sResolution;
+	F32 inv_res = 1.f/SKYTEX_RESOLUTION;
 	S32 x, y;
-	for (y = tile_y_pos; y < (tile_y_pos + sTileResY); ++y)
+	for (y = tile_y_pos; y < (tile_y_pos + SKYTEX_TILE_RES_Y); ++y)
 	{
-		for (x = tile_x_pos; x < (tile_x_pos + sTileResX); ++x)
+		for (x = tile_x_pos; x < (tile_x_pos + SKYTEX_TILE_RES_X); ++x)
 		{
 			coeff[x_coef] = F32((x<<1) + 1) * inv_res - 1.f;
 			coeff[y_coef] = F32((y<<1) + 1) * inv_res - 1.f;
@@ -629,21 +626,23 @@ void LLVOSky::initSkyTextureDirs(const S32 side, const S32 tile)
 	}
 }
 
-void LLVOSky::createSkyTexture(LLSettingsSky::ptr_t psky, AtmosphericsVars& vars, const S32 side, const S32 tile)
+void LLVOSky::createSkyTexture(const LLSettingsSky::ptr_t &psky, AtmosphericsVars& vars, const S32 side, const S32 tile)
 {
+    const bool low_end = !gPipeline.canUseWindLightShaders();
+
 	S32 tile_x = tile % NUM_TILES_X;
 	S32 tile_y = tile / NUM_TILES_X;
 
-	S32 tile_x_pos = tile_x * sTileResX;
-	S32 tile_y_pos = tile_y * sTileResY;
+	S32 tile_x_pos = tile_x * SKYTEX_TILE_RES_X;
+	S32 tile_y_pos = tile_y * SKYTEX_TILE_RES_Y;
 
 	S32 x, y;
-	for (y = tile_y_pos; y < (tile_y_pos + sTileResY); ++y)
+	for (y = tile_y_pos; y < (tile_y_pos + SKYTEX_TILE_RES_Y); ++y)
 	{
-		for (x = tile_x_pos; x < (tile_x_pos + sTileResX); ++x)
+		for (x = tile_x_pos; x < (tile_x_pos + SKYTEX_TILE_RES_X); ++x)
 		{
-			mSkyTex  [side].setPixel(m_legacyAtmospherics.calcSkyColorInDir(psky, vars, mSkyTex  [side].getDir(x, y), false), x, y);
-			mShinyTex[side].setPixel(m_legacyAtmospherics.calcSkyColorInDir(psky, vars, mShinyTex[side].getDir(x, y), true ), x, y);
+			mSkyTex  [side].setPixel(m_legacyAtmospherics.calcSkyColorInDir(psky, vars, mSkyTex  [side].getDir(x, y), false, low_end), x, y);
+			mShinyTex[side].setPixel(m_legacyAtmospherics.calcSkyColorInDir(psky, vars, mShinyTex[side].getDir(x, y), true , low_end), x, y);
 		}
 	}
 }
@@ -783,7 +782,7 @@ bool LLVOSky::updateSky()
     }
     // run 0 to 5 faces, each face in own frame
     else if (mCubeMapUpdateStage >= 0 && mCubeMapUpdateStage < NUM_CUBEMAP_FACES)
-		{
+	{
         LL_RECORD_BLOCK_TIME(FTM_VOSKY_CREATETEXTURES);
         S32 side = mCubeMapUpdateStage;
         // CPU hungry part, createSkyTexture() is math heavy
diff --git a/indra/newview/llvosky.h b/indra/newview/llvosky.h
index 793dcf4cbf..5941ab6e3b 100644
--- a/indra/newview/llvosky.h
+++ b/indra/newview/llvosky.h
@@ -43,6 +43,9 @@ const F32 HEAVENLY_BODY_DIST	= HORIZON_DIST - 20.f;
 const F32 HEAVENLY_BODY_FACTOR	= 0.1f;
 const F32 HEAVENLY_BODY_SCALE	= HEAVENLY_BODY_DIST * HEAVENLY_BODY_FACTOR;
 
+const F32 SKYTEX_COMPONENTS = 4;
+const F32 SKYTEX_RESOLUTION = 64;
+
 class LLFace;
 class LLHaze;
 
@@ -50,8 +53,6 @@ class LLSkyTex
 {
 	friend class LLVOSky;
 private:
-	static S32		sResolution;
-	static S32		sComponents;
 	LLPointer<LLViewerTexture> mTexture[2];
 	LLPointer<LLImageRaw> mImageRaw[2];
 	LLColor4		*mSkyData;
@@ -82,25 +83,25 @@ protected:
 
 	void setDir(const LLVector3 &dir, const S32 i, const S32 j)
 	{
-		S32 offset = i * sResolution + j;
+		S32 offset = i * SKYTEX_RESOLUTION + j;
 		mSkyDirs[offset] = dir;
 	}
 
 	const LLVector3 &getDir(const S32 i, const S32 j) const
 	{
-		S32 offset = i * sResolution + j;
+		S32 offset = i * SKYTEX_RESOLUTION + j;
 		return mSkyDirs[offset];
 	}
 
 	void setPixel(const LLColor4 &col, const S32 i, const S32 j)
 	{
-		S32 offset = i * sResolution + j;
+		S32 offset = i * SKYTEX_RESOLUTION + j;
 		mSkyData[offset] = col;
 	}
 
 	void setPixel(const LLColor4U &col, const S32 i, const S32 j)
 	{
-		S32 offset = (i * sResolution + j) * sComponents;
+		S32 offset = (i * SKYTEX_RESOLUTION + j) * SKYTEX_COMPONENTS;
 		U32* pix = (U32*) &(mImageRaw[sCurrent]->getData()[offset]);
 		*pix = col.asRGBA();
 	}
@@ -108,7 +109,7 @@ protected:
 	LLColor4U getPixel(const S32 i, const S32 j)
 	{
 		LLColor4U col;
-		S32 offset = (i * sResolution + j) * sComponents;
+		S32 offset = (i * SKYTEX_RESOLUTION + j) * SKYTEX_COMPONENTS;
 		U32* pix = (U32*) &(mImageRaw[sCurrent]->getData()[offset]);
 		col.fromRGBA( *pix );
 		return col;
@@ -300,7 +301,7 @@ protected:
 	void updateDirections(LLSettingsSky::ptr_t psky);
 
 	void initSkyTextureDirs(const S32 side, const S32 tile);
-	void createSkyTexture(LLSettingsSky::ptr_t psky, AtmosphericsVars& vars, const S32 side, const S32 tile);
+	void createSkyTexture(const LLSettingsSky::ptr_t &psky, AtmosphericsVars& vars, const S32 side, const S32 tile);
 
 	LLPointer<LLViewerFetchedTexture> mSunTexturep[2];
 	LLPointer<LLViewerFetchedTexture> mMoonTexturep[2];
diff --git a/indra/newview/llvowlsky.cpp b/indra/newview/llvowlsky.cpp
index d428cb1568..e292c4b8d8 100644
--- a/indra/newview/llvowlsky.cpp
+++ b/indra/newview/llvowlsky.cpp
@@ -36,8 +36,8 @@
 #include "llenvironment.h"
 #include "llsettingssky.h"
 
-static const U32 MIN_SKY_DETAIL = 8;
-static const U32 MAX_SKY_DETAIL = 180;
+constexpr U32 MIN_SKY_DETAIL = 8;
+constexpr U32 MAX_SKY_DETAIL = 180;
 
 inline U32 LLVOWLSky::getNumStacks(void)
 {
@@ -97,13 +97,14 @@ LLDrawable * LLVOWLSky::createDrawable(LLPipeline * pipeline)
 	return mDrawable;
 }
 
-inline F32 LLVOWLSky::calcPhi(U32 i)
+// a tiny helper function for controlling the sky dome tesselation.
+inline F32 calcPhi(const U32 &i, const F32 &reciprocal_num_stacks)
 {
     // Calc: PI/8 * 1-((1-t^4)*(1-t^4))  { 0<t<1 }
     // Demos: \pi/8*\left(1-((1-x^{4})*(1-x^{4}))\right)\ \left\{0<x\le1\right\}
 
 	// i should range from [0..SKY_STACKS] so t will range from [0.f .. 1.f]
-	F32 t = float(i) / float(getNumStacks());
+	F32 t = float(i) * reciprocal_num_stacks; //SL-16127: remove: / float(getNumStacks());
 
 	// ^4 the parameter of the tesselation to bias things toward 0 (the dome's apex)
 	t *= t;
@@ -189,6 +190,8 @@ BOOL LLVOWLSky::updateGeometry(LLDrawable * drawable)
     }
 
 	{
+        const F32 dome_radius = LLEnvironment::instance().getCurrentSky()->getDomeRadius();
+
 		const U32 max_buffer_bytes = gSavedSettings.getS32("RenderMaxVBOSize")*1024;
 		const U32 data_mask = LLDrawPoolWLSky::SKY_VERTEX_DATA_MASK;
 		const U32 max_verts = max_buffer_bytes / LLVertexBuffer::calcVertexSize(data_mask);
@@ -204,12 +207,14 @@ BOOL LLVOWLSky::updateGeometry(LLDrawable * drawable)
 		// round up to a whole number of segments
 		const U32 strips_segments = (total_stacks+stacks_per_seg-1) / stacks_per_seg;
 
-		LL_INFOS() << "WL Skydome strips in " << strips_segments << " batches." << LL_ENDL;
-
 		mStripsVerts.resize(strips_segments, NULL);
 
+#if RELEASE_SHOW_DEBUG
+		LL_INFOS() << "WL Skydome strips in " << strips_segments << " batches." << LL_ENDL;
+
 		LLTimer timer;
 		timer.start();
+#endif
 
 		for (U32 i = 0; i < strips_segments ;++i)
 		{
@@ -234,34 +239,42 @@ BOOL LLVOWLSky::updateGeometry(LLDrawable * drawable)
 			const U32 num_indices_this_seg = 1+num_stacks_this_seg*(2+2*verts_per_stack);
 			llassert(num_indices_this_seg * sizeof(U16) <= max_buffer_bytes);
 
-			if (!segment->allocateBuffer(num_verts_this_seg, num_indices_this_seg, TRUE))
+			bool allocated = segment->allocateBuffer(num_verts_this_seg, num_indices_this_seg, TRUE);
+#if RELEASE_SHOW_WARNS
+			if( !allocated )
 			{
 				LL_WARNS() << "Failed to allocate Vertex Buffer on update to "
 					<< num_verts_this_seg << " vertices and "
 					<< num_indices_this_seg << " indices" << LL_ENDL;
 			}
+#else
+			(void) allocated;
+#endif
 
 			// lock the buffer
 			BOOL success = segment->getVertexStrider(vertices)
 				&& segment->getTexCoord0Strider(texCoords)
 				&& segment->getIndexStrider(indices);
 
-			if(!success) 
+#if RELEASE_SHOW_DEBUG
+			if(!success)
 			{
 				LL_ERRS() << "Failed updating WindLight sky geometry." << LL_ENDL;
 			}
-
-            U32 vertex_count = 0;
-            U32 index_count  = 0;
+#else
+			(void) success;
+#endif
 
 			// fill it
-			buildStripsBuffer(begin_stack, end_stack, vertex_count, index_count, vertices, texCoords, indices);
+			buildStripsBuffer(begin_stack, end_stack, vertices, texCoords, indices, dome_radius, verts_per_stack, total_stacks);
 
 			// and unlock the buffer
 			segment->flush();
 		}
 	
+#if RELEASE_SHOW_DEBUG
 		LL_INFOS() << "completed in " << llformat("%.2f", timer.getElapsedTimeF32().value()) << "seconds" << LL_ENDL;
+#endif
 	}
 
 	updateStarColors();
@@ -366,23 +379,16 @@ void LLVOWLSky::initStars()
 
 void LLVOWLSky::buildStripsBuffer(U32 begin_stack,
                                   U32 end_stack,
-                                  U32& vertex_count,
-                                  U32& index_count,
-								  LLStrider<LLVector3> & vertices,
-								  LLStrider<LLVector2> & texCoords,
-								  LLStrider<U16> & indices)
+                                  LLStrider<LLVector3> & vertices,
+                                  LLStrider<LLVector2> & texCoords,
+                                  LLStrider<U16> & indices,
+                                  const F32 dome_radius,
+                                  const U32& num_slices,
+                                  const U32& num_stacks)
 {
-    const F32 RADIUS = LLEnvironment::instance().getCurrentSky()->getDomeRadius();
-
-	U32 i, j, num_slices, num_stacks;
+	U32 i, j;
 	F32 phi0, theta, x0, y0, z0;
-
-	// paranoia checking for SL-55986/SL-55833
-	U32 count_verts = 0;
-	U32 count_indices = 0;
-
-	num_slices = getNumSlices();
-	num_stacks = getNumStacks();
+	const F32 reciprocal_num_stacks = 1.f / num_stacks;
 
 	llassert(end_stack <= num_stacks);
 
@@ -393,7 +399,7 @@ void LLVOWLSky::buildStripsBuffer(U32 begin_stack,
     for(i = begin_stack + 1; i <= end_stack+1; ++i) 
 #endif
 	{
-		phi0 = calcPhi(i);
+		phi0 = calcPhi(i, reciprocal_num_stacks);
 
 		for(j = 0; j < num_slices; ++j)
 		{
@@ -406,24 +412,22 @@ void LLVOWLSky::buildStripsBuffer(U32 begin_stack,
 			z0 = sin(phi0) * sin(theta);
 
 #if NEW_TESS
-            *vertices++ = LLVector3(x0 * RADIUS, y0 * RADIUS, z0 * RADIUS);
+            *vertices++ = LLVector3(x0 * dome_radius, y0 * dome_radius, z0 * dome_radius);
 #else
             if (i == num_stacks-2)
 			{
-				*vertices++ = LLVector3(x0*RADIUS, y0*RADIUS-1024.f*2.f, z0*RADIUS);
+				*vertices++ = LLVector3(x0*dome_radius, y0*dome_radius-1024.f*2.f, z0*dome_radius);
 			}
 			else if (i == num_stacks-1)
 			{
-				*vertices++ = LLVector3(0, y0*RADIUS-1024.f*2.f, 0);
+				*vertices++ = LLVector3(0, y0*dome_radius-1024.f*2.f, 0);
 			}
 			else
 			{
-				*vertices++		= LLVector3(x0 * RADIUS, y0 * RADIUS, z0 * RADIUS);
+				*vertices++		= LLVector3(x0 * dome_radius, y0 * dome_radius, z0 * dome_radius);
 			}
 #endif
 
-			++count_verts;
-
 			// generate planar uv coordinates
 			// note: x and z are transposed in order for things to animate
 			// correctly in the global coordinate system where +x is east and
@@ -434,12 +438,11 @@ void LLVOWLSky::buildStripsBuffer(U32 begin_stack,
 
 	//build triangle strip...
 	*indices++ = 0 ;
-	count_indices++ ;
+
 	S32 k = 0 ;
 	for(i = 1; i <= end_stack - begin_stack; ++i) 
 	{
 		*indices++ = i * num_slices + k ;
-		count_indices++ ;
 
 		k = (k+1) % num_slices ;
 		for(j = 0; j < num_slices ; ++j) 
@@ -447,8 +450,6 @@ void LLVOWLSky::buildStripsBuffer(U32 begin_stack,
 			*indices++ = (i-1) * num_slices + k ;
 			*indices++ = i * num_slices + k ;
 
-			count_indices += 2 ;
-
 			k = (k+1) % num_slices ;
 		}
 
@@ -458,11 +459,7 @@ void LLVOWLSky::buildStripsBuffer(U32 begin_stack,
 		}
 
 		*indices++ = i * num_slices + k ;
-		count_indices++ ;
 	}
-
-    vertex_count = count_verts;
-    index_count = count_indices;
 }
 
 void LLVOWLSky::updateStarColors()
diff --git a/indra/newview/llvowlsky.h b/indra/newview/llvowlsky.h
index 2b7ebe75dd..3853dd2c70 100644
--- a/indra/newview/llvowlsky.h
+++ b/indra/newview/llvowlsky.h
@@ -55,8 +55,6 @@ public:
 	void restoreGL();
 
 private:
-	// a tiny helper function for controlling the sky dome tesselation.
-	static F32 calcPhi(U32 i);
 
 	// helper function for initializing the stars.
 	void initStars();
@@ -66,11 +64,12 @@ private:
 	// begin_stack is the first stack to be included, end_stack is the first
 	// stack not to be included.
 	static void buildStripsBuffer(U32 begin_stack, U32 end_stack,
-                                  U32& vertex_count,
-                                  U32& index_count,
-								  LLStrider<LLVector3> & vertices,
-								  LLStrider<LLVector2> & texCoords,
-								  LLStrider<U16> & indices);
+                                  LLStrider<LLVector3> & vertices,
+                                  LLStrider<LLVector2> & texCoords,
+                                  LLStrider<U16> & indices,
+                                  const F32 RADIUS,
+                                  const U32& num_slices,
+                                  const U32& num_stacks);
 
 	// helper function for updating the stars colors.
 	void updateStarColors();
-- 
cgit v1.2.3


From 8b16ecb9cfb4917fe38e4e5b0e4f40a23dd4ffbf Mon Sep 17 00:00:00 2001
From: Nat Goodspeed <nat@lindenlab.com>
Date: Wed, 27 Oct 2021 15:31:54 -0400
Subject: SL-16220: Add tests for WorkQueue::waitForResult(), void & non-void.

---
 indra/llcommon/tests/workqueue_test.cpp | 49 +++++++++++++++++++++++++++++++++
 indra/llcommon/workqueue.h              | 38 ++++++++++++-------------
 2 files changed, 68 insertions(+), 19 deletions(-)

(limited to 'indra')

diff --git a/indra/llcommon/tests/workqueue_test.cpp b/indra/llcommon/tests/workqueue_test.cpp
index b69df49d33..bea3ad911b 100644
--- a/indra/llcommon/tests/workqueue_test.cpp
+++ b/indra/llcommon/tests/workqueue_test.cpp
@@ -20,7 +20,10 @@
 // external library headers
 // other Linden headers
 #include "../test/lltut.h"
+#include "../test/catch_and_store_what_in.h"
 #include "llcond.h"
+#include "llcoros.h"
+#include "lleventcoro.h"
 #include "llstring.h"
 #include "stringize.h"
 
@@ -177,4 +180,50 @@ namespace tut
         main.runOne();
         ensure_equals("failed to run both lambdas", observe, "queue;main");
     }
+
+    template<> template<>
+    void object::test<6>()
+    {
+        set_test_name("waitForResult");
+        std::string stored;
+        // Try to call waitForResult() on this thread's main coroutine. It
+        // should throw because the main coroutine must service the queue.
+        auto what{ catch_what<WorkQueue::Error>(
+                [this, &stored](){ stored = queue.waitForResult(
+                        [](){ return "should throw"; }); }) };
+        ensure("lambda should not have run", stored.empty());
+        ensure_not("waitForResult() should have thrown", what.empty());
+        ensure(STRINGIZE("should mention waitForResult: " << what),
+               what.find("waitForResult") != std::string::npos);
+
+        // Call waitForResult() on a coroutine, with a string result.
+        LLCoros::instance().launch(
+            "waitForResult string",
+            [this, &stored]()
+            { stored = queue.waitForResult(
+                    [](){ return "string result"; }); });
+        llcoro::suspend();
+        // Nothing will have happened yet because, even if the coroutine did
+        // run immediately, all it did was to queue the inner lambda on
+        // 'queue'. Service it.
+        queue.runOne();
+        llcoro::suspend();
+        ensure_equals("bad waitForResult return", stored, "string result");
+
+        // Call waitForResult() on a coroutine, with a void callable.
+        stored.clear();
+        bool done = false;
+        LLCoros::instance().launch(
+            "waitForResult void",
+            [this, &stored, &done]()
+            {
+                queue.waitForResult([&stored](){ stored = "ran"; });
+                done = true;
+            });
+        llcoro::suspend();
+        queue.runOne();
+        llcoro::suspend();
+        ensure_equals("didn't run coroutine", stored, "ran");
+        ensure("void waitForResult() didn't return", done);
+    }
 } // namespace tut
diff --git a/indra/llcommon/workqueue.h b/indra/llcommon/workqueue.h
index 42f5d78ba3..7dbc735c6d 100644
--- a/indra/llcommon/workqueue.h
+++ b/indra/llcommon/workqueue.h
@@ -92,6 +92,25 @@ namespace LL
             post(TimePoint::clock::now(), std::move(callable));
         }
 
+        /**
+         * Post work to be run at a specified time to another WorkQueue, which
+         * may or may not still exist and be open. Return true if we were able
+         * to post.
+         */
+        template <typename CALLABLE>
+        static bool postMaybe(weak_t target, const TimePoint& time, CALLABLE&& callable);
+
+        /**
+         * Post work to another WorkQueue, which may or may not still exist
+         * and be open. Return true if we were able to post.
+         */
+        template <typename CALLABLE>
+        static bool postMaybe(weak_t target, CALLABLE&& callable)
+        {
+            return postMaybe(target, TimePoint::clock::now(),
+                             std::forward<CALLABLE>(callable));
+        }
+
         /**
          * Launch a callable returning bool that will trigger repeatedly at
          * specified interval, until the callable returns false.
@@ -136,25 +155,6 @@ namespace LL
                           std::move(callable), std::move(callback));
         }
 
-        /**
-         * Post work to be run at a specified time to another WorkQueue, which
-         * may or may not still exist and be open. Return true if we were able
-         * to post.
-         */
-        template <typename CALLABLE>
-        static bool postMaybe(weak_t target, const TimePoint& time, CALLABLE&& callable);
-
-        /**
-         * Post work to another WorkQueue, which may or may not still exist
-         * and be open. Return true if we were able to post.
-         */
-        template <typename CALLABLE>
-        static bool postMaybe(weak_t target, CALLABLE&& callable)
-        {
-            return postMaybe(target, TimePoint::clock::now(),
-                             std::forward<CALLABLE>(callable));
-        }
-
         /**
          * Post work to another WorkQueue to be run at a specified time,
          * blocking the calling coroutine until then, returning the result to
-- 
cgit v1.2.3


From 8d20480c5f77fe1fab8149d3cda79bdd61e77656 Mon Sep 17 00:00:00 2001
From: Dave Parks <davep@lindenlab.com>
Date: Thu, 28 Oct 2021 18:06:21 +0000
Subject: SL-16148 SL-16244 SL-16270 SL-16253 Remove most BlockTimers, remove
 LLMemTracked, introduce alignas, hook most/all reamining allocs, disable
 synchronous occlusion, and convert frequently accessed LLSingletons to
 LLSimpleton

---
 indra/llappearance/llavatarappearance.cpp          |   2 +-
 indra/llappearance/lldriverparam.h                 | 114 +++----
 indra/llappearance/llpolymorph.cpp                 |   4 +-
 indra/llappearance/llpolymorph.h                   |  29 +-
 indra/llappearance/llpolyskeletaldistortion.cpp    |   4 +-
 indra/llappearance/llpolyskeletaldistortion.h      |  30 +-
 indra/llappearance/lltexlayer.cpp                  |  21 +-
 indra/llappearance/lltexlayerparams.cpp            |   3 +-
 indra/llappearance/lltexlayerparams.h              |  31 +-
 indra/llcharacter/llcharacter.cpp                  |   8 +-
 indra/llcharacter/lleditingmotion.cpp              |   1 +
 indra/llcharacter/llhandmotion.cpp                 |   1 +
 indra/llcharacter/llheadrotmotion.cpp              |   2 +
 indra/llcharacter/llkeyframefallmotion.cpp         |   1 +
 indra/llcharacter/llkeyframemotion.cpp             |   1 +
 indra/llcharacter/llkeyframemotionparam.cpp        |   1 +
 indra/llcharacter/llkeyframewalkmotion.cpp         |   3 +
 indra/llcharacter/llmotioncontroller.cpp           |  10 +-
 indra/llcharacter/lltargetingmotion.cpp            |   1 +
 indra/llcommon/lldate.cpp                          |   6 +-
 indra/llcommon/llfasttimer.cpp                     |  49 +--
 indra/llcommon/llmemory.h                          |  77 +++--
 indra/llcommon/llprofiler.h                        |   8 +-
 indra/llcommon/llsdparam.cpp                       |   2 -
 indra/llcommon/llsdparam.h                         |   3 +-
 indra/llcommon/llsingleton.h                       |  26 ++
 indra/llcommon/llstring.cpp                        |   7 +-
 indra/llcommon/llsys.cpp                           |   4 +-
 indra/llcommon/lltrace.cpp                         |   1 +
 indra/llcommon/lltrace.h                           | 148 +-------
 indra/llcommon/lltraceaccumulators.cpp             |  14 +-
 indra/llcommon/lltraceaccumulators.h               |  19 +-
 indra/llcommon/lltracerecording.cpp                | 109 ++++--
 indra/llcommon/lltracerecording.h                  |  21 ++
 indra/llcommon/lltracethreadrecorder.cpp           |   4 +-
 indra/llimage/llimage.cpp                          |   9 +-
 indra/llimage/llimage.h                            |   3 +-
 indra/llimage/llimagej2c.cpp                       |   1 -
 indra/llimage/llimagejpeg.cpp                      |   8 -
 indra/llimage/tests/llimageworker_test.cpp         |   3 +-
 indra/llinventory/llinventory.cpp                  |  24 +-
 indra/llinventory/llinventory.h                    |   2 +-
 indra/llinventory/llsettingsdaycycle.cpp           |   3 -
 indra/llinventory/llsettingssky.cpp                |   7 +-
 indra/llinventory/llsettingswater.cpp              |   8 -
 indra/llkdu/tests/llimagej2ckdu_test.cpp           |   3 +-
 indra/llmath/lloctree.h                            |  13 +-
 indra/llmath/llrigginginfo.h                       |  29 +-
 indra/llmath/llvector4a.h                          |   6 +-
 indra/llmath/llvolumeoctree.h                      |  27 +-
 indra/llmessage/llfiltersd2xmlrpc.cpp              |  14 +-
 indra/llmessage/llhttpnode.cpp                     |   4 +
 indra/llmessage/lliohttpserver.cpp                 |  20 +-
 indra/llmessage/lliosocket.cpp                     |  10 +-
 indra/llmessage/llioutil.cpp                       |   6 +-
 indra/llmessage/llpumpio.cpp                       |  11 +-
 indra/llmessage/lltemplatemessagereader.cpp        |   9 +-
 indra/llrender/llfontbitmapcache.cpp               |  18 +-
 indra/llrender/llfontbitmapcache.h                 |   2 +-
 indra/llrender/llfontfreetype.cpp                  |   9 +-
 indra/llrender/llfontfreetype.h                    |   2 +-
 indra/llrender/llfontgl.cpp                        |   4 +-
 indra/llrender/llgl.cpp                            |   1 +
 indra/llrender/llimagegl.cpp                       |  43 +--
 indra/llrender/llimagegl.h                         |   2 +-
 indra/llrender/llrender2dutils.cpp                 |   8 +-
 indra/llrender/lltexture.h                         |   3 +-
 indra/llrender/llvertexbuffer.cpp                  |  72 ++--
 indra/llrender/llvertexbuffer.h                    |   5 +-
 indra/llui/llfloater.cpp                           |  17 +-
 indra/llui/llfolderview.cpp                        |  10 +-
 indra/llui/llfolderviewmodel.h                     |   6 +-
 indra/llui/lllayoutstack.cpp                       |   4 +-
 indra/llui/llpanel.cpp                             |   4 +-
 indra/llui/llscrolllistctrl.cpp                    |   7 +-
 indra/llui/lltextbase.cpp                          |  16 +-
 indra/llui/lluictrl.cpp                            |  17 +-
 indra/llui/lluictrlfactory.cpp                     |  15 +-
 indra/llui/lluictrlfactory.h                       |  16 +-
 indra/llui/llview.cpp                              |  13 +-
 indra/llui/llview.h                                |   3 +-
 indra/llui/llviewereventrecorder.cpp               |   2 +
 indra/llui/llviewereventrecorder.h                 |  10 +-
 indra/llui/llviewmodel.cpp                         |  20 +-
 indra/llui/llviewmodel.h                           |   3 +-
 indra/newview/app_settings/settings.xml            |  13 +-
 indra/newview/llappviewer.cpp                      |  28 +-
 .../newview/lldonotdisturbnotificationstorage.cpp  |   4 +-
 indra/newview/lldrawable.cpp                       |  41 +--
 indra/newview/lldrawable.h                         |   9 +-
 indra/newview/lldrawpoolalpha.cpp                  |  19 +-
 indra/newview/lldrawpoolavatar.cpp                 | 378 ++++++++++-----------
 indra/newview/lldrawpoolbump.cpp                   |  28 +-
 indra/newview/lldrawpoolsimple.cpp                 |   9 +-
 indra/newview/lldrawpoolterrain.cpp                |   1 +
 indra/newview/lldrawpooltree.cpp                   |   7 +-
 indra/newview/lldynamictexture.h                   |  10 +-
 indra/newview/llenvironment.cpp                    |   6 +-
 indra/newview/llenvironment.h                      |  11 +-
 indra/newview/llface.cpp                           | 135 ++------
 indra/newview/llface.h                             |   6 +-
 indra/newview/llfasttimerview.cpp                  |  19 +-
 indra/newview/llflexibleobject.cpp                 |  13 +-
 indra/newview/llgroupmgr.cpp                       |  14 +-
 indra/newview/llinventoryfilter.cpp                |   4 +-
 indra/newview/llinventoryitemslist.cpp             |   4 +-
 indra/newview/llinventorypanel.cpp                 |   6 +-
 indra/newview/llmaterialmgr.cpp                    |   4 +-
 indra/newview/llpersistentnotificationstorage.cpp  |   8 +-
 indra/newview/llphysicsmotion.cpp                  |   1 +
 indra/newview/llscenemonitor.cpp                   |  10 -
 indra/newview/llscreenchannel.cpp                  |   3 +-
 indra/newview/llscripteditor.cpp                   |   6 +-
 indra/newview/llselectmgr.cpp                      |   4 +-
 indra/newview/llselectmgr.h                        |   8 +-
 indra/newview/llspatialpartition.cpp               |  70 ++--
 indra/newview/llspatialpartition.h                 |   4 +-
 indra/newview/llviewercamera.cpp                   |   5 +-
 indra/newview/llviewercamera.h                     |  22 +-
 indra/newview/llviewerdisplay.cpp                  |  16 +-
 indra/newview/llviewerjointmesh.cpp                |   6 +-
 indra/newview/llviewermessage.cpp                  |  12 +-
 indra/newview/llviewerobject.cpp                   |  10 +-
 indra/newview/llviewerobject.h                     |   3 +-
 indra/newview/llviewerobjectlist.cpp               |  22 +-
 indra/newview/llvieweroctree.cpp                   |  65 +---
 indra/newview/llvieweroctree.h                     |   7 +-
 indra/newview/llviewertexture.cpp                  |  17 +-
 indra/newview/llviewertexture.h                    |   2 +-
 indra/newview/llviewertexturelist.cpp              |  87 ++---
 indra/newview/llvoavatar.cpp                       |  41 +--
 indra/newview/llvoavatar.h                         |  11 +-
 indra/newview/llvocache.cpp                        |  10 +-
 indra/newview/llvocache.h                          |   6 +-
 indra/newview/llvograss.cpp                        |   4 +-
 indra/newview/llvopartgroup.cpp                    |  12 +-
 indra/newview/llvosky.cpp                          |  19 +-
 indra/newview/llvosurfacepatch.cpp                 |   6 +-
 indra/newview/llvotree.cpp                         |   4 +-
 indra/newview/llvovolume.cpp                       |  92 ++---
 indra/newview/llvowater.cpp                        |   4 +-
 indra/newview/llvowlsky.cpp                        |   4 +-
 indra/newview/llworld.cpp                          |  11 +-
 indra/newview/llworld.h                            |   7 +-
 indra/newview/pipeline.cpp                         | 265 +++++----------
 indra/newview/pipeline.h                           |   3 -
 146 files changed, 1066 insertions(+), 1907 deletions(-)

(limited to 'indra')

diff --git a/indra/llappearance/llavatarappearance.cpp b/indra/llappearance/llavatarappearance.cpp
index 90dfa04f28..2d6d2a10d2 100644
--- a/indra/llappearance/llavatarappearance.cpp
+++ b/indra/llappearance/llavatarappearance.cpp
@@ -1590,7 +1590,7 @@ BOOL LLAvatarAppearance::allocateCollisionVolumes( U32 num )
         delete_and_clear_array(mCollisionVolumes);
         mNumCollisionVolumes = 0;
 
-        mCollisionVolumes = new(std::nothrow) LLAvatarJointCollisionVolume[num];
+        mCollisionVolumes = new LLAvatarJointCollisionVolume[num];
         if (!mCollisionVolumes)
         {
             LL_WARNS() << "Failed to allocate collision volumes" << LL_ENDL;
diff --git a/indra/llappearance/lldriverparam.h b/indra/llappearance/lldriverparam.h
index f278dcc2e2..a6261b507b 100644
--- a/indra/llappearance/lldriverparam.h
+++ b/indra/llappearance/lldriverparam.h
@@ -77,73 +77,63 @@ protected:
 
 //-----------------------------------------------------------------------------
 
-LL_ALIGN_PREFIX(16)
-class LLDriverParam : public LLViewerVisualParam
+class alignas(16) LLDriverParam : public LLViewerVisualParam
 {
+    LL_ALIGN_NEW
 private:
-	// Hide the default constructor.  Force construction with LLAvatarAppearance.
-	LLDriverParam() {}
+    // Hide the default constructor.  Force construction with LLAvatarAppearance.
+    LLDriverParam() {}
 public:
-	LLDriverParam(LLAvatarAppearance *appearance, LLWearable* wearable = NULL);
-	~LLDriverParam();
-
-	void* operator new(size_t size)
-	{
-		return ll_aligned_malloc_16(size);
-	}
-
-	void operator delete(void* ptr)
-	{
-		ll_aligned_free_16(ptr);
-	}
-
-	// Special: These functions are overridden by child classes
-	LLDriverParamInfo*		getInfo() const { return (LLDriverParamInfo*)mInfo; }
-	//   This sets mInfo and calls initialization functions
-	BOOL					setInfo(LLDriverParamInfo *info);
-
-	LLAvatarAppearance* getAvatarAppearance() { return mAvatarAppearance; }
-	const LLAvatarAppearance* getAvatarAppearance() const { return mAvatarAppearance; }
-
-	void					updateCrossDrivenParams(LLWearableType::EType driven_type);
-
-	/*virtual*/ LLViewerVisualParam* cloneParam(LLWearable* wearable) const;
-
-	// LLVisualParam Virtual functions
-	/*virtual*/ void				apply( ESex sex ) {} // apply is called separately for each driven param.
-	/*virtual*/ void				setWeight(F32 weight);
-	/*virtual*/ void				setAnimationTarget( F32 target_value);
-	/*virtual*/ void				stopAnimating();
-	/*virtual*/ BOOL				linkDrivenParams(visual_param_mapper mapper, BOOL only_cross_params);
-	/*virtual*/ void				resetDrivenParams();
-	
-	// LLViewerVisualParam Virtual functions
-	/*virtual*/ F32					getTotalDistortion();
-	/*virtual*/ const LLVector4a&	getAvgDistortion();
-	/*virtual*/ F32					getMaxDistortion();
-	/*virtual*/ LLVector4a			getVertexDistortion(S32 index, LLPolyMesh *poly_mesh);
-	/*virtual*/ const LLVector4a*	getFirstDistortion(U32 *index, LLPolyMesh **poly_mesh);
-	/*virtual*/ const LLVector4a*	getNextDistortion(U32 *index, LLPolyMesh **poly_mesh);
-
-	S32								getDrivenParamsCount() const;
-	const LLViewerVisualParam*		getDrivenParam(S32 index) const;
-
-	typedef std::vector<LLDrivenEntry> entry_list_t;
-    entry_list_t&                   getDrivenList() { return mDriven; }
+    LLDriverParam(LLAvatarAppearance* appearance, LLWearable* wearable = NULL);
+    ~LLDriverParam();
+
+    // Special: These functions are overridden by child classes
+    LLDriverParamInfo* getInfo() const { return (LLDriverParamInfo*)mInfo; }
+    //   This sets mInfo and calls initialization functions
+    BOOL					setInfo(LLDriverParamInfo* info);
+
+    LLAvatarAppearance* getAvatarAppearance() { return mAvatarAppearance; }
+    const LLAvatarAppearance* getAvatarAppearance() const { return mAvatarAppearance; }
+
+    void					updateCrossDrivenParams(LLWearableType::EType driven_type);
+
+    /*virtual*/ LLViewerVisualParam* cloneParam(LLWearable* wearable) const;
+
+    // LLVisualParam Virtual functions
+    /*virtual*/ void				apply(ESex sex) {} // apply is called separately for each driven param.
+    /*virtual*/ void				setWeight(F32 weight);
+    /*virtual*/ void				setAnimationTarget(F32 target_value);
+    /*virtual*/ void				stopAnimating();
+    /*virtual*/ BOOL				linkDrivenParams(visual_param_mapper mapper, BOOL only_cross_params);
+    /*virtual*/ void				resetDrivenParams();
+
+    // LLViewerVisualParam Virtual functions
+    /*virtual*/ F32					getTotalDistortion();
+    /*virtual*/ const LLVector4a& getAvgDistortion();
+    /*virtual*/ F32					getMaxDistortion();
+    /*virtual*/ LLVector4a			getVertexDistortion(S32 index, LLPolyMesh* poly_mesh);
+    /*virtual*/ const LLVector4a* getFirstDistortion(U32* index, LLPolyMesh** poly_mesh);
+    /*virtual*/ const LLVector4a* getNextDistortion(U32* index, LLPolyMesh** poly_mesh);
+
+    S32								getDrivenParamsCount() const;
+    const LLViewerVisualParam* getDrivenParam(S32 index) const;
+
+    typedef std::vector<LLDrivenEntry> entry_list_t;
+    entry_list_t& getDrivenList() { return mDriven; }
     void                            setDrivenList(entry_list_t& driven_list) { mDriven = driven_list; }
 
 protected:
-	LLDriverParam(const LLDriverParam& pOther);
-	F32 getDrivenWeight(const LLDrivenEntry* driven, F32 input_weight);
-	void setDrivenWeight(LLDrivenEntry *driven, F32 driven_weight);
-
-
-	LL_ALIGN_16(LLVector4a	mDefaultVec); // temp holder
-	entry_list_t mDriven;
-	LLViewerVisualParam* mCurrentDistortionParam;
-	// Backlink only; don't make this an LLPointer.
-	LLAvatarAppearance* mAvatarAppearance;
-	LLWearable* mWearablep;
-} LL_ALIGN_POSTFIX(16);
+    LLDriverParam(const LLDriverParam& pOther);
+    F32 getDrivenWeight(const LLDrivenEntry* driven, F32 input_weight);
+    void setDrivenWeight(LLDrivenEntry* driven, F32 driven_weight);
+
+
+    LL_ALIGN_16(LLVector4a	mDefaultVec); // temp holder
+    entry_list_t mDriven;
+    LLViewerVisualParam* mCurrentDistortionParam;
+    // Backlink only; don't make this an LLPointer.
+    LLAvatarAppearance* mAvatarAppearance;
+    LLWearable* mWearablep;
+};
 
 #endif  // LL_LLDRIVERPARAM_H
diff --git a/indra/llappearance/llpolymorph.cpp b/indra/llappearance/llpolymorph.cpp
index ce7010984a..16b5f1e204 100644
--- a/indra/llappearance/llpolymorph.cpp
+++ b/indra/llappearance/llpolymorph.cpp
@@ -539,8 +539,6 @@ F32	LLPolyMorphTarget::getMaxDistortion()
 //-----------------------------------------------------------------------------
 // apply()
 //-----------------------------------------------------------------------------
-static LLTrace::BlockTimerStatHandle FTM_APPLY_MORPH_TARGET("Apply Morph");
-
 void LLPolyMorphTarget::apply( ESex avatar_sex )
 {
 	if (!mMorphData || mNumMorphMasksPending > 0)
@@ -548,7 +546,7 @@ void LLPolyMorphTarget::apply( ESex avatar_sex )
 		return;
 	}
 
-	LL_RECORD_BLOCK_TIME(FTM_APPLY_MORPH_TARGET);
+    LL_PROFILE_ZONE_SCOPED;
 
 	mLastSex = avatar_sex;
 
diff --git a/indra/llappearance/llpolymorph.h b/indra/llappearance/llpolymorph.h
index c6133cd831..29cd373636 100644
--- a/indra/llappearance/llpolymorph.h
+++ b/indra/llappearance/llpolymorph.h
@@ -41,24 +41,14 @@ class LLWearable;
 //-----------------------------------------------------------------------------
 // LLPolyMorphData()
 //-----------------------------------------------------------------------------
-LL_ALIGN_PREFIX(16)
-class LLPolyMorphData
+class alignas(16) LLPolyMorphData
 {
+    LL_ALIGN_NEW
 public:
 	LLPolyMorphData(const std::string& morph_name);
 	~LLPolyMorphData();
 	LLPolyMorphData(const LLPolyMorphData &rhs);
 
-	void* operator new(size_t size)
-	{
-		return ll_aligned_malloc_16(size);
-	}
-
-	void operator delete(void* ptr)
-	{
-		ll_aligned_free_16(ptr);
-	}
-
 	BOOL			loadBinary(LLFILE* fp, LLPolyMeshSharedData *mesh);
 	const std::string& getName() { return mName; }
 
@@ -76,7 +66,7 @@ public:
 
 	F32					mTotalDistortion;	// vertex distortion summed over entire morph
 	F32					mMaxDistortion;		// maximum single vertex distortion in a given morph
-	LL_ALIGN_16(LLVector4a			mAvgDistortion);		// average vertex distortion, to infer directionality of the morph
+	LLVector4a			mAvgDistortion;		// average vertex distortion, to infer directionality of the morph
 	LLPolyMeshSharedData*	mMesh;
 
 private:
@@ -154,8 +144,9 @@ protected:
 // These morph targets must be topologically consistent with a given Polymesh
 // (share face sets)
 //-----------------------------------------------------------------------------
-class LLPolyMorphTarget : public LLViewerVisualParam
+class alignas(16) LLPolyMorphTarget : public LLViewerVisualParam
 {
+    LL_ALIGN_NEW
 public:
 	LLPolyMorphTarget(LLPolyMesh *poly_mesh);
 	~LLPolyMorphTarget();
@@ -184,16 +175,6 @@ public:
 
     void    applyVolumeChanges(F32 delta_weight); // SL-315 - for resetSkeleton()
 
-	void* operator new(size_t size)
-	{
-		return ll_aligned_malloc_16(size);
-	}
-
-	void operator delete(void* ptr)
-	{
-		ll_aligned_free_16(ptr);
-	}
-
 protected:
 	LLPolyMorphTarget(const LLPolyMorphTarget& pOther);
 
diff --git a/indra/llappearance/llpolyskeletaldistortion.cpp b/indra/llappearance/llpolyskeletaldistortion.cpp
index ae38c25dbf..360f17508f 100644
--- a/indra/llappearance/llpolyskeletaldistortion.cpp
+++ b/indra/llappearance/llpolyskeletaldistortion.cpp
@@ -188,11 +188,9 @@ BOOL LLPolySkeletalDistortion::setInfo(LLPolySkeletalDistortionInfo *info)
 //-----------------------------------------------------------------------------
 // apply()
 //-----------------------------------------------------------------------------
-static LLTrace::BlockTimerStatHandle FTM_POLYSKELETAL_DISTORTION_APPLY("Skeletal Distortion");
-
 void LLPolySkeletalDistortion::apply( ESex avatar_sex )
 {
-    LL_RECORD_BLOCK_TIME(FTM_POLYSKELETAL_DISTORTION_APPLY);
+    LL_PROFILE_ZONE_SCOPED;
 
     F32 effective_weight = ( getSex() & avatar_sex ) ? mCurWeight : getDefaultWeight();
 
diff --git a/indra/llappearance/llpolyskeletaldistortion.h b/indra/llappearance/llpolyskeletaldistortion.h
index ab1a132d19..585d85f055 100644
--- a/indra/llappearance/llpolyskeletaldistortion.h
+++ b/indra/llappearance/llpolyskeletaldistortion.h
@@ -62,9 +62,9 @@ struct LLPolySkeletalBoneInfo
 	BOOL mHasPositionDeformation;
 };
 
-LL_ALIGN_PREFIX(16)
-class LLPolySkeletalDistortionInfo : public LLViewerVisualParamInfo
+class alignas(16) LLPolySkeletalDistortionInfo : public LLViewerVisualParamInfo
 {
+    LL_ALIGN_NEW
 	friend class LLPolySkeletalDistortion;
 public:
 	
@@ -73,19 +73,6 @@ public:
 	
 	/*virtual*/ BOOL parseXml(LLXmlTreeNode* node);
 
-
-
-	void* operator new(size_t size)
-	{
-		return ll_aligned_malloc_16(size);
-	}
-
-	void operator delete(void* ptr)
-	{
-		ll_aligned_free_16(ptr);
-	}
-
-
 protected:
 	typedef std::vector<LLPolySkeletalBoneInfo> bone_info_list_t;
 	bone_info_list_t mBoneInfoList;
@@ -95,19 +82,10 @@ protected:
 // LLPolySkeletalDeformation
 // A set of joint scale data for deforming the avatar mesh
 //-----------------------------------------------------------------------------
-class LLPolySkeletalDistortion : public LLViewerVisualParam
+class alignas(16) LLPolySkeletalDistortion : public LLViewerVisualParam
 {
+    LL_ALIGN_NEW
 public:
-	void* operator new(size_t size)
-	{
-		return ll_aligned_malloc_16(size);
-	}
-
-	void operator delete(void* ptr)
-	{
-		ll_aligned_free_16(ptr);
-	}
-
 	LLPolySkeletalDistortion(LLAvatarAppearance *avatarp);
 	~LLPolySkeletalDistortion();
 
diff --git a/indra/llappearance/lltexlayer.cpp b/indra/llappearance/lltexlayer.cpp
index e5039141de..26e0ae9086 100644
--- a/indra/llappearance/lltexlayer.cpp
+++ b/indra/llappearance/lltexlayer.cpp
@@ -522,10 +522,9 @@ const LLTexLayerSetBuffer* LLTexLayerSet::getComposite() const
 	return mComposite;
 }
 
-static LLTrace::BlockTimerStatHandle FTM_GATHER_MORPH_MASK_ALPHA("gatherMorphMaskAlpha");
 void LLTexLayerSet::gatherMorphMaskAlpha(U8 *data, S32 origin_x, S32 origin_y, S32 width, S32 height, LLRenderTarget* bound_target)
 {
-	LL_RECORD_BLOCK_TIME(FTM_GATHER_MORPH_MASK_ALPHA);
+    LL_PROFILE_ZONE_SCOPED;
 	memset(data, 255, width * height);
 
 	for( layer_list_t::iterator iter = mLayerList.begin(); iter != mLayerList.end(); iter++ )
@@ -538,10 +537,9 @@ void LLTexLayerSet::gatherMorphMaskAlpha(U8 *data, S32 origin_x, S32 origin_y, S
 	renderAlphaMaskTextures(origin_x, origin_y, width, height, bound_target, true);
 }
 
-static LLTrace::BlockTimerStatHandle FTM_RENDER_ALPHA_MASK_TEXTURES("renderAlphaMaskTextures");
 void LLTexLayerSet::renderAlphaMaskTextures(S32 x, S32 y, S32 width, S32 height, LLRenderTarget* bound_target, bool forceClear)
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_MASK_TEXTURES);
+    LL_PROFILE_ZONE_SCOPED;
 	const LLTexLayerSetInfo *info = getInfo();
 	
 	bool use_shaders = LLGLSLShader::sNoFixedFunction;
@@ -1433,7 +1431,6 @@ BOOL LLTexLayer::blendAlphaTexture(S32 x, S32 y, S32 width, S32 height)
 	addAlphaMask(data, originX, originY, width, height, bound_target);
 }
 
-static LLTrace::BlockTimerStatHandle FTM_RENDER_MORPH_MASKS("renderMorphMasks");
 void LLTexLayer::renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLColor4 &layer_color, LLRenderTarget* bound_target, bool force_render)
 {
 	if (!force_render && !hasMorph())
@@ -1441,7 +1438,7 @@ void LLTexLayer::renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLC
 		LL_DEBUGS() << "skipping renderMorphMasks for " << getUUID() << LL_ENDL;
 		return;
 	}
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_MORPH_MASKS);
+    LL_PROFILE_ZONE_SCOPED;
 	BOOL success = TRUE;
 
 	llassert( !mParamAlphaList.empty() );
@@ -1639,10 +1636,9 @@ void LLTexLayer::renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLC
 	}
 }
 
-static LLTrace::BlockTimerStatHandle FTM_ADD_ALPHA_MASK("addAlphaMask");
 void LLTexLayer::addAlphaMask(U8 *data, S32 originX, S32 originY, S32 width, S32 height, LLRenderTarget* bound_target)
 {
-	LL_RECORD_BLOCK_TIME(FTM_ADD_ALPHA_MASK);
+    LL_PROFILE_ZONE_SCOPED;
 	S32 size = width * height;
 	const U8* alphaData = getAlphaData();
 	if (!alphaData && hasAlphaParams())
@@ -1983,10 +1979,9 @@ void LLTexLayerStaticImageList::deleteCachedImages()
 
 // Returns an LLImageTGA that contains the encoded data from a tga file named file_name.
 // Caches the result to speed identical subsequent requests.
-static LLTrace::BlockTimerStatHandle FTM_LOAD_STATIC_TGA("getImageTGA");
 LLImageTGA* LLTexLayerStaticImageList::getImageTGA(const std::string& file_name)
 {
-	LL_RECORD_BLOCK_TIME(FTM_LOAD_STATIC_TGA);
+    LL_PROFILE_ZONE_SCOPED;
 	const char *namekey = mImageNames.addString(file_name);
 	image_tga_map_t::const_iterator iter = mStaticImageListTGA.find(namekey);
 	if( iter != mStaticImageListTGA.end() )
@@ -2013,10 +2008,9 @@ LLImageTGA* LLTexLayerStaticImageList::getImageTGA(const std::string& file_name)
 
 // Returns a GL Image (without a backing ImageRaw) that contains the decoded data from a tga file named file_name.
 // Caches the result to speed identical subsequent requests.
-static LLTrace::BlockTimerStatHandle FTM_LOAD_STATIC_TEXTURE("getTexture");
 LLGLTexture* LLTexLayerStaticImageList::getTexture(const std::string& file_name, BOOL is_mask)
 {
-	LL_RECORD_BLOCK_TIME(FTM_LOAD_STATIC_TEXTURE);
+    LL_PROFILE_ZONE_SCOPED;
 	LLPointer<LLGLTexture> tex;
 	const char *namekey = mImageNames.addString(file_name);
 
@@ -2063,10 +2057,9 @@ LLGLTexture* LLTexLayerStaticImageList::getTexture(const std::string& file_name,
 
 // Reads a .tga file, decodes it, and puts the decoded data in image_raw.
 // Returns TRUE if successful.
-static LLTrace::BlockTimerStatHandle FTM_LOAD_IMAGE_RAW("loadImageRaw");
 BOOL LLTexLayerStaticImageList::loadImageRaw(const std::string& file_name, LLImageRaw* image_raw)
 {
-	LL_RECORD_BLOCK_TIME(FTM_LOAD_IMAGE_RAW);
+    LL_PROFILE_ZONE_SCOPED;
 	BOOL success = FALSE;
 	std::string path;
 	path = gDirUtilp->getExpandedFilename(LL_PATH_CHARACTER,file_name);
diff --git a/indra/llappearance/lltexlayerparams.cpp b/indra/llappearance/lltexlayerparams.cpp
index ff682d6906..ce5c7142d5 100644
--- a/indra/llappearance/lltexlayerparams.cpp
+++ b/indra/llappearance/lltexlayerparams.cpp
@@ -261,10 +261,9 @@ BOOL LLTexLayerParamAlpha::getSkip() const
 }
 
 
-static LLTrace::BlockTimerStatHandle FTM_TEX_LAYER_PARAM_ALPHA("alpha render");
 BOOL LLTexLayerParamAlpha::render(S32 x, S32 y, S32 width, S32 height)
 {
-	LL_RECORD_BLOCK_TIME(FTM_TEX_LAYER_PARAM_ALPHA);
+    LL_PROFILE_ZONE_SCOPED;
 	BOOL success = TRUE;
 
 	if (!mTexLayer)
diff --git a/indra/llappearance/lltexlayerparams.h b/indra/llappearance/lltexlayerparams.h
index 0cb2dedbff..e2440998b3 100644
--- a/indra/llappearance/lltexlayerparams.h
+++ b/indra/llappearance/lltexlayerparams.h
@@ -63,23 +63,14 @@ protected:
 // 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 LL_ALIGN_PREFIX(16)
-class LLTexLayerParamAlpha : public LLTexLayerParam
+class alignas(16) LLTexLayerParamAlpha : public LLTexLayerParam
 {
+    LL_ALIGN_NEW
 public:
 	LLTexLayerParamAlpha( LLTexLayerInterface* layer );
 	LLTexLayerParamAlpha( LLAvatarAppearance* appearance );
 	/*virtual*/ ~LLTexLayerParamAlpha();
 
-	void* operator new(size_t size)
-	{
-		return ll_aligned_malloc_16(size);
-	}
-
-	void operator delete(void* ptr)
-	{
-		ll_aligned_free_16(ptr);
-	}
-
 	/*virtual*/ LLViewerVisualParam* cloneParam(LLWearable* wearable = NULL) const;
 
 	// LLVisualParam Virtual functions
@@ -146,9 +137,9 @@ private:
 //
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-LL_ALIGN_PREFIX(16)
-class LLTexLayerParamColor : public LLTexLayerParam
+class alignas(16) LLTexLayerParamColor : public LLTexLayerParam
 {
+    LL_ALIGN_NEW
 public:
 	enum EColorOperation
 	{
@@ -161,16 +152,6 @@ public:
 	LLTexLayerParamColor( LLTexLayerInterface* layer );
 	LLTexLayerParamColor( LLAvatarAppearance* appearance );
 
-	void* operator new(size_t size)
-	{
-		return ll_aligned_malloc_16(size);
-	}
-
-	void operator delete(void* ptr)
-	{
-		ll_aligned_free_16(ptr);
-	}
-
 	/* virtual */ ~LLTexLayerParamColor();
 
 	/*virtual*/ LLViewerVisualParam* cloneParam(LLWearable* wearable = NULL) const;
@@ -198,8 +179,8 @@ protected:
 
 	virtual void onGlobalColorChanged() {}
 private:
-	LL_ALIGN_16(LLVector4a				mAvgDistortionVec);
-} LL_ALIGN_POSTFIX(16);
+	LLVector4a				mAvgDistortionVec;
+};
 
 class LLTexLayerParamColorInfo : public LLViewerVisualParamInfo
 {
diff --git a/indra/llcharacter/llcharacter.cpp b/indra/llcharacter/llcharacter.cpp
index b764ef0c7e..8874df32f5 100644
--- a/indra/llcharacter/llcharacter.cpp
+++ b/indra/llcharacter/llcharacter.cpp
@@ -188,20 +188,15 @@ void LLCharacter::requestStopMotion( LLMotion* motion)
 //-----------------------------------------------------------------------------
 // updateMotions()
 //-----------------------------------------------------------------------------
-static LLTrace::BlockTimerStatHandle FTM_UPDATE_ANIMATION("Update Animation");
-static LLTrace::BlockTimerStatHandle FTM_UPDATE_HIDDEN_ANIMATION("Update Hidden Anim");
-static LLTrace::BlockTimerStatHandle FTM_UPDATE_MOTIONS("Update Motions");
-
 void LLCharacter::updateMotions(e_update_t update_type)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	if (update_type == HIDDEN_UPDATE)
 	{
-		LL_RECORD_BLOCK_TIME(FTM_UPDATE_HIDDEN_ANIMATION);
 		mMotionController.updateMotionsMinimal();
 	}
 	else
 	{
-		LL_RECORD_BLOCK_TIME(FTM_UPDATE_ANIMATION);
 		// unpause if the number of outstanding pause requests has dropped to the initial one
 		if (mMotionController.isPaused() && mPauseRequest->getNumRefs() == 1)
 		{
@@ -209,7 +204,6 @@ void LLCharacter::updateMotions(e_update_t update_type)
 		}
 		bool force_update = (update_type == FORCE_UPDATE);
 		{
-			LL_RECORD_BLOCK_TIME(FTM_UPDATE_MOTIONS);
 			mMotionController.updateMotions(force_update);
 		}
 	}
diff --git a/indra/llcharacter/lleditingmotion.cpp b/indra/llcharacter/lleditingmotion.cpp
index ddf89f30f2..c5757163d9 100644
--- a/indra/llcharacter/lleditingmotion.cpp
+++ b/indra/llcharacter/lleditingmotion.cpp
@@ -163,6 +163,7 @@ BOOL LLEditingMotion::onActivate()
 //-----------------------------------------------------------------------------
 BOOL LLEditingMotion::onUpdate(F32 time, U8* joint_mask)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	LLVector3 focus_pt;
 	LLVector3* pointAtPt = (LLVector3*)mCharacter->getAnimationData("PointAtPoint");
 
diff --git a/indra/llcharacter/llhandmotion.cpp b/indra/llcharacter/llhandmotion.cpp
index b3bf5a9a91..ceba956214 100644
--- a/indra/llcharacter/llhandmotion.cpp
+++ b/indra/llcharacter/llhandmotion.cpp
@@ -121,6 +121,7 @@ BOOL LLHandMotion::onActivate()
 //-----------------------------------------------------------------------------
 BOOL LLHandMotion::onUpdate(F32 time, U8* joint_mask)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	eHandPose *requestedHandPose;
 
 	F32 timeDelta = time - mLastTime;
diff --git a/indra/llcharacter/llheadrotmotion.cpp b/indra/llcharacter/llheadrotmotion.cpp
index e91de7a11d..fdf97266a3 100644
--- a/indra/llcharacter/llheadrotmotion.cpp
+++ b/indra/llcharacter/llheadrotmotion.cpp
@@ -175,6 +175,7 @@ BOOL LLHeadRotMotion::onActivate()
 //-----------------------------------------------------------------------------
 BOOL LLHeadRotMotion::onUpdate(F32 time, U8* joint_mask)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	LLQuaternion	targetHeadRotWorld;
 	LLQuaternion	currentRootRotWorld = mRootJoint->getWorldRotation();
 	LLQuaternion	currentInvRootRotWorld = ~currentRootRotWorld;
@@ -458,6 +459,7 @@ void LLEyeMotion::adjustEyeTarget(LLVector3* targetPos, LLJointState& left_eye_s
 //-----------------------------------------------------------------------------
 BOOL LLEyeMotion::onUpdate(F32 time, U8* joint_mask)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	//calculate jitter
 	if (mEyeJitterTimer.getElapsedTimeF32() > mEyeJitterTime)
 	{
diff --git a/indra/llcharacter/llkeyframefallmotion.cpp b/indra/llcharacter/llkeyframefallmotion.cpp
index 60ab2e9929..ac53bcd768 100644
--- a/indra/llcharacter/llkeyframefallmotion.cpp
+++ b/indra/llcharacter/llkeyframefallmotion.cpp
@@ -116,6 +116,7 @@ BOOL LLKeyframeFallMotion::onActivate()
 //-----------------------------------------------------------------------------
 BOOL LLKeyframeFallMotion::onUpdate(F32 activeTime, U8* joint_mask)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	BOOL result = LLKeyframeMotion::onUpdate(activeTime, joint_mask);
 	F32  slerp_amt = clamp_rescale(activeTime / getDuration(), 0.5f, 0.75f, 0.f, 1.f);
 
diff --git a/indra/llcharacter/llkeyframemotion.cpp b/indra/llcharacter/llkeyframemotion.cpp
index cde38c8091..429c479d0d 100644
--- a/indra/llcharacter/llkeyframemotion.cpp
+++ b/indra/llcharacter/llkeyframemotion.cpp
@@ -683,6 +683,7 @@ BOOL LLKeyframeMotion::onActivate()
 //-----------------------------------------------------------------------------
 BOOL LLKeyframeMotion::onUpdate(F32 time, U8* joint_mask)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	// llassert(time >= 0.f);		// This will fire
 	time = llmax(0.f, time);
 
diff --git a/indra/llcharacter/llkeyframemotionparam.cpp b/indra/llcharacter/llkeyframemotionparam.cpp
index 6ed18bc445..aba1c5db39 100644
--- a/indra/llcharacter/llkeyframemotionparam.cpp
+++ b/indra/llcharacter/llkeyframemotionparam.cpp
@@ -158,6 +158,7 @@ BOOL LLKeyframeMotionParam::onActivate()
 //-----------------------------------------------------------------------------
 BOOL LLKeyframeMotionParam::onUpdate(F32 time, U8* joint_mask)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	F32 weightFactor = 1.f / (F32)mParameterizedMotions.size();
 
 	// zero out all pose weights
diff --git a/indra/llcharacter/llkeyframewalkmotion.cpp b/indra/llcharacter/llkeyframewalkmotion.cpp
index f180702385..298b37e60c 100644
--- a/indra/llcharacter/llkeyframewalkmotion.cpp
+++ b/indra/llcharacter/llkeyframewalkmotion.cpp
@@ -105,6 +105,7 @@ void LLKeyframeWalkMotion::onDeactivate()
 //-----------------------------------------------------------------------------
 BOOL LLKeyframeWalkMotion::onUpdate(F32 time, U8* joint_mask)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	// compute time since last update
 	F32 deltaTime = time - mRealTimeLast;
 
@@ -198,6 +199,7 @@ BOOL LLWalkAdjustMotion::onActivate()
 //-----------------------------------------------------------------------------
 BOOL LLWalkAdjustMotion::onUpdate(F32 time, U8* joint_mask)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	// delta_time is guaranteed to be non zero
 	F32 delta_time = llclamp(time - mLastTime, TIME_EPSILON, MAX_TIME_DELTA);
 	mLastTime = time;
@@ -373,6 +375,7 @@ BOOL LLFlyAdjustMotion::onActivate()
 //-----------------------------------------------------------------------------
 BOOL LLFlyAdjustMotion::onUpdate(F32 time, U8* joint_mask)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	LLVector3 ang_vel = mCharacter->getCharacterAngularVelocity() * mCharacter->getTimeDilation();
 	F32 speed = mCharacter->getCharacterVelocity().magVec();
 
diff --git a/indra/llcharacter/llmotioncontroller.cpp b/indra/llcharacter/llmotioncontroller.cpp
index c48d02b652..d4546ce901 100644
--- a/indra/llcharacter/llmotioncontroller.cpp
+++ b/indra/llcharacter/llmotioncontroller.cpp
@@ -503,6 +503,7 @@ void LLMotionController::resetJointSignatures()
 //-----------------------------------------------------------------------------
 void LLMotionController::updateIdleMotion(LLMotion* motionp)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	if (motionp->isStopped() && mAnimTime > motionp->getStopTime() + motionp->getEaseOutDuration())
 	{
 		deactivateMotionInstance(motionp);
@@ -541,6 +542,7 @@ void LLMotionController::updateIdleMotion(LLMotion* motionp)
 //-----------------------------------------------------------------------------
 void LLMotionController::updateIdleActiveMotions()
 {
+    LL_PROFILE_ZONE_SCOPED;
 	for (motion_list_t::iterator iter = mActiveMotions.begin();
 		 iter != mActiveMotions.end(); )
 	{
@@ -553,10 +555,9 @@ void LLMotionController::updateIdleActiveMotions()
 //-----------------------------------------------------------------------------
 // updateMotionsByType()
 //-----------------------------------------------------------------------------
-static LLTrace::BlockTimerStatHandle FTM_MOTION_ON_UPDATE("Motion onUpdate");
-
 void LLMotionController::updateMotionsByType(LLMotion::LLMotionBlendType anim_type)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	BOOL update_result = TRUE;
 	U8 last_joint_signature[LL_CHARACTER_MAX_ANIMATED_JOINTS];
 
@@ -712,7 +713,6 @@ void LLMotionController::updateMotionsByType(LLMotion::LLMotionBlendType anim_ty
 
 			// perform motion update
 			{
-				LL_RECORD_BLOCK_TIME(FTM_MOTION_ON_UPDATE);
 				update_result = motionp->onUpdate(mAnimTime - motionp->mActivationTimestamp, last_joint_signature);
 			}
 		}
@@ -768,6 +768,7 @@ void LLMotionController::updateMotionsByType(LLMotion::LLMotionBlendType anim_ty
 //-----------------------------------------------------------------------------
 void LLMotionController::updateLoadingMotions()
 {
+    LL_PROFILE_ZONE_SCOPED;
 	// query pending motions for completion
 	for (motion_set_t::iterator iter = mLoadingMotions.begin();
 		 iter != mLoadingMotions.end(); )
@@ -815,6 +816,7 @@ void LLMotionController::updateLoadingMotions()
 //-----------------------------------------------------------------------------
 void LLMotionController::updateMotions(bool force_update)
 {
+    LL_PROFILE_ZONE_SCOPED;
     // SL-763: "Distant animated objects run at super fast speed"
     // The use_quantum optimization or possibly the associated code in setTimeStamp()
     // does not work as implemented.
@@ -907,6 +909,7 @@ void LLMotionController::updateMotions(bool force_update)
 //-----------------------------------------------------------------------------
 void LLMotionController::updateMotionsMinimal()
 {
+    LL_PROFILE_ZONE_SCOPED;
 	// Always update mPrevTimerElapsed
 	mPrevTimerElapsed = mTimer.getElapsedTimeF32();
 
@@ -924,6 +927,7 @@ void LLMotionController::updateMotionsMinimal()
 //-----------------------------------------------------------------------------
 BOOL LLMotionController::activateMotionInstance(LLMotion *motion, F32 time)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	// It's not clear why the getWeight() line seems to be crashing this, but
 	// hopefully this fixes it.
 	if (motion == NULL || motion->getPose() == NULL)
diff --git a/indra/llcharacter/lltargetingmotion.cpp b/indra/llcharacter/lltargetingmotion.cpp
index 69681e4197..ec75212a40 100644
--- a/indra/llcharacter/lltargetingmotion.cpp
+++ b/indra/llcharacter/lltargetingmotion.cpp
@@ -103,6 +103,7 @@ BOOL LLTargetingMotion::onActivate()
 //-----------------------------------------------------------------------------
 BOOL LLTargetingMotion::onUpdate(F32 time, U8* joint_mask)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	F32 slerp_amt = LLSmoothInterpolation::getInterpolant(TORSO_TARGET_HALF_LIFE);
 
 	LLVector3 target;
diff --git a/indra/llcommon/lldate.cpp b/indra/llcommon/lldate.cpp
index 7a2a0869f4..2ddcf40895 100644
--- a/indra/llcommon/lldate.cpp
+++ b/indra/llcommon/lldate.cpp
@@ -86,11 +86,9 @@ std::string LLDate::asRFC1123() const
 	return toHTTPDateString (std::string ("%A, %d %b %Y %H:%M:%S GMT"));
 }
 
-LLTrace::BlockTimerStatHandle FT_DATE_FORMAT("Date Format");
-
 std::string LLDate::toHTTPDateString (std::string fmt) const
 {
-	LL_RECORD_BLOCK_TIME(FT_DATE_FORMAT);
+    LL_PROFILE_ZONE_SCOPED;
 	
 	time_t locSeconds = (time_t) mSecondsSinceEpoch;
 	struct tm * gmt = gmtime (&locSeconds);
@@ -99,7 +97,7 @@ std::string LLDate::toHTTPDateString (std::string fmt) const
 
 std::string LLDate::toHTTPDateString (tm * gmt, std::string fmt)
 {
-	LL_RECORD_BLOCK_TIME(FT_DATE_FORMAT);
+    LL_PROFILE_ZONE_SCOPED;
 
 	// avoid calling setlocale() unnecessarily - it's expensive.
 	static std::string prev_locale = "";
diff --git a/indra/llcommon/llfasttimer.cpp b/indra/llcommon/llfasttimer.cpp
index 5b6a7b82f8..d38946004f 100644
--- a/indra/llcommon/llfasttimer.cpp
+++ b/indra/llcommon/llfasttimer.cpp
@@ -191,29 +191,30 @@ TimeBlockTreeNode& BlockTimerStatHandle::getTreeNode() const
 }
 
 
+
 void BlockTimer::bootstrapTimerTree()
 {
-	for (auto& base : BlockTimerStatHandle::instance_snapshot())
-	{
-		// because of indirect derivation from LLInstanceTracker, have to downcast
-		BlockTimerStatHandle& timer = static_cast<BlockTimerStatHandle&>(base);
-		if (&timer == &BlockTimer::getRootTimeBlock()) continue;
-
-		// bootstrap tree construction by attaching to last timer to be on stack
-		// when this timer was called
-		if (timer.getParent() == &BlockTimer::getRootTimeBlock())
-		{
-			TimeBlockAccumulator& accumulator = timer.getCurrentAccumulator();
-
-			if (accumulator.mLastCaller)
-			{
-				timer.setParent(accumulator.mLastCaller);
-				accumulator.mParent = accumulator.mLastCaller;
-			}
-			// no need to push up tree on first use, flag can be set spuriously
-			accumulator.mMoveUpTree = false;
-		}
-	}
+    for (auto& base : BlockTimerStatHandle::instance_snapshot())
+    {
+        // because of indirect derivation from LLInstanceTracker, have to downcast
+        BlockTimerStatHandle& timer = static_cast<BlockTimerStatHandle&>(base);
+        if (&timer == &BlockTimer::getRootTimeBlock()) continue;
+
+        // bootstrap tree construction by attaching to last timer to be on stack
+        // when this timer was called
+        if (timer.getParent() == &BlockTimer::getRootTimeBlock())
+        {
+            TimeBlockAccumulator& accumulator = timer.getCurrentAccumulator();
+
+            if (accumulator.mLastCaller)
+            {
+                timer.setParent(accumulator.mLastCaller);
+                accumulator.mParent = accumulator.mLastCaller;
+            }
+            // no need to push up tree on first use, flag can be set spuriously
+            accumulator.mMoveUpTree = false;
+        }
+    }
 }
 
 // bump timers up tree if they have been flagged as being in the wrong place
@@ -221,6 +222,7 @@ void BlockTimer::bootstrapTimerTree()
 // this preserves partial order derived from current frame's observations
 void BlockTimer::incrementalUpdateTimerTree()
 {
+    LL_PROFILE_ZONE_SCOPED;
 	for(block_timer_tree_df_post_iterator_t it = begin_block_timer_tree_df_post(BlockTimer::getRootTimeBlock());
 		it != end_block_timer_tree_df_post();
 		++it)
@@ -260,7 +262,8 @@ void BlockTimer::incrementalUpdateTimerTree()
 
 
 void BlockTimer::updateTimes()
-	{
+{
+    LL_PROFILE_ZONE_SCOPED;
 	// walk up stack of active timers and accumulate current time while leaving timing structures active
 	BlockTimerStackRecord* stack_record	= LLThreadLocalSingletonPointer<BlockTimerStackRecord>::getInstance();
 	if (!stack_record) return;
@@ -271,7 +274,7 @@ void BlockTimer::updateTimes()
 
 	while(cur_timer 
 		&& cur_timer->mParentTimerData.mActiveTimer != cur_timer) // root defined by parent pointing to self
-		{
+	{
 		U64 cumulative_time_delta = cur_time - cur_timer->mStartTime;
 		cur_timer->mStartTime = cur_time;
 
diff --git a/indra/llcommon/llmemory.h b/indra/llcommon/llmemory.h
index 2704a495e0..41023b4ba4 100644
--- a/indra/llcommon/llmemory.h
+++ b/indra/llcommon/llmemory.h
@@ -109,6 +109,16 @@ public:                                     \
     }                                       \
                                             \
     void operator delete(void* ptr)         \
+    {                                       \
+        ll_aligned_free_16(ptr);            \
+    }                                       \
+                                            \
+    void* operator new[](size_t size)       \
+    {                                       \
+        return ll_aligned_malloc_16(size);  \
+    }                                       \
+                                            \
+    void operator delete[](void* ptr)       \
     {                                       \
         ll_aligned_free_16(ptr);            \
     }
@@ -126,8 +136,9 @@ public:                                     \
 #else
 	inline void* ll_aligned_malloc_fallback( size_t size, int align )
 	{
+        LL_PROFILE_ZONE_SCOPED;
 	#if defined(LL_WINDOWS)
-		return _aligned_malloc(size, align);
+        void* ret = _aligned_malloc(size, align);
 	#else
         char* aligned = NULL;
 		void* mem = malloc( size + (align - 1) + sizeof(void*) );
@@ -138,12 +149,16 @@ public:                                     \
 
             ((void**)aligned)[-1] = mem;
         }
-		return aligned;
+		void* ret = aligned;
 	#endif
+        LL_PROFILE_ALLOC(ret, size);
+        return ret;
 	}
 
 	inline void ll_aligned_free_fallback( void* ptr )
 	{
+        LL_PROFILE_ZONE_SCOPED;
+        LL_PROFILE_FREE(ptr);
 	#if defined(LL_WINDOWS)
 		_aligned_free(ptr);
 	#else
@@ -159,21 +174,24 @@ public:                                     \
 
 inline void* ll_aligned_malloc_16(size_t size) // returned hunk MUST be freed with ll_aligned_free_16().
 {
+    LL_PROFILE_ZONE_SCOPED;
 #if defined(LL_WINDOWS)
-	return _aligned_malloc(size, 16);
+	void* ret = _aligned_malloc(size, 16);
 #elif defined(LL_DARWIN)
-	return malloc(size); // default osx malloc is 16 byte aligned.
+	void* ret = malloc(size); // default osx malloc is 16 byte aligned.
 #else
-	void *rtn;
-	if (LL_LIKELY(0 == posix_memalign(&rtn, 16, size)))
-		return rtn;
-	else // bad alignment requested, or out of memory
-		return NULL;
+	void *ret;
+    if (0 != posix_memalign(&ret, 16, size))
+        return nullptr;
 #endif
+    LL_PROFILE_ALLOC(ret, size);
+    return ret;
 }
 
 inline void ll_aligned_free_16(void *p)
 {
+    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_FREE(p);
 #if defined(LL_WINDOWS)
 	_aligned_free(p);
 #elif defined(LL_DARWIN)
@@ -185,10 +203,12 @@ inline void ll_aligned_free_16(void *p)
 
 inline void* ll_aligned_realloc_16(void* ptr, size_t size, size_t old_size) // returned hunk MUST be freed with ll_aligned_free_16().
 {
+    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_FREE(ptr);
 #if defined(LL_WINDOWS)
-	return _aligned_realloc(ptr, size, 16);
+	void* ret = _aligned_realloc(ptr, size, 16);
 #elif defined(LL_DARWIN)
-	return realloc(ptr,size); // default osx malloc is 16 byte aligned.
+	void* ret = realloc(ptr,size); // default osx malloc is 16 byte aligned.
 #else
 	//FIXME: memcpy is SLOW
 	void* ret = ll_aligned_malloc_16(size);
@@ -201,27 +221,31 @@ inline void* ll_aligned_realloc_16(void* ptr, size_t size, size_t old_size) // r
 		}
 		ll_aligned_free_16(ptr);
 	}
-	return ret;
 #endif
+    LL_PROFILE_ALLOC(ptr, size);
+    return ret;
 }
 
 inline void* ll_aligned_malloc_32(size_t size) // returned hunk MUST be freed with ll_aligned_free_32().
 {
+    LL_PROFILE_ZONE_SCOPED;
 #if defined(LL_WINDOWS)
-	return _aligned_malloc(size, 32);
+	void* ret = _aligned_malloc(size, 32);
 #elif defined(LL_DARWIN)
-	return ll_aligned_malloc_fallback( size, 32 );
+	void* ret = ll_aligned_malloc_fallback( size, 32 );
 #else
-	void *rtn;
-	if (LL_LIKELY(0 == posix_memalign(&rtn, 32, size)))
-		return rtn;
-	else // bad alignment requested, or out of memory
-		return NULL;
+	void *ret;
+    if (0 != posix_memalign(&ret, 32, size))
+        return nullptr;
 #endif
+    LL_PROFILE_ALLOC(ret, size);
+    return ret;
 }
 
 inline void ll_aligned_free_32(void *p)
 {
+    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_FREE(p);
 #if defined(LL_WINDOWS)
 	_aligned_free(p);
 #elif defined(LL_DARWIN)
@@ -235,29 +259,35 @@ inline void ll_aligned_free_32(void *p)
 template<size_t ALIGNMENT>
 LL_FORCE_INLINE void* ll_aligned_malloc(size_t size)
 {
+    LL_PROFILE_ZONE_SCOPED;
+    void* ret;
 	if (LL_DEFAULT_HEAP_ALIGN % ALIGNMENT == 0)
 	{
-		return malloc(size);
+		ret = malloc(size);
+        LL_PROFILE_ALLOC(ret, size);
 	}
 	else if (ALIGNMENT == 16)
 	{
-		return ll_aligned_malloc_16(size);
+		ret = ll_aligned_malloc_16(size);
 	}
 	else if (ALIGNMENT == 32)
 	{
-		return ll_aligned_malloc_32(size);
+		ret = ll_aligned_malloc_32(size);
 	}
 	else
 	{
-		return ll_aligned_malloc_fallback(size, ALIGNMENT);
+		ret = ll_aligned_malloc_fallback(size, ALIGNMENT);
 	}
+    return ret;
 }
 
 template<size_t ALIGNMENT>
 LL_FORCE_INLINE void ll_aligned_free(void* ptr)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	if (ALIGNMENT == LL_DEFAULT_HEAP_ALIGN)
 	{
+        LL_PROFILE_FREE(ptr);
 		free(ptr);
 	}
 	else if (ALIGNMENT == 16)
@@ -279,6 +309,7 @@ LL_FORCE_INLINE void ll_aligned_free(void* ptr)
 //
 inline void ll_memcpy_nonaliased_aligned_16(char* __restrict dst, const char* __restrict src, size_t bytes)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	assert(src != NULL);
 	assert(dst != NULL);
 	assert(bytes > 0);
diff --git a/indra/llcommon/llprofiler.h b/indra/llcommon/llprofiler.h
index e36f693dd3..ca60d23248 100644
--- a/indra/llcommon/llprofiler.h
+++ b/indra/llcommon/llprofiler.h
@@ -66,6 +66,8 @@ extern thread_local bool gProfilerEnabled;
         #define LL_PROFILE_ZONE_ERR(name)               LL_PROFILE_ZONE_NAMED_COLOR( name, 0XFF0000  )  // RGB yellow
         #define LL_PROFILE_ZONE_INFO(name)              LL_PROFILE_ZONE_NAMED_COLOR( name, 0X00FFFF  )  // RGB cyan
         #define LL_PROFILE_ZONE_WARN(name)              LL_PROFILE_ZONE_NAMED_COLOR( name, 0x0FFFF00 )  // RGB red
+        #define LL_PROFILE_ALLOC(ptr, size)             TracyAlloc(ptr, size)
+        #define LL_PROFILE_FREE(ptr)                    TracyFree(ptr)
     #endif
     #if LL_PROFILER_CONFIGURATION == LL_PROFILER_CONFIG_FAST_TIMER
         #define LL_PROFILER_FRAME_END
@@ -81,11 +83,13 @@ extern thread_local bool gProfilerEnabled;
         #define LL_PROFILE_ZONE_ERR(name)               (void)(name); // Not supported
         #define LL_PROFILE_ZONE_INFO(name)              (void)(name); // Not supported
         #define LL_PROFILE_ZONE_WARN(name)              (void)(name); // Not supported
+        #define LL_PROFILE_ALLOC(ptr, size)             (void)(ptr); (void)(size);
+        #define LL_PROFILE_FREE(ptr)                    (void)(ptr);
     #endif
     #if LL_PROFILER_CONFIGURATION == LL_PROFILER_CONFIG_TRACY_FAST_TIMER
         #define LL_PROFILER_FRAME_END                   FrameMark
         #define LL_PROFILER_SET_THREAD_NAME( name )     tracy::SetThreadName( name );    gProfilerEnabled = true;
-        #define LL_RECORD_BLOCK_TIME(name)              ZoneScoped                                          const LLTrace::BlockTimer& LL_GLUE_TOKENS(block_time_recorder, __LINE__)(LLTrace::timeThisBlock(name)); (void)LL_GLUE_TOKENS(block_time_recorder, __LINE__);
+        #define LL_RECORD_BLOCK_TIME(name)              ZoneNamedN(___tracy_scoped_zone, #name, true);   const LLTrace::BlockTimer& LL_GLUE_TOKENS(block_time_recorder, __LINE__)(LLTrace::timeThisBlock(name)); (void)LL_GLUE_TOKENS(block_time_recorder, __LINE__);
         #define LL_PROFILE_ZONE_NAMED(name)             ZoneNamedN( ___tracy_scoped_zone, #name, true );
         #define LL_PROFILE_ZONE_NAMED_COLOR(name,color) ZoneNamedNC( ___tracy_scopped_zone, name, color, true ) // RGB
         #define LL_PROFILE_ZONE_SCOPED                  ZoneScoped
@@ -96,6 +100,8 @@ extern thread_local bool gProfilerEnabled;
         #define LL_PROFILE_ZONE_ERR(name)               LL_PROFILE_ZONE_NAMED_COLOR( name, 0XFF0000  )  // RGB yellow
         #define LL_PROFILE_ZONE_INFO(name)              LL_PROFILE_ZONE_NAMED_COLOR( name, 0X00FFFF  )  // RGB cyan
         #define LL_PROFILE_ZONE_WARN(name)              LL_PROFILE_ZONE_NAMED_COLOR( name, 0x0FFFF00 )  // RGB red
+        #define LL_PROFILE_ALLOC(ptr, size)             TracyAlloc(ptr, size)
+        #define LL_PROFILE_FREE(ptr)                    TracyFree(ptr)
     #endif
 #else
     #define LL_PROFILER_FRAME_END
diff --git a/indra/llcommon/llsdparam.cpp b/indra/llcommon/llsdparam.cpp
index 2e7b46f885..af4ccf25fd 100644
--- a/indra/llcommon/llsdparam.cpp
+++ b/indra/llcommon/llsdparam.cpp
@@ -37,8 +37,6 @@ static 	LLInitParam::Parser::parser_write_func_map_t sWriteFuncs;
 static 	LLInitParam::Parser::parser_inspect_func_map_t sInspectFuncs;
 static const LLSD NO_VALUE_MARKER;
 
-LLTrace::BlockTimerStatHandle FTM_SD_PARAM_ADAPTOR("LLSD to LLInitParam conversion");
-
 //
 // LLParamSDParser
 //
diff --git a/indra/llcommon/llsdparam.h b/indra/llcommon/llsdparam.h
index 93910b70ae..82a623a8a0 100644
--- a/indra/llcommon/llsdparam.h
+++ b/indra/llcommon/llsdparam.h
@@ -110,7 +110,6 @@ private:
 };
 
 
-extern LL_COMMON_API LLTrace::BlockTimerStatHandle FTM_SD_PARAM_ADAPTOR;
 template<typename T>
 class LLSDParamAdapter : public T
 {
@@ -118,7 +117,7 @@ public:
 	LLSDParamAdapter() {}
 	LLSDParamAdapter(const LLSD& sd)
 	{
-		LL_RECORD_BLOCK_TIME(FTM_SD_PARAM_ADAPTOR);
+        LL_PROFILE_ZONE_SCOPED;
 		LLParamSDParser parser;
 		// don't spam for implicit parsing of LLSD, as we want to allow arbitrary freeform data and ignore most of it
 		bool parse_silently = true;
diff --git a/indra/llcommon/llsingleton.h b/indra/llcommon/llsingleton.h
index 2e43a3cbed..10a8ecfedb 100644
--- a/indra/llcommon/llsingleton.h
+++ b/indra/llcommon/llsingleton.h
@@ -839,4 +839,30 @@ private:                                                                \
     /* LLSINGLETON() is carefully implemented to permit exactly this */ \
     LLSINGLETON_C11(DERIVED_CLASS) {}
 
+// Relatively unsafe singleton implementation that is much faster
+// and simpler than LLSingleton, but has no dependency tracking
+// or inherent thread safety and requires manual invocation of 
+// createInstance before first use.
+template<class T>
+class LLSimpleton
+{
+public:
+    static T* sInstance;
+    
+    static void createInstance() 
+    { 
+        llassert(sInstance == nullptr);
+        sInstance = new T(); 
+    }
+    
+    static inline T* getInstance() { return sInstance; }
+    static inline T& instance() { return *getInstance(); }
+    static inline bool instanceExists() { return sInstance != nullptr; }
+
+    static void deleteSingleton() { 
+        delete sInstance; 
+        sInstance = nullptr; 
+    }
+};
+
 #endif
diff --git a/indra/llcommon/llstring.cpp b/indra/llcommon/llstring.cpp
index 0290eea143..f6f9f97809 100644
--- a/indra/llcommon/llstring.cpp
+++ b/indra/llcommon/llstring.cpp
@@ -37,9 +37,6 @@
 #include <winnls.h> // for WideCharToMultiByte
 #endif
 
-LLTrace::BlockTimerStatHandle FT_STRING_FORMAT("String Format");
-
-
 std::string ll_safe_string(const char* in)
 {
 	if(in) return std::string(in);
@@ -1356,7 +1353,7 @@ bool LLStringUtil::formatDatetime(std::string& replacement, std::string token,
 template<> 
 S32 LLStringUtil::format(std::string& s, const format_map_t& substitutions)
 {
-	LL_RECORD_BLOCK_TIME(FT_STRING_FORMAT);
+    LL_PROFILE_ZONE_SCOPED;
 	S32 res = 0;
 
 	std::string output;
@@ -1429,7 +1426,7 @@ S32 LLStringUtil::format(std::string& s, const format_map_t& substitutions)
 template<> 
 S32 LLStringUtil::format(std::string& s, const LLSD& substitutions)
 {
-	LL_RECORD_BLOCK_TIME(FT_STRING_FORMAT);
+    LL_PROFILE_ZONE_SCOPED;
 	S32 res = 0;
 
 	if (!substitutions.isMap()) 
diff --git a/indra/llcommon/llsys.cpp b/indra/llcommon/llsys.cpp
index 6d5d043e8d..306ef05b6d 100644
--- a/indra/llcommon/llsys.cpp
+++ b/indra/llcommon/llsys.cpp
@@ -871,11 +871,9 @@ LLMemoryInfo& LLMemoryInfo::refresh()
 	return *this;
 }
 
-static LLTrace::BlockTimerStatHandle FTM_MEMINFO_LOAD_STATS("MemInfo Load Stats");
-
 LLSD LLMemoryInfo::loadStatsMap()
 {
-	LL_RECORD_BLOCK_TIME(FTM_MEMINFO_LOAD_STATS);
+    LL_PROFILE_ZONE_SCOPED;
 
 	// This implementation is derived from stream() code (as of 2011-06-29).
 	Stats stats;
diff --git a/indra/llcommon/lltrace.cpp b/indra/llcommon/lltrace.cpp
index 54079a4689..f59b207ded 100644
--- a/indra/llcommon/lltrace.cpp
+++ b/indra/llcommon/lltrace.cpp
@@ -61,6 +61,7 @@ TimeBlockTreeNode::TimeBlockTreeNode()
 
 void TimeBlockTreeNode::setParent( BlockTimerStatHandle* parent )
 {
+    LL_PROFILE_ZONE_SCOPED;
 	llassert_always(parent != mBlock);
 	llassert_always(parent != NULL);
 
diff --git a/indra/llcommon/lltrace.h b/indra/llcommon/lltrace.h
index 0d0cd6f581..4051c558a4 100644
--- a/indra/llcommon/lltrace.h
+++ b/indra/llcommon/lltrace.h
@@ -227,6 +227,7 @@ public:
 
 	void setName(const char* name)
 	{
+        LL_PROFILE_ZONE_SCOPED;
 		mName = name;
 		setKey(name);
 	}
@@ -234,12 +235,14 @@ public:
 	/*virtual*/ const char* getUnitLabel() const { return "KB"; }
 
 	StatType<MemAccumulator::AllocationFacet>& allocations() 
-	{ 
+	{
+        LL_PROFILE_ZONE_SCOPED;
 		return static_cast<StatType<MemAccumulator::AllocationFacet>&>(*(StatType<MemAccumulator>*)this);
 	}
 
 	StatType<MemAccumulator::DeallocationFacet>& deallocations() 
-	{ 
+	{
+        LL_PROFILE_ZONE_SCOPED;
 		return static_cast<StatType<MemAccumulator::DeallocationFacet>&>(*(StatType<MemAccumulator>*)this);
 	}
 };
@@ -261,6 +264,7 @@ struct MeasureMem<T, typename T::mem_trackable_tag_t, IS_BYTES>
 {
 	static size_t measureFootprint(const T& value)
 	{
+        LL_PROFILE_ZONE_SCOPED;
 		return sizeof(T) + value.getMemFootprint();
 	}
 };
@@ -270,6 +274,7 @@ struct MeasureMem<T, IS_MEM_TRACKABLE, typename T::is_unit_t>
 {
 	static size_t measureFootprint(const T& value)
 	{
+        LL_PROFILE_ZONE_SCOPED;
 		return U32Bytes(value).value();
 	}
 };
@@ -279,6 +284,7 @@ struct MeasureMem<T*, IS_MEM_TRACKABLE, IS_BYTES>
 {
 	static size_t measureFootprint(const T* value)
 	{
+        LL_PROFILE_ZONE_SCOPED;
 		if (!value)
 		{
 			return 0;
@@ -323,6 +329,7 @@ struct MeasureMem<std::basic_string<T>, IS_MEM_TRACKABLE, IS_BYTES>
 {
 	static size_t measureFootprint(const std::basic_string<T>& value)
 	{
+        LL_PROFILE_ZONE_SCOPED;
 		return value.capacity() * sizeof(T);
 	}
 };
@@ -331,6 +338,7 @@ struct MeasureMem<std::basic_string<T>, IS_MEM_TRACKABLE, IS_BYTES>
 template<typename T>
 inline void claim_alloc(MemStatHandle& measurement, const T& value)
 {
+    LL_PROFILE_ZONE_SCOPED;
 #if LL_TRACE_ENABLED
 	S32 size = MeasureMem<T>::measureFootprint(value);
 	if(size == 0) return;
@@ -343,6 +351,7 @@ inline void claim_alloc(MemStatHandle& measurement, const T& value)
 template<typename T>
 inline void disclaim_alloc(MemStatHandle& measurement, const T& value)
 {
+    LL_PROFILE_ZONE_SCOPED;
 #if LL_TRACE_ENABLED
 	S32 size = MeasureMem<T>::measureFootprint(value);
 	if(size == 0) return;
@@ -352,141 +361,6 @@ inline void disclaim_alloc(MemStatHandle& measurement, const T& value)
 #endif
 }
 
-template<typename DERIVED, size_t ALIGNMENT = LL_DEFAULT_HEAP_ALIGN>
-class MemTrackableNonVirtual
-{
-public:
-	typedef void mem_trackable_tag_t;
-
-	MemTrackableNonVirtual(const char* name)
-#if LL_TRACE_ENABLED
-	:	mMemFootprint(0)
-#endif
-	{
-#if LL_TRACE_ENABLED
-		static bool name_initialized = false;
-		if (!name_initialized)
-		{
-			name_initialized = true;
-			sMemStat.setName(name);
-		}
-#endif
-	}
-
-#if LL_TRACE_ENABLED
-	~MemTrackableNonVirtual()
-	{
-		disclaimMem(mMemFootprint);
-	}
-
-	static MemStatHandle& getMemStatHandle()
-	{
-		return sMemStat;
-	}
-
-	S32 getMemFootprint() const	{ return mMemFootprint; }
-#endif
-
-	void* operator new(size_t size) 
-	{
-#if LL_TRACE_ENABLED
-		claim_alloc(sMemStat, size);
-#endif
-		return ll_aligned_malloc<ALIGNMENT>(size);
-	}
-
-	template<int CUSTOM_ALIGNMENT>
-	static void* aligned_new(size_t size)
-	{
-#if LL_TRACE_ENABLED
-		claim_alloc(sMemStat, size);
-#endif
-		return ll_aligned_malloc<CUSTOM_ALIGNMENT>(size);
-	}
-
-	void operator delete(void* ptr, size_t size)
-	{
-#if LL_TRACE_ENABLED
-		disclaim_alloc(sMemStat, size);
-#endif
-		ll_aligned_free<ALIGNMENT>(ptr);
-	}
-
-	template<int CUSTOM_ALIGNMENT>
-	static void aligned_delete(void* ptr, size_t size)
-	{
-#if LL_TRACE_ENABLED
-		disclaim_alloc(sMemStat, size);
-#endif
-		ll_aligned_free<CUSTOM_ALIGNMENT>(ptr);
-	}
-
-	void* operator new [](size_t size)
-	{
-#if LL_TRACE_ENABLED
-		claim_alloc(sMemStat, size);
-#endif
-		return ll_aligned_malloc<ALIGNMENT>(size);
-	}
-
-	void operator delete[](void* ptr, size_t size)
-	{
-#if LL_TRACE_ENABLED
-		disclaim_alloc(sMemStat, size);
-#endif
-		ll_aligned_free<ALIGNMENT>(ptr);
-	}
-
-	// claim memory associated with other objects/data as our own, adding to our calculated footprint
-	template<typename CLAIM_T>
-	void claimMem(const CLAIM_T& value) const
-	{
-#if LL_TRACE_ENABLED
-		S32 size = MeasureMem<CLAIM_T>::measureFootprint(value);
-		claim_alloc(sMemStat, size);
-		mMemFootprint += size;
-#endif
-	}
-
-	// remove memory we had claimed from our calculated footprint
-	template<typename CLAIM_T>
-	void disclaimMem(const CLAIM_T& value) const
-	{
-#if LL_TRACE_ENABLED
-		S32 size = MeasureMem<CLAIM_T>::measureFootprint(value);
-		disclaim_alloc(sMemStat, size);
-		mMemFootprint -= size;
-#endif
-	}
-
-private:
-#if LL_TRACE_ENABLED
-	// use signed values so that we can temporarily go negative
-	// and reconcile in destructor
-	// NB: this assumes that no single class is responsible for > 2GB of allocations
-	mutable S32 mMemFootprint;
-	
-	static	MemStatHandle	sMemStat;
-#endif
-
-};
-
-#if LL_TRACE_ENABLED
-template<typename DERIVED, size_t ALIGNMENT>
-MemStatHandle MemTrackableNonVirtual<DERIVED, ALIGNMENT>::sMemStat(typeid(MemTrackableNonVirtual<DERIVED, ALIGNMENT>).name());
-#endif
-
-template<typename DERIVED, size_t ALIGNMENT = LL_DEFAULT_HEAP_ALIGN>
-class MemTrackable : public MemTrackableNonVirtual<DERIVED, ALIGNMENT>
-{
-public:
-	MemTrackable(const char* name)
-	:	MemTrackableNonVirtual<DERIVED, ALIGNMENT>(name)
-	{}
-
-	virtual ~MemTrackable()
-	{}
-};
 }
 
 #endif // LL_LLTRACE_H
diff --git a/indra/llcommon/lltraceaccumulators.cpp b/indra/llcommon/lltraceaccumulators.cpp
index b1c23c6fb7..8e9aaee0e6 100644
--- a/indra/llcommon/lltraceaccumulators.cpp
+++ b/indra/llcommon/lltraceaccumulators.cpp
@@ -41,6 +41,7 @@ extern MemStatHandle gTraceMemStat;
 
 AccumulatorBufferGroup::AccumulatorBufferGroup() 
 {
+    LL_PROFILE_ZONE_SCOPED;
 	claim_alloc(gTraceMemStat, mCounts.capacity() * sizeof(CountAccumulator));
 	claim_alloc(gTraceMemStat, mSamples.capacity() * sizeof(SampleAccumulator));
 	claim_alloc(gTraceMemStat, mEvents.capacity() * sizeof(EventAccumulator));
@@ -55,6 +56,7 @@ AccumulatorBufferGroup::AccumulatorBufferGroup(const AccumulatorBufferGroup& oth
 	mStackTimers(other.mStackTimers),
 	mMemStats(other.mMemStats)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	claim_alloc(gTraceMemStat, mCounts.capacity() * sizeof(CountAccumulator));
 	claim_alloc(gTraceMemStat, mSamples.capacity() * sizeof(SampleAccumulator));
 	claim_alloc(gTraceMemStat, mEvents.capacity() * sizeof(EventAccumulator));
@@ -64,6 +66,7 @@ AccumulatorBufferGroup::AccumulatorBufferGroup(const AccumulatorBufferGroup& oth
 
 AccumulatorBufferGroup::~AccumulatorBufferGroup()
 {
+    LL_PROFILE_ZONE_SCOPED;
 	disclaim_alloc(gTraceMemStat, mCounts.capacity() * sizeof(CountAccumulator));
 	disclaim_alloc(gTraceMemStat, mSamples.capacity() * sizeof(SampleAccumulator));
 	disclaim_alloc(gTraceMemStat, mEvents.capacity() * sizeof(EventAccumulator));
@@ -73,6 +76,7 @@ AccumulatorBufferGroup::~AccumulatorBufferGroup()
 
 void AccumulatorBufferGroup::handOffTo(AccumulatorBufferGroup& other)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	other.mCounts.reset(&mCounts);
 	other.mSamples.reset(&mSamples);
 	other.mEvents.reset(&mEvents);
@@ -82,6 +86,7 @@ void AccumulatorBufferGroup::handOffTo(AccumulatorBufferGroup& other)
 
 void AccumulatorBufferGroup::makeCurrent()
 {
+    LL_PROFILE_ZONE_SCOPED;
 	mCounts.makeCurrent();
 	mSamples.makeCurrent();
 	mEvents.makeCurrent();
@@ -104,6 +109,7 @@ void AccumulatorBufferGroup::makeCurrent()
 //static
 void AccumulatorBufferGroup::clearCurrent()
 {
+    LL_PROFILE_ZONE_SCOPED;
 	AccumulatorBuffer<CountAccumulator>::clearCurrent();	
 	AccumulatorBuffer<SampleAccumulator>::clearCurrent();
 	AccumulatorBuffer<EventAccumulator>::clearCurrent();
@@ -118,6 +124,7 @@ bool AccumulatorBufferGroup::isCurrent() const
 
 void AccumulatorBufferGroup::append( const AccumulatorBufferGroup& other )
 {
+    LL_PROFILE_ZONE_SCOPED;
 	mCounts.addSamples(other.mCounts, SEQUENTIAL);
 	mSamples.addSamples(other.mSamples, SEQUENTIAL);
 	mEvents.addSamples(other.mEvents, SEQUENTIAL);
@@ -127,6 +134,7 @@ void AccumulatorBufferGroup::append( const AccumulatorBufferGroup& other )
 
 void AccumulatorBufferGroup::merge( const AccumulatorBufferGroup& other)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	mCounts.addSamples(other.mCounts, NON_SEQUENTIAL);
 	mSamples.addSamples(other.mSamples, NON_SEQUENTIAL);
 	mEvents.addSamples(other.mEvents, NON_SEQUENTIAL);
@@ -137,6 +145,7 @@ void AccumulatorBufferGroup::merge( const AccumulatorBufferGroup& other)
 
 void AccumulatorBufferGroup::reset(AccumulatorBufferGroup* other)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	mCounts.reset(other ? &other->mCounts : NULL);
 	mSamples.reset(other ? &other->mSamples : NULL);
 	mEvents.reset(other ? &other->mEvents : NULL);
@@ -146,6 +155,7 @@ void AccumulatorBufferGroup::reset(AccumulatorBufferGroup* other)
 
 void AccumulatorBufferGroup::sync()
 {
+    LL_PROFILE_ZONE_SCOPED;
 	if (isCurrent())
 	{
 		F64SecondsImplicit time_stamp = LLTimer::getTotalSeconds();
@@ -190,7 +200,7 @@ F64 SampleAccumulator::mergeSumsOfSquares(const SampleAccumulator& a, const Samp
 
 void SampleAccumulator::addSamples( const SampleAccumulator& other, EBufferAppendType append_type )
 {
-	if (append_type == NON_SEQUENTIAL)
+    if (append_type == NON_SEQUENTIAL)
 	{
 		return;
 	}
@@ -289,7 +299,7 @@ void EventAccumulator::addSamples( const EventAccumulator& other, EBufferAppendT
 
 void EventAccumulator::reset( const EventAccumulator* other )
 {
-	mNumSamples = 0;
+    mNumSamples = 0;
 	mSum = 0;
 	mMin = F32(NaN);
 	mMax = F32(NaN);
diff --git a/indra/llcommon/lltraceaccumulators.h b/indra/llcommon/lltraceaccumulators.h
index 8eb5338a2a..b183fcd14a 100644
--- a/indra/llcommon/lltraceaccumulators.h
+++ b/indra/llcommon/lltraceaccumulators.h
@@ -66,6 +66,7 @@ namespace LLTrace
 			: mStorageSize(0),
 			mStorage(NULL)
 		{
+            LL_PROFILE_ZONE_SCOPED;
 			const AccumulatorBuffer& other = *getDefaultBuffer();
 			resize(sNextStorageSlot);
 			for (S32 i = 0; i < sNextStorageSlot; i++)
@@ -76,6 +77,7 @@ namespace LLTrace
 
 		~AccumulatorBuffer()
 		{
+            LL_PROFILE_ZONE_SCOPED;
 			if (isCurrent())
 			{
 				LLThreadLocalSingletonPointer<ACCUMULATOR>::setInstance(NULL);
@@ -98,6 +100,7 @@ namespace LLTrace
 			: mStorageSize(0),
 			mStorage(NULL)
 		{
+            LL_PROFILE_ZONE_SCOPED;
 			resize(sNextStorageSlot);
 			for (S32 i = 0; i < sNextStorageSlot; i++)
 			{
@@ -107,6 +110,7 @@ namespace LLTrace
 
 		void addSamples(const AccumulatorBuffer<ACCUMULATOR>& other, EBufferAppendType append_type)
 		{
+            LL_PROFILE_ZONE_SCOPED;
 			llassert(mStorageSize >= sNextStorageSlot && other.mStorageSize >= sNextStorageSlot);
 			for (size_t i = 0; i < sNextStorageSlot; i++)
 			{
@@ -116,6 +120,7 @@ namespace LLTrace
 
 		void copyFrom(const AccumulatorBuffer<ACCUMULATOR>& other)
 		{
+            LL_PROFILE_ZONE_SCOPED;
 			llassert(mStorageSize >= sNextStorageSlot && other.mStorageSize >= sNextStorageSlot);
 			for (size_t i = 0; i < sNextStorageSlot; i++)
 			{
@@ -125,6 +130,7 @@ namespace LLTrace
 
 		void reset(const AccumulatorBuffer<ACCUMULATOR>* other = NULL)
 		{
+            LL_PROFILE_ZONE_SCOPED;
 			llassert(mStorageSize >= sNextStorageSlot);
 			for (size_t i = 0; i < sNextStorageSlot; i++)
 			{
@@ -134,6 +140,7 @@ namespace LLTrace
 
 		void sync(F64SecondsImplicit time_stamp)
 		{
+            LL_PROFILE_ZONE_SCOPED;
 			llassert(mStorageSize >= sNextStorageSlot);
 			for (size_t i = 0; i < sNextStorageSlot; i++)
 			{
@@ -153,12 +160,13 @@ namespace LLTrace
 
 		static void clearCurrent()
 		{
-			LLThreadLocalSingletonPointer<ACCUMULATOR>::setInstance(NULL);
+            LLThreadLocalSingletonPointer<ACCUMULATOR>::setInstance(NULL);
 		}
 
 		// NOTE: this is not thread-safe.  We assume that slots are reserved in the main thread before any child threads are spawned
 		size_t reserveSlot()
 		{
+            LL_PROFILE_ZONE_SCOPED;
 			size_t next_slot = sNextStorageSlot++;
 			if (next_slot >= mStorageSize)
 			{
@@ -172,6 +180,7 @@ namespace LLTrace
 
 		void resize(size_t new_size)
 		{
+            LL_PROFILE_ZONE_SCOPED;
 			if (new_size <= mStorageSize) return;
 
 			ACCUMULATOR* old_storage = mStorage;
@@ -212,6 +221,7 @@ namespace LLTrace
 
 		static self_t* getDefaultBuffer()
 		{
+            LL_PROFILE_ZONE_SCOPED;
 			static bool sInitialized = false;
 			if (!sInitialized)
 			{
@@ -326,6 +336,7 @@ namespace LLTrace
 
 		void sample(F64 value)
 		{
+            LL_PROFILE_ZONE_SCOPED;
 			F64SecondsImplicit time_stamp = LLTimer::getTotalSeconds();
 
 			// store effect of last value
@@ -444,9 +455,9 @@ namespace LLTrace
 		S32	mNumSamples;
 	};
 
-	class TimeBlockAccumulator
+	class alignas(32) TimeBlockAccumulator
 	{
-	public:
+    public:
 		typedef F64Seconds value_t;
 		static F64Seconds getDefaultValue() { return F64Seconds(0); }
 
@@ -539,6 +550,7 @@ namespace LLTrace
 
 		void addSamples(const MemAccumulator& other, EBufferAppendType append_type)
 		{
+            LL_PROFILE_ZONE_SCOPED;
 			mAllocations.addSamples(other.mAllocations, append_type);
 			mDeallocations.addSamples(other.mDeallocations, append_type);
 
@@ -557,6 +569,7 @@ namespace LLTrace
 
 		void reset(const MemAccumulator* other)
 		{
+            LL_PROFILE_ZONE_SCOPED;
 			mSize.reset(other ? &other->mSize : NULL);
 			mAllocations.reset(other ? &other->mAllocations : NULL);
 			mDeallocations.reset(other ? &other->mDeallocations : NULL);
diff --git a/indra/llcommon/lltracerecording.cpp b/indra/llcommon/lltracerecording.cpp
index 3094b627a2..c72a64d086 100644
--- a/indra/llcommon/lltracerecording.cpp
+++ b/indra/llcommon/lltracerecording.cpp
@@ -50,6 +50,7 @@ Recording::Recording(EPlayState state)
 :	mElapsedSeconds(0),
 	mActiveBuffers(NULL)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	claim_alloc(gTraceMemStat, this);
 	mBuffers = new AccumulatorBufferGroup();
 	claim_alloc(gTraceMemStat, mBuffers);
@@ -59,12 +60,14 @@ Recording::Recording(EPlayState state)
 Recording::Recording( const Recording& other )
 :	mActiveBuffers(NULL)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	claim_alloc(gTraceMemStat, this);
 	*this = other;
 }
 
 Recording& Recording::operator = (const Recording& other)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	// this will allow us to seamlessly start without affecting any data we've acquired from other
 	setPlayState(PAUSED);
 
@@ -85,6 +88,7 @@ Recording& Recording::operator = (const Recording& other)
 
 Recording::~Recording()
 {
+    LL_PROFILE_ZONE_SCOPED;
 	disclaim_alloc(gTraceMemStat, this);
 	disclaim_alloc(gTraceMemStat, mBuffers);
 
@@ -103,6 +107,7 @@ void Recording::update()
 #if LL_TRACE_ENABLED
 	if (isStarted())
 	{
+        LL_PROFILE_ZONE_SCOPED;
 		mElapsedSeconds += mSamplingTimer.getElapsedTimeF64();
 
 		// must have 
@@ -123,6 +128,7 @@ void Recording::update()
 
 void Recording::handleReset()
 {
+    LL_PROFILE_ZONE_SCOPED;
 #if LL_TRACE_ENABLED
 	mBuffers.write()->reset();
 
@@ -133,6 +139,7 @@ void Recording::handleReset()
 
 void Recording::handleStart()
 {
+    LL_PROFILE_ZONE_SCOPED;
 #if LL_TRACE_ENABLED
 	mSamplingTimer.reset();
 	mBuffers.setStayUnique(true);
@@ -144,6 +151,7 @@ void Recording::handleStart()
 
 void Recording::handleStop()
 {
+    LL_PROFILE_ZONE_SCOPED;
 #if LL_TRACE_ENABLED
 	mElapsedSeconds += mSamplingTimer.getElapsedTimeF64();
 	// must have thread recorder running on this thread
@@ -273,7 +281,7 @@ F64Kilobytes Recording::getMean(const StatType<MemAccumulator>& stat)
 
 F64Kilobytes Recording::getMax(const StatType<MemAccumulator>& stat)
 {
-	update();
+    update();
 	const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()];
 	const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL;
 	return F64Bytes(llmax(accumulator.mSize.getMax(), active_accumulator && active_accumulator->mSize.hasValue() ? active_accumulator->mSize.getMax() : F32_MIN));
@@ -281,7 +289,7 @@ F64Kilobytes Recording::getMax(const StatType<MemAccumulator>& stat)
 
 F64Kilobytes Recording::getStandardDeviation(const StatType<MemAccumulator>& stat)
 {
-	update();
+    update();
 	const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()];
 	const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL;
 	if (active_accumulator && active_accumulator->hasValue())
@@ -297,7 +305,7 @@ F64Kilobytes Recording::getStandardDeviation(const StatType<MemAccumulator>& sta
 
 F64Kilobytes Recording::getLastValue(const StatType<MemAccumulator>& stat)
 {
-	update();
+    update();
 	const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()];
 	const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL;
 	return F64Bytes(active_accumulator ? active_accumulator->mSize.getLastValue() : accumulator.mSize.getLastValue());
@@ -305,7 +313,7 @@ F64Kilobytes Recording::getLastValue(const StatType<MemAccumulator>& stat)
 
 bool Recording::hasValue(const StatType<MemAccumulator::AllocationFacet>& stat)
 {
-	update();
+    update();
 	const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()];
 	const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL;
 	return accumulator.mAllocations.hasValue() || (active_accumulator ? active_accumulator->mAllocations.hasValue() : false);
@@ -313,7 +321,7 @@ bool Recording::hasValue(const StatType<MemAccumulator::AllocationFacet>& stat)
 
 F64Kilobytes Recording::getSum(const StatType<MemAccumulator::AllocationFacet>& stat)
 {
-	update();
+    update();
 	const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()];
 	const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL;
 	return F64Bytes(accumulator.mAllocations.getSum() + (active_accumulator ? active_accumulator->mAllocations.getSum() : 0));
@@ -321,7 +329,7 @@ F64Kilobytes Recording::getSum(const StatType<MemAccumulator::AllocationFacet>&
 
 F64Kilobytes Recording::getPerSec(const StatType<MemAccumulator::AllocationFacet>& stat)
 {
-	update();
+    update();
 	const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()];
 	const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL;
 	return F64Bytes((accumulator.mAllocations.getSum() + (active_accumulator ? active_accumulator->mAllocations.getSum() : 0)) / mElapsedSeconds.value());
@@ -329,7 +337,7 @@ F64Kilobytes Recording::getPerSec(const StatType<MemAccumulator::AllocationFacet
 
 S32 Recording::getSampleCount(const StatType<MemAccumulator::AllocationFacet>& stat)
 {
-	update();
+    update();
 	const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()];
 	const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL;
 	return accumulator.mAllocations.getSampleCount() + (active_accumulator ? active_accumulator->mAllocations.getSampleCount() : 0);
@@ -337,7 +345,7 @@ S32 Recording::getSampleCount(const StatType<MemAccumulator::AllocationFacet>& s
 
 bool Recording::hasValue(const StatType<MemAccumulator::DeallocationFacet>& stat)
 {
-	update();
+    update();
 	const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()];
 	const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL;
 	return accumulator.mDeallocations.hasValue() || (active_accumulator ? active_accumulator->mDeallocations.hasValue() : false);
@@ -346,7 +354,7 @@ bool Recording::hasValue(const StatType<MemAccumulator::DeallocationFacet>& stat
 
 F64Kilobytes Recording::getSum(const StatType<MemAccumulator::DeallocationFacet>& stat)
 {
-	update();
+    update();
 	const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()];
 	const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL;
 	return F64Bytes(accumulator.mDeallocations.getSum() + (active_accumulator ? active_accumulator->mDeallocations.getSum() : 0));
@@ -354,7 +362,7 @@ F64Kilobytes Recording::getSum(const StatType<MemAccumulator::DeallocationFacet>
 
 F64Kilobytes Recording::getPerSec(const StatType<MemAccumulator::DeallocationFacet>& stat)
 {
-	update();
+    update();
 	const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()];
 	const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL;
 	return F64Bytes((accumulator.mDeallocations.getSum() + (active_accumulator ? active_accumulator->mDeallocations.getSum() : 0)) / mElapsedSeconds.value());
@@ -362,7 +370,7 @@ F64Kilobytes Recording::getPerSec(const StatType<MemAccumulator::DeallocationFac
 
 S32 Recording::getSampleCount(const StatType<MemAccumulator::DeallocationFacet>& stat)
 {
-	update();
+    update();
 	const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()];
 	const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL;
 	return accumulator.mDeallocations.getSampleCount() + (active_accumulator ? active_accumulator->mDeallocations.getSampleCount() : 0);
@@ -370,7 +378,7 @@ S32 Recording::getSampleCount(const StatType<MemAccumulator::DeallocationFacet>&
 
 bool Recording::hasValue(const StatType<CountAccumulator>& stat)
 {
-	update();
+    update();
 	const CountAccumulator& accumulator = mBuffers->mCounts[stat.getIndex()];
 	const CountAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mCounts[stat.getIndex()] : NULL;
 	return accumulator.hasValue() || (active_accumulator ? active_accumulator->hasValue() : false);
@@ -378,7 +386,7 @@ bool Recording::hasValue(const StatType<CountAccumulator>& stat)
 
 F64 Recording::getSum(const StatType<CountAccumulator>& stat)
 {
-	update();
+    update();
 	const CountAccumulator& accumulator = mBuffers->mCounts[stat.getIndex()];
 	const CountAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mCounts[stat.getIndex()] : NULL;
 	return accumulator.getSum() + (active_accumulator ? active_accumulator->getSum() : 0);
@@ -386,7 +394,7 @@ F64 Recording::getSum(const StatType<CountAccumulator>& stat)
 
 F64 Recording::getPerSec( const StatType<CountAccumulator>& stat )
 {
-	update();
+    update();
 	const CountAccumulator& accumulator = mBuffers->mCounts[stat.getIndex()];
 	const CountAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mCounts[stat.getIndex()] : NULL;
 	F64 sum = accumulator.getSum() + (active_accumulator ? active_accumulator->getSum() : 0);
@@ -395,7 +403,7 @@ F64 Recording::getPerSec( const StatType<CountAccumulator>& stat )
 
 S32 Recording::getSampleCount( const StatType<CountAccumulator>& stat )
 {
-	update();
+    update();
 	const CountAccumulator& accumulator = mBuffers->mCounts[stat.getIndex()];
 	const CountAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mCounts[stat.getIndex()] : NULL;
 	return accumulator.getSampleCount() + (active_accumulator ? active_accumulator->getSampleCount() : 0);
@@ -403,7 +411,7 @@ S32 Recording::getSampleCount( const StatType<CountAccumulator>& stat )
 
 bool Recording::hasValue(const StatType<SampleAccumulator>& stat)
 {
-	update();
+    update();
 	const SampleAccumulator& accumulator = mBuffers->mSamples[stat.getIndex()];
 	const SampleAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mSamples[stat.getIndex()] : NULL;
 	return accumulator.hasValue() || (active_accumulator && active_accumulator->hasValue());
@@ -411,7 +419,7 @@ bool Recording::hasValue(const StatType<SampleAccumulator>& stat)
 
 F64 Recording::getMin( const StatType<SampleAccumulator>& stat )
 {
-	update();
+    update();
 	const SampleAccumulator& accumulator = mBuffers->mSamples[stat.getIndex()];
 	const SampleAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mSamples[stat.getIndex()] : NULL;
 	return llmin(accumulator.getMin(), active_accumulator && active_accumulator->hasValue() ? active_accumulator->getMin() : F32_MAX);
@@ -419,7 +427,7 @@ F64 Recording::getMin( const StatType<SampleAccumulator>& stat )
 
 F64 Recording::getMax( const StatType<SampleAccumulator>& stat )
 {
-	update();
+    update();
 	const SampleAccumulator& accumulator = mBuffers->mSamples[stat.getIndex()];
 	const SampleAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mSamples[stat.getIndex()] : NULL;
 	return llmax(accumulator.getMax(), active_accumulator && active_accumulator->hasValue() ? active_accumulator->getMax() : F32_MIN);
@@ -427,7 +435,7 @@ F64 Recording::getMax( const StatType<SampleAccumulator>& stat )
 
 F64 Recording::getMean( const StatType<SampleAccumulator>& stat )
 {
-	update();
+    update();
 	const SampleAccumulator& accumulator = mBuffers->mSamples[stat.getIndex()];
 	const SampleAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mSamples[stat.getIndex()] : NULL;
 	if (active_accumulator && active_accumulator->hasValue())
@@ -448,7 +456,7 @@ F64 Recording::getMean( const StatType<SampleAccumulator>& stat )
 
 F64 Recording::getStandardDeviation( const StatType<SampleAccumulator>& stat )
 {
-	update();
+    update();
 	const SampleAccumulator& accumulator = mBuffers->mSamples[stat.getIndex()];
 	const SampleAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mSamples[stat.getIndex()] : NULL;
 
@@ -465,7 +473,7 @@ F64 Recording::getStandardDeviation( const StatType<SampleAccumulator>& stat )
 
 F64 Recording::getLastValue( const StatType<SampleAccumulator>& stat )
 {
-	update();
+    update();
 	const SampleAccumulator& accumulator = mBuffers->mSamples[stat.getIndex()];
 	const SampleAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mSamples[stat.getIndex()] : NULL;
 	return (active_accumulator && active_accumulator->hasValue() ? active_accumulator->getLastValue() : accumulator.getLastValue());
@@ -473,7 +481,7 @@ F64 Recording::getLastValue( const StatType<SampleAccumulator>& stat )
 
 S32 Recording::getSampleCount( const StatType<SampleAccumulator>& stat )
 {
-	update();
+    update();
 	const SampleAccumulator& accumulator = mBuffers->mSamples[stat.getIndex()];
 	const SampleAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mSamples[stat.getIndex()] : NULL;
 	return accumulator.getSampleCount() + (active_accumulator && active_accumulator->hasValue() ? active_accumulator->getSampleCount() : 0);
@@ -481,7 +489,7 @@ S32 Recording::getSampleCount( const StatType<SampleAccumulator>& stat )
 
 bool Recording::hasValue(const StatType<EventAccumulator>& stat)
 {
-	update();
+    update();
 	const EventAccumulator& accumulator = mBuffers->mEvents[stat.getIndex()];
 	const EventAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mEvents[stat.getIndex()] : NULL;
 	return accumulator.hasValue() || (active_accumulator && active_accumulator->hasValue());
@@ -489,7 +497,7 @@ bool Recording::hasValue(const StatType<EventAccumulator>& stat)
 
 F64 Recording::getSum( const StatType<EventAccumulator>& stat)
 {
-	update();
+    update();
 	const EventAccumulator& accumulator = mBuffers->mEvents[stat.getIndex()];
 	const EventAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mEvents[stat.getIndex()] : NULL;
 	return (F64)(accumulator.getSum() + (active_accumulator && active_accumulator->hasValue() ? active_accumulator->getSum() : 0));
@@ -497,7 +505,7 @@ F64 Recording::getSum( const StatType<EventAccumulator>& stat)
 
 F64 Recording::getMin( const StatType<EventAccumulator>& stat )
 {
-	update();
+    update();
 	const EventAccumulator& accumulator = mBuffers->mEvents[stat.getIndex()];
 	const EventAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mEvents[stat.getIndex()] : NULL;
 	return llmin(accumulator.getMin(), active_accumulator && active_accumulator->hasValue() ? active_accumulator->getMin() : F32_MAX);
@@ -505,7 +513,7 @@ F64 Recording::getMin( const StatType<EventAccumulator>& stat )
 
 F64 Recording::getMax( const StatType<EventAccumulator>& stat )
 {
-	update();
+    update();
 	const EventAccumulator& accumulator = mBuffers->mEvents[stat.getIndex()];
 	const EventAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mEvents[stat.getIndex()] : NULL;
 	return llmax(accumulator.getMax(), active_accumulator && active_accumulator->hasValue() ? active_accumulator->getMax() : F32_MIN);
@@ -513,7 +521,7 @@ F64 Recording::getMax( const StatType<EventAccumulator>& stat )
 
 F64 Recording::getMean( const StatType<EventAccumulator>& stat )
 {
-	update();
+    update();
 	const EventAccumulator& accumulator = mBuffers->mEvents[stat.getIndex()];
 	const EventAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mEvents[stat.getIndex()] : NULL;
 	if (active_accumulator && active_accumulator->hasValue())
@@ -534,7 +542,7 @@ F64 Recording::getMean( const StatType<EventAccumulator>& stat )
 
 F64 Recording::getStandardDeviation( const StatType<EventAccumulator>& stat )
 {
-	update();
+    update();
 	const EventAccumulator& accumulator = mBuffers->mEvents[stat.getIndex()];
 	const EventAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mEvents[stat.getIndex()] : NULL;
 
@@ -551,7 +559,7 @@ F64 Recording::getStandardDeviation( const StatType<EventAccumulator>& stat )
 
 F64 Recording::getLastValue( const StatType<EventAccumulator>& stat )
 {
-	update();
+    update();
 	const EventAccumulator& accumulator = mBuffers->mEvents[stat.getIndex()];
 	const EventAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mEvents[stat.getIndex()] : NULL;
 	return active_accumulator ? active_accumulator->getLastValue() : accumulator.getLastValue();
@@ -559,7 +567,7 @@ F64 Recording::getLastValue( const StatType<EventAccumulator>& stat )
 
 S32 Recording::getSampleCount( const StatType<EventAccumulator>& stat )
 {
-	update();
+    update();
 	const EventAccumulator& accumulator = mBuffers->mEvents[stat.getIndex()];
 	const EventAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mEvents[stat.getIndex()] : NULL;
 	return accumulator.getSampleCount() + (active_accumulator ? active_accumulator->getSampleCount() : 0);
@@ -575,17 +583,20 @@ PeriodicRecording::PeriodicRecording( S32 num_periods, EPlayState state)
 	mNumRecordedPeriods(0),
 	mRecordingPeriods(num_periods ? num_periods : 1)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	setPlayState(state);
 	claim_alloc(gTraceMemStat, this);
 }
 
 PeriodicRecording::~PeriodicRecording()
 {
+    LL_PROFILE_ZONE_SCOPED;
 	disclaim_alloc(gTraceMemStat, this);
 }
 
 void PeriodicRecording::nextPeriod()
 {
+    LL_PROFILE_ZONE_SCOPED;
 	if (mAutoResize)
 	{
 		mRecordingPeriods.push_back(Recording());
@@ -600,6 +611,7 @@ void PeriodicRecording::nextPeriod()
 
 void PeriodicRecording::appendRecording(Recording& recording)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	getCurRecording().appendRecording(recording);
 	nextPeriod();
 }
@@ -607,6 +619,7 @@ void PeriodicRecording::appendRecording(Recording& recording)
 
 void PeriodicRecording::appendPeriodicRecording( PeriodicRecording& other )
 {
+    LL_PROFILE_ZONE_SCOPED;
 	if (other.mRecordingPeriods.empty()) return;
 
 	getCurRecording().update();
@@ -680,6 +693,7 @@ void PeriodicRecording::appendPeriodicRecording( PeriodicRecording& other )
 
 F64Seconds PeriodicRecording::getDuration() const
 {
+    LL_PROFILE_ZONE_SCOPED;
 	F64Seconds duration;
 	S32 num_periods = mRecordingPeriods.size();
 	for (S32 i = 1; i <= num_periods; i++)
@@ -693,6 +707,7 @@ F64Seconds PeriodicRecording::getDuration() const
 
 LLTrace::Recording PeriodicRecording::snapshotCurRecording() const
 {
+    LL_PROFILE_ZONE_SCOPED;
 	Recording recording_copy(getCurRecording());
 	recording_copy.stop();
 	return recording_copy;
@@ -735,16 +750,19 @@ const Recording& PeriodicRecording::getPrevRecording( S32 offset ) const
 
 void PeriodicRecording::handleStart()
 {
+    LL_PROFILE_ZONE_SCOPED;
 	getCurRecording().start();
 }
 
 void PeriodicRecording::handleStop()
 {
+    LL_PROFILE_ZONE_SCOPED;
 	getCurRecording().pause();
 }
 
 void PeriodicRecording::handleReset()
 {
+    LL_PROFILE_ZONE_SCOPED;
 	getCurRecording().stop();
 
 	if (mAutoResize)
@@ -768,11 +786,13 @@ void PeriodicRecording::handleReset()
 
 void PeriodicRecording::handleSplitTo(PeriodicRecording& other)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	getCurRecording().splitTo(other.getCurRecording());
 }
 
 F64 PeriodicRecording::getPeriodMin( const StatType<EventAccumulator>& stat, S32 num_periods /*= S32_MAX*/ )
 {
+    LL_PROFILE_ZONE_SCOPED;
 	num_periods = llmin(num_periods, getNumRecordedPeriods());
 
 	bool has_value = false;
@@ -794,6 +814,7 @@ F64 PeriodicRecording::getPeriodMin( const StatType<EventAccumulator>& stat, S32
 
 F64 PeriodicRecording::getPeriodMax( const StatType<EventAccumulator>& stat, S32 num_periods /*= S32_MAX*/ )
 {
+    LL_PROFILE_ZONE_SCOPED;
 	num_periods = llmin(num_periods, getNumRecordedPeriods());
 
 	bool has_value = false;
@@ -816,6 +837,7 @@ F64 PeriodicRecording::getPeriodMax( const StatType<EventAccumulator>& stat, S32
 // calculates means using aggregates per period
 F64 PeriodicRecording::getPeriodMean( const StatType<EventAccumulator>& stat, S32 num_periods /*= S32_MAX*/ )
 {
+    LL_PROFILE_ZONE_SCOPED;
 	num_periods = llmin(num_periods, getNumRecordedPeriods());
 
 	F64 mean = 0;
@@ -839,6 +861,7 @@ F64 PeriodicRecording::getPeriodMean( const StatType<EventAccumulator>& stat, S3
 
 F64 PeriodicRecording::getPeriodStandardDeviation( const StatType<EventAccumulator>& stat, S32 num_periods /*= S32_MAX*/ )
 {
+    LL_PROFILE_ZONE_SCOPED;
 	num_periods = llmin(num_periods, getNumRecordedPeriods());
 
 	F64 period_mean = getPeriodMean(stat, num_periods);
@@ -863,6 +886,7 @@ F64 PeriodicRecording::getPeriodStandardDeviation( const StatType<EventAccumulat
 
 F64 PeriodicRecording::getPeriodMin( const StatType<SampleAccumulator>& stat, S32 num_periods /*= S32_MAX*/ )
 {
+    LL_PROFILE_ZONE_SCOPED;
 	num_periods = llmin(num_periods, getNumRecordedPeriods());
 
 	bool has_value = false;
@@ -884,6 +908,7 @@ F64 PeriodicRecording::getPeriodMin( const StatType<SampleAccumulator>& stat, S3
 
 F64 PeriodicRecording::getPeriodMax(const StatType<SampleAccumulator>& stat, S32 num_periods /*= S32_MAX*/)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	num_periods = llmin(num_periods, getNumRecordedPeriods());
 
 	bool has_value = false;
@@ -906,6 +931,7 @@ F64 PeriodicRecording::getPeriodMax(const StatType<SampleAccumulator>& stat, S32
 
 F64 PeriodicRecording::getPeriodMean( const StatType<SampleAccumulator>& stat, S32 num_periods /*= S32_MAX*/ )
 {
+    LL_PROFILE_ZONE_SCOPED;
 	num_periods = llmin(num_periods, getNumRecordedPeriods());
 
 	S32 valid_period_count = 0;
@@ -928,6 +954,7 @@ F64 PeriodicRecording::getPeriodMean( const StatType<SampleAccumulator>& stat, S
 
 F64 PeriodicRecording::getPeriodStandardDeviation( const StatType<SampleAccumulator>& stat, S32 num_periods /*= S32_MAX*/ )
 {
+    LL_PROFILE_ZONE_SCOPED;
 	num_periods = llmin(num_periods, getNumRecordedPeriods());
 
 	F64 period_mean = getPeriodMean(stat, num_periods);
@@ -953,6 +980,7 @@ F64 PeriodicRecording::getPeriodStandardDeviation( const StatType<SampleAccumula
 
 F64Kilobytes PeriodicRecording::getPeriodMin( const StatType<MemAccumulator>& stat, S32 num_periods /*= S32_MAX*/ )
 {
+    LL_PROFILE_ZONE_SCOPED;
 	num_periods = llmin(num_periods, getNumRecordedPeriods());
 
 	F64Kilobytes min_val(std::numeric_limits<F64>::max());
@@ -972,6 +1000,7 @@ F64Kilobytes PeriodicRecording::getPeriodMin(const MemStatHandle& stat, S32 num_
 
 F64Kilobytes PeriodicRecording::getPeriodMax(const StatType<MemAccumulator>& stat, S32 num_periods /*= S32_MAX*/)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	num_periods = llmin(num_periods, getNumRecordedPeriods());
 
 	F64Kilobytes max_val(0.0);
@@ -991,6 +1020,7 @@ F64Kilobytes PeriodicRecording::getPeriodMax(const MemStatHandle& stat, S32 num_
 
 F64Kilobytes PeriodicRecording::getPeriodMean( const StatType<MemAccumulator>& stat, S32 num_periods /*= S32_MAX*/ )
 {
+    LL_PROFILE_ZONE_SCOPED;
 	num_periods = llmin(num_periods, getNumRecordedPeriods());
 
 	F64Kilobytes mean(0);
@@ -1011,6 +1041,7 @@ F64Kilobytes PeriodicRecording::getPeriodMean(const MemStatHandle& stat, S32 num
 
 F64Kilobytes PeriodicRecording::getPeriodStandardDeviation( const StatType<MemAccumulator>& stat, S32 num_periods /*= S32_MAX*/ )
 {
+    LL_PROFILE_ZONE_SCOPED;
 	num_periods = llmin(num_periods, getNumRecordedPeriods());
 
 	F64Kilobytes period_mean = getPeriodMean(stat, num_periods);
@@ -1044,6 +1075,7 @@ F64Kilobytes PeriodicRecording::getPeriodStandardDeviation(const MemStatHandle&
 
 void ExtendableRecording::extend()
 {
+    LL_PROFILE_ZONE_SCOPED;
 	// push the data back to accepted recording
 	mAcceptedRecording.appendRecording(mPotentialRecording);
 	// flush data, so we can start from scratch
@@ -1052,22 +1084,26 @@ void ExtendableRecording::extend()
 
 void ExtendableRecording::handleStart()
 {
+    LL_PROFILE_ZONE_SCOPED;
 	mPotentialRecording.start();
 }
 
 void ExtendableRecording::handleStop()
 {
+    LL_PROFILE_ZONE_SCOPED;
 	mPotentialRecording.pause();
 }
 
 void ExtendableRecording::handleReset()
 {
+    LL_PROFILE_ZONE_SCOPED;
 	mAcceptedRecording.reset();
 	mPotentialRecording.reset();
 }
 
 void ExtendableRecording::handleSplitTo(ExtendableRecording& other)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	mPotentialRecording.splitTo(other.mPotentialRecording);
 }
 
@@ -1084,6 +1120,7 @@ ExtendablePeriodicRecording::ExtendablePeriodicRecording()
 
 void ExtendablePeriodicRecording::extend()
 {
+    LL_PROFILE_ZONE_SCOPED;
 	// push the data back to accepted recording
 	mAcceptedRecording.appendPeriodicRecording(mPotentialRecording);
 	// flush data, so we can start from scratch
@@ -1093,22 +1130,26 @@ void ExtendablePeriodicRecording::extend()
 
 void ExtendablePeriodicRecording::handleStart()
 {
+    LL_PROFILE_ZONE_SCOPED;
 	mPotentialRecording.start();
 }
 
 void ExtendablePeriodicRecording::handleStop()
 {
+    LL_PROFILE_ZONE_SCOPED;
 	mPotentialRecording.pause();
 }
 
 void ExtendablePeriodicRecording::handleReset()
 {
+    LL_PROFILE_ZONE_SCOPED;
 	mAcceptedRecording.reset();
 	mPotentialRecording.reset();
 }
 
 void ExtendablePeriodicRecording::handleSplitTo(ExtendablePeriodicRecording& other)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	mPotentialRecording.splitTo(other.mPotentialRecording);
 }
 
@@ -1123,6 +1164,7 @@ PeriodicRecording& get_frame_recording()
 
 void LLStopWatchControlsMixinCommon::start()
 {
+    LL_PROFILE_ZONE_SCOPED;
 	switch (mPlayState)
 	{
 	case STOPPED:
@@ -1144,6 +1186,7 @@ void LLStopWatchControlsMixinCommon::start()
 
 void LLStopWatchControlsMixinCommon::stop()
 {
+    LL_PROFILE_ZONE_SCOPED;
 	switch (mPlayState)
 	{
 	case STOPPED:
@@ -1163,6 +1206,7 @@ void LLStopWatchControlsMixinCommon::stop()
 
 void LLStopWatchControlsMixinCommon::pause()
 {
+    LL_PROFILE_ZONE_SCOPED;
 	switch (mPlayState)
 	{
 	case STOPPED:
@@ -1182,6 +1226,7 @@ void LLStopWatchControlsMixinCommon::pause()
 
 void LLStopWatchControlsMixinCommon::unpause()
 {
+    LL_PROFILE_ZONE_SCOPED;
 	switch (mPlayState)
 	{
 	case STOPPED:
@@ -1201,6 +1246,7 @@ void LLStopWatchControlsMixinCommon::unpause()
 
 void LLStopWatchControlsMixinCommon::resume()
 {
+    LL_PROFILE_ZONE_SCOPED;
 	switch (mPlayState)
 	{
 	case STOPPED:
@@ -1221,6 +1267,7 @@ void LLStopWatchControlsMixinCommon::resume()
 
 void LLStopWatchControlsMixinCommon::restart()
 {
+    LL_PROFILE_ZONE_SCOPED;
 	switch (mPlayState)
 	{
 	case STOPPED:
@@ -1244,11 +1291,13 @@ void LLStopWatchControlsMixinCommon::restart()
 
 void LLStopWatchControlsMixinCommon::reset()
 {
+    LL_PROFILE_ZONE_SCOPED;
 	handleReset();
 }
 
 void LLStopWatchControlsMixinCommon::setPlayState( EPlayState state )
 {
+    LL_PROFILE_ZONE_SCOPED;
 	switch(state)
 	{
 	case STOPPED:
diff --git a/indra/llcommon/lltracerecording.h b/indra/llcommon/lltracerecording.h
index d0b4a842a6..6715104613 100644
--- a/indra/llcommon/lltracerecording.h
+++ b/indra/llcommon/lltracerecording.h
@@ -355,6 +355,7 @@ namespace LLTrace
 		template <typename T>
 		S32 getSampleCount(const StatType<T>& stat, S32 num_periods = S32_MAX)
         {
+            LL_PROFILE_ZONE_SCOPED;
 			num_periods = llmin(num_periods, getNumRecordedPeriods());
 
             S32 num_samples = 0;
@@ -374,6 +375,7 @@ namespace LLTrace
 		template <typename T>
 		typename T::value_t getPeriodMin(const StatType<T>& stat, S32 num_periods = S32_MAX)
 		{
+            LL_PROFILE_ZONE_SCOPED;
 			num_periods = llmin(num_periods, getNumRecordedPeriods());
 
 			bool has_value = false;
@@ -396,6 +398,7 @@ namespace LLTrace
 		template<typename T>
 		T getPeriodMin(const CountStatHandle<T>& stat, S32 num_periods = S32_MAX)
 		{
+            LL_PROFILE_ZONE_SCOPED;
 			return T(getPeriodMin(static_cast<const StatType<CountAccumulator>&>(stat), num_periods));
 		}
 
@@ -403,6 +406,7 @@ namespace LLTrace
 		template<typename T>
 		T getPeriodMin(const SampleStatHandle<T>& stat, S32 num_periods = S32_MAX)
 		{
+            LL_PROFILE_ZONE_SCOPED;
 			return T(getPeriodMin(static_cast<const StatType<SampleAccumulator>&>(stat), num_periods));
 		}
 
@@ -410,6 +414,7 @@ namespace LLTrace
 		template<typename T>
 		T getPeriodMin(const EventStatHandle<T>& stat, S32 num_periods = S32_MAX)
 		{
+            LL_PROFILE_ZONE_SCOPED;
 			return T(getPeriodMin(static_cast<const StatType<EventAccumulator>&>(stat), num_periods));
 		}
 
@@ -419,6 +424,7 @@ namespace LLTrace
 		template <typename T>
 		typename RelatedTypes<typename T::value_t>::fractional_t getPeriodMinPerSec(const StatType<T>& stat, S32 num_periods = S32_MAX)
 		{
+            LL_PROFILE_ZONE_SCOPED;
 			num_periods = llmin(num_periods, getNumRecordedPeriods());
 
 			typename RelatedTypes<typename T::value_t>::fractional_t min_val(std::numeric_limits<F64>::max());
@@ -433,6 +439,7 @@ namespace LLTrace
 		template<typename T>
 		typename RelatedTypes<T>::fractional_t getPeriodMinPerSec(const CountStatHandle<T>& stat, S32 num_periods = S32_MAX)
 		{
+            LL_PROFILE_ZONE_SCOPED;
 			return typename RelatedTypes<T>::fractional_t(getPeriodMinPerSec(static_cast<const StatType<CountAccumulator>&>(stat), num_periods));
 		}
 
@@ -444,6 +451,7 @@ namespace LLTrace
 		template <typename T>
 		typename T::value_t getPeriodMax(const StatType<T>& stat, S32 num_periods = S32_MAX)
 		{
+            LL_PROFILE_ZONE_SCOPED;
 			num_periods = llmin(num_periods, getNumRecordedPeriods());
 
 			bool has_value = false;
@@ -466,6 +474,7 @@ namespace LLTrace
 		template<typename T>
 		T getPeriodMax(const CountStatHandle<T>& stat, S32 num_periods = S32_MAX)
 		{
+            LL_PROFILE_ZONE_SCOPED;
 			return T(getPeriodMax(static_cast<const StatType<CountAccumulator>&>(stat), num_periods));
 		}
 
@@ -473,6 +482,7 @@ namespace LLTrace
 		template<typename T>
 		T getPeriodMax(const SampleStatHandle<T>& stat, S32 num_periods = S32_MAX)
 		{
+            LL_PROFILE_ZONE_SCOPED;
 			return T(getPeriodMax(static_cast<const StatType<SampleAccumulator>&>(stat), num_periods));
 		}
 
@@ -480,6 +490,7 @@ namespace LLTrace
 		template<typename T>
 		T getPeriodMax(const EventStatHandle<T>& stat, S32 num_periods = S32_MAX)
 		{
+            LL_PROFILE_ZONE_SCOPED;
 			return T(getPeriodMax(static_cast<const StatType<EventAccumulator>&>(stat), num_periods));
 		}
 
@@ -489,6 +500,7 @@ namespace LLTrace
 		template <typename T>
 		typename RelatedTypes<typename T::value_t>::fractional_t getPeriodMaxPerSec(const StatType<T>& stat, S32 num_periods = S32_MAX)
 		{
+            LL_PROFILE_ZONE_SCOPED;
 			num_periods = llmin(num_periods, getNumRecordedPeriods());
 
 			F64 max_val = std::numeric_limits<F64>::min();
@@ -503,6 +515,7 @@ namespace LLTrace
 		template<typename T>
 		typename RelatedTypes<T>::fractional_t getPeriodMaxPerSec(const CountStatHandle<T>& stat, S32 num_periods = S32_MAX)
 		{
+            LL_PROFILE_ZONE_SCOPED;
 			return typename RelatedTypes<T>::fractional_t(getPeriodMaxPerSec(static_cast<const StatType<CountAccumulator>&>(stat), num_periods));
 		}
 
@@ -514,6 +527,7 @@ namespace LLTrace
 		template <typename T>
 		typename RelatedTypes<typename T::value_t>::fractional_t getPeriodMean(const StatType<T >& stat, S32 num_periods = S32_MAX)
 		{
+            LL_PROFILE_ZONE_SCOPED;
 			num_periods = llmin(num_periods, getNumRecordedPeriods());
 
 			typename RelatedTypes<typename T::value_t>::fractional_t mean(0);
@@ -534,12 +548,14 @@ namespace LLTrace
 		template<typename T>
 		typename RelatedTypes<T>::fractional_t getPeriodMean(const CountStatHandle<T>& stat, S32 num_periods = S32_MAX)
 		{
+            LL_PROFILE_ZONE_SCOPED;
 			return typename RelatedTypes<T>::fractional_t(getPeriodMean(static_cast<const StatType<CountAccumulator>&>(stat), num_periods));
 		}
 		F64 getPeriodMean(const StatType<SampleAccumulator>& stat, S32 num_periods = S32_MAX);
 		template<typename T> 
 		typename RelatedTypes<T>::fractional_t getPeriodMean(const SampleStatHandle<T>& stat, S32 num_periods = S32_MAX)
 		{
+            LL_PROFILE_ZONE_SCOPED;
 			return typename RelatedTypes<T>::fractional_t(getPeriodMean(static_cast<const StatType<SampleAccumulator>&>(stat), num_periods));
 		}
 
@@ -547,6 +563,7 @@ namespace LLTrace
 		template<typename T>
 		typename RelatedTypes<T>::fractional_t getPeriodMean(const EventStatHandle<T>& stat, S32 num_periods = S32_MAX)
 		{
+            LL_PROFILE_ZONE_SCOPED;
 			return typename RelatedTypes<T>::fractional_t(getPeriodMean(static_cast<const StatType<EventAccumulator>&>(stat), num_periods));
 		}
 
@@ -556,6 +573,7 @@ namespace LLTrace
 		template <typename T>
 		typename RelatedTypes<typename T::value_t>::fractional_t getPeriodMeanPerSec(const StatType<T>& stat, S32 num_periods = S32_MAX)
 		{
+            LL_PROFILE_ZONE_SCOPED;
 			num_periods = llmin(num_periods, getNumRecordedPeriods());
 
 			typename RelatedTypes<typename T::value_t>::fractional_t mean = 0;
@@ -577,6 +595,7 @@ namespace LLTrace
 		template<typename T>
 		typename RelatedTypes<T>::fractional_t getPeriodMeanPerSec(const CountStatHandle<T>& stat, S32 num_periods = S32_MAX)
 		{
+            LL_PROFILE_ZONE_SCOPED;
 			return typename RelatedTypes<T>::fractional_t(getPeriodMeanPerSec(static_cast<const StatType<CountAccumulator>&>(stat), num_periods));
 		}
 
@@ -589,6 +608,7 @@ namespace LLTrace
 		template<typename T> 
 		typename RelatedTypes<T>::fractional_t getPeriodStandardDeviation(const SampleStatHandle<T>& stat, S32 num_periods = S32_MAX)
 		{
+            LL_PROFILE_ZONE_SCOPED;
 			return typename RelatedTypes<T>::fractional_t(getPeriodStandardDeviation(static_cast<const StatType<SampleAccumulator>&>(stat), num_periods));
 		}
 
@@ -596,6 +616,7 @@ namespace LLTrace
 		template<typename T>
 		typename RelatedTypes<T>::fractional_t getPeriodStandardDeviation(const EventStatHandle<T>& stat, S32 num_periods = S32_MAX)
 		{
+            LL_PROFILE_ZONE_SCOPED;
 			return typename RelatedTypes<T>::fractional_t(getPeriodStandardDeviation(static_cast<const StatType<EventAccumulator>&>(stat), num_periods));
 		}
 
diff --git a/indra/llcommon/lltracethreadrecorder.cpp b/indra/llcommon/lltracethreadrecorder.cpp
index 025dc57044..7ae1e72784 100644
--- a/indra/llcommon/lltracethreadrecorder.cpp
+++ b/indra/llcommon/lltracethreadrecorder.cpp
@@ -274,12 +274,10 @@ void ThreadRecorder::pushToParent()
 }
 
 
-static LLTrace::BlockTimerStatHandle FTM_PULL_TRACE_DATA_FROM_CHILDREN("Pull child thread trace data");
-
 void ThreadRecorder::pullFromChildren()
 {
 #if LL_TRACE_ENABLED
-	LL_RECORD_BLOCK_TIME(FTM_PULL_TRACE_DATA_FROM_CHILDREN);
+    LL_PROFILE_ZONE_SCOPED;
 	if (mActiveRecordings.empty()) return;
 
 	{ LLMutexLock lock(&mChildListMutex);
diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp
index aed8943439..5c49ec02ea 100644
--- a/indra/llimage/llimage.cpp
+++ b/indra/llimage/llimage.cpp
@@ -623,8 +623,7 @@ void LLImage::setLastError(const std::string& message)
 //---------------------------------------------------------------------------
 
 LLImageBase::LLImageBase()
-:	LLTrace::MemTrackable<LLImageBase>("LLImage"),
-	mData(NULL),
+:	mData(NULL),
 	mDataSize(0),
 	mWidth(0),
 	mHeight(0),
@@ -673,7 +672,6 @@ void LLImageBase::sanityCheck()
 void LLImageBase::deleteData()
 {
 	ll_aligned_free_16(mData);
-	disclaimMem(mDataSize);
 	mDataSize = 0;
 	mData = NULL;
 }
@@ -731,7 +729,6 @@ U8* LLImageBase::allocateData(S32 size)
 		}
 	}
 	mDataSize = size;
-	claimMem(mDataSize);
 
 	return mData;
 }
@@ -752,9 +749,7 @@ U8* LLImageBase::reallocateData(S32 size)
 		ll_aligned_free_16(mData) ;
 	}
 	mData = new_datap;
-	disclaimMem(mDataSize);
 	mDataSize = size;
-	claimMem(mDataSize);
 	mBadBufferAllocation = false;
 	return mData;
 }
@@ -2258,9 +2253,7 @@ void LLImageBase::setDataAndSize(U8 *data, S32 size)
 { 
 	ll_assert_aligned(data, 16);
 	mData = data; 
-	disclaimMem(mDataSize); 
 	mDataSize = size; 
-	claimMem(mDataSize);
 }	
 
 //static
diff --git a/indra/llimage/llimage.h b/indra/llimage/llimage.h
index f66b1666d7..354926ee58 100644
--- a/indra/llimage/llimage.h
+++ b/indra/llimage/llimage.h
@@ -112,8 +112,7 @@ protected:
 // Image base class
 
 class LLImageBase 
-:	public LLThreadSafeRefCount,
-	public LLTrace::MemTrackable<LLImageBase>
+:	public LLThreadSafeRefCount
 {
 protected:
 	virtual ~LLImageBase();
diff --git a/indra/llimage/llimagej2c.cpp b/indra/llimage/llimagej2c.cpp
index 4bff21610f..e1809dbe59 100644
--- a/indra/llimage/llimagej2c.cpp
+++ b/indra/llimage/llimagej2c.cpp
@@ -60,7 +60,6 @@ LLImageJ2C::LLImageJ2C() : 	LLImageFormatted(IMG_CODEC_J2C),
 							mAreaUsedForDataSizeCalcs(0)
 {
 	mImpl.reset(fallbackCreateLLImageJ2CImpl());
-	claimMem(mImpl);
 
 	// Clear data size table
 	for( S32 i = 0; i <= MAX_DISCARD_LEVEL; i++)
diff --git a/indra/llimage/llimagejpeg.cpp b/indra/llimage/llimagejpeg.cpp
index 62638fa16c..32a5472ec8 100644
--- a/indra/llimage/llimagejpeg.cpp
+++ b/indra/llimage/llimagejpeg.cpp
@@ -393,9 +393,7 @@ boolean LLImageJPEG::encodeEmptyOutputBuffer( j_compress_ptr cinfo )
 
   cinfo->dest->next_output_byte = self->mOutputBuffer + self->mOutputBufferSize;
   cinfo->dest->free_in_buffer = self->mOutputBufferSize;
-  self->disclaimMem(self->mOutputBufferSize);
   self->mOutputBufferSize = new_buffer_size;
-  self->claimMem(new_buffer_size);
 
   return true;
 }
@@ -501,13 +499,10 @@ bool LLImageJPEG::encode( const LLImageRaw* raw_image, F32 encode_time )
 	// Allocate a temporary buffer big enough to hold the entire compressed image (and then some)
 	// (Note: we make it bigger in emptyOutputBuffer() if we need to)
 	delete[] mOutputBuffer;
-	disclaimMem(mOutputBufferSize);
 	mOutputBufferSize = getWidth() * getHeight() * getComponents() + 1024;
-	claimMem(mOutputBufferSize);
 	mOutputBuffer = new(std::nothrow) U8[ mOutputBufferSize ];
 	if (mOutputBuffer == NULL)
 	{
-		disclaimMem(mOutputBufferSize);
 		mOutputBufferSize = 0;
 		setLastError("Failed to allocate output buffer");
 		return false;
@@ -547,7 +542,6 @@ bool LLImageJPEG::encode( const LLImageRaw* raw_image, F32 encode_time )
 		jpeg_destroy_compress(&cinfo);
 		delete[] mOutputBuffer;
 		mOutputBuffer = NULL;
-		disclaimMem(mOutputBufferSize);
 		mOutputBufferSize = 0;
 		return false;
 	}
@@ -650,7 +644,6 @@ bool LLImageJPEG::encode( const LLImageRaw* raw_image, F32 encode_time )
 		// After finish_compress, we can release the temp output buffer. 
 		delete[] mOutputBuffer;
 		mOutputBuffer = NULL;
-		disclaimMem(mOutputBufferSize);
 		mOutputBufferSize = 0;
 
 		////////////////////////////////////////
@@ -663,7 +656,6 @@ bool LLImageJPEG::encode( const LLImageRaw* raw_image, F32 encode_time )
 		jpeg_destroy_compress(&cinfo);
 		delete[] mOutputBuffer;
 		mOutputBuffer = NULL;
-		disclaimMem(mOutputBufferSize);
 		mOutputBufferSize = 0;
 		return false;
 	}
diff --git a/indra/llimage/tests/llimageworker_test.cpp b/indra/llimage/tests/llimageworker_test.cpp
index 51c5c63556..9011ac615c 100644
--- a/indra/llimage/tests/llimageworker_test.cpp
+++ b/indra/llimage/tests/llimageworker_test.cpp
@@ -45,8 +45,7 @@
 // * A simulator for a class can be implemented here. Please comment and document thoroughly.
 
 LLImageBase::LLImageBase() 
-: LLTrace::MemTrackable<LLImageBase>("LLImageBase"),
-mData(NULL),
+: mData(NULL),
 mDataSize(0),
 mWidth(0),
 mHeight(0),
diff --git a/indra/llinventory/llinventory.cpp b/indra/llinventory/llinventory.cpp
index 18bc1b5a91..81261f0767 100644
--- a/indra/llinventory/llinventory.cpp
+++ b/indra/llinventory/llinventory.cpp
@@ -74,20 +74,17 @@ LLInventoryObject::LLInventoryObject(const LLUUID& uuid,
 									 const LLUUID& parent_uuid,
 									 LLAssetType::EType type,
 									 const std::string& name) 
-:	LLTrace::MemTrackable<LLInventoryObject>("LLInventoryObject"),
-	mUUID(uuid),
+:	mUUID(uuid),
 	mParentUUID(parent_uuid),
 	mType(type),
 	mName(name),
 	mCreationDate(0)
 {
-	claimMem(mName);
 	correctInventoryName(mName);
 }
 
 LLInventoryObject::LLInventoryObject() 
-:	LLTrace::MemTrackable<LLInventoryObject>("LLInventoryObject"),
-	mType(LLAssetType::AT_NONE),
+:	mType(LLAssetType::AT_NONE),
 	mCreationDate(0)
 {
 }
@@ -101,9 +98,7 @@ void LLInventoryObject::copyObject(const LLInventoryObject* other)
 	mUUID = other->mUUID;
 	mParentUUID = other->mParentUUID;
 	mType = other->mType;
-	disclaimMem(mName);
 	mName = other->mName;
-	claimMem(mName);
 }
 
 const LLUUID& LLInventoryObject::getUUID() const
@@ -156,9 +151,7 @@ void LLInventoryObject::rename(const std::string& n)
 	correctInventoryName(new_name);
 	if( !new_name.empty() && new_name != mName )
 	{
-		disclaimMem(mName);
 		mName = new_name;
-		claimMem(mName);
 	}
 }
 
@@ -311,7 +304,6 @@ LLInventoryItem::LLInventoryItem(const LLUUID& uuid,
 
 	LLStringUtil::replaceNonstandardASCII(mDescription, ' ');
 	LLStringUtil::replaceChar(mDescription, '|', ' ');
-	claimMem(mDescription);
 
 	mPermissions.initMasks(inv_type);
 }
@@ -344,9 +336,7 @@ void LLInventoryItem::copyItem(const LLInventoryItem* other)
 	copyObject(other);
 	mPermissions = other->mPermissions;
 	mAssetUUID = other->mAssetUUID;
-	disclaimMem(mDescription);
 	mDescription = other->mDescription;
-	claimMem(mDescription);
 	mSaleInfo = other->mSaleInfo;
 	mInventoryType = other->mInventoryType;
 	mFlags = other->mFlags;
@@ -426,9 +416,7 @@ void LLInventoryItem::setDescription(const std::string& d)
 	LLInventoryItem::correctInventoryDescription(new_desc);
 	if( new_desc != mDescription )
 	{
-		disclaimMem(mDescription);
 		mDescription = new_desc;
-		claimMem(mDescription);
 	}
 }
 
@@ -708,10 +696,8 @@ BOOL LLInventoryItem::importLegacyStream(std::istream& input_stream)
 				valuestr[0] = '\000';
 			}
 
-			disclaimMem(mDescription);
 			mDescription.assign(valuestr);
 			LLStringUtil::replaceNonstandardASCII(mDescription, ' ');
-			claimMem(mDescription);
 			/* TODO -- ask Ian about this code
 			const char *donkey = mDescription.c_str();
 			if (donkey[0] == '|')
@@ -840,11 +826,9 @@ void LLInventoryItem::asLLSD( LLSD& sd ) const
 	sd[INV_CREATION_DATE_LABEL] = (S32) mCreationDate;
 }
 
-LLTrace::BlockTimerStatHandle FTM_INVENTORY_SD_DESERIALIZE("Inventory SD Deserialize");
-
 bool LLInventoryItem::fromLLSD(const LLSD& sd, bool is_new)
 {
-	LL_RECORD_BLOCK_TIME(FTM_INVENTORY_SD_DESERIALIZE);
+    LL_PROFILE_ZONE_SCOPED;
 	if (is_new)
 	{
 		// If we're adding LLSD to an existing object, need avoid
@@ -961,10 +945,8 @@ bool LLInventoryItem::fromLLSD(const LLSD& sd, bool is_new)
 	w = INV_DESC_LABEL;
 	if (sd.has(w))
 	{
-		disclaimMem(mDescription);
 		mDescription = sd[w].asString();
 		LLStringUtil::replaceNonstandardASCII(mDescription, ' ');
-		claimMem(mDescription);
 	}
 	w = INV_CREATION_DATE_LABEL;
 	if (sd.has(w))
diff --git a/indra/llinventory/llinventory.h b/indra/llinventory/llinventory.h
index 0f336a072f..7d9f9704f1 100644
--- a/indra/llinventory/llinventory.h
+++ b/indra/llinventory/llinventory.h
@@ -44,7 +44,7 @@ class LLMessageSystem;
 //   Base class for anything in the user's inventory.   Handles the common code 
 //   between items and categories. 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-class LLInventoryObject : public LLRefCount, public LLTrace::MemTrackable<LLInventoryObject>
+class LLInventoryObject : public LLRefCount
 {
 public:
 	typedef std::list<LLPointer<LLInventoryObject> > object_list_t;
diff --git a/indra/llinventory/llsettingsdaycycle.cpp b/indra/llinventory/llsettingsdaycycle.cpp
index a687fd840d..b390ea5b1e 100644
--- a/indra/llinventory/llsettingsdaycycle.cpp
+++ b/indra/llinventory/llsettingsdaycycle.cpp
@@ -41,9 +41,6 @@
 //=========================================================================
 namespace
 {
-    LLTrace::BlockTimerStatHandle FTM_BLEND_WATERVALUES("Blending Water Environment Day");
-    LLTrace::BlockTimerStatHandle FTM_UPDATE_WATERVALUES("Update Water Environment Day");
-
     template<typename T>
     inline T get_wrapping_distance(T begin, T end)
     {
diff --git a/indra/llinventory/llsettingssky.cpp b/indra/llinventory/llsettingssky.cpp
index 82c67a1066..23f9c8e9d7 100644
--- a/indra/llinventory/llsettingssky.cpp
+++ b/indra/llinventory/llsettingssky.cpp
@@ -66,11 +66,6 @@ namespace {
     }
 }
 
-static LLTrace::BlockTimerStatHandle FTM_BLEND_SKYVALUES("Blending Sky Environment");
-static LLTrace::BlockTimerStatHandle FTM_RECALCULATE_SKYVALUES("Recalculate Sky");
-static LLTrace::BlockTimerStatHandle FTM_RECALCULATE_BODIES("Recalculate Heavenly Bodies");
-static LLTrace::BlockTimerStatHandle FTM_RECALCULATE_LIGHTING("Recalculate Lighting");
-
 //=========================================================================
 const std::string LLSettingsSky::SETTING_AMBIENT("ambient");
 const std::string LLSettingsSky::SETTING_BLUE_DENSITY("blue_density");
@@ -940,7 +935,7 @@ LLSD LLSettingsSky::translateLegacySettings(const LLSD& legacy)
 
 void LLSettingsSky::updateSettings()
 {
-    LL_RECORD_BLOCK_TIME(FTM_RECALCULATE_SKYVALUES);
+    LL_PROFILE_ZONE_SCOPED;
 
     // base class clears dirty flag so as to not trigger recursive update
     LLSettingsBase::updateSettings();
diff --git a/indra/llinventory/llsettingswater.cpp b/indra/llinventory/llsettingswater.cpp
index 0eb95dcd89..16cd3343e4 100644
--- a/indra/llinventory/llsettingswater.cpp
+++ b/indra/llinventory/llsettingswater.cpp
@@ -33,14 +33,6 @@
 #include "v3colorutil.h"
 #include "indra_constants.h"
 
-//=========================================================================
-namespace
-{
-     LLTrace::BlockTimerStatHandle FTM_BLEND_WATERVALUES("Blending Water Environment");
-     LLTrace::BlockTimerStatHandle FTM_UPDATE_WATERVALUES("Update Water Environment");
-}
-
-//=========================================================================
 const std::string LLSettingsWater::SETTING_BLUR_MULTIPLIER("blur_multiplier");
 const std::string LLSettingsWater::SETTING_FOG_COLOR("water_fog_color");
 const std::string LLSettingsWater::SETTING_FOG_DENSITY("water_fog_density");
diff --git a/indra/llkdu/tests/llimagej2ckdu_test.cpp b/indra/llkdu/tests/llimagej2ckdu_test.cpp
index ee7b14be85..16213b7f45 100644
--- a/indra/llkdu/tests/llimagej2ckdu_test.cpp
+++ b/indra/llkdu/tests/llimagej2ckdu_test.cpp
@@ -63,8 +63,7 @@ U8* LLImageRaw::reallocateData(S32 ) { return NULL; }
 bool LLImageRaw::resize(U16, U16, S8) { return true; } // this method always returns true...
 
 LLImageBase::LLImageBase()
-: LLTrace::MemTrackable<LLImageBase>("LLImageBase"),
-mData(NULL),
+: mData(NULL),
 mDataSize(0),
 mWidth(0),
 mHeight(0),
diff --git a/indra/llmath/lloctree.h b/indra/llmath/lloctree.h
index 0e2f62f9db..8c4a1304b4 100644
--- a/indra/llmath/lloctree.h
+++ b/indra/llmath/lloctree.h
@@ -74,8 +74,9 @@ public:
 };
 
 template <class T>
-class LLOctreeNode : public LLTreeNode<T>
+class alignas(16) LLOctreeNode : public LLTreeNode<T>
 {
+    LL_ALIGN_NEW
 public:
 
 	typedef LLOctreeTraveler<T>									oct_traveler;
@@ -91,16 +92,6 @@ public:
 	typedef LLOctreeNode<T>		oct_node;
 	typedef LLOctreeListener<T>	oct_listener;
 
-	void* operator new(size_t size)
-	{
-		return ll_aligned_malloc_16(size);
-	}
-
-	void operator delete(void* ptr)
-	{
-		ll_aligned_free_16(ptr);
-	}
-
 	LLOctreeNode(	const LLVector4a& center, 
 					const LLVector4a& size, 
 					BaseType* parent, 
diff --git a/indra/llmath/llrigginginfo.h b/indra/llmath/llrigginginfo.h
index b3d6bc2d19..059c6ae082 100644
--- a/indra/llmath/llrigginginfo.h
+++ b/indra/llmath/llrigginginfo.h
@@ -34,9 +34,9 @@
 
 // Extents are in joint space
 // isRiggedTo is based on the state of all currently associated rigged meshes
-LL_ALIGN_PREFIX(16)
-class LLJointRiggingInfo
+class alignas(16) LLJointRiggingInfo
 {
+    LL_ALIGN_NEW
 public:
     LLJointRiggingInfo();
     bool isRiggedTo() const;
@@ -45,31 +45,10 @@ public:
     const LLVector4a *getRiggedExtents() const;
     void merge(const LLJointRiggingInfo& other);
 
-	void* operator new(size_t size)
-	{
-		return ll_aligned_malloc_16(size);
-	}
-
-	void operator delete(void* ptr)
-	{
-		ll_aligned_free_16(ptr);
-	}
-
-	void* operator new[](size_t size)
-	{
-		return ll_aligned_malloc_16(size);
-	}
-
-	void operator delete[](void* ptr)
-	{
-		ll_aligned_free_16(ptr);
-	}
-
-
 private:
-	LL_ALIGN_16(LLVector4a mRiggedExtents[2]);
+	LLVector4a mRiggedExtents[2];
     bool mIsRiggedTo;
-} LL_ALIGN_POSTFIX(16);
+};
 
 // For storing all the rigging info associated with a given avatar or
 // object, keyed by joint_num.
diff --git a/indra/llmath/llvector4a.h b/indra/llmath/llvector4a.h
index 5a02928374..53c8f604f6 100644
--- a/indra/llmath/llvector4a.h
+++ b/indra/llmath/llvector4a.h
@@ -47,9 +47,9 @@ class LLRotation;
 // LLVector3/LLVector4. 
 /////////////////////////////////
 
-LL_ALIGN_PREFIX(16)
-class LLVector4a
+class alignas(16) LLVector4a
 {
+    LL_ALIGN_NEW
 public:
 
 	///////////////////////////////////
@@ -323,7 +323,7 @@ public:
     
 private:
 	LLQuad mQ;
-} LL_ALIGN_POSTFIX(16);
+};
 
 inline void update_min_max(LLVector4a& min, LLVector4a& max, const LLVector4a& p)
 {
diff --git a/indra/llmath/llvolumeoctree.h b/indra/llmath/llvolumeoctree.h
index 13150028d8..b2bc440368 100644
--- a/indra/llmath/llvolumeoctree.h
+++ b/indra/llmath/llvolumeoctree.h
@@ -34,19 +34,10 @@
 #include "llvolume.h"
 #include "llvector4a.h"
 
-class LLVolumeTriangle : public LLRefCount
+class alignas(16) LLVolumeTriangle : public LLRefCount
 {
+    LL_ALIGN_NEW
 public:
-	void* operator new(size_t size)
-	{
-		return ll_aligned_malloc_16(size);
-	}
-
-	void operator delete(void* ptr)
-	{
-		ll_aligned_free_16(ptr);
-	}
-
 	LLVolumeTriangle()
 	{
 		mBinIndex = -1;	
@@ -86,20 +77,10 @@ public:
 
 };
 
-class LLVolumeOctreeListener : public LLOctreeListener<LLVolumeTriangle>
+class alignas(16) LLVolumeOctreeListener : public LLOctreeListener<LLVolumeTriangle>
 {
+    LL_ALIGN_NEW
 public:
-	
-	void* operator new(size_t size)
-	{
-		return ll_aligned_malloc_16(size);
-	}
-
-	void operator delete(void* ptr)
-	{
-		ll_aligned_free_16(ptr);
-	}
-
 	LLVolumeOctreeListener(LLOctreeNode<LLVolumeTriangle>* node);
 	~LLVolumeOctreeListener();
 	
diff --git a/indra/llmessage/llfiltersd2xmlrpc.cpp b/indra/llmessage/llfiltersd2xmlrpc.cpp
index d3e195789b..0abdafbdfc 100644
--- a/indra/llmessage/llfiltersd2xmlrpc.cpp
+++ b/indra/llmessage/llfiltersd2xmlrpc.cpp
@@ -309,7 +309,6 @@ LLFilterSD2XMLRPCResponse::~LLFilterSD2XMLRPCResponse()
 }
 
 
-static LLTrace::BlockTimerStatHandle FTM_PROCESS_SD2XMLRPC_RESPONSE("SD2XMLRPC Response");
 // virtual
 LLIOPipe::EStatus LLFilterSD2XMLRPCResponse::process_impl(
 	const LLChannelDescriptors& channels,
@@ -318,7 +317,7 @@ LLIOPipe::EStatus LLFilterSD2XMLRPCResponse::process_impl(
 	LLSD& context,
 	LLPumpIO* pump)
 {
-	LL_RECORD_BLOCK_TIME(FTM_PROCESS_SD2XMLRPC_RESPONSE);
+    LL_PROFILE_ZONE_SCOPED;
 
 	PUMP_DEBUG;
 	// This pipe does not work if it does not have everyting. This
@@ -386,8 +385,6 @@ LLFilterSD2XMLRPCRequest::~LLFilterSD2XMLRPCRequest()
 {
 }
 
-static LLTrace::BlockTimerStatHandle FTM_PROCESS_SD2XMLRPC_REQUEST("S22XMLRPC Request");
-
 // virtual
 LLIOPipe::EStatus LLFilterSD2XMLRPCRequest::process_impl(
 	const LLChannelDescriptors& channels,
@@ -396,7 +393,7 @@ LLIOPipe::EStatus LLFilterSD2XMLRPCRequest::process_impl(
 	LLSD& context,
 	LLPumpIO* pump)
 {
-	LL_RECORD_BLOCK_TIME(FTM_PROCESS_SD2XMLRPC_REQUEST);
+    LL_PROFILE_ZONE_SCOPED;
 	// This pipe does not work if it does not have everyting. This
 	// could be addressed by making a stream parser for llsd which
 	// handled partial information.
@@ -593,8 +590,6 @@ LLFilterXMLRPCResponse2LLSD::~LLFilterXMLRPCResponse2LLSD()
 {
 }
 
-static LLTrace::BlockTimerStatHandle FTM_PROCESS_XMLRPC2LLSD_RESPONSE("XMLRPC2LLSD Response");
-
 LLIOPipe::EStatus LLFilterXMLRPCResponse2LLSD::process_impl(
 	const LLChannelDescriptors& channels,
 	buffer_ptr_t& buffer,
@@ -602,7 +597,7 @@ LLIOPipe::EStatus LLFilterXMLRPCResponse2LLSD::process_impl(
 	LLSD& context,
 	LLPumpIO* pump)
 {
-	LL_RECORD_BLOCK_TIME(FTM_PROCESS_XMLRPC2LLSD_RESPONSE);
+    LL_PROFILE_ZONE_SCOPED;
 
 	PUMP_DEBUG;
 	if(!eos) return STATUS_BREAK;
@@ -679,7 +674,6 @@ LLFilterXMLRPCRequest2LLSD::~LLFilterXMLRPCRequest2LLSD()
 {
 }
 
-static LLTrace::BlockTimerStatHandle FTM_PROCESS_XMLRPC2LLSD_REQUEST("XMLRPC2LLSD Request");
 LLIOPipe::EStatus LLFilterXMLRPCRequest2LLSD::process_impl(
 	const LLChannelDescriptors& channels,
 	buffer_ptr_t& buffer,
@@ -687,7 +681,7 @@ LLIOPipe::EStatus LLFilterXMLRPCRequest2LLSD::process_impl(
 	LLSD& context,
 	LLPumpIO* pump)
 {
-	LL_RECORD_BLOCK_TIME(FTM_PROCESS_XMLRPC2LLSD_REQUEST);
+    LL_PROFILE_ZONE_SCOPED;
 	PUMP_DEBUG;
 	if(!eos) return STATUS_BREAK;
 	if(!buffer) return STATUS_ERROR;
diff --git a/indra/llmessage/llhttpnode.cpp b/indra/llmessage/llhttpnode.cpp
index 6fd17c9154..6e9598a0a3 100644
--- a/indra/llmessage/llhttpnode.cpp
+++ b/indra/llmessage/llhttpnode.cpp
@@ -121,6 +121,7 @@ LLSD LLHTTPNode::simplePost(const LLSD& input) const
 // virtual
 void LLHTTPNode::get(LLHTTPNode::ResponsePtr response, const LLSD& context) const
 {
+    LL_PROFILE_ZONE_SCOPED;
 	try
 	{
 		response->result(simpleGet());
@@ -134,6 +135,7 @@ void LLHTTPNode::get(LLHTTPNode::ResponsePtr response, const LLSD& context) cons
 // virtual
 void LLHTTPNode::put(LLHTTPNode::ResponsePtr response, const LLSD& context, const LLSD& input) const
 {
+    LL_PROFILE_ZONE_SCOPED;
 	try
 	{
 		response->result(simplePut(input));
@@ -147,6 +149,7 @@ void LLHTTPNode::put(LLHTTPNode::ResponsePtr response, const LLSD& context, cons
 // virtual
 void LLHTTPNode::post(LLHTTPNode::ResponsePtr response, const LLSD& context, const LLSD& input) const
 {
+    LL_PROFILE_ZONE_SCOPED;
 	try
 	{
 		response->result(simplePost(input));
@@ -160,6 +163,7 @@ void LLHTTPNode::post(LLHTTPNode::ResponsePtr response, const LLSD& context, con
 // virtual
 void LLHTTPNode::del(LLHTTPNode::ResponsePtr response, const LLSD& context) const
 {
+    LL_PROFILE_ZONE_SCOPED;
     try
     {
 	response->result(simpleDel(context));
diff --git a/indra/llmessage/lliohttpserver.cpp b/indra/llmessage/lliohttpserver.cpp
index d9042fa8b0..c707c7ad09 100644
--- a/indra/llmessage/lliohttpserver.cpp
+++ b/indra/llmessage/lliohttpserver.cpp
@@ -132,12 +132,6 @@ private:
 	LLSD mHeaders;
 };
 
-static LLTrace::BlockTimerStatHandle FTM_PROCESS_HTTP_PIPE("HTTP Pipe");
-static LLTrace::BlockTimerStatHandle FTM_PROCESS_HTTP_GET("HTTP Get");
-static LLTrace::BlockTimerStatHandle FTM_PROCESS_HTTP_PUT("HTTP Put");
-static LLTrace::BlockTimerStatHandle FTM_PROCESS_HTTP_POST("HTTP Post");
-static LLTrace::BlockTimerStatHandle FTM_PROCESS_HTTP_DELETE("HTTP Delete");
-
 LLIOPipe::EStatus LLHTTPPipe::process_impl(
 	const LLChannelDescriptors& channels,
     buffer_ptr_t& buffer,
@@ -145,7 +139,7 @@ LLIOPipe::EStatus LLHTTPPipe::process_impl(
     LLSD& context,
     LLPumpIO* pump)
 {
-	LL_RECORD_BLOCK_TIME(FTM_PROCESS_HTTP_PIPE);
+    LL_PROFILE_ZONE_SCOPED;
 	PUMP_DEBUG;
     LL_DEBUGS() << "LLSDHTTPServer::process_impl" << LL_ENDL;
 
@@ -174,12 +168,10 @@ LLIOPipe::EStatus LLHTTPPipe::process_impl(
 		std::string verb = context[CONTEXT_REQUEST][CONTEXT_VERB];
 		if(verb == HTTP_VERB_GET)
 		{
-			LL_RECORD_BLOCK_TIME(FTM_PROCESS_HTTP_GET);
 			mNode.get(LLHTTPNode::ResponsePtr(mResponse), context);
 		}
 		else if(verb == HTTP_VERB_PUT)
 		{
-			LL_RECORD_BLOCK_TIME(FTM_PROCESS_HTTP_PUT);
 			LLSD input;
 			if (mNode.getContentType() == LLHTTPNode::CONTENT_TYPE_LLSD)
 			{
@@ -195,7 +187,6 @@ LLIOPipe::EStatus LLHTTPPipe::process_impl(
 		}
 		else if(verb == HTTP_VERB_POST)
 		{
-			LL_RECORD_BLOCK_TIME(FTM_PROCESS_HTTP_POST);
 			LLSD input;
 			if (mNode.getContentType() == LLHTTPNode::CONTENT_TYPE_LLSD)
 			{
@@ -211,7 +202,6 @@ LLIOPipe::EStatus LLHTTPPipe::process_impl(
 		}
 		else if(verb == HTTP_VERB_DELETE)
 		{
-			LL_RECORD_BLOCK_TIME(FTM_PROCESS_HTTP_DELETE);
 			mNode.del(LLHTTPNode::ResponsePtr(mResponse), context);
 		}		
 		else if(verb == HTTP_VERB_OPTIONS)
@@ -455,8 +445,6 @@ protected:
  * LLHTTPResponseHeader
  */
 
-static LLTrace::BlockTimerStatHandle FTM_PROCESS_HTTP_HEADER("HTTP Header");
-
 // virtual
 LLIOPipe::EStatus LLHTTPResponseHeader::process_impl(
 	const LLChannelDescriptors& channels,
@@ -465,7 +453,7 @@ LLIOPipe::EStatus LLHTTPResponseHeader::process_impl(
 	LLSD& context,
 	LLPumpIO* pump)
 {
-	LL_RECORD_BLOCK_TIME(FTM_PROCESS_HTTP_HEADER);
+    LL_PROFILE_ZONE_SCOPED;
 	PUMP_DEBUG;
 	if(eos)
 	{
@@ -655,8 +643,6 @@ void LLHTTPResponder::markBad(
 		<< "</body>\n</html>\n";
 }
 
-static LLTrace::BlockTimerStatHandle FTM_PROCESS_HTTP_RESPONDER("HTTP Responder");
-
 // virtual
 LLIOPipe::EStatus LLHTTPResponder::process_impl(
 	const LLChannelDescriptors& channels,
@@ -665,7 +651,7 @@ LLIOPipe::EStatus LLHTTPResponder::process_impl(
 	LLSD& context,
 	LLPumpIO* pump)
 {
-	LL_RECORD_BLOCK_TIME(FTM_PROCESS_HTTP_RESPONDER);
+    LL_PROFILE_ZONE_SCOPED;
 	PUMP_DEBUG;
 	LLIOPipe::EStatus status = STATUS_OK;
 
diff --git a/indra/llmessage/lliosocket.cpp b/indra/llmessage/lliosocket.cpp
index a9cc71c365..321d7286eb 100644
--- a/indra/llmessage/lliosocket.cpp
+++ b/indra/llmessage/lliosocket.cpp
@@ -300,8 +300,6 @@ LLIOSocketReader::~LLIOSocketReader()
 	//LL_DEBUGS() << "Destroying LLIOSocketReader" << LL_ENDL;
 }
 
-static LLTrace::BlockTimerStatHandle FTM_PROCESS_SOCKET_READER("Socket Reader");
-
 // virtual
 LLIOPipe::EStatus LLIOSocketReader::process_impl(
 	const LLChannelDescriptors& channels,
@@ -310,7 +308,7 @@ LLIOPipe::EStatus LLIOSocketReader::process_impl(
 	LLSD& context,
 	LLPumpIO* pump)
 {
-	LL_RECORD_BLOCK_TIME(FTM_PROCESS_SOCKET_READER);
+    LL_PROFILE_ZONE_SCOPED;
 	PUMP_DEBUG;
 	if(!mSource) return STATUS_PRECONDITION_NOT_MET;
 	if(!mInitialized)
@@ -400,7 +398,6 @@ LLIOSocketWriter::~LLIOSocketWriter()
 	//LL_DEBUGS() << "Destroying LLIOSocketWriter" << LL_ENDL;
 }
 
-static LLTrace::BlockTimerStatHandle FTM_PROCESS_SOCKET_WRITER("Socket Writer");
 // virtual
 LLIOPipe::EStatus LLIOSocketWriter::process_impl(
 	const LLChannelDescriptors& channels,
@@ -409,7 +406,7 @@ LLIOPipe::EStatus LLIOSocketWriter::process_impl(
 	LLSD& context,
 	LLPumpIO* pump)
 {
-	LL_RECORD_BLOCK_TIME(FTM_PROCESS_SOCKET_WRITER);
+    LL_PROFILE_ZONE_SCOPED;
 	PUMP_DEBUG;
 	if(!mDestination) return STATUS_PRECONDITION_NOT_MET;
 	if(!mInitialized)
@@ -556,7 +553,6 @@ void LLIOServerSocket::setResponseTimeout(F32 timeout_secs)
 	mResponseTimeout = timeout_secs;
 }
 
-static LLTrace::BlockTimerStatHandle FTM_PROCESS_SERVER_SOCKET("Server Socket");
 // virtual
 LLIOPipe::EStatus LLIOServerSocket::process_impl(
 	const LLChannelDescriptors& channels,
@@ -565,7 +561,7 @@ LLIOPipe::EStatus LLIOServerSocket::process_impl(
 	LLSD& context,
 	LLPumpIO* pump)
 {
-	LL_RECORD_BLOCK_TIME(FTM_PROCESS_SERVER_SOCKET);
+    LL_PROFILE_ZONE_SCOPED;
 	PUMP_DEBUG;
 	if(!pump)
 	{
diff --git a/indra/llmessage/llioutil.cpp b/indra/llmessage/llioutil.cpp
index b8443c0600..850bc2a616 100644
--- a/indra/llmessage/llioutil.cpp
+++ b/indra/llmessage/llioutil.cpp
@@ -45,7 +45,6 @@ LLIOPipe::EStatus LLIOFlush::process_impl(
 }
 
 
-static LLTrace::BlockTimerStatHandle FTM_PROCESS_SLEEP("IO Sleep");
 /** 
  * @class LLIOSleep
  */
@@ -56,7 +55,7 @@ LLIOPipe::EStatus LLIOSleep::process_impl(
 	LLSD& context,
 	LLPumpIO* pump)
 {
-	LL_RECORD_BLOCK_TIME(FTM_PROCESS_SLEEP);
+    LL_PROFILE_ZONE_SCOPED;
 	if(mSeconds > 0.0)
 	{
 		if(pump) pump->sleepChain(mSeconds);
@@ -66,7 +65,6 @@ LLIOPipe::EStatus LLIOSleep::process_impl(
 	return STATUS_DONE;
 }
 
-static LLTrace::BlockTimerStatHandle FTM_PROCESS_ADD_CHAIN("Add Chain");
 /** 
  * @class LLIOAddChain
  */
@@ -77,7 +75,7 @@ LLIOPipe::EStatus LLIOAddChain::process_impl(
 	LLSD& context,
 	LLPumpIO* pump)
 {
-	LL_RECORD_BLOCK_TIME(FTM_PROCESS_ADD_CHAIN);
+    LL_PROFILE_ZONE_SCOPED;
 	pump->addChain(mChain, mTimeout);
 	return STATUS_DONE;
 }
diff --git a/indra/llmessage/llpumpio.cpp b/indra/llmessage/llpumpio.cpp
index a2524e9804..35365665f6 100644
--- a/indra/llmessage/llpumpio.cpp
+++ b/indra/llmessage/llpumpio.cpp
@@ -416,9 +416,6 @@ void LLPumpIO::pump()
 	pump(DEFAULT_POLL_TIMEOUT);
 }
 
-static LLTrace::BlockTimerStatHandle FTM_PUMP_IO("Pump IO");
-static LLTrace::BlockTimerStatHandle FTM_PUMP_POLL("Pump Poll");
-
 LLPumpIO::current_chain_t LLPumpIO::removeRunningChain(LLPumpIO::current_chain_t& run_chain) 
 {
 	std::for_each(
@@ -431,7 +428,7 @@ LLPumpIO::current_chain_t LLPumpIO::removeRunningChain(LLPumpIO::current_chain_t
 //timeout is in microseconds
 void LLPumpIO::pump(const S32& poll_timeout)
 {
-	LL_RECORD_BLOCK_TIME(FTM_PUMP_IO);
+    LL_PROFILE_ZONE_SCOPED;
 	//LL_INFOS() << "LLPumpIO::pump()" << LL_ENDL;
 
 	// Run any pending runners.
@@ -509,7 +506,7 @@ void LLPumpIO::pump(const S32& poll_timeout)
 		S32 count = 0;
 		S32 client_id = 0;
         {
-			LL_RECORD_BLOCK_TIME(FTM_PUMP_POLL);
+            LL_PROFILE_ZONE_SCOPED;
             apr_pollset_poll(mPollset, poll_timeout, &count, &poll_fd);
         }
 		PUMP_DEBUG;
@@ -737,10 +734,9 @@ bool LLPumpIO::respond(
 	return true;
 }
 
-static LLTrace::BlockTimerStatHandle FTM_PUMP_CALLBACK_CHAIN("Chain");
-
 void LLPumpIO::callback()
 {
+    LL_PROFILE_ZONE_SCOPED;
 	//LL_INFOS() << "LLPumpIO::callback()" << LL_ENDL;
 	if(true)
 	{
@@ -756,7 +752,6 @@ void LLPumpIO::callback()
 		callbacks_t::iterator end = mCallbacks.end();
 		for(; it != end; ++it)
 		{
-			LL_RECORD_BLOCK_TIME(FTM_PUMP_CALLBACK_CHAIN);
 			// it's always the first and last time for respone chains
 			(*it).mHead = (*it).mChainLinks.begin();
 			(*it).mInit = true;
diff --git a/indra/llmessage/lltemplatemessagereader.cpp b/indra/llmessage/lltemplatemessagereader.cpp
index 6d5ad0ba08..32f79f0546 100644
--- a/indra/llmessage/lltemplatemessagereader.cpp
+++ b/indra/llmessage/lltemplatemessagereader.cpp
@@ -533,6 +533,8 @@ static LLTrace::BlockTimerStatHandle FTM_PROCESS_MESSAGES("Process Messages");
 // decode a given message
 BOOL LLTemplateMessageReader::decodeData(const U8* buffer, const LLHost& sender )
 {
+    LL_RECORD_BLOCK_TIME(FTM_PROCESS_MESSAGES);
+
 	llassert( mReceiveSize >= 0 );
 	llassert( mCurrentRMessageTemplate);
 	llassert( !mCurrentRMessageData );
@@ -707,12 +709,9 @@ BOOL LLTemplateMessageReader::decodeData(const U8* buffer, const LLHost& sender
 			decode_timer.reset();
 		}
 
+		if( !mCurrentRMessageTemplate->callHandlerFunc(gMessageSystem) )
 		{
-			LL_RECORD_BLOCK_TIME(FTM_PROCESS_MESSAGES);
-			if( !mCurrentRMessageTemplate->callHandlerFunc(gMessageSystem) )
-			{
-				LL_WARNS() << "Message from " << sender << " with no handler function received: " << mCurrentRMessageTemplate->mName << LL_ENDL;
-			}
+			LL_WARNS() << "Message from " << sender << " with no handler function received: " << mCurrentRMessageTemplate->mName << LL_ENDL;
 		}
 
 		if(LLMessageReader::getTimeDecodes() || gMessageSystem->getTimingCallback())
diff --git a/indra/llrender/llfontbitmapcache.cpp b/indra/llrender/llfontbitmapcache.cpp
index f128636ab2..c71e24c83a 100644
--- a/indra/llrender/llfontbitmapcache.cpp
+++ b/indra/llrender/llfontbitmapcache.cpp
@@ -30,8 +30,7 @@
 #include "llfontbitmapcache.h"
 
 LLFontBitmapCache::LLFontBitmapCache()
-:	LLTrace::MemTrackable<LLFontBitmapCache>("LLFontBitmapCache"),
-	mNumComponents(0),
+:	mNumComponents(0),
 	mBitmapWidth(0),
 	mBitmapHeight(0),
 	mBitmapNum(-1),
@@ -124,9 +123,6 @@ BOOL LLFontBitmapCache::nextOpenPos(S32 width, S32 &pos_x, S32 &pos_y, S32& bitm
 			image_gl->createGLTexture(0, image_raw);
 			gGL.getTexUnit(0)->bind(image_gl);
 			image_gl->setFilteringOption(LLTexUnit::TFO_POINT); // was setMipFilterNearest(TRUE, TRUE);
-
-			claimMem(image_raw);
-			claimMem(image_gl);
 		}
 		else
 		{
@@ -156,20 +152,8 @@ void LLFontBitmapCache::destroyGL()
 
 void LLFontBitmapCache::reset()
 {
-	for (std::vector<LLPointer<LLImageRaw> >::iterator it = mImageRawVec.begin(), end_it = mImageRawVec.end();
-		it != end_it;
-		++it)
-	{
-		disclaimMem(**it);
-	}
 	mImageRawVec.clear();
 
-	for (std::vector<LLPointer<LLImageGL> >::iterator it = mImageGLVec.begin(), end_it = mImageGLVec.end();
-		it != end_it;
-		++it)
-	{
-		disclaimMem(**it);
-	}
 	mImageGLVec.clear();
 	
 	mBitmapWidth = 0;
diff --git a/indra/llrender/llfontbitmapcache.h b/indra/llrender/llfontbitmapcache.h
index 75df3a94a7..7de3a6b56f 100644
--- a/indra/llrender/llfontbitmapcache.h
+++ b/indra/llrender/llfontbitmapcache.h
@@ -32,7 +32,7 @@
 
 // Maintain a collection of bitmaps containing rendered glyphs.
 // Generalizes the single-bitmap logic from LLFontFreetype and LLFontGL.
-class LLFontBitmapCache : public LLTrace::MemTrackable<LLFontBitmapCache>
+class LLFontBitmapCache
 {
 public:
 	LLFontBitmapCache();
diff --git a/indra/llrender/llfontfreetype.cpp b/indra/llrender/llfontfreetype.cpp
index e18161e53c..e964d1586f 100644
--- a/indra/llrender/llfontfreetype.cpp
+++ b/indra/llrender/llfontfreetype.cpp
@@ -104,8 +104,7 @@ LLFontGlyphInfo::LLFontGlyphInfo(U32 index)
 }
 
 LLFontFreetype::LLFontFreetype()
-:	LLTrace::MemTrackable<LLFontFreetype>("LLFontFreetype"),
-	mFontBitmapCachep(new LLFontBitmapCache),
+:	mFontBitmapCachep(new LLFontBitmapCache),
 	mAscender(0.f),
 	mDescender(0.f),
 	mLineHeight(0.f),
@@ -222,8 +221,6 @@ BOOL LLFontFreetype::loadFace(const std::string& filename, F32 point_size, F32 v
 	S32 max_char_height = ll_round(0.5f + (y_max - y_min));
 
 	mFontBitmapCachep->init(components, max_char_width, max_char_height);
-	claimMem(mFontBitmapCachep);
-
 
 	if (!mFTFace->charmap)
 	{
@@ -238,7 +235,6 @@ BOOL LLFontFreetype::loadFace(const std::string& filename, F32 point_size, F32 v
 	}
 
 	mName = filename;
-	claimMem(mName);
 	mPointSize = point_size;
 
 	mStyle = LLFontGL::NORMAL;
@@ -586,7 +582,6 @@ void LLFontFreetype::insertGlyphInfo(llwchar wch, LLFontGlyphInfo* gi) const
 	}
 	else
 	{
-		claimMem(gi);
 		mCharGlyphInfoMap[wch] = gi;
 	}
 }
@@ -632,11 +627,9 @@ void LLFontFreetype::resetBitmapCache()
 		it != end_it;
 		++it)
 	{
-		disclaimMem(it->second);
 		delete it->second;
 	}
 	mCharGlyphInfoMap.clear();
-	disclaimMem(mFontBitmapCachep);
 	mFontBitmapCachep->reset();
 
 	// Adding default glyph is skipped for fallback fonts here as well as in loadFace(). 
diff --git a/indra/llrender/llfontfreetype.h b/indra/llrender/llfontfreetype.h
index 1afe84e770..f61f169987 100644
--- a/indra/llrender/llfontfreetype.h
+++ b/indra/llrender/llfontfreetype.h
@@ -76,7 +76,7 @@ struct LLFontGlyphInfo
 
 extern LLFontManager *gFontManagerp;
 
-class LLFontFreetype : public LLRefCount, public LLTrace::MemTrackable<LLFontFreetype>
+class LLFontFreetype : public LLRefCount
 {
 public:
 	LLFontFreetype();
diff --git a/indra/llrender/llfontgl.cpp b/indra/llrender/llfontgl.cpp
index 266399d212..7f734e41f3 100644
--- a/indra/llrender/llfontgl.cpp
+++ b/indra/llrender/llfontgl.cpp
@@ -109,8 +109,6 @@ S32 LLFontGL::getNumFaces(const std::string& filename)
 	return mFontFreetype->getNumFaces(filename);
 }
 
-static LLTrace::BlockTimerStatHandle FTM_RENDER_FONTS("Fonts");
-
 S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, const LLRect& rect, const LLColor4 &color, HAlign halign, VAlign valign, U8 style,
     ShadowType shadow, S32 max_chars, F32* right_x, BOOL use_ellipses) const
 {
@@ -147,7 +145,7 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, const LLRectf& rec
 S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, const LLColor4 &color, HAlign halign, VAlign valign, U8 style, 
 					 ShadowType shadow, S32 max_chars, S32 max_pixels, F32* right_x, BOOL use_ellipses) const
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_FONTS);
+    LL_PROFILE_ZONE_SCOPED;
 
 	if(!sDisplayFont) //do not display texts
 	{
diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp
index b66521132c..4f9aa5f979 100644
--- a/indra/llrender/llgl.cpp
+++ b/indra/llrender/llgl.cpp
@@ -2434,6 +2434,7 @@ void LLGLNamePool::cleanup()
 
 GLuint LLGLNamePool::allocate()
 {
+    LL_PROFILE_ZONE_SCOPED;
 #if LL_GL_NAME_POOLING
 	for (name_list_t::iterator iter = mNameList.begin(); iter != mNameList.end(); ++iter)
 	{
diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp
index b5e1910242..09b1c71f02 100644
--- a/indra/llrender/llimagegl.cpp
+++ b/indra/llrender/llimagegl.cpp
@@ -276,11 +276,10 @@ S32 LLImageGL::dataFormatComponents(S32 dataformat)
 
 //----------------------------------------------------------------------------
 
-static LLTrace::BlockTimerStatHandle FTM_IMAGE_UPDATE_STATS("Image Stats");
 // static
 void LLImageGL::updateStats(F32 current_time)
 {
-	LL_RECORD_BLOCK_TIME(FTM_IMAGE_UPDATE_STATS);
+    LL_PROFILE_ZONE_SCOPED;
 	sLastFrameTime = current_time;
 	sBoundTextureMemory = sCurBoundTextureMemory;
 	sCurBoundTextureMemory = S32Bytes(0);
@@ -313,10 +312,8 @@ void LLImageGL::destroyGL(BOOL save_state)
 			if (save_state && glimage->isGLTextureCreated() && glimage->mComponents)
 			{
 				glimage->mSaveData = new LLImageRaw;
-				glimage->claimMem(glimage->mSaveData);
 				if(!glimage->readBackRaw(glimage->mCurrentDiscardLevel, glimage->mSaveData, false)) //necessary, keep it.
 				{
-					glimage->disclaimMem(glimage->mSaveData);
 					glimage->mSaveData = NULL ;
 				}
 			}
@@ -390,8 +387,7 @@ BOOL LLImageGL::create(LLPointer<LLImageGL>& dest, const LLImageRaw* imageraw, B
 //----------------------------------------------------------------------------
 
 LLImageGL::LLImageGL(BOOL usemipmaps)
-:	LLTrace::MemTrackable<LLImageGL>("LLImageGL"),
-    mSaveData(0), mExternalTexture(FALSE)
+:	mSaveData(0), mExternalTexture(FALSE)
 {
 	init(usemipmaps);
 	setSize(0, 0, 0);
@@ -400,8 +396,7 @@ LLImageGL::LLImageGL(BOOL usemipmaps)
 }
 
 LLImageGL::LLImageGL(U32 width, U32 height, U8 components, BOOL usemipmaps)
-:	LLTrace::MemTrackable<LLImageGL>("LLImageGL"),
-    mSaveData(0), mExternalTexture(FALSE)
+:	mSaveData(0), mExternalTexture(FALSE)
 {
 	llassert( components <= 4 );
 	init(usemipmaps);
@@ -411,8 +406,7 @@ LLImageGL::LLImageGL(U32 width, U32 height, U8 components, BOOL usemipmaps)
 }
 
 LLImageGL::LLImageGL(const LLImageRaw* imageraw, BOOL usemipmaps)
-:	LLTrace::MemTrackable<LLImageGL>("LLImageGL"),
-    mSaveData(0), mExternalTexture(FALSE)
+:	mSaveData(0), mExternalTexture(FALSE)
 {
 	init(usemipmaps);
 	setSize(0, 0, 0);
@@ -430,7 +424,6 @@ LLImageGL::LLImageGL(
     LLGLenum formatPrimary,
     LLGLenum formatType,
     LLTexUnit::eTextureAddressMode addressMode)
-    : LLTrace::MemTrackable<LLImageGL>("LLImageGL"), mSaveData(0), mExternalTexture(TRUE)
 {
     init(false);
     mTexName = texName;
@@ -682,10 +675,9 @@ void LLImageGL::setImage(const LLImageRaw* imageraw)
 	setImage(rawdata, FALSE);
 }
 
-static LLTrace::BlockTimerStatHandle FTM_SET_IMAGE("setImage");
 BOOL LLImageGL::setImage(const U8* data_in, BOOL data_hasmips, S32 usename)
 {
-	LL_RECORD_BLOCK_TIME(FTM_SET_IMAGE);
+    LL_PROFILE_ZONE_SCOPED;
 	bool is_compressed = false;
 
     switch (mFormatPrimary)
@@ -746,8 +738,6 @@ BOOL LLImageGL::setImage(const U8* data_in, BOOL data_hasmips, S32 usename)
 				}
 				else
 				{
-// 					LL_RECORD_BLOCK_TIME(FTM_TEMP4);
-
 					if(mFormatSwapBytes)
 					{
 						glPixelStorei(GL_UNPACK_SWAP_BYTES, 1);
@@ -778,8 +768,6 @@ BOOL LLImageGL::setImage(const U8* data_in, BOOL data_hasmips, S32 usename)
 			{
 				stop_glerror();
 				{
-// 					LL_RECORD_BLOCK_TIME(FTM_TEMP4);
-
 					if(mFormatSwapBytes)
 					{
 						glPixelStorei(GL_UNPACK_SWAP_BYTES, 1);
@@ -889,7 +877,6 @@ BOOL LLImageGL::setImage(const U8* data_in, BOOL data_hasmips, S32 usename)
 					llassert(w > 0 && h > 0 && cur_mip_data);
 					(void)cur_mip_data;
 					{
-// 						LL_RECORD_BLOCK_TIME(FTM_TEMP4);
 						if(mFormatSwapBytes)
 						{
 							glPixelStorei(GL_UNPACK_SWAP_BYTES, 1);
@@ -1203,10 +1190,9 @@ BOOL LLImageGL::setSubImageFromFrameBuffer(S32 fb_x, S32 fb_y, S32 x_pos, S32 y_
 }
 
 // static
-static LLTrace::BlockTimerStatHandle FTM_GENERATE_TEXTURES("generate textures");
 void LLImageGL::generateTextures(S32 numTextures, U32 *textures)
 {
-	LL_RECORD_BLOCK_TIME(FTM_GENERATE_TEXTURES);
+    LL_PROFILE_ZONE_SCOPED;
 	glGenTextures(numTextures, textures);
 }
 
@@ -1220,10 +1206,9 @@ void LLImageGL::deleteTextures(S32 numTextures, const 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)
 {
-    LL_RECORD_BLOCK_TIME(FTM_SET_MANUAL_IMAGE);
+    LL_PROFILE_ZONE_SCOPED;
     bool use_scratch = false;
     U32* scratch = NULL;
     if (LLRender::sGLCoreProfile)
@@ -1338,10 +1323,9 @@ void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 widt
 
 //create an empty GL texture: just create a texture name
 //the texture is assiciate with some image by calling glTexImage outside LLImageGL
-static LLTrace::BlockTimerStatHandle FTM_CREATE_GL_TEXTURE1("createGLTexture()");
 BOOL LLImageGL::createGLTexture()
 {
-	LL_RECORD_BLOCK_TIME(FTM_CREATE_GL_TEXTURE1);
+    LL_PROFILE_ZONE_SCOPED;
 	if (gGLManager.mIsDisabled)
 	{
 		LL_WARNS() << "Trying to create a texture while GL is disabled!" << LL_ENDL;
@@ -1371,10 +1355,9 @@ BOOL LLImageGL::createGLTexture()
 	return TRUE ;
 }
 
-static LLTrace::BlockTimerStatHandle FTM_CREATE_GL_TEXTURE2("createGLTexture(raw)");
 BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename/*=0*/, BOOL to_create, S32 category)
 {
-	LL_RECORD_BLOCK_TIME(FTM_CREATE_GL_TEXTURE2);
+    LL_PROFILE_ZONE_SCOPED;
 	if (gGLManager.mIsDisabled)
 	{
 		LL_WARNS() << "Trying to create a texture while GL is disabled!" << LL_ENDL;
@@ -1485,10 +1468,9 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S
 	return createGLTexture(discard_level, rawdata, FALSE, usename);
 }
 
-static LLTrace::BlockTimerStatHandle FTM_CREATE_GL_TEXTURE3("createGLTexture3(data)");
 BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_hasmips, S32 usename)
 {
-    LL_RECORD_BLOCK_TIME(FTM_CREATE_GL_TEXTURE3);
+    LL_PROFILE_ZONE_SCOPED;
     llassert(data_in);
     stop_glerror();
 
@@ -1595,9 +1577,7 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_
         mNewTexName = 0;
     }
     
-    disclaimMem(mTextureMemory);
     mTextureMemory = (S32Bytes)getMipBytes(mCurrentDiscardLevel);
-    claimMem(mTextureMemory);
     sGlobalTextureMemory += mTextureMemory;
     mTexelsInGLTexture = getWidth() * getHeight();
 
@@ -1735,7 +1715,6 @@ void LLImageGL::destroyGLTexture()
 		if(mTextureMemory != S32Bytes(0))
 		{
 			sGlobalTextureMemory -= mTextureMemory;
-			disclaimMem(mTextureMemory);
 			mTextureMemory = (S32Bytes)0;
 		}
 		
@@ -2088,7 +2067,6 @@ U32 LLImageGL::createPickMask(S32 pWidth, S32 pHeight)
 	U32 size = pick_width * pick_height;
 	size = (size + 7) / 8; // pixelcount-to-bits
 	mPickMask = new U8[size];
-	claimMem(size);
 	mPickMaskWidth = pick_width - 1;
 	mPickMaskHeight = pick_height - 1;
 
@@ -2103,7 +2081,6 @@ void LLImageGL::freePickMask()
 	// pickmask validity depends on old image size, delete it
 	if (mPickMask != NULL)
 	{
-		disclaimMem((mPickMaskWidth * mPickMaskHeight + 7) / 8);
 		delete [] mPickMask;
 	}
 	mPickMask = NULL;
diff --git a/indra/llrender/llimagegl.h b/indra/llrender/llimagegl.h
index da626a1093..95b60bd0bd 100644
--- a/indra/llrender/llimagegl.h
+++ b/indra/llrender/llimagegl.h
@@ -46,7 +46,7 @@ class LLWindow;
 #define MEGA_BYTES_TO_BYTES(x) ((x) << 20)
 
 //============================================================================
-class LLImageGL : public LLRefCount, public LLTrace::MemTrackable<LLImageGL>
+class LLImageGL : public LLRefCount
 {
 	friend class LLTexUnit;
 public:
diff --git a/indra/llrender/llrender2dutils.cpp b/indra/llrender/llrender2dutils.cpp
index dd34f3e383..5a942996be 100644
--- a/indra/llrender/llrender2dutils.cpp
+++ b/indra/llrender/llrender2dutils.cpp
@@ -1083,8 +1083,6 @@ void gl_rect_2d_simple( S32 width, S32 height )
 	gGL.end();
 }
 
-static LLTrace::BlockTimerStatHandle FTM_RENDER_SEGMENTED_RECT ("Render segmented rectangle");
-
 void gl_segmented_rect_2d_tex(const S32 left, 
 							  const S32 top, 
 							  const S32 right, 
@@ -1094,7 +1092,7 @@ void gl_segmented_rect_2d_tex(const S32 left,
 							  const S32 border_size, 
 							  const U32 edges)
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_SEGMENTED_RECT);
+    LL_PROFILE_ZONE_SCOPED;
 
 	S32 width = llabs(right - left);
 	S32 height = llabs(top - bottom);
@@ -1253,7 +1251,7 @@ void gl_segmented_rect_2d_fragment_tex(const LLRect& rect,
 	const F32 end_fragment, 
 	const U32 edges)
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_SEGMENTED_RECT);
+    LL_PROFILE_ZONE_SCOPED;
 	const S32 left = rect.mLeft;
 	const S32 right = rect.mRight;
 	const S32 top = rect.mTop;
@@ -1440,7 +1438,7 @@ void gl_segmented_rect_2d_fragment_tex(const LLRect& rect,
 void gl_segmented_rect_3d_tex(const LLRectf& clip_rect, const LLRectf& center_uv_rect, const LLRectf& center_draw_rect, 
 							 const LLVector3& width_vec, const LLVector3& height_vec)
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_SEGMENTED_RECT);
+    LL_PROFILE_ZONE_SCOPED;
 
 	gGL.begin(LLRender::QUADS);
 	{
diff --git a/indra/llrender/lltexture.h b/indra/llrender/lltexture.h
index 256d85ce5a..e890a5a30b 100644
--- a/indra/llrender/lltexture.h
+++ b/indra/llrender/lltexture.h
@@ -42,7 +42,7 @@ class LLFontGL ;
 //
 //this is an abstract class as the parent for the class LLGLTexture
 //
-class LLTexture : public virtual LLRefCount, public LLTrace::MemTrackable<LLTexture>
+class LLTexture : public virtual LLRefCount
 {
 	friend class LLTexUnit ;
 	friend class LLFontGL ;
@@ -52,7 +52,6 @@ protected:
 
 public:
 	LLTexture()
-	:	LLTrace::MemTrackable<LLTexture>("LLTexture")
 	{}
 
 	//
diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp
index 7e726df907..5ea07ddcb1 100644
--- a/indra/llrender/llvertexbuffer.cpp
+++ b/indra/llrender/llvertexbuffer.cpp
@@ -805,13 +805,15 @@ void LLVertexBuffer::draw(U32 mode, U32 count, U32 indices_offset) const
 	placeFence();
 }
 
-static LLTrace::BlockTimerStatHandle FTM_GL_DRAW_ARRAYS("GL draw arrays");
+
 void LLVertexBuffer::drawArrays(U32 mode, U32 first, U32 count) const
 {
+    LL_PROFILE_ZONE_SCOPED;
     llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShaderPtr != NULL);
     mMappable = false;
     gGL.syncMatrices();
 
+#ifndef LL_RELEASE_FOR_DOWNLOAD
     llassert(mNumVerts >= 0);
     if (first >= (U32)mNumVerts ||
         first + count > (U32)mNumVerts)
@@ -839,16 +841,11 @@ void LLVertexBuffer::drawArrays(U32 mode, U32 first, U32 count) const
         LL_ERRS() << "Invalid draw mode: " << mode << LL_ENDL;
         return;
     }
+#endif
 
     {
-        LL_RECORD_BLOCK_TIME(FTM_GL_DRAW_ARRAYS);
-        stop_glerror();
-        LLGLSLShader::startProfile();
-        stop_glerror();
         LL_PROFILER_GPU_ZONEC("gl.DrawArrays", 0xFF4040)
             glDrawArrays(sGLMode[mode], first, count);
-        stop_glerror();
-        LLGLSLShader::stopProfile(count, mode);
     }
 
     stop_glerror();
@@ -949,8 +946,7 @@ S32 LLVertexBuffer::determineUsage(S32 usage)
 }
 
 LLVertexBuffer::LLVertexBuffer(U32 typemask, S32 usage) 
-:	LLTrace::MemTrackable<LLVertexBuffer>("LLVertexBuffer"),
-	LLRefCount(),
+:	LLRefCount(),
 
 	mNumVerts(0),
 	mNumIndices(0),
@@ -1095,9 +1091,7 @@ void LLVertexBuffer::waitFence() const
 
 void LLVertexBuffer::genBuffer(U32 size)
 {
-	disclaimMem(mSize);
 	mSize = vbo_block_size(size);
-	claimMem(mSize);
 
 	if (mUsage == GL_STREAM_DRAW_ARB)
 	{
@@ -1193,9 +1187,7 @@ bool LLVertexBuffer::createGLBuffer(U32 size)
 		static int gl_buffer_idx = 0;
 		mGLBuffer = ++gl_buffer_idx;
 		mMappedData = (U8*)ll_aligned_malloc_16(size);
-		disclaimMem(mSize);
 		mSize = size;
-		claimMem(mSize);
 	}
 
 	if (!mMappedData)
@@ -1365,8 +1357,6 @@ bool LLVertexBuffer::allocateBuffer(S32 nverts, S32 nindices, bool create)
 	return success;
 }
 
-static LLTrace::BlockTimerStatHandle FTM_SETUP_VERTEX_ARRAY("Setup VAO");
-
 void LLVertexBuffer::setupVertexArray()
 {
 	if (!mGLArray)
@@ -1374,7 +1364,7 @@ void LLVertexBuffer::setupVertexArray()
 		return;
 	}
 
-	LL_RECORD_BLOCK_TIME(FTM_SETUP_VERTEX_ARRAY);
+    LL_PROFILE_ZONE_SCOPED;
 #if GL_ARB_vertex_array_object
 	glBindVertexArray(mGLArray);
 #endif
@@ -1547,12 +1537,11 @@ bool expand_region(LLVertexBuffer::MappedRegion& region, S32 index, S32 count)
 	return true;
 }
 
-static LLTrace::BlockTimerStatHandle FTM_VBO_MAP_BUFFER_RANGE("VBO Map Range");
-static LLTrace::BlockTimerStatHandle FTM_VBO_MAP_BUFFER("VBO Map");
 
 // Map for data access
 volatile U8* LLVertexBuffer::mapVertexBuffer(S32 type, S32 index, S32 count, bool map_range)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	bindGLBuffer(true);
 	if (mFinal)
 	{
@@ -1619,7 +1608,6 @@ volatile U8* LLVertexBuffer::mapVertexBuffer(S32 type, S32 index, S32 count, boo
 					if (map_range)
 					{
 #ifdef GL_ARB_map_buffer_range
-						LL_RECORD_BLOCK_TIME(FTM_VBO_MAP_BUFFER_RANGE);
 						S32 offset = mOffsets[type] + sTypeSize[type]*index;
 						S32 length = (sTypeSize[type]*count+0xF) & ~0xF;
 						src = (U8*) glMapBufferRange(GL_ARRAY_BUFFER_ARB, offset, length, 
@@ -1643,7 +1631,6 @@ volatile U8* LLVertexBuffer::mapVertexBuffer(S32 type, S32 index, S32 count, boo
 							}
 						}
 
-						LL_RECORD_BLOCK_TIME(FTM_VBO_MAP_BUFFER);
 						src = (U8*) glMapBufferRange(GL_ARRAY_BUFFER_ARB, 0, mSize, 
 							GL_MAP_WRITE_BIT | 
 							GL_MAP_FLUSH_EXPLICIT_BIT);
@@ -1729,11 +1716,9 @@ volatile U8* LLVertexBuffer::mapVertexBuffer(S32 type, S32 index, S32 count, boo
 }
 
 
-static LLTrace::BlockTimerStatHandle FTM_VBO_MAP_INDEX_RANGE("IBO Map Range");
-static LLTrace::BlockTimerStatHandle FTM_VBO_MAP_INDEX("IBO Map");
-
 volatile U8* LLVertexBuffer::mapIndexBuffer(S32 index, S32 count, bool map_range)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	bindGLIndices(true);
 	if (mFinal)
 	{
@@ -1808,7 +1793,6 @@ volatile U8* LLVertexBuffer::mapIndexBuffer(S32 index, S32 count, bool map_range
 					if (map_range)
 					{
 #ifdef GL_ARB_map_buffer_range
-						LL_RECORD_BLOCK_TIME(FTM_VBO_MAP_INDEX_RANGE);
 						S32 offset = sizeof(U16)*index;
 						S32 length = sizeof(U16)*count;
 						src = (U8*) glMapBufferRange(GL_ELEMENT_ARRAY_BUFFER_ARB, offset, length, 
@@ -1820,7 +1804,6 @@ volatile U8* LLVertexBuffer::mapIndexBuffer(S32 index, S32 count, bool map_range
 					else
 					{
 #ifdef GL_ARB_map_buffer_range
-						LL_RECORD_BLOCK_TIME(FTM_VBO_MAP_INDEX);
 						src = (U8*) glMapBufferRange(GL_ELEMENT_ARRAY_BUFFER_ARB, 0, sizeof(U16)*mNumIndices, 
 							GL_MAP_WRITE_BIT | 
 							GL_MAP_FLUSH_EXPLICIT_BIT);
@@ -1844,7 +1827,6 @@ volatile U8* LLVertexBuffer::mapIndexBuffer(S32 index, S32 count, bool map_range
 				}
 				else
 				{
-					LL_RECORD_BLOCK_TIME(FTM_VBO_MAP_INDEX);
 					map_range = false;
 					src = (U8*) glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
 				}
@@ -1895,13 +1877,6 @@ volatile U8* LLVertexBuffer::mapIndexBuffer(S32 index, S32 count, bool map_range
 	}
 }
 
-static LLTrace::BlockTimerStatHandle FTM_VBO_UNMAP("VBO Unmap");
-static LLTrace::BlockTimerStatHandle FTM_VBO_FLUSH_RANGE("Flush VBO Range");
-
-
-static LLTrace::BlockTimerStatHandle FTM_IBO_UNMAP("IBO Unmap");
-static LLTrace::BlockTimerStatHandle FTM_IBO_FLUSH_RANGE("Flush IBO Range");
-
 void LLVertexBuffer::unmapBuffer()
 {
 	if (!useVBOs())
@@ -1910,10 +1885,10 @@ void LLVertexBuffer::unmapBuffer()
 	}
 
 	bool updated_all = false;
-
+    LL_PROFILE_ZONE_SCOPED;
 	if (mMappedData && mVertexLocked)
 	{
-		LL_RECORD_BLOCK_TIME(FTM_VBO_UNMAP);
+        LL_PROFILE_ZONE_NAMED("unmapBuffer - vertex");
 		bindGLBuffer(true);
 		updated_all = mIndexLocked; //both vertex and index buffers done updating
 
@@ -1960,7 +1935,7 @@ void LLVertexBuffer::unmapBuffer()
 			{
 				if (!mMappedVertexRegions.empty())
 				{
-					stop_glerror();
+                    LL_PROFILE_ZONE_NAMED("unmapBuffer - flush vertex");
 					for (U32 i = 0; i < mMappedVertexRegions.size(); ++i)
 					{
 						const MappedRegion& region = mMappedVertexRegions[i];
@@ -1968,18 +1943,16 @@ void LLVertexBuffer::unmapBuffer()
 						S32 length = sTypeSize[region.mType]*region.mCount;
 						if (gGLManager.mHasMapBufferRange)
 						{
-							LL_RECORD_BLOCK_TIME(FTM_VBO_FLUSH_RANGE);
 #ifdef GL_ARB_map_buffer_range
 							glFlushMappedBufferRange(GL_ARRAY_BUFFER_ARB, offset, length);
 #endif
 						}
 						else if (gGLManager.mHasFlushBufferRange)
-						{
+                        {
 #ifndef LL_MESA_HEADLESS
 							glFlushMappedBufferRangeAPPLE(GL_ARRAY_BUFFER_ARB, offset, length);
 #endif
 						}
-						stop_glerror();
 					}
 
 					mMappedVertexRegions.clear();
@@ -1998,7 +1971,7 @@ void LLVertexBuffer::unmapBuffer()
 	
 	if (mMappedIndexData && mIndexLocked)
 	{
-		LL_RECORD_BLOCK_TIME(FTM_IBO_UNMAP);
+        LL_PROFILE_ZONE_NAMED("unmapBuffer - index");
 		bindGLIndices();
 		if(!mMappable)
 		{
@@ -2044,12 +2017,12 @@ void LLVertexBuffer::unmapBuffer()
 				{
 					for (U32 i = 0; i < mMappedIndexRegions.size(); ++i)
 					{
+                        LL_PROFILE_ZONE_NAMED("unmapBuffer - flush index");
 						const MappedRegion& region = mMappedIndexRegions[i];
 						S32 offset = region.mIndex >= 0 ? sizeof(U16)*region.mIndex : 0;
 						S32 length = sizeof(U16)*region.mCount;
 						if (gGLManager.mHasMapBufferRange)
 						{
-							LL_RECORD_BLOCK_TIME(FTM_IBO_FLUSH_RANGE);
 #ifdef GL_ARB_map_buffer_range
 							glFlushMappedBufferRange(GL_ELEMENT_ARRAY_BUFFER_ARB, offset, length);
 #endif
@@ -2068,9 +2041,8 @@ void LLVertexBuffer::unmapBuffer()
 					mMappedIndexRegions.clear();
 				}
 			}
-			stop_glerror();
-			glUnmapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB);
-			stop_glerror();
+			
+            glUnmapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB);
 
 			mMappedIndexData = NULL;
 		}
@@ -2193,13 +2165,12 @@ bool LLVertexBuffer::getClothWeightStrider(LLStrider<LLVector4>& strider, S32 in
 
 //----------------------------------------------------------------------------
 
-static LLTrace::BlockTimerStatHandle FTM_BIND_GL_ARRAY("Bind Array");
 bool LLVertexBuffer::bindGLArray()
 {
 	if (mGLArray && sGLRenderArray != mGLArray)
 	{
 		{
-			LL_RECORD_BLOCK_TIME(FTM_BIND_GL_ARRAY);
+            LL_PROFILE_ZONE_SCOPED;
 #if GL_ARB_vertex_array_object
 			glBindVertexArray(mGLArray);
 #endif
@@ -2216,8 +2187,6 @@ bool LLVertexBuffer::bindGLArray()
 	return false;
 }
 
-static LLTrace::BlockTimerStatHandle FTM_BIND_GL_BUFFER("Bind Buffer");
-
 bool LLVertexBuffer::bindGLBuffer(bool force_bind)
 {
 	bindGLArray();
@@ -2226,8 +2195,7 @@ bool LLVertexBuffer::bindGLBuffer(bool force_bind)
 
 	if (useVBOs() && (force_bind || (mGLBuffer && (mGLBuffer != sGLRenderBuffer || !sVBOActive))))
 	{
-		//LL_RECORD_BLOCK_TIME(FTM_BIND_GL_BUFFER);
-		
+        LL_PROFILE_ZONE_SCOPED;
 		glBindBufferARB(GL_ARRAY_BUFFER_ARB, mGLBuffer);
 		sGLRenderBuffer = mGLBuffer;
 		sBindCount++;
@@ -2256,16 +2224,14 @@ bool LLVertexBuffer::bindGLBufferFast()
     return false;
 }
 
-static LLTrace::BlockTimerStatHandle FTM_BIND_GL_INDICES("Bind Indices");
-
 bool LLVertexBuffer::bindGLIndices(bool force_bind)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	bindGLArray();
 
 	bool ret = false;
 	if (useVBOs() && (force_bind || (mGLIndices && (mGLIndices != sGLRenderIndices || !sIBOActive))))
 	{
-		LL_RECORD_BLOCK_TIME(FTM_BIND_GL_INDICES);
 		/*if (sMapped)
 		{
 			LL_ERRS() << "VBO bound while another VBO mapped!" << LL_ENDL;
diff --git a/indra/llrender/llvertexbuffer.h b/indra/llrender/llvertexbuffer.h
index fad474a143..1b400b3aad 100644
--- a/indra/llrender/llvertexbuffer.h
+++ b/indra/llrender/llvertexbuffer.h
@@ -98,7 +98,7 @@ public:
 //============================================================================
 // base class 
 class LLPrivateMemoryPool;
-class LLVertexBuffer : public LLRefCount, public LLTrace::MemTrackable<LLVertexBuffer>
+class LLVertexBuffer : public LLRefCount
 {
 public:
 	class MappedRegion
@@ -113,8 +113,7 @@ public:
 	};
 
 	LLVertexBuffer(const LLVertexBuffer& rhs)
-	:	LLTrace::MemTrackable<LLVertexBuffer>("LLVertexBuffer"),
-		mUsage(rhs.mUsage)
+	:	mUsage(rhs.mUsage)
 	{
 		*this = rhs;
 	}
diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp
index 0e42922543..03efd09689 100644
--- a/indra/llui/llfloater.cpp
+++ b/indra/llui/llfloater.cpp
@@ -3268,11 +3268,9 @@ boost::signals2::connection LLFloater::setCloseCallback( const commit_signal_t::
 	return mCloseSignal.connect(cb);
 }
 
-LLTrace::BlockTimerStatHandle POST_BUILD("Floater Post Build");
-static LLTrace::BlockTimerStatHandle FTM_EXTERNAL_FLOATER_LOAD("Load Extern Floater Reference");
-
 bool LLFloater::initFloaterXML(LLXMLNodePtr node, LLView *parent, const std::string& filename, LLXMLNodePtr output_node)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	Params default_params(LLUICtrlFactory::getDefaultParams<LLFloater>());
 	Params params(default_params);
 
@@ -3299,7 +3297,6 @@ bool LLFloater::initFloaterXML(LLXMLNodePtr node, LLView *parent, const std::str
 
 		LLUICtrlFactory::instance().pushFileName(xml_filename);
 
-		LL_RECORD_BLOCK_TIME(FTM_EXTERNAL_FLOATER_LOAD);
 		if (!LLUICtrlFactory::getLayeredXMLNode(xml_filename, referenced_xml))
 		{
 			LL_WARNS() << "Couldn't parse panel from: " << xml_filename << LL_ENDL;
@@ -3375,12 +3372,8 @@ bool LLFloater::initFloaterXML(LLXMLNodePtr node, LLView *parent, const std::str
 	}
 
 	BOOL result;
-	{
-		LL_RECORD_BLOCK_TIME(POST_BUILD);
-
-		result = postBuild();
-	}
-
+	result = postBuild();
+	
 	if (!result)
 	{
 		LL_ERRS() << "Failed to construct floater " << getName() << LL_ENDL;
@@ -3424,11 +3417,9 @@ bool LLFloater::isVisible(const LLFloater* floater)
     return floater && floater->getVisible();
 }
 
-static LLTrace::BlockTimerStatHandle FTM_BUILD_FLOATERS("Build Floaters");
-
 bool LLFloater::buildFromFile(const std::string& filename)
 {
-	LL_RECORD_BLOCK_TIME(FTM_BUILD_FLOATERS);
+    LL_PROFILE_ZONE_SCOPED;
 	LLXMLNodePtr root;
 
 	if (!LLUICtrlFactory::getLayeredXMLNode(filename, root))
diff --git a/indra/llui/llfolderview.cpp b/indra/llui/llfolderview.cpp
index 622c9edba7..0996e82bf7 100644
--- a/indra/llui/llfolderview.cpp
+++ b/indra/llui/llfolderview.cpp
@@ -189,7 +189,6 @@ LLFolderView::LLFolderView(const Params& p)
 	mViewModel(p.view_model),
     mGroupedItemModel(p.grouped_item_model)
 {
-	claimMem(mViewModel);
     LLPanel* panel = p.parent_panel;
     mParentPanel = panel->getHandle();
 	mViewModel->setFolderView(this);
@@ -337,11 +336,9 @@ S32 LLFolderView::arrange( S32* unused_width, S32* unused_height )
 	return ll_round(mTargetHeight);
 }
 
-static LLTrace::BlockTimerStatHandle FTM_FILTER("Filter Folder View");
-
 void LLFolderView::filter( LLFolderViewFilter& filter )
 {
-	LL_RECORD_BLOCK_TIME(FTM_FILTER);
+    LL_PROFILE_ZONE_SCOPED;
     static LLCachedControl<S32> time_visible(*LLUI::getInstance()->mSettingGroups["config"], "FilterItemsMaxTimePerFrameVisible", 10);
     static LLCachedControl<S32> time_invisible(*LLUI::getInstance()->mSettingGroups["config"], "FilterItemsMaxTimePerFrameUnvisible", 1);
     filter.resetTime(llclamp((mParentPanel.get()->getVisible() ? time_visible() : time_invisible()), 1, 100));
@@ -503,10 +500,9 @@ BOOL LLFolderView::changeSelection(LLFolderViewItem* selection, BOOL selected)
 	return rv;
 }
 
-static LLTrace::BlockTimerStatHandle FTM_SANITIZE_SELECTION("Sanitize Selection");
 void LLFolderView::sanitizeSelection()
 {
-	LL_RECORD_BLOCK_TIME(FTM_SANITIZE_SELECTION);
+    LL_PROFILE_ZONE_SCOPED;
 	// store off current item in case it is automatically deselected
 	// and we want to preserve context
 	LLFolderViewItem* original_selected_item = getCurSelectedItem();
@@ -1621,7 +1617,6 @@ void LLFolderView::setShowSingleSelection(bool show)
 	}
 }
 
-static LLTrace::BlockTimerStatHandle FTM_AUTO_SELECT("Open and Select");
 static LLTrace::BlockTimerStatHandle FTM_INVENTORY("Inventory");
 
 // Main idle routine
@@ -1657,7 +1652,6 @@ void LLFolderView::update()
 	// automatically show matching items, and select first one if we had a selection
 	if (mNeedsAutoSelect)
 	{
-		LL_RECORD_BLOCK_TIME(FTM_AUTO_SELECT);
 		// select new item only if a filtered item not currently selected and there was a selection
 		LLFolderViewItem* selected_itemp = mSelectedItems.empty() ? NULL : mSelectedItems.back();
 		if (!mAutoSelectOverride && selected_itemp && !selected_itemp->getViewModelItem()->potentiallyVisible())
diff --git a/indra/llui/llfolderviewmodel.h b/indra/llui/llfolderviewmodel.h
index e62b2779dd..093e213be3 100644
--- a/indra/llui/llfolderviewmodel.h
+++ b/indra/llui/llfolderviewmodel.h
@@ -108,11 +108,10 @@ public:
 	virtual S32 				getFirstRequiredGeneration() const = 0;
 };
 
-class LLFolderViewModelInterface : public LLTrace::MemTrackable<LLFolderViewModelInterface>
+class LLFolderViewModelInterface
 {
 public:
 	LLFolderViewModelInterface() 
-	:	LLTrace::MemTrackable<LLFolderViewModelInterface>("LLFolderViewModelInterface") 
 	{}
 
 	virtual ~LLFolderViewModelInterface() {}
@@ -133,11 +132,10 @@ public:
 
 // This is an abstract base class that users of the folderview classes
 // would use to bridge the folder view with the underlying data
-class LLFolderViewModelItem : public LLRefCount, public LLTrace::MemTrackable<LLFolderViewModelItem>
+class LLFolderViewModelItem : public LLRefCount
 {
 public:
 	LLFolderViewModelItem() 
-	:	LLTrace::MemTrackable<LLFolderViewModelItem>("LLFolderViewModelItem") 
 	{}
 
 	virtual ~LLFolderViewModelItem() { }
diff --git a/indra/llui/lllayoutstack.cpp b/indra/llui/lllayoutstack.cpp
index 29a156e933..528d2e70ad 100644
--- a/indra/llui/lllayoutstack.cpp
+++ b/indra/llui/lllayoutstack.cpp
@@ -340,8 +340,6 @@ void LLLayoutStack::collapsePanel(LLPanel* panel, BOOL collapsed)
 	mNeedsLayout = true;
 }
 
-static LLTrace::BlockTimerStatHandle FTM_UPDATE_LAYOUT("Update LayoutStacks");
-
 class LLImagePanel : public LLPanel
 {
 public:
@@ -369,7 +367,7 @@ private:
 
 void LLLayoutStack::updateLayout()
 {	
-	LL_RECORD_BLOCK_TIME(FTM_UPDATE_LAYOUT);
+    LL_PROFILE_ZONE_SCOPED;
 
 	if (!mNeedsLayout) return;
 
diff --git a/indra/llui/llpanel.cpp b/indra/llui/llpanel.cpp
index 00da0f5fec..f770920c4a 100644
--- a/indra/llui/llpanel.cpp
+++ b/indra/llui/llpanel.cpp
@@ -800,14 +800,12 @@ boost::signals2::connection LLPanel::setVisibleCallback( const commit_signal_t::
 	return mVisibleSignal->connect(cb);
 }
 
-static LLTrace::BlockTimerStatHandle FTM_BUILD_PANELS("Build Panels");
-
 //-----------------------------------------------------------------------------
 // buildPanel()
 //-----------------------------------------------------------------------------
 BOOL LLPanel::buildFromFile(const std::string& filename, const LLPanel::Params& default_params)
 {
-	LL_RECORD_BLOCK_TIME(FTM_BUILD_PANELS);
+    LL_PROFILE_ZONE_SCOPED;
 	BOOL didPost = FALSE;
 	LLXMLNodePtr root;
 
diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp
index de644185fd..c70085b72f 100644
--- a/indra/llui/llscrolllistctrl.cpp
+++ b/indra/llui/llscrolllistctrl.cpp
@@ -3045,10 +3045,9 @@ LLScrollListColumn* LLScrollListCtrl::getColumn(const std::string& name)
 	return NULL;
 }
 
-LLTrace::BlockTimerStatHandle FTM_ADD_SCROLLLIST_ELEMENT("Add Scroll List Item");
 LLScrollListItem* LLScrollListCtrl::addElement(const LLSD& element, EAddPosition pos, void* userdata)
 {
-	LL_RECORD_BLOCK_TIME(FTM_ADD_SCROLLLIST_ELEMENT);
+    LL_PROFILE_ZONE_SCOPED;
 	LLScrollListItem::Params item_params;
 	LLParamSDParser parser;
 	parser.readSD(element, item_params);
@@ -3058,14 +3057,14 @@ LLScrollListItem* LLScrollListCtrl::addElement(const LLSD& element, EAddPosition
 
 LLScrollListItem* LLScrollListCtrl::addRow(const LLScrollListItem::Params& item_p, EAddPosition pos)
 {
-	LL_RECORD_BLOCK_TIME(FTM_ADD_SCROLLLIST_ELEMENT);
+    LL_PROFILE_ZONE_SCOPED;
 	LLScrollListItem *new_item = new LLScrollListItem(item_p);
 	return addRow(new_item, item_p, pos);
 }
 
 LLScrollListItem* LLScrollListCtrl::addRow(LLScrollListItem *new_item, const LLScrollListItem::Params& item_p, EAddPosition pos)
 {
-	LL_RECORD_BLOCK_TIME(FTM_ADD_SCROLLLIST_ELEMENT);
+    LL_PROFILE_ZONE_SCOPED;
 	if (!item_p.validateBlock() || !new_item) return NULL;
 	new_item->setNumColumns(mColumns.size());
 
diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp
index 20bea7fe24..4274c81645 100644
--- a/indra/llui/lltextbase.cpp
+++ b/indra/llui/lltextbase.cpp
@@ -1484,11 +1484,9 @@ S32 LLTextBase::getLeftOffset(S32 width)
 	}
 }
 
-
-static LLTrace::BlockTimerStatHandle FTM_TEXT_REFLOW ("Text Reflow");
 void LLTextBase::reflow()
 {
-	LL_RECORD_BLOCK_TIME(FTM_TEXT_REFLOW);
+    LL_PROFILE_ZONE_SCOPED;
 
 	updateSegments();
 
@@ -1833,10 +1831,9 @@ void LLTextBase::removeDocumentChild(LLView* view)
 }
 
 
-static LLTrace::BlockTimerStatHandle FTM_UPDATE_TEXT_SEGMENTS("Update Text Segments");
 void LLTextBase::updateSegments()
 {
-	LL_RECORD_BLOCK_TIME(FTM_UPDATE_TEXT_SEGMENTS);
+    LL_PROFILE_ZONE_SCOPED;
 	createDefaultSegment();
 }
 
@@ -2096,19 +2093,16 @@ static LLUIImagePtr image_from_icon_name(const std::string& icon_name)
 	}
 }
 
-static LLTrace::BlockTimerStatHandle FTM_PARSE_HTML("Parse HTML");
-
-
 
 void LLTextBase::appendTextImpl(const std::string &new_text, const LLStyle::Params& input_params)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	LLStyle::Params style_params(input_params);
 	style_params.fillFrom(getStyleParams());
 
 	S32 part = (S32)LLTextParser::WHOLE;
 	if (mParseHTML && !style_params.is_link) // Don't search for URLs inside a link segment (STORM-358).
 	{
-		LL_RECORD_BLOCK_TIME(FTM_PARSE_HTML);
 		S32 start=0,end=0;
 		LLUrlMatch match;
 		std::string text = new_text;
@@ -2202,11 +2196,9 @@ void LLTextBase::setLastSegmentToolTip(const std::string &tooltip)
 	}
 }
 
-static LLTrace::BlockTimerStatHandle FTM_APPEND_TEXT("Append Text");
-
 void LLTextBase::appendText(const std::string &new_text, bool prepend_newline, const LLStyle::Params& input_params)
 {
-	LL_RECORD_BLOCK_TIME(FTM_APPEND_TEXT);
+    LL_PROFILE_ZONE_SCOPED;
 	if (new_text.empty()) 
 		return;
 
diff --git a/indra/llui/lluictrl.cpp b/indra/llui/lluictrl.cpp
index 5924542a19..51391bb5e8 100644
--- a/indra/llui/lluictrl.cpp
+++ b/indra/llui/lluictrl.cpp
@@ -121,7 +121,6 @@ LLUICtrl::LLUICtrl(const LLUICtrl::Params& p, const LLViewModelPtr& viewmodel)
 	mDoubleClickSignal(NULL),
 	mTransparencyType(TT_DEFAULT)
 {
-	claimMem(viewmodel.get());
 }
 
 void LLUICtrl::initFromParams(const Params& p)
@@ -476,6 +475,7 @@ LLViewModel* LLUICtrl::getViewModel() const
 //virtual
 BOOL LLUICtrl::postBuild()
 {
+    LL_PROFILE_ZONE_SCOPED;
 	//
 	// Find all of the children that want to be in front and move them to the front
 	//
@@ -781,12 +781,9 @@ BOOL LLUICtrl::getIsChrome() const
 }
 
 
-
-LLTrace::BlockTimerStatHandle FTM_FOCUS_FIRST_ITEM("Focus First Item");
-
 BOOL LLUICtrl::focusFirstItem(BOOL prefer_text_fields, BOOL focus_flash)
 {
-	LL_RECORD_BLOCK_TIME(FTM_FOCUS_FIRST_ITEM);
+    LL_PROFILE_ZONE_SCOPED;
 	// try to select default tab group child
 	LLViewQuery query = getTabOrderQuery();
 	child_list_t result = query(this);
@@ -1005,7 +1002,6 @@ boost::signals2::connection LLUICtrl::setCommitCallback( boost::function<void (L
 boost::signals2::connection LLUICtrl::setValidateBeforeCommit( boost::function<bool (const LLSD& data)> cb )
 {
 	if (!mValidateSignal) mValidateSignal = new enable_signal_t();
-	claimMem(mValidateSignal);
 
 	return mValidateSignal->connect(boost::bind(cb, _2));
 }
@@ -1070,7 +1066,6 @@ boost::signals2::connection LLUICtrl::setValidateCallback(const EnableCallbackPa
 boost::signals2::connection LLUICtrl::setCommitCallback( const commit_signal_t::slot_type& cb ) 
 { 
 	if (!mCommitSignal) mCommitSignal = new commit_signal_t();
-	claimMem(mCommitSignal);
 
 	return mCommitSignal->connect(cb); 
 }
@@ -1078,7 +1073,6 @@ boost::signals2::connection LLUICtrl::setCommitCallback( const commit_signal_t::
 boost::signals2::connection LLUICtrl::setValidateCallback( const enable_signal_t::slot_type& cb ) 
 { 
 	if (!mValidateSignal) mValidateSignal = new enable_signal_t();
-	claimMem(mValidateSignal);
 
 	return mValidateSignal->connect(cb); 
 }
@@ -1086,7 +1080,6 @@ boost::signals2::connection LLUICtrl::setValidateCallback( const enable_signal_t
 boost::signals2::connection LLUICtrl::setMouseEnterCallback( const commit_signal_t::slot_type& cb ) 
 { 
 	if (!mMouseEnterSignal) mMouseEnterSignal = new commit_signal_t();
-	claimMem(mMouseEnterSignal);
 
 	return mMouseEnterSignal->connect(cb); 
 }
@@ -1094,7 +1087,6 @@ boost::signals2::connection LLUICtrl::setMouseEnterCallback( const commit_signal
 boost::signals2::connection LLUICtrl::setMouseLeaveCallback( const commit_signal_t::slot_type& cb ) 
 { 
 	if (!mMouseLeaveSignal) mMouseLeaveSignal = new commit_signal_t();
-	claimMem(mMouseLeaveSignal);
 
 	return mMouseLeaveSignal->connect(cb); 
 }
@@ -1102,7 +1094,6 @@ boost::signals2::connection LLUICtrl::setMouseLeaveCallback( const commit_signal
 boost::signals2::connection LLUICtrl::setMouseDownCallback( const mouse_signal_t::slot_type& cb ) 
 { 
 	if (!mMouseDownSignal) mMouseDownSignal = new mouse_signal_t();
-	claimMem(mMouseDownSignal);
 
 	return mMouseDownSignal->connect(cb); 
 }
@@ -1110,7 +1101,6 @@ boost::signals2::connection LLUICtrl::setMouseDownCallback( const mouse_signal_t
 boost::signals2::connection LLUICtrl::setMouseUpCallback( const mouse_signal_t::slot_type& cb ) 
 { 
 	if (!mMouseUpSignal) mMouseUpSignal = new mouse_signal_t();
-	claimMem(mMouseUpSignal);
 
 	return mMouseUpSignal->connect(cb); 
 }
@@ -1118,7 +1108,6 @@ boost::signals2::connection LLUICtrl::setMouseUpCallback( const mouse_signal_t::
 boost::signals2::connection LLUICtrl::setRightMouseDownCallback( const mouse_signal_t::slot_type& cb ) 
 { 
 	if (!mRightMouseDownSignal) mRightMouseDownSignal = new mouse_signal_t();
-	claimMem(mRightMouseDownSignal);
 
 	return mRightMouseDownSignal->connect(cb); 
 }
@@ -1126,7 +1115,6 @@ boost::signals2::connection LLUICtrl::setRightMouseDownCallback( const mouse_sig
 boost::signals2::connection LLUICtrl::setRightMouseUpCallback( const mouse_signal_t::slot_type& cb ) 
 { 
 	if (!mRightMouseUpSignal) mRightMouseUpSignal = new mouse_signal_t();
-	claimMem(mRightMouseUpSignal);
 
 	return mRightMouseUpSignal->connect(cb); 
 }
@@ -1134,7 +1122,6 @@ boost::signals2::connection LLUICtrl::setRightMouseUpCallback( const mouse_signa
 boost::signals2::connection LLUICtrl::setDoubleClickCallback( const mouse_signal_t::slot_type& cb ) 
 { 
 	if (!mDoubleClickSignal) mDoubleClickSignal = new mouse_signal_t();
-	claimMem(mDoubleClickSignal);
 
 	return mDoubleClickSignal->connect(cb); 
 }
diff --git a/indra/llui/lluictrlfactory.cpp b/indra/llui/lluictrlfactory.cpp
index fdefae01b1..2d0c0ea8aa 100644
--- a/indra/llui/lluictrlfactory.cpp
+++ b/indra/llui/lluictrlfactory.cpp
@@ -44,10 +44,6 @@
 // this library includes
 #include "llpanel.h"
 
-LLTrace::BlockTimerStatHandle FTM_WIDGET_CONSTRUCTION("Widget Construction");
-LLTrace::BlockTimerStatHandle FTM_INIT_FROM_PARAMS("Widget InitFromParams");
-LLTrace::BlockTimerStatHandle FTM_WIDGET_SETUP("Widget Setup");
-
 //-----------------------------------------------------------------------------
 
 // UI Ctrl class for padding
@@ -117,12 +113,10 @@ void LLUICtrlFactory::loadWidgetTemplate(const std::string& widget_tag, LLInitPa
 	}
 }
 
-static LLTrace::BlockTimerStatHandle FTM_CREATE_CHILDREN("Create XUI Children");
-
 //static 
 void LLUICtrlFactory::createChildren(LLView* viewp, LLXMLNodePtr node, const widget_registry_t& registry, LLXMLNodePtr output_node)
 {
-	LL_RECORD_BLOCK_TIME(FTM_CREATE_CHILDREN);
+    LL_PROFILE_ZONE_SCOPED;
 	if (node.isNull()) return;
 
 	for (LLXMLNodePtr child_node = node->getFirstChild(); child_node.notNull(); child_node = child_node->getNextSibling())
@@ -159,14 +153,13 @@ void LLUICtrlFactory::createChildren(LLView* viewp, LLXMLNodePtr node, const wid
 
 }
 
-static LLTrace::BlockTimerStatHandle FTM_XML_PARSE("XML Reading/Parsing");
 //-----------------------------------------------------------------------------
 // getLayeredXMLNode()
 //-----------------------------------------------------------------------------
 bool LLUICtrlFactory::getLayeredXMLNode(const std::string &xui_filename, LLXMLNodePtr& root,
                                         LLDir::ESkinConstraint constraint)
 {
-	LL_RECORD_BLOCK_TIME(FTM_XML_PARSE);
+    LL_PROFILE_ZONE_SCOPED;
 	std::vector<std::string> paths =
 		gDirUtilp->findSkinnedFilenames(LLDir::XUI, xui_filename, constraint);
 
@@ -191,11 +184,9 @@ S32 LLUICtrlFactory::saveToXML(LLView* viewp, const std::string& filename)
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
 
-static LLTrace::BlockTimerStatHandle FTM_CREATE_FROM_XML("Create child widget");
-
 LLView *LLUICtrlFactory::createFromXML(LLXMLNodePtr node, LLView* parent, const std::string& filename, const widget_registry_t& registry, LLXMLNodePtr output_node)
 {
-	LL_RECORD_BLOCK_TIME(FTM_CREATE_FROM_XML);
+    LL_PROFILE_ZONE_SCOPED;
 	std::string ctrl_type = node->getName()->mString;
 	LLStringUtil::toLower(ctrl_type);
 
diff --git a/indra/llui/lluictrlfactory.h b/indra/llui/lluictrlfactory.h
index 135ed57a4f..3f24a3f1a5 100644
--- a/indra/llui/lluictrlfactory.h
+++ b/indra/llui/lluictrlfactory.h
@@ -79,10 +79,6 @@ class LLWidgetNameRegistry
 //	LLSINGLETON(LLDefaultParamBlockRegistry);
 //};
 
-extern LLTrace::BlockTimerStatHandle FTM_WIDGET_SETUP;
-extern LLTrace::BlockTimerStatHandle FTM_WIDGET_CONSTRUCTION;
-extern LLTrace::BlockTimerStatHandle FTM_INIT_FROM_PARAMS;
-
 // Build time optimization, generate this once in .cpp file
 #ifndef LLUICTRLFACTORY_CPP
 extern template class LLUICtrlFactory* LLSingleton<class LLUICtrlFactory>::getInstance();
@@ -213,6 +209,7 @@ private:
 	template<typename T>
 	static T* createWidgetImpl(const typename T::Params& params, LLView* parent = NULL)
 	{
+        LL_PROFILE_ZONE_SCOPED;
 		T* widget = NULL;
 
 		if (!params.validateBlock())
@@ -221,12 +218,9 @@ private:
 			//return NULL;
 		}
 
-		{ LL_RECORD_BLOCK_TIME(FTM_WIDGET_CONSTRUCTION);
-			widget = new T(params);	
-		}
-		{ LL_RECORD_BLOCK_TIME(FTM_INIT_FROM_PARAMS);
-			widget->initFromParams(params);
-		}
+		widget = new T(params);	
+		
+		widget->initFromParams(params);
 
 		if (parent)
 		{
@@ -239,7 +233,7 @@ private:
 	template<typename T>
 	static T* defaultBuilder(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr output_node)
 	{
-		LL_RECORD_BLOCK_TIME(FTM_WIDGET_SETUP);
+        LL_PROFILE_ZONE_SCOPED;
 
 		typename T::Params params(getDefaultParams<T>());
 
diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp
index b942be2a4a..bd0b9d3db2 100644
--- a/indra/llui/llview.cpp
+++ b/indra/llui/llview.cpp
@@ -140,8 +140,7 @@ LLView::Params::Params()
 }
 
 LLView::LLView(const LLView::Params& p)
-:	LLTrace::MemTrackable<LLView>("LLView"),
-	mVisible(p.visible),
+:	mVisible(p.visible),
 	mInDraw(false),
 	mName(p.name),
 	mParentView(NULL),
@@ -1597,15 +1596,11 @@ LLView* LLView::getChildView(const std::string& name, BOOL recurse) const
 	return getChild<LLView>(name, recurse);
 }
 
-static LLTrace::BlockTimerStatHandle FTM_FIND_VIEWS("Find Widgets");
-
 LLView* LLView::findChildView(const std::string& name, BOOL recurse) const
 {
-	LL_RECORD_BLOCK_TIME(FTM_FIND_VIEWS);
-	//richard: should we allow empty names?
-	//if(name.empty())
-	//	return NULL;
-	// Look for direct children *first*
+    LL_PROFILE_ZONE_SCOPED;
+	
+    // Look for direct children *first*
 	BOOST_FOREACH(LLView* childp, mChildList)
 	{
 		llassert(childp);
diff --git a/indra/llui/llview.h b/indra/llui/llview.h
index c60dcf3344..bec45df78a 100644
--- a/indra/llui/llview.h
+++ b/indra/llui/llview.h
@@ -100,8 +100,7 @@ class LLView
 :	public LLMouseHandler,			// handles mouse events
 	public LLFocusableElement,		// handles keyboard events
 	public LLMortician,				// lazy deletion
-	public LLHandleProvider<LLView>,     // passes out weak references to self
-	public LLTrace::MemTrackable<LLView> // track memory usage
+	public LLHandleProvider<LLView>     // passes out weak references to self
 {
 public:
 
diff --git a/indra/llui/llviewereventrecorder.cpp b/indra/llui/llviewereventrecorder.cpp
index cb000aef74..5a44ec947a 100644
--- a/indra/llui/llviewereventrecorder.cpp
+++ b/indra/llui/llviewereventrecorder.cpp
@@ -28,6 +28,8 @@
 #include "llui.h"
 #include "llleap.h"
 
+LLViewerEventRecorder* LLSimpleton<LLViewerEventRecorder>::sInstance = nullptr;
+
 LLViewerEventRecorder::LLViewerEventRecorder() {
 
   clear(UNDEFINED);
diff --git a/indra/llui/llviewereventrecorder.h b/indra/llui/llviewereventrecorder.h
index d1059d55de..d2c0780361 100644
--- a/indra/llui/llviewereventrecorder.h
+++ b/indra/llui/llviewereventrecorder.h
@@ -42,12 +42,12 @@
 
 #include "llsingleton.h" // includes llerror which we need here so we can skip the include here
 
-class LLViewerEventRecorder : public LLSingleton<LLViewerEventRecorder>
+class LLViewerEventRecorder : public LLSimpleton<LLViewerEventRecorder>
 {
-  LLSINGLETON(LLViewerEventRecorder);
-  ~LLViewerEventRecorder();
-
- public:
+public:
+    LLViewerEventRecorder();
+    ~LLViewerEventRecorder();
+   
   void updateMouseEventInfo(S32 local_x,S32 local_y, S32 global_x, S32 global_y,  std::string mName);
   void setMouseLocalCoords(S32 x,S32 y);
   void setMouseGlobalCoords(S32 x,S32 y);
diff --git a/indra/llui/llviewmodel.cpp b/indra/llui/llviewmodel.cpp
index 282addf692..a400eb70c0 100644
--- a/indra/llui/llviewmodel.cpp
+++ b/indra/llui/llviewmodel.cpp
@@ -37,15 +37,13 @@
 
 ///
 LLViewModel::LLViewModel()
-:	LLTrace::MemTrackable<LLViewModel>("LLViewModel"),
-	mDirty(false)
+:	mDirty(false)
 {
 }
 
 /// Instantiate an LLViewModel with an existing data value
 LLViewModel::LLViewModel(const LLSD& value)
-:	LLTrace::MemTrackable<LLViewModel>("LLViewModel"),
-	mDirty(false)
+:	mDirty(false)
 {
     setValue(value);
 }
@@ -82,15 +80,9 @@ LLTextViewModel::LLTextViewModel(const LLSD& value)
 void LLTextViewModel::setValue(const LLSD& value)
 {
 	// approximate LLSD storage usage
-	disclaimMem(mDisplay.size());
 	LLViewModel::setValue(value);
-	disclaimMem(mDisplay);
     mDisplay = utf8str_to_wstring(value.asString());
 
-	claimMem(mDisplay);
-	// approximate LLSD storage usage
-	claimMem(mDisplay.size());
-
     // mDisplay and mValue agree
     mUpdateFromDisplay = false;
 }
@@ -101,12 +93,8 @@ void LLTextViewModel::setDisplay(const LLWString& value)
     // and do the utf8str_to_wstring() to get the corresponding mDisplay
     // value. But a text editor might want to edit the display string
     // directly, then convert back to UTF8 on commit.
-	disclaimMem(mDisplay.size());
-	disclaimMem(mDisplay);
-    mDisplay = value;
-	claimMem(mDisplay);
-	claimMem(mDisplay.size());
-    mDirty = true;
+	mDisplay = value;
+	mDirty = true;
     // Don't immediately convert to UTF8 -- do it lazily -- we expect many
     // more setDisplay() calls than getValue() calls. Just flag that it needs
     // doing.
diff --git a/indra/llui/llviewmodel.h b/indra/llui/llviewmodel.h
index 49d7c322a3..e7dceb6c31 100644
--- a/indra/llui/llviewmodel.h
+++ b/indra/llui/llviewmodel.h
@@ -62,8 +62,7 @@ typedef LLPointer<LLListViewModel> LLListViewModelPtr;
  * last referencing widget is destroyed.
  */
 class LLViewModel 
-:	public LLRefCount,
-	public LLTrace::MemTrackable<LLViewModel>
+:	public LLRefCount
 {
 public:
     LLViewModel();
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index aeeba58a68..291f0f7d95 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -14104,18 +14104,7 @@
     <key>Value</key>
     <integer>1</integer>
   </map>
-  <key>RenderSynchronousOcclusion</key>
-  <map>
-    <key>Comment</key>
-    <string>Don't let occlusion queries get more than one frame behind (block until they complete).</string>
-    <key>Persist</key>
-    <integer>1</integer>
-    <key>Type</key>
-    <string>Boolean</string>
-    <key>Value</key>
-    <integer>1</integer>
-  </map>
-    <key>RenderDelayVBUpdate</key>
+  <key>RenderDelayVBUpdate</key>
     <map>
       <key>Comment</key>
       <string>Delay vertex buffer updates until just before rendering</string>
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 400a6a722b..8b4fcfccd9 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -977,6 +977,9 @@ bool LLAppViewer::init()
 	// Initialize the repeater service.
 	LLMainLoopRepeater::instance().start();
 
+    // Initialize event recorder
+    LLViewerEventRecorder::createInstance();
+
 	//
 	// Initialize the window
 	//
@@ -1316,6 +1319,13 @@ bool LLAppViewer::init()
 	// Load User's bindings
 	loadKeyBindings();
 
+    //LLSimpleton creations
+    LLEnvironment::createInstance();
+    LLEnvironment::getInstance()->initSingleton();
+    LLWorld::createInstance();
+    LLSelectMgr::createInstance();
+    LLViewerCamera::createInstance();
+
 	return true;
 }
 
@@ -1410,10 +1420,14 @@ bool LLAppViewer::doFrame()
 	LLSD newFrame;
 
 	{
-		LL_PROFILE_ZONE_NAMED( "df blocktimer" )
-		LLTrace::BlockTimer::processTimes();
-		LLTrace::get_frame_recording().nextPeriod();
-		LLTrace::BlockTimer::logStats();
+        LL_PROFILE_ZONE_NAMED("df LLTrace");
+        if (LLFloaterReg::instanceVisible("block_timers"))
+        {
+            LLTrace::BlockTimer::processTimes();
+        }
+        
+        LLTrace::get_frame_recording().nextPeriod();
+        LLTrace::BlockTimer::logStats();
 	}
 
 	LLTrace::get_thread_recorder()->pullFromChildren();
@@ -2184,6 +2198,10 @@ bool LLAppViewer::cleanup()
 
 	LLError::LLCallStacks::cleanup();
 
+    LLEnvironment::deleteSingleton();
+    LLSelectMgr::deleteSingleton();
+    LLViewerEventRecorder::deleteSingleton();
+
 	// It's not at first obvious where, in this long sequence, a generic cleanup
 	// call OUGHT to go. So let's say this: as we migrate cleanup from
 	// explicit hand-placed calls into the generic mechanism, eventually
@@ -2195,6 +2213,7 @@ bool LLAppViewer::cleanup()
 	// deleteSingleton() methods.
 	LLSingletonBase::deleteAll();
 
+
     LL_INFOS() << "Goodbye!" << LL_ENDL;
 
 	removeDumpDir();
@@ -5641,6 +5660,7 @@ void LLAppViewer::disconnectViewer()
 		LLWorld::getInstance()->destroyClass();
 	}
 	LLVOCache::deleteSingleton();
+    LLViewerCamera::deleteSingleton();
 
 	// call all self-registered classes
 	LLDestroyClassList::instance().fireCallbacks();
diff --git a/indra/newview/lldonotdisturbnotificationstorage.cpp b/indra/newview/lldonotdisturbnotificationstorage.cpp
index cb5f9c8a2c..7d4961c598 100644
--- a/indra/newview/lldonotdisturbnotificationstorage.cpp
+++ b/indra/newview/lldonotdisturbnotificationstorage.cpp
@@ -96,11 +96,9 @@ void LLDoNotDisturbNotificationStorage::resetDirty()
     mDirty = false;
 }
 
-static LLTrace::BlockTimerStatHandle FTM_SAVE_DND_NOTIFICATIONS("Save DND Notifications");
-
 void LLDoNotDisturbNotificationStorage::saveNotifications()
 {
-	LL_RECORD_BLOCK_TIME(FTM_SAVE_DND_NOTIFICATIONS);
+    LL_PROFILE_ZONE_SCOPED;
 
 	LLNotificationChannelPtr channelPtr = getCommunicationChannel();
 	const LLCommunicationChannel *commChannel = dynamic_cast<LLCommunicationChannel*>(channelPtr.get());
diff --git a/indra/newview/lldrawable.cpp b/indra/newview/lldrawable.cpp
index 495e06b6f7..502ebbd4b1 100644
--- a/indra/newview/lldrawable.cpp
+++ b/indra/newview/lldrawable.cpp
@@ -58,8 +58,6 @@ const F32 MIN_INTERPOLATE_DISTANCE_SQUARED = 0.001f * 0.001f;
 const F32 MAX_INTERPOLATE_DISTANCE_SQUARED = 10.f * 10.f;
 const F32 OBJECT_DAMPING_TIME_CONSTANT = 0.06f;
 
-static LLTrace::BlockTimerStatHandle FTM_CULL_REBOUND("Cull Rebound");
-
 extern bool gShiftFrame;
 
 
@@ -93,7 +91,6 @@ void LLDrawable::incrementVisible()
 
 LLDrawable::LLDrawable(LLViewerObject *vobj, bool new_entry)
 :	LLViewerOctreeEntryData(LLViewerOctreeEntry::LLDRAWABLE),
-	LLTrace::MemTrackable<LLDrawable, 16>("LLDrawable"),
 	mVObjp(vobj)
 {
 	init(new_entry); 
@@ -263,19 +260,13 @@ BOOL LLDrawable::isLight() const
 	}
 }
 
-static LLTrace::BlockTimerStatHandle FTM_CLEANUP_DRAWABLE("Cleanup Drawable");
-static LLTrace::BlockTimerStatHandle FTM_DEREF_DRAWABLE("Deref");
-static LLTrace::BlockTimerStatHandle FTM_DELETE_FACES("Faces");
-
 void LLDrawable::cleanupReferences()
 {
-	LL_RECORD_BLOCK_TIME(FTM_CLEANUP_DRAWABLE);
+    LL_PROFILE_ZONE_SCOPED;
 	
-	{
-		LL_RECORD_BLOCK_TIME(FTM_DELETE_FACES);
-		std::for_each(mFaces.begin(), mFaces.end(), DeletePointer());
-		mFaces.clear();
-	}
+	
+	std::for_each(mFaces.begin(), mFaces.end(), DeletePointer());
+	mFaces.clear();
 
 	gObjectList.removeDrawable(this);
 	
@@ -283,12 +274,9 @@ void LLDrawable::cleanupReferences()
 	
 	removeFromOctree();
 
-	{
-		LL_RECORD_BLOCK_TIME(FTM_DEREF_DRAWABLE);
-		// Cleanup references to other objects
-		mVObjp = NULL;
-		mParent = NULL;
-	}
+	// Cleanup references to other objects
+	mVObjp = NULL;
+	mParent = NULL;
 }
 
 void LLDrawable::removeFromOctree()
@@ -333,15 +321,12 @@ S32 LLDrawable::findReferences(LLDrawable *drawablep)
 	return count;
 }
 
-static LLTrace::BlockTimerStatHandle FTM_ALLOCATE_FACE("Allocate Face");
-
 LLFace*	LLDrawable::addFace(LLFacePool *poolp, LLViewerTexture *texturep)
 {
 	LL_PROFILE_ZONE_SCOPED
 	
 	LLFace *face;
 	{
-		LL_RECORD_BLOCK_TIME(FTM_ALLOCATE_FACE);
 		face = new LLFace(this, mVObjp);
 	}
 
@@ -370,11 +355,8 @@ LLFace*	LLDrawable::addFace(const LLTextureEntry *te, LLViewerTexture *texturep)
 
 	LLFace *face;
 
-	{
-		LL_RECORD_BLOCK_TIME(FTM_ALLOCATE_FACE);
-		face = new LLFace(this, mVObjp);
-	}
-
+	face = new LLFace(this, mVObjp);
+	
 	face->setTEOffset(mFaces.size());
 	face->setTexture(texturep);
 	face->setPoolType(gPipeline.getPoolTypeFromTE(te, texturep));
@@ -1333,10 +1315,7 @@ void LLSpatialBridge::updateSpatialExtents()
 
 	LLSpatialGroup* root = (LLSpatialGroup*) mOctree->getListener(0);
 	
-	{
-		LL_RECORD_BLOCK_TIME(FTM_CULL_REBOUND);
-		root->rebound();
-	}
+	root->rebound();
 	
 	const LLVector4a* root_bounds = root->getBounds();
 	LLVector4a offset;
diff --git a/indra/newview/lldrawable.h b/indra/newview/lldrawable.h
index 14d782d6f2..6002e3e0dd 100644
--- a/indra/newview/lldrawable.h
+++ b/indra/newview/lldrawable.h
@@ -59,14 +59,13 @@ const U32 SILHOUETTE_HIGHLIGHT = 0;
 
 // All data for new renderer goes into this class.
 LL_ALIGN_PREFIX(16)
-class LLDrawable 
-:	public LLViewerOctreeEntryData,
-	public LLTrace::MemTrackable<LLDrawable, 16>
+class LLDrawable
+    : public LLViewerOctreeEntryData
 {
+    LL_ALIGN_NEW;
 public:
 	LLDrawable(const LLDrawable& rhs) 
-	:	LLTrace::MemTrackable<LLDrawable, 16>("LLDrawable"),
-		LLViewerOctreeEntryData(rhs)
+        : LLViewerOctreeEntryData(rhs)
 	{
 		*this = rhs;
 	}
diff --git a/indra/newview/lldrawpoolalpha.cpp b/indra/newview/lldrawpoolalpha.cpp
index 369d7a6bb8..34f9bfe35d 100644
--- a/indra/newview/lldrawpoolalpha.cpp
+++ b/indra/newview/lldrawpoolalpha.cpp
@@ -53,10 +53,6 @@ BOOL LLDrawPoolAlpha::sShowDebugAlpha = FALSE;
 
 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_DEFERRED("Alpha Deferred");
-
 LLDrawPoolAlpha::LLDrawPoolAlpha(U32 type) :
 		LLRenderPass(type), current_shader(NULL), target_shader(NULL),
 		simple_shader(NULL), fullbright_shader(NULL), emissive_shader(NULL),
@@ -98,7 +94,7 @@ S32 LLDrawPoolAlpha::getNumPostDeferredPasses()
 
 void LLDrawPoolAlpha::beginPostDeferredPass(S32 pass) 
 { 
-    LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_DEFERRED);
+    LL_PROFILE_ZONE_SCOPED;
 
     F32 gamma = gSavedSettings.getF32("RenderDeferredDisplayGamma");
 
@@ -153,7 +149,7 @@ void LLDrawPoolAlpha::beginPostDeferredPass(S32 pass)
 
 void LLDrawPoolAlpha::endPostDeferredPass(S32 pass) 
 { 
-    LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_DEFERRED);
+    LL_PROFILE_ZONE_SCOPED;
 
 	if (pass == 1 && !LLPipeline::sImpostorRender)
 	{
@@ -168,13 +164,13 @@ void LLDrawPoolAlpha::endPostDeferredPass(S32 pass)
 
 void LLDrawPoolAlpha::renderPostDeferred(S32 pass) 
 { 
-    LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_DEFERRED);
+    LL_PROFILE_ZONE_SCOPED;
 	render(pass); 
 }
 
 void LLDrawPoolAlpha::beginRenderPass(S32 pass)
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_SETUP);
+    LL_PROFILE_ZONE_SCOPED;
 	
     simple_shader     = (LLPipeline::sImpostorRender)   ? &gObjectSimpleImpostorProgram  :
                         (LLPipeline::sUnderWaterRender) ? &gObjectSimpleWaterProgram     : &gObjectSimpleProgram;
@@ -225,7 +221,7 @@ void LLDrawPoolAlpha::beginRenderPass(S32 pass)
 
 void LLDrawPoolAlpha::endRenderPass( S32 pass )
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_SETUP);
+    LL_PROFILE_ZONE_SCOPED;
 	LLRenderPass::endRenderPass(pass);
 
 	if(gPipeline.canUseWindLightShaders()) 
@@ -522,6 +518,7 @@ void LLDrawPoolAlpha::renderEmissives(U32 mask, std::vector<LLDrawInfo*>& emissi
 
 void LLDrawPoolAlpha::renderAlpha(U32 mask, S32 pass)
 {
+    LL_PROFILE_ZONE_SCOPED;
     BOOL batch_fullbrights = gSavedSettings.getBOOL("RenderAlphaBatchFullbrights");
     BOOL batch_emissives   = gSavedSettings.getBOOL("RenderAlphaBatchEmissives");
 	BOOL initialized_lighting = FALSE;
@@ -529,6 +526,7 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, S32 pass)
 	
 	for (LLCullResult::sg_iterator i = gPipeline.beginAlphaGroups(); i != gPipeline.endAlphaGroups(); ++i)
 	{
+        LL_PROFILE_ZONE_NAMED("renderAlpha - group");
 		LLSpatialGroup* group = *i;
 		llassert(group);
 		llassert(group->getSpatialPartition());
@@ -546,9 +544,6 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, S32 pass)
 
 			bool draw_glow_for_this_partition = mShaderLevel > 0; // no shaders = no glow.
 
-			
-			LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_GROUP_LOOP);
-
 			bool disable_cull = is_particle_or_hud_particle;
 			LLGLDisable cull(disable_cull ? GL_CULL_FACE : 0);
 
diff --git a/indra/newview/lldrawpoolavatar.cpp b/indra/newview/lldrawpoolavatar.cpp
index 52d308f6bd..5b51e9db24 100644
--- a/indra/newview/lldrawpoolavatar.cpp
+++ b/indra/newview/lldrawpoolavatar.cpp
@@ -103,8 +103,6 @@ S32 normal_channel = -1;
 S32 specular_channel = -1;
 S32 cube_channel = -1;
 
-static LLTrace::BlockTimerStatHandle FTM_SHADOW_AVATAR("Avatar Shadow");
-
 LLDrawPoolAvatar::LLDrawPoolAvatar(U32 type) : 
 	LLFacePool(type)	
 {
@@ -196,7 +194,7 @@ LLMatrix4& LLDrawPoolAvatar::getModelView()
 
 void LLDrawPoolAvatar::beginDeferredPass(S32 pass)
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_CHARACTERS);
+    LL_PROFILE_ZONE_SCOPED;
 	
 	sSkipTransparent = TRUE;
 	is_deferred_render = true;
@@ -231,7 +229,7 @@ void LLDrawPoolAvatar::beginDeferredPass(S32 pass)
 
 void LLDrawPoolAvatar::endDeferredPass(S32 pass)
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_CHARACTERS);
+    LL_PROFILE_ZONE_SCOPED;
 
 	sSkipTransparent = FALSE;
 	is_deferred_render = false;
@@ -454,229 +452,220 @@ 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)
     {
-        LL_PROFILE_ZONE_SCOPED;
+        sVertexProgram = &gDeferredAvatarShadowProgram;
 
-        if (pass == SHADOW_PASS_AVATAR_OPAQUE)
+        if ((sShaderLevel > 0))  // for hardware blending
         {
-            sVertexProgram = &gDeferredAvatarShadowProgram;
-
-            if ((sShaderLevel > 0))  // for hardware blending
-            {
-                sRenderingSkinned = TRUE;
-                sVertexProgram->bind();
-            }
-
-            gGL.diffuseColor4f(1, 1, 1, 1);
+            sRenderingSkinned = TRUE;
+            sVertexProgram->bind();
         }
-        else if (pass == SHADOW_PASS_AVATAR_ALPHA_BLEND)
-        {
-            sVertexProgram = &gDeferredAvatarAlphaShadowProgram;
 
-            // bind diffuse tex so we can reference the alpha channel...
-            S32 loc = sVertexProgram->getUniformLocation(LLViewerShaderMgr::DIFFUSE_MAP);
-            sDiffuseChannel = 0;
-            if (loc != -1)
-            {
-                sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
-            }
-
-            if ((sShaderLevel > 0))  // for hardware blending
-            {
-                sRenderingSkinned = TRUE;
-                sVertexProgram->bind();
-            }
+        gGL.diffuseColor4f(1, 1, 1, 1);
+    }
+    else if (pass == SHADOW_PASS_AVATAR_ALPHA_BLEND)
+    {
+        sVertexProgram = &gDeferredAvatarAlphaShadowProgram;
 
-            gGL.diffuseColor4f(1, 1, 1, 1);
-        }
-        else if (pass == SHADOW_PASS_AVATAR_ALPHA_MASK)
+        // bind diffuse tex so we can reference the alpha channel...
+        S32 loc = sVertexProgram->getUniformLocation(LLViewerShaderMgr::DIFFUSE_MAP);
+        sDiffuseChannel = 0;
+        if (loc != -1)
         {
-            sVertexProgram = &gDeferredAvatarAlphaMaskShadowProgram;
+            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)
-            {
-                sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
-            }
+        if ((sShaderLevel > 0))  // for hardware blending
+        {
+            sRenderingSkinned = TRUE;
+            sVertexProgram->bind();
+        }
 
-            if ((sShaderLevel > 0))  // for hardware blending
-            {
-                sRenderingSkinned = TRUE;
-                sVertexProgram->bind();
-            }
+        gGL.diffuseColor4f(1, 1, 1, 1);
+    }
+    else if (pass == SHADOW_PASS_AVATAR_ALPHA_MASK)
+    {
+        sVertexProgram = &gDeferredAvatarAlphaMaskShadowProgram;
 
-            gGL.diffuseColor4f(1, 1, 1, 1);
-        }
-        else if (pass == SHADOW_PASS_ATTACHMENT_ALPHA_BLEND)
+        // bind diffuse tex so we can reference the alpha channel...
+        S32 loc = sVertexProgram->getUniformLocation(LLViewerShaderMgr::DIFFUSE_MAP);
+        sDiffuseChannel = 0;
+        if (loc != -1)
         {
-            sVertexProgram = &gDeferredAttachmentAlphaShadowProgram;
+            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)
-            {
-                sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
-            }
+        if ((sShaderLevel > 0))  // for hardware blending
+        {
+            sRenderingSkinned = TRUE;
+            sVertexProgram->bind();
+        }
 
-            if ((sShaderLevel > 0))  // for hardware blending
-            {
-                sRenderingSkinned = TRUE;
-                sVertexProgram->bind();
-            }
+        gGL.diffuseColor4f(1, 1, 1, 1);
+    }
+    else if (pass == SHADOW_PASS_ATTACHMENT_ALPHA_BLEND)
+    {
+        sVertexProgram = &gDeferredAttachmentAlphaShadowProgram;
 
-            gGL.diffuseColor4f(1, 1, 1, 1);
-        }
-        else if (pass == SHADOW_PASS_ATTACHMENT_ALPHA_MASK)
+        // bind diffuse tex so we can reference the alpha channel...
+        S32 loc = sVertexProgram->getUniformLocation(LLViewerShaderMgr::DIFFUSE_MAP);
+        sDiffuseChannel = 0;
+        if (loc != -1)
         {
-            sVertexProgram = &gDeferredAttachmentAlphaMaskShadowProgram;
+            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)
-            {
-                sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
-            }
+        if ((sShaderLevel > 0))  // for hardware blending
+        {
+            sRenderingSkinned = TRUE;
+            sVertexProgram->bind();
+        }
 
-            if ((sShaderLevel > 0))  // for hardware blending
-            {
-                sRenderingSkinned = TRUE;
-                sVertexProgram->bind();
-            }
+        gGL.diffuseColor4f(1, 1, 1, 1);
+    }
+    else if (pass == SHADOW_PASS_ATTACHMENT_ALPHA_MASK)
+    {
+        sVertexProgram = &gDeferredAttachmentAlphaMaskShadowProgram;
 
-            gGL.diffuseColor4f(1, 1, 1, 1);
+        // 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);
         }
-        else // SHADOW_PASS_ATTACHMENT_OPAQUE
+
+        if ((sShaderLevel > 0))  // for hardware blending
         {
-            sVertexProgram = &gDeferredAttachmentShadowProgram;
-            S32 loc = sVertexProgram->getUniformLocation(LLViewerShaderMgr::DIFFUSE_MAP);
-            sDiffuseChannel = 0;
-            if (loc != -1)
-            {
-                sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
-            }
+            sRenderingSkinned = TRUE;
             sVertexProgram->bind();
         }
+
+        gGL.diffuseColor4f(1, 1, 1, 1);
+    }
+    else // SHADOW_PASS_ATTACHMENT_OPAQUE
+    {
+        sVertexProgram = &gDeferredAttachmentShadowProgram;
+        S32 loc = sVertexProgram->getUniformLocation(LLViewerShaderMgr::DIFFUSE_MAP);
+        sDiffuseChannel = 0;
+        if (loc != -1)
+        {
+            sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
+        }
+        sVertexProgram->bind();
     }
 }
 
 void LLDrawPoolAvatar::endShadowPass(S32 pass)
 {
-	LL_RECORD_BLOCK_TIME(FTM_SHADOW_AVATAR);
-    {
-        LL_PROFILE_ZONE_SCOPED;
+	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_PROFILE_ZONE_SCOPED;
+    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 (impostor || (oa == LLVOAvatar::AOA_INVISIBLE))
-        {
-            // No shadows for impostored (including jellydolled) or invisible avs.
-            return;
-        }
+    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;
+    }
 
-        LLDrawPoolAvatar::sShadowPass = pass;
+    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;
-        }
+    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;
     }
 }
 
@@ -712,7 +701,7 @@ S32 LLDrawPoolAvatar::getNumDeferredPasses()
 
 void LLDrawPoolAvatar::render(S32 pass)
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_CHARACTERS);
+    LL_PROFILE_ZONE_SCOPED;
 	if (LLPipeline::sImpostorRender)
 	{
 		renderAvatars(NULL, pass+2);
@@ -724,7 +713,7 @@ void LLDrawPoolAvatar::render(S32 pass)
 
 void LLDrawPoolAvatar::beginRenderPass(S32 pass)
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_CHARACTERS);
+    LL_PROFILE_ZONE_SCOPED;
 	//reset vertex buffer mappings
 	LLVertexBuffer::unbind();
 
@@ -775,7 +764,7 @@ void LLDrawPoolAvatar::beginRenderPass(S32 pass)
 
 void LLDrawPoolAvatar::endRenderPass(S32 pass)
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_CHARACTERS);
+    LL_PROFILE_ZONE_SCOPED;
 
 	if (LLPipeline::sImpostorRender)
 	{
@@ -1542,13 +1531,8 @@ void LLDrawPoolAvatar::endDeferredSkinned()
 	gGL.getTexUnit(0)->activate();
 }
 
-static LLTrace::BlockTimerStatHandle FTM_RENDER_AVATARS("renderAvatars");
-
-
 void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass)
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_AVATARS);
-
 	if (pass == -1)
 	{
 		for (S32 i = 1; i < getNumPasses(); i++)
@@ -1588,6 +1572,8 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass)
 		return;
 	}
 
+    LL_RECORD_BLOCK_TIME(FTM_RENDER_CHARACTERS);
+
 	if (!single_avatar && !avatarp->isFullyLoaded() )
 	{
 		if (pass==0 && (!gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_PARTICLES) || LLViewerPartSim::getMaxPartCount() <= 0))
diff --git a/indra/newview/lldrawpoolbump.cpp b/indra/newview/lldrawpoolbump.cpp
index b08fbcbd89..8f3b0c99b4 100644
--- a/indra/newview/lldrawpoolbump.cpp
+++ b/indra/newview/lldrawpoolbump.cpp
@@ -1116,11 +1116,10 @@ LLViewerTexture* LLBumpImageList::getBrightnessDarknessImage(LLViewerFetchedText
 }
 
 
-static LLTrace::BlockTimerStatHandle FTM_BUMP_SOURCE_STANDARD_LOADED("Bump Standard Callback");
-
 // static
 void LLBumpImageList::onSourceBrightnessLoaded( BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata )
 {
+    LL_PROFILE_ZONE_SCOPED;
 	LLUUID* source_asset_id = (LLUUID*)userdata;
 	LLBumpImageList::onSourceLoaded( success, src_vi, src, *source_asset_id, BE_BRIGHTNESS );
 	if( final )
@@ -1140,22 +1139,17 @@ void LLBumpImageList::onSourceDarknessLoaded( BOOL success, LLViewerFetchedTextu
 	}
 }
 
-static LLTrace::BlockTimerStatHandle FTM_BUMP_GEN_NORMAL("Generate Normal Map");
-static LLTrace::BlockTimerStatHandle FTM_BUMP_CREATE_TEXTURE("Create GL Normal Map");
-
 void LLBumpImageList::onSourceStandardLoaded( BOOL success, LLViewerFetchedTexture* src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata)
 {
 	if (success && LLPipeline::sRenderDeferred)
 	{
-		LL_RECORD_BLOCK_TIME(FTM_BUMP_SOURCE_STANDARD_LOADED);
+        LL_PROFILE_ZONE_SCOPED;
 		LLPointer<LLImageRaw> nrm_image = new LLImageRaw(src->getWidth(), src->getHeight(), 4);
 		{
-			LL_RECORD_BLOCK_TIME(FTM_BUMP_GEN_NORMAL);
 			generateNormalMapFromAlpha(src, nrm_image);
 		}
 		src_vi->setExplicitFormat(GL_RGBA, GL_RGBA);
 		{
-			LL_RECORD_BLOCK_TIME(FTM_BUMP_CREATE_TEXTURE);
 			src_vi->createGLTexture(src_vi->getDiscardLevel(), nrm_image);
 		}
 	}
@@ -1216,28 +1210,18 @@ void LLBumpImageList::generateNormalMapFromAlpha(LLImageRaw* src, LLImageRaw* nr
 	}
 }
 
-
-static LLTrace::BlockTimerStatHandle FTM_BUMP_SOURCE_LOADED("Bump Source Loaded");
-static LLTrace::BlockTimerStatHandle FTM_BUMP_SOURCE_ENTRIES_UPDATE("Entries Update");
-static LLTrace::BlockTimerStatHandle FTM_BUMP_SOURCE_MIN_MAX("Min/Max");
-static LLTrace::BlockTimerStatHandle FTM_BUMP_SOURCE_RGB2LUM("RGB to Luminance");
-static LLTrace::BlockTimerStatHandle FTM_BUMP_SOURCE_RESCALE("Rescale");
-static LLTrace::BlockTimerStatHandle FTM_BUMP_SOURCE_GEN_NORMAL("Generate Normal");
-static LLTrace::BlockTimerStatHandle FTM_BUMP_SOURCE_CREATE("Bump Source Create");
-
 // static
 void LLBumpImageList::onSourceLoaded( BOOL success, LLViewerTexture *src_vi, LLImageRaw* src, LLUUID& source_asset_id, EBumpEffect bump_code )
 {
 	if( success )
 	{
-		LL_RECORD_BLOCK_TIME(FTM_BUMP_SOURCE_LOADED);
+        LL_PROFILE_ZONE_SCOPED;
 
 
 		bump_image_map_t& entries_list(bump_code == BE_BRIGHTNESS ? gBumpImageList.mBrightnessEntries : gBumpImageList.mDarknessEntries );
 		bump_image_map_t::iterator iter = entries_list.find(source_asset_id);
 
 		{
-			LL_RECORD_BLOCK_TIME(FTM_BUMP_SOURCE_ENTRIES_UPDATE);
 			if (iter == entries_list.end() ||
 				iter->second.isNull() ||
 							iter->second->getWidth() != src->getWidth() ||
@@ -1280,7 +1264,6 @@ void LLBumpImageList::onSourceLoaded( BOOL success, LLViewerTexture *src_vi, LLI
 			case 1:
 			case 2:
 				{
-					LL_RECORD_BLOCK_TIME(FTM_BUMP_SOURCE_MIN_MAX);
 					if( src_data_size == dst_data_size * src_components )
 					{
 						for( S32 i = 0, j=0; i < dst_data_size; i++, j+= src_components )
@@ -1306,7 +1289,6 @@ void LLBumpImageList::onSourceLoaded( BOOL success, LLViewerTexture *src_vi, LLI
 			case 3:
 			case 4:
 				{
-					LL_RECORD_BLOCK_TIME(FTM_BUMP_SOURCE_RGB2LUM);
 					if( src_data_size == dst_data_size * src_components )
 					{
 						for( S32 i = 0, j=0; i < dst_data_size; i++, j+= src_components )
@@ -1339,7 +1321,6 @@ void LLBumpImageList::onSourceLoaded( BOOL success, LLViewerTexture *src_vi, LLI
 
 			if( maximum > minimum )
 			{
-				LL_RECORD_BLOCK_TIME(FTM_BUMP_SOURCE_RESCALE);
 				U8 bias_and_scale_lut[256];
 				F32 twice_one_over_range = 2.f / (maximum - minimum);
 				S32 i;
@@ -1375,7 +1356,6 @@ void LLBumpImageList::onSourceLoaded( BOOL success, LLViewerTexture *src_vi, LLI
 
 			if (!LLPipeline::sRenderDeferred)
 			{
-				LL_RECORD_BLOCK_TIME(FTM_BUMP_SOURCE_CREATE);
 				bump->setExplicitFormat(GL_ALPHA8, GL_ALPHA);
 				bump->createGLTexture(0, dst_image);
 			}
@@ -1386,13 +1366,11 @@ void LLBumpImageList::onSourceLoaded( BOOL success, LLViewerTexture *src_vi, LLI
 				bump->getGLTexture()->setAllowCompression(false);
 
 				{
-					LL_RECORD_BLOCK_TIME(FTM_BUMP_SOURCE_CREATE);
 					bump->setExplicitFormat(GL_RGBA8, GL_ALPHA);
 					bump->createGLTexture(0, dst_image);
 				}
 
 				{
-					LL_RECORD_BLOCK_TIME(FTM_BUMP_SOURCE_GEN_NORMAL);
 					gPipeline.mScreen.bindTarget();
 					
 					LLGLDepthTest depth(GL_FALSE);
diff --git a/indra/newview/lldrawpoolsimple.cpp b/indra/newview/lldrawpoolsimple.cpp
index 843288cfb0..320160d10d 100644
--- a/indra/newview/lldrawpoolsimple.cpp
+++ b/indra/newview/lldrawpoolsimple.cpp
@@ -57,8 +57,6 @@ void LLDrawPoolGlow::beginPostDeferredPass(S32 pass)
 	}
 }
 
-static LLTrace::BlockTimerStatHandle FTM_RENDER_GLOW_PUSH("Glow Push");
-
 void LLDrawPoolGlow::renderPostDeferred(S32 pass)
 {
 	LL_RECORD_BLOCK_TIME(FTM_RENDER_GLOW);
@@ -73,10 +71,7 @@ void LLDrawPoolGlow::renderPostDeferred(S32 pass)
 	LLGLDepthTest depth(GL_TRUE, GL_FALSE);
 	gGL.setColorMask(false, true);
 
-	{
-		LL_RECORD_BLOCK_TIME(FTM_RENDER_GLOW_PUSH);
-		pushBatches(LLRenderPass::PASS_GLOW, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
-	}
+	pushBatches(LLRenderPass::PASS_GLOW, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
 	
 	gGL.setColorMask(true, false);
 	gGL.setSceneBlendType(LLRender::BT_ALPHA);	
@@ -309,7 +304,7 @@ void LLDrawPoolAlphaMask::endRenderPass(S32 pass)
 void LLDrawPoolAlphaMask::render(S32 pass)
 {
 	LLGLDisable blend(GL_BLEND);
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_MASK);
+    LL_PROFILE_ZONE_SCOPED;
 	
 	if (mShaderLevel > 0)
 	{
diff --git a/indra/newview/lldrawpoolterrain.cpp b/indra/newview/lldrawpoolterrain.cpp
index 34a8b6b2cc..9cea8f5460 100644
--- a/indra/newview/lldrawpoolterrain.cpp
+++ b/indra/newview/lldrawpoolterrain.cpp
@@ -920,6 +920,7 @@ void LLDrawPoolTerrain::renderOwnership()
 
 void LLDrawPoolTerrain::dirtyTextures(const std::set<LLViewerFetchedTexture*>& textures)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	LLViewerFetchedTexture* tex = LLViewerTextureManager::staticCastToFetchedTexture(mTexturep) ;
 	if (tex && textures.find(tex) != textures.end())
 	{
diff --git a/indra/newview/lldrawpooltree.cpp b/indra/newview/lldrawpooltree.cpp
index a1ff020068..202f648e3f 100644
--- a/indra/newview/lldrawpooltree.cpp
+++ b/indra/newview/lldrawpooltree.cpp
@@ -42,7 +42,6 @@
 
 S32 LLDrawPoolTree::sDiffTex = 0;
 static LLGLSLShader* shader = NULL;
-static LLTrace::BlockTimerStatHandle FTM_SHADOW_TREE("Tree Shadow");
 
 LLDrawPoolTree::LLDrawPoolTree(LLViewerTexture *texturep) :
 	LLFacePool(POOL_TREE),
@@ -84,7 +83,7 @@ void LLDrawPoolTree::beginRenderPass(S32 pass)
 
 void LLDrawPoolTree::render(S32 pass)
 {
-	LL_RECORD_BLOCK_TIME(LLPipeline::sShadowRender ? FTM_SHADOW_TREE : FTM_RENDER_TREES);
+    LL_PROFILE_ZONE_SCOPED;
 
 	if (mDrawFace.empty())
 	{
@@ -169,7 +168,7 @@ void LLDrawPoolTree::endDeferredPass(S32 pass)
 //============================================
 void LLDrawPoolTree::beginShadowPass(S32 pass)
 {
-	LL_RECORD_BLOCK_TIME(FTM_SHADOW_TREE);
+    LL_PROFILE_ZONE_SCOPED;
 	
 	glPolygonOffset(gSavedSettings.getF32("RenderDeferredTreeShadowOffset"),
 					gSavedSettings.getF32("RenderDeferredTreeShadowBias"));
@@ -188,7 +187,7 @@ void LLDrawPoolTree::renderShadow(S32 pass)
 
 void LLDrawPoolTree::endShadowPass(S32 pass)
 {
-	LL_RECORD_BLOCK_TIME(FTM_SHADOW_TREE);
+    LL_PROFILE_ZONE_SCOPED;
 	
 	glPolygonOffset(gSavedSettings.getF32("RenderDeferredSpotShadowOffset"),
 						gSavedSettings.getF32("RenderDeferredSpotShadowBias"));
diff --git a/indra/newview/lldynamictexture.h b/indra/newview/lldynamictexture.h
index 4bd74a8425..caedf928c3 100644
--- a/indra/newview/lldynamictexture.h
+++ b/indra/newview/lldynamictexture.h
@@ -35,16 +35,8 @@
 
 class LLViewerDynamicTexture : public LLViewerTexture
 {
+    LL_ALIGN_NEW
 public:
-	void* operator new(size_t size)
-	{
-		return LLTrace::MemTrackable<LLTexture>::aligned_new<16>(size);
-	}
-
-	void operator delete(void* ptr, size_t size)
-	{
-		LLTrace::MemTrackable<LLTexture>::aligned_delete<16>(ptr, size);
-	}
 
 	enum
 	{
diff --git a/indra/newview/llenvironment.cpp b/indra/newview/llenvironment.cpp
index 69d3075928..dba24b3d02 100644
--- a/indra/newview/llenvironment.cpp
+++ b/indra/newview/llenvironment.cpp
@@ -105,7 +105,6 @@ namespace
 
     //---------------------------------------------------------------------
     LLTrace::BlockTimerStatHandle   FTM_ENVIRONMENT_UPDATE("Update Environment Tick");
-    LLTrace::BlockTimerStatHandle   FTM_SHADER_PARAM_UPDATE("Update Shader Parameters");
 
     LLSettingsBase::Seconds         DEFAULT_UPDATE_THRESHOLD(10.0);
     const LLSettingsBase::Seconds   MINIMUM_SPANLENGTH(0.01f);
@@ -825,7 +824,7 @@ std::string env_selection_to_string(LLEnvironment::EnvSelection_t sel)
 #undef RTNENUM
 }
 
-
+LLEnvironment* LLSimpleton<LLEnvironment>::sInstance = nullptr;
 //-------------------------------------------------------------------------
 LLEnvironment::LLEnvironment():
     mCloudScrollDelta(),
@@ -879,6 +878,7 @@ void LLEnvironment::cleanupSingleton()
 
 LLEnvironment::~LLEnvironment()
 {
+    cleanupSingleton();
 }
 
 bool LLEnvironment::canEdit() const
@@ -1655,7 +1655,7 @@ void LLEnvironment::updateCloudScroll()
 // static
 void LLEnvironment::updateGLVariablesForSettings(LLShaderUniforms* uniforms, const LLSettingsBase::ptr_t &psetting)
 {
-    LL_RECORD_BLOCK_TIME(FTM_SHADER_PARAM_UPDATE);
+    LL_PROFILE_ZONE_SCOPED;
 
     for (int i = 0; i < LLGLSLShader::SG_COUNT; ++i)
     {
diff --git a/indra/newview/llenvironment.h b/indra/newview/llenvironment.h
index 3568fbcfd1..0ec06402f8 100644
--- a/indra/newview/llenvironment.h
+++ b/indra/newview/llenvironment.h
@@ -47,11 +47,11 @@ class LLViewerCamera;
 class LLParcel;
 
 //-------------------------------------------------------------------------
-class LLEnvironment : public LLSingleton<LLEnvironment>
+class LLEnvironment : public LLSimpleton<LLEnvironment>
 {
-    LLSINGLETON_C11(LLEnvironment);
     LOG_CLASS(LLEnvironment);
 public:
+    LLEnvironment();
 
     static const F64Seconds     TRANSITION_INSTANT;
     static const F64Seconds     TRANSITION_FAST;
@@ -115,7 +115,7 @@ public:
     typedef std::array<F32, 4>                                      altitude_list_t;
     typedef std::vector<F32>                                        altitudes_vect_t;
 
-    virtual                     ~LLEnvironment();
+    ~LLEnvironment();
 
     bool                        canEdit() const;
     bool                        isExtendedEnvironmentEnabled() const;
@@ -337,9 +337,10 @@ public:
     DayInstance::ptr_t          getSelectedEnvironmentInstance();
     DayInstance::ptr_t          getSharedEnvironmentInstance();
 
+    void                initSingleton();
+
 protected:
-    virtual void                initSingleton() override;
-    virtual void                cleanupSingleton() override;
+    void                cleanupSingleton();
 
 
 private:
diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp
index 34448a780d..88b958d24a 100644
--- a/indra/newview/llface.cpp
+++ b/indra/newview/llface.cpp
@@ -127,6 +127,7 @@ void planarProjection(LLVector2 &tc, const LLVector4a& normal,
 
 void LLFace::init(LLDrawable* drawablep, LLViewerObject* objp)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	mLastUpdateTime = gFrameTimeSeconds;
 	mLastMoveTime = 0.f;
 	mLastSkinTime = gFrameTimeSeconds;
@@ -1206,12 +1207,10 @@ bool LLFace::canRenderAsMask()
 }
 
 
-static LLTrace::BlockTimerStatHandle FTM_FACE_GEOM_VOLUME("Volume VB Cache");
-
 //static 
 void LLFace::cacheFaceInVRAM(const LLVolumeFace& vf)
 {
-	LL_RECORD_BLOCK_TIME(FTM_FACE_GEOM_VOLUME);
+    LL_PROFILE_ZONE_SCOPED;
 	U32 mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 |
 				LLVertexBuffer::MAP_TANGENT | LLVertexBuffer::MAP_NORMAL;
 	
@@ -1273,41 +1272,13 @@ void push_for_transform(LLVertexBuffer* buff, U32 source_count, U32 dest_count)
 	}
 }
 
-static LLTrace::BlockTimerStatHandle FTM_FACE_GET_GEOM("Face Geom");
-static LLTrace::BlockTimerStatHandle FTM_FACE_GEOM_POSITION("Position");
-static LLTrace::BlockTimerStatHandle FTM_FACE_GEOM_NORMAL("Normal");
-static LLTrace::BlockTimerStatHandle FTM_FACE_GEOM_TEXTURE("Texture");
-static LLTrace::BlockTimerStatHandle FTM_FACE_GEOM_COLOR("Color");
-static LLTrace::BlockTimerStatHandle FTM_FACE_GEOM_EMISSIVE("Emissive");
-static LLTrace::BlockTimerStatHandle FTM_FACE_GEOM_WEIGHTS("Weights");
-static LLTrace::BlockTimerStatHandle FTM_FACE_GEOM_TANGENT("Binormal");
-
-static LLTrace::BlockTimerStatHandle FTM_FACE_GEOM_FEEDBACK("Face Feedback");
-static LLTrace::BlockTimerStatHandle FTM_FACE_GEOM_FEEDBACK_POSITION("Feedback Position");
-static LLTrace::BlockTimerStatHandle FTM_FACE_GEOM_FEEDBACK_NORMAL("Feedback  Normal");
-static LLTrace::BlockTimerStatHandle FTM_FACE_GEOM_FEEDBACK_TEXTURE("Feedback  Texture");
-static LLTrace::BlockTimerStatHandle FTM_FACE_GEOM_FEEDBACK_COLOR("Feedback  Color");
-static LLTrace::BlockTimerStatHandle FTM_FACE_GEOM_FEEDBACK_EMISSIVE("Feedback  Emissive");
-static LLTrace::BlockTimerStatHandle FTM_FACE_GEOM_FEEDBACK_BINORMAL("Feedback Binormal");
-
-static LLTrace::BlockTimerStatHandle FTM_FACE_GEOM_INDEX("Index");
-static LLTrace::BlockTimerStatHandle FTM_FACE_GEOM_INDEX_TAIL("Tail");
-static LLTrace::BlockTimerStatHandle FTM_FACE_POSITION_STORE("Pos");
-static LLTrace::BlockTimerStatHandle FTM_FACE_TEXTURE_INDEX_STORE("TexIdx");
-static LLTrace::BlockTimerStatHandle FTM_FACE_POSITION_PAD("Pad");
-static LLTrace::BlockTimerStatHandle FTM_FACE_TEX_DEFAULT("Default");
-static LLTrace::BlockTimerStatHandle FTM_FACE_TEX_QUICK("Quick");
-static LLTrace::BlockTimerStatHandle FTM_FACE_TEX_QUICK_NO_XFORM("No Xform");
-static LLTrace::BlockTimerStatHandle FTM_FACE_TEX_QUICK_XFORM("Xform");
-static LLTrace::BlockTimerStatHandle FTM_FACE_TEX_QUICK_PLANAR("Quick Planar");
-
 BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 							   const S32 &f,
 								const LLMatrix4& mat_vert_in, const LLMatrix3& mat_norm_in,
 								const U16 &index_offset,
 								bool force_rebuild)
 {
-	LL_RECORD_BLOCK_TIME(FTM_FACE_GET_GEOM);
+    LL_PROFILE_ZONE_SCOPED;
 	llassert(verify());
 
 	if (volume.getNumVolumeFaces() <= f) {
@@ -1448,7 +1419,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 	// INDICES
 	if (full_rebuild)
 	{
-		LL_RECORD_BLOCK_TIME(FTM_FACE_GEOM_INDEX);
+        LL_PROFILE_ZONE_NAMED("getGeometryVolume - indices");
 		mVertexBuffer->getIndexStrider(indicesp, mIndicesIndex, mIndicesCount, map_range);
 
 		volatile __m128i* dst = (__m128i*) indicesp.get();
@@ -1464,7 +1435,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 		}
 
 		{
-			LL_RECORD_BLOCK_TIME(FTM_FACE_GEOM_INDEX_TAIL);
+            LL_PROFILE_ZONE_NAMED("getGeometryVolume - indices tail");
 			U16* idx = (U16*) dst;
 
 			for (S32 i = end*8; i < num_indices; ++i)
@@ -1527,7 +1498,8 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 		!volume.isUnique()) //source volume is NOT flexi
 	{ //use transform feedback to pack vertex buffer
 		//gGLDebugLoggingEnabled = TRUE;
-		LL_RECORD_BLOCK_TIME(FTM_FACE_GEOM_FEEDBACK);
+
+        LL_PROFILE_ZONE_NAMED("getGeometryVolume - transform feedback");
 		LLGLEnable discard(GL_RASTERIZER_DISCARD);
 		LLVertexBuffer* buff = (LLVertexBuffer*) vf.mVertexBuffer.get();
 
@@ -1545,7 +1517,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 
 		if (rebuild_pos)
 		{
-			LL_RECORD_BLOCK_TIME(FTM_FACE_GEOM_FEEDBACK_POSITION);
+            LL_PROFILE_ZONE_NAMED("getGeometryVolume - tf position");
 			gTransformPositionProgram.bind();
 
 			mVertexBuffer->bindForFeedback(0, LLVertexBuffer::TYPE_VERTEX, mGeomIndex, mGeomCount);
@@ -1570,7 +1542,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 
 		if (rebuild_color)
 		{
-			LL_RECORD_BLOCK_TIME(FTM_FACE_GEOM_FEEDBACK_COLOR);
+            LL_PROFILE_ZONE_NAMED("getGeometryVolume - tf color");
 			gTransformColorProgram.bind();
 			
 			mVertexBuffer->bindForFeedback(0, LLVertexBuffer::TYPE_COLOR, mGeomIndex, mGeomCount);
@@ -1586,7 +1558,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 
 		if (rebuild_emissive)
 		{
-			LL_RECORD_BLOCK_TIME(FTM_FACE_GEOM_FEEDBACK_EMISSIVE);
+            LL_PROFILE_ZONE_NAMED("getGeometryVolume - tf emissive");
 			gTransformColorProgram.bind();
 			
 			mVertexBuffer->bindForFeedback(0, LLVertexBuffer::TYPE_EMISSIVE, mGeomIndex, mGeomCount);
@@ -1607,7 +1579,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 
 		if (rebuild_normal)
 		{
-			LL_RECORD_BLOCK_TIME(FTM_FACE_GEOM_FEEDBACK_NORMAL);
+            LL_PROFILE_ZONE_NAMED("getGeometryVolume - tf normal");
 			gTransformNormalProgram.bind();
 			
 			mVertexBuffer->bindForFeedback(0, LLVertexBuffer::TYPE_NORMAL, mGeomIndex, mGeomCount);
@@ -1620,7 +1592,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 
 		if (rebuild_tangent)
 		{
-			LL_RECORD_BLOCK_TIME(FTM_FACE_GEOM_TANGENT);
+            LL_PROFILE_ZONE_NAMED("getGeometryVolume - tf tangent");
 			gTransformTangentProgram.bind();
 			
 			mVertexBuffer->bindForFeedback(0, LLVertexBuffer::TYPE_TANGENT, mGeomIndex, mGeomCount);
@@ -1633,7 +1605,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 
 		if (rebuild_tcoord)
 		{
-			LL_RECORD_BLOCK_TIME(FTM_FACE_GEOM_FEEDBACK_TEXTURE);
+            LL_PROFILE_ZONE_NAMED("getGeometryVolume - tf tcoord");
 			gTransformTexCoordProgram.bind();
 			
 			mVertexBuffer->bindForFeedback(0, LLVertexBuffer::TYPE_TEXCOORD0, mGeomIndex, mGeomCount);
@@ -1672,7 +1644,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 
 		if (rebuild_tcoord)
 		{
-			LL_RECORD_BLOCK_TIME(FTM_FACE_GEOM_TEXTURE);
+            LL_PROFILE_ZONE_NAMED("getGeometryVolume - tcoord");
 									
 			//bump setup
 			LLVector4a binormal_dir( -sin_ang, cos_ang, 0.f );
@@ -1795,18 +1767,18 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 
 				if (texgen != LLTextureEntry::TEX_GEN_PLANAR)
 				{
-					LL_RECORD_BLOCK_TIME(FTM_FACE_TEX_QUICK);
+                    LL_PROFILE_ZONE_NAMED("getGeometryVolume - texgen");
 					if (!do_tex_mat)
 					{
 						if (!do_xform)
 						{
-							LL_RECORD_BLOCK_TIME(FTM_FACE_TEX_QUICK_NO_XFORM);
+                            LL_PROFILE_ZONE_NAMED("ggv - texgen 1");
 							S32 tc_size = (num_vertices*2*sizeof(F32)+0xF) & ~0xF;
 							LLVector4a::memcpyNonAliased16((F32*) tex_coords0.get(), (F32*) vf.mTexCoords, tc_size);
 						}
 						else
 						{
-							LL_RECORD_BLOCK_TIME(FTM_FACE_TEX_QUICK_XFORM);
+                            LL_PROFILE_ZONE_NAMED("ggv - texgen 2");
 							F32* dst = (F32*) tex_coords0.get();
 							LLVector4a* src = (LLVector4a*) vf.mTexCoords;
 
@@ -1846,9 +1818,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 						for (S32 i = 0; i < num_vertices; i++)
 						{	
 							LLVector2 tc(vf.mTexCoords[i]);
-							//LLVector4a& norm = vf.mNormals[i];
-							//LLVector4a& center = *(vf.mCenter);
-
+							
 							LLVector3 tmp(tc.mV[0], tc.mV[1], 0.f);
 							tmp = tmp * *mTextureMatrix;
 							tc.mV[0] = tmp.mV[0];
@@ -1859,7 +1829,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 				}
 				else
 				{ //no bump, tex gen planar
-					LL_RECORD_BLOCK_TIME(FTM_FACE_TEX_QUICK_PLANAR);
+                    LL_PROFILE_ZONE_NAMED("getGeometryVolume - texgen planar");
 					if (do_tex_mat)
 					{
 						for (S32 i = 0; i < num_vertices; i++)
@@ -1904,7 +1874,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 			}
 			else
 			{ //bump mapped or has material, just do the whole expensive loop
-				LL_RECORD_BLOCK_TIME(FTM_FACE_TEX_DEFAULT);
+                LL_PROFILE_ZONE_NAMED("getGeometryVolume - texgen default");
 
 				std::vector<LLVector2> bump_tc;
 		
@@ -2062,7 +2032,6 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 			LLVector4a* end = src+num_vertices;
 			//LLVector4a* end_64 = end-4;
 
-			//LL_RECORD_TIME_BLOCK(FTM_FACE_GEOM_POSITION);
 			llassert(num_vertices > 0);
 		
 			mVertexBuffer->getVertexStrider(vert, mGeomIndex, mGeomCount, map_range);
@@ -2099,53 +2068,19 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 
 			LLVector4a tmp;
 
-			{
-				//LL_RECORD_TIME_BLOCK(FTM_FACE_POSITION_STORE);
-
-				/*if (num_vertices > 4)
-				{ //more than 64 bytes
-					while (src < end_64)
-					{	
-						_mm_prefetch((char*)src + 64, _MM_HINT_T0);
-						_mm_prefetch((char*)dst + 64, _MM_HINT_T0);
-
-						mat_vert.affineTransform(*src, res0);
-						tmp.setSelectWithMask(mask, texIdx, res0);
-						tmp.store4a((F32*) dst);
-
-						mat_vert.affineTransform(*(src+1), res1);
-						tmp.setSelectWithMask(mask, texIdx, res1);
-						tmp.store4a((F32*) dst+4);
-
-						mat_vert.affineTransform(*(src+2), res2);
-						tmp.setSelectWithMask(mask, texIdx, res2);
-						tmp.store4a((F32*) dst+8);
-
-						mat_vert.affineTransform(*(src+3), res3);
-						tmp.setSelectWithMask(mask, texIdx, res3);
-						tmp.store4a((F32*) dst+12);
-
-						dst += 16;
-						src += 4;
-					}
-				}*/
-
-				while (src < end)
-				{	
-					mat_vert.affineTransform(*src++, res0);
-					tmp.setSelectWithMask(mask, texIdx, res0);
-					tmp.store4a((F32*) dst);
-					dst += 4;
-				}
+			
+			while (src < end)
+			{	
+				mat_vert.affineTransform(*src++, res0);
+				tmp.setSelectWithMask(mask, texIdx, res0);
+				tmp.store4a((F32*) dst);
+				dst += 4;
 			}
-
+			
+			while (dst < end_f32)
 			{
-				//LL_RECORD_TIME_BLOCK(FTM_FACE_POSITION_PAD);
-				while (dst < end_f32)
-				{
-					res0.store4a((F32*) dst);
-					dst += 4;
-				}
+				res0.store4a((F32*) dst);
+				dst += 4;
 			}
 
 			if (map_range)
@@ -2179,7 +2114,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 		
 		if (rebuild_tangent)
 		{
-			LL_RECORD_BLOCK_TIME(FTM_FACE_GEOM_TANGENT);
+            LL_PROFILE_ZONE_NAMED("getGeometryVolume - tangent");
 			mVertexBuffer->getTangentStrider(tangent, mGeomIndex, mGeomCount, map_range);
 			F32* tangents = (F32*) tangent.get();
 			
@@ -2212,7 +2147,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 	
 		if (rebuild_weights && vf.mWeights)
 		{
-			LL_RECORD_BLOCK_TIME(FTM_FACE_GEOM_WEIGHTS);
+            LL_PROFILE_ZONE_NAMED("getGeometryVolume - weight");
 			mVertexBuffer->getWeight4Strider(wght, mGeomIndex, mGeomCount, map_range);
 			F32* weights = (F32*) wght.get();
 			LLVector4a::memcpyNonAliased16(weights, (F32*) vf.mWeights, num_vertices*4*sizeof(F32));
@@ -2224,7 +2159,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 
 		if (rebuild_color && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_COLOR) )
 		{
-			LL_RECORD_BLOCK_TIME(FTM_FACE_GEOM_COLOR);
+            LL_PROFILE_ZONE_NAMED("getGeometryVolume - color");
 			mVertexBuffer->getColorStrider(colors, mGeomIndex, mGeomCount, map_range);
 
 			LLVector4a src;
@@ -2255,7 +2190,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 
 		if (rebuild_emissive)
 		{
-			LL_RECORD_BLOCK_TIME(FTM_FACE_GEOM_EMISSIVE);
+            LL_PROFILE_ZONE_NAMED("getGeometryVolume - emissive");
 			LLStrider<LLColor4U> emissive;
 			mVertexBuffer->getEmissiveStrider(emissive, mGeomIndex, mGeomCount, map_range);
 
diff --git a/indra/newview/llface.h b/indra/newview/llface.h
index 9dd365e3dc..2e76c974fa 100644
--- a/indra/newview/llface.h
+++ b/indra/newview/llface.h
@@ -54,11 +54,11 @@ const F32 MIN_ALPHA_SIZE = 1024.f;
 const F32 MIN_TEX_ANIM_SIZE = 512.f;
 const U8 FACE_DO_NOT_BATCH_TEXTURES = 255;
 
-class LLFace : public LLTrace::MemTrackableNonVirtual<LLFace, 16>
+class alignas(16) LLFace
 {
+    LL_ALIGN_NEW
 public:
 	LLFace(const LLFace& rhs)
-	:	LLTrace::MemTrackableNonVirtual<LLFace, 16>("LLFace")
 	{
 		*this = rhs;
 	}
@@ -85,8 +85,8 @@ public:
 
 public:
 	LLFace(LLDrawable* drawablep, LLViewerObject* objp)
-	:	LLTrace::MemTrackableNonVirtual<LLFace, 16>("LLFace")
 	{
+        LL_PROFILE_ZONE_SCOPED;
 		init(drawablep, objp);
 	}
 	~LLFace()  { destroy(); }
diff --git a/indra/newview/llfasttimerview.cpp b/indra/newview/llfasttimerview.cpp
index 239d162101..1605e4133d 100644
--- a/indra/newview/llfasttimerview.cpp
+++ b/indra/newview/llfasttimerview.cpp
@@ -716,7 +716,6 @@ void LLFastTimerView::exportCharts(const std::string& base, const std::string& t
 		//======================================
 		buffer.clear();
 
-
 		gGL.color3fv(base_col.mV);
 		U32 count = 0;
 		U32 total_count = base_execution.size();
@@ -1019,11 +1018,9 @@ void LLFastTimerView::printLineStats()
 	}
 }
 
-static LLTrace::BlockTimerStatHandle FTM_DRAW_LINE_GRAPH("Draw line graph");
-
 void LLFastTimerView::drawLineGraph()
 {
-	LL_RECORD_BLOCK_TIME(FTM_DRAW_LINE_GRAPH);
+    LL_PROFILE_ZONE_SCOPED;
 	//draw line graph history
 	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 	LLLocalClipRect clip(mGraphRect);
@@ -1062,6 +1059,7 @@ void LLFastTimerView::drawLineGraph()
 
 	F32Seconds cur_max(0);
 	U32 cur_max_calls = 0;
+
 	for(block_timer_tree_df_iterator_t it = LLTrace::begin_block_timer_tree_df(FTM_FRAME);
 		it != LLTrace::end_block_timer_tree_df();
 		++it)
@@ -1096,6 +1094,7 @@ void LLFastTimerView::drawLineGraph()
 		F32 call_scale_factor = (F32)mGraphRect.getHeight() / (F32)max_calls;
 		F32 time_scale_factor = (F32)mGraphRect.getHeight() / max_time.value();
 		F32 hz_scale_factor = (F32) mGraphRect.getHeight() / (1.f / max_time.value());
+        
 		for (U32 j = mRecording.getNumRecordedPeriods();
 			j > 0;
 			j--)
@@ -1103,7 +1102,7 @@ void LLFastTimerView::drawLineGraph()
 			LLTrace::Recording& recording = mRecording.getPrevRecording(j);
 			F32Seconds time = llmax(recording.getSum(*idp), F64Seconds(0.000001));
 			U32 calls = recording.getSum(idp->callCount());
-
+            
 			if (is_hover_timer)
 			{ 
 				//normalize to highlighted timer
@@ -1450,6 +1449,7 @@ void LLFastTimerView::updateTotalTime()
 
 void LLFastTimerView::drawBars()
 {
+    LL_PROFILE_ZONE_SCOPED;
 	LLLocalClipRect clip(mBarRect);
 
 	S32 bar_height = mBarRect.getHeight() / (MAX_VISIBLE_HISTORY + 2);
@@ -1527,11 +1527,9 @@ void LLFastTimerView::drawBars()
 	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 }
 
-static LLTrace::BlockTimerStatHandle FTM_UPDATE_TIMER_BAR_WIDTHS("Update timer bar widths");
-
 F32Seconds LLFastTimerView::updateTimerBarWidths(LLTrace::BlockTimerStatHandle* time_block, TimerBarRow& row, S32 history_index, U32& bar_index)
 {
-	LL_RECORD_BLOCK_TIME(FTM_UPDATE_TIMER_BAR_WIDTHS);
+    LL_PROFILE_ZONE_SCOPED;
 	const F32Seconds self_time = history_index == -1
 										? mRecording.getPeriodMean(time_block->selfTime(), RUNNING_AVERAGE_WIDTH) 
 										: mRecording.getPrevRecording(history_index).getSum(time_block->selfTime());
@@ -1555,11 +1553,9 @@ F32Seconds LLFastTimerView::updateTimerBarWidths(LLTrace::BlockTimerStatHandle*
 	return full_time;
 }
 
-static LLTrace::BlockTimerStatHandle FTM_UPDATE_TIMER_BAR_FRACTIONS("Update timer bar fractions");
-
 S32 LLFastTimerView::updateTimerBarOffsets(LLTrace::BlockTimerStatHandle* time_block, TimerBarRow& row, S32 timer_bar_index)
 {
-	LL_RECORD_BLOCK_TIME(FTM_UPDATE_TIMER_BAR_FRACTIONS);
+    LL_PROFILE_ZONE_SCOPED;
 
 	TimerBar& timer_bar = row.mBars[timer_bar_index];
 	const F32Seconds bar_time = timer_bar.mTotalTime - timer_bar.mSelfTime;
@@ -1620,6 +1616,7 @@ S32 LLFastTimerView::updateTimerBarOffsets(LLTrace::BlockTimerStatHandle* time_b
 
 S32 LLFastTimerView::drawBar(LLRect bar_rect, TimerBarRow& row, S32 image_width, S32 image_height, bool hovered, bool visible, S32 bar_index)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	TimerBar& timer_bar = row.mBars[bar_index];
 	LLTrace::BlockTimerStatHandle* time_block = timer_bar.mTimeBlock;
 
diff --git a/indra/newview/llflexibleobject.cpp b/indra/newview/llflexibleobject.cpp
index e075a311c2..0b0567b687 100644
--- a/indra/newview/llflexibleobject.cpp
+++ b/indra/newview/llflexibleobject.cpp
@@ -47,9 +47,6 @@ static const F32 SEC_PER_FLEXI_FRAME = 1.f / 60.f; // 60 flexi updates per secon
 /*static*/ F32 LLVolumeImplFlexible::sUpdateFactor = 1.0f;
 std::vector<LLVolumeImplFlexible*> LLVolumeImplFlexible::sInstanceList;
 
-static LLTrace::BlockTimerStatHandle FTM_FLEXIBLE_REBUILD("Rebuild");
-static LLTrace::BlockTimerStatHandle FTM_DO_FLEXIBLE_UPDATE("Flexible Update");
-
 // LLFlexibleObjectData::pack/unpack now in llprimitive.cpp
 
 //-----------------------------------------------
@@ -95,7 +92,7 @@ LLVolumeImplFlexible::~LLVolumeImplFlexible()
 //static
 void LLVolumeImplFlexible::updateClass()
 {
-	LL_RECORD_BLOCK_TIME(FTM_DO_FLEXIBLE_UPDATE);
+    LL_PROFILE_ZONE_SCOPED;
 
 	U64 virtual_frame_num = LLTimer::getElapsedSeconds() / SEC_PER_FLEXI_FRAME;
 	for (std::vector<LLVolumeImplFlexible*>::iterator iter = sInstanceList.begin();
@@ -429,7 +426,7 @@ inline S32 log2(S32 x)
 
 void LLVolumeImplFlexible::doFlexibleUpdate()
 {
-	LL_RECORD_BLOCK_TIME(FTM_DO_FLEXIBLE_UPDATE);
+    LL_PROFILE_ZONE_SCOPED;
 	LLVolume* volume = mVO->getVolume();
 	LLPath *path = &volume->getPath();
 	if ((mSimulateRes == 0 || !mInitialized) && mVO->mDrawable->isVisible()) 
@@ -720,13 +717,12 @@ void LLVolumeImplFlexible::doFlexibleUpdate()
 	mLastSegmentRotation = parentSegmentRotation;
 }
 
-static LLTrace::BlockTimerStatHandle FTM_FLEXI_PREBUILD("Flexi Prebuild");
 
 void LLVolumeImplFlexible::preRebuild()
 {
 	if (!mUpdated)
 	{
-		LL_RECORD_BLOCK_TIME(FTM_FLEXI_PREBUILD);
+        LL_PROFILE_ZONE_SCOPED;
 		doFlexibleRebuild(false);
 	}
 }
@@ -752,6 +748,7 @@ void LLVolumeImplFlexible::onSetScale(const LLVector3& scale, BOOL damped)
 
 BOOL LLVolumeImplFlexible::doUpdateGeometry(LLDrawable *drawable)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	LLVOVolume *volume = (LLVOVolume*)mVO;
 
 	if (mVO->isAttachment())
@@ -789,7 +786,6 @@ BOOL LLVolumeImplFlexible::doUpdateGeometry(LLDrawable *drawable)
 
 	if (mRenderRes > -1)
 	{
-		LL_RECORD_BLOCK_TIME(FTM_DO_FLEXIBLE_UPDATE);
 		doFlexibleUpdate();
 	}
 	
@@ -809,7 +805,6 @@ BOOL LLVolumeImplFlexible::doUpdateGeometry(LLDrawable *drawable)
 		volume->mDrawable->setState(LLDrawable::REBUILD_VOLUME);
 		volume->dirtySpatialGroup();
 		{
-			LL_RECORD_BLOCK_TIME(FTM_FLEXIBLE_REBUILD);
 			doFlexibleRebuild(volume->mVolumeChanged);
 		}
 		volume->genBBoxes(isVolumeGlobal());
diff --git a/indra/newview/llgroupmgr.cpp b/indra/newview/llgroupmgr.cpp
index 32f88b49ac..7f65153879 100644
--- a/indra/newview/llgroupmgr.cpp
+++ b/indra/newview/llgroupmgr.cpp
@@ -944,12 +944,10 @@ static void formatDateString(std::string &date_string)
 	}
 }
 
-static LLTrace::BlockTimerStatHandle FTM_PROCESS_GROUP_MEMBERS_REPLY("Process Group Members");
-
 // static
 void LLGroupMgr::processGroupMembersReply(LLMessageSystem* msg, void** data)
 {
-    LL_RECORD_BLOCK_TIME(FTM_PROCESS_GROUP_MEMBERS_REPLY);
+    LL_PROFILE_ZONE_SCOPED;
 
 	LL_DEBUGS("GrpMgr") << "LLGroupMgr::processGroupMembersReply" << LL_ENDL;
 	LLUUID agent_id;
@@ -1054,12 +1052,10 @@ void LLGroupMgr::processGroupMembersReply(LLMessageSystem* msg, void** data)
 	LLGroupMgr::getInstance()->notifyObservers(GC_MEMBER_DATA);
 }
 
-static LLTrace::BlockTimerStatHandle FTM_PROCESS_GROUP_PROPERTIES_REPLY("Process Group Properties");
-
 //static 
 void LLGroupMgr::processGroupPropertiesReply(LLMessageSystem* msg, void** data)
 {
-    LL_RECORD_BLOCK_TIME(FTM_PROCESS_GROUP_PROPERTIES_REPLY);
+    LL_PROFILE_ZONE_SCOPED;
 
 	LL_DEBUGS("GrpMgr") << "LLGroupMgr::processGroupPropertiesReply" << LL_ENDL;
 	if (!msg)
@@ -1139,11 +1135,10 @@ void LLGroupMgr::processGroupPropertiesReply(LLMessageSystem* msg, void** data)
 	LLGroupMgr::getInstance()->notifyObservers(GC_PROPERTIES);
 }
 
-static LLTrace::BlockTimerStatHandle FTM_PROCESS_GROUP_ROLE_DATA_REPLY("Process Group Role Data");
 // static
 void LLGroupMgr::processGroupRoleDataReply(LLMessageSystem* msg, void** data)
 {
-    LL_RECORD_BLOCK_TIME(FTM_PROCESS_GROUP_ROLE_DATA_REPLY);
+    LL_PROFILE_ZONE_SCOPED;
 
 	LL_DEBUGS("GrpMgr") << "LLGroupMgr::processGroupRoleDataReply" << LL_ENDL;
 	LLUUID agent_id;
@@ -1227,11 +1222,10 @@ void LLGroupMgr::processGroupRoleDataReply(LLMessageSystem* msg, void** data)
 	LLGroupMgr::getInstance()->notifyObservers(GC_ROLE_DATA);
 }
 
-static LLTrace::BlockTimerStatHandle FTM_PROCESS_GROUP_ROLE_MEMBERS_REPLY("Process Group Role Members");
 // static
 void LLGroupMgr::processGroupRoleMembersReply(LLMessageSystem* msg, void** data)
 {
-    LL_RECORD_BLOCK_TIME(FTM_PROCESS_GROUP_ROLE_MEMBERS_REPLY);
+    LL_PROFILE_ZONE_SCOPED;
 
 	LL_DEBUGS("GrpMgr") << "LLGroupMgr::processGroupRoleMembersReply" << LL_ENDL;
 	LLUUID agent_id;
diff --git a/indra/newview/llinventoryfilter.cpp b/indra/newview/llinventoryfilter.cpp
index 411311bbea..84018655d0 100644
--- a/indra/newview/llinventoryfilter.cpp
+++ b/indra/newview/llinventoryfilter.cpp
@@ -47,8 +47,6 @@
 #include "llclipboard.h"
 #include "lltrans.h"
 
-LLTrace::BlockTimerStatHandle FT_FILTER_CLIPBOARD("Filter Clipboard");
-
 LLInventoryFilter::FilterOps::FilterOps(const Params& p)
 :	mFilterObjectTypes(p.object_types),
 	mFilterCategoryTypes(p.category_types),
@@ -505,7 +503,7 @@ bool LLInventoryFilter::checkAgainstClipboard(const LLUUID& object_id) const
 {
 	if (LLClipboard::instance().isCutMode())
 	{
-		LL_RECORD_BLOCK_TIME(FT_FILTER_CLIPBOARD);
+        LL_PROFILE_ZONE_SCOPED;
 		LLUUID current_id = object_id;
 		LLInventoryObject *current_object = gInventory.getObject(object_id);
 		while (current_id.notNull() && current_object)
diff --git a/indra/newview/llinventoryitemslist.cpp b/indra/newview/llinventoryitemslist.cpp
index 1dc1aa395e..23129f7d44 100644
--- a/indra/newview/llinventoryitemslist.cpp
+++ b/indra/newview/llinventoryitemslist.cpp
@@ -133,11 +133,9 @@ void LLInventoryItemsList::idle(void* user_data)
 	}
 }
 
-LLTrace::BlockTimerStatHandle FTM_INVENTORY_ITEMS_REFRESH("Inventory List Refresh");
-
 void LLInventoryItemsList::refresh()
 {
-    LL_RECORD_BLOCK_TIME(FTM_INVENTORY_ITEMS_REFRESH);
+    LL_PROFILE_ZONE_SCOPED;
 
     switch (mRefreshState)
     {
diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp
index 3608f9e23f..9b7e0c7824 100644
--- a/indra/newview/llinventorypanel.cpp
+++ b/indra/newview/llinventorypanel.cpp
@@ -673,10 +673,9 @@ void LLInventoryPanel::itemChanged(const LLUUID& item_id, U32 mask, const LLInve
 }
 
 // Called when something changed in the global model (new item, item coming through the wire, rename, move, etc...) (CHUI-849)
-static LLTrace::BlockTimerStatHandle FTM_REFRESH("Inventory Refresh");
 void LLInventoryPanel::modelChanged(U32 mask)
 {
-	LL_RECORD_BLOCK_TIME(FTM_REFRESH);
+    LL_PROFILE_ZONE_SCOPED;
 
 	if (mViewsInitialized != VIEWS_INITIALIZED) return;
 	
@@ -1691,10 +1690,9 @@ void LLInventoryPanel::removeItemID(const LLUUID& id)
 	}
 }
 
-LLTrace::BlockTimerStatHandle FTM_GET_ITEM_BY_ID("Get FolderViewItem by ID");
 LLFolderViewItem* LLInventoryPanel::getItemByID(const LLUUID& id)
 {
-	LL_RECORD_BLOCK_TIME(FTM_GET_ITEM_BY_ID);
+    LL_PROFILE_ZONE_SCOPED;
 
 	std::map<LLUUID, LLFolderViewItem*>::iterator map_it;
 	map_it = mItemMap.find(id);
diff --git a/indra/newview/llmaterialmgr.cpp b/indra/newview/llmaterialmgr.cpp
index 52b9fb40ae..11aa607393 100644
--- a/indra/newview/llmaterialmgr.cpp
+++ b/indra/newview/llmaterialmgr.cpp
@@ -580,11 +580,9 @@ void LLMaterialMgr::onPutResponse(bool success, const LLSD& content)
 	}
 }
 
-static LLTrace::BlockTimerStatHandle FTM_MATERIALS_IDLE("Idle Materials");
-
 void LLMaterialMgr::onIdle(void*)
 {
-	LL_RECORD_BLOCK_TIME(FTM_MATERIALS_IDLE);
+    LL_PROFILE_ZONE_SCOPED;
 
 	LLMaterialMgr* instancep = LLMaterialMgr::getInstance();
 
diff --git a/indra/newview/llpersistentnotificationstorage.cpp b/indra/newview/llpersistentnotificationstorage.cpp
index f95ab9928d..20cf4df56b 100644
--- a/indra/newview/llpersistentnotificationstorage.cpp
+++ b/indra/newview/llpersistentnotificationstorage.cpp
@@ -47,11 +47,9 @@ LLPersistentNotificationStorage::~LLPersistentNotificationStorage()
 {
 }
 
-static LLTrace::BlockTimerStatHandle FTM_SAVE_NOTIFICATIONS("Save Notifications");
-
 void LLPersistentNotificationStorage::saveNotifications()
 {
-	LL_RECORD_BLOCK_TIME(FTM_SAVE_NOTIFICATIONS);
+    LL_PROFILE_ZONE_SCOPED;
 
 	boost::intrusive_ptr<LLPersistentNotificationChannel> history_channel = boost::dynamic_pointer_cast<LLPersistentNotificationChannel>(LLNotifications::instance().getChannel("Persistent"));
 	if (!history_channel)
@@ -90,11 +88,9 @@ void LLPersistentNotificationStorage::saveNotifications()
 	writeNotifications(output);
 }
 
-static LLTrace::BlockTimerStatHandle FTM_LOAD_NOTIFICATIONS("Load Notifications");
-
 void LLPersistentNotificationStorage::loadNotifications()
 {
-	LL_RECORD_BLOCK_TIME(FTM_LOAD_NOTIFICATIONS);
+    LL_PROFILE_ZONE_SCOPED;
 
 	LL_INFOS("LLPersistentNotificationStorage") << "start loading notifications" << LL_ENDL;
 
diff --git a/indra/newview/llphysicsmotion.cpp b/indra/newview/llphysicsmotion.cpp
index f48ce680fd..30ca7ae539 100644
--- a/indra/newview/llphysicsmotion.cpp
+++ b/indra/newview/llphysicsmotion.cpp
@@ -453,6 +453,7 @@ F32 LLPhysicsMotion::calculateAcceleration_local(const F32 velocity_local, const
 
 BOOL LLPhysicsMotionController::onUpdate(F32 time, U8* joint_mask)
 {
+    LL_PROFILE_ZONE_SCOPED;
         // Skip if disabled globally.
         if (!gSavedSettings.getBOOL("AvatarPhysics"))
         {
diff --git a/indra/newview/llscenemonitor.cpp b/indra/newview/llscenemonitor.cpp
index f9baf5fbd3..177bc84cee 100644
--- a/indra/newview/llscenemonitor.cpp
+++ b/indra/newview/llscenemonitor.cpp
@@ -332,9 +332,6 @@ bool LLSceneMonitor::needsUpdate() const
 	return mDiffState == NEED_DIFF;
 }
 
-static LLTrace::BlockTimerStatHandle FTM_GENERATE_SCENE_LOAD_DITHER_TEXTURE("Generate Scene Load Dither Texture");
-static LLTrace::BlockTimerStatHandle FTM_SCENE_LOAD_IMAGE_DIFF("Scene Load Image Diff");
-
 static LLStaticHashedString sDitherScale("dither_scale");
 static LLStaticHashedString sDitherScaleS("dither_scale_s");
 static LLStaticHashedString sDitherScaleT("dither_scale_t");
@@ -356,14 +353,12 @@ void LLSceneMonitor::compare()
 		return; 
 	}
 
-	LL_RECORD_BLOCK_TIME(FTM_SCENE_LOAD_IMAGE_DIFF);
 	mDiffState = EXECUTE_DIFF;
 
 	S32 width = gViewerWindow->getWindowWidthRaw();
 	S32 height = gViewerWindow->getWindowHeightRaw();
 	if(!mDiff)
 	{
-		LL_RECORD_BLOCK_TIME(FTM_GENERATE_SCENE_LOAD_DITHER_TEXTURE);
 		mDiff = new LLRenderTarget();
 		mDiff->allocate(width, height, GL_RGBA, false, false, LLTexUnit::TT_TEXTURE, true);
 
@@ -371,7 +366,6 @@ void LLSceneMonitor::compare()
 	}
 	else if(mDiff->getWidth() != width || mDiff->getHeight() != height)
 	{
-		LL_RECORD_BLOCK_TIME(FTM_GENERATE_SCENE_LOAD_DITHER_TEXTURE);
 		mDiff->resize(width, height);
 		generateDitheringTexture(width, height);
 	}
@@ -427,8 +421,6 @@ void LLSceneMonitor::calcDiffAggregate()
 {
 #ifdef LL_WINDOWS
 
-	LL_RECORD_BLOCK_TIME(FTM_SCENE_LOAD_IMAGE_DIFF);
-
 	if(mDiffState != EXECUTE_DIFF && !mDebugViewerVisible)
 	{
 		return;
@@ -481,8 +473,6 @@ void LLSceneMonitor::calcDiffAggregate()
 static LLTrace::EventStatHandle<> sFramePixelDiff("FramePixelDifference");
 void LLSceneMonitor::fetchQueryResult()
 {
-	LL_RECORD_BLOCK_TIME(FTM_SCENE_LOAD_IMAGE_DIFF);
-
 	// also throttle timing here, to avoid going below sample time due to phasing with frame capture
 	static LLCachedControl<F32>  scene_load_sample_time_control(gSavedSettings, "SceneLoadingMonitorSampleTime");
 	F32Seconds scene_load_sample_time = (F32Seconds)scene_load_sample_time_control();
diff --git a/indra/newview/llscreenchannel.cpp b/indra/newview/llscreenchannel.cpp
index ca48c9d58c..17f2970f99 100644
--- a/indra/newview/llscreenchannel.cpp
+++ b/indra/newview/llscreenchannel.cpp
@@ -49,10 +49,9 @@ using namespace LLNotificationsUI;
 
 bool LLScreenChannel::mWasStartUpToastShown = false;
 
-LLTrace::BlockTimerStatHandle FTM_GET_CHANNEL_RECT("Calculate Notification Channel Region");
 LLRect LLScreenChannelBase::getChannelRect()
 {
-	LL_RECORD_BLOCK_TIME(FTM_GET_CHANNEL_RECT);
+    LL_PROFILE_ZONE_SCOPED;
 
 	if (mFloaterSnapRegion == NULL)
 	{
diff --git a/indra/newview/llscripteditor.cpp b/indra/newview/llscripteditor.cpp
index cd3a4dfd11..c6bb2f19dd 100644
--- a/indra/newview/llscripteditor.cpp
+++ b/indra/newview/llscripteditor.cpp
@@ -138,11 +138,9 @@ void LLScriptEditor::initKeywords()
 	mKeywords.initialize(LLSyntaxIdLSL::getInstance()->getKeywordsXML());
 }
 
-LLTrace::BlockTimerStatHandle FTM_SYNTAX_HIGHLIGHTING("Syntax Highlighting");
-
 void LLScriptEditor::loadKeywords()
 {
-	LL_RECORD_BLOCK_TIME(FTM_SYNTAX_HIGHLIGHTING);
+    LL_PROFILE_ZONE_SCOPED;
 	mKeywords.processTokens();
 	
 	segment_vec_t segment_list;
@@ -160,7 +158,7 @@ void LLScriptEditor::updateSegments()
 {
 	if (mReflowIndex < S32_MAX && mKeywords.isLoaded() && mParseOnTheFly)
 	{
-		LL_RECORD_BLOCK_TIME(FTM_SYNTAX_HIGHLIGHTING);
+        LL_PROFILE_ZONE_SCOPED;
 		// HACK:  No non-ascii keywords for now
 		segment_vec_t segment_list;
 		mKeywords.findSegments(&segment_list, getWText(), mDefaultColor.get(), *this);
diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp
index 50884762a8..53247031b4 100644
--- a/indra/newview/llselectmgr.cpp
+++ b/indra/newview/llselectmgr.cpp
@@ -97,6 +97,8 @@
 #include "llglheaders.h"
 #include "llinventoryobserver.h"
 
+LLSelectMgr* LLSimpleton<LLSelectMgr>::sInstance = nullptr;
+
 LLViewerObject* getSelectedParentObject(LLViewerObject *object) ;
 //
 // Consts
@@ -209,8 +211,6 @@ void LLSelectMgr::cleanupGlobals()
 	LLSelectMgr::getInstance()->clearSelections();
 }
 
-// Build time optimization, generate this function once here
-template class LLSelectMgr* LLSingleton<class LLSelectMgr>::getInstance();
 //-----------------------------------------------------------------------------
 // LLSelectMgr()
 //-----------------------------------------------------------------------------
diff --git a/indra/newview/llselectmgr.h b/indra/newview/llselectmgr.h
index 57fdfce152..0fd2e74090 100644
--- a/indra/newview/llselectmgr.h
+++ b/indra/newview/llselectmgr.h
@@ -407,11 +407,8 @@ private:
     LLObjectSelectionHandle					mSelectedObjects;
 };
 
-class LLSelectMgr : public LLEditMenuHandler, public LLSingleton<LLSelectMgr>
+class LLSelectMgr : public LLEditMenuHandler, public LLSimpleton<LLSelectMgr>
 {
-	LLSINGLETON(LLSelectMgr);
-	~LLSelectMgr();
-
 public:
 	static BOOL					sRectSelectInclusive;	// do we need to surround an object to pick it?
 	static BOOL					sRenderHiddenSelections;	// do we show selection silhouettes that are occluded?
@@ -437,6 +434,9 @@ public:
 	LLCachedControl<bool>					mDebugSelectMgr;
 
 public:
+    LLSelectMgr();
+    ~LLSelectMgr();
+
 	static void cleanupGlobals();
 
 	// LLEditMenuHandler interface
diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp
index 5cac9cd7ae..30b7124550 100644
--- a/indra/newview/llspatialpartition.cpp
+++ b/indra/newview/llspatialpartition.cpp
@@ -55,9 +55,6 @@
 #include "llviewershadermgr.h"
 #include "llcontrolavatar.h"
 
-static LLTrace::BlockTimerStatHandle FTM_FRUSTUM_CULL("Frustum Culling");
-static LLTrace::BlockTimerStatHandle FTM_CULL_REBOUND("Cull Rebound Partition");
-
 extern bool gShiftFrame;
 
 static U32 sZombieGroups = 0;
@@ -409,11 +406,6 @@ void LLSpatialGroup::rebuildMesh()
 	}
 }
 
-static LLTrace::BlockTimerStatHandle FTM_REBUILD_VBO("VBO Rebuilt");
-static LLTrace::BlockTimerStatHandle FTM_ADD_GEOMETRY_COUNT("Add Geometry");
-static LLTrace::BlockTimerStatHandle FTM_CREATE_VB("Create VB");
-static LLTrace::BlockTimerStatHandle FTM_GET_GEOMETRY("Get Geometry");
-
 void LLSpatialPartition::rebuildGeom(LLSpatialGroup* group)
 {
 	if (group->isDead() || !group->hasState(LLSpatialGroup::GEOM_DIRTY))
@@ -427,7 +419,7 @@ void LLSpatialPartition::rebuildGeom(LLSpatialGroup* group)
 		group->mLastUpdateViewAngle = group->mViewAngle;
 	}
 	
-	LL_RECORD_BLOCK_TIME(FTM_REBUILD_VBO);	
+    LL_PROFILE_ZONE_SCOPED;
 
 	group->clearDrawMap();
 	
@@ -435,15 +427,12 @@ void LLSpatialPartition::rebuildGeom(LLSpatialGroup* group)
 	U32 index_count = 0;
 	U32 vertex_count = 0;
 
-	{
-		LL_RECORD_BLOCK_TIME(FTM_ADD_GEOMETRY_COUNT);
-		addGeometryCount(group, vertex_count, index_count);
-	}
-
+    addGeometryCount(group, vertex_count, index_count);
+	
 	if (vertex_count > 0 && index_count > 0)
 	{ //create vertex buffer containing volume geometry for this node
 		{
-			LL_RECORD_BLOCK_TIME(FTM_CREATE_VB);
+
 			group->mBuilt = 1.f;
 			if (group->mVertexBuffer.isNull() ||
 				!group->mVertexBuffer->isWriteable() ||
@@ -458,7 +447,6 @@ void LLSpatialPartition::rebuildGeom(LLSpatialGroup* group)
 					group->mVertexBuffer = NULL;
 					group->mBufferMap.clear();
 				}
-				stop_glerror();
 			}
 			else
 			{
@@ -471,13 +459,11 @@ void LLSpatialPartition::rebuildGeom(LLSpatialGroup* group)
 					group->mVertexBuffer = NULL;
 					group->mBufferMap.clear();
 				}
-				stop_glerror();
 			}
 		}
 
 		if (group->mVertexBuffer)
 		{
-			LL_RECORD_BLOCK_TIME(FTM_GET_GEOMETRY);
 			getGeometry(group);
 		}
 	}
@@ -1489,12 +1475,12 @@ void LLSpatialPartition::resetVertexBuffers()
 
 BOOL LLSpatialPartition::getVisibleExtents(LLCamera& camera, LLVector3& visMin, LLVector3& visMax)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	LLVector4a visMina, visMaxa;
 	visMina.load3(visMin.mV);
 	visMaxa.load3(visMax.mV);
 
 	{
-		LL_RECORD_BLOCK_TIME(FTM_CULL_REBOUND);		
 		LLSpatialGroup* group = (LLSpatialGroup*) mOctree->getListener(0);
 		group->rebound();
 	}
@@ -1516,11 +1502,11 @@ BOOL LLSpatialPartition::visibleObjectsInFrustum(LLCamera& camera)
 
 S32 LLSpatialPartition::cull(LLCamera &camera, std::vector<LLDrawable *>* results, BOOL for_select)
 {
+    LL_PROFILE_ZONE_SCOPED;
 #if LL_OCTREE_PARANOIA_CHECK
 	((LLSpatialGroup*)mOctree->getListener(0))->checkStates();
 #endif
 	{
-		LL_RECORD_BLOCK_TIME(FTM_CULL_REBOUND);		
 		LLSpatialGroup* group = (LLSpatialGroup*) mOctree->getListener(0);
 		group->rebound();
 	}
@@ -1537,37 +1523,32 @@ S32 LLSpatialPartition::cull(LLCamera &camera, std::vector<LLDrawable *>* result
 	
 S32 LLSpatialPartition::cull(LLCamera &camera, bool do_occlusion)
 {
+    LL_PROFILE_ZONE_SCOPED;
 #if LL_OCTREE_PARANOIA_CHECK
 	((LLSpatialGroup*)mOctree->getListener(0))->checkStates();
 #endif
-	{
-		LL_RECORD_BLOCK_TIME(FTM_CULL_REBOUND);		
-		LLSpatialGroup* group = (LLSpatialGroup*) mOctree->getListener(0);
-		group->rebound();
-	}
+	LLSpatialGroup* group = (LLSpatialGroup*) mOctree->getListener(0);
+	group->rebound();
 
 #if LL_OCTREE_PARANOIA_CHECK
 	((LLSpatialGroup*)mOctree->getListener(0))->validate();
 #endif
 
-	if (LLPipeline::sShadowRender)
-	{
-		LL_RECORD_BLOCK_TIME(FTM_FRUSTUM_CULL);
-		LLOctreeCullShadow culler(&camera);
-		culler.traverse(mOctree);
-	}
-	else if (mInfiniteFarClip || !LLPipeline::sUseFarClip)
-	{
-		LL_RECORD_BLOCK_TIME(FTM_FRUSTUM_CULL);		
-		LLOctreeCullNoFarClip culler(&camera);
-		culler.traverse(mOctree);
-	}
-	else
-	{
-		LL_RECORD_BLOCK_TIME(FTM_FRUSTUM_CULL);		
-		LLOctreeCull culler(&camera);
-		culler.traverse(mOctree);
-	}
+    if (LLPipeline::sShadowRender)
+    {
+        LLOctreeCullShadow culler(&camera);
+        culler.traverse(mOctree);
+    }
+    else if (mInfiniteFarClip || !LLPipeline::sUseFarClip)
+    {
+        LLOctreeCullNoFarClip culler(&camera);
+        culler.traverse(mOctree);
+    }
+    else
+    {
+        LLOctreeCull culler(&camera);
+        culler.traverse(mOctree);
+    }
 	
 	return 0;
 }
@@ -4048,8 +4029,7 @@ LLDrawInfo::LLDrawInfo(U16 start, U16 end, U32 count, U32 offset,
 					   LLViewerTexture* texture, LLVertexBuffer* buffer,
 					   bool selected,
 					   BOOL fullbright, U8 bump, BOOL particle, F32 part_size)
-:	LLTrace::MemTrackableNonVirtual<LLDrawInfo, 16>("LLDrawInfo"),
-	mVertexBuffer(buffer),
+:	mVertexBuffer(buffer),
 	mTexture(texture),
 	mTextureMatrix(NULL),
 	mModelMatrix(NULL),
diff --git a/indra/newview/llspatialpartition.h b/indra/newview/llspatialpartition.h
index 6ef82fac9c..8cc50e71b1 100644
--- a/indra/newview/llspatialpartition.h
+++ b/indra/newview/llspatialpartition.h
@@ -56,14 +56,14 @@ class LLViewerRegion;
 
 void pushVerts(LLFace* face, U32 mask);
 
-class LLDrawInfo : public LLRefCount, public LLTrace::MemTrackableNonVirtual<LLDrawInfo, 16>
+class LLDrawInfo : public LLRefCount
 {
+    LL_ALIGN_NEW;
 protected:
 	~LLDrawInfo();	
 	
 public:
 	LLDrawInfo(const LLDrawInfo& rhs)
-	:	LLTrace::MemTrackableNonVirtual<LLDrawInfo, 16>("LLDrawInfo")
 	{
 		*this = rhs;
 	}
diff --git a/indra/newview/llviewercamera.cpp b/indra/newview/llviewercamera.cpp
index 27a87ee1a0..5ebce115f6 100644
--- a/indra/newview/llviewercamera.cpp
+++ b/indra/newview/llviewercamera.cpp
@@ -54,6 +54,8 @@
 // System includes
 #include <iomanip> // for setprecision
 
+LLViewerCamera* LLSimpleton<LLViewerCamera>::sInstance = nullptr;
+
 LLTrace::CountStatHandle<> LLViewerCamera::sVelocityStat("camera_velocity");
 LLTrace::CountStatHandle<> LLViewerCamera::sAngularVelocityStat("camera_angular_velocity");
 
@@ -81,9 +83,6 @@ glh::matrix4f gl_pick_matrix(GLfloat x, GLfloat y, GLfloat width, GLfloat height
 	return glh::matrix4f(m);
 }
 
-// Build time optimization, generate this once in .cpp file
-template class LLViewerCamera* LLSingleton<class LLViewerCamera>::getInstance();
-
 LLViewerCamera::LLViewerCamera() : LLCamera()
 {
 	calcProjection(getFar());
diff --git a/indra/newview/llviewercamera.h b/indra/newview/llviewercamera.h
index fb07a3fb2d..549778a841 100644
--- a/indra/newview/llviewercamera.h
+++ b/indra/newview/llviewercamera.h
@@ -38,25 +38,11 @@ class LLViewerObject;
 const BOOL FOR_SELECTION = TRUE;
 const BOOL NOT_FOR_SELECTION = FALSE;
 
-// Build time optimization, generate this once in .cpp file
-#ifndef LLVIEWERCAMERA_CPP
-extern template class LLViewerCamera* LLSingleton<class LLViewerCamera>::getInstance();
-#endif
-
-LL_ALIGN_PREFIX(16)
-class LLViewerCamera : public LLCamera, public LLSingleton<LLViewerCamera>
+class alignas(16) LLViewerCamera : public LLCamera, public LLSimpleton<LLViewerCamera>
 {
-	LLSINGLETON(LLViewerCamera);
+    LL_ALIGN_NEW
 public:
-	void* operator new(size_t size)
-	{
-		return ll_aligned_malloc_16(size);
-	}
-
-	void operator delete(void* ptr)
-	{
-		ll_aligned_free_16(ptr);
-	}
+    LLViewerCamera();
 
 	typedef enum
 	{
@@ -141,7 +127,7 @@ protected:
 	S16					mZoomSubregion;
 
 public:
-} LL_ALIGN_POSTFIX(16);
+};
 
 
 #endif // LL_LLVIEWERCAMERA_H
diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp
index 1236695e4f..6368286f6e 100644
--- a/indra/newview/llviewerdisplay.cpp
+++ b/indra/newview/llviewerdisplay.cpp
@@ -809,13 +809,9 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 			
 			{
 				LL_RECORD_BLOCK_TIME(FTM_IMAGE_UPDATE_CLASS);
-				LLTrace::CountStatHandle<>* velocity_stat = LLViewerCamera::getVelocityStat();
-				LLTrace::CountStatHandle<>* angular_velocity_stat = LLViewerCamera::getAngularVelocityStat();
-				LLViewerTexture::updateClass(LLTrace::get_frame_recording().getPeriodMeanPerSec(*velocity_stat),
-											LLTrace::get_frame_recording().getPeriodMeanPerSec(*angular_velocity_stat));
+				LLViewerTexture::updateClass();
 			}
 
-			
 			{
 				LL_RECORD_BLOCK_TIME(FTM_IMAGE_UPDATE_BUMP);
 				gBumpImageList.updateImages();  // must be called before gTextureList version so that it's textures are thrown out first.
@@ -1285,7 +1281,6 @@ void render_ui(F32 zoom_factor, int subfield)
 	
 	if(LLSceneMonitor::getInstance()->needsUpdate())
 	{
-		LL_RECORD_BLOCK_TIME(FTM_RENDER_UI_SCENE_MON);
 		gGL.pushMatrix();
 		gViewerWindow->setup2DRender();
 		LLSceneMonitor::getInstance()->compare();
@@ -1334,12 +1329,9 @@ void render_ui(F32 zoom_factor, int subfield)
 			}
 			gGL.flush();
 
-			{
-				LL_RECORD_BLOCK_TIME(FTM_RENDER_UI_DEBUG_TEXT);
-				gViewerWindow->setup2DRender();
-				gViewerWindow->updateDebugText();
-				gViewerWindow->drawDebugText();
-			}
+			gViewerWindow->setup2DRender();
+			gViewerWindow->updateDebugText();
+			gViewerWindow->drawDebugText();
 
 			LLVertexBuffer::unbind();
 		}
diff --git a/indra/newview/llviewerjointmesh.cpp b/indra/newview/llviewerjointmesh.cpp
index 63ad708e59..3e385a46e4 100644
--- a/indra/newview/llviewerjointmesh.cpp
+++ b/indra/newview/llviewerjointmesh.cpp
@@ -362,7 +362,6 @@ void LLViewerJointMesh::updateFaceSizes(U32 &num_vertices, U32& num_indices, F32
 //-----------------------------------------------------------------------------
 // updateFaceData()
 //-----------------------------------------------------------------------------
-static LLTrace::BlockTimerStatHandle FTM_AVATAR_FACE("Avatar Face");
 
 void LLViewerJointMesh::updateFaceData(LLFace *face, F32 pixel_area, BOOL damp_wind, bool terse_update)
 {
@@ -383,9 +382,8 @@ void LLViewerJointMesh::updateFaceData(LLFace *face, F32 pixel_area, BOOL damp_w
 	 // since mMesh is being copied into mVertexBuffer every frame
 		return;
 	}
-
-
-	LL_RECORD_BLOCK_TIME(FTM_AVATAR_FACE);
+    
+    LL_PROFILE_ZONE_SCOPED;
 
 	LLStrider<LLVector3> verticesp;
 	LLStrider<LLVector3> normalsp;
diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp
index 5e99d13206..52a65abf9b 100644
--- a/indra/newview/llviewermessage.cpp
+++ b/indra/newview/llviewermessage.cpp
@@ -2219,11 +2219,9 @@ protected:
 	}
 };
 
-static LLTrace::BlockTimerStatHandle FTM_PROCESS_IMPROVED_IM("Process IM");
-
 void process_improved_im(LLMessageSystem *msg, void **user_data)
 {
-    LL_RECORD_BLOCK_TIME(FTM_PROCESS_IMPROVED_IM);
+    LL_PROFILE_ZONE_SCOPED;
 
     LLUUID from_id;
     BOOL from_group;
@@ -3267,10 +3265,9 @@ const F32 THRESHOLD_HEAD_ROT_QDOT = 0.9997f;	// ~= 2.5 degrees -- if its less th
 const F32 MAX_HEAD_ROT_QDOT = 0.99999f;			// ~= 0.5 degrees -- if its greater than this then no need to update head_rot
 												// between these values we delay the updates (but no more than one second)
 
-static LLTrace::BlockTimerStatHandle FTM_AGENT_UPDATE_SEND("Send Message");
-
 void send_agent_update(BOOL force_send, BOOL send_reliable)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	if (gAgent.getTeleportState() != LLAgent::TELEPORT_NONE)
 	{
 		// We don't care if they want to send an agent update, they're not allowed to until the simulator
@@ -3451,7 +3448,6 @@ void send_agent_update(BOOL force_send, BOOL send_reliable)
 		}
 		*/
 
-		LL_RECORD_BLOCK_TIME(FTM_AGENT_UPDATE_SEND);
 		// Build the message
 		msg->newMessageFast(_PREHASH_AgentUpdate);
 		msg->nextBlockFast(_PREHASH_AgentData);
@@ -3701,11 +3697,9 @@ void process_terse_object_update_improved(LLMessageSystem *mesgsys, void **user_
 	}
 }
 
-static LLTrace::BlockTimerStatHandle FTM_PROCESS_OBJECTS("Process Kill Objects");
-
 void process_kill_object(LLMessageSystem *mesgsys, void **user_data)
 {
-	LL_RECORD_BLOCK_TIME(FTM_PROCESS_OBJECTS);
+    LL_PROFILE_ZONE_SCOPED;
 
 	LLUUID		id;
 
diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp
index 0832415e1e..c671aec224 100644
--- a/indra/newview/llviewerobject.cpp
+++ b/indra/newview/llviewerobject.cpp
@@ -146,16 +146,14 @@ const S32 MAX_OBJECT_BINARY_DATA_SIZE = 60 + 16;
 const F64 INVENTORY_UPDATE_WAIT_TIME_DESYNC = 5; // seconds
 const F64 INVENTORY_UPDATE_WAIT_TIME_OUTDATED = 1;
 
-static LLTrace::BlockTimerStatHandle FTM_CREATE_OBJECT("Create Object");
-
 // static
 LLViewerObject *LLViewerObject::createObject(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp, S32 flags)
 {
+    LL_PROFILE_ZONE_SCOPED;
     LL_DEBUGS("ObjectUpdate") << "creating " << id << LL_ENDL;
     dumpStack("ObjectUpdateStack");
     
 	LLViewerObject *res = NULL;
-	LL_RECORD_BLOCK_TIME(FTM_CREATE_OBJECT);
 
 	if (gNonInteractive
 		&& pcode != LL_PCODE_LEGACY_AVATAR
@@ -252,8 +250,7 @@ LLViewerObject *LLViewerObject::createObject(const LLUUID &id, const LLPCode pco
 }
 
 LLViewerObject::LLViewerObject(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp, BOOL is_global)
-:	LLTrace::MemTrackable<LLViewerObject>("LLViewerObject"),
-	LLPrimitive(),
+:	LLPrimitive(),
 	mChildList(),
 	mID(id),
 	mLocalID(0),
@@ -2517,9 +2514,6 @@ void LLViewerObject::loadFlags(U32 flags)
 
 void LLViewerObject::idleUpdate(LLAgent &agent, const F64 &frame_time)
 {
-	//static LLTrace::BlockTimerStatHandle ftm("Viewer Object");
-	//LL_RECORD_BLOCK_TIME(ftm);
-
 	if (!mDead)
 	{
 		if (!mStatic && sVelocityInterpolate && !isSelected())
diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h
index 250c4ac328..bef8e3e7e3 100644
--- a/indra/newview/llviewerobject.h
+++ b/indra/newview/llviewerobject.h
@@ -110,8 +110,7 @@ struct PotentialReturnableObject
 class LLViewerObject 
 :	public LLPrimitive, 
 	public LLRefCount, 
-	public LLGLUpdate,
-	public LLTrace::MemTrackable<LLViewerObject>
+	public LLGLUpdate
 {
 protected:
 	virtual ~LLViewerObject(); // use unref()
diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp
index 097b5e3645..971a355a65 100644
--- a/indra/newview/llviewerobjectlist.cpp
+++ b/indra/newview/llviewerobjectlist.cpp
@@ -849,8 +849,6 @@ void LLViewerObjectList::updateApparentAngles(LLAgent &agent)
 	LLVOAvatar::cullAvatarsByPixelArea();
 }
 
-static LLTrace::BlockTimerStatHandle FTM_IDLE_COPY("Idle Copy");
-
 void LLViewerObjectList::update(LLAgent &agent)
 {
 	LL_PROFILE_ZONE_SCOPED
@@ -906,8 +904,6 @@ void LLViewerObjectList::update(LLAgent &agent)
 	U32 idle_count = 0;
 	
 	{
-		LL_RECORD_BLOCK_TIME(FTM_IDLE_COPY);
-
  		for (std::vector<LLPointer<LLViewerObject> >::iterator active_iter = mActiveObjects.begin();
 			active_iter != mActiveObjects.end(); active_iter++)
 		{
@@ -1352,11 +1348,9 @@ void LLViewerObjectList::cleanupReferences(LLViewerObject *objectp)
 	}
 }
 
-static LLTrace::BlockTimerStatHandle FTM_REMOVE_DRAWABLE("Remove Drawable");
-
 void LLViewerObjectList::removeDrawable(LLDrawable* drawablep)
 {
-	LL_RECORD_BLOCK_TIME(FTM_REMOVE_DRAWABLE);
+    LL_PROFILE_ZONE_SCOPED;
 
 	if (!drawablep)
 	{
@@ -1645,12 +1639,9 @@ void LLViewerObjectList::onPhysicsFlagsFetchFailure(const LLUUID& object_id)
 	mPendingPhysicsFlags.erase(object_id);
 }
 
-static LLTrace::BlockTimerStatHandle FTM_SHIFT_OBJECTS("Shift Objects");
-static LLTrace::BlockTimerStatHandle FTM_PIPELINE_SHIFT("Pipeline Shift");
-static LLTrace::BlockTimerStatHandle FTM_REGION_SHIFT("Region Shift");
-
 void LLViewerObjectList::shiftObjects(const LLVector3 &offset)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	// This is called when we shift our origin when we cross region boundaries...
 	// We need to update many object caches, I'll document this more as I dig through the code
 	// cleaning things out...
@@ -1660,7 +1651,6 @@ void LLViewerObjectList::shiftObjects(const LLVector3 &offset)
 		return;
 	}
 
-	LL_RECORD_BLOCK_TIME(FTM_SHIFT_OBJECTS);
 
 	LLViewerObject *objectp;
 	for (vobj_list_t::iterator iter = mObjects.begin(); iter != mObjects.end(); ++iter)
@@ -1678,16 +1668,10 @@ void LLViewerObjectList::shiftObjects(const LLVector3 &offset)
 		}
 	}
 
-	{
-		LL_RECORD_BLOCK_TIME(FTM_PIPELINE_SHIFT);
 	gPipeline.shiftObjects(offset);
-	}
-
-	{
-		LL_RECORD_BLOCK_TIME(FTM_REGION_SHIFT);
+	
 	LLWorld::getInstance()->shiftRegions(offset);
 }
-}
 
 void LLViewerObjectList::repartitionObjects()
 {
diff --git a/indra/newview/llvieweroctree.cpp b/indra/newview/llvieweroctree.cpp
index 6365df09e1..868cf75d11 100644
--- a/indra/newview/llvieweroctree.cpp
+++ b/indra/newview/llvieweroctree.cpp
@@ -231,8 +231,7 @@ S32 AABBSphereIntersectR2(const LLVector4a& min, const LLVector4a& max, const LL
 //class LLViewerOctreeEntry definitions
 //-----------------------------------------------------------------------------------
 LLViewerOctreeEntry::LLViewerOctreeEntry() 
-:	LLTrace::MemTrackable<LLViewerOctreeEntry, 16>("LLViewerOctreeEntry"),
-	mGroup(NULL),
+:	mGroup(NULL),
 	mBinRadius(0.f),
 	mBinIndex(-1),
 	mVisible(0)
@@ -458,8 +457,7 @@ LLViewerOctreeGroup::~LLViewerOctreeGroup()
 }
 
 LLViewerOctreeGroup::LLViewerOctreeGroup(OctreeNode* node)
-:	LLTrace::MemTrackable<LLViewerOctreeGroup, 16>("LLViewerOctreeGroup"),
-	mOctreeNode(node),
+:	mOctreeNode(node),
 	mAnyVisible(0),
 	mState(CLEAN)
 {
@@ -545,6 +543,7 @@ void LLViewerOctreeGroup::unbound()
 //virtual 
 void LLViewerOctreeGroup::rebound()
 {
+    LL_PROFILE_ZONE_SCOPED;
 	if (!isDirty())
 	{	
 		return;
@@ -1039,11 +1038,9 @@ void LLOcclusionCullingGroup::clearOcclusionState(U32 state, S32 mode)
 	}
 }
 
-static LLTrace::BlockTimerStatHandle FTM_OCCLUSION_READBACK("Readback Occlusion");
-static LLTrace::BlockTimerStatHandle FTM_OCCLUSION_WAIT("Occlusion Wait");
-
 BOOL LLOcclusionCullingGroup::earlyFail(LLCamera* camera, const LLVector4a* bounds)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	if (camera->getOrigin().isExactlyZero())
 	{
 		return FALSE;
@@ -1094,7 +1091,7 @@ void LLOcclusionCullingGroup::checkOcclusion()
 {
 	if (LLPipeline::sUseOcclusion > 1)
 	{
-		LL_RECORD_BLOCK_TIME(FTM_OCCLUSION_READBACK);
+        LL_PROFILE_ZONE_SCOPED;
 		LLOcclusionCullingGroup* parent = (LLOcclusionCullingGroup*)getParent();
 		if (parent && parent->isOcclusionState(LLOcclusionCullingGroup::OCCLUDED))
 		{	//if the parent has been marked as occluded, the child is implicitly occluded
@@ -1106,19 +1103,8 @@ void LLOcclusionCullingGroup::checkOcclusion()
 			GLuint available = 0;
 			if (mOcclusionQuery[LLViewerCamera::sCurCameraID])
 			{
+                LL_PROFILE_ZONE_NAMED("co - query available")
 				glGetQueryObjectuivARB(mOcclusionQuery[LLViewerCamera::sCurCameraID], GL_QUERY_RESULT_AVAILABLE_ARB, &available);
-
-				static LLCachedControl<bool> wait_for_query(gSavedSettings, "RenderSynchronousOcclusion", true);
-
-				if (wait_for_query && mOcclusionIssued[LLViewerCamera::sCurCameraID] < gFrameCount)
-				{ //query was issued last frame, wait until it's available
-					S32 max_loop = 1024;
-					LL_RECORD_BLOCK_TIME(FTM_OCCLUSION_WAIT);
-					while (!available && max_loop-- > 0)
-					{
-						glGetQueryObjectuivARB(mOcclusionQuery[LLViewerCamera::sCurCameraID], GL_QUERY_RESULT_AVAILABLE_ARB, &available);
-					}
-				}
 			}
 			else
 			{
@@ -1130,6 +1116,7 @@ void LLOcclusionCullingGroup::checkOcclusion()
 				GLuint res = 1;
 				if (!isOcclusionState(DISCARD_QUERY) && mOcclusionQuery[LLViewerCamera::sCurCameraID])
 				{
+                    LL_PROFILE_ZONE_NAMED("co - query result")
 					glGetQueryObjectuivARB(mOcclusionQuery[LLViewerCamera::sCurCameraID], GL_QUERY_RESULT_ARB, &res);	
 #if LL_TRACK_PENDING_OCCLUSION_QUERIES
 					sPendingQueries.erase(mOcclusionQuery[LLViewerCamera::sCurCameraID]);
@@ -1173,19 +1160,9 @@ void LLOcclusionCullingGroup::checkOcclusion()
 	}
 }
 
-static LLTrace::BlockTimerStatHandle FTM_PUSH_OCCLUSION_VERTS("Push Occlusion");
-static LLTrace::BlockTimerStatHandle FTM_SET_OCCLUSION_STATE("Occlusion State");
-static LLTrace::BlockTimerStatHandle FTM_OCCLUSION_EARLY_FAIL("Occlusion Early Fail");
-static LLTrace::BlockTimerStatHandle FTM_OCCLUSION_ALLOCATE("Allocate");
-static LLTrace::BlockTimerStatHandle FTM_OCCLUSION_BUILD("Build");
-static LLTrace::BlockTimerStatHandle FTM_OCCLUSION_BEGIN_QUERY("Begin Query");
-static LLTrace::BlockTimerStatHandle FTM_OCCLUSION_END_QUERY("End Query");
-static LLTrace::BlockTimerStatHandle FTM_OCCLUSION_SET_BUFFER("Set Buffer");
-static LLTrace::BlockTimerStatHandle FTM_OCCLUSION_DRAW_WATER("Draw Water");
-static LLTrace::BlockTimerStatHandle FTM_OCCLUSION_DRAW("Draw");
-
 void LLOcclusionCullingGroup::doOcclusion(LLCamera* camera, const LLVector4a* shift)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	if (mSpatialPartition->isOcclusionEnabled() && LLPipeline::sUseOcclusion > 1)
 	{
 		//move mBounds to the agent space if necessary
@@ -1206,7 +1183,7 @@ void LLOcclusionCullingGroup::doOcclusion(LLCamera* camera, const LLVector4a* sh
 		// Don't cull hole/edge water, unless we have the GL_ARB_depth_clamp extension
 		if (earlyFail(camera, bounds))
 		{
-			LL_RECORD_BLOCK_TIME(FTM_OCCLUSION_EARLY_FAIL);
+            LL_PROFILE_ZONE_NAMED("doOcclusion - early fail");
 			setOcclusionState(LLOcclusionCullingGroup::DISCARD_QUERY);
 			assert_states_valid(this);
 			clearOcclusionState(LLOcclusionCullingGroup::OCCLUDED, LLOcclusionCullingGroup::STATE_MODE_DIFF);
@@ -1217,11 +1194,10 @@ void LLOcclusionCullingGroup::doOcclusion(LLCamera* camera, const LLVector4a* sh
 			if (!isOcclusionState(QUERY_PENDING) || isOcclusionState(DISCARD_QUERY))
 			{
 				{ //no query pending, or previous query to be discarded
-					LL_RECORD_BLOCK_TIME(FTM_RENDER_OCCLUSION);
+                    LL_PROFILE_ZONE_NAMED("doOcclusion - render");
 
 					if (!mOcclusionQuery[LLViewerCamera::sCurCameraID])
 					{
-						LL_RECORD_BLOCK_TIME(FTM_OCCLUSION_ALLOCATE);
 						mOcclusionQuery[LLViewerCamera::sCurCameraID] = getNewOcclusionQueryObjectName();
 					}
 
@@ -1246,15 +1222,12 @@ void LLOcclusionCullingGroup::doOcclusion(LLCamera* camera, const LLVector4a* sh
 					add(sOcclusionQueries, 1);
 
 					{
-						LL_RECORD_BLOCK_TIME(FTM_PUSH_OCCLUSION_VERTS);
+                        LL_PROFILE_ZONE_NAMED("doOcclusion - push");
 						
 						//store which frame this query was issued on
 						mOcclusionIssued[LLViewerCamera::sCurCameraID] = gFrameCount;
 
-						{
-							LL_RECORD_BLOCK_TIME(FTM_OCCLUSION_BEGIN_QUERY);
-							glBeginQueryARB(mode, mOcclusionQuery[LLViewerCamera::sCurCameraID]);					
-						}
+    					glBeginQueryARB(mode, mOcclusionQuery[LLViewerCamera::sCurCameraID]);					
 					
 						LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
 						llassert(shader);
@@ -1266,7 +1239,7 @@ void LLOcclusionCullingGroup::doOcclusion(LLCamera* camera, const LLVector4a* sh
 
 						if (!use_depth_clamp && mSpatialPartition->mDrawableType == LLDrawPool::POOL_VOIDWATER)
 						{
-							LL_RECORD_BLOCK_TIME(FTM_OCCLUSION_DRAW_WATER);
+                            LL_PROFILE_ZONE_NAMED("doOcclusion - draw water");
 
 							LLGLSquashToFarClip squash;
 							if (camera->getOrigin().isExactlyZero())
@@ -1281,7 +1254,7 @@ void LLOcclusionCullingGroup::doOcclusion(LLCamera* camera, const LLVector4a* sh
 						}
 						else
 						{
-							LL_RECORD_BLOCK_TIME(FTM_OCCLUSION_DRAW);
+                            LL_PROFILE_ZONE_NAMED("doOcclusion - draw");
 							if (camera->getOrigin().isExactlyZero())
 							{ //origin is invalid, draw entire box
 								gPipeline.mCubeVB->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, 0);
@@ -1292,17 +1265,13 @@ void LLOcclusionCullingGroup::doOcclusion(LLCamera* camera, const LLVector4a* sh
 								gPipeline.mCubeVB->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, get_box_fan_indices(camera, bounds[0]));
 							}
 						}
-
-
-						{
-							LL_RECORD_BLOCK_TIME(FTM_OCCLUSION_END_QUERY);
-							glEndQueryARB(mode);
-						}
+	
+						glEndQueryARB(mode);
 					}
 				}
 
 				{
-					LL_RECORD_BLOCK_TIME(FTM_SET_OCCLUSION_STATE);
+                    LL_PROFILE_ZONE_NAMED("doOcclusion - set state");
 					setOcclusionState(LLOcclusionCullingGroup::QUERY_PENDING);
 					clearOcclusionState(LLOcclusionCullingGroup::DISCARD_QUERY);
 				}
diff --git a/indra/newview/llvieweroctree.h b/indra/newview/llvieweroctree.h
index 219ec7e8da..11ba7e4f1e 100644
--- a/indra/newview/llvieweroctree.h
+++ b/indra/newview/llvieweroctree.h
@@ -71,8 +71,9 @@ S32 AABBSphereIntersectR2(const LLVector3& min, const LLVector3& max, const LLVe
 
 //defines data needed for octree of an entry
 //LL_ALIGN_PREFIX(16)
-class LLViewerOctreeEntry : public LLRefCount, public LLTrace::MemTrackable<LLViewerOctreeEntry, 16>
+class LLViewerOctreeEntry : public LLRefCount
 {
+    LL_ALIGN_NEW
 	friend class LLViewerOctreeEntryData;
 
 public:
@@ -178,8 +179,9 @@ protected:
 //defines an octree group for an octree node, which contains multiple entries.
 //LL_ALIGN_PREFIX(16)
 class LLViewerOctreeGroup
-:	public LLOctreeListener<LLViewerOctreeEntry>, public LLTrace::MemTrackable<LLViewerOctreeGroup, 16>
+:	public LLOctreeListener<LLViewerOctreeEntry>
 {
+    LL_ALIGN_NEW
 	friend class LLViewerOctreeCull;
 protected:
 	virtual ~LLViewerOctreeGroup();
@@ -201,7 +203,6 @@ public:
 
 	LLViewerOctreeGroup(OctreeNode* node);
 	LLViewerOctreeGroup(const LLViewerOctreeGroup& rhs)
-	: LLTrace::MemTrackable<LLViewerOctreeGroup, 16>("LLViewerOctreeGroup")
 	{
 		*this = rhs;
 	}
diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp
index 34847d8618..fbc5830a5c 100644
--- a/indra/newview/llviewertexture.cpp
+++ b/indra/newview/llviewertexture.cpp
@@ -481,8 +481,6 @@ const F32 GPU_MEMORY_CHECK_WAIT_TIME = 1.0f;
 F32 texmem_lower_bound_scale = 0.85f;
 F32 texmem_middle_bound_scale = 0.925f;
 
-static LLTrace::BlockTimerStatHandle FTM_TEXTURE_MEMORY_CHECK("Memory Check");
-
 //static 
 bool LLViewerTexture::isMemoryForTextureLow()
 {
@@ -531,8 +529,6 @@ void LLViewerTexture::getGPUMemoryForTextures(S32Megabytes &gpu, S32Megabytes &p
     timer.reset();
 
     {
-        LL_RECORD_BLOCK_TIME(FTM_TEXTURE_MEMORY_CHECK);
-
         if (gGLManager.mHasATIMemInfo)
         {
             S32 meminfo[4];
@@ -555,11 +551,8 @@ void LLViewerTexture::getGPUMemoryForTextures(S32Megabytes &gpu, S32Megabytes &p
     }
 }
 
-static LLTrace::BlockTimerStatHandle FTM_TEXTURE_UPDATE_MEDIA("Media");
-static LLTrace::BlockTimerStatHandle FTM_TEXTURE_UPDATE_TEST("Test");
-
 //static
-void LLViewerTexture::updateClass(const F32 velocity, const F32 angular_velocity)
+void LLViewerTexture::updateClass()
 {
     LL_PROFILE_ZONE_SCOPED;
 	sCurrentTime = gFrameTimeSeconds;
@@ -567,14 +560,10 @@ void LLViewerTexture::updateClass(const F32 velocity, const F32 angular_velocity
 	LLTexturePipelineTester* tester = (LLTexturePipelineTester*)LLMetricPerformanceTesterBasic::getTester(sTesterName);
 	if (tester)
 	{
-		LL_RECORD_BLOCK_TIME(FTM_TEXTURE_UPDATE_TEST);
 		tester->update();
 	}
 
-	{
-		LL_RECORD_BLOCK_TIME(FTM_TEXTURE_UPDATE_MEDIA);
-		LLViewerMediaTexture::updateClass();
-	}
+	LLViewerMediaTexture::updateClass();
 
 	sBoundTextureMemory = LLImageGL::sBoundTextureMemory;
 	sTotalTextureMemory = LLImageGL::sGlobalTextureMemory;
@@ -2614,6 +2603,7 @@ void LLViewerFetchedTexture::pauseLoadedCallbacks(const LLLoadedCallbackEntry::s
 
 bool LLViewerFetchedTexture::doLoadedCallbacks()
 {
+    LL_PROFILE_ZONE_SCOPED;
 	static const F32 MAX_INACTIVE_TIME = 900.f ; //seconds
 	static const F32 MAX_IDLE_WAIT_TIME = 5.f ; //seconds
 
@@ -3419,6 +3409,7 @@ bool LLViewerLODTexture::scaleDown()
 //static
 void LLViewerMediaTexture::updateClass()
 {
+    LL_PROFILE_ZONE_SCOPED;
 	static const F32 MAX_INACTIVE_TIME = 30.f;
 
 #if 0
diff --git a/indra/newview/llviewertexture.h b/indra/newview/llviewertexture.h
index a5a1fb2c16..f9f1bfef44 100644
--- a/indra/newview/llviewertexture.h
+++ b/indra/newview/llviewertexture.h
@@ -114,7 +114,7 @@ protected:
 
 public:	
 	static void initClass();
-	static void updateClass(const F32 velocity, const F32 angular_velocity) ;
+	static void updateClass();
 	
 	LLViewerTexture(BOOL usemipmaps = TRUE);
 	LLViewerTexture(const LLUUID& id, BOOL usemipmaps) ;
diff --git a/indra/newview/llviewertexturelist.cpp b/indra/newview/llviewertexturelist.cpp
index db740b69e9..fe26cd67a4 100644
--- a/indra/newview/llviewertexturelist.cpp
+++ b/indra/newview/llviewertexturelist.cpp
@@ -68,7 +68,6 @@ void (*LLViewerTextureList::sUUIDCallback)(void **, const LLUUID&) = NULL;
 S32 LLViewerTextureList::sNumImages = 0;
 
 LLViewerTextureList gTextureList;
-static LLTrace::BlockTimerStatHandle FTM_PROCESS_IMAGES("Process Images");
 
 ETexListType get_element_type(S32 priority)
 {
@@ -761,18 +760,10 @@ void LLViewerTextureList::dirtyImage(LLViewerFetchedTexture *image)
 }
 
 ////////////////////////////////////////////////////////////////////////////
-static LLTrace::BlockTimerStatHandle FTM_IMAGE_MARK_DIRTY("Dirty Images");
-static LLTrace::BlockTimerStatHandle FTM_IMAGE_UPDATE_PRIORITIES("Prioritize");
-static LLTrace::BlockTimerStatHandle FTM_IMAGE_CALLBACKS("Callbacks");
-static LLTrace::BlockTimerStatHandle FTM_IMAGE_FETCH("Fetch");
-static LLTrace::BlockTimerStatHandle FTM_FAST_CACHE_IMAGE_FETCH("Fast Cache Fetch");
-static LLTrace::BlockTimerStatHandle FTM_IMAGE_CREATE("Create");
-static LLTrace::BlockTimerStatHandle FTM_IMAGE_STATS("Stats");
-static LLTrace::BlockTimerStatHandle FTM_UPDATE_TEXTURES("Update Textures");
 
 void LLViewerTextureList::updateImages(F32 max_time)
 {
-	LL_RECORD_BLOCK_TIME(FTM_UPDATE_TEXTURES);
+    LL_PROFILE_ZONE_SCOPED;
 	static BOOL cleared = FALSE;
 	if(gTeleportDisplay)
 	{
@@ -798,62 +789,44 @@ void LLViewerTextureList::updateImages(F32 max_time)
 		sample(FORMATTED_MEM, F64Bytes(LLImageFormatted::sGlobalFormattedMemory));
 	}
 
-	{
-		//loading from fast cache 
-		LL_RECORD_BLOCK_TIME(FTM_FAST_CACHE_IMAGE_FETCH);
-		max_time -= updateImagesLoadingFastCache(max_time);
-	}
-
-	{
-		LL_RECORD_BLOCK_TIME(FTM_IMAGE_UPDATE_PRIORITIES);
-		updateImagesDecodePriorities();
-	}
-
-	F32 total_max_time = max_time;
-
-	{
-		LL_RECORD_BLOCK_TIME(FTM_IMAGE_FETCH);
-		max_time -= updateImagesFetchTextures(max_time);
-	}
+	//loading from fast cache 
+	max_time -= updateImagesLoadingFastCache(max_time);
 	
-	{
-		LL_RECORD_BLOCK_TIME(FTM_IMAGE_CREATE);
-		max_time = llmax(max_time, total_max_time*.50f); // at least 50% of max_time
-		max_time -= updateImagesCreateTextures(max_time);
-	}
+	updateImagesDecodePriorities();
+	
+    F32 total_max_time = max_time;
+
+	max_time -= updateImagesFetchTextures(max_time);
+		
+	max_time = llmax(max_time, total_max_time*.50f); // at least 50% of max_time
+	max_time -= updateImagesCreateTextures(max_time);
 	
 	if (!mDirtyTextureList.empty())
 	{
-		LL_RECORD_BLOCK_TIME(FTM_IMAGE_MARK_DIRTY);
 		gPipeline.dirtyPoolObjectTextures(mDirtyTextureList);
 		mDirtyTextureList.clear();
 	}
 
+	bool didone = false;
+	for (image_list_t::iterator iter = mCallbackList.begin();
+		iter != mCallbackList.end(); )
 	{
-		LL_RECORD_BLOCK_TIME(FTM_IMAGE_CALLBACKS);
-		bool didone = false;
-		for (image_list_t::iterator iter = mCallbackList.begin();
-			iter != mCallbackList.end(); )
+		//trigger loaded callbacks on local textures immediately
+		LLViewerFetchedTexture* image = *iter++;
+		if (!image->getUrl().empty())
 		{
-			//trigger loaded callbacks on local textures immediately
-			LLViewerFetchedTexture* image = *iter++;
-			if (!image->getUrl().empty())
-			{
-				// Do stuff to handle callbacks, update priorities, etc.
-				didone = image->doLoadedCallbacks();
-			}
-			else if (!didone)
-			{
-				// Do stuff to handle callbacks, update priorities, etc.
-				didone = image->doLoadedCallbacks();
-			}
+			// Do stuff to handle callbacks, update priorities, etc.
+			didone = image->doLoadedCallbacks();
+		}
+		else if (!didone)
+		{
+			// Do stuff to handle callbacks, update priorities, etc.
+			didone = image->doLoadedCallbacks();
 		}
 	}
+	
 
-	{
-		LL_RECORD_BLOCK_TIME(FTM_IMAGE_STATS);
-		updateImagesUpdateStats();
-	}
+	updateImagesUpdateStats();
 }
 
 void LLViewerTextureList::clearFetchingRequests()
@@ -1497,8 +1470,8 @@ void LLViewerTextureList::receiveImageHeader(LLMessageSystem *msg, void **user_d
 {
 	static LLCachedControl<bool> log_texture_traffic(gSavedSettings,"LogTextureNetworkTraffic", false) ;
 
-	LL_RECORD_BLOCK_TIME(FTM_PROCESS_IMAGES);
-	
+    LL_PROFILE_ZONE_SCOPED;
+
 	// Receive image header, copy into image object and decompresses 
 	// if this is a one-packet image. 
 	
@@ -1569,7 +1542,7 @@ void LLViewerTextureList::receiveImagePacket(LLMessageSystem *msg, void **user_d
 {
 	static LLCachedControl<bool> log_texture_traffic(gSavedSettings,"LogTextureNetworkTraffic", false) ;
 
-	LL_RECORD_BLOCK_TIME(FTM_PROCESS_IMAGES);
+    LL_PROFILE_ZONE_SCOPED;
 	
 	// Receives image packet, copy into image object,
 	// checks if all packets received, decompresses if so. 
@@ -1642,7 +1615,7 @@ void LLViewerTextureList::receiveImagePacket(LLMessageSystem *msg, void **user_d
 // static
 void LLViewerTextureList::processImageNotInDatabase(LLMessageSystem *msg,void **user_data)
 {
-	LL_RECORD_BLOCK_TIME(FTM_PROCESS_IMAGES);
+    LL_PROFILE_ZONE_SCOPED;
 	LLUUID image_id;
 	msg->getUUIDFast(_PREHASH_ImageID, _PREHASH_ID, image_id);
 	
diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp
index a588d05ff7..4a179146f8 100644
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -328,6 +328,7 @@ public:
 	// must return FALSE when the motion is completed.
 	virtual BOOL onUpdate(F32 time, U8* joint_mask)
 	{
+        LL_PROFILE_ZONE_SCOPED;
 		F32 nx[2];
 		nx[0]=time*TORSO_NOISE_SPEED;
 		nx[1]=0.0f;
@@ -448,6 +449,7 @@ public:
 	// must return FALSE when the motion is completed.
 	virtual BOOL onUpdate(F32 time, U8* joint_mask)
 	{
+        LL_PROFILE_ZONE_SCOPED;
 		mBreatheRate = 1.f;
 
 		F32 breathe_amt = (sinf(mBreatheRate * time) * BREATHE_ROT_MOTION_STRENGTH);
@@ -549,6 +551,7 @@ public:
 	// must return FALSE when the motion is completed.
 	virtual BOOL onUpdate(F32 time, U8* joint_mask)
 	{
+        LL_PROFILE_ZONE_SCOPED;
 		mPelvisState->setPosition(LLVector3::zero);
 
 		return TRUE;
@@ -1318,11 +1321,9 @@ void LLVOAvatar::updateSpatialExtents(LLVector4a& newMin, LLVector4a &newMax)
 }
 
 
-static LLTrace::BlockTimerStatHandle FTM_AVATAR_EXTENT_UPDATE("Av Upd Extent");
-
 void LLVOAvatar::calculateSpatialExtents(LLVector4a& newMin, LLVector4a& newMax)
 {
-    LL_RECORD_BLOCK_TIME(FTM_AVATAR_EXTENT_UPDATE);
+    LL_PROFILE_ZONE_SCOPED;
 
     S32 box_detail = gSavedSettings.getS32("AvatarBoundingBoxComplexity");
     if (getOverallAppearance() != AOA_NORMAL)
@@ -2491,10 +2492,6 @@ S32 LLVOAvatar::setTETexture(const U8 te, const LLUUID& uuid)
 	return setTETextureCore(te, image);
 }
 
-static LLTrace::BlockTimerStatHandle FTM_AVATAR_UPDATE("Avatar Update");
-static LLTrace::BlockTimerStatHandle FTM_AVATAR_UPDATE_COMPLEXITY("Avatar Update Complexity");
-static LLTrace::BlockTimerStatHandle FTM_JOINT_UPDATE("Update Joints");
-
 //------------------------------------------------------------------------
 // LLVOAvatar::dumpAnimationState()
 //------------------------------------------------------------------------
@@ -2527,7 +2524,7 @@ void LLVOAvatar::dumpAnimationState()
 //------------------------------------------------------------------------
 void LLVOAvatar::idleUpdate(LLAgent &agent, const F64 &time)
 {
-	LL_RECORD_BLOCK_TIME(FTM_AVATAR_UPDATE);
+    LL_PROFILE_ZONE_SCOPED;
 
 	if (isDead())
 	{
@@ -2563,8 +2560,6 @@ void LLVOAvatar::idleUpdate(LLAgent &agent, const F64 &time)
 	// force asynchronous drawable update
 	if(mDrawable.notNull())
 	{	
-		LL_RECORD_BLOCK_TIME(FTM_JOINT_UPDATE);
-	
 		if (isSitting() && getParent())
 		{
 			LLViewerObject *root_object = (LLViewerObject*)getRoot();
@@ -2664,9 +2659,8 @@ void LLVOAvatar::idleUpdate(LLAgent &agent, const F64 &time)
 
     if ((LLFrameTimer::getFrameCount() + mID.mData[0]) % compl_upd_freq == 0)
     {
-        LL_RECORD_BLOCK_TIME(FTM_AVATAR_UPDATE_COMPLEXITY);
-	idleUpdateRenderComplexity();
-}
+        idleUpdateRenderComplexity();
+    }
     idleUpdateDebugInfo();
 }
 
@@ -2779,10 +2773,9 @@ void LLVOAvatar::idleUpdateVoiceVisualizer(bool voice_enabled)
 	}//if ( voiceEnabled )
 }		
 
-static LLTrace::BlockTimerStatHandle FTM_ATTACHMENT_UPDATE("Update Attachments");
-
 void LLVOAvatar::idleUpdateMisc(bool detailed_update)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	if (LLVOAvatar::sJointDebug)
 	{
 		LL_INFOS() << getFullname() << ": joint touches: " << LLJoint::sNumTouches << " updates: " << LLJoint::sNumUpdates << LL_ENDL;
@@ -2796,7 +2789,6 @@ void LLVOAvatar::idleUpdateMisc(bool detailed_update)
 	// update attachments positions
 	if (detailed_update)
 	{
-		LL_RECORD_BLOCK_TIME(FTM_ATTACHMENT_UPDATE);
 		for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); 
 			 iter != mAttachmentPoints.end();
 			 ++iter)
@@ -7132,10 +7124,9 @@ void LLVOAvatar::updateGL()
 //-----------------------------------------------------------------------------
 // updateGeometry()
 //-----------------------------------------------------------------------------
-static LLTrace::BlockTimerStatHandle FTM_UPDATE_AVATAR("Update Avatar");
 BOOL LLVOAvatar::updateGeometry(LLDrawable *drawable)
 {
-	LL_RECORD_BLOCK_TIME(FTM_UPDATE_AVATAR);
+    LL_PROFILE_ZONE_SCOPED;
 	if (!(gPipeline.hasRenderType(mIsControlAvatar ? LLPipeline::RENDER_TYPE_CONTROL_AV : LLPipeline::RENDER_TYPE_AVATAR)))
 	{
 		return TRUE;
@@ -10193,6 +10184,7 @@ void showRigInfoTabExtents(LLVOAvatar *avatar, LLJointRiggingInfoTab& tab, S32&
 
 void LLVOAvatar::getAssociatedVolumes(std::vector<LLVOVolume*>& volumes)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	for ( LLVOAvatar::attachment_map_t::iterator iter = mAttachmentPoints.begin(); iter != mAttachmentPoints.end(); ++iter )
 	{
 		LLViewerJointAttachment* attachment = iter->second;
@@ -10250,27 +10242,19 @@ void LLVOAvatar::getAssociatedVolumes(std::vector<LLVOVolume*>& volumes)
     }
 }
 
-static LLTrace::BlockTimerStatHandle FTM_AVATAR_RIGGING_INFO_UPDATE("Av Upd Rig Info");
-static LLTrace::BlockTimerStatHandle FTM_AVATAR_RIGGING_KEY_UPDATE("Av Upd Rig Key");
-static LLTrace::BlockTimerStatHandle FTM_AVATAR_RIGGING_AVOL_UPDATE("Av Upd Avol");
-
 // virtual
 void LLVOAvatar::updateRiggingInfo()
 {
-    LL_RECORD_BLOCK_TIME(FTM_AVATAR_RIGGING_INFO_UPDATE);
+    LL_PROFILE_ZONE_SCOPED;
 
     LL_DEBUGS("RigSpammish") << getFullname() << " updating rig tab" << LL_ENDL;
 
     std::vector<LLVOVolume*> volumes;
 
-	{
-		LL_RECORD_BLOCK_TIME(FTM_AVATAR_RIGGING_AVOL_UPDATE);
-		getAssociatedVolumes(volumes);
-	}
+	getAssociatedVolumes(volumes);
 
 	std::map<LLUUID,S32> curr_rigging_info_key;
 	{
-		LL_RECORD_BLOCK_TIME(FTM_AVATAR_RIGGING_KEY_UPDATE);
 		// Get current rigging info key
 		for (std::vector<LLVOVolume*>::iterator it = volumes.begin(); it != volumes.end(); ++it)
 		{
@@ -10432,6 +10416,7 @@ void LLVOAvatar::updateImpostorRendering(U32 newMaxNonImpostorsValue)
 
 void LLVOAvatar::idleUpdateRenderComplexity()
 {
+    LL_PROFILE_ZONE_SCOPED;
     if (isControlAvatar())
     {
         LLControlAvatar *cav = dynamic_cast<LLControlAvatar*>(this);
diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h
index 39adaab8ca..7042406091 100644
--- a/indra/newview/llvoavatar.h
+++ b/indra/newview/llvoavatar.h
@@ -87,6 +87,7 @@ class LLVOAvatar :
 	public LLViewerObject,
 	public boost::signals2::trackable
 {
+    LL_ALIGN_NEW;
 	LOG_CLASS(LLVOAvatar);
 
 public:
@@ -99,16 +100,6 @@ public:
  **/
 
 public:
-	void* operator new(size_t size)
-	{
-		return LLTrace::MemTrackable<LLViewerObject>::aligned_new<16>(size);
-	}
-
-	void operator delete(void* ptr, size_t size)
-	{
-		LLTrace::MemTrackable<LLViewerObject>::aligned_delete<16>(ptr, size);
-	}
-
 	LLVOAvatar(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp);
 	virtual void		markDead();
 	static void			initClass(); // Initialize data that's only init'd once per class.
diff --git a/indra/newview/llvocache.cpp b/indra/newview/llvocache.cpp
index 5ebc65405f..e10a9f9bcb 100644
--- a/indra/newview/llvocache.cpp
+++ b/indra/newview/llvocache.cpp
@@ -63,8 +63,7 @@ BOOL check_write(LLAPRFile* apr_file, void* src, S32 n_bytes)
 //---------------------------------------------------------------------------
 
 LLVOCacheEntry::LLVOCacheEntry(U32 local_id, U32 crc, LLDataPackerBinaryBuffer &dp)
-:	LLTrace::MemTrackable<LLVOCacheEntry, 16>("LLVOCacheEntry"),
-	LLViewerOctreeEntryData(LLViewerOctreeEntry::LLVOCACHEENTRY),
+:	LLViewerOctreeEntryData(LLViewerOctreeEntry::LLVOCACHEENTRY),
 	mLocalID(local_id),
 	mCRC(crc),
 	mUpdateFlags(-1),
@@ -83,8 +82,7 @@ LLVOCacheEntry::LLVOCacheEntry(U32 local_id, U32 crc, LLDataPackerBinaryBuffer &
 }
 
 LLVOCacheEntry::LLVOCacheEntry()
-:	LLTrace::MemTrackable<LLVOCacheEntry, 16>("LLVOCacheEntry"),
-	LLViewerOctreeEntryData(LLViewerOctreeEntry::LLVOCACHEENTRY),
+:	LLViewerOctreeEntryData(LLViewerOctreeEntry::LLVOCACHEENTRY),
 	mLocalID(0),
 	mCRC(0),
 	mUpdateFlags(-1),
@@ -102,8 +100,7 @@ LLVOCacheEntry::LLVOCacheEntry()
 }
 
 LLVOCacheEntry::LLVOCacheEntry(LLAPRFile* apr_file)
-:	LLTrace::MemTrackable<LLVOCacheEntry, 16>("LLVOCacheEntry"),
-	LLViewerOctreeEntryData(LLViewerOctreeEntry::LLVOCACHEENTRY), 
+:	LLViewerOctreeEntryData(LLViewerOctreeEntry::LLVOCACHEENTRY), 
 	mBuffer(NULL),
 	mUpdateFlags(-1),
 	mState(INACTIVE),
@@ -619,7 +616,6 @@ void LLVOCacheGroup::handleChildAddition(const OctreeNode* parent, OctreeNode* c
 }
 
 LLVOCachePartition::LLVOCachePartition(LLViewerRegion* regionp)
-:	LLTrace::MemTrackable<LLVOCachePartition>("LLVOCachePartition")
 {
 	mLODPeriod = 16;
 	mRegionp = regionp;
diff --git a/indra/newview/llvocache.h b/indra/newview/llvocache.h
index dd6afd6b85..c510ff77fc 100644
--- a/indra/newview/llvocache.h
+++ b/indra/newview/llvocache.h
@@ -38,9 +38,9 @@
 class LLCamera;
 
 class LLVOCacheEntry 
-:	public LLViewerOctreeEntryData,
-	public LLTrace::MemTrackable<LLVOCacheEntry, 16>
+:	public LLViewerOctreeEntryData
 {
+    LL_ALIGN_NEW
 public:
 	enum 
 	{
@@ -185,7 +185,7 @@ protected:
 	virtual ~LLVOCacheGroup();
 };
 
-class LLVOCachePartition : public LLViewerOctreePartition, public LLTrace::MemTrackable<LLVOCachePartition>
+class LLVOCachePartition : public LLViewerOctreePartition
 {
 public:
 	LLVOCachePartition(LLViewerRegion* regionp);
diff --git a/indra/newview/llvograss.cpp b/indra/newview/llvograss.cpp
index 345e87eea8..9a41eedb54 100644
--- a/indra/newview/llvograss.cpp
+++ b/indra/newview/llvograss.cpp
@@ -661,11 +661,9 @@ void LLGrassPartition::addGeometryCount(LLSpatialGroup* group, U32& vertex_count
 	}
 }
 
-static LLTrace::BlockTimerStatHandle FTM_REBUILD_GRASS_VB("Grass VB");
-
 void LLGrassPartition::getGeometry(LLSpatialGroup* group)
 {
-	LL_RECORD_BLOCK_TIME(FTM_REBUILD_GRASS_VB);
+    LL_PROFILE_ZONE_SCOPED;
 
 	std::sort(mFaceList.begin(), mFaceList.end(), LLFace::CompareDistanceGreater());
 
diff --git a/indra/newview/llvopartgroup.cpp b/indra/newview/llvopartgroup.cpp
index b31afca61d..068e8a131d 100644
--- a/indra/newview/llvopartgroup.cpp
+++ b/indra/newview/llvopartgroup.cpp
@@ -306,10 +306,9 @@ LLVector3 LLVOPartGroup::getCameraPosition() const
 	return gAgentCamera.getCameraPositionAgent();
 }
 
-static LLTrace::BlockTimerStatHandle FTM_UPDATE_PARTICLES("Update Particles");
 BOOL LLVOPartGroup::updateGeometry(LLDrawable *drawable)
 {
-	LL_RECORD_BLOCK_TIME(FTM_UPDATE_PARTICLES);
+    LL_PROFILE_ZONE_SCOPED;
 
 	dirtySpatialGroup();
 	
@@ -754,10 +753,9 @@ LLHUDParticlePartition::LLHUDParticlePartition(LLViewerRegion* regionp) :
 	mPartitionType = LLViewerRegion::PARTITION_HUD_PARTICLE;
 }
 
-static LLTrace::BlockTimerStatHandle FTM_REBUILD_PARTICLE_VBO("Particle VBO");
-
 void LLParticlePartition::rebuildGeom(LLSpatialGroup* group)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	if (group->isDead() || !group->hasState(LLSpatialGroup::GEOM_DIRTY))
 	{
 		return;
@@ -769,8 +767,6 @@ void LLParticlePartition::rebuildGeom(LLSpatialGroup* group)
 		group->mLastUpdateViewAngle = group->mViewAngle;
 	}
 	
-	LL_RECORD_BLOCK_TIME(FTM_REBUILD_PARTICLE_VBO);	
-
 	group->clearDrawMap();
 	
 	//get geometry count
@@ -843,11 +839,9 @@ void LLParticlePartition::addGeometryCount(LLSpatialGroup* group, U32& vertex_co
 }
 
 
-static LLTrace::BlockTimerStatHandle FTM_REBUILD_PARTICLE_GEOM("Particle Geom");
-
 void LLParticlePartition::getGeometry(LLSpatialGroup* group)
 {
-	LL_RECORD_BLOCK_TIME(FTM_REBUILD_PARTICLE_GEOM);
+    LL_PROFILE_ZONE_SCOPED;
 
 	std::sort(mFaceList.begin(), mFaceList.end(), LLFace::CompareDistanceGreater());
 
diff --git a/indra/newview/llvosky.cpp b/indra/newview/llvosky.cpp
index edf8c40bd3..1e546861b9 100644
--- a/indra/newview/llvosky.cpp
+++ b/indra/newview/llvosky.cpp
@@ -79,11 +79,6 @@ namespace
     const LLVector2 TEX10 = LLVector2(1.f, 0.f);
     const LLVector2 TEX11 = LLVector2(1.f, 1.f);
 
-    LLTrace::BlockTimerStatHandle FTM_VOSKY_UPDATETIMER("VOSky Update Timer Tick");
-    LLTrace::BlockTimerStatHandle FTM_VOSKY_CALC("VOSky Update Calculations");
-    LLTrace::BlockTimerStatHandle FTM_VOSKY_CREATETEXTURES("VOSky Update Textures");
-    LLTrace::BlockTimerStatHandle FTM_VOSKY_UPDATEFORCED("VOSky Update Forced");
-
     F32Seconds UPDATE_EXPRY(0.25f);
 
     const F32 UPDATE_MIN_DELTA_THRESHOLD = 0.0005f;
@@ -518,6 +513,7 @@ void LLVOSky::cacheEnvironment(LLSettingsSky::ptr_t psky,AtmosphericsVars& atmos
 
 void LLVOSky::calc()
 {
+    LL_PROFILE_ZONE_SCOPED;
     LLSettingsSky::ptr_t psky = LLEnvironment::instance().getCurrentSky();
     cacheEnvironment(psky,m_atmosphericsVars);
 
@@ -686,6 +682,8 @@ bool LLVOSky::updateSky()
 		return TRUE;
 	}
 
+    LL_PROFILE_ZONE_SCOPED;
+
 	static S32 next_frame = 0;
 
     mNeedUpdate = mForceUpdate;
@@ -706,7 +704,6 @@ bool LLVOSky::updateSky()
 
     if (mCubeMapUpdateStage < 0)
     {
-        LL_RECORD_BLOCK_TIME(FTM_VOSKY_CALC);
         calc();
 
         bool same_atmospherics = approximatelyEqual(m_lastAtmosphericsVars, m_atmosphericsVars, UPDATE_MIN_DELTA_THRESHOLD);
@@ -723,7 +720,7 @@ bool LLVOSky::updateSky()
 	}
     else if (mCubeMapUpdateStage == NUM_CUBEMAP_FACES)
 	{
-        LL_RECORD_BLOCK_TIME(FTM_VOSKY_UPDATEFORCED);
+        LL_PROFILE_ZONE_NAMED("updateSky - forced");
         LLSkyTex::stepCurrent();
 
         bool is_alm_wl_sky = gPipeline.canUseWindLightShaders();
@@ -783,8 +780,8 @@ bool LLVOSky::updateSky()
     }
     // run 0 to 5 faces, each face in own frame
     else if (mCubeMapUpdateStage >= 0 && mCubeMapUpdateStage < NUM_CUBEMAP_FACES)
-		{
-        LL_RECORD_BLOCK_TIME(FTM_VOSKY_CREATETEXTURES);
+	{
+        LL_PROFILE_ZONE_NAMED("updateSky - create");
         S32 side = mCubeMapUpdateStage;
         // CPU hungry part, createSkyTexture() is math heavy
         // Prior to EEP it was mostly per tile, but since EPP it is per face.
@@ -974,11 +971,9 @@ void LLVOSky::setBloomTextures(const LLUUID& bloom_texture, const LLUUID& bloom_
     }
 }
 
-static LLTrace::BlockTimerStatHandle FTM_GEO_SKY("Sky Geometry");
-
 BOOL LLVOSky::updateGeometry(LLDrawable *drawable)
 {
-	LL_RECORD_BLOCK_TIME(FTM_GEO_SKY);
+    LL_PROFILE_ZONE_SCOPED;
 	if (mFace[FACE_REFLECTION] == NULL)
 	{
 		LLDrawPoolWater *poolp = (LLDrawPoolWater*) gPipeline.getPool(LLDrawPool::POOL_WATER);
diff --git a/indra/newview/llvosurfacepatch.cpp b/indra/newview/llvosurfacepatch.cpp
index b5560d3d79..4d25e8c7bd 100644
--- a/indra/newview/llvosurfacepatch.cpp
+++ b/indra/newview/llvosurfacepatch.cpp
@@ -212,7 +212,6 @@ LLDrawable *LLVOSurfacePatch::createDrawable(LLPipeline *pipeline)
 	return mDrawable;
 }
 
-static LLTrace::BlockTimerStatHandle FTM_UPDATE_TERRAIN("Update Terrain");
 
 void LLVOSurfacePatch::updateGL()
 {
@@ -225,7 +224,7 @@ void LLVOSurfacePatch::updateGL()
 
 BOOL LLVOSurfacePatch::updateGeometry(LLDrawable *drawable)
 {
-	LL_RECORD_BLOCK_TIME(FTM_UPDATE_TERRAIN);
+    LL_PROFILE_ZONE_SCOPED;
 
 	dirtySpatialGroup(TRUE);
 	
@@ -1071,10 +1070,9 @@ LLVertexBuffer* LLTerrainPartition::createVertexBuffer(U32 type_mask, U32 usage)
 	return new LLVertexBufferTerrain();
 }
 
-static LLTrace::BlockTimerStatHandle FTM_REBUILD_TERRAIN_VB("Terrain VB");
 void LLTerrainPartition::getGeometry(LLSpatialGroup* group)
 {
-	LL_RECORD_BLOCK_TIME(FTM_REBUILD_TERRAIN_VB);
+    LL_PROFILE_ZONE_SCOPED;
 
 	LLVertexBuffer* buffer = group->mVertexBuffer;
 
diff --git a/indra/newview/llvotree.cpp b/indra/newview/llvotree.cpp
index 41099cb570..493162b47b 100644
--- a/indra/newview/llvotree.cpp
+++ b/indra/newview/llvotree.cpp
@@ -493,11 +493,9 @@ LLDrawable* LLVOTree::createDrawable(LLPipeline *pipeline)
 const S32 LEAF_INDICES = 24;
 const S32 LEAF_VERTICES = 16;
 
-static LLTrace::BlockTimerStatHandle FTM_UPDATE_TREE("Update Tree");
-
 BOOL LLVOTree::updateGeometry(LLDrawable *drawable)
 {
-	LL_RECORD_BLOCK_TIME(FTM_UPDATE_TREE);
+    LL_PROFILE_ZONE_SCOPED;
 
 	if(mTrunkLOD >= sMAX_NUM_TREE_LOD_LEVELS) //do not display the tree.
 	{
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index b86935b081..be390e44a3 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -103,10 +103,6 @@ S32 LLVOVolume::mRenderComplexity_current = 0;
 LLPointer<LLObjectMediaDataClient> LLVOVolume::sObjectMediaClient = NULL;
 LLPointer<LLObjectMediaNavigateClient> LLVOVolume::sObjectMediaNavigateClient = NULL;
 
-static LLTrace::BlockTimerStatHandle FTM_GEN_TRIANGLES("Generate Triangles");
-static LLTrace::BlockTimerStatHandle FTM_GEN_VOLUME("Generate Volumes");
-static LLTrace::BlockTimerStatHandle FTM_VOLUME_TEXTURES("Volume Textures");
-
 extern BOOL gGLDebugLoggingEnabled;
 
 // Implementation class of LLMediaDataClientObject.  See llmediadataclient.h
@@ -692,7 +688,7 @@ BOOL LLVOVolume::isVisible() const
 
 void LLVOVolume::updateTextureVirtualSize(bool forced)
 {
-	LL_RECORD_BLOCK_TIME(FTM_VOLUME_TEXTURES);
+    LL_PROFILE_ZONE_SCOPED;
 	// Update the pixel area of all faces
 
     if (mDrawable.isNull())
@@ -971,6 +967,7 @@ LLDrawable *LLVOVolume::createDrawable(LLPipeline *pipeline)
 
 BOOL LLVOVolume::setVolume(const LLVolumeParams &params_in, const S32 detail, bool unique_volume)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	LLVolumeParams volume_params = params_in;
 
 	S32 last_lod = mVolumep.notNull() ? LLVolumeLODGroup::getVolumeDetailFromScale(mVolumep->getDetail()) : -1;
@@ -1598,6 +1595,7 @@ BOOL LLVOVolume::setParent(LLViewerObject* parent)
 // NOTE: regenFaces() MUST be followed by genTriangles()!
 void LLVOVolume::regenFaces()
 {
+    LL_PROFILE_ZONE_SCOPED;
 	// remove existing faces
 	BOOL count_changed = mNumFaces != getNumTEs();
 	
@@ -1645,6 +1643,7 @@ void LLVOVolume::regenFaces()
 
 BOOL LLVOVolume::genBBoxes(BOOL force_global)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	BOOL res = TRUE;
 
 	LLVector4a min,max;
@@ -1855,12 +1854,9 @@ void LLVOVolume::updateRelativeXform(bool force_identity)
 	}
 }
 
-static LLTrace::BlockTimerStatHandle FTM_GEN_FLEX("Generate Flexies");
-static LLTrace::BlockTimerStatHandle FTM_UPDATE_PRIMITIVES("Update Primitives");
-static LLTrace::BlockTimerStatHandle FTM_UPDATE_RIGGED_VOLUME("Update Rigged");
-
 bool LLVOVolume::lodOrSculptChanged(LLDrawable *drawable, BOOL &compiled)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	bool regen_faces = false;
 
 	LLVolume *old_volumep, *new_volumep;
@@ -1873,7 +1869,6 @@ bool LLVOVolume::lodOrSculptChanged(LLDrawable *drawable, BOOL &compiled)
 	old_volumep = NULL;
 
 	{
-		LL_RECORD_BLOCK_TIME(FTM_GEN_VOLUME);
 		const LLVolumeParams &volume_params = getVolume()->getParams();
 		setVolume(volume_params, 0);
 	}
@@ -1901,7 +1896,6 @@ bool LLVOVolume::lodOrSculptChanged(LLDrawable *drawable, BOOL &compiled)
 		drawable->setState(LLDrawable::REBUILD_VOLUME); // for face->genVolumeTriangles()
 
 		{
-			LL_RECORD_BLOCK_TIME(FTM_GEN_TRIANGLES);
 			regen_faces = new_num_faces != old_num_faces || mNumFaces != (S32)getNumTEs();
 			if (regen_faces)
 			{
@@ -1926,14 +1920,11 @@ bool LLVOVolume::lodOrSculptChanged(LLDrawable *drawable, BOOL &compiled)
 
 BOOL LLVOVolume::updateGeometry(LLDrawable *drawable)
 {
-	LL_RECORD_BLOCK_TIME(FTM_UPDATE_PRIMITIVES);
+    LL_PROFILE_ZONE_SCOPED;
 	
 	if (mDrawable->isState(LLDrawable::REBUILD_RIGGED))
 	{
-		{
-			LL_RECORD_BLOCK_TIME(FTM_UPDATE_RIGGED_VOLUME);
-			updateRiggedVolume();
-		}
+		updateRiggedVolume();
 		genBBoxes(FALSE);
 		mDrawable->clearState(LLDrawable::REBUILD_RIGGED);
 	}
@@ -1942,7 +1933,6 @@ BOOL LLVOVolume::updateGeometry(LLDrawable *drawable)
 	{
 		BOOL res;
 		{
-			LL_RECORD_BLOCK_TIME(FTM_GEN_FLEX);
 			res = mVolumeImpl->doUpdateGeometry(drawable);
 		}
 		updateFaceFlags();
@@ -1982,7 +1972,6 @@ BOOL LLVOVolume::updateGeometry(LLDrawable *drawable)
 		}
 
 		if (!was_regen_faces) {
-			LL_RECORD_BLOCK_TIME(FTM_GEN_TRIANGLES);
 			regenFaces();
 		}
 
@@ -2005,7 +1994,6 @@ BOOL LLVOVolume::updateGeometry(LLDrawable *drawable)
 	{
 		compiled = TRUE;
 		// All it did was move or we changed the texture coordinate offset
-		LL_RECORD_BLOCK_TIME(FTM_GEN_TRIANGLES);
 		genBBoxes(FALSE);
 	}
 
@@ -3717,11 +3705,9 @@ void LLVOVolume::afterReparent()
 }
 
 //----------------------------------------------------------------------------
-static LLTrace::BlockTimerStatHandle FTM_VOVOL_RIGGING_INFO("VOVol Rigging Info");
-
 void LLVOVolume::updateRiggingInfo()
 {
-    LL_RECORD_BLOCK_TIME(FTM_VOVOL_RIGGING_INFO);
+    LL_PROFILE_ZONE_SCOPED;
     if (isRiggedMesh())
     {
         const LLMeshSkinInfo* skin = getSkinInfo();
@@ -4726,6 +4712,7 @@ void LLVOVolume::clearRiggedVolume()
 
 void LLVOVolume::updateRiggedVolume(bool force_update)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	//Update mRiggedVolume to match current animation frame of avatar. 
 	//Also update position/size in octree.  
 
@@ -4761,11 +4748,9 @@ void LLVOVolume::updateRiggedVolume(bool force_update)
 	mRiggedVolume->update(skin, avatar, volume);
 }
 
-static LLTrace::BlockTimerStatHandle FTM_SKIN_RIGGED("Skin");
-static LLTrace::BlockTimerStatHandle FTM_RIGGED_OCTREE("Octree");
-
 void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, const LLVolume* volume)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	bool copy = false;
 	if (volume->getNumVolumeFaces() != getNumVolumeFaces())
 	{ 
@@ -4829,8 +4814,6 @@ void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, cons
 
 			if (pos && dst_face.mExtents)
 			{
-				LL_RECORD_BLOCK_TIME(FTM_SKIN_RIGGED);
-
                 U32 max_joints = LLSkinningUtil::getMaxJointCount();
                 rigged_vert_count += dst_face.mNumVertices;
                 rigged_face_count++;
@@ -4901,8 +4884,7 @@ void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, cons
 			}
 
 			{
-				LL_RECORD_BLOCK_TIME(FTM_RIGGED_OCTREE);
-				delete dst_face.mOctree;
+    			delete dst_face.mOctree;
 				dst_face.mOctree = NULL;
 
 				LLVector4a size;
@@ -5066,11 +5048,9 @@ void LLVolumeGeometryManager::freeFaces()
 	sAlphaFaces = NULL;
 }
 
-static LLTrace::BlockTimerStatHandle FTM_REGISTER_FACE("Register Face");
-
 void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep, U32 type)
 {
-	LL_RECORD_BLOCK_TIME(FTM_REGISTER_FACE);
+    LL_PROFILE_ZONE_SCOPED;
 	if (   type == LLRenderPass::PASS_ALPHA 
 		&& facep->getTextureEntry()->getMaterialParams().notNull() 
 		&& !facep->getVertexBuffer()->hasDataType(LLVertexBuffer::TYPE_TANGENT)
@@ -5302,10 +5282,6 @@ void LLVolumeGeometryManager::getGeometry(LLSpatialGroup* group)
 
 }
 
-static LLTrace::BlockTimerStatHandle FTM_REBUILD_VOLUME_VB("Volume VB");
-static LLTrace::BlockTimerStatHandle FTM_REBUILD_VOLUME_FACE_LIST("Build Face List");
-static LLTrace::BlockTimerStatHandle FTM_REBUILD_VOLUME_GEN_DRAW_INFO("Gen Draw Info");
-
 static LLDrawPoolAvatar* get_avatar_drawpool(LLViewerObject* vobj)
 {
 	LLVOAvatar* avatar = vobj->getAvatar();
@@ -5411,6 +5387,7 @@ void handleRenderAutoMuteByteLimitChanged(const LLSD& new_value)
 
 void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	if (group->changeLOD())
 	{
 		group->mLastUpdateDistance = group->mDistance;
@@ -5427,8 +5404,6 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 		return;
 	}
 
-	LL_RECORD_BLOCK_TIME(FTM_REBUILD_VOLUME_VB);
-
 	group->mBuilt = 1.f;
 	
 	LLSpatialBridge* bridge = group->getSpatialPartition()->asBridge();
@@ -5485,7 +5460,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 #endif
 
 	{
-		LL_RECORD_BLOCK_TIME(FTM_REBUILD_VOLUME_FACE_LIST);
+        LL_PROFILE_ZONE_NAMED("rebuildGeom - face list");
 
 		//get all the faces into a list
 		for (LLSpatialGroup::element_iter drawable_iter = group->getDataBegin(); 
@@ -6036,23 +6011,16 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 	mFaceList.clear();
 }
 
-static LLTrace::BlockTimerStatHandle FTM_REBUILD_MESH_FLUSH("Flush Mesh");
-
 void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	llassert(group);
 	if (group && group->hasState(LLSpatialGroup::MESH_DIRTY) && !group->hasState(LLSpatialGroup::GEOM_DIRTY))
 	{
-		LL_RECORD_BLOCK_TIME(FTM_REBUILD_VOLUME_VB);
 		{
-			// 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
+            LL_PROFILE_ZONE_NAMED("rebuildMesh - gen draw info");
 
-			group->mBuilt = 1.f;
+            group->mBuilt = 1.f;
 		
 			S32 num_mapped_vertex_buffer = LLVertexBuffer::sMappedCount ;
 
@@ -6123,7 +6091,7 @@ void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group)
 			}
 
 			{
-				LL_RECORD_BLOCK_TIME(FTM_REBUILD_MESH_FLUSH);
+                LL_PROFILE_ZONE_NAMED("rebuildMesh - flush");
 				for (LLVertexBuffer** iter = locked_buffer, ** end_iter = locked_buffer+buffer_count; iter != end_iter; ++iter)
 				{
 					(*iter)->flush();
@@ -6166,10 +6134,7 @@ void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group)
 
 			group->clearState(LLSpatialGroup::MESH_DIRTY | LLSpatialGroup::NEW_DRAWINFO);
 		}
-
-	} // Tracy integration
-
-//	llassert(!group || !group->isState(LLSpatialGroup::NEW_DRAWINFO));
+	} 
 }
 
 struct CompareBatchBreakerModified
@@ -6202,19 +6167,10 @@ struct CompareBatchBreakerModified
 	}
 };
 
-static LLTrace::BlockTimerStatHandle FTM_GEN_DRAW_INFO_SORT("Draw Info Face Sort");
-static LLTrace::BlockTimerStatHandle FTM_GEN_DRAW_INFO_FACE_SIZE("Face Sizing");
-static LLTrace::BlockTimerStatHandle FTM_GEN_DRAW_INFO_ALLOCATE("Allocate VB");
-static LLTrace::BlockTimerStatHandle FTM_GEN_DRAW_INFO_FIND_VB("Find VB");
-static LLTrace::BlockTimerStatHandle FTM_GEN_DRAW_INFO_RESIZE_VB("Resize VB");
-
-
-
-
 
 U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace** faces, U32 face_count, BOOL distance_sort, BOOL batch_textures, BOOL no_materials)
 {
-	LL_RECORD_BLOCK_TIME(FTM_REBUILD_VOLUME_GEN_DRAW_INFO);
+    LL_PROFILE_ZONE_SCOPED;
 
 	U32 geometryBytes = 0;
 	U32 buffer_usage = group->mBufferUsage;
@@ -6246,7 +6202,7 @@ U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace
 	max_vertices = llmin(max_vertices, (U32) 65535);
 
 	{
-		LL_RECORD_BLOCK_TIME(FTM_GEN_DRAW_INFO_SORT);
+        LL_PROFILE_ZONE_NAMED("genDrawInfo - sort");
 		if (!distance_sort)
 		{
 			//sort faces by things that break batches
@@ -6332,7 +6288,7 @@ U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace
 		U32 texture_count = 0;
 
 		{
-			LL_RECORD_BLOCK_TIME(FTM_GEN_DRAW_INFO_FACE_SIZE);
+            LL_PROFILE_ZONE_NAMED("genDrawInfo - face size");
 			if (batch_textures)
 			{
 				U8 cur_tex = 0;
@@ -6455,7 +6411,7 @@ U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace
 		LLPointer<LLVertexBuffer> buffer;
 
 		{
-			LL_RECORD_BLOCK_TIME(FTM_GEN_DRAW_INFO_ALLOCATE);
+            LL_PROFILE_ZONE_NAMED("genDrawInfo - allocate");
 			buffer = createVertexBuffer(mask, buffer_usage);
 			if(!buffer->allocateBuffer(geom_count, index_count, TRUE))
 			{
@@ -6843,6 +6799,8 @@ U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace
 
 void LLGeometryManager::addGeometryCount(LLSpatialGroup* group, U32 &vertex_count, U32 &index_count)
 {	
+    LL_PROFILE_ZONE_SCOPED;
+
 	//initialize to default usage for this partition
 	U32 usage = group->getSpatialPartition()->mBufferUsage;
 	
diff --git a/indra/newview/llvowater.cpp b/indra/newview/llvowater.cpp
index 12def24a0d..efe6aa158e 100644
--- a/indra/newview/llvowater.cpp
+++ b/indra/newview/llvowater.cpp
@@ -114,11 +114,9 @@ LLDrawable *LLVOWater::createDrawable(LLPipeline *pipeline)
 	return mDrawable;
 }
 
-static LLTrace::BlockTimerStatHandle FTM_UPDATE_WATER("Update Water");
-
 BOOL LLVOWater::updateGeometry(LLDrawable *drawable)
 {
-	LL_RECORD_BLOCK_TIME(FTM_UPDATE_WATER);
+    LL_PROFILE_ZONE_SCOPED;
 	LLFace *face;
 
 	if (drawable->getNumFaces() < 1)
diff --git a/indra/newview/llvowlsky.cpp b/indra/newview/llvowlsky.cpp
index d428cb1568..5a8126fa38 100644
--- a/indra/newview/llvowlsky.cpp
+++ b/indra/newview/llvowlsky.cpp
@@ -141,11 +141,9 @@ void LLVOWLSky::restoreGL()
 	gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_ALL, TRUE);
 }
 
-static LLTrace::BlockTimerStatHandle FTM_GEO_SKY("Windlight Sky Geometry");
-
 BOOL LLVOWLSky::updateGeometry(LLDrawable * drawable)
 {
-    LL_RECORD_BLOCK_TIME(FTM_GEO_SKY);
+    LL_PROFILE_ZONE_SCOPED;
 	LLStrider<LLVector3>	vertices;
 	LLStrider<LLVector2>	texCoords;
 	LLStrider<U16>			indices;
diff --git a/indra/newview/llworld.cpp b/indra/newview/llworld.cpp
index c7b0a2bfb4..0a8457eb2c 100644
--- a/indra/newview/llworld.cpp
+++ b/indra/newview/llworld.cpp
@@ -62,6 +62,8 @@
 #include <cstring>
 
 
+LLWorld* LLSimpleton<LLWorld>::sInstance = nullptr;
+
 //
 // Globals
 //
@@ -135,6 +137,7 @@ void LLWorld::destroyClass()
 	LLDrawable::incrementVisible();
 
 	LLSceneMonitor::deleteSingleton();
+    LLWorld::deleteSingleton();
 }
 
 
@@ -1077,6 +1080,7 @@ void LLWorld::updateWaterObjects()
 
 void LLWorld::shiftRegions(const LLVector3& offset)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	for (region_list_t::const_iterator i = getRegionList().begin(); i != getRegionList().end(); ++i)
 	{
 		LLViewerRegion* region = *i;
@@ -1147,11 +1151,9 @@ void LLWorld::disconnectRegions()
 	}
 }
 
-static LLTrace::BlockTimerStatHandle FTM_ENABLE_SIMULATOR("Enable Sim");
-
 void process_enable_simulator(LLMessageSystem *msg, void **user_data)
 {
-	LL_RECORD_BLOCK_TIME(FTM_ENABLE_SIMULATOR);
+    LL_PROFILE_ZONE_SCOPED;
 	// enable the appropriate circuit for this simulator and 
 	// add its values into the gSimulator structure
 	U64		handle;
@@ -1217,12 +1219,11 @@ public:
 	}
 };
 
-static LLTrace::BlockTimerStatHandle FTM_DISABLE_REGION("Disable Region");
 // disable the circuit to this simulator
 // Called in response to "DisableSimulator" message.
 void process_disable_simulator(LLMessageSystem *mesgsys, void **user_data)
 {
-    LL_RECORD_BLOCK_TIME(FTM_DISABLE_REGION);
+    LL_PROFILE_ZONE_SCOPED;
 
     LLHost host = mesgsys->getSender();
 
diff --git a/indra/newview/llworld.h b/indra/newview/llworld.h
index 98552bc4d1..69f2df4203 100644
--- a/indra/newview/llworld.h
+++ b/indra/newview/llworld.h
@@ -59,11 +59,12 @@ class LLVOAvatar;
 // as simulators are connected to, viewer_regions are popped off the stack and connected as required
 // as simulators are removed, they are pushed back onto the stack
 
-class LLWorld : public LLSingleton<LLWorld>
+class LLWorld : public LLSimpleton<LLWorld>
 {
-	LLSINGLETON(LLWorld);
 public:
-	void destroyClass();
+    LLWorld();
+
+    void destroyClass();
 
 	LLViewerRegion*	addRegion(const U64 &region_handle, const LLHost &host);
 		// safe to call if already present, does the "right thing" if
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index 7aa05fb22f..6ed6e20b03 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -238,7 +238,6 @@ const LLMatrix4* gGLLastMatrix = NULL;
 LLTrace::BlockTimerStatHandle FTM_RENDER_GEOMETRY("Render Geometry");
 LLTrace::BlockTimerStatHandle FTM_RENDER_GRASS("Grass");
 LLTrace::BlockTimerStatHandle FTM_RENDER_INVISIBLE("Invisible");
-LLTrace::BlockTimerStatHandle FTM_RENDER_OCCLUSION("Occlusion");
 LLTrace::BlockTimerStatHandle FTM_RENDER_SHINY("Shiny");
 LLTrace::BlockTimerStatHandle FTM_RENDER_SIMPLE("Simple");
 LLTrace::BlockTimerStatHandle FTM_RENDER_TERRAIN("Terrain");
@@ -253,14 +252,12 @@ LLTrace::BlockTimerStatHandle FTM_RENDER_MATERIALS("Render Materials");
 LLTrace::BlockTimerStatHandle FTM_RENDER_FULLBRIGHT("Fullbright");
 LLTrace::BlockTimerStatHandle FTM_RENDER_GLOW("Glow");
 LLTrace::BlockTimerStatHandle FTM_GEO_UPDATE("Geo Update");
-LLTrace::BlockTimerStatHandle FTM_PIPELINE_CREATE("Pipeline Create");
 LLTrace::BlockTimerStatHandle FTM_POOLRENDER("RenderPool");
 LLTrace::BlockTimerStatHandle FTM_POOLS("Pools");
 LLTrace::BlockTimerStatHandle FTM_DEFERRED_POOLRENDER("RenderPool (Deferred)");
 LLTrace::BlockTimerStatHandle FTM_DEFERRED_POOLS("Pools (Deferred)");
 LLTrace::BlockTimerStatHandle FTM_POST_DEFERRED_POOLRENDER("RenderPool (Post)");
 LLTrace::BlockTimerStatHandle FTM_POST_DEFERRED_POOLS("Pools (Post)");
-LLTrace::BlockTimerStatHandle FTM_RENDER_BLOOM_FBO("First FBO");
 LLTrace::BlockTimerStatHandle FTM_STATESORT("Sort Draw State");
 LLTrace::BlockTimerStatHandle FTM_PIPELINE("Pipeline");
 LLTrace::BlockTimerStatHandle FTM_CLIENT_COPY("Client Copy");
@@ -269,11 +266,8 @@ LLTrace::BlockTimerStatHandle FTM_RENDER_DEFERRED("Deferred Shading");
 LLTrace::BlockTimerStatHandle FTM_RENDER_UI_HUD("HUD");
 LLTrace::BlockTimerStatHandle FTM_RENDER_UI_3D("3D");
 LLTrace::BlockTimerStatHandle FTM_RENDER_UI_2D("2D");
-LLTrace::BlockTimerStatHandle FTM_RENDER_UI_DEBUG_TEXT("Debug Text");
-LLTrace::BlockTimerStatHandle FTM_RENDER_UI_SCENE_MON("Scene Mon");
 
 static LLTrace::BlockTimerStatHandle FTM_STATESORT_DRAWABLE("Sort Drawables");
-static LLTrace::BlockTimerStatHandle FTM_STATESORT_POSTSORT("Post Sort");
 
 static LLStaticHashedString sTint("tint");
 static LLStaticHashedString sAmbiance("ambiance");
@@ -727,8 +721,6 @@ void LLPipeline::destroyGL()
 	}
 }
 
-static LLTrace::BlockTimerStatHandle FTM_RESIZE_SCREEN_TEXTURE("Resize Screen Texture");
-
 void LLPipeline::requestResizeScreenTexture()
 {
     gResizeScreenTexture = TRUE;
@@ -748,7 +740,6 @@ void LLPipeline::resizeShadowTexture()
 
 void LLPipeline::resizeScreenTexture()
 {
-	LL_RECORD_BLOCK_TIME(FTM_RESIZE_SCREEN_TEXTURE);
 	if (gPipeline.canUseVertexShaders() && assertInitialized())
 	{
 		GLuint resX = gViewerWindow->getWorldViewWidthRaw();
@@ -1518,6 +1509,7 @@ public:
 // Called when a texture changes # of channels (causes faces to move to alpha pool)
 void LLPipeline::dirtyPoolObjectTextures(const std::set<LLViewerFetchedTexture*>& textures)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	assertInitialized();
 
 	// *TODO: This is inefficient and causes frame spikes; need a better way to do this
@@ -1729,15 +1721,9 @@ void LLPipeline::allocDrawable(LLViewerObject *vobj)
 }
 
 
-static LLTrace::BlockTimerStatHandle FTM_UNLINK("Unlink");
-static LLTrace::BlockTimerStatHandle FTM_REMOVE_FROM_MOVE_LIST("Movelist");
-static LLTrace::BlockTimerStatHandle FTM_REMOVE_FROM_SPATIAL_PARTITION("Spatial Partition");
-static LLTrace::BlockTimerStatHandle FTM_REMOVE_FROM_LIGHT_SET("Light Set");
-static LLTrace::BlockTimerStatHandle FTM_REMOVE_FROM_HIGHLIGHT_SET("Highlight Set");
-
 void LLPipeline::unlinkDrawable(LLDrawable *drawable)
 {
-	LL_RECORD_BLOCK_TIME(FTM_UNLINK);
+    LL_PROFILE_ZONE_SCOPED;
 
 	assertInitialized();
 
@@ -1746,7 +1732,6 @@ void LLPipeline::unlinkDrawable(LLDrawable *drawable)
 	// Based on flags, remove the drawable from the queues that it's on.
 	if (drawablep->isState(LLDrawable::ON_MOVE_LIST))
 	{
-		LL_RECORD_BLOCK_TIME(FTM_REMOVE_FROM_MOVE_LIST);
 		LLDrawable::drawable_vector_t::iterator iter = std::find(mMovedList.begin(), mMovedList.end(), drawablep);
 		if (iter != mMovedList.end())
 		{
@@ -1756,7 +1741,6 @@ void LLPipeline::unlinkDrawable(LLDrawable *drawable)
 
 	if (drawablep->getSpatialGroup())
 	{
-		LL_RECORD_BLOCK_TIME(FTM_REMOVE_FROM_SPATIAL_PARTITION);
 		if (!drawablep->getSpatialGroup()->getSpatialPartition()->remove(drawablep, drawablep->getSpatialGroup()))
 		{
 #ifdef LL_RELEASE_FOR_DOWNLOAD
@@ -1767,30 +1751,24 @@ void LLPipeline::unlinkDrawable(LLDrawable *drawable)
 		}
 	}
 
-	{
-		LL_RECORD_BLOCK_TIME(FTM_REMOVE_FROM_LIGHT_SET);
-		mLights.erase(drawablep);
+	mLights.erase(drawablep);
 
-		for (light_set_t::iterator iter = mNearbyLights.begin();
-					iter != mNearbyLights.end(); iter++)
+	for (light_set_t::iterator iter = mNearbyLights.begin();
+				iter != mNearbyLights.end(); iter++)
+	{
+		if (iter->drawable == drawablep)
 		{
-			if (iter->drawable == drawablep)
-			{
-				mNearbyLights.erase(iter);
-				break;
-			}
+			mNearbyLights.erase(iter);
+			break;
 		}
 	}
 
-	{
-		LL_RECORD_BLOCK_TIME(FTM_REMOVE_FROM_HIGHLIGHT_SET);
-		HighlightItem item(drawablep);
-		mHighlightSet.erase(item);
+	HighlightItem item(drawablep);
+	mHighlightSet.erase(item);
 
-		if (mHighlightObject == drawablep)
-		{
-			mHighlightObject = NULL;
-		}
+	if (mHighlightObject == drawablep)
+	{
+		mHighlightObject = NULL;
 	}
 
 	for (U32 i = 0; i < 2; ++i)
@@ -1805,14 +1783,12 @@ void LLPipeline::unlinkDrawable(LLDrawable *drawable)
 			mTargetShadowSpotLight[i] = NULL;
 		}
 	}
-
-
 }
 
 //static
 void LLPipeline::removeMutedAVsLights(LLVOAvatar* muted_avatar)
 {
-	LL_RECORD_BLOCK_TIME(FTM_REMOVE_FROM_LIGHT_SET);
+    LL_PROFILE_ZONE_SCOPED;
 	for (light_set_t::iterator iter = gPipeline.mNearbyLights.begin();
 		 iter != gPipeline.mNearbyLights.end(); iter++)
 	{
@@ -1840,7 +1816,7 @@ U32 LLPipeline::addObject(LLViewerObject *vobj)
 
 void LLPipeline::createObjects(F32 max_dtime)
 {
-	LL_RECORD_BLOCK_TIME(FTM_PIPELINE_CREATE);
+    LL_PROFILE_ZONE_SCOPED;
 
 	LLTimer update_timer;
 
@@ -1864,6 +1840,7 @@ void LLPipeline::createObjects(F32 max_dtime)
 
 void LLPipeline::createObject(LLViewerObject* vobj)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	LLDrawable* drawablep = vobj->mDrawable;
 
 	if (!drawablep)
@@ -2010,14 +1987,9 @@ void LLPipeline::updateMovedList(LLDrawable::drawable_vector_t& moved_list)
 	}
 }
 
-static LLTrace::BlockTimerStatHandle FTM_OCTREE_BALANCE("Balance Octree");
-static LLTrace::BlockTimerStatHandle FTM_UPDATE_MOVE("Update Move");
-static LLTrace::BlockTimerStatHandle FTM_RETEXTURE("Retexture");
-static LLTrace::BlockTimerStatHandle FTM_MOVED_LIST("Moved List");
-
 void LLPipeline::updateMove()
 {
-	LL_RECORD_BLOCK_TIME(FTM_UPDATE_MOVE);
+    LL_PROFILE_ZONE_SCOPED;
 
 	if (FreezeTime)
 	{
@@ -2026,49 +1998,38 @@ void LLPipeline::updateMove()
 
 	assertInitialized();
 
+	for (LLDrawable::drawable_set_t::iterator iter = mRetexturedList.begin();
+			iter != mRetexturedList.end(); ++iter)
 	{
-		LL_RECORD_BLOCK_TIME(FTM_RETEXTURE);
-
-		for (LLDrawable::drawable_set_t::iterator iter = mRetexturedList.begin();
-			 iter != mRetexturedList.end(); ++iter)
+		LLDrawable* drawablep = *iter;
+		if (drawablep && !drawablep->isDead())
 		{
-			LLDrawable* drawablep = *iter;
-			if (drawablep && !drawablep->isDead())
-			{
-				drawablep->updateTexture();
-			}
+			drawablep->updateTexture();
 		}
-		mRetexturedList.clear();
 	}
+	mRetexturedList.clear();
 
-	{
-		LL_RECORD_BLOCK_TIME(FTM_MOVED_LIST);
-		updateMovedList(mMovedList);
-	}
+	updateMovedList(mMovedList);
 
 	//balance octrees
+	for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); 
+		iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
 	{
- 		LL_RECORD_BLOCK_TIME(FTM_OCTREE_BALANCE);
-
-		for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); 
-			iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
+		LLViewerRegion* region = *iter;
+		for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++)
 		{
-			LLViewerRegion* region = *iter;
-			for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++)
+			LLSpatialPartition* part = region->getSpatialPartition(i);
+			if (part)
 			{
-				LLSpatialPartition* part = region->getSpatialPartition(i);
-				if (part)
-				{
-					part->mOctree->balance();
-				}
+				part->mOctree->balance();
 			}
+		}
 
-			//balance the VO Cache tree
-			LLVOCachePartition* vo_part = region->getVOCachePartition();
-			if(vo_part)
-			{
-				vo_part->mOctree->balance();
-			}
+		//balance the VO Cache tree
+		LLVOCachePartition* vo_part = region->getVOCachePartition();
+		if(vo_part)
+		{
+			vo_part->mOctree->balance();
 		}
 	}
 }
@@ -2752,14 +2713,10 @@ bool LLPipeline::updateDrawableGeom(LLDrawable* drawablep, bool priority)
 	return update_complete;
 }
 
-static LLTrace::BlockTimerStatHandle FTM_SEED_VBO_POOLS("Seed VBO Pool");
-
-static LLTrace::BlockTimerStatHandle FTM_UPDATE_GL("Update GL");
-
 void LLPipeline::updateGL()
 {
+    LL_PROFILE_ZONE_SCOPED;
 	{
-		LL_RECORD_BLOCK_TIME(FTM_UPDATE_GL);
 		while (!LLGLUpdate::sGLQ.empty())
 		{
 			LLGLUpdate* glu = LLGLUpdate::sGLQ.front();
@@ -2770,15 +2727,13 @@ void LLPipeline::updateGL()
 	}
 
 	{ //seed VBO Pools
-		LL_RECORD_BLOCK_TIME(FTM_SEED_VBO_POOLS);
 		LLVertexBuffer::seedPools();
 	}
 }
 
-static LLTrace::BlockTimerStatHandle FTM_REBUILD_PRIORITY_GROUPS("Rebuild Priority Groups");
-
 void LLPipeline::clearRebuildGroups()
 {
+    LL_PROFILE_ZONE_SCOPED;
 	LLSpatialGroup::sg_vector_t	hudGroups;
 
 	mGroupQ1Locked = true;
@@ -2883,7 +2838,7 @@ void LLPipeline::clearRebuildDrawables()
 
 void LLPipeline::rebuildPriorityGroups()
 {
-	LL_RECORD_BLOCK_TIME(FTM_REBUILD_PRIORITY_GROUPS);
+    LL_PROFILE_ZONE_SCOPED;
 	LLTimer update_timer;
 	assertInitialized();
 
@@ -2905,8 +2860,6 @@ void LLPipeline::rebuildPriorityGroups()
 
 }
 
-static LLTrace::BlockTimerStatHandle FTM_REBUILD_GROUPS("Rebuild Groups");
-
 void LLPipeline::rebuildGroups()
 {
 	if (mGroupQ2.empty())
@@ -2914,7 +2867,7 @@ void LLPipeline::rebuildGroups()
 		return;
 	}
 
-	LL_RECORD_BLOCK_TIME(FTM_REBUILD_GROUPS);
+    LL_PROFILE_ZONE_SCOPED;
 	mGroupQ2Locked = true;
 	// Iterate through some drawables on the non-priority build queue
 	S32 size = (S32) mGroupQ2.size();
@@ -3160,12 +3113,9 @@ void LLPipeline::markShift(LLDrawable *drawablep)
 	}
 }
 
-static LLTrace::BlockTimerStatHandle FTM_SHIFT_DRAWABLE("Shift Drawable");
-static LLTrace::BlockTimerStatHandle FTM_SHIFT_OCTREE("Shift Octree");
-static LLTrace::BlockTimerStatHandle FTM_SHIFT_HUD("Shift HUD");
-
 void LLPipeline::shiftObjects(const LLVector3 &offset)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	assertInitialized();
 
 	glClear(GL_DEPTH_BUFFER_BIT);
@@ -3174,46 +3124,36 @@ void LLPipeline::shiftObjects(const LLVector3 &offset)
 	LLVector4a offseta;
 	offseta.load3(offset.mV);
 
+	for (LLDrawable::drawable_vector_t::iterator iter = mShiftList.begin();
+			iter != mShiftList.end(); iter++)
 	{
-		LL_RECORD_BLOCK_TIME(FTM_SHIFT_DRAWABLE);
-
-		for (LLDrawable::drawable_vector_t::iterator iter = mShiftList.begin();
-			 iter != mShiftList.end(); iter++)
+		LLDrawable *drawablep = *iter;
+		if (drawablep->isDead())
 		{
-			LLDrawable *drawablep = *iter;
-			if (drawablep->isDead())
-			{
-				continue;
-			}	
-			drawablep->shiftPos(offseta);	
-			drawablep->clearState(LLDrawable::ON_SHIFT_LIST);
-		}
-		mShiftList.resize(0);
+			continue;
+		}	
+		drawablep->shiftPos(offseta);	
+		drawablep->clearState(LLDrawable::ON_SHIFT_LIST);
 	}
-
+	mShiftList.resize(0);
 	
+	for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); 
+			iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
 	{
-		LL_RECORD_BLOCK_TIME(FTM_SHIFT_OCTREE);
-		for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); 
-				iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
+		LLViewerRegion* region = *iter;
+		for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++)
 		{
-			LLViewerRegion* region = *iter;
-			for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++)
+			LLSpatialPartition* part = region->getSpatialPartition(i);
+			if (part)
 			{
-				LLSpatialPartition* part = region->getSpatialPartition(i);
-				if (part)
-				{
-					part->shift(offseta);
-				}
+				part->shift(offseta);
 			}
 		}
 	}
 
-	{
-		LL_RECORD_BLOCK_TIME(FTM_SHIFT_HUD);
-		LLHUDText::shiftAll(offset);
-		LLHUDNameTag::shiftAll(offset);
-	}
+	LLHUDText::shiftAll(offset);
+	LLHUDNameTag::shiftAll(offset);
+
 	display_update_camera();
 }
 
@@ -3244,10 +3184,9 @@ void LLPipeline::markPartitionMove(LLDrawable* drawable)
 	}
 }
 
-static LLTrace::BlockTimerStatHandle FTM_PROCESS_PARTITIONQ("PartitionQ");
 void LLPipeline::processPartitionQ()
 {
-	LL_RECORD_BLOCK_TIME(FTM_PROCESS_PARTITIONQ);
+    LL_PROFILE_ZONE_SCOPED;
 	for (LLDrawable::drawable_list_t::iterator iter = mPartitionQ.begin(); iter != mPartitionQ.end(); ++iter)
 	{
 		LLDrawable* drawable = *iter;
@@ -3347,8 +3286,6 @@ void LLPipeline::markRebuild(LLDrawable *drawablep, LLDrawable::EDrawableFlags f
 	}
 }
 
-static LLTrace::BlockTimerStatHandle FTM_RESET_DRAWORDER("Reset Draw Order");
-
 void LLPipeline::stateSort(LLCamera& camera, LLCullResult &result)
 {
 	if (hasAnyRenderType(LLPipeline::RENDER_TYPE_AVATAR,
@@ -3362,7 +3299,6 @@ void LLPipeline::stateSort(LLCamera& camera, LLCullResult &result)
 					  LLPipeline::END_RENDER_TYPES))
 	{
 		//clear faces from face pools
-		LL_RECORD_BLOCK_TIME(FTM_RESET_DRAWORDER);
 		gPipeline.resetDrawOrders();
 	}
 
@@ -3811,7 +3747,7 @@ void LLPipeline::touchTextures(LLDrawInfo* info)
 
 void LLPipeline::postSort(LLCamera& camera)
 {
-	LL_RECORD_BLOCK_TIME(FTM_STATESORT_POSTSORT);
+    LL_PROFILE_ZONE_SCOPED;
 
 	assertInitialized();
 
@@ -4837,6 +4773,7 @@ void LLPipeline::renderGeomShadow(LLCamera& camera)
 
 void LLPipeline::addTrianglesDrawn(S32 index_count, U32 render_type)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	assertInitialized();
 	S32 count = 0;
 	if (render_type == LLRender::TRIANGLE_STRIP)
@@ -5617,11 +5554,9 @@ void LLPipeline::renderDebug()
 	}
 }
 
-static LLTrace::BlockTimerStatHandle FTM_REBUILD_POOLS("Rebuild Pools");
-
 void LLPipeline::rebuildPools()
 {
-	LL_RECORD_BLOCK_TIME(FTM_REBUILD_POOLS);
+    LL_PROFILE_ZONE_SCOPED;
 
 	assertInitialized();
 
@@ -5965,6 +5900,7 @@ void LLPipeline::removeFromQuickLookup( LLDrawPool* poolp )
 
 void LLPipeline::resetDrawOrders()
 {
+    LL_PROFILE_ZONE_SCOPED;
 	assertInitialized();
 	// Iterate through all of the draw pools and rebuild them.
 	for (pool_set_t::iterator iter = mPools.begin(); iter != mPools.end(); ++iter)
@@ -7380,8 +7316,6 @@ void LLPipeline::resetVertexBuffers()
 	mResetVertexBuffers = true;
 }
 
-static LLTrace::BlockTimerStatHandle FTM_RESET_VB("Reset VB");
-
 void LLPipeline::doResetVertexBuffers(bool forced)
 {
 	if (!mResetVertexBuffers)
@@ -7403,7 +7337,7 @@ void LLPipeline::doResetVertexBuffers(bool forced)
 		}
 	}
 
-	LL_RECORD_BLOCK_TIME(FTM_RESET_VB);
+    LL_PROFILE_ZONE_SCOPED;
 	mResetVertexBuffers = false;
 
 	mCubeVB = NULL;
@@ -7603,11 +7537,8 @@ void LLPipeline::renderFinalize()
 
     if (sRenderGlow)
     {
-        {
-            LL_RECORD_BLOCK_TIME(FTM_RENDER_BLOOM_FBO);
-            mGlow[2].bindTarget();
-            mGlow[2].clear();
-        }
+        mGlow[2].bindTarget();
+        mGlow[2].clear();
 
         gGlowExtractProgram.bind();
         F32 minLum = llmax((F32) RenderGlowMinLuminance, 0.0f);
@@ -7673,11 +7604,8 @@ void LLPipeline::renderFinalize()
 
         for (S32 i = 0; i < kernel; i++)
         {
-            {
-                LL_RECORD_BLOCK_TIME(FTM_RENDER_BLOOM_FBO);
-                mGlow[i % 2].bindTarget();
-                mGlow[i % 2].clear();
-            }
+            mGlow[i % 2].bindTarget();
+            mGlow[i % 2].clear();
 
             if (i == 0)
             {
@@ -8194,11 +8122,9 @@ void LLPipeline::renderFinalize()
     LLGLState::checkTextureChannels();
 }
 
-static LLTrace::BlockTimerStatHandle FTM_BIND_DEFERRED("Bind Deferred");
-
 void LLPipeline::bindDeferredShader(LLGLSLShader& shader, LLRenderTarget* light_target)
 {
-	LL_RECORD_BLOCK_TIME(FTM_BIND_DEFERRED);
+    LL_PROFILE_ZONE_SCOPED;
 
     LLRenderTarget* deferred_target       = &mDeferredScreen;
     LLRenderTarget* deferred_depth_target = &mDeferredDepth;
@@ -8458,16 +8384,7 @@ LLVector4 pow4fsrgb(LLVector4 v, F32 f)
 	return v;
 }
 
-static LLTrace::BlockTimerStatHandle FTM_GI_TRACE("Trace");
-static LLTrace::BlockTimerStatHandle FTM_GI_GATHER("Gather");
-static LLTrace::BlockTimerStatHandle FTM_SUN_SHADOW("Shadow Map");
-static LLTrace::BlockTimerStatHandle FTM_SOFTEN_SHADOW("Shadow Soften");
-static LLTrace::BlockTimerStatHandle FTM_EDGE_DETECTION("Find Edges");
-static LLTrace::BlockTimerStatHandle FTM_LOCAL_LIGHTS("Local Lights");
-static LLTrace::BlockTimerStatHandle FTM_ATMOSPHERICS("Atmospherics");
-static LLTrace::BlockTimerStatHandle FTM_FULLSCREEN_LIGHTS("Fullscreen Lights");
-static LLTrace::BlockTimerStatHandle FTM_PROJECTORS("Projectors");
-static LLTrace::BlockTimerStatHandle FTM_POST("Post");
+static LLTrace::BlockTimerStatHandle FTM_DEFERRED_LIGHTING("Deferred Lighting");
 
 void LLPipeline::renderDeferredLighting(LLRenderTarget *screen_target)
 {
@@ -8475,6 +8392,7 @@ void LLPipeline::renderDeferredLighting(LLRenderTarget *screen_target)
     {
         return;
     }
+    LL_RECORD_BLOCK_TIME(FTM_DEFERRED_LIGHTING);
 
     LLRenderTarget *deferred_target       = &mDeferredScreen;
     LLRenderTarget *deferred_depth_target = &mDeferredDepth;
@@ -8547,7 +8465,7 @@ void LLPipeline::renderDeferredLighting(LLRenderTarget *screen_target)
         {
             deferred_light_target->bindTarget();
             {  // paint shadow/SSAO light map (direct lighting lightmap)
-                LL_RECORD_BLOCK_TIME(FTM_SUN_SHADOW);
+                LL_PROFILE_ZONE_NAMED("renderDeferredLighting - sun shadow");
                 bindDeferredShader(gDeferredSunProgram, deferred_light_target);
                 mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX);
                 glClearColor(1, 1, 1, 1);
@@ -8593,7 +8511,7 @@ void LLPipeline::renderDeferredLighting(LLRenderTarget *screen_target)
 
         if (RenderDeferredSSAO)
         {  // soften direct lighting lightmap
-            LL_RECORD_BLOCK_TIME(FTM_SOFTEN_SHADOW);
+            LL_PROFILE_ZONE_NAMED("renderDeferredLighting - soften shadow");
             // blur lightmap
             screen_target->bindTarget();
             glClearColor(1, 1, 1, 1);
@@ -8671,7 +8589,7 @@ void LLPipeline::renderDeferredLighting(LLRenderTarget *screen_target)
         {  // apply sunlight contribution
             LLGLSLShader &soften_shader = LLPipeline::sUnderWaterRender ? gDeferredSoftenWaterProgram : gDeferredSoftenProgram;
 
-            LL_RECORD_BLOCK_TIME(FTM_ATMOSPHERICS);
+            LL_PROFILE_ZONE_NAMED("renderDeferredLighting - atmospherics");
             bindDeferredShader(soften_shader);
 
             LLEnvironment &environment = LLEnvironment::instance();
@@ -8737,6 +8655,7 @@ void LLPipeline::renderDeferredLighting(LLRenderTarget *screen_target)
             LLVertexBuffer::unbind();
 
             {
+                LL_PROFILE_ZONE_NAMED("renderDeferredLighting - local lights");
                 bindDeferredShader(gDeferredLightProgram);
 
                 if (mCubeVB.isNull())
@@ -8807,7 +8726,6 @@ void LLPipeline::renderDeferredLighting(LLRenderTarget *screen_target)
                                 continue;
                             }
 
-                            LL_RECORD_BLOCK_TIME(FTM_LOCAL_LIGHTS);
                             gDeferredLightProgram.uniform3fv(LLShaderMgr::LIGHT_CENTER, 1, c);
                             gDeferredLightProgram.uniform1f(LLShaderMgr::LIGHT_SIZE, s);
                             gDeferredLightProgram.uniform3fv(LLShaderMgr::DIFFUSE_COLOR, 1, col.mV);
@@ -8843,6 +8761,7 @@ void LLPipeline::renderDeferredLighting(LLRenderTarget *screen_target)
 
             if (!spot_lights.empty())
             {
+                LL_PROFILE_ZONE_NAMED("renderDeferredLighting - projectors");
                 LLGLDepthTest depth(GL_TRUE, GL_FALSE);
                 bindDeferredShader(gDeferredSpotLightProgram);
 
@@ -8852,7 +8771,6 @@ void LLPipeline::renderDeferredLighting(LLRenderTarget *screen_target)
 
                 for (LLDrawable::drawable_list_t::iterator iter = spot_lights.begin(); iter != spot_lights.end(); ++iter)
                 {
-                    LL_RECORD_BLOCK_TIME(FTM_PROJECTORS);
                     LLDrawable *drawablep = *iter;
 
                     LLVOVolume *volume = drawablep->getVOVolume();
@@ -8888,6 +8806,7 @@ void LLPipeline::renderDeferredLighting(LLRenderTarget *screen_target)
             vert[2].set(3, 1, 0);
 
             {
+                LL_PROFILE_ZONE_NAMED("renderDeferredLighting - fullscreen lights");
                 LLGLDepthTest depth(GL_FALSE);
 
                 // full screen blit
@@ -8907,7 +8826,6 @@ void LLPipeline::renderDeferredLighting(LLRenderTarget *screen_target)
 
                 while (!fullscreen_lights.empty())
                 {
-                    LL_RECORD_BLOCK_TIME(FTM_FULLSCREEN_LIGHTS);
                     light[count] = fullscreen_lights.front();
                     fullscreen_lights.pop_front();
                     col[count] = light_colors.front();
@@ -8939,7 +8857,6 @@ void LLPipeline::renderDeferredLighting(LLRenderTarget *screen_target)
 
                 for (LLDrawable::drawable_list_t::iterator iter = fullscreen_spot_lights.begin(); iter != fullscreen_spot_lights.end(); ++iter)
                 {
-                    LL_RECORD_BLOCK_TIME(FTM_PROJECTORS);
                     LLDrawable *drawablep           = *iter;
                     LLVOVolume *volume              = drawablep->getVOVolume();
                     LLVector3   center              = drawablep->getPositionAgent();
@@ -9849,10 +9766,9 @@ void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera
 	LLPipeline::sShadowRender = false;
 }
 
-static LLTrace::BlockTimerStatHandle FTM_VISIBLE_CLOUD("Visible Cloud");
 bool LLPipeline::getVisiblePointCloud(LLCamera& camera, LLVector3& min, LLVector3& max, std::vector<LLVector3>& fp, LLVector3 light_dir)
 {
-	LL_RECORD_BLOCK_TIME(FTM_VISIBLE_CLOUD);
+    LL_PROFILE_ZONE_SCOPED;
 	//get point cloud of intersection of frust and min, max
 
 	if (getVisibleExtents(camera, min, max))
@@ -10109,9 +10025,6 @@ LLRenderTarget* LLPipeline::getShadowTarget(U32 i)
 }
 
 static LLTrace::BlockTimerStatHandle FTM_GEN_SUN_SHADOW("Gen Sun Shadow");
-static LLTrace::BlockTimerStatHandle FTM_GEN_SUN_SHADOW_SETUP("Sun Shadow Setup");
-static LLTrace::BlockTimerStatHandle FTM_GEN_SUN_SHADOW_RENDER_DIRECTIONAL("Render Dir");
-static LLTrace::BlockTimerStatHandle FTM_GEN_SUN_SHADOW_SPOT_SETUP("Spot Shadow Setup");
 static LLTrace::BlockTimerStatHandle FTM_GEN_SUN_SHADOW_SPOT_RENDER("Spot Shadow Render");
 
 void LLPipeline::generateSunShadow(LLCamera& camera)
@@ -10907,14 +10820,11 @@ void LLPipeline::renderGroups(LLRenderPass* pass, U32 type, U32 mask, bool textu
 	}
 }
 
-static LLTrace::BlockTimerStatHandle FTM_IMPOSTOR_MARK_VISIBLE("Impostor Mark Visible");
-static LLTrace::BlockTimerStatHandle FTM_IMPOSTOR_SETUP("Impostor Setup");
-static LLTrace::BlockTimerStatHandle FTM_IMPOSTOR_BACKGROUND("Impostor Background");
-static LLTrace::BlockTimerStatHandle FTM_IMPOSTOR_ALLOCATE("Impostor Allocate");
-static LLTrace::BlockTimerStatHandle FTM_IMPOSTOR_RESIZE("Impostor Resize");
+static LLTrace::BlockTimerStatHandle FTM_GENERATE_IMPOSTOR("Generate Impostor");
 
 void LLPipeline::generateImpostor(LLVOAvatar* avatar)
 {
+    LL_RECORD_BLOCK_TIME(FTM_GENERATE_IMPOSTOR);
 	LLGLState::checkStates();
 	LLGLState::checkTextureChannels();
 	LLGLState::checkClientArrays();
@@ -10989,7 +10899,6 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar)
 	LLViewerCamera* viewer_camera = LLViewerCamera::getInstance();
 
 	{
-		LL_RECORD_BLOCK_TIME(FTM_IMPOSTOR_MARK_VISIBLE);
 		markVisible(avatar->mDrawable, *viewer_camera);
 
 		LLVOAvatar::attachment_map_t::iterator iter;
@@ -11018,7 +10927,6 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar)
 	U32 resX = 0;
 
 	{
-		LL_RECORD_BLOCK_TIME(FTM_IMPOSTOR_SETUP);
 		const LLVector4a* ext = avatar->mDrawable->getSpatialExtents();
 		LLVector3 pos(avatar->getRenderPosition()+avatar->getImpostorOffset());
 
@@ -11075,9 +10983,6 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar)
 
 		if (!avatar->mImpostor.isComplete())
 		{
-			LL_RECORD_BLOCK_TIME(FTM_IMPOSTOR_ALLOCATE);
-			
-
 			if (LLPipeline::sRenderDeferred)
 			{
 				avatar->mImpostor.allocate(resX,resY,GL_SRGB8_ALPHA8,TRUE,FALSE);
@@ -11094,7 +10999,6 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar)
 		}
 		else if(resX != avatar->mImpostor.getWidth() || resY != avatar->mImpostor.getHeight())
 		{
-			LL_RECORD_BLOCK_TIME(FTM_IMPOSTOR_RESIZE);
 			avatar->mImpostor.resize(resX,resY);
 		}
 
@@ -11156,7 +11060,6 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar)
 	LLDrawPoolAvatar::sMinimumAlpha = old_alpha;
 
 	{ //create alpha mask based on depth buffer (grey out if muted)
-		LL_RECORD_BLOCK_TIME(FTM_IMPOSTOR_BACKGROUND);
 		if (LLPipeline::sRenderDeferred)
 		{
 			GLuint buff = GL_COLOR_ATTACHMENT0;
diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h
index 8ffbddca21..b87a726647 100644
--- a/indra/newview/pipeline.h
+++ b/indra/newview/pipeline.h
@@ -66,7 +66,6 @@ bool setup_hud_matrices(const LLRect& screen_region); // specify portion of scre
 extern LLTrace::BlockTimerStatHandle FTM_RENDER_GEOMETRY;
 extern LLTrace::BlockTimerStatHandle FTM_RENDER_GRASS;
 extern LLTrace::BlockTimerStatHandle FTM_RENDER_INVISIBLE;
-extern LLTrace::BlockTimerStatHandle FTM_RENDER_OCCLUSION;
 extern LLTrace::BlockTimerStatHandle FTM_RENDER_SHINY;
 extern LLTrace::BlockTimerStatHandle FTM_RENDER_SIMPLE;
 extern LLTrace::BlockTimerStatHandle FTM_RENDER_TERRAIN;
@@ -87,8 +86,6 @@ extern LLTrace::BlockTimerStatHandle FTM_CLIENT_COPY;
 extern LLTrace::BlockTimerStatHandle FTM_RENDER_UI_HUD;
 extern LLTrace::BlockTimerStatHandle FTM_RENDER_UI_3D;
 extern LLTrace::BlockTimerStatHandle FTM_RENDER_UI_2D;
-extern LLTrace::BlockTimerStatHandle FTM_RENDER_UI_DEBUG_TEXT;
-extern LLTrace::BlockTimerStatHandle FTM_RENDER_UI_SCENE_MON;
 
 class LLPipeline
 {
-- 
cgit v1.2.3


From 68b75be652575ff301172b7b19522d4f0494bdf0 Mon Sep 17 00:00:00 2001
From: Dave Parks <davep@lindenlab.com>
Date: Thu, 28 Oct 2021 22:09:22 +0000
Subject: SL-9436 Don't render 100% transparent objects.

---
 indra/llwindow/llwindowwin32.cpp |  2 +
 indra/newview/llviewermenu.cpp   |  1 +
 indra/newview/llvovolume.cpp     | 82 +++++++++++++++-------------------------
 3 files changed, 33 insertions(+), 52 deletions(-)

(limited to 'indra')

diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp
index 26bb56d72d..70cf839510 100644
--- a/indra/llwindow/llwindowwin32.cpp
+++ b/indra/llwindow/llwindowwin32.cpp
@@ -982,6 +982,8 @@ void LLWindowWin32::close()
 
     while (!mWindowThread->isStopped())
     {
+        //nudge window thread
+        PostMessage(mWindowHandle, WM_USER + 0x0017, 0xB0B0, 0x1337);
         std::this_thread::sleep_for(std::chrono::milliseconds(1));
     }
 }
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index ad81cb07c1..534c03d581 100644
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -8314,6 +8314,7 @@ class LLViewHighlightTransparent : public view_listener_t
 	bool handleEvent(const LLSD& userdata)
 	{
 		LLDrawPoolAlpha::sShowDebugAlpha = !LLDrawPoolAlpha::sShowDebugAlpha;
+        gPipeline.resetVertexBuffers();
 		return true;
 	}
 };
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index be390e44a3..893c5f4fac 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -5385,6 +5385,16 @@ void handleRenderAutoMuteByteLimitChanged(const LLSD& new_value)
 	}
 }
 
+// add a face pointer to a list of face pointers without going over MAX_COUNT faces
+template<typename T>
+static inline void add_face(T** list, U32& count, T* face)
+{
+    if (count < MAX_FACE_COUNT)
+    {
+        list[count++] = face;
+    }
+}
+
 void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 {
     LL_PROFILE_ZONE_SCOPED;
@@ -5801,21 +5811,19 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 					{
 						if (facep->canRenderAsMask())
 						{ //can be treated as alpha mask
-							if (simple_count < MAX_FACE_COUNT)
-							{
-								sSimpleFaces[simple_count++] = facep;
-							}
+                            add_face(sSimpleFaces, simple_count, facep);
 						}
 						else
 						{
-							if (te->getColor().mV[3] > 0.f)
-							{ //only treat as alpha in the pipeline if < 100% transparent
-								drawablep->setState(LLDrawable::HAS_ALPHA);
-							}
-							if (alpha_count < MAX_FACE_COUNT)
-							{
-								sAlphaFaces[alpha_count++] = facep;
-							}
+                            if (te->getColor().mV[3] > 0.f)
+                            { //only treat as alpha in the pipeline if < 100% transparent
+                                drawablep->setState(LLDrawable::HAS_ALPHA);
+                                add_face(sAlphaFaces, alpha_count, facep);
+                            }
+                            else if (LLDrawPoolAlpha::sShowDebugAlpha)
+                            {
+                                add_face(sAlphaFaces, alpha_count, facep);
+                            }
 						}
 					}
 					else
@@ -5835,81 +5843,51 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 								{
 									if (mat->getSpecularID().notNull())
 									{ //has normal and specular maps (needs texcoord1, texcoord2, and tangent)
-										if (normspec_count < MAX_FACE_COUNT)
-										{
-											sNormSpecFaces[normspec_count++] = facep;
-										}
+                                        add_face(sNormSpecFaces, normspec_count, facep);
 									}
 									else
 									{ //has normal map (needs texcoord1 and tangent)
-										if (norm_count < MAX_FACE_COUNT)
-										{
-											sNormFaces[norm_count++] = facep;
-										}
+                                        add_face(sNormFaces, norm_count, facep);
 									}
 								}
 								else if (mat->getSpecularID().notNull())
 								{ //has specular map but no normal map, needs texcoord2
-									if (spec_count < MAX_FACE_COUNT)
-									{
-										sSpecFaces[spec_count++] = facep;
-									}
+                                    add_face(sSpecFaces, spec_count, facep);
 								}
 								else
 								{ //has neither specular map nor normal map, only needs texcoord0
-									if (simple_count < MAX_FACE_COUNT)
-									{
-										sSimpleFaces[simple_count++] = facep;
-									}
+                                    add_face(sSimpleFaces, simple_count, facep);
 								}									
 							}
 							else if (te->getBumpmap())
 							{ //needs normal + tangent
-								if (bump_count < MAX_FACE_COUNT)
-								{
-									sBumpFaces[bump_count++] = facep;
-								}
+                                add_face(sBumpFaces, bump_count, facep);
 							}
 							else if (te->getShiny() || !te->getFullbright())
 							{ //needs normal
-								if (simple_count < MAX_FACE_COUNT)
-								{
-									sSimpleFaces[simple_count++] = facep;
-								}
+                                add_face(sSimpleFaces, simple_count, facep);
 							}
 							else 
 							{ //doesn't need normal
 								facep->setState(LLFace::FULLBRIGHT);
-								if (fullbright_count < MAX_FACE_COUNT)
-								{
-									sFullbrightFaces[fullbright_count++] = facep;
-								}
+                                add_face(sFullbrightFaces, fullbright_count, facep);
 							}
 						}
 						else
 						{
 							if (te->getBumpmap() && LLPipeline::sRenderBump)
 							{ //needs normal + tangent
-								if (bump_count < MAX_FACE_COUNT)
-								{
-									sBumpFaces[bump_count++] = facep;
-								}
+                                add_face(sBumpFaces, bump_count, facep);
 							}
 							else if ((te->getShiny() && LLPipeline::sRenderBump) ||
 								!(te->getFullbright() || bake_sunlight))
 							{ //needs normal
-								if (simple_count < MAX_FACE_COUNT)
-								{
-									sSimpleFaces[simple_count++] = facep;
-								}
+                                add_face(sSimpleFaces, simple_count, facep);
 							}
 							else 
 							{ //doesn't need normal
 								facep->setState(LLFace::FULLBRIGHT);
-								if (fullbright_count < MAX_FACE_COUNT)
-								{
-									sFullbrightFaces[fullbright_count++] = facep;
-								}
+                                add_face(sFullbrightFaces, fullbright_count, facep);
 							}
 						}
 					}
-- 
cgit v1.2.3


From 3faba7515c757ca3183522bd017c0f76d9c4581c Mon Sep 17 00:00:00 2001
From: Mnikolenko Productengine <mnikolenko@productengine.com>
Date: Mon, 1 Nov 2021 19:38:55 +0200
Subject: SL-16237 FIXED Viewer hangs on login

---
 indra/llcommon/workqueue.h   |  6 ++++++
 indra/llrender/llimagegl.cpp | 17 ++++++++++++++++-
 indra/llrender/llimagegl.h   |  2 ++
 3 files changed, 24 insertions(+), 1 deletion(-)

(limited to 'indra')

diff --git a/indra/llcommon/workqueue.h b/indra/llcommon/workqueue.h
index b88aef989a..5ec790da79 100644
--- a/indra/llcommon/workqueue.h
+++ b/indra/llcommon/workqueue.h
@@ -94,6 +94,12 @@ namespace LL
         void postEvery(const std::chrono::duration<Rep, Period>& interval,
                        CALLABLE&& callable);
 
+        template <typename CALLABLE>
+        bool tryPost(CALLABLE&& callable)
+        {
+            return mQueue.tryPush(TimedWork(TimePoint::clock::now(), std::move(callable)));
+        }
+
         /*------------------------- handshake API --------------------------*/
 
         /**
diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp
index 09b1c71f02..cbc5392882 100644
--- a/indra/llrender/llimagegl.cpp
+++ b/indra/llrender/llimagegl.cpp
@@ -2288,7 +2288,10 @@ bool LLImageGLThread::postCallback(const std::function<void()>& callback)
 {
     try
     {
-        mCallbackQueue.post(callback);
+        if (!mCallbackQueue.tryPost(callback))
+        {
+            mPendingCallbackQ.push(callback);
+        }
     }
     catch (LLThreadSafeQueueInterrupt e)
     {
@@ -2304,6 +2307,18 @@ void LLImageGLThread::executeCallbacks()
     LL_PROFILE_ZONE_SCOPED;
     //executed from main thread
     mCallbackQueue.runPending();
+
+    while (!mPendingCallbackQ.empty())
+    {
+        if (mCallbackQueue.tryPost(mPendingCallbackQ.front()))
+        {
+            mPendingCallbackQ.pop();
+        }
+        else
+        {
+            break;
+        }
+    }
 }
 
 void LLImageGLThread::run()
diff --git a/indra/llrender/llimagegl.h b/indra/llrender/llimagegl.h
index 95b60bd0bd..8264e4a5f2 100644
--- a/indra/llrender/llimagegl.h
+++ b/indra/llrender/llimagegl.h
@@ -332,6 +332,8 @@ public:
     void* mContext;
     LLAtomicBool mFinished;
 
+    std::queue<std::function<void()>> mPendingCallbackQ;
+
     static LLImageGLThread* sInstance;
 };
 
-- 
cgit v1.2.3


From a88da4ca169a01f45a71513e599e154e0c64b615 Mon Sep 17 00:00:00 2001
From: Nat Goodspeed <nat@lindenlab.com>
Date: Mon, 1 Nov 2021 16:48:57 -0400
Subject: SL-16207: Remove CMake cxx_range_for from media_plugin_cef.

Now that we've enabled -std=c++14 for the whole viewer source tree, that CMake
directive is actually a step backwards -- since it introduces -std=gnu++11 on
the compiler command line, after the one we want, which apparently overrides
c++14 with gnu++11 and causes errors with legitimate C++14 constructs.
---
 indra/media_plugins/cef/CMakeLists.txt | 3 ---
 1 file changed, 3 deletions(-)

(limited to 'indra')

diff --git a/indra/media_plugins/cef/CMakeLists.txt b/indra/media_plugins/cef/CMakeLists.txt
index ce6278963d..76d398576c 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"
-- 
cgit v1.2.3


From 10692ab4a4f999e1ee302675e4ffb84f37a52643 Mon Sep 17 00:00:00 2001
From: Nat Goodspeed <nat@lindenlab.com>
Date: Tue, 2 Nov 2021 10:35:34 -0400
Subject: SL-16207: Create uniform overload sets for wide-string conversions.

Use new ll_convert_forms() macro in llstring.h to declare, for each
wide-string conversion function of interest, four overloads. The real one, the
nontrivial one, is (const char*, size_t len), implemented in llstring.cpp. Then
(const string&, size_t len), (const char*) and (const string&) are each
trivially implemented with an inline call to (const char*, size_t len).

Notably, we change all S32 len parameters to size_t. Using S32 is old skool.

Tweak each nontrivial implementation in llstring.cpp to accept (const char*,
size_t len) instead of (const string&) with or without explicit length.
Eliminate from llstring.cpp trivial overloads (deriving length from either a
const char* or from a string), since those are now inline in the header.

Of course three of those overloads will be unified once we enable C++17 and
change each relevant parameter to std::string_view, but we're not yet there.
Meanwhile, this suite of overloads minimizes, to the best of our ability, new
string allocations solely for parameter passing. And use of a macro means we
need only change the macro once we get std::string_view.

We take this step because some use cases require (const char*), some require
(const string&, size_t len), others (const char*, size_t len) ... We were
missing some key overloads, and had to work around them by instantiating new
string objects (necessitating both allocation and character copying) just to
pass the desired parameter. Using the macro ensures this consistent set of
overloads for every wide-string conversion function.

Additionally, knowing that the ugly-name overloads exist, ll_convert_forms()
implicitly defines corresponding ll_convert<TARGET>() overloads.

Streamline declarations of utf16str_to_wstring(), wstring_to_utf16str(),
utf8str_to_utf16str(), utf16str_to_utf8str(), utf8str_to_wstring(),
wstring_to_utf8str(), ll_convert_wide_to_wstring() and
ll_convert_wstring_to_wide() using ll_convert_forms().

Use corresponding new ll_convert_cp_forms() macro to declare consistent
overloads for conversion functions accepting an optional unsigned int
code_page parameter. We used to delegate to the .cpp file the implementation
of each overload accepting code_page so llstring.h need not include the
Windows header defining the CP_UTF8 default; this is more simply accomplished
by introducing a small ll_wstring_default_code_page() function to retrieve it
from the .cpp file. That lets us specify the code_page parameter as optional,
using that function as its default value.

Use ll_convert_cp_forms() to streamline declarations of
ll_convert_wide_to_string() and ll_convert_string_to_wide().

Introduce real implementations of ll_convert_wide_to_wstring() and
ll_convert_wstring_to_wide(). The previous implementations merely copied
individual characters, which is wrong: when we convert UTF16LE to UTF32, we
can and should fold multi-character UTF16LE encodings to the corresponding
single UTF32 character. The real implemenations leverage our awareness that
both llutf16string and Windows std::wstring (either variant) use UTF16LE
encoding, so we can reuse the corresponding llutf16string conversions.

Introduce generic ll_convert_length() function, specialized as either
std::strlen() or std::wcslen() depending on parameter type. (Even if
std::wcslen() is derived from classic C, why doesn't the C++ standard library
define a std::strlen(const wchar_t*) overload to call it?)

Fix ll_convert_alias()'s ll_convert_impl specialization's operator() to accept
boost::call_traits::param_type, so we can pass (e.g.) const std::wstring& but
also const wchar_t* instead of const wchar_t*&.
---
 indra/llcommon/llstring.cpp |  95 +++++++++--------------------
 indra/llcommon/llstring.h   | 143 ++++++++++++++++++++++++++------------------
 2 files changed, 113 insertions(+), 125 deletions(-)

(limited to 'indra')

diff --git a/indra/llcommon/llstring.cpp b/indra/llcommon/llstring.cpp
index 0290eea143..5f426e5dca 100644
--- a/indra/llcommon/llstring.cpp
+++ b/indra/llcommon/llstring.cpp
@@ -215,7 +215,7 @@ S32 utf16chars_to_wchar(const U16* inchars, llwchar* outchar)
 	return inchars - base;
 }
 
-llutf16string wstring_to_utf16str(const LLWString &utf32str, S32 len)
+llutf16string wstring_to_utf16str(const llwchar* utf32str, size_t len)
 {
 	llutf16string out;
 
@@ -237,27 +237,19 @@ llutf16string wstring_to_utf16str(const LLWString &utf32str, S32 len)
 	return out;
 }
 
-llutf16string wstring_to_utf16str(const LLWString &utf32str)
+llutf16string utf8str_to_utf16str( const char* utf8str, size_t len )
 {
-	const S32 len = (S32)utf32str.length();
-	return wstring_to_utf16str(utf32str, len);
-}
-
-llutf16string utf8str_to_utf16str ( const std::string& utf8str )
-{
-	LLWString wstr = utf8str_to_wstring ( utf8str );
+	LLWString wstr = utf8str_to_wstring ( utf8str, len );
 	return wstring_to_utf16str ( wstr );
 }
 
-
-LLWString utf16str_to_wstring(const llutf16string &utf16str, S32 len)
+LLWString utf16str_to_wstring(const U16* utf16str, size_t len)
 {
 	LLWString wout;
-	if((len <= 0) || utf16str.empty()) return wout;
+	if (len == 0) return wout;
 
 	S32 i = 0;
-	// craziness to make gcc happy (llutf16string.c_str() is tweaked on linux):
-	const U16* chars16 = &(*(utf16str.begin()));
+	const U16* chars16 = utf16str;
 	while (i < len)
 	{
 		llwchar cur_char;
@@ -267,12 +259,6 @@ LLWString utf16str_to_wstring(const llutf16string &utf16str, S32 len)
 	return wout;
 }
 
-LLWString utf16str_to_wstring(const llutf16string &utf16str)
-{
-	const S32 len = (S32)utf16str.length();
-	return utf16str_to_wstring(utf16str, len);
-}
-
 // Length in llwchar (UTF-32) of the first len units (16 bits) of the given UTF-16 string.
 S32 utf16str_wstring_length(const llutf16string &utf16str, const S32 utf16_len)
 {
@@ -392,8 +378,7 @@ S32 wstring_utf8_length(const LLWString& wstr)
 	return len;
 }
 
-
-LLWString utf8str_to_wstring(const std::string& utf8str, S32 len)
+LLWString utf8str_to_wstring(const char* utf8str, size_t len)
 {
 	LLWString wout;
 
@@ -481,13 +466,7 @@ LLWString utf8str_to_wstring(const std::string& utf8str, S32 len)
 	return wout;
 }
 
-LLWString utf8str_to_wstring(const std::string& utf8str)
-{
-	const S32 len = (S32)utf8str.length();
-	return utf8str_to_wstring(utf8str, len);
-}
-
-std::string wstring_to_utf8str(const LLWString& utf32str, S32 len)
+std::string wstring_to_utf8str(const llwchar* utf32str, size_t len)
 {
 	std::string out;
 
@@ -503,20 +482,9 @@ std::string wstring_to_utf8str(const LLWString& utf32str, S32 len)
 	return out;
 }
 
-std::string wstring_to_utf8str(const LLWString& utf32str)
-{
-	const S32 len = (S32)utf32str.length();
-	return wstring_to_utf8str(utf32str, len);
-}
-
-std::string utf16str_to_utf8str(const llutf16string& utf16str)
-{
-	return wstring_to_utf8str(utf16str_to_wstring(utf16str));
-}
-
-std::string utf16str_to_utf8str(const llutf16string& utf16str, S32 len)
+std::string utf16str_to_utf8str(const U16* utf16str, size_t len)
 {
-	return wstring_to_utf8str(utf16str_to_wstring(utf16str, len), len);
+	return wstring_to_utf8str(utf16str_to_wstring(utf16str, len));
 }
 
 std::string utf8str_trim(const std::string& utf8str)
@@ -657,17 +625,16 @@ std::string utf8str_removeCRLF(const std::string& utf8str)
 }
 
 #if LL_WINDOWS
-std::string ll_convert_wide_to_string(const wchar_t* in)
+unsigned int ll_wstring_default_code_page()
 {
-	return ll_convert_wide_to_string(in, CP_UTF8);
+    return CP_UTF8;
 }
 
-std::string ll_convert_wide_to_string(const wchar_t* in, unsigned int code_page)
+std::string ll_convert_wide_to_string(const wchar_t* in, size_t len_in, unsigned int code_page)
 {
 	std::string out;
 	if(in)
 	{
-		int len_in = wcslen(in);
 		int len_out = WideCharToMultiByte(
 			code_page,
 			0,
@@ -699,12 +666,7 @@ std::string ll_convert_wide_to_string(const wchar_t* in, unsigned int code_page)
 	return out;
 }
 
-std::wstring ll_convert_string_to_wide(const std::string& in)
-{
-	return ll_convert_string_to_wide(in, CP_UTF8);
-}
-
-std::wstring ll_convert_string_to_wide(const std::string& in, unsigned int code_page)
+std::wstring ll_convert_string_to_wide(const char* in, size_t len, unsigned int code_page)
 {
 	// From review:
 	// We can preallocate a wide char buffer that is the same length (in wchar_t elements) as the utf8 input,
@@ -716,10 +678,10 @@ std::wstring ll_convert_string_to_wide(const std::string& in, unsigned int code_
 
 	// reserve an output buffer that will be destroyed on exit, with a place
 	// to put NULL terminator
-	std::vector<wchar_t> w_out(in.length() + 1);
+	std::vector<wchar_t> w_out(len + 1);
 
 	memset(&w_out[0], 0, w_out.size());
-	int real_output_str_len = MultiByteToWideChar(code_page, 0, in.c_str(), in.length(),
+	int real_output_str_len = MultiByteToWideChar(code_page, 0, in, len,
 												  &w_out[0], w_out.size() - 1);
 
 	//looks like MultiByteToWideChar didn't add null terminator to converted string, see EXT-4858.
@@ -729,22 +691,23 @@ std::wstring ll_convert_string_to_wide(const std::string& in, unsigned int code_
 	return {&w_out[0]};
 }
 
-LLWString ll_convert_wide_to_wstring(const std::wstring& in)
+LLWString ll_convert_wide_to_wstring(const wchar_t* in, size_t len)
 {
-    // This function, like its converse, is a placeholder, encapsulating a
-    // guilty little hack: the only "official" way nat has found to convert
-    // between std::wstring (16 bits on Windows) and LLWString (UTF-32) is
-    // by using iconv, which we've avoided so far. It kinda sorta works to
-    // just copy individual characters...
-    // The point is that if/when we DO introduce some more official way to
-    // perform such conversions, we should only have to call it here.
-    return { in.begin(), in.end() };
+    // Whether or not std::wstring and llutf16string are distinct types, they
+    // both hold UTF-16LE characters. (See header file comments.) Pretend this
+    // wchar_t* sequence is really a U16* sequence and use the conversion we
+    // define above.
+    return utf16str_to_wstring(reinterpret_cast<const U16*>(in), len);
 }
 
-std::wstring ll_convert_wstring_to_wide(const LLWString& in)
+std::wstring ll_convert_wstring_to_wide(const llwchar* in, size_t len)
 {
-    // See comments in ll_convert_wide_to_wstring()
-    return { in.begin(), in.end() };
+    // first, convert to llutf16string, for which we have a real implementation
+    auto utf16str{ wstring_to_utf16str(in, len) };
+    // then, because each U16 char must be UTF-16LE encoded, pretend the U16*
+    // string pointer is a wchar_t* and instantiate a std::wstring of the same
+    // length.
+    return { reinterpret_cast<const wchar_t*>(utf16str.c_str()), utf16str.length() };
 }
 
 std::string ll_convert_string_to_utf8_string(const std::string& in)
diff --git a/indra/llcommon/llstring.h b/indra/llcommon/llstring.h
index 89e95ef40a..a0598e8a11 100644
--- a/indra/llcommon/llstring.h
+++ b/indra/llcommon/llstring.h
@@ -27,9 +27,11 @@
 #ifndef LL_LLSTRING_H
 #define LL_LLSTRING_H
 
+#include <boost/call_traits.hpp>
 #include <boost/optional/optional.hpp>
 #include <string>
 #include <cstdio>
+#include <cwchar>                   // std::wcslen()
 //#include <locale>
 #include <iomanip>
 #include <algorithm>
@@ -532,14 +534,59 @@ struct ll_convert_impl<T, T>
 template<>                                                  \
 struct ll_convert_impl<TO, FROM>                            \
 {                                                           \
-    TO operator()(const FROM& in) const { return EXPR; }    \
+    /* param_type optimally passes both char* and string */ \
+    TO operator()(typename boost::call_traits<FROM>::param_type in) const { return EXPR; } \
 }
 
-// If all we're doing is copying characters, pass this as EXPR. Since it
-// expands into the 'return EXPR' slot in the ll_convert_impl specialization
-// above, it implies TO{ in.begin(), in.end() }.
+// If all we're doing is copying characters, pass this to ll_convert_alias as
+// EXPR. Since it expands into the 'return EXPR' slot in the ll_convert_impl
+// specialization above, it implies TO{ in.begin(), in.end() }.
 #define LL_CONVERT_COPY_CHARS { in.begin(), in.end() }
 
+// Generic name for strlen() / wcslen() - the default implementation should
+// (!) work with U16 and llwchar, but we don't intend to engage it.
+template <typename CHARTYPE>
+size_t ll_convert_length(const CHARTYPE* zstr)
+{
+    const CHARTYPE* zp;
+    // classic C string scan
+    for (zp = zstr; *zp; ++zp)
+        ;
+    return (zp - zstr);
+}
+
+// specialize where we have a library function; may use intrinsic operations
+template <>
+inline size_t ll_convert_length<wchar_t>(const wchar_t* zstr) { return std::wcslen(zstr); }
+template <>
+inline size_t ll_convert_length<char>   (const char*    zstr) { return std::strlen(zstr); }
+
+// ll_convert_forms() is short for a bunch of boilerplate. It defines
+// longname(const char*, len), longname(const char*), longname(const string&)
+// and longname(const string&, len) so calls written pre-ll_convert() will
+// work. Most of these overloads will be unified once we turn on C++17 and can
+// use std::string_view.
+// It also uses aliasmacro to ensure that both ll_convert<OUTSTR>(const char*)
+// and ll_convert<OUTSTR>(const string&) will work.
+#define ll_convert_forms(aliasmacro, OUTSTR, INSTR, longname)           \
+LL_COMMON_API OUTSTR longname(const INSTR::value_type* in, size_t len); \
+inline auto longname(const INSTR& in, size_t len)                       \
+{                                                                       \
+    return longname(in.c_str(), len);                                   \
+}                                                                       \
+inline auto longname(const INSTR::value_type* in)                       \
+{                                                                       \
+    return longname(in, ll_convert_length(in));                         \
+}                                                                       \
+inline auto longname(const INSTR& in)                                   \
+{                                                                       \
+    return longname(in.c_str(), in.length());                           \
+}                                                                       \
+/* string param */                                                      \
+aliasmacro(OUTSTR, INSTR, longname(in));                                \
+/* char* param */                                                       \
+aliasmacro(OUTSTR, const INSTR::value_type*, longname(in))
+
 // Make the incoming string a utf8 string. Replaces any unknown glyph
 // with the UNKNOWN_CHARACTER. Once any unknown glyph is found, the rest
 // of the data may not be recovered.
@@ -602,34 +649,18 @@ typedef std::basic_string<U16> llutf16string;
 #define ll_convert_wstr_alias(TO, FROM, EXPR) ll_convert_alias(TO, FROM, EXPR)
 #endif
 
-LL_COMMON_API LLWString utf16str_to_wstring(const llutf16string &utf16str, S32 len);
-LL_COMMON_API LLWString utf16str_to_wstring(const llutf16string &utf16str);
-ll_convert_u16_alias(LLWString, llutf16string, utf16str_to_wstring(in));
-
-LL_COMMON_API llutf16string wstring_to_utf16str(const LLWString &utf32str, S32 len);
-LL_COMMON_API llutf16string wstring_to_utf16str(const LLWString &utf32str);
-ll_convert_u16_alias(llutf16string, LLWString, wstring_to_utf16str(in));
+ll_convert_forms(ll_convert_u16_alias, LLWString,     llutf16string, utf16str_to_wstring);
+ll_convert_forms(ll_convert_u16_alias, llutf16string, LLWString,     wstring_to_utf16str);
+ll_convert_forms(ll_convert_u16_alias, llutf16string, std::string,   utf8str_to_utf16str);
+ll_convert_forms(ll_convert_alias,     LLWString,     std::string,   utf8str_to_wstring);
 
-LL_COMMON_API llutf16string utf8str_to_utf16str ( const std::string& utf8str, S32 len);
-LL_COMMON_API llutf16string utf8str_to_utf16str ( const std::string& utf8str );
-ll_convert_u16_alias(llutf16string, std::string, utf8str_to_utf16str(in));
-
-LL_COMMON_API LLWString utf8str_to_wstring(const std::string &utf8str, S32 len);
-LL_COMMON_API LLWString utf8str_to_wstring(const std::string &utf8str);
 // Same function, better name. JC
 inline LLWString utf8string_to_wstring(const std::string& utf8_string) { return utf8str_to_wstring(utf8_string); }
-// best name of all
-ll_convert_alias(LLWString, std::string, utf8string_to_wstring(in));
 
-//
 LL_COMMON_API S32 wchar_to_utf8chars(llwchar inchar, char* outchars);
 
-LL_COMMON_API std::string wstring_to_utf8str(const LLWString &utf32str, S32 len);
-LL_COMMON_API std::string wstring_to_utf8str(const LLWString &utf32str);
-ll_convert_alias(std::string, LLWString, wstring_to_utf8str(in));
-LL_COMMON_API std::string utf16str_to_utf8str(const llutf16string &utf16str, S32 len);
-LL_COMMON_API std::string utf16str_to_utf8str(const llutf16string &utf16str);
-ll_convert_u16_alias(std::string, llutf16string, utf16str_to_utf8str(in));
+ll_convert_forms(ll_convert_alias,     std::string, LLWString,     wstring_to_utf8str);
+ll_convert_forms(ll_convert_u16_alias, std::string, llutf16string, utf16str_to_utf8str);
 
 // an older alias for utf16str_to_utf8str(llutf16string)
 inline std::string wstring_to_utf8str(const llutf16string &utf16str) { return utf16str_to_utf8str(utf16str);}
@@ -706,42 +737,36 @@ LL_COMMON_API std::string utf8str_removeCRLF(const std::string& utf8str);
 //@{
 
 /**
- * @brief Convert a wide string to std::string
+ * @brief Convert a wide string to/from std::string
+ * Convert a Windows wide string to/from our LLWString
  *
  * This replaces the unsafe W2A macro from ATL.
  */
-LL_COMMON_API std::string ll_convert_wide_to_string(const wchar_t* in, unsigned int code_page);
-LL_COMMON_API std::string ll_convert_wide_to_string(const wchar_t* in); // default CP_UTF8
-inline std::string ll_convert_wide_to_string(const std::wstring& in, unsigned int code_page)
-{
-    return ll_convert_wide_to_string(in.c_str(), code_page);
-}
-inline std::string ll_convert_wide_to_string(const std::wstring& in)
-{
-    return ll_convert_wide_to_string(in.c_str());
-}
-ll_convert_wstr_alias(std::string, std::wstring, ll_convert_wide_to_string(in));
-
-/**
- * Converts a string to wide string.
- */
-LL_COMMON_API std::wstring ll_convert_string_to_wide(const std::string& in,
-                                                     unsigned int code_page);
-LL_COMMON_API std::wstring ll_convert_string_to_wide(const std::string& in);
-                                                     // default CP_UTF8
-ll_convert_wstr_alias(std::wstring, std::string, ll_convert_string_to_wide(in));
-
-/**
- * Convert a Windows wide string to our LLWString
- */
-LL_COMMON_API LLWString ll_convert_wide_to_wstring(const std::wstring& in);
-ll_convert_wstr_alias(LLWString, std::wstring, ll_convert_wide_to_wstring(in));
-
-/**
- * Convert LLWString to Windows wide string
- */
-LL_COMMON_API std::wstring ll_convert_wstring_to_wide(const LLWString& in);
-ll_convert_wstr_alias(std::wstring, LLWString, ll_convert_wstring_to_wide(in));
+// Avoid requiring this header to #include the Windows header file declaring
+// our actual default code_page by delegating this function to our .cpp file.
+LL_COMMON_API unsigned int ll_wstring_default_code_page();
+
+// This is like ll_convert_forms(), with the added complexity of a code page
+// parameter that may or may not be passed.
+#define ll_convert_cp_forms(aliasmacro, OUTSTR, INSTR, longname)    \
+LL_COMMON_API OUTSTR longname(                                      \
+    const INSTR::value_type* in,                                    \
+    size_t len=ll_convert_length(in),                               \
+    unsigned int code_page=ll_wstring_default_code_page());         \
+inline auto longname(                                               \
+    const INSTR& in,                                                \
+    size_t len=in.length(),                                         \
+    unsigned int code_page=ll_wstring_default_code_page())          \
+{                                                                   \
+    return longname(in.c_str(), len, code_page);                    \
+}                                                                   \
+aliasmacro(OUTSTR, INSTR, longname(in));                            \
+aliasmacro(OUTSTR, const INSTR::value_type*, longname(in))
+
+ll_convert_cp_forms(ll_convert_wstr_alias, std::string,  std::wstring, ll_convert_wide_to_string);
+ll_convert_cp_forms(ll_convert_wstr_alias, std::wstring, std::string,  ll_convert_string_to_wide);
+   ll_convert_forms(ll_convert_wstr_alias, LLWString,    std::wstring, ll_convert_wide_to_wstring);
+   ll_convert_forms(ll_convert_wstr_alias, std::wstring, LLWString,    ll_convert_wstring_to_wide);
 
 /**
  * Converts incoming string into utf8 string
-- 
cgit v1.2.3


From 95958bc8b2a5340bef93996f2ff0c04956bfb743 Mon Sep 17 00:00:00 2001
From: Nat Goodspeed <nat@lindenlab.com>
Date: Tue, 2 Nov 2021 11:31:47 -0400
Subject: SL-16207: Guess Microsoft compiler isn't smart about default params?

clang allows us to specify, as a default function parameter, an expression
involving a preceding parameter, e.g. (char* ptr, size_t len=strlen(ptr)). The
Microsoft compiler produces errors, requiring more overloads to address that.

Also #undef llstring.h's declaration helper macros at the bottom of the file.
Once we've used them to declare stuff, they need not (should not) be visible
to the consuming source file.
---
 indra/llcommon/llstring.h | 26 ++++++++++++++++++++++++--
 1 file changed, 24 insertions(+), 2 deletions(-)

(limited to 'indra')

diff --git a/indra/llcommon/llstring.h b/indra/llcommon/llstring.h
index a0598e8a11..54e3f9ee63 100644
--- a/indra/llcommon/llstring.h
+++ b/indra/llcommon/llstring.h
@@ -749,17 +749,29 @@ LL_COMMON_API unsigned int ll_wstring_default_code_page();
 // This is like ll_convert_forms(), with the added complexity of a code page
 // parameter that may or may not be passed.
 #define ll_convert_cp_forms(aliasmacro, OUTSTR, INSTR, longname)    \
+/* declare the only nontrivial implementation (in .cpp file) */     \
 LL_COMMON_API OUTSTR longname(                                      \
     const INSTR::value_type* in,                                    \
-    size_t len=ll_convert_length(in),                               \
+    size_t len,                                                     \
     unsigned int code_page=ll_wstring_default_code_page());         \
+/* if passed only a char pointer, scan for nul terminator */        \
+inline auto longname(const INSTR::value_type* in)                   \
+{                                                                   \
+    return longname(in, ll_convert_length(in));                     \
+}                                                                   \
+/* if passed string and length, extract its char pointer */         \
 inline auto longname(                                               \
     const INSTR& in,                                                \
-    size_t len=in.length(),                                         \
+    size_t len,                                                     \
     unsigned int code_page=ll_wstring_default_code_page())          \
 {                                                                   \
     return longname(in.c_str(), len, code_page);                    \
 }                                                                   \
+/* if passed only a string object, no scan, pass known length */    \
+inline auto longname(const INSTR& in)                               \
+{                                                                   \
+    return longname(in.c_str(), in.length());                       \
+}                                                                   \
 aliasmacro(OUTSTR, INSTR, longname(in));                            \
 aliasmacro(OUTSTR, const INSTR::value_type*, longname(in))
 
@@ -1967,4 +1979,14 @@ void LLStringUtilBase<T>::truncate(string_type& string, size_type count)
 	string.resize(count < cur_size ? count : cur_size);
 }
 
+// The good thing about *declaration* macros, vs. usage macros, is that now
+// we're done with them: we don't need them to bleed into the consuming source
+// file.
+#undef ll_convert_alias
+#undef ll_convert_u16_alias
+#undef ll_convert_wstr_alias
+#undef LL_CONVERT_COPY_CHARS
+#undef ll_convert_forms
+#undef ll_convert_cp_forms
+
 #endif  // LL_STRING_H
-- 
cgit v1.2.3


From a33718ee4ca4edbbc4c4034b29ec4c8d102f3a7e Mon Sep 17 00:00:00 2001
From: Nat Goodspeed <nat@lindenlab.com>
Date: Tue, 2 Nov 2021 17:27:59 -0400
Subject: SL-16207: Fix bug in ll_convert_string_to_utf8_string().

That function wants to pass a code_page to ll_convert_string_to_wide(), but
the code_page parameter was being mistaken for the length parameter, leading
to access violations.
---
 indra/llcommon/llstring.cpp | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

(limited to 'indra')

diff --git a/indra/llcommon/llstring.cpp b/indra/llcommon/llstring.cpp
index 5f426e5dca..03f706f5a5 100644
--- a/indra/llcommon/llstring.cpp
+++ b/indra/llcommon/llstring.cpp
@@ -712,10 +712,11 @@ std::wstring ll_convert_wstring_to_wide(const llwchar* in, size_t len)
 
 std::string ll_convert_string_to_utf8_string(const std::string& in)
 {
-	auto w_mesg = ll_convert_string_to_wide(in, CP_ACP);
-	std::string out_utf8(ll_convert_wide_to_string(w_mesg.c_str(), CP_UTF8));
-
-	return out_utf8;
+	// If you pass code_page, you must also pass length, otherwise the code
+	// page parameter will be mistaken for length.
+	auto w_mesg = ll_convert_string_to_wide(in, in.length(), CP_ACP);
+	// CP_UTF8 is default -- see ll_wstring_default_code_page() above.
+	return ll_convert_wide_to_string(w_mesg);
 }
 
 namespace
-- 
cgit v1.2.3


From 8458ad8890cf0a11804996210d7bcfbdaa3eec2e Mon Sep 17 00:00:00 2001
From: Nat Goodspeed <nat@lindenlab.com>
Date: Thu, 4 Nov 2021 16:40:05 -0400
Subject: SL-16202: Instantiate LLSimpleton::sInstance generically

instead of requiring a separate declaration for each subclass.

The previous way produces errors in clang.
---
 indra/llcommon/llsingleton.h         | 3 +++
 indra/llui/llviewereventrecorder.cpp | 2 --
 indra/newview/llenvironment.cpp      | 1 -
 indra/newview/llselectmgr.cpp        | 2 --
 indra/newview/llviewercamera.cpp     | 2 --
 indra/newview/llworld.cpp            | 2 --
 6 files changed, 3 insertions(+), 9 deletions(-)

(limited to 'indra')

diff --git a/indra/llcommon/llsingleton.h b/indra/llcommon/llsingleton.h
index 10a8ecfedb..24d01812c9 100644
--- a/indra/llcommon/llsingleton.h
+++ b/indra/llcommon/llsingleton.h
@@ -865,4 +865,7 @@ public:
     }
 };
 
+template <class T>
+T* LLSimpleton<T>::sInstance{ nullptr };
+
 #endif
diff --git a/indra/llui/llviewereventrecorder.cpp b/indra/llui/llviewereventrecorder.cpp
index 5a44ec947a..cb000aef74 100644
--- a/indra/llui/llviewereventrecorder.cpp
+++ b/indra/llui/llviewereventrecorder.cpp
@@ -28,8 +28,6 @@
 #include "llui.h"
 #include "llleap.h"
 
-LLViewerEventRecorder* LLSimpleton<LLViewerEventRecorder>::sInstance = nullptr;
-
 LLViewerEventRecorder::LLViewerEventRecorder() {
 
   clear(UNDEFINED);
diff --git a/indra/newview/llenvironment.cpp b/indra/newview/llenvironment.cpp
index dba24b3d02..1a66f10b8f 100644
--- a/indra/newview/llenvironment.cpp
+++ b/indra/newview/llenvironment.cpp
@@ -824,7 +824,6 @@ std::string env_selection_to_string(LLEnvironment::EnvSelection_t sel)
 #undef RTNENUM
 }
 
-LLEnvironment* LLSimpleton<LLEnvironment>::sInstance = nullptr;
 //-------------------------------------------------------------------------
 LLEnvironment::LLEnvironment():
     mCloudScrollDelta(),
diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp
index 53247031b4..bc00c518e9 100644
--- a/indra/newview/llselectmgr.cpp
+++ b/indra/newview/llselectmgr.cpp
@@ -97,8 +97,6 @@
 #include "llglheaders.h"
 #include "llinventoryobserver.h"
 
-LLSelectMgr* LLSimpleton<LLSelectMgr>::sInstance = nullptr;
-
 LLViewerObject* getSelectedParentObject(LLViewerObject *object) ;
 //
 // Consts
diff --git a/indra/newview/llviewercamera.cpp b/indra/newview/llviewercamera.cpp
index 5ebce115f6..5d8e80cc41 100644
--- a/indra/newview/llviewercamera.cpp
+++ b/indra/newview/llviewercamera.cpp
@@ -54,8 +54,6 @@
 // System includes
 #include <iomanip> // for setprecision
 
-LLViewerCamera* LLSimpleton<LLViewerCamera>::sInstance = nullptr;
-
 LLTrace::CountStatHandle<> LLViewerCamera::sVelocityStat("camera_velocity");
 LLTrace::CountStatHandle<> LLViewerCamera::sAngularVelocityStat("camera_angular_velocity");
 
diff --git a/indra/newview/llworld.cpp b/indra/newview/llworld.cpp
index 0a8457eb2c..5f62908009 100644
--- a/indra/newview/llworld.cpp
+++ b/indra/newview/llworld.cpp
@@ -62,8 +62,6 @@
 #include <cstring>
 
 
-LLWorld* LLSimpleton<LLWorld>::sInstance = nullptr;
-
 //
 // Globals
 //
-- 
cgit v1.2.3


From 89f2169e9d2c03ed92810689563ca110886abf16 Mon Sep 17 00:00:00 2001
From: Nat Goodspeed <nat@lindenlab.com>
Date: Thu, 4 Nov 2021 16:43:11 -0400
Subject: SL-16202: Add postIfOpen() methods to WorkQueue, LLThreadSafeQueue.

postIfOpen() provides a no-exception alternative to post(), which blocks if
full but throws if closed. postIfOpen() likewise blocks if full, but returns
true if able to post and false if the queue was closed.
---
 indra/llcommon/llthreadsafequeue.h | 30 ++++++++++++++++++++++--------
 indra/llcommon/workqueue.h         | 29 ++++++++++++++++++++++++++---
 2 files changed, 48 insertions(+), 11 deletions(-)

(limited to 'indra')

diff --git a/indra/llcommon/llthreadsafequeue.h b/indra/llcommon/llthreadsafequeue.h
index 06e8d8f609..5c934791fe 100644
--- a/indra/llcommon/llthreadsafequeue.h
+++ b/indra/llcommon/llthreadsafequeue.h
@@ -85,8 +85,8 @@ public:
 	LLThreadSafeQueue(U32 capacity = 1024);
 	virtual ~LLThreadSafeQueue() {}
 
-	// Add an element to the queue (will block if the queue has
-	// reached capacity).
+	// 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.
@@ -95,6 +95,11 @@ public:
 	// legacy name
 	void pushFront(ElementT const & element) { return push(element); }
 
+	// Add an element to the queue (will block if the queue has reached
+	// capacity). Return false if the queue is closed before push is possible.
+	template <typename T>
+	bool pushIfOpen(T&& element);
+
 	// Try to add an element to the queue without blocking. Returns
 	// true only if the element was actually added.
 	template <typename T>
@@ -311,8 +316,8 @@ bool LLThreadSafeQueue<ElementT, QueueT>::push_(lock_t& lock, T&& element)
 
 
 template <typename ElementT, typename QueueT>
-template<typename T>
-void LLThreadSafeQueue<ElementT, QueueT>::push(T&& element)
+template <typename T>
+bool LLThreadSafeQueue<ElementT, QueueT>::pushIfOpen(T&& element)
 {
     lock_t lock1(mLock);
     while (true)
@@ -321,12 +326,10 @@ void LLThreadSafeQueue<ElementT, QueueT>::push(T&& element)
         // drained or not: the moment either end calls close(), further push()
         // operations will fail.
         if (mClosed)
-        {
-            LLTHROW(LLThreadSafeQueueInterrupt());
-        }
+            return false;
 
         if (push_(lock1, std::forward<T>(element)))
-            return;
+            return true;
 
         // Storage Full. Wait for signal.
         mCapacityCond.wait(lock1);
@@ -334,6 +337,17 @@ void LLThreadSafeQueue<ElementT, QueueT>::push(T&& element)
 }
 
 
+template <typename ElementT, typename QueueT>
+template<typename T>
+void LLThreadSafeQueue<ElementT, QueueT>::push(T&& element)
+{
+    if (! pushIfOpen(std::forward<T>(element)))
+    {
+        LLTHROW(LLThreadSafeQueueInterrupt());
+    }
+}
+
+
 template<typename ElementT, typename QueueT>
 template<typename T>
 bool LLThreadSafeQueue<ElementT, QueueT>::tryPush(T&& element)
diff --git a/indra/llcommon/workqueue.h b/indra/llcommon/workqueue.h
index 76d31f32a6..d0e3f870fe 100644
--- a/indra/llcommon/workqueue.h
+++ b/indra/llcommon/workqueue.h
@@ -75,9 +75,10 @@ namespace LL
         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.
+            // Defer reifying an arbitrary CALLABLE until we hit this or
+            // postIfOpen(). All other methods should accept CALLABLEs of
+            // arbitrary type to avoid multiple levels of std::function
+            // indirection.
             mQueue.push(TimedWork(time, std::move(callable)));
         }
 
@@ -92,6 +93,28 @@ namespace LL
             post(TimePoint::clock::now(), std::move(callable));
         }
 
+        /**
+         * post work for a particular time, unless the queue is closed before
+         * we can post
+         */
+        template <typename CALLABLE>
+        bool postIfOpen(const TimePoint& time, CALLABLE&& callable)
+        {
+            // Defer reifying an arbitrary CALLABLE until we hit this or
+            // post(). All other methods should accept CALLABLEs of arbitrary
+            // type to avoid multiple levels of std::function indirection.
+            return mQueue.pushIfOpen(TimedWork(time, std::move(callable)));
+        }
+
+        /**
+         * post work, unless the queue is closed before we can post
+         */
+        template <typename CALLABLE>
+        bool postIfOpen(CALLABLE&& callable)
+        {
+            return postIfOpen(TimePoint::clock::now(), std::move(callable));
+        }
+
         /**
          * Post work to be run at a specified time to another WorkQueue, which
          * may or may not still exist and be open. Return true if we were able
-- 
cgit v1.2.3


From d848d9e888690210dd37a40c634820fd473699fb Mon Sep 17 00:00:00 2001
From: Nat Goodspeed <nat@lindenlab.com>
Date: Thu, 4 Nov 2021 16:50:31 -0400
Subject: SL-16202: Streamline WorkQueues in LLImageGLThread.

Use the new WorkQueue::postIfOpen() method in LLImageGLThread::post(). That
makes the LLImageGLThread method a trivial wrapper, which can accept templated
work items and pass them through to the WorkQueue method, eliminating double
indirection due to multiple layers of std::function.

Eliminate LLImageGLThread's WorkQueue intended for work on the main queue.
Since the main loop already has a WorkQueue of its own, post work directly to
that WorkQueue instead of using a separate WorkQueue misleadingly embedded in
LLImageGLThread.

Instead of looking up the main thread's WorkQueue every time, capture a
pointer in LLImageGL's constructor.

We no longer need a fallback queue for when the main thread's WorkQueue is
full. We no longer need the main loop to poll LLImageGL to service the local
main-thread-targeted WorkQueue, or to copy work from the fallback queue to the
main queue. That eliminates LLImageGLThread::postCallback(), mCallbackQueue,
mPendingCallbackQ, executeCallbacks() -- and even LLImageGL::updateClass() and
LLAppViewer's call to it.

Change LLViewerFetchedTexture::scheduleCreateTexture() to post work to the
main thread's WorkQueue instead of calling LLImageGLThread::postCallback().
---
 indra/llrender/llimagegl.cpp      | 69 ++++-----------------------------------
 indra/llrender/llimagegl.h        | 18 ++++------
 indra/newview/llappviewer.cpp     |  1 -
 indra/newview/llviewertexture.cpp |  2 +-
 4 files changed, 13 insertions(+), 77 deletions(-)

(limited to 'indra')

diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp
index cbc5392882..71c48801ac 100644
--- a/indra/llrender/llimagegl.cpp
+++ b/indra/llrender/llimagegl.cpp
@@ -183,13 +183,6 @@ void LLImageGL::initClass(LLWindow* window, S32 num_catagories, BOOL skip_analyz
     LLImageGLThread::sInstance->start();
 }
 
-//static
-void LLImageGL::updateClass()
-{
-    LL_PROFILE_ZONE_SCOPED;
-    LLImageGLThread::sInstance->executeCallbacks();
-}
-
 //static 
 void LLImageGL::cleanupClass() 
 {
@@ -504,6 +497,9 @@ void LLImageGL::init(BOOL usemipmaps)
 #endif
 
 	mCategory = -1;
+
+	// Sometimes we have to post work for the main thread.
+	mMainQueue = LL::WorkQueue::getInstance("mainloop");
 }
 
 void LLImageGL::cleanup()
@@ -1554,7 +1550,9 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_
         }
 
         ref();
-        LLImageGLThread::sInstance->postCallback([=]()
+        LL::WorkQueue::postMaybe(
+            mMainQueue,
+            [=]()
             {
                 LL_PROFILE_ZONE_NAMED("cglt - delete callback");
                 if (old_texname != 0)
@@ -2266,61 +2264,6 @@ LLImageGLThread::LLImageGLThread(LLWindow* window)
     mContext = mWindow->createSharedContext();
 }
 
-// post a function to be executed on the LLImageGL background thread
-
-bool LLImageGLThread::post(const std::function<void()>& func)
-{
-    try
-    {
-        mFunctionQueue.post(func);
-    }
-    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
-    {
-        if (!mCallbackQueue.tryPost(callback))
-        {
-            mPendingCallbackQ.push(callback);
-        }
-    }
-    catch (LLThreadSafeQueueInterrupt e)
-    {
-        //thread is closing, drop request
-        return false;
-    }
-
-    return true;
-}
-
-void LLImageGLThread::executeCallbacks()
-{
-    LL_PROFILE_ZONE_SCOPED;
-    //executed from main thread
-    mCallbackQueue.runPending();
-
-    while (!mPendingCallbackQ.empty())
-    {
-        if (mCallbackQueue.tryPost(mPendingCallbackQ.front()))
-        {
-            mPendingCallbackQ.pop();
-        }
-        else
-        {
-            break;
-        }
-    }
-}
-
 void LLImageGLThread::run()
 {
     mWindow->makeContextCurrent(mContext);
diff --git a/indra/llrender/llimagegl.h b/indra/llrender/llimagegl.h
index 8264e4a5f2..b9de481aae 100644
--- a/indra/llrender/llimagegl.h
+++ b/indra/llrender/llimagegl.h
@@ -198,6 +198,7 @@ private:
 	void freePickMask();
 
 	LLPointer<LLImageRaw> mSaveData; // used for destroyGL/restoreGL
+	LL::WorkQueue::weak_t mMainQueue;
 	U8* mPickMask;  //downsampled bitmap approximation of alpha channel.  NULL if no alpha channel
 	U16 mPickMaskWidth;
 	U16 mPickMaskHeight;
@@ -271,7 +272,6 @@ public:
 
 public:
 	static void initClass(LLWindow* window, S32 num_catagories, BOOL skip_analyze_alpha = false); 
-    static void updateClass();
 	static void cleanupClass() ;
 
 private:
@@ -313,27 +313,21 @@ 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();
+    template <typename CALLABLE>
+    bool post(CALLABLE&& func)
+    {
+        return mFunctionQueue.postIfOpen(std::forward<CALLABLE>(func));
+    }
 
     void run() override;
 
     // Work Queue for background thread
     LL::WorkQueue mFunctionQueue;
 
-    // Work Queue for main thread (run from updateClass)
-    LL::WorkQueue mCallbackQueue;
-
     LLWindow* mWindow;
     void* mContext;
     LLAtomicBool mFinished;
 
-    std::queue<std::function<void()>> mPendingCallbackQ;
-
     static LLImageGLThread* sInstance;
 };
 
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 220dff3ccb..ea2e3a4007 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -4848,7 +4848,6 @@ 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();
diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp
index fbc5830a5c..9f3819f7d1 100644
--- a/indra/newview/llviewertexture.cpp
+++ b/indra/newview/llviewertexture.cpp
@@ -1626,7 +1626,7 @@ void LLViewerFetchedTexture::scheduleCreateTexture()
             {
                 //actually create the texture on a background thread
                 createTexture();
-                LLImageGLThread::sInstance->postCallback([this]()
+                LL::WorkQueue::getInstance("mainloop")->post([this]()
                     {
                         //finalize on main thread
                         postCreateTexture();
-- 
cgit v1.2.3


From 834e7ca088b5f417235327cd290b42459c733594 Mon Sep 17 00:00:00 2001
From: Nat Goodspeed <nat@lindenlab.com>
Date: Thu, 4 Nov 2021 17:18:57 -0400
Subject: SL-16202: Use large WorkQueue size limits for mainloop and General.

Give ThreadPool and WorkQueue the ability to override default
ThreadSafeSchedule capacity.

Instantiate "mainloop" WorkQueue and "General" ThreadPool with very large
capacity because we never want to have to block trying to push to either.
---
 indra/llcommon/threadpool.cpp | 4 ++--
 indra/llcommon/threadpool.h   | 2 +-
 indra/llcommon/workqueue.cpp  | 5 +++--
 indra/llcommon/workqueue.h    | 2 +-
 indra/newview/llappviewer.cpp | 4 +++-
 indra/newview/llstartup.cpp   | 4 +++-
 6 files changed, 13 insertions(+), 8 deletions(-)

(limited to 'indra')

diff --git a/indra/llcommon/threadpool.cpp b/indra/llcommon/threadpool.cpp
index 1899f9a20a..e4fa0eccf3 100644
--- a/indra/llcommon/threadpool.cpp
+++ b/indra/llcommon/threadpool.cpp
@@ -21,8 +21,8 @@
 #include "llevents.h"
 #include "stringize.h"
 
-LL::ThreadPool::ThreadPool(const std::string& name, size_t threads):
-    mQueue(name),
+LL::ThreadPool::ThreadPool(const std::string& name, size_t threads, size_t capacity):
+    mQueue(name, capacity),
     mName("ThreadPool:" + name)
 {
     for (size_t i = 0; i < threads; ++i)
diff --git a/indra/llcommon/threadpool.h b/indra/llcommon/threadpool.h
index 8f3c8514b5..6e3858508b 100644
--- a/indra/llcommon/threadpool.h
+++ b/indra/llcommon/threadpool.h
@@ -29,7 +29,7 @@ namespace LL
          * Pass ThreadPool a string name. This can be used to look up the
          * relevant WorkQueue.
          */
-        ThreadPool(const std::string& name, size_t threads=1);
+        ThreadPool(const std::string& name, size_t threads=1, size_t capacity=1024);
         ~ThreadPool();
         void close();
 
diff --git a/indra/llcommon/workqueue.cpp b/indra/llcommon/workqueue.cpp
index 9808757b0a..14ae4c4ab8 100644
--- a/indra/llcommon/workqueue.cpp
+++ b/indra/llcommon/workqueue.cpp
@@ -26,8 +26,9 @@
 using Mutex = LLCoros::Mutex;
 using Lock  = LLCoros::LockType;
 
-LL::WorkQueue::WorkQueue(const std::string& name):
-    super(makeName(name))
+LL::WorkQueue::WorkQueue(const std::string& name, size_t capacity):
+    super(makeName(name)),
+    mQueue(capacity)
 {
     // TODO: register for "LLApp" events so we can implicitly close() on
     // viewer shutdown.
diff --git a/indra/llcommon/workqueue.h b/indra/llcommon/workqueue.h
index d0e3f870fe..5987883829 100644
--- a/indra/llcommon/workqueue.h
+++ b/indra/llcommon/workqueue.h
@@ -54,7 +54,7 @@ namespace LL
          * 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());
+        WorkQueue(const std::string& name = std::string(), size_t capacity=1024);
 
         /**
          * Since the point of WorkQueue is to pass work to some other worker
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index ea2e3a4007..02b4dd57f1 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -367,7 +367,9 @@ BOOL gLogoutInProgress = FALSE;
 
 BOOL gSimulateMemLeak = FALSE;
 
-WorkQueue gMainloopWork("mainloop");
+// We don't want anyone, especially threads working on the graphics pipeline,
+// to have to block due to this WorkQueue being full.
+WorkQueue gMainloopWork("mainloop", 1024*1024);
 
 ////////////////////////////////////////////////////////////
 // Internal globals... that should be removed.
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index 13e7fcb6e4..9a4149948c 100644
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -313,7 +313,9 @@ void launchThreadPool()
                             << size << " threads" << LL_ENDL;
     // Use a function-static ThreadPool: static duration, but instantiated
     // only on demand.
-    static LL::ThreadPool pool("General", size);
+    // We don't want anyone, especially the main thread, to have to block
+    // due to this ThreadPool being full.
+    static LL::ThreadPool pool("General", size, 1024*1024);
 }
 
 void update_texture_fetch()
-- 
cgit v1.2.3


From 5e9351a41a7c8d22c60e02d71876d1ee327a3890 Mon Sep 17 00:00:00 2001
From: Dave Houlton <euclid@lindenlab.com>
Date: Mon, 18 Oct 2021 14:38:12 -0600
Subject: SL-13565 occlusion/reflection tracy markup

---
 indra/newview/lldrawpoolwater.cpp |  8 ++++++--
 indra/newview/pipeline.cpp        | 19 +++++++++++++------
 2 files changed, 19 insertions(+), 8 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/lldrawpoolwater.cpp b/indra/newview/lldrawpoolwater.cpp
index aa426cd785..5f9e623b4c 100644
--- a/indra/newview/lldrawpoolwater.cpp
+++ b/indra/newview/lldrawpoolwater.cpp
@@ -337,7 +337,8 @@ void LLDrawPoolWater::render(S32 pass)
 // for low end hardware
 void LLDrawPoolWater::renderOpaqueLegacyWater()
 {
-	LLVOSky *voskyp = gSky.mVOSkyp;
+    LL_PROFILE_ZONE_SCOPED;
+    LLVOSky *voskyp = gSky.mVOSkyp;
 
 	LLGLSLShader* shader = NULL;
 	if (LLGLSLShader::sNoFixedFunction)
@@ -444,6 +445,7 @@ void LLDrawPoolWater::renderOpaqueLegacyWater()
 
 void LLDrawPoolWater::renderReflection(LLFace* face)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	LLVOSky *voskyp = gSky.mVOSkyp;
 
 	if (!voskyp)
@@ -472,6 +474,7 @@ void LLDrawPoolWater::renderReflection(LLFace* face)
 
 void LLDrawPoolWater::shade2(bool edge, LLGLSLShader* shader, const LLColor3& light_diffuse, const LLVector3& light_dir, F32 light_exp)
 {
+    LL_PROFILE_ZONE_SCOPED;
     F32  water_height  = LLEnvironment::instance().getWaterHeight(); 
     F32  camera_height = LLViewerCamera::getInstance()->getOrigin().mV[2];
     F32  eyedepth      = camera_height - water_height;
@@ -680,7 +683,8 @@ void LLDrawPoolWater::shade2(bool edge, LLGLSLShader* shader, const LLColor3& li
 
 void LLDrawPoolWater::shade()
 {
-	if (!deferred_render)
+    LL_PROFILE_ZONE_SCOPED;
+    if (!deferred_render)
 	{
 		gGL.setColorMask(true, true);
 	}
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index 6ed6e20b03..ed68cc7f32 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -1231,7 +1231,8 @@ void LLPipeline::releaseShadowTargets()
 
 void LLPipeline::createGLBuffers()
 {
-	stop_glerror();
+    LL_PROFILE_ZONE_SCOPED;
+    stop_glerror();
 	assertInitialized();
 
 	updateRenderDeferred();
@@ -1384,7 +1385,7 @@ void LLPipeline::restoreGL()
 			if (part)
 			{
 				part->restoreGL();
-			}
+		}
 		}
 	}
 }
@@ -2629,7 +2630,8 @@ void LLPipeline::doOcclusion(LLCamera& camera, LLRenderTarget& source, LLRenderT
 
 void LLPipeline::doOcclusion(LLCamera& camera)
 {
-	if (LLPipeline::sUseOcclusion > 1 && !LLSpatialPartition::sTeleportRequested && 
+    LL_PROFILE_ZONE_SCOPED;
+    if (LLPipeline::sUseOcclusion > 1 && !LLSpatialPartition::sTeleportRequested &&
 		(sCull->hasOcclusionGroups() || LLVOCachePartition::sNeedsOcclusionCheck))
 	{
 		LLVertexBuffer::unbind();
@@ -3422,7 +3424,8 @@ void LLPipeline::stateSort(LLSpatialGroup* group, LLCamera& camera)
 
 void LLPipeline::stateSort(LLSpatialBridge* bridge, LLCamera& camera, BOOL fov_changed)
 {
-	if (bridge->getSpatialGroup()->changeLOD() || fov_changed)
+    LL_PROFILE_ZONE_SCOPED;
+    if (bridge->getSpatialGroup()->changeLOD() || fov_changed)
 	{
 		bool force_update = false;
 		bridge->updateDistance(camera, force_update);
@@ -3431,7 +3434,8 @@ void LLPipeline::stateSort(LLSpatialBridge* bridge, LLCamera& camera, BOOL fov_c
 
 void LLPipeline::stateSort(LLDrawable* drawablep, LLCamera& camera)
 {
-	if (!drawablep
+    LL_PROFILE_ZONE_SCOPED;
+    if (!drawablep
 		|| drawablep->isDead() 
 		|| !hasRenderType(drawablep->getRenderType()))
 	{
@@ -4708,7 +4712,8 @@ void LLPipeline::renderGeomPostDeferred(LLCamera& camera, bool do_occlusion)
 
 void LLPipeline::renderGeomShadow(LLCamera& camera)
 {
-	U32 cur_type = 0;
+    LL_PROFILE_ZONE_SCOPED;
+    U32 cur_type = 0;
 	
 	LLGLEnable cull(GL_CULL_FACE);
 
@@ -8388,6 +8393,7 @@ static LLTrace::BlockTimerStatHandle FTM_DEFERRED_LIGHTING("Deferred Lighting");
 
 void LLPipeline::renderDeferredLighting(LLRenderTarget *screen_target)
 {
+    LL_PROFILE_ZONE_SCOPED;
     if (!sCull)
     {
         return;
@@ -9200,6 +9206,7 @@ inline float sgn(float a)
 
 void LLPipeline::generateWaterReflection(LLCamera& camera_in)
 {
+    LL_PROFILE_ZONE_SCOPED;
     if (LLPipeline::sWaterReflections && assertInitialized() && LLDrawPoolWater::sNeedsReflectionUpdate)
     {
         bool skip_avatar_update = false;
-- 
cgit v1.2.3


From 747ccda0b42856fc8e7b512dce143b0b93ae5def Mon Sep 17 00:00:00 2001
From: Dave Houlton <euclid@lindenlab.com>
Date: Thu, 4 Nov 2021 13:55:47 -0600
Subject: SL-14098 re-enable occlusion culling during reflection pass

---
 indra/newview/pipeline.cpp | 11 +----------
 1 file changed, 1 insertion(+), 10 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index ed68cc7f32..1821ca067a 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -2429,8 +2429,7 @@ void LLPipeline::updateCull(LLCamera& camera, LLCullResult& result, S32 water_cl
 		LLVOCachePartition* vo_part = region->getVOCachePartition();
 		if(vo_part)
 		{
-			bool do_occlusion_cull = can_use_occlusion && use_occlusion && !gUseWireframe && 0 > water_clip /* && !gViewerWindow->getProgressView()->getVisible()*/;
-            do_occlusion_cull &= !sReflectionRender;
+            bool do_occlusion_cull = can_use_occlusion && use_occlusion && !gUseWireframe; // && 0 > water_clip
 			vo_part->cull(camera, do_occlusion_cull);
 		}
 	}
@@ -9261,11 +9260,6 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in)
             water_clip = -1;
         }
 
-        S32 occlusion = LLPipeline::sUseOcclusion;
-
-        //disable occlusion culling for reflection map for now
-        LLPipeline::sUseOcclusion = 0;
-
         if (!camera_is_underwater)
         {
             //generate planar reflection map
@@ -9381,8 +9375,6 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in)
             set_current_modelview(saved_modelview);
         }
 
-        //LLPipeline::sUseOcclusion = occlusion;
-
         camera.setOrigin(camera_in.getOrigin());
         //render distortion map
         static bool last_update = true;
@@ -9477,7 +9469,6 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in)
 
         gPipeline.popRenderTypeMask();
 
-        LLPipeline::sUseOcclusion     = occlusion;
         LLPipeline::sUnderWaterRender = false;
         LLPipeline::sReflectionRender = false;
 
-- 
cgit v1.2.3


From b6afa7f7dd5eb4f6df9580a25fbffb491ccef921 Mon Sep 17 00:00:00 2001
From: Mnikolenko Productengine <mnikolenko@productengine.com>
Date: Fri, 5 Nov 2021 17:48:40 +0200
Subject: SL-16288 FIXED Dragging a file across the viewer cancels the drag and
 freezes the File Explorer

---
 indra/llwindow/llwindowwin32.cpp | 11 +++++++++++
 1 file changed, 11 insertions(+)

(limited to 'indra')

diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp
index 70cf839510..dddc8deb02 100644
--- a/indra/llwindow/llwindowwin32.cpp
+++ b/indra/llwindow/llwindowwin32.cpp
@@ -2202,6 +2202,17 @@ void LLWindowWin32::gatherInput()
         }
     }
 
+    {
+        LL_PROFILE_ZONE_NAMED("gi - PeekMessage");
+        S32 msg_count = 0;
+        while ((msg_count < MAX_MESSAGE_PER_UPDATE) && PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_REMOVE))
+        {
+            TranslateMessage(&msg);
+            DispatchMessage(&msg);
+            msg_count++;
+        }
+    }
+
     {
         LL_PROFILE_ZONE_NAMED("gi - function queue");
         //process any pending functions
-- 
cgit v1.2.3


From ff5496239bffadaca111b1e4380a01447f85843a Mon Sep 17 00:00:00 2001
From: Nat Goodspeed <nat@lindenlab.com>
Date: Fri, 5 Nov 2021 12:33:31 -0400
Subject: SL-16202: Use WorkQueue::postTo() for texture create/post handshake.

That is, when LLViewerFetchedTexture::scheduleCreateTexture() wants to call
createTexture() on the LLImageGLThread, but postCreateTexture() on the main
thread, use the "mainloop" WorkQueue to set up the handshake.

Give ThreadPool a public virtual run() method so a subclass can override with
desired behavior. This necessitates a virtual destructor. Add accessors for
embedded WorkQueue (for post calls), ThreadPool name and width (in threads).

Allow LLSimpleton::createInstance() to forward arguments to the subject
constructor.

Make LLImageGLThread an LLSimpleton - that abstraction didn't yet exist at the
time LLImageGLThread was coded. Also derive from ThreadPool rather than
LLThread. Make it a single-thread "pool" with a very large queue capacity.
---
 indra/llcommon/llsingleton.h      | 20 +++++++++++---------
 indra/llcommon/threadpool.cpp     |  7 ++++++-
 indra/llcommon/threadpool.h       | 18 +++++++++++++++++-
 indra/llrender/llimagegl.cpp      | 22 +++++++++++-----------
 indra/llrender/llimagegl.h        | 11 ++++-------
 indra/newview/llviewertexture.cpp | 34 +++++++++++++++++++++++-----------
 indra/newview/llviewertexture.h   |  4 ++++
 7 files changed, 76 insertions(+), 40 deletions(-)

(limited to 'indra')

diff --git a/indra/llcommon/llsingleton.h b/indra/llcommon/llsingleton.h
index 24d01812c9..fdd5bdfea9 100644
--- a/indra/llcommon/llsingleton.h
+++ b/indra/llcommon/llsingleton.h
@@ -847,22 +847,24 @@ template<class T>
 class LLSimpleton
 {
 public:
-    static T* sInstance;
-    
-    static void createInstance() 
-    { 
+    template <typename... ARGS>
+    static void createInstance(ARGS&&... args)
+    {
         llassert(sInstance == nullptr);
-        sInstance = new T(); 
+        sInstance = new T(std::forward<ARGS>(args)...);
     }
-    
+
     static inline T* getInstance() { return sInstance; }
     static inline T& instance() { return *getInstance(); }
     static inline bool instanceExists() { return sInstance != nullptr; }
 
-    static void deleteSingleton() { 
-        delete sInstance; 
-        sInstance = nullptr; 
+    static void deleteSingleton() {
+        delete sInstance;
+        sInstance = nullptr;
     }
+
+private:
+    static T* sInstance;
 };
 
 template <class T>
diff --git a/indra/llcommon/threadpool.cpp b/indra/llcommon/threadpool.cpp
index e4fa0eccf3..cf25cc838e 100644
--- a/indra/llcommon/threadpool.cpp
+++ b/indra/llcommon/threadpool.cpp
@@ -70,6 +70,11 @@ void LL::ThreadPool::close()
 void LL::ThreadPool::run(const std::string& name)
 {
     LL_DEBUGS("ThreadPool") << name << " starting" << LL_ENDL;
-    mQueue.runUntilClose();
+    run();
     LL_DEBUGS("ThreadPool") << name << " stopping" << LL_ENDL;
 }
+
+void LL::ThreadPool::run()
+{
+    mQueue.runUntilClose();
+}
diff --git a/indra/llcommon/threadpool.h b/indra/llcommon/threadpool.h
index 6e3858508b..1ca24aec58 100644
--- a/indra/llcommon/threadpool.h
+++ b/indra/llcommon/threadpool.h
@@ -30,9 +30,25 @@ namespace LL
          * relevant WorkQueue.
          */
         ThreadPool(const std::string& name, size_t threads=1, size_t capacity=1024);
-        ~ThreadPool();
+        virtual ~ThreadPool();
+
+        /**
+         * ThreadPool listens for application shutdown messages on the "LLApp"
+         * LLEventPump. Call close() to shut down this ThreadPool early.
+         */
         void close();
 
+        std::string getName() const { return mName; }
+        size_t getWidth() const { return mThreads.size(); }
+        /// obtain a non-const reference to the WorkQueue to post work to it
+        WorkQueue& getQueue() { return mQueue; }
+
+        /**
+         * Override run() if you need special processing. The default run()
+         * implementation simply calls WorkQueue::runUntilClose().
+         */
+        virtual void run();
+
     private:
         void run(const std::string& name);
 
diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp
index 71c48801ac..1b6920fe3b 100644
--- a/indra/llrender/llimagegl.cpp
+++ b/indra/llrender/llimagegl.cpp
@@ -172,24 +172,19 @@ BOOL is_little_endian()
 	return (*c == 0x78) ;
 }
 
-LLImageGLThread* LLImageGLThread::sInstance = nullptr;
-
 //static 
 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();
+    LLImageGLThread::createInstance(window);
 }
 
 //static 
 void LLImageGL::cleanupClass() 
 {
     LL_PROFILE_ZONE_SCOPED;
-    LLImageGLThread::sInstance->mFunctionQueue.close();
-    delete LLImageGLThread::sInstance;
-    LLImageGLThread::sInstance = nullptr;
+    LLImageGLThread::deleteSingleton();
 }
 
 //static
@@ -1532,8 +1527,7 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_
     }
 
     //if we're on the image loading thread, be sure to delete old_texname and update mTexName on the main thread
-    if (LLImageGLThread::sInstance != nullptr && 
-        LLThread::currentID() == LLImageGLThread::sInstance->getID())
+    if (! on_main_thread())
     {
         {
             LL_PROFILE_ZONE_NAMED("cglt - sync");
@@ -2257,7 +2251,11 @@ void LLImageGL::resetCurTexSizebar()
 */  
 
 LLImageGLThread::LLImageGLThread(LLWindow* window)
-    : LLThread("LLImageGL"), mWindow(window)
+    // We want exactly one thread, but a very large capacity: we never want
+    // anyone, especially inner-loop render code, to have to block on post()
+    // because we're full.
+    : ThreadPool("LLImageGL", 1, 1024*1024)
+    , mWindow(window)
 {
     mFinished = false;
 
@@ -2266,9 +2264,11 @@ LLImageGLThread::LLImageGLThread(LLWindow* window)
 
 void LLImageGLThread::run()
 {
+    // We must perform setup on this thread before actually servicing our
+    // WorkQueue, likewise cleanup afterwards.
     mWindow->makeContextCurrent(mContext);
     gGL.init();
-    mFunctionQueue.runUntilClose();
+    ThreadPool::run();
     gGL.shutdown();
     mWindow->destroySharedContext(mContext);
 }
diff --git a/indra/llrender/llimagegl.h b/indra/llrender/llimagegl.h
index b9de481aae..27496def1d 100644
--- a/indra/llrender/llimagegl.h
+++ b/indra/llrender/llimagegl.h
@@ -37,6 +37,7 @@
 #include "llunits.h"
 #include "llthreadsafequeue.h"
 #include "llrender.h"
+#include "threadpool.h"
 #include "workqueue.h"
 
 class LLTextureAtlas ;
@@ -307,7 +308,7 @@ public:
 
 };
 
-class LLImageGLThread : public LLThread
+class LLImageGLThread : public LLSimpleton<LLImageGLThread>, LL::ThreadPool
 {
 public:
     LLImageGLThread(LLWindow* window);
@@ -316,19 +317,15 @@ public:
     template <typename CALLABLE>
     bool post(CALLABLE&& func)
     {
-        return mFunctionQueue.postIfOpen(std::forward<CALLABLE>(func));
+        return getQueue().postIfOpen(std::forward<CALLABLE>(func));
     }
 
     void run() override;
 
-    // Work Queue for background thread
-    LL::WorkQueue mFunctionQueue;
-
+private:
     LLWindow* mWindow;
     void* mContext;
     LLAtomicBool mFinished;
-
-    static LLImageGLThread* sInstance;
 };
 
 
diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp
index 9f3819f7d1..498e4ef8bc 100644
--- a/indra/newview/llviewertexture.cpp
+++ b/indra/newview/llviewertexture.cpp
@@ -679,6 +679,9 @@ void LLViewerTexture::init(bool firstinit)
 	
 	mVolumeList[LLRender::LIGHT_TEX].clear();
 	mVolumeList[LLRender::SCULPT_TEX].clear();
+
+	mMainQueue	= LL::WorkQueue::getInstance("mainloop");
+	mImageQueue = LL::WorkQueue::getInstance("LLImageGL");
 }
 
 //virtual 
@@ -1622,17 +1625,26 @@ void LLViewerFetchedTexture::scheduleCreateTexture()
     {
         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::WorkQueue::getInstance("mainloop")->post([this]()
-                    {
-                        //finalize on main thread
-                        postCreateTexture();
-                        unref();
-                    });
-            }))
+        auto mainq = mMainQueue.lock();
+        if (mainq)
+        {
+            mainq->postTo(
+                mImageQueue,
+                // work to be done on LLImageGL worker thread
+                [this]()
+                {
+                    //actually create the texture on a background thread
+                    createTexture();
+                },
+                // callback to be run on main thread
+                [this]()
+                {
+                    //finalize on main thread
+                    postCreateTexture();
+                    unref();
+                });
+        }
+        else
 #endif
         {
             gTextureList.mCreateTextureList.insert(this);
diff --git a/indra/newview/llviewertexture.h b/indra/newview/llviewertexture.h
index f9f1bfef44..4cd4c7cd39 100644
--- a/indra/newview/llviewertexture.h
+++ b/indra/newview/llviewertexture.h
@@ -35,6 +35,7 @@
 #include "llrender.h"
 #include "llmetricperformancetester.h"
 #include "httpcommon.h"
+#include "workqueue.h"
 
 #include <map>
 #include <list>
@@ -213,6 +214,9 @@ protected:
 	//do not use LLPointer here.
 	LLViewerMediaTexture* mParcelMedia ;
 
+	LL::WorkQueue::weak_t mMainQueue;
+	LL::WorkQueue::weak_t mImageQueue;
+
 	static F32 sTexelPixelRatio;
 public:
 	static const U32 sCurrentFileVersion;	
-- 
cgit v1.2.3


From c7af4921db7f62005f3f668ca7fca45d01d80781 Mon Sep 17 00:00:00 2001
From: Nat Goodspeed <nat@lindenlab.com>
Date: Fri, 5 Nov 2021 17:20:11 -0400
Subject: SL-16094: Use ThreadPool for LLWindowWin32Thread.

Move the whole LLWindowWin32Thread class inside LLWindowWin32, and make it a
struct. Migrate the struct declaration to llwindowwin32.cpp.

Derive it from ThreadPool, which provides the WorkQueue. Use runPending()
instead of manually popping and running individual queue items.

Make its post() operation always PostMessage(bogus) whenever we put an entry
in the WorkQueue, so we won't remain blocked in GetMessage().

Instead of storing a back pointer to the LLWindowWin32 instance, store the
relevant HWND and HDC in LLWindowWin32Thread itself to avoid cross-thread
timing problems.

Extract both instances of a large duplicated block of LLWindowWin32 code to a
new recreateWindow() method, and call it in those places. Per the TODO, use a
std::future to pass the new HWND and HDC back to LLWindowWin32 -- but also
store them locally on the LLWindowWin32Thread instance.
---
 indra/llwindow/llwindowwin32.cpp | 240 ++++++++++++++++++---------------------
 indra/llwindow/llwindowwin32.h   |  47 ++------
 2 files changed, 117 insertions(+), 170 deletions(-)

(limited to 'indra')

diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp
index 70cf839510..4b40fae1bf 100644
--- a/indra/llwindow/llwindowwin32.cpp
+++ b/indra/llwindow/llwindowwin32.cpp
@@ -55,6 +55,8 @@
 #include <shellapi.h>
 #include <fstream>
 #include <Imm.h>
+#include <future>
+#include <utility>                  // std::pair
 
 // Require DirectInput version 8
 #define DIRECTINPUT_VERSION 0x0800
@@ -468,6 +470,37 @@ private:
 static LLMonitorInfo sMonitorInfo;
 
 
+// Thread that owns the Window Handle
+// This whole struct is private to LLWindowWin32, which needs to mess with its
+// members, which is why it's a struct rather than a class. In effect, we make
+// the containing class a friend.
+struct LLWindowWin32::LLWindowWin32Thread : public LL::ThreadPool
+{
+    static const int MAX_QUEUE_SIZE = 2048;
+
+    LLThreadSafeQueue<MSG> mMessageQueue;
+
+    LLWindowWin32Thread();
+
+    void run() override;
+
+    template <typename CALLABLE>
+    void post(CALLABLE&& func)
+    {
+        getQueue().post(std::forward<CALLABLE>(func));
+        // bump us out of blocked GetMessage() call
+        if (mWindowHandle)
+        {
+            PostMessage(mWindowHandle, WM_USER + 0x0017, 0xB0B0, 0x1337);
+        }
+    }
+
+    // call PeekMessage and pull enqueue messages for later processing
+    void gatherInput();
+    HWND mWindowHandle = NULL;
+    HDC mhDC = 0;
+};
+
 
 LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks,
 							 const std::string& title, const std::string& name, S32 x, S32 y, S32 width,
@@ -479,8 +512,7 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks,
 	: LLWindow(callbacks, fullscreen, flags)
 {
     sMainThreadId = LLThread::currentID();
-    mWindowThread = new LLWindowWin32Thread(this);
-    mWindowThread->start();
+    mWindowThread = new LLWindowWin32Thread();
 	//MAINT-516 -- force a load of opengl32.dll just in case windows went sideways 
 	LoadLibrary(L"opengl32.dll");
 
@@ -975,17 +1007,13 @@ void LLWindowWin32::close()
                 // 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())
-    {
-        //nudge window thread
-        PostMessage(mWindowHandle, WM_USER + 0x0017, 0xB0B0, 0x1337);
-        std::this_thread::sleep_for(std::chrono::milliseconds(1));
-    }
+    // Even though the above lambda might not yet have run, we've already
+    // bound mWindowHandle into it by value, which should suffice for the
+    // operations we're asking. That's the last time WE should touch it.
+    mWindowHandle = NULL;
+    mWindowThread->close();
 }
 
 BOOL LLWindowWin32::isValid()
@@ -1278,51 +1306,7 @@ BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen& size, BO
         << " Fullscreen: " << mFullscreen
         << LL_ENDL;
 
-    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 = 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;
-    }
+	recreateWindow(window_rect, dw_ex_style, dw_style);
 
 	if (mWindowHandle)
 	{
@@ -1650,48 +1634,7 @@ 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 (oldHandle && !destroy_window_handler(oldHandle))
-        {
-            LL_WARNS("Window") << "Failed to properly close window!" << LL_ENDL;
-        }		
-
-        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;
-        }
+		recreateWindow(window_rect, dw_ex_style, dw_style);
 
 		if (mWindowHandle)
 		{
@@ -1837,6 +1780,64 @@ const	S32   max_format  = (S32)num_formats - 1;
 	return TRUE;
 }
 
+void LLWindowWin32::recreateWindow(RECT window_rect, DWORD dw_ex_style, DWORD dw_style)
+{
+    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;
+    }
+
+    std::promise<std::pair<HWND, HDC>> promise;
+    mWindowThread->post(
+        [this, window_rect, dw_ex_style, dw_style, &promise]()
+        {
+            auto handle = 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 (! handle)
+            {
+                // Failed to create window: clear the variables. This
+                // assignment is valid because we're running on mWindowThread.
+                mWindowThread->mWindowHandle = NULL;
+                mWindowThread->mhDC = 0;
+            }
+            else
+            {
+                // Update mWindowThread's own mWindowHandle and mhDC.
+                mWindowThread->mWindowHandle = handle;
+                mWindowThread->mhDC = GetDC(handle);
+            }
+                
+            // It's important to wake up the future either way.
+            promise.set_value(std::make_pair(mWindowThread->mWindowHandle, mWindowThread->mhDC));
+        }
+    );
+
+    auto future = promise.get_future();
+    // This blocks until mWindowThread processes CreateWindowEx() and calls
+    // promise.set_value().
+    auto pair = future.get();
+    mWindowHandle = pair.first;
+    mhDC = pair.second;
+}
+
 void* LLWindowWin32::createSharedContext()
 {
     S32 attribs[] =
@@ -2174,17 +2175,6 @@ void LLWindowWin32::gatherInput()
         mRawMouseDelta.mX = 0;
         mRawMouseDelta.mY = 0;
     }
-
-
-    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))
     {
@@ -4551,35 +4541,32 @@ std::vector<std::string> LLWindowWin32::getDynamicFallbackFontList()
 
 #endif // LL_WINDOWS
 
-inline LLWindowWin32Thread::LLWindowWin32Thread(LLWindowWin32* window)
-    : LLThread("Window Thread"), 
-    mWindow(window),
-    mFunctionQueue(MAX_QUEUE_SIZE)
+inline LLWindowWin32::LLWindowWin32Thread::LLWindowWin32Thread()
+    : ThreadPool("Window Thread", 1, MAX_QUEUE_SIZE)
 {
-
 }
 
-inline void LLWindowWin32Thread::run()
+void LLWindowWin32::LLWindowWin32Thread::run()
 {
-    sWindowThreadId = getID();
-    while (!mFinished)
+    sWindowThreadId = std::this_thread::get_id();
+    while (! getQueue().done())
     {
         LL_PROFILE_ZONE_SCOPED;
 
 
-        if (mWindow && mWindow->mWindowHandle != 0)
+        if (mWindowHandle != 0)
         {
             MSG msg;
             BOOL status;
-            if (mWindow->mhDC == 0)
+            if (mhDC == 0)
             {
                 LL_PROFILE_ZONE_NAMED("w32t - PeekMessage");
-                status = PeekMessage(&msg, mWindow->mWindowHandle, 0, 0, PM_REMOVE);
+                status = PeekMessage(&msg, mWindowHandle, 0, 0, PM_REMOVE);
             }
             else
             {
                 LL_PROFILE_ZONE_NAMED("w32t - GetMessage");
-                status = GetMessage(&msg, mWindow->mWindowHandle, 0, 0);
+                status = GetMessage(&msg, mWindowHandle, 0, 0);
             }
             if (status > 0)
             {
@@ -4593,11 +4580,7 @@ inline void LLWindowWin32Thread::run()
         {
             LL_PROFILE_ZONE_NAMED("w32t - Function Queue");
             //process any pending functions
-            std::function<void()> curFunc;
-            while (mFunctionQueue.tryPopBack(curFunc))
-            {
-                curFunc();
-            }
+            getQueue().runPending();
         }
         
 #if 0
@@ -4609,11 +4592,6 @@ inline void LLWindowWin32Thread::run()
     }
 }
 
-void LLWindowWin32Thread::post(const std::function<void()>& func)
-{
-    mFunctionQueue.pushFront(func);
-}
-
 void LLWindowWin32::post(const std::function<void()>& func)
 {
     mFunctionQueue.pushFront(func);
diff --git a/indra/llwindow/llwindowwin32.h b/indra/llwindow/llwindowwin32.h
index 7a9a30ccea..97d1e6d7a3 100644
--- a/indra/llwindow/llwindowwin32.h
+++ b/indra/llwindow/llwindowwin32.h
@@ -36,44 +36,12 @@
 #include "llthread.h"
 #include "llthreadsafequeue.h"
 #include "llmutex.h"
+#include "workqueue.h"
 
 // Hack for async host by name
 #define LL_WM_HOST_RESOLVED      (WM_APP + 1)
 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:
@@ -269,14 +237,15 @@ protected:
 
 	BOOL			mMouseVanish;
 
-    LLWindowWin32Thread* mWindowThread = nullptr;
-    LLThreadSafeQueue<std::function<void()>> mFunctionQueue;
-    LLThreadSafeQueue<std::function<void()>> mMouseQueue;
-    void post(const std::function<void()>& func);
-    void postMouseButtonEvent(const std::function<void()>& func);
+	struct LLWindowWin32Thread;
+	LLWindowWin32Thread* mWindowThread = nullptr;
+	LLThreadSafeQueue<std::function<void()>> mFunctionQueue;
+	LLThreadSafeQueue<std::function<void()>> mMouseQueue;
+	void post(const std::function<void()>& func);
+	void postMouseButtonEvent(const std::function<void()>& func);
+	void recreateWindow(RECT window_rect, DWORD dw_ex_style, DWORD dw_style);
 
 	friend class LLWindowManager;
-    friend class LLWindowWin32Thread;
 };
 
 class LLSplashScreenWin32 : public LLSplashScreen
-- 
cgit v1.2.3


From 08336bb469b8db41809893a2ed26599777383eed Mon Sep 17 00:00:00 2001
From: Nat Goodspeed <nat@lindenlab.com>
Date: Mon, 8 Nov 2021 15:15:56 -0500
Subject: SL-16094: Zap thread safety land mine; thin PostMessage() calls.

LLWindowWin32::mWndProc was a public WNDPROC member. If set non-NULL,
mainWindowProc() would call that before falling into its own handler code. But
now, mWndProc would be called on the window thread instead of on the main
thread. Running arbitrary callback code on the window thread could cause all
sorts of problems.

It could be made safe by posting the callback call to the "mainloop" WorkQueue
for execution on the main thread. But as no code actually references it,
delete it instead.

Per DaveP, the recent change to LLWindowsWin32Thread::post() could end up
calling PostMessage() many times per frame, with nontrivial overhead.
Reinstate the more selective code that calls PostMessage() with the dummy
message (to bust us out of GetMessage() to check pending window-thread work
requests) at most once per frame.
---
 indra/llwindow/llwindowwin32.cpp | 30 +++++++++++++-----------------
 indra/llwindow/llwindowwin32.h   |  1 -
 2 files changed, 13 insertions(+), 18 deletions(-)

(limited to 'indra')

diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp
index 4b40fae1bf..a26924c2fb 100644
--- a/indra/llwindow/llwindowwin32.cpp
+++ b/indra/llwindow/llwindowwin32.cpp
@@ -488,11 +488,6 @@ struct LLWindowWin32::LLWindowWin32Thread : public LL::ThreadPool
     void post(CALLABLE&& func)
     {
         getQueue().post(std::forward<CALLABLE>(func));
-        // bump us out of blocked GetMessage() call
-        if (mWindowHandle)
-        {
-            PostMessage(mWindowHandle, WM_USER + 0x0017, 0xB0B0, 0x1337);
-        }
     }
 
     // call PeekMessage and pull enqueue messages for later processing
@@ -583,7 +578,6 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks,
 
 	// Make an instance of our window then define the window class
 	mhInstance = GetModuleHandle(NULL);
-	mWndProc = NULL;
 
     // Init Direct Input - needed for joystick / Spacemouse
 
@@ -2175,6 +2169,19 @@ void LLWindowWin32::gatherInput()
         mRawMouseDelta.mX = 0;
         mRawMouseDelta.mY = 0;
     }
+
+
+    if (mWindowThread->getQueue().size())
+    {
+        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))
     {
@@ -2250,17 +2257,6 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
 
     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;
-            }
-        }
-
         // 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));
diff --git a/indra/llwindow/llwindowwin32.h b/indra/llwindow/llwindowwin32.h
index 97d1e6d7a3..c3ce1e25a9 100644
--- a/indra/llwindow/llwindowwin32.h
+++ b/indra/llwindow/llwindowwin32.h
@@ -185,7 +185,6 @@ protected:
 	HGLRC		mhRC = 0;			// OpenGL rendering context
 	HDC			mhDC = 0;			// Windows Device context handle
 	HINSTANCE	mhInstance;		// handle to application instance
-	WNDPROC		mWndProc;		// user-installable window proc
 	RECT		mOldMouseClip;  // Screen rect to which the mouse cursor was globally constrained before we changed it in clipMouse()
 	WPARAM		mLastSizeWParam;
 	F32			mOverrideAspectRatio;
-- 
cgit v1.2.3


From 768b7a4d33b64dc3e9d7f7c0c384bb2aa37b458b Mon Sep 17 00:00:00 2001
From: Mnikolenko Productengine <mnikolenko@productengine.com>
Date: Tue, 9 Nov 2021 17:17:49 +0200
Subject: SL-16330 Clean up vertical sync handling, add to UI

---
 indra/llwindow/llwindow.cpp                        | 12 ++++-----
 indra/llwindow/llwindow.h                          |  5 ++--
 indra/llwindow/llwindowheadless.cpp                |  2 +-
 indra/llwindow/llwindowheadless.h                  |  5 ++--
 indra/llwindow/llwindowmacosx.cpp                  | 12 ++++-----
 indra/llwindow/llwindowmacosx.h                    |  6 ++---
 indra/llwindow/llwindowwin32.cpp                   | 31 +++++++++++++---------
 indra/llwindow/llwindowwin32.h                     |  5 ++--
 indra/newview/app_settings/settings.xml            |  6 ++---
 indra/newview/llviewercontrol.cpp                  |  7 +++++
 indra/newview/llviewerwindow.cpp                   |  4 +--
 indra/newview/llviewerwindow.h                     |  2 +-
 indra/newview/pipeline.cpp                         |  3 ---
 .../en/floater_preferences_graphics_advanced.xml   |  8 +++---
 14 files changed, 60 insertions(+), 48 deletions(-)

(limited to 'indra')

diff --git a/indra/llwindow/llwindow.cpp b/indra/llwindow/llwindow.cpp
index 67ef98d7b3..f4678a70c5 100644
--- a/indra/llwindow/llwindow.cpp
+++ b/indra/llwindow/llwindow.cpp
@@ -403,7 +403,7 @@ LLWindow* LLWindowManager::createWindow(
 	const std::string& title, const std::string& name, S32 x, S32 y, S32 width, S32 height, U32 flags,
 	BOOL fullscreen, 
 	BOOL clearBg,
-	BOOL disable_vsync,
+	BOOL enable_vsync,
 	BOOL use_gl,
 	BOOL ignore_pixel_depth,
 	U32 fsaa_samples)
@@ -415,26 +415,26 @@ LLWindow* LLWindowManager::createWindow(
 #if LL_MESA_HEADLESS
 		new_window = new LLWindowMesaHeadless(callbacks,
 			title, name, x, y, width, height, flags, 
-			fullscreen, clearBg, disable_vsync, use_gl, ignore_pixel_depth);
+			fullscreen, clearBg, enable_vsync, use_gl, ignore_pixel_depth);
 #elif LL_SDL
 		new_window = new LLWindowSDL(callbacks,
 			title, x, y, width, height, flags, 
-			fullscreen, clearBg, disable_vsync, use_gl, ignore_pixel_depth, fsaa_samples);
+			fullscreen, clearBg, enable_vsync, use_gl, ignore_pixel_depth, fsaa_samples);
 #elif LL_WINDOWS
 		new_window = new LLWindowWin32(callbacks,
 			title, name, x, y, width, height, flags, 
-			fullscreen, clearBg, disable_vsync, use_gl, ignore_pixel_depth, fsaa_samples);
+			fullscreen, clearBg, enable_vsync, use_gl, ignore_pixel_depth, fsaa_samples);
 #elif LL_DARWIN
 		new_window = new LLWindowMacOSX(callbacks,
 			title, name, x, y, width, height, flags, 
-			fullscreen, clearBg, disable_vsync, use_gl, ignore_pixel_depth, fsaa_samples);
+			fullscreen, clearBg, enable_vsync, use_gl, ignore_pixel_depth, fsaa_samples);
 #endif
 	}
 	else
 	{
 		new_window = new LLWindowHeadless(callbacks,
 			title, name, x, y, width, height, flags, 
-			fullscreen, clearBg, disable_vsync, use_gl, ignore_pixel_depth);
+			fullscreen, clearBg, enable_vsync, use_gl, ignore_pixel_depth);
 	}
 
 	if (FALSE == new_window->isValid())
diff --git a/indra/llwindow/llwindow.h b/indra/llwindow/llwindow.h
index b76d313011..43d81e4d59 100644
--- a/indra/llwindow/llwindow.h
+++ b/indra/llwindow/llwindow.h
@@ -77,7 +77,7 @@ public:
 	BOOL setSize(LLCoordScreen size);
 	BOOL setSize(LLCoordWindow size);
 	virtual void setMinSize(U32 min_width, U32 min_height, bool enforce_immediately = true);
-	virtual BOOL switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL disable_vsync, const LLCoordScreen * const posp = NULL) = 0;
+	virtual BOOL switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL enable_vsync, const LLCoordScreen * const posp = NULL) = 0;
 
     //create a new GL context that shares a namespace with this Window's main GL context and make it current on the current thread
     // returns a pointer to be handed back to destroySharedConext/makeContextCurrent
@@ -92,6 +92,7 @@ public:
     virtual BOOL setCursorPosition(LLCoordWindow position) = 0;
 	virtual BOOL getCursorPosition(LLCoordWindow *position) = 0;
 #if LL_WINDOWS
+    virtual void toggleVSync(bool enable_vsync) = 0;
     virtual BOOL getCursorDelta(LLCoordCommon* delta) = 0;
 #endif
 	virtual void showCursor() = 0;
@@ -295,7 +296,7 @@ public:
 		U32 flags = 0,
 		BOOL fullscreen = FALSE,
 		BOOL clearBg = FALSE,
-		BOOL disable_vsync = TRUE,
+		BOOL enable_vsync = FALSE,
 		BOOL use_gl = TRUE,
 		BOOL ignore_pixel_depth = FALSE,
 		U32 fsaa_samples = 0);
diff --git a/indra/llwindow/llwindowheadless.cpp b/indra/llwindow/llwindowheadless.cpp
index 70f473281b..c3738af6ca 100644
--- a/indra/llwindow/llwindowheadless.cpp
+++ b/indra/llwindow/llwindowheadless.cpp
@@ -35,7 +35,7 @@
 //
 LLWindowHeadless::LLWindowHeadless(LLWindowCallbacks* callbacks, const std::string& title, const std::string& name, S32 x, S32 y, S32 width, S32 height,
 							 U32 flags,  BOOL fullscreen, BOOL clear_background,
-							 BOOL disable_vsync, BOOL use_gl, BOOL ignore_pixel_depth)
+							 BOOL enable_vsync, BOOL use_gl, BOOL ignore_pixel_depth)
 	: LLWindow(callbacks, fullscreen, flags)
 {
 	// Initialize a headless keyboard.
diff --git a/indra/llwindow/llwindowheadless.h b/indra/llwindow/llwindowheadless.h
index f8ba9bbed4..78c5e4bae4 100644
--- a/indra/llwindow/llwindowheadless.h
+++ b/indra/llwindow/llwindowheadless.h
@@ -48,13 +48,14 @@ public:
 	/*virtual*/ BOOL setPosition(LLCoordScreen position) {return FALSE;};
 	/*virtual*/ BOOL setSizeImpl(LLCoordScreen size) {return FALSE;};
 	/*virtual*/ BOOL setSizeImpl(LLCoordWindow size) {return FALSE;};
-	/*virtual*/ BOOL switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL disable_vsync, const LLCoordScreen * const posp = NULL) {return FALSE;};
+	/*virtual*/ BOOL switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL enable_vsync, const LLCoordScreen * const posp = NULL) {return FALSE;};
     void* createSharedContext()  { return nullptr; }
     void makeContextCurrent(void*)  {}
     void destroySharedContext(void*)  {}
 	/*virtual*/ BOOL setCursorPosition(LLCoordWindow position) {return FALSE;};
 	/*virtual*/ BOOL getCursorPosition(LLCoordWindow *position) {return FALSE;};
 #if LL_WINDOWS
+    /*virtual*/ virtual void toggleVSync(bool enable_vsync) { }
     /*virtual*/ BOOL getCursorDelta(LLCoordCommon* delta) { return FALSE; }
 #endif
 	/*virtual*/ void showCursor() {};
@@ -103,7 +104,7 @@ public:
 		S32 x, S32 y, 
 		S32 width, S32 height,
 		U32 flags,  BOOL fullscreen, BOOL clear_background,
-		BOOL disable_vsync, BOOL use_gl, BOOL ignore_pixel_depth);
+		BOOL enable_vsync, BOOL use_gl, BOOL ignore_pixel_depth);
 	virtual ~LLWindowHeadless();
 
 private:
diff --git a/indra/llwindow/llwindowmacosx.cpp b/indra/llwindow/llwindowmacosx.cpp
index 23830dd24e..a74fa78388 100644
--- a/indra/llwindow/llwindowmacosx.cpp
+++ b/indra/llwindow/llwindowmacosx.cpp
@@ -111,7 +111,7 @@ LLWindowMacOSX::LLWindowMacOSX(LLWindowCallbacks* callbacks,
 							   const std::string& title, const std::string& name, S32 x, S32 y, S32 width,
 							   S32 height, U32 flags,
 							   BOOL fullscreen, BOOL clearBg,
-							   BOOL disable_vsync, BOOL use_gl,
+							   BOOL enable_vsync, BOOL use_gl,
 							   BOOL ignore_pixel_depth,
 							   U32 fsaa_samples)
 	: LLWindow(NULL, fullscreen, flags)
@@ -165,7 +165,7 @@ LLWindowMacOSX::LLWindowMacOSX(LLWindowCallbacks* callbacks,
 	// Stash an object pointer for OSMessageBox()
 	gWindowImplementation = this;
 	// Create the GL context and set it up for windowed or fullscreen, as appropriate.
-	if(createContext(x, y, width, height, 32, fullscreen, disable_vsync))
+	if(createContext(x, y, width, height, 32, fullscreen, enable_vsync))
 	{
 		if(mWindow != NULL)
 		{
@@ -610,7 +610,7 @@ void LLWindowMacOSX::getMouseDeltas(float* delta)
 	delta[1] = mCursorLastEventDeltaY;
 }
 
-BOOL LLWindowMacOSX::createContext(int x, int y, int width, int height, int bits, BOOL fullscreen, BOOL disable_vsync)
+BOOL LLWindowMacOSX::createContext(int x, int y, int width, int height, int bits, BOOL fullscreen, BOOL enable_vsync)
 {
 	BOOL			glNeedsInit = FALSE;
 
@@ -625,7 +625,7 @@ BOOL LLWindowMacOSX::createContext(int x, int y, int width, int height, int bits
 	{
 		// Our OpenGL view is already defined within SecondLife.xib.
 		// Get the view instead.
-		mGLView = createOpenGLView(mWindow, mFSAASamples, !disable_vsync);
+		mGLView = createOpenGLView(mWindow, mFSAASamples, enable_vsync);
 		mContext = getCGLContextObj(mGLView);
 		
 		// Since we just created the context, it needs to be set up.
@@ -653,7 +653,7 @@ BOOL LLWindowMacOSX::createContext(int x, int y, int width, int height, int bits
 
 	// Disable vertical sync for swap
 	GLint frames_per_swap = 0;
-	if (disable_vsync)
+	if (!enable_vsync)
 	{
 		frames_per_swap = 0;
 	}
@@ -689,7 +689,7 @@ BOOL LLWindowMacOSX::createContext(int x, int y, int width, int height, int bits
 
 // We only support OS X 10.7's fullscreen app mode which is literally a full screen window that fills a virtual desktop.
 // This makes this method obsolete.
-BOOL LLWindowMacOSX::switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL disable_vsync, const LLCoordScreen * const posp)
+BOOL LLWindowMacOSX::switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL enable_vsync, const LLCoordScreen * const posp)
 {
 	return FALSE;
 }
diff --git a/indra/llwindow/llwindowmacosx.h b/indra/llwindow/llwindowmacosx.h
index ede2b453d5..18fa86930f 100644
--- a/indra/llwindow/llwindowmacosx.h
+++ b/indra/llwindow/llwindowmacosx.h
@@ -60,7 +60,7 @@ public:
 	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 switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL enable_vsync, const LLCoordScreen * const posp = NULL) override;
 	BOOL setCursorPosition(LLCoordWindow position) override;
 	BOOL getCursorPosition(LLCoordWindow *position) override;
 	void showCursor() override;
@@ -143,7 +143,7 @@ public:
 protected:
 	LLWindowMacOSX(LLWindowCallbacks* callbacks,
 		const std::string& title, const std::string& name, int x, int y, int width, int height, U32 flags,
-		BOOL fullscreen, BOOL clearBg, BOOL disable_vsync, BOOL use_gl,
+		BOOL fullscreen, BOOL clearBg, BOOL enable_vsync, BOOL use_gl,
 		BOOL ignore_pixel_depth,
 		U32 fsaa_samples);
 		~LLWindowMacOSX();
@@ -176,7 +176,7 @@ protected:
 	//
 
 	// create or re-create the GL context/window.  Called from the constructor and switchContext().
-	BOOL createContext(int x, int y, int width, int height, int bits, BOOL fullscreen, BOOL disable_vsync);
+	BOOL createContext(int x, int y, int width, int height, int bits, BOOL fullscreen, BOOL enable_vsync);
 	void destroyContext();
 	void setupFailure(const std::string& text, const std::string& caption, U32 type);
 	void adjustCursorDecouple(bool warpingMouse = false);
diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp
index dddc8deb02..e52624d66a 100644
--- a/indra/llwindow/llwindowwin32.cpp
+++ b/indra/llwindow/llwindowwin32.cpp
@@ -473,7 +473,7 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks,
 							 const std::string& title, const std::string& name, S32 x, S32 y, S32 width,
 							 S32 height, U32 flags, 
 							 BOOL fullscreen, BOOL clearBg,
-							 BOOL disable_vsync, BOOL use_gl,
+							 BOOL enable_vsync, BOOL use_gl,
 							 BOOL ignore_pixel_depth,
 							 U32 fsaa_samples)
 	: LLWindow(callbacks, fullscreen, flags)
@@ -800,7 +800,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, disable_vsync, &windowPos))
+	if (!switchContext(mFullscreen, windowSize, enable_vsync, &windowPos))
 	{
 		return;
 	}
@@ -1126,7 +1126,7 @@ 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 enable_vsync, const LLCoordScreen* const posp)
 {
     //called from main thread
     GLuint	pixel_format;
@@ -1802,16 +1802,7 @@ const	S32   max_format  = (S32)num_formats - 1;
 	}
 	
 	// Disable vertical sync for swap
-	if (disable_vsync && wglSwapIntervalEXT)
-	{
-		LL_DEBUGS("Window") << "Disabling vertical sync" << LL_ENDL;
-		wglSwapIntervalEXT(0);
-	}
-	else
-	{
-		LL_DEBUGS("Window") << "Keeping vertical sync" << LL_ENDL;
-        wglSwapIntervalEXT(1);
-	}
+    toggleVSync(enable_vsync);
 
 	SetWindowLongPtr(mWindowHandle, GWLP_USERDATA, (LONG_PTR)this);
 
@@ -1906,6 +1897,20 @@ void LLWindowWin32::destroySharedContext(void* contextPtr)
     wglDeleteContext((HGLRC)contextPtr);
 }
 
+void LLWindowWin32::toggleVSync(bool enable_vsync)
+{
+    if (!enable_vsync && wglSwapIntervalEXT)
+    {
+        LL_INFOS("Window") << "Disabling vertical sync" << LL_ENDL;
+        wglSwapIntervalEXT(0);
+    }
+    else
+    {
+        LL_INFOS("Window") << "Enabling vertical sync" << LL_ENDL;
+        wglSwapIntervalEXT(1);
+    }
+}
+
 void LLWindowWin32::moveWindow( const LLCoordScreen& position, const LLCoordScreen& size )
 {
 	if( mIsMouseClipping )
diff --git a/indra/llwindow/llwindowwin32.h b/indra/llwindow/llwindowwin32.h
index 7a9a30ccea..d082080807 100644
--- a/indra/llwindow/llwindowwin32.h
+++ b/indra/llwindow/llwindowwin32.h
@@ -93,11 +93,12 @@ public:
 	/*virtual*/ BOOL setPosition(LLCoordScreen position);
 	/*virtual*/ BOOL setSizeImpl(LLCoordScreen size);
 	/*virtual*/ BOOL setSizeImpl(LLCoordWindow size);
-	/*virtual*/ BOOL switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL disable_vsync, const LLCoordScreen * const posp = NULL);
+	/*virtual*/ BOOL switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL enable_vsync, const LLCoordScreen * const posp = NULL);
     /*virtual*/ void setTitle(const std::string title);
     void* createSharedContext() override;
     void makeContextCurrent(void* context) override;
     void destroySharedContext(void* context) override;
+    /*virtual*/ void toggleVSync(bool enable_vsync);
 	/*virtual*/ BOOL setCursorPosition(LLCoordWindow position);
 	/*virtual*/ BOOL getCursorPosition(LLCoordWindow *position);
     /*virtual*/ BOOL getCursorDelta(LLCoordCommon* delta);
@@ -164,7 +165,7 @@ public:
 protected:
 	LLWindowWin32(LLWindowCallbacks* callbacks,
 		const std::string& title, const std::string& name, int x, int y, int width, int height, U32 flags, 
-		BOOL fullscreen, BOOL clearBg, BOOL disable_vsync, BOOL use_gl,
+		BOOL fullscreen, BOOL clearBg, BOOL enable_vsync, BOOL use_gl,
 		BOOL ignore_pixel_depth, U32 fsaa_samples);
 	~LLWindowWin32();
 
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 291f0f7d95..f15b5d0981 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -3352,16 +3352,16 @@
       <key>Value</key>
       <integer>0</integer>
     </map>
-    <key>DisableVerticalSync</key>
+    <key>RenderVSyncEnable</key>
     <map>
       <key>Comment</key>
-      <string>Update frames as fast as possible (FALSE = update frames between display scans).  Requires restart.</string>
+      <string>Update frames between display scans (FALSE = Update frames as fast as possible).</string>
       <key>Persist</key>
       <integer>1</integer>
       <key>Type</key>
       <string>Boolean</string>
       <key>Value</key>
-      <integer>0</integer>
+      <integer>1</integer>
     </map>
     <key>EnableGroupChatPopups</key>
     <map>
diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp
index 76dc9a6790..3e7459ee8a 100644
--- a/indra/newview/llviewercontrol.cpp
+++ b/indra/newview/llviewercontrol.cpp
@@ -241,6 +241,12 @@ static bool handleAnisotropicChanged(const LLSD& newvalue)
 	return true;
 }
 
+static bool handleVSyncChanged(const LLSD& newvalue)
+{
+    gViewerWindow->getWindow()->toggleVSync(newvalue.asBoolean());
+    return true;
+}
+
 static bool handleVolumeLODChanged(const LLSD& newvalue)
 {
 	LLVOVolume::sLODFactor = llclamp((F32) newvalue.asReal(), 0.01f, MAX_LOD_FACTOR);
@@ -665,6 +671,7 @@ void settings_setup_listeners()
 	gSavedSettings.getControl("RenderAutoMaskAlphaNonDeferred")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _2));
 	gSavedSettings.getControl("RenderObjectBump")->getSignal()->connect(boost::bind(&handleRenderBumpChanged, _2));
 	gSavedSettings.getControl("RenderMaxVBOSize")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _2));
+    gSavedSettings.getControl("RenderVSyncEnable")->getSignal()->connect(boost::bind(&handleVSyncChanged, _2));
 	gSavedSettings.getControl("RenderDeferredNoise")->getSignal()->connect(boost::bind(&handleReleaseGLBufferChanged, _2));
 	gSavedSettings.getControl("RenderDebugGL")->getSignal()->connect(boost::bind(&handleRenderDebugGLChanged, _2));
 	gSavedSettings.getControl("RenderDebugPipeline")->getSignal()->connect(boost::bind(&handleRenderDebugPipelineChanged, _2));
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index 7dc7b33938..a35ad55cf7 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -1903,7 +1903,7 @@ LLViewerWindow::LLViewerWindow(const Params& p)
 		p.title, p.name, p.x, p.y, p.width, p.height, 0,
 		p.fullscreen, 
 		gHeadlessClient,
-		gSavedSettings.getBOOL("DisableVerticalSync"),
+		gSavedSettings.getBOOL("RenderVSyncEnable"),
 		!gHeadlessClient,
 		p.ignore_pixel_depth,
 		gSavedSettings.getBOOL("RenderDeferred") ? 0 : gSavedSettings.getU32("RenderFSAASamples")); //don't use window level anti-aliasing if FBOs are enabled
@@ -5569,7 +5569,7 @@ void LLViewerWindow::restartDisplay(BOOL show_progress_bar)
 	}
 }
 
-BOOL LLViewerWindow::changeDisplaySettings(LLCoordScreen size, BOOL disable_vsync, BOOL show_progress_bar)
+BOOL LLViewerWindow::changeDisplaySettings(LLCoordScreen size, BOOL enable_vsync, BOOL show_progress_bar)
 {
 	//BOOL was_maximized = gSavedSettings.getBOOL("WindowMaximized");
 
diff --git a/indra/newview/llviewerwindow.h b/indra/newview/llviewerwindow.h
index 8a6df613dc..93194b1884 100644
--- a/indra/newview/llviewerwindow.h
+++ b/indra/newview/llviewerwindow.h
@@ -424,7 +424,7 @@ public:
 	void			requestResolutionUpdate();
 	void			checkSettings();
 	void			restartDisplay(BOOL show_progress_bar);
-	BOOL			changeDisplaySettings(LLCoordScreen size, BOOL disable_vsync, BOOL show_progress_bar);
+	BOOL			changeDisplaySettings(LLCoordScreen size, BOOL enable_vsync, BOOL show_progress_bar);
 	BOOL			getIgnoreDestroyWindow() { return mIgnoreActivate; }
 	F32				getWorldViewAspectRatio() const;
 	const LLVector2& getDisplayScale() const { return mDisplayScale; }
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index 1821ca067a..71a438302a 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -8388,8 +8388,6 @@ LLVector4 pow4fsrgb(LLVector4 v, F32 f)
 	return v;
 }
 
-static LLTrace::BlockTimerStatHandle FTM_DEFERRED_LIGHTING("Deferred Lighting");
-
 void LLPipeline::renderDeferredLighting(LLRenderTarget *screen_target)
 {
     LL_PROFILE_ZONE_SCOPED;
@@ -8397,7 +8395,6 @@ void LLPipeline::renderDeferredLighting(LLRenderTarget *screen_target)
     {
         return;
     }
-    LL_RECORD_BLOCK_TIME(FTM_DEFERRED_LIGHTING);
 
     LLRenderTarget *deferred_target       = &mDeferredScreen;
     LLRenderTarget *deferred_depth_target = &mDeferredDepth;
diff --git a/indra/newview/skins/default/xui/en/floater_preferences_graphics_advanced.xml b/indra/newview/skins/default/xui/en/floater_preferences_graphics_advanced.xml
index 7786ba8a1c..cba75e8ea7 100644
--- a/indra/newview/skins/default/xui/en/floater_preferences_graphics_advanced.xml
+++ b/indra/newview/skins/default/xui/en/floater_preferences_graphics_advanced.xml
@@ -334,15 +334,15 @@
     width="256" />
 
   <check_box
-    control_name="RenderVBOEnable"
+    control_name="RenderVSyncEnable"
     height="16"
     initial_value="true"
-    label="Enable OpenGL Vertex Buffer Objects"
+    label="Enable VSync"
     layout="topleft"
     left="30"
     top_delta="16"
-    name="vbo"
-    tool_tip="Enabling this on modern hardware gives a performance gain.  However, older hardware often has poor implementations of VBOs and you may get crashes when this is enabled."
+    name="vsync"
+    tool_tip="Synchronizes the frame rate to the refresh rate of the monitor, which results in smooth performance."
     width="315" />
 
   <check_box
-- 
cgit v1.2.3


From ca0b9a3753fa3b42d4ac8183adcf30d957f55016 Mon Sep 17 00:00:00 2001
From: "Brad Payne (Vir Linden)" <vir@lindenlab.com>
Date: Tue, 9 Nov 2021 20:25:25 +0000
Subject: SL-16329 - track frame time and jitter (as average deviation frame to
 frame) in stats window

---
 indra/llcommon/lltracerecording.cpp                | 27 +++++++++++++++++++-
 indra/llcommon/lltracerecording.h                  | 29 ++++++++++++++++++++++
 indra/llui/llstatbar.cpp                           | 17 +++++++++++--
 indra/llui/llstatbar.h                             |  6 +++--
 indra/newview/llviewerstats.cpp                    | 11 +++++---
 indra/newview/llviewerstats.h                      |  4 +--
 .../newview/skins/default/xui/en/floater_stats.xml | 19 ++++++++++++++
 7 files changed, 103 insertions(+), 10 deletions(-)

(limited to 'indra')

diff --git a/indra/llcommon/lltracerecording.cpp b/indra/llcommon/lltracerecording.cpp
index c72a64d086..5ce1b337fe 100644
--- a/indra/llcommon/lltracerecording.cpp
+++ b/indra/llcommon/lltracerecording.cpp
@@ -858,7 +858,6 @@ F64 PeriodicRecording::getPeriodMean( const StatType<EventAccumulator>& stat, S3
 			: NaN;
 }
 
-
 F64 PeriodicRecording::getPeriodStandardDeviation( const StatType<EventAccumulator>& stat, S32 num_periods /*= S32_MAX*/ )
 {
     LL_PROFILE_ZONE_SCOPED;
@@ -952,6 +951,32 @@ F64 PeriodicRecording::getPeriodMean( const StatType<SampleAccumulator>& stat, S
 			: NaN;
 }
 
+F64 PeriodicRecording::getPeriodMedian( const StatType<SampleAccumulator>& stat, S32 num_periods /*= S32_MAX*/ )
+{
+    LL_PROFILE_ZONE_SCOPED;
+	num_periods = llmin(num_periods, getNumRecordedPeriods());
+
+	std::vector<F64> buf;
+	for (S32 i = 1; i <= num_periods; i++)
+	{
+		Recording& recording = getPrevRecording(i);
+		if (recording.getDuration() > (F32Seconds)0.f)
+		{
+			if (recording.hasValue(stat))
+			{
+				buf.push_back(recording.getMean(stat));
+			}
+		}
+	}
+	if (buf.size()==0)
+	{
+		return 0.0f;
+	}
+	std::sort(buf.begin(), buf.end());
+
+	return F64((buf.size() % 2 == 0) ? (buf[buf.size() / 2 - 1] + buf[buf.size() / 2]) / 2 : buf[buf.size() / 2]);
+}
+
 F64 PeriodicRecording::getPeriodStandardDeviation( const StatType<SampleAccumulator>& stat, S32 num_periods /*= S32_MAX*/ )
 {
     LL_PROFILE_ZONE_SCOPED;
diff --git a/indra/llcommon/lltracerecording.h b/indra/llcommon/lltracerecording.h
index 6715104613..1f3d37336a 100644
--- a/indra/llcommon/lltracerecording.h
+++ b/indra/llcommon/lltracerecording.h
@@ -599,6 +599,35 @@ namespace LLTrace
 			return typename RelatedTypes<T>::fractional_t(getPeriodMeanPerSec(static_cast<const StatType<CountAccumulator>&>(stat), num_periods));
 		}
 
+        F64 getPeriodMedian( const StatType<SampleAccumulator>& stat, S32 num_periods = S32_MAX);
+
+        template <typename T>
+        typename RelatedTypes<typename T::value_t>::fractional_t getPeriodMedianPerSec(const StatType<T>& stat, S32 num_periods = S32_MAX)
+        {
+            LL_PROFILE_ZONE_SCOPED;
+            num_periods = llmin(num_periods, getNumRecordedPeriods());
+
+            std::vector <typename RelatedTypes<typename T::value_t>::fractional_t> buf;
+            for (S32 i = 1; i <= num_periods; i++)
+            {
+                Recording& recording = getPrevRecording(i);
+                if (recording.getDuration() > (F32Seconds)0.f)
+                {
+                    buf.push_back(recording.getPerSec(stat));
+                }
+            }
+            std::sort(buf.begin(), buf.end());
+
+            return typename RelatedTypes<T>::fractional_t((buf.size() % 2 == 0) ? (buf[buf.size() / 2 - 1] + buf[buf.size() / 2]) / 2 : buf[buf.size() / 2]);
+        }
+
+        template<typename T>
+        typename RelatedTypes<T>::fractional_t getPeriodMedianPerSec(const CountStatHandle<T>& stat, S32 num_periods = S32_MAX)
+        {
+            LL_PROFILE_ZONE_SCOPED;
+            return typename RelatedTypes<T>::fractional_t(getPeriodMedianPerSec(static_cast<const StatType<CountAccumulator>&>(stat), num_periods));
+        }
+
 		//
 		// PERIODIC STANDARD DEVIATION
 		//
diff --git a/indra/llui/llstatbar.cpp b/indra/llui/llstatbar.cpp
index 8adcd664df..2449100952 100644
--- a/indra/llui/llstatbar.cpp
+++ b/indra/llui/llstatbar.cpp
@@ -160,6 +160,7 @@ LLStatBar::Params::Params()
 	tick_spacing("tick_spacing", 0.f),
 	decimal_digits("decimal_digits", 3),
 	show_bar("show_bar", false),
+	show_median("show_median", false),
 	show_history("show_history", false),
 	scale_range("scale_range", true),
 	num_frames("num_frames", 200),
@@ -186,6 +187,7 @@ LLStatBar::LLStatBar(const Params& p)
 	mNumShortHistoryFrames(p.num_frames_short),
 	mMaxHeight(p.max_height),
 	mDisplayBar(p.show_bar),
+	mShowMedian(p.show_median),
 	mDisplayHistory(p.show_history),
 	mOrientation(p.orientation),
 	mAutoScaleMax(!p.bar_max.isProvided()),
@@ -318,7 +320,14 @@ void LLStatBar::draw()
 			min           = frame_recording.getPeriodMinPerSec(count_stat, num_frames);
 			max           = frame_recording.getPeriodMaxPerSec(count_stat, num_frames);
 			mean          = frame_recording.getPeriodMeanPerSec(count_stat, num_frames);
-			display_value = mean;
+			if (mShowMedian)
+			{
+				display_value = frame_recording.getPeriodMedianPerSec(count_stat, num_frames);
+			}
+			else
+			{
+				display_value = mean;
+			}
 		}
 		break;
 	case STAT_EVENT:
@@ -344,7 +353,11 @@ void LLStatBar::draw()
 			mean              = frame_recording.getPeriodMean(sample_stat, num_frames);
 			num_rapid_changes = calc_num_rapid_changes(frame_recording, sample_stat, RAPID_CHANGE_WINDOW);
 
-			if (num_rapid_changes / RAPID_CHANGE_WINDOW.value() > MAX_RAPID_CHANGES_PER_SEC)
+			if (mShowMedian)
+			{
+				display_value = frame_recording.getPeriodMedian(sample_stat, num_frames);
+			}
+			else if (num_rapid_changes / RAPID_CHANGE_WINDOW.value() > MAX_RAPID_CHANGES_PER_SEC)
 			{
 				display_value = mean;
 			}
diff --git a/indra/llui/llstatbar.h b/indra/llui/llstatbar.h
index 1ff4c67fc5..6b481ca68f 100644
--- a/indra/llui/llstatbar.h
+++ b/indra/llui/llstatbar.h
@@ -44,9 +44,10 @@ public:
 								bar_max,
 								tick_spacing;
 
-		Optional<bool>			show_bar,
+		Optional<bool> 			show_bar,
 								show_history,
-								scale_range;
+								scale_range,
+								show_median; // default is mean
 
 		Optional<S32>			decimal_digits,
 								num_frames,
@@ -112,6 +113,7 @@ private:
 
 	bool         mDisplayBar,			// Display the bar graph.
 				 mDisplayHistory,
+				 mShowMedian,
 				 mAutoScaleMax,
 				 mAutoScaleMin;
 };
diff --git a/indra/newview/llviewerstats.cpp b/indra/newview/llviewerstats.cpp
index 314c1a1f1e..ac8a657fb2 100644
--- a/indra/newview/llviewerstats.cpp
+++ b/indra/newview/llviewerstats.cpp
@@ -183,8 +183,9 @@ SimMeasurement<F64Kilobytes >	SIM_UNACKED_BYTES("simtotalunackedbytes", "", LL_S
 SimMeasurement<F64Megabytes >	SIM_PHYSICS_MEM("physicsmemoryallocated", "", LL_SIM_STAT_SIMPHYSICSMEMORY);
 
 LLTrace::SampleStatHandle<F64Milliseconds >	FRAMETIME_JITTER("frametimejitter", "Average delta between successive frame times"),
-																FRAMETIME_SLEW("frametimeslew", "Average delta between frame time and mean"),
-																SIM_PING("simpingstat");
+											FRAMETIME_SLEW("frametimeslew", "Average delta between frame time and mean"),
+											FRAMETIME("frametime", "Measured frame time"),
+											SIM_PING("simpingstat");
 
 LLTrace::EventStatHandle<LLUnit<F64, LLUnits::Meters> > AGENT_POSITION_SNAP("agentpositionsnap", "agent position corrections");
 
@@ -261,8 +262,12 @@ void LLViewerStats::updateFrameStats(const F64Seconds time_diff)
 		// new "stutter" meter
 		add(LLStatViewer::FRAMETIME_DOUBLED, time_diff >= 2.0 * mLastTimeDiff ? 1 : 0);
 
+		sample(LLStatViewer::FRAMETIME, time_diff);
+
 		// old stats that were never really used
-		sample(LLStatViewer::FRAMETIME_JITTER, F64Milliseconds (mLastTimeDiff - time_diff));
+		F64Seconds jit = (F64Seconds) std::fabs((mLastTimeDiff - time_diff));
+		LL_INFOS() << "times " << mLastTimeDiff << ", " << time_diff << " jit " << jit << LL_ENDL;
+		sample(LLStatViewer::FRAMETIME_JITTER, jit);
 			
 		F32Seconds average_frametime = gRenderStartTime.getElapsedTimeF32() / (F32)gFrameCount;
 		sample(LLStatViewer::FRAMETIME_SLEW, F64Milliseconds (average_frametime - time_diff));
diff --git a/indra/newview/llviewerstats.h b/indra/newview/llviewerstats.h
index 04870e0c26..ac8eccc0ca 100644
--- a/indra/newview/llviewerstats.h
+++ b/indra/newview/llviewerstats.h
@@ -218,8 +218,8 @@ extern SimMeasurement<F64Megabytes >	SIM_PHYSICS_MEM;
 
 
 extern LLTrace::SampleStatHandle<F64Milliseconds >	FRAMETIME_JITTER,
-																		FRAMETIME_SLEW,
-																		SIM_PING;
+													FRAMETIME_SLEW,
+													SIM_PING;
 
 extern LLTrace::EventStatHandle<LLUnit<F64, LLUnits::Meters> > AGENT_POSITION_SNAP;
 
diff --git a/indra/newview/skins/default/xui/en/floater_stats.xml b/indra/newview/skins/default/xui/en/floater_stats.xml
index e4f735740b..6f84930c75 100644
--- a/indra/newview/skins/default/xui/en/floater_stats.xml
+++ b/indra/newview/skins/default/xui/en/floater_stats.xml
@@ -35,6 +35,25 @@
                   decimal_digits="1"
                   show_bar="true"
                   show_history="true"/>
+        <stat_bar name="frame_mean"
+                  label="frame (mean)"
+                  unit_label="ms"
+                  stat="frametime"
+                  decimal_digits="1"
+                  show_bar="false"
+                  show_history="false"/>
+        <stat_bar name="frame_median"
+                  label="frame (median)"
+                  unit_label="ms"
+                  stat="frametime"
+                  show_median="true"
+                  decimal_digits="1"
+                  show_bar="false"
+                  show_history="false"/>
+        <stat_bar name="framet_jitter"
+                  label="jitter"
+                  decimal_digits="1"
+                  stat="frametimejitter"/>
        <stat_bar name="bandwidth"
                   label="UDP Data Received"
                   stat="activemessagedatareceived"
-- 
cgit v1.2.3


From 7c561ca1c7732d1d95562069565f605f46e8c9e3 Mon Sep 17 00:00:00 2001
From: Mnikolenko Productengine <mnikolenko@productengine.com>
Date: Wed, 10 Nov 2021 13:02:18 +0200
Subject: SL-16330 move VSync checkbox to General group

---
 .../en/floater_preferences_graphics_advanced.xml   | 24 +++++++++++-----------
 1 file changed, 12 insertions(+), 12 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/skins/default/xui/en/floater_preferences_graphics_advanced.xml b/indra/newview/skins/default/xui/en/floater_preferences_graphics_advanced.xml
index cba75e8ea7..4f355cce00 100644
--- a/indra/newview/skins/default/xui/en/floater_preferences_graphics_advanced.xml
+++ b/indra/newview/skins/default/xui/en/floater_preferences_graphics_advanced.xml
@@ -102,6 +102,18 @@
        Low
   </text>
 
+  <check_box
+    control_name="RenderVSyncEnable"
+    height="16"
+    initial_value="true"
+    label="Enable VSync"
+    layout="topleft"
+    left="30"
+    top_delta="16"
+    name="vsync"
+    tool_tip="Synchronizes the frame rate to the refresh rate of the monitor, which results in smooth performance."
+    width="315" />
+
   <text
     type="string"
     length="1"
@@ -333,18 +345,6 @@
     top_delta="16"
     width="256" />
 
-  <check_box
-    control_name="RenderVSyncEnable"
-    height="16"
-    initial_value="true"
-    label="Enable VSync"
-    layout="topleft"
-    left="30"
-    top_delta="16"
-    name="vsync"
-    tool_tip="Synchronizes the frame rate to the refresh rate of the monitor, which results in smooth performance."
-    width="315" />
-
   <check_box
     control_name="RenderCompressTextures"
     height="16"
-- 
cgit v1.2.3


From df8e17d8e851c34a83de6c508aba07f6bde12a10 Mon Sep 17 00:00:00 2001
From: Nat Goodspeed <nat@lindenlab.com>
Date: Wed, 10 Nov 2021 10:13:38 -0500
Subject: SL-16094: Add WorkQueue::size() method to support changeset 08336bb.

We want to skip calling PostMessage() to bump the window thread out of
GetMessage() in any frame with no work functions pending for that thread. That
test depends on being able to sense the size() of the queue. Having converted
to WorkQueue, we need that queue to support size().
---
 indra/llcommon/workqueue.cpp |  5 +++++
 indra/llcommon/workqueue.h   | 15 +++++++++++++++
 2 files changed, 20 insertions(+)

(limited to 'indra')

diff --git a/indra/llcommon/workqueue.cpp b/indra/llcommon/workqueue.cpp
index 14ae4c4ab8..633594ceea 100644
--- a/indra/llcommon/workqueue.cpp
+++ b/indra/llcommon/workqueue.cpp
@@ -39,6 +39,11 @@ void LL::WorkQueue::close()
     mQueue.close();
 }
 
+size_t LL::WorkQueue::size()
+{
+    return mQueue.size();
+}
+
 bool LL::WorkQueue::isClosed()
 {
     return mQueue.isClosed();
diff --git a/indra/llcommon/workqueue.h b/indra/llcommon/workqueue.h
index 5987883829..c25d787425 100644
--- a/indra/llcommon/workqueue.h
+++ b/indra/llcommon/workqueue.h
@@ -64,6 +64,21 @@ namespace LL
          */
         void close();
 
+        /**
+         * WorkQueue supports multiple producers and multiple consumers. In
+         * the general case it's misleading to test size(), since any other
+         * thread might change it the nanosecond the lock is released. On that
+         * basis, some might argue against publishing a size() method at all.
+         *
+         * But there are two specific cases in which a test based on size()
+         * might be reasonable:
+         *
+         * * If you're the only producer, noticing that size() == 0 is
+         *   meaningful.
+         * * If you're the only consumer, noticing that size() > 0 is
+         *   meaningful.
+         */
+        size_t size();
         /// producer end: are we prevented from pushing any additional items?
         bool isClosed();
         /// consumer end: are we done, is the queue entirely drained?
-- 
cgit v1.2.3


From 214d8d40c12c0a39dffdd837c861abe4c005caf1 Mon Sep 17 00:00:00 2001
From: Nat Goodspeed <nat@lindenlab.com>
Date: Wed, 10 Nov 2021 10:17:12 -0500
Subject: SL-16094: Statically link to Windows IMM32.LIB.

llwindowwin32.cpp's LLWinImm class used to dynamically load IMM32.DLL and
populate its methods using GetProcAddress(). That was to support Windows XP.
Since we've dropped Windows XP, use static linking instead, with dramatically
fewer lines of code (and less of a thread safety alarm trigger).

We retain the LLWinImm wrapper class only as a hook for Tracy instrumentation.
---
 indra/llui/CMakeLists.txt        |   2 +-
 indra/llwindow/llwindowwin32.cpp | 182 ++++-----------------------------------
 indra/newview/CMakeLists.txt     |   1 +
 3 files changed, 21 insertions(+), 164 deletions(-)

(limited to 'indra')

diff --git a/indra/llui/CMakeLists.txt b/indra/llui/CMakeLists.txt
index f781ff4110..25ceb68b19 100644
--- a/indra/llui/CMakeLists.txt
+++ b/indra/llui/CMakeLists.txt
@@ -308,6 +308,6 @@ if(LL_TESTS)
       ${BOOST_FIBER_LIBRARY} ${BOOST_CONTEXT_LIBRARY} ${BOOST_SYSTEM_LIBRARY}
       ${WINDOWS_LIBRARIES})
   if(NOT LINUX)
-    LL_ADD_INTEGRATION_TEST(llurlentry llurlentry.cpp "${test_libs}")
+    LL_ADD_INTEGRATION_TEST(llurlentry llurlentry.cpp "imm32;${test_libs}")
   endif(NOT LINUX)
 endif(LL_TESTS)
diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp
index a26924c2fb..736887e286 100644
--- a/indra/llwindow/llwindowwin32.cpp
+++ b/indra/llwindow/llwindowwin32.cpp
@@ -176,23 +176,19 @@ DWORD	LLWindowWin32::sWinIMESentenceMode = IME_SMODE_AUTOMATIC;
 LLCoordWindow LLWindowWin32::sWinIMEWindowPosition(-1,-1);
 
 // The following class LLWinImm delegates Windows IMM APIs.
-// We need this because some language versions of Windows,
-// e.g., US version of Windows XP, doesn't install IMM32.DLL
-// as a default, and we can't link against imm32.lib statically.
-// I believe DLL loading of this type is best suited to do
-// in a static initialization of a class.  What I'm not sure is
-// whether it follows the Linden Conding Standard... 
-// See http://wiki.secondlife.com/wiki/Coding_standards#Static_Members
+// It was originally introduced to support US Windows XP, on which we needed
+// to dynamically load IMM32.DLL and use GetProcAddress to resolve its entry
+// points. Now that that's moot, we retain this wrapper only for hooks for
+// metrics.
 
 class LLWinImm
 {
 public:
-	static bool		isAvailable() { return sTheInstance.mHImmDll != NULL; }
+	static bool		isAvailable() { return true; }
 
 public:
 	// Wrappers for IMM API.
 	static BOOL		isIME(HKL hkl);															
-	static HWND		getDefaultIMEWnd(HWND hwnd);
 	static HIMC		getContext(HWND hwnd);													
 	static BOOL		releaseContext(HWND hwnd, HIMC himc);
 	static BOOL		getOpenStatus(HIMC himc);												
@@ -206,236 +202,96 @@ public:
 	static BOOL		setCompositionFont(HIMC himc, LPLOGFONTW logfont);
 	static BOOL		setCandidateWindow(HIMC himc, LPCANDIDATEFORM candidate_form);
 	static BOOL		notifyIME(HIMC himc, DWORD action, DWORD index, DWORD value);
-
-private:
-	LLWinImm();
-	~LLWinImm();
-
-private:
-	// Pointers to IMM API.
-	BOOL	 	(WINAPI *mImmIsIME)(HKL);
-	HWND		(WINAPI *mImmGetDefaultIMEWnd)(HWND);
-	HIMC		(WINAPI *mImmGetContext)(HWND);
-	BOOL		(WINAPI *mImmReleaseContext)(HWND, HIMC);
-	BOOL		(WINAPI *mImmGetOpenStatus)(HIMC);
-	BOOL		(WINAPI *mImmSetOpenStatus)(HIMC, BOOL);
-	BOOL		(WINAPI *mImmGetConversionStatus)(HIMC, LPDWORD, LPDWORD);
-	BOOL		(WINAPI *mImmSetConversionStatus)(HIMC, DWORD, DWORD);
-	BOOL		(WINAPI *mImmGetCompostitionWindow)(HIMC, LPCOMPOSITIONFORM);
-	BOOL		(WINAPI *mImmSetCompostitionWindow)(HIMC, LPCOMPOSITIONFORM);
-	LONG		(WINAPI *mImmGetCompositionString)(HIMC, DWORD, LPVOID, DWORD);
-	BOOL		(WINAPI *mImmSetCompositionString)(HIMC, DWORD, LPVOID, DWORD, LPVOID, DWORD);
-	BOOL		(WINAPI *mImmSetCompositionFont)(HIMC, LPLOGFONTW);
-	BOOL		(WINAPI *mImmSetCandidateWindow)(HIMC, LPCANDIDATEFORM);
-	BOOL		(WINAPI *mImmNotifyIME)(HIMC, DWORD, DWORD, DWORD);
-
-private:
-	HMODULE		mHImmDll;
-	static LLWinImm sTheInstance;
 };
 
-LLWinImm LLWinImm::sTheInstance;
-
-LLWinImm::LLWinImm() : mHImmDll(NULL)
-{
-	// Check system metrics 
-	if ( !GetSystemMetrics( SM_IMMENABLED ) )
-		return;
-
-	mHImmDll = LoadLibraryA("Imm32");
-	if (mHImmDll != NULL)
-	{
-		mImmIsIME               = (BOOL (WINAPI *)(HKL))                    GetProcAddress(mHImmDll, "ImmIsIME");
-		mImmGetDefaultIMEWnd	= (HWND (WINAPI *)(HWND))					GetProcAddress(mHImmDll, "ImmGetDefaultIMEWnd");
-		mImmGetContext          = (HIMC (WINAPI *)(HWND))                   GetProcAddress(mHImmDll, "ImmGetContext");
-		mImmReleaseContext      = (BOOL (WINAPI *)(HWND, HIMC))             GetProcAddress(mHImmDll, "ImmReleaseContext");
-		mImmGetOpenStatus       = (BOOL (WINAPI *)(HIMC))                   GetProcAddress(mHImmDll, "ImmGetOpenStatus");
-		mImmSetOpenStatus       = (BOOL (WINAPI *)(HIMC, BOOL))             GetProcAddress(mHImmDll, "ImmSetOpenStatus");
-		mImmGetConversionStatus = (BOOL (WINAPI *)(HIMC, LPDWORD, LPDWORD)) GetProcAddress(mHImmDll, "ImmGetConversionStatus");
-		mImmSetConversionStatus = (BOOL (WINAPI *)(HIMC, DWORD, DWORD))     GetProcAddress(mHImmDll, "ImmSetConversionStatus");
-		mImmGetCompostitionWindow = (BOOL (WINAPI *)(HIMC, LPCOMPOSITIONFORM))   GetProcAddress(mHImmDll, "ImmGetCompositionWindow");
-		mImmSetCompostitionWindow = (BOOL (WINAPI *)(HIMC, LPCOMPOSITIONFORM))   GetProcAddress(mHImmDll, "ImmSetCompositionWindow");
-		mImmGetCompositionString= (LONG (WINAPI *)(HIMC, DWORD, LPVOID, DWORD))					GetProcAddress(mHImmDll, "ImmGetCompositionStringW");
-		mImmSetCompositionString= (BOOL (WINAPI *)(HIMC, DWORD, LPVOID, DWORD, LPVOID, DWORD))	GetProcAddress(mHImmDll, "ImmSetCompositionStringW");
-		mImmSetCompositionFont  = (BOOL (WINAPI *)(HIMC, LPLOGFONTW))		GetProcAddress(mHImmDll, "ImmSetCompositionFontW");
-		mImmSetCandidateWindow  = (BOOL (WINAPI *)(HIMC, LPCANDIDATEFORM))  GetProcAddress(mHImmDll, "ImmSetCandidateWindow");
-		mImmNotifyIME			= (BOOL (WINAPI *)(HIMC, DWORD, DWORD, DWORD))	GetProcAddress(mHImmDll, "ImmNotifyIME");
-
-		if (mImmIsIME == NULL ||
-			mImmGetDefaultIMEWnd == NULL ||
-			mImmGetContext == NULL ||
-			mImmReleaseContext == NULL ||
-			mImmGetOpenStatus == NULL ||
-			mImmSetOpenStatus == NULL ||
-			mImmGetConversionStatus == NULL ||
-			mImmSetConversionStatus == NULL ||
-			mImmGetCompostitionWindow == NULL ||
-			mImmSetCompostitionWindow == NULL ||
-			mImmGetCompositionString == NULL ||
-			mImmSetCompositionString == NULL ||
-			mImmSetCompositionFont == NULL ||
-			mImmSetCandidateWindow == NULL ||
-			mImmNotifyIME == NULL)
-		{
-			// If any of the above API entires are not found, we can't use IMM API.  
-			// So, turn off the IMM support.  We should log some warning message in 
-			// the case, since it is very unusual; these APIs are available from 
-			// the beginning, and all versions of IMM32.DLL should have them all.  
-			// Unfortunately, this code may be executed before initialization of 
-			// the logging channel (LL_WARNS()), and we can't do it here...  Yes, this 
-			// is one of disadvantages to use static constraction to DLL loading. 
-			FreeLibrary(mHImmDll);
-			mHImmDll = NULL;
-
-			// If we unload the library, make sure all the function pointers are cleared
-			mImmIsIME = NULL;
-			mImmGetDefaultIMEWnd = NULL;
-			mImmGetContext = NULL;
-			mImmReleaseContext = NULL;
-			mImmGetOpenStatus = NULL;
-			mImmSetOpenStatus = NULL;
-			mImmGetConversionStatus = NULL;
-			mImmSetConversionStatus = NULL;
-			mImmGetCompostitionWindow = NULL;
-			mImmSetCompostitionWindow = NULL;
-			mImmGetCompositionString = NULL;
-			mImmSetCompositionString = NULL;
-			mImmSetCompositionFont = NULL;
-			mImmSetCandidateWindow = NULL;
-			mImmNotifyIME = NULL;
-		}
-	}
-}
-
-
 // static 
 BOOL	LLWinImm::isIME(HKL hkl)
 { 
-	if ( sTheInstance.mImmIsIME )
-		return sTheInstance.mImmIsIME(hkl); 
-	return FALSE;
+	return ImmIsIME(hkl);
 }
 
 // static 
 HIMC		LLWinImm::getContext(HWND hwnd)
 {
-	if ( sTheInstance.mImmGetContext )
-		return sTheInstance.mImmGetContext(hwnd); 
-	return 0;
+	return ImmGetContext(hwnd);
 }
 
 //static 
 BOOL		LLWinImm::releaseContext(HWND hwnd, HIMC himc)
 { 
-	if ( sTheInstance.mImmIsIME )
-		return sTheInstance.mImmReleaseContext(hwnd, himc); 
-	return FALSE;
+	return ImmReleaseContext(hwnd, himc);
 }
 
 // static 
 BOOL		LLWinImm::getOpenStatus(HIMC himc)
 { 
-	if ( sTheInstance.mImmGetOpenStatus )
-		return sTheInstance.mImmGetOpenStatus(himc); 
-	return FALSE;
+	return ImmGetOpenStatus(himc);
 }
 
 // static 
 BOOL		LLWinImm::setOpenStatus(HIMC himc, BOOL status)
 { 
-	if ( sTheInstance.mImmSetOpenStatus )
-		return sTheInstance.mImmSetOpenStatus(himc, status); 
-	return FALSE;
+	return ImmSetOpenStatus(himc, status);
 }
 
 // static 
 BOOL		LLWinImm::getConversionStatus(HIMC himc, LPDWORD conversion, LPDWORD sentence)	
 { 
-	if ( sTheInstance.mImmGetConversionStatus )
-		return sTheInstance.mImmGetConversionStatus(himc, conversion, sentence); 
-	return FALSE;
+	return ImmGetConversionStatus(himc, conversion, sentence);
 }
 
 // static 
 BOOL		LLWinImm::setConversionStatus(HIMC himc, DWORD conversion, DWORD sentence)		
 { 
-	if ( sTheInstance.mImmSetConversionStatus )
-		return sTheInstance.mImmSetConversionStatus(himc, conversion, sentence); 
-	return FALSE;
+	return ImmSetConversionStatus(himc, conversion, sentence);
 }
 
 // static 
 BOOL		LLWinImm::getCompositionWindow(HIMC himc, LPCOMPOSITIONFORM form)					
 { 
-	if ( sTheInstance.mImmGetCompostitionWindow )
-		return sTheInstance.mImmGetCompostitionWindow(himc, form);	
-	return FALSE;
+	return ImmGetCompositionWindow(himc, form);
 }
 
 // static 
 BOOL		LLWinImm::setCompositionWindow(HIMC himc, LPCOMPOSITIONFORM form)					
 { 
-	if ( sTheInstance.mImmSetCompostitionWindow )
-		return sTheInstance.mImmSetCompostitionWindow(himc, form);	
-	return FALSE;
+	return ImmSetCompositionWindow(himc, form);
 }
 
 
 // static 
 LONG		LLWinImm::getCompositionString(HIMC himc, DWORD index, LPVOID data, DWORD length)					
 { 
-	if ( sTheInstance.mImmGetCompositionString )
-		return sTheInstance.mImmGetCompositionString(himc, index, data, length);	
-	return FALSE;
+	return ImmGetCompositionString(himc, index, data, length);
 }
 
 
 // static 
 BOOL		LLWinImm::setCompositionString(HIMC himc, DWORD index, LPVOID pComp, DWORD compLength, LPVOID pRead, DWORD readLength)					
 { 
-	if ( sTheInstance.mImmSetCompositionString )
-		return sTheInstance.mImmSetCompositionString(himc, index, pComp, compLength, pRead, readLength);	
-	return FALSE;
+	return ImmSetCompositionString(himc, index, pComp, compLength, pRead, readLength);
 }
 
 // static 
 BOOL		LLWinImm::setCompositionFont(HIMC himc, LPLOGFONTW pFont)					
 { 
-	if ( sTheInstance.mImmSetCompositionFont )
-		return sTheInstance.mImmSetCompositionFont(himc, pFont);	
-	return FALSE;
+	return ImmSetCompositionFont(himc, pFont);
 }
 
 // static 
 BOOL		LLWinImm::setCandidateWindow(HIMC himc, LPCANDIDATEFORM form)					
 { 
-	if ( sTheInstance.mImmSetCandidateWindow )
-		return sTheInstance.mImmSetCandidateWindow(himc, form);	
-	return FALSE;
+	return ImmSetCandidateWindow(himc, form);
 }
 
 // static 
 BOOL		LLWinImm::notifyIME(HIMC himc, DWORD action, DWORD index, DWORD value)					
 { 
-	if ( sTheInstance.mImmNotifyIME )
-		return sTheInstance.mImmNotifyIME(himc, action, index, value);	
-	return FALSE;
+	return ImmNotifyIME(himc, action, index, value);
 }
 
 
 
-
-// ----------------------------------------------------------------------------------------
-LLWinImm::~LLWinImm()
-{
-	if (mHImmDll != NULL)
-	{
-		FreeLibrary(mHImmDll);
-		mHImmDll = NULL;
-	}
-}
-
-
 class LLMonitorInfo
 {
 public:
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 0144cff4b2..6d090be33a 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -1602,6 +1602,7 @@ if (WINDOWS)
         ${WINDOWS_LIBRARIES}
         comdlg32
         dxguid
+        imm32
         kernel32
         odbc32
         odbccp32
-- 
cgit v1.2.3


From 33f52ee51dad85802d124e987aa6ee9b7faf0cb2 Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Wed, 10 Nov 2021 17:48:55 +0200
Subject: SL-14403 Removed glod

---
 indra/cmake/CMakeLists.txt                         |   1 -
 indra/cmake/Copy3rdPartyLibs.cmake                 |   3 -
 indra/cmake/GLOD.cmake                             |   9 -
 indra/newview/CMakeLists.txt                       |   6 -
 indra/newview/licenses-win32.txt                   |  68 ----
 indra/newview/llfloatermodelpreview.cpp            |   6 +-
 indra/newview/llmodelpreview.cpp                   | 438 ---------------------
 indra/newview/llmodelpreview.h                     |  14 +-
 .../newview/skins/default/xui/en/floater_about.xml |   1 -
 .../skins/default/xui/en/floater_model_preview.xml |  64 ++-
 indra/newview/viewer_manifest.py                   |  10 -
 11 files changed, 26 insertions(+), 594 deletions(-)
 delete mode 100644 indra/cmake/GLOD.cmake

(limited to 'indra')

diff --git a/indra/cmake/CMakeLists.txt b/indra/cmake/CMakeLists.txt
index 9c497001c7..78d8652394 100644
--- a/indra/cmake/CMakeLists.txt
+++ b/indra/cmake/CMakeLists.txt
@@ -40,7 +40,6 @@ set(cmake_SOURCE_FILES
     FreeType.cmake
     GLEXT.cmake
     GLH.cmake
-    GLOD.cmake
 ##  GStreamer010Plugin.cmake
     GoogleMock.cmake
     Havok.cmake
diff --git a/indra/cmake/Copy3rdPartyLibs.cmake b/indra/cmake/Copy3rdPartyLibs.cmake
index b20d23cead..336896ed01 100644
--- a/indra/cmake/Copy3rdPartyLibs.cmake
+++ b/indra/cmake/Copy3rdPartyLibs.cmake
@@ -57,7 +57,6 @@ if(WINDOWS)
         libaprutil-1.dll
         libapriconv-1.dll
         nghttp2.dll
-        glod.dll
         libhunspell.dll
         uriparser.dll
         )
@@ -166,7 +165,6 @@ elseif(DARWIN)
         libaprutil-1.0.dylib
         libaprutil-1.dylib
         ${EXPAT_COPY}
-        libGLOD.dylib
         libhunspell-1.3.0.dylib
         libndofdev.dylib
         libnghttp2.dylib
@@ -215,7 +213,6 @@ elseif(LINUX)
         ${EXPAT_COPY}
         libfreetype.so.6.6.2
         libfreetype.so.6
-        libGLOD.so
         libgmodule-2.0.so
         libgobject-2.0.so
         libhunspell-1.3.so.0.0.0
diff --git a/indra/cmake/GLOD.cmake b/indra/cmake/GLOD.cmake
deleted file mode 100644
index a347eb6fee..0000000000
--- a/indra/cmake/GLOD.cmake
+++ /dev/null
@@ -1,9 +0,0 @@
-# -*- cmake -*-
-include(Prebuilt)
-
-if (NOT USESYSTEMLIBS)
-  use_prebuilt_binary(glod)
-endif (NOT USESYSTEMLIBS)
-
-set(GLOD_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include)
-set(GLOD_LIBRARIES GLOD)
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 4c237c5ef3..75935ff56a 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -16,7 +16,6 @@ include(DBusGlib)
 include(DragDrop)
 include(EXPAT)
 include(FMODSTUDIO)
-include(GLOD)
 include(Hunspell)
 include(JsonCpp)
 include(LLAppearance)
@@ -68,7 +67,6 @@ endif(FMODSTUDIO)
 include_directories(
     ${DBUSGLIB_INCLUDE_DIRS}
     ${JSONCPP_INCLUDE_DIR}
-    ${GLOD_INCLUDE_DIR}
     ${LLAUDIO_INCLUDE_DIRS}
     ${LLCHARACTER_INCLUDE_DIRS}
     ${LLCOMMON_INCLUDE_DIRS}
@@ -1815,9 +1813,6 @@ if (WINDOWS)
       ${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/libapr-1.dll
       ${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/libaprutil-1.dll
       ${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/libapriconv-1.dll
-      ${SHARED_LIB_STAGING_DIR}/Release/glod.dll
-      ${SHARED_LIB_STAGING_DIR}/RelWithDebInfo/glod.dll
-      ${SHARED_LIB_STAGING_DIR}/Debug/glod.dll
       ${SHARED_LIB_STAGING_DIR}/Release/libcollada14dom22.dll
       ${SHARED_LIB_STAGING_DIR}/RelWithDebInfo/libcollada14dom22.dll
       ${SHARED_LIB_STAGING_DIR}/Debug/libcollada14dom22-d.dll
@@ -2053,7 +2048,6 @@ target_link_libraries(${VIEWER_BINARY_NAME}
     ${DBUSGLIB_LIBRARIES}
     ${OPENGL_LIBRARIES}
     ${FMODWRAPPER_LIBRARY} # must come after LLAudio
-    ${GLOD_LIBRARIES}
     ${OPENGL_LIBRARIES}
     ${JSONCPP_LIBRARIES}
     ${SDL_LIBRARY}
diff --git a/indra/newview/licenses-win32.txt b/indra/newview/licenses-win32.txt
index 3e337851d7..749ca1c21d 100644
--- a/indra/newview/licenses-win32.txt
+++ b/indra/newview/licenses-win32.txt
@@ -770,74 +770,6 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-
-=============
-GLOD license
-=============
-The GLOD Open-Source License   Version 1.0                June 16, 2004
-
-Copyright (C) 2003-04 Jonathan Cohen, Nat Duca, Chris Niski, Johns 
-Hopkins University and David Luebke, Brenden Schubert, University of 
-Virginia. All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, is permitted provided that the following conditions are
-met:
-
-1. Redistributions of source code must retain the above copyright
-   notice, this list of conditions and the following disclaimer and
-   request.
-
-2. Redistributions in binary form must reproduce the above copyright
-   notice, this list of conditions and the following disclaimer and
-   request in the documentation and/or other materials provided with
-   the distribution.
-
-3. The name "GLOD" must not be used to endorse or promote products
-   derived from this software without prior written permission.
-
-4. Redistributions of any modified version of this source, whether in
-   source or binary form , must include a form of the following
-   acknowledgment: "This product is derived from the GLOD library,
-   which is available from http://www.cs.jhu.edu/~graphics/GLOD."
-
-5. Redistributions of any modified version of this source in binary
-   form must provide, free of charge, access to the modified version
-   of the code.
-
-6. This license shall be governed by and construed and enforced in
-   accordance with the laws of the State of Maryland, without
-   reference to its conflicts of law provisions. The exclusive
-   jurisdiction and venue for all legal actions relating to this
-   license shall be in courts of competent subject matter jurisdiction
-   located in the State of Maryland.
-
-TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, GLOD IS PROVIDED
-UNDER THIS LICENSE ON AN AS IS BASIS, WITHOUT WARRANTY OF ANY KIND,
-EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES
-THAT GLOD IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR
-PURPOSE OR NON-INFRINGING. ALL WARRANTIES ARE DISCLAIMED AND THE
-ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE CODE IS WITH
-YOU. SHOULD ANY CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT THE
-COPYRIGHT HOLDER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY
-NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY
-CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF ANY CODE IS
-AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER.
-
-TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, IN NO EVENT SHALL
-THE COPYRIGHT HOLDER OR ANY OTHER CONTRIBUTOR BE LIABLE FOR ANY
-SPECIAL, INCIDENTAL, INDIRECT, OR CONSEQUENTIAL DAMAGES FOR LOSS OF
-PROFITS, REVENUE, OR FOR LOSS OF INFORMATION OR ANY OTHER LOSS.
-
-YOU EXPRESSLY AGREE TO FOREVER INDEMNIFY, DEFEND AND HOLD HARMLESS THE
-COPYRIGHT HOLDERS AND CONTRIBUTORS OF GLOD AGAINST ALL CLAIMS,
-DEMANDS, SUITS OR OTHER ACTIONS ARISING DIRECTLY OR INDIRECTLY FROM
-YOUR ACCEPTANCE AND USE OF GLOD.
-
-Although NOT REQUIRED, we would appreciate it if active users of GLOD
-put a link on their web site to the GLOD web site when possible.
-
-
 =============
 meshoptimizer
 =============
diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp
index 6795ea8f53..de89d776df 100644
--- a/indra/newview/llfloatermodelpreview.cpp
+++ b/indra/newview/llfloatermodelpreview.cpp
@@ -726,9 +726,6 @@ void LLFloaterModelPreview::onLODParamCommit(S32 lod, bool enforce_tri_limit)
     S32 mode = lod_source_combo->getCurrentIndex();
     switch (mode)
     {
-    case LLModelPreview::GENERATE:
-        mModelPreview->onLODGenerateParamCommit(lod, enforce_tri_limit);
-        break;
     case LLModelPreview::MESH_OPTIMIZER_AUTO:
     case LLModelPreview::MESH_OPTIMIZER:
     case LLModelPreview::MESH_OPTIMIZER_SLOPPY:
@@ -1738,8 +1735,7 @@ void LLFloaterModelPreview::onLoDSourceCommit(S32 lod)
 
 	LLComboBox* lod_source_combo = getChild<LLComboBox>("lod_source_" + lod_name[lod]);
     S32 index = lod_source_combo->getCurrentIndex();
-	if (index == LLModelPreview::GENERATE
-        || index == LLModelPreview::MESH_OPTIMIZER_AUTO
+	if (index == LLModelPreview::MESH_OPTIMIZER_AUTO
         || index == LLModelPreview::MESH_OPTIMIZER
         || index == LLModelPreview::MESH_OPTIMIZER_SLOPPY
         || index == LLModelPreview::MESH_OPTIMIZER_COMBINE)
diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp
index 4f759446f1..d629358355 100644
--- a/indra/newview/llmodelpreview.cpp
+++ b/indra/newview/llmodelpreview.cpp
@@ -67,7 +67,6 @@
 #include "lltabcontainer.h"
 #include "lltextbox.h"
 
-#include "glod/glod.h"
 #include <boost/algorithm/string.hpp>
 
 bool LLModelPreview::sIgnoreLoadedCallback = false;
@@ -90,19 +89,6 @@ static const F32 PREVIEW_ZOOM_LIMIT(10.f);
 
 const F32 SKIN_WEIGHT_CAMERA_DISTANCE = 16.f;
 
-BOOL stop_gloderror()
-{
-    GLuint error = glodGetError();
-
-    if (error != GLOD_NO_ERROR)
-    {
-        LL_WARNS() << "GLOD error detected, cannot generate LOD: " << std::hex << error << LL_ENDL;
-        return TRUE;
-    }
-
-    return FALSE;
-}
-
 LLViewerFetchedTexture* bindMaterialDiffuseTexture(const LLImportMaterial& material)
 {
     LLViewerFetchedTexture *texture = LLViewerTextureManager::getFetchedTexture(material.getDiffuseMap(), FTT_DEFAULT, TRUE, LLGLTexture::BOOST_PREVIEW);
@@ -202,10 +188,6 @@ LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloater* fmp)
     mLoadState = LLModelLoader::STARTING;
     mGroup = 0;
     mLODFrozen = false;
-    mBuildShareTolerance = 0.f;
-    mBuildQueueMode = GLOD_QUEUE_GREEDY;
-    mBuildBorderMode = GLOD_BORDER_UNLOCK;
-    mBuildOperator = GLOD_OPERATOR_EDGE_COLLAPSE;
 
     for (U32 i = 0; i < LLModel::NUM_LODS; ++i)
     {
@@ -213,10 +195,6 @@ LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloater* fmp)
         mRequestedCreaseAngle[i] = -1.f;
         mRequestedLoDMode[i] = 0;
         mRequestedErrorThreshold[i] = 0.f;
-        mRequestedBuildOperator[i] = 0;
-        mRequestedQueueMode[i] = 0;
-        mRequestedBorderMode[i] = 0;
-        mRequestedShareTolerance[i] = 0.f;
     }
 
     mViewOption["show_textures"] = false;
@@ -226,23 +204,11 @@ LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloater* fmp)
     mHasPivot = false;
     mModelPivot = LLVector3(0.0f, 0.0f, 0.0f);
 
-    glodInit();
-
     createPreviewAvatar();
 }
 
 LLModelPreview::~LLModelPreview()
 {
-    // glod apparently has internal mem alignment issues that are angering
-    // the heap-check code in windows, these should be hunted down in that
-    // TP code, if possible
-    //
-    // kernel32.dll!HeapFree()  + 0x14 bytes	
-    // msvcr100.dll!free(void * pBlock)  Line 51	C
-    // glod.dll!glodGetGroupParameteriv()  + 0x119 bytes	
-    // glod.dll!glodShutdown()  + 0x77 bytes	
-    //
-    //glodShutdown();
     if (mModelLoader)
     {
         mModelLoader->shutdown();
@@ -828,11 +794,6 @@ void LLModelPreview::loadModel(std::string filename, S32 lod, bool force_disable
 
     mLODFile[lod] = filename;
 
-    if (lod == LLModel::LOD_HIGH)
-    {
-        clearGLODGroup();
-    }
-
     std::map<std::string, std::string> joint_alias_map;
     getJointAliases(joint_alias_map);
 
@@ -933,7 +894,6 @@ void LLModelPreview::clearIncompatible(S32 lod)
                 if (i == LLModel::LOD_HIGH)
                 {
                     mBaseModel = mModel[lod];
-                    clearGLODGroup();
                     mBaseScene = mScene[lod];
                     mVertexBuffer[5].clear();
                 }
@@ -942,23 +902,6 @@ void LLModelPreview::clearIncompatible(S32 lod)
     }
 }
 
-void LLModelPreview::clearGLODGroup()
-{
-    if (mGroup)
-    {
-        for (std::map<LLPointer<LLModel>, U32>::iterator iter = mObject.begin(); iter != mObject.end(); ++iter)
-        {
-            glodDeleteObject(iter->second);
-            stop_gloderror();
-        }
-        mObject.clear();
-
-        glodDeleteGroup(mGroup);
-        stop_gloderror();
-        mGroup = 0;
-    }
-}
-
 void LLModelPreview::loadModelCallback(S32 loaded_lod)
 {
     assert_main_thread();
@@ -1110,7 +1053,6 @@ void LLModelPreview::loadModelCallback(S32 loaded_lod)
             }
 
             mBaseModel = mModel[loaded_lod];
-            clearGLODGroup();
 
             mBaseScene = mScene[loaded_lod];
             mVertexBuffer[5].clear();
@@ -1341,373 +1283,6 @@ void LLModelPreview::restoreNormals()
     updateStatusMessages();
 }
 
-void LLModelPreview::genGlodLODs(S32 which_lod, U32 decimation, bool enforce_tri_limit)
-{
-    LL_INFOS() << "Generating lod " << which_lod << " using glod" << LL_ENDL;
-    // Allow LoD from -1 to LLModel::LOD_PHYSICS
-    if (which_lod < -1 || which_lod > LLModel::NUM_LODS - 1)
-    {
-        std::ostringstream out;
-        out << "Invalid level of detail: " << which_lod;
-        LL_WARNS() << out.str() << LL_ENDL;
-        LLFloaterModelPreview::addStringToLog(out, false);
-        assert(which_lod >= -1 && which_lod < LLModel::NUM_LODS);
-        return;
-    }
-
-    if (mBaseModel.empty())
-    {
-        return;
-    }
-
-    LLVertexBuffer::unbind();
-
-    bool no_ff = LLGLSLShader::sNoFixedFunction;
-    LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
-    LLGLSLShader::sNoFixedFunction = false;
-
-    if (shader)
-    {
-        shader->unbind();
-    }
-
-    stop_gloderror();
-    static U32 cur_name = 1;
-
-    S32 limit = -1;
-
-    U32 triangle_count = 0;
-
-    U32 instanced_triangle_count = 0;
-
-    //get the triangle count for the whole scene
-    for (LLModelLoader::scene::iterator iter = mBaseScene.begin(), endIter = mBaseScene.end(); iter != endIter; ++iter)
-    {
-        for (LLModelLoader::model_instance_list::iterator instance = iter->second.begin(), end_instance = iter->second.end(); instance != end_instance; ++instance)
-        {
-            LLModel* mdl = instance->mModel;
-            if (mdl)
-            {
-                instanced_triangle_count += mdl->getNumTriangles();
-            }
-        }
-    }
-
-    //get the triangle count for the non-instanced set of models
-    for (U32 i = 0; i < mBaseModel.size(); ++i)
-    {
-        triangle_count += mBaseModel[i]->getNumTriangles();
-    }
-
-    //get ratio of uninstanced triangles to instanced triangles
-    F32 triangle_ratio = (F32)triangle_count / (F32)instanced_triangle_count;
-
-    U32 base_triangle_count = triangle_count;
-
-    U32 type_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0;
-
-    U32 lod_mode = LIMIT_TRIANGLES;
-
-    F32 lod_error_threshold = 0;
-
-    // The LoD should be in range from Lowest to High
-    if (which_lod > -1 && which_lod < NUM_LOD)
-    {
-        LLCtrlSelectionInterface* iface = mFMP->childGetSelectionInterface("lod_mode_" + lod_name[which_lod]);
-        if (iface)
-        {
-            lod_mode = iface->getFirstSelectedIndex();
-        }
-
-        lod_error_threshold = mFMP->childGetValue("lod_error_threshold_" + lod_name[which_lod]).asReal();
-    }
-
-    if (which_lod != -1)
-    {
-        mRequestedLoDMode[which_lod] = lod_mode;
-    }
-
-    if (lod_mode == LIMIT_TRIANGLES)
-    {
-        lod_mode = GLOD_TRIANGLE_BUDGET;
-
-        // The LoD should be in range from Lowest to High
-        if (which_lod > -1 && which_lod < NUM_LOD)
-        {
-            limit = mFMP->childGetValue("lod_triangle_limit_" + lod_name[which_lod]).asInteger();
-            //convert from "scene wide" to "non-instanced" triangle limit
-            limit = (S32)((F32)limit*triangle_ratio);
-        }
-    }
-    else
-    {
-        lod_mode = GLOD_ERROR_THRESHOLD;
-    }
-
-    bool object_dirty = false;
-
-    if (mGroup == 0)
-    {
-        object_dirty = true;
-        mGroup = cur_name++;
-        glodNewGroup(mGroup);
-    }
-
-    if (object_dirty)
-    {
-        for (LLModelLoader::model_list::iterator iter = mBaseModel.begin(); iter != mBaseModel.end(); ++iter)
-        { //build GLOD objects for each model in base model list
-            LLModel* mdl = *iter;
-
-            if (mObject[mdl] != 0)
-            {
-                glodDeleteObject(mObject[mdl]);
-            }
-
-            mObject[mdl] = cur_name++;
-
-            glodNewObject(mObject[mdl], mGroup, GLOD_DISCRETE);
-            stop_gloderror();
-
-            if (iter == mBaseModel.begin() && !mdl->mSkinWeights.empty())
-            { //regenerate vertex buffer for skinned models to prevent animation feedback during LOD generation
-                mVertexBuffer[5].clear();
-            }
-
-            if (mVertexBuffer[5].empty())
-            {
-                genBuffers(5, false);
-            }
-
-            U32 tri_count = 0;
-            for (U32 i = 0; i < mVertexBuffer[5][mdl].size(); ++i)
-            {
-                LLVertexBuffer* buff = mVertexBuffer[5][mdl][i];
-                buff->setBuffer(type_mask & buff->getTypeMask());
-
-                U32 num_indices = mVertexBuffer[5][mdl][i]->getNumIndices();
-                if (num_indices > 2)
-                {
-                    glodInsertElements(mObject[mdl], i, GL_TRIANGLES, num_indices, GL_UNSIGNED_SHORT, (U8*)mVertexBuffer[5][mdl][i]->getIndicesPointer(), 0, 0.f);
-                }
-                tri_count += num_indices / 3;
-                stop_gloderror();
-            }
-
-            glodBuildObject(mObject[mdl]);
-            stop_gloderror();
-        }
-    }
-
-
-    S32 start = LLModel::LOD_HIGH;
-    S32 end = 0;
-
-    if (which_lod != -1)
-    {
-        start = end = which_lod;
-    }
-
-    mMaxTriangleLimit = base_triangle_count;
-    mMinTriangleLimit = mBaseModel.size();
-
-    for (S32 lod = start; lod >= end; --lod)
-    {
-        if (which_lod == -1)
-        {
-            if (lod < start)
-            {
-                triangle_count /= decimation;
-            }
-        }
-        else
-        {
-            if (enforce_tri_limit)
-            {
-                triangle_count = limit;
-            }
-            else
-            {
-                for (S32 j = LLModel::LOD_HIGH; j>which_lod; --j)
-                {
-                    triangle_count /= decimation;
-                }
-            }
-        }
-
-        mModel[lod].clear();
-        mModel[lod].resize(mBaseModel.size());
-        mVertexBuffer[lod].clear();
-
-        U32 actual_tris = 0;
-        U32 actual_verts = 0;
-        U32 submeshes = 0;
-
-        mRequestedTriangleCount[lod] = llmax(mMinTriangleLimit, (S32)((F32)triangle_count / triangle_ratio));
-        mRequestedErrorThreshold[lod] = lod_error_threshold;
-
-        glodGroupParameteri(mGroup, GLOD_ADAPT_MODE, lod_mode);
-        stop_gloderror();
-
-        glodGroupParameteri(mGroup, GLOD_ERROR_MODE, GLOD_OBJECT_SPACE_ERROR);
-        stop_gloderror();
-
-        glodGroupParameterf(mGroup, GLOD_OBJECT_SPACE_ERROR_THRESHOLD, lod_error_threshold);
-        stop_gloderror();
-
-        if (lod_mode != GLOD_TRIANGLE_BUDGET)
-        {
-            glodGroupParameteri(mGroup, GLOD_MAX_TRIANGLES, 0);
-        }
-        else
-        {
-            //SH-632: always add 1 to desired amount to avoid decimating below desired amount
-            glodGroupParameteri(mGroup, GLOD_MAX_TRIANGLES, triangle_count + 1);
-        }
-
-        stop_gloderror();
-        glodAdaptGroup(mGroup);
-        stop_gloderror();
-
-        for (U32 mdl_idx = 0; mdl_idx < mBaseModel.size(); ++mdl_idx)
-        {
-            LLModel* base = mBaseModel[mdl_idx];
-
-            GLint patch_count = 0;
-            glodGetObjectParameteriv(mObject[base], GLOD_NUM_PATCHES, &patch_count);
-            stop_gloderror();
-
-            LLVolumeParams volume_params;
-            volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE);
-            mModel[lod][mdl_idx] = new LLModel(volume_params, 0.f);
-
-            std::string name = base->mLabel + getLodSuffix(lod);
-
-            mModel[lod][mdl_idx]->mLabel = name;
-            mModel[lod][mdl_idx]->mSubmodelID = base->mSubmodelID;
-
-            GLint* sizes = new GLint[patch_count * 2];
-            glodGetObjectParameteriv(mObject[base], GLOD_PATCH_SIZES, sizes);
-            stop_gloderror();
-
-            GLint* names = new GLint[patch_count];
-            glodGetObjectParameteriv(mObject[base], GLOD_PATCH_NAMES, names);
-            stop_gloderror();
-
-            mModel[lod][mdl_idx]->setNumVolumeFaces(patch_count);
-
-            LLModel* target_model = mModel[lod][mdl_idx];
-
-            for (GLint i = 0; i < patch_count; ++i)
-            {
-                type_mask = mVertexBuffer[5][base][i]->getTypeMask();
-
-                LLPointer<LLVertexBuffer> buff = new LLVertexBuffer(type_mask, 0);
-
-                if (sizes[i * 2 + 1] > 0 && sizes[i * 2] > 0)
-                {
-                    if (!buff->allocateBuffer(sizes[i * 2 + 1], sizes[i * 2], true))
-                    {
-                        // Todo: find a way to stop preview in this case instead of crashing
-                        LL_ERRS() << "Failed buffer allocation during preview LOD generation."
-                            << " Vertices: " << sizes[i * 2 + 1]
-                            << " Indices: " << sizes[i * 2] << LL_ENDL;
-                    }
-                    buff->setBuffer(type_mask);
-                    glodFillElements(mObject[base], names[i], GL_UNSIGNED_SHORT, (U8*)buff->getIndicesPointer());
-                    stop_gloderror();
-                }
-                else
-                {
-                    // This face was eliminated or we failed to allocate buffer,
-                    // attempt to create a dummy triangle (one vertex, 3 indices, all 0)
-                    buff->allocateBuffer(1, 3, true);
-                    memset((U8*)buff->getMappedData(), 0, buff->getSize());
-                    memset((U8*)buff->getIndicesPointer(), 0, buff->getIndicesSize());
-                }
-
-                buff->validateRange(0, buff->getNumVerts() - 1, buff->getNumIndices(), 0);
-
-                LLStrider<LLVector3> pos;
-                LLStrider<LLVector3> norm;
-                LLStrider<LLVector2> tc;
-                LLStrider<U16> index;
-
-                buff->getVertexStrider(pos);
-                if (type_mask & LLVertexBuffer::MAP_NORMAL)
-                {
-                    buff->getNormalStrider(norm);
-                }
-                if (type_mask & LLVertexBuffer::MAP_TEXCOORD0)
-                {
-                    buff->getTexCoord0Strider(tc);
-                }
-
-                buff->getIndexStrider(index);
-
-                target_model->setVolumeFaceData(names[i], pos, norm, tc, index, buff->getNumVerts(), buff->getNumIndices());
-                actual_tris += buff->getNumIndices() / 3;
-                actual_verts += buff->getNumVerts();
-                ++submeshes;
-
-                if (!validate_face(target_model->getVolumeFace(names[i])))
-                {
-                    LL_ERRS() << "Invalid face generated during LOD generation." << LL_ENDL;
-                }
-            }
-
-            //blind copy skin weights and just take closest skin weight to point on
-            //decimated mesh for now (auto-generating LODs with skin weights is still a bit
-            //of an open problem).
-            target_model->mPosition = base->mPosition;
-            target_model->mSkinWeights = base->mSkinWeights;
-            target_model->mSkinInfo = base->mSkinInfo;
-            //copy material list
-            target_model->mMaterialList = base->mMaterialList;
-
-            if (!validate_model(target_model))
-            {
-                LL_ERRS() << "Invalid model generated when creating LODs" << LL_ENDL;
-            }
-
-            delete[] sizes;
-            delete[] names;
-        }
-
-        //rebuild scene based on mBaseScene
-        mScene[lod].clear();
-        mScene[lod] = mBaseScene;
-
-        for (U32 i = 0; i < mBaseModel.size(); ++i)
-        {
-            LLModel* mdl = mBaseModel[i];
-            LLModel* target = mModel[lod][i];
-            if (target)
-            {
-                for (LLModelLoader::scene::iterator iter = mScene[lod].begin(); iter != mScene[lod].end(); ++iter)
-                {
-                    for (U32 j = 0; j < iter->second.size(); ++j)
-                    {
-                        if (iter->second[j].mModel == mdl)
-                        {
-                            iter->second[j].mModel = target;
-                        }
-                    }
-                }
-            }
-        }
-    }
-
-    mResourceCost = calcResourceCost();
-
-    LLVertexBuffer::unbind();
-    LLGLSLShader::sNoFixedFunction = no_ff;
-    if (shader)
-    {
-        shader->bind();
-    }
-}
-
 // Runs per object, but likely it is a better way to run per model+submodels
 // returns a ratio of base model indices to resulting indices
 // returns -1 in case of failure
@@ -2104,9 +1679,6 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d
     mMaxTriangleLimit = base_triangle_count;
     mMinTriangleLimit = mBaseModel.size();
 
-    // TODO: Glod regenerates vertex buffer at this stage
-    // check why, it might be needed to regenerate buffer as well
-
     // Build models
 
     S32 start = LLModel::LOD_HIGH;
@@ -3573,7 +3145,6 @@ BOOL LLModelPreview::render()
     {
         genBuffers(-1, skin_weight);
         //genBuffers(3);
-        //genGlodLODs();
     }
 
     if (!mModel[mPreviewLOD].empty())
@@ -4175,15 +3746,6 @@ bool LLModelPreview::lodQueryCallback()
     return true;
 }
 
-void LLModelPreview::onLODGenerateParamCommit(S32 lod, bool enforce_tri_limit)
-{
-    if (!mLODFrozen)
-    {
-        genGlodLODs(lod, 3, enforce_tri_limit);
-        refresh();
-    }
-}
-
 void LLModelPreview::onLODMeshOptimizerParamCommit(S32 requested_lod, bool enforce_tri_limit, S32 mode)
 {
     if (!mLODFrozen)
diff --git a/indra/newview/llmodelpreview.h b/indra/newview/llmodelpreview.h
index 49032f0dbf..7d4507ccf2 100644
--- a/indra/newview/llmodelpreview.h
+++ b/indra/newview/llmodelpreview.h
@@ -124,7 +124,6 @@ public:
     typedef enum
     {
         LOD_FROM_FILE = 0,
-        GENERATE,
         MESH_OPTIMIZER_AUTO, // automatically selects method based on model or face
         MESH_OPTIMIZER_COMBINE,
         MESH_OPTIMIZER,
@@ -165,7 +164,6 @@ public:
     void loadModelCallback(S32 lod);
     bool lodsReady() { return !mGenLOD && mLodsQuery.empty(); }
     void queryLODs() { mGenLOD = true; };
-    void genGlodLODs(S32 which_lod = -1, U32 decimation = 3, bool enforce_tri_limit = false);
     void genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 decimation = 3, bool enforce_tri_limit = false);
     void generateNormals();
     void restoreNormals();
@@ -176,8 +174,6 @@ public:
     void clearIncompatible(S32 lod);
     void updateStatusMessages();
     void updateLodControls(S32 lod);
-    void clearGLODGroup();
-    void onLODGenerateParamCommit(S32 lod, bool enforce_tri_limit);
     void onLODMeshOptimizerParamCommit(S32 lod, bool enforce_tri_limit, S32 mode);
     void addEmptyFace(LLModel* pTarget);
 
@@ -265,19 +261,11 @@ protected:
 
     std::map<std::string, bool> mViewOption;
 
-    //GLOD object parameters (must rebuild object if these change)
+    // Model generation parameters (must rebuild object if these change)
     bool mLODFrozen;
-    F32 mBuildShareTolerance;
-    U32 mBuildQueueMode;
-    U32 mBuildOperator;
-    U32 mBuildBorderMode;
     U32 mRequestedLoDMode[LLModel::NUM_LODS];
     S32 mRequestedTriangleCount[LLModel::NUM_LODS];
     F32 mRequestedErrorThreshold[LLModel::NUM_LODS];
-    U32 mRequestedBuildOperator[LLModel::NUM_LODS];
-    U32 mRequestedQueueMode[LLModel::NUM_LODS];
-    U32 mRequestedBorderMode[LLModel::NUM_LODS];
-    F32 mRequestedShareTolerance[LLModel::NUM_LODS];
     F32 mRequestedCreaseAngle[LLModel::NUM_LODS];
 
     LLModelLoader* mModelLoader;
diff --git a/indra/newview/skins/default/xui/en/floater_about.xml b/indra/newview/skins/default/xui/en/floater_about.xml
index 71f4d81195..bde7aec672 100644
--- a/indra/newview/skins/default/xui/en/floater_about.xml
+++ b/indra/newview/skins/default/xui/en/floater_about.xml
@@ -101,7 +101,6 @@ Dummy Name replaced at run time
         expat Copyright (C) 1998, 1999, 2000 Thai Open Source Software Center Ltd.
         FreeType Copyright (C) 1996-2002, 2006 David Turner, Robert Wilhelm, and Werner Lemberg.
         GL Copyright (C) 1999-2004 Brian Paul.
-        GLOD Copyright (C) 2003-04 Jonathan Cohen, Nat Duca, Chris Niski, Johns Hopkins University and David Luebke, Brenden Schubert, University of Virginia.
         google-perftools Copyright (c) 2005, Google Inc.
         Havok.com(TM) Copyright (C) 1999-2001, Telekinesys Research Limited.
         jpeg2000 Copyright (C) 2001, David Taubman, The University of New South Wales (UNSW)
diff --git a/indra/newview/skins/default/xui/en/floater_model_preview.xml b/indra/newview/skins/default/xui/en/floater_model_preview.xml
index 05990e28d8..d08bc92e5d 100644
--- a/indra/newview/skins/default/xui/en/floater_model_preview.xml
+++ b/indra/newview/skins/default/xui/en/floater_model_preview.xml
@@ -187,24 +187,20 @@
                  label="Load from file"
                  value="Load from file" />
                 <item
-                 name="Generate"
-                 label="Generate"
-                 value="Generate" />
-                <item
-                 name="MeshOpt"
-                 label="Simplify (auto)"
-                 value="MeshOpt" />
+                 name="MeshOpt Auto"
+                 label="Generate Auto"
+                 value="MeshOpt Auto" />
                 <item
                  name="MeshOptCombine"
-                 label="Simplify per object"
+                 label="Generate Precise"
                  value="MeshOptCombine" />
                 <item
                  name="MeshOpt"
-                 label="Simplify per face"
+                 label="Generate per face"
                  value="MeshOpt" />
                 <item
                  name="MeshOptSloppy"
-                 label="Simplify sloppy"
+                 label="Generate Sloppy"
                  value="MeshOptSloppy" />
             </combo_box>
             <line_editor
@@ -332,24 +328,20 @@
                  label="Load from file"
                  value="Load from file" />
                 <item
-                 name="Generate"
-                 label="Generate"
-                 value="Generate" />
-                <item
-                 name="MeshOpt"
-                 label="Simplify (auto)"
-                 value="MeshOpt" />
+                 name="MeshOpt Auto"
+                 label="Generate Auto"
+                 value="MeshOpt Auto" />
                 <item
                  name="MeshOptCombine"
-                 label="Simplify per object"
+                 label="Generate Precise"
                  value="MeshOptCombine" />
                 <item
                  name="MeshOpt"
-                 label="Simplify per face"
+                 label="Generate per face"
                  value="MeshOpt" />
                 <item
                  name="MeshOptSloppy"
-                 label="Simplify sloppy"
+                 label="Generate Sloppy"
                  value="MeshOptSloppy" />
                 <item
                  name="Use LoD above"
@@ -481,24 +473,20 @@
                  label="Load from file"
                  value="Load from file" />
                 <item
-                 name="Generate"
-                 label="Generate"
-                 value="Generate" />
-                <item
-                 name="MeshOpt"
-                 label="Simplify (auto)"
-                 value="MeshOpt" />
+                 name="MeshOpt Auto"
+                 label="Generate Auto"
+                 value="MeshOpt Auto" />
                 <item
                  name="MeshOptCombine"
-                 label="Simplify per object"
+                 label="Generate Precise"
                  value="MeshOptCombine" />
                 <item
                  name="MeshOpt"
-                 label="Simplify per face"
+                 label="Generate per face"
                  value="MeshOpt" />
                 <item
                  name="MeshOptSloppy"
-                 label="Simplify sloppy"
+                 label="Generate Sloppy"
                  value="MeshOptSloppy" />
                 <item
                  name="Use LoD above"
@@ -630,24 +618,20 @@
                  label="Load from file"
                  value="Load from file" />
                 <item
-                 name="Generate"
-                 label="Generate"
-                 value="Generate" />
-                <item
-                 name="MeshOpt"
-                 label="Simplify (auto)"
-                 value="MeshOpt" />
+                 name="MeshOpt Auto"
+                 label="Generate Auto"
+                 value="MeshOpt Auto" />
                 <item
                  name="MeshOptCombine"
-                 label="Simplify per object"
+                 label="Generate Precise"
                  value="MeshOptCombine" />
                 <item
                  name="MeshOpt"
-                 label="Simplify per face"
+                 label="Generate per face"
                  value="MeshOpt" />
                 <item
                  name="MeshOptSloppy"
-                 label="Simplify sloppy"
+                 label="Generate Sloppy"
                  value="MeshOptSloppy" />
                 <item
                  name="Use LoD above"
diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py
index b932f43141..f1c4975cb1 100755
--- a/indra/newview/viewer_manifest.py
+++ b/indra/newview/viewer_manifest.py
@@ -510,14 +510,6 @@ class WindowsManifest(ViewerManifest):
         # Get shared libs from the shared libs staging directory
         with self.prefix(src=os.path.join(self.args['build'], os.pardir,
                                           'sharedlibs', self.args['configuration'])):
-
-            # Mesh 3rd party libs needed for auto LOD and collada reading
-            try:
-                self.path("glod.dll")
-            except RuntimeError as err:
-                print err.message
-                print "Skipping GLOD library (assumming linked statically)"
-
             # Get fmodstudio dll if needed
             if self.args['fmodstudio'] == 'ON':
                 if(self.args['configuration'].lower() == 'debug'):
@@ -1029,7 +1021,6 @@ class DarwinManifest(ViewerManifest):
                                 "libapr-1.0.dylib",
                                 "libaprutil-1.0.dylib",
                                 "libexpat.1.dylib",
-                                "libGLOD.dylib",
                                 # libnghttp2.dylib is a symlink to
                                 # libnghttp2.major.dylib, which is a symlink to
                                 # libnghttp2.version.dylib. Get all of them.
@@ -1473,7 +1464,6 @@ class Linux_i686_Manifest(LinuxManifest):
             self.path("libaprutil-1.so.0.4.1")
             self.path("libdb*.so")
             self.path("libexpat.so.*")
-            self.path("libGLOD.so")
             self.path("libuuid.so*")
             self.path("libSDL-1.2.so.*")
             self.path("libdirectfb-1.*.so.*")
-- 
cgit v1.2.3


From 27c1f52e6e484c778448d026600bdbcad7d19fb9 Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Wed, 10 Nov 2021 18:00:49 +0200
Subject: SL-15521 Fix debian license file not mentioning meshoptimizer

Just in case
---
 indra/newview/skins/default/xui/en/floater_about.xml | 1 +
 1 file changed, 1 insertion(+)

(limited to 'indra')

diff --git a/indra/newview/skins/default/xui/en/floater_about.xml b/indra/newview/skins/default/xui/en/floater_about.xml
index bde7aec672..eb07425dfe 100644
--- a/indra/newview/skins/default/xui/en/floater_about.xml
+++ b/indra/newview/skins/default/xui/en/floater_about.xml
@@ -105,6 +105,7 @@ Dummy Name replaced at run time
         Havok.com(TM) Copyright (C) 1999-2001, Telekinesys Research Limited.
         jpeg2000 Copyright (C) 2001, David Taubman, The University of New South Wales (UNSW)
         jpeglib Copyright (C) 1991-1998, Thomas G. Lane.
+        meshoptimizer Copyright (c) 2016-2021 Arseny Kapoulkine
         ogg/vorbis Copyright (C) 2002, Xiphophorus
         OpenSSL Copyright (C) 1998-2008 The OpenSSL Project.
         PCRE Copyright (c) 1997-2012 University of Cambridge
-- 
cgit v1.2.3


From 69a39dce0b6e96e03414928a3db8189cc5aece7e Mon Sep 17 00:00:00 2001
From: Nat Goodspeed <nat@lindenlab.com>
Date: Wed, 10 Nov 2021 11:11:04 -0500
Subject: SL-16094: Only link IMM32.LIB for llurlentry tests on Windows.

---
 indra/llui/CMakeLists.txt | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

(limited to 'indra')

diff --git a/indra/llui/CMakeLists.txt b/indra/llui/CMakeLists.txt
index 25ceb68b19..55c1655d7b 100644
--- a/indra/llui/CMakeLists.txt
+++ b/indra/llui/CMakeLists.txt
@@ -308,6 +308,10 @@ if(LL_TESTS)
       ${BOOST_FIBER_LIBRARY} ${BOOST_CONTEXT_LIBRARY} ${BOOST_SYSTEM_LIBRARY}
       ${WINDOWS_LIBRARIES})
   if(NOT LINUX)
-    LL_ADD_INTEGRATION_TEST(llurlentry llurlentry.cpp "imm32;${test_libs}")
+    if(WINDOWS)
+      LL_ADD_INTEGRATION_TEST(llurlentry llurlentry.cpp "imm32;${test_libs}")
+    else(WINDOWS)
+      LL_ADD_INTEGRATION_TEST(llurlentry llurlentry.cpp "${test_libs}")
+    endif(WINDOWS)
   endif(NOT LINUX)
 endif(LL_TESTS)
-- 
cgit v1.2.3


From d3b8f823fa48a6f7d15d569b9e554e25c97075f6 Mon Sep 17 00:00:00 2001
From: Mnikolenko Productengine <mnikolenko@productengine.com>
Date: Wed, 10 Nov 2021 18:44:00 +0200
Subject: SL-16330 mac build fix

---
 indra/newview/llviewercontrol.cpp | 2 ++
 1 file changed, 2 insertions(+)

(limited to 'indra')

diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp
index 3e7459ee8a..0e64d7152a 100644
--- a/indra/newview/llviewercontrol.cpp
+++ b/indra/newview/llviewercontrol.cpp
@@ -243,7 +243,9 @@ static bool handleAnisotropicChanged(const LLSD& newvalue)
 
 static bool handleVSyncChanged(const LLSD& newvalue)
 {
+#if LL_WINDOWS
     gViewerWindow->getWindow()->toggleVSync(newvalue.asBoolean());
+#endif
     return true;
 }
 
-- 
cgit v1.2.3


From 75110629de7786d667ea7c90b025f97c22650316 Mon Sep 17 00:00:00 2001
From: Nat Goodspeed <nat@lindenlab.com>
Date: Thu, 11 Nov 2021 10:23:16 -0500
Subject: SL-16094: Stylish braces!

---
 indra/llcommon/llsingleton.h | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

(limited to 'indra')

diff --git a/indra/llcommon/llsingleton.h b/indra/llcommon/llsingleton.h
index fdd5bdfea9..6042c0906c 100644
--- a/indra/llcommon/llsingleton.h
+++ b/indra/llcommon/llsingleton.h
@@ -858,7 +858,8 @@ public:
     static inline T& instance() { return *getInstance(); }
     static inline bool instanceExists() { return sInstance != nullptr; }
 
-    static void deleteSingleton() {
+    static void deleteSingleton()
+    {
         delete sInstance;
         sInstance = nullptr;
     }
-- 
cgit v1.2.3


From 28cefb3a37f8b6a626b963c8264bc24fdb47c096 Mon Sep 17 00:00:00 2001
From: "Brad Payne (Vir Linden)" <vir@lindenlab.com>
Date: Thu, 11 Nov 2021 23:33:41 +0000
Subject: SL-16355 - spammy message removed

---
 indra/newview/llviewerstats.cpp | 1 -
 1 file changed, 1 deletion(-)

(limited to 'indra')

diff --git a/indra/newview/llviewerstats.cpp b/indra/newview/llviewerstats.cpp
index ac8a657fb2..1fda2fb20e 100644
--- a/indra/newview/llviewerstats.cpp
+++ b/indra/newview/llviewerstats.cpp
@@ -266,7 +266,6 @@ void LLViewerStats::updateFrameStats(const F64Seconds time_diff)
 
 		// old stats that were never really used
 		F64Seconds jit = (F64Seconds) std::fabs((mLastTimeDiff - time_diff));
-		LL_INFOS() << "times " << mLastTimeDiff << ", " << time_diff << " jit " << jit << LL_ENDL;
 		sample(LLStatViewer::FRAMETIME_JITTER, jit);
 			
 		F32Seconds average_frametime = gRenderStartTime.getElapsedTimeF32() / (F32)gFrameCount;
-- 
cgit v1.2.3


From 5534781acf4a656478c27d5b94991e98bd876413 Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Tue, 1 Jun 2021 20:13:13 +0300
Subject: SL-15333 Crash in glh_init_extensions

---
 indra/llrender/llgl.cpp            |    2 +-
 indra/llwindow/GL/glh_extensions.h |  211 -----
 indra/llwindow/GL/glh_genext.h     | 1674 ------------------------------------
 3 files changed, 1 insertion(+), 1886 deletions(-)
 delete mode 100644 indra/llwindow/GL/glh_extensions.h
 delete mode 100644 indra/llwindow/GL/glh_genext.h

(limited to 'indra')

diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp
index 4f9aa5f979..c7f85aec21 100644
--- a/indra/llrender/llgl.cpp
+++ b/indra/llrender/llgl.cpp
@@ -557,7 +557,7 @@ bool LLGLManager::initGL()
 		glGetIntegerv(GL_NUM_EXTENSIONS, &count);
 		for (GLint i = 0; i < count; ++i)
 		{
-			std::string ext((const char*) glGetStringi(GL_EXTENSIONS, i));
+			std::string ext = ll_safe_string((const char*) glGetStringi(GL_EXTENSIONS, i));
 			str << ext << " ";
 			LL_DEBUGS("GLExtensions") << ext << LL_ENDL;
 		}
diff --git a/indra/llwindow/GL/glh_extensions.h b/indra/llwindow/GL/glh_extensions.h
deleted file mode 100644
index 554cb1731f..0000000000
--- a/indra/llwindow/GL/glh_extensions.h
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
- *  glh_extensions.h
- * $LicenseInfo:firstyear=2006&license=mit$ (mit used here to satisfy validity checker)
- * Copyright (C) 2006, NVIDIA
- *  From nVidia Corporation, downloaded 2006-12-18 from:
- *  http://developer.nvidia.com/attach/8196
- *  ("NVParse Library with Source (.zip) (2390 KB)")
- *
- *  License (quoted from license_info.txt in aforementioned file):
- *  "The files bison.exe, bison.simple, and flex.exe are covered by
- *  the GPL.  All other files in this distribution can be used however
- *  you want."
- * $/LicenseInfo$
-
- */
-
-#ifndef GLH_EXTENSIONS
-#define GLH_EXTENSIONS
-
-#include <string.h>
-#include <stdio.h>
-
-#ifdef _WIN32
-# include <windows.h>
-#endif
-
-#ifndef __APPLE__
-#include <GL/gl.h>
-#endif
-
-#ifdef _WIN32
-# include "GL/wglext.h"
-#endif
-
-#define CHECK_MEMORY(ptr) \
-    if (NULL == ptr) { \
-		printf("Error allocating memory in file %s, line %d\n", __FILE__, __LINE__); \
-		exit(-1); \
-	}
-
-#ifdef GLH_EXT_SINGLE_FILE
-#  define GLH_EXTENSIONS_SINGLE_FILE  // have to do this because glh_genext.h unsets GLH_EXT_SINGLE_FILE
-#endif
-
-#include "glh_genext.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifdef GLH_EXTENSIONS_SINGLE_FILE
-
-class GLHExts
-{
-public:
-	GLHExts()
-	{
-		mSysExts = NULL;
-//		mUnsupportedExts = NULL;
-	}
-	~GLHExts()
-	{
-		if (mSysExts)
-		{
-			free(mSysExts);
-		}
-//		if (mUnsupportedExts)
-//		{
-//			free(mUnsupportedExts);
-//		}
-	}
-	char *mSysExts;
-//	char *mUnsupportedExts;
-};
-
-GLHExts gGLHExts;
-
-static int ExtensionExists(const char* extName, const char* sysExts)
-{
-    char *padExtName = (char*)malloc(strlen(extName) + 2);
-    strcat(strcpy(padExtName, extName), " ");
-
-	if (0 == strcmp(extName, "GL_VERSION_1_2")) {
-		const char *version = (const char*)glGetString(GL_VERSION);
-		if (strstr(version, "1.0") == version || strstr(version, "1.1") == version) {
-			return FALSE;
-		} else {
-			return TRUE;
-		}
-	}
-    if (strstr(sysExts, padExtName)) {
-		free(padExtName);
-        return TRUE;
-    } else {
-		free(padExtName);
-        return FALSE;
-    }
-}
-
-static const char* EatWhiteSpace(const char *str)
-{
-	for (; *str && (' ' == *str || '\t' == *str || '\n' == *str); str++);
-	return str;
-}
-
-static const char* EatNonWhiteSpace(const char *str)
-{
-	for (; *str && (' ' != *str && '\t' != *str && '\n' != *str); str++);
-	return str;
-}
-
-
-int glh_init_extensions(const char *origReqExts)
-{
-	// Length of requested extensions string
-	//unsigned reqExtsLen;
-	char *reqExts;
-	// Ptr for individual extensions within reqExts
-	char *reqExt;
-	int success = TRUE;
-
-	// build space-padded extension string
-	if (NULL == gGLHExts.mSysExts) {
-		const char *extensions = (const char*)glGetString(GL_EXTENSIONS);
-		int sysExtsLen = (int)strlen(extensions);
-		const char *winsys_extensions = 0;		
-		int winsysExtsLen = 0;
-#ifdef _WIN32
-		{
-			PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetExtensionsStringARB = 0;
-			wglGetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC)wglGetProcAddress("wglGetExtensionsStringARB");
-			if(wglGetExtensionsStringARB)
-			{
-				winsys_extensions = wglGetExtensionsStringARB(wglGetCurrentDC());
-				winsysExtsLen = (S32)strlen(winsys_extensions);
-			}
-		}
-#endif
-		// Add 2 bytes, one for padding space, one for terminating NULL
-		gGLHExts.mSysExts = (char*)malloc(sysExtsLen + winsysExtsLen + 3);
-		CHECK_MEMORY(gGLHExts.mSysExts);
-		strcpy(gGLHExts.mSysExts, extensions);
-		gGLHExts.mSysExts[sysExtsLen] = ' ';
-		gGLHExts.mSysExts[sysExtsLen + 1] = 0;
-		if (winsysExtsLen)
-		{
-			strcat(gGLHExts.mSysExts, winsys_extensions);
-		}
-		gGLHExts.mSysExts[sysExtsLen + 1 + winsysExtsLen] = ' ';
-		gGLHExts.mSysExts[sysExtsLen + 1 + winsysExtsLen + 1] = 0;
-	}
-
-	if (NULL == origReqExts)
-	{
-		return TRUE;
-	}
-	reqExts = strdup(origReqExts);
-	/*
-	reqExtsLen = (S32)strlen(reqExts);
-	if (NULL == gGLHExts.mUnsupportedExts)
-	{
-		gGLHExts.mUnsupportedExts = (char*)malloc(reqExtsLen + 1);
-	}
-	else if (reqExtsLen > strlen(gGLHExts.mUnsupportedExts))
-	{
-		gGLHExts.mUnsupportedExts = (char*)realloc(gGLHExts.mUnsupportedExts, reqExtsLen + 1);
-	}
-	CHECK_MEMORY(gGLHExts.mUnsupportedExts);
-	*gGLHExts.mUnsupportedExts = 0;
-	*/
-
-	// Parse requested extension list
-	for (reqExt = reqExts;
-		(reqExt = (char*)EatWhiteSpace(reqExt)) && *reqExt;
-		reqExt = (char*)EatNonWhiteSpace(reqExt))
-	{
-		char *extEnd = (char*)EatNonWhiteSpace(reqExt);
-		char saveChar = *extEnd;
-		*extEnd = (char)0;
-		
-		if (!ExtensionExists(reqExt, gGLHExts.mSysExts) ||
-			!glh_init_extension(reqExt)) {
-			/*
-			// add reqExt to end of unsupportedExts
-			strcat(gGLHExts.mUnsupportedExts, reqExt);
-			strcat(gGLHExts.mUnsupportedExts, " ");
-			*/
-			success = FALSE;
-		}
-		*extEnd = saveChar;
-	}
-	free(reqExts);
-	return success;
-}
-
-const char* glh_get_unsupported_extensions()
-{
-	return "";
-//	return (const char*)gGLHExts.mUnsupportedExts;
-}
-
-#else
-int glh_init_extensions(const char *origReqExts);
-const char* glh_get_unsupported_extensions();
-#endif /* GLH_EXT_SINGLE_FILE */
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* GLH_EXTENSIONS */
diff --git a/indra/llwindow/GL/glh_genext.h b/indra/llwindow/GL/glh_genext.h
deleted file mode 100644
index cd5d1604a8..0000000000
--- a/indra/llwindow/GL/glh_genext.h
+++ /dev/null
@@ -1,1674 +0,0 @@
-/*
- *  glh_genext.h
- * $LicenseInfo:firstyear=2008&license=mit$ (mit used here to satisfy validity checker)
- * Copyright (C) 2008, NVIDIA
- *  From nVidia Corporation, downloaded 2006-12-18 from:
- *  http://developer.nvidia.com/attach/8196
- *  ("NVParse Library with Source (.zip) (2390 KB)")
- *
- *  License (quoted from license_info.txt in aforementioned file):
- *  "The files bison.exe, bison.simple, and flex.exe are covered by
- *  the GPL.  All other files in this distribution can be used however
- *  you want."
- * $/LicenseInfo$
- */
-
-/* File generated by extgen.cpp -- do not modify */
-#ifndef GLH_GENEXT_H
-#define GLH_GENEXT_H
-
-// MBW -- None of this is necessary on Mac OS.
-#ifndef __APPLE__
-
-#include <GL/gl.h>
-#include <GL/glext.h>
-
-#ifdef _WIN32 /* supports windows, x -- need to generalize */
-#  include <GL/wglext.h>
-#  define GLH_EXT_GET_PROC_ADDRESS(p)   wglGetProcAddress(p) 
-#else if GLX_VERSION_1_3
-#  include <GL/glxext.h>
-#  define GLH_EXT_GET_PROC_ADDRESS(p)   glXGetProcAddressARB(p) 
-#endif
-
-#ifdef GLH_EXT_SINGLE_FILE
-	#define GLH_EXTERN
- #define GLH_INITIALIZER = 0
-#else
-	#define GLH_EXTERN extern
- #define GLH_INITIALIZER
-#endif
-
-#define GLH__PREPROCESSOR_GYMNASTICS2(a,b) a##b
-#define GLH__PREPROCESSOR_GYMNASTICS(a,b) GLH__PREPROCESSOR_GYMNASTICS2(a,b)
-
-#ifndef GLH_EXT_PREFIX
-# define GLH_EXT_NAME(a) a
-#else
-# define GLH_EXT_NAME(a) GLH__PREPROCESSOR_GYMNASTICS(GLH_EXT_PREFIX,a)
-#endif
-
-#ifndef _WIN32
-# ifndef GLH_CORE_1_2_PREFIX
-#  define GLH_CORE_1_2_PREFIX _
-# endif
-#endif
-
-#ifndef GLH_CORE_1_2_PREFIX
-# define GLH_CORE_1_2_NAME(a) a
-#else
-# define GLH_CORE_1_2_NAME(a) GLH__PREPROCESSOR_GYMNASTICS(GLH_CORE_1_2_PREFIX,a)
-#endif
-
-#ifdef GL_ARB_multitexture
-    GLH_EXTERN PFNGLMULTITEXCOORD1DARBPROC GLH_EXT_NAME(glMultiTexCoord1dARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMULTITEXCOORD1DVARBPROC GLH_EXT_NAME(glMultiTexCoord1dvARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMULTITEXCOORD1FARBPROC GLH_EXT_NAME(glMultiTexCoord1fARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMULTITEXCOORD1FVARBPROC GLH_EXT_NAME(glMultiTexCoord1fvARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMULTITEXCOORD1IARBPROC GLH_EXT_NAME(glMultiTexCoord1iARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMULTITEXCOORD1IVARBPROC GLH_EXT_NAME(glMultiTexCoord1ivARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMULTITEXCOORD1SARBPROC GLH_EXT_NAME(glMultiTexCoord1sARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMULTITEXCOORD1SVARBPROC GLH_EXT_NAME(glMultiTexCoord1svARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMULTITEXCOORD2DARBPROC GLH_EXT_NAME(glMultiTexCoord2dARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMULTITEXCOORD2DVARBPROC GLH_EXT_NAME(glMultiTexCoord2dvARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMULTITEXCOORD2FARBPROC GLH_EXT_NAME(glMultiTexCoord2fARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMULTITEXCOORD2FVARBPROC GLH_EXT_NAME(glMultiTexCoord2fvARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMULTITEXCOORD2IARBPROC GLH_EXT_NAME(glMultiTexCoord2iARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMULTITEXCOORD2IVARBPROC GLH_EXT_NAME(glMultiTexCoord2ivARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMULTITEXCOORD2SARBPROC GLH_EXT_NAME(glMultiTexCoord2sARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMULTITEXCOORD2SVARBPROC GLH_EXT_NAME(glMultiTexCoord2svARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMULTITEXCOORD3DARBPROC GLH_EXT_NAME(glMultiTexCoord3dARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMULTITEXCOORD3DVARBPROC GLH_EXT_NAME(glMultiTexCoord3dvARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMULTITEXCOORD3FARBPROC GLH_EXT_NAME(glMultiTexCoord3fARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMULTITEXCOORD3FVARBPROC GLH_EXT_NAME(glMultiTexCoord3fvARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMULTITEXCOORD3IARBPROC GLH_EXT_NAME(glMultiTexCoord3iARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMULTITEXCOORD3IVARBPROC GLH_EXT_NAME(glMultiTexCoord3ivARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMULTITEXCOORD3SARBPROC GLH_EXT_NAME(glMultiTexCoord3sARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMULTITEXCOORD3SVARBPROC GLH_EXT_NAME(glMultiTexCoord3svARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMULTITEXCOORD4DARBPROC GLH_EXT_NAME(glMultiTexCoord4dARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMULTITEXCOORD4DVARBPROC GLH_EXT_NAME(glMultiTexCoord4dvARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMULTITEXCOORD4FARBPROC GLH_EXT_NAME(glMultiTexCoord4fARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMULTITEXCOORD4FVARBPROC GLH_EXT_NAME(glMultiTexCoord4fvARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMULTITEXCOORD4IARBPROC GLH_EXT_NAME(glMultiTexCoord4iARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMULTITEXCOORD4IVARBPROC GLH_EXT_NAME(glMultiTexCoord4ivARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMULTITEXCOORD4SARBPROC GLH_EXT_NAME(glMultiTexCoord4sARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMULTITEXCOORD4SVARBPROC GLH_EXT_NAME(glMultiTexCoord4svARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLACTIVETEXTUREARBPROC GLH_EXT_NAME(glActiveTextureARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLCLIENTACTIVETEXTUREARBPROC GLH_EXT_NAME(glClientActiveTextureARB) GLH_INITIALIZER;
-#endif
-
-#ifdef GL_ARB_texture_border_clamp
-#endif
-
-#ifdef GL_ARB_texture_compression
-    GLH_EXTERN PFNGLCOMPRESSEDTEXIMAGE3DARBPROC GLH_EXT_NAME(glCompressedTexImage3DARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLCOMPRESSEDTEXIMAGE2DARBPROC GLH_EXT_NAME(glCompressedTexImage2DARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLCOMPRESSEDTEXIMAGE1DARBPROC GLH_EXT_NAME(glCompressedTexImage1DARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLCOMPRESSEDTEXSUBIMAGE3DARBPROC GLH_EXT_NAME(glCompressedTexSubImage3DARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLCOMPRESSEDTEXSUBIMAGE2DARBPROC GLH_EXT_NAME(glCompressedTexSubImage2DARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLCOMPRESSEDTEXSUBIMAGE1DARBPROC GLH_EXT_NAME(glCompressedTexSubImage1DARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETCOMPRESSEDTEXIMAGEARBPROC GLH_EXT_NAME(glGetCompressedTexImageARB) GLH_INITIALIZER;
-#endif
-
-#ifdef GL_ARB_texture_cube_map
-#endif
-
-#ifdef GL_ARB_transpose_matrix
-    GLH_EXTERN PFNGLLOADTRANSPOSEMATRIXFARBPROC GLH_EXT_NAME(glLoadTransposeMatrixfARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLLOADTRANSPOSEMATRIXDARBPROC GLH_EXT_NAME(glLoadTransposeMatrixdARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMULTTRANSPOSEMATRIXFARBPROC GLH_EXT_NAME(glMultTransposeMatrixfARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMULTTRANSPOSEMATRIXDARBPROC GLH_EXT_NAME(glMultTransposeMatrixdARB) GLH_INITIALIZER;
-#endif
-
-#ifdef GL_ARB_vertex_program
-    GLH_EXTERN PFNGLVERTEXATTRIB1SARBPROC GLH_EXT_NAME(glVertexAttrib1sARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB1FARBPROC GLH_EXT_NAME(glVertexAttrib1fARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB1DARBPROC GLH_EXT_NAME(glVertexAttrib1dARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB2SARBPROC GLH_EXT_NAME(glVertexAttrib2sARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB2FARBPROC GLH_EXT_NAME(glVertexAttrib2fARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB2DARBPROC GLH_EXT_NAME(glVertexAttrib2dARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB3SARBPROC GLH_EXT_NAME(glVertexAttrib3sARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB3FARBPROC GLH_EXT_NAME(glVertexAttrib3fARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB3DARBPROC GLH_EXT_NAME(glVertexAttrib3dARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB4SARBPROC GLH_EXT_NAME(glVertexAttrib4sARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB4FARBPROC GLH_EXT_NAME(glVertexAttrib4fARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB4DARBPROC GLH_EXT_NAME(glVertexAttrib4dARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB4NUBARBPROC GLH_EXT_NAME(glVertexAttrib4NubARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB1SVARBPROC GLH_EXT_NAME(glVertexAttrib1svARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB1FVARBPROC GLH_EXT_NAME(glVertexAttrib1fvARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB1DVARBPROC GLH_EXT_NAME(glVertexAttrib1dvARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB2SVARBPROC GLH_EXT_NAME(glVertexAttrib2svARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB2FVARBPROC GLH_EXT_NAME(glVertexAttrib2fvARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB2DVARBPROC GLH_EXT_NAME(glVertexAttrib2dvARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB3SVARBPROC GLH_EXT_NAME(glVertexAttrib3svARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB3FVARBPROC GLH_EXT_NAME(glVertexAttrib3fvARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB3DVARBPROC GLH_EXT_NAME(glVertexAttrib3dvARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB4BVARBPROC GLH_EXT_NAME(glVertexAttrib4bvARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB4SVARBPROC GLH_EXT_NAME(glVertexAttrib4svARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB4IVARBPROC GLH_EXT_NAME(glVertexAttrib4ivARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB4UBVARBPROC GLH_EXT_NAME(glVertexAttrib4ubvARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB4USVARBPROC GLH_EXT_NAME(glVertexAttrib4usvARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB4UIVARBPROC GLH_EXT_NAME(glVertexAttrib4uivARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB4FVARBPROC GLH_EXT_NAME(glVertexAttrib4fvARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB4DVARBPROC GLH_EXT_NAME(glVertexAttrib4dvARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB4NBVARBPROC GLH_EXT_NAME(glVertexAttrib4NbvARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB4NSVARBPROC GLH_EXT_NAME(glVertexAttrib4NsvARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB4NIVARBPROC GLH_EXT_NAME(glVertexAttrib4NivARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB4NUBVARBPROC GLH_EXT_NAME(glVertexAttrib4NubvARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB4NUSVARBPROC GLH_EXT_NAME(glVertexAttrib4NusvARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB4NUIVARBPROC GLH_EXT_NAME(glVertexAttrib4NuivARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIBPOINTERARBPROC GLH_EXT_NAME(glVertexAttribPointerARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLENABLEVERTEXATTRIBARRAYARBPROC GLH_EXT_NAME(glEnableVertexAttribArrayARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLDISABLEVERTEXATTRIBARRAYARBPROC GLH_EXT_NAME(glDisableVertexAttribArrayARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLPROGRAMSTRINGARBPROC GLH_EXT_NAME(glProgramStringARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLBINDPROGRAMARBPROC GLH_EXT_NAME(glBindProgramARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLDELETEPROGRAMSARBPROC GLH_EXT_NAME(glDeleteProgramsARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGENPROGRAMSARBPROC GLH_EXT_NAME(glGenProgramsARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLPROGRAMENVPARAMETER4DARBPROC GLH_EXT_NAME(glProgramEnvParameter4dARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLPROGRAMENVPARAMETER4DVARBPROC GLH_EXT_NAME(glProgramEnvParameter4dvARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLPROGRAMENVPARAMETER4FARBPROC GLH_EXT_NAME(glProgramEnvParameter4fARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLPROGRAMENVPARAMETER4FVARBPROC GLH_EXT_NAME(glProgramEnvParameter4fvARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLPROGRAMLOCALPARAMETER4DARBPROC GLH_EXT_NAME(glProgramLocalParameter4dARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLPROGRAMLOCALPARAMETER4DVARBPROC GLH_EXT_NAME(glProgramLocalParameter4dvARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLPROGRAMLOCALPARAMETER4FARBPROC GLH_EXT_NAME(glProgramLocalParameter4fARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLPROGRAMLOCALPARAMETER4FVARBPROC GLH_EXT_NAME(glProgramLocalParameter4fvARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETPROGRAMENVPARAMETERDVARBPROC GLH_EXT_NAME(glGetProgramEnvParameterdvARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETPROGRAMENVPARAMETERFVARBPROC GLH_EXT_NAME(glGetProgramEnvParameterfvARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC GLH_EXT_NAME(glGetProgramLocalParameterdvARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETPROGRAMLOCALPARAMETERFVARBPROC GLH_EXT_NAME(glGetProgramLocalParameterfvARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETPROGRAMIVARBPROC GLH_EXT_NAME(glGetProgramivARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETPROGRAMSTRINGARBPROC GLH_EXT_NAME(glGetProgramStringARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETVERTEXATTRIBDVARBPROC GLH_EXT_NAME(glGetVertexAttribdvARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETVERTEXATTRIBFVARBPROC GLH_EXT_NAME(glGetVertexAttribfvARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETVERTEXATTRIBIVARBPROC GLH_EXT_NAME(glGetVertexAttribivARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETVERTEXATTRIBPOINTERVARBPROC GLH_EXT_NAME(glGetVertexAttribPointervARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLISPROGRAMARBPROC GLH_EXT_NAME(glIsProgramARB) GLH_INITIALIZER;
-#endif
-
-#ifdef GL_EXT_abgr
-#endif
-
-#ifdef GL_EXT_bgra
-#endif
-
-#ifdef GL_EXT_blend_color
-    GLH_EXTERN PFNGLBLENDCOLOREXTPROC GLH_EXT_NAME(glBlendColorEXT) GLH_INITIALIZER;
-#endif
-
-#ifdef GL_EXT_blend_minmax
-    GLH_EXTERN PFNGLBLENDEQUATIONEXTPROC GLH_EXT_NAME(glBlendEquationEXT) GLH_INITIALIZER;
-#endif
-
-#ifdef GL_EXT_blend_subtract
-#endif
-
-#ifdef GL_EXT_compiled_vertex_array
-    GLH_EXTERN PFNGLLOCKARRAYSEXTPROC GLH_EXT_NAME(glLockArraysEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLUNLOCKARRAYSEXTPROC GLH_EXT_NAME(glUnlockArraysEXT) GLH_INITIALIZER;
-#endif
-
-#ifdef GL_EXT_fog_coord
-    GLH_EXTERN PFNGLFOGCOORDDEXTPROC GLH_EXT_NAME(glFogCoorddEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLFOGCOORDDVEXTPROC GLH_EXT_NAME(glFogCoorddvEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLFOGCOORDFEXTPROC GLH_EXT_NAME(glFogCoordfEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLFOGCOORDFVEXTPROC GLH_EXT_NAME(glFogCoordfvEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLFOGCOORDPOINTEREXTPROC GLH_EXT_NAME(glFogCoordPointerEXT) GLH_INITIALIZER;
-#endif
-
-#ifdef GL_EXT_light_max_exponent
-#endif
-
-#ifdef GL_EXT_packed_pixels
-#endif
-
-#ifdef GL_EXT_paletted_texture
-    GLH_EXTERN PFNGLCOLORSUBTABLEEXTPROC GLH_EXT_NAME(glColorSubTableEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLCOLORTABLEEXTPROC GLH_EXT_NAME(glColorTableEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETCOLORTABLEEXTPROC GLH_EXT_NAME(glGetColorTableEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETCOLORTABLEPARAMETERFVEXTPROC GLH_EXT_NAME(glGetColorTableParameterfvEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETCOLORTABLEPARAMETERIVEXTPROC GLH_EXT_NAME(glGetColorTableParameterivEXT) GLH_INITIALIZER;
-#endif
-
-#ifdef GL_EXT_point_parameters
-    GLH_EXTERN PFNGLPOINTPARAMETERFEXTPROC GLH_EXT_NAME(glPointParameterfEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLPOINTPARAMETERFVEXTPROC GLH_EXT_NAME(glPointParameterfvEXT) GLH_INITIALIZER;
-#endif
-
-#ifdef GL_EXT_rescale_normal
-#endif
-
-#ifdef GL_EXT_secondary_color
-    GLH_EXTERN PFNGLSECONDARYCOLOR3BEXTPROC GLH_EXT_NAME(glSecondaryColor3bEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLSECONDARYCOLOR3BVEXTPROC GLH_EXT_NAME(glSecondaryColor3bvEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLSECONDARYCOLOR3DEXTPROC GLH_EXT_NAME(glSecondaryColor3dEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLSECONDARYCOLOR3DVEXTPROC GLH_EXT_NAME(glSecondaryColor3dvEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLSECONDARYCOLOR3FEXTPROC GLH_EXT_NAME(glSecondaryColor3fEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLSECONDARYCOLOR3FVEXTPROC GLH_EXT_NAME(glSecondaryColor3fvEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLSECONDARYCOLOR3IEXTPROC GLH_EXT_NAME(glSecondaryColor3iEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLSECONDARYCOLOR3IVEXTPROC GLH_EXT_NAME(glSecondaryColor3ivEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLSECONDARYCOLOR3SEXTPROC GLH_EXT_NAME(glSecondaryColor3sEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLSECONDARYCOLOR3SVEXTPROC GLH_EXT_NAME(glSecondaryColor3svEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLSECONDARYCOLOR3UBEXTPROC GLH_EXT_NAME(glSecondaryColor3ubEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLSECONDARYCOLOR3UBVEXTPROC GLH_EXT_NAME(glSecondaryColor3ubvEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLSECONDARYCOLOR3UIEXTPROC GLH_EXT_NAME(glSecondaryColor3uiEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLSECONDARYCOLOR3UIVEXTPROC GLH_EXT_NAME(glSecondaryColor3uivEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLSECONDARYCOLOR3USEXTPROC GLH_EXT_NAME(glSecondaryColor3usEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLSECONDARYCOLOR3USVEXTPROC GLH_EXT_NAME(glSecondaryColor3usvEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLSECONDARYCOLORPOINTEREXTPROC GLH_EXT_NAME(glSecondaryColorPointerEXT) GLH_INITIALIZER;
-#endif
-
-#ifdef GL_EXT_separate_specular_color
-#endif
-
-#ifdef GL_EXT_shared_texture_palette
-#endif
-
-#ifdef GL_EXT_stencil_wrap
-#endif
-
-#ifdef GL_EXT_texture_compression_s3tc
-#endif
-
-#ifdef GL_EXT_texture_cube_map
-#endif
-
-#ifdef GL_EXT_texture_edge_clamp
-#endif
-
-#ifdef GL_EXT_texture_env_add
-#endif
-
-#ifdef GL_EXT_texture_env_combine
-#endif
-
-#ifdef GL_EXT_texture_filter_anisotropic
-#endif
-
-#ifdef GL_EXT_texture_lod_bias
-#endif
-
-#ifdef GL_EXT_texture_object
-    GLH_EXTERN PFNGLARETEXTURESRESIDENTEXTPROC GLH_EXT_NAME(glAreTexturesResidentEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLBINDTEXTUREEXTPROC GLH_EXT_NAME(glBindTextureEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLDELETETEXTURESEXTPROC GLH_EXT_NAME(glDeleteTexturesEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGENTEXTURESEXTPROC GLH_EXT_NAME(glGenTexturesEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLISTEXTUREEXTPROC GLH_EXT_NAME(glIsTextureEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLPRIORITIZETEXTURESEXTPROC GLH_EXT_NAME(glPrioritizeTexturesEXT) GLH_INITIALIZER;
-#endif
-
-#ifdef GL_EXT_texture3D
-    GLH_EXTERN PFNGLTEXIMAGE3DEXTPROC GLH_EXT_NAME(glTexImage3DEXT) GLH_INITIALIZER;
-#endif
-
-#ifdef GL_EXT_vertex_array
-    GLH_EXTERN PFNGLARRAYELEMENTEXTPROC GLH_EXT_NAME(glArrayElementEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLCOLORPOINTEREXTPROC GLH_EXT_NAME(glColorPointerEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLEDGEFLAGPOINTEREXTPROC GLH_EXT_NAME(glEdgeFlagPointerEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETPOINTERVEXTPROC GLH_EXT_NAME(glGetPointervEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLINDEXPOINTEREXTPROC GLH_EXT_NAME(glIndexPointerEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLNORMALPOINTEREXTPROC GLH_EXT_NAME(glNormalPointerEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLTEXCOORDPOINTEREXTPROC GLH_EXT_NAME(glTexCoordPointerEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXPOINTEREXTPROC GLH_EXT_NAME(glVertexPointerEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLDRAWARRAYSEXTPROC GLH_EXT_NAME(glDrawArraysEXT) GLH_INITIALIZER;
-#endif
-
-#ifdef GL_EXT_vertex_weighting
-    GLH_EXTERN PFNGLVERTEXWEIGHTFEXTPROC GLH_EXT_NAME(glVertexWeightfEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXWEIGHTFVEXTPROC GLH_EXT_NAME(glVertexWeightfvEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXWEIGHTPOINTEREXTPROC GLH_EXT_NAME(glVertexWeightPointerEXT) GLH_INITIALIZER;
-#endif
-
-#ifdef GL_NV_blend_square
-#endif
-
-#ifdef GL_NV_evaluators
-    GLH_EXTERN PFNGLMAPCONTROLPOINTSNVPROC GLH_EXT_NAME(glMapControlPointsNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMAPPARAMETERIVNVPROC GLH_EXT_NAME(glMapParameterivNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMAPPARAMETERFVNVPROC GLH_EXT_NAME(glMapParameterfvNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETMAPCONTROLPOINTSNVPROC GLH_EXT_NAME(glGetMapControlPointsNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETMAPPARAMETERIVNVPROC GLH_EXT_NAME(glGetMapParameterivNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETMAPPARAMETERFVNVPROC GLH_EXT_NAME(glGetMapParameterfvNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETMAPATTRIBPARAMETERIVNVPROC GLH_EXT_NAME(glGetMapAttribParameterivNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETMAPATTRIBPARAMETERFVNVPROC GLH_EXT_NAME(glGetMapAttribParameterfvNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLEVALMAPSNVPROC GLH_EXT_NAME(glEvalMapsNV) GLH_INITIALIZER;
-#endif
-
-#ifdef GL_NV_fence
-    GLH_EXTERN PFNGLGENFENCESNVPROC GLH_EXT_NAME(glGenFencesNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLDELETEFENCESNVPROC GLH_EXT_NAME(glDeleteFencesNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLSETFENCENVPROC GLH_EXT_NAME(glSetFenceNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLTESTFENCENVPROC GLH_EXT_NAME(glTestFenceNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLFINISHFENCENVPROC GLH_EXT_NAME(glFinishFenceNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLISFENCENVPROC GLH_EXT_NAME(glIsFenceNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETFENCEIVNVPROC GLH_EXT_NAME(glGetFenceivNV) GLH_INITIALIZER;
-#endif
-
-#ifdef GL_NV_fog_distance
-#endif
-
-#ifdef GL_NV_packed_depth_stencil
-#endif
-
-#ifdef GL_NV_register_combiners
-    GLH_EXTERN PFNGLCOMBINERPARAMETERFVNVPROC GLH_EXT_NAME(glCombinerParameterfvNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLCOMBINERPARAMETERFNVPROC GLH_EXT_NAME(glCombinerParameterfNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLCOMBINERPARAMETERIVNVPROC GLH_EXT_NAME(glCombinerParameterivNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLCOMBINERPARAMETERINVPROC GLH_EXT_NAME(glCombinerParameteriNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLCOMBINERINPUTNVPROC GLH_EXT_NAME(glCombinerInputNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLCOMBINEROUTPUTNVPROC GLH_EXT_NAME(glCombinerOutputNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLFINALCOMBINERINPUTNVPROC GLH_EXT_NAME(glFinalCombinerInputNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETCOMBINERINPUTPARAMETERFVNVPROC GLH_EXT_NAME(glGetCombinerInputParameterfvNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETCOMBINERINPUTPARAMETERIVNVPROC GLH_EXT_NAME(glGetCombinerInputParameterivNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETCOMBINEROUTPUTPARAMETERFVNVPROC GLH_EXT_NAME(glGetCombinerOutputParameterfvNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETCOMBINEROUTPUTPARAMETERIVNVPROC GLH_EXT_NAME(glGetCombinerOutputParameterivNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETFINALCOMBINERINPUTPARAMETERFVNVPROC GLH_EXT_NAME(glGetFinalCombinerInputParameterfvNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETFINALCOMBINERINPUTPARAMETERIVNVPROC GLH_EXT_NAME(glGetFinalCombinerInputParameterivNV) GLH_INITIALIZER;
-#endif
-
-#ifdef GL_NV_register_combiners2
-    GLH_EXTERN PFNGLCOMBINERSTAGEPARAMETERFVNVPROC GLH_EXT_NAME(glCombinerStageParameterfvNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETCOMBINERSTAGEPARAMETERFVNVPROC GLH_EXT_NAME(glGetCombinerStageParameterfvNV) GLH_INITIALIZER;
-#endif
-
-#ifdef GL_NV_texgen_reflection
-#endif
-
-#ifdef GL_NV_texture_env_combine4
-#endif
-
-#ifdef GL_NV_texture_rectangle
-#endif
-
-#ifdef GL_NV_texture_shader
-#endif
-
-#ifdef GL_NV_vertex_array_range
-    GLH_EXTERN PFNGLFLUSHVERTEXARRAYRANGENVPROC GLH_EXT_NAME(glFlushVertexArrayRangeNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXARRAYRANGENVPROC GLH_EXT_NAME(glVertexArrayRangeNV) GLH_INITIALIZER;
-# ifdef _WIN32
-    GLH_EXTERN PFNWGLALLOCATEMEMORYNVPROC GLH_EXT_NAME(wglAllocateMemoryNV) GLH_INITIALIZER;
-# endif
-# ifdef GLX_VERSION_1_3
-    GLH_EXTERN PFNGLXALLOCATEMEMORYNVPROC GLH_EXT_NAME(glXAllocateMemoryNV) GLH_INITIALIZER;
-# endif
-# ifdef _WIN32
-    GLH_EXTERN PFNWGLFREEMEMORYNVPROC GLH_EXT_NAME(wglFreeMemoryNV) GLH_INITIALIZER;
-# endif
-# ifdef GLX_VERSION_1_3
-    GLH_EXTERN PFNGLXFREEMEMORYNVPROC GLH_EXT_NAME(glXFreeMemoryNV) GLH_INITIALIZER;
-# endif
-#endif
-
-#ifdef GL_NV_vertex_program
-    GLH_EXTERN PFNGLAREPROGRAMSRESIDENTNVPROC GLH_EXT_NAME(glAreProgramsResidentNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLBINDPROGRAMNVPROC GLH_EXT_NAME(glBindProgramNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLDELETEPROGRAMSNVPROC GLH_EXT_NAME(glDeleteProgramsNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLEXECUTEPROGRAMNVPROC GLH_EXT_NAME(glExecuteProgramNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGENPROGRAMSNVPROC GLH_EXT_NAME(glGenProgramsNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETPROGRAMPARAMETERDVNVPROC GLH_EXT_NAME(glGetProgramParameterdvNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETPROGRAMPARAMETERFVNVPROC GLH_EXT_NAME(glGetProgramParameterfvNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETPROGRAMIVNVPROC GLH_EXT_NAME(glGetProgramivNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETPROGRAMSTRINGNVPROC GLH_EXT_NAME(glGetProgramStringNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETTRACKMATRIXIVNVPROC GLH_EXT_NAME(glGetTrackMatrixivNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETVERTEXATTRIBDVNVPROC GLH_EXT_NAME(glGetVertexAttribdvNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETVERTEXATTRIBFVNVPROC GLH_EXT_NAME(glGetVertexAttribfvNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETVERTEXATTRIBIVNVPROC GLH_EXT_NAME(glGetVertexAttribivNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETVERTEXATTRIBPOINTERVNVPROC GLH_EXT_NAME(glGetVertexAttribPointervNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLISPROGRAMNVPROC GLH_EXT_NAME(glIsProgramNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLLOADPROGRAMNVPROC GLH_EXT_NAME(glLoadProgramNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLPROGRAMPARAMETER4DNVPROC GLH_EXT_NAME(glProgramParameter4dNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLPROGRAMPARAMETER4DVNVPROC GLH_EXT_NAME(glProgramParameter4dvNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLPROGRAMPARAMETER4FNVPROC GLH_EXT_NAME(glProgramParameter4fNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLPROGRAMPARAMETER4FVNVPROC GLH_EXT_NAME(glProgramParameter4fvNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLPROGRAMPARAMETERS4DVNVPROC GLH_EXT_NAME(glProgramParameters4dvNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLPROGRAMPARAMETERS4FVNVPROC GLH_EXT_NAME(glProgramParameters4fvNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLREQUESTRESIDENTPROGRAMSNVPROC GLH_EXT_NAME(glRequestResidentProgramsNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLTRACKMATRIXNVPROC GLH_EXT_NAME(glTrackMatrixNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIBPOINTERNVPROC GLH_EXT_NAME(glVertexAttribPointerNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB1DNVPROC GLH_EXT_NAME(glVertexAttrib1dNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB1DVNVPROC GLH_EXT_NAME(glVertexAttrib1dvNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB1FNVPROC GLH_EXT_NAME(glVertexAttrib1fNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB1FVNVPROC GLH_EXT_NAME(glVertexAttrib1fvNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB1SNVPROC GLH_EXT_NAME(glVertexAttrib1sNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB1SVNVPROC GLH_EXT_NAME(glVertexAttrib1svNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB2DNVPROC GLH_EXT_NAME(glVertexAttrib2dNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB2DVNVPROC GLH_EXT_NAME(glVertexAttrib2dvNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB2FNVPROC GLH_EXT_NAME(glVertexAttrib2fNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB2FVNVPROC GLH_EXT_NAME(glVertexAttrib2fvNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB2SNVPROC GLH_EXT_NAME(glVertexAttrib2sNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB2SVNVPROC GLH_EXT_NAME(glVertexAttrib2svNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB3DNVPROC GLH_EXT_NAME(glVertexAttrib3dNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB3DVNVPROC GLH_EXT_NAME(glVertexAttrib3dvNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB3FNVPROC GLH_EXT_NAME(glVertexAttrib3fNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB3FVNVPROC GLH_EXT_NAME(glVertexAttrib3fvNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB3SNVPROC GLH_EXT_NAME(glVertexAttrib3sNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB3SVNVPROC GLH_EXT_NAME(glVertexAttrib3svNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB4DNVPROC GLH_EXT_NAME(glVertexAttrib4dNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB4DVNVPROC GLH_EXT_NAME(glVertexAttrib4dvNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB4FNVPROC GLH_EXT_NAME(glVertexAttrib4fNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB4FVNVPROC GLH_EXT_NAME(glVertexAttrib4fvNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB4SNVPROC GLH_EXT_NAME(glVertexAttrib4sNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB4SVNVPROC GLH_EXT_NAME(glVertexAttrib4svNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB4UBVNVPROC GLH_EXT_NAME(glVertexAttrib4ubvNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIBS1DVNVPROC GLH_EXT_NAME(glVertexAttribs1dvNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIBS1FVNVPROC GLH_EXT_NAME(glVertexAttribs1fvNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIBS1SVNVPROC GLH_EXT_NAME(glVertexAttribs1svNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIBS2DVNVPROC GLH_EXT_NAME(glVertexAttribs2dvNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIBS2FVNVPROC GLH_EXT_NAME(glVertexAttribs2fvNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIBS2SVNVPROC GLH_EXT_NAME(glVertexAttribs2svNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIBS3DVNVPROC GLH_EXT_NAME(glVertexAttribs3dvNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIBS3FVNVPROC GLH_EXT_NAME(glVertexAttribs3fvNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIBS3SVNVPROC GLH_EXT_NAME(glVertexAttribs3svNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIBS4DVNVPROC GLH_EXT_NAME(glVertexAttribs4dvNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIBS4FVNVPROC GLH_EXT_NAME(glVertexAttribs4fvNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIBS4SVNVPROC GLH_EXT_NAME(glVertexAttribs4svNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIBS4UBVNVPROC GLH_EXT_NAME(glVertexAttribs4ubvNV) GLH_INITIALIZER;
-#endif
-
-#ifdef GL_SGIS_generate_mipmap
-#endif
-
-#ifdef GL_SGIS_texture_lod
-#endif
-
-#ifdef GL_SGIX_depth_texture
-#endif
-
-#ifdef GL_SGIX_shadow
-#endif
-
-#ifdef GL_VERSION_1_2
-    /* These routines are prefixed by the preprocessor constant
-       GLH_CORE_1_2_PREFIX to avoid colliding with the OpenGL 1.2 namespace. */
-    GLH_EXTERN PFNGLBLENDCOLORPROC GLH_CORE_1_2_NAME(glBlendColor) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLBLENDEQUATIONPROC GLH_CORE_1_2_NAME(glBlendEquation) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLDRAWRANGEELEMENTSPROC GLH_CORE_1_2_NAME(glDrawRangeElements) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLCOLORTABLEPROC GLH_CORE_1_2_NAME(glColorTable) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLCOLORTABLEPARAMETERFVPROC GLH_CORE_1_2_NAME(glColorTableParameterfv) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLCOLORTABLEPARAMETERIVPROC GLH_CORE_1_2_NAME(glColorTableParameteriv) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLCOPYCOLORTABLEPROC GLH_CORE_1_2_NAME(glCopyColorTable) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETCOLORTABLEPROC GLH_CORE_1_2_NAME(glGetColorTable) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETCOLORTABLEPARAMETERFVPROC GLH_CORE_1_2_NAME(glGetColorTableParameterfv) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETCOLORTABLEPARAMETERIVPROC GLH_CORE_1_2_NAME(glGetColorTableParameteriv) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLTEXIMAGE3DPROC GLH_CORE_1_2_NAME(glTexImage3D) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLTEXSUBIMAGE3DPROC GLH_CORE_1_2_NAME(glTexSubImage3D) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLCOPYTEXSUBIMAGE3DPROC GLH_CORE_1_2_NAME(glCopyTexSubImage3D) GLH_INITIALIZER;
-#endif
-
-#ifdef GL_WIN_swap_hint
-    GLH_EXTERN PFNGLADDSWAPHINTRECTWINPROC GLH_EXT_NAME(glAddSwapHintRectWIN) GLH_INITIALIZER;
-#endif
-
-#ifdef WGL_ARB_pbuffer
-# ifdef _WIN32
-    GLH_EXTERN PFNWGLCREATEPBUFFERARBPROC GLH_EXT_NAME(wglCreatePbufferARB) GLH_INITIALIZER;
-# endif
-# ifdef _WIN32
-    GLH_EXTERN PFNWGLGETPBUFFERDCARBPROC GLH_EXT_NAME(wglGetPbufferDCARB) GLH_INITIALIZER;
-# endif
-# ifdef _WIN32
-    GLH_EXTERN PFNWGLRELEASEPBUFFERDCARBPROC GLH_EXT_NAME(wglReleasePbufferDCARB) GLH_INITIALIZER;
-# endif
-# ifdef _WIN32
-    GLH_EXTERN PFNWGLDESTROYPBUFFERARBPROC GLH_EXT_NAME(wglDestroyPbufferARB) GLH_INITIALIZER;
-# endif
-# ifdef _WIN32
-    GLH_EXTERN PFNWGLQUERYPBUFFERARBPROC GLH_EXT_NAME(wglQueryPbufferARB) GLH_INITIALIZER;
-# endif
-#endif
-
-#ifdef WGL_ARB_render_texture
-# ifdef _WIN32
-    GLH_EXTERN PFNWGLBINDTEXIMAGEARBPROC GLH_EXT_NAME(wglBindTexImageARB) GLH_INITIALIZER;
-# endif
-# ifdef _WIN32
-    GLH_EXTERN PFNWGLRELEASETEXIMAGEARBPROC GLH_EXT_NAME(wglReleaseTexImageARB) GLH_INITIALIZER;
-# endif
-# ifdef _WIN32
-    GLH_EXTERN PFNWGLSETPBUFFERATTRIBARBPROC GLH_EXT_NAME(wglSetPbufferAttribARB) GLH_INITIALIZER;
-# endif
-#endif
-
-#ifdef WGL_ARB_pixel_format
-# ifdef _WIN32
-    GLH_EXTERN PFNWGLGETPIXELFORMATATTRIBIVARBPROC GLH_EXT_NAME(wglGetPixelFormatAttribivARB) GLH_INITIALIZER;
-# endif
-# ifdef _WIN32
-    GLH_EXTERN PFNWGLGETPIXELFORMATATTRIBFVARBPROC GLH_EXT_NAME(wglGetPixelFormatAttribfvARB) GLH_INITIALIZER;
-# endif
-# ifdef _WIN32
-    GLH_EXTERN PFNWGLCHOOSEPIXELFORMATARBPROC GLH_EXT_NAME(wglChoosePixelFormatARB) GLH_INITIALIZER;
-# endif
-#endif
-
-
-#ifdef GLH_EXT_SINGLE_FILE
-
-int glh_init_extension(const char* extension)
-{
-    if (NULL == extension) {
-        return FALSE;
-#ifdef GL_ARB_multitexture
-    } else if (0 == strcmp(extension, "GL_ARB_multitexture")) {
-        GLH_EXT_NAME(glMultiTexCoord1dARB) = (PFNGLMULTITEXCOORD1DARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord1dARB");
-        if (NULL == GLH_EXT_NAME(glMultiTexCoord1dARB))
-            return FALSE;
-        GLH_EXT_NAME(glMultiTexCoord1dvARB) = (PFNGLMULTITEXCOORD1DVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord1dvARB");
-        if (NULL == GLH_EXT_NAME(glMultiTexCoord1dvARB))
-            return FALSE;
-        GLH_EXT_NAME(glMultiTexCoord1fARB) = (PFNGLMULTITEXCOORD1FARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord1fARB");
-        if (NULL == GLH_EXT_NAME(glMultiTexCoord1fARB))
-            return FALSE;
-        GLH_EXT_NAME(glMultiTexCoord1fvARB) = (PFNGLMULTITEXCOORD1FVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord1fvARB");
-        if (NULL == GLH_EXT_NAME(glMultiTexCoord1fvARB))
-            return FALSE;
-        GLH_EXT_NAME(glMultiTexCoord1iARB) = (PFNGLMULTITEXCOORD1IARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord1iARB");
-        if (NULL == GLH_EXT_NAME(glMultiTexCoord1iARB))
-            return FALSE;
-        GLH_EXT_NAME(glMultiTexCoord1ivARB) = (PFNGLMULTITEXCOORD1IVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord1ivARB");
-        if (NULL == GLH_EXT_NAME(glMultiTexCoord1ivARB))
-            return FALSE;
-        GLH_EXT_NAME(glMultiTexCoord1sARB) = (PFNGLMULTITEXCOORD1SARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord1sARB");
-        if (NULL == GLH_EXT_NAME(glMultiTexCoord1sARB))
-            return FALSE;
-        GLH_EXT_NAME(glMultiTexCoord1svARB) = (PFNGLMULTITEXCOORD1SVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord1svARB");
-        if (NULL == GLH_EXT_NAME(glMultiTexCoord1svARB))
-            return FALSE;
-        GLH_EXT_NAME(glMultiTexCoord2dARB) = (PFNGLMULTITEXCOORD2DARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord2dARB");
-        if (NULL == GLH_EXT_NAME(glMultiTexCoord2dARB))
-            return FALSE;
-        GLH_EXT_NAME(glMultiTexCoord2dvARB) = (PFNGLMULTITEXCOORD2DVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord2dvARB");
-        if (NULL == GLH_EXT_NAME(glMultiTexCoord2dvARB))
-            return FALSE;
-        GLH_EXT_NAME(glMultiTexCoord2fARB) = (PFNGLMULTITEXCOORD2FARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord2fARB");
-        if (NULL == GLH_EXT_NAME(glMultiTexCoord2fARB))
-            return FALSE;
-        GLH_EXT_NAME(glMultiTexCoord2fvARB) = (PFNGLMULTITEXCOORD2FVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord2fvARB");
-        if (NULL == GLH_EXT_NAME(glMultiTexCoord2fvARB))
-            return FALSE;
-        GLH_EXT_NAME(glMultiTexCoord2iARB) = (PFNGLMULTITEXCOORD2IARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord2iARB");
-        if (NULL == GLH_EXT_NAME(glMultiTexCoord2iARB))
-            return FALSE;
-        GLH_EXT_NAME(glMultiTexCoord2ivARB) = (PFNGLMULTITEXCOORD2IVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord2ivARB");
-        if (NULL == GLH_EXT_NAME(glMultiTexCoord2ivARB))
-            return FALSE;
-        GLH_EXT_NAME(glMultiTexCoord2sARB) = (PFNGLMULTITEXCOORD2SARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord2sARB");
-        if (NULL == GLH_EXT_NAME(glMultiTexCoord2sARB))
-            return FALSE;
-        GLH_EXT_NAME(glMultiTexCoord2svARB) = (PFNGLMULTITEXCOORD2SVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord2svARB");
-        if (NULL == GLH_EXT_NAME(glMultiTexCoord2svARB))
-            return FALSE;
-        GLH_EXT_NAME(glMultiTexCoord3dARB) = (PFNGLMULTITEXCOORD3DARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord3dARB");
-        if (NULL == GLH_EXT_NAME(glMultiTexCoord3dARB))
-            return FALSE;
-        GLH_EXT_NAME(glMultiTexCoord3dvARB) = (PFNGLMULTITEXCOORD3DVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord3dvARB");
-        if (NULL == GLH_EXT_NAME(glMultiTexCoord3dvARB))
-            return FALSE;
-        GLH_EXT_NAME(glMultiTexCoord3fARB) = (PFNGLMULTITEXCOORD3FARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord3fARB");
-        if (NULL == GLH_EXT_NAME(glMultiTexCoord3fARB))
-            return FALSE;
-        GLH_EXT_NAME(glMultiTexCoord3fvARB) = (PFNGLMULTITEXCOORD3FVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord3fvARB");
-        if (NULL == GLH_EXT_NAME(glMultiTexCoord3fvARB))
-            return FALSE;
-        GLH_EXT_NAME(glMultiTexCoord3iARB) = (PFNGLMULTITEXCOORD3IARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord3iARB");
-        if (NULL == GLH_EXT_NAME(glMultiTexCoord3iARB))
-            return FALSE;
-        GLH_EXT_NAME(glMultiTexCoord3ivARB) = (PFNGLMULTITEXCOORD3IVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord3ivARB");
-        if (NULL == GLH_EXT_NAME(glMultiTexCoord3ivARB))
-            return FALSE;
-        GLH_EXT_NAME(glMultiTexCoord3sARB) = (PFNGLMULTITEXCOORD3SARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord3sARB");
-        if (NULL == GLH_EXT_NAME(glMultiTexCoord3sARB))
-            return FALSE;
-        GLH_EXT_NAME(glMultiTexCoord3svARB) = (PFNGLMULTITEXCOORD3SVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord3svARB");
-        if (NULL == GLH_EXT_NAME(glMultiTexCoord3svARB))
-            return FALSE;
-        GLH_EXT_NAME(glMultiTexCoord4dARB) = (PFNGLMULTITEXCOORD4DARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord4dARB");
-        if (NULL == GLH_EXT_NAME(glMultiTexCoord4dARB))
-            return FALSE;
-        GLH_EXT_NAME(glMultiTexCoord4dvARB) = (PFNGLMULTITEXCOORD4DVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord4dvARB");
-        if (NULL == GLH_EXT_NAME(glMultiTexCoord4dvARB))
-            return FALSE;
-        GLH_EXT_NAME(glMultiTexCoord4fARB) = (PFNGLMULTITEXCOORD4FARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord4fARB");
-        if (NULL == GLH_EXT_NAME(glMultiTexCoord4fARB))
-            return FALSE;
-        GLH_EXT_NAME(glMultiTexCoord4fvARB) = (PFNGLMULTITEXCOORD4FVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord4fvARB");
-        if (NULL == GLH_EXT_NAME(glMultiTexCoord4fvARB))
-            return FALSE;
-        GLH_EXT_NAME(glMultiTexCoord4iARB) = (PFNGLMULTITEXCOORD4IARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord4iARB");
-        if (NULL == GLH_EXT_NAME(glMultiTexCoord4iARB))
-            return FALSE;
-        GLH_EXT_NAME(glMultiTexCoord4ivARB) = (PFNGLMULTITEXCOORD4IVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord4ivARB");
-        if (NULL == GLH_EXT_NAME(glMultiTexCoord4ivARB))
-            return FALSE;
-        GLH_EXT_NAME(glMultiTexCoord4sARB) = (PFNGLMULTITEXCOORD4SARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord4sARB");
-        if (NULL == GLH_EXT_NAME(glMultiTexCoord4sARB))
-            return FALSE;
-        GLH_EXT_NAME(glMultiTexCoord4svARB) = (PFNGLMULTITEXCOORD4SVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord4svARB");
-        if (NULL == GLH_EXT_NAME(glMultiTexCoord4svARB))
-            return FALSE;
-        GLH_EXT_NAME(glActiveTextureARB) = (PFNGLACTIVETEXTUREARBPROC)GLH_EXT_GET_PROC_ADDRESS("glActiveTextureARB");
-        if (NULL == GLH_EXT_NAME(glActiveTextureARB))
-            return FALSE;
-        GLH_EXT_NAME(glClientActiveTextureARB) = (PFNGLCLIENTACTIVETEXTUREARBPROC)GLH_EXT_GET_PROC_ADDRESS("glClientActiveTextureARB");
-        if (NULL == GLH_EXT_NAME(glClientActiveTextureARB))
-            return FALSE;
-#endif
-
-#ifdef GL_ARB_texture_border_clamp
-    } else if (0 == strcmp(extension, "GL_ARB_texture_border_clamp")) {
-#endif
-
-#ifdef GL_ARB_texture_compression
-    } else if (0 == strcmp(extension, "GL_ARB_texture_compression")) {
-        GLH_EXT_NAME(glCompressedTexImage3DARB) = (PFNGLCOMPRESSEDTEXIMAGE3DARBPROC)GLH_EXT_GET_PROC_ADDRESS("glCompressedTexImage3DARB");
-        if (NULL == GLH_EXT_NAME(glCompressedTexImage3DARB))
-            return FALSE;
-        GLH_EXT_NAME(glCompressedTexImage2DARB) = (PFNGLCOMPRESSEDTEXIMAGE2DARBPROC)GLH_EXT_GET_PROC_ADDRESS("glCompressedTexImage2DARB");
-        if (NULL == GLH_EXT_NAME(glCompressedTexImage2DARB))
-            return FALSE;
-        GLH_EXT_NAME(glCompressedTexImage1DARB) = (PFNGLCOMPRESSEDTEXIMAGE1DARBPROC)GLH_EXT_GET_PROC_ADDRESS("glCompressedTexImage1DARB");
-        if (NULL == GLH_EXT_NAME(glCompressedTexImage1DARB))
-            return FALSE;
-        GLH_EXT_NAME(glCompressedTexSubImage3DARB) = (PFNGLCOMPRESSEDTEXSUBIMAGE3DARBPROC)GLH_EXT_GET_PROC_ADDRESS("glCompressedTexSubImage3DARB");
-        if (NULL == GLH_EXT_NAME(glCompressedTexSubImage3DARB))
-            return FALSE;
-        GLH_EXT_NAME(glCompressedTexSubImage2DARB) = (PFNGLCOMPRESSEDTEXSUBIMAGE2DARBPROC)GLH_EXT_GET_PROC_ADDRESS("glCompressedTexSubImage2DARB");
-        if (NULL == GLH_EXT_NAME(glCompressedTexSubImage2DARB))
-            return FALSE;
-        GLH_EXT_NAME(glCompressedTexSubImage1DARB) = (PFNGLCOMPRESSEDTEXSUBIMAGE1DARBPROC)GLH_EXT_GET_PROC_ADDRESS("glCompressedTexSubImage1DARB");
-        if (NULL == GLH_EXT_NAME(glCompressedTexSubImage1DARB))
-            return FALSE;
-        GLH_EXT_NAME(glGetCompressedTexImageARB) = (PFNGLGETCOMPRESSEDTEXIMAGEARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGetCompressedTexImageARB");
-        if (NULL == GLH_EXT_NAME(glGetCompressedTexImageARB))
-            return FALSE;
-#endif
-
-#ifdef GL_ARB_texture_cube_map
-    } else if (0 == strcmp(extension, "GL_ARB_texture_cube_map")) {
-#endif
-
-#ifdef GL_ARB_transpose_matrix
-    } else if (0 == strcmp(extension, "GL_ARB_transpose_matrix")) {
-        GLH_EXT_NAME(glLoadTransposeMatrixfARB) = (PFNGLLOADTRANSPOSEMATRIXFARBPROC)GLH_EXT_GET_PROC_ADDRESS("glLoadTransposeMatrixfARB");
-        if (NULL == GLH_EXT_NAME(glLoadTransposeMatrixfARB))
-            return FALSE;
-        GLH_EXT_NAME(glLoadTransposeMatrixdARB) = (PFNGLLOADTRANSPOSEMATRIXDARBPROC)GLH_EXT_GET_PROC_ADDRESS("glLoadTransposeMatrixdARB");
-        if (NULL == GLH_EXT_NAME(glLoadTransposeMatrixdARB))
-            return FALSE;
-        GLH_EXT_NAME(glMultTransposeMatrixfARB) = (PFNGLMULTTRANSPOSEMATRIXFARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultTransposeMatrixfARB");
-        if (NULL == GLH_EXT_NAME(glMultTransposeMatrixfARB))
-            return FALSE;
-        GLH_EXT_NAME(glMultTransposeMatrixdARB) = (PFNGLMULTTRANSPOSEMATRIXDARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultTransposeMatrixdARB");
-        if (NULL == GLH_EXT_NAME(glMultTransposeMatrixdARB))
-            return FALSE;
-#endif
-
-#ifdef GL_ARB_vertex_program
-    } else if (0 == strcmp(extension, "GL_ARB_vertex_program")) {
-        GLH_EXT_NAME(glVertexAttrib1sARB) = (PFNGLVERTEXATTRIB1SARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1sARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib1sARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib1fARB) = (PFNGLVERTEXATTRIB1FARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1fARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib1fARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib1dARB) = (PFNGLVERTEXATTRIB1DARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1dARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib1dARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib2sARB) = (PFNGLVERTEXATTRIB2SARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2sARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib2sARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib2fARB) = (PFNGLVERTEXATTRIB2FARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2fARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib2fARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib2dARB) = (PFNGLVERTEXATTRIB2DARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2dARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib2dARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib3sARB) = (PFNGLVERTEXATTRIB3SARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3sARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib3sARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib3fARB) = (PFNGLVERTEXATTRIB3FARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3fARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib3fARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib3dARB) = (PFNGLVERTEXATTRIB3DARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3dARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib3dARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib4sARB) = (PFNGLVERTEXATTRIB4SARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4sARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib4sARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib4fARB) = (PFNGLVERTEXATTRIB4FARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4fARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib4fARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib4dARB) = (PFNGLVERTEXATTRIB4DARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4dARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib4dARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib4NubARB) = (PFNGLVERTEXATTRIB4NUBARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4NubARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib4NubARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib1svARB) = (PFNGLVERTEXATTRIB1SVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1svARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib1svARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib1fvARB) = (PFNGLVERTEXATTRIB1FVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1fvARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib1fvARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib1dvARB) = (PFNGLVERTEXATTRIB1DVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1dvARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib1dvARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib2svARB) = (PFNGLVERTEXATTRIB2SVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2svARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib2svARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib2fvARB) = (PFNGLVERTEXATTRIB2FVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2fvARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib2fvARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib2dvARB) = (PFNGLVERTEXATTRIB2DVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2dvARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib2dvARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib3svARB) = (PFNGLVERTEXATTRIB3SVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3svARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib3svARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib3fvARB) = (PFNGLVERTEXATTRIB3FVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3fvARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib3fvARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib3dvARB) = (PFNGLVERTEXATTRIB3DVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3dvARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib3dvARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib4bvARB) = (PFNGLVERTEXATTRIB4BVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4bvARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib4bvARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib4svARB) = (PFNGLVERTEXATTRIB4SVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4svARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib4svARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib4ivARB) = (PFNGLVERTEXATTRIB4IVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4ivARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib4ivARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib4ubvARB) = (PFNGLVERTEXATTRIB4UBVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4ubvARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib4ubvARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib4usvARB) = (PFNGLVERTEXATTRIB4USVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4usvARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib4usvARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib4uivARB) = (PFNGLVERTEXATTRIB4UIVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4uivARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib4uivARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib4fvARB) = (PFNGLVERTEXATTRIB4FVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4fvARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib4fvARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib4dvARB) = (PFNGLVERTEXATTRIB4DVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4dvARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib4dvARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib4NbvARB) = (PFNGLVERTEXATTRIB4NBVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4NbvARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib4NbvARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib4NsvARB) = (PFNGLVERTEXATTRIB4NSVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4NsvARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib4NsvARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib4NivARB) = (PFNGLVERTEXATTRIB4NIVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4NivARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib4NivARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib4NubvARB) = (PFNGLVERTEXATTRIB4NUBVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4NubvARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib4NubvARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib4NusvARB) = (PFNGLVERTEXATTRIB4NUSVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4NusvARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib4NusvARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib4NuivARB) = (PFNGLVERTEXATTRIB4NUIVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4NuivARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib4NuivARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttribPointerARB) = (PFNGLVERTEXATTRIBPOINTERARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttribPointerARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttribPointerARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glEnableVertexAttribArrayARB) = (PFNGLENABLEVERTEXATTRIBARRAYARBPROC)GLH_EXT_GET_PROC_ADDRESS("glEnableVertexAttribArrayARB");
-        if (NULL == GLH_EXT_NAME(glEnableVertexAttribArrayARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glDisableVertexAttribArrayARB) = (PFNGLDISABLEVERTEXATTRIBARRAYARBPROC)GLH_EXT_GET_PROC_ADDRESS("glDisableVertexAttribArrayARB");
-        if (NULL == GLH_EXT_NAME(glDisableVertexAttribArrayARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glProgramStringARB) = (PFNGLPROGRAMSTRINGARBPROC)GLH_EXT_GET_PROC_ADDRESS("glProgramStringARB");
-        if (NULL == GLH_EXT_NAME(glProgramStringARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glBindProgramARB) = (PFNGLBINDPROGRAMARBPROC)GLH_EXT_GET_PROC_ADDRESS("glBindProgramARB");
-        if (NULL == GLH_EXT_NAME(glBindProgramARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glDeleteProgramsARB) = (PFNGLDELETEPROGRAMSARBPROC)GLH_EXT_GET_PROC_ADDRESS("glDeleteProgramsARB");
-        if (NULL == GLH_EXT_NAME(glDeleteProgramsARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glGenProgramsARB) = (PFNGLGENPROGRAMSARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGenProgramsARB");
-        if (NULL == GLH_EXT_NAME(glGenProgramsARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glProgramEnvParameter4dARB) = (PFNGLPROGRAMENVPARAMETER4DARBPROC)GLH_EXT_GET_PROC_ADDRESS("glProgramEnvParameter4dARB");
-        if (NULL == GLH_EXT_NAME(glProgramEnvParameter4dARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glProgramEnvParameter4dvARB) = (PFNGLPROGRAMENVPARAMETER4DVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glProgramEnvParameter4dvARB");
-        if (NULL == GLH_EXT_NAME(glProgramEnvParameter4dvARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glProgramEnvParameter4fARB) = (PFNGLPROGRAMENVPARAMETER4FARBPROC)GLH_EXT_GET_PROC_ADDRESS("glProgramEnvParameter4fARB");
-        if (NULL == GLH_EXT_NAME(glProgramEnvParameter4fARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glProgramEnvParameter4fvARB) = (PFNGLPROGRAMENVPARAMETER4FVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glProgramEnvParameter4fvARB");
-        if (NULL == GLH_EXT_NAME(glProgramEnvParameter4fvARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glProgramLocalParameter4dARB) = (PFNGLPROGRAMLOCALPARAMETER4DARBPROC)GLH_EXT_GET_PROC_ADDRESS("glProgramLocalParameter4dARB");
-        if (NULL == GLH_EXT_NAME(glProgramLocalParameter4dARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glProgramLocalParameter4dvARB) = (PFNGLPROGRAMLOCALPARAMETER4DVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glProgramLocalParameter4dvARB");
-        if (NULL == GLH_EXT_NAME(glProgramLocalParameter4dvARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glProgramLocalParameter4fARB) = (PFNGLPROGRAMLOCALPARAMETER4FARBPROC)GLH_EXT_GET_PROC_ADDRESS("glProgramLocalParameter4fARB");
-        if (NULL == GLH_EXT_NAME(glProgramLocalParameter4fARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glProgramLocalParameter4fvARB) = (PFNGLPROGRAMLOCALPARAMETER4FVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glProgramLocalParameter4fvARB");
-        if (NULL == GLH_EXT_NAME(glProgramLocalParameter4fvARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glGetProgramEnvParameterdvARB) = (PFNGLGETPROGRAMENVPARAMETERDVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGetProgramEnvParameterdvARB");
-        if (NULL == GLH_EXT_NAME(glGetProgramEnvParameterdvARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glGetProgramEnvParameterfvARB) = (PFNGLGETPROGRAMENVPARAMETERFVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGetProgramEnvParameterfvARB");
-        if (NULL == GLH_EXT_NAME(glGetProgramEnvParameterfvARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glGetProgramLocalParameterdvARB) = (PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGetProgramLocalParameterdvARB");
-        if (NULL == GLH_EXT_NAME(glGetProgramLocalParameterdvARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glGetProgramLocalParameterfvARB) = (PFNGLGETPROGRAMLOCALPARAMETERFVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGetProgramLocalParameterfvARB");
-        if (NULL == GLH_EXT_NAME(glGetProgramLocalParameterfvARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glGetProgramivARB) = (PFNGLGETPROGRAMIVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGetProgramivARB");
-        if (NULL == GLH_EXT_NAME(glGetProgramivARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glGetProgramStringARB) = (PFNGLGETPROGRAMSTRINGARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGetProgramStringARB");
-        if (NULL == GLH_EXT_NAME(glGetProgramStringARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glGetVertexAttribdvARB) = (PFNGLGETVERTEXATTRIBDVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGetVertexAttribdvARB");
-        if (NULL == GLH_EXT_NAME(glGetVertexAttribdvARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glGetVertexAttribfvARB) = (PFNGLGETVERTEXATTRIBFVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGetVertexAttribfvARB");
-        if (NULL == GLH_EXT_NAME(glGetVertexAttribfvARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glGetVertexAttribivARB) = (PFNGLGETVERTEXATTRIBIVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGetVertexAttribivARB");
-        if (NULL == GLH_EXT_NAME(glGetVertexAttribivARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glGetVertexAttribPointervARB) = (PFNGLGETVERTEXATTRIBPOINTERVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGetVertexAttribPointervARB");
-        if (NULL == GLH_EXT_NAME(glGetVertexAttribPointervARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glIsProgramARB) = (PFNGLISPROGRAMARBPROC)GLH_EXT_GET_PROC_ADDRESS("glIsProgramARB");
-        if (NULL == GLH_EXT_NAME(glIsProgramARB))
-            return GL_FALSE;
-#endif
-
-#ifdef GL_EXT_abgr
-    } else if (0 == strcmp(extension, "GL_EXT_abgr")) {
-#endif
-
-#ifdef GL_EXT_bgra
-    } else if (0 == strcmp(extension, "GL_EXT_bgra")) {
-#endif
-
-#ifdef GL_EXT_blend_color
-    } else if (0 == strcmp(extension, "GL_EXT_blend_color")) {
-        GLH_EXT_NAME(glBlendColorEXT) = (PFNGLBLENDCOLOREXTPROC)GLH_EXT_GET_PROC_ADDRESS("glBlendColorEXT");
-        if (NULL == GLH_EXT_NAME(glBlendColorEXT))
-            return FALSE;
-#endif
-
-#ifdef GL_EXT_blend_minmax
-    } else if (0 == strcmp(extension, "GL_EXT_blend_minmax")) {
-        GLH_EXT_NAME(glBlendEquationEXT) = (PFNGLBLENDEQUATIONEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glBlendEquationEXT");
-        if (NULL == GLH_EXT_NAME(glBlendEquationEXT))
-            return FALSE;
-#endif
-
-#ifdef GL_EXT_blend_subtract
-    } else if (0 == strcmp(extension, "GL_EXT_blend_subtract")) {
-#endif
-
-#ifdef GL_EXT_compiled_vertex_array
-    } else if (0 == strcmp(extension, "GL_EXT_compiled_vertex_array")) {
-        GLH_EXT_NAME(glLockArraysEXT) = (PFNGLLOCKARRAYSEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glLockArraysEXT");
-        if (NULL == GLH_EXT_NAME(glLockArraysEXT))
-            return FALSE;
-        GLH_EXT_NAME(glUnlockArraysEXT) = (PFNGLUNLOCKARRAYSEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glUnlockArraysEXT");
-        if (NULL == GLH_EXT_NAME(glUnlockArraysEXT))
-            return FALSE;
-#endif
-
-#ifdef GL_EXT_fog_coord
-    } else if (0 == strcmp(extension, "GL_EXT_fog_coord")) {
-        GLH_EXT_NAME(glFogCoorddEXT) = (PFNGLFOGCOORDDEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glFogCoorddEXT");
-        if (NULL == GLH_EXT_NAME(glFogCoorddEXT))
-            return FALSE;
-        GLH_EXT_NAME(glFogCoorddvEXT) = (PFNGLFOGCOORDDVEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glFogCoorddvEXT");
-        if (NULL == GLH_EXT_NAME(glFogCoorddvEXT))
-            return FALSE;
-        GLH_EXT_NAME(glFogCoordfEXT) = (PFNGLFOGCOORDFEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glFogCoordfEXT");
-        if (NULL == GLH_EXT_NAME(glFogCoordfEXT))
-            return FALSE;
-        GLH_EXT_NAME(glFogCoordfvEXT) = (PFNGLFOGCOORDFVEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glFogCoordfvEXT");
-        if (NULL == GLH_EXT_NAME(glFogCoordfvEXT))
-            return FALSE;
-        GLH_EXT_NAME(glFogCoordPointerEXT) = (PFNGLFOGCOORDPOINTEREXTPROC)GLH_EXT_GET_PROC_ADDRESS("glFogCoordPointerEXT");
-        if (NULL == GLH_EXT_NAME(glFogCoordPointerEXT))
-            return FALSE;
-#endif
-
-#ifdef GL_EXT_light_max_exponent
-    } else if (0 == strcmp(extension, "GL_EXT_light_max_exponent")) {
-#endif
-
-#ifdef GL_EXT_packed_pixels
-    } else if (0 == strcmp(extension, "GL_EXT_packed_pixels")) {
-#endif
-
-#ifdef GL_EXT_paletted_texture
-    } else if (0 == strcmp(extension, "GL_EXT_paletted_texture")) {
-        GLH_EXT_NAME(glColorSubTableEXT) = (PFNGLCOLORSUBTABLEEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glColorSubTableEXT");
-        if (NULL == GLH_EXT_NAME(glColorSubTableEXT))
-            return FALSE;
-        GLH_EXT_NAME(glColorTableEXT) = (PFNGLCOLORTABLEEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glColorTableEXT");
-        if (NULL == GLH_EXT_NAME(glColorTableEXT))
-            return FALSE;
-        GLH_EXT_NAME(glGetColorTableEXT) = (PFNGLGETCOLORTABLEEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glGetColorTableEXT");
-        if (NULL == GLH_EXT_NAME(glGetColorTableEXT))
-            return FALSE;
-        GLH_EXT_NAME(glGetColorTableParameterfvEXT) = (PFNGLGETCOLORTABLEPARAMETERFVEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glGetColorTableParameterfvEXT");
-        if (NULL == GLH_EXT_NAME(glGetColorTableParameterfvEXT))
-            return FALSE;
-        GLH_EXT_NAME(glGetColorTableParameterivEXT) = (PFNGLGETCOLORTABLEPARAMETERIVEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glGetColorTableParameterivEXT");
-        if (NULL == GLH_EXT_NAME(glGetColorTableParameterivEXT))
-            return FALSE;
-#endif
-
-#ifdef GL_EXT_point_parameters
-    } else if (0 == strcmp(extension, "GL_EXT_point_parameters")) {
-        GLH_EXT_NAME(glPointParameterfEXT) = (PFNGLPOINTPARAMETERFEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glPointParameterfEXT");
-        if (NULL == GLH_EXT_NAME(glPointParameterfEXT))
-            return FALSE;
-        GLH_EXT_NAME(glPointParameterfvEXT) = (PFNGLPOINTPARAMETERFVEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glPointParameterfvEXT");
-        if (NULL == GLH_EXT_NAME(glPointParameterfvEXT))
-            return FALSE;
-#endif
-
-#ifdef GL_EXT_rescale_normal
-    } else if (0 == strcmp(extension, "GL_EXT_rescale_normal")) {
-#endif
-
-#ifdef GL_EXT_secondary_color
-    } else if (0 == strcmp(extension, "GL_EXT_secondary_color")) {
-        GLH_EXT_NAME(glSecondaryColor3bEXT) = (PFNGLSECONDARYCOLOR3BEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glSecondaryColor3bEXT");
-        if (NULL == GLH_EXT_NAME(glSecondaryColor3bEXT))
-            return FALSE;
-        GLH_EXT_NAME(glSecondaryColor3bvEXT) = (PFNGLSECONDARYCOLOR3BVEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glSecondaryColor3bvEXT");
-        if (NULL == GLH_EXT_NAME(glSecondaryColor3bvEXT))
-            return FALSE;
-        GLH_EXT_NAME(glSecondaryColor3dEXT) = (PFNGLSECONDARYCOLOR3DEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glSecondaryColor3dEXT");
-        if (NULL == GLH_EXT_NAME(glSecondaryColor3dEXT))
-            return FALSE;
-        GLH_EXT_NAME(glSecondaryColor3dvEXT) = (PFNGLSECONDARYCOLOR3DVEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glSecondaryColor3dvEXT");
-        if (NULL == GLH_EXT_NAME(glSecondaryColor3dvEXT))
-            return FALSE;
-        GLH_EXT_NAME(glSecondaryColor3fEXT) = (PFNGLSECONDARYCOLOR3FEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glSecondaryColor3fEXT");
-        if (NULL == GLH_EXT_NAME(glSecondaryColor3fEXT))
-            return FALSE;
-        GLH_EXT_NAME(glSecondaryColor3fvEXT) = (PFNGLSECONDARYCOLOR3FVEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glSecondaryColor3fvEXT");
-        if (NULL == GLH_EXT_NAME(glSecondaryColor3fvEXT))
-            return FALSE;
-        GLH_EXT_NAME(glSecondaryColor3iEXT) = (PFNGLSECONDARYCOLOR3IEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glSecondaryColor3iEXT");
-        if (NULL == GLH_EXT_NAME(glSecondaryColor3iEXT))
-            return FALSE;
-        GLH_EXT_NAME(glSecondaryColor3ivEXT) = (PFNGLSECONDARYCOLOR3IVEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glSecondaryColor3ivEXT");
-        if (NULL == GLH_EXT_NAME(glSecondaryColor3ivEXT))
-            return FALSE;
-        GLH_EXT_NAME(glSecondaryColor3sEXT) = (PFNGLSECONDARYCOLOR3SEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glSecondaryColor3sEXT");
-        if (NULL == GLH_EXT_NAME(glSecondaryColor3sEXT))
-            return FALSE;
-        GLH_EXT_NAME(glSecondaryColor3svEXT) = (PFNGLSECONDARYCOLOR3SVEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glSecondaryColor3svEXT");
-        if (NULL == GLH_EXT_NAME(glSecondaryColor3svEXT))
-            return FALSE;
-        GLH_EXT_NAME(glSecondaryColor3ubEXT) = (PFNGLSECONDARYCOLOR3UBEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glSecondaryColor3ubEXT");
-        if (NULL == GLH_EXT_NAME(glSecondaryColor3ubEXT))
-            return FALSE;
-        GLH_EXT_NAME(glSecondaryColor3ubvEXT) = (PFNGLSECONDARYCOLOR3UBVEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glSecondaryColor3ubvEXT");
-        if (NULL == GLH_EXT_NAME(glSecondaryColor3ubvEXT))
-            return FALSE;
-        GLH_EXT_NAME(glSecondaryColor3uiEXT) = (PFNGLSECONDARYCOLOR3UIEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glSecondaryColor3uiEXT");
-        if (NULL == GLH_EXT_NAME(glSecondaryColor3uiEXT))
-            return FALSE;
-        GLH_EXT_NAME(glSecondaryColor3uivEXT) = (PFNGLSECONDARYCOLOR3UIVEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glSecondaryColor3uivEXT");
-        if (NULL == GLH_EXT_NAME(glSecondaryColor3uivEXT))
-            return FALSE;
-        GLH_EXT_NAME(glSecondaryColor3usEXT) = (PFNGLSECONDARYCOLOR3USEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glSecondaryColor3usEXT");
-        if (NULL == GLH_EXT_NAME(glSecondaryColor3usEXT))
-            return FALSE;
-        GLH_EXT_NAME(glSecondaryColor3usvEXT) = (PFNGLSECONDARYCOLOR3USVEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glSecondaryColor3usvEXT");
-        if (NULL == GLH_EXT_NAME(glSecondaryColor3usvEXT))
-            return FALSE;
-        GLH_EXT_NAME(glSecondaryColorPointerEXT) = (PFNGLSECONDARYCOLORPOINTEREXTPROC)GLH_EXT_GET_PROC_ADDRESS("glSecondaryColorPointerEXT");
-        if (NULL == GLH_EXT_NAME(glSecondaryColorPointerEXT))
-            return FALSE;
-#endif
-
-#ifdef GL_EXT_separate_specular_color
-    } else if (0 == strcmp(extension, "GL_EXT_separate_specular_color")) {
-#endif
-
-#ifdef GL_EXT_shared_texture_palette
-    } else if (0 == strcmp(extension, "GL_EXT_shared_texture_palette")) {
-#endif
-
-#ifdef GL_EXT_stencil_wrap
-    } else if (0 == strcmp(extension, "GL_EXT_stencil_wrap")) {
-#endif
-
-#ifdef GL_EXT_texture_compression_s3tc
-    } else if (0 == strcmp(extension, "GL_EXT_texture_compression_s3tc")) {
-#endif
-
-#ifdef GL_EXT_texture_cube_map
-    } else if (0 == strcmp(extension, "GL_EXT_texture_cube_map")) {
-#endif
-
-#ifdef GL_EXT_texture_edge_clamp
-    } else if (0 == strcmp(extension, "GL_EXT_texture_edge_clamp")) {
-#endif
-
-#ifdef GL_EXT_texture_env_add
-    } else if (0 == strcmp(extension, "GL_EXT_texture_env_add")) {
-#endif
-
-#ifdef GL_EXT_texture_env_combine
-    } else if (0 == strcmp(extension, "GL_EXT_texture_env_combine")) {
-#endif
-
-#ifdef GL_EXT_texture_filter_anisotropic
-    } else if (0 == strcmp(extension, "GL_EXT_texture_filter_anisotropic")) {
-#endif
-
-#ifdef GL_EXT_texture_lod_bias
-    } else if (0 == strcmp(extension, "GL_EXT_texture_lod_bias")) {
-#endif
-
-#ifdef GL_EXT_texture_object
-    } else if (0 == strcmp(extension, "GL_EXT_texture_object")) {
-        GLH_EXT_NAME(glAreTexturesResidentEXT) = (PFNGLARETEXTURESRESIDENTEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glAreTexturesResidentEXT");
-        if (NULL == GLH_EXT_NAME(glAreTexturesResidentEXT))
-            return FALSE;
-        GLH_EXT_NAME(glBindTextureEXT) = (PFNGLBINDTEXTUREEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glBindTextureEXT");
-        if (NULL == GLH_EXT_NAME(glBindTextureEXT))
-            return FALSE;
-        GLH_EXT_NAME(glDeleteTexturesEXT) = (PFNGLDELETETEXTURESEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glDeleteTexturesEXT");
-        if (NULL == GLH_EXT_NAME(glDeleteTexturesEXT))
-            return FALSE;
-        GLH_EXT_NAME(glGenTexturesEXT) = (PFNGLGENTEXTURESEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glGenTexturesEXT");
-        if (NULL == GLH_EXT_NAME(glGenTexturesEXT))
-            return FALSE;
-        GLH_EXT_NAME(glIsTextureEXT) = (PFNGLISTEXTUREEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glIsTextureEXT");
-        if (NULL == GLH_EXT_NAME(glIsTextureEXT))
-            return FALSE;
-        GLH_EXT_NAME(glPrioritizeTexturesEXT) = (PFNGLPRIORITIZETEXTURESEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glPrioritizeTexturesEXT");
-        if (NULL == GLH_EXT_NAME(glPrioritizeTexturesEXT))
-            return FALSE;
-#endif
-
-#ifdef GL_EXT_texture3D
-    } else if (0 == strcmp(extension, "GL_EXT_texture3D")) {
-        GLH_EXT_NAME(glTexImage3DEXT) = (PFNGLTEXIMAGE3DEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glTexImage3DEXT");
-        if (NULL == GLH_EXT_NAME(glTexImage3DEXT))
-            return FALSE;
-#endif
-
-#ifdef GL_EXT_vertex_array
-    } else if (0 == strcmp(extension, "GL_EXT_vertex_array")) {
-        GLH_EXT_NAME(glArrayElementEXT) = (PFNGLARRAYELEMENTEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glArrayElementEXT");
-        if (NULL == GLH_EXT_NAME(glArrayElementEXT))
-            return FALSE;
-        GLH_EXT_NAME(glColorPointerEXT) = (PFNGLCOLORPOINTEREXTPROC)GLH_EXT_GET_PROC_ADDRESS("glColorPointerEXT");
-        if (NULL == GLH_EXT_NAME(glColorPointerEXT))
-            return FALSE;
-        GLH_EXT_NAME(glEdgeFlagPointerEXT) = (PFNGLEDGEFLAGPOINTEREXTPROC)GLH_EXT_GET_PROC_ADDRESS("glEdgeFlagPointerEXT");
-        if (NULL == GLH_EXT_NAME(glEdgeFlagPointerEXT))
-            return FALSE;
-        GLH_EXT_NAME(glGetPointervEXT) = (PFNGLGETPOINTERVEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glGetPointervEXT");
-        if (NULL == GLH_EXT_NAME(glGetPointervEXT))
-            return FALSE;
-        GLH_EXT_NAME(glIndexPointerEXT) = (PFNGLINDEXPOINTEREXTPROC)GLH_EXT_GET_PROC_ADDRESS("glIndexPointerEXT");
-        if (NULL == GLH_EXT_NAME(glIndexPointerEXT))
-            return FALSE;
-        GLH_EXT_NAME(glNormalPointerEXT) = (PFNGLNORMALPOINTEREXTPROC)GLH_EXT_GET_PROC_ADDRESS("glNormalPointerEXT");
-        if (NULL == GLH_EXT_NAME(glNormalPointerEXT))
-            return FALSE;
-        GLH_EXT_NAME(glTexCoordPointerEXT) = (PFNGLTEXCOORDPOINTEREXTPROC)GLH_EXT_GET_PROC_ADDRESS("glTexCoordPointerEXT");
-        if (NULL == GLH_EXT_NAME(glTexCoordPointerEXT))
-            return FALSE;
-        GLH_EXT_NAME(glVertexPointerEXT) = (PFNGLVERTEXPOINTEREXTPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexPointerEXT");
-        if (NULL == GLH_EXT_NAME(glVertexPointerEXT))
-            return FALSE;
-        GLH_EXT_NAME(glDrawArraysEXT) = (PFNGLDRAWARRAYSEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glDrawArraysEXT");
-        if (NULL == GLH_EXT_NAME(glDrawArraysEXT))
-            return FALSE;
-#endif
-
-#ifdef GL_EXT_vertex_weighting
-    } else if (0 == strcmp(extension, "GL_EXT_vertex_weighting")) {
-        GLH_EXT_NAME(glVertexWeightfEXT) = (PFNGLVERTEXWEIGHTFEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexWeightfEXT");
-        if (NULL == GLH_EXT_NAME(glVertexWeightfEXT))
-            return FALSE;
-        GLH_EXT_NAME(glVertexWeightfvEXT) = (PFNGLVERTEXWEIGHTFVEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexWeightfvEXT");
-        if (NULL == GLH_EXT_NAME(glVertexWeightfvEXT))
-            return FALSE;
-        GLH_EXT_NAME(glVertexWeightPointerEXT) = (PFNGLVERTEXWEIGHTPOINTEREXTPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexWeightPointerEXT");
-        if (NULL == GLH_EXT_NAME(glVertexWeightPointerEXT))
-            return FALSE;
-#endif
-
-#ifdef GL_NV_blend_square
-    } else if (0 == strcmp(extension, "GL_NV_blend_square")) {
-#endif
-
-#ifdef GL_NV_evaluators
-    } else if (0 == strcmp(extension, "GL_NV_evaluators")) {
-        GLH_EXT_NAME(glMapControlPointsNV) = (PFNGLMAPCONTROLPOINTSNVPROC)GLH_EXT_GET_PROC_ADDRESS("glMapControlPointsNV");
-        if (NULL == GLH_EXT_NAME(glMapControlPointsNV))
-            return FALSE;
-        GLH_EXT_NAME(glMapParameterivNV) = (PFNGLMAPPARAMETERIVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glMapParameterivNV");
-        if (NULL == GLH_EXT_NAME(glMapParameterivNV))
-            return FALSE;
-        GLH_EXT_NAME(glMapParameterfvNV) = (PFNGLMAPPARAMETERFVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glMapParameterfvNV");
-        if (NULL == GLH_EXT_NAME(glMapParameterfvNV))
-            return FALSE;
-        GLH_EXT_NAME(glGetMapControlPointsNV) = (PFNGLGETMAPCONTROLPOINTSNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetMapControlPointsNV");
-        if (NULL == GLH_EXT_NAME(glGetMapControlPointsNV))
-            return FALSE;
-        GLH_EXT_NAME(glGetMapParameterivNV) = (PFNGLGETMAPPARAMETERIVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetMapParameterivNV");
-        if (NULL == GLH_EXT_NAME(glGetMapParameterivNV))
-            return FALSE;
-        GLH_EXT_NAME(glGetMapParameterfvNV) = (PFNGLGETMAPPARAMETERFVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetMapParameterfvNV");
-        if (NULL == GLH_EXT_NAME(glGetMapParameterfvNV))
-            return FALSE;
-        GLH_EXT_NAME(glGetMapAttribParameterivNV) = (PFNGLGETMAPATTRIBPARAMETERIVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetMapAttribParameterivNV");
-        if (NULL == GLH_EXT_NAME(glGetMapAttribParameterivNV))
-            return FALSE;
-        GLH_EXT_NAME(glGetMapAttribParameterfvNV) = (PFNGLGETMAPATTRIBPARAMETERFVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetMapAttribParameterfvNV");
-        if (NULL == GLH_EXT_NAME(glGetMapAttribParameterfvNV))
-            return FALSE;
-        GLH_EXT_NAME(glEvalMapsNV) = (PFNGLEVALMAPSNVPROC)GLH_EXT_GET_PROC_ADDRESS("glEvalMapsNV");
-        if (NULL == GLH_EXT_NAME(glEvalMapsNV))
-            return FALSE;
-#endif
-
-#ifdef GL_NV_fence
-    } else if (0 == strcmp(extension, "GL_NV_fence")) {
-        GLH_EXT_NAME(glGenFencesNV) = (PFNGLGENFENCESNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGenFencesNV");
-        if (NULL == GLH_EXT_NAME(glGenFencesNV))
-            return FALSE;
-        GLH_EXT_NAME(glDeleteFencesNV) = (PFNGLDELETEFENCESNVPROC)GLH_EXT_GET_PROC_ADDRESS("glDeleteFencesNV");
-        if (NULL == GLH_EXT_NAME(glDeleteFencesNV))
-            return FALSE;
-        GLH_EXT_NAME(glSetFenceNV) = (PFNGLSETFENCENVPROC)GLH_EXT_GET_PROC_ADDRESS("glSetFenceNV");
-        if (NULL == GLH_EXT_NAME(glSetFenceNV))
-            return FALSE;
-        GLH_EXT_NAME(glTestFenceNV) = (PFNGLTESTFENCENVPROC)GLH_EXT_GET_PROC_ADDRESS("glTestFenceNV");
-        if (NULL == GLH_EXT_NAME(glTestFenceNV))
-            return FALSE;
-        GLH_EXT_NAME(glFinishFenceNV) = (PFNGLFINISHFENCENVPROC)GLH_EXT_GET_PROC_ADDRESS("glFinishFenceNV");
-        if (NULL == GLH_EXT_NAME(glFinishFenceNV))
-            return FALSE;
-        GLH_EXT_NAME(glIsFenceNV) = (PFNGLISFENCENVPROC)GLH_EXT_GET_PROC_ADDRESS("glIsFenceNV");
-        if (NULL == GLH_EXT_NAME(glIsFenceNV))
-            return FALSE;
-        GLH_EXT_NAME(glGetFenceivNV) = (PFNGLGETFENCEIVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetFenceivNV");
-        if (NULL == GLH_EXT_NAME(glGetFenceivNV))
-            return FALSE;
-#endif
-
-#ifdef GL_NV_fog_distance
-    } else if (0 == strcmp(extension, "GL_NV_fog_distance")) {
-#endif
-
-#ifdef GL_NV_packed_depth_stencil
-    } else if (0 == strcmp(extension, "GL_NV_packed_depth_stencil")) {
-#endif
-
-#ifdef GL_NV_register_combiners
-    } else if (0 == strcmp(extension, "GL_NV_register_combiners")) {
-        GLH_EXT_NAME(glCombinerParameterfvNV) = (PFNGLCOMBINERPARAMETERFVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glCombinerParameterfvNV");
-        if (NULL == GLH_EXT_NAME(glCombinerParameterfvNV))
-            return FALSE;
-        GLH_EXT_NAME(glCombinerParameterfNV) = (PFNGLCOMBINERPARAMETERFNVPROC)GLH_EXT_GET_PROC_ADDRESS("glCombinerParameterfNV");
-        if (NULL == GLH_EXT_NAME(glCombinerParameterfNV))
-            return FALSE;
-        GLH_EXT_NAME(glCombinerParameterivNV) = (PFNGLCOMBINERPARAMETERIVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glCombinerParameterivNV");
-        if (NULL == GLH_EXT_NAME(glCombinerParameterivNV))
-            return FALSE;
-        GLH_EXT_NAME(glCombinerParameteriNV) = (PFNGLCOMBINERPARAMETERINVPROC)GLH_EXT_GET_PROC_ADDRESS("glCombinerParameteriNV");
-        if (NULL == GLH_EXT_NAME(glCombinerParameteriNV))
-            return FALSE;
-        GLH_EXT_NAME(glCombinerInputNV) = (PFNGLCOMBINERINPUTNVPROC)GLH_EXT_GET_PROC_ADDRESS("glCombinerInputNV");
-        if (NULL == GLH_EXT_NAME(glCombinerInputNV))
-            return FALSE;
-        GLH_EXT_NAME(glCombinerOutputNV) = (PFNGLCOMBINEROUTPUTNVPROC)GLH_EXT_GET_PROC_ADDRESS("glCombinerOutputNV");
-        if (NULL == GLH_EXT_NAME(glCombinerOutputNV))
-            return FALSE;
-        GLH_EXT_NAME(glFinalCombinerInputNV) = (PFNGLFINALCOMBINERINPUTNVPROC)GLH_EXT_GET_PROC_ADDRESS("glFinalCombinerInputNV");
-        if (NULL == GLH_EXT_NAME(glFinalCombinerInputNV))
-            return FALSE;
-        GLH_EXT_NAME(glGetCombinerInputParameterfvNV) = (PFNGLGETCOMBINERINPUTPARAMETERFVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetCombinerInputParameterfvNV");
-        if (NULL == GLH_EXT_NAME(glGetCombinerInputParameterfvNV))
-            return FALSE;
-        GLH_EXT_NAME(glGetCombinerInputParameterivNV) = (PFNGLGETCOMBINERINPUTPARAMETERIVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetCombinerInputParameterivNV");
-        if (NULL == GLH_EXT_NAME(glGetCombinerInputParameterivNV))
-            return FALSE;
-        GLH_EXT_NAME(glGetCombinerOutputParameterfvNV) = (PFNGLGETCOMBINEROUTPUTPARAMETERFVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetCombinerOutputParameterfvNV");
-        if (NULL == GLH_EXT_NAME(glGetCombinerOutputParameterfvNV))
-            return FALSE;
-        GLH_EXT_NAME(glGetCombinerOutputParameterivNV) = (PFNGLGETCOMBINEROUTPUTPARAMETERIVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetCombinerOutputParameterivNV");
-        if (NULL == GLH_EXT_NAME(glGetCombinerOutputParameterivNV))
-            return FALSE;
-        GLH_EXT_NAME(glGetFinalCombinerInputParameterfvNV) = (PFNGLGETFINALCOMBINERINPUTPARAMETERFVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetFinalCombinerInputParameterfvNV");
-        if (NULL == GLH_EXT_NAME(glGetFinalCombinerInputParameterfvNV))
-            return FALSE;
-        GLH_EXT_NAME(glGetFinalCombinerInputParameterivNV) = (PFNGLGETFINALCOMBINERINPUTPARAMETERIVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetFinalCombinerInputParameterivNV");
-        if (NULL == GLH_EXT_NAME(glGetFinalCombinerInputParameterivNV))
-            return FALSE;
-#endif
-
-#ifdef GL_NV_register_combiners2
-    } else if (0 == strcmp(extension, "GL_NV_register_combiners2")) {
-        GLH_EXT_NAME(glCombinerStageParameterfvNV) = (PFNGLCOMBINERSTAGEPARAMETERFVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glCombinerStageParameterfvNV");
-        if (NULL == GLH_EXT_NAME(glCombinerStageParameterfvNV))
-            return FALSE;
-        GLH_EXT_NAME(glGetCombinerStageParameterfvNV) = (PFNGLGETCOMBINERSTAGEPARAMETERFVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetCombinerStageParameterfvNV");
-        if (NULL == GLH_EXT_NAME(glGetCombinerStageParameterfvNV))
-            return FALSE;
-#endif
-
-#ifdef GL_NV_texgen_reflection
-    } else if (0 == strcmp(extension, "GL_NV_texgen_reflection")) {
-#endif
-
-#ifdef GL_NV_texture_env_combine4
-    } else if (0 == strcmp(extension, "GL_NV_texture_env_combine4")) {
-#endif
-
-#ifdef GL_NV_texture_rectangle
-    } else if (0 == strcmp(extension, "GL_NV_texture_rectangle")) {
-#endif
-
-#ifdef GL_NV_texture_shader
-    } else if (0 == strcmp(extension, "GL_NV_texture_shader")) {
-#endif
-
-#ifdef GL_NV_vertex_array_range
-    } else if (0 == strcmp(extension, "GL_NV_vertex_array_range")) {
-        GLH_EXT_NAME(glFlushVertexArrayRangeNV) = (PFNGLFLUSHVERTEXARRAYRANGENVPROC)GLH_EXT_GET_PROC_ADDRESS("glFlushVertexArrayRangeNV");
-        if (NULL == GLH_EXT_NAME(glFlushVertexArrayRangeNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexArrayRangeNV) = (PFNGLVERTEXARRAYRANGENVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexArrayRangeNV");
-        if (NULL == GLH_EXT_NAME(glVertexArrayRangeNV))
-            return FALSE;
-# ifdef _WIN32
-        GLH_EXT_NAME(wglAllocateMemoryNV) = (PFNWGLALLOCATEMEMORYNVPROC)GLH_EXT_GET_PROC_ADDRESS("wglAllocateMemoryNV");
-        if (NULL == GLH_EXT_NAME(wglAllocateMemoryNV))
-            return FALSE;
-# endif
-# ifdef GLX_VERSION_1_3
-        GLH_EXT_NAME(glXAllocateMemoryNV) = (PFNGLXALLOCATEMEMORYNVPROC)GLH_EXT_GET_PROC_ADDRESS("glXAllocateMemoryNV");
-        if (NULL == GLH_EXT_NAME(glXAllocateMemoryNV))
-            return FALSE;
-# endif
-# ifdef _WIN32
-        GLH_EXT_NAME(wglFreeMemoryNV) = (PFNWGLFREEMEMORYNVPROC)GLH_EXT_GET_PROC_ADDRESS("wglFreeMemoryNV");
-        if (NULL == GLH_EXT_NAME(wglFreeMemoryNV))
-            return FALSE;
-# endif
-# ifdef GLX_VERSION_1_3
-        GLH_EXT_NAME(glXFreeMemoryNV) = (PFNGLXFREEMEMORYNVPROC)GLH_EXT_GET_PROC_ADDRESS("glXFreeMemoryNV");
-        if (NULL == GLH_EXT_NAME(glXFreeMemoryNV))
-            return FALSE;
-# endif
-#endif
-
-#ifdef GL_NV_vertex_program
-    } else if (0 == strcmp(extension, "GL_NV_vertex_program")) {
-        GLH_EXT_NAME(glAreProgramsResidentNV) = (PFNGLAREPROGRAMSRESIDENTNVPROC)GLH_EXT_GET_PROC_ADDRESS("glAreProgramsResidentNV");
-        if (NULL == GLH_EXT_NAME(glAreProgramsResidentNV))
-            return FALSE;
-        GLH_EXT_NAME(glBindProgramNV) = (PFNGLBINDPROGRAMNVPROC)GLH_EXT_GET_PROC_ADDRESS("glBindProgramNV");
-        if (NULL == GLH_EXT_NAME(glBindProgramNV))
-            return FALSE;
-        GLH_EXT_NAME(glDeleteProgramsNV) = (PFNGLDELETEPROGRAMSNVPROC)GLH_EXT_GET_PROC_ADDRESS("glDeleteProgramsNV");
-        if (NULL == GLH_EXT_NAME(glDeleteProgramsNV))
-            return FALSE;
-        GLH_EXT_NAME(glExecuteProgramNV) = (PFNGLEXECUTEPROGRAMNVPROC)GLH_EXT_GET_PROC_ADDRESS("glExecuteProgramNV");
-        if (NULL == GLH_EXT_NAME(glExecuteProgramNV))
-            return FALSE;
-        GLH_EXT_NAME(glGenProgramsNV) = (PFNGLGENPROGRAMSNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGenProgramsNV");
-        if (NULL == GLH_EXT_NAME(glGenProgramsNV))
-            return FALSE;
-        GLH_EXT_NAME(glGetProgramParameterdvNV) = (PFNGLGETPROGRAMPARAMETERDVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetProgramParameterdvNV");
-        if (NULL == GLH_EXT_NAME(glGetProgramParameterdvNV))
-            return FALSE;
-        GLH_EXT_NAME(glGetProgramParameterfvNV) = (PFNGLGETPROGRAMPARAMETERFVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetProgramParameterfvNV");
-        if (NULL == GLH_EXT_NAME(glGetProgramParameterfvNV))
-            return FALSE;
-        GLH_EXT_NAME(glGetProgramivNV) = (PFNGLGETPROGRAMIVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetProgramivNV");
-        if (NULL == GLH_EXT_NAME(glGetProgramivNV))
-            return FALSE;
-        GLH_EXT_NAME(glGetProgramStringNV) = (PFNGLGETPROGRAMSTRINGNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetProgramStringNV");
-        if (NULL == GLH_EXT_NAME(glGetProgramStringNV))
-            return FALSE;
-        GLH_EXT_NAME(glGetTrackMatrixivNV) = (PFNGLGETTRACKMATRIXIVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetTrackMatrixivNV");
-        if (NULL == GLH_EXT_NAME(glGetTrackMatrixivNV))
-            return FALSE;
-        GLH_EXT_NAME(glGetVertexAttribdvNV) = (PFNGLGETVERTEXATTRIBDVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetVertexAttribdvNV");
-        if (NULL == GLH_EXT_NAME(glGetVertexAttribdvNV))
-            return FALSE;
-        GLH_EXT_NAME(glGetVertexAttribfvNV) = (PFNGLGETVERTEXATTRIBFVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetVertexAttribfvNV");
-        if (NULL == GLH_EXT_NAME(glGetVertexAttribfvNV))
-            return FALSE;
-        GLH_EXT_NAME(glGetVertexAttribivNV) = (PFNGLGETVERTEXATTRIBIVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetVertexAttribivNV");
-        if (NULL == GLH_EXT_NAME(glGetVertexAttribivNV))
-            return FALSE;
-        GLH_EXT_NAME(glGetVertexAttribPointervNV) = (PFNGLGETVERTEXATTRIBPOINTERVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetVertexAttribPointervNV");
-        if (NULL == GLH_EXT_NAME(glGetVertexAttribPointervNV))
-            return FALSE;
-        GLH_EXT_NAME(glIsProgramNV) = (PFNGLISPROGRAMNVPROC)GLH_EXT_GET_PROC_ADDRESS("glIsProgramNV");
-        if (NULL == GLH_EXT_NAME(glIsProgramNV))
-            return FALSE;
-        GLH_EXT_NAME(glLoadProgramNV) = (PFNGLLOADPROGRAMNVPROC)GLH_EXT_GET_PROC_ADDRESS("glLoadProgramNV");
-        if (NULL == GLH_EXT_NAME(glLoadProgramNV))
-            return FALSE;
-        GLH_EXT_NAME(glProgramParameter4dNV) = (PFNGLPROGRAMPARAMETER4DNVPROC)GLH_EXT_GET_PROC_ADDRESS("glProgramParameter4dNV");
-        if (NULL == GLH_EXT_NAME(glProgramParameter4dNV))
-            return FALSE;
-        GLH_EXT_NAME(glProgramParameter4dvNV) = (PFNGLPROGRAMPARAMETER4DVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glProgramParameter4dvNV");
-        if (NULL == GLH_EXT_NAME(glProgramParameter4dvNV))
-            return FALSE;
-        GLH_EXT_NAME(glProgramParameter4fNV) = (PFNGLPROGRAMPARAMETER4FNVPROC)GLH_EXT_GET_PROC_ADDRESS("glProgramParameter4fNV");
-        if (NULL == GLH_EXT_NAME(glProgramParameter4fNV))
-            return FALSE;
-        GLH_EXT_NAME(glProgramParameter4fvNV) = (PFNGLPROGRAMPARAMETER4FVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glProgramParameter4fvNV");
-        if (NULL == GLH_EXT_NAME(glProgramParameter4fvNV))
-            return FALSE;
-        GLH_EXT_NAME(glProgramParameters4dvNV) = (PFNGLPROGRAMPARAMETERS4DVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glProgramParameters4dvNV");
-        if (NULL == GLH_EXT_NAME(glProgramParameters4dvNV))
-            return FALSE;
-        GLH_EXT_NAME(glProgramParameters4fvNV) = (PFNGLPROGRAMPARAMETERS4FVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glProgramParameters4fvNV");
-        if (NULL == GLH_EXT_NAME(glProgramParameters4fvNV))
-            return FALSE;
-        GLH_EXT_NAME(glRequestResidentProgramsNV) = (PFNGLREQUESTRESIDENTPROGRAMSNVPROC)GLH_EXT_GET_PROC_ADDRESS("glRequestResidentProgramsNV");
-        if (NULL == GLH_EXT_NAME(glRequestResidentProgramsNV))
-            return FALSE;
-        GLH_EXT_NAME(glTrackMatrixNV) = (PFNGLTRACKMATRIXNVPROC)GLH_EXT_GET_PROC_ADDRESS("glTrackMatrixNV");
-        if (NULL == GLH_EXT_NAME(glTrackMatrixNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttribPointerNV) = (PFNGLVERTEXATTRIBPOINTERNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttribPointerNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttribPointerNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttrib1dNV) = (PFNGLVERTEXATTRIB1DNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1dNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib1dNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttrib1dvNV) = (PFNGLVERTEXATTRIB1DVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1dvNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib1dvNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttrib1fNV) = (PFNGLVERTEXATTRIB1FNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1fNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib1fNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttrib1fvNV) = (PFNGLVERTEXATTRIB1FVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1fvNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib1fvNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttrib1sNV) = (PFNGLVERTEXATTRIB1SNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1sNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib1sNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttrib1svNV) = (PFNGLVERTEXATTRIB1SVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1svNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib1svNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttrib2dNV) = (PFNGLVERTEXATTRIB2DNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2dNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib2dNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttrib2dvNV) = (PFNGLVERTEXATTRIB2DVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2dvNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib2dvNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttrib2fNV) = (PFNGLVERTEXATTRIB2FNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2fNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib2fNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttrib2fvNV) = (PFNGLVERTEXATTRIB2FVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2fvNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib2fvNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttrib2sNV) = (PFNGLVERTEXATTRIB2SNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2sNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib2sNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttrib2svNV) = (PFNGLVERTEXATTRIB2SVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2svNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib2svNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttrib3dNV) = (PFNGLVERTEXATTRIB3DNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3dNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib3dNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttrib3dvNV) = (PFNGLVERTEXATTRIB3DVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3dvNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib3dvNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttrib3fNV) = (PFNGLVERTEXATTRIB3FNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3fNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib3fNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttrib3fvNV) = (PFNGLVERTEXATTRIB3FVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3fvNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib3fvNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttrib3sNV) = (PFNGLVERTEXATTRIB3SNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3sNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib3sNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttrib3svNV) = (PFNGLVERTEXATTRIB3SVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3svNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib3svNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttrib4dNV) = (PFNGLVERTEXATTRIB4DNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4dNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib4dNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttrib4dvNV) = (PFNGLVERTEXATTRIB4DVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4dvNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib4dvNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttrib4fNV) = (PFNGLVERTEXATTRIB4FNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4fNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib4fNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttrib4fvNV) = (PFNGLVERTEXATTRIB4FVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4fvNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib4fvNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttrib4sNV) = (PFNGLVERTEXATTRIB4SNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4sNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib4sNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttrib4svNV) = (PFNGLVERTEXATTRIB4SVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4svNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib4svNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttrib4ubvNV) = (PFNGLVERTEXATTRIB4UBVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4ubvNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib4ubvNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttribs1dvNV) = (PFNGLVERTEXATTRIBS1DVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttribs1dvNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttribs1dvNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttribs1fvNV) = (PFNGLVERTEXATTRIBS1FVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttribs1fvNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttribs1fvNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttribs1svNV) = (PFNGLVERTEXATTRIBS1SVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttribs1svNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttribs1svNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttribs2dvNV) = (PFNGLVERTEXATTRIBS2DVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttribs2dvNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttribs2dvNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttribs2fvNV) = (PFNGLVERTEXATTRIBS2FVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttribs2fvNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttribs2fvNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttribs2svNV) = (PFNGLVERTEXATTRIBS2SVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttribs2svNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttribs2svNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttribs3dvNV) = (PFNGLVERTEXATTRIBS3DVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttribs3dvNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttribs3dvNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttribs3fvNV) = (PFNGLVERTEXATTRIBS3FVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttribs3fvNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttribs3fvNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttribs3svNV) = (PFNGLVERTEXATTRIBS3SVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttribs3svNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttribs3svNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttribs4dvNV) = (PFNGLVERTEXATTRIBS4DVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttribs4dvNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttribs4dvNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttribs4fvNV) = (PFNGLVERTEXATTRIBS4FVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttribs4fvNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttribs4fvNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttribs4svNV) = (PFNGLVERTEXATTRIBS4SVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttribs4svNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttribs4svNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttribs4ubvNV) = (PFNGLVERTEXATTRIBS4UBVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttribs4ubvNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttribs4ubvNV))
-            return FALSE;
-#endif
-
-#ifdef GL_SGIS_generate_mipmap
-    } else if (0 == strcmp(extension, "GL_SGIS_generate_mipmap")) {
-#endif
-
-#ifdef GL_SGIS_texture_lod
-    } else if (0 == strcmp(extension, "GL_SGIS_texture_lod")) {
-#endif
-
-#ifdef GL_SGIX_depth_texture
-    } else if (0 == strcmp(extension, "GL_SGIX_depth_texture")) {
-#endif
-
-#ifdef GL_SGIX_shadow
-    } else if (0 == strcmp(extension, "GL_SGIX_shadow")) {
-#endif
-
-#ifdef GL_VERSION_1_2
-    } else if (0 == strcmp(extension, "GL_VERSION_1_2")) {
-        GLH_CORE_1_2_NAME(glBlendColor) = (PFNGLBLENDCOLORPROC)GLH_EXT_GET_PROC_ADDRESS("glBlendColor");
-        if (NULL == GLH_CORE_1_2_NAME(glBlendColor))
-            return FALSE;
-        GLH_CORE_1_2_NAME(glBlendEquation) = (PFNGLBLENDEQUATIONPROC)GLH_EXT_GET_PROC_ADDRESS("glBlendEquation");
-        if (NULL == GLH_CORE_1_2_NAME(glBlendEquation))
-            return FALSE;
-        GLH_CORE_1_2_NAME(glDrawRangeElements) = (PFNGLDRAWRANGEELEMENTSPROC)GLH_EXT_GET_PROC_ADDRESS("glDrawRangeElements");
-        if (NULL == GLH_CORE_1_2_NAME(glDrawRangeElements))
-            return FALSE;
-        GLH_CORE_1_2_NAME(glColorTable) = (PFNGLCOLORTABLEPROC)GLH_EXT_GET_PROC_ADDRESS("glColorTable");
-        if (NULL == GLH_CORE_1_2_NAME(glColorTable))
-            return FALSE;
-        GLH_CORE_1_2_NAME(glColorTableParameterfv) = (PFNGLCOLORTABLEPARAMETERFVPROC)GLH_EXT_GET_PROC_ADDRESS("glColorTableParameterfv");
-        if (NULL == GLH_CORE_1_2_NAME(glColorTableParameterfv))
-            return FALSE;
-        GLH_CORE_1_2_NAME(glColorTableParameteriv) = (PFNGLCOLORTABLEPARAMETERIVPROC)GLH_EXT_GET_PROC_ADDRESS("glColorTableParameteriv");
-        if (NULL == GLH_CORE_1_2_NAME(glColorTableParameteriv))
-            return FALSE;
-        GLH_CORE_1_2_NAME(glCopyColorTable) = (PFNGLCOPYCOLORTABLEPROC)GLH_EXT_GET_PROC_ADDRESS("glCopyColorTable");
-        if (NULL == GLH_CORE_1_2_NAME(glCopyColorTable))
-            return FALSE;
-        GLH_CORE_1_2_NAME(glGetColorTable) = (PFNGLGETCOLORTABLEPROC)GLH_EXT_GET_PROC_ADDRESS("glGetColorTable");
-        if (NULL == GLH_CORE_1_2_NAME(glGetColorTable))
-            return FALSE;
-        GLH_CORE_1_2_NAME(glGetColorTableParameterfv) = (PFNGLGETCOLORTABLEPARAMETERFVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetColorTableParameterfv");
-        if (NULL == GLH_CORE_1_2_NAME(glGetColorTableParameterfv))
-            return FALSE;
-        GLH_CORE_1_2_NAME(glGetColorTableParameteriv) = (PFNGLGETCOLORTABLEPARAMETERIVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetColorTableParameteriv");
-        if (NULL == GLH_CORE_1_2_NAME(glGetColorTableParameteriv))
-            return FALSE;
-        GLH_CORE_1_2_NAME(glTexImage3D) = (PFNGLTEXIMAGE3DPROC)GLH_EXT_GET_PROC_ADDRESS("glTexImage3D");
-        if (NULL == GLH_CORE_1_2_NAME(glTexImage3D))
-            return FALSE;
-        GLH_CORE_1_2_NAME(glTexSubImage3D) = (PFNGLTEXSUBIMAGE3DPROC)GLH_EXT_GET_PROC_ADDRESS("glTexSubImage3D");
-        if (NULL == GLH_CORE_1_2_NAME(glTexSubImage3D))
-            return FALSE;
-        GLH_CORE_1_2_NAME(glCopyTexSubImage3D) = (PFNGLCOPYTEXSUBIMAGE3DPROC)GLH_EXT_GET_PROC_ADDRESS("glCopyTexSubImage3D");
-        if (NULL == GLH_CORE_1_2_NAME(glCopyTexSubImage3D))
-            return FALSE;
-#endif
-
-#ifdef GL_WIN_swap_hint
-    } else if (0 == strcmp(extension, "GL_WIN_swap_hint")) {
-        GLH_EXT_NAME(glAddSwapHintRectWIN) = (PFNGLADDSWAPHINTRECTWINPROC)GLH_EXT_GET_PROC_ADDRESS("glAddSwapHintRectWIN");
-        if (NULL == GLH_EXT_NAME(glAddSwapHintRectWIN))
-            return FALSE;
-#endif
-
-#ifdef WGL_ARB_pbuffer
-    } else if (0 == strcmp(extension, "WGL_ARB_pbuffer")) {
-# ifdef _WIN32
-        GLH_EXT_NAME(wglCreatePbufferARB) = (PFNWGLCREATEPBUFFERARBPROC)GLH_EXT_GET_PROC_ADDRESS("wglCreatePbufferARB");
-        if (NULL == GLH_EXT_NAME(wglCreatePbufferARB))
-            return FALSE;
-# endif
-# ifdef _WIN32
-        GLH_EXT_NAME(wglGetPbufferDCARB) = (PFNWGLGETPBUFFERDCARBPROC)GLH_EXT_GET_PROC_ADDRESS("wglGetPbufferDCARB");
-        if (NULL == GLH_EXT_NAME(wglGetPbufferDCARB))
-            return FALSE;
-# endif
-# ifdef _WIN32
-        GLH_EXT_NAME(wglReleasePbufferDCARB) = (PFNWGLRELEASEPBUFFERDCARBPROC)GLH_EXT_GET_PROC_ADDRESS("wglReleasePbufferDCARB");
-        if (NULL == GLH_EXT_NAME(wglReleasePbufferDCARB))
-            return FALSE;
-# endif
-# ifdef _WIN32
-        GLH_EXT_NAME(wglDestroyPbufferARB) = (PFNWGLDESTROYPBUFFERARBPROC)GLH_EXT_GET_PROC_ADDRESS("wglDestroyPbufferARB");
-        if (NULL == GLH_EXT_NAME(wglDestroyPbufferARB))
-            return FALSE;
-# endif
-# ifdef _WIN32
-        GLH_EXT_NAME(wglQueryPbufferARB) = (PFNWGLQUERYPBUFFERARBPROC)GLH_EXT_GET_PROC_ADDRESS("wglQueryPbufferARB");
-        if (NULL == GLH_EXT_NAME(wglQueryPbufferARB))
-            return FALSE;
-# endif
-#endif
-
-#ifdef WGL_ARB_render_texture
-# ifdef _WIN32
-		GLH_EXT_NAME(wglBindTexImageARB) = (PFNWGLBINDTEXIMAGEARBPROC)GLH_EXT_GET_PROC_ADDRESS("wglBindTexImageARB");
-		if (NULL == GLH_EXT_NAME(wglBindTexImageARB))
-			return FALSE;
-# endif
-# ifdef _WIN32
-		GLH_EXT_NAME(wglReleaseTexImageARB) = (PFNWGLRELEASETEXIMAGEARBPROC)GLH_EXT_GET_PROC_ADDRESS("wglReleaseTexImageARB");
-		if (NULL == GLH_EXT_NAME(wglReleaseTexImageARB))
-			return FALSE;
-# endif
-# ifdef _WIN32
-		GLH_EXT_NAME(wglSetPbufferAttribARB) = (PFNWGLSETPBUFFERATTRIBARBPROC)GLH_EXT_GET_PROC_ADDRESS("wglSetPbufferAttribARB");
-		if (NULL == GLH_EXT_NAME(wglSetPbufferAttribARB))
-			return FALSE;
-# endif
-#endif
-
-#ifdef WGL_ARB_pixel_format
-    } else if (0 == strcmp(extension, "WGL_ARB_pixel_format")) {
-# ifdef _WIN32
-        GLH_EXT_NAME(wglGetPixelFormatAttribivARB) = (PFNWGLGETPIXELFORMATATTRIBIVARBPROC)GLH_EXT_GET_PROC_ADDRESS("wglGetPixelFormatAttribivARB");
-        if (NULL == GLH_EXT_NAME(wglGetPixelFormatAttribivARB))
-            return FALSE;
-# endif
-# ifdef _WIN32
-        GLH_EXT_NAME(wglGetPixelFormatAttribfvARB) = (PFNWGLGETPIXELFORMATATTRIBFVARBPROC)GLH_EXT_GET_PROC_ADDRESS("wglGetPixelFormatAttribfvARB");
-        if (NULL == GLH_EXT_NAME(wglGetPixelFormatAttribfvARB))
-            return FALSE;
-# endif
-# ifdef _WIN32
-        GLH_EXT_NAME(wglChoosePixelFormatARB) = (PFNWGLCHOOSEPIXELFORMATARBPROC)GLH_EXT_GET_PROC_ADDRESS("wglChoosePixelFormatARB");
-        if (NULL == GLH_EXT_NAME(wglChoosePixelFormatARB))
-            return FALSE;
-# endif
-#endif
-
-    } else {
-        return FALSE;
-    }
-    return TRUE;
-}
-#endif
-
-#else // defined(__APPLE__)
-
-#ifdef GLH_EXT_SINGLE_FILE
-
-int glh_init_extension(const char* extension)
-{
-	// MBW -- XXX -- Should this check for extension availability?
-	return TRUE;
-}
-#endif // GLH_EXT_SINGLE_FILE
-
-#endif // defined(__APPLE__)
-
-#undef GLH_EXT_SINGLE_FILE
-
-#endif /* GLH_GENEXT_H */
-- 
cgit v1.2.3


From cb07acf9fe349a19b63c0d6c3bc65fc66ce5a7a6 Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Fri, 17 Sep 2021 15:48:57 +0300
Subject: SL-13561 When ALM is enabled, disabling water rendering breaks the
 sky

---
 indra/newview/pipeline.cpp | 31 ++++++++++++++++++++++++++++++-
 1 file changed, 30 insertions(+), 1 deletion(-)

(limited to 'indra')

diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index 71a438302a..e23aeb286c 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -9203,7 +9203,13 @@ inline float sgn(float a)
 void LLPipeline::generateWaterReflection(LLCamera& camera_in)
 {
     LL_PROFILE_ZONE_SCOPED;
-    if (LLPipeline::sWaterReflections && assertInitialized() && LLDrawPoolWater::sNeedsReflectionUpdate)
+
+    if (!assertInitialized())
+    {
+        return;
+    }
+
+    if (LLPipeline::sWaterReflections && LLDrawPoolWater::sNeedsReflectionUpdate)
     {
         bool skip_avatar_update = false;
         if (!isAgentAvatarValid() || gAgentCamera.getCameraAnimating() || gAgentCamera.getCameraMode() != CAMERA_MODE_MOUSELOOK || !LLVOAvatar::sVisibleInFirstPerson)
@@ -9488,6 +9494,29 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in)
 
         LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD;
     }
+    else
+    {
+        // Initial sky pass is still needed even if water reflection is not rendering
+        bool camera_is_underwater = LLViewerCamera::getInstance()->cameraUnderWater();
+        if (!camera_is_underwater)
+        {
+            gPipeline.pushRenderTypeMask();
+            {
+                gPipeline.andRenderTypeMask(
+                    LLPipeline::RENDER_TYPE_SKY,
+                    LLPipeline::RENDER_TYPE_WL_SKY,
+                    LLPipeline::END_RENDER_TYPES);
+
+                LLCamera camera = camera_in;
+                camera.setFar(camera_in.getFar() * 0.75f);
+
+                updateCull(camera, mSky);
+                stateSort(camera, mSky);
+                renderGeom(camera, TRUE);
+            }
+            gPipeline.popRenderTypeMask();
+        }
+    }
 }
 
 glh::matrix4f look(const LLVector3 pos, const LLVector3 dir, const LLVector3 up)
-- 
cgit v1.2.3


From c1c2830f9b7bf4d91977133ffbcd8d0240bcc7fe Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Fri, 11 Jun 2021 21:16:08 +0300
Subject: SL-15391 Crash at getUniformLocation

---
 indra/llrender/llglslshader.cpp | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

(limited to 'indra')

diff --git a/indra/llrender/llglslshader.cpp b/indra/llrender/llglslshader.cpp
index 0e4753fcc6..08c9dd8769 100644
--- a/indra/llrender/llglslshader.cpp
+++ b/indra/llrender/llglslshader.cpp
@@ -1436,7 +1436,11 @@ GLint LLGLSLShader::getUniformLocation(U32 index)
     GLint ret = -1;
     if (mProgramObject)
     {
-        llassert(index < mUniform.size());
+        if (index >= mUniform.size())
+        {
+            LL_WARNS_ONCE("Shader") << "Uniform index " << index << " out of bounds " << (S32)mUniform.size() << LL_ENDL;
+            return ret;
+        }
         return mUniform[index];
     }
 
-- 
cgit v1.2.3


From 2b543f92fac5df04d1c0dfce0606998a600f947f Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Fri, 24 Sep 2021 23:35:12 +0300
Subject: SL-16056 Improve 'avatar cloud' behavior

Make avatar cloud delay longer proportionally to load time
---
 indra/newview/llvoavatar.cpp | 35 +++++++++++++++++++++++++++++------
 indra/newview/llvoavatar.h   |  3 +++
 2 files changed, 32 insertions(+), 6 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp
index 4a179146f8..04356e6507 100644
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -126,6 +126,9 @@ const F32 MIN_HOVER_Z = -2.0;
 const F32 MIN_ATTACHMENT_COMPLEXITY = 0.f;
 const F32 DEFAULT_MAX_ATTACHMENT_COMPLEXITY = 1.0e6f;
 
+const F32 FIRST_APPEARANCE_CLOUD_MIN_DELAY = 3.f; // seconds
+const F32 FIRST_APPEARANCE_CLOUD_MAX_DELAY = 45.f;
+
 using namespace LLAvatarAppearanceDefines;
 
 //-----------------------------------------------------------------------------
@@ -667,6 +670,7 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id,
 	mVisuallyMuteSetting(AV_RENDER_NORMALLY),
 	mMutedAVColor(LLColor4::white /* used for "uninitialize" */),
 	mFirstFullyVisible(TRUE),
+	mFirstUseDelaySeconds(FIRST_APPEARANCE_CLOUD_MIN_DELAY),
 	mFullyLoaded(FALSE),
 	mPreviousFullyLoaded(FALSE),
 	mFullyLoadedInitialized(FALSE),
@@ -741,7 +745,7 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id,
 
 	mCurrentGesticulationLevel = 0;
 
-    
+	mFirstSeenTimer.reset();
 	mRuthTimer.reset();
 	mRuthDebugTimer.reset();
 	mDebugExistenceTimer.reset();
@@ -8126,16 +8130,35 @@ void LLVOAvatar::updateRuthTimer(bool loading)
 BOOL LLVOAvatar::processFullyLoadedChange(bool loading)
 {
 	// We wait a little bit before giving the 'all clear', to let things to
-	// settle down (models to snap into place, textures to get first packets)
+	// settle down (models to snap into place, textures to get first packets).
+    // And if viewer isn't aware of some parts yet, this gives them a chance
+    // to arrive.
 	const F32 LOADED_DELAY = 1.f;
-	const F32 FIRST_USE_DELAY = 3.f;
 
-	if (loading)
-		mFullyLoadedTimer.reset();
+    if (loading)
+    {
+        mFullyLoadedTimer.reset();
+    }
 
 	if (mFirstFullyVisible)
 	{
-		mFullyLoaded = (mFullyLoadedTimer.getElapsedTimeF32() > FIRST_USE_DELAY);
+        if (!isSelf() && loading)
+        {
+                // Note that textures can causes 60s delay on thier own
+                // so this delay might end up on top of textures' delay
+                mFirstUseDelaySeconds = llclamp(
+                    mFirstSeenTimer.getElapsedTimeF32(),
+                    FIRST_APPEARANCE_CLOUD_MIN_DELAY,
+                    FIRST_APPEARANCE_CLOUD_MAX_DELAY);
+
+                if (shouldImpostor())
+                {
+                    // Impostors are less of a priority,
+                    // let them stay cloud longer
+                    mFirstUseDelaySeconds *= 1.25;
+                }
+        }
+		mFullyLoaded = (mFullyLoadedTimer.getElapsedTimeF32() > mFirstUseDelaySeconds);
 	}
 	else
 	{
diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h
index 7042406091..aeac23ad92 100644
--- a/indra/newview/llvoavatar.h
+++ b/indra/newview/llvoavatar.h
@@ -376,6 +376,9 @@ protected:
 
 private:
 	BOOL			mFirstFullyVisible;
+	F32				mFirstUseDelaySeconds;
+	LLFrameTimer	mFirstSeenTimer;
+
 	BOOL			mFullyLoaded;
 	BOOL			mPreviousFullyLoaded;
 	BOOL			mFullyLoadedInitialized;
-- 
cgit v1.2.3


From 709184e0ffdd9967444c07bd52d479be4d932835 Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Tue, 14 Sep 2021 22:43:17 +0300
Subject: SL-15993 Disabling transparent water should not disable advanced
 lighting

---
 indra/newview/llappviewer.cpp         |  2 +-
 indra/newview/lldrawpoolwater.cpp     | 13 +++++++++++++
 indra/newview/llfloaterpreference.cpp |  6 ------
 indra/newview/llviewercontrol.cpp     |  1 -
 indra/newview/llviewershadermgr.cpp   |  2 +-
 indra/newview/pipeline.cpp            |  1 -
 6 files changed, 15 insertions(+), 10 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 8b4fcfccd9..89756d0881 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -610,7 +610,7 @@ static void settings_modify()
 	LLRenderTarget::sUseFBO				= gSavedSettings.getBOOL("RenderDeferred");
 	LLPipeline::sRenderTransparentWater	= gSavedSettings.getBOOL("RenderTransparentWater");
 	LLPipeline::sRenderBump				= gSavedSettings.getBOOL("RenderObjectBump");
-	LLPipeline::sRenderDeferred		= LLPipeline::sRenderTransparentWater && LLPipeline::sRenderBump && gSavedSettings.getBOOL("RenderDeferred");
+	LLPipeline::sRenderDeferred		= 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;
diff --git a/indra/newview/lldrawpoolwater.cpp b/indra/newview/lldrawpoolwater.cpp
index 5f9e623b4c..2f3c52ecd2 100644
--- a/indra/newview/lldrawpoolwater.cpp
+++ b/indra/newview/lldrawpoolwater.cpp
@@ -137,6 +137,14 @@ void LLDrawPoolWater::endPostDeferredPass(S32 pass)
 void LLDrawPoolWater::renderDeferred(S32 pass)
 {
 	LL_RECORD_BLOCK_TIME(FTM_RENDER_WATER);
+
+    if (!LLPipeline::sRenderTransparentWater)
+    {
+        // Will render opaque water without use of ALM
+        render(pass);
+        return;
+    }
+
 	deferred_render = TRUE;
 	shade();
 	deferred_render = FALSE;
@@ -340,6 +348,11 @@ void LLDrawPoolWater::renderOpaqueLegacyWater()
     LL_PROFILE_ZONE_SCOPED;
     LLVOSky *voskyp = gSky.mVOSkyp;
 
+    if (voskyp == NULL)
+    {
+        return;
+    }
+
 	LLGLSLShader* shader = NULL;
 	if (LLGLSLShader::sNoFixedFunction)
 	{
diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp
index 6bf2136f60..92e64d0b95 100644
--- a/indra/newview/llfloaterpreference.cpp
+++ b/indra/newview/llfloaterpreference.cpp
@@ -1198,11 +1198,9 @@ void LLFloaterPreference::refreshEnabledState()
 
 	//Deferred/SSAO/Shadows
 	BOOL bumpshiny = gGLManager.mHasCubeMap && LLCubeMap::sUseCubeMaps && LLFeatureManager::getInstance()->isFeatureAvailable("RenderObjectBump") && gSavedSettings.getBOOL("RenderObjectBump");
-	BOOL transparent_water = LLFeatureManager::getInstance()->isFeatureAvailable("RenderTransparentWater") && gSavedSettings.getBOOL("RenderTransparentWater");
 	BOOL shaders = gSavedSettings.getBOOL("WindLightUseAtmosShaders");
 	BOOL enabled = LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferred") &&
 						bumpshiny &&
-						transparent_water &&
 						shaders && 
 						gGLManager.mHasFramebufferObject &&
 						gSavedSettings.getBOOL("RenderAvatarVP") &&
@@ -1226,9 +1224,6 @@ void LLFloaterPreferenceGraphicsAdvanced::refreshEnabledState()
 	ctrl_reflections->setEnabled(reflections);
 	reflections_text->setEnabled(reflections);
 
-    // Transparent Water
-    LLCheckBoxCtrl* transparent_water_ctrl = getChild<LLCheckBoxCtrl>("TransparentWater");
-
 	// Bump & Shiny	
 	LLCheckBoxCtrl* bumpshiny_ctrl = getChild<LLCheckBoxCtrl>("BumpShiny");
 	bool bumpshiny = gGLManager.mHasCubeMap && LLCubeMap::sUseCubeMaps && LLFeatureManager::getInstance()->isFeatureAvailable("RenderObjectBump");
@@ -1279,7 +1274,6 @@ void LLFloaterPreferenceGraphicsAdvanced::refreshEnabledState()
     
     BOOL enabled = LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferred") &&
                         ((bumpshiny_ctrl && bumpshiny_ctrl->get()) ? TRUE : FALSE) &&
-                        ((transparent_water_ctrl && transparent_water_ctrl->get()) ? TRUE : FALSE) &&
                         gGLManager.mHasFramebufferObject &&
                         gSavedSettings.getBOOL("RenderAvatarVP") &&
                         (ctrl_wind_light->get()) ? TRUE : FALSE;
diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp
index 0e64d7152a..e5ebbcb9ab 100644
--- a/indra/newview/llviewercontrol.cpp
+++ b/indra/newview/llviewercontrol.cpp
@@ -187,7 +187,6 @@ static bool handleRenderPerfTestChanged(const LLSD& newvalue)
 
 bool handleRenderTransparentWaterChanged(const LLSD& newvalue)
 {
-	LLRenderTarget::sUseFBO = newvalue.asBoolean();
 	if (gPipeline.isInit())
 	{
 		gPipeline.updateRenderTransparentWater();
diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp
index 7dcf29eb75..1b6d8210c3 100644
--- a/indra/newview/llviewershadermgr.cpp
+++ b/indra/newview/llviewershadermgr.cpp
@@ -424,7 +424,7 @@ void LLViewerShaderMgr::setShaders()
     initAttribsAndUniforms();
     gPipeline.releaseGLBuffers();
 
-    LLPipeline::sWaterReflections = gGLManager.mHasCubeMap;
+    LLPipeline::sWaterReflections = gGLManager.mHasCubeMap && LLPipeline::sRenderTransparentWater;
     LLPipeline::sRenderGlow = gSavedSettings.getBOOL("RenderGlow"); 
     LLPipeline::updateRenderDeferred();
     
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index e23aeb286c..586e5b7c2d 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -1047,7 +1047,6 @@ void LLPipeline::updateRenderDeferred()
                       RenderDeferred &&
                       LLRenderTarget::sUseFBO &&
                       LLPipeline::sRenderBump &&
-                      LLPipeline::sRenderTransparentWater &&
                       RenderAvatarVP &&
                       WindLightUseAtmosShaders &&
                       (bool) LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferred");
-- 
cgit v1.2.3


From 819088563e13f1d75e048311fbaf0df4a79b7e19 Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Thu, 23 Sep 2021 22:38:30 +0300
Subject: SL-11678 Avatar is reflecting on the under side of water surface

Avatar wasn't reflecting but distorting, since avatar was already under water it looked like a 'reflection' of avatar, but was not rotated right and with wrong angle.
---
 indra/newview/pipeline.cpp | 8 +-------
 1 file changed, 1 insertion(+), 7 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index 586e5b7c2d..de95eb1a87 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -9428,19 +9428,13 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in)
 
                 //clip out geometry on the same side of water as the camera w/ enough margin to not include the water geo itself,
                 // but not so much as to clip out parts of avatars that should be seen under the water in the distortion map
-                LLPlane plane(-pnorm, water_dist);
+                LLPlane plane(-pnorm, camera_is_underwater ? -water_height : water_dist);
                 LLGLUserClipPlane clip_plane(plane, saved_modelview, saved_projection);
 
                 gGL.setColorMask(true, true);
                 mWaterDis.clear();
                 gGL.setColorMask(true, false);
 
-                // ignore clip plane if we're underwater and viewing distortion map of objects above waterline
-                if (camera_is_underwater)
-                {
-                    clip_plane.disable();
-                }
-
                 if (reflection_detail >= WATER_REFLECT_NONE_WATER_TRANSPARENT)
                 {
                     updateCull(camera, mRefractedObjects, water_clip, &plane);
-- 
cgit v1.2.3


From a08a45c00f99e89439ecfe7ae03137c59571e16c Mon Sep 17 00:00:00 2001
From: Dave Houlton <euclid@lindenlab.com>
Date: Wed, 17 Mar 2021 14:12:04 -0600
Subject: SL-14895, point light atten should move inversely light radius

---
 indra/newview/pipeline.cpp | 18 ++++++++----------
 1 file changed, 8 insertions(+), 10 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index de95eb1a87..cb54b1eaed 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -6349,21 +6349,19 @@ void LLPipeline::setupHWLights(LLDrawPool* pool)
                 continue;
             }
 
-			LLVector3 light_pos(light->getRenderPosition());
-			LLVector4 light_pos_gl(light_pos, 1.0f);
-	
-			F32 light_radius = llmax(light->getLightRadius(), 0.001f);
-            F32 size = light_radius * (sRenderDeferred ? 1.5f : 1.0f);
+            LLVector3 light_pos(light->getRenderPosition());
+            LLVector4 light_pos_gl(light_pos, 1.0f);
 
-            if (size <= 0.001f)
+            F32 adjusted_radius = light->getLightRadius() * (sRenderDeferred ? 1.5f : 1.0f);
+            if (adjusted_radius <= 0.001f)
             {
                 continue;
             }
 
-			F32 x = (3.f * (1.f + (light->getLightFalloff() * 2.0f))); // why this magic?  probably trying to match a historic behavior.
-			F32 linatten = x / (light_radius); // % of brightness at radius
+            F32 x = (3.f * (1.f + (light->getLightFalloff() * 2.0f)));  // why this magic?  probably trying to match a historic behavior.
+            F32 linatten = x / adjusted_radius;                         // % of brightness at radius
 
-			mHWLightColors[cur_light] = light_color;
+            mHWLightColors[cur_light] = light_color;
 			LLLightState* light_state = gGL.getLight(cur_light);
 			
 			light_state->setPosition(light_pos_gl);
@@ -6372,7 +6370,7 @@ void LLPipeline::setupHWLights(LLDrawPool* pool)
 			light_state->setConstantAttenuation(0.f);
 			if (sRenderDeferred)
 			{
-				light_state->setLinearAttenuation(size);
+				light_state->setLinearAttenuation(linatten);
 				light_state->setQuadraticAttenuation(light->getLightFalloff(DEFERRED_LIGHT_FALLOFF) + 1.f); // get falloff to match for forward deferred rendering lights
 			}
 			else
-- 
cgit v1.2.3


From 2e2d9b611530bd0113612dbe019c8e413e1bb20e Mon Sep 17 00:00:00 2001
From: Dave Houlton <euclid@lindenlab.com>
Date: Mon, 29 Mar 2021 16:00:19 -0600
Subject: SL-14895, restore previous post-deferred alpha behavior

---
 .../app_settings/shaders/class1/deferred/alphaF.glsl       | 14 +++++++++++---
 .../app_settings/shaders/class1/deferred/materialF.glsl    | 12 ++++++++++--
 2 files changed, 21 insertions(+), 5 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/app_settings/shaders/class1/deferred/alphaF.glsl b/indra/newview/app_settings/shaders/class1/deferred/alphaF.glsl
index dc484317e9..d3a05c34c0 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/alphaF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/alphaF.glsl
@@ -86,6 +86,14 @@ float getAmbientClamp();
 
 vec3 calcPointLightOrSpotLight(vec3 light_col, vec3 diffuse, vec3 v, vec3 n, vec4 lp, vec3 ln, float la, float fa, float is_pointlight, float ambiance)
 {
+    // SL-14895 inverted attenuation work-around
+    // This routine is tweaked to match deferred lighting, but previously used an inverted la value. To reconstruct
+    // that previous value now that the inversion is corrected, we reverse the calculations in LLPipeline::setupHWLights()
+    // to recover the `adjusted_radius` value previously being sent as la.
+    float falloff_factor = (12.0 * fa) - 9.0;
+    float inverted_la = falloff_factor / la;
+    // Yes, it makes me want to cry as well. DJH
+    
     vec3 col = vec3(0);
 
 	//get light vector
@@ -95,7 +103,7 @@ vec3 calcPointLightOrSpotLight(vec3 light_col, vec3 diffuse, vec3 v, vec3 n, vec
 	float dist = length(lv);
 	float da = 1.0;
 
-    /*if (dist > la)
+    /*if (dist > inverted_la)
     {
         return col;
     }
@@ -113,9 +121,9 @@ vec3 calcPointLightOrSpotLight(vec3 light_col, vec3 diffuse, vec3 v, vec3 n, vec
         return col;
     }*/
 
-	if (dist > 0.0 && la > 0.0)
+	if (dist > 0.0 && inverted_la > 0.0)
 	{
-        dist /= la;
+        dist /= inverted_la;
 
 		//normalize light vector
 		lv = normalize(lv);
diff --git a/indra/newview/app_settings/shaders/class1/deferred/materialF.glsl b/indra/newview/app_settings/shaders/class1/deferred/materialF.glsl
index e1f7031af6..02d83925ea 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/materialF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/materialF.glsl
@@ -91,6 +91,14 @@ float getAmbientClamp();
 
 vec3 calcPointLightOrSpotLight(vec3 light_col, vec3 npos, vec3 diffuse, vec4 spec, vec3 v, vec3 n, vec4 lp, vec3 ln, float la, float fa, float is_pointlight, inout float glare, float ambiance)
 {
+    // SL-14895 inverted attenuation work-around
+    // This routine is tweaked to match deferred lighting, but previously used an inverted la value. To reconstruct
+    // that previous value now that the inversion is corrected, we reverse the calculations in LLPipeline::setupHWLights()
+    // to recover the `adjusted_radius` value previously being sent as la.
+    float falloff_factor = (12.0 * fa) - 9.0;
+    float inverted_la = falloff_factor / la;
+    // Yes, it makes me want to cry as well. DJH
+    
     vec3 col = vec3(0);
 
     //get light vector
@@ -100,9 +108,9 @@ vec3 calcPointLightOrSpotLight(vec3 light_col, vec3 npos, vec3 diffuse, vec4 spe
     float dist = length(lv);
     float da = 1.0;
 
-    dist /= la;
+    dist /= inverted_la;
 
-    if (dist > 0.0 && la > 0.0)
+    if (dist > 0.0 && inverted_la > 0.0)
     {
         //normalize light vector
         lv = normalize(lv);
-- 
cgit v1.2.3


From aeed774ff9cc55c0c1dd2784e23b2366ff367fbe Mon Sep 17 00:00:00 2001
From: Dave Houlton <euclid@lindenlab.com>
Date: Thu, 15 Apr 2021 09:46:31 -0600
Subject: (Moved from DRTVWR-528) clean up cmake recursive CXX_FLAGS definition
 (/Zo)

---
 indra/cmake/00-Common.cmake | 13 +++++++++----
 1 file changed, 9 insertions(+), 4 deletions(-)

(limited to 'indra')

diff --git a/indra/cmake/00-Common.cmake b/indra/cmake/00-Common.cmake
index 8aea50e02b..7c9e07b099 100644
--- a/indra/cmake/00-Common.cmake
+++ b/indra/cmake/00-Common.cmake
@@ -42,8 +42,8 @@ if(NON_RELEASE_CRASH_REPORTING)
   set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DLL_SEND_CRASH_REPORTS=1")
 endif()  
 
-# Don't bother with a MinSizeRel build.
-set(CMAKE_CONFIGURATION_TYPES "RelWithDebInfo;Release;Debug" CACHE STRING
+# Don't bother with MinSizeRel or Debug builds.
+set(CMAKE_CONFIGURATION_TYPES "RelWithDebInfo;Release" CACHE STRING
     "Supported build types." FORCE)
 
 
@@ -70,13 +70,18 @@ if (WINDOWS)
   if( ADDRESS_SIZE EQUAL 32 )
     set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /p:PreferredToolArchitecture=x64")  
   endif()
+  
+  # Preserve first-pass-through versions (ie no FORCE overwrite). Prevents recursive addition of /Zo (04/2021)
+  set(OG_CMAKE_CXX_FLAGS_RELEASE ${CMAKE_CXX_FLAGS_RELEASE} CACHE STRING "OG_CXX_FLAGS_RELEASE")
+  set(OG_CMAKE_CXX_FLAGS_RELWITHDEBINFO ${CMAKE_CXX_FLAGS_RELWITHDEBINFO} CACHE STRING "OG_CXX_FLAGS_RELWITHDEBINFO")
 
   set(CMAKE_CXX_FLAGS_RELWITHDEBINFO 
-      "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /Zo"
+      "${OG_CMAKE_CXX_FLAGS_RELWITHDEBINFO} /Zo"
       CACHE STRING "C++ compiler release-with-debug options" FORCE)
   set(CMAKE_CXX_FLAGS_RELEASE
-      "${CMAKE_CXX_FLAGS_RELEASE} ${LL_CXX_FLAGS} /Zo"
+      "${OG_CMAKE_CXX_FLAGS_RELEASE} ${LL_CXX_FLAGS} /Zo"
       CACHE STRING "C++ compiler release options" FORCE)
+	  
   # zlib has assembly-language object files incompatible with SAFESEH
   set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /LARGEADDRESSAWARE /SAFESEH:NO /NODEFAULTLIB:LIBCMT /IGNORE:4099")
 
-- 
cgit v1.2.3


From 029b41c0419e975bbb28454538b46dc69ce5d2ba Mon Sep 17 00:00:00 2001
From: Dave Houlton <euclid@lindenlab.com>
Date: Mon, 15 Nov 2021 09:25:35 -0700
Subject: Revert "SL-16220: Merge branch 'origin/DRTVWR-546' into glthread"

This reverts commit 5188a26a8521251dda07ac0140bb129f28417e49, reversing
changes made to 819088563e13f1d75e048311fbaf0df4a79b7e19.
---
 indra/llcommon/CMakeLists.txt                    |   3 +-
 indra/llcommon/llsingleton.h                     |  24 +-
 indra/llcommon/llthreadsafequeue.h               |  30 +-
 indra/llcommon/tests/threadsafeschedule_test.cpp |   4 +-
 indra/llcommon/tests/workqueue_test.cpp          |  72 +---
 indra/llcommon/threadpool.cpp                    |  80 -----
 indra/llcommon/threadpool.h                      |  62 ----
 indra/llcommon/timing.cpp                        |  25 ++
 indra/llcommon/workqueue.cpp                     |  30 +-
 indra/llcommon/workqueue.h                       | 378 ++++----------------
 indra/llrender/llimagegl.cpp                     |  91 ++++-
 indra/llrender/llimagegl.h                       |  27 +-
 indra/llui/CMakeLists.txt                        |   6 +-
 indra/llui/llviewereventrecorder.cpp             |   2 +
 indra/llwindow/llwindowwin32.cpp                 | 426 ++++++++++++++++-------
 indra/llwindow/llwindowwin32.h                   |  48 ++-
 indra/newview/CMakeLists.txt                     |   3 +-
 indra/newview/app_settings/settings.xml          |  25 --
 indra/newview/llappviewer.cpp                    |  66 ++--
 indra/newview/llenvironment.cpp                  |   1 +
 indra/newview/llmainlooprepeater.cpp             |  88 +++++
 indra/newview/llmainlooprepeater.h               |  64 ++++
 indra/newview/llselectmgr.cpp                    |   2 +
 indra/newview/llstartup.cpp                      |  20 --
 indra/newview/llviewercamera.cpp                 |   2 +
 indra/newview/llviewertexture.cpp                |  34 +-
 indra/newview/llviewertexture.h                  |   4 -
 indra/newview/llworld.cpp                        |   2 +
 28 files changed, 770 insertions(+), 849 deletions(-)
 delete mode 100644 indra/llcommon/threadpool.cpp
 delete mode 100644 indra/llcommon/threadpool.h
 create mode 100644 indra/llcommon/timing.cpp
 create mode 100644 indra/newview/llmainlooprepeater.cpp
 create mode 100644 indra/newview/llmainlooprepeater.h

(limited to 'indra')

diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt
index 78d6ea3090..ad6d3a5049 100644
--- a/indra/llcommon/CMakeLists.txt
+++ b/indra/llcommon/CMakeLists.txt
@@ -119,8 +119,8 @@ set(llcommon_SOURCE_FILES
     lluriparser.cpp
     lluuid.cpp
     llworkerthread.cpp
+    timing.cpp
     u64.cpp
-    threadpool.cpp
     workqueue.cpp
     StackWalker.cpp
     )
@@ -256,7 +256,6 @@ set(llcommon_HEADER_FILES
     lockstatic.h
     stdtypes.h
     stringize.h
-    threadpool.h
     threadsafeschedule.h
     timer.h
     tuple.h
diff --git a/indra/llcommon/llsingleton.h b/indra/llcommon/llsingleton.h
index 6042c0906c..10a8ecfedb 100644
--- a/indra/llcommon/llsingleton.h
+++ b/indra/llcommon/llsingleton.h
@@ -847,28 +847,22 @@ template<class T>
 class LLSimpleton
 {
 public:
-    template <typename... ARGS>
-    static void createInstance(ARGS&&... args)
-    {
+    static T* sInstance;
+    
+    static void createInstance() 
+    { 
         llassert(sInstance == nullptr);
-        sInstance = new T(std::forward<ARGS>(args)...);
+        sInstance = new T(); 
     }
-
+    
     static inline T* getInstance() { return sInstance; }
     static inline T& instance() { return *getInstance(); }
     static inline bool instanceExists() { return sInstance != nullptr; }
 
-    static void deleteSingleton()
-    {
-        delete sInstance;
-        sInstance = nullptr;
+    static void deleteSingleton() { 
+        delete sInstance; 
+        sInstance = nullptr; 
     }
-
-private:
-    static T* sInstance;
 };
 
-template <class T>
-T* LLSimpleton<T>::sInstance{ nullptr };
-
 #endif
diff --git a/indra/llcommon/llthreadsafequeue.h b/indra/llcommon/llthreadsafequeue.h
index 5c934791fe..06e8d8f609 100644
--- a/indra/llcommon/llthreadsafequeue.h
+++ b/indra/llcommon/llthreadsafequeue.h
@@ -85,8 +85,8 @@ public:
 	LLThreadSafeQueue(U32 capacity = 1024);
 	virtual ~LLThreadSafeQueue() {}
 
-	// Add an element to the queue (will block if the queue has reached
-	// capacity).
+	// 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.
@@ -95,11 +95,6 @@ public:
 	// legacy name
 	void pushFront(ElementT const & element) { return push(element); }
 
-	// Add an element to the queue (will block if the queue has reached
-	// capacity). Return false if the queue is closed before push is possible.
-	template <typename T>
-	bool pushIfOpen(T&& element);
-
 	// Try to add an element to the queue without blocking. Returns
 	// true only if the element was actually added.
 	template <typename T>
@@ -316,8 +311,8 @@ bool LLThreadSafeQueue<ElementT, QueueT>::push_(lock_t& lock, T&& element)
 
 
 template <typename ElementT, typename QueueT>
-template <typename T>
-bool LLThreadSafeQueue<ElementT, QueueT>::pushIfOpen(T&& element)
+template<typename T>
+void LLThreadSafeQueue<ElementT, QueueT>::push(T&& element)
 {
     lock_t lock1(mLock);
     while (true)
@@ -326,10 +321,12 @@ bool LLThreadSafeQueue<ElementT, QueueT>::pushIfOpen(T&& element)
         // drained or not: the moment either end calls close(), further push()
         // operations will fail.
         if (mClosed)
-            return false;
+        {
+            LLTHROW(LLThreadSafeQueueInterrupt());
+        }
 
         if (push_(lock1, std::forward<T>(element)))
-            return true;
+            return;
 
         // Storage Full. Wait for signal.
         mCapacityCond.wait(lock1);
@@ -337,17 +334,6 @@ bool LLThreadSafeQueue<ElementT, QueueT>::pushIfOpen(T&& element)
 }
 
 
-template <typename ElementT, typename QueueT>
-template<typename T>
-void LLThreadSafeQueue<ElementT, QueueT>::push(T&& element)
-{
-    if (! pushIfOpen(std::forward<T>(element)))
-    {
-        LLTHROW(LLThreadSafeQueueInterrupt());
-    }
-}
-
-
 template<typename ElementT, typename QueueT>
 template<typename T>
 bool LLThreadSafeQueue<ElementT, QueueT>::tryPush(T&& element)
diff --git a/indra/llcommon/tests/threadsafeschedule_test.cpp b/indra/llcommon/tests/threadsafeschedule_test.cpp
index c421cc7b1c..af67b9f492 100644
--- a/indra/llcommon/tests/threadsafeschedule_test.cpp
+++ b/indra/llcommon/tests/threadsafeschedule_test.cpp
@@ -46,11 +46,11 @@ namespace tut
         // the real time required for each push() call. Explicitly increment
         // the timestamp for each one -- but since we're passing explicit
         // timestamps, make the queue reorder them.
-        queue.push(Queue::TimeTuple(Queue::Clock::now() + 200ms, "ghi"));
+        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() + 100ms, "def");
+        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);
diff --git a/indra/llcommon/tests/workqueue_test.cpp b/indra/llcommon/tests/workqueue_test.cpp
index bea3ad911b..d5405400fd 100644
--- a/indra/llcommon/tests/workqueue_test.cpp
+++ b/indra/llcommon/tests/workqueue_test.cpp
@@ -20,10 +20,7 @@
 // external library headers
 // other Linden headers
 #include "../test/lltut.h"
-#include "../test/catch_and_store_what_in.h"
 #include "llcond.h"
-#include "llcoros.h"
-#include "lleventcoro.h"
 #include "llstring.h"
 #include "stringize.h"
 
@@ -141,8 +138,7 @@ namespace tut
             [](){ return 17; },
             // Note that a postTo() *callback* can safely bind a reference to
             // a variable on the invoking thread, because the callback is run
-            // on the invoking thread. (Of course the bound variable must
-            // survive until the callback is called.)
+            // on the invoking thread.
             [&result](int i){ result = i; });
         // this should post the callback to main
         qptr->runOne();
@@ -160,70 +156,4 @@ namespace tut
         main.runPending();
         ensure_equals("failed to run string callback", alpha, "abc");
     }
-
-    template<> template<>
-    void object::test<5>()
-    {
-        set_test_name("postTo with void return");
-        WorkQueue main("main");
-        auto qptr = WorkQueue::getInstance("queue");
-        std::string observe;
-        main.postTo(
-            qptr,
-            // The ONLY reason we can get away with binding a reference to
-            // 'observe' in our work callable is because we're directly
-            // calling qptr->runOne() on this same thread. It would be a
-            // mistake to do that if some other thread were servicing 'queue'.
-            [&observe](){ observe = "queue"; },
-            [&observe](){ observe.append(";main"); });
-        qptr->runOne();
-        main.runOne();
-        ensure_equals("failed to run both lambdas", observe, "queue;main");
-    }
-
-    template<> template<>
-    void object::test<6>()
-    {
-        set_test_name("waitForResult");
-        std::string stored;
-        // Try to call waitForResult() on this thread's main coroutine. It
-        // should throw because the main coroutine must service the queue.
-        auto what{ catch_what<WorkQueue::Error>(
-                [this, &stored](){ stored = queue.waitForResult(
-                        [](){ return "should throw"; }); }) };
-        ensure("lambda should not have run", stored.empty());
-        ensure_not("waitForResult() should have thrown", what.empty());
-        ensure(STRINGIZE("should mention waitForResult: " << what),
-               what.find("waitForResult") != std::string::npos);
-
-        // Call waitForResult() on a coroutine, with a string result.
-        LLCoros::instance().launch(
-            "waitForResult string",
-            [this, &stored]()
-            { stored = queue.waitForResult(
-                    [](){ return "string result"; }); });
-        llcoro::suspend();
-        // Nothing will have happened yet because, even if the coroutine did
-        // run immediately, all it did was to queue the inner lambda on
-        // 'queue'. Service it.
-        queue.runOne();
-        llcoro::suspend();
-        ensure_equals("bad waitForResult return", stored, "string result");
-
-        // Call waitForResult() on a coroutine, with a void callable.
-        stored.clear();
-        bool done = false;
-        LLCoros::instance().launch(
-            "waitForResult void",
-            [this, &stored, &done]()
-            {
-                queue.waitForResult([&stored](){ stored = "ran"; });
-                done = true;
-            });
-        llcoro::suspend();
-        queue.runOne();
-        llcoro::suspend();
-        ensure_equals("didn't run coroutine", stored, "ran");
-        ensure("void waitForResult() didn't return", done);
-    }
 } // namespace tut
diff --git a/indra/llcommon/threadpool.cpp b/indra/llcommon/threadpool.cpp
deleted file mode 100644
index cf25cc838e..0000000000
--- a/indra/llcommon/threadpool.cpp
+++ /dev/null
@@ -1,80 +0,0 @@
-/**
- * @file   threadpool.cpp
- * @author Nat Goodspeed
- * @date   2021-10-21
- * @brief  Implementation for threadpool.
- * 
- * $LicenseInfo:firstyear=2021&license=viewerlgpl$
- * Copyright (c) 2021, Linden Research, Inc.
- * $/LicenseInfo$
- */
-
-// Precompiled header
-#include "linden_common.h"
-// associated header
-#include "threadpool.h"
-// STL headers
-// std headers
-// external library headers
-// other Linden headers
-#include "llerror.h"
-#include "llevents.h"
-#include "stringize.h"
-
-LL::ThreadPool::ThreadPool(const std::string& name, size_t threads, size_t capacity):
-    mQueue(name, capacity),
-    mName("ThreadPool:" + name)
-{
-    for (size_t i = 0; i < threads; ++i)
-    {
-        std::string tname{ STRINGIZE(mName << ':' << (i+1) << '/' << threads) };
-        mThreads.emplace_back(tname, [this, tname](){ run(tname); });
-    }
-    // Listen on "LLApp", and when the app is shutting down, close the queue
-    // and join the workers.
-    LLEventPumps::instance().obtain("LLApp").listen(
-        mName,
-        [this](const LLSD& stat)
-        {
-            std::string status(stat["status"]);
-            if (status != "running")
-            {
-                // viewer is starting shutdown -- proclaim the end is nigh!
-                LL_DEBUGS("ThreadPool") << mName << " saw " << status << LL_ENDL;
-                close();
-            }
-            return false;
-        });
-}
-
-LL::ThreadPool::~ThreadPool()
-{
-    close();
-}
-
-void LL::ThreadPool::close()
-{
-    if (! mQueue.isClosed())
-    {
-        LL_DEBUGS("ThreadPool") << mName << " closing queue and joining threads" << LL_ENDL;
-        mQueue.close();
-        for (auto& pair: mThreads)
-        {
-            LL_DEBUGS("ThreadPool") << mName << " waiting on thread " << pair.first << LL_ENDL;
-            pair.second.join();
-        }
-        LL_DEBUGS("ThreadPool") << mName << " shutdown complete" << LL_ENDL;
-    }
-}
-
-void LL::ThreadPool::run(const std::string& name)
-{
-    LL_DEBUGS("ThreadPool") << name << " starting" << LL_ENDL;
-    run();
-    LL_DEBUGS("ThreadPool") << name << " stopping" << LL_ENDL;
-}
-
-void LL::ThreadPool::run()
-{
-    mQueue.runUntilClose();
-}
diff --git a/indra/llcommon/threadpool.h b/indra/llcommon/threadpool.h
deleted file mode 100644
index 1ca24aec58..0000000000
--- a/indra/llcommon/threadpool.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/**
- * @file   threadpool.h
- * @author Nat Goodspeed
- * @date   2021-10-21
- * @brief  ThreadPool configures a WorkQueue along with a pool of threads to
- *         service it.
- * 
- * $LicenseInfo:firstyear=2021&license=viewerlgpl$
- * Copyright (c) 2021, Linden Research, Inc.
- * $/LicenseInfo$
- */
-
-#if ! defined(LL_THREADPOOL_H)
-#define LL_THREADPOOL_H
-
-#include "workqueue.h"
-#include <string>
-#include <thread>
-#include <utility>                  // std::pair
-#include <vector>
-
-namespace LL
-{
-
-    class ThreadPool
-    {
-    public:
-        /**
-         * Pass ThreadPool a string name. This can be used to look up the
-         * relevant WorkQueue.
-         */
-        ThreadPool(const std::string& name, size_t threads=1, size_t capacity=1024);
-        virtual ~ThreadPool();
-
-        /**
-         * ThreadPool listens for application shutdown messages on the "LLApp"
-         * LLEventPump. Call close() to shut down this ThreadPool early.
-         */
-        void close();
-
-        std::string getName() const { return mName; }
-        size_t getWidth() const { return mThreads.size(); }
-        /// obtain a non-const reference to the WorkQueue to post work to it
-        WorkQueue& getQueue() { return mQueue; }
-
-        /**
-         * Override run() if you need special processing. The default run()
-         * implementation simply calls WorkQueue::runUntilClose().
-         */
-        virtual void run();
-
-    private:
-        void run(const std::string& name);
-
-        WorkQueue mQueue;
-        std::string mName;
-        std::vector<std::pair<std::string, std::thread>> mThreads;
-    };
-
-} // namespace LL
-
-#endif /* ! defined(LL_THREADPOOL_H) */
diff --git a/indra/llcommon/timing.cpp b/indra/llcommon/timing.cpp
new file mode 100644
index 0000000000..c2dc695ef3
--- /dev/null
+++ b/indra/llcommon/timing.cpp
@@ -0,0 +1,25 @@
+/** 
+ * @file timing.cpp
+ * @brief This file will be deprecated in the future.
+ *
+ * $LicenseInfo:firstyear=2000&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$
+ */
diff --git a/indra/llcommon/workqueue.cpp b/indra/llcommon/workqueue.cpp
index 633594ceea..b32357e832 100644
--- a/indra/llcommon/workqueue.cpp
+++ b/indra/llcommon/workqueue.cpp
@@ -26,9 +26,8 @@
 using Mutex = LLCoros::Mutex;
 using Lock  = LLCoros::LockType;
 
-LL::WorkQueue::WorkQueue(const std::string& name, size_t capacity):
-    super(makeName(name)),
-    mQueue(capacity)
+LL::WorkQueue::WorkQueue(const std::string& name):
+    super(makeName(name))
 {
     // TODO: register for "LLApp" events so we can implicitly close() on
     // viewer shutdown.
@@ -39,21 +38,6 @@ void LL::WorkQueue::close()
     mQueue.close();
 }
 
-size_t LL::WorkQueue::size()
-{
-    return mQueue.size();
-}
-
-bool LL::WorkQueue::isClosed()
-{
-    return mQueue.isClosed();
-}
-
-bool LL::WorkQueue::done()
-{
-    return mQueue.done();
-}
-
 void LL::WorkQueue::runUntilClose()
 {
     try
@@ -144,13 +128,3 @@ void LL::WorkQueue::error(const std::string& msg)
 {
     LL_ERRS("WorkQueue") << msg << LL_ENDL;
 }
-
-void LL::WorkQueue::checkCoroutine(const std::string& method)
-{
-    // By convention, the default coroutine on each thread has an empty name
-    // string. See also LLCoros::logname().
-    if (LLCoros::getName().empty())
-    {
-        LLTHROW(Error("Do not call " + method + " from a thread's default coroutine"));
-    }
-}
diff --git a/indra/llcommon/workqueue.h b/indra/llcommon/workqueue.h
index c25d787425..5ec790da79 100644
--- a/indra/llcommon/workqueue.h
+++ b/indra/llcommon/workqueue.h
@@ -12,14 +12,14 @@
 #if ! defined(LL_WORKQUEUE_H)
 #define LL_WORKQUEUE_H
 
-#include "llcoros.h"
-#include "llexception.h"
 #include "llinstancetracker.h"
 #include "threadsafeschedule.h"
 #include <chrono>
-#include <exception>                // std::current_exception
 #include <functional>               // std::function
+#include <queue>
 #include <string>
+#include <utility>                  // std::pair
+#include <vector>
 
 namespace LL
 {
@@ -45,16 +45,11 @@ namespace LL
         using TimedWork = Queue::TimeTuple;
         using Closed    = Queue::Closed;
 
-        struct Error: public LLException
-        {
-            Error(const std::string& what): LLException(what) {}
-        };
-
         /**
          * You may omit the WorkQueue name, in which case a unique name is
          * synthesized; for practical purposes that makes it anonymous.
          */
-        WorkQueue(const std::string& name = std::string(), size_t capacity=1024);
+        WorkQueue(const std::string& name = std::string());
 
         /**
          * Since the point of WorkQueue is to pass work to some other worker
@@ -64,36 +59,15 @@ namespace LL
          */
         void close();
 
-        /**
-         * WorkQueue supports multiple producers and multiple consumers. In
-         * the general case it's misleading to test size(), since any other
-         * thread might change it the nanosecond the lock is released. On that
-         * basis, some might argue against publishing a size() method at all.
-         *
-         * But there are two specific cases in which a test based on size()
-         * might be reasonable:
-         *
-         * * If you're the only producer, noticing that size() == 0 is
-         *   meaningful.
-         * * If you're the only consumer, noticing that size() > 0 is
-         *   meaningful.
-         */
-        size_t size();
-        /// producer end: are we prevented from pushing any additional items?
-        bool isClosed();
-        /// consumer end: are we done, is the queue entirely drained?
-        bool done();
-
         /*---------------------- fire and forget API -----------------------*/
 
         /// fire-and-forget, but at a particular (future?) time
         template <typename CALLABLE>
         void post(const TimePoint& time, CALLABLE&& callable)
         {
-            // Defer reifying an arbitrary CALLABLE until we hit this or
-            // postIfOpen(). All other methods should accept CALLABLEs of
-            // arbitrary type to avoid multiple levels of std::function
-            // indirection.
+            // 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)));
         }
 
@@ -108,47 +82,6 @@ namespace LL
             post(TimePoint::clock::now(), std::move(callable));
         }
 
-        /**
-         * post work for a particular time, unless the queue is closed before
-         * we can post
-         */
-        template <typename CALLABLE>
-        bool postIfOpen(const TimePoint& time, CALLABLE&& callable)
-        {
-            // Defer reifying an arbitrary CALLABLE until we hit this or
-            // post(). All other methods should accept CALLABLEs of arbitrary
-            // type to avoid multiple levels of std::function indirection.
-            return mQueue.pushIfOpen(TimedWork(time, std::move(callable)));
-        }
-
-        /**
-         * post work, unless the queue is closed before we can post
-         */
-        template <typename CALLABLE>
-        bool postIfOpen(CALLABLE&& callable)
-        {
-            return postIfOpen(TimePoint::clock::now(), std::move(callable));
-        }
-
-        /**
-         * Post work to be run at a specified time to another WorkQueue, which
-         * may or may not still exist and be open. Return true if we were able
-         * to post.
-         */
-        template <typename CALLABLE>
-        static bool postMaybe(weak_t target, const TimePoint& time, CALLABLE&& callable);
-
-        /**
-         * Post work to another WorkQueue, which may or may not still exist
-         * and be open. Return true if we were able to post.
-         */
-        template <typename CALLABLE>
-        static bool postMaybe(weak_t target, CALLABLE&& callable)
-        {
-            return postMaybe(target, TimePoint::clock::now(),
-                             std::forward<CALLABLE>(callable));
-        }
-
         /**
          * Launch a callable returning bool that will trigger repeatedly at
          * specified interval, until the callable returns false.
@@ -182,8 +115,63 @@ namespace LL
         // Studio compile errors that seem utterly unrelated to this source
         // code.
         template <typename CALLABLE, typename FOLLOWUP>
-        bool postTo(weak_t target,
-                    const TimePoint& time, CALLABLE&& callable, FOLLOWUP&& callback);
+        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
@@ -193,36 +181,10 @@ namespace LL
          * inaccessible.
          */
         template <typename CALLABLE, typename FOLLOWUP>
-        bool postTo(weak_t target, CALLABLE&& callable, FOLLOWUP&& callback)
+        bool postTo(WorkQueue::weak_t target,
+                    CALLABLE&& callable, FOLLOWUP&& callback)
         {
-            return postTo(target, TimePoint::clock::now(),
-                          std::move(callable), std::move(callback));
-        }
-
-        /**
-         * Post work to another WorkQueue to be run at a specified time,
-         * blocking the calling coroutine until then, returning the result to
-         * caller on completion.
-         *
-         * In general, we assume that each thread's default coroutine is busy
-         * servicing its WorkQueue or whatever. To try to prevent mistakes, we
-         * forbid calling waitForResult() from a thread's default coroutine.
-         */
-        template <typename CALLABLE>
-        auto waitForResult(const TimePoint& time, CALLABLE&& callable);
-
-        /**
-         * Post work to another WorkQueue, blocking the calling coroutine
-         * until then, returning the result to caller on completion.
-         *
-         * In general, we assume that each thread's default coroutine is busy
-         * servicing its WorkQueue or whatever. To try to prevent mistakes, we
-         * forbid calling waitForResult() from a thread's default coroutine.
-         */
-        template <typename CALLABLE>
-        auto waitForResult(CALLABLE&& callable)
-        {
-            return waitForResult(TimePoint::clock::now(), std::move(callable));
+            return postTo(target, TimePoint::clock::now(), std::move(callable), std::move(callback));
         }
 
         /*--------------------------- worker API ---------------------------*/
@@ -270,23 +232,6 @@ namespace LL
         bool runUntil(const TimePoint& until);
 
     private:
-        template <typename CALLABLE, typename FOLLOWUP>
-        static auto makeReplyLambda(CALLABLE&& callable, FOLLOWUP&& callback);
-        /// general case: arbitrary C++ return type
-        template <typename CALLABLE, typename FOLLOWUP, typename RETURNTYPE>
-        struct MakeReplyLambda;
-        /// specialize for CALLABLE returning void
-        template <typename CALLABLE, typename FOLLOWUP>
-        struct MakeReplyLambda<CALLABLE, FOLLOWUP, void>;
-
-        /// general case: arbitrary C++ return type
-        template <typename CALLABLE, typename RETURNTYPE>
-        struct WaitForResult;
-        /// specialize for CALLABLE returning void
-        template <typename CALLABLE>
-        struct WaitForResult<CALLABLE, void>;
-
-        static void checkCoroutine(const std::string& method);
         static void error(const std::string& msg);
         static std::string makeName(const std::string& name);
         void callWork(const Queue::DataTuple& work);
@@ -308,8 +253,8 @@ namespace LL
     {
     public:
         // bind the desired data
-        BackJack(weak_t target,
-                 const TimePoint& start,
+        BackJack(WorkQueue::weak_t target,
+                 const WorkQueue::TimePoint& start,
                  const std::chrono::duration<Rep, Period>& interval,
                  CALLABLE&& callable):
             mTarget(target),
@@ -356,8 +301,8 @@ namespace LL
         }
 
     private:
-        weak_t mTarget;
-        TimePoint mStart;
+        WorkQueue::weak_t mTarget;
+        WorkQueue::TimePoint mStart;
         std::chrono::duration<Rep, Period> mInterval;
         CALLABLE mCallable;
     };
@@ -385,187 +330,6 @@ namespace LL
                  getWeak(), TimePoint::clock::now(), interval, std::move(callable)));
     }
 
-    /// general case: arbitrary C++ return type
-    template <typename CALLABLE, typename FOLLOWUP, typename RETURNTYPE>
-    struct WorkQueue::MakeReplyLambda
-    {
-        auto operator()(CALLABLE&& callable, FOLLOWUP&& callback)
-        {
-            // Call the callable in any case -- but to minimize
-            // copying the result, immediately bind it into the reply
-            // lambda. The reply lambda also binds the original
-            // callback, so that when we, the originating WorkQueue,
-            // finally receive and process the reply lambda, we'll
-            // call the bound callback with the bound result -- on the
-            // same thread that originally called postTo().
-            return
-                [result = std::forward<CALLABLE>(callable)(),
-                 callback = std::move(callback)]
-                ()
-                { callback(std::move(result)); };
-        }
-    };
-
-    /// specialize for CALLABLE returning void
-    template <typename CALLABLE, typename FOLLOWUP>
-    struct WorkQueue::MakeReplyLambda<CALLABLE, FOLLOWUP, void>
-    {
-        auto operator()(CALLABLE&& callable, FOLLOWUP&& callback)
-        {
-            // Call the callable, which produces no result.
-            std::forward<CALLABLE>(callable)();
-            // Our completion callback is simply the caller's callback.
-            return std::move(callback);
-        }
-    };
-
-    template <typename CALLABLE, typename FOLLOWUP>
-    auto WorkQueue::makeReplyLambda(CALLABLE&& callable, FOLLOWUP&& callback)
-    {
-        return MakeReplyLambda<CALLABLE, FOLLOWUP,
-                               decltype(std::forward<CALLABLE>(callable)())>()
-            (std::move(callable), std::move(callback));
-    }
-
-    template <typename CALLABLE, typename FOLLOWUP>
-    bool WorkQueue::postTo(weak_t target,
-                           const TimePoint& time, CALLABLE&& callable, FOLLOWUP&& callback)
-    {
-        // 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)]
-            ()
-            {
-                // Use postMaybe() below in case this originating WorkQueue
-                // has been closed or destroyed. Remember, the outer lambda is
-                // now running on a thread servicing the target WorkQueue, and
-                // real time has elapsed since postTo()'s tptr->post() call.
-                try
-                {
-                    // Make a reply lambda to repost to THIS WorkQueue.
-                    // Delegate to makeReplyLambda() so we can partially
-                    // specialize on void return.
-                    postMaybe(reply, makeReplyLambda(std::move(callable), std::move(callback)));
-                }
-                catch (...)
-                {
-                    // Either variant of makeReplyLambda() is responsible for
-                    // calling the caller's callable. If that throws, return
-                    // the exception to the originating thread.
-                    postMaybe(
-                        reply,
-                        // Bind the current exception to transport back to the
-                        // originating WorkQueue. Once there, rethrow it.
-                        [exc = std::current_exception()](){ std::rethrow_exception(exc); });
-                }
-            });
-
-        // looks like we were able to post()
-        return true;
-    }
-
-    template <typename CALLABLE>
-    bool WorkQueue::postMaybe(weak_t target, const TimePoint& time, CALLABLE&& callable)
-    {
-        // target is a weak_ptr: have to lock it to check it
-        auto tptr = target.lock();
-        if (tptr)
-        {
-            try
-            {
-                tptr->post(time, std::forward<CALLABLE>(callable));
-                // we were able to post()
-                return true;
-            }
-            catch (const Closed&)
-            {
-                // target WorkQueue still exists, but is Closed
-            }
-        }
-        // either target no longer exists, or its WorkQueue is Closed
-        return false;
-    }
-
-    /// general case: arbitrary C++ return type
-    template <typename CALLABLE, typename RETURNTYPE>
-    struct WorkQueue::WaitForResult
-    {
-        auto operator()(WorkQueue* self, const TimePoint& time, CALLABLE&& callable)
-        {
-            LLCoros::Promise<RETURNTYPE> promise;
-            self->post(
-                time,
-                // We dare to bind a reference to Promise because it's
-                // specifically designed for cross-thread communication.
-                [&promise, callable = std::move(callable)]()
-                {
-                    try
-                    {
-                        // call the caller's callable and trigger promise with result
-                        promise.set_value(callable());
-                    }
-                    catch (...)
-                    {
-                        promise.set_exception(std::current_exception());
-                    }
-                });
-            auto future{ LLCoros::getFuture(promise) };
-            // now, on the calling thread, wait for that result
-            LLCoros::TempStatus st("waiting for WorkQueue::waitForResult()");
-            return future.get();
-        }
-    };
-
-    /// specialize for CALLABLE returning void
-    template <typename CALLABLE>
-    struct WorkQueue::WaitForResult<CALLABLE, void>
-    {
-        void operator()(WorkQueue* self, const TimePoint& time, CALLABLE&& callable)
-        {
-            LLCoros::Promise<void> promise;
-            self->post(
-                time,
-                // &promise is designed for cross-thread access
-                [&promise, callable = std::move(callable)]()
-                {
-                    try
-                    {
-                        callable();
-                        promise.set_value();
-                    }
-                    catch (...)
-                    {
-                        promise.set_exception(std::current_exception());
-                    }
-                });
-            auto future{ LLCoros::getFuture(promise) };
-            // block until set_value()
-            LLCoros::TempStatus st("waiting for void WorkQueue::waitForResult()");
-            future.get();
-        }
-    };
-
-    template <typename CALLABLE>
-    auto WorkQueue::waitForResult(const TimePoint& time, CALLABLE&& callable)
-    {
-        checkCoroutine("waitForResult()");
-        // derive callable's return type so we can specialize for void
-        return WaitForResult<CALLABLE, decltype(std::forward<CALLABLE>(callable)())>()
-            (this, time, std::forward<CALLABLE>(callable));
-    }
-
 } // namespace LL
 
 #endif /* ! defined(LL_WORKQUEUE_H) */
diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp
index 1b6920fe3b..cbc5392882 100644
--- a/indra/llrender/llimagegl.cpp
+++ b/indra/llrender/llimagegl.cpp
@@ -172,19 +172,31 @@ BOOL is_little_endian()
 	return (*c == 0x78) ;
 }
 
+LLImageGLThread* LLImageGLThread::sInstance = nullptr;
+
 //static 
 void LLImageGL::initClass(LLWindow* window, S32 num_catagories, BOOL skip_analyze_alpha /* = false */)
 {
     LL_PROFILE_ZONE_SCOPED;
 	sSkipAnalyzeAlpha = skip_analyze_alpha;
-    LLImageGLThread::createInstance(window);
+    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::deleteSingleton();
+    LLImageGLThread::sInstance->mFunctionQueue.close();
+    delete LLImageGLThread::sInstance;
+    LLImageGLThread::sInstance = nullptr;
 }
 
 //static
@@ -492,9 +504,6 @@ void LLImageGL::init(BOOL usemipmaps)
 #endif
 
 	mCategory = -1;
-
-	// Sometimes we have to post work for the main thread.
-	mMainQueue = LL::WorkQueue::getInstance("mainloop");
 }
 
 void LLImageGL::cleanup()
@@ -1527,7 +1536,8 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_
     }
 
     //if we're on the image loading thread, be sure to delete old_texname and update mTexName on the main thread
-    if (! on_main_thread())
+    if (LLImageGLThread::sInstance != nullptr && 
+        LLThread::currentID() == LLImageGLThread::sInstance->getID())
     {
         {
             LL_PROFILE_ZONE_NAMED("cglt - sync");
@@ -1544,9 +1554,7 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_
         }
 
         ref();
-        LL::WorkQueue::postMaybe(
-            mMainQueue,
-            [=]()
+        LLImageGLThread::sInstance->postCallback([=]()
             {
                 LL_PROFILE_ZONE_NAMED("cglt - delete callback");
                 if (old_texname != 0)
@@ -2251,24 +2259,73 @@ void LLImageGL::resetCurTexSizebar()
 */  
 
 LLImageGLThread::LLImageGLThread(LLWindow* window)
-    // We want exactly one thread, but a very large capacity: we never want
-    // anyone, especially inner-loop render code, to have to block on post()
-    // because we're full.
-    : ThreadPool("LLImageGL", 1, 1024*1024)
-    , mWindow(window)
+    : 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
+    {
+        mFunctionQueue.post(func);
+    }
+    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
+    {
+        if (!mCallbackQueue.tryPost(callback))
+        {
+            mPendingCallbackQ.push(callback);
+        }
+    }
+    catch (LLThreadSafeQueueInterrupt e)
+    {
+        //thread is closing, drop request
+        return false;
+    }
+
+    return true;
+}
+
+void LLImageGLThread::executeCallbacks()
+{
+    LL_PROFILE_ZONE_SCOPED;
+    //executed from main thread
+    mCallbackQueue.runPending();
+
+    while (!mPendingCallbackQ.empty())
+    {
+        if (mCallbackQueue.tryPost(mPendingCallbackQ.front()))
+        {
+            mPendingCallbackQ.pop();
+        }
+        else
+        {
+            break;
+        }
+    }
+}
+
 void LLImageGLThread::run()
 {
-    // We must perform setup on this thread before actually servicing our
-    // WorkQueue, likewise cleanup afterwards.
     mWindow->makeContextCurrent(mContext);
     gGL.init();
-    ThreadPool::run();
+    mFunctionQueue.runUntilClose();
     gGL.shutdown();
     mWindow->destroySharedContext(mContext);
 }
diff --git a/indra/llrender/llimagegl.h b/indra/llrender/llimagegl.h
index 27496def1d..8264e4a5f2 100644
--- a/indra/llrender/llimagegl.h
+++ b/indra/llrender/llimagegl.h
@@ -37,7 +37,6 @@
 #include "llunits.h"
 #include "llthreadsafequeue.h"
 #include "llrender.h"
-#include "threadpool.h"
 #include "workqueue.h"
 
 class LLTextureAtlas ;
@@ -199,7 +198,6 @@ private:
 	void freePickMask();
 
 	LLPointer<LLImageRaw> mSaveData; // used for destroyGL/restoreGL
-	LL::WorkQueue::weak_t mMainQueue;
 	U8* mPickMask;  //downsampled bitmap approximation of alpha channel.  NULL if no alpha channel
 	U16 mPickMaskWidth;
 	U16 mPickMaskHeight;
@@ -273,6 +271,7 @@ public:
 
 public:
 	static void initClass(LLWindow* window, S32 num_catagories, BOOL skip_analyze_alpha = false); 
+    static void updateClass();
 	static void cleanupClass() ;
 
 private:
@@ -308,24 +307,34 @@ public:
 
 };
 
-class LLImageGLThread : public LLSimpleton<LLImageGLThread>, LL::ThreadPool
+class LLImageGLThread : public LLThread
 {
 public:
     LLImageGLThread(LLWindow* window);
 
     // post a function to be executed on the LLImageGL background thread
-    template <typename CALLABLE>
-    bool post(CALLABLE&& func)
-    {
-        return getQueue().postIfOpen(std::forward<CALLABLE>(func));
-    }
+    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;
 
-private:
+    // Work Queue for background thread
+    LL::WorkQueue mFunctionQueue;
+
+    // Work Queue for main thread (run from updateClass)
+    LL::WorkQueue mCallbackQueue;
+
     LLWindow* mWindow;
     void* mContext;
     LLAtomicBool mFinished;
+
+    std::queue<std::function<void()>> mPendingCallbackQ;
+
+    static LLImageGLThread* sInstance;
 };
 
 
diff --git a/indra/llui/CMakeLists.txt b/indra/llui/CMakeLists.txt
index 55c1655d7b..f781ff4110 100644
--- a/indra/llui/CMakeLists.txt
+++ b/indra/llui/CMakeLists.txt
@@ -308,10 +308,6 @@ if(LL_TESTS)
       ${BOOST_FIBER_LIBRARY} ${BOOST_CONTEXT_LIBRARY} ${BOOST_SYSTEM_LIBRARY}
       ${WINDOWS_LIBRARIES})
   if(NOT LINUX)
-    if(WINDOWS)
-      LL_ADD_INTEGRATION_TEST(llurlentry llurlentry.cpp "imm32;${test_libs}")
-    else(WINDOWS)
-      LL_ADD_INTEGRATION_TEST(llurlentry llurlentry.cpp "${test_libs}")
-    endif(WINDOWS)
+    LL_ADD_INTEGRATION_TEST(llurlentry llurlentry.cpp "${test_libs}")
   endif(NOT LINUX)
 endif(LL_TESTS)
diff --git a/indra/llui/llviewereventrecorder.cpp b/indra/llui/llviewereventrecorder.cpp
index cb000aef74..5a44ec947a 100644
--- a/indra/llui/llviewereventrecorder.cpp
+++ b/indra/llui/llviewereventrecorder.cpp
@@ -28,6 +28,8 @@
 #include "llui.h"
 #include "llleap.h"
 
+LLViewerEventRecorder* LLSimpleton<LLViewerEventRecorder>::sInstance = nullptr;
+
 LLViewerEventRecorder::LLViewerEventRecorder() {
 
   clear(UNDEFINED);
diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp
index 3f3dd43daf..e52624d66a 100644
--- a/indra/llwindow/llwindowwin32.cpp
+++ b/indra/llwindow/llwindowwin32.cpp
@@ -55,8 +55,6 @@
 #include <shellapi.h>
 #include <fstream>
 #include <Imm.h>
-#include <future>
-#include <utility>                  // std::pair
 
 // Require DirectInput version 8
 #define DIRECTINPUT_VERSION 0x0800
@@ -176,19 +174,23 @@ DWORD	LLWindowWin32::sWinIMESentenceMode = IME_SMODE_AUTOMATIC;
 LLCoordWindow LLWindowWin32::sWinIMEWindowPosition(-1,-1);
 
 // The following class LLWinImm delegates Windows IMM APIs.
-// It was originally introduced to support US Windows XP, on which we needed
-// to dynamically load IMM32.DLL and use GetProcAddress to resolve its entry
-// points. Now that that's moot, we retain this wrapper only for hooks for
-// metrics.
+// We need this because some language versions of Windows,
+// e.g., US version of Windows XP, doesn't install IMM32.DLL
+// as a default, and we can't link against imm32.lib statically.
+// I believe DLL loading of this type is best suited to do
+// in a static initialization of a class.  What I'm not sure is
+// whether it follows the Linden Conding Standard... 
+// See http://wiki.secondlife.com/wiki/Coding_standards#Static_Members
 
 class LLWinImm
 {
 public:
-	static bool		isAvailable() { return true; }
+	static bool		isAvailable() { return sTheInstance.mHImmDll != NULL; }
 
 public:
 	// Wrappers for IMM API.
 	static BOOL		isIME(HKL hkl);															
+	static HWND		getDefaultIMEWnd(HWND hwnd);
 	static HIMC		getContext(HWND hwnd);													
 	static BOOL		releaseContext(HWND hwnd, HIMC himc);
 	static BOOL		getOpenStatus(HIMC himc);												
@@ -202,96 +204,236 @@ public:
 	static BOOL		setCompositionFont(HIMC himc, LPLOGFONTW logfont);
 	static BOOL		setCandidateWindow(HIMC himc, LPCANDIDATEFORM candidate_form);
 	static BOOL		notifyIME(HIMC himc, DWORD action, DWORD index, DWORD value);
+
+private:
+	LLWinImm();
+	~LLWinImm();
+
+private:
+	// Pointers to IMM API.
+	BOOL	 	(WINAPI *mImmIsIME)(HKL);
+	HWND		(WINAPI *mImmGetDefaultIMEWnd)(HWND);
+	HIMC		(WINAPI *mImmGetContext)(HWND);
+	BOOL		(WINAPI *mImmReleaseContext)(HWND, HIMC);
+	BOOL		(WINAPI *mImmGetOpenStatus)(HIMC);
+	BOOL		(WINAPI *mImmSetOpenStatus)(HIMC, BOOL);
+	BOOL		(WINAPI *mImmGetConversionStatus)(HIMC, LPDWORD, LPDWORD);
+	BOOL		(WINAPI *mImmSetConversionStatus)(HIMC, DWORD, DWORD);
+	BOOL		(WINAPI *mImmGetCompostitionWindow)(HIMC, LPCOMPOSITIONFORM);
+	BOOL		(WINAPI *mImmSetCompostitionWindow)(HIMC, LPCOMPOSITIONFORM);
+	LONG		(WINAPI *mImmGetCompositionString)(HIMC, DWORD, LPVOID, DWORD);
+	BOOL		(WINAPI *mImmSetCompositionString)(HIMC, DWORD, LPVOID, DWORD, LPVOID, DWORD);
+	BOOL		(WINAPI *mImmSetCompositionFont)(HIMC, LPLOGFONTW);
+	BOOL		(WINAPI *mImmSetCandidateWindow)(HIMC, LPCANDIDATEFORM);
+	BOOL		(WINAPI *mImmNotifyIME)(HIMC, DWORD, DWORD, DWORD);
+
+private:
+	HMODULE		mHImmDll;
+	static LLWinImm sTheInstance;
 };
 
+LLWinImm LLWinImm::sTheInstance;
+
+LLWinImm::LLWinImm() : mHImmDll(NULL)
+{
+	// Check system metrics 
+	if ( !GetSystemMetrics( SM_IMMENABLED ) )
+		return;
+
+	mHImmDll = LoadLibraryA("Imm32");
+	if (mHImmDll != NULL)
+	{
+		mImmIsIME               = (BOOL (WINAPI *)(HKL))                    GetProcAddress(mHImmDll, "ImmIsIME");
+		mImmGetDefaultIMEWnd	= (HWND (WINAPI *)(HWND))					GetProcAddress(mHImmDll, "ImmGetDefaultIMEWnd");
+		mImmGetContext          = (HIMC (WINAPI *)(HWND))                   GetProcAddress(mHImmDll, "ImmGetContext");
+		mImmReleaseContext      = (BOOL (WINAPI *)(HWND, HIMC))             GetProcAddress(mHImmDll, "ImmReleaseContext");
+		mImmGetOpenStatus       = (BOOL (WINAPI *)(HIMC))                   GetProcAddress(mHImmDll, "ImmGetOpenStatus");
+		mImmSetOpenStatus       = (BOOL (WINAPI *)(HIMC, BOOL))             GetProcAddress(mHImmDll, "ImmSetOpenStatus");
+		mImmGetConversionStatus = (BOOL (WINAPI *)(HIMC, LPDWORD, LPDWORD)) GetProcAddress(mHImmDll, "ImmGetConversionStatus");
+		mImmSetConversionStatus = (BOOL (WINAPI *)(HIMC, DWORD, DWORD))     GetProcAddress(mHImmDll, "ImmSetConversionStatus");
+		mImmGetCompostitionWindow = (BOOL (WINAPI *)(HIMC, LPCOMPOSITIONFORM))   GetProcAddress(mHImmDll, "ImmGetCompositionWindow");
+		mImmSetCompostitionWindow = (BOOL (WINAPI *)(HIMC, LPCOMPOSITIONFORM))   GetProcAddress(mHImmDll, "ImmSetCompositionWindow");
+		mImmGetCompositionString= (LONG (WINAPI *)(HIMC, DWORD, LPVOID, DWORD))					GetProcAddress(mHImmDll, "ImmGetCompositionStringW");
+		mImmSetCompositionString= (BOOL (WINAPI *)(HIMC, DWORD, LPVOID, DWORD, LPVOID, DWORD))	GetProcAddress(mHImmDll, "ImmSetCompositionStringW");
+		mImmSetCompositionFont  = (BOOL (WINAPI *)(HIMC, LPLOGFONTW))		GetProcAddress(mHImmDll, "ImmSetCompositionFontW");
+		mImmSetCandidateWindow  = (BOOL (WINAPI *)(HIMC, LPCANDIDATEFORM))  GetProcAddress(mHImmDll, "ImmSetCandidateWindow");
+		mImmNotifyIME			= (BOOL (WINAPI *)(HIMC, DWORD, DWORD, DWORD))	GetProcAddress(mHImmDll, "ImmNotifyIME");
+
+		if (mImmIsIME == NULL ||
+			mImmGetDefaultIMEWnd == NULL ||
+			mImmGetContext == NULL ||
+			mImmReleaseContext == NULL ||
+			mImmGetOpenStatus == NULL ||
+			mImmSetOpenStatus == NULL ||
+			mImmGetConversionStatus == NULL ||
+			mImmSetConversionStatus == NULL ||
+			mImmGetCompostitionWindow == NULL ||
+			mImmSetCompostitionWindow == NULL ||
+			mImmGetCompositionString == NULL ||
+			mImmSetCompositionString == NULL ||
+			mImmSetCompositionFont == NULL ||
+			mImmSetCandidateWindow == NULL ||
+			mImmNotifyIME == NULL)
+		{
+			// If any of the above API entires are not found, we can't use IMM API.  
+			// So, turn off the IMM support.  We should log some warning message in 
+			// the case, since it is very unusual; these APIs are available from 
+			// the beginning, and all versions of IMM32.DLL should have them all.  
+			// Unfortunately, this code may be executed before initialization of 
+			// the logging channel (LL_WARNS()), and we can't do it here...  Yes, this 
+			// is one of disadvantages to use static constraction to DLL loading. 
+			FreeLibrary(mHImmDll);
+			mHImmDll = NULL;
+
+			// If we unload the library, make sure all the function pointers are cleared
+			mImmIsIME = NULL;
+			mImmGetDefaultIMEWnd = NULL;
+			mImmGetContext = NULL;
+			mImmReleaseContext = NULL;
+			mImmGetOpenStatus = NULL;
+			mImmSetOpenStatus = NULL;
+			mImmGetConversionStatus = NULL;
+			mImmSetConversionStatus = NULL;
+			mImmGetCompostitionWindow = NULL;
+			mImmSetCompostitionWindow = NULL;
+			mImmGetCompositionString = NULL;
+			mImmSetCompositionString = NULL;
+			mImmSetCompositionFont = NULL;
+			mImmSetCandidateWindow = NULL;
+			mImmNotifyIME = NULL;
+		}
+	}
+}
+
+
 // static 
 BOOL	LLWinImm::isIME(HKL hkl)
 { 
-	return ImmIsIME(hkl);
+	if ( sTheInstance.mImmIsIME )
+		return sTheInstance.mImmIsIME(hkl); 
+	return FALSE;
 }
 
 // static 
 HIMC		LLWinImm::getContext(HWND hwnd)
 {
-	return ImmGetContext(hwnd);
+	if ( sTheInstance.mImmGetContext )
+		return sTheInstance.mImmGetContext(hwnd); 
+	return 0;
 }
 
 //static 
 BOOL		LLWinImm::releaseContext(HWND hwnd, HIMC himc)
 { 
-	return ImmReleaseContext(hwnd, himc);
+	if ( sTheInstance.mImmIsIME )
+		return sTheInstance.mImmReleaseContext(hwnd, himc); 
+	return FALSE;
 }
 
 // static 
 BOOL		LLWinImm::getOpenStatus(HIMC himc)
 { 
-	return ImmGetOpenStatus(himc);
+	if ( sTheInstance.mImmGetOpenStatus )
+		return sTheInstance.mImmGetOpenStatus(himc); 
+	return FALSE;
 }
 
 // static 
 BOOL		LLWinImm::setOpenStatus(HIMC himc, BOOL status)
 { 
-	return ImmSetOpenStatus(himc, status);
+	if ( sTheInstance.mImmSetOpenStatus )
+		return sTheInstance.mImmSetOpenStatus(himc, status); 
+	return FALSE;
 }
 
 // static 
 BOOL		LLWinImm::getConversionStatus(HIMC himc, LPDWORD conversion, LPDWORD sentence)	
 { 
-	return ImmGetConversionStatus(himc, conversion, sentence);
+	if ( sTheInstance.mImmGetConversionStatus )
+		return sTheInstance.mImmGetConversionStatus(himc, conversion, sentence); 
+	return FALSE;
 }
 
 // static 
 BOOL		LLWinImm::setConversionStatus(HIMC himc, DWORD conversion, DWORD sentence)		
 { 
-	return ImmSetConversionStatus(himc, conversion, sentence);
+	if ( sTheInstance.mImmSetConversionStatus )
+		return sTheInstance.mImmSetConversionStatus(himc, conversion, sentence); 
+	return FALSE;
 }
 
 // static 
 BOOL		LLWinImm::getCompositionWindow(HIMC himc, LPCOMPOSITIONFORM form)					
 { 
-	return ImmGetCompositionWindow(himc, form);
+	if ( sTheInstance.mImmGetCompostitionWindow )
+		return sTheInstance.mImmGetCompostitionWindow(himc, form);	
+	return FALSE;
 }
 
 // static 
 BOOL		LLWinImm::setCompositionWindow(HIMC himc, LPCOMPOSITIONFORM form)					
 { 
-	return ImmSetCompositionWindow(himc, form);
+	if ( sTheInstance.mImmSetCompostitionWindow )
+		return sTheInstance.mImmSetCompostitionWindow(himc, form);	
+	return FALSE;
 }
 
 
 // static 
 LONG		LLWinImm::getCompositionString(HIMC himc, DWORD index, LPVOID data, DWORD length)					
 { 
-	return ImmGetCompositionString(himc, index, data, length);
+	if ( sTheInstance.mImmGetCompositionString )
+		return sTheInstance.mImmGetCompositionString(himc, index, data, length);	
+	return FALSE;
 }
 
 
 // static 
 BOOL		LLWinImm::setCompositionString(HIMC himc, DWORD index, LPVOID pComp, DWORD compLength, LPVOID pRead, DWORD readLength)					
 { 
-	return ImmSetCompositionString(himc, index, pComp, compLength, pRead, readLength);
+	if ( sTheInstance.mImmSetCompositionString )
+		return sTheInstance.mImmSetCompositionString(himc, index, pComp, compLength, pRead, readLength);	
+	return FALSE;
 }
 
 // static 
 BOOL		LLWinImm::setCompositionFont(HIMC himc, LPLOGFONTW pFont)					
 { 
-	return ImmSetCompositionFont(himc, pFont);
+	if ( sTheInstance.mImmSetCompositionFont )
+		return sTheInstance.mImmSetCompositionFont(himc, pFont);	
+	return FALSE;
 }
 
 // static 
 BOOL		LLWinImm::setCandidateWindow(HIMC himc, LPCANDIDATEFORM form)					
 { 
-	return ImmSetCandidateWindow(himc, form);
+	if ( sTheInstance.mImmSetCandidateWindow )
+		return sTheInstance.mImmSetCandidateWindow(himc, form);	
+	return FALSE;
 }
 
 // static 
 BOOL		LLWinImm::notifyIME(HIMC himc, DWORD action, DWORD index, DWORD value)					
 { 
-	return ImmNotifyIME(himc, action, index, value);
+	if ( sTheInstance.mImmNotifyIME )
+		return sTheInstance.mImmNotifyIME(himc, action, index, value);	
+	return FALSE;
 }
 
 
 
+
+// ----------------------------------------------------------------------------------------
+LLWinImm::~LLWinImm()
+{
+	if (mHImmDll != NULL)
+	{
+		FreeLibrary(mHImmDll);
+		mHImmDll = NULL;
+	}
+}
+
+
 class LLMonitorInfo
 {
 public:
@@ -326,32 +468,6 @@ private:
 static LLMonitorInfo sMonitorInfo;
 
 
-// Thread that owns the Window Handle
-// This whole struct is private to LLWindowWin32, which needs to mess with its
-// members, which is why it's a struct rather than a class. In effect, we make
-// the containing class a friend.
-struct LLWindowWin32::LLWindowWin32Thread : public LL::ThreadPool
-{
-    static const int MAX_QUEUE_SIZE = 2048;
-
-    LLThreadSafeQueue<MSG> mMessageQueue;
-
-    LLWindowWin32Thread();
-
-    void run() override;
-
-    template <typename CALLABLE>
-    void post(CALLABLE&& func)
-    {
-        getQueue().post(std::forward<CALLABLE>(func));
-    }
-
-    // call PeekMessage and pull enqueue messages for later processing
-    void gatherInput();
-    HWND mWindowHandle = NULL;
-    HDC mhDC = 0;
-};
-
 
 LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks,
 							 const std::string& title, const std::string& name, S32 x, S32 y, S32 width,
@@ -363,7 +479,8 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks,
 	: LLWindow(callbacks, fullscreen, flags)
 {
     sMainThreadId = LLThread::currentID();
-    mWindowThread = new LLWindowWin32Thread();
+    mWindowThread = new LLWindowWin32Thread(this);
+    mWindowThread->start();
 	//MAINT-516 -- force a load of opengl32.dll just in case windows went sideways 
 	LoadLibrary(L"opengl32.dll");
 
@@ -434,6 +551,7 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks,
 
 	// Make an instance of our window then define the window class
 	mhInstance = GetModuleHandle(NULL);
+	mWndProc = NULL;
 
     // Init Direct Input - needed for joystick / Spacemouse
 
@@ -857,13 +975,17 @@ void LLWindowWin32::close()
                 // 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;
         });
-    // Even though the above lambda might not yet have run, we've already
-    // bound mWindowHandle into it by value, which should suffice for the
-    // operations we're asking. That's the last time WE should touch it.
-    mWindowHandle = NULL;
-    mWindowThread->close();
+
+    while (!mWindowThread->isStopped())
+    {
+        //nudge window thread
+        PostMessage(mWindowHandle, WM_USER + 0x0017, 0xB0B0, 0x1337);
+        std::this_thread::sleep_for(std::chrono::milliseconds(1));
+    }
 }
 
 BOOL LLWindowWin32::isValid()
@@ -1156,7 +1278,51 @@ BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen& size, BO
         << " Fullscreen: " << mFullscreen
         << LL_ENDL;
 
-	recreateWindow(window_rect, dw_ex_style, dw_style);
+    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 = 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)
 	{
@@ -1484,7 +1650,48 @@ const	S32   max_format  = (S32)num_formats - 1;
 			mhDC = 0;											// Zero The Device Context
 		}
 
-		recreateWindow(window_rect, dw_ex_style, dw_style);
+        auto oldHandle = mWindowHandle;
+        mWindowHandle = NULL;
+        mhDC = 0;
+
+        // Destroy The Window
+        if (oldHandle && !destroy_window_handler(oldHandle))
+        {
+            LL_WARNS("Window") << "Failed to properly close window!" << LL_ENDL;
+        }		
+
+        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)
 		{
@@ -1621,64 +1828,6 @@ const	S32   max_format  = (S32)num_formats - 1;
 	return TRUE;
 }
 
-void LLWindowWin32::recreateWindow(RECT window_rect, DWORD dw_ex_style, DWORD dw_style)
-{
-    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;
-    }
-
-    std::promise<std::pair<HWND, HDC>> promise;
-    mWindowThread->post(
-        [this, window_rect, dw_ex_style, dw_style, &promise]()
-        {
-            auto handle = 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 (! handle)
-            {
-                // Failed to create window: clear the variables. This
-                // assignment is valid because we're running on mWindowThread.
-                mWindowThread->mWindowHandle = NULL;
-                mWindowThread->mhDC = 0;
-            }
-            else
-            {
-                // Update mWindowThread's own mWindowHandle and mhDC.
-                mWindowThread->mWindowHandle = handle;
-                mWindowThread->mhDC = GetDC(handle);
-            }
-                
-            // It's important to wake up the future either way.
-            promise.set_value(std::make_pair(mWindowThread->mWindowHandle, mWindowThread->mhDC));
-        }
-    );
-
-    auto future = promise.get_future();
-    // This blocks until mWindowThread processes CreateWindowEx() and calls
-    // promise.set_value().
-    auto pair = future.get();
-    mWindowHandle = pair.first;
-    mhDC = pair.second;
-}
-
 void* LLWindowWin32::createSharedContext()
 {
     S32 attribs[] =
@@ -2032,14 +2181,12 @@ void LLWindowWin32::gatherInput()
     }
 
 
-    if (mWindowThread->getQueue().size())
+    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
+        { // 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);
         }
     }
@@ -2129,6 +2276,17 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
 
     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;
+            }
+        }
+
         // 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));
@@ -4409,32 +4567,35 @@ std::vector<std::string> LLWindowWin32::getDynamicFallbackFontList()
 
 #endif // LL_WINDOWS
 
-inline LLWindowWin32::LLWindowWin32Thread::LLWindowWin32Thread()
-    : ThreadPool("Window Thread", 1, MAX_QUEUE_SIZE)
+inline LLWindowWin32Thread::LLWindowWin32Thread(LLWindowWin32* window)
+    : LLThread("Window Thread"), 
+    mWindow(window),
+    mFunctionQueue(MAX_QUEUE_SIZE)
 {
+
 }
 
-void LLWindowWin32::LLWindowWin32Thread::run()
+inline void LLWindowWin32Thread::run()
 {
-    sWindowThreadId = std::this_thread::get_id();
-    while (! getQueue().done())
+    sWindowThreadId = getID();
+    while (!mFinished)
     {
         LL_PROFILE_ZONE_SCOPED;
 
 
-        if (mWindowHandle != 0)
+        if (mWindow && mWindow->mWindowHandle != 0)
         {
             MSG msg;
             BOOL status;
-            if (mhDC == 0)
+            if (mWindow->mhDC == 0)
             {
                 LL_PROFILE_ZONE_NAMED("w32t - PeekMessage");
-                status = PeekMessage(&msg, mWindowHandle, 0, 0, PM_REMOVE);
+                status = PeekMessage(&msg, mWindow->mWindowHandle, 0, 0, PM_REMOVE);
             }
             else
             {
                 LL_PROFILE_ZONE_NAMED("w32t - GetMessage");
-                status = GetMessage(&msg, mWindowHandle, 0, 0);
+                status = GetMessage(&msg, mWindow->mWindowHandle, 0, 0);
             }
             if (status > 0)
             {
@@ -4448,7 +4609,11 @@ void LLWindowWin32::LLWindowWin32Thread::run()
         {
             LL_PROFILE_ZONE_NAMED("w32t - Function Queue");
             //process any pending functions
-            getQueue().runPending();
+            std::function<void()> curFunc;
+            while (mFunctionQueue.tryPopBack(curFunc))
+            {
+                curFunc();
+            }
         }
         
 #if 0
@@ -4460,6 +4625,11 @@ void LLWindowWin32::LLWindowWin32Thread::run()
     }
 }
 
+void LLWindowWin32Thread::post(const std::function<void()>& func)
+{
+    mFunctionQueue.pushFront(func);
+}
+
 void LLWindowWin32::post(const std::function<void()>& func)
 {
     mFunctionQueue.pushFront(func);
diff --git a/indra/llwindow/llwindowwin32.h b/indra/llwindow/llwindowwin32.h
index 5966061177..d082080807 100644
--- a/indra/llwindow/llwindowwin32.h
+++ b/indra/llwindow/llwindowwin32.h
@@ -36,12 +36,44 @@
 #include "llthread.h"
 #include "llthreadsafequeue.h"
 #include "llmutex.h"
-#include "workqueue.h"
 
 // Hack for async host by name
 #define LL_WM_HOST_RESOLVED      (WM_APP + 1)
 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:
@@ -186,6 +218,7 @@ protected:
 	HGLRC		mhRC = 0;			// OpenGL rendering context
 	HDC			mhDC = 0;			// Windows Device context handle
 	HINSTANCE	mhInstance;		// handle to application instance
+	WNDPROC		mWndProc;		// user-installable window proc
 	RECT		mOldMouseClip;  // Screen rect to which the mouse cursor was globally constrained before we changed it in clipMouse()
 	WPARAM		mLastSizeWParam;
 	F32			mOverrideAspectRatio;
@@ -237,15 +270,14 @@ protected:
 
 	BOOL			mMouseVanish;
 
-	struct LLWindowWin32Thread;
-	LLWindowWin32Thread* mWindowThread = nullptr;
-	LLThreadSafeQueue<std::function<void()>> mFunctionQueue;
-	LLThreadSafeQueue<std::function<void()>> mMouseQueue;
-	void post(const std::function<void()>& func);
-	void postMouseButtonEvent(const std::function<void()>& func);
-	void recreateWindow(RECT window_rect, DWORD dw_ex_style, DWORD dw_style);
+    LLWindowWin32Thread* mWindowThread = nullptr;
+    LLThreadSafeQueue<std::function<void()>> mFunctionQueue;
+    LLThreadSafeQueue<std::function<void()>> mMouseQueue;
+    void post(const std::function<void()>& func);
+    void postMouseButtonEvent(const std::function<void()>& func);
 
 	friend class LLWindowManager;
+    friend class LLWindowWin32Thread;
 };
 
 class LLSplashScreenWin32 : public LLSplashScreen
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 6d090be33a..631089f6ce 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -393,6 +393,7 @@ set(viewer_SOURCE_FILES
     llloginhandler.cpp
     lllogininstance.cpp
     llmachineid.cpp
+    llmainlooprepeater.cpp
     llmanip.cpp
     llmaniprotate.cpp
     llmanipscale.cpp
@@ -1031,6 +1032,7 @@ set(viewer_HEADER_FILES
     llloginhandler.h
     lllogininstance.h
     llmachineid.h
+    llmainlooprepeater.h
     llmanip.h
     llmaniprotate.h
     llmanipscale.h
@@ -1602,7 +1604,6 @@ if (WINDOWS)
         ${WINDOWS_LIBRARIES}
         comdlg32
         dxguid
-        imm32
         kernel32
         odbc32
         odbccp32
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 607e531e62..f15b5d0981 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -3858,17 +3858,6 @@
         <key>Value</key>
         <integer>1</integer>
     </map>
-    <key>MainWorkTime</key>
-    <map>
-        <key>Comment</key>
-        <string>Max time per frame devoted to mainloop work queue (in milliseconds)</string>
-        <key>Persist</key>
-        <integer>1</integer>
-        <key>Type</key>
-        <string>F32</string>
-        <key>Value</key>
-        <real>0.1</real>
-    </map>
     <key>QueueInventoryFetchTimeout</key>
     <map>
         <key>Comment</key>
@@ -12674,20 +12663,6 @@
       <key>Value</key>
       <integer>50</integer>
     </map>
-    <key>ThreadPoolSizes</key>
-    <map>
-      <key>Comment</key>
-      <string>Map of size overrides for specific thread pools.</string>
-      <key>Persist</key>
-      <integer>1</integer>
-      <key>Type</key>
-      <string>LLSD</string>
-      <key>Value</key>
-      <map>
-        <key>General</key>
-        <integer>4</integer>
-      </map>
-    </map>
     <key>ThrottleBandwidthKBPS</key>
     <map>
       <key>Comment</key>
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 93e5c2e341..89756d0881 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -233,12 +233,11 @@
 #include "llavatariconctrl.h"
 #include "llgroupiconctrl.h"
 #include "llviewerassetstats.h"
-#include "workqueue.h"
-using namespace LL;
 
 // Include for security api initialization
 #include "llsecapi.h"
 #include "llmachineid.h"
+#include "llmainlooprepeater.h"
 #include "llcleanup.h"
 
 #include "llcoproceduremanager.h"
@@ -367,10 +366,6 @@ BOOL gLogoutInProgress = FALSE;
 
 BOOL gSimulateMemLeak = FALSE;
 
-// We don't want anyone, especially threads working on the graphics pipeline,
-// to have to block due to this WorkQueue being full.
-WorkQueue gMainloopWork("mainloop", 1024*1024);
-
 ////////////////////////////////////////////////////////////
 // Internal globals... that should be removed.
 static std::string gArgs;
@@ -386,6 +381,42 @@ static std::string gLaunchFileOnQuit;
 // Used on Win32 for other apps to identify our window (eg, win_setup)
 const char* const VIEWER_WINDOW_CLASSNAME = "Second Life";
 
+//-- LLDeferredTaskList ------------------------------------------------------
+
+/**
+ * A list of deferred tasks.
+ *
+ * We sometimes need to defer execution of some code until the viewer gets idle,
+ * e.g. removing an inventory item from within notifyObservers() may not work out.
+ *
+ * Tasks added to this list will be executed in the next LLAppViewer::idle() iteration.
+ * All tasks are executed only once.
+ */
+class LLDeferredTaskList: public LLSingleton<LLDeferredTaskList>
+{
+	LLSINGLETON_EMPTY_CTOR(LLDeferredTaskList);
+	LOG_CLASS(LLDeferredTaskList);
+
+	friend class LLAppViewer;
+	typedef boost::signals2::signal<void()> signal_t;
+
+	void addTask(const signal_t::slot_type& cb)
+	{
+		mSignal.connect(cb);
+	}
+
+	void run()
+	{
+		if (!mSignal.empty())
+		{
+			mSignal();
+			mSignal.disconnect_all_slots();
+		}
+	}
+
+	signal_t mSignal;
+};
+
 //----------------------------------------------------------------------------
 
 // List of entries from strings.xml to always replace
@@ -943,6 +974,9 @@ bool LLAppViewer::init()
 	}
 	LL_INFOS("InitInfo") << "Cache initialization is done." << LL_ENDL ;
 
+	// Initialize the repeater service.
+	LLMainLoopRepeater::instance().start();
+
     // Initialize event recorder
     LLViewerEventRecorder::createInstance();
 
@@ -2158,6 +2192,8 @@ bool LLAppViewer::cleanup()
 	SUBSYSTEM_CLEANUP(LLProxy);
     LLCore::LLHttp::cleanup();
 
+	LLMainLoopRepeater::instance().stop();
+
 	ll_close_fail_log();
 
 	LLError::LLCallStacks::cleanup();
@@ -4452,7 +4488,7 @@ bool LLAppViewer::initCache()
 
 void LLAppViewer::addOnIdleCallback(const boost::function<void()>& cb)
 {
-	gMainloopWork.post(cb);
+	LLDeferredTaskList::instance().addTask(cb);
 }
 
 void LLAppViewer::loadKeyBindings()
@@ -4850,6 +4886,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();
@@ -5226,19 +5263,8 @@ void LLAppViewer::idle()
 		}
 	}
 
-	// Service the WorkQueue we use for replies from worker threads.
-	// Use function statics for the timeslice setting so we only have to fetch
-	// and convert MainWorkTime once.
-	static F32 MainWorkTimeRaw = gSavedSettings.getF32("MainWorkTime");
-	static F32Milliseconds MainWorkTimeMs(MainWorkTimeRaw);
-	// MainWorkTime is specified in fractional milliseconds, but std::chrono
-	// uses integer representations. What if we want less than a microsecond?
-	// Use nanoseconds. We're very sure we will never need to specify a
-	// MainWorkTime that would be larger than we could express in
-	// std::chrono::nanoseconds.
-	static std::chrono::nanoseconds MainWorkTimeNanoSec{
-		std::chrono::nanoseconds::rep(MainWorkTimeMs.value() * 1000000)};
-	gMainloopWork.runFor(MainWorkTimeNanoSec);
+	// Execute deferred tasks.
+	LLDeferredTaskList::instance().run();
 
 	// Handle shutdown process, for example,
 	// wait for floaters to close, send quit message,
diff --git a/indra/newview/llenvironment.cpp b/indra/newview/llenvironment.cpp
index 1a66f10b8f..dba24b3d02 100644
--- a/indra/newview/llenvironment.cpp
+++ b/indra/newview/llenvironment.cpp
@@ -824,6 +824,7 @@ std::string env_selection_to_string(LLEnvironment::EnvSelection_t sel)
 #undef RTNENUM
 }
 
+LLEnvironment* LLSimpleton<LLEnvironment>::sInstance = nullptr;
 //-------------------------------------------------------------------------
 LLEnvironment::LLEnvironment():
     mCloudScrollDelta(),
diff --git a/indra/newview/llmainlooprepeater.cpp b/indra/newview/llmainlooprepeater.cpp
new file mode 100644
index 0000000000..6736e9a950
--- /dev/null
+++ b/indra/newview/llmainlooprepeater.cpp
@@ -0,0 +1,88 @@
+/** 
+ * @file llmachineid.cpp
+ * @brief retrieves unique machine ids
+ *
+ * $LicenseInfo:firstyear=2009&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+#include "llapr.h"
+#include "llevents.h"
+#include "llmainlooprepeater.h"
+
+
+
+// LLMainLoopRepeater
+//-----------------------------------------------------------------------------
+
+
+LLMainLoopRepeater::LLMainLoopRepeater(void):
+	mQueue(0)
+{
+	; // No op.
+}
+
+
+void LLMainLoopRepeater::start(void)
+{
+	if(mQueue != 0) return;
+
+	mQueue = new LLThreadSafeQueue<LLSD>(1024);
+	mMainLoopConnection = LLEventPumps::instance().
+		obtain("mainloop").listen(LLEventPump::inventName(), boost::bind(&LLMainLoopRepeater::onMainLoop, this, _1));
+	mRepeaterConnection = LLEventPumps::instance().
+		obtain("mainlooprepeater").listen(LLEventPump::inventName(), boost::bind(&LLMainLoopRepeater::onMessage, this, _1));
+}
+
+
+void LLMainLoopRepeater::stop(void)
+{
+	mMainLoopConnection.release();
+	mRepeaterConnection.release();
+
+	delete mQueue;
+	mQueue = 0;
+}
+
+
+bool LLMainLoopRepeater::onMainLoop(LLSD const &)
+{
+	LLSD message;
+	while(mQueue->tryPopBack(message)) {
+		std::string pump = message["pump"].asString();
+		if(pump.length() == 0 ) continue; // No pump.
+		LLEventPumps::instance().obtain(pump).post(message["payload"]);
+	}
+	return false;
+}
+
+
+bool LLMainLoopRepeater::onMessage(LLSD const & event)
+{
+	try {
+		mQueue->pushFront(event);
+	} catch(LLThreadSafeQueueError & e) {
+		LL_WARNS() << "could not repeat message (" << e.what() << ")" << 
+			event.asString() << LL_ENDL;
+	}
+	return false;
+}
diff --git a/indra/newview/llmainlooprepeater.h b/indra/newview/llmainlooprepeater.h
new file mode 100644
index 0000000000..2ec3a74e4a
--- /dev/null
+++ b/indra/newview/llmainlooprepeater.h
@@ -0,0 +1,64 @@
+/** 
+ * @file llmainlooprepeater.h
+ * @brief a service for repeating messages on the main loop.
+ *
+ * $LicenseInfo:firstyear=2010&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLMAINLOOPREPEATER_H
+#define LL_LLMAINLOOPREPEATER_H
+
+
+#include "llsd.h"
+#include "llthreadsafequeue.h"
+
+
+//
+// A service which creates the pump 'mainlooprepeater' to which any thread can
+// post a message that will be re-posted on the main loop.
+//
+// The posted message should contain two map elements: pump and payload.  The
+// pump value is a string naming the pump to which the message should be
+// re-posted.  The payload value is what will be posted to the designated pump.
+//
+class LLMainLoopRepeater:
+	public LLSingleton<LLMainLoopRepeater>
+{
+	LLSINGLETON(LLMainLoopRepeater);
+public:
+	// Start the repeater service.
+	void start(void);
+	
+	// Stop the repeater service.
+	void stop(void);
+	
+private:
+	LLTempBoundListener mMainLoopConnection;
+	LLTempBoundListener mRepeaterConnection;
+	LLThreadSafeQueue<LLSD> * mQueue;
+	
+	bool onMainLoop(LLSD const &);
+	bool onMessage(LLSD const & event);
+};
+
+
+#endif
diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp
index bc00c518e9..53247031b4 100644
--- a/indra/newview/llselectmgr.cpp
+++ b/indra/newview/llselectmgr.cpp
@@ -97,6 +97,8 @@
 #include "llglheaders.h"
 #include "llinventoryobserver.h"
 
+LLSelectMgr* LLSimpleton<LLSelectMgr>::sInstance = nullptr;
+
 LLViewerObject* getSelectedParentObject(LLViewerObject *object) ;
 //
 // Consts
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index 9a4149948c..57c5074804 100644
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -205,9 +205,6 @@
 
 #include "llstacktrace.h"
 
-#include "threadpool.h"
-
-
 #if LL_WINDOWS
 #include "lldxhardware.h"
 #endif
@@ -304,20 +301,6 @@ void callback_cache_name(const LLUUID& id, const std::string& full_name, bool is
 // local classes
 //
 
-void launchThreadPool()
-{
-    LLSD poolSizes{ gSavedSettings.getLLSD("ThreadPoolSizes") };
-    LLSD sizeSpec{ poolSizes["General"] };
-    LLSD::Integer size{ sizeSpec.isInteger()? sizeSpec.asInteger() : 3 };
-    LL_DEBUGS("ThreadPool") << "Instantiating General pool with "
-                            << size << " threads" << LL_ENDL;
-    // Use a function-static ThreadPool: static duration, but instantiated
-    // only on demand.
-    // We don't want anyone, especially the main thread, to have to block
-    // due to this ThreadPool being full.
-    static LL::ThreadPool pool("General", size, 1024*1024);
-}
-
 void update_texture_fetch()
 {
 	LLAppViewer::getTextureCache()->update(1); // unpauses the texture cache thread
@@ -1506,9 +1489,6 @@ bool idle_startup()
 		gAgentCamera.resetCamera();
 		display_startup();
 
-		// start up the ThreadPool we'll use for textures et al.
-		launchThreadPool();
-
 		// Initialize global class data needed for surfaces (i.e. textures)
 		LL_DEBUGS("AppInit") << "Initializing sky..." << LL_ENDL;
 		// Initialize all of the viewer object classes for the first time (doing things like texture fetches.
diff --git a/indra/newview/llviewercamera.cpp b/indra/newview/llviewercamera.cpp
index 5d8e80cc41..5ebce115f6 100644
--- a/indra/newview/llviewercamera.cpp
+++ b/indra/newview/llviewercamera.cpp
@@ -54,6 +54,8 @@
 // System includes
 #include <iomanip> // for setprecision
 
+LLViewerCamera* LLSimpleton<LLViewerCamera>::sInstance = nullptr;
+
 LLTrace::CountStatHandle<> LLViewerCamera::sVelocityStat("camera_velocity");
 LLTrace::CountStatHandle<> LLViewerCamera::sAngularVelocityStat("camera_angular_velocity");
 
diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp
index 498e4ef8bc..fbc5830a5c 100644
--- a/indra/newview/llviewertexture.cpp
+++ b/indra/newview/llviewertexture.cpp
@@ -679,9 +679,6 @@ void LLViewerTexture::init(bool firstinit)
 	
 	mVolumeList[LLRender::LIGHT_TEX].clear();
 	mVolumeList[LLRender::SCULPT_TEX].clear();
-
-	mMainQueue	= LL::WorkQueue::getInstance("mainloop");
-	mImageQueue = LL::WorkQueue::getInstance("LLImageGL");
 }
 
 //virtual 
@@ -1625,26 +1622,17 @@ void LLViewerFetchedTexture::scheduleCreateTexture()
     {
         mNeedsCreateTexture = TRUE;
 #if LL_WINDOWS //flip to 0 to revert to single-threaded OpenGL texture uploads
-        auto mainq = mMainQueue.lock();
-        if (mainq)
-        {
-            mainq->postTo(
-                mImageQueue,
-                // work to be done on LLImageGL worker thread
-                [this]()
-                {
-                    //actually create the texture on a background thread
-                    createTexture();
-                },
-                // callback to be run on main thread
-                [this]()
-                {
-                    //finalize on main thread
-                    postCreateTexture();
-                    unref();
-                });
-        }
-        else
+        if (!LLImageGLThread::sInstance->post([this]()
+            {
+                //actually create the texture on a background thread
+                createTexture();
+                LLImageGLThread::sInstance->postCallback([this]()
+                    {
+                        //finalize on main thread
+                        postCreateTexture();
+                        unref();
+                    });
+            }))
 #endif
         {
             gTextureList.mCreateTextureList.insert(this);
diff --git a/indra/newview/llviewertexture.h b/indra/newview/llviewertexture.h
index 4cd4c7cd39..f9f1bfef44 100644
--- a/indra/newview/llviewertexture.h
+++ b/indra/newview/llviewertexture.h
@@ -35,7 +35,6 @@
 #include "llrender.h"
 #include "llmetricperformancetester.h"
 #include "httpcommon.h"
-#include "workqueue.h"
 
 #include <map>
 #include <list>
@@ -214,9 +213,6 @@ protected:
 	//do not use LLPointer here.
 	LLViewerMediaTexture* mParcelMedia ;
 
-	LL::WorkQueue::weak_t mMainQueue;
-	LL::WorkQueue::weak_t mImageQueue;
-
 	static F32 sTexelPixelRatio;
 public:
 	static const U32 sCurrentFileVersion;	
diff --git a/indra/newview/llworld.cpp b/indra/newview/llworld.cpp
index 5f62908009..0a8457eb2c 100644
--- a/indra/newview/llworld.cpp
+++ b/indra/newview/llworld.cpp
@@ -62,6 +62,8 @@
 #include <cstring>
 
 
+LLWorld* LLSimpleton<LLWorld>::sInstance = nullptr;
+
 //
 // Globals
 //
-- 
cgit v1.2.3


From a633efdc0b62f28f145ec26c2efa8dfc06a3729e Mon Sep 17 00:00:00 2001
From: Nat Goodspeed <nat@lindenlab.com>
Date: Mon, 15 Nov 2021 14:34:30 -0500
Subject: SL-16094: In LLWindowWin32::recreateWindow(), kick window thread

before blocking on the pending future. Otherwise the window thread can remain
blocked in a GetMessage() call and deadlock the app.
---
 indra/llwindow/llwindowwin32.cpp | 29 +++++++++++++++++++++--------
 indra/llwindow/llwindowwin32.h   |  1 +
 2 files changed, 22 insertions(+), 8 deletions(-)

(limited to 'indra')

diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp
index 3f3dd43daf..b845f75ce4 100644
--- a/indra/llwindow/llwindowwin32.cpp
+++ b/indra/llwindow/llwindowwin32.cpp
@@ -346,7 +346,7 @@ struct LLWindowWin32::LLWindowWin32Thread : public LL::ThreadPool
         getQueue().post(std::forward<CALLABLE>(func));
     }
 
-    // call PeekMessage and pull enqueue messages for later processing
+    // call GetMessage() and pull enqueue messages for later processing
     void gatherInput();
     HWND mWindowHandle = NULL;
     HDC mhDC = 0;
@@ -1671,6 +1671,13 @@ void LLWindowWin32::recreateWindow(RECT window_rect, DWORD dw_ex_style, DWORD dw
         }
     );
 
+    // Having posted work to mWindowThread, bump it out of blocked
+    // GetMessage() call. Normally we could just wait for the next
+    // gatherInput() call to notice the pending work item and call
+    // kickWindowThread(), but that would be on THIS calling thread, and we're
+    // about to block this thread until we get a result from mWindowThread.
+    kickWindowThread(oldHandle);
+
     auto future = promise.get_future();
     // This blocks until mWindowThread processes CreateWindowEx() and calls
     // promise.set_value().
@@ -2035,13 +2042,7 @@ void LLWindowWin32::gatherInput()
     if (mWindowThread->getQueue().size())
     {
         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);
-        }
+        kickWindowThread();
     }
         
     while (mWindowThread->mMessageQueue.tryPopBack(msg))
@@ -4470,3 +4471,15 @@ void LLWindowWin32::postMouseButtonEvent(const std::function<void()>& func)
     mMouseQueue.pushFront(func);
 }
 
+void LLWindowWin32::kickWindowThread(HWND windowHandle)
+{
+    if (! windowHandle)
+        windowHandle = mWindowHandle;
+    if (windowHandle)
+    {
+        // post a nonsense user message to wake up the Window Thread in
+        // case any functions are pending and no windows events came
+        // through this frame
+        PostMessage(windowHandle, WM_USER + 0x0017, 0xB0B0, 0x1337);
+    }
+}
diff --git a/indra/llwindow/llwindowwin32.h b/indra/llwindow/llwindowwin32.h
index 5966061177..b02815e990 100644
--- a/indra/llwindow/llwindowwin32.h
+++ b/indra/llwindow/llwindowwin32.h
@@ -244,6 +244,7 @@ protected:
 	void post(const std::function<void()>& func);
 	void postMouseButtonEvent(const std::function<void()>& func);
 	void recreateWindow(RECT window_rect, DWORD dw_ex_style, DWORD dw_style);
+	void kickWindowThread(HWND windowHandle=0);
 
 	friend class LLWindowManager;
 };
-- 
cgit v1.2.3


From 3641541c6cc7f33f0e0dc2e1eb2cfdfcec23322b Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Mon, 15 Nov 2021 23:23:09 +0200
Subject: SL-15756 Removed mHasGeneratedFaces

mHasGeneratedFaces is always true for some types of models and glod was treating faces as one mesh by default, so meshoptimizer should do the same regardles of mHasGeneratedFaces
---
 indra/llprimitive/lldaeloader.cpp | 16 ++-------
 indra/llprimitive/llmodel.cpp     |  3 +-
 indra/llprimitive/llmodel.h       |  5 ---
 indra/newview/llmodelpreview.cpp  | 73 ++++++++++++---------------------------
 4 files changed, 26 insertions(+), 71 deletions(-)

(limited to 'indra')

diff --git a/indra/llprimitive/lldaeloader.cpp b/indra/llprimitive/lldaeloader.cpp
index 73a0b3d673..93d492b42d 100644
--- a/indra/llprimitive/lldaeloader.cpp
+++ b/indra/llprimitive/lldaeloader.cpp
@@ -153,7 +153,6 @@ LLModel::EModelStatus load_face_from_dom_triangles(
     std::vector<LLVolumeFace>& face_list,
     std::vector<std::string>& materials,
     domTrianglesRef& tri,
-    bool &generated_additional_faces,
     LLSD& log_msg)
 {
 	LLVolumeFace face;
@@ -293,8 +292,6 @@ LLModel::EModelStatus load_face_from_dom_triangles(
 
 		if (indices.size()%3 == 0 && verts.size() >= 65532)
 		{
-            generated_additional_faces = true;
-
 			std::string material;
 
 			if (tri->getMaterial())
@@ -360,7 +357,6 @@ LLModel::EModelStatus load_face_from_dom_polylist(
     std::vector<LLVolumeFace>& face_list,
     std::vector<std::string>& materials,
     domPolylistRef& poly,
-    bool& generated_additional_faces,
     LLSD& log_msg)
 {
 	domPRef p = poly->getP();
@@ -574,8 +570,6 @@ LLModel::EModelStatus load_face_from_dom_polylist(
 
 			if (indices.size()%3 == 0 && indices.size() >= 65532)
 			{
-                generated_additional_faces = true;
-
 				std::string material;
 
 				if (poly->getMaterial())
@@ -2453,13 +2447,11 @@ bool LLDAELoader::addVolumeFacesFromDomMesh(LLModel* pModel,domMesh* mesh, LLSD&
 	LLModel::EModelStatus status = LLModel::NO_ERRORS;
 	domTriangles_Array& tris = mesh->getTriangles_array();
 
-    pModel->mHasGeneratedFaces = false;
-
 	for (U32 i = 0; i < tris.getCount(); ++i)
 	{
 		domTrianglesRef& tri = tris.get(i);
 
-		status = load_face_from_dom_triangles(pModel->getVolumeFaces(), pModel->getMaterialList(), tri, pModel->mHasGeneratedFaces, log_msg);
+		status = load_face_from_dom_triangles(pModel->getVolumeFaces(), pModel->getMaterialList(), tri, log_msg);
 		pModel->mStatus = status;
 		if(status != LLModel::NO_ERRORS)
 		{
@@ -2472,7 +2464,7 @@ bool LLDAELoader::addVolumeFacesFromDomMesh(LLModel* pModel,domMesh* mesh, LLSD&
 	for (U32 i = 0; i < polys.getCount(); ++i)
 	{
 		domPolylistRef& poly = polys.get(i);
-		status = load_face_from_dom_polylist(pModel->getVolumeFaces(), pModel->getMaterialList(), poly, pModel->mHasGeneratedFaces, log_msg);
+		status = load_face_from_dom_polylist(pModel->getVolumeFaces(), pModel->getMaterialList(), poly, log_msg);
 
 		if(status != LLModel::NO_ERRORS)
 		{
@@ -2487,9 +2479,6 @@ bool LLDAELoader::addVolumeFacesFromDomMesh(LLModel* pModel,domMesh* mesh, LLSD&
 	{
 		domPolygonsRef& poly = polygons.get(i);
 
-        // Due to how poligons work, assume that face was 'generated' by default
-        pModel->mHasGeneratedFaces = true;
-
 		status = load_face_from_dom_polygons(pModel->getVolumeFaces(), pModel->getMaterialList(), poly);
 
 		if(status != LLModel::NO_ERRORS)
@@ -2589,7 +2578,6 @@ bool LLDAELoader::loadModelsFromDomMesh(domMesh* mesh, std::vector<LLModel*>& mo
 		{
 			LLModel* next = new LLModel(volume_params, 0.f);
 			next->mSubmodelID = ++submodelID;
-			next->mHasGeneratedFaces = ret->mHasGeneratedFaces;
 			next->mLabel = model_name + (char)((int)'a' + next->mSubmodelID) + lod_suffix[mLod];
 			next->getVolumeFaces() = remainder;
 			next->mNormalizedScale = ret->mNormalizedScale;
diff --git a/indra/llprimitive/llmodel.cpp b/indra/llprimitive/llmodel.cpp
index 8b8fde0ea0..702a1b5238 100644
--- a/indra/llprimitive/llmodel.cpp
+++ b/indra/llprimitive/llmodel.cpp
@@ -55,8 +55,7 @@ LLModel::LLModel(LLVolumeParams& params, F32 detail)
       mNormalizedTranslation(0,0,0), 
       mPelvisOffset( 0.0f ), 
       mStatus(NO_ERRORS), 
-      mSubmodelID(0),
-      mHasGeneratedFaces(false)
+      mSubmodelID(0)
 {
 	mDecompID = -1;
 	mLocalID = -1;
diff --git a/indra/llprimitive/llmodel.h b/indra/llprimitive/llmodel.h
index 87a47dcb36..96368d64e5 100644
--- a/indra/llprimitive/llmodel.h
+++ b/indra/llprimitive/llmodel.h
@@ -284,11 +284,6 @@ public:
     // A model/object can only have 8 faces, spillover faces will
     // be moved to new model/object and assigned a submodel id.
 	int mSubmodelID;
-    // A .dae face can have more than 65K vertices, but viewer
-    // is limited to U16 for indices, in such case spilower will
-    // be moved into new face and this will be set to true.
-    // Also true in case faces were generated from polygons
-    bool mHasGeneratedFaces;
 };
 
 typedef std::vector<LLPointer<LLModel> >	model_list;
diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp
index d629358355..f6edbf6bc6 100644
--- a/indra/newview/llmodelpreview.cpp
+++ b/indra/newview/llmodelpreview.cpp
@@ -1775,68 +1775,41 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d
             if (model_meshopt_mode == MESH_OPTIMIZER_AUTO)
             {
                 F32 allowed_ratio_drift = 2.f;
-                F32 res_ratio = 0;
-                if (base->mHasGeneratedFaces)
-                {
-                    res_ratio = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, false);
+                F32 res_ratio = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, false);
 
-                    if (res_ratio < 0)
+                if (res_ratio < 0)
+                {
+                    // U16 vertices overflow, shouldn't happen, but just in case
+                    for (U32 face_idx = 0; face_idx < base->getNumVolumeFaces(); ++face_idx)
                     {
-                        // U16 vertices overflow, shouldn't happen, but just in case
-                        for (U32 face_idx = 0; face_idx < base->getNumVolumeFaces(); ++face_idx)
-                        {
-                            genMeshOptimizerPerFace(base, target_model, face_idx, indices_decimator, lod_error_threshold, false);
-                        }
-                        LL_INFOS() << "Model " << target_model->getName()
-                            << " lod " << which_lod
-                            << " per model method overflow, defaulting to per face." << LL_ENDL;
+                        genMeshOptimizerPerFace(base, target_model, face_idx, indices_decimator, lod_error_threshold, false);
                     }
-                    else if (res_ratio * allowed_ratio_drift < indices_decimator)
-                    {
-                        // Try sloppy variant if normal one failed to simplify model enough.
-                        res_ratio = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, true);
-                        LL_INFOS() << "Model " << target_model->getName()
-                                   << " lod " << which_lod
-                                   << " sloppily simplified using per model method." << LL_ENDL;
+                    LL_INFOS() << "Model " << target_model->getName()
+                        << " lod " << which_lod
+                        << " per model method overflow, defaulting to per face." << LL_ENDL;
+                }
+                else if (res_ratio * allowed_ratio_drift < indices_decimator)
+                {
+                    // Try sloppy variant if normal one failed to simplify model enough.
+                    res_ratio = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, true);
+                    LL_INFOS() << "Model " << target_model->getName()
+                        << " lod " << which_lod
+                        << " sloppily simplified using per model method." << LL_ENDL;
 
 
-                        if (res_ratio < 0)
-                        {
-                            // Sloppy variant failed to generate triangles.
-                            // Can happen with models that are too simple as is.
-                            // Fallback to normal method.
-                            genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, false);
-                        }
-                    }
-                    else
+                    if (res_ratio < 0)
                     {
-                        LL_INFOS() << "Model " << target_model->getName()
-                            << " lod " << which_lod
-                            << " simplified using per model method." << LL_ENDL;
+                        // Sloppy variant failed to generate triangles.
+                        // Can happen with models that are too simple as is.
+                        // Fallback to normal method.
+                        genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, false);
                     }
                 }
                 else
                 {
-                    for (U32 face_idx = 0; face_idx < base->getNumVolumeFaces(); ++face_idx)
-                    {
-                        res_ratio = genMeshOptimizerPerFace(base, target_model, face_idx, indices_decimator, lod_error_threshold, false);
-                        
-                        if (res_ratio * allowed_ratio_drift < indices_decimator)
-                        {
-                            // normal method failed to sufficiently simplify, try sloppy
-                            res_ratio = genMeshOptimizerPerFace(base, target_model, face_idx, indices_decimator, lod_error_threshold, true);
-                            if (res_ratio < 0)
-                            {
-                                // Sloppy failed to generate triangles.
-                                // Can happen with models that are too simple as is.
-                                // Fallback to normal method.
-                                genMeshOptimizerPerFace(base, target_model, face_idx, indices_decimator, lod_error_threshold, false);
-                            }
-                        }
-                    }
                     LL_INFOS() << "Model " << target_model->getName()
                         << " lod " << which_lod
-                        << " simplified using per face methods." << LL_ENDL;
+                        << " simplified using per model method." << LL_ENDL;
                 }
             }
 
-- 
cgit v1.2.3


From e95b7efd0b4469ce18bce3bc0261ecc9be06ea9c Mon Sep 17 00:00:00 2001
From: Mnikolenko Productengine <mnikolenko@productengine.com>
Date: Tue, 16 Nov 2021 16:18:01 +0200
Subject: SL-16362 FIXED Viewer crashes if settings.xml file is missing

---
 indra/newview/llviewercontrol.cpp | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp
index e5ebbcb9ab..693c24634e 100644
--- a/indra/newview/llviewercontrol.cpp
+++ b/indra/newview/llviewercontrol.cpp
@@ -107,10 +107,14 @@ static bool handleRenderAvatarMouselookChanged(const LLSD& newvalue)
 
 static bool handleRenderFarClipChanged(const LLSD& newvalue)
 {
-	F32 draw_distance = (F32) newvalue.asReal();
-	gAgentCamera.mDrawDistance = draw_distance;
-	LLWorld::getInstance()->setLandFarClip(draw_distance);
-	return true;
+    if (LLStartUp::getStartupState() >= STATE_STARTED)
+    {
+        F32 draw_distance = (F32)newvalue.asReal();
+        gAgentCamera.mDrawDistance = draw_distance;
+        LLWorld::getInstance()->setLandFarClip(draw_distance);
+        return true;
+    }
+    return false;
 }
 
 static bool handleTerrainDetailChanged(const LLSD& newvalue)
-- 
cgit v1.2.3


From 4745aab37647956cf92e760df525d5fe64f47908 Mon Sep 17 00:00:00 2001
From: Dave Houlton <euclid@lindenlab.com>
Date: Tue, 16 Nov 2021 12:17:36 -0700
Subject: DRTVWR-546 exterminate tab char from 00-Common.cmake (fails Mac
 build)

---
 indra/cmake/00-Common.cmake | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'indra')

diff --git a/indra/cmake/00-Common.cmake b/indra/cmake/00-Common.cmake
index 7c9e07b099..bf54b655c2 100644
--- a/indra/cmake/00-Common.cmake
+++ b/indra/cmake/00-Common.cmake
@@ -81,7 +81,7 @@ if (WINDOWS)
   set(CMAKE_CXX_FLAGS_RELEASE
       "${OG_CMAKE_CXX_FLAGS_RELEASE} ${LL_CXX_FLAGS} /Zo"
       CACHE STRING "C++ compiler release options" FORCE)
-	  
+  
   # zlib has assembly-language object files incompatible with SAFESEH
   set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /LARGEADDRESSAWARE /SAFESEH:NO /NODEFAULTLIB:LIBCMT /IGNORE:4099")
 
-- 
cgit v1.2.3


From fdeeb0190eb6fa2d6b39816d14a664f5d38aa4ec Mon Sep 17 00:00:00 2001
From: Mnikolenko ProductEngine <mnikolenko@productengine.com>
Date: Wed, 17 Nov 2021 17:51:50 +0200
Subject: SL-16330 Allow vsync update without restart on mac

---
 indra/llwindow/llwindow.h         |  2 +-
 indra/llwindow/llwindowheadless.h |  6 +++---
 indra/llwindow/llwindowmacosx.cpp | 27 ++++++++++++++++-----------
 indra/llwindow/llwindowmacosx.h   |  2 ++
 indra/newview/llviewercontrol.cpp |  2 --
 5 files changed, 22 insertions(+), 17 deletions(-)

(limited to 'indra')

diff --git a/indra/llwindow/llwindow.h b/indra/llwindow/llwindow.h
index 43d81e4d59..0edf39f6ef 100644
--- a/indra/llwindow/llwindow.h
+++ b/indra/llwindow/llwindow.h
@@ -88,11 +88,11 @@ public:
     //Must be called on the same thread that called createSharedContext()
     virtual void destroySharedContext(void* context) = 0;
 
+    virtual void toggleVSync(bool enable_vsync) = 0;
 
     virtual BOOL setCursorPosition(LLCoordWindow position) = 0;
 	virtual BOOL getCursorPosition(LLCoordWindow *position) = 0;
 #if LL_WINDOWS
-    virtual void toggleVSync(bool enable_vsync) = 0;
     virtual BOOL getCursorDelta(LLCoordCommon* delta) = 0;
 #endif
 	virtual void showCursor() = 0;
diff --git a/indra/llwindow/llwindowheadless.h b/indra/llwindow/llwindowheadless.h
index 78c5e4bae4..410da79623 100644
--- a/indra/llwindow/llwindowheadless.h
+++ b/indra/llwindow/llwindowheadless.h
@@ -52,10 +52,10 @@ public:
     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 toggleVSync(bool enable_vsync) { }
+    /*virtual*/ BOOL setCursorPosition(LLCoordWindow position) {return FALSE;};
+    /*virtual*/ BOOL getCursorPosition(LLCoordWindow *position) {return FALSE;};
 #if LL_WINDOWS
-    /*virtual*/ virtual void toggleVSync(bool enable_vsync) { }
     /*virtual*/ BOOL getCursorDelta(LLCoordCommon* delta) { return FALSE; }
 #endif
 	/*virtual*/ void showCursor() {};
diff --git a/indra/llwindow/llwindowmacosx.cpp b/indra/llwindow/llwindowmacosx.cpp
index dac84690db..0e37e82091 100644
--- a/indra/llwindow/llwindowmacosx.cpp
+++ b/indra/llwindow/llwindowmacosx.cpp
@@ -661,17 +661,7 @@ BOOL LLWindowMacOSX::createContext(int x, int y, int width, int height, int bits
 	}
 
 	// Disable vertical sync for swap
-	GLint frames_per_swap = 0;
-	if (!enable_vsync)
-	{
-		frames_per_swap = 0;
-	}
-	else
-	{
-		frames_per_swap = 1;
-	}
-	
-	CGLSetParameter(mContext, kCGLCPSwapInterval, &frames_per_swap);
+    toggleVSync(enable_vsync);
 
 	//enable multi-threaded OpenGL
 	if (sUseMultGL)
@@ -1944,6 +1934,21 @@ void LLWindowMacOSX::destroySharedContext(void* context)
     delete sc;
 }
 
+void LLWindowMacOSX::toggleVSync(bool enable_vsync)
+{
+    GLint frames_per_swap = 0;
+    if (!enable_vsync)
+    {
+        frames_per_swap = 0;
+    }
+    else
+    {
+        frames_per_swap = 1;
+    }
+    
+    CGLSetParameter(mContext, kCGLCPSwapInterval, &frames_per_swap);
+}
+
 void LLWindowMacOSX::interruptLanguageTextInput()
 {
 	commitCurrentPreedit(mGLView);
diff --git a/indra/llwindow/llwindowmacosx.h b/indra/llwindow/llwindowmacosx.h
index 18fa86930f..b0f339e1db 100644
--- a/indra/llwindow/llwindowmacosx.h
+++ b/indra/llwindow/llwindowmacosx.h
@@ -140,6 +140,8 @@ public:
     //Must be called on the same thread that called createSharedContext()
     void destroySharedContext(void* context) override;
 
+    void toggleVSync(bool enable_vsync) override;
+
 protected:
 	LLWindowMacOSX(LLWindowCallbacks* callbacks,
 		const std::string& title, const std::string& name, int x, int y, int width, int height, U32 flags,
diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp
index 9f76543647..e20c64e48e 100644
--- a/indra/newview/llviewercontrol.cpp
+++ b/indra/newview/llviewercontrol.cpp
@@ -260,9 +260,7 @@ static bool handleAnisotropicChanged(const LLSD& newvalue)
 
 static bool handleVSyncChanged(const LLSD& newvalue)
 {
-#if LL_WINDOWS
     gViewerWindow->getWindow()->toggleVSync(newvalue.asBoolean());
-#endif
     return true;
 }
 
-- 
cgit v1.2.3


From cba1daaf6be4dfd031cd10d9aea07c7124d32726 Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Wed, 17 Nov 2021 21:46:43 +0200
Subject: SL-16226 Fix crash with extra large faces

---
 indra/newview/llmodelpreview.cpp | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

(limited to 'indra')

diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp
index f6edbf6bc6..6a827207ae 100644
--- a/indra/newview/llmodelpreview.cpp
+++ b/indra/newview/llmodelpreview.cpp
@@ -1373,7 +1373,8 @@ F32 LLModelPreview::genMeshOptimizerPerModel(LLModel *base_model, LLModel *targe
     LLVector4a* buffer_positions = (LLVector4a*)ll_aligned_malloc<64>(sizeof(LLVector4a) * 2 * size_vertices + tc_bytes_size);
     LLVector4a* buffer_normals = buffer_positions + size_vertices;
     LLVector2* buffer_tex_coords = (LLVector2*)(buffer_normals + size_vertices);
-    U16* buffer_indices = (U16*)ll_aligned_malloc_16(U16_MAX * sizeof(U16));
+    S32 buffer_idx_size = (size_indices * sizeof(U16) + 0xF) & ~0xF;
+    U16* buffer_indices = (U16*)ll_aligned_malloc_16(buffer_idx_size);
     S32* old_to_new_positions_map = new S32[size_vertices];
 
     S32 buf_positions_copied = 0;
-- 
cgit v1.2.3


From bbf3f516bdd551a53b7dfc0affcb1a36e6680169 Mon Sep 17 00:00:00 2001
From: Nat Goodspeed <nat@lindenlab.com>
Date: Wed, 10 Nov 2021 11:11:04 -0500
Subject: SL-16094: Only link IMM32.LIB for llurlentry tests on Windows.

---
 indra/llui/CMakeLists.txt | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

(limited to 'indra')

diff --git a/indra/llui/CMakeLists.txt b/indra/llui/CMakeLists.txt
index 25ceb68b19..55c1655d7b 100644
--- a/indra/llui/CMakeLists.txt
+++ b/indra/llui/CMakeLists.txt
@@ -308,6 +308,10 @@ if(LL_TESTS)
       ${BOOST_FIBER_LIBRARY} ${BOOST_CONTEXT_LIBRARY} ${BOOST_SYSTEM_LIBRARY}
       ${WINDOWS_LIBRARIES})
   if(NOT LINUX)
-    LL_ADD_INTEGRATION_TEST(llurlentry llurlentry.cpp "imm32;${test_libs}")
+    if(WINDOWS)
+      LL_ADD_INTEGRATION_TEST(llurlentry llurlentry.cpp "imm32;${test_libs}")
+    else(WINDOWS)
+      LL_ADD_INTEGRATION_TEST(llurlentry llurlentry.cpp "${test_libs}")
+    endif(WINDOWS)
   endif(NOT LINUX)
 endif(LL_TESTS)
-- 
cgit v1.2.3


From 18de6c9b989cc7060f2a314f5b68cc102677823b Mon Sep 17 00:00:00 2001
From: Nat Goodspeed <nat@lindenlab.com>
Date: Thu, 11 Nov 2021 10:23:16 -0500
Subject: SL-16094: Stylish braces!

---
 indra/llcommon/llsingleton.h | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

(limited to 'indra')

diff --git a/indra/llcommon/llsingleton.h b/indra/llcommon/llsingleton.h
index fdd5bdfea9..6042c0906c 100644
--- a/indra/llcommon/llsingleton.h
+++ b/indra/llcommon/llsingleton.h
@@ -858,7 +858,8 @@ public:
     static inline T& instance() { return *getInstance(); }
     static inline bool instanceExists() { return sInstance != nullptr; }
 
-    static void deleteSingleton() {
+    static void deleteSingleton()
+    {
         delete sInstance;
         sInstance = nullptr;
     }
-- 
cgit v1.2.3


From 730b8427b5f40e5f62bca15c5109f50db5c10be5 Mon Sep 17 00:00:00 2001
From: "Brad Payne (Vir Linden)" <vir@lindenlab.com>
Date: Tue, 9 Nov 2021 20:25:25 +0000
Subject: SL-16329 - track frame time and jitter (as average deviation frame to
 frame) in stats window

---
 indra/llcommon/lltracerecording.cpp                | 27 +++++++++++++++++++-
 indra/llcommon/lltracerecording.h                  | 29 ++++++++++++++++++++++
 indra/llui/llstatbar.cpp                           | 17 +++++++++++--
 indra/llui/llstatbar.h                             |  6 +++--
 indra/newview/llviewerstats.cpp                    | 11 +++++---
 indra/newview/llviewerstats.h                      |  4 +--
 .../newview/skins/default/xui/en/floater_stats.xml | 19 ++++++++++++++
 7 files changed, 103 insertions(+), 10 deletions(-)

(limited to 'indra')

diff --git a/indra/llcommon/lltracerecording.cpp b/indra/llcommon/lltracerecording.cpp
index c72a64d086..5ce1b337fe 100644
--- a/indra/llcommon/lltracerecording.cpp
+++ b/indra/llcommon/lltracerecording.cpp
@@ -858,7 +858,6 @@ F64 PeriodicRecording::getPeriodMean( const StatType<EventAccumulator>& stat, S3
 			: NaN;
 }
 
-
 F64 PeriodicRecording::getPeriodStandardDeviation( const StatType<EventAccumulator>& stat, S32 num_periods /*= S32_MAX*/ )
 {
     LL_PROFILE_ZONE_SCOPED;
@@ -952,6 +951,32 @@ F64 PeriodicRecording::getPeriodMean( const StatType<SampleAccumulator>& stat, S
 			: NaN;
 }
 
+F64 PeriodicRecording::getPeriodMedian( const StatType<SampleAccumulator>& stat, S32 num_periods /*= S32_MAX*/ )
+{
+    LL_PROFILE_ZONE_SCOPED;
+	num_periods = llmin(num_periods, getNumRecordedPeriods());
+
+	std::vector<F64> buf;
+	for (S32 i = 1; i <= num_periods; i++)
+	{
+		Recording& recording = getPrevRecording(i);
+		if (recording.getDuration() > (F32Seconds)0.f)
+		{
+			if (recording.hasValue(stat))
+			{
+				buf.push_back(recording.getMean(stat));
+			}
+		}
+	}
+	if (buf.size()==0)
+	{
+		return 0.0f;
+	}
+	std::sort(buf.begin(), buf.end());
+
+	return F64((buf.size() % 2 == 0) ? (buf[buf.size() / 2 - 1] + buf[buf.size() / 2]) / 2 : buf[buf.size() / 2]);
+}
+
 F64 PeriodicRecording::getPeriodStandardDeviation( const StatType<SampleAccumulator>& stat, S32 num_periods /*= S32_MAX*/ )
 {
     LL_PROFILE_ZONE_SCOPED;
diff --git a/indra/llcommon/lltracerecording.h b/indra/llcommon/lltracerecording.h
index 6715104613..1f3d37336a 100644
--- a/indra/llcommon/lltracerecording.h
+++ b/indra/llcommon/lltracerecording.h
@@ -599,6 +599,35 @@ namespace LLTrace
 			return typename RelatedTypes<T>::fractional_t(getPeriodMeanPerSec(static_cast<const StatType<CountAccumulator>&>(stat), num_periods));
 		}
 
+        F64 getPeriodMedian( const StatType<SampleAccumulator>& stat, S32 num_periods = S32_MAX);
+
+        template <typename T>
+        typename RelatedTypes<typename T::value_t>::fractional_t getPeriodMedianPerSec(const StatType<T>& stat, S32 num_periods = S32_MAX)
+        {
+            LL_PROFILE_ZONE_SCOPED;
+            num_periods = llmin(num_periods, getNumRecordedPeriods());
+
+            std::vector <typename RelatedTypes<typename T::value_t>::fractional_t> buf;
+            for (S32 i = 1; i <= num_periods; i++)
+            {
+                Recording& recording = getPrevRecording(i);
+                if (recording.getDuration() > (F32Seconds)0.f)
+                {
+                    buf.push_back(recording.getPerSec(stat));
+                }
+            }
+            std::sort(buf.begin(), buf.end());
+
+            return typename RelatedTypes<T>::fractional_t((buf.size() % 2 == 0) ? (buf[buf.size() / 2 - 1] + buf[buf.size() / 2]) / 2 : buf[buf.size() / 2]);
+        }
+
+        template<typename T>
+        typename RelatedTypes<T>::fractional_t getPeriodMedianPerSec(const CountStatHandle<T>& stat, S32 num_periods = S32_MAX)
+        {
+            LL_PROFILE_ZONE_SCOPED;
+            return typename RelatedTypes<T>::fractional_t(getPeriodMedianPerSec(static_cast<const StatType<CountAccumulator>&>(stat), num_periods));
+        }
+
 		//
 		// PERIODIC STANDARD DEVIATION
 		//
diff --git a/indra/llui/llstatbar.cpp b/indra/llui/llstatbar.cpp
index 8adcd664df..2449100952 100644
--- a/indra/llui/llstatbar.cpp
+++ b/indra/llui/llstatbar.cpp
@@ -160,6 +160,7 @@ LLStatBar::Params::Params()
 	tick_spacing("tick_spacing", 0.f),
 	decimal_digits("decimal_digits", 3),
 	show_bar("show_bar", false),
+	show_median("show_median", false),
 	show_history("show_history", false),
 	scale_range("scale_range", true),
 	num_frames("num_frames", 200),
@@ -186,6 +187,7 @@ LLStatBar::LLStatBar(const Params& p)
 	mNumShortHistoryFrames(p.num_frames_short),
 	mMaxHeight(p.max_height),
 	mDisplayBar(p.show_bar),
+	mShowMedian(p.show_median),
 	mDisplayHistory(p.show_history),
 	mOrientation(p.orientation),
 	mAutoScaleMax(!p.bar_max.isProvided()),
@@ -318,7 +320,14 @@ void LLStatBar::draw()
 			min           = frame_recording.getPeriodMinPerSec(count_stat, num_frames);
 			max           = frame_recording.getPeriodMaxPerSec(count_stat, num_frames);
 			mean          = frame_recording.getPeriodMeanPerSec(count_stat, num_frames);
-			display_value = mean;
+			if (mShowMedian)
+			{
+				display_value = frame_recording.getPeriodMedianPerSec(count_stat, num_frames);
+			}
+			else
+			{
+				display_value = mean;
+			}
 		}
 		break;
 	case STAT_EVENT:
@@ -344,7 +353,11 @@ void LLStatBar::draw()
 			mean              = frame_recording.getPeriodMean(sample_stat, num_frames);
 			num_rapid_changes = calc_num_rapid_changes(frame_recording, sample_stat, RAPID_CHANGE_WINDOW);
 
-			if (num_rapid_changes / RAPID_CHANGE_WINDOW.value() > MAX_RAPID_CHANGES_PER_SEC)
+			if (mShowMedian)
+			{
+				display_value = frame_recording.getPeriodMedian(sample_stat, num_frames);
+			}
+			else if (num_rapid_changes / RAPID_CHANGE_WINDOW.value() > MAX_RAPID_CHANGES_PER_SEC)
 			{
 				display_value = mean;
 			}
diff --git a/indra/llui/llstatbar.h b/indra/llui/llstatbar.h
index 1ff4c67fc5..6b481ca68f 100644
--- a/indra/llui/llstatbar.h
+++ b/indra/llui/llstatbar.h
@@ -44,9 +44,10 @@ public:
 								bar_max,
 								tick_spacing;
 
-		Optional<bool>			show_bar,
+		Optional<bool> 			show_bar,
 								show_history,
-								scale_range;
+								scale_range,
+								show_median; // default is mean
 
 		Optional<S32>			decimal_digits,
 								num_frames,
@@ -112,6 +113,7 @@ private:
 
 	bool         mDisplayBar,			// Display the bar graph.
 				 mDisplayHistory,
+				 mShowMedian,
 				 mAutoScaleMax,
 				 mAutoScaleMin;
 };
diff --git a/indra/newview/llviewerstats.cpp b/indra/newview/llviewerstats.cpp
index 314c1a1f1e..ac8a657fb2 100644
--- a/indra/newview/llviewerstats.cpp
+++ b/indra/newview/llviewerstats.cpp
@@ -183,8 +183,9 @@ SimMeasurement<F64Kilobytes >	SIM_UNACKED_BYTES("simtotalunackedbytes", "", LL_S
 SimMeasurement<F64Megabytes >	SIM_PHYSICS_MEM("physicsmemoryallocated", "", LL_SIM_STAT_SIMPHYSICSMEMORY);
 
 LLTrace::SampleStatHandle<F64Milliseconds >	FRAMETIME_JITTER("frametimejitter", "Average delta between successive frame times"),
-																FRAMETIME_SLEW("frametimeslew", "Average delta between frame time and mean"),
-																SIM_PING("simpingstat");
+											FRAMETIME_SLEW("frametimeslew", "Average delta between frame time and mean"),
+											FRAMETIME("frametime", "Measured frame time"),
+											SIM_PING("simpingstat");
 
 LLTrace::EventStatHandle<LLUnit<F64, LLUnits::Meters> > AGENT_POSITION_SNAP("agentpositionsnap", "agent position corrections");
 
@@ -261,8 +262,12 @@ void LLViewerStats::updateFrameStats(const F64Seconds time_diff)
 		// new "stutter" meter
 		add(LLStatViewer::FRAMETIME_DOUBLED, time_diff >= 2.0 * mLastTimeDiff ? 1 : 0);
 
+		sample(LLStatViewer::FRAMETIME, time_diff);
+
 		// old stats that were never really used
-		sample(LLStatViewer::FRAMETIME_JITTER, F64Milliseconds (mLastTimeDiff - time_diff));
+		F64Seconds jit = (F64Seconds) std::fabs((mLastTimeDiff - time_diff));
+		LL_INFOS() << "times " << mLastTimeDiff << ", " << time_diff << " jit " << jit << LL_ENDL;
+		sample(LLStatViewer::FRAMETIME_JITTER, jit);
 			
 		F32Seconds average_frametime = gRenderStartTime.getElapsedTimeF32() / (F32)gFrameCount;
 		sample(LLStatViewer::FRAMETIME_SLEW, F64Milliseconds (average_frametime - time_diff));
diff --git a/indra/newview/llviewerstats.h b/indra/newview/llviewerstats.h
index 04870e0c26..ac8eccc0ca 100644
--- a/indra/newview/llviewerstats.h
+++ b/indra/newview/llviewerstats.h
@@ -218,8 +218,8 @@ extern SimMeasurement<F64Megabytes >	SIM_PHYSICS_MEM;
 
 
 extern LLTrace::SampleStatHandle<F64Milliseconds >	FRAMETIME_JITTER,
-																		FRAMETIME_SLEW,
-																		SIM_PING;
+													FRAMETIME_SLEW,
+													SIM_PING;
 
 extern LLTrace::EventStatHandle<LLUnit<F64, LLUnits::Meters> > AGENT_POSITION_SNAP;
 
diff --git a/indra/newview/skins/default/xui/en/floater_stats.xml b/indra/newview/skins/default/xui/en/floater_stats.xml
index e4f735740b..6f84930c75 100644
--- a/indra/newview/skins/default/xui/en/floater_stats.xml
+++ b/indra/newview/skins/default/xui/en/floater_stats.xml
@@ -35,6 +35,25 @@
                   decimal_digits="1"
                   show_bar="true"
                   show_history="true"/>
+        <stat_bar name="frame_mean"
+                  label="frame (mean)"
+                  unit_label="ms"
+                  stat="frametime"
+                  decimal_digits="1"
+                  show_bar="false"
+                  show_history="false"/>
+        <stat_bar name="frame_median"
+                  label="frame (median)"
+                  unit_label="ms"
+                  stat="frametime"
+                  show_median="true"
+                  decimal_digits="1"
+                  show_bar="false"
+                  show_history="false"/>
+        <stat_bar name="framet_jitter"
+                  label="jitter"
+                  decimal_digits="1"
+                  stat="frametimejitter"/>
        <stat_bar name="bandwidth"
                   label="UDP Data Received"
                   stat="activemessagedatareceived"
-- 
cgit v1.2.3


From ca4fb96e1dfb5c372fe6f0951db7e14266db538e Mon Sep 17 00:00:00 2001
From: Mnikolenko Productengine <mnikolenko@productengine.com>
Date: Wed, 10 Nov 2021 18:44:00 +0200
Subject: SL-16330 mac build fix

---
 indra/newview/llviewercontrol.cpp | 2 ++
 1 file changed, 2 insertions(+)

(limited to 'indra')

diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp
index 3e7459ee8a..0e64d7152a 100644
--- a/indra/newview/llviewercontrol.cpp
+++ b/indra/newview/llviewercontrol.cpp
@@ -243,7 +243,9 @@ static bool handleAnisotropicChanged(const LLSD& newvalue)
 
 static bool handleVSyncChanged(const LLSD& newvalue)
 {
+#if LL_WINDOWS
     gViewerWindow->getWindow()->toggleVSync(newvalue.asBoolean());
+#endif
     return true;
 }
 
-- 
cgit v1.2.3


From 0d4c6ee5721f554313a1701575c533b038764895 Mon Sep 17 00:00:00 2001
From: "Brad Payne (Vir Linden)" <vir@lindenlab.com>
Date: Thu, 11 Nov 2021 23:33:41 +0000
Subject: SL-16355 - spammy message removed

---
 indra/newview/llviewerstats.cpp | 1 -
 1 file changed, 1 deletion(-)

(limited to 'indra')

diff --git a/indra/newview/llviewerstats.cpp b/indra/newview/llviewerstats.cpp
index ac8a657fb2..1fda2fb20e 100644
--- a/indra/newview/llviewerstats.cpp
+++ b/indra/newview/llviewerstats.cpp
@@ -266,7 +266,6 @@ void LLViewerStats::updateFrameStats(const F64Seconds time_diff)
 
 		// old stats that were never really used
 		F64Seconds jit = (F64Seconds) std::fabs((mLastTimeDiff - time_diff));
-		LL_INFOS() << "times " << mLastTimeDiff << ", " << time_diff << " jit " << jit << LL_ENDL;
 		sample(LLStatViewer::FRAMETIME_JITTER, jit);
 			
 		F32Seconds average_frametime = gRenderStartTime.getElapsedTimeF32() / (F32)gFrameCount;
-- 
cgit v1.2.3


From 7f2e740591ed7afa5b8da620802dbdca40da7f4c Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Tue, 1 Jun 2021 20:13:13 +0300
Subject: SL-15333 Crash in glh_init_extensions

---
 indra/llrender/llgl.cpp            |    2 +-
 indra/llwindow/GL/glh_extensions.h |  211 -----
 indra/llwindow/GL/glh_genext.h     | 1674 ------------------------------------
 3 files changed, 1 insertion(+), 1886 deletions(-)
 delete mode 100644 indra/llwindow/GL/glh_extensions.h
 delete mode 100644 indra/llwindow/GL/glh_genext.h

(limited to 'indra')

diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp
index 4f9aa5f979..c7f85aec21 100644
--- a/indra/llrender/llgl.cpp
+++ b/indra/llrender/llgl.cpp
@@ -557,7 +557,7 @@ bool LLGLManager::initGL()
 		glGetIntegerv(GL_NUM_EXTENSIONS, &count);
 		for (GLint i = 0; i < count; ++i)
 		{
-			std::string ext((const char*) glGetStringi(GL_EXTENSIONS, i));
+			std::string ext = ll_safe_string((const char*) glGetStringi(GL_EXTENSIONS, i));
 			str << ext << " ";
 			LL_DEBUGS("GLExtensions") << ext << LL_ENDL;
 		}
diff --git a/indra/llwindow/GL/glh_extensions.h b/indra/llwindow/GL/glh_extensions.h
deleted file mode 100644
index 554cb1731f..0000000000
--- a/indra/llwindow/GL/glh_extensions.h
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
- *  glh_extensions.h
- * $LicenseInfo:firstyear=2006&license=mit$ (mit used here to satisfy validity checker)
- * Copyright (C) 2006, NVIDIA
- *  From nVidia Corporation, downloaded 2006-12-18 from:
- *  http://developer.nvidia.com/attach/8196
- *  ("NVParse Library with Source (.zip) (2390 KB)")
- *
- *  License (quoted from license_info.txt in aforementioned file):
- *  "The files bison.exe, bison.simple, and flex.exe are covered by
- *  the GPL.  All other files in this distribution can be used however
- *  you want."
- * $/LicenseInfo$
-
- */
-
-#ifndef GLH_EXTENSIONS
-#define GLH_EXTENSIONS
-
-#include <string.h>
-#include <stdio.h>
-
-#ifdef _WIN32
-# include <windows.h>
-#endif
-
-#ifndef __APPLE__
-#include <GL/gl.h>
-#endif
-
-#ifdef _WIN32
-# include "GL/wglext.h"
-#endif
-
-#define CHECK_MEMORY(ptr) \
-    if (NULL == ptr) { \
-		printf("Error allocating memory in file %s, line %d\n", __FILE__, __LINE__); \
-		exit(-1); \
-	}
-
-#ifdef GLH_EXT_SINGLE_FILE
-#  define GLH_EXTENSIONS_SINGLE_FILE  // have to do this because glh_genext.h unsets GLH_EXT_SINGLE_FILE
-#endif
-
-#include "glh_genext.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifdef GLH_EXTENSIONS_SINGLE_FILE
-
-class GLHExts
-{
-public:
-	GLHExts()
-	{
-		mSysExts = NULL;
-//		mUnsupportedExts = NULL;
-	}
-	~GLHExts()
-	{
-		if (mSysExts)
-		{
-			free(mSysExts);
-		}
-//		if (mUnsupportedExts)
-//		{
-//			free(mUnsupportedExts);
-//		}
-	}
-	char *mSysExts;
-//	char *mUnsupportedExts;
-};
-
-GLHExts gGLHExts;
-
-static int ExtensionExists(const char* extName, const char* sysExts)
-{
-    char *padExtName = (char*)malloc(strlen(extName) + 2);
-    strcat(strcpy(padExtName, extName), " ");
-
-	if (0 == strcmp(extName, "GL_VERSION_1_2")) {
-		const char *version = (const char*)glGetString(GL_VERSION);
-		if (strstr(version, "1.0") == version || strstr(version, "1.1") == version) {
-			return FALSE;
-		} else {
-			return TRUE;
-		}
-	}
-    if (strstr(sysExts, padExtName)) {
-		free(padExtName);
-        return TRUE;
-    } else {
-		free(padExtName);
-        return FALSE;
-    }
-}
-
-static const char* EatWhiteSpace(const char *str)
-{
-	for (; *str && (' ' == *str || '\t' == *str || '\n' == *str); str++);
-	return str;
-}
-
-static const char* EatNonWhiteSpace(const char *str)
-{
-	for (; *str && (' ' != *str && '\t' != *str && '\n' != *str); str++);
-	return str;
-}
-
-
-int glh_init_extensions(const char *origReqExts)
-{
-	// Length of requested extensions string
-	//unsigned reqExtsLen;
-	char *reqExts;
-	// Ptr for individual extensions within reqExts
-	char *reqExt;
-	int success = TRUE;
-
-	// build space-padded extension string
-	if (NULL == gGLHExts.mSysExts) {
-		const char *extensions = (const char*)glGetString(GL_EXTENSIONS);
-		int sysExtsLen = (int)strlen(extensions);
-		const char *winsys_extensions = 0;		
-		int winsysExtsLen = 0;
-#ifdef _WIN32
-		{
-			PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetExtensionsStringARB = 0;
-			wglGetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC)wglGetProcAddress("wglGetExtensionsStringARB");
-			if(wglGetExtensionsStringARB)
-			{
-				winsys_extensions = wglGetExtensionsStringARB(wglGetCurrentDC());
-				winsysExtsLen = (S32)strlen(winsys_extensions);
-			}
-		}
-#endif
-		// Add 2 bytes, one for padding space, one for terminating NULL
-		gGLHExts.mSysExts = (char*)malloc(sysExtsLen + winsysExtsLen + 3);
-		CHECK_MEMORY(gGLHExts.mSysExts);
-		strcpy(gGLHExts.mSysExts, extensions);
-		gGLHExts.mSysExts[sysExtsLen] = ' ';
-		gGLHExts.mSysExts[sysExtsLen + 1] = 0;
-		if (winsysExtsLen)
-		{
-			strcat(gGLHExts.mSysExts, winsys_extensions);
-		}
-		gGLHExts.mSysExts[sysExtsLen + 1 + winsysExtsLen] = ' ';
-		gGLHExts.mSysExts[sysExtsLen + 1 + winsysExtsLen + 1] = 0;
-	}
-
-	if (NULL == origReqExts)
-	{
-		return TRUE;
-	}
-	reqExts = strdup(origReqExts);
-	/*
-	reqExtsLen = (S32)strlen(reqExts);
-	if (NULL == gGLHExts.mUnsupportedExts)
-	{
-		gGLHExts.mUnsupportedExts = (char*)malloc(reqExtsLen + 1);
-	}
-	else if (reqExtsLen > strlen(gGLHExts.mUnsupportedExts))
-	{
-		gGLHExts.mUnsupportedExts = (char*)realloc(gGLHExts.mUnsupportedExts, reqExtsLen + 1);
-	}
-	CHECK_MEMORY(gGLHExts.mUnsupportedExts);
-	*gGLHExts.mUnsupportedExts = 0;
-	*/
-
-	// Parse requested extension list
-	for (reqExt = reqExts;
-		(reqExt = (char*)EatWhiteSpace(reqExt)) && *reqExt;
-		reqExt = (char*)EatNonWhiteSpace(reqExt))
-	{
-		char *extEnd = (char*)EatNonWhiteSpace(reqExt);
-		char saveChar = *extEnd;
-		*extEnd = (char)0;
-		
-		if (!ExtensionExists(reqExt, gGLHExts.mSysExts) ||
-			!glh_init_extension(reqExt)) {
-			/*
-			// add reqExt to end of unsupportedExts
-			strcat(gGLHExts.mUnsupportedExts, reqExt);
-			strcat(gGLHExts.mUnsupportedExts, " ");
-			*/
-			success = FALSE;
-		}
-		*extEnd = saveChar;
-	}
-	free(reqExts);
-	return success;
-}
-
-const char* glh_get_unsupported_extensions()
-{
-	return "";
-//	return (const char*)gGLHExts.mUnsupportedExts;
-}
-
-#else
-int glh_init_extensions(const char *origReqExts);
-const char* glh_get_unsupported_extensions();
-#endif /* GLH_EXT_SINGLE_FILE */
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* GLH_EXTENSIONS */
diff --git a/indra/llwindow/GL/glh_genext.h b/indra/llwindow/GL/glh_genext.h
deleted file mode 100644
index cd5d1604a8..0000000000
--- a/indra/llwindow/GL/glh_genext.h
+++ /dev/null
@@ -1,1674 +0,0 @@
-/*
- *  glh_genext.h
- * $LicenseInfo:firstyear=2008&license=mit$ (mit used here to satisfy validity checker)
- * Copyright (C) 2008, NVIDIA
- *  From nVidia Corporation, downloaded 2006-12-18 from:
- *  http://developer.nvidia.com/attach/8196
- *  ("NVParse Library with Source (.zip) (2390 KB)")
- *
- *  License (quoted from license_info.txt in aforementioned file):
- *  "The files bison.exe, bison.simple, and flex.exe are covered by
- *  the GPL.  All other files in this distribution can be used however
- *  you want."
- * $/LicenseInfo$
- */
-
-/* File generated by extgen.cpp -- do not modify */
-#ifndef GLH_GENEXT_H
-#define GLH_GENEXT_H
-
-// MBW -- None of this is necessary on Mac OS.
-#ifndef __APPLE__
-
-#include <GL/gl.h>
-#include <GL/glext.h>
-
-#ifdef _WIN32 /* supports windows, x -- need to generalize */
-#  include <GL/wglext.h>
-#  define GLH_EXT_GET_PROC_ADDRESS(p)   wglGetProcAddress(p) 
-#else if GLX_VERSION_1_3
-#  include <GL/glxext.h>
-#  define GLH_EXT_GET_PROC_ADDRESS(p)   glXGetProcAddressARB(p) 
-#endif
-
-#ifdef GLH_EXT_SINGLE_FILE
-	#define GLH_EXTERN
- #define GLH_INITIALIZER = 0
-#else
-	#define GLH_EXTERN extern
- #define GLH_INITIALIZER
-#endif
-
-#define GLH__PREPROCESSOR_GYMNASTICS2(a,b) a##b
-#define GLH__PREPROCESSOR_GYMNASTICS(a,b) GLH__PREPROCESSOR_GYMNASTICS2(a,b)
-
-#ifndef GLH_EXT_PREFIX
-# define GLH_EXT_NAME(a) a
-#else
-# define GLH_EXT_NAME(a) GLH__PREPROCESSOR_GYMNASTICS(GLH_EXT_PREFIX,a)
-#endif
-
-#ifndef _WIN32
-# ifndef GLH_CORE_1_2_PREFIX
-#  define GLH_CORE_1_2_PREFIX _
-# endif
-#endif
-
-#ifndef GLH_CORE_1_2_PREFIX
-# define GLH_CORE_1_2_NAME(a) a
-#else
-# define GLH_CORE_1_2_NAME(a) GLH__PREPROCESSOR_GYMNASTICS(GLH_CORE_1_2_PREFIX,a)
-#endif
-
-#ifdef GL_ARB_multitexture
-    GLH_EXTERN PFNGLMULTITEXCOORD1DARBPROC GLH_EXT_NAME(glMultiTexCoord1dARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMULTITEXCOORD1DVARBPROC GLH_EXT_NAME(glMultiTexCoord1dvARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMULTITEXCOORD1FARBPROC GLH_EXT_NAME(glMultiTexCoord1fARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMULTITEXCOORD1FVARBPROC GLH_EXT_NAME(glMultiTexCoord1fvARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMULTITEXCOORD1IARBPROC GLH_EXT_NAME(glMultiTexCoord1iARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMULTITEXCOORD1IVARBPROC GLH_EXT_NAME(glMultiTexCoord1ivARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMULTITEXCOORD1SARBPROC GLH_EXT_NAME(glMultiTexCoord1sARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMULTITEXCOORD1SVARBPROC GLH_EXT_NAME(glMultiTexCoord1svARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMULTITEXCOORD2DARBPROC GLH_EXT_NAME(glMultiTexCoord2dARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMULTITEXCOORD2DVARBPROC GLH_EXT_NAME(glMultiTexCoord2dvARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMULTITEXCOORD2FARBPROC GLH_EXT_NAME(glMultiTexCoord2fARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMULTITEXCOORD2FVARBPROC GLH_EXT_NAME(glMultiTexCoord2fvARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMULTITEXCOORD2IARBPROC GLH_EXT_NAME(glMultiTexCoord2iARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMULTITEXCOORD2IVARBPROC GLH_EXT_NAME(glMultiTexCoord2ivARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMULTITEXCOORD2SARBPROC GLH_EXT_NAME(glMultiTexCoord2sARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMULTITEXCOORD2SVARBPROC GLH_EXT_NAME(glMultiTexCoord2svARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMULTITEXCOORD3DARBPROC GLH_EXT_NAME(glMultiTexCoord3dARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMULTITEXCOORD3DVARBPROC GLH_EXT_NAME(glMultiTexCoord3dvARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMULTITEXCOORD3FARBPROC GLH_EXT_NAME(glMultiTexCoord3fARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMULTITEXCOORD3FVARBPROC GLH_EXT_NAME(glMultiTexCoord3fvARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMULTITEXCOORD3IARBPROC GLH_EXT_NAME(glMultiTexCoord3iARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMULTITEXCOORD3IVARBPROC GLH_EXT_NAME(glMultiTexCoord3ivARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMULTITEXCOORD3SARBPROC GLH_EXT_NAME(glMultiTexCoord3sARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMULTITEXCOORD3SVARBPROC GLH_EXT_NAME(glMultiTexCoord3svARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMULTITEXCOORD4DARBPROC GLH_EXT_NAME(glMultiTexCoord4dARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMULTITEXCOORD4DVARBPROC GLH_EXT_NAME(glMultiTexCoord4dvARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMULTITEXCOORD4FARBPROC GLH_EXT_NAME(glMultiTexCoord4fARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMULTITEXCOORD4FVARBPROC GLH_EXT_NAME(glMultiTexCoord4fvARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMULTITEXCOORD4IARBPROC GLH_EXT_NAME(glMultiTexCoord4iARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMULTITEXCOORD4IVARBPROC GLH_EXT_NAME(glMultiTexCoord4ivARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMULTITEXCOORD4SARBPROC GLH_EXT_NAME(glMultiTexCoord4sARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMULTITEXCOORD4SVARBPROC GLH_EXT_NAME(glMultiTexCoord4svARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLACTIVETEXTUREARBPROC GLH_EXT_NAME(glActiveTextureARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLCLIENTACTIVETEXTUREARBPROC GLH_EXT_NAME(glClientActiveTextureARB) GLH_INITIALIZER;
-#endif
-
-#ifdef GL_ARB_texture_border_clamp
-#endif
-
-#ifdef GL_ARB_texture_compression
-    GLH_EXTERN PFNGLCOMPRESSEDTEXIMAGE3DARBPROC GLH_EXT_NAME(glCompressedTexImage3DARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLCOMPRESSEDTEXIMAGE2DARBPROC GLH_EXT_NAME(glCompressedTexImage2DARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLCOMPRESSEDTEXIMAGE1DARBPROC GLH_EXT_NAME(glCompressedTexImage1DARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLCOMPRESSEDTEXSUBIMAGE3DARBPROC GLH_EXT_NAME(glCompressedTexSubImage3DARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLCOMPRESSEDTEXSUBIMAGE2DARBPROC GLH_EXT_NAME(glCompressedTexSubImage2DARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLCOMPRESSEDTEXSUBIMAGE1DARBPROC GLH_EXT_NAME(glCompressedTexSubImage1DARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETCOMPRESSEDTEXIMAGEARBPROC GLH_EXT_NAME(glGetCompressedTexImageARB) GLH_INITIALIZER;
-#endif
-
-#ifdef GL_ARB_texture_cube_map
-#endif
-
-#ifdef GL_ARB_transpose_matrix
-    GLH_EXTERN PFNGLLOADTRANSPOSEMATRIXFARBPROC GLH_EXT_NAME(glLoadTransposeMatrixfARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLLOADTRANSPOSEMATRIXDARBPROC GLH_EXT_NAME(glLoadTransposeMatrixdARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMULTTRANSPOSEMATRIXFARBPROC GLH_EXT_NAME(glMultTransposeMatrixfARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMULTTRANSPOSEMATRIXDARBPROC GLH_EXT_NAME(glMultTransposeMatrixdARB) GLH_INITIALIZER;
-#endif
-
-#ifdef GL_ARB_vertex_program
-    GLH_EXTERN PFNGLVERTEXATTRIB1SARBPROC GLH_EXT_NAME(glVertexAttrib1sARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB1FARBPROC GLH_EXT_NAME(glVertexAttrib1fARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB1DARBPROC GLH_EXT_NAME(glVertexAttrib1dARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB2SARBPROC GLH_EXT_NAME(glVertexAttrib2sARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB2FARBPROC GLH_EXT_NAME(glVertexAttrib2fARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB2DARBPROC GLH_EXT_NAME(glVertexAttrib2dARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB3SARBPROC GLH_EXT_NAME(glVertexAttrib3sARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB3FARBPROC GLH_EXT_NAME(glVertexAttrib3fARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB3DARBPROC GLH_EXT_NAME(glVertexAttrib3dARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB4SARBPROC GLH_EXT_NAME(glVertexAttrib4sARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB4FARBPROC GLH_EXT_NAME(glVertexAttrib4fARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB4DARBPROC GLH_EXT_NAME(glVertexAttrib4dARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB4NUBARBPROC GLH_EXT_NAME(glVertexAttrib4NubARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB1SVARBPROC GLH_EXT_NAME(glVertexAttrib1svARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB1FVARBPROC GLH_EXT_NAME(glVertexAttrib1fvARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB1DVARBPROC GLH_EXT_NAME(glVertexAttrib1dvARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB2SVARBPROC GLH_EXT_NAME(glVertexAttrib2svARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB2FVARBPROC GLH_EXT_NAME(glVertexAttrib2fvARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB2DVARBPROC GLH_EXT_NAME(glVertexAttrib2dvARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB3SVARBPROC GLH_EXT_NAME(glVertexAttrib3svARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB3FVARBPROC GLH_EXT_NAME(glVertexAttrib3fvARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB3DVARBPROC GLH_EXT_NAME(glVertexAttrib3dvARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB4BVARBPROC GLH_EXT_NAME(glVertexAttrib4bvARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB4SVARBPROC GLH_EXT_NAME(glVertexAttrib4svARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB4IVARBPROC GLH_EXT_NAME(glVertexAttrib4ivARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB4UBVARBPROC GLH_EXT_NAME(glVertexAttrib4ubvARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB4USVARBPROC GLH_EXT_NAME(glVertexAttrib4usvARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB4UIVARBPROC GLH_EXT_NAME(glVertexAttrib4uivARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB4FVARBPROC GLH_EXT_NAME(glVertexAttrib4fvARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB4DVARBPROC GLH_EXT_NAME(glVertexAttrib4dvARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB4NBVARBPROC GLH_EXT_NAME(glVertexAttrib4NbvARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB4NSVARBPROC GLH_EXT_NAME(glVertexAttrib4NsvARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB4NIVARBPROC GLH_EXT_NAME(glVertexAttrib4NivARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB4NUBVARBPROC GLH_EXT_NAME(glVertexAttrib4NubvARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB4NUSVARBPROC GLH_EXT_NAME(glVertexAttrib4NusvARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB4NUIVARBPROC GLH_EXT_NAME(glVertexAttrib4NuivARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIBPOINTERARBPROC GLH_EXT_NAME(glVertexAttribPointerARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLENABLEVERTEXATTRIBARRAYARBPROC GLH_EXT_NAME(glEnableVertexAttribArrayARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLDISABLEVERTEXATTRIBARRAYARBPROC GLH_EXT_NAME(glDisableVertexAttribArrayARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLPROGRAMSTRINGARBPROC GLH_EXT_NAME(glProgramStringARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLBINDPROGRAMARBPROC GLH_EXT_NAME(glBindProgramARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLDELETEPROGRAMSARBPROC GLH_EXT_NAME(glDeleteProgramsARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGENPROGRAMSARBPROC GLH_EXT_NAME(glGenProgramsARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLPROGRAMENVPARAMETER4DARBPROC GLH_EXT_NAME(glProgramEnvParameter4dARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLPROGRAMENVPARAMETER4DVARBPROC GLH_EXT_NAME(glProgramEnvParameter4dvARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLPROGRAMENVPARAMETER4FARBPROC GLH_EXT_NAME(glProgramEnvParameter4fARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLPROGRAMENVPARAMETER4FVARBPROC GLH_EXT_NAME(glProgramEnvParameter4fvARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLPROGRAMLOCALPARAMETER4DARBPROC GLH_EXT_NAME(glProgramLocalParameter4dARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLPROGRAMLOCALPARAMETER4DVARBPROC GLH_EXT_NAME(glProgramLocalParameter4dvARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLPROGRAMLOCALPARAMETER4FARBPROC GLH_EXT_NAME(glProgramLocalParameter4fARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLPROGRAMLOCALPARAMETER4FVARBPROC GLH_EXT_NAME(glProgramLocalParameter4fvARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETPROGRAMENVPARAMETERDVARBPROC GLH_EXT_NAME(glGetProgramEnvParameterdvARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETPROGRAMENVPARAMETERFVARBPROC GLH_EXT_NAME(glGetProgramEnvParameterfvARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC GLH_EXT_NAME(glGetProgramLocalParameterdvARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETPROGRAMLOCALPARAMETERFVARBPROC GLH_EXT_NAME(glGetProgramLocalParameterfvARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETPROGRAMIVARBPROC GLH_EXT_NAME(glGetProgramivARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETPROGRAMSTRINGARBPROC GLH_EXT_NAME(glGetProgramStringARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETVERTEXATTRIBDVARBPROC GLH_EXT_NAME(glGetVertexAttribdvARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETVERTEXATTRIBFVARBPROC GLH_EXT_NAME(glGetVertexAttribfvARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETVERTEXATTRIBIVARBPROC GLH_EXT_NAME(glGetVertexAttribivARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETVERTEXATTRIBPOINTERVARBPROC GLH_EXT_NAME(glGetVertexAttribPointervARB) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLISPROGRAMARBPROC GLH_EXT_NAME(glIsProgramARB) GLH_INITIALIZER;
-#endif
-
-#ifdef GL_EXT_abgr
-#endif
-
-#ifdef GL_EXT_bgra
-#endif
-
-#ifdef GL_EXT_blend_color
-    GLH_EXTERN PFNGLBLENDCOLOREXTPROC GLH_EXT_NAME(glBlendColorEXT) GLH_INITIALIZER;
-#endif
-
-#ifdef GL_EXT_blend_minmax
-    GLH_EXTERN PFNGLBLENDEQUATIONEXTPROC GLH_EXT_NAME(glBlendEquationEXT) GLH_INITIALIZER;
-#endif
-
-#ifdef GL_EXT_blend_subtract
-#endif
-
-#ifdef GL_EXT_compiled_vertex_array
-    GLH_EXTERN PFNGLLOCKARRAYSEXTPROC GLH_EXT_NAME(glLockArraysEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLUNLOCKARRAYSEXTPROC GLH_EXT_NAME(glUnlockArraysEXT) GLH_INITIALIZER;
-#endif
-
-#ifdef GL_EXT_fog_coord
-    GLH_EXTERN PFNGLFOGCOORDDEXTPROC GLH_EXT_NAME(glFogCoorddEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLFOGCOORDDVEXTPROC GLH_EXT_NAME(glFogCoorddvEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLFOGCOORDFEXTPROC GLH_EXT_NAME(glFogCoordfEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLFOGCOORDFVEXTPROC GLH_EXT_NAME(glFogCoordfvEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLFOGCOORDPOINTEREXTPROC GLH_EXT_NAME(glFogCoordPointerEXT) GLH_INITIALIZER;
-#endif
-
-#ifdef GL_EXT_light_max_exponent
-#endif
-
-#ifdef GL_EXT_packed_pixels
-#endif
-
-#ifdef GL_EXT_paletted_texture
-    GLH_EXTERN PFNGLCOLORSUBTABLEEXTPROC GLH_EXT_NAME(glColorSubTableEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLCOLORTABLEEXTPROC GLH_EXT_NAME(glColorTableEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETCOLORTABLEEXTPROC GLH_EXT_NAME(glGetColorTableEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETCOLORTABLEPARAMETERFVEXTPROC GLH_EXT_NAME(glGetColorTableParameterfvEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETCOLORTABLEPARAMETERIVEXTPROC GLH_EXT_NAME(glGetColorTableParameterivEXT) GLH_INITIALIZER;
-#endif
-
-#ifdef GL_EXT_point_parameters
-    GLH_EXTERN PFNGLPOINTPARAMETERFEXTPROC GLH_EXT_NAME(glPointParameterfEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLPOINTPARAMETERFVEXTPROC GLH_EXT_NAME(glPointParameterfvEXT) GLH_INITIALIZER;
-#endif
-
-#ifdef GL_EXT_rescale_normal
-#endif
-
-#ifdef GL_EXT_secondary_color
-    GLH_EXTERN PFNGLSECONDARYCOLOR3BEXTPROC GLH_EXT_NAME(glSecondaryColor3bEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLSECONDARYCOLOR3BVEXTPROC GLH_EXT_NAME(glSecondaryColor3bvEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLSECONDARYCOLOR3DEXTPROC GLH_EXT_NAME(glSecondaryColor3dEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLSECONDARYCOLOR3DVEXTPROC GLH_EXT_NAME(glSecondaryColor3dvEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLSECONDARYCOLOR3FEXTPROC GLH_EXT_NAME(glSecondaryColor3fEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLSECONDARYCOLOR3FVEXTPROC GLH_EXT_NAME(glSecondaryColor3fvEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLSECONDARYCOLOR3IEXTPROC GLH_EXT_NAME(glSecondaryColor3iEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLSECONDARYCOLOR3IVEXTPROC GLH_EXT_NAME(glSecondaryColor3ivEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLSECONDARYCOLOR3SEXTPROC GLH_EXT_NAME(glSecondaryColor3sEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLSECONDARYCOLOR3SVEXTPROC GLH_EXT_NAME(glSecondaryColor3svEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLSECONDARYCOLOR3UBEXTPROC GLH_EXT_NAME(glSecondaryColor3ubEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLSECONDARYCOLOR3UBVEXTPROC GLH_EXT_NAME(glSecondaryColor3ubvEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLSECONDARYCOLOR3UIEXTPROC GLH_EXT_NAME(glSecondaryColor3uiEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLSECONDARYCOLOR3UIVEXTPROC GLH_EXT_NAME(glSecondaryColor3uivEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLSECONDARYCOLOR3USEXTPROC GLH_EXT_NAME(glSecondaryColor3usEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLSECONDARYCOLOR3USVEXTPROC GLH_EXT_NAME(glSecondaryColor3usvEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLSECONDARYCOLORPOINTEREXTPROC GLH_EXT_NAME(glSecondaryColorPointerEXT) GLH_INITIALIZER;
-#endif
-
-#ifdef GL_EXT_separate_specular_color
-#endif
-
-#ifdef GL_EXT_shared_texture_palette
-#endif
-
-#ifdef GL_EXT_stencil_wrap
-#endif
-
-#ifdef GL_EXT_texture_compression_s3tc
-#endif
-
-#ifdef GL_EXT_texture_cube_map
-#endif
-
-#ifdef GL_EXT_texture_edge_clamp
-#endif
-
-#ifdef GL_EXT_texture_env_add
-#endif
-
-#ifdef GL_EXT_texture_env_combine
-#endif
-
-#ifdef GL_EXT_texture_filter_anisotropic
-#endif
-
-#ifdef GL_EXT_texture_lod_bias
-#endif
-
-#ifdef GL_EXT_texture_object
-    GLH_EXTERN PFNGLARETEXTURESRESIDENTEXTPROC GLH_EXT_NAME(glAreTexturesResidentEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLBINDTEXTUREEXTPROC GLH_EXT_NAME(glBindTextureEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLDELETETEXTURESEXTPROC GLH_EXT_NAME(glDeleteTexturesEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGENTEXTURESEXTPROC GLH_EXT_NAME(glGenTexturesEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLISTEXTUREEXTPROC GLH_EXT_NAME(glIsTextureEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLPRIORITIZETEXTURESEXTPROC GLH_EXT_NAME(glPrioritizeTexturesEXT) GLH_INITIALIZER;
-#endif
-
-#ifdef GL_EXT_texture3D
-    GLH_EXTERN PFNGLTEXIMAGE3DEXTPROC GLH_EXT_NAME(glTexImage3DEXT) GLH_INITIALIZER;
-#endif
-
-#ifdef GL_EXT_vertex_array
-    GLH_EXTERN PFNGLARRAYELEMENTEXTPROC GLH_EXT_NAME(glArrayElementEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLCOLORPOINTEREXTPROC GLH_EXT_NAME(glColorPointerEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLEDGEFLAGPOINTEREXTPROC GLH_EXT_NAME(glEdgeFlagPointerEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETPOINTERVEXTPROC GLH_EXT_NAME(glGetPointervEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLINDEXPOINTEREXTPROC GLH_EXT_NAME(glIndexPointerEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLNORMALPOINTEREXTPROC GLH_EXT_NAME(glNormalPointerEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLTEXCOORDPOINTEREXTPROC GLH_EXT_NAME(glTexCoordPointerEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXPOINTEREXTPROC GLH_EXT_NAME(glVertexPointerEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLDRAWARRAYSEXTPROC GLH_EXT_NAME(glDrawArraysEXT) GLH_INITIALIZER;
-#endif
-
-#ifdef GL_EXT_vertex_weighting
-    GLH_EXTERN PFNGLVERTEXWEIGHTFEXTPROC GLH_EXT_NAME(glVertexWeightfEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXWEIGHTFVEXTPROC GLH_EXT_NAME(glVertexWeightfvEXT) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXWEIGHTPOINTEREXTPROC GLH_EXT_NAME(glVertexWeightPointerEXT) GLH_INITIALIZER;
-#endif
-
-#ifdef GL_NV_blend_square
-#endif
-
-#ifdef GL_NV_evaluators
-    GLH_EXTERN PFNGLMAPCONTROLPOINTSNVPROC GLH_EXT_NAME(glMapControlPointsNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMAPPARAMETERIVNVPROC GLH_EXT_NAME(glMapParameterivNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLMAPPARAMETERFVNVPROC GLH_EXT_NAME(glMapParameterfvNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETMAPCONTROLPOINTSNVPROC GLH_EXT_NAME(glGetMapControlPointsNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETMAPPARAMETERIVNVPROC GLH_EXT_NAME(glGetMapParameterivNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETMAPPARAMETERFVNVPROC GLH_EXT_NAME(glGetMapParameterfvNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETMAPATTRIBPARAMETERIVNVPROC GLH_EXT_NAME(glGetMapAttribParameterivNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETMAPATTRIBPARAMETERFVNVPROC GLH_EXT_NAME(glGetMapAttribParameterfvNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLEVALMAPSNVPROC GLH_EXT_NAME(glEvalMapsNV) GLH_INITIALIZER;
-#endif
-
-#ifdef GL_NV_fence
-    GLH_EXTERN PFNGLGENFENCESNVPROC GLH_EXT_NAME(glGenFencesNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLDELETEFENCESNVPROC GLH_EXT_NAME(glDeleteFencesNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLSETFENCENVPROC GLH_EXT_NAME(glSetFenceNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLTESTFENCENVPROC GLH_EXT_NAME(glTestFenceNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLFINISHFENCENVPROC GLH_EXT_NAME(glFinishFenceNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLISFENCENVPROC GLH_EXT_NAME(glIsFenceNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETFENCEIVNVPROC GLH_EXT_NAME(glGetFenceivNV) GLH_INITIALIZER;
-#endif
-
-#ifdef GL_NV_fog_distance
-#endif
-
-#ifdef GL_NV_packed_depth_stencil
-#endif
-
-#ifdef GL_NV_register_combiners
-    GLH_EXTERN PFNGLCOMBINERPARAMETERFVNVPROC GLH_EXT_NAME(glCombinerParameterfvNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLCOMBINERPARAMETERFNVPROC GLH_EXT_NAME(glCombinerParameterfNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLCOMBINERPARAMETERIVNVPROC GLH_EXT_NAME(glCombinerParameterivNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLCOMBINERPARAMETERINVPROC GLH_EXT_NAME(glCombinerParameteriNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLCOMBINERINPUTNVPROC GLH_EXT_NAME(glCombinerInputNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLCOMBINEROUTPUTNVPROC GLH_EXT_NAME(glCombinerOutputNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLFINALCOMBINERINPUTNVPROC GLH_EXT_NAME(glFinalCombinerInputNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETCOMBINERINPUTPARAMETERFVNVPROC GLH_EXT_NAME(glGetCombinerInputParameterfvNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETCOMBINERINPUTPARAMETERIVNVPROC GLH_EXT_NAME(glGetCombinerInputParameterivNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETCOMBINEROUTPUTPARAMETERFVNVPROC GLH_EXT_NAME(glGetCombinerOutputParameterfvNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETCOMBINEROUTPUTPARAMETERIVNVPROC GLH_EXT_NAME(glGetCombinerOutputParameterivNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETFINALCOMBINERINPUTPARAMETERFVNVPROC GLH_EXT_NAME(glGetFinalCombinerInputParameterfvNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETFINALCOMBINERINPUTPARAMETERIVNVPROC GLH_EXT_NAME(glGetFinalCombinerInputParameterivNV) GLH_INITIALIZER;
-#endif
-
-#ifdef GL_NV_register_combiners2
-    GLH_EXTERN PFNGLCOMBINERSTAGEPARAMETERFVNVPROC GLH_EXT_NAME(glCombinerStageParameterfvNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETCOMBINERSTAGEPARAMETERFVNVPROC GLH_EXT_NAME(glGetCombinerStageParameterfvNV) GLH_INITIALIZER;
-#endif
-
-#ifdef GL_NV_texgen_reflection
-#endif
-
-#ifdef GL_NV_texture_env_combine4
-#endif
-
-#ifdef GL_NV_texture_rectangle
-#endif
-
-#ifdef GL_NV_texture_shader
-#endif
-
-#ifdef GL_NV_vertex_array_range
-    GLH_EXTERN PFNGLFLUSHVERTEXARRAYRANGENVPROC GLH_EXT_NAME(glFlushVertexArrayRangeNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXARRAYRANGENVPROC GLH_EXT_NAME(glVertexArrayRangeNV) GLH_INITIALIZER;
-# ifdef _WIN32
-    GLH_EXTERN PFNWGLALLOCATEMEMORYNVPROC GLH_EXT_NAME(wglAllocateMemoryNV) GLH_INITIALIZER;
-# endif
-# ifdef GLX_VERSION_1_3
-    GLH_EXTERN PFNGLXALLOCATEMEMORYNVPROC GLH_EXT_NAME(glXAllocateMemoryNV) GLH_INITIALIZER;
-# endif
-# ifdef _WIN32
-    GLH_EXTERN PFNWGLFREEMEMORYNVPROC GLH_EXT_NAME(wglFreeMemoryNV) GLH_INITIALIZER;
-# endif
-# ifdef GLX_VERSION_1_3
-    GLH_EXTERN PFNGLXFREEMEMORYNVPROC GLH_EXT_NAME(glXFreeMemoryNV) GLH_INITIALIZER;
-# endif
-#endif
-
-#ifdef GL_NV_vertex_program
-    GLH_EXTERN PFNGLAREPROGRAMSRESIDENTNVPROC GLH_EXT_NAME(glAreProgramsResidentNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLBINDPROGRAMNVPROC GLH_EXT_NAME(glBindProgramNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLDELETEPROGRAMSNVPROC GLH_EXT_NAME(glDeleteProgramsNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLEXECUTEPROGRAMNVPROC GLH_EXT_NAME(glExecuteProgramNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGENPROGRAMSNVPROC GLH_EXT_NAME(glGenProgramsNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETPROGRAMPARAMETERDVNVPROC GLH_EXT_NAME(glGetProgramParameterdvNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETPROGRAMPARAMETERFVNVPROC GLH_EXT_NAME(glGetProgramParameterfvNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETPROGRAMIVNVPROC GLH_EXT_NAME(glGetProgramivNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETPROGRAMSTRINGNVPROC GLH_EXT_NAME(glGetProgramStringNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETTRACKMATRIXIVNVPROC GLH_EXT_NAME(glGetTrackMatrixivNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETVERTEXATTRIBDVNVPROC GLH_EXT_NAME(glGetVertexAttribdvNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETVERTEXATTRIBFVNVPROC GLH_EXT_NAME(glGetVertexAttribfvNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETVERTEXATTRIBIVNVPROC GLH_EXT_NAME(glGetVertexAttribivNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETVERTEXATTRIBPOINTERVNVPROC GLH_EXT_NAME(glGetVertexAttribPointervNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLISPROGRAMNVPROC GLH_EXT_NAME(glIsProgramNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLLOADPROGRAMNVPROC GLH_EXT_NAME(glLoadProgramNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLPROGRAMPARAMETER4DNVPROC GLH_EXT_NAME(glProgramParameter4dNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLPROGRAMPARAMETER4DVNVPROC GLH_EXT_NAME(glProgramParameter4dvNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLPROGRAMPARAMETER4FNVPROC GLH_EXT_NAME(glProgramParameter4fNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLPROGRAMPARAMETER4FVNVPROC GLH_EXT_NAME(glProgramParameter4fvNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLPROGRAMPARAMETERS4DVNVPROC GLH_EXT_NAME(glProgramParameters4dvNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLPROGRAMPARAMETERS4FVNVPROC GLH_EXT_NAME(glProgramParameters4fvNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLREQUESTRESIDENTPROGRAMSNVPROC GLH_EXT_NAME(glRequestResidentProgramsNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLTRACKMATRIXNVPROC GLH_EXT_NAME(glTrackMatrixNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIBPOINTERNVPROC GLH_EXT_NAME(glVertexAttribPointerNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB1DNVPROC GLH_EXT_NAME(glVertexAttrib1dNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB1DVNVPROC GLH_EXT_NAME(glVertexAttrib1dvNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB1FNVPROC GLH_EXT_NAME(glVertexAttrib1fNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB1FVNVPROC GLH_EXT_NAME(glVertexAttrib1fvNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB1SNVPROC GLH_EXT_NAME(glVertexAttrib1sNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB1SVNVPROC GLH_EXT_NAME(glVertexAttrib1svNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB2DNVPROC GLH_EXT_NAME(glVertexAttrib2dNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB2DVNVPROC GLH_EXT_NAME(glVertexAttrib2dvNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB2FNVPROC GLH_EXT_NAME(glVertexAttrib2fNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB2FVNVPROC GLH_EXT_NAME(glVertexAttrib2fvNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB2SNVPROC GLH_EXT_NAME(glVertexAttrib2sNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB2SVNVPROC GLH_EXT_NAME(glVertexAttrib2svNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB3DNVPROC GLH_EXT_NAME(glVertexAttrib3dNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB3DVNVPROC GLH_EXT_NAME(glVertexAttrib3dvNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB3FNVPROC GLH_EXT_NAME(glVertexAttrib3fNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB3FVNVPROC GLH_EXT_NAME(glVertexAttrib3fvNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB3SNVPROC GLH_EXT_NAME(glVertexAttrib3sNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB3SVNVPROC GLH_EXT_NAME(glVertexAttrib3svNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB4DNVPROC GLH_EXT_NAME(glVertexAttrib4dNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB4DVNVPROC GLH_EXT_NAME(glVertexAttrib4dvNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB4FNVPROC GLH_EXT_NAME(glVertexAttrib4fNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB4FVNVPROC GLH_EXT_NAME(glVertexAttrib4fvNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB4SNVPROC GLH_EXT_NAME(glVertexAttrib4sNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB4SVNVPROC GLH_EXT_NAME(glVertexAttrib4svNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIB4UBVNVPROC GLH_EXT_NAME(glVertexAttrib4ubvNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIBS1DVNVPROC GLH_EXT_NAME(glVertexAttribs1dvNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIBS1FVNVPROC GLH_EXT_NAME(glVertexAttribs1fvNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIBS1SVNVPROC GLH_EXT_NAME(glVertexAttribs1svNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIBS2DVNVPROC GLH_EXT_NAME(glVertexAttribs2dvNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIBS2FVNVPROC GLH_EXT_NAME(glVertexAttribs2fvNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIBS2SVNVPROC GLH_EXT_NAME(glVertexAttribs2svNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIBS3DVNVPROC GLH_EXT_NAME(glVertexAttribs3dvNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIBS3FVNVPROC GLH_EXT_NAME(glVertexAttribs3fvNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIBS3SVNVPROC GLH_EXT_NAME(glVertexAttribs3svNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIBS4DVNVPROC GLH_EXT_NAME(glVertexAttribs4dvNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIBS4FVNVPROC GLH_EXT_NAME(glVertexAttribs4fvNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIBS4SVNVPROC GLH_EXT_NAME(glVertexAttribs4svNV) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLVERTEXATTRIBS4UBVNVPROC GLH_EXT_NAME(glVertexAttribs4ubvNV) GLH_INITIALIZER;
-#endif
-
-#ifdef GL_SGIS_generate_mipmap
-#endif
-
-#ifdef GL_SGIS_texture_lod
-#endif
-
-#ifdef GL_SGIX_depth_texture
-#endif
-
-#ifdef GL_SGIX_shadow
-#endif
-
-#ifdef GL_VERSION_1_2
-    /* These routines are prefixed by the preprocessor constant
-       GLH_CORE_1_2_PREFIX to avoid colliding with the OpenGL 1.2 namespace. */
-    GLH_EXTERN PFNGLBLENDCOLORPROC GLH_CORE_1_2_NAME(glBlendColor) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLBLENDEQUATIONPROC GLH_CORE_1_2_NAME(glBlendEquation) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLDRAWRANGEELEMENTSPROC GLH_CORE_1_2_NAME(glDrawRangeElements) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLCOLORTABLEPROC GLH_CORE_1_2_NAME(glColorTable) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLCOLORTABLEPARAMETERFVPROC GLH_CORE_1_2_NAME(glColorTableParameterfv) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLCOLORTABLEPARAMETERIVPROC GLH_CORE_1_2_NAME(glColorTableParameteriv) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLCOPYCOLORTABLEPROC GLH_CORE_1_2_NAME(glCopyColorTable) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETCOLORTABLEPROC GLH_CORE_1_2_NAME(glGetColorTable) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETCOLORTABLEPARAMETERFVPROC GLH_CORE_1_2_NAME(glGetColorTableParameterfv) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLGETCOLORTABLEPARAMETERIVPROC GLH_CORE_1_2_NAME(glGetColorTableParameteriv) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLTEXIMAGE3DPROC GLH_CORE_1_2_NAME(glTexImage3D) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLTEXSUBIMAGE3DPROC GLH_CORE_1_2_NAME(glTexSubImage3D) GLH_INITIALIZER;
-    GLH_EXTERN PFNGLCOPYTEXSUBIMAGE3DPROC GLH_CORE_1_2_NAME(glCopyTexSubImage3D) GLH_INITIALIZER;
-#endif
-
-#ifdef GL_WIN_swap_hint
-    GLH_EXTERN PFNGLADDSWAPHINTRECTWINPROC GLH_EXT_NAME(glAddSwapHintRectWIN) GLH_INITIALIZER;
-#endif
-
-#ifdef WGL_ARB_pbuffer
-# ifdef _WIN32
-    GLH_EXTERN PFNWGLCREATEPBUFFERARBPROC GLH_EXT_NAME(wglCreatePbufferARB) GLH_INITIALIZER;
-# endif
-# ifdef _WIN32
-    GLH_EXTERN PFNWGLGETPBUFFERDCARBPROC GLH_EXT_NAME(wglGetPbufferDCARB) GLH_INITIALIZER;
-# endif
-# ifdef _WIN32
-    GLH_EXTERN PFNWGLRELEASEPBUFFERDCARBPROC GLH_EXT_NAME(wglReleasePbufferDCARB) GLH_INITIALIZER;
-# endif
-# ifdef _WIN32
-    GLH_EXTERN PFNWGLDESTROYPBUFFERARBPROC GLH_EXT_NAME(wglDestroyPbufferARB) GLH_INITIALIZER;
-# endif
-# ifdef _WIN32
-    GLH_EXTERN PFNWGLQUERYPBUFFERARBPROC GLH_EXT_NAME(wglQueryPbufferARB) GLH_INITIALIZER;
-# endif
-#endif
-
-#ifdef WGL_ARB_render_texture
-# ifdef _WIN32
-    GLH_EXTERN PFNWGLBINDTEXIMAGEARBPROC GLH_EXT_NAME(wglBindTexImageARB) GLH_INITIALIZER;
-# endif
-# ifdef _WIN32
-    GLH_EXTERN PFNWGLRELEASETEXIMAGEARBPROC GLH_EXT_NAME(wglReleaseTexImageARB) GLH_INITIALIZER;
-# endif
-# ifdef _WIN32
-    GLH_EXTERN PFNWGLSETPBUFFERATTRIBARBPROC GLH_EXT_NAME(wglSetPbufferAttribARB) GLH_INITIALIZER;
-# endif
-#endif
-
-#ifdef WGL_ARB_pixel_format
-# ifdef _WIN32
-    GLH_EXTERN PFNWGLGETPIXELFORMATATTRIBIVARBPROC GLH_EXT_NAME(wglGetPixelFormatAttribivARB) GLH_INITIALIZER;
-# endif
-# ifdef _WIN32
-    GLH_EXTERN PFNWGLGETPIXELFORMATATTRIBFVARBPROC GLH_EXT_NAME(wglGetPixelFormatAttribfvARB) GLH_INITIALIZER;
-# endif
-# ifdef _WIN32
-    GLH_EXTERN PFNWGLCHOOSEPIXELFORMATARBPROC GLH_EXT_NAME(wglChoosePixelFormatARB) GLH_INITIALIZER;
-# endif
-#endif
-
-
-#ifdef GLH_EXT_SINGLE_FILE
-
-int glh_init_extension(const char* extension)
-{
-    if (NULL == extension) {
-        return FALSE;
-#ifdef GL_ARB_multitexture
-    } else if (0 == strcmp(extension, "GL_ARB_multitexture")) {
-        GLH_EXT_NAME(glMultiTexCoord1dARB) = (PFNGLMULTITEXCOORD1DARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord1dARB");
-        if (NULL == GLH_EXT_NAME(glMultiTexCoord1dARB))
-            return FALSE;
-        GLH_EXT_NAME(glMultiTexCoord1dvARB) = (PFNGLMULTITEXCOORD1DVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord1dvARB");
-        if (NULL == GLH_EXT_NAME(glMultiTexCoord1dvARB))
-            return FALSE;
-        GLH_EXT_NAME(glMultiTexCoord1fARB) = (PFNGLMULTITEXCOORD1FARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord1fARB");
-        if (NULL == GLH_EXT_NAME(glMultiTexCoord1fARB))
-            return FALSE;
-        GLH_EXT_NAME(glMultiTexCoord1fvARB) = (PFNGLMULTITEXCOORD1FVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord1fvARB");
-        if (NULL == GLH_EXT_NAME(glMultiTexCoord1fvARB))
-            return FALSE;
-        GLH_EXT_NAME(glMultiTexCoord1iARB) = (PFNGLMULTITEXCOORD1IARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord1iARB");
-        if (NULL == GLH_EXT_NAME(glMultiTexCoord1iARB))
-            return FALSE;
-        GLH_EXT_NAME(glMultiTexCoord1ivARB) = (PFNGLMULTITEXCOORD1IVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord1ivARB");
-        if (NULL == GLH_EXT_NAME(glMultiTexCoord1ivARB))
-            return FALSE;
-        GLH_EXT_NAME(glMultiTexCoord1sARB) = (PFNGLMULTITEXCOORD1SARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord1sARB");
-        if (NULL == GLH_EXT_NAME(glMultiTexCoord1sARB))
-            return FALSE;
-        GLH_EXT_NAME(glMultiTexCoord1svARB) = (PFNGLMULTITEXCOORD1SVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord1svARB");
-        if (NULL == GLH_EXT_NAME(glMultiTexCoord1svARB))
-            return FALSE;
-        GLH_EXT_NAME(glMultiTexCoord2dARB) = (PFNGLMULTITEXCOORD2DARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord2dARB");
-        if (NULL == GLH_EXT_NAME(glMultiTexCoord2dARB))
-            return FALSE;
-        GLH_EXT_NAME(glMultiTexCoord2dvARB) = (PFNGLMULTITEXCOORD2DVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord2dvARB");
-        if (NULL == GLH_EXT_NAME(glMultiTexCoord2dvARB))
-            return FALSE;
-        GLH_EXT_NAME(glMultiTexCoord2fARB) = (PFNGLMULTITEXCOORD2FARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord2fARB");
-        if (NULL == GLH_EXT_NAME(glMultiTexCoord2fARB))
-            return FALSE;
-        GLH_EXT_NAME(glMultiTexCoord2fvARB) = (PFNGLMULTITEXCOORD2FVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord2fvARB");
-        if (NULL == GLH_EXT_NAME(glMultiTexCoord2fvARB))
-            return FALSE;
-        GLH_EXT_NAME(glMultiTexCoord2iARB) = (PFNGLMULTITEXCOORD2IARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord2iARB");
-        if (NULL == GLH_EXT_NAME(glMultiTexCoord2iARB))
-            return FALSE;
-        GLH_EXT_NAME(glMultiTexCoord2ivARB) = (PFNGLMULTITEXCOORD2IVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord2ivARB");
-        if (NULL == GLH_EXT_NAME(glMultiTexCoord2ivARB))
-            return FALSE;
-        GLH_EXT_NAME(glMultiTexCoord2sARB) = (PFNGLMULTITEXCOORD2SARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord2sARB");
-        if (NULL == GLH_EXT_NAME(glMultiTexCoord2sARB))
-            return FALSE;
-        GLH_EXT_NAME(glMultiTexCoord2svARB) = (PFNGLMULTITEXCOORD2SVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord2svARB");
-        if (NULL == GLH_EXT_NAME(glMultiTexCoord2svARB))
-            return FALSE;
-        GLH_EXT_NAME(glMultiTexCoord3dARB) = (PFNGLMULTITEXCOORD3DARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord3dARB");
-        if (NULL == GLH_EXT_NAME(glMultiTexCoord3dARB))
-            return FALSE;
-        GLH_EXT_NAME(glMultiTexCoord3dvARB) = (PFNGLMULTITEXCOORD3DVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord3dvARB");
-        if (NULL == GLH_EXT_NAME(glMultiTexCoord3dvARB))
-            return FALSE;
-        GLH_EXT_NAME(glMultiTexCoord3fARB) = (PFNGLMULTITEXCOORD3FARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord3fARB");
-        if (NULL == GLH_EXT_NAME(glMultiTexCoord3fARB))
-            return FALSE;
-        GLH_EXT_NAME(glMultiTexCoord3fvARB) = (PFNGLMULTITEXCOORD3FVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord3fvARB");
-        if (NULL == GLH_EXT_NAME(glMultiTexCoord3fvARB))
-            return FALSE;
-        GLH_EXT_NAME(glMultiTexCoord3iARB) = (PFNGLMULTITEXCOORD3IARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord3iARB");
-        if (NULL == GLH_EXT_NAME(glMultiTexCoord3iARB))
-            return FALSE;
-        GLH_EXT_NAME(glMultiTexCoord3ivARB) = (PFNGLMULTITEXCOORD3IVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord3ivARB");
-        if (NULL == GLH_EXT_NAME(glMultiTexCoord3ivARB))
-            return FALSE;
-        GLH_EXT_NAME(glMultiTexCoord3sARB) = (PFNGLMULTITEXCOORD3SARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord3sARB");
-        if (NULL == GLH_EXT_NAME(glMultiTexCoord3sARB))
-            return FALSE;
-        GLH_EXT_NAME(glMultiTexCoord3svARB) = (PFNGLMULTITEXCOORD3SVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord3svARB");
-        if (NULL == GLH_EXT_NAME(glMultiTexCoord3svARB))
-            return FALSE;
-        GLH_EXT_NAME(glMultiTexCoord4dARB) = (PFNGLMULTITEXCOORD4DARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord4dARB");
-        if (NULL == GLH_EXT_NAME(glMultiTexCoord4dARB))
-            return FALSE;
-        GLH_EXT_NAME(glMultiTexCoord4dvARB) = (PFNGLMULTITEXCOORD4DVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord4dvARB");
-        if (NULL == GLH_EXT_NAME(glMultiTexCoord4dvARB))
-            return FALSE;
-        GLH_EXT_NAME(glMultiTexCoord4fARB) = (PFNGLMULTITEXCOORD4FARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord4fARB");
-        if (NULL == GLH_EXT_NAME(glMultiTexCoord4fARB))
-            return FALSE;
-        GLH_EXT_NAME(glMultiTexCoord4fvARB) = (PFNGLMULTITEXCOORD4FVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord4fvARB");
-        if (NULL == GLH_EXT_NAME(glMultiTexCoord4fvARB))
-            return FALSE;
-        GLH_EXT_NAME(glMultiTexCoord4iARB) = (PFNGLMULTITEXCOORD4IARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord4iARB");
-        if (NULL == GLH_EXT_NAME(glMultiTexCoord4iARB))
-            return FALSE;
-        GLH_EXT_NAME(glMultiTexCoord4ivARB) = (PFNGLMULTITEXCOORD4IVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord4ivARB");
-        if (NULL == GLH_EXT_NAME(glMultiTexCoord4ivARB))
-            return FALSE;
-        GLH_EXT_NAME(glMultiTexCoord4sARB) = (PFNGLMULTITEXCOORD4SARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord4sARB");
-        if (NULL == GLH_EXT_NAME(glMultiTexCoord4sARB))
-            return FALSE;
-        GLH_EXT_NAME(glMultiTexCoord4svARB) = (PFNGLMULTITEXCOORD4SVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord4svARB");
-        if (NULL == GLH_EXT_NAME(glMultiTexCoord4svARB))
-            return FALSE;
-        GLH_EXT_NAME(glActiveTextureARB) = (PFNGLACTIVETEXTUREARBPROC)GLH_EXT_GET_PROC_ADDRESS("glActiveTextureARB");
-        if (NULL == GLH_EXT_NAME(glActiveTextureARB))
-            return FALSE;
-        GLH_EXT_NAME(glClientActiveTextureARB) = (PFNGLCLIENTACTIVETEXTUREARBPROC)GLH_EXT_GET_PROC_ADDRESS("glClientActiveTextureARB");
-        if (NULL == GLH_EXT_NAME(glClientActiveTextureARB))
-            return FALSE;
-#endif
-
-#ifdef GL_ARB_texture_border_clamp
-    } else if (0 == strcmp(extension, "GL_ARB_texture_border_clamp")) {
-#endif
-
-#ifdef GL_ARB_texture_compression
-    } else if (0 == strcmp(extension, "GL_ARB_texture_compression")) {
-        GLH_EXT_NAME(glCompressedTexImage3DARB) = (PFNGLCOMPRESSEDTEXIMAGE3DARBPROC)GLH_EXT_GET_PROC_ADDRESS("glCompressedTexImage3DARB");
-        if (NULL == GLH_EXT_NAME(glCompressedTexImage3DARB))
-            return FALSE;
-        GLH_EXT_NAME(glCompressedTexImage2DARB) = (PFNGLCOMPRESSEDTEXIMAGE2DARBPROC)GLH_EXT_GET_PROC_ADDRESS("glCompressedTexImage2DARB");
-        if (NULL == GLH_EXT_NAME(glCompressedTexImage2DARB))
-            return FALSE;
-        GLH_EXT_NAME(glCompressedTexImage1DARB) = (PFNGLCOMPRESSEDTEXIMAGE1DARBPROC)GLH_EXT_GET_PROC_ADDRESS("glCompressedTexImage1DARB");
-        if (NULL == GLH_EXT_NAME(glCompressedTexImage1DARB))
-            return FALSE;
-        GLH_EXT_NAME(glCompressedTexSubImage3DARB) = (PFNGLCOMPRESSEDTEXSUBIMAGE3DARBPROC)GLH_EXT_GET_PROC_ADDRESS("glCompressedTexSubImage3DARB");
-        if (NULL == GLH_EXT_NAME(glCompressedTexSubImage3DARB))
-            return FALSE;
-        GLH_EXT_NAME(glCompressedTexSubImage2DARB) = (PFNGLCOMPRESSEDTEXSUBIMAGE2DARBPROC)GLH_EXT_GET_PROC_ADDRESS("glCompressedTexSubImage2DARB");
-        if (NULL == GLH_EXT_NAME(glCompressedTexSubImage2DARB))
-            return FALSE;
-        GLH_EXT_NAME(glCompressedTexSubImage1DARB) = (PFNGLCOMPRESSEDTEXSUBIMAGE1DARBPROC)GLH_EXT_GET_PROC_ADDRESS("glCompressedTexSubImage1DARB");
-        if (NULL == GLH_EXT_NAME(glCompressedTexSubImage1DARB))
-            return FALSE;
-        GLH_EXT_NAME(glGetCompressedTexImageARB) = (PFNGLGETCOMPRESSEDTEXIMAGEARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGetCompressedTexImageARB");
-        if (NULL == GLH_EXT_NAME(glGetCompressedTexImageARB))
-            return FALSE;
-#endif
-
-#ifdef GL_ARB_texture_cube_map
-    } else if (0 == strcmp(extension, "GL_ARB_texture_cube_map")) {
-#endif
-
-#ifdef GL_ARB_transpose_matrix
-    } else if (0 == strcmp(extension, "GL_ARB_transpose_matrix")) {
-        GLH_EXT_NAME(glLoadTransposeMatrixfARB) = (PFNGLLOADTRANSPOSEMATRIXFARBPROC)GLH_EXT_GET_PROC_ADDRESS("glLoadTransposeMatrixfARB");
-        if (NULL == GLH_EXT_NAME(glLoadTransposeMatrixfARB))
-            return FALSE;
-        GLH_EXT_NAME(glLoadTransposeMatrixdARB) = (PFNGLLOADTRANSPOSEMATRIXDARBPROC)GLH_EXT_GET_PROC_ADDRESS("glLoadTransposeMatrixdARB");
-        if (NULL == GLH_EXT_NAME(glLoadTransposeMatrixdARB))
-            return FALSE;
-        GLH_EXT_NAME(glMultTransposeMatrixfARB) = (PFNGLMULTTRANSPOSEMATRIXFARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultTransposeMatrixfARB");
-        if (NULL == GLH_EXT_NAME(glMultTransposeMatrixfARB))
-            return FALSE;
-        GLH_EXT_NAME(glMultTransposeMatrixdARB) = (PFNGLMULTTRANSPOSEMATRIXDARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultTransposeMatrixdARB");
-        if (NULL == GLH_EXT_NAME(glMultTransposeMatrixdARB))
-            return FALSE;
-#endif
-
-#ifdef GL_ARB_vertex_program
-    } else if (0 == strcmp(extension, "GL_ARB_vertex_program")) {
-        GLH_EXT_NAME(glVertexAttrib1sARB) = (PFNGLVERTEXATTRIB1SARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1sARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib1sARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib1fARB) = (PFNGLVERTEXATTRIB1FARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1fARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib1fARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib1dARB) = (PFNGLVERTEXATTRIB1DARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1dARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib1dARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib2sARB) = (PFNGLVERTEXATTRIB2SARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2sARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib2sARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib2fARB) = (PFNGLVERTEXATTRIB2FARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2fARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib2fARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib2dARB) = (PFNGLVERTEXATTRIB2DARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2dARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib2dARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib3sARB) = (PFNGLVERTEXATTRIB3SARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3sARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib3sARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib3fARB) = (PFNGLVERTEXATTRIB3FARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3fARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib3fARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib3dARB) = (PFNGLVERTEXATTRIB3DARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3dARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib3dARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib4sARB) = (PFNGLVERTEXATTRIB4SARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4sARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib4sARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib4fARB) = (PFNGLVERTEXATTRIB4FARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4fARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib4fARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib4dARB) = (PFNGLVERTEXATTRIB4DARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4dARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib4dARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib4NubARB) = (PFNGLVERTEXATTRIB4NUBARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4NubARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib4NubARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib1svARB) = (PFNGLVERTEXATTRIB1SVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1svARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib1svARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib1fvARB) = (PFNGLVERTEXATTRIB1FVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1fvARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib1fvARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib1dvARB) = (PFNGLVERTEXATTRIB1DVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1dvARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib1dvARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib2svARB) = (PFNGLVERTEXATTRIB2SVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2svARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib2svARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib2fvARB) = (PFNGLVERTEXATTRIB2FVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2fvARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib2fvARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib2dvARB) = (PFNGLVERTEXATTRIB2DVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2dvARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib2dvARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib3svARB) = (PFNGLVERTEXATTRIB3SVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3svARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib3svARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib3fvARB) = (PFNGLVERTEXATTRIB3FVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3fvARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib3fvARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib3dvARB) = (PFNGLVERTEXATTRIB3DVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3dvARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib3dvARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib4bvARB) = (PFNGLVERTEXATTRIB4BVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4bvARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib4bvARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib4svARB) = (PFNGLVERTEXATTRIB4SVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4svARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib4svARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib4ivARB) = (PFNGLVERTEXATTRIB4IVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4ivARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib4ivARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib4ubvARB) = (PFNGLVERTEXATTRIB4UBVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4ubvARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib4ubvARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib4usvARB) = (PFNGLVERTEXATTRIB4USVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4usvARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib4usvARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib4uivARB) = (PFNGLVERTEXATTRIB4UIVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4uivARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib4uivARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib4fvARB) = (PFNGLVERTEXATTRIB4FVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4fvARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib4fvARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib4dvARB) = (PFNGLVERTEXATTRIB4DVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4dvARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib4dvARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib4NbvARB) = (PFNGLVERTEXATTRIB4NBVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4NbvARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib4NbvARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib4NsvARB) = (PFNGLVERTEXATTRIB4NSVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4NsvARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib4NsvARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib4NivARB) = (PFNGLVERTEXATTRIB4NIVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4NivARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib4NivARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib4NubvARB) = (PFNGLVERTEXATTRIB4NUBVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4NubvARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib4NubvARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib4NusvARB) = (PFNGLVERTEXATTRIB4NUSVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4NusvARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib4NusvARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttrib4NuivARB) = (PFNGLVERTEXATTRIB4NUIVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4NuivARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib4NuivARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glVertexAttribPointerARB) = (PFNGLVERTEXATTRIBPOINTERARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttribPointerARB");
-        if (NULL == GLH_EXT_NAME(glVertexAttribPointerARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glEnableVertexAttribArrayARB) = (PFNGLENABLEVERTEXATTRIBARRAYARBPROC)GLH_EXT_GET_PROC_ADDRESS("glEnableVertexAttribArrayARB");
-        if (NULL == GLH_EXT_NAME(glEnableVertexAttribArrayARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glDisableVertexAttribArrayARB) = (PFNGLDISABLEVERTEXATTRIBARRAYARBPROC)GLH_EXT_GET_PROC_ADDRESS("glDisableVertexAttribArrayARB");
-        if (NULL == GLH_EXT_NAME(glDisableVertexAttribArrayARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glProgramStringARB) = (PFNGLPROGRAMSTRINGARBPROC)GLH_EXT_GET_PROC_ADDRESS("glProgramStringARB");
-        if (NULL == GLH_EXT_NAME(glProgramStringARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glBindProgramARB) = (PFNGLBINDPROGRAMARBPROC)GLH_EXT_GET_PROC_ADDRESS("glBindProgramARB");
-        if (NULL == GLH_EXT_NAME(glBindProgramARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glDeleteProgramsARB) = (PFNGLDELETEPROGRAMSARBPROC)GLH_EXT_GET_PROC_ADDRESS("glDeleteProgramsARB");
-        if (NULL == GLH_EXT_NAME(glDeleteProgramsARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glGenProgramsARB) = (PFNGLGENPROGRAMSARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGenProgramsARB");
-        if (NULL == GLH_EXT_NAME(glGenProgramsARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glProgramEnvParameter4dARB) = (PFNGLPROGRAMENVPARAMETER4DARBPROC)GLH_EXT_GET_PROC_ADDRESS("glProgramEnvParameter4dARB");
-        if (NULL == GLH_EXT_NAME(glProgramEnvParameter4dARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glProgramEnvParameter4dvARB) = (PFNGLPROGRAMENVPARAMETER4DVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glProgramEnvParameter4dvARB");
-        if (NULL == GLH_EXT_NAME(glProgramEnvParameter4dvARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glProgramEnvParameter4fARB) = (PFNGLPROGRAMENVPARAMETER4FARBPROC)GLH_EXT_GET_PROC_ADDRESS("glProgramEnvParameter4fARB");
-        if (NULL == GLH_EXT_NAME(glProgramEnvParameter4fARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glProgramEnvParameter4fvARB) = (PFNGLPROGRAMENVPARAMETER4FVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glProgramEnvParameter4fvARB");
-        if (NULL == GLH_EXT_NAME(glProgramEnvParameter4fvARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glProgramLocalParameter4dARB) = (PFNGLPROGRAMLOCALPARAMETER4DARBPROC)GLH_EXT_GET_PROC_ADDRESS("glProgramLocalParameter4dARB");
-        if (NULL == GLH_EXT_NAME(glProgramLocalParameter4dARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glProgramLocalParameter4dvARB) = (PFNGLPROGRAMLOCALPARAMETER4DVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glProgramLocalParameter4dvARB");
-        if (NULL == GLH_EXT_NAME(glProgramLocalParameter4dvARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glProgramLocalParameter4fARB) = (PFNGLPROGRAMLOCALPARAMETER4FARBPROC)GLH_EXT_GET_PROC_ADDRESS("glProgramLocalParameter4fARB");
-        if (NULL == GLH_EXT_NAME(glProgramLocalParameter4fARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glProgramLocalParameter4fvARB) = (PFNGLPROGRAMLOCALPARAMETER4FVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glProgramLocalParameter4fvARB");
-        if (NULL == GLH_EXT_NAME(glProgramLocalParameter4fvARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glGetProgramEnvParameterdvARB) = (PFNGLGETPROGRAMENVPARAMETERDVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGetProgramEnvParameterdvARB");
-        if (NULL == GLH_EXT_NAME(glGetProgramEnvParameterdvARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glGetProgramEnvParameterfvARB) = (PFNGLGETPROGRAMENVPARAMETERFVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGetProgramEnvParameterfvARB");
-        if (NULL == GLH_EXT_NAME(glGetProgramEnvParameterfvARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glGetProgramLocalParameterdvARB) = (PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGetProgramLocalParameterdvARB");
-        if (NULL == GLH_EXT_NAME(glGetProgramLocalParameterdvARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glGetProgramLocalParameterfvARB) = (PFNGLGETPROGRAMLOCALPARAMETERFVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGetProgramLocalParameterfvARB");
-        if (NULL == GLH_EXT_NAME(glGetProgramLocalParameterfvARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glGetProgramivARB) = (PFNGLGETPROGRAMIVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGetProgramivARB");
-        if (NULL == GLH_EXT_NAME(glGetProgramivARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glGetProgramStringARB) = (PFNGLGETPROGRAMSTRINGARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGetProgramStringARB");
-        if (NULL == GLH_EXT_NAME(glGetProgramStringARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glGetVertexAttribdvARB) = (PFNGLGETVERTEXATTRIBDVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGetVertexAttribdvARB");
-        if (NULL == GLH_EXT_NAME(glGetVertexAttribdvARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glGetVertexAttribfvARB) = (PFNGLGETVERTEXATTRIBFVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGetVertexAttribfvARB");
-        if (NULL == GLH_EXT_NAME(glGetVertexAttribfvARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glGetVertexAttribivARB) = (PFNGLGETVERTEXATTRIBIVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGetVertexAttribivARB");
-        if (NULL == GLH_EXT_NAME(glGetVertexAttribivARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glGetVertexAttribPointervARB) = (PFNGLGETVERTEXATTRIBPOINTERVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGetVertexAttribPointervARB");
-        if (NULL == GLH_EXT_NAME(glGetVertexAttribPointervARB))
-            return GL_FALSE;
-        GLH_EXT_NAME(glIsProgramARB) = (PFNGLISPROGRAMARBPROC)GLH_EXT_GET_PROC_ADDRESS("glIsProgramARB");
-        if (NULL == GLH_EXT_NAME(glIsProgramARB))
-            return GL_FALSE;
-#endif
-
-#ifdef GL_EXT_abgr
-    } else if (0 == strcmp(extension, "GL_EXT_abgr")) {
-#endif
-
-#ifdef GL_EXT_bgra
-    } else if (0 == strcmp(extension, "GL_EXT_bgra")) {
-#endif
-
-#ifdef GL_EXT_blend_color
-    } else if (0 == strcmp(extension, "GL_EXT_blend_color")) {
-        GLH_EXT_NAME(glBlendColorEXT) = (PFNGLBLENDCOLOREXTPROC)GLH_EXT_GET_PROC_ADDRESS("glBlendColorEXT");
-        if (NULL == GLH_EXT_NAME(glBlendColorEXT))
-            return FALSE;
-#endif
-
-#ifdef GL_EXT_blend_minmax
-    } else if (0 == strcmp(extension, "GL_EXT_blend_minmax")) {
-        GLH_EXT_NAME(glBlendEquationEXT) = (PFNGLBLENDEQUATIONEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glBlendEquationEXT");
-        if (NULL == GLH_EXT_NAME(glBlendEquationEXT))
-            return FALSE;
-#endif
-
-#ifdef GL_EXT_blend_subtract
-    } else if (0 == strcmp(extension, "GL_EXT_blend_subtract")) {
-#endif
-
-#ifdef GL_EXT_compiled_vertex_array
-    } else if (0 == strcmp(extension, "GL_EXT_compiled_vertex_array")) {
-        GLH_EXT_NAME(glLockArraysEXT) = (PFNGLLOCKARRAYSEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glLockArraysEXT");
-        if (NULL == GLH_EXT_NAME(glLockArraysEXT))
-            return FALSE;
-        GLH_EXT_NAME(glUnlockArraysEXT) = (PFNGLUNLOCKARRAYSEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glUnlockArraysEXT");
-        if (NULL == GLH_EXT_NAME(glUnlockArraysEXT))
-            return FALSE;
-#endif
-
-#ifdef GL_EXT_fog_coord
-    } else if (0 == strcmp(extension, "GL_EXT_fog_coord")) {
-        GLH_EXT_NAME(glFogCoorddEXT) = (PFNGLFOGCOORDDEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glFogCoorddEXT");
-        if (NULL == GLH_EXT_NAME(glFogCoorddEXT))
-            return FALSE;
-        GLH_EXT_NAME(glFogCoorddvEXT) = (PFNGLFOGCOORDDVEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glFogCoorddvEXT");
-        if (NULL == GLH_EXT_NAME(glFogCoorddvEXT))
-            return FALSE;
-        GLH_EXT_NAME(glFogCoordfEXT) = (PFNGLFOGCOORDFEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glFogCoordfEXT");
-        if (NULL == GLH_EXT_NAME(glFogCoordfEXT))
-            return FALSE;
-        GLH_EXT_NAME(glFogCoordfvEXT) = (PFNGLFOGCOORDFVEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glFogCoordfvEXT");
-        if (NULL == GLH_EXT_NAME(glFogCoordfvEXT))
-            return FALSE;
-        GLH_EXT_NAME(glFogCoordPointerEXT) = (PFNGLFOGCOORDPOINTEREXTPROC)GLH_EXT_GET_PROC_ADDRESS("glFogCoordPointerEXT");
-        if (NULL == GLH_EXT_NAME(glFogCoordPointerEXT))
-            return FALSE;
-#endif
-
-#ifdef GL_EXT_light_max_exponent
-    } else if (0 == strcmp(extension, "GL_EXT_light_max_exponent")) {
-#endif
-
-#ifdef GL_EXT_packed_pixels
-    } else if (0 == strcmp(extension, "GL_EXT_packed_pixels")) {
-#endif
-
-#ifdef GL_EXT_paletted_texture
-    } else if (0 == strcmp(extension, "GL_EXT_paletted_texture")) {
-        GLH_EXT_NAME(glColorSubTableEXT) = (PFNGLCOLORSUBTABLEEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glColorSubTableEXT");
-        if (NULL == GLH_EXT_NAME(glColorSubTableEXT))
-            return FALSE;
-        GLH_EXT_NAME(glColorTableEXT) = (PFNGLCOLORTABLEEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glColorTableEXT");
-        if (NULL == GLH_EXT_NAME(glColorTableEXT))
-            return FALSE;
-        GLH_EXT_NAME(glGetColorTableEXT) = (PFNGLGETCOLORTABLEEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glGetColorTableEXT");
-        if (NULL == GLH_EXT_NAME(glGetColorTableEXT))
-            return FALSE;
-        GLH_EXT_NAME(glGetColorTableParameterfvEXT) = (PFNGLGETCOLORTABLEPARAMETERFVEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glGetColorTableParameterfvEXT");
-        if (NULL == GLH_EXT_NAME(glGetColorTableParameterfvEXT))
-            return FALSE;
-        GLH_EXT_NAME(glGetColorTableParameterivEXT) = (PFNGLGETCOLORTABLEPARAMETERIVEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glGetColorTableParameterivEXT");
-        if (NULL == GLH_EXT_NAME(glGetColorTableParameterivEXT))
-            return FALSE;
-#endif
-
-#ifdef GL_EXT_point_parameters
-    } else if (0 == strcmp(extension, "GL_EXT_point_parameters")) {
-        GLH_EXT_NAME(glPointParameterfEXT) = (PFNGLPOINTPARAMETERFEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glPointParameterfEXT");
-        if (NULL == GLH_EXT_NAME(glPointParameterfEXT))
-            return FALSE;
-        GLH_EXT_NAME(glPointParameterfvEXT) = (PFNGLPOINTPARAMETERFVEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glPointParameterfvEXT");
-        if (NULL == GLH_EXT_NAME(glPointParameterfvEXT))
-            return FALSE;
-#endif
-
-#ifdef GL_EXT_rescale_normal
-    } else if (0 == strcmp(extension, "GL_EXT_rescale_normal")) {
-#endif
-
-#ifdef GL_EXT_secondary_color
-    } else if (0 == strcmp(extension, "GL_EXT_secondary_color")) {
-        GLH_EXT_NAME(glSecondaryColor3bEXT) = (PFNGLSECONDARYCOLOR3BEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glSecondaryColor3bEXT");
-        if (NULL == GLH_EXT_NAME(glSecondaryColor3bEXT))
-            return FALSE;
-        GLH_EXT_NAME(glSecondaryColor3bvEXT) = (PFNGLSECONDARYCOLOR3BVEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glSecondaryColor3bvEXT");
-        if (NULL == GLH_EXT_NAME(glSecondaryColor3bvEXT))
-            return FALSE;
-        GLH_EXT_NAME(glSecondaryColor3dEXT) = (PFNGLSECONDARYCOLOR3DEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glSecondaryColor3dEXT");
-        if (NULL == GLH_EXT_NAME(glSecondaryColor3dEXT))
-            return FALSE;
-        GLH_EXT_NAME(glSecondaryColor3dvEXT) = (PFNGLSECONDARYCOLOR3DVEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glSecondaryColor3dvEXT");
-        if (NULL == GLH_EXT_NAME(glSecondaryColor3dvEXT))
-            return FALSE;
-        GLH_EXT_NAME(glSecondaryColor3fEXT) = (PFNGLSECONDARYCOLOR3FEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glSecondaryColor3fEXT");
-        if (NULL == GLH_EXT_NAME(glSecondaryColor3fEXT))
-            return FALSE;
-        GLH_EXT_NAME(glSecondaryColor3fvEXT) = (PFNGLSECONDARYCOLOR3FVEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glSecondaryColor3fvEXT");
-        if (NULL == GLH_EXT_NAME(glSecondaryColor3fvEXT))
-            return FALSE;
-        GLH_EXT_NAME(glSecondaryColor3iEXT) = (PFNGLSECONDARYCOLOR3IEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glSecondaryColor3iEXT");
-        if (NULL == GLH_EXT_NAME(glSecondaryColor3iEXT))
-            return FALSE;
-        GLH_EXT_NAME(glSecondaryColor3ivEXT) = (PFNGLSECONDARYCOLOR3IVEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glSecondaryColor3ivEXT");
-        if (NULL == GLH_EXT_NAME(glSecondaryColor3ivEXT))
-            return FALSE;
-        GLH_EXT_NAME(glSecondaryColor3sEXT) = (PFNGLSECONDARYCOLOR3SEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glSecondaryColor3sEXT");
-        if (NULL == GLH_EXT_NAME(glSecondaryColor3sEXT))
-            return FALSE;
-        GLH_EXT_NAME(glSecondaryColor3svEXT) = (PFNGLSECONDARYCOLOR3SVEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glSecondaryColor3svEXT");
-        if (NULL == GLH_EXT_NAME(glSecondaryColor3svEXT))
-            return FALSE;
-        GLH_EXT_NAME(glSecondaryColor3ubEXT) = (PFNGLSECONDARYCOLOR3UBEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glSecondaryColor3ubEXT");
-        if (NULL == GLH_EXT_NAME(glSecondaryColor3ubEXT))
-            return FALSE;
-        GLH_EXT_NAME(glSecondaryColor3ubvEXT) = (PFNGLSECONDARYCOLOR3UBVEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glSecondaryColor3ubvEXT");
-        if (NULL == GLH_EXT_NAME(glSecondaryColor3ubvEXT))
-            return FALSE;
-        GLH_EXT_NAME(glSecondaryColor3uiEXT) = (PFNGLSECONDARYCOLOR3UIEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glSecondaryColor3uiEXT");
-        if (NULL == GLH_EXT_NAME(glSecondaryColor3uiEXT))
-            return FALSE;
-        GLH_EXT_NAME(glSecondaryColor3uivEXT) = (PFNGLSECONDARYCOLOR3UIVEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glSecondaryColor3uivEXT");
-        if (NULL == GLH_EXT_NAME(glSecondaryColor3uivEXT))
-            return FALSE;
-        GLH_EXT_NAME(glSecondaryColor3usEXT) = (PFNGLSECONDARYCOLOR3USEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glSecondaryColor3usEXT");
-        if (NULL == GLH_EXT_NAME(glSecondaryColor3usEXT))
-            return FALSE;
-        GLH_EXT_NAME(glSecondaryColor3usvEXT) = (PFNGLSECONDARYCOLOR3USVEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glSecondaryColor3usvEXT");
-        if (NULL == GLH_EXT_NAME(glSecondaryColor3usvEXT))
-            return FALSE;
-        GLH_EXT_NAME(glSecondaryColorPointerEXT) = (PFNGLSECONDARYCOLORPOINTEREXTPROC)GLH_EXT_GET_PROC_ADDRESS("glSecondaryColorPointerEXT");
-        if (NULL == GLH_EXT_NAME(glSecondaryColorPointerEXT))
-            return FALSE;
-#endif
-
-#ifdef GL_EXT_separate_specular_color
-    } else if (0 == strcmp(extension, "GL_EXT_separate_specular_color")) {
-#endif
-
-#ifdef GL_EXT_shared_texture_palette
-    } else if (0 == strcmp(extension, "GL_EXT_shared_texture_palette")) {
-#endif
-
-#ifdef GL_EXT_stencil_wrap
-    } else if (0 == strcmp(extension, "GL_EXT_stencil_wrap")) {
-#endif
-
-#ifdef GL_EXT_texture_compression_s3tc
-    } else if (0 == strcmp(extension, "GL_EXT_texture_compression_s3tc")) {
-#endif
-
-#ifdef GL_EXT_texture_cube_map
-    } else if (0 == strcmp(extension, "GL_EXT_texture_cube_map")) {
-#endif
-
-#ifdef GL_EXT_texture_edge_clamp
-    } else if (0 == strcmp(extension, "GL_EXT_texture_edge_clamp")) {
-#endif
-
-#ifdef GL_EXT_texture_env_add
-    } else if (0 == strcmp(extension, "GL_EXT_texture_env_add")) {
-#endif
-
-#ifdef GL_EXT_texture_env_combine
-    } else if (0 == strcmp(extension, "GL_EXT_texture_env_combine")) {
-#endif
-
-#ifdef GL_EXT_texture_filter_anisotropic
-    } else if (0 == strcmp(extension, "GL_EXT_texture_filter_anisotropic")) {
-#endif
-
-#ifdef GL_EXT_texture_lod_bias
-    } else if (0 == strcmp(extension, "GL_EXT_texture_lod_bias")) {
-#endif
-
-#ifdef GL_EXT_texture_object
-    } else if (0 == strcmp(extension, "GL_EXT_texture_object")) {
-        GLH_EXT_NAME(glAreTexturesResidentEXT) = (PFNGLARETEXTURESRESIDENTEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glAreTexturesResidentEXT");
-        if (NULL == GLH_EXT_NAME(glAreTexturesResidentEXT))
-            return FALSE;
-        GLH_EXT_NAME(glBindTextureEXT) = (PFNGLBINDTEXTUREEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glBindTextureEXT");
-        if (NULL == GLH_EXT_NAME(glBindTextureEXT))
-            return FALSE;
-        GLH_EXT_NAME(glDeleteTexturesEXT) = (PFNGLDELETETEXTURESEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glDeleteTexturesEXT");
-        if (NULL == GLH_EXT_NAME(glDeleteTexturesEXT))
-            return FALSE;
-        GLH_EXT_NAME(glGenTexturesEXT) = (PFNGLGENTEXTURESEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glGenTexturesEXT");
-        if (NULL == GLH_EXT_NAME(glGenTexturesEXT))
-            return FALSE;
-        GLH_EXT_NAME(glIsTextureEXT) = (PFNGLISTEXTUREEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glIsTextureEXT");
-        if (NULL == GLH_EXT_NAME(glIsTextureEXT))
-            return FALSE;
-        GLH_EXT_NAME(glPrioritizeTexturesEXT) = (PFNGLPRIORITIZETEXTURESEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glPrioritizeTexturesEXT");
-        if (NULL == GLH_EXT_NAME(glPrioritizeTexturesEXT))
-            return FALSE;
-#endif
-
-#ifdef GL_EXT_texture3D
-    } else if (0 == strcmp(extension, "GL_EXT_texture3D")) {
-        GLH_EXT_NAME(glTexImage3DEXT) = (PFNGLTEXIMAGE3DEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glTexImage3DEXT");
-        if (NULL == GLH_EXT_NAME(glTexImage3DEXT))
-            return FALSE;
-#endif
-
-#ifdef GL_EXT_vertex_array
-    } else if (0 == strcmp(extension, "GL_EXT_vertex_array")) {
-        GLH_EXT_NAME(glArrayElementEXT) = (PFNGLARRAYELEMENTEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glArrayElementEXT");
-        if (NULL == GLH_EXT_NAME(glArrayElementEXT))
-            return FALSE;
-        GLH_EXT_NAME(glColorPointerEXT) = (PFNGLCOLORPOINTEREXTPROC)GLH_EXT_GET_PROC_ADDRESS("glColorPointerEXT");
-        if (NULL == GLH_EXT_NAME(glColorPointerEXT))
-            return FALSE;
-        GLH_EXT_NAME(glEdgeFlagPointerEXT) = (PFNGLEDGEFLAGPOINTEREXTPROC)GLH_EXT_GET_PROC_ADDRESS("glEdgeFlagPointerEXT");
-        if (NULL == GLH_EXT_NAME(glEdgeFlagPointerEXT))
-            return FALSE;
-        GLH_EXT_NAME(glGetPointervEXT) = (PFNGLGETPOINTERVEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glGetPointervEXT");
-        if (NULL == GLH_EXT_NAME(glGetPointervEXT))
-            return FALSE;
-        GLH_EXT_NAME(glIndexPointerEXT) = (PFNGLINDEXPOINTEREXTPROC)GLH_EXT_GET_PROC_ADDRESS("glIndexPointerEXT");
-        if (NULL == GLH_EXT_NAME(glIndexPointerEXT))
-            return FALSE;
-        GLH_EXT_NAME(glNormalPointerEXT) = (PFNGLNORMALPOINTEREXTPROC)GLH_EXT_GET_PROC_ADDRESS("glNormalPointerEXT");
-        if (NULL == GLH_EXT_NAME(glNormalPointerEXT))
-            return FALSE;
-        GLH_EXT_NAME(glTexCoordPointerEXT) = (PFNGLTEXCOORDPOINTEREXTPROC)GLH_EXT_GET_PROC_ADDRESS("glTexCoordPointerEXT");
-        if (NULL == GLH_EXT_NAME(glTexCoordPointerEXT))
-            return FALSE;
-        GLH_EXT_NAME(glVertexPointerEXT) = (PFNGLVERTEXPOINTEREXTPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexPointerEXT");
-        if (NULL == GLH_EXT_NAME(glVertexPointerEXT))
-            return FALSE;
-        GLH_EXT_NAME(glDrawArraysEXT) = (PFNGLDRAWARRAYSEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glDrawArraysEXT");
-        if (NULL == GLH_EXT_NAME(glDrawArraysEXT))
-            return FALSE;
-#endif
-
-#ifdef GL_EXT_vertex_weighting
-    } else if (0 == strcmp(extension, "GL_EXT_vertex_weighting")) {
-        GLH_EXT_NAME(glVertexWeightfEXT) = (PFNGLVERTEXWEIGHTFEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexWeightfEXT");
-        if (NULL == GLH_EXT_NAME(glVertexWeightfEXT))
-            return FALSE;
-        GLH_EXT_NAME(glVertexWeightfvEXT) = (PFNGLVERTEXWEIGHTFVEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexWeightfvEXT");
-        if (NULL == GLH_EXT_NAME(glVertexWeightfvEXT))
-            return FALSE;
-        GLH_EXT_NAME(glVertexWeightPointerEXT) = (PFNGLVERTEXWEIGHTPOINTEREXTPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexWeightPointerEXT");
-        if (NULL == GLH_EXT_NAME(glVertexWeightPointerEXT))
-            return FALSE;
-#endif
-
-#ifdef GL_NV_blend_square
-    } else if (0 == strcmp(extension, "GL_NV_blend_square")) {
-#endif
-
-#ifdef GL_NV_evaluators
-    } else if (0 == strcmp(extension, "GL_NV_evaluators")) {
-        GLH_EXT_NAME(glMapControlPointsNV) = (PFNGLMAPCONTROLPOINTSNVPROC)GLH_EXT_GET_PROC_ADDRESS("glMapControlPointsNV");
-        if (NULL == GLH_EXT_NAME(glMapControlPointsNV))
-            return FALSE;
-        GLH_EXT_NAME(glMapParameterivNV) = (PFNGLMAPPARAMETERIVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glMapParameterivNV");
-        if (NULL == GLH_EXT_NAME(glMapParameterivNV))
-            return FALSE;
-        GLH_EXT_NAME(glMapParameterfvNV) = (PFNGLMAPPARAMETERFVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glMapParameterfvNV");
-        if (NULL == GLH_EXT_NAME(glMapParameterfvNV))
-            return FALSE;
-        GLH_EXT_NAME(glGetMapControlPointsNV) = (PFNGLGETMAPCONTROLPOINTSNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetMapControlPointsNV");
-        if (NULL == GLH_EXT_NAME(glGetMapControlPointsNV))
-            return FALSE;
-        GLH_EXT_NAME(glGetMapParameterivNV) = (PFNGLGETMAPPARAMETERIVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetMapParameterivNV");
-        if (NULL == GLH_EXT_NAME(glGetMapParameterivNV))
-            return FALSE;
-        GLH_EXT_NAME(glGetMapParameterfvNV) = (PFNGLGETMAPPARAMETERFVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetMapParameterfvNV");
-        if (NULL == GLH_EXT_NAME(glGetMapParameterfvNV))
-            return FALSE;
-        GLH_EXT_NAME(glGetMapAttribParameterivNV) = (PFNGLGETMAPATTRIBPARAMETERIVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetMapAttribParameterivNV");
-        if (NULL == GLH_EXT_NAME(glGetMapAttribParameterivNV))
-            return FALSE;
-        GLH_EXT_NAME(glGetMapAttribParameterfvNV) = (PFNGLGETMAPATTRIBPARAMETERFVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetMapAttribParameterfvNV");
-        if (NULL == GLH_EXT_NAME(glGetMapAttribParameterfvNV))
-            return FALSE;
-        GLH_EXT_NAME(glEvalMapsNV) = (PFNGLEVALMAPSNVPROC)GLH_EXT_GET_PROC_ADDRESS("glEvalMapsNV");
-        if (NULL == GLH_EXT_NAME(glEvalMapsNV))
-            return FALSE;
-#endif
-
-#ifdef GL_NV_fence
-    } else if (0 == strcmp(extension, "GL_NV_fence")) {
-        GLH_EXT_NAME(glGenFencesNV) = (PFNGLGENFENCESNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGenFencesNV");
-        if (NULL == GLH_EXT_NAME(glGenFencesNV))
-            return FALSE;
-        GLH_EXT_NAME(glDeleteFencesNV) = (PFNGLDELETEFENCESNVPROC)GLH_EXT_GET_PROC_ADDRESS("glDeleteFencesNV");
-        if (NULL == GLH_EXT_NAME(glDeleteFencesNV))
-            return FALSE;
-        GLH_EXT_NAME(glSetFenceNV) = (PFNGLSETFENCENVPROC)GLH_EXT_GET_PROC_ADDRESS("glSetFenceNV");
-        if (NULL == GLH_EXT_NAME(glSetFenceNV))
-            return FALSE;
-        GLH_EXT_NAME(glTestFenceNV) = (PFNGLTESTFENCENVPROC)GLH_EXT_GET_PROC_ADDRESS("glTestFenceNV");
-        if (NULL == GLH_EXT_NAME(glTestFenceNV))
-            return FALSE;
-        GLH_EXT_NAME(glFinishFenceNV) = (PFNGLFINISHFENCENVPROC)GLH_EXT_GET_PROC_ADDRESS("glFinishFenceNV");
-        if (NULL == GLH_EXT_NAME(glFinishFenceNV))
-            return FALSE;
-        GLH_EXT_NAME(glIsFenceNV) = (PFNGLISFENCENVPROC)GLH_EXT_GET_PROC_ADDRESS("glIsFenceNV");
-        if (NULL == GLH_EXT_NAME(glIsFenceNV))
-            return FALSE;
-        GLH_EXT_NAME(glGetFenceivNV) = (PFNGLGETFENCEIVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetFenceivNV");
-        if (NULL == GLH_EXT_NAME(glGetFenceivNV))
-            return FALSE;
-#endif
-
-#ifdef GL_NV_fog_distance
-    } else if (0 == strcmp(extension, "GL_NV_fog_distance")) {
-#endif
-
-#ifdef GL_NV_packed_depth_stencil
-    } else if (0 == strcmp(extension, "GL_NV_packed_depth_stencil")) {
-#endif
-
-#ifdef GL_NV_register_combiners
-    } else if (0 == strcmp(extension, "GL_NV_register_combiners")) {
-        GLH_EXT_NAME(glCombinerParameterfvNV) = (PFNGLCOMBINERPARAMETERFVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glCombinerParameterfvNV");
-        if (NULL == GLH_EXT_NAME(glCombinerParameterfvNV))
-            return FALSE;
-        GLH_EXT_NAME(glCombinerParameterfNV) = (PFNGLCOMBINERPARAMETERFNVPROC)GLH_EXT_GET_PROC_ADDRESS("glCombinerParameterfNV");
-        if (NULL == GLH_EXT_NAME(glCombinerParameterfNV))
-            return FALSE;
-        GLH_EXT_NAME(glCombinerParameterivNV) = (PFNGLCOMBINERPARAMETERIVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glCombinerParameterivNV");
-        if (NULL == GLH_EXT_NAME(glCombinerParameterivNV))
-            return FALSE;
-        GLH_EXT_NAME(glCombinerParameteriNV) = (PFNGLCOMBINERPARAMETERINVPROC)GLH_EXT_GET_PROC_ADDRESS("glCombinerParameteriNV");
-        if (NULL == GLH_EXT_NAME(glCombinerParameteriNV))
-            return FALSE;
-        GLH_EXT_NAME(glCombinerInputNV) = (PFNGLCOMBINERINPUTNVPROC)GLH_EXT_GET_PROC_ADDRESS("glCombinerInputNV");
-        if (NULL == GLH_EXT_NAME(glCombinerInputNV))
-            return FALSE;
-        GLH_EXT_NAME(glCombinerOutputNV) = (PFNGLCOMBINEROUTPUTNVPROC)GLH_EXT_GET_PROC_ADDRESS("glCombinerOutputNV");
-        if (NULL == GLH_EXT_NAME(glCombinerOutputNV))
-            return FALSE;
-        GLH_EXT_NAME(glFinalCombinerInputNV) = (PFNGLFINALCOMBINERINPUTNVPROC)GLH_EXT_GET_PROC_ADDRESS("glFinalCombinerInputNV");
-        if (NULL == GLH_EXT_NAME(glFinalCombinerInputNV))
-            return FALSE;
-        GLH_EXT_NAME(glGetCombinerInputParameterfvNV) = (PFNGLGETCOMBINERINPUTPARAMETERFVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetCombinerInputParameterfvNV");
-        if (NULL == GLH_EXT_NAME(glGetCombinerInputParameterfvNV))
-            return FALSE;
-        GLH_EXT_NAME(glGetCombinerInputParameterivNV) = (PFNGLGETCOMBINERINPUTPARAMETERIVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetCombinerInputParameterivNV");
-        if (NULL == GLH_EXT_NAME(glGetCombinerInputParameterivNV))
-            return FALSE;
-        GLH_EXT_NAME(glGetCombinerOutputParameterfvNV) = (PFNGLGETCOMBINEROUTPUTPARAMETERFVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetCombinerOutputParameterfvNV");
-        if (NULL == GLH_EXT_NAME(glGetCombinerOutputParameterfvNV))
-            return FALSE;
-        GLH_EXT_NAME(glGetCombinerOutputParameterivNV) = (PFNGLGETCOMBINEROUTPUTPARAMETERIVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetCombinerOutputParameterivNV");
-        if (NULL == GLH_EXT_NAME(glGetCombinerOutputParameterivNV))
-            return FALSE;
-        GLH_EXT_NAME(glGetFinalCombinerInputParameterfvNV) = (PFNGLGETFINALCOMBINERINPUTPARAMETERFVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetFinalCombinerInputParameterfvNV");
-        if (NULL == GLH_EXT_NAME(glGetFinalCombinerInputParameterfvNV))
-            return FALSE;
-        GLH_EXT_NAME(glGetFinalCombinerInputParameterivNV) = (PFNGLGETFINALCOMBINERINPUTPARAMETERIVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetFinalCombinerInputParameterivNV");
-        if (NULL == GLH_EXT_NAME(glGetFinalCombinerInputParameterivNV))
-            return FALSE;
-#endif
-
-#ifdef GL_NV_register_combiners2
-    } else if (0 == strcmp(extension, "GL_NV_register_combiners2")) {
-        GLH_EXT_NAME(glCombinerStageParameterfvNV) = (PFNGLCOMBINERSTAGEPARAMETERFVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glCombinerStageParameterfvNV");
-        if (NULL == GLH_EXT_NAME(glCombinerStageParameterfvNV))
-            return FALSE;
-        GLH_EXT_NAME(glGetCombinerStageParameterfvNV) = (PFNGLGETCOMBINERSTAGEPARAMETERFVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetCombinerStageParameterfvNV");
-        if (NULL == GLH_EXT_NAME(glGetCombinerStageParameterfvNV))
-            return FALSE;
-#endif
-
-#ifdef GL_NV_texgen_reflection
-    } else if (0 == strcmp(extension, "GL_NV_texgen_reflection")) {
-#endif
-
-#ifdef GL_NV_texture_env_combine4
-    } else if (0 == strcmp(extension, "GL_NV_texture_env_combine4")) {
-#endif
-
-#ifdef GL_NV_texture_rectangle
-    } else if (0 == strcmp(extension, "GL_NV_texture_rectangle")) {
-#endif
-
-#ifdef GL_NV_texture_shader
-    } else if (0 == strcmp(extension, "GL_NV_texture_shader")) {
-#endif
-
-#ifdef GL_NV_vertex_array_range
-    } else if (0 == strcmp(extension, "GL_NV_vertex_array_range")) {
-        GLH_EXT_NAME(glFlushVertexArrayRangeNV) = (PFNGLFLUSHVERTEXARRAYRANGENVPROC)GLH_EXT_GET_PROC_ADDRESS("glFlushVertexArrayRangeNV");
-        if (NULL == GLH_EXT_NAME(glFlushVertexArrayRangeNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexArrayRangeNV) = (PFNGLVERTEXARRAYRANGENVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexArrayRangeNV");
-        if (NULL == GLH_EXT_NAME(glVertexArrayRangeNV))
-            return FALSE;
-# ifdef _WIN32
-        GLH_EXT_NAME(wglAllocateMemoryNV) = (PFNWGLALLOCATEMEMORYNVPROC)GLH_EXT_GET_PROC_ADDRESS("wglAllocateMemoryNV");
-        if (NULL == GLH_EXT_NAME(wglAllocateMemoryNV))
-            return FALSE;
-# endif
-# ifdef GLX_VERSION_1_3
-        GLH_EXT_NAME(glXAllocateMemoryNV) = (PFNGLXALLOCATEMEMORYNVPROC)GLH_EXT_GET_PROC_ADDRESS("glXAllocateMemoryNV");
-        if (NULL == GLH_EXT_NAME(glXAllocateMemoryNV))
-            return FALSE;
-# endif
-# ifdef _WIN32
-        GLH_EXT_NAME(wglFreeMemoryNV) = (PFNWGLFREEMEMORYNVPROC)GLH_EXT_GET_PROC_ADDRESS("wglFreeMemoryNV");
-        if (NULL == GLH_EXT_NAME(wglFreeMemoryNV))
-            return FALSE;
-# endif
-# ifdef GLX_VERSION_1_3
-        GLH_EXT_NAME(glXFreeMemoryNV) = (PFNGLXFREEMEMORYNVPROC)GLH_EXT_GET_PROC_ADDRESS("glXFreeMemoryNV");
-        if (NULL == GLH_EXT_NAME(glXFreeMemoryNV))
-            return FALSE;
-# endif
-#endif
-
-#ifdef GL_NV_vertex_program
-    } else if (0 == strcmp(extension, "GL_NV_vertex_program")) {
-        GLH_EXT_NAME(glAreProgramsResidentNV) = (PFNGLAREPROGRAMSRESIDENTNVPROC)GLH_EXT_GET_PROC_ADDRESS("glAreProgramsResidentNV");
-        if (NULL == GLH_EXT_NAME(glAreProgramsResidentNV))
-            return FALSE;
-        GLH_EXT_NAME(glBindProgramNV) = (PFNGLBINDPROGRAMNVPROC)GLH_EXT_GET_PROC_ADDRESS("glBindProgramNV");
-        if (NULL == GLH_EXT_NAME(glBindProgramNV))
-            return FALSE;
-        GLH_EXT_NAME(glDeleteProgramsNV) = (PFNGLDELETEPROGRAMSNVPROC)GLH_EXT_GET_PROC_ADDRESS("glDeleteProgramsNV");
-        if (NULL == GLH_EXT_NAME(glDeleteProgramsNV))
-            return FALSE;
-        GLH_EXT_NAME(glExecuteProgramNV) = (PFNGLEXECUTEPROGRAMNVPROC)GLH_EXT_GET_PROC_ADDRESS("glExecuteProgramNV");
-        if (NULL == GLH_EXT_NAME(glExecuteProgramNV))
-            return FALSE;
-        GLH_EXT_NAME(glGenProgramsNV) = (PFNGLGENPROGRAMSNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGenProgramsNV");
-        if (NULL == GLH_EXT_NAME(glGenProgramsNV))
-            return FALSE;
-        GLH_EXT_NAME(glGetProgramParameterdvNV) = (PFNGLGETPROGRAMPARAMETERDVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetProgramParameterdvNV");
-        if (NULL == GLH_EXT_NAME(glGetProgramParameterdvNV))
-            return FALSE;
-        GLH_EXT_NAME(glGetProgramParameterfvNV) = (PFNGLGETPROGRAMPARAMETERFVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetProgramParameterfvNV");
-        if (NULL == GLH_EXT_NAME(glGetProgramParameterfvNV))
-            return FALSE;
-        GLH_EXT_NAME(glGetProgramivNV) = (PFNGLGETPROGRAMIVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetProgramivNV");
-        if (NULL == GLH_EXT_NAME(glGetProgramivNV))
-            return FALSE;
-        GLH_EXT_NAME(glGetProgramStringNV) = (PFNGLGETPROGRAMSTRINGNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetProgramStringNV");
-        if (NULL == GLH_EXT_NAME(glGetProgramStringNV))
-            return FALSE;
-        GLH_EXT_NAME(glGetTrackMatrixivNV) = (PFNGLGETTRACKMATRIXIVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetTrackMatrixivNV");
-        if (NULL == GLH_EXT_NAME(glGetTrackMatrixivNV))
-            return FALSE;
-        GLH_EXT_NAME(glGetVertexAttribdvNV) = (PFNGLGETVERTEXATTRIBDVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetVertexAttribdvNV");
-        if (NULL == GLH_EXT_NAME(glGetVertexAttribdvNV))
-            return FALSE;
-        GLH_EXT_NAME(glGetVertexAttribfvNV) = (PFNGLGETVERTEXATTRIBFVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetVertexAttribfvNV");
-        if (NULL == GLH_EXT_NAME(glGetVertexAttribfvNV))
-            return FALSE;
-        GLH_EXT_NAME(glGetVertexAttribivNV) = (PFNGLGETVERTEXATTRIBIVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetVertexAttribivNV");
-        if (NULL == GLH_EXT_NAME(glGetVertexAttribivNV))
-            return FALSE;
-        GLH_EXT_NAME(glGetVertexAttribPointervNV) = (PFNGLGETVERTEXATTRIBPOINTERVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetVertexAttribPointervNV");
-        if (NULL == GLH_EXT_NAME(glGetVertexAttribPointervNV))
-            return FALSE;
-        GLH_EXT_NAME(glIsProgramNV) = (PFNGLISPROGRAMNVPROC)GLH_EXT_GET_PROC_ADDRESS("glIsProgramNV");
-        if (NULL == GLH_EXT_NAME(glIsProgramNV))
-            return FALSE;
-        GLH_EXT_NAME(glLoadProgramNV) = (PFNGLLOADPROGRAMNVPROC)GLH_EXT_GET_PROC_ADDRESS("glLoadProgramNV");
-        if (NULL == GLH_EXT_NAME(glLoadProgramNV))
-            return FALSE;
-        GLH_EXT_NAME(glProgramParameter4dNV) = (PFNGLPROGRAMPARAMETER4DNVPROC)GLH_EXT_GET_PROC_ADDRESS("glProgramParameter4dNV");
-        if (NULL == GLH_EXT_NAME(glProgramParameter4dNV))
-            return FALSE;
-        GLH_EXT_NAME(glProgramParameter4dvNV) = (PFNGLPROGRAMPARAMETER4DVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glProgramParameter4dvNV");
-        if (NULL == GLH_EXT_NAME(glProgramParameter4dvNV))
-            return FALSE;
-        GLH_EXT_NAME(glProgramParameter4fNV) = (PFNGLPROGRAMPARAMETER4FNVPROC)GLH_EXT_GET_PROC_ADDRESS("glProgramParameter4fNV");
-        if (NULL == GLH_EXT_NAME(glProgramParameter4fNV))
-            return FALSE;
-        GLH_EXT_NAME(glProgramParameter4fvNV) = (PFNGLPROGRAMPARAMETER4FVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glProgramParameter4fvNV");
-        if (NULL == GLH_EXT_NAME(glProgramParameter4fvNV))
-            return FALSE;
-        GLH_EXT_NAME(glProgramParameters4dvNV) = (PFNGLPROGRAMPARAMETERS4DVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glProgramParameters4dvNV");
-        if (NULL == GLH_EXT_NAME(glProgramParameters4dvNV))
-            return FALSE;
-        GLH_EXT_NAME(glProgramParameters4fvNV) = (PFNGLPROGRAMPARAMETERS4FVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glProgramParameters4fvNV");
-        if (NULL == GLH_EXT_NAME(glProgramParameters4fvNV))
-            return FALSE;
-        GLH_EXT_NAME(glRequestResidentProgramsNV) = (PFNGLREQUESTRESIDENTPROGRAMSNVPROC)GLH_EXT_GET_PROC_ADDRESS("glRequestResidentProgramsNV");
-        if (NULL == GLH_EXT_NAME(glRequestResidentProgramsNV))
-            return FALSE;
-        GLH_EXT_NAME(glTrackMatrixNV) = (PFNGLTRACKMATRIXNVPROC)GLH_EXT_GET_PROC_ADDRESS("glTrackMatrixNV");
-        if (NULL == GLH_EXT_NAME(glTrackMatrixNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttribPointerNV) = (PFNGLVERTEXATTRIBPOINTERNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttribPointerNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttribPointerNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttrib1dNV) = (PFNGLVERTEXATTRIB1DNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1dNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib1dNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttrib1dvNV) = (PFNGLVERTEXATTRIB1DVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1dvNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib1dvNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttrib1fNV) = (PFNGLVERTEXATTRIB1FNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1fNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib1fNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttrib1fvNV) = (PFNGLVERTEXATTRIB1FVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1fvNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib1fvNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttrib1sNV) = (PFNGLVERTEXATTRIB1SNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1sNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib1sNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttrib1svNV) = (PFNGLVERTEXATTRIB1SVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1svNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib1svNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttrib2dNV) = (PFNGLVERTEXATTRIB2DNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2dNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib2dNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttrib2dvNV) = (PFNGLVERTEXATTRIB2DVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2dvNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib2dvNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttrib2fNV) = (PFNGLVERTEXATTRIB2FNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2fNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib2fNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttrib2fvNV) = (PFNGLVERTEXATTRIB2FVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2fvNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib2fvNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttrib2sNV) = (PFNGLVERTEXATTRIB2SNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2sNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib2sNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttrib2svNV) = (PFNGLVERTEXATTRIB2SVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2svNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib2svNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttrib3dNV) = (PFNGLVERTEXATTRIB3DNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3dNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib3dNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttrib3dvNV) = (PFNGLVERTEXATTRIB3DVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3dvNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib3dvNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttrib3fNV) = (PFNGLVERTEXATTRIB3FNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3fNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib3fNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttrib3fvNV) = (PFNGLVERTEXATTRIB3FVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3fvNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib3fvNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttrib3sNV) = (PFNGLVERTEXATTRIB3SNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3sNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib3sNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttrib3svNV) = (PFNGLVERTEXATTRIB3SVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3svNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib3svNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttrib4dNV) = (PFNGLVERTEXATTRIB4DNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4dNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib4dNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttrib4dvNV) = (PFNGLVERTEXATTRIB4DVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4dvNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib4dvNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttrib4fNV) = (PFNGLVERTEXATTRIB4FNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4fNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib4fNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttrib4fvNV) = (PFNGLVERTEXATTRIB4FVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4fvNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib4fvNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttrib4sNV) = (PFNGLVERTEXATTRIB4SNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4sNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib4sNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttrib4svNV) = (PFNGLVERTEXATTRIB4SVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4svNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib4svNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttrib4ubvNV) = (PFNGLVERTEXATTRIB4UBVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4ubvNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttrib4ubvNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttribs1dvNV) = (PFNGLVERTEXATTRIBS1DVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttribs1dvNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttribs1dvNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttribs1fvNV) = (PFNGLVERTEXATTRIBS1FVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttribs1fvNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttribs1fvNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttribs1svNV) = (PFNGLVERTEXATTRIBS1SVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttribs1svNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttribs1svNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttribs2dvNV) = (PFNGLVERTEXATTRIBS2DVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttribs2dvNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttribs2dvNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttribs2fvNV) = (PFNGLVERTEXATTRIBS2FVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttribs2fvNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttribs2fvNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttribs2svNV) = (PFNGLVERTEXATTRIBS2SVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttribs2svNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttribs2svNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttribs3dvNV) = (PFNGLVERTEXATTRIBS3DVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttribs3dvNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttribs3dvNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttribs3fvNV) = (PFNGLVERTEXATTRIBS3FVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttribs3fvNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttribs3fvNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttribs3svNV) = (PFNGLVERTEXATTRIBS3SVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttribs3svNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttribs3svNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttribs4dvNV) = (PFNGLVERTEXATTRIBS4DVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttribs4dvNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttribs4dvNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttribs4fvNV) = (PFNGLVERTEXATTRIBS4FVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttribs4fvNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttribs4fvNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttribs4svNV) = (PFNGLVERTEXATTRIBS4SVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttribs4svNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttribs4svNV))
-            return FALSE;
-        GLH_EXT_NAME(glVertexAttribs4ubvNV) = (PFNGLVERTEXATTRIBS4UBVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttribs4ubvNV");
-        if (NULL == GLH_EXT_NAME(glVertexAttribs4ubvNV))
-            return FALSE;
-#endif
-
-#ifdef GL_SGIS_generate_mipmap
-    } else if (0 == strcmp(extension, "GL_SGIS_generate_mipmap")) {
-#endif
-
-#ifdef GL_SGIS_texture_lod
-    } else if (0 == strcmp(extension, "GL_SGIS_texture_lod")) {
-#endif
-
-#ifdef GL_SGIX_depth_texture
-    } else if (0 == strcmp(extension, "GL_SGIX_depth_texture")) {
-#endif
-
-#ifdef GL_SGIX_shadow
-    } else if (0 == strcmp(extension, "GL_SGIX_shadow")) {
-#endif
-
-#ifdef GL_VERSION_1_2
-    } else if (0 == strcmp(extension, "GL_VERSION_1_2")) {
-        GLH_CORE_1_2_NAME(glBlendColor) = (PFNGLBLENDCOLORPROC)GLH_EXT_GET_PROC_ADDRESS("glBlendColor");
-        if (NULL == GLH_CORE_1_2_NAME(glBlendColor))
-            return FALSE;
-        GLH_CORE_1_2_NAME(glBlendEquation) = (PFNGLBLENDEQUATIONPROC)GLH_EXT_GET_PROC_ADDRESS("glBlendEquation");
-        if (NULL == GLH_CORE_1_2_NAME(glBlendEquation))
-            return FALSE;
-        GLH_CORE_1_2_NAME(glDrawRangeElements) = (PFNGLDRAWRANGEELEMENTSPROC)GLH_EXT_GET_PROC_ADDRESS("glDrawRangeElements");
-        if (NULL == GLH_CORE_1_2_NAME(glDrawRangeElements))
-            return FALSE;
-        GLH_CORE_1_2_NAME(glColorTable) = (PFNGLCOLORTABLEPROC)GLH_EXT_GET_PROC_ADDRESS("glColorTable");
-        if (NULL == GLH_CORE_1_2_NAME(glColorTable))
-            return FALSE;
-        GLH_CORE_1_2_NAME(glColorTableParameterfv) = (PFNGLCOLORTABLEPARAMETERFVPROC)GLH_EXT_GET_PROC_ADDRESS("glColorTableParameterfv");
-        if (NULL == GLH_CORE_1_2_NAME(glColorTableParameterfv))
-            return FALSE;
-        GLH_CORE_1_2_NAME(glColorTableParameteriv) = (PFNGLCOLORTABLEPARAMETERIVPROC)GLH_EXT_GET_PROC_ADDRESS("glColorTableParameteriv");
-        if (NULL == GLH_CORE_1_2_NAME(glColorTableParameteriv))
-            return FALSE;
-        GLH_CORE_1_2_NAME(glCopyColorTable) = (PFNGLCOPYCOLORTABLEPROC)GLH_EXT_GET_PROC_ADDRESS("glCopyColorTable");
-        if (NULL == GLH_CORE_1_2_NAME(glCopyColorTable))
-            return FALSE;
-        GLH_CORE_1_2_NAME(glGetColorTable) = (PFNGLGETCOLORTABLEPROC)GLH_EXT_GET_PROC_ADDRESS("glGetColorTable");
-        if (NULL == GLH_CORE_1_2_NAME(glGetColorTable))
-            return FALSE;
-        GLH_CORE_1_2_NAME(glGetColorTableParameterfv) = (PFNGLGETCOLORTABLEPARAMETERFVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetColorTableParameterfv");
-        if (NULL == GLH_CORE_1_2_NAME(glGetColorTableParameterfv))
-            return FALSE;
-        GLH_CORE_1_2_NAME(glGetColorTableParameteriv) = (PFNGLGETCOLORTABLEPARAMETERIVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetColorTableParameteriv");
-        if (NULL == GLH_CORE_1_2_NAME(glGetColorTableParameteriv))
-            return FALSE;
-        GLH_CORE_1_2_NAME(glTexImage3D) = (PFNGLTEXIMAGE3DPROC)GLH_EXT_GET_PROC_ADDRESS("glTexImage3D");
-        if (NULL == GLH_CORE_1_2_NAME(glTexImage3D))
-            return FALSE;
-        GLH_CORE_1_2_NAME(glTexSubImage3D) = (PFNGLTEXSUBIMAGE3DPROC)GLH_EXT_GET_PROC_ADDRESS("glTexSubImage3D");
-        if (NULL == GLH_CORE_1_2_NAME(glTexSubImage3D))
-            return FALSE;
-        GLH_CORE_1_2_NAME(glCopyTexSubImage3D) = (PFNGLCOPYTEXSUBIMAGE3DPROC)GLH_EXT_GET_PROC_ADDRESS("glCopyTexSubImage3D");
-        if (NULL == GLH_CORE_1_2_NAME(glCopyTexSubImage3D))
-            return FALSE;
-#endif
-
-#ifdef GL_WIN_swap_hint
-    } else if (0 == strcmp(extension, "GL_WIN_swap_hint")) {
-        GLH_EXT_NAME(glAddSwapHintRectWIN) = (PFNGLADDSWAPHINTRECTWINPROC)GLH_EXT_GET_PROC_ADDRESS("glAddSwapHintRectWIN");
-        if (NULL == GLH_EXT_NAME(glAddSwapHintRectWIN))
-            return FALSE;
-#endif
-
-#ifdef WGL_ARB_pbuffer
-    } else if (0 == strcmp(extension, "WGL_ARB_pbuffer")) {
-# ifdef _WIN32
-        GLH_EXT_NAME(wglCreatePbufferARB) = (PFNWGLCREATEPBUFFERARBPROC)GLH_EXT_GET_PROC_ADDRESS("wglCreatePbufferARB");
-        if (NULL == GLH_EXT_NAME(wglCreatePbufferARB))
-            return FALSE;
-# endif
-# ifdef _WIN32
-        GLH_EXT_NAME(wglGetPbufferDCARB) = (PFNWGLGETPBUFFERDCARBPROC)GLH_EXT_GET_PROC_ADDRESS("wglGetPbufferDCARB");
-        if (NULL == GLH_EXT_NAME(wglGetPbufferDCARB))
-            return FALSE;
-# endif
-# ifdef _WIN32
-        GLH_EXT_NAME(wglReleasePbufferDCARB) = (PFNWGLRELEASEPBUFFERDCARBPROC)GLH_EXT_GET_PROC_ADDRESS("wglReleasePbufferDCARB");
-        if (NULL == GLH_EXT_NAME(wglReleasePbufferDCARB))
-            return FALSE;
-# endif
-# ifdef _WIN32
-        GLH_EXT_NAME(wglDestroyPbufferARB) = (PFNWGLDESTROYPBUFFERARBPROC)GLH_EXT_GET_PROC_ADDRESS("wglDestroyPbufferARB");
-        if (NULL == GLH_EXT_NAME(wglDestroyPbufferARB))
-            return FALSE;
-# endif
-# ifdef _WIN32
-        GLH_EXT_NAME(wglQueryPbufferARB) = (PFNWGLQUERYPBUFFERARBPROC)GLH_EXT_GET_PROC_ADDRESS("wglQueryPbufferARB");
-        if (NULL == GLH_EXT_NAME(wglQueryPbufferARB))
-            return FALSE;
-# endif
-#endif
-
-#ifdef WGL_ARB_render_texture
-# ifdef _WIN32
-		GLH_EXT_NAME(wglBindTexImageARB) = (PFNWGLBINDTEXIMAGEARBPROC)GLH_EXT_GET_PROC_ADDRESS("wglBindTexImageARB");
-		if (NULL == GLH_EXT_NAME(wglBindTexImageARB))
-			return FALSE;
-# endif
-# ifdef _WIN32
-		GLH_EXT_NAME(wglReleaseTexImageARB) = (PFNWGLRELEASETEXIMAGEARBPROC)GLH_EXT_GET_PROC_ADDRESS("wglReleaseTexImageARB");
-		if (NULL == GLH_EXT_NAME(wglReleaseTexImageARB))
-			return FALSE;
-# endif
-# ifdef _WIN32
-		GLH_EXT_NAME(wglSetPbufferAttribARB) = (PFNWGLSETPBUFFERATTRIBARBPROC)GLH_EXT_GET_PROC_ADDRESS("wglSetPbufferAttribARB");
-		if (NULL == GLH_EXT_NAME(wglSetPbufferAttribARB))
-			return FALSE;
-# endif
-#endif
-
-#ifdef WGL_ARB_pixel_format
-    } else if (0 == strcmp(extension, "WGL_ARB_pixel_format")) {
-# ifdef _WIN32
-        GLH_EXT_NAME(wglGetPixelFormatAttribivARB) = (PFNWGLGETPIXELFORMATATTRIBIVARBPROC)GLH_EXT_GET_PROC_ADDRESS("wglGetPixelFormatAttribivARB");
-        if (NULL == GLH_EXT_NAME(wglGetPixelFormatAttribivARB))
-            return FALSE;
-# endif
-# ifdef _WIN32
-        GLH_EXT_NAME(wglGetPixelFormatAttribfvARB) = (PFNWGLGETPIXELFORMATATTRIBFVARBPROC)GLH_EXT_GET_PROC_ADDRESS("wglGetPixelFormatAttribfvARB");
-        if (NULL == GLH_EXT_NAME(wglGetPixelFormatAttribfvARB))
-            return FALSE;
-# endif
-# ifdef _WIN32
-        GLH_EXT_NAME(wglChoosePixelFormatARB) = (PFNWGLCHOOSEPIXELFORMATARBPROC)GLH_EXT_GET_PROC_ADDRESS("wglChoosePixelFormatARB");
-        if (NULL == GLH_EXT_NAME(wglChoosePixelFormatARB))
-            return FALSE;
-# endif
-#endif
-
-    } else {
-        return FALSE;
-    }
-    return TRUE;
-}
-#endif
-
-#else // defined(__APPLE__)
-
-#ifdef GLH_EXT_SINGLE_FILE
-
-int glh_init_extension(const char* extension)
-{
-	// MBW -- XXX -- Should this check for extension availability?
-	return TRUE;
-}
-#endif // GLH_EXT_SINGLE_FILE
-
-#endif // defined(__APPLE__)
-
-#undef GLH_EXT_SINGLE_FILE
-
-#endif /* GLH_GENEXT_H */
-- 
cgit v1.2.3


From 80ac5d49d950a773768550070dd272a58c95c245 Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Fri, 17 Sep 2021 15:48:57 +0300
Subject: SL-13561 When ALM is enabled, disabling water rendering breaks the
 sky

---
 indra/newview/pipeline.cpp | 31 ++++++++++++++++++++++++++++++-
 1 file changed, 30 insertions(+), 1 deletion(-)

(limited to 'indra')

diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index 71a438302a..e23aeb286c 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -9203,7 +9203,13 @@ inline float sgn(float a)
 void LLPipeline::generateWaterReflection(LLCamera& camera_in)
 {
     LL_PROFILE_ZONE_SCOPED;
-    if (LLPipeline::sWaterReflections && assertInitialized() && LLDrawPoolWater::sNeedsReflectionUpdate)
+
+    if (!assertInitialized())
+    {
+        return;
+    }
+
+    if (LLPipeline::sWaterReflections && LLDrawPoolWater::sNeedsReflectionUpdate)
     {
         bool skip_avatar_update = false;
         if (!isAgentAvatarValid() || gAgentCamera.getCameraAnimating() || gAgentCamera.getCameraMode() != CAMERA_MODE_MOUSELOOK || !LLVOAvatar::sVisibleInFirstPerson)
@@ -9488,6 +9494,29 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in)
 
         LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD;
     }
+    else
+    {
+        // Initial sky pass is still needed even if water reflection is not rendering
+        bool camera_is_underwater = LLViewerCamera::getInstance()->cameraUnderWater();
+        if (!camera_is_underwater)
+        {
+            gPipeline.pushRenderTypeMask();
+            {
+                gPipeline.andRenderTypeMask(
+                    LLPipeline::RENDER_TYPE_SKY,
+                    LLPipeline::RENDER_TYPE_WL_SKY,
+                    LLPipeline::END_RENDER_TYPES);
+
+                LLCamera camera = camera_in;
+                camera.setFar(camera_in.getFar() * 0.75f);
+
+                updateCull(camera, mSky);
+                stateSort(camera, mSky);
+                renderGeom(camera, TRUE);
+            }
+            gPipeline.popRenderTypeMask();
+        }
+    }
 }
 
 glh::matrix4f look(const LLVector3 pos, const LLVector3 dir, const LLVector3 up)
-- 
cgit v1.2.3


From 3b3ff53eb53db023462eba0283ef7586e79df35a Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Fri, 11 Jun 2021 21:16:08 +0300
Subject: SL-15391 Crash at getUniformLocation

---
 indra/llrender/llglslshader.cpp | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

(limited to 'indra')

diff --git a/indra/llrender/llglslshader.cpp b/indra/llrender/llglslshader.cpp
index 0e4753fcc6..08c9dd8769 100644
--- a/indra/llrender/llglslshader.cpp
+++ b/indra/llrender/llglslshader.cpp
@@ -1436,7 +1436,11 @@ GLint LLGLSLShader::getUniformLocation(U32 index)
     GLint ret = -1;
     if (mProgramObject)
     {
-        llassert(index < mUniform.size());
+        if (index >= mUniform.size())
+        {
+            LL_WARNS_ONCE("Shader") << "Uniform index " << index << " out of bounds " << (S32)mUniform.size() << LL_ENDL;
+            return ret;
+        }
         return mUniform[index];
     }
 
-- 
cgit v1.2.3


From 58cd9d547c57b4491c3a85b7aade0f56ae7397c8 Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Fri, 24 Sep 2021 23:35:12 +0300
Subject: SL-16056 Improve 'avatar cloud' behavior

Make avatar cloud delay longer proportionally to load time
---
 indra/newview/llvoavatar.cpp | 35 +++++++++++++++++++++++++++++------
 indra/newview/llvoavatar.h   |  3 +++
 2 files changed, 32 insertions(+), 6 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp
index 4a179146f8..04356e6507 100644
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -126,6 +126,9 @@ const F32 MIN_HOVER_Z = -2.0;
 const F32 MIN_ATTACHMENT_COMPLEXITY = 0.f;
 const F32 DEFAULT_MAX_ATTACHMENT_COMPLEXITY = 1.0e6f;
 
+const F32 FIRST_APPEARANCE_CLOUD_MIN_DELAY = 3.f; // seconds
+const F32 FIRST_APPEARANCE_CLOUD_MAX_DELAY = 45.f;
+
 using namespace LLAvatarAppearanceDefines;
 
 //-----------------------------------------------------------------------------
@@ -667,6 +670,7 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id,
 	mVisuallyMuteSetting(AV_RENDER_NORMALLY),
 	mMutedAVColor(LLColor4::white /* used for "uninitialize" */),
 	mFirstFullyVisible(TRUE),
+	mFirstUseDelaySeconds(FIRST_APPEARANCE_CLOUD_MIN_DELAY),
 	mFullyLoaded(FALSE),
 	mPreviousFullyLoaded(FALSE),
 	mFullyLoadedInitialized(FALSE),
@@ -741,7 +745,7 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id,
 
 	mCurrentGesticulationLevel = 0;
 
-    
+	mFirstSeenTimer.reset();
 	mRuthTimer.reset();
 	mRuthDebugTimer.reset();
 	mDebugExistenceTimer.reset();
@@ -8126,16 +8130,35 @@ void LLVOAvatar::updateRuthTimer(bool loading)
 BOOL LLVOAvatar::processFullyLoadedChange(bool loading)
 {
 	// We wait a little bit before giving the 'all clear', to let things to
-	// settle down (models to snap into place, textures to get first packets)
+	// settle down (models to snap into place, textures to get first packets).
+    // And if viewer isn't aware of some parts yet, this gives them a chance
+    // to arrive.
 	const F32 LOADED_DELAY = 1.f;
-	const F32 FIRST_USE_DELAY = 3.f;
 
-	if (loading)
-		mFullyLoadedTimer.reset();
+    if (loading)
+    {
+        mFullyLoadedTimer.reset();
+    }
 
 	if (mFirstFullyVisible)
 	{
-		mFullyLoaded = (mFullyLoadedTimer.getElapsedTimeF32() > FIRST_USE_DELAY);
+        if (!isSelf() && loading)
+        {
+                // Note that textures can causes 60s delay on thier own
+                // so this delay might end up on top of textures' delay
+                mFirstUseDelaySeconds = llclamp(
+                    mFirstSeenTimer.getElapsedTimeF32(),
+                    FIRST_APPEARANCE_CLOUD_MIN_DELAY,
+                    FIRST_APPEARANCE_CLOUD_MAX_DELAY);
+
+                if (shouldImpostor())
+                {
+                    // Impostors are less of a priority,
+                    // let them stay cloud longer
+                    mFirstUseDelaySeconds *= 1.25;
+                }
+        }
+		mFullyLoaded = (mFullyLoadedTimer.getElapsedTimeF32() > mFirstUseDelaySeconds);
 	}
 	else
 	{
diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h
index 7042406091..aeac23ad92 100644
--- a/indra/newview/llvoavatar.h
+++ b/indra/newview/llvoavatar.h
@@ -376,6 +376,9 @@ protected:
 
 private:
 	BOOL			mFirstFullyVisible;
+	F32				mFirstUseDelaySeconds;
+	LLFrameTimer	mFirstSeenTimer;
+
 	BOOL			mFullyLoaded;
 	BOOL			mPreviousFullyLoaded;
 	BOOL			mFullyLoadedInitialized;
-- 
cgit v1.2.3


From 1acd92c30c88a9718385f29a558b77bd20588764 Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Tue, 14 Sep 2021 22:43:17 +0300
Subject: SL-15993 Disabling transparent water should not disable advanced
 lighting

---
 indra/newview/llappviewer.cpp         |  2 +-
 indra/newview/lldrawpoolwater.cpp     | 13 +++++++++++++
 indra/newview/llfloaterpreference.cpp |  6 ------
 indra/newview/llviewercontrol.cpp     |  1 -
 indra/newview/llviewershadermgr.cpp   |  2 +-
 indra/newview/pipeline.cpp            |  1 -
 6 files changed, 15 insertions(+), 10 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 02b4dd57f1..93e5c2e341 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -579,7 +579,7 @@ static void settings_modify()
 	LLRenderTarget::sUseFBO				= gSavedSettings.getBOOL("RenderDeferred");
 	LLPipeline::sRenderTransparentWater	= gSavedSettings.getBOOL("RenderTransparentWater");
 	LLPipeline::sRenderBump				= gSavedSettings.getBOOL("RenderObjectBump");
-	LLPipeline::sRenderDeferred		= LLPipeline::sRenderTransparentWater && LLPipeline::sRenderBump && gSavedSettings.getBOOL("RenderDeferred");
+	LLPipeline::sRenderDeferred		= 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;
diff --git a/indra/newview/lldrawpoolwater.cpp b/indra/newview/lldrawpoolwater.cpp
index 5f9e623b4c..2f3c52ecd2 100644
--- a/indra/newview/lldrawpoolwater.cpp
+++ b/indra/newview/lldrawpoolwater.cpp
@@ -137,6 +137,14 @@ void LLDrawPoolWater::endPostDeferredPass(S32 pass)
 void LLDrawPoolWater::renderDeferred(S32 pass)
 {
 	LL_RECORD_BLOCK_TIME(FTM_RENDER_WATER);
+
+    if (!LLPipeline::sRenderTransparentWater)
+    {
+        // Will render opaque water without use of ALM
+        render(pass);
+        return;
+    }
+
 	deferred_render = TRUE;
 	shade();
 	deferred_render = FALSE;
@@ -340,6 +348,11 @@ void LLDrawPoolWater::renderOpaqueLegacyWater()
     LL_PROFILE_ZONE_SCOPED;
     LLVOSky *voskyp = gSky.mVOSkyp;
 
+    if (voskyp == NULL)
+    {
+        return;
+    }
+
 	LLGLSLShader* shader = NULL;
 	if (LLGLSLShader::sNoFixedFunction)
 	{
diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp
index 6bf2136f60..92e64d0b95 100644
--- a/indra/newview/llfloaterpreference.cpp
+++ b/indra/newview/llfloaterpreference.cpp
@@ -1198,11 +1198,9 @@ void LLFloaterPreference::refreshEnabledState()
 
 	//Deferred/SSAO/Shadows
 	BOOL bumpshiny = gGLManager.mHasCubeMap && LLCubeMap::sUseCubeMaps && LLFeatureManager::getInstance()->isFeatureAvailable("RenderObjectBump") && gSavedSettings.getBOOL("RenderObjectBump");
-	BOOL transparent_water = LLFeatureManager::getInstance()->isFeatureAvailable("RenderTransparentWater") && gSavedSettings.getBOOL("RenderTransparentWater");
 	BOOL shaders = gSavedSettings.getBOOL("WindLightUseAtmosShaders");
 	BOOL enabled = LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferred") &&
 						bumpshiny &&
-						transparent_water &&
 						shaders && 
 						gGLManager.mHasFramebufferObject &&
 						gSavedSettings.getBOOL("RenderAvatarVP") &&
@@ -1226,9 +1224,6 @@ void LLFloaterPreferenceGraphicsAdvanced::refreshEnabledState()
 	ctrl_reflections->setEnabled(reflections);
 	reflections_text->setEnabled(reflections);
 
-    // Transparent Water
-    LLCheckBoxCtrl* transparent_water_ctrl = getChild<LLCheckBoxCtrl>("TransparentWater");
-
 	// Bump & Shiny	
 	LLCheckBoxCtrl* bumpshiny_ctrl = getChild<LLCheckBoxCtrl>("BumpShiny");
 	bool bumpshiny = gGLManager.mHasCubeMap && LLCubeMap::sUseCubeMaps && LLFeatureManager::getInstance()->isFeatureAvailable("RenderObjectBump");
@@ -1279,7 +1274,6 @@ void LLFloaterPreferenceGraphicsAdvanced::refreshEnabledState()
     
     BOOL enabled = LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferred") &&
                         ((bumpshiny_ctrl && bumpshiny_ctrl->get()) ? TRUE : FALSE) &&
-                        ((transparent_water_ctrl && transparent_water_ctrl->get()) ? TRUE : FALSE) &&
                         gGLManager.mHasFramebufferObject &&
                         gSavedSettings.getBOOL("RenderAvatarVP") &&
                         (ctrl_wind_light->get()) ? TRUE : FALSE;
diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp
index 0e64d7152a..e5ebbcb9ab 100644
--- a/indra/newview/llviewercontrol.cpp
+++ b/indra/newview/llviewercontrol.cpp
@@ -187,7 +187,6 @@ static bool handleRenderPerfTestChanged(const LLSD& newvalue)
 
 bool handleRenderTransparentWaterChanged(const LLSD& newvalue)
 {
-	LLRenderTarget::sUseFBO = newvalue.asBoolean();
 	if (gPipeline.isInit())
 	{
 		gPipeline.updateRenderTransparentWater();
diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp
index 7dcf29eb75..1b6d8210c3 100644
--- a/indra/newview/llviewershadermgr.cpp
+++ b/indra/newview/llviewershadermgr.cpp
@@ -424,7 +424,7 @@ void LLViewerShaderMgr::setShaders()
     initAttribsAndUniforms();
     gPipeline.releaseGLBuffers();
 
-    LLPipeline::sWaterReflections = gGLManager.mHasCubeMap;
+    LLPipeline::sWaterReflections = gGLManager.mHasCubeMap && LLPipeline::sRenderTransparentWater;
     LLPipeline::sRenderGlow = gSavedSettings.getBOOL("RenderGlow"); 
     LLPipeline::updateRenderDeferred();
     
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index e23aeb286c..586e5b7c2d 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -1047,7 +1047,6 @@ void LLPipeline::updateRenderDeferred()
                       RenderDeferred &&
                       LLRenderTarget::sUseFBO &&
                       LLPipeline::sRenderBump &&
-                      LLPipeline::sRenderTransparentWater &&
                       RenderAvatarVP &&
                       WindLightUseAtmosShaders &&
                       (bool) LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferred");
-- 
cgit v1.2.3


From 176b2acdacd2703eea15584f8e763abfc50f6266 Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Thu, 23 Sep 2021 22:38:30 +0300
Subject: SL-11678 Avatar is reflecting on the under side of water surface

Avatar wasn't reflecting but distorting, since avatar was already under water it looked like a 'reflection' of avatar, but was not rotated right and with wrong angle.
---
 indra/newview/pipeline.cpp | 8 +-------
 1 file changed, 1 insertion(+), 7 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index 586e5b7c2d..de95eb1a87 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -9428,19 +9428,13 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in)
 
                 //clip out geometry on the same side of water as the camera w/ enough margin to not include the water geo itself,
                 // but not so much as to clip out parts of avatars that should be seen under the water in the distortion map
-                LLPlane plane(-pnorm, water_dist);
+                LLPlane plane(-pnorm, camera_is_underwater ? -water_height : water_dist);
                 LLGLUserClipPlane clip_plane(plane, saved_modelview, saved_projection);
 
                 gGL.setColorMask(true, true);
                 mWaterDis.clear();
                 gGL.setColorMask(true, false);
 
-                // ignore clip plane if we're underwater and viewing distortion map of objects above waterline
-                if (camera_is_underwater)
-                {
-                    clip_plane.disable();
-                }
-
                 if (reflection_detail >= WATER_REFLECT_NONE_WATER_TRANSPARENT)
                 {
                     updateCull(camera, mRefractedObjects, water_clip, &plane);
-- 
cgit v1.2.3


From 53cf740d874f376f212a5d706ca70cbf35fee259 Mon Sep 17 00:00:00 2001
From: Nat Goodspeed <nat@lindenlab.com>
Date: Fri, 19 Nov 2021 14:42:49 -0500
Subject: SL-16094: Service mainloop WorkQueue every LLAppViewer::idle() call

even if idle() exits early.
---
 indra/newview/llappviewer.cpp | 28 ++++++++++++++--------------
 1 file changed, 14 insertions(+), 14 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 93e5c2e341..e7f104d6fd 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -4854,6 +4854,20 @@ void LLAppViewer::idle()
 	LLDirPickerThread::clearDead();
 	F32 dt_raw = idle_timer.getElapsedTimeAndResetF32();
 
+	// Service the WorkQueue we use for replies from worker threads.
+	// Use function statics for the timeslice setting so we only have to fetch
+	// and convert MainWorkTime once.
+	static F32 MainWorkTimeRaw = gSavedSettings.getF32("MainWorkTime");
+	static F32Milliseconds MainWorkTimeMs(MainWorkTimeRaw);
+	// MainWorkTime is specified in fractional milliseconds, but std::chrono
+	// uses integer representations. What if we want less than a microsecond?
+	// Use nanoseconds. We're very sure we will never need to specify a
+	// MainWorkTime that would be larger than we could express in
+	// std::chrono::nanoseconds.
+	static std::chrono::nanoseconds MainWorkTimeNanoSec{
+		std::chrono::nanoseconds::rep(MainWorkTimeMs.value() * 1000000)};
+	gMainloopWork.runFor(MainWorkTimeNanoSec);
+
 	// Cap out-of-control frame times
 	// Too low because in menus, swapping, debugger, etc.
 	// Too high because idle called with no objects in view, etc.
@@ -5226,20 +5240,6 @@ void LLAppViewer::idle()
 		}
 	}
 
-	// Service the WorkQueue we use for replies from worker threads.
-	// Use function statics for the timeslice setting so we only have to fetch
-	// and convert MainWorkTime once.
-	static F32 MainWorkTimeRaw = gSavedSettings.getF32("MainWorkTime");
-	static F32Milliseconds MainWorkTimeMs(MainWorkTimeRaw);
-	// MainWorkTime is specified in fractional milliseconds, but std::chrono
-	// uses integer representations. What if we want less than a microsecond?
-	// Use nanoseconds. We're very sure we will never need to specify a
-	// MainWorkTime that would be larger than we could express in
-	// std::chrono::nanoseconds.
-	static std::chrono::nanoseconds MainWorkTimeNanoSec{
-		std::chrono::nanoseconds::rep(MainWorkTimeMs.value() * 1000000)};
-	gMainloopWork.runFor(MainWorkTimeNanoSec);
-
 	// Handle shutdown process, for example,
 	// wait for floaters to close, send quit message,
 	// forcibly quit if it has taken too long
-- 
cgit v1.2.3


From 106d52c6ee9b10dd7a7baca3b09a01073c61949d Mon Sep 17 00:00:00 2001
From: Nat Goodspeed <nat@lindenlab.com>
Date: Thu, 4 Nov 2021 16:40:05 -0400
Subject: SL-16202: Instantiate LLSimpleton::sInstance generically

instead of requiring a separate declaration for each subclass.

The previous way produces errors in clang.

(cherry picked from commit 8458ad8890cf0a11804996210d7bcfbdaa3eec2e)
---
 indra/llcommon/llsingleton.h         | 3 +++
 indra/llui/llviewereventrecorder.cpp | 2 --
 indra/newview/llenvironment.cpp      | 1 -
 indra/newview/llselectmgr.cpp        | 2 --
 indra/newview/llviewercamera.cpp     | 2 --
 indra/newview/llworld.cpp            | 2 --
 6 files changed, 3 insertions(+), 9 deletions(-)

(limited to 'indra')

diff --git a/indra/llcommon/llsingleton.h b/indra/llcommon/llsingleton.h
index 10a8ecfedb..24d01812c9 100644
--- a/indra/llcommon/llsingleton.h
+++ b/indra/llcommon/llsingleton.h
@@ -865,4 +865,7 @@ public:
     }
 };
 
+template <class T>
+T* LLSimpleton<T>::sInstance{ nullptr };
+
 #endif
diff --git a/indra/llui/llviewereventrecorder.cpp b/indra/llui/llviewereventrecorder.cpp
index 5a44ec947a..cb000aef74 100644
--- a/indra/llui/llviewereventrecorder.cpp
+++ b/indra/llui/llviewereventrecorder.cpp
@@ -28,8 +28,6 @@
 #include "llui.h"
 #include "llleap.h"
 
-LLViewerEventRecorder* LLSimpleton<LLViewerEventRecorder>::sInstance = nullptr;
-
 LLViewerEventRecorder::LLViewerEventRecorder() {
 
   clear(UNDEFINED);
diff --git a/indra/newview/llenvironment.cpp b/indra/newview/llenvironment.cpp
index 0b914f07ab..4bec7fa111 100644
--- a/indra/newview/llenvironment.cpp
+++ b/indra/newview/llenvironment.cpp
@@ -824,7 +824,6 @@ std::string env_selection_to_string(LLEnvironment::EnvSelection_t sel)
 #undef RTNENUM
 }
 
-LLEnvironment* LLSimpleton<LLEnvironment>::sInstance = nullptr;
 //-------------------------------------------------------------------------
 LLEnvironment::LLEnvironment():
     mCloudScrollDelta(),
diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp
index e7670b5a73..6f136e50e0 100644
--- a/indra/newview/llselectmgr.cpp
+++ b/indra/newview/llselectmgr.cpp
@@ -97,8 +97,6 @@
 #include "llglheaders.h"
 #include "llinventoryobserver.h"
 
-LLSelectMgr* LLSimpleton<LLSelectMgr>::sInstance = nullptr;
-
 LLViewerObject* getSelectedParentObject(LLViewerObject *object) ;
 //
 // Consts
diff --git a/indra/newview/llviewercamera.cpp b/indra/newview/llviewercamera.cpp
index 5ebce115f6..5d8e80cc41 100644
--- a/indra/newview/llviewercamera.cpp
+++ b/indra/newview/llviewercamera.cpp
@@ -54,8 +54,6 @@
 // System includes
 #include <iomanip> // for setprecision
 
-LLViewerCamera* LLSimpleton<LLViewerCamera>::sInstance = nullptr;
-
 LLTrace::CountStatHandle<> LLViewerCamera::sVelocityStat("camera_velocity");
 LLTrace::CountStatHandle<> LLViewerCamera::sAngularVelocityStat("camera_angular_velocity");
 
diff --git a/indra/newview/llworld.cpp b/indra/newview/llworld.cpp
index 4cb63d0ab8..d5cce6a52a 100644
--- a/indra/newview/llworld.cpp
+++ b/indra/newview/llworld.cpp
@@ -62,8 +62,6 @@
 #include <cstring>
 
 
-LLWorld* LLSimpleton<LLWorld>::sInstance = nullptr;
-
 //
 // Globals
 //
-- 
cgit v1.2.3


From f997bcd186d00e30132f32be007bb3978bf3a8f5 Mon Sep 17 00:00:00 2001
From: Nat Goodspeed <nat@lindenlab.com>
Date: Thu, 11 Nov 2021 10:23:16 -0500
Subject: SL-16094: Stylish braces!

(cherry picked from commit 18de6c9b989cc7060f2a314f5b68cc102677823b)
---
 indra/llcommon/llsingleton.h | 7 +++++++
 1 file changed, 7 insertions(+)

(limited to 'indra')

diff --git a/indra/llcommon/llsingleton.h b/indra/llcommon/llsingleton.h
index 24d01812c9..da2d6fd984 100644
--- a/indra/llcommon/llsingleton.h
+++ b/indra/llcommon/llsingleton.h
@@ -859,9 +859,16 @@ public:
     static inline T& instance() { return *getInstance(); }
     static inline bool instanceExists() { return sInstance != nullptr; }
 
+<<<<<<< HEAD
     static void deleteSingleton() { 
         delete sInstance; 
         sInstance = nullptr; 
+=======
+    static void deleteSingleton()
+    {
+        delete sInstance;
+        sInstance = nullptr;
+>>>>>>> 18de6c9b98 (SL-16094: Stylish braces!)
     }
 };
 
-- 
cgit v1.2.3


From 3171aaad9b1f2757f8b0d8cbb784a45a7bbebafa Mon Sep 17 00:00:00 2001
From: Nat Goodspeed <nat@lindenlab.com>
Date: Fri, 19 Nov 2021 14:57:36 -0500
Subject: SL-16094: fix merge glitch

---
 indra/llcommon/llsingleton.h | 6 ------
 1 file changed, 6 deletions(-)

(limited to 'indra')

diff --git a/indra/llcommon/llsingleton.h b/indra/llcommon/llsingleton.h
index da2d6fd984..f85f961287 100644
--- a/indra/llcommon/llsingleton.h
+++ b/indra/llcommon/llsingleton.h
@@ -859,16 +859,10 @@ public:
     static inline T& instance() { return *getInstance(); }
     static inline bool instanceExists() { return sInstance != nullptr; }
 
-<<<<<<< HEAD
-    static void deleteSingleton() { 
-        delete sInstance; 
-        sInstance = nullptr; 
-=======
     static void deleteSingleton()
     {
         delete sInstance;
         sInstance = nullptr;
->>>>>>> 18de6c9b98 (SL-16094: Stylish braces!)
     }
 };
 
-- 
cgit v1.2.3


From 28f9fb06a9f4cb9edccb2ff8132c7f6a9b27c060 Mon Sep 17 00:00:00 2001
From: Dave Parks <davep@lindenlab.com>
Date: Sat, 20 Nov 2021 18:49:19 +0000
Subject: SL-16289 Rigged mesh rendering overhaul

---
 indra/llmath/llmatrix4a.h                          |    9 +-
 indra/llprimitive/llmodel.cpp                      |   35 +
 indra/llprimitive/llmodel.h                        |    3 +
 indra/llrender/llglslshader.cpp                    |   13 +
 indra/llrender/llglslshader.h                      |    8 +-
 indra/llrender/llrender.cpp                        |    2 +-
 indra/llrender/llshadermgr.cpp                     |    5 +-
 indra/llrender/llshadermgr.h                       |    2 +-
 indra/llwindow/llwindowwin32.cpp                   |    2 +-
 indra/llxml/llcontrol.h                            |    1 +
 indra/newview/app_settings/settings.xml            |   24 +-
 .../shaders/class1/deferred/alphaV.glsl            |    4 +-
 .../shaders/class1/deferred/bumpSkinnedV.glsl      |   64 -
 .../shaders/class1/deferred/bumpV.glsl             |   22 +-
 .../shaders/class1/deferred/diffuseSkinnedV.glsl   |   59 -
 .../shaders/class1/deferred/diffuseV.glsl          |   20 +-
 .../shaders/class1/deferred/fullbrightShinyV.glsl  |   18 +-
 .../shaders/class1/deferred/fullbrightV.glsl       |   13 +-
 .../class1/deferred/shadowAlphaMaskSkinnedV.glsl   |   70 +
 .../shaders/class1/deferred/shadowSkinnedV.glsl    |   52 +
 .../class1/deferred/treeShadowSkinnedV.glsl        |   53 +
 .../shaders/class1/interface/debugSkinnedV.glsl    |   41 +
 .../class1/interface/occlusionSkinnedV.glsl        |   40 +
 .../shaders/class1/lighting/lightFullbrightF.glsl  |    1 +
 .../app_settings/shaders/class1/objects/bumpV.glsl |   13 +
 .../shaders/class1/objects/emissiveSkinnedV.glsl   |   56 -
 .../shaders/class1/objects/emissiveV.glsl          |   20 +-
 .../class1/objects/fullbrightShinySkinnedV.glsl    |   71 -
 .../shaders/class1/objects/fullbrightShinyV.glsl   |   17 +-
 .../shaders/class1/objects/fullbrightSkinnedV.glsl |   57 -
 .../shaders/class1/objects/fullbrightV.glsl        |   17 +-
 .../class1/objects/shinySimpleSkinnedV.glsl        |   66 -
 .../shaders/class1/objects/shinyV.glsl             |   20 +-
 .../shaders/class1/objects/simpleSkinnedV.glsl     |   65 -
 .../shaders/class1/objects/simpleV.glsl            |   18 +-
 indra/newview/llappviewer.cpp                      |    5 +
 indra/newview/lldrawable.cpp                       |   15 -
 indra/newview/lldrawpool.cpp                       |  119 +-
 indra/newview/lldrawpool.h                         |   41 +-
 indra/newview/lldrawpoolalpha.cpp                  |  391 ++--
 indra/newview/lldrawpoolalpha.h                    |   22 +-
 indra/newview/lldrawpoolavatar.cpp                 | 2023 ++------------------
 indra/newview/lldrawpoolavatar.h                   |  202 +-
 indra/newview/lldrawpoolbump.cpp                   |  309 ++-
 indra/newview/lldrawpoolbump.h                     |    7 +-
 indra/newview/lldrawpoolmaterials.cpp              |   66 +-
 indra/newview/lldrawpoolmaterials.h                |   18 +-
 indra/newview/lldrawpoolsimple.cpp                 |  511 ++---
 indra/newview/lldrawpoolsimple.h                   |   33 +-
 indra/newview/llface.cpp                           |  133 +-
 indra/newview/llface.h                             |   10 +-
 indra/newview/llmeshrepository.cpp                 |    2 +-
 indra/newview/llspatialpartition.cpp               |   25 +-
 indra/newview/llspatialpartition.h                 |   21 +-
 indra/newview/llviewerdisplay.cpp                  |    7 +-
 indra/newview/llviewershadermgr.cpp                | 1245 +++++-------
 indra/newview/llviewershadermgr.h                  |   25 -
 indra/newview/llvoavatar.cpp                       |   49 +
 indra/newview/llvoavatar.h                         |   23 +
 indra/newview/llvovolume.cpp                       |  470 +++--
 indra/newview/pipeline.cpp                         |  462 +++--
 indra/newview/pipeline.h                           |   35 +-
 62 files changed, 2690 insertions(+), 4560 deletions(-)
 delete mode 100644 indra/newview/app_settings/shaders/class1/deferred/bumpSkinnedV.glsl
 delete mode 100644 indra/newview/app_settings/shaders/class1/deferred/diffuseSkinnedV.glsl
 create mode 100644 indra/newview/app_settings/shaders/class1/deferred/shadowAlphaMaskSkinnedV.glsl
 create mode 100644 indra/newview/app_settings/shaders/class1/deferred/shadowSkinnedV.glsl
 create mode 100644 indra/newview/app_settings/shaders/class1/deferred/treeShadowSkinnedV.glsl
 create mode 100644 indra/newview/app_settings/shaders/class1/interface/debugSkinnedV.glsl
 create mode 100644 indra/newview/app_settings/shaders/class1/interface/occlusionSkinnedV.glsl
 delete mode 100644 indra/newview/app_settings/shaders/class1/objects/emissiveSkinnedV.glsl
 delete mode 100644 indra/newview/app_settings/shaders/class1/objects/fullbrightShinySkinnedV.glsl
 delete mode 100644 indra/newview/app_settings/shaders/class1/objects/fullbrightSkinnedV.glsl
 delete mode 100644 indra/newview/app_settings/shaders/class1/objects/shinySimpleSkinnedV.glsl
 delete mode 100644 indra/newview/app_settings/shaders/class1/objects/simpleSkinnedV.glsl

(limited to 'indra')

diff --git a/indra/llmath/llmatrix4a.h b/indra/llmath/llmatrix4a.h
index 5291a05607..2cf50e9cd2 100644
--- a/indra/llmath/llmatrix4a.h
+++ b/indra/llmath/llmatrix4a.h
@@ -78,8 +78,15 @@ public:
 		mMatrix[1] = _mm_loadu_ps(src.mMatrix[1]);
 		mMatrix[2] = _mm_loadu_ps(src.mMatrix[2]);
 		mMatrix[3] = _mm_loadu_ps(src.mMatrix[3]);
-		
 	}
+    
+    inline void loadu(const F32* src)
+    {
+        mMatrix[0] = _mm_loadu_ps(src);
+        mMatrix[1] = _mm_loadu_ps(src+4);
+        mMatrix[2] = _mm_loadu_ps(src+8);
+        mMatrix[3] = _mm_loadu_ps(src+12);
+    }
 
 	inline void loadu(const LLMatrix3& src)
 	{
diff --git a/indra/llprimitive/llmodel.cpp b/indra/llprimitive/llmodel.cpp
index a23b991f1d..dd37b8ce0b 100644
--- a/indra/llprimitive/llmodel.cpp
+++ b/indra/llprimitive/llmodel.cpp
@@ -31,6 +31,7 @@
 #include "llconvexdecomposition.h"
 #include "llsdserialize.h"
 #include "llvector4a.h"
+#include "llmd5.h"
 
 #ifdef LL_USESYSTEMLIBS
 # include <zlib.h>
@@ -1451,6 +1452,8 @@ void LLMeshSkinInfo::fromLLSD(LLSD& skin)
 	{
 		mLockScaleIfJointPosition = false;
 	}
+
+    updateHash();
 }
 
 LLSD LLMeshSkinInfo::asLLSD(bool include_joints, bool lock_scale_if_joint_position) const
@@ -1502,6 +1505,38 @@ LLSD LLMeshSkinInfo::asLLSD(bool include_joints, bool lock_scale_if_joint_positi
 	return ret;
 }
 
+void LLMeshSkinInfo::updateHash()
+{
+    //  get hash of data relevant to render batches
+    LLMD5 hash;
+
+    //mJointNames
+    for (auto& name : mJointNames)
+    {
+        hash.update(name);
+    }
+    
+    //mJointNums 
+    hash.update((U8*)&(mJointNums[0]), sizeof(S32) * mJointNums.size());
+    
+    //mInvBindMatrix
+    F32* src = mInvBindMatrix[0].getF32ptr();
+    
+    for (int i = 0; i < mInvBindMatrix.size() * 16; ++i)
+    {
+        S32 t = llround(src[i] * 10000.f);
+        hash.update((U8*)&t, sizeof(S32));
+    }
+    //hash.update((U8*)&(mInvBindMatrix[0]), sizeof(LLMatrix4a) * mInvBindMatrix.size());
+
+    hash.finalize();
+
+    U64 digest[2];
+    hash.raw_digest((U8*) digest);
+
+    mHash = digest[0];
+}
+
 LLModel::Decomposition::Decomposition(LLSD& data)
 {
 	fromLLSD(data);
diff --git a/indra/llprimitive/llmodel.h b/indra/llprimitive/llmodel.h
index cd2b6c6728..2d27592bc8 100644
--- a/indra/llprimitive/llmodel.h
+++ b/indra/llprimitive/llmodel.h
@@ -49,6 +49,7 @@ public:
 	LLMeshSkinInfo(LLSD& data);
 	void fromLLSD(LLSD& data);
 	LLSD asLLSD(bool include_joints, bool lock_scale_if_joint_position) const;
+    void updateHash();
 
 	LLUUID mMeshID;
 	std::vector<std::string> mJointNames;
@@ -58,10 +59,12 @@ public:
 	matrix_list_t mAlternateBindMatrix;
 
 	LL_ALIGN_16(LLMatrix4a mBindShapeMatrix);
+
 	float mPelvisOffset;
     bool mLockScaleIfJointPosition;
     bool mInvalidJointsScrubbed;
     bool mJointNumsInitialized;
+    U64 mHash = 0;
 } LL_ALIGN_POSTFIX(16);
 
 LL_ALIGN_PREFIX(16)
diff --git a/indra/llrender/llglslshader.cpp b/indra/llrender/llglslshader.cpp
index 08c9dd8769..2f1ce0eec9 100644
--- a/indra/llrender/llglslshader.cpp
+++ b/indra/llrender/llglslshader.cpp
@@ -970,6 +970,19 @@ void LLGLSLShader::bind()
     }
 }
 
+void LLGLSLShader::bind(bool rigged)
+{
+    if (rigged)
+    {
+        llassert(mRiggedVariant);
+        mRiggedVariant->bind();
+    }
+    else
+    {
+        bind();
+    }
+}
+
 void LLGLSLShader::unbind()
 {
     LL_PROFILE_ZONE_SCOPED;
diff --git a/indra/llrender/llglslshader.h b/indra/llrender/llglslshader.h
index 3b23cf1b28..6fdb789087 100644
--- a/indra/llrender/llglslshader.h
+++ b/indra/llrender/llglslshader.h
@@ -230,6 +230,8 @@ public:
 	
     BOOL link(BOOL suppress_errors = FALSE);
 	void bind();
+    //helper to conditionally bind mRiggedVariant instead of this
+    void bind(bool rigged);
 	void unbind();
 
 	// Unbinds any previously bound shader by explicitly binding no shader.
@@ -267,7 +269,8 @@ public:
 	LLShaderFeatures mFeatures;
 	std::vector< std::pair< std::string, GLenum > > mShaderFiles;
 	std::string mName;
-	boost::unordered_map<std::string, std::string> mDefines;
+    typedef std::unordered_map<std::string, std::string> defines_map_t;
+	defines_map_t mDefines;
 
 	//statistcis for profiling shader performance
 	U32 mTimerQuery;
@@ -285,6 +288,9 @@ public:
 	std::vector<U32> mTextureMagFilter;
 	std::vector<U32> mTextureMinFilter;
 
+    // this pointer should be set to whichever shader represents this shader's rigged variant
+    LLGLSLShader* mRiggedVariant = nullptr;
+
 private:
 	void unloadInternal();
 };
diff --git a/indra/llrender/llrender.cpp b/indra/llrender/llrender.cpp
index aad04beea2..0c180ed50d 100644
--- a/indra/llrender/llrender.cpp
+++ b/indra/llrender/llrender.cpp
@@ -1283,7 +1283,7 @@ void LLRender::syncLightState()
 
 void LLRender::syncMatrices()
 {
-	static const U32 name[] = 
+    static const U32 name[] = 
 	{
 		LLShaderMgr::MODELVIEW_MATRIX,
 		LLShaderMgr::PROJECTION_MATRIX,
diff --git a/indra/llrender/llshadermgr.cpp b/indra/llrender/llshadermgr.cpp
index e8c6295930..a9a4314afa 100644
--- a/indra/llrender/llshadermgr.cpp
+++ b/indra/llrender/llshadermgr.cpp
@@ -165,6 +165,7 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader)
 
 	if (features->hasObjectSkinning)
 	{
+        shader->mRiggedVariant = shader;
         if (!shader->attachVertexObject("avatar/objectSkinV.glsl"))
 		{
 			return FALSE;
@@ -599,7 +600,7 @@ void LLShaderMgr::dumpObjectLog(GLhandleARB ret, BOOL warns, const std::string&
 	}
  }
 
-GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shader_level, GLenum type, boost::unordered_map<std::string, std::string>* defines, S32 texture_index_channels)
+GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shader_level, GLenum type, std::unordered_map<std::string, std::string>* defines, S32 texture_index_channels)
 {
 
 // endsure work-around for missing GLSL funcs gets propogated to feature shader files (e.g. srgbF.glsl)
@@ -774,7 +775,7 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade
 	
 	if (defines)
 	{
-		for (boost::unordered_map<std::string,std::string>::iterator iter = defines->begin(); iter != defines->end(); ++iter)
+		for (std::unordered_map<std::string,std::string>::iterator iter = defines->begin(); iter != defines->end(); ++iter)
 		{
 			std::string define = "#define " + iter->first + " " + iter->second + "\n";
 			extra_code_text[extra_code_count++] = (GLcharARB *) strdup(define.c_str());
diff --git a/indra/llrender/llshadermgr.h b/indra/llrender/llshadermgr.h
index 3908efd4ec..67c0d6ab10 100644
--- a/indra/llrender/llshadermgr.h
+++ b/indra/llrender/llshadermgr.h
@@ -264,7 +264,7 @@ public:
     void dumpShaderSource(U32 shader_code_count, GLcharARB** shader_code_text);
 	BOOL	linkProgramObject(GLhandleARB obj, BOOL suppress_errors = FALSE);
 	BOOL	validateProgramObject(GLhandleARB obj);
-	GLhandleARB loadShaderFile(const std::string& filename, S32 & shader_level, GLenum type, boost::unordered_map<std::string, std::string>* defines = NULL, S32 texture_index_channels = -1);
+	GLhandleARB loadShaderFile(const std::string& filename, S32 & shader_level, GLenum type, std::unordered_map<std::string, std::string>* defines = NULL, S32 texture_index_channels = -1);
 
 	// Implemented in the application to actually point to the shader directory.
 	virtual std::string getShaderDirPrefix(void) = 0; // Pure Virtual
diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp
index e52624d66a..485d332068 100644
--- a/indra/llwindow/llwindowwin32.cpp
+++ b/indra/llwindow/llwindowwin32.cpp
@@ -1833,7 +1833,7 @@ void* LLWindowWin32::createSharedContext()
     S32 attribs[] =
     {
         WGL_CONTEXT_MAJOR_VERSION_ARB, 4,
-        WGL_CONTEXT_MINOR_VERSION_ARB, 2,
+        WGL_CONTEXT_MINOR_VERSION_ARB, 6,
         WGL_CONTEXT_PROFILE_MASK_ARB,  LLRender::sGLCoreProfile ? WGL_CONTEXT_CORE_PROFILE_BIT_ARB : WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB,
         WGL_CONTEXT_FLAGS_ARB, gDebugGL ? WGL_CONTEXT_DEBUG_BIT_ARB : 0,
         0
diff --git a/indra/llxml/llcontrol.h b/indra/llxml/llcontrol.h
index 5da13f5010..088502c017 100644
--- a/indra/llxml/llcontrol.h
+++ b/indra/llxml/llcontrol.h
@@ -247,6 +247,7 @@ public:
 	// generic getter
 	template<typename T> T get(const std::string& name)
 	{
+        LL_PROFILE_ZONE_SCOPED;
 		LLControlVariable* control = getControl(name);
 		LLSD value;
 		eControlType type = TYPE_COUNT;
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 144323bb11..2d821b7451 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -8649,28 +8649,6 @@
     </array>
   </map>
 
-    <key>RenderAlphaBatchFullbrights</key>
-    <map>
-      <key>Comment</key>
-      <string>Render fullbright alpha content more efficiently, but with possible visual differences from prev viewers.</string>
-      <key>Persist</key>
-      <integer>1</integer>
-      <key>Type</key>
-      <string>Boolean</string>
-      <key>Value</key>
-      <integer>0</integer>
-    </map>
-    <key>RenderAlphaBatchEmissives</key>
-    <map>
-      <key>Comment</key>
-      <string>Render emissive alpha content more efficiently, but with possible visual differences from prev viewers.</string>
-      <key>Persist</key>
-      <integer>1</integer>
-      <key>Type</key>
-      <string>Boolean</string>
-      <key>Value</key>
-      <integer>1</integer>
-    </map>
     <key>RenderAnisotropic</key>
     <map>
       <key>Comment</key>
@@ -10145,7 +10123,7 @@
       <key>Type</key>
       <string>S32</string>
       <key>Value</key>
-      <integer>512</integer>
+      <integer>4096</integer>
     </map>
     <key>RenderNameFadeDuration</key>
     <map>
diff --git a/indra/newview/app_settings/shaders/class1/deferred/alphaV.glsl b/indra/newview/app_settings/shaders/class1/deferred/alphaV.glsl
index 506118d381..6a93bc2fd2 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/alphaV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/alphaV.glsl
@@ -105,9 +105,9 @@ void main()
 	vec4 vert = vec4(position.xyz, 1.0);
 	pos = (modelview_matrix * vert);
 	gl_Position = modelview_projection_matrix*vec4(position.xyz, 1.0);
-#endif
+#endif //IS_AVATAR_SKIN
 	
-#endif
+#endif // HAS_SKIN
 
 #ifdef USE_INDEXED_TEX
 	passTextureIndex();
diff --git a/indra/newview/app_settings/shaders/class1/deferred/bumpSkinnedV.glsl b/indra/newview/app_settings/shaders/class1/deferred/bumpSkinnedV.glsl
deleted file mode 100644
index 10144f3e16..0000000000
--- a/indra/newview/app_settings/shaders/class1/deferred/bumpSkinnedV.glsl
+++ /dev/null
@@ -1,64 +0,0 @@
-/** 
- * @file bumpV.glsl
- * $LicenseInfo:firstyear=2007&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2007, Linden Research, Inc.
- * 
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- * 
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
- * $/LicenseInfo$
- */
-
-uniform mat4 projection_matrix;
-uniform mat4 texture_matrix0;
-uniform mat4 modelview_matrix;
-
-ATTRIBUTE vec3 position;
-ATTRIBUTE vec4 diffuse_color;
-ATTRIBUTE vec3 normal;
-ATTRIBUTE vec2 texcoord0;
-ATTRIBUTE vec4 tangent;
-
-VARYING vec3 vary_mat0;
-VARYING vec3 vary_mat1;
-VARYING vec3 vary_mat2;
-VARYING vec4 vertex_color;
-VARYING vec2 vary_texcoord0;
-
-mat4 getObjectSkinnedTransform();
-
-void main()
-{
-	vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy;
-	
-	mat4 mat = getObjectSkinnedTransform();
-	
-	mat = modelview_matrix * mat;
-	
-	vec3 pos = (mat*vec4(position.xyz, 1.0)).xyz;
-	
-	
-	vec3 n = normalize((mat * vec4(normal.xyz+position.xyz, 1.0)).xyz-pos.xyz);
-	vec3 t = normalize((mat * vec4(tangent.xyz+position.xyz, 1.0)).xyz-pos.xyz);
-	vec3 b = cross(n, t) * tangent.w;
-	
-	vary_mat0 = vec3(t.x, b.x, n.x);
-	vary_mat1 = vec3(t.y, b.y, n.y);
-	vary_mat2 = vec3(t.z, b.z, n.z);
-	
-	gl_Position = projection_matrix*vec4(pos, 1.0);
-	vertex_color = diffuse_color;
-}
diff --git a/indra/newview/app_settings/shaders/class1/deferred/bumpV.glsl b/indra/newview/app_settings/shaders/class1/deferred/bumpV.glsl
index 9f9749394e..d90891aa20 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/bumpV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/bumpV.glsl
@@ -39,16 +39,32 @@ VARYING vec3 vary_mat2;
 VARYING vec4 vertex_color;
 VARYING vec2 vary_texcoord0;
 
+#ifdef HAS_SKIN
+mat4 getObjectSkinnedTransform();
+uniform mat4 projection_matrix;
+uniform mat4 modelview_matrix;
+#endif
+
 void main()
 {
 	//transform vertex
+#ifdef HAS_SKIN
+    mat4 mat = getObjectSkinnedTransform();
+	mat = modelview_matrix * mat;
+	vec3 pos = (mat*vec4(position.xyz, 1.0)).xyz;
+	gl_Position = projection_matrix*vec4(pos, 1.0);
+
+	vec3 n = normalize((mat * vec4(normal.xyz+position.xyz, 1.0)).xyz-pos.xyz);
+	vec3 t = normalize((mat * vec4(tangent.xyz+position.xyz, 1.0)).xyz-pos.xyz);
+#else
 	gl_Position = modelview_projection_matrix * vec4(position.xyz, 1.0); 
-	vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy;
-	
 	vec3 n = normalize(normal_matrix * normal);
 	vec3 t = normalize(normal_matrix * tangent.xyz);
+#endif
+
 	vec3 b = cross(n, t) * tangent.w;
-	
+	vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy;
+
 	vary_mat0 = vec3(t.x, b.x, n.x);
 	vary_mat1 = vec3(t.y, b.y, n.y);
 	vary_mat2 = vec3(t.z, b.z, n.z);
diff --git a/indra/newview/app_settings/shaders/class1/deferred/diffuseSkinnedV.glsl b/indra/newview/app_settings/shaders/class1/deferred/diffuseSkinnedV.glsl
deleted file mode 100644
index 2487110624..0000000000
--- a/indra/newview/app_settings/shaders/class1/deferred/diffuseSkinnedV.glsl
+++ /dev/null
@@ -1,59 +0,0 @@
-/** 
- * @file diffuseSkinnedV.glsl
- * $LicenseInfo:firstyear=2007&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2007, Linden Research, Inc.
- * 
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- * 
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
- * $/LicenseInfo$
- */
-
-uniform mat4 projection_matrix;
-uniform mat4 texture_matrix0;
-uniform mat4 modelview_matrix;
-
-ATTRIBUTE vec3 position;
-ATTRIBUTE vec4 diffuse_color;
-ATTRIBUTE vec3 normal;
-ATTRIBUTE vec2 texcoord0;
-
-VARYING vec3 vary_normal;
-VARYING vec4 vertex_color;
-VARYING vec2 vary_texcoord0;
-
-mat4 getObjectSkinnedTransform();
-
-void main()
-{
-	vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy;
-		
-	mat4 mat = getObjectSkinnedTransform();
-	
-	mat = modelview_matrix * mat;
-	vec3 pos = (mat*vec4(position.xyz, 1.0)).xyz;
-	
-	vec4 norm = vec4(position.xyz, 1.0);
-	norm.xyz += normal.xyz;
-	norm.xyz = (mat*norm).xyz;
-	norm.xyz = normalize(norm.xyz-pos.xyz);
-
-	vary_normal = norm.xyz;
-			
-	vertex_color = diffuse_color;
-	
-	gl_Position = projection_matrix*vec4(pos, 1.0);
-}
diff --git a/indra/newview/app_settings/shaders/class1/deferred/diffuseV.glsl b/indra/newview/app_settings/shaders/class1/deferred/diffuseV.glsl
index 3c026796c8..d64bcefade 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/diffuseV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/diffuseV.glsl
@@ -39,14 +39,28 @@ VARYING vec2 vary_texcoord0;
 
 void passTextureIndex();
 
+#ifdef HAS_SKIN
+mat4 getObjectSkinnedTransform();
+uniform mat4 projection_matrix;
+uniform mat4 modelview_matrix;
+#endif
+
 void main()
 {
-	//transform vertex
+#ifdef HAS_SKIN
+    mat4 mat = getObjectSkinnedTransform();
+    mat = modelview_matrix * mat;
+    vec4 pos = mat * vec4(position.xyz, 1.0);
+    gl_Position = projection_matrix * pos;
+    vary_normal = normalize((mat*vec4(normal.xyz+position.xyz,1.0)).xyz-pos.xyz);
+#else
 	gl_Position = modelview_projection_matrix * vec4(position.xyz, 1.0); 
+    vary_normal = normalize(normal_matrix * normal);
+#endif
+	
 	vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy;
 	
 	passTextureIndex();
-	vary_normal = normalize(normal_matrix * normal);
-	
+
 	vertex_color = diffuse_color;
 }
diff --git a/indra/newview/app_settings/shaders/class1/deferred/fullbrightShinyV.glsl b/indra/newview/app_settings/shaders/class1/deferred/fullbrightShinyV.glsl
index 8f6eb79668..2c139430e7 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/fullbrightShinyV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/fullbrightShinyV.glsl
@@ -25,7 +25,6 @@
 
 uniform mat3 normal_matrix;
 uniform mat4 texture_matrix0;
-uniform mat4 texture_matrix1;
 uniform mat4 modelview_matrix;
 uniform mat4 modelview_projection_matrix;
 
@@ -47,19 +46,32 @@ VARYING vec2 vary_texcoord0;
 VARYING vec3 vary_texcoord1;
 VARYING vec4 vary_position;
 
+#ifdef HAS_SKIN
+mat4 getObjectSkinnedTransform();
+uniform mat4 projection_matrix;
+#endif
+
 void main()
 {
 	//transform vertex
 	vec4 vert = vec4(position.xyz,1.0);
 	passTextureIndex();
+
+#ifdef HAS_SKIN
+    mat4 mat = getObjectSkinnedTransform();
+    mat = modelview_matrix * mat;
+    vec4 pos = mat * vert;
+    vary_position = gl_Position = projection_matrix * pos;
+	vec3 norm = normalize((mat*vec4(normal.xyz+position.xyz,1.0)).xyz-pos.xyz);
+#else
 	vec4 pos = (modelview_matrix * vert);
 	vary_position = gl_Position = modelview_projection_matrix*vec4(position.xyz, 1.0);
-	
 	vec3 norm = normalize(normal_matrix * normal);
+#endif
 	vec3 ref = reflect(pos.xyz, -norm);
 
 	vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy;
-	vary_texcoord1 = (texture_matrix1*vec4(ref,1.0)).xyz;
+	vary_texcoord1 = transpose(normal_matrix) * ref.xyz;
 
 	calcAtmospherics(pos.xyz);
 
diff --git a/indra/newview/app_settings/shaders/class1/deferred/fullbrightV.glsl b/indra/newview/app_settings/shaders/class1/deferred/fullbrightV.glsl
index bdf3546aa5..e71636f2c9 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/fullbrightV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/fullbrightV.glsl
@@ -45,15 +45,26 @@ VARYING vec3 vary_position;
 VARYING vec4 vertex_color;
 VARYING vec2 vary_texcoord0;
 
+#ifdef HAS_SKIN
+mat4 getObjectSkinnedTransform();
+uniform mat4 projection_matrix;
+#endif
 
 void main()
 {
 	//transform vertex
 	vec4 vert = vec4(position.xyz, 1.0);
-	vec4 pos = (modelview_matrix * vert);
 	passTextureIndex();
 
+#ifdef HAS_SKIN
+    mat4 mat = getObjectSkinnedTransform();
+    mat = modelview_matrix * mat;
+    vec4 pos = mat * vert;
+    gl_Position = projection_matrix * pos;
+#else
+	vec4 pos = (modelview_matrix * vert);
 	gl_Position = modelview_projection_matrix*vec4(position.xyz, 1.0);
+#endif
 
 #ifdef WATER_FOG
 	vary_position = pos.xyz;
diff --git a/indra/newview/app_settings/shaders/class1/deferred/shadowAlphaMaskSkinnedV.glsl b/indra/newview/app_settings/shaders/class1/deferred/shadowAlphaMaskSkinnedV.glsl
new file mode 100644
index 0000000000..2b17aea75a
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/deferred/shadowAlphaMaskSkinnedV.glsl
@@ -0,0 +1,70 @@
+/** 
+ * @file shadowAlphaMaskSkinnedV.glsl
+ *
+ * $LicenseInfo:firstyear=2021&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2011, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+uniform mat4 texture_matrix0;
+uniform mat4 modelview_matrix;
+uniform mat4 projection_matrix;
+uniform float shadow_target_width;
+
+ATTRIBUTE vec3 position;
+ATTRIBUTE vec4 diffuse_color;
+ATTRIBUTE vec2 texcoord0;
+
+VARYING vec4 post_pos;
+VARYING float target_pos_x;
+VARYING vec4 vertex_color;
+VARYING vec2 vary_texcoord0;
+
+void passTextureIndex();
+
+mat4 getObjectSkinnedTransform();
+
+void main()
+{
+	//transform vertex
+	vec4 pre_pos = vec4(position.xyz, 1.0);
+
+	mat4 mat = getObjectSkinnedTransform();
+	
+	mat = modelview_matrix * mat;
+	
+	vec4 pos = mat * pre_pos;
+	pos = projection_matrix * pos;
+
+	target_pos_x = 0.5 * (shadow_target_width - 1.0) * pos.x;
+
+	post_pos = pos;
+
+#if !defined(DEPTH_CLAMP)
+	gl_Position = vec4(pos.x, pos.y, pos.w*0.5, pos.w);
+#else
+	gl_Position = pos;
+#endif
+	
+	passTextureIndex();
+
+	vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy;
+	vertex_color = diffuse_color;
+}
diff --git a/indra/newview/app_settings/shaders/class1/deferred/shadowSkinnedV.glsl b/indra/newview/app_settings/shaders/class1/deferred/shadowSkinnedV.glsl
new file mode 100644
index 0000000000..bdf8e0854d
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/deferred/shadowSkinnedV.glsl
@@ -0,0 +1,52 @@
+/** 
+ * @file shadowSkinnedV.glsl
+ *
+ * $LicenseInfo:firstyear=2021&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2007, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+uniform mat4 modelview_matrix;
+uniform mat4 projection_matrix;
+
+ATTRIBUTE vec3 position;
+
+VARYING vec4 post_pos;
+
+mat4 getObjectSkinnedTransform();
+
+void main()
+{
+	//transform vertex
+	mat4 mat = getObjectSkinnedTransform();
+	
+	mat = modelview_matrix * mat;
+	vec4 pos = (mat*vec4(position.xyz, 1.0));
+	pos = projection_matrix*pos;
+
+	post_pos = pos;
+
+#if !defined(DEPTH_CLAMP)
+	gl_Position = vec4(pos.x, pos.y, pos.w*0.5, pos.w);
+#else
+	gl_Position = pos;
+#endif
+
+}
diff --git a/indra/newview/app_settings/shaders/class1/deferred/treeShadowSkinnedV.glsl b/indra/newview/app_settings/shaders/class1/deferred/treeShadowSkinnedV.glsl
new file mode 100644
index 0000000000..d9ca6d3a46
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/deferred/treeShadowSkinnedV.glsl
@@ -0,0 +1,53 @@
+/** 
+ * @file treeShadowV.glsl
+ *
+  * $LicenseInfo:firstyear=2007&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2007, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+uniform mat4 texture_matrix0;
+uniform mat4 modelview_matrix;
+uniform mat4 projection_matrix;
+ 
+ATTRIBUTE vec3 position;
+ATTRIBUTE vec2 texcoord0;
+
+VARYING vec4 post_pos;
+VARYING vec2 vary_texcoord0;
+
+mat4 getObjectSkinnedTransform();
+
+void main()
+{
+	//transform vertex
+    mat4 mat = getObjectSkinnedTransform();
+	
+	mat = modelview_matrix * mat;
+	
+	vec4 pos = mat * vec4(position.xyz, 1.0);
+    pos = projection_matrix * pos;
+	
+	post_pos = pos;
+	
+	gl_Position = vec4(pos.x, pos.y, pos.w*0.5, pos.w);
+	
+	vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy;
+}
diff --git a/indra/newview/app_settings/shaders/class1/interface/debugSkinnedV.glsl b/indra/newview/app_settings/shaders/class1/interface/debugSkinnedV.glsl
new file mode 100644
index 0000000000..74f22aec4f
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/interface/debugSkinnedV.glsl
@@ -0,0 +1,41 @@
+/** 
+ * @file debugSkinnedV.glsl
+ *
+ * $LicenseInfo:firstyear=2021&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2011, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+uniform mat4 projection_matrix;
+uniform mat4 modelview_matrix;
+
+mat4 getObjectSkinnedTransform();
+
+ATTRIBUTE vec3 position;
+
+void main()
+{
+    mat4 mat = getObjectSkinnedTransform();
+    mat = modelview_matrix * mat;
+    vec3 pos = (mat*vec4(position.xyz, 1.0)).xyz;
+
+    gl_Position = projection_matrix*vec4(pos, 1.0);
+}
+
diff --git a/indra/newview/app_settings/shaders/class1/interface/occlusionSkinnedV.glsl b/indra/newview/app_settings/shaders/class1/interface/occlusionSkinnedV.glsl
new file mode 100644
index 0000000000..7305065a05
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/interface/occlusionSkinnedV.glsl
@@ -0,0 +1,40 @@
+/** 
+ * @file occlusionSkinnedV.glsl
+ *
+ * $LicenseInfo:firstyear=2021&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2007, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+uniform mat4 projection_matrix;
+uniform mat4 modelview_matrix;
+
+ATTRIBUTE vec3 position;
+
+mat4 getObjectSkinnedTransform();
+
+void main()
+{
+	mat4 mat = getObjectSkinnedTransform();
+	mat = modelview_matrix * mat;
+	vec3 pos = (mat*vec4(position.xyz, 1.0)).xyz;
+	gl_Position = projection_matrix*vec4(pos, 1.0);
+}
+
diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightF.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightF.glsl
index 5fcdf3107c..89be8195f0 100644
--- a/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightF.glsl
+++ b/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightF.glsl
@@ -56,5 +56,6 @@ void fullbright_lighting()
 	color.rgb = pow(color.rgb, vec3(1.0/texture_gamma));
 
 	frag_color = color;
+
 }
 
diff --git a/indra/newview/app_settings/shaders/class1/objects/bumpV.glsl b/indra/newview/app_settings/shaders/class1/objects/bumpV.glsl
index a7738087dc..ee9970bc70 100644
--- a/indra/newview/app_settings/shaders/class1/objects/bumpV.glsl
+++ b/indra/newview/app_settings/shaders/class1/objects/bumpV.glsl
@@ -33,10 +33,23 @@ ATTRIBUTE vec2 texcoord1;
 VARYING vec2 vary_texcoord0;
 VARYING vec2 vary_texcoord1;
 
+#ifdef HAS_SKIN
+mat4 getObjectSkinnedTransform();
+uniform mat4 projection_matrix;
+uniform mat4 modelview_matrix;
+#endif
+
 void main()
 {
 	//transform vertex
+#ifdef HAS_SKIN
+    mat4 mat = getObjectSkinnedTransform();
+    mat = modelview_matrix * mat;
+    vec4 pos = mat * vec4(position.xyz, 1.0);
+    gl_Position = projection_matrix * pos;
+#else
 	gl_Position = modelview_projection_matrix*vec4(position.xyz, 1.0);
+#endif
 	vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy;
 	vary_texcoord1 = (texture_matrix0 * vec4(texcoord1,0,1)).xy;
 }
diff --git a/indra/newview/app_settings/shaders/class1/objects/emissiveSkinnedV.glsl b/indra/newview/app_settings/shaders/class1/objects/emissiveSkinnedV.glsl
deleted file mode 100644
index 9064904191..0000000000
--- a/indra/newview/app_settings/shaders/class1/objects/emissiveSkinnedV.glsl
+++ /dev/null
@@ -1,56 +0,0 @@
-/** 
- * @file emissiveSkinnedV.glsl
- *
- * $LicenseInfo:firstyear=2007&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2007, Linden Research, Inc.
- * 
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- * 
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
- * $/LicenseInfo$
- */
-
-uniform mat4 projection_matrix;
-uniform mat4 texture_matrix0;
-uniform mat4 modelview_matrix;
-
-ATTRIBUTE vec3 position;
-ATTRIBUTE vec4 emissive;
-ATTRIBUTE vec2 texcoord0;
-
-VARYING vec4 vertex_color;
-VARYING vec2 vary_texcoord0;
-
-
-void calcAtmospherics(vec3 inPositionEye);
-mat4 getObjectSkinnedTransform();
-
-void main()
-{
-	//transform vertex
-	vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy;
-	
-	mat4 mat = getObjectSkinnedTransform();
-	
-	mat = modelview_matrix * mat;
-	vec3 pos = (mat*vec4(position.xyz, 1.0)).xyz;
-	
-	vertex_color = emissive;
-
-	calcAtmospherics(pos.xyz);
-
-	gl_Position = projection_matrix*vec4(pos, 1.0);
-}
diff --git a/indra/newview/app_settings/shaders/class1/objects/emissiveV.glsl b/indra/newview/app_settings/shaders/class1/objects/emissiveV.glsl
index e984deb0c8..d762239e51 100644
--- a/indra/newview/app_settings/shaders/class1/objects/emissiveV.glsl
+++ b/indra/newview/app_settings/shaders/class1/objects/emissiveV.glsl
@@ -37,20 +37,30 @@ VARYING vec2 vary_texcoord0;
 
 void calcAtmospherics(vec3 inPositionEye);
 
-
-
+#ifdef HAS_SKIN
+mat4 getObjectSkinnedTransform();
+uniform mat4 projection_matrix;
+#endif
 
 void main()
 {
 	//transform vertex
 	passTextureIndex();
+
+#ifdef HAS_SKIN
+    mat4 mat = getObjectSkinnedTransform();
+    mat = modelview_matrix * mat;
+
+    vec4 pos = mat * vec4(position.xyz, 1.0);
+    gl_Position = projection_matrix * pos;
+#else
 	gl_Position = modelview_projection_matrix * vec4(position.xyz, 1.0);
+    vec4 pos = (modelview_matrix * vec4(position.xyz, 1.0));
+#endif
 	vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy;
 	
-	vec4 pos = (modelview_matrix * vec4(position.xyz, 1.0));
+	
 	calcAtmospherics(pos.xyz);
 
 	vertex_color = emissive;
-
-	
 }
diff --git a/indra/newview/app_settings/shaders/class1/objects/fullbrightShinySkinnedV.glsl b/indra/newview/app_settings/shaders/class1/objects/fullbrightShinySkinnedV.glsl
deleted file mode 100644
index 1e244d9dfd..0000000000
--- a/indra/newview/app_settings/shaders/class1/objects/fullbrightShinySkinnedV.glsl
+++ /dev/null
@@ -1,71 +0,0 @@
-/** 
- * @file shinySimpleSkinnedV.glsl
- * $LicenseInfo:firstyear=2007&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2007, Linden Research, Inc.
- * 
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- * 
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
- * $/LicenseInfo$
- */
-
-uniform mat4 texture_matrix0;
-uniform mat4 texture_matrix1;
-uniform mat4 modelview_matrix;
-uniform mat4 projection_matrix;
-
-ATTRIBUTE vec3 position;
-ATTRIBUTE vec3 normal;
-ATTRIBUTE vec4 diffuse_color;
-ATTRIBUTE vec2 texcoord0;
-
-VARYING vec4 vertex_color;
-VARYING vec2 vary_texcoord0;
-VARYING vec3 vary_texcoord1;
-VARYING vec4 vary_position;
-
-
-void calcAtmospherics(vec3 inPositionEye);
-mat4 getObjectSkinnedTransform();
-
-void main()
-{
-	mat4 mat = getObjectSkinnedTransform();
-	
-	mat = modelview_matrix * mat;
-	vec3 pos = (mat*vec4(position.xyz, 1.0)).xyz;
-
-    mat4 mvp = modelview_matrix * projection_matrix;
-    vary_position = mvp * vec4(position, 1.0);
-	
-	vec4 norm = vec4(position.xyz, 1.0);
-	norm.xyz += normal.xyz;
-	norm.xyz = (mat*norm).xyz;
-	norm.xyz = normalize(norm.xyz-pos.xyz);
-		
-	vec3 ref = reflect(pos.xyz, -norm.xyz);
-
-	vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy;
-	vary_texcoord1 = (texture_matrix1*vec4(ref,1.0)).xyz;
-
-	calcAtmospherics(pos.xyz);
-
-	vertex_color = diffuse_color;
-	
-	gl_Position = projection_matrix*vec4(pos, 1.0);
-	
-	
-}
diff --git a/indra/newview/app_settings/shaders/class1/objects/fullbrightShinyV.glsl b/indra/newview/app_settings/shaders/class1/objects/fullbrightShinyV.glsl
index 34bd8d445a..ace2574ac2 100644
--- a/indra/newview/app_settings/shaders/class1/objects/fullbrightShinyV.glsl
+++ b/indra/newview/app_settings/shaders/class1/objects/fullbrightShinyV.glsl
@@ -25,7 +25,6 @@
 
 uniform mat3 normal_matrix;
 uniform mat4 texture_matrix0;
-uniform mat4 texture_matrix1;
 uniform mat4 modelview_matrix;
 uniform mat4 modelview_projection_matrix;
 
@@ -46,20 +45,32 @@ VARYING vec4 vertex_color;
 VARYING vec2 vary_texcoord0;
 VARYING vec3 vary_texcoord1;
 
+#ifdef HAS_SKIN
+mat4 getObjectSkinnedTransform();
+uniform mat4 projection_matrix;
+#endif
 
 void main()
 {
 	//transform vertex
 	vec4 vert = vec4(position.xyz,1.0);
 	passTextureIndex();
+
+#ifdef HAS_SKIN
+    mat4 mat = getObjectSkinnedTransform();
+    mat = modelview_matrix * mat;
+    vec4 pos = mat * vert;
+    gl_Position = projection_matrix * pos;
+	vec3 norm = normalize((mat*vec4(normal.xyz+position.xyz,1.0)).xyz-pos.xyz);
+#else
 	vec4 pos = (modelview_matrix * vert);
 	gl_Position = modelview_projection_matrix*vec4(position.xyz, 1.0);
-	
 	vec3 norm = normalize(normal_matrix * normal);
+#endif
 	vec3 ref = reflect(pos.xyz, -norm);
 
 	vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy;
-	vary_texcoord1 = (texture_matrix1*vec4(ref,1.0)).xyz;
+	vary_texcoord1 = transpose(normal_matrix) * ref;
 
 	calcAtmospherics(pos.xyz);
 
diff --git a/indra/newview/app_settings/shaders/class1/objects/fullbrightSkinnedV.glsl b/indra/newview/app_settings/shaders/class1/objects/fullbrightSkinnedV.glsl
deleted file mode 100644
index eff75435a9..0000000000
--- a/indra/newview/app_settings/shaders/class1/objects/fullbrightSkinnedV.glsl
+++ /dev/null
@@ -1,57 +0,0 @@
-/** 
- * @file fullbrightSkinnedV.glsl
- * $LicenseInfo:firstyear=2007&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2007, Linden Research, Inc.
- * 
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- * 
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
- * $/LicenseInfo$
- */
-
-uniform mat4 projection_matrix;
-uniform mat4 texture_matrix0;
-uniform mat4 modelview_matrix;
-
-ATTRIBUTE vec3 position;
-ATTRIBUTE vec4 diffuse_color;
-ATTRIBUTE vec2 texcoord0;
-
-void calcAtmospherics(vec3 inPositionEye);
-mat4 getObjectSkinnedTransform();
-
-VARYING vec4 vertex_color;
-VARYING vec2 vary_texcoord0;
-
-
-void main()
-{
-	//transform vertex
-	vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy;
-	
-	mat4 mat = getObjectSkinnedTransform();
-	
-	mat = modelview_matrix * mat;
-	vec3 pos = (mat*vec4(position.xyz, 1.0)).xyz;
-	
-	calcAtmospherics(pos.xyz);
-
-	vertex_color = diffuse_color;
-	
-	gl_Position = projection_matrix*vec4(pos, 1.0);
-		
-	
-}
diff --git a/indra/newview/app_settings/shaders/class1/objects/fullbrightV.glsl b/indra/newview/app_settings/shaders/class1/objects/fullbrightV.glsl
index fc20d3270e..5af42f1fcf 100644
--- a/indra/newview/app_settings/shaders/class1/objects/fullbrightV.glsl
+++ b/indra/newview/app_settings/shaders/class1/objects/fullbrightV.glsl
@@ -33,26 +33,33 @@ ATTRIBUTE vec2 texcoord0;
 ATTRIBUTE vec3 normal;
 ATTRIBUTE vec4 diffuse_color;
 
-
 void calcAtmospherics(vec3 inPositionEye);
 
-
 VARYING vec4 vertex_color;
 VARYING vec2 vary_texcoord0;
 
+#ifdef HAS_SKIN
+mat4 getObjectSkinnedTransform();
+uniform mat4 projection_matrix;
+#endif
 
 void main()
 {
 	//transform vertex
 	vec4 vert = vec4(position.xyz,1.0);
 	passTextureIndex();
-	vec4 pos = (modelview_matrix * vert);
+#ifdef HAS_SKIN
+    mat4 mat = getObjectSkinnedTransform();
+    mat = modelview_matrix * mat;
+    vec4 pos = mat * vert;
+    gl_Position = projection_matrix * pos;
+#else
+    vec4 pos = (modelview_matrix * vert);
 	gl_Position = modelview_projection_matrix*vec4(position.xyz, 1.0);
+#endif
 	vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy;
 	
 	calcAtmospherics(pos.xyz);
 
 	vertex_color = diffuse_color;
-
-	
 }
diff --git a/indra/newview/app_settings/shaders/class1/objects/shinySimpleSkinnedV.glsl b/indra/newview/app_settings/shaders/class1/objects/shinySimpleSkinnedV.glsl
deleted file mode 100644
index 727bae19c0..0000000000
--- a/indra/newview/app_settings/shaders/class1/objects/shinySimpleSkinnedV.glsl
+++ /dev/null
@@ -1,66 +0,0 @@
-/** 
- * @file shinySimpleSkinnedV.glsl
- * $LicenseInfo:firstyear=2007&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2007, Linden Research, Inc.
- * 
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- * 
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
- * $/LicenseInfo$
- */
-
-uniform mat4 projection_matrix;
-uniform mat4 texture_matrix0;
-uniform mat4 texture_matrix1;
-uniform mat4 modelview_matrix;
-
-ATTRIBUTE vec3 position;
-ATTRIBUTE vec3 normal;
-ATTRIBUTE vec4 diffuse_color;
-ATTRIBUTE vec2 texcoord0;
-
-VARYING vec4 vertex_color;
-VARYING vec2 vary_texcoord0;
-VARYING vec3 vary_texcoord1;
-
-vec4 calcLighting(vec3 pos, vec3 norm, vec4 color);
-void calcAtmospherics(vec3 inPositionEye);
-mat4 getObjectSkinnedTransform();
-
-void main()
-{
-	mat4 mat = getObjectSkinnedTransform();
-	
-	mat = modelview_matrix * mat;
-	vec3 pos = (mat*vec4(position.xyz, 1.0)).xyz;
-	
-	vec4 norm = vec4(position.xyz, 1.0);
-	norm.xyz += normal.xyz;
-	norm.xyz = (mat*norm).xyz;
-	norm.xyz = normalize(norm.xyz-pos.xyz);
-		
-	vec3 ref = reflect(pos.xyz, -norm.xyz);
-
-	vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy;
-	vary_texcoord1 = (texture_matrix1*vec4(ref,1.0)).xyz;
-
-	calcAtmospherics(pos.xyz);
-
-	vec4 color = calcLighting(pos.xyz, norm.xyz, diffuse_color);
-	vertex_color = color;
-	
-	gl_Position = projection_matrix*vec4(pos, 1.0);
-}
diff --git a/indra/newview/app_settings/shaders/class1/objects/shinyV.glsl b/indra/newview/app_settings/shaders/class1/objects/shinyV.glsl
index 4ba8194d03..097e42d233 100644
--- a/indra/newview/app_settings/shaders/class1/objects/shinyV.glsl
+++ b/indra/newview/app_settings/shaders/class1/objects/shinyV.glsl
@@ -25,7 +25,6 @@
 
 uniform mat3 normal_matrix;
 uniform mat4 texture_matrix0;
-uniform mat4 texture_matrix1;
 uniform mat4 modelview_matrix;
 uniform mat4 modelview_projection_matrix;
 
@@ -45,19 +44,32 @@ void calcAtmospherics(vec3 inPositionEye);
 
 uniform vec4 origin;
 
+#ifdef HAS_SKIN
+mat4 getObjectSkinnedTransform();
+uniform mat4 projection_matrix;
+#endif
+
 void main()
 {
 	//transform vertex
 	vec4 vert = vec4(position.xyz,1.0);
 	passTextureIndex();
+
+#ifdef HAS_SKIN
+    mat4 mat = getObjectSkinnedTransform();
+    mat = modelview_matrix * mat;
+    vec4 pos = mat * vert;
+    gl_Position = projection_matrix * pos;
+	vec3 norm = normalize((mat*vec4(normal.xyz+position.xyz,1.0)).xyz-pos.xyz);
+#else
 	vec4 pos = (modelview_matrix * vert);
 	gl_Position = modelview_projection_matrix*vec4(position.xyz, 1.0);
-		
 	vec3 norm = normalize(normal_matrix * normal);
+#endif
 	vec3 ref = reflect(pos.xyz, -norm);
 
-	vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy;
-	vary_texcoord1 = (texture_matrix1*vec4(ref,1.0)).xyz;
+	vary_texcoord0 = (texture_matrix0*vec4(texcoord0,0,1)).xy;
+	vary_texcoord1 = transpose(normal_matrix) * ref;
 
 	calcAtmospherics(pos.xyz);
 
diff --git a/indra/newview/app_settings/shaders/class1/objects/simpleSkinnedV.glsl b/indra/newview/app_settings/shaders/class1/objects/simpleSkinnedV.glsl
deleted file mode 100644
index df31b5a79f..0000000000
--- a/indra/newview/app_settings/shaders/class1/objects/simpleSkinnedV.glsl
+++ /dev/null
@@ -1,65 +0,0 @@
-/** 
- * @file simpleSkinnedV.glsl
- * $LicenseInfo:firstyear=2007&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2007, Linden Research, Inc.
- * 
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- * 
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
- * $/LicenseInfo$
- */
-
-uniform mat4 texture_matrix0;
-uniform mat4 modelview_matrix;
-uniform mat4 projection_matrix;
-
-ATTRIBUTE vec3 position;
-ATTRIBUTE vec3 normal;
-ATTRIBUTE vec4 diffuse_color;
-ATTRIBUTE vec2 texcoord0;
-
-VARYING vec4 vertex_color;
-VARYING vec2 vary_texcoord0;
-
-
-vec4 calcLighting(vec3 pos, vec3 norm, vec4 color);
-void calcAtmospherics(vec3 inPositionEye);
-mat4 getObjectSkinnedTransform();
-
-void main()
-{
-	//transform vertex
-	vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy;
-	
-	mat4 mat = getObjectSkinnedTransform();
-	
-	mat = modelview_matrix * mat;
-	vec3 pos = (mat*vec4(position.xyz, 1.0)).xyz;
-	
-	vec4 norm = vec4(position.xyz, 1.0);
-	norm.xyz += normal.xyz;
-	norm.xyz = (mat*norm).xyz;
-	norm.xyz = normalize(norm.xyz-pos.xyz);
-		
-	calcAtmospherics(pos.xyz);
-
-	vec4 color = calcLighting(pos.xyz, norm.xyz, diffuse_color);
-	vertex_color = color;
-	
-	gl_Position = projection_matrix*vec4(pos, 1.0);
-	
-	
-}
diff --git a/indra/newview/app_settings/shaders/class1/objects/simpleV.glsl b/indra/newview/app_settings/shaders/class1/objects/simpleV.glsl
index 9ef7704b70..2025174f7d 100644
--- a/indra/newview/app_settings/shaders/class1/objects/simpleV.glsl
+++ b/indra/newview/app_settings/shaders/class1/objects/simpleV.glsl
@@ -44,12 +44,16 @@ void calcAtmospherics(vec3 inPositionEye);
 VARYING vec4 vertex_color;
 VARYING vec2 vary_texcoord0;
 
+#ifdef HAS_SKIN
+mat4 getObjectSkinnedTransform();
+uniform mat4 projection_matrix;
+#endif
+
 
 void main()
 {
 	//transform vertex
 	vec4 vert = vec4(position.xyz,1.0);
-	gl_Position = modelview_projection_matrix*vec4(position.xyz, 1.0);
 
 	passTextureIndex();
 	vary_texcoord0 = (texture_matrix0 * vec4(texcoord0, 0, 1)).xy;
@@ -58,11 +62,23 @@ void main()
 	if (no_atmo == 1)
 	{
 		vertex_color = diffuse_color;
+        gl_Position = modelview_projection_matrix*vec4(position.xyz, 1.0);
 	}
 	else
 	{
+#ifdef HAS_SKIN
+        mat4 mat = getObjectSkinnedTransform();
+        mat = modelview_matrix * mat;
+
+        vec4 pos = mat * vert;
+        vec3 norm = normalize((mat*vec4(normal.xyz+vert.xyz,1.0)).xyz-pos.xyz);
+
+        gl_Position = projection_matrix * pos;
+#else
 		vec4 pos = (modelview_matrix * vert);
 		vec3 norm = normalize(normal_matrix * normal);
+        gl_Position = modelview_projection_matrix*vec4(position.xyz, 1.0);
+#endif
 
 		calcAtmospherics(pos.xyz);
 
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 52ef2966ce..177558d38f 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -1430,6 +1430,11 @@ bool LLAppViewer::doFrame()
 {
 	LL_RECORD_BLOCK_TIME(FTM_FRAME);
 
+    if (!LLWorld::instanceExists())
+    {
+        LLWorld::createInstance();
+    }
+
 	LLEventPump& mainloop(LLEventPumps::instance().obtain("mainloop"));
 	LLSD newFrame;
 
diff --git a/indra/newview/lldrawable.cpp b/indra/newview/lldrawable.cpp
index 502ebbd4b1..7e99b99284 100644
--- a/indra/newview/lldrawable.cpp
+++ b/indra/newview/lldrawable.cpp
@@ -149,21 +149,6 @@ void LLDrawable::unload()
 {
 	LLVOVolume *pVVol = getVOVolume();
 	pVVol->setNoLOD();
-
-	for (S32 i = 0; i < getNumFaces(); i++)
-	{
-		LLFace* facep = getFace(i);
-		if (facep->isState(LLFace::RIGGED))
-		{
-			LLDrawPoolAvatar* pool = (LLDrawPoolAvatar*)facep->getPool();
-			if (pool) {
-				pool->removeRiggedFace(facep);
-			}
-			facep->setVertexBuffer(NULL);
-		}
-		facep->clearState(LLFace::RIGGED);
-	}
-
 	pVVol->markForUpdate(TRUE);
 }
 
diff --git a/indra/newview/lldrawpool.cpp b/indra/newview/lldrawpool.cpp
index 3e4f97e494..92a9bed504 100644
--- a/indra/newview/lldrawpool.cpp
+++ b/indra/newview/lldrawpool.cpp
@@ -50,6 +50,9 @@
 #include "lldrawpoolwlsky.h"
 #include "llglslshader.h"
 #include "llglcommonfunc.h"
+#include "llvoavatar.h"
+#include "llviewershadermgr.h"
+
 
 S32 LLDrawPool::sNumDrawPools = 0;
 
@@ -385,21 +388,43 @@ LLRenderPass::~LLRenderPass()
 }
 
 void LLRenderPass::renderGroup(LLSpatialGroup* group, U32 type, U32 mask, BOOL texture)
-{					
+{
+    LL_PROFILE_ZONE_SCOPED;
 	LLSpatialGroup::drawmap_elem_t& draw_info = group->mDrawMap[type];
 	
 	for (LLSpatialGroup::drawmap_elem_t::iterator k = draw_info.begin(); k != draw_info.end(); ++k)	
 	{
 		LLDrawInfo *pparams = *k;
-		if (pparams) {
+		if (pparams) 
+        {
 			pushBatch(*pparams, mask, texture);
 		}
 	}
 }
 
-void LLRenderPass::renderTexture(U32 type, U32 mask, BOOL batch_textures)
+void LLRenderPass::renderRiggedGroup(LLSpatialGroup* group, U32 type, U32 mask, BOOL texture)
 {
-	pushBatches(type, mask, true, batch_textures);
+    LL_PROFILE_ZONE_SCOPED;
+    LLSpatialGroup::drawmap_elem_t& draw_info = group->mDrawMap[type];
+    LLVOAvatar* lastAvatar = nullptr;
+    U64 lastMeshId = 0;
+    mask |= LLVertexBuffer::MAP_WEIGHT4;
+
+    for (LLSpatialGroup::drawmap_elem_t::iterator k = draw_info.begin(); k != draw_info.end(); ++k)
+    {
+        LLDrawInfo* pparams = *k;
+        if (pparams) 
+        {
+            if (lastAvatar != pparams->mAvatar || lastMeshId != pparams->mSkinInfo->mHash)
+            {
+                uploadMatrixPalette(*pparams);
+                lastAvatar = pparams->mAvatar;
+                lastMeshId = pparams->mSkinInfo->mHash;
+            }
+
+            pushBatch(*pparams, mask, texture);
+        }
+    }
 }
 
 void LLRenderPass::pushBatches(U32 type, U32 mask, BOOL texture, BOOL batch_textures)
@@ -415,27 +440,74 @@ void LLRenderPass::pushBatches(U32 type, U32 mask, BOOL texture, BOOL batch_text
 	}
 }
 
+void LLRenderPass::pushRiggedBatches(U32 type, U32 mask, BOOL texture, BOOL batch_textures)
+{
+    LL_PROFILE_ZONE_SCOPED;
+    LLVOAvatar* lastAvatar = nullptr;
+    U64 lastMeshId = 0;
+    mask |= LLVertexBuffer::MAP_WEIGHT4;
+    for (LLCullResult::drawinfo_iterator i = gPipeline.beginRenderMap(type); i != gPipeline.endRenderMap(type); ++i)
+    {
+        LLDrawInfo* pparams = *i;
+        if (pparams)
+        {
+            if (lastAvatar != pparams->mAvatar || lastMeshId != pparams->mSkinInfo->mHash)
+            {
+                uploadMatrixPalette(*pparams);
+                lastAvatar = pparams->mAvatar;
+                lastMeshId = pparams->mSkinInfo->mHash;
+            }
+
+            pushBatch(*pparams, mask, texture, batch_textures);
+        }
+    }
+}
+
 void LLRenderPass::pushMaskBatches(U32 type, U32 mask, BOOL texture, BOOL batch_textures)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	for (LLCullResult::drawinfo_iterator i = gPipeline.beginRenderMap(type); i != gPipeline.endRenderMap(type); ++i)	
 	{
 		LLDrawInfo* pparams = *i;
 		if (pparams) 
 		{
-			if (LLGLSLShader::sCurBoundShaderPtr)
-			{
-				LLGLSLShader::sCurBoundShaderPtr->setMinimumAlpha(pparams->mAlphaMaskCutoff);
-			}
-			else
-			{
-				gGL.setAlphaRejectSettings(LLRender::CF_GREATER, pparams->mAlphaMaskCutoff);
-			}
-			
+			LLGLSLShader::sCurBoundShaderPtr->setMinimumAlpha(pparams->mAlphaMaskCutoff);
 			pushBatch(*pparams, mask, texture, batch_textures);
 		}
 	}
 }
 
+void LLRenderPass::pushRiggedMaskBatches(U32 type, U32 mask, BOOL texture, BOOL batch_textures)
+{
+    LL_PROFILE_ZONE_SCOPED;
+    LLVOAvatar* lastAvatar = nullptr;
+    U64 lastMeshId = 0;
+    for (LLCullResult::drawinfo_iterator i = gPipeline.beginRenderMap(type); i != gPipeline.endRenderMap(type); ++i)
+    {
+        LLDrawInfo* pparams = *i;
+        if (pparams)
+        {
+            if (LLGLSLShader::sCurBoundShaderPtr)
+            {
+                LLGLSLShader::sCurBoundShaderPtr->setMinimumAlpha(pparams->mAlphaMaskCutoff);
+            }
+            else
+            {
+                gGL.setAlphaRejectSettings(LLRender::CF_GREATER, pparams->mAlphaMaskCutoff);
+            }
+
+            if (lastAvatar != pparams->mAvatar || lastMeshId != pparams->mSkinInfo->mHash)
+            {
+                uploadMatrixPalette(*pparams);
+                lastAvatar = pparams->mAvatar;
+                lastMeshId = pparams->mSkinInfo->mHash;
+            }
+
+            pushBatch(*pparams, mask | LLVertexBuffer::MAP_WEIGHT4, texture, batch_textures);
+        }
+    }
+}
+
 void LLRenderPass::applyModelMatrix(const LLDrawInfo& params)
 {
 	if (params.mModelMatrix != gGLLastMatrix)
@@ -514,7 +586,24 @@ void LLRenderPass::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture, BOOL ba
 	}
 }
 
-void LLRenderPass::renderGroups(U32 type, U32 mask, BOOL texture)
+// static
+bool LLRenderPass::uploadMatrixPalette(LLDrawInfo& params)
 {
-	gPipeline.renderGroups(this, type, mask, texture);
+    // upload matrix palette to shader
+    const LLVOAvatar::MatrixPaletteCache& mpc = params.mAvatar->updateSkinInfoMatrixPalette(params.mSkinInfo);
+    U32 count = mpc.mMatrixPalette.size();
+
+    if (count == 0)
+    {
+        //skin info not loaded yet, don't render
+        return false;
+    }
+
+    LLGLSLShader::sCurBoundShaderPtr->uniformMatrix3x4fv(LLViewerShaderMgr::AVATAR_MATRIX,
+        count,
+        FALSE,
+        (GLfloat*)&(mpc.mGLMp[0]));
+
+    return true;
 }
+
diff --git a/indra/newview/lldrawpool.h b/indra/newview/lldrawpool.h
index ecd9bd034f..6d49b0254b 100644
--- a/indra/newview/lldrawpool.h
+++ b/indra/newview/lldrawpool.h
@@ -125,38 +125,68 @@ protected:
 class LLRenderPass : public LLDrawPool
 {
 public:
+    // list of possible LLRenderPass types to assign a render batch to
+    // NOTE: "rigged" variant MUST be non-rigged variant + 1
 	enum
 	{
 		PASS_SIMPLE = NUM_POOL_TYPES,
+        PASS_SIMPLE_RIGGED,
 		PASS_GRASS,
 		PASS_FULLBRIGHT,
+        PASS_FULLBRIGHT_RIGGED,
 		PASS_INVISIBLE,
-		PASS_INVISI_SHINY,
+        PASS_INVISIBLE_RIGGED,
+		PASS_INVISI_SHINY, 
+        PASS_INVISI_SHINY_RIGGED,
 		PASS_FULLBRIGHT_SHINY,
+        PASS_FULLBRIGHT_SHINY_RIGGED,
 		PASS_SHINY,
+        PASS_SHINY_RIGGED,
 		PASS_BUMP,
+        PASS_BUMP_RIGGED,
 		PASS_POST_BUMP,
+        PASS_POST_BUMP_RIGGED,
 		PASS_MATERIAL,
+        PASS_MATERIAL_RIGGED,
 		PASS_MATERIAL_ALPHA,
+        PASS_MATERIAL_ALPHA_RIGGED,
 		PASS_MATERIAL_ALPHA_MASK,              // Diffuse texture used as alpha mask
+        PASS_MATERIAL_ALPHA_MASK_RIGGED,
 		PASS_MATERIAL_ALPHA_EMISSIVE,
+        PASS_MATERIAL_ALPHA_EMISSIVE_RIGGED,
 		PASS_SPECMAP,
+        PASS_SPECMAP_RIGGED,
 		PASS_SPECMAP_BLEND,
+        PASS_SPECMAP_BLEND_RIGGED,
 		PASS_SPECMAP_MASK,                     // Diffuse texture used as alpha mask and specular texture(map)
+        PASS_SPECMAP_MASK_RIGGED,
 		PASS_SPECMAP_EMISSIVE,
+        PASS_SPECMAP_EMISSIVE_RIGGED,
 		PASS_NORMMAP,
+        PASS_NORMMAP_RIGGED,
 		PASS_NORMMAP_BLEND,
+        PASS_NORMMAP_BLEND_RIGGED,
 		PASS_NORMMAP_MASK,                     // Diffuse texture used as alpha mask and normal map
+        PASS_NORMMAP_MASK_RIGGED,
 		PASS_NORMMAP_EMISSIVE,
+        PASS_NORMMAP_EMISSIVE_RIGGED,
 		PASS_NORMSPEC,
-		PASS_NORMSPEC_BLEND,
+        PASS_NORMSPEC_RIGGED,
+		PASS_NORMSPEC_BLEND, 
+        PASS_NORMSPEC_BLEND_RIGGED,
 		PASS_NORMSPEC_MASK,                    // Diffuse texture used as alpha mask with normal and specular map
+        PASS_NORMSPEC_MASK_RIGGED,
 		PASS_NORMSPEC_EMISSIVE,
+        PASS_NORMSPEC_EMISSIVE_RIGGED,
 		PASS_GLOW,
+        PASS_GLOW_RIGGED,
 		PASS_ALPHA,
 		PASS_ALPHA_MASK,
+        PASS_ALPHA_MASK_RIGGED,
 		PASS_FULLBRIGHT_ALPHA_MASK,            // Diffuse texture used as alpha mask and fullbright
+        PASS_FULLBRIGHT_ALPHA_MASK_RIGGED,
 		PASS_ALPHA_INVISIBLE,
+        PASS_ALPHA_INVISIBLE_RIGGED,
 		NUM_RENDER_TYPES,
 	};
 
@@ -169,12 +199,13 @@ public:
 
 	static void applyModelMatrix(const LLDrawInfo& params);
 	virtual void pushBatches(U32 type, U32 mask, BOOL texture = TRUE, BOOL batch_textures = FALSE);
+    virtual void pushRiggedBatches(U32 type, U32 mask, BOOL texture = TRUE, BOOL batch_textures = FALSE);
 	virtual void pushMaskBatches(U32 type, U32 mask, BOOL texture = TRUE, BOOL batch_textures = FALSE);
+    virtual void pushRiggedMaskBatches(U32 type, U32 mask, BOOL texture = TRUE, BOOL batch_textures = FALSE);
 	virtual void pushBatch(LLDrawInfo& params, U32 mask, BOOL texture, BOOL batch_textures = FALSE);
+    static bool uploadMatrixPalette(LLDrawInfo& params);
 	virtual void renderGroup(LLSpatialGroup* group, U32 type, U32 mask, BOOL texture = TRUE);
-	virtual void renderGroups(U32 type, U32 mask, BOOL texture = TRUE);
-	virtual void renderTexture(U32 type, U32 mask, BOOL batch_textures = TRUE);
-
+    virtual void renderRiggedGroup(LLSpatialGroup* group, U32 type, U32 mask, BOOL texture = TRUE);
 };
 
 class LLFacePool : public LLDrawPool
diff --git a/indra/newview/lldrawpoolalpha.cpp b/indra/newview/lldrawpoolalpha.cpp
index 34f9bfe35d..9b298b120a 100644
--- a/indra/newview/lldrawpoolalpha.cpp
+++ b/indra/newview/lldrawpoolalpha.cpp
@@ -48,18 +48,20 @@
 #include "lldrawpoolwater.h"
 #include "llspatialpartition.h"
 #include "llglcommonfunc.h"
+#include "llvoavatar.h"
 
 BOOL LLDrawPoolAlpha::sShowDebugAlpha = FALSE;
 
+#define current_shader (LLGLSLShader::sCurBoundShaderPtr)
+
 static BOOL deferred_render = FALSE;
 
 LLDrawPoolAlpha::LLDrawPoolAlpha(U32 type) :
-		LLRenderPass(type), current_shader(NULL), target_shader(NULL),
-		simple_shader(NULL), fullbright_shader(NULL), emissive_shader(NULL),
+		LLRenderPass(type), target_shader(NULL),
 		mColorSFactor(LLRender::BF_UNDEF), mColorDFactor(LLRender::BF_UNDEF),
 		mAlphaSFactor(LLRender::BF_UNDEF), mAlphaDFactor(LLRender::BF_UNDEF)
 {
-
+ 
 }
 
 LLDrawPoolAlpha::~LLDrawPoolAlpha()
@@ -98,33 +100,43 @@ void LLDrawPoolAlpha::beginPostDeferredPass(S32 pass)
 
     F32 gamma = gSavedSettings.getF32("RenderDeferredDisplayGamma");
 
-    emissive_shader = (LLPipeline::sRenderDeferred)   ? &gDeferredEmissiveProgram    :
-                      (LLPipeline::sUnderWaterRender) ? &gObjectEmissiveWaterProgram : &gObjectEmissiveProgram;
+    emissive_shader[0] = (LLPipeline::sUnderWaterRender) ? &gObjectEmissiveWaterProgram : &gObjectEmissiveProgram;
+    emissive_shader[1] = emissive_shader[0]->mRiggedVariant;
 
-    emissive_shader->bind();
-    emissive_shader->uniform1i(LLShaderMgr::NO_ATMO, (LLPipeline::sRenderingHUDs) ? 1 : 0);
-    emissive_shader->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 2.2f); 
-	emissive_shader->uniform1f(LLShaderMgr::DISPLAY_GAMMA, (gamma > 0.1f) ? 1.0f / gamma : (1.0f/2.2f));
+    for (int i = 0; i < 2; ++i)
+    {
+        emissive_shader[i]->bind();
+        emissive_shader[i]->uniform1i(LLShaderMgr::NO_ATMO, (LLPipeline::sRenderingHUDs) ? 1 : 0);
+        emissive_shader[i]->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 2.2f);
+        emissive_shader[i]->uniform1f(LLShaderMgr::DISPLAY_GAMMA, (gamma > 0.1f) ? 1.0f / gamma : (1.0f / 2.2f));
+    }
 
 	if (pass == 0)
 	{
-        fullbright_shader = (LLPipeline::sImpostorRender)   ? &gDeferredFullbrightProgram      :
-                            (LLPipeline::sUnderWaterRender) ? &gDeferredFullbrightWaterProgram : &gDeferredFullbrightProgram;
-
-		fullbright_shader->bind();
-		fullbright_shader->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 2.2f); 
-		fullbright_shader->uniform1f(LLShaderMgr::DISPLAY_GAMMA, (gamma > 0.1f) ? 1.0f / gamma : (1.0f/2.2f));
-        fullbright_shader->uniform1i(LLShaderMgr::NO_ATMO, LLPipeline::sRenderingHUDs ? 1 : 0);
-		fullbright_shader->unbind();
+        fullbright_shader[0] = (LLPipeline::sImpostorRender) ? &gDeferredFullbrightProgram :
+                (LLPipeline::sUnderWaterRender) ? &gDeferredFullbrightWaterProgram : &gDeferredFullbrightProgram;
+        fullbright_shader[1] = fullbright_shader[0]->mRiggedVariant;
+ 
+        for (int i = 0; i < 2; ++i)
+        {
+            fullbright_shader[i]->bind();
+            fullbright_shader[i]->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 2.2f);
+            fullbright_shader[i]->uniform1f(LLShaderMgr::DISPLAY_GAMMA, (gamma > 0.1f) ? 1.0f / gamma : (1.0f / 2.2f));
+            fullbright_shader[i]->uniform1i(LLShaderMgr::NO_ATMO, LLPipeline::sRenderingHUDs ? 1 : 0);
+            fullbright_shader[i]->unbind();
+        }
 
-        simple_shader = (LLPipeline::sImpostorRender)   ? &gDeferredAlphaImpostorProgram :
-                        (LLPipeline::sUnderWaterRender) ? &gDeferredAlphaWaterProgram    : &gDeferredAlphaProgram;
+        simple_shader[0] = (LLPipeline::sImpostorRender) ? &gDeferredAlphaImpostorProgram :
+                (LLPipeline::sUnderWaterRender) ? &gDeferredAlphaWaterProgram : &gDeferredAlphaProgram;
+        simple_shader[1] = simple_shader[0]->mRiggedVariant;
 
 		//prime simple shader (loads shadow relevant uniforms)
-		gPipeline.bindDeferredShader(*simple_shader);
-
-		simple_shader->uniform1f(LLShaderMgr::DISPLAY_GAMMA, (gamma > 0.1f) ? 1.0f / gamma : (1.0f/2.2f));
-        simple_shader->uniform1i(LLShaderMgr::NO_ATMO, LLPipeline::sRenderingHUDs ? 1 : 0);
+        for (int i = 0; i < 2; ++i)
+        {
+            gPipeline.bindDeferredShader(*simple_shader[i]);
+            simple_shader[i]->uniform1f(LLShaderMgr::DISPLAY_GAMMA, (gamma > 0.1f) ? 1.0f / gamma : (1.0f / 2.2f));
+            simple_shader[i]->uniform1i(LLShaderMgr::NO_ATMO, LLPipeline::sRenderingHUDs ? 1 : 0);
+        }
 	}
 	else if (!LLPipeline::sImpostorRender)
 	{
@@ -133,16 +145,21 @@ void LLDrawPoolAlpha::beginPostDeferredPass(S32 pass)
 		gPipeline.mDeferredDepth.copyContents(gPipeline.mDeferredScreen, 0, 0, gPipeline.mDeferredScreen.getWidth(), gPipeline.mDeferredScreen.getHeight(),
 							0, 0, gPipeline.mDeferredDepth.getWidth(), gPipeline.mDeferredDepth.getHeight(), GL_DEPTH_BUFFER_BIT, GL_NEAREST);	
 		gPipeline.mDeferredDepth.bindTarget();
-		simple_shader = fullbright_shader = &gObjectFullbrightAlphaMaskProgram;
-		gObjectFullbrightAlphaMaskProgram.bind();
-		gObjectFullbrightAlphaMaskProgram.setMinimumAlpha(0.33f);
+		simple_shader[0] = fullbright_shader[0] = &gObjectFullbrightAlphaMaskProgram;
+        simple_shader[1] = fullbright_shader[1] = simple_shader[0]->mRiggedVariant;
+        
+        for (int i = 0; i < 2; ++i)
+        {
+            simple_shader[i]->bind();
+            simple_shader[i]->setMinimumAlpha(0.33f);
+        }
 	}
 
 	deferred_render = TRUE;
 	if (mShaderLevel > 0)
 	{
 		// Start out with no shaders.
-		current_shader = target_shader = NULL;
+		target_shader = NULL;
 	}
 	gPipeline.enableLightsDynamic();
 }
@@ -155,7 +172,7 @@ void LLDrawPoolAlpha::endPostDeferredPass(S32 pass)
 	{
 		gPipeline.mDeferredDepth.flush();
 		gPipeline.mScreen.bindTarget();
-		gObjectFullbrightAlphaMaskProgram.unbind();
+		LLGLSLShader::sCurBoundShaderPtr->unbind();
 	}
 
 	deferred_render = FALSE;
@@ -172,51 +189,46 @@ void LLDrawPoolAlpha::beginRenderPass(S32 pass)
 {
     LL_PROFILE_ZONE_SCOPED;
 	
-    simple_shader     = (LLPipeline::sImpostorRender)   ? &gObjectSimpleImpostorProgram  :
+    simple_shader[0]     = (LLPipeline::sImpostorRender)   ? &gObjectSimpleImpostorProgram  :
                         (LLPipeline::sUnderWaterRender) ? &gObjectSimpleWaterProgram     : &gObjectSimpleProgram;
 
-    fullbright_shader = (LLPipeline::sImpostorRender)   ? &gObjectFullbrightProgram      :
+    fullbright_shader[0] = (LLPipeline::sImpostorRender)   ? &gObjectFullbrightProgram      :
                         (LLPipeline::sUnderWaterRender) ? &gObjectFullbrightWaterProgram : &gObjectFullbrightProgram;
 
-    emissive_shader   = (LLPipeline::sImpostorRender)   ? &gObjectEmissiveProgram        :
+    emissive_shader[0]   = (LLPipeline::sImpostorRender)   ? &gObjectEmissiveProgram        :
                         (LLPipeline::sUnderWaterRender) ? &gObjectEmissiveWaterProgram   : &gObjectEmissiveProgram;
 
+    simple_shader[1] = simple_shader[0]->mRiggedVariant;
+    fullbright_shader[1] = fullbright_shader[0]->mRiggedVariant;
+    emissive_shader[1] = emissive_shader[0]->mRiggedVariant;
+
     if (LLPipeline::sImpostorRender)
 	{
-        if (mShaderLevel > 0)
-		{
-            fullbright_shader->bind();
-			fullbright_shader->setMinimumAlpha(0.5f);
-            fullbright_shader->uniform1i(LLShaderMgr::NO_ATMO, LLPipeline::sRenderingHUDs ? 1 : 0);
-			simple_shader->bind();
-			simple_shader->setMinimumAlpha(0.5f);
-            simple_shader->uniform1i(LLShaderMgr::NO_ATMO, LLPipeline::sRenderingHUDs ? 1 : 0);
-        }
-        else
+        for (int i = 0; i < 2; ++i)
         {
-            gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.5f); //OK
+            fullbright_shader[i]->bind();
+            fullbright_shader[i]->setMinimumAlpha(0.5f);
+            fullbright_shader[i]->uniform1i(LLShaderMgr::NO_ATMO, LLPipeline::sRenderingHUDs ? 1 : 0);
+            simple_shader[i]->bind();
+            simple_shader[i]->setMinimumAlpha(0.5f);
+            simple_shader[i]->uniform1i(LLShaderMgr::NO_ATMO, LLPipeline::sRenderingHUDs ? 1 : 0);
         }
 	}
     else
 	{
-        if (mShaderLevel > 0)
-	    {
-			fullbright_shader->bind();
-			fullbright_shader->setMinimumAlpha(0.f);
-            fullbright_shader->uniform1i(LLShaderMgr::NO_ATMO, LLPipeline::sRenderingHUDs ? 1 : 0);
-			simple_shader->bind();
-			simple_shader->setMinimumAlpha(0.f);
-            simple_shader->uniform1i(LLShaderMgr::NO_ATMO, LLPipeline::sRenderingHUDs ? 1 : 0);
-		}
-        else
+        for (int i = 0; i < 2; ++i)
         {
-            gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT); //OK
+            fullbright_shader[i]->bind();
+            fullbright_shader[i]->setMinimumAlpha(0.f);
+            fullbright_shader[i]->uniform1i(LLShaderMgr::NO_ATMO, LLPipeline::sRenderingHUDs ? 1 : 0);
+            simple_shader[i]->bind();
+            simple_shader[i]->setMinimumAlpha(0.f);
+            simple_shader[i]->uniform1i(LLShaderMgr::NO_ATMO, LLPipeline::sRenderingHUDs ? 1 : 0);
         }
     }
 	gPipeline.enableLightsDynamic();
 
     LLGLSLShader::bindNoShader();
-	current_shader = NULL;
 }
 
 void LLDrawPoolAlpha::endRenderPass( S32 pass )
@@ -266,14 +278,7 @@ void LLDrawPoolAlpha::render(S32 pass)
 		gGL.blendFunc(mColorSFactor, mColorDFactor, mAlphaSFactor, mAlphaDFactor);
 	}
 
-	if (mShaderLevel > 0)
-	{
-		renderAlpha(getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX | LLVertexBuffer::MAP_TANGENT | LLVertexBuffer::MAP_TEXCOORD1 | LLVertexBuffer::MAP_TEXCOORD2, pass);
-	}
-	else
-	{
-		renderAlpha(getVertexDataMask(), pass);
-	}
+	renderAlpha(getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX | LLVertexBuffer::MAP_TANGENT | LLVertexBuffer::MAP_TEXCOORD1 | LLVertexBuffer::MAP_TEXCOORD2, pass);
 
 	gGL.setColorMask(true, false);
 
@@ -284,16 +289,8 @@ void LLDrawPoolAlpha::render(S32 pass)
 
 	if (sShowDebugAlpha)
 	{
-		BOOL shaders = gPipeline.canUseVertexShaders();
-		if(shaders) 
-		{
-			gHighlightProgram.bind();
-		}
-		else
-		{
-			gPipeline.enableLightsFullbright();
-		}
-
+		gHighlightProgram.bind();
+		
 		gGL.diffuseColor4f(1,0,0,1);
 				
 		LLViewerFetchedTexture::sSmokeImagep->addTextureStats(1024.f*1024.f);
@@ -315,10 +312,23 @@ void LLDrawPoolAlpha::render(S32 pass)
 		gGL.diffuseColor4f(0, 1, 0, 1);
 		pushBatches(LLRenderPass::PASS_INVISIBLE, LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0, FALSE);
 
-		if(shaders) 
-		{
-			gHighlightProgram.unbind();
-		}
+        gHighlightProgram.mRiggedVariant->bind();
+        gGL.diffuseColor4f(1, 0, 0, 1);
+
+        pushRiggedBatches(LLRenderPass::PASS_ALPHA_MASK_RIGGED, LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0, FALSE);
+        pushRiggedBatches(LLRenderPass::PASS_ALPHA_INVISIBLE_RIGGED, LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0, FALSE);
+
+        // Material alpha mask
+        gGL.diffuseColor4f(0, 0, 1, 1);
+        pushRiggedBatches(LLRenderPass::PASS_MATERIAL_ALPHA_MASK_RIGGED, LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0, FALSE);
+        pushRiggedBatches(LLRenderPass::PASS_NORMMAP_MASK_RIGGED, LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0, FALSE);
+        pushRiggedBatches(LLRenderPass::PASS_SPECMAP_MASK_RIGGED, LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0, FALSE);
+        pushRiggedBatches(LLRenderPass::PASS_NORMSPEC_MASK_RIGGED, LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0, FALSE);
+        pushRiggedBatches(LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK_RIGGED, LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0, FALSE);
+
+        gGL.diffuseColor4f(0, 1, 0, 1);
+        pushRiggedBatches(LLRenderPass::PASS_INVISIBLE_RIGGED, LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0, FALSE);
+        LLGLSLShader::sCurBoundShaderPtr->unbind();
 	}
 }
 
@@ -375,7 +385,7 @@ inline void Draw(LLDrawInfo* draw, U32 mask)
 	draw->mVertexBuffer->drawRangeFast(draw->mDrawMode, draw->mStart, draw->mEnd, draw->mCount, draw->mOffset);                    
 }
 
-bool LLDrawPoolAlpha::TexSetup(LLDrawInfo* draw, bool use_material, LLGLSLShader* current_shader)
+bool LLDrawPoolAlpha::TexSetup(LLDrawInfo* draw, bool use_material)
 {
     bool tex_setup = false;
 
@@ -393,7 +403,7 @@ bool LLDrawPoolAlpha::TexSetup(LLDrawInfo* draw, bool use_material, LLGLSLShader
 			current_shader->bindTexture(LLShaderMgr::SPECULAR_MAP, draw->mSpecularMap);
 		} 
     }
-    else if (current_shader == simple_shader)
+    else if (current_shader == simple_shader[0] || current_shader == simple_shader[1])
     {
         current_shader->bindTexture(LLShaderMgr::BUMP_MAP, LLViewerFetchedTexture::sFlatNormalImagep);
 	    current_shader->bindTexture(LLShaderMgr::SPECULAR_MAP, LLViewerFetchedTexture::sWhiteImagep);
@@ -450,81 +460,86 @@ void LLDrawPoolAlpha::RestoreTexSetup(bool tex_setup)
 	}
 }
 
-void LLDrawPoolAlpha::renderFullbrights(U32 mask, std::vector<LLDrawInfo*>& fullbrights)
-{
-    gPipeline.enableLightsFullbright();
-    fullbright_shader->bind();
-    fullbright_shader->uniform1f(LLShaderMgr::EMISSIVE_BRIGHTNESS, 1.0f);
-    
-    for (LLDrawInfo* draw : fullbrights)
-    {
-        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);
-
-        Draw(draw, mask & ~(LLVertexBuffer::MAP_TANGENT | LLVertexBuffer::MAP_TEXCOORD1 | LLVertexBuffer::MAP_TEXCOORD2));
-        RestoreTexSetup(tex_setup);
-    }
-    fullbright_shader->unbind();
-}
-
 void LLDrawPoolAlpha::drawEmissive(U32 mask, LLDrawInfo* draw)
 {
+    LLGLSLShader::sCurBoundShaderPtr->uniform1f(LLShaderMgr::EMISSIVE_BRIGHTNESS, 1.f);
     draw->mVertexBuffer->setBufferFast((mask & ~LLVertexBuffer::MAP_COLOR) | LLVertexBuffer::MAP_EMISSIVE);
 	draw->mVertexBuffer->drawRangeFast(draw->mDrawMode, draw->mStart, draw->mEnd, draw->mCount, draw->mOffset);
 }
 
-void LLDrawPoolAlpha::drawEmissiveInline(U32 mask, LLDrawInfo* draw)
+
+void LLDrawPoolAlpha::renderEmissives(U32 mask, std::vector<LLDrawInfo*>& emissives)
 {
+    emissive_shader[0]->bind();
+    emissive_shader[0]->uniform1f(LLShaderMgr::EMISSIVE_BRIGHTNESS, 1.f);
+
+    gPipeline.enableLightsDynamic();
+
     // install glow-accumulating blend mode
-    gGL.blendFunc(
-            LLRender::BF_ZERO, LLRender::BF_ONE, // don't touch color
-			LLRender::BF_ONE, LLRender::BF_ONE); // add to alpha (glow)
+    // don't touch color, add to alpha (glow)
+    gGL.blendFunc(LLRender::BF_ZERO, LLRender::BF_ONE, LLRender::BF_ONE, LLRender::BF_ONE);
 
-	emissive_shader->bind();
-					
-	drawEmissive(mask, draw);
+    for (LLDrawInfo* draw : emissives)
+    {
+        bool tex_setup = TexSetup(draw, false);
+        drawEmissive(mask, draw);
+        RestoreTexSetup(tex_setup);
+    }
 
-	// restore our alpha blend mode
-	gGL.blendFunc(mColorSFactor, mColorDFactor, mAlphaSFactor, mAlphaDFactor);
+    // restore our alpha blend mode
+    gGL.blendFunc(mColorSFactor, mColorDFactor, mAlphaSFactor, mAlphaDFactor);
 
-    current_shader->bind();
+    emissive_shader[0]->unbind();
 }
 
-void LLDrawPoolAlpha::renderEmissives(U32 mask, std::vector<LLDrawInfo*>& emissives)
+void LLDrawPoolAlpha::renderRiggedEmissives(U32 mask, std::vector<LLDrawInfo*>& emissives)
 {
-    emissive_shader->bind();
-    emissive_shader->uniform1f(LLShaderMgr::EMISSIVE_BRIGHTNESS, 1.f);
+    emissive_shader[1]->bind();
+    emissive_shader[1]->uniform1f(LLShaderMgr::EMISSIVE_BRIGHTNESS, 1.f);
 
     gPipeline.enableLightsDynamic();
 
+    mask |= LLVertexBuffer::MAP_WEIGHT4;
     // 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); 
- 
+    gGL.blendFunc(LLRender::BF_ZERO, LLRender::BF_ONE, LLRender::BF_ONE, LLRender::BF_ONE);
+
+    LLVOAvatar* lastAvatar = nullptr;
+    U64 lastMeshId = 0;
+
     for (LLDrawInfo* draw : emissives)
     {
-        bool tex_setup = TexSetup(draw, false, emissive_shader);
+        bool tex_setup = TexSetup(draw, false);
+        if (lastAvatar != draw->mAvatar || lastMeshId != draw->mSkinInfo->mHash)
+        {
+            if (!uploadMatrixPalette(*draw))
+            { // failed to upload matrix palette, skip rendering
+                continue;
+            }
+            lastAvatar = draw->mAvatar;
+            lastMeshId = draw->mSkinInfo->mHash;
+        }
         drawEmissive(mask, draw);
         RestoreTexSetup(tex_setup);
     }
 
     // restore our alpha blend mode
-	gGL.blendFunc(mColorSFactor, mColorDFactor, mAlphaSFactor, mAlphaDFactor);
+    gGL.blendFunc(mColorSFactor, mColorDFactor, mAlphaSFactor, mAlphaDFactor);
 
-    emissive_shader->unbind();
+    emissive_shader[1]->unbind();
 }
 
 void LLDrawPoolAlpha::renderAlpha(U32 mask, S32 pass)
 {
     LL_PROFILE_ZONE_SCOPED;
-    BOOL batch_fullbrights = gSavedSettings.getBOOL("RenderAlphaBatchFullbrights");
-    BOOL batch_emissives   = gSavedSettings.getBOOL("RenderAlphaBatchEmissives");
-	BOOL initialized_lighting = FALSE;
+    BOOL initialized_lighting = FALSE;
 	BOOL light_enabled = TRUE;
-	
-	for (LLCullResult::sg_iterator i = gPipeline.beginAlphaGroups(); i != gPipeline.endAlphaGroups(); ++i)
+
+    LLVOAvatar* lastAvatar = nullptr;
+    U64 lastMeshId = 0;
+    LLGLSLShader* lastAvatarShader = nullptr;
+
+    for (LLCullResult::sg_iterator i = gPipeline.beginAlphaGroups(); i != gPipeline.endAlphaGroups(); ++i)
 	{
         LL_PROFILE_ZONE_NAMED("renderAlpha - group");
 		LLSpatialGroup* group = *i;
@@ -535,9 +550,9 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, S32 pass)
 		    !group->isDead())
 		{
             static std::vector<LLDrawInfo*> emissives;
-            static std::vector<LLDrawInfo*> fullbrights;
+            static std::vector<LLDrawInfo*> rigged_emissives;
             emissives.resize(0);
-            fullbrights.resize(0);
+            rigged_emissives.resize(0);
 
 			bool is_particle_or_hud_particle = group->getSpatialPartition()->mPartitionType == LLViewerRegion::PARTITION_PARTICLE
 													  || group->getSpatialPartition()->mPartitionType == LLViewerRegion::PARTITION_HUD_PARTICLE;
@@ -579,12 +594,6 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, S32 pass)
 					}
 				}
 
-                if (params.mFullbright && batch_fullbrights)
-				{
-                    fullbrights.push_back(&params);
-                    continue;
-				}
-
 				LLRenderPass::applyModelMatrix(params);
 
 				LLMaterial* mat = NULL;
@@ -600,7 +609,7 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, S32 pass)
 					if (light_enabled || !initialized_lighting)
 					{
 						initialized_lighting = TRUE;
-						target_shader = fullbright_shader;
+						target_shader = fullbright_shader[0];
 
 						light_enabled = FALSE;
 					}
@@ -609,7 +618,7 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, S32 pass)
 				else if (!light_enabled || !initialized_lighting)
 				{
 					initialized_lighting = TRUE;
-					target_shader = simple_shader;
+					target_shader = simple_shader[0];
 					light_enabled = TRUE;
 				}
 
@@ -625,27 +634,36 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, S32 pass)
 						target_shader = &(gDeferredMaterialWaterProgram[mask]);
 					}
 
+                    if (params.mAvatar != nullptr)
+                    {
+                        llassert(target_shader->mRiggedVariant != nullptr);
+                        target_shader = target_shader->mRiggedVariant;
+                    }
+
 					if (current_shader != target_shader)
 					{
 						gPipeline.bindDeferredShader(*target_shader);
-                        current_shader = target_shader;
 					}
 				}
 				else if (!params.mFullbright)
 				{
-					target_shader = simple_shader;
+					target_shader = simple_shader[0];
 				}
 				else
 				{
-					target_shader = fullbright_shader;
+					target_shader = fullbright_shader[0];
 				}
 				
-				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).
-					current_shader = target_shader;
-					current_shader->bind();
-				}
+                if (params.mAvatar != nullptr)
+                {
+                    target_shader = target_shader->mRiggedVariant;
+                }
+
+                if (current_shader != target_shader)
+                {// If we need shaders, and we're not ALREADY using the proper shader, then bind it
+                // (this way we won't rebind shaders unnecessarily).
+                    target_shader->bind();
+                }
 
                 LLVector4 spec_color(1, 1, 1, 1);
                 F32 env_intensity = 0.0f;
@@ -661,7 +679,7 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, S32 pass)
 
                 if (current_shader)
                 {
-                    current_shader->uniform4f(LLShaderMgr::SPECULAR_COLOR, spec_color.mV[0], spec_color.mV[1], spec_color.mV[2], spec_color.mV[3]);						
+                    current_shader->uniform4f(LLShaderMgr::SPECULAR_COLOR, spec_color.mV[0], spec_color.mV[1], spec_color.mV[2], spec_color.mV[3]);
 				    current_shader->uniform1f(LLShaderMgr::ENVIRONMENT_INTENSITY, env_intensity);
 					current_shader->uniform1f(LLShaderMgr::EMISSIVE_BRIGHTNESS, brightness);
                 }
@@ -671,32 +689,54 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, S32 pass)
 					params.mGroup->rebuildMesh();
 				}
 
-                bool tex_setup = TexSetup(&params, (mat != nullptr), current_shader);
+                if (params.mAvatar != nullptr)
+                {
+                    if (lastAvatar != params.mAvatar ||
+                        lastMeshId != params.mSkinInfo->mHash ||
+                        lastAvatarShader != LLGLSLShader::sCurBoundShaderPtr)
+                    {
+                        if (!uploadMatrixPalette(params))
+                        {
+                            continue;
+                        }
+                        lastAvatar = params.mAvatar;
+                        lastMeshId = params.mSkinInfo->mHash;
+                        lastAvatarShader = LLGLSLShader::sCurBoundShaderPtr;
+                    }
+                }
+
+                bool tex_setup = TexSetup(&params, (mat != nullptr));
 
 				{
 					LLGLEnableFunc stencil_test(GL_STENCIL_TEST, params.mSelected, &LLGLCommonFunc::selected_stencil_test);
 
 					gGL.blendFunc((LLRender::eBlendFactor) params.mBlendFuncSrc, (LLRender::eBlendFactor) params.mBlendFuncDst, mAlphaSFactor, mAlphaDFactor);
-					params.mVertexBuffer->setBufferFast(mask & ~(params.mFullbright ? (LLVertexBuffer::MAP_TANGENT | LLVertexBuffer::MAP_TEXCOORD1 | LLVertexBuffer::MAP_TEXCOORD2) : 0));
-
+                    U32 drawMask = mask;
+                    if (params.mFullbright)
                     {
-					    params.mVertexBuffer->drawRangeFast(params.mDrawMode, params.mStart, params.mEnd, params.mCount, params.mOffset);
+                        drawMask &= ~(LLVertexBuffer::MAP_TANGENT | LLVertexBuffer::MAP_TEXCOORD1 | LLVertexBuffer::MAP_TEXCOORD2);
                     }
+                    if (params.mAvatar != nullptr)
+                    {
+                        drawMask |= LLVertexBuffer::MAP_WEIGHT4;
+                    }
+
+                    params.mVertexBuffer->setBufferFast(drawMask);
+                    params.mVertexBuffer->drawRangeFast(params.mDrawMode, params.mStart, params.mEnd, params.mCount, params.mOffset);
 				}
 
 				// If this alpha mesh has glow, then draw it a second time to add the destination-alpha (=glow).  Interleaving these state-changing calls is expensive, but glow must be drawn Z-sorted with alpha.
-				if (current_shader && 
-					draw_glow_for_this_partition &&
+				if (draw_glow_for_this_partition &&
 					params.mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_EMISSIVE))
 				{
-                    if (batch_emissives)
+                    if (params.mAvatar != nullptr)
                     {
-                        emissives.push_back(&params);
+                        rigged_emissives.push_back(&params);
                     }
                     else
                     {
-                        drawEmissiveInline(mask, &params);
-                    } 
+                        emissives.push_back(&params);
+                    }
 				}
 			
 				if (tex_setup)
@@ -708,41 +748,56 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, S32 pass)
 				}
 			}
 
-
-            bool rebind = false;
-            if (batch_fullbrights)
             {
-                if (!fullbrights.empty())
+                bool rebind = false;
+                LLGLSLShader* lastShader = current_shader;
+                if (!emissives.empty())
                 {
-                    light_enabled = false;
-                    renderFullbrights(mask, fullbrights);
+                    light_enabled = true;
+                    renderEmissives(mask, emissives);
                     rebind = true;
                 }
-            }
 
-            if (batch_emissives)
-            {
-                if (!emissives.empty())
+                if (!rigged_emissives.empty())
                 {
                     light_enabled = true;
-                    renderEmissives(mask, emissives);
+                    renderRiggedEmissives(mask, rigged_emissives);
                     rebind = true;
                 }
-            }
 
-            if (current_shader && rebind)
-            {
-                current_shader->bind();
+                if (lastShader && rebind)
+                {
+                    lastShader->bind();
+                }
             }
-		}        
+		}
 	}
 
 	gGL.setSceneBlendType(LLRender::BT_ALPHA);
 
-	LLVertexBuffer::unbind();	
-		
+	LLVertexBuffer::unbind();
+
 	if (!light_enabled)
 	{
 		gPipeline.enableLightsDynamic();
 	}
 }
+
+bool LLDrawPoolAlpha::uploadMatrixPalette(const LLDrawInfo& params)
+{
+    const LLVOAvatar::MatrixPaletteCache& mpc = params.mAvatar->updateSkinInfoMatrixPalette(params.mSkinInfo);
+    U32 count = mpc.mMatrixPalette.size();
+
+    if (count == 0)
+    {
+        //skin info not loaded yet, don't render
+        return false;
+    }
+
+    LLGLSLShader::sCurBoundShaderPtr->uniformMatrix3x4fv(LLViewerShaderMgr::AVATAR_MATRIX,
+        count,
+        FALSE,
+        (GLfloat*)&(mpc.mGLMp[0]));
+
+    return true;
+}
diff --git a/indra/newview/lldrawpoolalpha.h b/indra/newview/lldrawpoolalpha.h
index a50b1d929e..64c17c3fef 100644
--- a/indra/newview/lldrawpoolalpha.h
+++ b/indra/newview/lldrawpoolalpha.h
@@ -65,23 +65,22 @@ public:
 	void renderGroupAlpha(LLSpatialGroup* group, U32 type, U32 mask, BOOL texture = TRUE);
 	void renderAlpha(U32 mask, S32 pass);
 	void renderAlphaHighlight(U32 mask);
-		
+    bool uploadMatrixPalette(const LLDrawInfo& params);
+
 	static BOOL sShowDebugAlpha;
 
 private:
-	LLGLSLShader* current_shader;
 	LLGLSLShader* target_shader;
-	LLGLSLShader* simple_shader;
-	LLGLSLShader* fullbright_shader;	
-	LLGLSLShader* emissive_shader;
 
-    void renderFullbrights(U32 mask, std::vector<LLDrawInfo*>& fullbrights);
-    void renderEmissives(U32 mask, std::vector<LLDrawInfo*>& emissives);
+    // setup by beginFooPass, [0] is static variant, [1] is rigged variant
+    LLGLSLShader* simple_shader[2] = { nullptr };
+	LLGLSLShader* fullbright_shader[2] = { nullptr };
+	LLGLSLShader* emissive_shader[2] = { nullptr };
 
     void drawEmissive(U32 mask, LLDrawInfo* draw);
-    void drawEmissiveInline(U32 mask, LLDrawInfo* draw);
-
-    bool TexSetup(LLDrawInfo* draw, bool use_material, LLGLSLShader* current_shader);
+    void renderEmissives(U32 mask, std::vector<LLDrawInfo*>& emissives);
+    void renderRiggedEmissives(U32 mask, std::vector<LLDrawInfo*>& emissives);
+    bool TexSetup(LLDrawInfo* draw, bool use_material);
     void RestoreTexSetup(bool tex_setup);
 
 	// our 'normal' alpha blend function for this pass
@@ -89,6 +88,9 @@ private:
 	LLRender::eBlendFactor mColorDFactor;	
 	LLRender::eBlendFactor mAlphaSFactor;
 	LLRender::eBlendFactor mAlphaDFactor;
+
+    // if true, we're executing a rigged render pass
+    bool mRigged = false;
 };
 
 class LLDrawPoolAlphaPostWater : public LLDrawPoolAlpha
diff --git a/indra/newview/lldrawpoolavatar.cpp b/indra/newview/lldrawpoolavatar.cpp
index 5b51e9db24..125cd3fd5b 100644
--- a/indra/newview/lldrawpoolavatar.cpp
+++ b/indra/newview/lldrawpoolavatar.cpp
@@ -126,13 +126,6 @@ BOOL LLDrawPoolAvatar::isDead()
         return FALSE;
     }
     
-	for (U32 i = 0; i < NUM_RIGGED_PASSES; ++i)
-    {
-        if (mRiggedFace[i].size() > 0)
-        {
-            return FALSE;
-        }
-    }
     return TRUE;
 }
 
@@ -159,17 +152,6 @@ void LLDrawPoolAvatar::prerender()
 	{
 		sBufferUsage = GL_STREAM_DRAW_ARB;
 	}
-
-	if (!mDrawFace.empty())
-	{
-		const LLFace *facep = mDrawFace[0];
-		if (facep && facep->getDrawable())
-		{
-			LLVOAvatar* avatarp = (LLVOAvatar *)facep->getDrawable()->getVObj().get();
-			updateRiggedVertexBuffers(avatarp);
-            updateSkinInfoMatrixPalettes(avatarp);
-		}
-	}
 }
 
 LLMatrix4& LLDrawPoolAvatar::getModelView()
@@ -215,15 +197,6 @@ void LLDrawPoolAvatar::beginDeferredPass(S32 pass)
 	case 2:
 		beginDeferredSkinned();
 		break;
-	case 3:
-		beginDeferredRiggedSimple();
-		break;
-	case 4:
-		beginDeferredRiggedBump();
-		break;
-	default:
-		beginDeferredRiggedMaterial(pass-5);
-		break;
 	}
 }
 
@@ -250,15 +223,6 @@ void LLDrawPoolAvatar::endDeferredPass(S32 pass)
 	case 2:
 		endDeferredSkinned();
 		break;
-	case 3:
-		endDeferredRiggedSimple();
-		break;
-	case 4:
-		endDeferredRiggedBump();
-		break;
-	default:
-		endDeferredRiggedMaterial(pass-5);
-		break;
 	}
 }
 
@@ -271,176 +235,51 @@ void LLDrawPoolAvatar::renderDeferred(S32 pass)
 
 S32 LLDrawPoolAvatar::getNumPostDeferredPasses()
 {
-	return 10;
+	return 1;
 }
 
 void LLDrawPoolAvatar::beginPostDeferredPass(S32 pass)
 {
     LL_PROFILE_ZONE_SCOPED
 
-	switch (pass)
-	{
-	case 0:
-		beginPostDeferredAlpha();
-		break;
-	case 1:
-		beginRiggedFullbright();
-		break;
-	case 2:
-		beginRiggedFullbrightShiny();
-		break;
-	case 3:
-		beginDeferredRiggedAlpha();
-		break;
-	case 4:
-		beginRiggedFullbrightAlpha();
-		break;
-	case 9:
-		beginRiggedGlow();
-		break;
-	default:
-		beginDeferredRiggedMaterialAlpha(pass-5);
-		break;
-	}
-}
-
-void LLDrawPoolAvatar::beginPostDeferredAlpha()
-{
-    LL_PROFILE_ZONE_SCOPED
-
-	sSkipOpaque = TRUE;
-	sShaderLevel = mShaderLevel;
-	sVertexProgram = &gDeferredAvatarAlphaProgram;
-	sRenderingSkinned = TRUE;
-
-	gPipeline.bindDeferredShader(*sVertexProgram);
-
-	sVertexProgram->setMinimumAlpha(LLDrawPoolAvatar::sMinimumAlpha);
-
-	sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
-}
-
-void LLDrawPoolAvatar::beginDeferredRiggedAlpha()
-{
-    LL_PROFILE_ZONE_SCOPED
-
-	sVertexProgram = &gDeferredSkinnedAlphaProgram;
-	gPipeline.bindDeferredShader(*sVertexProgram);
-	sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
-	gPipeline.enableLightsDynamic();
-}
-
-void LLDrawPoolAvatar::beginDeferredRiggedMaterialAlpha(S32 pass)
-{
-    LL_PROFILE_ZONE_SCOPED
-
-	switch (pass)
-	{
-	case 0: pass = 1; break;
-	case 1: pass = 5; break;
-	case 2: pass = 9; break;
-	default: pass = 13; break;
-	}
-
-	pass += LLMaterial::SHADER_COUNT;
-
-	sVertexProgram = &gDeferredMaterialProgram[pass];
-
-	if (LLPipeline::sUnderWaterRender)
-	{
-		sVertexProgram = &(gDeferredMaterialWaterProgram[pass]);
-	}
+        sSkipOpaque = TRUE;
+    sShaderLevel = mShaderLevel;
+    sVertexProgram = &gDeferredAvatarAlphaProgram;
+    sRenderingSkinned = TRUE;
 
-	gPipeline.bindDeferredShader(*sVertexProgram);
-	sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
-	normal_channel = sVertexProgram->enableTexture(LLViewerShaderMgr::BUMP_MAP);
-	specular_channel = sVertexProgram->enableTexture(LLViewerShaderMgr::SPECULAR_MAP);
-	gPipeline.enableLightsDynamic();
-}
+    gPipeline.bindDeferredShader(*sVertexProgram);
 
-void LLDrawPoolAvatar::endDeferredRiggedAlpha()
-{
-    LL_PROFILE_ZONE_SCOPED
+    sVertexProgram->setMinimumAlpha(LLDrawPoolAvatar::sMinimumAlpha);
 
-	LLVertexBuffer::unbind();
-	gPipeline.unbindDeferredShader(*sVertexProgram);
-	sDiffuseChannel = 0;
-	normal_channel = -1;
-	specular_channel = -1;
-	sVertexProgram = NULL;
+    sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
 }
 
 void LLDrawPoolAvatar::endPostDeferredPass(S32 pass)
 {
     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;
 
-	switch (pass)
-	{
-	case 0:
-		endPostDeferredAlpha();
-		break;
-	case 1:
-		endRiggedFullbright();
-		break;
-	case 2:
-		endRiggedFullbrightShiny();
-		break;
-	case 3:
-		endDeferredRiggedAlpha();
-		break;
-	case 4:
-		endRiggedFullbrightAlpha();
-		break;
-	case 5:
-		endRiggedGlow();
-		break;
-	default:
-		endDeferredRiggedAlpha();
-		break;
-	}
-}
-
-void LLDrawPoolAvatar::endPostDeferredAlpha()
-{
-    LL_PROFILE_ZONE_SCOPED
-
-	// 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;
-		
-	gPipeline.unbindDeferredShader(*sVertexProgram);
-	sDiffuseChannel = 0;
-	sShaderLevel = mShaderLevel;
+    gPipeline.unbindDeferredShader(*sVertexProgram);
+    sDiffuseChannel = 0;
+    sShaderLevel = mShaderLevel;
 }
 
 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
-		4, // rigged fullbright
-		6, //rigged fullbright shiny
-		7, //rigged alpha
-		8, //rigged fullbright alpha
-		9, //rigged material alpha 1
-		10,//rigged material alpha 2
-		11,//rigged material alpha 3
-		12,//rigged material alpha 4
-		13, //rigged glow
-	};
-
-	S32 p = actual_pass[pass];
-
+    is_post_deferred_render = true;
 	if (LLPipeline::sImpostorRender)
 	{ //HACK for impostors so actual pass ends up being proper pass
-		p -= 2;
+        render(0);
 	}
-
-	is_post_deferred_render = true;
-	render(p);
-	is_post_deferred_render = false;
+    else
+    {
+        render(2);
+    }
+    is_post_deferred_render = false;
 }
 
 
@@ -506,68 +345,12 @@ void LLDrawPoolAvatar::beginShadowPass(S32 pass)
 
         gGL.diffuseColor4f(1, 1, 1, 1);
     }
-    else if (pass == SHADOW_PASS_ATTACHMENT_ALPHA_BLEND)
-    {
-        sVertexProgram = &gDeferredAttachmentAlphaShadowProgram;
-
-        // bind diffuse tex so we can reference the alpha channel...
-        S32 loc = sVertexProgram->getUniformLocation(LLViewerShaderMgr::DIFFUSE_MAP);
-        sDiffuseChannel = 0;
-        if (loc != -1)
-        {
-            sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
-        }
-
-        if ((sShaderLevel > 0))  // for hardware blending
-        {
-            sRenderingSkinned = TRUE;
-            sVertexProgram->bind();
-        }
-
-        gGL.diffuseColor4f(1, 1, 1, 1);
-    }
-    else if (pass == SHADOW_PASS_ATTACHMENT_ALPHA_MASK)
-    {
-        sVertexProgram = &gDeferredAttachmentAlphaMaskShadowProgram;
-
-        // bind diffuse tex so we can reference the alpha channel...
-        S32 loc = sVertexProgram->getUniformLocation(LLViewerShaderMgr::DIFFUSE_MAP);
-        sDiffuseChannel = 0;
-        if (loc != -1)
-        {
-            sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
-        }
-
-        if ((sShaderLevel > 0))  // for hardware blending
-        {
-            sRenderingSkinned = TRUE;
-            sVertexProgram->bind();
-        }
-
-        gGL.diffuseColor4f(1, 1, 1, 1);
-    }
-    else // SHADOW_PASS_ATTACHMENT_OPAQUE
-    {
-        sVertexProgram = &gDeferredAttachmentShadowProgram;
-        S32 loc = sVertexProgram->getUniformLocation(LLViewerShaderMgr::DIFFUSE_MAP);
-        sDiffuseChannel = 0;
-        if (loc != -1)
-        {
-            sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
-        }
-        sVertexProgram->bind();
-    }
 }
 
 void LLDrawPoolAvatar::endShadowPass(S32 pass)
 {
 	LL_PROFILE_ZONE_SCOPED;
 
-    if (pass == SHADOW_PASS_ATTACHMENT_OPAQUE)
-    {
-        LLVertexBuffer::unbind();
-    }
-
     if (sShaderLevel > 0)
     {
         sVertexProgram->unbind();
@@ -625,77 +408,17 @@ void LLDrawPoolAvatar::renderShadow(S32 pass)
         avatarp->renderSkinned();
         LLDrawPoolAvatar::sSkipOpaque = false;
     }
-    else if (pass == SHADOW_PASS_ATTACHMENT_ALPHA_BLEND) // rigged alpha
-    {
-        LLDrawPoolAvatar::sSkipOpaque = true;
-        renderRigged(avatarp, RIGGED_MATERIAL_ALPHA);
-        renderRigged(avatarp, RIGGED_MATERIAL_ALPHA_EMISSIVE);
-        renderRigged(avatarp, RIGGED_ALPHA);
-        renderRigged(avatarp, RIGGED_FULLBRIGHT_ALPHA);
-        renderRigged(avatarp, RIGGED_GLOW);
-        renderRigged(avatarp, RIGGED_SPECMAP_BLEND);
-        renderRigged(avatarp, RIGGED_NORMMAP_BLEND);
-        renderRigged(avatarp, RIGGED_NORMSPEC_BLEND);
-        LLDrawPoolAvatar::sSkipOpaque = false;
-    }
-    else if (pass == SHADOW_PASS_ATTACHMENT_ALPHA_MASK) // rigged alpha mask
-    {
-        LLDrawPoolAvatar::sSkipOpaque = true;
-        renderRigged(avatarp, RIGGED_MATERIAL_ALPHA_MASK);
-        renderRigged(avatarp, RIGGED_NORMMAP_MASK);
-        renderRigged(avatarp, RIGGED_SPECMAP_MASK);
-        renderRigged(avatarp, RIGGED_NORMSPEC_MASK);
-        renderRigged(avatarp, RIGGED_GLOW);
-        LLDrawPoolAvatar::sSkipOpaque = false;
-    }
-    else // rigged opaque (SHADOW_PASS_ATTACHMENT_OPAQUE
-    {
-        LLDrawPoolAvatar::sSkipTransparent = true;
-        renderRigged(avatarp, RIGGED_MATERIAL);
-        renderRigged(avatarp, RIGGED_SPECMAP);
-        renderRigged(avatarp, RIGGED_SPECMAP_EMISSIVE);
-        renderRigged(avatarp, RIGGED_NORMMAP);
-        renderRigged(avatarp, RIGGED_NORMMAP_EMISSIVE);
-        renderRigged(avatarp, RIGGED_NORMSPEC);
-        renderRigged(avatarp, RIGGED_NORMSPEC_EMISSIVE);
-        renderRigged(avatarp, RIGGED_SIMPLE);
-        renderRigged(avatarp, RIGGED_FULLBRIGHT);
-        renderRigged(avatarp, RIGGED_SHINY);
-        renderRigged(avatarp, RIGGED_FULLBRIGHT_SHINY);
-        renderRigged(avatarp, RIGGED_GLOW);
-        renderRigged(avatarp, RIGGED_DEFERRED_BUMP);
-        renderRigged(avatarp, RIGGED_DEFERRED_SIMPLE);
-        LLDrawPoolAvatar::sSkipTransparent = false;
-    }
 }
 
 S32 LLDrawPoolAvatar::getNumPasses()
 {
-    LL_PROFILE_ZONE_SCOPED
-
-	if (LLPipeline::sImpostorRender)
-	{
-		return 8;
-	}
-	else 
-	{
-		return 10;
-	}
+    return 3;
 }
 
 
 S32 LLDrawPoolAvatar::getNumDeferredPasses()
 {
-    LL_PROFILE_ZONE_SCOPED
-
-	if (LLPipeline::sImpostorRender)
-	{
-		return 19;
-	}
-	else
-	{
-		return 21;
-	}
+    return 3;
 }
 
 
@@ -733,27 +456,6 @@ void LLDrawPoolAvatar::beginRenderPass(S32 pass)
 	case 2:
 		beginSkinned();
 		break;
-	case 3:
-		beginRiggedSimple();
-		break;
-	case 4:
-		beginRiggedFullbright();
-		break;
-	case 5:
-		beginRiggedShinySimple();
-		break;
-	case 6:
-		beginRiggedFullbrightShiny();
-		break;
-	case 7:
-		beginRiggedAlpha();
-		break;
-	case 8:
-		beginRiggedFullbrightAlpha();
-		break;
-	case 9:
-		beginRiggedGlow();
-		break;
 	}
 
 	if (pass == 0)
@@ -782,27 +484,6 @@ void LLDrawPoolAvatar::endRenderPass(S32 pass)
 	case 2:
 		endSkinned();
 		break;
-	case 3:
-		endRiggedSimple();
-		break;
-	case 4:
-		endRiggedFullbright();
-		break;
-	case 5:
-		endRiggedShinySimple();
-		break;
-	case 6:
-		endRiggedFullbrightShiny();
-		break;
-	case 7:
-		endRiggedAlpha();
-		break;
-	case 8:
-		endRiggedFullbrightAlpha();
-		break;
-	case 9:
-		endRiggedGlow();
-		break;
 	}
 }
 
@@ -1037,1559 +718,199 @@ void LLDrawPoolAvatar::endSkinned()
 	gGL.getTexUnit(0)->activate();
 }
 
-void LLDrawPoolAvatar::beginRiggedSimple()
+void LLDrawPoolAvatar::beginDeferredSkinned()
 {
     LL_PROFILE_ZONE_SCOPED
 
-	if (sShaderLevel > 0)
+	sShaderLevel = mShaderLevel;
+	sVertexProgram = &gDeferredAvatarProgram;
+	sRenderingSkinned = TRUE;
+
+	sVertexProgram->bind();
+	sVertexProgram->setMinimumAlpha(LLDrawPoolAvatar::sMinimumAlpha);
+	if (LLPipeline::sRenderingHUDs)
 	{
-		if (LLPipeline::sUnderWaterRender)
-		{
-			sVertexProgram = &gSkinnedObjectSimpleWaterProgram;
-		}
-		else
-		{
-			sVertexProgram = &gSkinnedObjectSimpleProgram;
-		}
+		sVertexProgram->uniform1i(LLShaderMgr::NO_ATMO, 1);
 	}
 	else
 	{
-		if (LLPipeline::sUnderWaterRender)
-		{
-			sVertexProgram = &gObjectSimpleNonIndexedWaterProgram;
-		}
-		else
-		{
-			sVertexProgram = &gObjectSimpleNonIndexedProgram;
-		}
+		sVertexProgram->uniform1i(LLShaderMgr::NO_ATMO, 0);
 	}
 
-	if (sShaderLevel > 0 || gPipeline.canUseVertexShaders())
-	{
-		sDiffuseChannel = 0;
-		sVertexProgram->bind();
-        if (LLPipeline::sRenderingHUDs)
-	    {
-		    sVertexProgram->uniform1i(LLShaderMgr::NO_ATMO, 1);
-	    }
-	    else
-	    {
-		    sVertexProgram->uniform1i(LLShaderMgr::NO_ATMO, 0);
-	    }
-	}
+	sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
+	gGL.getTexUnit(0)->activate();
 }
 
-void LLDrawPoolAvatar::endRiggedSimple()
+void LLDrawPoolAvatar::endDeferredSkinned()
 {
     LL_PROFILE_ZONE_SCOPED
 
-	LLVertexBuffer::unbind();
-	if (sShaderLevel > 0 || gPipeline.canUseVertexShaders())
-	{
-		sVertexProgram->unbind();
-		sVertexProgram = NULL;
-	}
-}
-
-void LLDrawPoolAvatar::beginRiggedAlpha()
-{
-    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();
 
-	beginRiggedSimple();
-}
+	sVertexProgram->disableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
 
-void LLDrawPoolAvatar::endRiggedAlpha()
-{
-    LL_PROFILE_ZONE_SCOPED
+	sShaderLevel = mShaderLevel;
 
-	endRiggedSimple();
+	gGL.getTexUnit(0)->activate();
 }
 
-
-void LLDrawPoolAvatar::beginRiggedFullbrightAlpha()
+void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass)
 {
-    LL_PROFILE_ZONE_SCOPED
-
-	beginRiggedFullbright();
-}
+	if (pass == -1)
+	{
+		for (S32 i = 1; i < getNumPasses(); i++)
+		{ //skip foot shadows
+			prerender();
+			beginRenderPass(i);
+			renderAvatars(single_avatar, i);
+			endRenderPass(i);
+		}
 
-void LLDrawPoolAvatar::endRiggedFullbrightAlpha()
-{
-    LL_PROFILE_ZONE_SCOPED
-
-	endRiggedFullbright();
-}
-
-void LLDrawPoolAvatar::beginRiggedGlow()
-{
-    LL_PROFILE_ZONE_SCOPED
-
-	if (sShaderLevel > 0)
-	{
-		if (LLPipeline::sUnderWaterRender)
-		{
-			sVertexProgram = &gSkinnedObjectEmissiveWaterProgram;
-		}
-		else
-		{
-			sVertexProgram = &gSkinnedObjectEmissiveProgram;
-		}
-	}
-	else
-	{
-		if (LLPipeline::sUnderWaterRender)
-		{
-			sVertexProgram = &gObjectEmissiveNonIndexedWaterProgram;
-		}
-		else
-		{
-			sVertexProgram = &gObjectEmissiveNonIndexedProgram;
-		}
-	}
-
-	if (sShaderLevel > 0 || gPipeline.canUseVertexShaders())
-	{
-		sDiffuseChannel = 0;
-		sVertexProgram->bind();
-
-		sVertexProgram->uniform1f(LLShaderMgr::TEXTURE_GAMMA, LLPipeline::sRenderDeferred ? 2.2f : 1.1f);
-
-        if (LLPipeline::sRenderingHUDs)
-	    {
-		    sVertexProgram->uniform1i(LLShaderMgr::NO_ATMO, 1);
-	    }
-	    else
-	    {
-		    sVertexProgram->uniform1i(LLShaderMgr::NO_ATMO, 0);
-	    }
-
-		F32 gamma = gSavedSettings.getF32("RenderDeferredDisplayGamma");
-		sVertexProgram->uniform1f(LLShaderMgr::DISPLAY_GAMMA, (gamma > 0.1f) ? 1.0f / gamma : (1.0f/2.2f));
-	}
-}
-
-void LLDrawPoolAvatar::endRiggedGlow()
-{
-    LL_PROFILE_ZONE_SCOPED
-
-	endRiggedFullbright();
-}
-
-void LLDrawPoolAvatar::beginRiggedFullbright()
-{
-    LL_PROFILE_ZONE_SCOPED
-
-	if (sShaderLevel > 0)
-	{
-		if (LLPipeline::sUnderWaterRender)
-		{
-			sVertexProgram = &gSkinnedObjectFullbrightWaterProgram;
-		}
-		else
-		{
-			if (LLPipeline::sRenderDeferred)
-			{
-				sVertexProgram = &gDeferredSkinnedFullbrightProgram;
-			}
-			else
-			{
-				sVertexProgram = &gSkinnedObjectFullbrightProgram;
-			}
-		}
-	}
-	else
-	{
-		if (LLPipeline::sUnderWaterRender)
-		{
-			sVertexProgram = &gObjectFullbrightNonIndexedWaterProgram;
-		}
-		else
-		{
-			sVertexProgram = &gObjectFullbrightNonIndexedProgram;
-		}
-	}
-
-	if (sShaderLevel > 0 || gPipeline.canUseVertexShaders())
-	{
-		sDiffuseChannel = 0;
-		sVertexProgram->bind();
-
-        if (LLPipeline::sRenderingHUDs)
-        {            
-            sVertexProgram->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 1.0f);
-            sVertexProgram->uniform1i(LLShaderMgr::NO_ATMO, 1);
-        }
-		else if (LLPipeline::sRenderDeferred)
-		{
-            sVertexProgram->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 2.2f);
-            sVertexProgram->uniform1i(LLShaderMgr::NO_ATMO, 0);
-			F32 gamma = gSavedSettings.getF32("RenderDeferredDisplayGamma");
-			sVertexProgram->uniform1f(LLShaderMgr::DISPLAY_GAMMA, (gamma > 0.1f) ? 1.0f / gamma : (1.0f/2.2f));
-		} 
-		else 
-		{
-            sVertexProgram->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 1.0f);
-            sVertexProgram->uniform1i(LLShaderMgr::NO_ATMO, 0);
-		}
-	}
-}
-
-void LLDrawPoolAvatar::endRiggedFullbright()
-{
-    LL_PROFILE_ZONE_SCOPED
-
-	LLVertexBuffer::unbind();
-	if (sShaderLevel > 0 || gPipeline.canUseVertexShaders())
-	{
-		sVertexProgram->unbind();
-		sVertexProgram = NULL;
-	}
-}
-
-void LLDrawPoolAvatar::beginRiggedShinySimple()
-{
-    LL_PROFILE_ZONE_SCOPED
-
-	if (sShaderLevel > 0)
-	{
-		if (LLPipeline::sUnderWaterRender)
-		{
-			sVertexProgram = &gSkinnedObjectShinySimpleWaterProgram;
-		}
-		else
-		{
-			sVertexProgram = &gSkinnedObjectShinySimpleProgram;
-		}
-	}
-	else
-	{
-		if (LLPipeline::sUnderWaterRender)
-		{
-			sVertexProgram = &gObjectShinyNonIndexedWaterProgram;
-		}
-		else
-		{
-			sVertexProgram = &gObjectShinyNonIndexedProgram;
-		}
-	}
-
-	if (sShaderLevel > 0 || gPipeline.canUseVertexShaders())
-	{
-		sVertexProgram->bind();
-        if (LLPipeline::sRenderingHUDs)
-	    {
-		    sVertexProgram->uniform1i(LLShaderMgr::NO_ATMO, 1);
-	    }
-	    else
-	    {
-		    sVertexProgram->uniform1i(LLShaderMgr::NO_ATMO, 0);
-	    }
-		LLDrawPoolBump::bindCubeMap(sVertexProgram, 2, sDiffuseChannel, cube_channel, false);
-	}
-}
-
-void LLDrawPoolAvatar::endRiggedShinySimple()
-{
-    LL_PROFILE_ZONE_SCOPED
-
-	LLVertexBuffer::unbind();
-	if (sShaderLevel > 0 || gPipeline.canUseVertexShaders())
-	{
-		LLDrawPoolBump::unbindCubeMap(sVertexProgram, 2, sDiffuseChannel, cube_channel, false);
-		sVertexProgram->unbind();
-		sVertexProgram = NULL;
-	}
-}
-
-void LLDrawPoolAvatar::beginRiggedFullbrightShiny()
-{
-    LL_PROFILE_ZONE_SCOPED
-
-	if (sShaderLevel > 0)
-	{
-		if (LLPipeline::sUnderWaterRender)
-		{
-			sVertexProgram = &gSkinnedObjectFullbrightShinyWaterProgram;
-		}
-		else
-		{
-			if (LLPipeline::sRenderDeferred)
-			{
-				sVertexProgram = &gDeferredSkinnedFullbrightShinyProgram;
-			}
-			else
-			{
-				sVertexProgram = &gSkinnedObjectFullbrightShinyProgram;
-			}
-		}
-	}
-	else
-	{
-		if (LLPipeline::sUnderWaterRender)
-		{
-			sVertexProgram = &gObjectFullbrightShinyNonIndexedWaterProgram;
-		}
-		else
-		{
-			sVertexProgram = &gObjectFullbrightShinyNonIndexedProgram;
-		}
-	}
-
-	if (sShaderLevel > 0 || gPipeline.canUseVertexShaders())
-	{
-		sVertexProgram->bind();
-        if (LLPipeline::sRenderingHUDs)
-	    {
-		    sVertexProgram->uniform1i(LLShaderMgr::NO_ATMO, 1);
-	    }
-	    else
-	    {
-		    sVertexProgram->uniform1i(LLShaderMgr::NO_ATMO, 0);
-	    }
-		LLDrawPoolBump::bindCubeMap(sVertexProgram, 2, sDiffuseChannel, cube_channel, false);
-
-        if (LLPipeline::sRenderingHUDs)
-		{
-			sVertexProgram->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 1.0f);
-            sVertexProgram->uniform1i(LLShaderMgr::NO_ATMO, 1);
-        }
-		else if (LLPipeline::sRenderDeferred)
-		{
-            sVertexProgram->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 2.2f);
-			F32 gamma = gSavedSettings.getF32("RenderDeferredDisplayGamma");
-			sVertexProgram->uniform1f(LLShaderMgr::DISPLAY_GAMMA, (gamma > 0.1f) ? 1.0f / gamma : (1.0f/2.2f));
-            sVertexProgram->uniform1i(LLShaderMgr::NO_ATMO, 0);
-        }
-        else
-        {
-			sVertexProgram->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 1.0f);
-            sVertexProgram->uniform1i(LLShaderMgr::NO_ATMO, 0);
-		}
-	}
-}
-
-void LLDrawPoolAvatar::endRiggedFullbrightShiny()
-{
-    LL_PROFILE_ZONE_SCOPED
-
-	LLVertexBuffer::unbind();
-	if (sShaderLevel > 0 || gPipeline.canUseVertexShaders())
-	{
-		LLDrawPoolBump::unbindCubeMap(sVertexProgram, 2, sDiffuseChannel, cube_channel, false);
-		sVertexProgram->unbind();
-		sVertexProgram = NULL;
-	}
-}
-
-
-void LLDrawPoolAvatar::beginDeferredRiggedSimple()
-{
-    LL_PROFILE_ZONE_SCOPED
-
-	sVertexProgram = &gDeferredSkinnedDiffuseProgram;
-	sDiffuseChannel = 0;
-	sVertexProgram->bind();
-    if (LLPipeline::sRenderingHUDs)
-	{
-		sVertexProgram->uniform1i(LLShaderMgr::NO_ATMO, 1);
-	}
-	else
-	{
-		sVertexProgram->uniform1i(LLShaderMgr::NO_ATMO, 0);
-	}
-}
-
-void LLDrawPoolAvatar::endDeferredRiggedSimple()
-{
-    LL_PROFILE_ZONE_SCOPED
-
-	LLVertexBuffer::unbind();
-	sVertexProgram->unbind();
-	sVertexProgram = NULL;
-}
-
-void LLDrawPoolAvatar::beginDeferredRiggedBump()
-{
-    LL_PROFILE_ZONE_SCOPED
-
-	sVertexProgram = &gDeferredSkinnedBumpProgram;
-	sVertexProgram->bind();
-    if (LLPipeline::sRenderingHUDs)
-	{
-		sVertexProgram->uniform1i(LLShaderMgr::NO_ATMO, 1);
-	}
-	else
-	{
-		sVertexProgram->uniform1i(LLShaderMgr::NO_ATMO, 0);
-	}
-	normal_channel = sVertexProgram->enableTexture(LLViewerShaderMgr::BUMP_MAP);
-	sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
-}
-
-void LLDrawPoolAvatar::endDeferredRiggedBump()
-{
-    LL_PROFILE_ZONE_SCOPED
-
-	LLVertexBuffer::unbind();
-	sVertexProgram->disableTexture(LLViewerShaderMgr::BUMP_MAP);
-	sVertexProgram->disableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
-	sVertexProgram->unbind();
-	normal_channel = -1;
-	sDiffuseChannel = 0;
-	sVertexProgram = NULL;
-}
-
-void LLDrawPoolAvatar::beginDeferredRiggedMaterial(S32 pass)
-{
-    LL_PROFILE_ZONE_SCOPED
-
-	if (pass == 1 ||
-		pass == 5 ||
-		pass == 9 ||
-		pass == 13)
-	{ //skip alpha passes
-		return;
-	}
-	sVertexProgram = &gDeferredMaterialProgram[pass+LLMaterial::SHADER_COUNT];
-
-	if (LLPipeline::sUnderWaterRender)
-	{
-		sVertexProgram = &(gDeferredMaterialWaterProgram[pass+LLMaterial::SHADER_COUNT]);
-	}
-
-	sVertexProgram->bind();
-    if (LLPipeline::sRenderingHUDs)
-	{
-		sVertexProgram->uniform1i(LLShaderMgr::NO_ATMO, 1);
-	}
-	else
-	{
-		sVertexProgram->uniform1i(LLShaderMgr::NO_ATMO, 0);
-	}
-	normal_channel = sVertexProgram->enableTexture(LLViewerShaderMgr::BUMP_MAP);
-	specular_channel = sVertexProgram->enableTexture(LLViewerShaderMgr::SPECULAR_MAP);
-	sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
-}
-
-void LLDrawPoolAvatar::endDeferredRiggedMaterial(S32 pass)
-{
-    LL_PROFILE_ZONE_SCOPED
-
-	if (pass == 1 ||
-		pass == 5 ||
-		pass == 9 ||
-		pass == 13)
-	{
-		return;
-	}
-
-	LLVertexBuffer::unbind();
-	sVertexProgram->disableTexture(LLViewerShaderMgr::BUMP_MAP);
-	sVertexProgram->disableTexture(LLViewerShaderMgr::SPECULAR_MAP);
-	sVertexProgram->disableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
-	sVertexProgram->unbind();
-	normal_channel = -1;
-	sDiffuseChannel = 0;
-	sVertexProgram = NULL;
-}
-
-void LLDrawPoolAvatar::beginDeferredSkinned()
-{
-    LL_PROFILE_ZONE_SCOPED
-
-	sShaderLevel = mShaderLevel;
-	sVertexProgram = &gDeferredAvatarProgram;
-	sRenderingSkinned = TRUE;
-
-	sVertexProgram->bind();
-	sVertexProgram->setMinimumAlpha(LLDrawPoolAvatar::sMinimumAlpha);
-	if (LLPipeline::sRenderingHUDs)
-	{
-		sVertexProgram->uniform1i(LLShaderMgr::NO_ATMO, 1);
-	}
-	else
-	{
-		sVertexProgram->uniform1i(LLShaderMgr::NO_ATMO, 0);
-	}
-
-	sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
-	gGL.getTexUnit(0)->activate();
-}
-
-void LLDrawPoolAvatar::endDeferredSkinned()
-{
-    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();
-
-	sVertexProgram->disableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
-
-	sShaderLevel = mShaderLevel;
-
-	gGL.getTexUnit(0)->activate();
-}
-
-void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass)
-{
-	if (pass == -1)
-	{
-		for (S32 i = 1; i < getNumPasses(); i++)
-		{ //skip foot shadows
-			prerender();
-			beginRenderPass(i);
-			renderAvatars(single_avatar, i);
-			endRenderPass(i);
-		}
-
-		return;
-	}
-
-	if (mDrawFace.empty() && !single_avatar)
-	{
-		return;
-	}
-
-	LLVOAvatar *avatarp = NULL;
-
-	if (single_avatar)
-	{
-		avatarp = single_avatar;
-	}
-	else
-	{
-		const LLFace *facep = mDrawFace[0];
-		if (!facep->getDrawable())
-		{
-			return;
-		}
-		avatarp = (LLVOAvatar *)facep->getDrawable()->getVObj().get();
-	}
-
-    if (avatarp->isDead() || avatarp->mDrawable.isNull())
-	{
-		return;
-	}
-
-    LL_RECORD_BLOCK_TIME(FTM_RENDER_CHARACTERS);
-
-	if (!single_avatar && !avatarp->isFullyLoaded() )
-	{
-		if (pass==0 && (!gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_PARTICLES) || LLViewerPartSim::getMaxPartCount() <= 0))
-		{
-			// debug code to draw a sphere in place of avatar
-			gGL.getTexUnit(0)->bind(LLViewerFetchedTexture::sWhiteImagep);
-			gGL.setColorMask(true, true);
-			LLVector3 pos = avatarp->getPositionAgent();
-			gGL.color4f(1.0f, 1.0f, 1.0f, 0.7f);
-			
-			gGL.pushMatrix();	 
-			gGL.translatef((F32)(pos.mV[VX]),	 
-						   (F32)(pos.mV[VY]),	 
-							(F32)(pos.mV[VZ]));	 
-			 gGL.scalef(0.15f, 0.15f, 0.3f);
-
-			 gSphere.renderGGL();
-				 
-			 gGL.popMatrix();
-			 gGL.setColorMask(true, false);
-		}
-		// don't render please
-		return;
-	}
-
-	BOOL impostor = !LLPipeline::sImpostorRender && avatarp->isImpostor() && !single_avatar;
-
-	if (( avatarp->isInMuteList() 
-		  || impostor 
-		  || (LLVOAvatar::AOA_NORMAL != avatarp->getOverallAppearance() && !avatarp->needsImpostorUpdate()) ) && pass != 0)
-//		  || (LLVOAvatar::AV_DO_NOT_RENDER == avatarp->getVisualMuteSettings() && !avatarp->needsImpostorUpdate()) ) && pass != 0)
-	{ //don't draw anything but the impostor for impostored avatars
-		return;
-	}
-	
-	if (pass == 0 && !impostor && LLPipeline::sUnderWaterRender)
-	{ //don't draw foot shadows under water
-		return;
-	}
-
-	LLVOAvatar *attached_av = avatarp->getAttachedAvatar();
-	if (attached_av && LLVOAvatar::AOA_NORMAL != attached_av->getOverallAppearance())
-	{
-		// Animesh attachment of a jellydolled or invisible parent - don't show
-		return;
-	}
-
-	if (pass == 0)
-	{
-		if (!LLPipeline::sReflectionRender)
-		{
-			LLVOAvatar::sNumVisibleAvatars++;
-		}
-
-//		if (impostor || (LLVOAvatar::AV_DO_NOT_RENDER == avatarp->getVisualMuteSettings() && !avatarp->needsImpostorUpdate()))
-		if (impostor || (LLVOAvatar::AOA_NORMAL != avatarp->getOverallAppearance() && !avatarp->needsImpostorUpdate()))
-		{
-			if (LLPipeline::sRenderDeferred && !LLPipeline::sReflectionRender && avatarp->mImpostor.isComplete()) 
-			{
-				if (normal_channel > -1)
-				{
-					avatarp->mImpostor.bindTexture(2, normal_channel);
-				}
-				if (specular_channel > -1)
-				{
-					avatarp->mImpostor.bindTexture(1, specular_channel);
-				}
-			}
-			avatarp->renderImpostor(avatarp->getMutedAVColor(), sDiffuseChannel);
-		}
-		return;
-	}
-
-	if (pass == 1)
-	{
-		// render rigid meshes (eyeballs) first
-		avatarp->renderRigid();
-		return;
-	}
-
-	if (pass == 3)
-	{
-		if (is_deferred_render)
-		{
-			renderDeferredRiggedSimple(avatarp);
-		}
-		else
-		{
-			renderRiggedSimple(avatarp);
-
-			if (LLPipeline::sRenderDeferred)
-			{ //render "simple" materials
-				renderRigged(avatarp, RIGGED_MATERIAL);
-				renderRigged(avatarp, RIGGED_MATERIAL_ALPHA_MASK);
-				renderRigged(avatarp, RIGGED_MATERIAL_ALPHA_EMISSIVE);
-				renderRigged(avatarp, RIGGED_NORMMAP);
-				renderRigged(avatarp, RIGGED_NORMMAP_MASK);
-				renderRigged(avatarp, RIGGED_NORMMAP_EMISSIVE);
-				renderRigged(avatarp, RIGGED_SPECMAP);
-				renderRigged(avatarp, RIGGED_SPECMAP_MASK);
-				renderRigged(avatarp, RIGGED_SPECMAP_EMISSIVE);
-				renderRigged(avatarp, RIGGED_NORMSPEC);
-				renderRigged(avatarp, RIGGED_NORMSPEC_MASK);
-				renderRigged(avatarp, RIGGED_NORMSPEC_EMISSIVE);
-			}
-		}
-		return;
-	}
-
-	if (pass == 4)
-	{
-		if (is_deferred_render)
-		{
-			renderDeferredRiggedBump(avatarp);
-		}
-		else
-		{
-			renderRiggedFullbright(avatarp);
-		}
-
-		return;
-	}
-
-	if (is_deferred_render && pass >= 5 && pass <= 21)
-	{
-		S32 p = pass-5;
-
-		if (p != 1 &&
-			p != 5 &&
-			p != 9 &&
-			p != 13)
-		{
-			renderDeferredRiggedMaterial(avatarp, p);
-		}
-		return;
-	}
-
-
-
-
-	if (pass == 5)
-	{
-		renderRiggedShinySimple(avatarp);
-				
-		return;
-	}
-
-	if (pass == 6)
-	{
-		renderRiggedFullbrightShiny(avatarp);
 		return;
 	}
 
-	if (pass >= 7 && pass < 13)
-	{
-		if (pass == 7)
-		{
-			renderRiggedAlpha(avatarp);
-
-			if (LLPipeline::sRenderDeferred && !is_post_deferred_render)
-			{ //render transparent materials under water
-				LLGLEnable blend(GL_BLEND);
-
-				gGL.setColorMask(true, true);
-				gGL.blendFunc(LLRender::BF_SOURCE_ALPHA,
-								LLRender::BF_ONE_MINUS_SOURCE_ALPHA,
-								LLRender::BF_ZERO,
-								LLRender::BF_ONE_MINUS_SOURCE_ALPHA);
-
-				renderRigged(avatarp, RIGGED_MATERIAL_ALPHA);
-				renderRigged(avatarp, RIGGED_SPECMAP_BLEND);
-				renderRigged(avatarp, RIGGED_NORMMAP_BLEND);
-				renderRigged(avatarp, RIGGED_NORMSPEC_BLEND);
-
-				gGL.setColorMask(true, false);
-			}
-			return;
-		}
-
-		if (pass == 8)
-		{
-			renderRiggedFullbrightAlpha(avatarp);
-			return;
-		}
-
-		if (LLPipeline::sRenderDeferred && is_post_deferred_render)
-		{
-			S32 p = 0;
-			switch (pass)
-			{
-			case 9: p = 1; break;
-			case 10: p = 5; break;
-			case 11: p = 9; break;
-			case 12: p = 13; break;
-			}
-
-			{
-				LLGLEnable blend(GL_BLEND);
-				renderDeferredRiggedMaterial(avatarp, p);
-			}
-			return;
-		}
-		else if (pass == 9)
-		{
-			renderRiggedGlow(avatarp);
-			return;
-		}
-	}
-
-	if (pass == 13)
+	if (mDrawFace.empty() && !single_avatar)
 	{
-		renderRiggedGlow(avatarp);
-		
 		return;
 	}
-	
-	if ((sShaderLevel >= SHADER_LEVEL_CLOTH))
-	{
-		LLMatrix4 rot_mat;
-		LLViewerCamera::getInstance()->getMatrixToLocal(rot_mat);
-		LLMatrix4 cfr(OGL_TO_CFR_ROTATION);
-		rot_mat *= cfr;
-		
-		LLVector4 wind;
-		wind.setVec(avatarp->mWindVec);
-		wind.mV[VW] = 0;
-		wind = wind * rot_mat;
-		wind.mV[VW] = avatarp->mWindVec.mV[VW];
-
-		sVertexProgram->uniform4fv(LLViewerShaderMgr::AVATAR_WIND, 1, wind.mV);
-		F32 phase = -1.f * (avatarp->mRipplePhase);
-
-		F32 freq = 7.f + (noise1(avatarp->mRipplePhase) * 2.f);
-		LLVector4 sin_params(freq, freq, freq, phase);
-		sVertexProgram->uniform4fv(LLViewerShaderMgr::AVATAR_SINWAVE, 1, sin_params.mV);
-
-		LLVector4 gravity(0.f, 0.f, -CLOTHING_GRAVITY_EFFECT, 0.f);
-		gravity = gravity * rot_mat;
-		sVertexProgram->uniform4fv(LLViewerShaderMgr::AVATAR_GRAVITY, 1, gravity.mV);
-	}
-
-	if( !single_avatar || (avatarp == single_avatar) )
-	{
-		avatarp->renderSkinned();
-	}
-}
-
-void LLDrawPoolAvatar::getRiggedGeometry(
-    LLFace* face,
-    LLPointer<LLVertexBuffer>& buffer,
-    U32 data_mask,
-    const LLMeshSkinInfo* skin,
-    LLVolume* volume,
-    const LLVolumeFace& vol_face)
-{
-    LL_PROFILE_ZONE_SCOPED
-
-    face->setGeomIndex(0);
-    face->setIndicesIndex(0);
-
-    if (face->getTextureIndex() != FACE_DO_NOT_BATCH_TEXTURES)
-    {
-        face->setDrawInfo(NULL);
-    }
-
-    //rigged faces do not batch textures
-    face->setTextureIndex(FACE_DO_NOT_BATCH_TEXTURES);
-
-	if (buffer.isNull() || buffer->getTypeMask() != data_mask || !buffer->isWriteable())
-	{
-        // make a new buffer
-		if (sShaderLevel > 0)
-		{
-			buffer = new LLVertexBuffer(data_mask, GL_DYNAMIC_DRAW_ARB);
-		}
-		else
-		{
-			buffer = new LLVertexBuffer(data_mask, GL_STREAM_DRAW_ARB);
-		}
-
-		if (!buffer->allocateBuffer(vol_face.mNumVertices, vol_face.mNumIndices, true))
-		{
-			LL_WARNS("LLDrawPoolAvatar") << "Failed to allocate Vertex Buffer to "
-				<< vol_face.mNumVertices << " vertices and "
-				<< vol_face.mNumIndices << " indices" << LL_ENDL;
-			// allocate dummy triangle
-			buffer->allocateBuffer(1, 3, true);
-			memset((U8*)buffer->getMappedData(), 0, buffer->getSize());
-			memset((U8*)buffer->getMappedIndices(), 0, buffer->getIndicesSize());
-		}
-	}
-	else
-	{
-        //resize existing buffer
-		if(!buffer->resizeBuffer(vol_face.mNumVertices, vol_face.mNumIndices))
-		{
-			LL_WARNS("LLDrawPoolAvatar") << "Failed to resize Vertex Buffer to "
-				<< vol_face.mNumVertices << " vertices and "
-				<< vol_face.mNumIndices << " indices" << LL_ENDL;
-			// allocate dummy triangle
-			buffer->resizeBuffer(1, 3);
-			memset((U8*)buffer->getMappedData(), 0, buffer->getSize());
-			memset((U8*)buffer->getMappedIndices(), 0, buffer->getIndicesSize());
-		}
-	}
-
-	face->setSize(buffer->getNumVerts(), buffer->getNumIndices());
-	face->setVertexBuffer(buffer);
-
-	U16 offset = 0;
-		
-	LLMatrix4 mat_vert = LLMatrix4(skin->mBindShapeMatrix);
-	glh::matrix4f m((F32*) mat_vert.mMatrix);
-	m = m.inverse().transpose();
-		
-	F32 mat3[] = 
-        { m.m[0], m.m[1], m.m[2],
-          m.m[4], m.m[5], m.m[6],
-          m.m[8], m.m[9], m.m[10] };
-
-	LLMatrix3 mat_normal(mat3);				
-
-	//let getGeometryVolume know if alpha should override shiny
-	U32 type = gPipeline.getPoolTypeFromTE(face->getTextureEntry(), face->getTexture());
-
-	if (type == LLDrawPool::POOL_ALPHA)
-	{
-		face->setPoolType(LLDrawPool::POOL_ALPHA);
-	}
-	else
-	{
-		face->setPoolType(mType); // either POOL_AVATAR or POOL_CONTROL_AV
-	}
 
-	//LL_INFOS() << "Rebuilt face " << face->getTEOffset() << " of " << face->getDrawable() << " at " << gFrameTimeSeconds << LL_ENDL;
+	LLVOAvatar *avatarp = NULL;
 
-	// Let getGeometryVolume know if a texture matrix is in play
-	if (face->mTextureMatrix)
+	if (single_avatar)
 	{
-		face->setState(LLFace::TEXTURE_ANIM);
+		avatarp = single_avatar;
 	}
 	else
 	{
-		face->clearState(LLFace::TEXTURE_ANIM);
-	}
-	face->getGeometryVolume(*volume, face->getTEOffset(), mat_vert, mat_normal, offset, true);
-
-	buffer->flush();
-}
-
-void LLDrawPoolAvatar::updateRiggedFaceVertexBuffer(
-    LLVOAvatar* avatar,
-    LLFace* face,
-    const 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();
-
-    const U32 max_joints = LLSkinningUtil::getMaxJointCount();
-
-#if USE_SEPARATE_JOINT_INDICES_AND_WEIGHTS
-    #define CONDITION_WEIGHT(f) ((U8)llclamp((S32)f, (S32)0, (S32)max_joints-1))
-    LLVector4a* just_weights = vol_face.mJustWeights;
-    // we need to calculate the separated indices and store just the matrix weights for this vol...
-    if (!vol_face.mJointIndices)
-    {
-        // not very consty after all...
-        vol_face.allocateJointIndices(vol_face.mNumVertices);
-        just_weights = vol_face.mJustWeights;
-
-        U8* joint_indices_cursor = vol_face.mJointIndices;
-        for (int i = 0; i < vol_face.mNumVertices; i++)
-        {
-            F32* w = weights[i].getF32ptr();
-            F32* w_ = just_weights[i].getF32ptr();
-
-            F32 w0 = floorf(w[0]);
-            F32 w1 = floorf(w[1]);
-            F32 w2 = floorf(w[2]);
-            F32 w3 = floorf(w[3]);
-
-            joint_indices_cursor[0] = CONDITION_WEIGHT(w0);
-            joint_indices_cursor[1] = CONDITION_WEIGHT(w1);
-            joint_indices_cursor[2] = CONDITION_WEIGHT(w2);
-            joint_indices_cursor[3] = CONDITION_WEIGHT(w3);
-
-            // remove joint portion of combined weight
-            w_[0] = w[0] - w0;
-            w_[1] = w[1] - w1;
-            w_[2] = w[2] - w2;
-            w_[3] = w[3] - w3;
-
-            joint_indices_cursor += 4;
-        }
-    }
-#endif
-
-    U32 data_mask = face->getRiggedVertexBufferDataMask();
-    const LLMeshSkinInfo* skin = nullptr;
-
-	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
-			for (S32 i = 0; i < drawable->getNumFaces(); ++i)
-			{
-				LLFace* facep = drawable->getFace(i);
-				U32 face_data_mask = facep->getRiggedVertexBufferDataMask();
-				if (face_data_mask)
-				{
-					LLPointer<LLVertexBuffer> cur_buffer = facep->getVertexBuffer();
-					const LLVolumeFace& cur_vol_face = volume->getVolumeFace(i);
-					getRiggedGeometry(facep, cur_buffer, face_data_mask, skin, volume, cur_vol_face);
-				}
-			}
-			drawable->clearState(LLDrawable::REBUILD_ALL);
-
-			buffer = face->getVertexBuffer();
-		}
-		else
-		{
-			//just rebuild this face
-			getRiggedGeometry(face, buffer, data_mask, skin, volume, vol_face);
-		}
-	}
-
-	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;
-
-		bool has_normal = buffer->hasDataType(LLVertexBuffer::TYPE_NORMAL);
-		buffer->getVertexStrider(position);
-
-		if (has_normal)
+		const LLFace *facep = mDrawFace[0];
+		if (!facep->getDrawable())
 		{
-			buffer->getNormalStrider(normal);
-		}
-
-		LLVector4a* pos = (LLVector4a*) position.get();
-
-		LLVector4a* norm = has_normal ? (LLVector4a*) normal.get() : NULL;
-
-        const MatrixPaletteCache& mpc = updateSkinInfoMatrixPalette(avatar, vobj->getMeshID());
-        const LLMatrix4a* mat = &(mpc.mMatrixPalette[0]);
-        const LLMatrix4a& bind_shape_matrix = mpc.mBindShapeMatrix;
-
-        if (!mpc.mMatrixPalette.empty())
-        {
-            for (U32 j = 0; j < buffer->getNumVerts(); ++j)
-		    {
-			    LLMatrix4a final_mat;
-                LLSkinningUtil::getPerVertexSkinMatrix(weights[j].getF32ptr(), mat, false, final_mat, max_joints);
-
-			    LLVector4a& v = vol_face.mPositions[j];
-			    LLVector4a t;
-			    LLVector4a dst;
-			    bind_shape_matrix.affineTransform(v, t);
-			    final_mat.affineTransform(t, dst);
-			    pos[j] = dst;
-
-			    if (norm)
-			    {
-				    LLVector4a& n = vol_face.mNormals[j];
-				    bind_shape_matrix.rotate(n, t);
-				    final_mat.rotate(t, dst);
-				    //dst.normalize3fast();
-				    norm[j] = dst;
-			    }
-		    }
-        }
+			return;
+		}
+		avatarp = (LLVOAvatar *)facep->getDrawable()->getVObj().get();
 	}
-}
-
-void LLDrawPoolAvatar::renderRigged(LLVOAvatar* avatar, U32 type, bool glow)
-{
-    LL_PROFILE_ZONE_SCOPED
 
-	if (!avatar->shouldRenderRigged())
+    if (avatarp->isDead() || avatarp->mDrawable.isNull())
 	{
 		return;
 	}
 
-    LLUUID lastMeshId;
+    LL_RECORD_BLOCK_TIME(FTM_RENDER_CHARACTERS);
 
-	for (U32 i = 0; i < mRiggedFace[type].size(); ++i)
+	if (!single_avatar && !avatarp->isFullyLoaded() )
 	{
-        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;
-
-		LLDrawable* drawable = face->getDrawable();
-		if (!drawable)
+		if (pass==0 && (!gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_PARTICLES) || LLViewerPartSim::getMaxPartCount() <= 0))
 		{
-			continue;
+			// debug code to draw a sphere in place of avatar
+			gGL.getTexUnit(0)->bind(LLViewerFetchedTexture::sWhiteImagep);
+			gGL.setColorMask(true, true);
+			LLVector3 pos = avatarp->getPositionAgent();
+			gGL.color4f(1.0f, 1.0f, 1.0f, 0.7f);
+			
+			gGL.pushMatrix();	 
+			gGL.translatef((F32)(pos.mV[VX]),	 
+						   (F32)(pos.mV[VY]),	 
+							(F32)(pos.mV[VZ]));	 
+			 gGL.scalef(0.15f, 0.15f, 0.3f);
+
+			 gSphere.renderGGL();
+				 
+			 gGL.popMatrix();
+			 gGL.setColorMask(true, false);
 		}
+		// don't render please
+		return;
+	}
 
-		LLVOVolume* vobj = drawable->getVOVolume();
+	BOOL impostor = !LLPipeline::sImpostorRender && avatarp->isImpostor() && !single_avatar;
 
-		if (!vobj)
-		{
-			continue;
-		}
+	if (( avatarp->isInMuteList() 
+		  || impostor 
+		  || (LLVOAvatar::AOA_NORMAL != avatarp->getOverallAppearance() && !avatarp->needsImpostorUpdate()) ) && pass != 0)
+//		  || (LLVOAvatar::AV_DO_NOT_RENDER == avatarp->getVisualMuteSettings() && !avatarp->needsImpostorUpdate()) ) && pass != 0)
+	{ //don't draw anything but the impostor for impostored avatars
+		return;
+	}
+	
+	if (pass == 0 && !impostor && LLPipeline::sUnderWaterRender)
+	{ //don't draw foot shadows under water
+		return;
+	}
 
-		LLVolume* volume = vobj->getVolume();
-		S32 te = face->getTEOffset();
+	LLVOAvatar *attached_av = avatarp->getAttachedAvatar();
+	if (attached_av && LLVOAvatar::AOA_NORMAL != attached_av->getOverallAppearance())
+	{
+		// Animesh attachment of a jellydolled or invisible parent - don't show
+		return;
+	}
 
-		if (!volume || volume->getNumVolumeFaces() <= te || !volume->isMeshAssetLoaded())
+	if (pass == 0)
+	{
+		if (!LLPipeline::sReflectionRender)
 		{
-			continue;
+			LLVOAvatar::sNumVisibleAvatars++;
 		}
 
-		U32 data_mask = LLFace::getRiggedDataMask(type);
-
-		LLVertexBuffer* buff = face->getVertexBuffer();
-
-        const LLTextureEntry* tex_entry = face->getTextureEntry();
-		LLMaterial* mat = tex_entry ? tex_entry->getMaterialParams().get() : nullptr;
-
-        if (LLDrawPoolAvatar::sShadowPass >= 0)
-        {
-            bool is_alpha_blend = false;
-            bool is_alpha_mask  = false;
-
-            LLViewerTexture* tex = face->getTexture(LLRender::DIFFUSE_MAP);
-            if (tex)
-            {
-                if (tex->getIsAlphaMask())
-                {
-                    is_alpha_mask = true;
-                }
-            }
-
-            if (tex)
-            {
-                LLGLenum image_format = tex->getPrimaryFormat();
-                if (!is_alpha_mask && (image_format == GL_RGBA || image_format == GL_ALPHA))
-                {
-                    is_alpha_blend = true;
-                }
-            }
-
-            if (tex_entry)
-            {
-                if (tex_entry->getAlpha() <= 0.99f)
-                {
-                    is_alpha_blend = true;
-                }
-            }
-
-            if (mat)
-            {                
-                switch (LLMaterial::eDiffuseAlphaMode(mat->getDiffuseAlphaMode()))
-                {
-                    case LLMaterial::DIFFUSE_ALPHA_MODE_MASK:
-                    {
-                        is_alpha_mask  = true;
-                        is_alpha_blend = false;
-                    }
-                    break;
-
-                    case LLMaterial::DIFFUSE_ALPHA_MODE_BLEND:
-                    {
-                        is_alpha_blend = true;
-                        is_alpha_mask  = false;
-                    }
-                    break;
-
-                    case LLMaterial::DIFFUSE_ALPHA_MODE_EMISSIVE:
-                    case LLMaterial::DIFFUSE_ALPHA_MODE_DEFAULT:
-                    case LLMaterial::DIFFUSE_ALPHA_MODE_NONE:
-                    default:
-                        is_alpha_blend = false;
-                        is_alpha_mask  = false;
-                        break;
-                }
-            }
-
-            // if this is alpha mask content and we're doing opaques or a non-alpha-mask shadow pass...
-            if (is_alpha_mask && (LLDrawPoolAvatar::sSkipTransparent || LLDrawPoolAvatar::sShadowPass != SHADOW_PASS_ATTACHMENT_ALPHA_MASK))
-            {
-                return;
-            }
-
-            // if this is alpha blend content and we're doing opaques or a non-alpha-blend shadow pass...
-            if (is_alpha_blend && (LLDrawPoolAvatar::sSkipTransparent || LLDrawPoolAvatar::sShadowPass != SHADOW_PASS_ATTACHMENT_ALPHA_BLEND))
-            {
-                return;
-            }
-
-            // if this is opaque content and we're skipping opaques...
-            if (!is_alpha_mask && !is_alpha_blend && LLDrawPoolAvatar::sSkipOpaque)
-            {
-                return;
-            }
-        }
-
-		if (buff)
+//		if (impostor || (LLVOAvatar::AV_DO_NOT_RENDER == avatarp->getVisualMuteSettings() && !avatarp->needsImpostorUpdate()))
+		if (impostor || (LLVOAvatar::AOA_NORMAL != avatarp->getOverallAppearance() && !avatarp->needsImpostorUpdate()))
 		{
-			if (sShaderLevel > 0)
-			{
-                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();
-
-                    if (count == 0)
-                    {
-                        //skin info not loaded yet, don't render
-                        continue;
-                    }
-
-                    LLDrawPoolAvatar::sVertexProgram->uniformMatrix3x4fv(LLViewerShaderMgr::AVATAR_MATRIX,
-                        count,
-                        FALSE,
-                        (GLfloat*) &(mpc.mGLMp[0]));
-                }
-
-                lastMeshId = meshId;
-			}
-			else
-			{
-				data_mask &= ~LLVertexBuffer::MAP_WEIGHT4;
-			}
-
-			if (mat)
+			if (LLPipeline::sRenderDeferred && !LLPipeline::sReflectionRender && avatarp->mImpostor.isComplete()) 
 			{
-				//order is important here LLRender::DIFFUSE_MAP should be last, becouse it change 
-				//(gGL).mCurrTextureUnitIndex
-                LLViewerTexture* specular = NULL;
-                if (LLPipeline::sImpostorRender)
-                {
-                    specular = LLViewerTextureManager::findFetchedTexture(gBlackSquareID, TEX_LIST_STANDARD);
-                    llassert(NULL != specular);
-                }
-                else
-                {
-                    specular = face->getTexture(LLRender::SPECULAR_MAP);
-                }
-                if (specular && specular_channel >= 0)
-                {
-                    gGL.getTexUnit(specular_channel)->bindFast(specular);
-                }
-                
-                if (normal_channel >= 0)
-                {
-                    auto* texture = face->getTexture(LLRender::NORMAL_MAP);
-                    if (texture)
-                    {
-                        gGL.getTexUnit(normal_channel)->bindFast(texture);
-                    }
-                    //else
-                    //{
-                        // TODO handle missing normal map
-                    //}
-                }
-
-				gGL.getTexUnit(sDiffuseChannel)->bindFast(face->getTexture(LLRender::DIFFUSE_MAP));
-
-
-				LLColor4 col = mat->getSpecularLightColor();
-				F32 spec = mat->getSpecularLightExponent()/255.f;
-
-				F32 env = mat->getEnvironmentIntensity()/255.f;
-
-				if (mat->getSpecularID().isNull())
-				{
-					env = tex_entry->getShiny()*0.25f;
-					col.set(env,env,env,0);
-					spec = env;
-				}
-		
-				BOOL fullbright = tex_entry->getFullbright();
-
-				sVertexProgram->uniform1f(LLShaderMgr::EMISSIVE_BRIGHTNESS, fullbright ? 1.f : 0.f);
-				sVertexProgram->uniform4f(LLShaderMgr::SPECULAR_COLOR, col.mV[0], col.mV[1], col.mV[2], spec);
-				sVertexProgram->uniform1f(LLShaderMgr::ENVIRONMENT_INTENSITY, env);
-
-				if (mat->getDiffuseAlphaMode() == LLMaterial::DIFFUSE_ALPHA_MODE_MASK)
-				{
-                    F32 cutoff = mat->getAlphaMaskCutoff()/255.f;
-					sVertexProgram->setMinimumAlpha(cutoff);
-				}
-				else
+				if (normal_channel > -1)
 				{
-					sVertexProgram->setMinimumAlpha(0.f);
+					avatarp->mImpostor.bindTexture(2, normal_channel);
 				}
-
-                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
-			{
-				sVertexProgram->setMinimumAlpha(0.f);
-				if (normal_channel > -1)
+				if (specular_channel > -1)
 				{
-					LLDrawPoolBump::bindBumpMap(face, normal_channel);
+					avatarp->mImpostor.bindTexture(1, specular_channel);
 				}
-
-                gGL.getTexUnit(sDiffuseChannel)->bindFast(face->getTexture());
-
-			}
-
-			if (face->mTextureMatrix && vobj->mTexAnimMode)
-			{
-                U32 tex_index = gGL.getCurrentTexUnitIndex();
-
-                if (tex_index <= 1)
-                {
-                    gGL.matrixMode(LLRender::eMatrixMode(LLRender::MM_TEXTURE0 + tex_index));
-                    gGL.pushMatrix();
-				    gGL.loadMatrix((F32*) face->mTextureMatrix->mMatrix);
-                }
-
-				buff->setBufferFast(data_mask);
-				buff->drawRangeFast(LLRender::TRIANGLES, start, end, count, offset);
-
-                if (tex_index <= 1)
-                {
-                    gGL.matrixMode(LLRender::eMatrixMode(LLRender::MM_TEXTURE0 + tex_index));
-				    gGL.popMatrix();
-                    gGL.matrixMode(LLRender::MM_MODELVIEW);
-                }
-			}
-			else
-			{
-				buff->setBufferFast(data_mask);
-				buff->drawRangeFast(LLRender::TRIANGLES, start, end, count, offset);
 			}
+			avatarp->renderImpostor(avatarp->getMutedAVColor(), sDiffuseChannel);
 		}
+		return;
 	}
-}
 
-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);
-}
-
-static LLTrace::BlockTimerStatHandle FTM_RIGGED_VBO("Rigged VBO");
-
-void LLDrawPoolAvatar::updateRiggedVertexBuffers(LLVOAvatar* avatar)
-{
-	LL_RECORD_BLOCK_TIME(FTM_RIGGED_VBO);
-
-	//update rigged vertex buffers
-	for (U32 type = 0; type < NUM_RIGGED_PASSES; ++type)
+	if (pass == 1)
 	{
-        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)
-			{
-				continue;
-			}
-
-			LLVOVolume* vobj = drawable->getVOVolume();
-
-			if (!vobj || vobj->isNoLOD())
-			{
-				continue;
-			}
-
-			LLVolume* volume = vobj->getVolume();
-			S32 te = face->getTEOffset();
-
-			if (!volume || volume->getNumVolumeFaces() <= te)
-			{
-				continue;
-			}
-
-			LLVolumeFace& vol_face = volume->getVolumeFace(te);
-			updateRiggedFaceVertexBuffer(avatar, face, vobj, volume, vol_face);
-		}
+		// render rigid meshes (eyeballs) first
+		avatarp->renderRigid();
+		return;
 	}
-}
-
-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())
+	if ((sShaderLevel >= SHADER_LEVEL_CLOTH))
 	{
-		LLGLEnable blend(GL_BLEND);
-
-		gGL.setColorMask(true, true);
-		gGL.blendFunc(LLRender::BF_SOURCE_ALPHA,
-						LLRender::BF_ONE_MINUS_SOURCE_ALPHA,
-						LLRender::BF_ZERO,
-						LLRender::BF_ONE_MINUS_SOURCE_ALPHA);
-
-		renderRigged(avatar, RIGGED_ALPHA);
-		gGL.setColorMask(true, false);
-	}
-}
-
-void LLDrawPoolAvatar::renderRiggedFullbrightAlpha(LLVOAvatar* avatar)
-{
-    LL_PROFILE_ZONE_SCOPED
+		LLMatrix4 rot_mat;
+		LLViewerCamera::getInstance()->getMatrixToLocal(rot_mat);
+		LLMatrix4 cfr(OGL_TO_CFR_ROTATION);
+		rot_mat *= cfr;
+		
+		LLVector4 wind;
+		wind.setVec(avatarp->mWindVec);
+		wind.mV[VW] = 0;
+		wind = wind * rot_mat;
+		wind.mV[VW] = avatarp->mWindVec.mV[VW];
 
-	if (!mRiggedFace[RIGGED_FULLBRIGHT_ALPHA].empty())
-	{
-		LLGLEnable blend(GL_BLEND);
+		sVertexProgram->uniform4fv(LLViewerShaderMgr::AVATAR_WIND, 1, wind.mV);
+		F32 phase = -1.f * (avatarp->mRipplePhase);
 
-		gGL.setColorMask(true, true);
-		gGL.blendFunc(LLRender::BF_SOURCE_ALPHA,
-						LLRender::BF_ONE_MINUS_SOURCE_ALPHA,
-						LLRender::BF_ZERO,
-						LLRender::BF_ONE_MINUS_SOURCE_ALPHA);
+		F32 freq = 7.f + (noise1(avatarp->mRipplePhase) * 2.f);
+		LLVector4 sin_params(freq, freq, freq, phase);
+		sVertexProgram->uniform4fv(LLViewerShaderMgr::AVATAR_SINWAVE, 1, sin_params.mV);
 
-		renderRigged(avatar, RIGGED_FULLBRIGHT_ALPHA);
-		gGL.setColorMask(true, false);
+		LLVector4 gravity(0.f, 0.f, -CLOTHING_GRAVITY_EFFECT, 0.f);
+		gravity = gravity * rot_mat;
+		sVertexProgram->uniform4fv(LLViewerShaderMgr::AVATAR_GRAVITY, 1, gravity.mV);
 	}
-}
-
-void LLDrawPoolAvatar::renderRiggedGlow(LLVOAvatar* avatar)
-{
-    LL_PROFILE_ZONE_SCOPED
 
-	if (!mRiggedFace[RIGGED_GLOW].empty())
+	if( !single_avatar || (avatarp == single_avatar) )
 	{
-		LLGLEnable blend(GL_BLEND);
-		LLGLDisable test(GL_ALPHA_TEST);
-		gGL.flush();
-
-		LLGLEnable polyOffset(GL_POLYGON_OFFSET_FILL);
-		glPolygonOffset(-1.0f, -1.0f);
-		gGL.setSceneBlendType(LLRender::BT_ADD);
-
-		LLGLDepthTest depth(GL_TRUE, GL_FALSE);
-		gGL.setColorMask(false, true);
-
-		renderRigged(avatar, RIGGED_GLOW, true);
-
-		gGL.setColorMask(true, false);
-		gGL.setSceneBlendType(LLRender::BT_ALPHA);
+		avatarp->renderSkinned();
 	}
 }
 
-
+static LLTrace::BlockTimerStatHandle FTM_RIGGED_VBO("Rigged VBO");
 
 //-----------------------------------------------------------------------------
 // getDebugTexture()
@@ -2619,66 +940,6 @@ LLColor3 LLDrawPoolAvatar::getDebugColor() const
 	return LLColor3(0.f, 1.f, 0.f);
 }
 
-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)
-    {
-        LL_ERRS() << "adding rigged face that's already in another pool" << LL_ENDL;
-    }
-	if (type >= NUM_RIGGED_PASSES)
-	{
-		LL_ERRS() << "Invalid rigged face type." << LL_ENDL;
-	}
-	if (facep->getRiggedIndex(type) != -1)
-	{
-		LL_ERRS() << "Tried to add a rigged face that's referenced elsewhere." << LL_ENDL;
-	}	
-	
-	facep->setRiggedIndex(type, mRiggedFace[type].size());
-	facep->setPool(this);
-	mRiggedFace[type].push_back(facep);
-}
-
-void LLDrawPoolAvatar::removeRiggedFace(LLFace* facep)
-{
-    LL_PROFILE_ZONE_SCOPED
-
-    llassert (facep->isState(LLFace::RIGGED));
-    llassert(getType() == LLDrawPool::POOL_AVATAR || getType() == LLDrawPool::POOL_CONTROL_AV);
-    if (facep->getPool() != this)
-    {
-        LL_ERRS() << "Tried to remove a rigged face from the wrong pool" << LL_ENDL;
-    }
-	facep->setPool(NULL);
-
-	for (U32 i = 0; i < NUM_RIGGED_PASSES; ++i)
-	{
-		S32 index = facep->getRiggedIndex(i);
-		
-		if (index > -1)
-		{
-			if (mRiggedFace[i].size() > index && mRiggedFace[i][index] == facep)
-			{
-				facep->setRiggedIndex(i,-1);
-				mRiggedFace[i].erase(mRiggedFace[i].begin()+index);
-				for (U32 j = index; j < mRiggedFace[i].size(); ++j)
-				{ //bump indexes down for faces referenced after erased face
-					mRiggedFace[i][j]->setRiggedIndex(i, j);
-				}
-			}
-			else
-			{
-				LL_ERRS() << "Face reference data corrupt for rigged type " << i
-					<< ((mRiggedFace[i].size() <= index) ? "; wrong index (out of bounds)" : (mRiggedFace[i][index] != facep) ? "; wrong face pointer" : "")
-					<< LL_ENDL;
-			}
-		}
-	}
-}
 
 LLVertexBufferAvatar::LLVertexBufferAvatar()
 : LLVertexBuffer(sDataMask, 
diff --git a/indra/newview/lldrawpoolavatar.h b/indra/newview/lldrawpoolavatar.h
index 800bbc5f62..21add39b21 100644
--- a/indra/newview/lldrawpoolavatar.h
+++ b/indra/newview/lldrawpoolavatar.h
@@ -62,119 +62,11 @@ public:
     ~LLDrawPoolAvatar();
     /*virtual*/ BOOL isDead();
 
-    typedef enum
-	{
-		RIGGED_MATERIAL=0,
-		RIGGED_MATERIAL_ALPHA,
-		RIGGED_MATERIAL_ALPHA_MASK,
-		RIGGED_MATERIAL_ALPHA_EMISSIVE,
-		RIGGED_SPECMAP,
-		RIGGED_SPECMAP_BLEND,
-		RIGGED_SPECMAP_MASK,
-		RIGGED_SPECMAP_EMISSIVE,
-		RIGGED_NORMMAP,
-		RIGGED_NORMMAP_BLEND,
-		RIGGED_NORMMAP_MASK,
-		RIGGED_NORMMAP_EMISSIVE,
-		RIGGED_NORMSPEC,
-		RIGGED_NORMSPEC_BLEND,
-		RIGGED_NORMSPEC_MASK,
-		RIGGED_NORMSPEC_EMISSIVE,
-		RIGGED_SIMPLE,
-		RIGGED_FULLBRIGHT,
-		RIGGED_SHINY,
-		RIGGED_FULLBRIGHT_SHINY,
-		RIGGED_GLOW,
-		RIGGED_ALPHA,
-		RIGGED_FULLBRIGHT_ALPHA,
-		RIGGED_DEFERRED_BUMP,
-		RIGGED_DEFERRED_SIMPLE,
-		NUM_RIGGED_PASSES,
-		RIGGED_UNKNOWN,
-	} eRiggedPass;
-
-	typedef enum
-	{
-		RIGGED_MATERIAL_MASK =
-						LLVertexBuffer::MAP_VERTEX | 
-						LLVertexBuffer::MAP_NORMAL | 
-						LLVertexBuffer::MAP_TEXCOORD0 |
-						LLVertexBuffer::MAP_COLOR |
-						LLVertexBuffer::MAP_WEIGHT4,
-		RIGGED_MATERIAL_ALPHA_VMASK = RIGGED_MATERIAL_MASK,
-		RIGGED_MATERIAL_ALPHA_MASK_MASK = RIGGED_MATERIAL_MASK,
-		RIGGED_MATERIAL_ALPHA_EMISSIVE_MASK = RIGGED_MATERIAL_MASK,
-		RIGGED_SPECMAP_VMASK =
-						LLVertexBuffer::MAP_VERTEX | 
-						LLVertexBuffer::MAP_NORMAL | 
-						LLVertexBuffer::MAP_TEXCOORD0 |
-						LLVertexBuffer::MAP_TEXCOORD2 |
-						LLVertexBuffer::MAP_COLOR |
-						LLVertexBuffer::MAP_WEIGHT4,
-		RIGGED_SPECMAP_BLEND_MASK = RIGGED_SPECMAP_VMASK,
-		RIGGED_SPECMAP_MASK_MASK = RIGGED_SPECMAP_VMASK,
-		RIGGED_SPECMAP_EMISSIVE_MASK = RIGGED_SPECMAP_VMASK,
-		RIGGED_NORMMAP_VMASK =
-						LLVertexBuffer::MAP_VERTEX | 
-						LLVertexBuffer::MAP_NORMAL | 
-						LLVertexBuffer::MAP_TANGENT | 
-						LLVertexBuffer::MAP_TEXCOORD0 |
-						LLVertexBuffer::MAP_TEXCOORD1 |
-						LLVertexBuffer::MAP_COLOR |
-						LLVertexBuffer::MAP_WEIGHT4,
-		RIGGED_NORMMAP_BLEND_MASK = RIGGED_NORMMAP_VMASK,
-		RIGGED_NORMMAP_MASK_MASK = RIGGED_NORMMAP_VMASK,
-		RIGGED_NORMMAP_EMISSIVE_MASK = RIGGED_NORMMAP_VMASK,
-		RIGGED_NORMSPEC_VMASK =
-						LLVertexBuffer::MAP_VERTEX | 
-						LLVertexBuffer::MAP_NORMAL | 
-						LLVertexBuffer::MAP_TANGENT | 
-						LLVertexBuffer::MAP_TEXCOORD0 |
-						LLVertexBuffer::MAP_TEXCOORD1 |
-						LLVertexBuffer::MAP_TEXCOORD2 |
-						LLVertexBuffer::MAP_COLOR |
-						LLVertexBuffer::MAP_WEIGHT4,
-		RIGGED_NORMSPEC_BLEND_MASK = RIGGED_NORMSPEC_VMASK,
-		RIGGED_NORMSPEC_MASK_MASK = RIGGED_NORMSPEC_VMASK,
-		RIGGED_NORMSPEC_EMISSIVE_MASK = RIGGED_NORMSPEC_VMASK,
-		RIGGED_SIMPLE_MASK = LLVertexBuffer::MAP_VERTEX | 
-							 LLVertexBuffer::MAP_NORMAL | 
-							 LLVertexBuffer::MAP_TEXCOORD0 |
-							 LLVertexBuffer::MAP_COLOR |
-							 LLVertexBuffer::MAP_WEIGHT4,
-		RIGGED_FULLBRIGHT_MASK = LLVertexBuffer::MAP_VERTEX | 
-							 LLVertexBuffer::MAP_TEXCOORD0 |
-							 LLVertexBuffer::MAP_COLOR |
-							 LLVertexBuffer::MAP_WEIGHT4,
-		RIGGED_SHINY_MASK = RIGGED_SIMPLE_MASK,
-		RIGGED_FULLBRIGHT_SHINY_MASK = RIGGED_SIMPLE_MASK,							 
-		RIGGED_GLOW_MASK = LLVertexBuffer::MAP_VERTEX | 
-							 LLVertexBuffer::MAP_TEXCOORD0 |
-							 LLVertexBuffer::MAP_EMISSIVE |
-							 LLVertexBuffer::MAP_WEIGHT4,
-		RIGGED_ALPHA_MASK = RIGGED_SIMPLE_MASK,
-		RIGGED_FULLBRIGHT_ALPHA_MASK = RIGGED_FULLBRIGHT_MASK,
-		RIGGED_DEFERRED_BUMP_MASK = LLVertexBuffer::MAP_VERTEX | 
-							 LLVertexBuffer::MAP_NORMAL | 
-							 LLVertexBuffer::MAP_TEXCOORD0 |
-							 LLVertexBuffer::MAP_TANGENT |
-							 LLVertexBuffer::MAP_COLOR |
-							 LLVertexBuffer::MAP_WEIGHT4,
-		RIGGED_DEFERRED_SIMPLE_MASK = LLVertexBuffer::MAP_VERTEX | 
-							 LLVertexBuffer::MAP_NORMAL | 
-							 LLVertexBuffer::MAP_TEXCOORD0 |
-							 LLVertexBuffer::MAP_COLOR |
-							 LLVertexBuffer::MAP_WEIGHT4,
-	} eRiggedDataMask;
-
 typedef enum
 	{
 		SHADOW_PASS_AVATAR_OPAQUE,
         SHADOW_PASS_AVATAR_ALPHA_BLEND,
         SHADOW_PASS_AVATAR_ALPHA_MASK,
-        SHADOW_PASS_ATTACHMENT_ALPHA_BLEND,
-        SHADOW_PASS_ATTACHMENT_ALPHA_MASK,
-        SHADOW_PASS_ATTACHMENT_OPAQUE,
         NUM_SHADOW_PASSES
 	} eShadowPass;
 
@@ -215,101 +107,19 @@ typedef enum
 	void endImpostor();
 	void endSkinned();
 
-	void beginDeferredImpostor();
-	void beginDeferredRigid();
-	void beginDeferredSkinned();
-	
-	void endDeferredImpostor();
-	void endDeferredRigid();
-	void endDeferredSkinned();
-	
-	void beginPostDeferredAlpha();
-	void endPostDeferredAlpha();
-
-	void beginRiggedSimple();
-	void beginRiggedFullbright();
-	void beginRiggedFullbrightShiny();
-	void beginRiggedShinySimple();
-	void beginRiggedAlpha();
-	void beginRiggedFullbrightAlpha();
-	void beginRiggedGlow();
-	void beginDeferredRiggedAlpha();
-	void beginDeferredRiggedMaterial(S32 pass);
-	void beginDeferredRiggedMaterialAlpha(S32 pass);
-
-	void endRiggedSimple();
-	void endRiggedFullbright();
-	void endRiggedFullbrightShiny();
-	void endRiggedShinySimple();
-	void endRiggedAlpha();
-	void endRiggedFullbrightAlpha();
-	void endRiggedGlow();
-	void endDeferredRiggedAlpha();
-	void endDeferredRiggedMaterial(S32 pass);
-	void endDeferredRiggedMaterialAlpha(S32 pass);
-
-	void beginDeferredRiggedSimple();
-	void beginDeferredRiggedBump();
-	
-	void endDeferredRiggedSimple();
-	void endDeferredRiggedBump();
-		
-	void getRiggedGeometry(LLFace* face, LLPointer<LLVertexBuffer>& buffer, U32 data_mask, const LLMeshSkinInfo* skin, LLVolume* volume, const LLVolumeFace& vol_face);
-	void updateRiggedFaceVertexBuffer(LLVOAvatar* avatar,
-									  LLFace* facep, 
-									  const LLVOVolume* vobj,
-									  LLVolume* volume,
-									  LLVolumeFace& vol_face);
-	void updateRiggedVertexBuffers(LLVOAvatar* avatar);
+    void beginDeferredRigid();
+    void beginDeferredImpostor();
+    void beginDeferredSkinned();
 
-    void updateSkinInfoMatrixPalettes(LLVOAvatar* avatarp);
-
-	void renderRigged(LLVOAvatar* avatar, U32 type, bool glow = false);
-	void renderRiggedSimple(LLVOAvatar* avatar);
-	void renderRiggedAlpha(LLVOAvatar* avatar);
-	void renderRiggedFullbrightAlpha(LLVOAvatar* avatar);
-	void renderRiggedFullbright(LLVOAvatar* avatar);
-	void renderRiggedShinySimple(LLVOAvatar* avatar);
-	void renderRiggedFullbrightShiny(LLVOAvatar* avatar);
-	void renderRiggedGlow(LLVOAvatar* avatar);
-	void renderDeferredRiggedSimple(LLVOAvatar* avatar);
-	void renderDeferredRiggedBump(LLVOAvatar* avatar);
-	void renderDeferredRiggedMaterial(LLVOAvatar* avatar, S32 pass);
-	
-	
-
-	void addRiggedFace(LLFace* facep, U32 type);
-	void removeRiggedFace(LLFace* facep); 
-
-	std::vector<LLFace*> mRiggedFace[NUM_RIGGED_PASSES];
-
-    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;
+    void endDeferredRigid();
+    void endDeferredImpostor();
+    void endDeferredSkinned();
 
 	/*virtual*/ LLViewerTexture *getDebugTexture();
 	/*virtual*/ LLColor3 getDebugColor() const; // For AGP debug display
 
 	void renderAvatars(LLVOAvatar *single_avatar, S32 pass = -1); // renders only one avatar if single_avatar is not null.
 
-
 	static BOOL sSkipOpaque;
 	static BOOL sSkipTransparent;
     static S32  sShadowPass;
diff --git a/indra/newview/lldrawpoolbump.cpp b/indra/newview/lldrawpoolbump.cpp
index 8f3b0c99b4..af8b194f38 100644
--- a/indra/newview/lldrawpoolbump.cpp
+++ b/indra/newview/lldrawpoolbump.cpp
@@ -47,6 +47,7 @@
 #include "pipeline.h"
 #include "llspatialpartition.h"
 #include "llviewershadermgr.h"
+#include "llmodel.h"
 
 //#include "llimagebmp.h"
 //#include "../tools/imdebug/imdebug.h"
@@ -203,22 +204,11 @@ S32 LLDrawPoolBump::numBumpPasses()
 	{
 		if (mShaderLevel > 1)
 		{
-			if (LLPipeline::sImpostorRender)
-			{
-				return 2;
-			}
-			else
-			{
-				return 3;
-			}
-		}
-		else if (LLPipeline::sImpostorRender)
-		{
-			return 1;
+			return 6;
 		}
 		else
 		{
-			return 2;
+			return 4;
 		}
 	}
     else
@@ -235,6 +225,8 @@ S32 LLDrawPoolBump::getNumPasses()
 void LLDrawPoolBump::beginRenderPass(S32 pass)
 {
 	LL_RECORD_BLOCK_TIME(FTM_RENDER_BUMP);
+    mRigged = ((pass % 2) == 1);
+    pass /= 2;
 	switch( pass )
 	{
 		case 0:
@@ -267,7 +259,7 @@ void LLDrawPoolBump::render(S32 pass)
 	{
 		return;
 	}
-	
+    pass /= 2;
 	switch( pass )
 	{
 		case 0:
@@ -295,6 +287,7 @@ void LLDrawPoolBump::render(S32 pass)
 void LLDrawPoolBump::endRenderPass(S32 pass)
 {
 	LL_RECORD_BLOCK_TIME(FTM_RENDER_BUMP);
+    pass /= 2;
 	switch( pass )
 	{
 		case 0:
@@ -326,12 +319,7 @@ void LLDrawPoolBump::endRenderPass(S32 pass)
 void LLDrawPoolBump::beginShiny(bool invisible)
 {
 	LL_RECORD_BLOCK_TIME(FTM_RENDER_SHINY);
-	if ((!invisible && !gPipeline.hasRenderBatches(LLRenderPass::PASS_SHINY))|| 
-		(invisible && !gPipeline.hasRenderBatches(LLRenderPass::PASS_INVISI_SHINY)))
-	{
-		return;
-	}
-
+	
 	mShiny = TRUE;
 	sVertexMask = VERTEX_MASK_SHINY;
 	// Second pass: environment map
@@ -340,31 +328,31 @@ void LLDrawPoolBump::beginShiny(bool invisible)
 		sVertexMask = VERTEX_MASK_SHINY | LLVertexBuffer::MAP_TEXCOORD0;
 	}
 	
-	if (getShaderLevel() > 0)
+	if (LLPipeline::sUnderWaterRender)
 	{
-		if (LLPipeline::sUnderWaterRender)
-		{
-			shader = &gObjectShinyWaterProgram;
-		}
-		else
-		{
-			shader = &gObjectShinyProgram;
-		}
-		shader->bind();
-        if (LLPipeline::sRenderingHUDs)
-        {
-            shader->uniform1i(LLShaderMgr::NO_ATMO, 1);
-        }
-        else
-        {
-            shader->uniform1i(LLShaderMgr::NO_ATMO, 0);
-        }
+		shader = &gObjectShinyWaterProgram;
 	}
 	else
 	{
-		shader = NULL;
+		shader = &gObjectShinyProgram;
 	}
 
+    if (mRigged)
+    {
+        llassert(shader->mRiggedVariant);
+        shader = shader->mRiggedVariant;
+    }
+
+	shader->bind();
+    if (LLPipeline::sRenderingHUDs)
+    {
+        shader->uniform1i(LLShaderMgr::NO_ATMO, 1);
+    }
+    else
+    {
+        shader->uniform1i(LLShaderMgr::NO_ATMO, 0);
+    }
+
 	bindCubeMap(shader, mShaderLevel, diffuse_channel, cube_channel, invisible);
 
 	if (mShaderLevel > 1)
@@ -391,7 +379,6 @@ void LLDrawPoolBump::bindCubeMap(LLGLSLShader* shader, S32 shader_level, S32& di
 			shader->uniform4fv(LLViewerShaderMgr::SHINY_ORIGIN, 1, vec4.mV);			
 			if (shader_level > 1)
 			{
-				cube_map->setMatrix(1);
 				// Make sure that texture coord generation happens for tex unit 1, as that's the one we use for 
 				// the cube map in the one pass shiny shaders
 				cube_channel = shader->enableTexture(LLViewerShaderMgr::ENVIRONMENT_MAP, LLTexUnit::TT_CUBE_MAP);
@@ -403,7 +390,6 @@ void LLDrawPoolBump::bindCubeMap(LLGLSLShader* shader, S32 shader_level, S32& di
 			{
 				cube_channel = shader->enableTexture(LLViewerShaderMgr::ENVIRONMENT_MAP, LLTexUnit::TT_CUBE_MAP);
 				diffuse_channel = -1;
-				cube_map->setMatrix(0);
 				cube_map->enable(cube_channel);
 			}			
 			gGL.getTexUnit(cube_channel)->bind(cube_map);
@@ -415,7 +401,6 @@ void LLDrawPoolBump::bindCubeMap(LLGLSLShader* shader, S32 shader_level, S32& di
 			diffuse_channel = -1;
 			gGL.getTexUnit(0)->disable();
 			cube_map->enable(0);
-			cube_map->setMatrix(0);
 			gGL.getTexUnit(0)->bind(cube_map);
 
 			gGL.getTexUnit(0)->setTextureColorBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_TEX_COLOR);
@@ -427,27 +412,32 @@ void LLDrawPoolBump::bindCubeMap(LLGLSLShader* shader, S32 shader_level, S32& di
 void LLDrawPoolBump::renderShiny(bool invisible)
 {
 	LL_RECORD_BLOCK_TIME(FTM_RENDER_SHINY);
-	if ((!invisible && !gPipeline.hasRenderBatches(LLRenderPass::PASS_SHINY))|| 
-		(invisible && !gPipeline.hasRenderBatches(LLRenderPass::PASS_INVISI_SHINY)))
-	{
-		return;
-	}
-
+	
 	if( gSky.mVOSkyp->getCubeMap() )
 	{
 		LLGLEnable blend_enable(GL_BLEND);
 		if (!invisible && mShaderLevel > 1)
 		{
-			LLRenderPass::pushBatches(LLRenderPass::PASS_SHINY, sVertexMask | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
+            if (mRigged)
+            {
+                LLRenderPass::pushRiggedBatches(LLRenderPass::PASS_SHINY_RIGGED, sVertexMask | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
+            }
+            else
+            {
+                LLRenderPass::pushBatches(LLRenderPass::PASS_SHINY, sVertexMask | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
+            }
 		}
 		else if (!invisible)
 		{
-			renderGroups(LLRenderPass::PASS_SHINY, sVertexMask);
+            if (mRigged)
+            {
+                gPipeline.renderRiggedGroups(this, LLRenderPass::PASS_SHINY_RIGGED, sVertexMask, TRUE);
+            }
+            else
+            {
+                gPipeline.renderGroups(this, LLRenderPass::PASS_SHINY, sVertexMask, TRUE);
+            }
 		}
-		//else // invisible (deprecated)
-		//{
-			//renderGroups(LLRenderPass::PASS_INVISI_SHINY, sVertexMask);
-		//}
 	}
 }
 
@@ -472,27 +462,12 @@ void LLDrawPoolBump::unbindCubeMap(LLGLSLShader* shader, S32 shader_level, S32&
         // Moved below shader->disableTexture call to avoid false alarms from auto-re-enable of textures on stage 0
         // MAINT-755
 		cube_map->disable();
-		cube_map->restoreMatrix();
-	}
-
-	if (!LLGLSLShader::sNoFixedFunction)
-	{
-		gGL.getTexUnit(diffuse_channel)->disable();
-		gGL.getTexUnit(cube_channel)->disable();
-
-		gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
-		gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
 	}
 }
 
 void LLDrawPoolBump::endShiny(bool invisible)
 {
 	LL_RECORD_BLOCK_TIME(FTM_RENDER_SHINY);
-	if ((!invisible && !gPipeline.hasRenderBatches(LLRenderPass::PASS_SHINY))|| 
-		(invisible && !gPipeline.hasRenderBatches(LLRenderPass::PASS_INVISI_SHINY)))
-	{
-		return;
-	}
 
 	unbindCubeMap(shader, mShaderLevel, diffuse_channel, cube_channel, invisible);
 	if (shader)
@@ -508,11 +483,7 @@ void LLDrawPoolBump::endShiny(bool invisible)
 void LLDrawPoolBump::beginFullbrightShiny()
 {
 	LL_RECORD_BLOCK_TIME(FTM_RENDER_SHINY);
-	if (!gPipeline.hasRenderBatches(LLRenderPass::PASS_FULLBRIGHT_SHINY))
-	{
-		return;
-	}
-
+	
 	sVertexMask = VERTEX_MASK_SHINY | LLVertexBuffer::MAP_TEXCOORD0;
 
 	// Second pass: environment map
@@ -533,6 +504,12 @@ void LLDrawPoolBump::beginFullbrightShiny()
 		}
 	}
 
+    if (mRigged)
+    {
+        llassert(shader->mRiggedVariant);
+        shader = shader->mRiggedVariant;
+    }
+
 	LLCubeMap* cube_map = gSky.mVOSkyp ? gSky.mVOSkyp->getCubeMap() : NULL;
 	if( cube_map )
 	{
@@ -553,9 +530,8 @@ void LLDrawPoolBump::beginFullbrightShiny()
 
 		LLVector3 vec = LLVector3(gShinyOrigin) * mat;
 		LLVector4 vec4(vec, gShinyOrigin.mV[3]);
-		shader->uniform4fv(LLViewerShaderMgr::SHINY_ORIGIN, 1, vec4.mV);			
+		shader->uniform4fv(LLViewerShaderMgr::SHINY_ORIGIN, 1, vec4.mV);
 
-		cube_map->setMatrix(1);
 		// Make sure that texture coord generation happens for tex unit 1, as that's the one we use for 
 		// the cube map in the one pass shiny shaders
 		gGL.getTexUnit(1)->disable();
@@ -579,10 +555,6 @@ void LLDrawPoolBump::beginFullbrightShiny()
 void LLDrawPoolBump::renderFullbrightShiny()
 {
 	LL_RECORD_BLOCK_TIME(FTM_RENDER_SHINY);
-	if (!gPipeline.hasRenderBatches(LLRenderPass::PASS_FULLBRIGHT_SHINY))
-	{
-		return;
-	}
 
 	if( gSky.mVOSkyp->getCubeMap() )
 	{
@@ -590,11 +562,25 @@ void LLDrawPoolBump::renderFullbrightShiny()
 
 		if (mShaderLevel > 1)
 		{
-			LLRenderPass::pushBatches(LLRenderPass::PASS_FULLBRIGHT_SHINY, sVertexMask | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
+            if (mRigged)
+            {
+                LLRenderPass::pushRiggedBatches(LLRenderPass::PASS_FULLBRIGHT_SHINY_RIGGED, sVertexMask | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
+            }
+            else
+            {
+                LLRenderPass::pushBatches(LLRenderPass::PASS_FULLBRIGHT_SHINY, sVertexMask | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
+            }
 		}
 		else
 		{
-			LLRenderPass::renderTexture(LLRenderPass::PASS_FULLBRIGHT_SHINY, sVertexMask);
+            if (mRigged)
+            {
+                LLRenderPass::pushRiggedBatches(LLRenderPass::PASS_FULLBRIGHT_SHINY_RIGGED, sVertexMask);
+            }
+            else
+            {
+                LLRenderPass::pushBatches(LLRenderPass::PASS_FULLBRIGHT_SHINY, sVertexMask);
+            }
 		}
 	}
 }
@@ -602,18 +588,13 @@ void LLDrawPoolBump::renderFullbrightShiny()
 void LLDrawPoolBump::endFullbrightShiny()
 {
 	LL_RECORD_BLOCK_TIME(FTM_RENDER_SHINY);
-	if (!gPipeline.hasRenderBatches(LLRenderPass::PASS_FULLBRIGHT_SHINY))
-	{
-		return;
-	}
 
 	LLCubeMap* cube_map = gSky.mVOSkyp ? gSky.mVOSkyp->getCubeMap() : NULL;
 	if( cube_map )
 	{
 		cube_map->disable();
-		cube_map->restoreMatrix();
 
-		/*if (diffuse_channel != 0)
+        /*if (diffuse_channel != 0)
 		{
 			shader->disableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
 		}
@@ -726,53 +707,22 @@ BOOL LLDrawPoolBump::bindBumpMap(U8 bump_code, LLViewerTexture* texture, F32 vsi
 }
 
 //static
-void LLDrawPoolBump::beginBump(U32 pass)
+void LLDrawPoolBump::beginBump()
 {	
-	if (!gPipeline.hasRenderBatches(pass))
-	{
-		return;
-	}
-
 	sVertexMask = VERTEX_MASK_BUMP;
 	LL_RECORD_BLOCK_TIME(FTM_RENDER_BUMP);
 	// Optional second pass: emboss bump map
 	stop_glerror();
 
-	if (LLGLSLShader::sNoFixedFunction)
-	{
-		gObjectBumpProgram.bind();
-	}
-	else
-	{
-		// TEXTURE UNIT 0
-		// Output.rgb = texture at texture coord 0
-		gGL.getTexUnit(0)->activate();
-
-		gGL.getTexUnit(0)->setTextureColorBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_TEX_ALPHA);
-		gGL.getTexUnit(0)->setTextureAlphaBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_TEX_ALPHA);
+    shader = &gObjectBumpProgram;
 
-		// TEXTURE UNIT 1
-		gGL.getTexUnit(1)->activate();
- 
-		gGL.getTexUnit(1)->enable(LLTexUnit::TT_TEXTURE);
-
-		gGL.getTexUnit(1)->setTextureColorBlend(LLTexUnit::TBO_ADD_SIGNED, LLTexUnit::TBS_PREV_COLOR, LLTexUnit::TBS_ONE_MINUS_TEX_ALPHA);
-		gGL.getTexUnit(1)->setTextureAlphaBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_TEX_ALPHA);
-
-		// src	= tex0 + (1 - tex1) - 0.5
-		//		= (bump0/2 + 0.5) + (1 - (bump1/2 + 0.5)) - 0.5
-		//		= (1 + bump0 - bump1) / 2
+    if (mRigged)
+    {
+        llassert(shader->mRiggedVariant);
+        shader = shader->mRiggedVariant;
+    }
 
-
-		// Blend: src * dst + dst * src
-		//		= 2 * src * dst
-		//		= 2 * ((1 + bump0 - bump1) / 2) * dst   [0 - 2 * dst]
-		//		= (1 + bump0 - bump1) * dst.rgb
-		//		= dst.rgb + dst.rgb * (bump0 - bump1)
-
-		gGL.getTexUnit(0)->activate();
-		gGL.getTexUnit(1)->unbind(LLTexUnit::TT_TEXTURE);
-	}
+    shader->bind();
 
 	gGL.setSceneBlendType(LLRender::BT_MULT_X2);
 	stop_glerror();
@@ -781,11 +731,6 @@ void LLDrawPoolBump::beginBump(U32 pass)
 //static
 void LLDrawPoolBump::renderBump(U32 pass)
 {
-	if (!gPipeline.hasRenderBatches(pass))
-	{
-		return;
-	}
-
 	LL_RECORD_BLOCK_TIME(FTM_RENDER_BUMP);
 	LLGLDisable fog(GL_FOG);
 	LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE, GL_LEQUAL);
@@ -800,11 +745,6 @@ void LLDrawPoolBump::renderBump(U32 pass)
 //static
 void LLDrawPoolBump::endBump(U32 pass)
 {
-	if (!gPipeline.hasRenderBatches(pass))
-	{
-		return;
-	}
-
 	if (LLGLSLShader::sNoFixedFunction)
 	{
 		gObjectBumpProgram.unbind();
@@ -828,7 +768,7 @@ S32 LLDrawPoolBump::getNumDeferredPasses()
 { 
 	if (gSavedSettings.getBOOL("RenderObjectBump"))
 	{
-		return 1;
+		return 2;
 	}
 	else
 	{
@@ -838,66 +778,86 @@ S32 LLDrawPoolBump::getNumDeferredPasses()
 
 void LLDrawPoolBump::beginDeferredPass(S32 pass)
 {
-	if (!gPipeline.hasRenderBatches(LLRenderPass::PASS_BUMP))
+	if (!gPipeline.hasRenderBatches( pass == 0 ? LLRenderPass::PASS_BUMP : LLRenderPass::PASS_BUMP_RIGGED))
 	{
 		return;
 	}
 	LL_RECORD_BLOCK_TIME(FTM_RENDER_BUMP);
 	mShiny = TRUE;
-	gDeferredBumpProgram.bind();
-	diffuse_channel = gDeferredBumpProgram.enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
-	bump_channel = gDeferredBumpProgram.enableTexture(LLViewerShaderMgr::BUMP_MAP);
+	gDeferredBumpProgram.bind(pass == 1);
+	diffuse_channel = LLGLSLShader::sCurBoundShaderPtr->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
+	bump_channel = LLGLSLShader::sCurBoundShaderPtr->enableTexture(LLViewerShaderMgr::BUMP_MAP);
 	gGL.getTexUnit(diffuse_channel)->unbind(LLTexUnit::TT_TEXTURE);
 	gGL.getTexUnit(bump_channel)->unbind(LLTexUnit::TT_TEXTURE);
 }
 
 void LLDrawPoolBump::endDeferredPass(S32 pass)
 {
-	if (!gPipeline.hasRenderBatches(LLRenderPass::PASS_BUMP))
+	if (!gPipeline.hasRenderBatches(pass == 0 ? LLRenderPass::PASS_BUMP : LLRenderPass::PASS_BUMP_RIGGED))
 	{
 		return;
 	}
 	LL_RECORD_BLOCK_TIME(FTM_RENDER_BUMP);
 	mShiny = FALSE;
-	gDeferredBumpProgram.disableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
-	gDeferredBumpProgram.disableTexture(LLViewerShaderMgr::BUMP_MAP);
-	gDeferredBumpProgram.unbind();
+    LLGLSLShader::sCurBoundShaderPtr->disableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
+    LLGLSLShader::sCurBoundShaderPtr->disableTexture(LLViewerShaderMgr::BUMP_MAP);
+    LLGLSLShader::sCurBoundShaderPtr->unbind();
 	gGL.getTexUnit(0)->activate();
 }
 
 void LLDrawPoolBump::renderDeferred(S32 pass)
 {
-	if (!gPipeline.hasRenderBatches(LLRenderPass::PASS_BUMP))
+    if (!gPipeline.hasRenderBatches(pass == 0 ? LLRenderPass::PASS_BUMP : LLRenderPass::PASS_BUMP_RIGGED))
 	{
 		return;
 	}
 	LL_RECORD_BLOCK_TIME(FTM_RENDER_BUMP);
 
-	U32 type = LLRenderPass::PASS_BUMP;
-	LLCullResult::drawinfo_iterator begin = gPipeline.beginRenderMap(type);
-	LLCullResult::drawinfo_iterator end = gPipeline.endRenderMap(type);
+    bool rigged = pass == 1;
+    U32 type = rigged ? LLRenderPass::PASS_BUMP_RIGGED : LLRenderPass::PASS_BUMP;
+    LLCullResult::drawinfo_iterator begin = gPipeline.beginRenderMap(type);
+    LLCullResult::drawinfo_iterator end = gPipeline.endRenderMap(type);
 
-	U32 mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_TANGENT | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_COLOR;
-	
-	for (LLCullResult::drawinfo_iterator i = begin; i != end; ++i)	
-	{
-		LLDrawInfo& params = **i;
+    U32 mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_TANGENT | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_COLOR;
 
-		gDeferredBumpProgram.setMinimumAlpha(params.mAlphaMaskCutoff);
-		LLDrawPoolBump::bindBumpMap(params, bump_channel);
-		pushBatch(params, mask, TRUE);
-	}
+    LLVOAvatar* avatar = nullptr;
+    U64 skin = 0;
+
+    for (LLCullResult::drawinfo_iterator i = begin; i != end; ++i)
+    {
+        LLDrawInfo& params = **i;
+
+        LLGLSLShader::sCurBoundShaderPtr->setMinimumAlpha(params.mAlphaMaskCutoff);
+        LLDrawPoolBump::bindBumpMap(params, bump_channel);
+
+        if (rigged)
+        {
+            if (avatar != params.mAvatar || skin != params.mSkinInfo->mHash)
+            {
+                uploadMatrixPalette(params);
+                avatar = params.mAvatar;
+                skin = params.mSkinInfo->mHash;
+            }
+            pushBatch(params, mask | LLVertexBuffer::MAP_WEIGHT4, TRUE, FALSE);
+        }
+        else
+        {
+            pushBatch(params, mask, TRUE, FALSE);
+        }
+    }
 }
 
 void LLDrawPoolBump::beginPostDeferredPass(S32 pass)
 {
+    mRigged = ((pass % 2) == 1);
+    pass /= 2;
 	switch (pass)
 	{
 	case 0:
 		beginFullbrightShiny();
 		break;
 	case 1:
-		beginBump(LLRenderPass::PASS_POST_BUMP);
+		beginBump();
 		break;
 	}
 }
@@ -920,6 +880,7 @@ void LLDrawPoolBump::endPostDeferredPass(S32 pass)
 
 void LLDrawPoolBump::renderPostDeferred(S32 pass)
 {
+    pass /= 2;
 	switch (pass)
 	{
 	case 0:
@@ -1462,8 +1423,17 @@ void LLBumpImageList::onSourceLoaded( BOOL success, LLViewerTexture *src_vi, LLI
 
 void LLDrawPoolBump::renderBump(U32 type, U32 mask)
 {	
-	LLCullResult::drawinfo_iterator begin = gPipeline.beginRenderMap(type);
-	LLCullResult::drawinfo_iterator end = gPipeline.endRenderMap(type);
+    LLVOAvatar* avatar = nullptr;
+    U64 skin = 0;
+
+    if (mRigged)
+    { // nudge type enum and include skinweights for rigged pass
+        type += 1;
+        mask |= LLVertexBuffer::MAP_WEIGHT4;
+    }
+
+    LLCullResult::drawinfo_iterator begin = gPipeline.beginRenderMap(type);
+    LLCullResult::drawinfo_iterator end = gPipeline.endRenderMap(type);
 
 	for (LLCullResult::drawinfo_iterator i = begin; i != end; ++i)	
 	{
@@ -1471,6 +1441,21 @@ void LLDrawPoolBump::renderBump(U32 type, U32 mask)
 
 		if (LLDrawPoolBump::bindBumpMap(params))
 		{
+            if (mRigged)
+            {
+                if (avatar != params.mAvatar || skin != params.mSkinInfo->mHash)
+                {
+                    if (uploadMatrixPalette(params))
+                    {
+                        avatar = params.mAvatar;
+                        skin = params.mSkinInfo->mHash;
+                    }
+                    else
+                    {
+                        continue;
+                    }
+                }
+            }
 			pushBatch(params, mask, FALSE);
 		}
 	}
diff --git a/indra/newview/lldrawpoolbump.h b/indra/newview/lldrawpoolbump.h
index bab160c34d..d76e925eb0 100644
--- a/indra/newview/lldrawpoolbump.h
+++ b/indra/newview/lldrawpoolbump.h
@@ -57,7 +57,7 @@ public:
 	virtual void endRenderPass( S32 pass );
 	virtual S32	 getNumPasses();
 	/*virtual*/ void prerender();
-	/*virtual*/ void pushBatch(LLDrawInfo& params, U32 mask, BOOL texture, BOOL batch_textures = FALSE);
+	void pushBatch(LLDrawInfo& params, U32 mask, BOOL texture, BOOL batch_textures = FALSE) override;
 
 	void renderBump(U32 type, U32 mask);
 	void renderGroup(LLSpatialGroup* group, U32 type, U32 mask, BOOL texture);
@@ -72,7 +72,7 @@ public:
 	void renderFullbrightShiny();
 	void endFullbrightShiny();
 
-	void beginBump(U32 pass = LLRenderPass::PASS_BUMP);
+	void beginBump();
 	void renderBump(U32 pass = LLRenderPass::PASS_BUMP);
 	void endBump(U32 pass = LLRenderPass::PASS_BUMP);
 
@@ -84,7 +84,7 @@ public:
 	/*virtual*/ void endDeferredPass(S32 pass);
 	/*virtual*/ void renderDeferred(S32 pass);
 
-	virtual S32 getNumPostDeferredPasses() { return 2; }
+	virtual S32 getNumPostDeferredPasses() { return 4; }
 	/*virtual*/ void beginPostDeferredPass(S32 pass);
 	/*virtual*/ void endPostDeferredPass(S32 pass);
 	/*virtual*/ void renderPostDeferred(S32 pass);
@@ -94,6 +94,7 @@ public:
 
 private:
 	static BOOL bindBumpMap(U8 bump_code, LLViewerTexture* tex, F32 vsize, S32 channel);
+    bool mRigged = false; // if true, doing a rigged pass
 
 };
 
diff --git a/indra/newview/lldrawpoolmaterials.cpp b/indra/newview/lldrawpoolmaterials.cpp
index d2a8757379..fd5850084b 100644
--- a/indra/newview/lldrawpoolmaterials.cpp
+++ b/indra/newview/lldrawpoolmaterials.cpp
@@ -31,6 +31,7 @@
 #include "llviewershadermgr.h"
 #include "pipeline.h"
 #include "llglcommonfunc.h"
+#include "llvoavatar.h"
 
 S32 diffuse_channel = -1;
 
@@ -47,11 +48,18 @@ void LLDrawPoolMaterials::prerender()
 
 S32 LLDrawPoolMaterials::getNumDeferredPasses()
 {
-	return 12;
+    // 12 render passes times 2 (one for each rigged and non rigged)
+	return 12*2;
 }
 
 void LLDrawPoolMaterials::beginDeferredPass(S32 pass)
 {
+    bool rigged = false;
+    if (pass >= 12)
+    { 
+        rigged = true;
+        pass -= 12;
+    }
 	U32 shader_idx[] = 
 	{
 		0, //LLRenderPass::PASS_MATERIAL,
@@ -72,13 +80,22 @@ void LLDrawPoolMaterials::beginDeferredPass(S32 pass)
 		15, //LLRenderPass::PASS_NORMSPEC_GLOW,
 	};
 	
-	mShader = &(gDeferredMaterialProgram[shader_idx[pass]]);
-
-	if (LLPipeline::sUnderWaterRender)
-	{
-		mShader = &(gDeferredMaterialWaterProgram[shader_idx[pass]]);
-	}
-
+    U32 idx = shader_idx[pass];
+    
+    if (LLPipeline::sUnderWaterRender)
+    {
+        mShader = &(gDeferredMaterialWaterProgram[idx]);
+    }
+    else
+    {
+        mShader = &(gDeferredMaterialProgram[idx]);
+    }
+    
+    if (rigged)
+    {
+        llassert(mShader->mRiggedVariant != nullptr);
+        mShader = mShader->mRiggedVariant;
+    }
 	mShader->bind();
 
     if (LLPipeline::sRenderingHUDs)
@@ -127,9 +144,20 @@ void LLDrawPoolMaterials::renderDeferred(S32 pass)
 		LLRenderPass::PASS_NORMSPEC_EMISSIVE,
 	};
 
+    bool rigged = false;
+    if (pass >= 12)
+    {
+        rigged = true;
+        pass -= 12;
+    }
+
 	llassert(pass < sizeof(type_list)/sizeof(U32));
 
 	U32 type = type_list[pass];
+    if (rigged)
+    {
+        type += 1;
+    }
 
 	U32 mask = mShader->mAttributeMask;
 
@@ -160,7 +188,7 @@ void LLDrawPoolMaterials::renderDeferred(S32 pass)
 
         {
             LL_PROFILE_ZONE_SCOPED;
-            pushMaterialsBatch(params, mask);
+            pushMaterialsBatch(params, mask, rigged);
         }
 	}
 }
@@ -175,7 +203,7 @@ void LLDrawPoolMaterials::bindNormalMap(LLViewerTexture* tex)
 	mShader->bindTexture(LLShaderMgr::BUMP_MAP, tex);
 }
 
-void LLDrawPoolMaterials::pushMaterialsBatch(LLDrawInfo& params, U32 mask)
+void LLDrawPoolMaterials::pushMaterialsBatch(LLDrawInfo& params, U32 mask, bool rigged)
 {
     LL_PROFILE_ZONE_SCOPED;
 	applyModelMatrix(params);
@@ -214,6 +242,24 @@ void LLDrawPoolMaterials::pushMaterialsBatch(LLDrawInfo& params, U32 mask)
 		params.mGroup->rebuildMesh();
 	}
 
+    // upload matrix palette to shader
+    if (rigged)
+    {
+        const LLVOAvatar::MatrixPaletteCache& mpc = params.mAvatar->updateSkinInfoMatrixPalette(params.mSkinInfo);
+        U32 count = mpc.mMatrixPalette.size();
+
+        if (count == 0)
+        {
+            //skin info not loaded yet, don't render
+            return;
+        }
+
+        mShader->uniformMatrix3x4fv(LLViewerShaderMgr::AVATAR_MATRIX,
+            count,
+            FALSE,
+            (GLfloat*)&(mpc.mGLMp[0]));
+    }
+
 	LLGLEnableFunc stencil_test(GL_STENCIL_TEST, params.mSelected, &LLGLCommonFunc::selected_stencil_test);
 
 	params.mVertexBuffer->setBufferFast(mask);
diff --git a/indra/newview/lldrawpoolmaterials.h b/indra/newview/lldrawpoolmaterials.h
index 6e39821b07..8a3ad923df 100644
--- a/indra/newview/lldrawpoolmaterials.h
+++ b/indra/newview/lldrawpoolmaterials.h
@@ -55,21 +55,21 @@ public:
 		LLVertexBuffer::MAP_TANGENT
 	};
 	
-	/*virtual*/ U32 getVertexDataMask() { return VERTEX_DATA_MASK; }
+	U32 getVertexDataMask() override { return VERTEX_DATA_MASK; }
 	
-	/*virtual*/ void render(S32 pass = 0) { }
-	/*virtual*/ S32	 getNumPasses() {return 0;}
-	/*virtual*/ void prerender();
+	void render(S32 pass = 0) override { }
+	S32	 getNumPasses() override {return 0;}
+	void prerender() override;
 	
-	/*virtual*/ S32 getNumDeferredPasses();
-	/*virtual*/ void beginDeferredPass(S32 pass);
-	/*virtual*/ void endDeferredPass(S32 pass);
-	/*virtual*/ void renderDeferred(S32 pass);
+	S32 getNumDeferredPasses() override;
+	void beginDeferredPass(S32 pass) override;
+	void endDeferredPass(S32 pass) override;
+	void renderDeferred(S32 pass) override;
 	
 	void bindSpecularMap(LLViewerTexture* tex);
 	void bindNormalMap(LLViewerTexture* tex);
 	
-	/*virtual*/ void pushMaterialsBatch(LLDrawInfo& params, U32 mask);
+	void pushMaterialsBatch(LLDrawInfo& params, U32 mask, bool rigged);
 };
 
 #endif //LL_LLDRAWPOOLMATERIALS_H
diff --git a/indra/newview/lldrawpoolsimple.cpp b/indra/newview/lldrawpoolsimple.cpp
index 320160d10d..ca4e20ae9b 100644
--- a/indra/newview/lldrawpoolsimple.cpp
+++ b/indra/newview/lldrawpoolsimple.cpp
@@ -45,15 +45,24 @@ static LLTrace::BlockTimerStatHandle FTM_RENDER_GRASS_DEFERRED("Deferred Grass")
 
 void LLDrawPoolGlow::beginPostDeferredPass(S32 pass)
 {
-	gDeferredEmissiveProgram.bind();
-	gDeferredEmissiveProgram.uniform1f(LLShaderMgr::TEXTURE_GAMMA, 2.2f);
+    if (pass == 0)
+    {
+        gDeferredEmissiveProgram.bind();
+    }
+    else
+    {
+        llassert(gDeferredEmissiveProgram.mRiggedVariant);
+        gDeferredEmissiveProgram.mRiggedVariant->bind();
+    }
+
+	LLGLSLShader::sCurBoundShaderPtr->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 2.2f);
     if (LLPipeline::sRenderingHUDs)
 	{
-		gDeferredEmissiveProgram.uniform1i(LLShaderMgr::NO_ATMO, 1);
+        LLGLSLShader::sCurBoundShaderPtr->uniform1i(LLShaderMgr::NO_ATMO, 1);
 	}
 	else
 	{
-		gDeferredEmissiveProgram.uniform1i(LLShaderMgr::NO_ATMO, 0);
+        LLGLSLShader::sCurBoundShaderPtr->uniform1i(LLShaderMgr::NO_ATMO, 0);
 	}
 }
 
@@ -71,7 +80,14 @@ void LLDrawPoolGlow::renderPostDeferred(S32 pass)
 	LLGLDepthTest depth(GL_TRUE, GL_FALSE);
 	gGL.setColorMask(false, true);
 
-	pushBatches(LLRenderPass::PASS_GLOW, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
+    if (pass == 0)
+    {
+        pushBatches(LLRenderPass::PASS_GLOW, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
+    }
+    else
+    {
+        pushRiggedBatches(LLRenderPass::PASS_GLOW_RIGGED, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
+    }
 	
 	gGL.setColorMask(true, false);
 	gGL.setSceneBlendType(LLRender::BT_ALPHA);	
@@ -79,7 +95,8 @@ void LLDrawPoolGlow::renderPostDeferred(S32 pass)
 
 void LLDrawPoolGlow::endPostDeferredPass(S32 pass)
 {
-	gDeferredEmissiveProgram.unbind();
+    LLGLSLShader::sCurBoundShaderPtr->unbind();
+
 	LLRenderPass::endRenderPass(pass);
 }
 
@@ -87,7 +104,7 @@ S32 LLDrawPoolGlow::getNumPasses()
 {
 	if (LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_OBJECT) > 0)
 	{
-		return 1;
+		return 2;
 	}
 	else
 	{
@@ -112,6 +129,11 @@ void LLDrawPoolGlow::render(S32 pass)
 	llassert(shader_level > 0);
 	
 	LLGLSLShader* shader = LLPipeline::sUnderWaterRender ? &gObjectEmissiveWaterProgram : &gObjectEmissiveProgram;
+    if (pass == 1)
+    {
+        llassert(shader->mRiggedVariant);
+        shader = shader->mRiggedVariant;
+    }
 	shader->bind();
 	if (LLPipeline::sRenderDeferred)
 	{
@@ -120,7 +142,7 @@ void LLDrawPoolGlow::render(S32 pass)
 	else
 	{
 		shader->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 1.f);
-	}	
+	}
 
     if (LLPipeline::sRenderingHUDs)
 	{
@@ -134,7 +156,14 @@ void LLDrawPoolGlow::render(S32 pass)
 	LLGLDepthTest depth(GL_TRUE, GL_FALSE);
 	gGL.setColorMask(false, true);
 
-	pushBatches(LLRenderPass::PASS_GLOW, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
+    if (pass == 0)
+    {
+        pushBatches(LLRenderPass::PASS_GLOW, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
+    }
+    else
+    {
+        pushRiggedBatches(LLRenderPass::PASS_GLOW_RIGGED, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
+    }
 	
 	gGL.setColorMask(true, false);
 	gGL.setSceneBlendType(LLRender::BT_ALPHA);
@@ -155,39 +184,43 @@ void LLDrawPoolSimple::prerender()
 	mShaderLevel = LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_OBJECT);
 }
 
+S32 LLDrawPoolSimple::getNumPasses()
+{
+    return 2;
+}
+
 void LLDrawPoolSimple::beginRenderPass(S32 pass)
 {
 	LL_RECORD_BLOCK_TIME(FTM_RENDER_SIMPLE);
 
-	if (LLPipeline::sImpostorRender)
-	{
-		simple_shader = &gObjectSimpleImpostorProgram;
-	}
-	else if (LLPipeline::sUnderWaterRender)
-	{
-		simple_shader = &gObjectSimpleWaterProgram;
-	}
-	else
-	{
-		simple_shader = &gObjectSimpleProgram;
-	}
+    if (LLPipeline::sImpostorRender)
+    {
+        simple_shader = &gObjectSimpleImpostorProgram;
+    }
+    else if (LLPipeline::sUnderWaterRender)
+    {
+        simple_shader = &gObjectSimpleWaterProgram;
+    }
+    else
+    {
+        simple_shader = &gObjectSimpleProgram;
+    }
+ 
+    if (pass == 1)
+    {
+        llassert(simple_shader->mRiggedVariant);
+        simple_shader = simple_shader->mRiggedVariant;
+    }
 
-	if (mShaderLevel > 0)
-	{
-		simple_shader->bind();
+	simple_shader->bind();
 
-        if (LLPipeline::sRenderingHUDs)
-	    {
-		    simple_shader->uniform1i(LLShaderMgr::NO_ATMO, 1);
-	    }
-	    else
-	    {
-		    simple_shader->uniform1i(LLShaderMgr::NO_ATMO, 0);
-	    }
+    if (LLPipeline::sRenderingHUDs)
+	{
+		simple_shader->uniform1i(LLShaderMgr::NO_ATMO, 1);
 	}
-	else 
+	else
 	{
-		LLGLSLShader::bindNoShader();
+		simple_shader->uniform1i(LLShaderMgr::NO_ATMO, 0);
 	}
 }
 
@@ -197,10 +230,7 @@ void LLDrawPoolSimple::endRenderPass(S32 pass)
 	stop_glerror();
 	LLRenderPass::endRenderPass(pass);
 	stop_glerror();
-	if (mShaderLevel > 0)
-	{
-		simple_shader->unbind();
-	}
+	simple_shader->unbind();
 }
 
 void LLDrawPoolSimple::render(S32 pass)
@@ -211,35 +241,38 @@ void LLDrawPoolSimple::render(S32 pass)
 		LL_RECORD_BLOCK_TIME(FTM_RENDER_SIMPLE);
 		gPipeline.enableLightsDynamic();
 
-		if (mShaderLevel > 0)
-		{
-			U32 mask = getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX;
-
-			pushBatches(LLRenderPass::PASS_SIMPLE, mask, TRUE, TRUE);
-
-			if (LLPipeline::sRenderDeferred)
-			{ //if deferred rendering is enabled, bump faces aren't registered as simple
-				//render bump faces here as simple so bump faces will appear under water
-				pushBatches(LLRenderPass::PASS_BUMP, mask, TRUE, TRUE);			
-				pushBatches(LLRenderPass::PASS_MATERIAL, mask, TRUE, TRUE);
-				pushBatches(LLRenderPass::PASS_SPECMAP, mask, TRUE, TRUE);
-				pushBatches(LLRenderPass::PASS_NORMMAP, mask, TRUE, TRUE);
-				pushBatches(LLRenderPass::PASS_NORMSPEC, mask, TRUE, TRUE);		
-			}
-		}
-		else
-		{
-			LLGLDisable alpha_test(GL_ALPHA_TEST);
-			renderTexture(LLRenderPass::PASS_SIMPLE, getVertexDataMask());
-		}
-		
-	}
-}
-
-
+		U32 mask = getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX;
 
+        if (pass == 0)
+        {
+            pushBatches(LLRenderPass::PASS_SIMPLE, mask, TRUE, TRUE);
 
+            if (LLPipeline::sRenderDeferred)
+            { //if deferred rendering is enabled, bump faces aren't registered as simple
+                //render bump faces here as simple so bump faces will appear under water
+                pushBatches(LLRenderPass::PASS_BUMP, mask, TRUE, TRUE);
+                pushBatches(LLRenderPass::PASS_MATERIAL, mask, TRUE, TRUE);
+                pushBatches(LLRenderPass::PASS_SPECMAP, mask, TRUE, TRUE);
+                pushBatches(LLRenderPass::PASS_NORMMAP, mask, TRUE, TRUE);
+                pushBatches(LLRenderPass::PASS_NORMSPEC, mask, TRUE, TRUE);
+            }
+        }
+        else
+        {
+            pushRiggedBatches(LLRenderPass::PASS_SIMPLE_RIGGED, mask, TRUE, TRUE);
 
+            if (LLPipeline::sRenderDeferred)
+            { //if deferred rendering is enabled, bump faces aren't registered as simple
+                //render bump faces here as simple so bump faces will appear under water
+                pushRiggedBatches(LLRenderPass::PASS_BUMP_RIGGED, mask, TRUE, TRUE);
+                pushRiggedBatches(LLRenderPass::PASS_MATERIAL_RIGGED, mask, TRUE, TRUE);
+                pushRiggedBatches(LLRenderPass::PASS_SPECMAP_RIGGED, mask, TRUE, TRUE);
+                pushRiggedBatches(LLRenderPass::PASS_NORMMAP_RIGGED, mask, TRUE, TRUE);
+                pushRiggedBatches(LLRenderPass::PASS_NORMSPEC_RIGGED, mask, TRUE, TRUE);
+            }
+        }
+	}
+}
 
 
 
@@ -261,32 +294,31 @@ void LLDrawPoolAlphaMask::beginRenderPass(S32 pass)
 {
 	LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_MASK);
 
-	if (LLPipeline::sUnderWaterRender)
-	{
-		simple_shader = &gObjectSimpleWaterAlphaMaskProgram;
-	}
-	else
-	{
-		simple_shader = &gObjectSimpleAlphaMaskProgram;
-	}
+    if (LLPipeline::sUnderWaterRender)
+    {
+        simple_shader = &gObjectSimpleWaterAlphaMaskProgram;
+    }
+    else
+    {
+        simple_shader = &gObjectSimpleAlphaMaskProgram;
+    }
 
-	if (mShaderLevel > 0)
-	{
-		simple_shader->bind();
+    if (pass == 1)
+    {
+        llassert(simple_shader->mRiggedVariant);
+        simple_shader = simple_shader->mRiggedVariant;
+    }
 
-        if (LLPipeline::sRenderingHUDs)
-	    {
-		    simple_shader->uniform1i(LLShaderMgr::NO_ATMO, 1);
-	    }
-	    else
-	    {
-		    simple_shader->uniform1i(LLShaderMgr::NO_ATMO, 0);
-	    }
-	}
-	else 
-	{
-		LLGLSLShader::bindNoShader();
-	}
+    simple_shader->bind();
+
+    if (LLPipeline::sRenderingHUDs)
+    {
+	    simple_shader->uniform1i(LLShaderMgr::NO_ATMO, 1);
+    }
+    else
+    {
+	    simple_shader->uniform1i(LLShaderMgr::NO_ATMO, 0);
+    }
 }
 
 void LLDrawPoolAlphaMask::endRenderPass(S32 pass)
@@ -306,20 +338,22 @@ void LLDrawPoolAlphaMask::render(S32 pass)
 	LLGLDisable blend(GL_BLEND);
     LL_PROFILE_ZONE_SCOPED;
 	
-	if (mShaderLevel > 0)
-	{
-		simple_shader->bind();
-		simple_shader->setMinimumAlpha(0.33f);
+	
 
-        if (LLPipeline::sRenderingHUDs)
-	    {
-		    simple_shader->uniform1i(LLShaderMgr::NO_ATMO, 1);
-	    }
-	    else
-	    {
-		    simple_shader->uniform1i(LLShaderMgr::NO_ATMO, 0);
-	    }
+	simple_shader->bind();
+	simple_shader->setMinimumAlpha(0.33f);
+
+    if (LLPipeline::sRenderingHUDs)
+	{
+		simple_shader->uniform1i(LLShaderMgr::NO_ATMO, 1);
+	}
+	else
+	{
+		simple_shader->uniform1i(LLShaderMgr::NO_ATMO, 0);
+	}
 
+    if (pass == 0)
+    {
 		pushMaskBatches(LLRenderPass::PASS_ALPHA_MASK, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
 		pushMaskBatches(LLRenderPass::PASS_MATERIAL_ALPHA_MASK, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
 		pushMaskBatches(LLRenderPass::PASS_SPECMAP_MASK, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
@@ -328,9 +362,11 @@ void LLDrawPoolAlphaMask::render(S32 pass)
 	}
 	else
 	{
-		LLGLEnable test(GL_ALPHA_TEST);
-		pushMaskBatches(LLRenderPass::PASS_ALPHA_MASK, getVertexDataMask(), TRUE, FALSE);
-		gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT); //OK
+        pushRiggedMaskBatches(LLRenderPass::PASS_ALPHA_MASK_RIGGED, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
+        pushRiggedMaskBatches(LLRenderPass::PASS_MATERIAL_ALPHA_MASK_RIGGED, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
+        pushRiggedMaskBatches(LLRenderPass::PASS_SPECMAP_MASK_RIGGED, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
+        pushRiggedMaskBatches(LLRenderPass::PASS_NORMMAP_MASK_RIGGED, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
+        pushRiggedMaskBatches(LLRenderPass::PASS_NORMSPEC_MASK_RIGGED, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
 	}
 }
 
@@ -348,31 +384,32 @@ void LLDrawPoolFullbrightAlphaMask::beginRenderPass(S32 pass)
 {
 	LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_MASK);
 
+    bool rigged = (pass == 1);
 	if (LLPipeline::sUnderWaterRender)
 	{
-		simple_shader = &gObjectFullbrightWaterAlphaMaskProgram;
+        gObjectFullbrightWaterAlphaMaskProgram.bind(rigged);
 	}
 	else
 	{
-		simple_shader = &gObjectFullbrightAlphaMaskProgram;
+		gObjectFullbrightAlphaMaskProgram.bind(rigged);
 	}
 
-	if (mShaderLevel > 0)
+    if (LLPipeline::sRenderingHUDs)
 	{
-		simple_shader->bind();
-
-        if (LLPipeline::sRenderingHUDs)
-	    {
-		    simple_shader->uniform1i(LLShaderMgr::NO_ATMO, 1);
-	    }
-	    else
-	    {
-		    simple_shader->uniform1i(LLShaderMgr::NO_ATMO, 0);
-	    }
+		LLGLSLShader::sCurBoundShaderPtr->uniform1i(LLShaderMgr::NO_ATMO, 1);
+        LLGLSLShader::sCurBoundShaderPtr->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 1.f);
 	}
-	else 
+	else
 	{
-		LLGLSLShader::bindNoShader();
+        LLGLSLShader::sCurBoundShaderPtr->uniform1i(LLShaderMgr::NO_ATMO, 0);
+        if (LLPipeline::sRenderDeferred)
+        {
+            LLGLSLShader::sCurBoundShaderPtr->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 2.2f);
+        }
+        else
+        {
+            LLGLSLShader::sCurBoundShaderPtr->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 1.0f);
+        }
 	}
 }
 
@@ -382,70 +419,61 @@ void LLDrawPoolFullbrightAlphaMask::endRenderPass(S32 pass)
 	stop_glerror();
 	LLRenderPass::endRenderPass(pass);
 	stop_glerror();
-	if (mShaderLevel > 0)
-	{
-		simple_shader->unbind();
-	}
+    LLGLSLShader::sCurBoundShaderPtr->unbind();
 }
 
 void LLDrawPoolFullbrightAlphaMask::render(S32 pass)
 {
 	LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_MASK);
 
-	if (mShaderLevel > 0)
-	{
-		if (simple_shader)
-		{
-			simple_shader->bind();
-			simple_shader->setMinimumAlpha(0.33f);
-
-            if (LLPipeline::sRenderingHUDs)
-	        {
-		        simple_shader->uniform1i(LLShaderMgr::NO_ATMO, 1);
-                simple_shader->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 1.0f);
-	        }
-	        else
-	        {
-		        simple_shader->uniform1i(LLShaderMgr::NO_ATMO, 0);
-                if (LLPipeline::sRenderDeferred)
-			    {
-                    simple_shader->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 2.2f);				    
-			    }
-                else
-                {
-				    simple_shader->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 1.0f);
-			    }
-	        }
-		}
-		pushMaskBatches(LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
-		//LLGLSLShader::bindNoShader();
-	}
-	else
-	{
-		LLGLEnable test(GL_ALPHA_TEST);
-		gPipeline.enableLightsFullbright();
-		pushMaskBatches(LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK, getVertexDataMask(), TRUE, FALSE);
-		gPipeline.enableLightsDynamic();
-		gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT); //OK
-	}
+    if (pass == 0)
+    {
+        pushMaskBatches(LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
+    }
+    else
+    {
+        pushRiggedMaskBatches(LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK_RIGGED, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
+    }
+	
 }
 
 //===============================
 //DEFERRED IMPLEMENTATION
 //===============================
 
+S32 LLDrawPoolSimple::getNumDeferredPasses()
+{
+    if (LLPipeline::sRenderingHUDs)
+    {
+        return 1;
+    }
+    else
+    {
+        return 2;
+    }
+}
 void LLDrawPoolSimple::beginDeferredPass(S32 pass)
 {
 	LL_RECORD_BLOCK_TIME(FTM_RENDER_SIMPLE_DEFERRED);
-	gDeferredDiffuseProgram.bind();
+
+    mShader = &gDeferredDiffuseProgram;
+    
+    if (pass == 1)
+    {
+        llassert(mShader->mRiggedVariant != nullptr);
+        mShader = mShader->mRiggedVariant;
+    }
+    
+
+    mShader->bind();
 
     if (LLPipeline::sRenderingHUDs)
 	{
-		gDeferredDiffuseProgram.uniform1i(LLShaderMgr::NO_ATMO, 1);
+		mShader->uniform1i(LLShaderMgr::NO_ATMO, 1);
 	}
 	else
 	{
-		gDeferredDiffuseProgram.uniform1i(LLShaderMgr::NO_ATMO, 0);
+		mShader->uniform1i(LLShaderMgr::NO_ATMO, 0);
 	}
 }
 
@@ -454,7 +482,7 @@ void LLDrawPoolSimple::endDeferredPass(S32 pass)
 	LL_RECORD_BLOCK_TIME(FTM_RENDER_SIMPLE_DEFERRED);
 	LLRenderPass::endRenderPass(pass);
 
-	gDeferredDiffuseProgram.unbind();
+	mShader->unbind();
 }
 
 void LLDrawPoolSimple::renderDeferred(S32 pass)
@@ -463,41 +491,61 @@ void LLDrawPoolSimple::renderDeferred(S32 pass)
 	LLGLDisable blend(GL_BLEND);
 	LLGLDisable alpha_test(GL_ALPHA_TEST);
 
+    if (pass == 0)
 	{ //render simple
 		LL_RECORD_BLOCK_TIME(FTM_RENDER_SIMPLE_DEFERRED);
 		pushBatches(LLRenderPass::PASS_SIMPLE, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
 	}
+    else
+    {
+        //render simple rigged
+        pushRiggedBatches(LLRenderPass::PASS_SIMPLE_RIGGED, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
+    }
 }
 
 static LLTrace::BlockTimerStatHandle FTM_RENDER_ALPHA_MASK_DEFERRED("Deferred Alpha Mask");
 
 void LLDrawPoolAlphaMask::beginDeferredPass(S32 pass)
 {
-	
+    if (pass == 0)
+    {
+        gDeferredDiffuseAlphaMaskProgram.bind();
+    }
+    else
+    {
+        llassert(gDeferredDiffuseAlphaMaskProgram.mRiggedVariant);
+        gDeferredDiffuseAlphaMaskProgram.mRiggedVariant->bind();
+    }
+
 }
 
 void LLDrawPoolAlphaMask::endDeferredPass(S32 pass)
 {
-	
+    LLGLSLShader::sCurBoundShaderPtr->unbind();
 }
 
 void LLDrawPoolAlphaMask::renderDeferred(S32 pass)
 {
 	LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_MASK_DEFERRED);
-	gDeferredDiffuseAlphaMaskProgram.bind();
-	gDeferredDiffuseAlphaMaskProgram.setMinimumAlpha(0.33f);
+	LLGLSLShader::sCurBoundShaderPtr->setMinimumAlpha(0.33f);
 
     if (LLPipeline::sRenderingHUDs)
 	{
-		gDeferredDiffuseAlphaMaskProgram.uniform1i(LLShaderMgr::NO_ATMO, 1);
+        LLGLSLShader::sCurBoundShaderPtr->uniform1i(LLShaderMgr::NO_ATMO, 1);
 	}
 	else
 	{
-		gDeferredDiffuseAlphaMaskProgram.uniform1i(LLShaderMgr::NO_ATMO, 0);
+        LLGLSLShader::sCurBoundShaderPtr->uniform1i(LLShaderMgr::NO_ATMO, 0);
 	}
 
-	pushMaskBatches(LLRenderPass::PASS_ALPHA_MASK, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
-	gDeferredDiffuseAlphaMaskProgram.unbind();			
+    if (pass == 0)
+    {
+        pushMaskBatches(LLRenderPass::PASS_ALPHA_MASK, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
+    }
+    else
+    {
+        pushRiggedMaskBatches(LLRenderPass::PASS_ALPHA_MASK_RIGGED, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
+    }
 }
 
 
@@ -572,7 +620,7 @@ void LLDrawPoolGrass::render(S32 pass)
 		LLGLEnable test(GL_ALPHA_TEST);
 		gGL.setSceneBlendType(LLRender::BT_ALPHA);
 		//render grass
-		LLRenderPass::renderTexture(LLRenderPass::PASS_GRASS, getVertexDataMask());
+		LLRenderPass::pushBatches(LLRenderPass::PASS_GRASS, getVertexDataMask());
 	}
 }
 
@@ -603,7 +651,7 @@ void LLDrawPoolGrass::renderDeferred(S32 pass)
 	    }
 
 		//render grass
-		LLRenderPass::renderTexture(LLRenderPass::PASS_GRASS, getVertexDataMask());
+		LLRenderPass::pushBatches(LLRenderPass::PASS_GRASS, getVertexDataMask());
 	}			
 }
 
@@ -621,24 +669,24 @@ void LLDrawPoolFullbright::prerender()
 
 void LLDrawPoolFullbright::beginPostDeferredPass(S32 pass)
 {
+    bool rigged = (pass == 1);
 	if (LLPipeline::sUnderWaterRender)
 	{
-		gDeferredFullbrightWaterProgram.bind();
+		gDeferredFullbrightWaterProgram.bind(rigged);
 	}
 	else
 	{
-		gDeferredFullbrightProgram.bind();
+		gDeferredFullbrightProgram.bind(rigged);
 
         if (LLPipeline::sRenderingHUDs)
 	    {
-		    gDeferredFullbrightProgram.uniform1i(LLShaderMgr::NO_ATMO, 1);
+            LLGLSLShader::sCurBoundShaderPtr->uniform1i(LLShaderMgr::NO_ATMO, 1);
 	    }
 	    else
 	    {
-		    gDeferredFullbrightProgram.uniform1i(LLShaderMgr::NO_ATMO, 0);
+            LLGLSLShader::sCurBoundShaderPtr->uniform1i(LLShaderMgr::NO_ATMO, 0);
 	    }
 	}
-	
 }
 
 void LLDrawPoolFullbright::renderPostDeferred(S32 pass)
@@ -647,19 +695,19 @@ void LLDrawPoolFullbright::renderPostDeferred(S32 pass)
 	
 	gGL.setSceneBlendType(LLRender::BT_ALPHA);
 	U32 fullbright_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_COLOR | LLVertexBuffer::MAP_TEXTURE_INDEX;
-	pushBatches(LLRenderPass::PASS_FULLBRIGHT, fullbright_mask, TRUE, TRUE);
+    if (pass == 0)
+    {
+        pushBatches(LLRenderPass::PASS_FULLBRIGHT, fullbright_mask, TRUE, TRUE);
+    }
+    else
+    {
+        pushRiggedBatches(LLRenderPass::PASS_FULLBRIGHT_RIGGED, fullbright_mask, TRUE, TRUE);
+    }
 }
 
 void LLDrawPoolFullbright::endPostDeferredPass(S32 pass)
 {
-	if (LLPipeline::sUnderWaterRender)
-	{
-		gDeferredFullbrightWaterProgram.unbind();
-	}
-	else
-	{
-		gDeferredFullbrightProgram.unbind();
-	}
+    LLGLSLShader::sCurBoundShaderPtr->unbind();
 	LLRenderPass::endRenderPass(pass);
 }
 
@@ -675,6 +723,12 @@ void LLDrawPoolFullbright::beginRenderPass(S32 pass)
 	{
 		fullbright_shader = &gObjectFullbrightProgram;
 	}
+
+    if (pass == 1)
+    {
+        llassert(fullbright_shader->mRiggedVariant);
+        fullbright_shader = fullbright_shader->mRiggedVariant;
+    }
 }
 
 void LLDrawPoolFullbright::endRenderPass(S32 pass)
@@ -715,21 +769,23 @@ void LLDrawPoolFullbright::render(S32 pass)
 	    }
 
 		U32 fullbright_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_COLOR | LLVertexBuffer::MAP_TEXTURE_INDEX;
-		pushBatches(LLRenderPass::PASS_FULLBRIGHT, fullbright_mask, TRUE, TRUE);
-		pushBatches(LLRenderPass::PASS_MATERIAL_ALPHA_EMISSIVE, fullbright_mask, TRUE, TRUE);
-		pushBatches(LLRenderPass::PASS_SPECMAP_EMISSIVE, fullbright_mask, TRUE, TRUE);
-		pushBatches(LLRenderPass::PASS_NORMMAP_EMISSIVE, fullbright_mask, TRUE, TRUE);
-		pushBatches(LLRenderPass::PASS_NORMSPEC_EMISSIVE, fullbright_mask, TRUE, TRUE);
-	}
-	else
-	{
-		gPipeline.enableLightsFullbright();
-		U32 fullbright_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_COLOR;
-		renderTexture(LLRenderPass::PASS_FULLBRIGHT, fullbright_mask);
-		pushBatches(LLRenderPass::PASS_MATERIAL_ALPHA_EMISSIVE, fullbright_mask);
-		pushBatches(LLRenderPass::PASS_SPECMAP_EMISSIVE, fullbright_mask);
-		pushBatches(LLRenderPass::PASS_NORMMAP_EMISSIVE, fullbright_mask);
-		pushBatches(LLRenderPass::PASS_NORMSPEC_EMISSIVE, fullbright_mask);
+
+        if (pass == 0)
+        {
+            pushBatches(LLRenderPass::PASS_FULLBRIGHT, fullbright_mask, TRUE, TRUE);
+            pushBatches(LLRenderPass::PASS_MATERIAL_ALPHA_EMISSIVE, fullbright_mask, TRUE, TRUE);
+            pushBatches(LLRenderPass::PASS_SPECMAP_EMISSIVE, fullbright_mask, TRUE, TRUE);
+            pushBatches(LLRenderPass::PASS_NORMMAP_EMISSIVE, fullbright_mask, TRUE, TRUE);
+            pushBatches(LLRenderPass::PASS_NORMSPEC_EMISSIVE, fullbright_mask, TRUE, TRUE);
+        }
+        else
+        {
+            pushRiggedBatches(LLRenderPass::PASS_FULLBRIGHT_RIGGED, fullbright_mask, TRUE, TRUE);
+            pushRiggedBatches(LLRenderPass::PASS_MATERIAL_ALPHA_EMISSIVE_RIGGED, fullbright_mask, TRUE, TRUE);
+            pushRiggedBatches(LLRenderPass::PASS_SPECMAP_EMISSIVE_RIGGED, fullbright_mask, TRUE, TRUE);
+            pushRiggedBatches(LLRenderPass::PASS_NORMMAP_EMISSIVE_RIGGED, fullbright_mask, TRUE, TRUE);
+            pushRiggedBatches(LLRenderPass::PASS_NORMSPEC_EMISSIVE_RIGGED, fullbright_mask, TRUE, TRUE);
+        }
 	}
 
 	stop_glerror();
@@ -737,39 +793,39 @@ void LLDrawPoolFullbright::render(S32 pass)
 
 S32 LLDrawPoolFullbright::getNumPasses()
 { 
-	return 1;
+	return 2;
 }
 
 
 void LLDrawPoolFullbrightAlphaMask::beginPostDeferredPass(S32 pass)
 {
-	
+    bool rigged = (pass == 1);
     if (LLPipeline::sRenderingHUDs)
     {
-        gObjectFullbrightAlphaMaskProgram.bind();
-		gObjectFullbrightAlphaMaskProgram.uniform1f(LLShaderMgr::TEXTURE_GAMMA, 1.0f);
-        gObjectFullbrightAlphaMaskProgram.uniform1i(LLShaderMgr::NO_ATMO, 1);
+        gObjectFullbrightAlphaMaskProgram.bind(rigged);
+		LLGLSLShader::sCurBoundShaderPtr->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 1.0f);
+        LLGLSLShader::sCurBoundShaderPtr->uniform1i(LLShaderMgr::NO_ATMO, 1);
     }
 	else if (LLPipeline::sRenderDeferred)
 	{
         if (LLPipeline::sUnderWaterRender)
 		{
-			gDeferredFullbrightAlphaMaskWaterProgram.bind();
-			gDeferredFullbrightAlphaMaskWaterProgram.uniform1f(LLShaderMgr::TEXTURE_GAMMA, 2.2f);
-            gDeferredFullbrightAlphaMaskProgram.uniform1i(LLShaderMgr::NO_ATMO, 1);
+            gDeferredFullbrightAlphaMaskWaterProgram.bind(rigged);
+            LLGLSLShader::sCurBoundShaderPtr->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 2.2f);
+            LLGLSLShader::sCurBoundShaderPtr->uniform1i(LLShaderMgr::NO_ATMO, 1);
 		}
 		else
 		{
-			gDeferredFullbrightAlphaMaskProgram.bind();
-			gDeferredFullbrightAlphaMaskProgram.uniform1f(LLShaderMgr::TEXTURE_GAMMA, 2.2f);
-            gDeferredFullbrightAlphaMaskProgram.uniform1i(LLShaderMgr::NO_ATMO, 0);
+			gDeferredFullbrightAlphaMaskProgram.bind(rigged);
+            LLGLSLShader::sCurBoundShaderPtr->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 2.2f);
+            LLGLSLShader::sCurBoundShaderPtr->uniform1i(LLShaderMgr::NO_ATMO, 0);
 		}
     }
     else
     {
-		gObjectFullbrightAlphaMaskProgram.bind();
-		gObjectFullbrightAlphaMaskProgram.uniform1f(LLShaderMgr::TEXTURE_GAMMA, 1.0f);
-        gObjectFullbrightAlphaMaskProgram.uniform1i(LLShaderMgr::NO_ATMO, 0);
+		gObjectFullbrightAlphaMaskProgram.bind(rigged);
+        LLGLSLShader::sCurBoundShaderPtr->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 1.0f);
+        LLGLSLShader::sCurBoundShaderPtr->uniform1i(LLShaderMgr::NO_ATMO, 0);
 	}
 }
 
@@ -778,26 +834,19 @@ void LLDrawPoolFullbrightAlphaMask::renderPostDeferred(S32 pass)
 	LL_RECORD_BLOCK_TIME(FTM_RENDER_FULLBRIGHT);
 	LLGLDisable blend(GL_BLEND);
 	U32 fullbright_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_COLOR | LLVertexBuffer::MAP_TEXTURE_INDEX;
-	pushMaskBatches(LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK, fullbright_mask, TRUE, TRUE);
+    if (pass == 0)
+    {
+        pushMaskBatches(LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK, fullbright_mask, TRUE, TRUE);
+    }
+    else
+    {
+        pushRiggedMaskBatches(LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK_RIGGED, fullbright_mask, TRUE, TRUE);
+    }
 }
 
 void LLDrawPoolFullbrightAlphaMask::endPostDeferredPass(S32 pass)
 {
-	if (LLPipeline::sRenderingHUDs || !LLPipeline::sRenderDeferred)
-	{
-		gObjectFullbrightAlphaMaskProgram.unbind();
-	}
-	else
-	{
-		if (LLPipeline::sUnderWaterRender)
-		{
-			gDeferredFullbrightAlphaMaskWaterProgram.unbind();
-		}
-		else
-		{
-			gDeferredFullbrightAlphaMaskProgram.unbind();
-		}
-	}
+    LLGLSLShader::sCurBoundShaderPtr->unbind();
 	LLRenderPass::endRenderPass(pass);
 }
 
diff --git a/indra/newview/lldrawpoolsimple.h b/indra/newview/lldrawpoolsimple.h
index b27cc4babc..9ef9ea910d 100644
--- a/indra/newview/lldrawpoolsimple.h
+++ b/indra/newview/lldrawpoolsimple.h
@@ -29,6 +29,8 @@
 
 #include "lldrawpool.h"
 
+class LLGLSLShader;
+
 class LLDrawPoolSimple : public LLRenderPass
 {
 public:
@@ -43,18 +45,19 @@ public:
 
 	LLDrawPoolSimple();
 	
-	/*virtual*/ S32 getNumDeferredPasses() { return 1; }
-	/*virtual*/ void beginDeferredPass(S32 pass);
-	/*virtual*/ void endDeferredPass(S32 pass);
-	/*virtual*/ void renderDeferred(S32 pass);
+    S32 getNumDeferredPasses() override;
+	void beginDeferredPass(S32 pass) override;
+	void endDeferredPass(S32 pass) override;
+	void renderDeferred(S32 pass) override;
 
-	/*virtual*/ void beginRenderPass(S32 pass);
-	/*virtual*/ void endRenderPass(S32 pass);
+	void beginRenderPass(S32 pass) override;
+	void endRenderPass(S32 pass) override;
 	/// We need two passes so we can handle emissive materials separately.
-	/*virtual*/ S32	 getNumPasses() { return 1; }
-	/*virtual*/ void render(S32 pass = 0);
-	/*virtual*/ void prerender();
+    S32	 getNumPasses() override;
+	void render(S32 pass = 0) override;
+	void prerender() override;
 
+    LLGLSLShader* mShader = nullptr;
 };
 
 class LLDrawPoolGrass : public LLRenderPass
@@ -98,12 +101,12 @@ public:
 
 	LLDrawPoolAlphaMask();
 
-	/*virtual*/ S32 getNumDeferredPasses() { return 1; }
+	/*virtual*/ S32 getNumDeferredPasses() { return 2; }
 	/*virtual*/ void beginDeferredPass(S32 pass);
 	/*virtual*/ void endDeferredPass(S32 pass);
 	/*virtual*/ void renderDeferred(S32 pass);
 
-	/*virtual*/ S32	 getNumPasses() { return 1; }
+	/*virtual*/ S32	 getNumPasses() { return 2; }
 	/*virtual*/ void beginRenderPass(S32 pass);
 	/*virtual*/ void endRenderPass(S32 pass);
 	/*virtual*/ void render(S32 pass = 0);
@@ -124,12 +127,12 @@ public:
 
 	LLDrawPoolFullbrightAlphaMask();
 	
-	/*virtual*/ S32 getNumPostDeferredPasses() { return 1; }
+	/*virtual*/ S32 getNumPostDeferredPasses() { return 2; }
 	/*virtual*/ void beginPostDeferredPass(S32 pass);
 	/*virtual*/ void endPostDeferredPass(S32 pass);
 	/*virtual*/ void renderPostDeferred(S32 pass);
 
-	/*virtual*/ S32	 getNumPasses() { return 1; }
+	/*virtual*/ S32	 getNumPasses() { return 2; }
 	/*virtual*/ void beginRenderPass(S32 pass);
 	/*virtual*/ void endRenderPass(S32 pass);
 	/*virtual*/ void render(S32 pass = 0);
@@ -150,7 +153,7 @@ public:
 
 	LLDrawPoolFullbright();
 	
-	/*virtual*/ S32 getNumPostDeferredPasses() { return 1; }
+	/*virtual*/ S32 getNumPostDeferredPasses() { return 2; }
 	/*virtual*/ void beginPostDeferredPass(S32 pass);
 	/*virtual*/ void endPostDeferredPass(S32 pass);
 	/*virtual*/ void renderPostDeferred(S32 pass);
@@ -179,7 +182,7 @@ public:
 
 	virtual void prerender() { }
 
-	/*virtual*/ S32 getNumPostDeferredPasses() { return 1; }
+	/*virtual*/ S32 getNumPostDeferredPasses() { return 2; }
 	/*virtual*/ void beginPostDeferredPass(S32 pass); 
 	/*virtual*/ void endPostDeferredPass(S32 pass);
 	/*virtual*/ void renderPostDeferred(S32 pass);
diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp
index 88b958d24a..39ca7961d8 100644
--- a/indra/newview/llface.cpp
+++ b/indra/newview/llface.cpp
@@ -56,6 +56,7 @@
 #include "llviewertexture.h"
 #include "llvoavatar.h"
 #include "llsculptidsize.h"
+#include "llmeshrepository.h"
 
 #if LL_LINUX
 // Work-around spurious used before init warning on Vector4a
@@ -71,6 +72,7 @@ static LLStaticHashedString sColorIn("color_in");
 
 BOOL LLFace::sSafeRenderSelect = TRUE; // FALSE
 
+
 #define DOTVEC(a,b) (a.mV[0]*b.mV[0] + a.mV[1]*b.mV[1] + a.mV[2]*b.mV[2])
 
 /*
@@ -197,14 +199,7 @@ void LLFace::destroy()
 
 	if (mDrawPoolp)
 	{
-		if (this->isState(LLFace::RIGGED) && (mDrawPoolp->getType() == LLDrawPool::POOL_CONTROL_AV || mDrawPoolp->getType() == LLDrawPool::POOL_AVATAR))
-		{
-			((LLDrawPoolAvatar*) mDrawPoolp)->removeRiggedFace(this);
-		}
-		else
-		{
-			mDrawPoolp->removeFace(this);
-		}
+		mDrawPoolp->removeFace(this);
 		mDrawPoolp = NULL;
 	}
 
@@ -1286,7 +1281,9 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 		return FALSE;
 	}
 
-	const LLVolumeFace &vf = volume.getVolumeFace(f);
+    bool rigged = isState(RIGGED);
+
+    const LLVolumeFace &vf = volume.getVolumeFace(f);
 	S32 num_vertices = (S32)vf.mNumVertices;
 	S32 num_indices = (S32) vf.mNumIndices;
 	
@@ -1450,9 +1447,6 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 		}
 	}
 	
-	LLMatrix4a mat_normal;
-	mat_normal.loadu(mat_norm_in);
-	
 	F32 r = 0, os = 0, ot = 0, ms = 0, mt = 0, cos_ang = 0, sin_ang = 0;
 	bool do_xform = false;
 	if (rebuild_tcoord)
@@ -1487,6 +1481,45 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 		}
 	}
 	
+    const LLMeshSkinInfo* skin = nullptr;
+    LLMatrix4a mat_vert;
+    LLMatrix4a mat_normal;
+
+    // prepare mat_vert
+    if (rebuild_pos)
+    {
+        if (rigged)
+        { //override with bind shape matrix if rigged
+            skin = mSkinInfo;
+            mat_vert = skin->mBindShapeMatrix;
+        }
+        else
+        {
+            mat_vert.loadu(mat_vert_in);
+        }
+    }
+
+    if (rebuild_normal || rebuild_tangent)
+    { //override mat_normal with inverse of skin->mBindShapeMatrix
+        LL_PROFILE_ZONE_NAMED("getGeometryVolume - norm mat override");
+        if (rigged)
+        {
+            if (skin == nullptr)
+            {
+                skin = mSkinInfo;
+            }
+
+            //TODO -- cache this (check profile marker above)?
+            glh::matrix4f m((F32*) skin->mBindShapeMatrix.getF32ptr());
+            m = m.inverse().transpose();
+            mat_normal.loadu(m.m);
+        }
+        else
+        {
+            mat_normal.loadu(mat_norm_in);
+        }
+    }
+
 	static LLCachedControl<bool> use_transform_feedback(gSavedSettings, "RenderUseTransformFeedback", false);
 
 #ifdef GL_TRANSFORM_FEEDBACK_BUFFER
@@ -1740,7 +1773,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 					do_xform = false;
 				}
 
-				if (getVirtualSize() >= MIN_TEX_ANIM_SIZE || isState(LLFace::RIGGED))
+				if (getVirtualSize() >= MIN_TEX_ANIM_SIZE) // || isState(LLFace::RIGGED))
 				{ //don't override texture transform during tc bake
 					tex_mode = 0;
 				}
@@ -2036,9 +2069,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 		
 			mVertexBuffer->getVertexStrider(vert, mGeomIndex, mGeomCount, map_range);
 			
-			LLMatrix4a mat_vert;
-			mat_vert.loadu(mat_vert_in);
-
+			
 			F32* dst = (F32*) vert.get();
 			F32* end_f32 = dst+mGeomCount*4;
 
@@ -2089,10 +2120,10 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 			}
 		}
 
-		
 		if (rebuild_normal)
 		{
-			//LL_RECORD_TIME_BLOCK(FTM_FACE_GEOM_NORMAL);
+            LL_PROFILE_ZONE_NAMED("getGeometryVolume - normal");
+
 			mVertexBuffer->getNormalStrider(norm, mGeomIndex, mGeomCount, map_range);
 			F32* normals = (F32*) norm.get();
 			LLVector4a* src = vf.mNormals;
@@ -2714,56 +2745,6 @@ void LLFace::clearVertexBuffer()
 	mVertexBuffer = NULL;
 }
 
-//static
-U32 LLFace::getRiggedDataMask(U32 type)
-{
-	static const U32 rigged_data_mask[] = {
-		LLDrawPoolAvatar::RIGGED_MATERIAL_MASK,
-		LLDrawPoolAvatar::RIGGED_MATERIAL_ALPHA_VMASK,
-		LLDrawPoolAvatar::RIGGED_MATERIAL_ALPHA_MASK_MASK,
-		LLDrawPoolAvatar::RIGGED_MATERIAL_ALPHA_EMISSIVE_MASK,
-		LLDrawPoolAvatar::RIGGED_SPECMAP_VMASK,
-		LLDrawPoolAvatar::RIGGED_SPECMAP_BLEND_MASK,
-		LLDrawPoolAvatar::RIGGED_SPECMAP_MASK_MASK,
-		LLDrawPoolAvatar::RIGGED_SPECMAP_EMISSIVE_MASK,
-		LLDrawPoolAvatar::RIGGED_NORMMAP_VMASK,
-		LLDrawPoolAvatar::RIGGED_NORMMAP_BLEND_MASK,
-		LLDrawPoolAvatar::RIGGED_NORMMAP_MASK_MASK,
-		LLDrawPoolAvatar::RIGGED_NORMMAP_EMISSIVE_MASK,
-		LLDrawPoolAvatar::RIGGED_NORMSPEC_VMASK,
-		LLDrawPoolAvatar::RIGGED_NORMSPEC_BLEND_MASK,
-		LLDrawPoolAvatar::RIGGED_NORMSPEC_MASK_MASK,
-		LLDrawPoolAvatar::RIGGED_NORMSPEC_EMISSIVE_MASK,
-		LLDrawPoolAvatar::RIGGED_SIMPLE_MASK,
-		LLDrawPoolAvatar::RIGGED_FULLBRIGHT_MASK,
-		LLDrawPoolAvatar::RIGGED_SHINY_MASK,
-		LLDrawPoolAvatar::RIGGED_FULLBRIGHT_SHINY_MASK,
-		LLDrawPoolAvatar::RIGGED_GLOW_MASK,
-		LLDrawPoolAvatar::RIGGED_ALPHA_MASK,
-		LLDrawPoolAvatar::RIGGED_FULLBRIGHT_ALPHA_MASK,
-		LLDrawPoolAvatar::RIGGED_DEFERRED_BUMP_MASK,						 
-		LLDrawPoolAvatar::RIGGED_DEFERRED_SIMPLE_MASK,
-	};
-
-	llassert(type < sizeof(rigged_data_mask)/sizeof(U32));
-
-	return rigged_data_mask[type];
-}
-
-U32 LLFace::getRiggedVertexBufferDataMask() const
-{
-	U32 data_mask = 0;
-	for (U32 i = 0; i < mRiggedIndex.size(); ++i)
-	{
-		if (mRiggedIndex[i] > -1)
-		{
-			data_mask |= LLFace::getRiggedDataMask(i);
-		}
-	}
-
-	return data_mask;
-}
-
 S32 LLFace::getRiggedIndex(U32 type) const
 {
 	if (mRiggedIndex.empty())
@@ -2776,19 +2757,7 @@ S32 LLFace::getRiggedIndex(U32 type) const
 	return mRiggedIndex[type];
 }
 
-void LLFace::setRiggedIndex(U32 type, S32 index)
+U64 LLFace::getSkinHash()
 {
-	if (mRiggedIndex.empty())
-	{
-		mRiggedIndex.resize(LLDrawPoolAvatar::NUM_RIGGED_PASSES);
-		for (U32 i = 0; i < mRiggedIndex.size(); ++i)
-		{
-			mRiggedIndex[i] = -1;
-		}
-	}
-
-	llassert(type < mRiggedIndex.size());
-
-	mRiggedIndex[type] = index;
+    return mSkinInfo ? mSkinInfo->mHash : 0;
 }
-
diff --git a/indra/newview/llface.h b/indra/newview/llface.h
index 2e76c974fa..c533edede4 100644
--- a/indra/newview/llface.h
+++ b/indra/newview/llface.h
@@ -49,6 +49,7 @@ class LLViewerTexture;
 class LLGeometryManager;
 class LLTextureAtlasSlot;
 class LLDrawInfo;
+class LLMeshSkinInfo;
 
 const F32 MIN_ALPHA_SIZE = 1024.f;
 const F32 MIN_TEX_ANIM_SIZE = 512.f;
@@ -228,11 +229,7 @@ public:
 	void setVertexBuffer(LLVertexBuffer* buffer);
 	void clearVertexBuffer(); //sets mVertexBuffer to NULL
 	LLVertexBuffer* getVertexBuffer()	const	{ return mVertexBuffer; }
-	U32 getRiggedVertexBufferDataMask() const;
 	S32 getRiggedIndex(U32 type) const;
-	void setRiggedIndex(U32 type, S32 index);
-
-	static U32 getRiggedDataMask(U32 type);
 
 	void	notifyAboutCreatingTexture(LLViewerTexture *texture);
 	void	notifyAboutMissingAsset(LLViewerTexture *texture);
@@ -261,6 +258,11 @@ public:
 	LLMatrix4*	mSpecMapMatrix;
 	LLMatrix4*	mNormalMapMatrix;
 	LLDrawInfo* mDrawInfo;
+    LLVOAvatar* mAvatar = nullptr;
+    LLMeshSkinInfo* mSkinInfo = nullptr;
+    
+    // return mSkinInfo->mHash or 0 if mSkinInfo is null
+    U64 getSkinHash();
 
 private:
 	LLPointer<LLVertexBuffer> mVertexBuffer;
diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp
index a19d6d0b19..c5a3ff44b3 100644
--- a/indra/newview/llmeshrepository.cpp
+++ b/indra/newview/llmeshrepository.cpp
@@ -1956,7 +1956,7 @@ bool LLMeshRepoThread::skinInfoReceived(const LLUUID& mesh_id, U8* data, S32 dat
 		LLMeshSkinInfo info(skin);
 		info.mMeshID = mesh_id;
 
-		// LL_DEBUGS(LOG_MESH) << "info pelvis offset" << info.mPelvisOffset << LL_ENDL;
+        // LL_DEBUGS(LOG_MESH) << "info pelvis offset" << info.mPelvisOffset << LL_ENDL;
 		{
 			LLMutexLock lock(mMutex);
 			mSkinInfoQ.push_back(info);
diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp
index 30b7124550..332fa73944 100644
--- a/indra/newview/llspatialpartition.cpp
+++ b/indra/newview/llspatialpartition.cpp
@@ -2901,8 +2901,24 @@ void renderBatchSize(LLDrawInfo* params)
 {
 	LLGLEnable offset(GL_POLYGON_OFFSET_FILL);
 	glPolygonOffset(-1.f, 1.f);
-	gGL.diffuseColor4ubv((GLubyte*) &(params->mDebugColor));
-	pushVerts(params, LLVertexBuffer::MAP_VERTEX);
+    LLGLSLShader* old_shader = LLGLSLShader::sCurBoundShaderPtr;
+    U32 mask = LLVertexBuffer::MAP_VERTEX;
+    bool bind = false;
+    if (params->mAvatar)
+    { 
+        bind = true;
+        old_shader->mRiggedVariant->bind();
+        LLRenderPass::uploadMatrixPalette(*params);
+        mask |= LLVertexBuffer::MAP_WEIGHT4;
+    }
+	
+    gGL.diffuseColor4ubv((GLubyte*)&(params->mDebugColor));
+	pushVerts(params, mask);
+
+    if (bind)
+    {
+        old_shader->bind();
+    }
 }
 
 void renderShadowFrusta(LLDrawInfo* params)
@@ -4085,6 +4101,11 @@ void LLDrawInfo::validate()
 	mVertexBuffer->validateRange(mStart, mEnd, mCount, mOffset);
 }
 
+U64 LLDrawInfo::getSkinHash()
+{
+    return mSkinInfo ? mSkinInfo->mHash : 0;
+}
+
 LLVertexBuffer* LLGeometryManager::createVertexBuffer(U32 type_mask, U32 usage)
 {
 	return new LLVertexBuffer(type_mask, usage);
diff --git a/indra/newview/llspatialpartition.h b/indra/newview/llspatialpartition.h
index 8cc50e71b1..5fca516f19 100644
--- a/indra/newview/llspatialpartition.h
+++ b/indra/newview/llspatialpartition.h
@@ -82,6 +82,9 @@ public:
 
 	void validate();
 
+    // return mSkinHash->mHash, or 0 if mSkinHash is null
+    U64 getSkinHash();
+
 	LLVector4a mExtents[2];
 	
 	LLPointer<LLVertexBuffer> mVertexBuffer;
@@ -120,6 +123,8 @@ public:
 	F32  mAlphaMaskCutoff;
 	U8   mDiffuseAlphaMode;
 	bool mSelected;
+    LLVOAvatar* mAvatar = nullptr;
+    LLMeshSkinInfo* mSkinInfo = nullptr;
 
 
 	struct CompareTexture
@@ -647,7 +652,7 @@ class LLVolumeGeometryManager: public LLGeometryManager
 	virtual void rebuildGeom(LLSpatialGroup* group);
 	virtual void rebuildMesh(LLSpatialGroup* group);
 	virtual void getGeometry(LLSpatialGroup* group);
-	U32 genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace** faces, U32 face_count, BOOL distance_sort = FALSE, BOOL batch_textures = FALSE, BOOL no_materials = FALSE);
+	U32 genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace** faces, U32 face_count, BOOL distance_sort = FALSE, BOOL batch_textures = FALSE, BOOL rigged = FALSE);
 	void registerFace(LLSpatialGroup* group, LLFace* facep, U32 type);
 
 private:
@@ -655,13 +660,13 @@ private:
 	void freeFaces();
 
 	static int32_t sInstanceCount;
-	static LLFace** sFullbrightFaces;
-	static LLFace** sBumpFaces;
-	static LLFace** sSimpleFaces;
-	static LLFace** sNormFaces;
-	static LLFace** sSpecFaces;
-	static LLFace** sNormSpecFaces;
-	static LLFace** sAlphaFaces;
+	static LLFace** sFullbrightFaces[2];
+	static LLFace** sBumpFaces[2];
+	static LLFace** sSimpleFaces[2];
+	static LLFace** sNormFaces[2];
+	static LLFace** sSpecFaces[2];
+	static LLFace** sNormSpecFaces[2];
+	static LLFace** sAlphaFaces[2];
 };
 
 //spatial partition that uses volume geometry manager (implemented in LLVOVolume.cpp)
diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp
index 6368286f6e..38ac4275cf 100644
--- a/indra/newview/llviewerdisplay.cpp
+++ b/indra/newview/llviewerdisplay.cpp
@@ -578,8 +578,11 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 	//
 
 	LLAppViewer::instance()->pingMainloopTimeout("Display:Camera");
-	LLViewerCamera::getInstance()->setZoomParameters(zoom_factor, subfield);
-	LLViewerCamera::getInstance()->setNear(MIN_NEAR_PLANE);
+    if (LLViewerCamera::instanceExists())
+    {
+        LLViewerCamera::getInstance()->setZoomParameters(zoom_factor, subfield);
+        LLViewerCamera::getInstance()->setNear(MIN_NEAR_PLANE);
+    }
 
 	//////////////////////////
 	//
diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp
index b34c5b1188..a1f532dd35 100644
--- a/indra/newview/llviewershadermgr.cpp
+++ b/indra/newview/llviewershadermgr.cpp
@@ -77,6 +77,7 @@ LLGLSLShader			gTransformTangentProgram;
 
 //utility shaders
 LLGLSLShader	gOcclusionProgram;
+LLGLSLShader    gSkinnedOcclusionProgram;
 LLGLSLShader	gOcclusionCubeProgram;
 LLGLSLShader	gCustomAlphaProgram;
 LLGLSLShader	gGlowCombineProgram;
@@ -87,6 +88,7 @@ LLGLSLShader	gTwoTextureCompareProgram;
 LLGLSLShader	gOneTextureFilterProgram;
 LLGLSLShader	gOneTextureNoColorProgram;
 LLGLSLShader	gDebugProgram;
+LLGLSLShader    gSkinnedDebugProgram;
 LLGLSLShader	gClipProgram;
 LLGLSLShader	gDownsampleDepthProgram;
 LLGLSLShader	gDownsampleDepthRectProgram;
@@ -96,56 +98,49 @@ LLGLSLShader	gBenchmarkProgram;
 
 //object shaders
 LLGLSLShader		gObjectSimpleProgram;
+LLGLSLShader        gSkinnedObjectSimpleProgram;
 LLGLSLShader		gObjectSimpleImpostorProgram;
+LLGLSLShader        gSkinnedObjectSimpleImpostorProgram;
 LLGLSLShader		gObjectPreviewProgram;
 LLGLSLShader		gObjectSimpleWaterProgram;
+LLGLSLShader        gSkinnedObjectSimpleWaterProgram;
 LLGLSLShader		gObjectSimpleAlphaMaskProgram;
+LLGLSLShader        gSkinnedObjectSimpleAlphaMaskProgram;
 LLGLSLShader		gObjectSimpleWaterAlphaMaskProgram;
+LLGLSLShader        gSkinnedObjectSimpleWaterAlphaMaskProgram;
 LLGLSLShader		gObjectFullbrightProgram;
+LLGLSLShader        gSkinnedObjectFullbrightProgram;
 LLGLSLShader		gObjectFullbrightWaterProgram;
+LLGLSLShader        gSkinnedObjectFullbrightWaterProgram;
 LLGLSLShader		gObjectEmissiveProgram;
+LLGLSLShader        gSkinnedObjectEmissiveProgram;
 LLGLSLShader		gObjectEmissiveWaterProgram;
+LLGLSLShader        gSkinnedObjectEmissiveWaterProgram;
 LLGLSLShader		gObjectFullbrightAlphaMaskProgram;
+LLGLSLShader        gSkinnedObjectFullbrightAlphaMaskProgram;
 LLGLSLShader		gObjectFullbrightWaterAlphaMaskProgram;
+LLGLSLShader        gSkinnedObjectFullbrightWaterAlphaMaskProgram;
 LLGLSLShader		gObjectFullbrightShinyProgram;
+LLGLSLShader        gSkinnedObjectFullbrightShinyProgram;
 LLGLSLShader		gObjectFullbrightShinyWaterProgram;
+LLGLSLShader        gSkinnedObjectFullbrightShinyWaterProgram;
 LLGLSLShader		gObjectShinyProgram;
+LLGLSLShader        gSkinnedObjectShinyProgram;
 LLGLSLShader		gObjectShinyWaterProgram;
+LLGLSLShader        gSkinnedObjectShinyWaterProgram;
 LLGLSLShader		gObjectBumpProgram;
+LLGLSLShader        gSkinnedObjectBumpProgram;
 LLGLSLShader		gTreeProgram;
 LLGLSLShader		gTreeWaterProgram;
 LLGLSLShader		gObjectFullbrightNoColorProgram;
 LLGLSLShader		gObjectFullbrightNoColorWaterProgram;
 
-LLGLSLShader		gObjectSimpleNonIndexedProgram;
 LLGLSLShader		gObjectSimpleNonIndexedTexGenProgram;
 LLGLSLShader		gObjectSimpleNonIndexedTexGenWaterProgram;
-LLGLSLShader		gObjectSimpleNonIndexedWaterProgram;
 LLGLSLShader		gObjectAlphaMaskNonIndexedProgram;
 LLGLSLShader		gObjectAlphaMaskNonIndexedWaterProgram;
 LLGLSLShader		gObjectAlphaMaskNoColorProgram;
 LLGLSLShader		gObjectAlphaMaskNoColorWaterProgram;
-LLGLSLShader		gObjectFullbrightNonIndexedProgram;
-LLGLSLShader		gObjectFullbrightNonIndexedWaterProgram;
-LLGLSLShader		gObjectEmissiveNonIndexedProgram;
-LLGLSLShader		gObjectEmissiveNonIndexedWaterProgram;
-LLGLSLShader		gObjectFullbrightShinyNonIndexedProgram;
-LLGLSLShader		gObjectFullbrightShinyNonIndexedWaterProgram;
-LLGLSLShader		gObjectShinyNonIndexedProgram;
-LLGLSLShader		gObjectShinyNonIndexedWaterProgram;
-
-//object hardware skinning shaders
-LLGLSLShader		gSkinnedObjectSimpleProgram;
-LLGLSLShader		gSkinnedObjectFullbrightProgram;
-LLGLSLShader		gSkinnedObjectEmissiveProgram;
-LLGLSLShader		gSkinnedObjectFullbrightShinyProgram;
-LLGLSLShader		gSkinnedObjectShinySimpleProgram;
-
-LLGLSLShader		gSkinnedObjectSimpleWaterProgram;
-LLGLSLShader		gSkinnedObjectFullbrightWaterProgram;
-LLGLSLShader		gSkinnedObjectEmissiveWaterProgram;
-LLGLSLShader		gSkinnedObjectFullbrightShinyWaterProgram;
-LLGLSLShader		gSkinnedObjectShinySimpleWaterProgram;
 
 //environment shaders
 LLGLSLShader		gTerrainProgram;
@@ -191,17 +186,18 @@ LLGLSLShader			gDeferredWaterProgram;
 LLGLSLShader			gDeferredUnderWaterProgram;
 LLGLSLShader			gDeferredDiffuseProgram;
 LLGLSLShader			gDeferredDiffuseAlphaMaskProgram;
+LLGLSLShader            gDeferredSkinnedDiffuseAlphaMaskProgram;
 LLGLSLShader			gDeferredNonIndexedDiffuseProgram;
 LLGLSLShader			gDeferredNonIndexedDiffuseAlphaMaskProgram;
 LLGLSLShader			gDeferredNonIndexedDiffuseAlphaMaskNoColorProgram;
 LLGLSLShader			gDeferredSkinnedDiffuseProgram;
 LLGLSLShader			gDeferredSkinnedBumpProgram;
-LLGLSLShader			gDeferredSkinnedAlphaProgram;
 LLGLSLShader			gDeferredBumpProgram;
 LLGLSLShader			gDeferredTerrainProgram;
 LLGLSLShader            gDeferredTerrainWaterProgram;
 LLGLSLShader			gDeferredTreeProgram;
 LLGLSLShader			gDeferredTreeShadowProgram;
+LLGLSLShader            gDeferredSkinnedTreeShadowProgram;
 LLGLSLShader			gDeferredAvatarProgram;
 LLGLSLShader			gDeferredAvatarAlphaProgram;
 LLGLSLShader			gDeferredLightProgram;
@@ -213,9 +209,12 @@ LLGLSLShader			gDeferredBlurLightProgram;
 LLGLSLShader			gDeferredSoftenProgram;
 LLGLSLShader			gDeferredSoftenWaterProgram;
 LLGLSLShader			gDeferredShadowProgram;
+LLGLSLShader            gDeferredSkinnedShadowProgram;
 LLGLSLShader			gDeferredShadowCubeProgram;
 LLGLSLShader			gDeferredShadowAlphaMaskProgram;
+LLGLSLShader            gDeferredSkinnedShadowAlphaMaskProgram;
 LLGLSLShader			gDeferredShadowFullbrightAlphaMaskProgram;
+LLGLSLShader            gDeferredSkinnedShadowFullbrightAlphaMaskProgram;
 LLGLSLShader			gDeferredAvatarShadowProgram;
 LLGLSLShader			gDeferredAvatarAlphaShadowProgram;
 LLGLSLShader			gDeferredAvatarAlphaMaskShadowProgram;
@@ -223,14 +222,20 @@ LLGLSLShader			gDeferredAttachmentShadowProgram;
 LLGLSLShader			gDeferredAttachmentAlphaShadowProgram;
 LLGLSLShader			gDeferredAttachmentAlphaMaskShadowProgram;
 LLGLSLShader			gDeferredAlphaProgram;
+LLGLSLShader            gDeferredSkinnedAlphaProgram;
 LLGLSLShader			gDeferredAlphaImpostorProgram;
+LLGLSLShader            gDeferredSkinnedAlphaImpostorProgram;
 LLGLSLShader			gDeferredAlphaWaterProgram;
+LLGLSLShader            gDeferredSkinnedAlphaWaterProgram;
 LLGLSLShader			gDeferredAvatarEyesProgram;
 LLGLSLShader			gDeferredFullbrightProgram;
 LLGLSLShader			gDeferredFullbrightAlphaMaskProgram;
 LLGLSLShader			gDeferredFullbrightWaterProgram;
+LLGLSLShader            gDeferredSkinnedFullbrightWaterProgram;
 LLGLSLShader			gDeferredFullbrightAlphaMaskWaterProgram;
+LLGLSLShader            gDeferredSkinnedFullbrightAlphaMaskWaterProgram;
 LLGLSLShader			gDeferredEmissiveProgram;
+LLGLSLShader            gDeferredSkinnedEmissiveProgram;
 LLGLSLShader			gDeferredPostProgram;
 LLGLSLShader			gDeferredCoFProgram;
 LLGLSLShader			gDeferredDoFCombineProgram;
@@ -243,14 +248,29 @@ LLGLSLShader			gDeferredWLSunProgram;
 LLGLSLShader			gDeferredWLMoonProgram;
 LLGLSLShader			gDeferredStarProgram;
 LLGLSLShader			gDeferredFullbrightShinyProgram;
-LLGLSLShader			gDeferredSkinnedFullbrightShinyProgram;
+LLGLSLShader            gDeferredSkinnedFullbrightShinyProgram;
 LLGLSLShader			gDeferredSkinnedFullbrightProgram;
+LLGLSLShader            gDeferredSkinnedFullbrightAlphaMaskProgram;
 LLGLSLShader			gNormalMapGenProgram;
 
 // Deferred materials shaders
 LLGLSLShader			gDeferredMaterialProgram[LLMaterial::SHADER_COUNT*2];
 LLGLSLShader			gDeferredMaterialWaterProgram[LLMaterial::SHADER_COUNT*2];
 
+//helper for making a rigged variant of a given shader
+bool make_rigged_variant(LLGLSLShader& shader, LLGLSLShader& riggedShader)
+{
+    riggedShader.mName = llformat("Skinned %s", shader.mName.c_str());
+    riggedShader.mFeatures = shader.mFeatures;
+    riggedShader.mFeatures.hasObjectSkinning = true;
+    riggedShader.addPermutation("HAS_SKIN", "1");
+    riggedShader.mShaderFiles = shader.mShaderFiles;
+    riggedShader.mShaderLevel = shader.mShaderLevel;
+    riggedShader.mShaderGroup = shader.mShaderGroup;
+    shader.mRiggedVariant = &riggedShader;
+    return riggedShader.createShader(NULL, NULL);
+}
+
 LLViewerShaderMgr::LLViewerShaderMgr() :
 	mShaderLevel(SHADER_COUNT, 0),
 	mMaxAvatarShaderLevel(0)
@@ -263,75 +283,77 @@ LLViewerShaderMgr::LLViewerShaderMgr() :
 	mShaderList.push_back(&gWLMoonProgram);
 	mShaderList.push_back(&gAvatarProgram);
 	mShaderList.push_back(&gObjectShinyProgram);
-	mShaderList.push_back(&gObjectShinyNonIndexedProgram);
+    mShaderList.push_back(&gSkinnedObjectShinyProgram);
 	mShaderList.push_back(&gWaterProgram);
 	mShaderList.push_back(&gWaterEdgeProgram);
 	mShaderList.push_back(&gAvatarEyeballProgram); 
 	mShaderList.push_back(&gObjectSimpleProgram);
+    mShaderList.push_back(&gSkinnedObjectSimpleProgram);
 	mShaderList.push_back(&gObjectSimpleImpostorProgram);
+    mShaderList.push_back(&gSkinnedObjectSimpleImpostorProgram);
 	mShaderList.push_back(&gObjectPreviewProgram);
 	mShaderList.push_back(&gImpostorProgram);
 	mShaderList.push_back(&gObjectFullbrightNoColorProgram);
 	mShaderList.push_back(&gObjectFullbrightNoColorWaterProgram);
 	mShaderList.push_back(&gObjectSimpleAlphaMaskProgram);
+    mShaderList.push_back(&gSkinnedObjectSimpleAlphaMaskProgram);
 	mShaderList.push_back(&gObjectBumpProgram);
+    mShaderList.push_back(&gSkinnedObjectBumpProgram);
 	mShaderList.push_back(&gObjectEmissiveProgram);
+    mShaderList.push_back(&gSkinnedObjectEmissiveProgram);
 	mShaderList.push_back(&gObjectEmissiveWaterProgram);
+    mShaderList.push_back(&gSkinnedObjectEmissiveWaterProgram);
 	mShaderList.push_back(&gObjectFullbrightProgram);
+    mShaderList.push_back(&gSkinnedObjectFullbrightProgram);
 	mShaderList.push_back(&gObjectFullbrightAlphaMaskProgram);
+    mShaderList.push_back(&gSkinnedObjectFullbrightAlphaMaskProgram);
 	mShaderList.push_back(&gObjectFullbrightShinyProgram);
+    mShaderList.push_back(&gSkinnedObjectFullbrightShinyProgram);
 	mShaderList.push_back(&gObjectFullbrightShinyWaterProgram);
-	mShaderList.push_back(&gObjectSimpleNonIndexedProgram);
+    mShaderList.push_back(&gSkinnedObjectFullbrightShinyWaterProgram);
 	mShaderList.push_back(&gObjectSimpleNonIndexedTexGenProgram);
 	mShaderList.push_back(&gObjectSimpleNonIndexedTexGenWaterProgram);
-	mShaderList.push_back(&gObjectSimpleNonIndexedWaterProgram);
 	mShaderList.push_back(&gObjectAlphaMaskNonIndexedProgram);
 	mShaderList.push_back(&gObjectAlphaMaskNonIndexedWaterProgram);
 	mShaderList.push_back(&gObjectAlphaMaskNoColorProgram);
 	mShaderList.push_back(&gObjectAlphaMaskNoColorWaterProgram);
 	mShaderList.push_back(&gTreeProgram);
 	mShaderList.push_back(&gTreeWaterProgram);
-	mShaderList.push_back(&gObjectFullbrightNonIndexedProgram);
-	mShaderList.push_back(&gObjectFullbrightNonIndexedWaterProgram);
-	mShaderList.push_back(&gObjectEmissiveNonIndexedProgram);
-	mShaderList.push_back(&gObjectEmissiveNonIndexedWaterProgram);
-	mShaderList.push_back(&gObjectFullbrightShinyNonIndexedProgram);
-	mShaderList.push_back(&gObjectFullbrightShinyNonIndexedWaterProgram);
-	mShaderList.push_back(&gSkinnedObjectSimpleProgram);
-	mShaderList.push_back(&gSkinnedObjectFullbrightProgram);
-	mShaderList.push_back(&gSkinnedObjectEmissiveProgram);
-	mShaderList.push_back(&gSkinnedObjectFullbrightShinyProgram);
-	mShaderList.push_back(&gSkinnedObjectShinySimpleProgram);
-	mShaderList.push_back(&gSkinnedObjectSimpleWaterProgram);
-	mShaderList.push_back(&gSkinnedObjectFullbrightWaterProgram);
-	mShaderList.push_back(&gSkinnedObjectEmissiveWaterProgram);
-	mShaderList.push_back(&gSkinnedObjectFullbrightShinyWaterProgram);
-	mShaderList.push_back(&gSkinnedObjectShinySimpleWaterProgram);
 	mShaderList.push_back(&gTerrainProgram);
 	mShaderList.push_back(&gTerrainWaterProgram);
 	mShaderList.push_back(&gObjectSimpleWaterProgram);
+    mShaderList.push_back(&gSkinnedObjectSimpleWaterProgram);
 	mShaderList.push_back(&gObjectFullbrightWaterProgram);
+    mShaderList.push_back(&gSkinnedObjectFullbrightWaterProgram);
 	mShaderList.push_back(&gObjectSimpleWaterAlphaMaskProgram);
+    mShaderList.push_back(&gSkinnedObjectSimpleWaterAlphaMaskProgram);
 	mShaderList.push_back(&gObjectFullbrightWaterAlphaMaskProgram);
+    mShaderList.push_back(&gSkinnedObjectFullbrightWaterAlphaMaskProgram);
 	mShaderList.push_back(&gAvatarWaterProgram);
 	mShaderList.push_back(&gObjectShinyWaterProgram);
-	mShaderList.push_back(&gObjectShinyNonIndexedWaterProgram);
+    mShaderList.push_back(&gSkinnedObjectShinyWaterProgram);
 	mShaderList.push_back(&gUnderWaterProgram);
 	mShaderList.push_back(&gDeferredSunProgram);
 	mShaderList.push_back(&gDeferredSoftenProgram);
 	mShaderList.push_back(&gDeferredSoftenWaterProgram);
 	mShaderList.push_back(&gDeferredAlphaProgram);
+    mShaderList.push_back(&gDeferredSkinnedAlphaProgram);
 	mShaderList.push_back(&gDeferredAlphaImpostorProgram);
+    mShaderList.push_back(&gDeferredSkinnedAlphaImpostorProgram);
 	mShaderList.push_back(&gDeferredAlphaWaterProgram);
-	mShaderList.push_back(&gDeferredSkinnedAlphaProgram);
+    mShaderList.push_back(&gDeferredSkinnedAlphaWaterProgram);
 	mShaderList.push_back(&gDeferredFullbrightProgram);
 	mShaderList.push_back(&gDeferredFullbrightAlphaMaskProgram);
 	mShaderList.push_back(&gDeferredFullbrightWaterProgram);
-	mShaderList.push_back(&gDeferredFullbrightAlphaMaskWaterProgram);	
+    mShaderList.push_back(&gDeferredSkinnedFullbrightWaterProgram);
+	mShaderList.push_back(&gDeferredFullbrightAlphaMaskWaterProgram);
+    mShaderList.push_back(&gDeferredSkinnedFullbrightAlphaMaskWaterProgram);
 	mShaderList.push_back(&gDeferredFullbrightShinyProgram);
-	mShaderList.push_back(&gDeferredSkinnedFullbrightShinyProgram);
+    mShaderList.push_back(&gDeferredSkinnedFullbrightShinyProgram);
 	mShaderList.push_back(&gDeferredSkinnedFullbrightProgram);
+    mShaderList.push_back(&gDeferredSkinnedFullbrightAlphaMaskProgram);
 	mShaderList.push_back(&gDeferredEmissiveProgram);
+    mShaderList.push_back(&gDeferredSkinnedEmissiveProgram);
 	mShaderList.push_back(&gDeferredAvatarEyesProgram);
 	mShaderList.push_back(&gDeferredWaterProgram);
 	mShaderList.push_back(&gDeferredUnderWaterProgram);	
@@ -732,8 +754,10 @@ void LLViewerShaderMgr::setShaders()
 void LLViewerShaderMgr::unloadShaders()
 {
 	gOcclusionProgram.unload();
+    gSkinnedOcclusionProgram.unload();
 	gOcclusionCubeProgram.unload();
 	gDebugProgram.unload();
+    gSkinnedDebugProgram.unload();
 	gClipProgram.unload();
 	gDownsampleDepthProgram.unload();
 	gDownsampleDepthRectProgram.unload();
@@ -755,58 +779,50 @@ void LLViewerShaderMgr::unloadShaders()
 	gObjectFullbrightNoColorProgram.unload();
 	gObjectFullbrightNoColorWaterProgram.unload();
 	gObjectSimpleProgram.unload();
+    gSkinnedObjectSimpleProgram.unload();
 	gObjectSimpleImpostorProgram.unload();
+    gSkinnedObjectSimpleImpostorProgram.unload();
 	gObjectPreviewProgram.unload();
 	gImpostorProgram.unload();
 	gObjectSimpleAlphaMaskProgram.unload();
+    gSkinnedObjectSimpleAlphaMaskProgram.unload();
 	gObjectBumpProgram.unload();
+    gSkinnedObjectBumpProgram.unload();
 	gObjectSimpleWaterProgram.unload();
+    gSkinnedObjectSimpleWaterProgram.unload();
 	gObjectSimpleWaterAlphaMaskProgram.unload();
+    gSkinnedObjectSimpleWaterAlphaMaskProgram.unload();
 	gObjectFullbrightProgram.unload();
+    gSkinnedObjectFullbrightProgram.unload();
 	gObjectFullbrightWaterProgram.unload();
+    gSkinnedObjectFullbrightWaterProgram.unload();
 	gObjectEmissiveProgram.unload();
+    gSkinnedObjectEmissiveProgram.unload();
 	gObjectEmissiveWaterProgram.unload();
+    gSkinnedObjectEmissiveWaterProgram.unload();
 	gObjectFullbrightAlphaMaskProgram.unload();
+    gSkinnedObjectFullbrightAlphaMaskProgram.unload();
 	gObjectFullbrightWaterAlphaMaskProgram.unload();
+    gSkinnedObjectFullbrightWaterAlphaMaskProgram.unload();
 
 	gObjectShinyProgram.unload();
+    gSkinnedObjectShinyProgram.unload();
 	gObjectFullbrightShinyProgram.unload();
+    gSkinnedObjectFullbrightShinyProgram.unload();
 	gObjectFullbrightShinyWaterProgram.unload();
+    gSkinnedObjectFullbrightShinyWaterProgram.unload();
 	gObjectShinyWaterProgram.unload();
+    gSkinnedObjectShinyWaterProgram.unload();
 
-	gObjectSimpleNonIndexedProgram.unload();
 	gObjectSimpleNonIndexedTexGenProgram.unload();
 	gObjectSimpleNonIndexedTexGenWaterProgram.unload();
-	gObjectSimpleNonIndexedWaterProgram.unload();
 	gObjectAlphaMaskNonIndexedProgram.unload();
 	gObjectAlphaMaskNonIndexedWaterProgram.unload();
 	gObjectAlphaMaskNoColorProgram.unload();
 	gObjectAlphaMaskNoColorWaterProgram.unload();
-	gObjectFullbrightNonIndexedProgram.unload();
-	gObjectFullbrightNonIndexedWaterProgram.unload();
-	gObjectEmissiveNonIndexedProgram.unload();
-	gObjectEmissiveNonIndexedWaterProgram.unload();
 	gTreeProgram.unload();
 	gTreeWaterProgram.unload();
 
-	gObjectShinyNonIndexedProgram.unload();
-	gObjectFullbrightShinyNonIndexedProgram.unload();
-	gObjectFullbrightShinyNonIndexedWaterProgram.unload();
-	gObjectShinyNonIndexedWaterProgram.unload();
-
-	gSkinnedObjectSimpleProgram.unload();
-	gSkinnedObjectFullbrightProgram.unload();
-	gSkinnedObjectEmissiveProgram.unload();
-	gSkinnedObjectFullbrightShinyProgram.unload();
-	gSkinnedObjectShinySimpleProgram.unload();
-	
-	gSkinnedObjectSimpleWaterProgram.unload();
-	gSkinnedObjectFullbrightWaterProgram.unload();
-	gSkinnedObjectEmissiveWaterProgram.unload();
-	gSkinnedObjectFullbrightShinyWaterProgram.unload();
-	gSkinnedObjectShinySimpleWaterProgram.unload();
-	
-
 	gWaterProgram.unload();
     gWaterEdgeProgram.unload();
 	gUnderWaterProgram.unload();
@@ -832,13 +848,13 @@ void LLViewerShaderMgr::unloadShaders()
 
 	gDeferredDiffuseProgram.unload();
 	gDeferredDiffuseAlphaMaskProgram.unload();
+    gDeferredSkinnedDiffuseAlphaMaskProgram.unload();
 	gDeferredNonIndexedDiffuseAlphaMaskProgram.unload();
 	gDeferredNonIndexedDiffuseAlphaMaskNoColorProgram.unload();
 	gDeferredNonIndexedDiffuseProgram.unload();
 	gDeferredSkinnedDiffuseProgram.unload();
 	gDeferredSkinnedBumpProgram.unload();
-	gDeferredSkinnedAlphaProgram.unload();
-
+	
 	gTransformPositionProgram.unload();
 	gTransformTexCoordProgram.unload();
 	gTransformNormalProgram.unload();
@@ -915,7 +931,7 @@ BOOL LLViewerShaderMgr::loadBasicShaders()
 	}
 	shaders.push_back( make_pair( "objects/nonindexedTextureV.glsl",        1 ) );
 
-	boost::unordered_map<std::string, std::string> attribs;
+	std::unordered_map<std::string, std::string> attribs;
 	attribs["MAX_JOINTS_PER_MESH_OBJECT"] = 
 		boost::lexical_cast<std::string>(LLSkinningUtil::getMaxJointCount());
 
@@ -1227,14 +1243,15 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 	{
 		gDeferredTreeProgram.unload();
 		gDeferredTreeShadowProgram.unload();
+        gDeferredSkinnedTreeShadowProgram.unload();
 		gDeferredDiffuseProgram.unload();
 		gDeferredDiffuseAlphaMaskProgram.unload();
+        gDeferredSkinnedDiffuseAlphaMaskProgram.unload();
 		gDeferredNonIndexedDiffuseAlphaMaskProgram.unload();
 		gDeferredNonIndexedDiffuseAlphaMaskNoColorProgram.unload();
 		gDeferredNonIndexedDiffuseProgram.unload();
 		gDeferredSkinnedDiffuseProgram.unload();
 		gDeferredSkinnedBumpProgram.unload();
-		gDeferredSkinnedAlphaProgram.unload();
 		gDeferredBumpProgram.unload();
 		gDeferredImpostorProgram.unload();
 		gDeferredTerrainProgram.unload();
@@ -1251,9 +1268,12 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		gDeferredSoftenProgram.unload();
 		gDeferredSoftenWaterProgram.unload();
 		gDeferredShadowProgram.unload();
+        gDeferredSkinnedShadowProgram.unload();
 		gDeferredShadowCubeProgram.unload();
         gDeferredShadowAlphaMaskProgram.unload();
+        gDeferredSkinnedShadowAlphaMaskProgram.unload();
         gDeferredShadowFullbrightAlphaMaskProgram.unload();
+        gDeferredSkinnedShadowFullbrightAlphaMaskProgram.unload();
 		gDeferredAvatarShadowProgram.unload();
         gDeferredAvatarAlphaShadowProgram.unload();
         gDeferredAvatarAlphaMaskShadowProgram.unload();
@@ -1263,12 +1283,17 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		gDeferredAvatarProgram.unload();
 		gDeferredAvatarAlphaProgram.unload();
 		gDeferredAlphaProgram.unload();
+        gDeferredSkinnedAlphaProgram.unload();
 		gDeferredAlphaWaterProgram.unload();
+        gDeferredSkinnedAlphaWaterProgram.unload();
 		gDeferredFullbrightProgram.unload();
 		gDeferredFullbrightAlphaMaskProgram.unload();
 		gDeferredFullbrightWaterProgram.unload();
+        gDeferredSkinnedFullbrightWaterProgram.unload();
 		gDeferredFullbrightAlphaMaskWaterProgram.unload();
+        gDeferredSkinnedFullbrightAlphaMaskWaterProgram.unload();
 		gDeferredEmissiveProgram.unload();
+        gDeferredSkinnedEmissiveProgram.unload();
 		gDeferredAvatarEyesProgram.unload();
 		gDeferredPostProgram.unload();		
 		gDeferredCoFProgram.unload();		
@@ -1283,8 +1308,9 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
         gDeferredWLMoonProgram.unload();
 		gDeferredStarProgram.unload();
 		gDeferredFullbrightShinyProgram.unload();
-		gDeferredSkinnedFullbrightShinyProgram.unload();
+        gDeferredSkinnedFullbrightShinyProgram.unload();
 		gDeferredSkinnedFullbrightProgram.unload();
+        gDeferredSkinnedFullbrightAlphaMaskProgram.unload();
 
         gDeferredHighlightProgram.unload();
         gDeferredHighlightNormalProgram.unload();
@@ -1341,7 +1367,8 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		gDeferredDiffuseProgram.mShaderFiles.push_back(make_pair("deferred/diffuseIndexedF.glsl", GL_FRAGMENT_SHADER_ARB));
 		gDeferredDiffuseProgram.mFeatures.mIndexedTextureChannels = LLGLSLShader::sIndexedTextureChannels;
 		gDeferredDiffuseProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED];
-		success = gDeferredDiffuseProgram.createShader(NULL, NULL);
+        success = make_rigged_variant(gDeferredDiffuseProgram, gDeferredSkinnedDiffuseProgram);
+		success = success && gDeferredDiffuseProgram.createShader(NULL, NULL);
 	}
 
 	if (success)
@@ -1353,7 +1380,8 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		gDeferredDiffuseAlphaMaskProgram.mShaderFiles.push_back(make_pair("deferred/diffuseAlphaMaskIndexedF.glsl", GL_FRAGMENT_SHADER_ARB));
 		gDeferredDiffuseAlphaMaskProgram.mFeatures.mIndexedTextureChannels = LLGLSLShader::sIndexedTextureChannels;
 		gDeferredDiffuseAlphaMaskProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED];
-		success = gDeferredDiffuseAlphaMaskProgram.createShader(NULL, NULL);
+        success = make_rigged_variant(gDeferredDiffuseAlphaMaskProgram, gDeferredSkinnedDiffuseAlphaMaskProgram);
+		success = success && gDeferredDiffuseAlphaMaskProgram.createShader(NULL, NULL);
 	}
 
 	if (success)
@@ -1393,87 +1421,6 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
         llassert(success);
 	}
 
-	if (success)
-	{
-		gDeferredSkinnedDiffuseProgram.mName = "Deferred Skinned Diffuse Shader";
-		gDeferredSkinnedDiffuseProgram.mFeatures.hasObjectSkinning = true;
-		gDeferredSkinnedDiffuseProgram.mFeatures.encodesNormal = true;
-        gDeferredSkinnedDiffuseProgram.mFeatures.hasSrgb = true;
-		gDeferredSkinnedDiffuseProgram.mShaderFiles.clear();
-		gDeferredSkinnedDiffuseProgram.mShaderFiles.push_back(make_pair("deferred/diffuseSkinnedV.glsl", GL_VERTEX_SHADER_ARB));
-		gDeferredSkinnedDiffuseProgram.mShaderFiles.push_back(make_pair("deferred/diffuseF.glsl", GL_FRAGMENT_SHADER_ARB));
-		gDeferredSkinnedDiffuseProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED];
-		success = gDeferredSkinnedDiffuseProgram.createShader(NULL, NULL);
-		llassert(success);
-	}
-
-	if (success)
-	{
-		gDeferredSkinnedBumpProgram.mName = "Deferred Skinned Bump Shader";
-		gDeferredSkinnedBumpProgram.mFeatures.hasObjectSkinning = true;
-        gDeferredSkinnedBumpProgram.mFeatures.encodesNormal = true;
-		gDeferredSkinnedBumpProgram.mShaderFiles.clear();
-		gDeferredSkinnedBumpProgram.mShaderFiles.push_back(make_pair("deferred/bumpSkinnedV.glsl", GL_VERTEX_SHADER_ARB));
-		gDeferredSkinnedBumpProgram.mShaderFiles.push_back(make_pair("deferred/bumpF.glsl", GL_FRAGMENT_SHADER_ARB));
-		gDeferredSkinnedBumpProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED];
-		success = gDeferredSkinnedBumpProgram.createShader(NULL, NULL);
-        llassert(success);
-	}
-
-	if (success)
-	{
-		gDeferredSkinnedAlphaProgram.mName = "Deferred Skinned Alpha Shader";
-		gDeferredSkinnedAlphaProgram.mFeatures.hasObjectSkinning = true;
-		gDeferredSkinnedAlphaProgram.mFeatures.calculatesLighting = false;
-		gDeferredSkinnedAlphaProgram.mFeatures.hasLighting = false;
-		gDeferredSkinnedAlphaProgram.mFeatures.isAlphaLighting = true;
-		gDeferredSkinnedAlphaProgram.mFeatures.disableTextureIndex = true;
-		gDeferredSkinnedAlphaProgram.mFeatures.hasSrgb = true;
-		gDeferredSkinnedAlphaProgram.mFeatures.encodesNormal = true;
-		gDeferredSkinnedAlphaProgram.mFeatures.calculatesAtmospherics = true;
-		gDeferredSkinnedAlphaProgram.mFeatures.hasAtmospherics = true;
-		gDeferredSkinnedAlphaProgram.mFeatures.hasTransport = true;
-		gDeferredSkinnedAlphaProgram.mFeatures.hasGamma = true;
-		gDeferredSkinnedAlphaProgram.mFeatures.hasShadows = true;
-        
-		gDeferredSkinnedAlphaProgram.mShaderFiles.clear();
-		gDeferredSkinnedAlphaProgram.mShaderFiles.push_back(make_pair("deferred/alphaV.glsl", GL_VERTEX_SHADER_ARB));
-		gDeferredSkinnedAlphaProgram.mShaderFiles.push_back(make_pair("deferred/alphaF.glsl", GL_FRAGMENT_SHADER_ARB));
-		gDeferredSkinnedAlphaProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED];
-
-		gDeferredSkinnedAlphaProgram.clearPermutations();
-		gDeferredSkinnedAlphaProgram.addPermutation("USE_DIFFUSE_TEX", "1");
-		gDeferredSkinnedAlphaProgram.addPermutation("HAS_SKIN", "1");
-        gDeferredSkinnedAlphaProgram.addPermutation("USE_VERTEX_COLOR", "1");
-
-		if (use_sun_shadow)
-		{
-			gDeferredSkinnedAlphaProgram.addPermutation("HAS_SHADOW", "1");
-		}
-
-        if (ambient_kill)
-        {
-            gDeferredSkinnedAlphaProgram.addPermutation("AMBIENT_KILL", "1");
-        }
-
-        if (sunlight_kill)
-        {
-            gDeferredSkinnedAlphaProgram.addPermutation("SUNLIGHT_KILL", "1");
-        }
-
-        if (local_light_kill)
-        {
-            gDeferredSkinnedAlphaProgram.addPermutation("LOCAL_LIGHT_KILL", "1");
-        }
-
-		success = gDeferredSkinnedAlphaProgram.createShader(NULL, NULL);
-		llassert(success);
-
-		// Hack to include uniforms for lighting without linking in lighting file
-		gDeferredSkinnedAlphaProgram.mFeatures.calculatesLighting = true;
-		gDeferredSkinnedAlphaProgram.mFeatures.hasLighting = true;
-	}
-
 	if (success)
 	{
 		gDeferredBumpProgram.mName = "Deferred Bump Shader";
@@ -1482,7 +1429,8 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		gDeferredBumpProgram.mShaderFiles.push_back(make_pair("deferred/bumpV.glsl", GL_VERTEX_SHADER_ARB));
 		gDeferredBumpProgram.mShaderFiles.push_back(make_pair("deferred/bumpF.glsl", GL_FRAGMENT_SHADER_ARB));
 		gDeferredBumpProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED];
-		success = gDeferredBumpProgram.createShader(NULL, NULL);
+        success = make_rigged_variant(gDeferredBumpProgram, gDeferredSkinnedBumpProgram);
+		success = success && gDeferredBumpProgram.createShader(NULL, NULL);
 		llassert(success);
 	}
 
@@ -1570,6 +1518,10 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
                 gDeferredMaterialProgram[i].addPermutation("HAS_SKIN", "1");
                 gDeferredMaterialProgram[i].mFeatures.hasObjectSkinning = true;
             }
+            else
+            {
+                gDeferredMaterialProgram[i].mRiggedVariant = &gDeferredMaterialProgram[i + 0x10];
+            }
 
             success = gDeferredMaterialProgram[i].createShader(NULL, NULL);
             llassert(success);
@@ -1615,6 +1567,10 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
             {
                 gDeferredMaterialWaterProgram[i].addPermutation("HAS_SKIN", "1");
             }
+            else
+            {
+                gDeferredMaterialWaterProgram[i].mRiggedVariant = &(gDeferredMaterialWaterProgram[i + 0x10]);
+            }
             gDeferredMaterialWaterProgram[i].addPermutation("WATER_FOG","1");
 
             if (ambient_kill)
@@ -1691,10 +1647,25 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		gDeferredTreeShadowProgram.mShaderFiles.push_back(make_pair("deferred/treeShadowV.glsl", GL_VERTEX_SHADER_ARB));
 		gDeferredTreeShadowProgram.mShaderFiles.push_back(make_pair("deferred/treeShadowF.glsl", GL_FRAGMENT_SHADER_ARB));
 		gDeferredTreeShadowProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED];
+        gDeferredTreeShadowProgram.mRiggedVariant = &gDeferredSkinnedTreeShadowProgram;
 		success = gDeferredTreeShadowProgram.createShader(NULL, NULL);
         llassert(success);
 	}
 
+    if (success)
+    {
+        gDeferredSkinnedTreeShadowProgram.mName = "Deferred Skinned Tree Shadow Shader";
+        gDeferredSkinnedTreeShadowProgram.mShaderFiles.clear();
+        gDeferredSkinnedTreeShadowProgram.mFeatures.isDeferred = true;
+        gDeferredSkinnedTreeShadowProgram.mFeatures.hasShadows = true;
+        gDeferredSkinnedTreeShadowProgram.mFeatures.hasObjectSkinning = true;
+        gDeferredSkinnedTreeShadowProgram.mShaderFiles.push_back(make_pair("deferred/treeShadowSkinnedV.glsl", GL_VERTEX_SHADER_ARB));
+        gDeferredSkinnedTreeShadowProgram.mShaderFiles.push_back(make_pair("deferred/treeShadowF.glsl", GL_FRAGMENT_SHADER_ARB));
+        gDeferredSkinnedTreeShadowProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED];
+        success = gDeferredSkinnedTreeShadowProgram.createShader(NULL, NULL);
+        llassert(success);
+    }
+
 	if (success)
 	{
 		gDeferredImpostorProgram.mName = "Deferred Impostor Shader";
@@ -1883,172 +1854,235 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 
 	if (success)
 	{
-		gDeferredAlphaProgram.mName = "Deferred Alpha Shader";
-
-		gDeferredAlphaProgram.mFeatures.calculatesLighting = false;
-		gDeferredAlphaProgram.mFeatures.hasLighting = false;
-		gDeferredAlphaProgram.mFeatures.isAlphaLighting = true;
-		gDeferredAlphaProgram.mFeatures.disableTextureIndex = true; //hack to disable auto-setup of texture channels
-		gDeferredAlphaProgram.mFeatures.hasSrgb = true;
-		gDeferredAlphaProgram.mFeatures.encodesNormal = true;
-		gDeferredAlphaProgram.mFeatures.calculatesAtmospherics = true;
-        gDeferredAlphaProgram.mFeatures.hasAtmospherics = true;
-        gDeferredAlphaProgram.mFeatures.hasGamma = true;
-        gDeferredAlphaProgram.mFeatures.hasTransport = true;
-        gDeferredAlphaProgram.mFeatures.hasShadows = use_sun_shadow;
-
-        if (mShaderLevel[SHADER_DEFERRED] < 1)
+        for (int i = 0; i < 2 && success; ++i)
         {
-            gDeferredAlphaProgram.mFeatures.mIndexedTextureChannels = LLGLSLShader::sIndexedTextureChannels;
-        }
-        else
-        { //shave off some texture units for shadow maps
-            gDeferredAlphaProgram.mFeatures.mIndexedTextureChannels = llmax(LLGLSLShader::sIndexedTextureChannels - 6, 1);
-        }
-            
-        gDeferredAlphaProgram.mShaderFiles.clear();
-        gDeferredAlphaProgram.mShaderFiles.push_back(make_pair("deferred/alphaV.glsl", GL_VERTEX_SHADER_ARB));
-        gDeferredAlphaProgram.mShaderFiles.push_back(make_pair("deferred/alphaF.glsl", GL_FRAGMENT_SHADER_ARB));
-
-        gDeferredAlphaProgram.clearPermutations();
-        gDeferredAlphaProgram.addPermutation("USE_VERTEX_COLOR", "1");
-        gDeferredAlphaProgram.addPermutation("USE_INDEXED_TEX", "1");
-        if (use_sun_shadow)
-        {
-            gDeferredAlphaProgram.addPermutation("HAS_SHADOW", "1");
-        }
+            LLGLSLShader* shader = nullptr;
+            bool rigged = i == 1;
+            if (!rigged)
+            {
+                shader = &gDeferredAlphaProgram;
+                shader->mName = "Deferred Alpha Shader";
+                shader->mRiggedVariant = &gDeferredSkinnedAlphaProgram;
+            }
+            else
+            {
+                shader = &gDeferredSkinnedAlphaProgram;
+                shader->mName = "Skinned Deferred Alpha Shader";
+                shader->mFeatures.hasObjectSkinning = true;
+            }
 
-        if (ambient_kill)
-        {
-            gDeferredAlphaProgram.addPermutation("AMBIENT_KILL", "1");
-        }
+            shader->mFeatures.calculatesLighting = false;
+            shader->mFeatures.hasLighting = false;
+            shader->mFeatures.isAlphaLighting = true;
+            shader->mFeatures.disableTextureIndex = true; //hack to disable auto-setup of texture channels
+            shader->mFeatures.hasSrgb = true;
+            shader->mFeatures.encodesNormal = true;
+            shader->mFeatures.calculatesAtmospherics = true;
+            shader->mFeatures.hasAtmospherics = true;
+            shader->mFeatures.hasGamma = true;
+            shader->mFeatures.hasTransport = true;
+            shader->mFeatures.hasShadows = use_sun_shadow;
+
+            if (mShaderLevel[SHADER_DEFERRED] < 1)
+            {
+                shader->mFeatures.mIndexedTextureChannels = LLGLSLShader::sIndexedTextureChannels;
+            }
+            else
+            { //shave off some texture units for shadow maps
+                shader->mFeatures.mIndexedTextureChannels = llmax(LLGLSLShader::sIndexedTextureChannels - 6, 1);
+            }
 
-        if (sunlight_kill)
-        {
-            gDeferredAlphaProgram.addPermutation("SUNLIGHT_KILL", "1");
-        }
+            shader->mShaderFiles.clear();
+            shader->mShaderFiles.push_back(make_pair("deferred/alphaV.glsl", GL_VERTEX_SHADER_ARB));
+            shader->mShaderFiles.push_back(make_pair("deferred/alphaF.glsl", GL_FRAGMENT_SHADER_ARB));
 
-        if (local_light_kill)
-        {
-            gDeferredAlphaProgram.addPermutation("LOCAL_LIGHT_KILL", "1");
-        }
+            shader->clearPermutations();
+            shader->addPermutation("USE_VERTEX_COLOR", "1");
+            shader->addPermutation("USE_INDEXED_TEX", "1");
+            if (use_sun_shadow)
+            {
+                shader->addPermutation("HAS_SHADOW", "1");
+            }
 
-        gDeferredAlphaProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED];
+            if (ambient_kill)
+            {
+                shader->addPermutation("AMBIENT_KILL", "1");
+            }
 
-        success = gDeferredAlphaProgram.createShader(NULL, NULL);
-        llassert(success);
+            if (sunlight_kill)
+            {
+                shader->addPermutation("SUNLIGHT_KILL", "1");
+            }
 
-        // Hack
-        gDeferredAlphaProgram.mFeatures.calculatesLighting = true;
-        gDeferredAlphaProgram.mFeatures.hasLighting = true;
+            if (local_light_kill)
+            {
+                shader->addPermutation("LOCAL_LIGHT_KILL", "1");
+            }
+
+            if (rigged)
+            {
+                shader->addPermutation("HAS_SKIN", "1");
+            }
+
+            shader->mShaderLevel = mShaderLevel[SHADER_DEFERRED];
+
+            success = shader->createShader(NULL, NULL);
+            llassert(success);
+
+            // Hack
+            shader->mFeatures.calculatesLighting = true;
+            shader->mFeatures.hasLighting = true;
+        }
     }
 
     if (success)
     {
-        gDeferredAlphaImpostorProgram.mName = "Deferred Alpha Impostor Shader";
+        LLGLSLShader* shaders[] = { 
+            &gDeferredAlphaImpostorProgram, 
+            &gDeferredSkinnedAlphaImpostorProgram 
+        };
 
-// Begin Hack
-		gDeferredAlphaImpostorProgram.mFeatures.calculatesLighting = false;
-		gDeferredAlphaImpostorProgram.mFeatures.hasLighting = false;
+        for (int i = 0; i < 2 && success; ++i)
+        {
+            bool rigged = i == 1;
+            LLGLSLShader* shader = shaders[i];
 
-        gDeferredAlphaImpostorProgram.mFeatures.hasSrgb = true;
-		gDeferredAlphaImpostorProgram.mFeatures.isAlphaLighting = true;
-        gDeferredAlphaImpostorProgram.mFeatures.encodesNormal = true;
-        gDeferredAlphaImpostorProgram.mFeatures.hasShadows = use_sun_shadow;
+            shader->mName = rigged ? "Skinned Deferred Alpha Impostor Shader" : "Deferred Alpha Impostor Shader";
 
-        if (mShaderLevel[SHADER_DEFERRED] < 1)
-        {
-            gDeferredAlphaImpostorProgram.mFeatures.mIndexedTextureChannels = LLGLSLShader::sIndexedTextureChannels;
-        }
-        else
-        { //shave off some texture units for shadow maps
-            gDeferredAlphaImpostorProgram.mFeatures.mIndexedTextureChannels = llmax(LLGLSLShader::sIndexedTextureChannels - 6, 1);
-        }
+            // Begin Hack
+            shader->mFeatures.calculatesLighting = false;
+            shader->mFeatures.hasLighting = false;
 
-        gDeferredAlphaImpostorProgram.mShaderFiles.clear();
-        gDeferredAlphaImpostorProgram.mShaderFiles.push_back(make_pair("deferred/alphaV.glsl", GL_VERTEX_SHADER_ARB));
-        gDeferredAlphaImpostorProgram.mShaderFiles.push_back(make_pair("deferred/alphaF.glsl", GL_FRAGMENT_SHADER_ARB));
+            shader->mFeatures.hasSrgb = true;
+            shader->mFeatures.isAlphaLighting = true;
+            shader->mFeatures.encodesNormal = true;
+            shader->mFeatures.hasShadows = use_sun_shadow;
 
-        gDeferredAlphaImpostorProgram.clearPermutations();
-        gDeferredAlphaImpostorProgram.addPermutation("USE_INDEXED_TEX", "1");
-        gDeferredAlphaImpostorProgram.addPermutation("FOR_IMPOSTOR", "1");
-        gDeferredAlphaImpostorProgram.addPermutation("USE_VERTEX_COLOR", "1");
+            if (mShaderLevel[SHADER_DEFERRED] < 1)
+            {
+                shader->mFeatures.mIndexedTextureChannels = LLGLSLShader::sIndexedTextureChannels;
+            }
+            else
+            { //shave off some texture units for shadow maps
+                shader->mFeatures.mIndexedTextureChannels = llmax(LLGLSLShader::sIndexedTextureChannels - 6, 1);
+            }
 
-        if (use_sun_shadow)
-        {
-            gDeferredAlphaImpostorProgram.addPermutation("HAS_SHADOW", "1");
-        }
+            shader->mShaderFiles.clear();
+            shader->mShaderFiles.push_back(make_pair("deferred/alphaV.glsl", GL_VERTEX_SHADER_ARB));
+            shader->mShaderFiles.push_back(make_pair("deferred/alphaF.glsl", GL_FRAGMENT_SHADER_ARB));
+
+            shader->clearPermutations();
+            shader->addPermutation("USE_INDEXED_TEX", "1");
+            shader->addPermutation("FOR_IMPOSTOR", "1");
+            shader->addPermutation("USE_VERTEX_COLOR", "1");
+            if (rigged)
+            {
+                shader->mFeatures.hasObjectSkinning = true;
+                shader->addPermutation("HAS_SKIN", "1");
+            }
 
-        gDeferredAlphaImpostorProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED];
+            if (use_sun_shadow)
+            {
+                shader->addPermutation("HAS_SHADOW", "1");
+            }
 
-        success = gDeferredAlphaImpostorProgram.createShader(NULL, NULL);
-        llassert(success);
+            shader->mRiggedVariant = &gDeferredSkinnedAlphaImpostorProgram;
+            shader->mShaderLevel = mShaderLevel[SHADER_DEFERRED];
+            if (!rigged)
+            {
+                shader->mRiggedVariant = shaders[1];
+            }
+            success = shader->createShader(NULL, NULL);
+            llassert(success);
 
-// End Hack
-        gDeferredAlphaImpostorProgram.mFeatures.calculatesLighting = true;
-        gDeferredAlphaImpostorProgram.mFeatures.hasLighting = true;
+            // End Hack
+            shader->mFeatures.calculatesLighting = true;
+            shader->mFeatures.hasLighting = true;
+        }
     }
 
-	if (success)
-	{
-		gDeferredAlphaWaterProgram.mName = "Deferred Alpha Underwater Shader";
-		gDeferredAlphaWaterProgram.mFeatures.calculatesLighting = false;
-		gDeferredAlphaWaterProgram.mFeatures.hasLighting = false;
-		gDeferredAlphaWaterProgram.mFeatures.isAlphaLighting = true;
-		gDeferredAlphaWaterProgram.mFeatures.disableTextureIndex = true; //hack to disable auto-setup of texture channels
-		gDeferredAlphaWaterProgram.mFeatures.hasWaterFog = true;
-		gDeferredAlphaWaterProgram.mFeatures.hasSrgb = true;
-		gDeferredAlphaWaterProgram.mFeatures.encodesNormal = true;
-		gDeferredAlphaWaterProgram.mFeatures.calculatesAtmospherics = true;
-		gDeferredAlphaWaterProgram.mFeatures.hasAtmospherics = true;
-		gDeferredAlphaWaterProgram.mFeatures.hasGamma = true;
-		gDeferredAlphaWaterProgram.mFeatures.hasTransport = true;
-		gDeferredAlphaWaterProgram.mFeatures.hasShadows = use_sun_shadow;
-
-		if (mShaderLevel[SHADER_DEFERRED] < 1)
-		{
-			gDeferredAlphaWaterProgram.mFeatures.mIndexedTextureChannels = LLGLSLShader::sIndexedTextureChannels;
-		}
-		else
-		{ //shave off some texture units for shadow maps
-			gDeferredAlphaWaterProgram.mFeatures.mIndexedTextureChannels = llmax(LLGLSLShader::sIndexedTextureChannels - 6, 1);
-		}
-		gDeferredAlphaWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER;
-		gDeferredAlphaWaterProgram.mShaderFiles.clear();
-		gDeferredAlphaWaterProgram.mShaderFiles.push_back(make_pair("deferred/alphaV.glsl", GL_VERTEX_SHADER_ARB));
-		gDeferredAlphaWaterProgram.mShaderFiles.push_back(make_pair("deferred/alphaF.glsl", GL_FRAGMENT_SHADER_ARB));
-
-		gDeferredAlphaWaterProgram.clearPermutations();
-		gDeferredAlphaWaterProgram.addPermutation("USE_INDEXED_TEX", "1");
-		gDeferredAlphaWaterProgram.addPermutation("WATER_FOG", "1");
-        gDeferredAlphaWaterProgram.addPermutation("USE_VERTEX_COLOR", "1");
-		if (use_sun_shadow)
-		{
-			gDeferredAlphaWaterProgram.addPermutation("HAS_SHADOW", "1");
-		}
+    if (success)
+    {
+        LLGLSLShader* shader[] = {
+            &gDeferredAlphaWaterProgram,
+            &gDeferredSkinnedAlphaWaterProgram
+        };
+        
+        gDeferredAlphaWaterProgram.mRiggedVariant = &gDeferredSkinnedAlphaWaterProgram;
+		
+        gDeferredAlphaWaterProgram.mName = "Deferred Alpha Underwater Shader";
+        gDeferredSkinnedAlphaWaterProgram.mName = "Deferred Skinned Alpha Underwater Shader";
 
-        if (ambient_kill)
+        for (int i = 0; i < 2 && success; ++i)
         {
-            gDeferredAlphaWaterProgram.addPermutation("AMBIENT_KILL", "1");
-        }
+            shader[i]->mFeatures.calculatesLighting = false;
+            shader[i]->mFeatures.hasLighting = false;
+            shader[i]->mFeatures.isAlphaLighting = true;
+            shader[i]->mFeatures.disableTextureIndex = true; //hack to disable auto-setup of texture channels
+            shader[i]->mFeatures.hasWaterFog = true;
+            shader[i]->mFeatures.hasSrgb = true;
+            shader[i]->mFeatures.encodesNormal = true;
+            shader[i]->mFeatures.calculatesAtmospherics = true;
+            shader[i]->mFeatures.hasAtmospherics = true;
+            shader[i]->mFeatures.hasGamma = true;
+            shader[i]->mFeatures.hasTransport = true;
+            shader[i]->mFeatures.hasShadows = use_sun_shadow;
+
+            if (mShaderLevel[SHADER_DEFERRED] < 1)
+            {
+                shader[i]->mFeatures.mIndexedTextureChannels = LLGLSLShader::sIndexedTextureChannels;
+            }
+            else
+            { //shave off some texture units for shadow maps
+                shader[i]->mFeatures.mIndexedTextureChannels = llmax(LLGLSLShader::sIndexedTextureChannels - 6, 1);
+            }
+            shader[i]->mShaderGroup = LLGLSLShader::SG_WATER;
+            shader[i]->mShaderFiles.clear();
+            shader[i]->mShaderFiles.push_back(make_pair("deferred/alphaV.glsl", GL_VERTEX_SHADER_ARB));
+            shader[i]->mShaderFiles.push_back(make_pair("deferred/alphaF.glsl", GL_FRAGMENT_SHADER_ARB));
+
+            shader[i]->clearPermutations();
+            shader[i]->addPermutation("USE_INDEXED_TEX", "1");
+            shader[i]->addPermutation("WATER_FOG", "1");
+            shader[i]->addPermutation("USE_VERTEX_COLOR", "1");
+            if (use_sun_shadow)
+            {
+                shader[i]->addPermutation("HAS_SHADOW", "1");
+            }
 
-        if (sunlight_kill)
-        {
-            gDeferredAlphaWaterProgram.addPermutation("SUNLIGHT_KILL", "1");
-        }
+            if (ambient_kill)
+            {
+                shader[i]->addPermutation("AMBIENT_KILL", "1");
+            }
 
-        if (local_light_kill)
-        {
-            gDeferredAlphaWaterProgram.addPermutation("LOCAL_LIGHT_KILL", "1");
-        }
-        gDeferredAlphaWaterProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED];
+            if (sunlight_kill)
+            {
+                shader[i]->addPermutation("SUNLIGHT_KILL", "1");
+            }
 
-		success = gDeferredAlphaWaterProgram.createShader(NULL, NULL);
-		llassert(success);
+            if (local_light_kill)
+            {
+                shader[i]->addPermutation("LOCAL_LIGHT_KILL", "1");
+            }
 
-		// Hack
-		gDeferredAlphaWaterProgram.mFeatures.calculatesLighting = true;
-		gDeferredAlphaWaterProgram.mFeatures.hasLighting = true;
+            if (i == 1)
+            { // rigged variant
+                shader[i]->mFeatures.hasObjectSkinning = true;
+                shader[i]->addPermutation("HAS_SKIN", "1");
+            }
+            else
+            {
+                shader[i]->mRiggedVariant = shader[1];
+            }
+            shader[i]->mShaderLevel = mShaderLevel[SHADER_DEFERRED];
+
+            success = shader[i]->createShader(NULL, NULL);
+            llassert(success);
+
+            // Hack
+            shader[i]->mFeatures.calculatesLighting = true;
+            shader[i]->mFeatures.hasLighting = true;
+        }
 	}
 
 	if (success)
@@ -2082,6 +2116,7 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		gDeferredFullbrightProgram.mShaderFiles.push_back(make_pair("deferred/fullbrightV.glsl", GL_VERTEX_SHADER_ARB));
 		gDeferredFullbrightProgram.mShaderFiles.push_back(make_pair("deferred/fullbrightF.glsl", GL_FRAGMENT_SHADER_ARB));
 		gDeferredFullbrightProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED];
+        success = make_rigged_variant(gDeferredFullbrightProgram, gDeferredSkinnedFullbrightProgram);
 		success = gDeferredFullbrightProgram.createShader(NULL, NULL);
 		llassert(success);
 	}
@@ -2099,7 +2134,8 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		gDeferredFullbrightAlphaMaskProgram.mShaderFiles.push_back(make_pair("deferred/fullbrightF.glsl", GL_FRAGMENT_SHADER_ARB));
 		gDeferredFullbrightAlphaMaskProgram.addPermutation("HAS_ALPHA_MASK","1");
 		gDeferredFullbrightAlphaMaskProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED];
-		success = gDeferredFullbrightAlphaMaskProgram.createShader(NULL, NULL);
+        success = make_rigged_variant(gDeferredFullbrightAlphaMaskProgram, gDeferredSkinnedFullbrightAlphaMaskProgram);
+		success = success && gDeferredFullbrightAlphaMaskProgram.createShader(NULL, NULL);
 		llassert(success);
 	}
 
@@ -2118,10 +2154,11 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		gDeferredFullbrightWaterProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED];
 		gDeferredFullbrightWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER;
 		gDeferredFullbrightWaterProgram.addPermutation("WATER_FOG","1");
-		success = gDeferredFullbrightWaterProgram.createShader(NULL, NULL);
+        success = make_rigged_variant(gDeferredFullbrightWaterProgram, gDeferredSkinnedFullbrightWaterProgram);
+		success = success && gDeferredFullbrightWaterProgram.createShader(NULL, NULL);
 		llassert(success);
 	}
-
+    
 	if (success)
 	{
 		gDeferredFullbrightAlphaMaskWaterProgram.mName = "Deferred Fullbright Underwater Alpha Masking Shader";
@@ -2138,7 +2175,8 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		gDeferredFullbrightAlphaMaskWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER;
 		gDeferredFullbrightAlphaMaskWaterProgram.addPermutation("HAS_ALPHA_MASK","1");
 		gDeferredFullbrightAlphaMaskWaterProgram.addPermutation("WATER_FOG","1");
-		success = gDeferredFullbrightAlphaMaskWaterProgram.createShader(NULL, NULL);
+        success = make_rigged_variant(gDeferredFullbrightAlphaMaskWaterProgram, gDeferredSkinnedFullbrightAlphaMaskWaterProgram);
+		success = success && gDeferredFullbrightAlphaMaskWaterProgram.createShader(NULL, NULL);
 		llassert(success);
 	}
 
@@ -2155,43 +2193,8 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		gDeferredFullbrightShinyProgram.mShaderFiles.push_back(make_pair("deferred/fullbrightShinyV.glsl", GL_VERTEX_SHADER_ARB));
 		gDeferredFullbrightShinyProgram.mShaderFiles.push_back(make_pair("deferred/fullbrightShinyF.glsl", GL_FRAGMENT_SHADER_ARB));
 		gDeferredFullbrightShinyProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED];
-		success = gDeferredFullbrightShinyProgram.createShader(NULL, NULL);
-		llassert(success);
-	}
-
-	if (success)
-	{
-		gDeferredSkinnedFullbrightProgram.mName = "Skinned Fullbright Shader";
-		gDeferredSkinnedFullbrightProgram.mFeatures.calculatesAtmospherics = true;
-		gDeferredSkinnedFullbrightProgram.mFeatures.hasAtmospherics = true;
-		gDeferredSkinnedFullbrightProgram.mFeatures.hasGamma = true;
-		gDeferredSkinnedFullbrightProgram.mFeatures.hasTransport = true;
-		gDeferredSkinnedFullbrightProgram.mFeatures.hasObjectSkinning = true;
-		gDeferredSkinnedFullbrightProgram.mFeatures.disableTextureIndex = true;
-		gDeferredSkinnedFullbrightProgram.mFeatures.hasSrgb = true;
-		gDeferredSkinnedFullbrightProgram.mShaderFiles.clear();
-		gDeferredSkinnedFullbrightProgram.mShaderFiles.push_back(make_pair("objects/fullbrightSkinnedV.glsl", GL_VERTEX_SHADER_ARB));
-		gDeferredSkinnedFullbrightProgram.mShaderFiles.push_back(make_pair("deferred/fullbrightF.glsl", GL_FRAGMENT_SHADER_ARB));
-		gDeferredSkinnedFullbrightProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT];
-		success = gDeferredSkinnedFullbrightProgram.createShader(NULL, NULL);
-		llassert(success);
-	}
-
-	if (success)
-	{
-		gDeferredSkinnedFullbrightShinyProgram.mName = "Skinned Fullbright Shiny Shader";
-		gDeferredSkinnedFullbrightShinyProgram.mFeatures.calculatesAtmospherics = true;
-        gDeferredSkinnedFullbrightShinyProgram.mFeatures.hasAtmospherics = true;
-		gDeferredSkinnedFullbrightShinyProgram.mFeatures.hasGamma = true;
-		gDeferredSkinnedFullbrightShinyProgram.mFeatures.hasTransport = true;
-		gDeferredSkinnedFullbrightShinyProgram.mFeatures.hasObjectSkinning = true;
-		gDeferredSkinnedFullbrightShinyProgram.mFeatures.disableTextureIndex = true;
-        gDeferredSkinnedFullbrightShinyProgram.mFeatures.hasSrgb = true;
-		gDeferredSkinnedFullbrightShinyProgram.mShaderFiles.clear();
-		gDeferredSkinnedFullbrightShinyProgram.mShaderFiles.push_back(make_pair("objects/fullbrightShinySkinnedV.glsl", GL_VERTEX_SHADER_ARB));
-		gDeferredSkinnedFullbrightShinyProgram.mShaderFiles.push_back(make_pair("deferred/fullbrightShinyF.glsl", GL_FRAGMENT_SHADER_ARB));
-		gDeferredSkinnedFullbrightShinyProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT];
-		success = gDeferredSkinnedFullbrightShinyProgram.createShader(NULL, NULL);
+        success = make_rigged_variant(gDeferredFullbrightShinyProgram, gDeferredSkinnedFullbrightShinyProgram);
+		success = success && gDeferredFullbrightShinyProgram.createShader(NULL, NULL);
 		llassert(success);
 	}
 
@@ -2206,7 +2209,8 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		gDeferredEmissiveProgram.mShaderFiles.push_back(make_pair("deferred/emissiveV.glsl", GL_VERTEX_SHADER_ARB));
 		gDeferredEmissiveProgram.mShaderFiles.push_back(make_pair("deferred/emissiveF.glsl", GL_FRAGMENT_SHADER_ARB));
 		gDeferredEmissiveProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED];
-		success = gDeferredEmissiveProgram.createShader(NULL, NULL);
+        success = make_rigged_variant(gDeferredEmissiveProgram, gDeferredSkinnedEmissiveProgram);
+		success = success && gDeferredEmissiveProgram.createShader(NULL, NULL);
 		llassert(success);
 	}
 
@@ -2349,10 +2353,29 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		{
 			gDeferredShadowProgram.addPermutation("DEPTH_CLAMP", "1");
 		}
+        gDeferredShadowProgram.mRiggedVariant = &gDeferredSkinnedShadowProgram;
 		success = gDeferredShadowProgram.createShader(NULL, NULL);
 		llassert(success);
 	}
 
+    if (success)
+    {
+        gDeferredSkinnedShadowProgram.mName = "Deferred Skinned Shadow Shader";
+        gDeferredSkinnedShadowProgram.mFeatures.isDeferred = true;
+        gDeferredSkinnedShadowProgram.mFeatures.hasShadows = true;
+        gDeferredSkinnedShadowProgram.mFeatures.hasObjectSkinning = true;
+        gDeferredSkinnedShadowProgram.mShaderFiles.clear();
+        gDeferredSkinnedShadowProgram.mShaderFiles.push_back(make_pair("deferred/shadowSkinnedV.glsl", GL_VERTEX_SHADER_ARB));
+        gDeferredSkinnedShadowProgram.mShaderFiles.push_back(make_pair("deferred/shadowF.glsl", GL_FRAGMENT_SHADER_ARB));
+        gDeferredSkinnedShadowProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED];
+        if (gGLManager.mHasDepthClamp)
+        {
+            gDeferredSkinnedShadowProgram.addPermutation("DEPTH_CLAMP", "1");
+        }
+        success = gDeferredSkinnedShadowProgram.createShader(NULL, NULL);
+        llassert(success);
+    }
+
 	if (success)
 	{
 		gDeferredShadowCubeProgram.mName = "Deferred Shadow Cube Shader";
@@ -2386,10 +2409,31 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		}
         gDeferredShadowFullbrightAlphaMaskProgram.addPermutation("IS_FULLBRIGHT", "1");
 		gDeferredShadowFullbrightAlphaMaskProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED];
+        gDeferredShadowFullbrightAlphaMaskProgram.mRiggedVariant = &gDeferredSkinnedShadowFullbrightAlphaMaskProgram;
 		success = gDeferredShadowFullbrightAlphaMaskProgram.createShader(NULL, NULL);
 		llassert(success);
 	}
     
+    if (success)
+    {
+        gDeferredSkinnedShadowFullbrightAlphaMaskProgram.mName = "Deferred Skinned Shadow Fullbright Alpha Mask Shader";
+        gDeferredSkinnedShadowFullbrightAlphaMaskProgram.mFeatures.mIndexedTextureChannels = LLGLSLShader::sIndexedTextureChannels;
+        gDeferredSkinnedShadowFullbrightAlphaMaskProgram.mFeatures.hasObjectSkinning = true;
+        gDeferredSkinnedShadowFullbrightAlphaMaskProgram.mShaderFiles.clear();
+        gDeferredSkinnedShadowFullbrightAlphaMaskProgram.mShaderFiles.push_back(make_pair("deferred/shadowAlphaMaskSkinnedV.glsl", GL_VERTEX_SHADER_ARB));
+        gDeferredSkinnedShadowFullbrightAlphaMaskProgram.mShaderFiles.push_back(make_pair("deferred/shadowAlphaMaskF.glsl", GL_FRAGMENT_SHADER_ARB));
+
+        gDeferredSkinnedShadowFullbrightAlphaMaskProgram.clearPermutations();
+        if (gGLManager.mHasDepthClamp)
+        {
+            gDeferredSkinnedShadowFullbrightAlphaMaskProgram.addPermutation("DEPTH_CLAMP", "1");
+        }
+        gDeferredSkinnedShadowFullbrightAlphaMaskProgram.addPermutation("IS_FULLBRIGHT", "1");
+        gDeferredSkinnedShadowFullbrightAlphaMaskProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED];
+        success = gDeferredSkinnedShadowFullbrightAlphaMaskProgram.createShader(NULL, NULL);
+        llassert(success);
+    }
+
     if (success)
 	{
 		gDeferredShadowAlphaMaskProgram.mName = "Deferred Shadow Alpha Mask Shader";
@@ -2403,10 +2447,28 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 			gDeferredShadowAlphaMaskProgram.addPermutation("DEPTH_CLAMP", "1");
 		}
 		gDeferredShadowAlphaMaskProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED];
+        gDeferredShadowAlphaMaskProgram.mRiggedVariant = &gDeferredSkinnedShadowAlphaMaskProgram;
 		success = gDeferredShadowAlphaMaskProgram.createShader(NULL, NULL);
 		llassert(success);
 	}
 
+    if (success)
+    {
+        gDeferredSkinnedShadowAlphaMaskProgram.mName = "Deferred Skinned Shadow Alpha Mask Shader";
+        gDeferredSkinnedShadowAlphaMaskProgram.mFeatures.mIndexedTextureChannels = LLGLSLShader::sIndexedTextureChannels;
+        gDeferredSkinnedShadowAlphaMaskProgram.mFeatures.hasObjectSkinning = true;
+        gDeferredSkinnedShadowAlphaMaskProgram.mShaderFiles.clear();
+        gDeferredSkinnedShadowAlphaMaskProgram.mShaderFiles.push_back(make_pair("deferred/shadowAlphaMaskSkinnedV.glsl", GL_VERTEX_SHADER_ARB));
+        gDeferredSkinnedShadowAlphaMaskProgram.mShaderFiles.push_back(make_pair("deferred/shadowAlphaMaskF.glsl", GL_FRAGMENT_SHADER_ARB));
+        if (gGLManager.mHasDepthClamp)
+        {
+            gDeferredSkinnedShadowAlphaMaskProgram.addPermutation("DEPTH_CLAMP", "1");
+        }
+        gDeferredSkinnedShadowAlphaMaskProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED];
+        success = gDeferredSkinnedShadowAlphaMaskProgram.createShader(NULL, NULL);
+        llassert(success);
+    }
+
 	if (success)
 	{
 		gDeferredAvatarShadowProgram.mName = "Deferred Avatar Shadow Shader";
@@ -2782,77 +2844,7 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 BOOL LLViewerShaderMgr::loadShadersObject()
 {
 	BOOL success = TRUE;
-	
-	if (mShaderLevel[SHADER_OBJECT] == 0)
-	{
-		gObjectShinyProgram.unload();
-		gObjectFullbrightShinyProgram.unload();
-		gObjectFullbrightShinyWaterProgram.unload();
-		gObjectShinyWaterProgram.unload();
-		gObjectFullbrightNoColorProgram.unload();
-		gObjectFullbrightNoColorWaterProgram.unload();
-		gObjectSimpleProgram.unload();
-		gObjectSimpleImpostorProgram.unload();
-		gObjectPreviewProgram.unload();
-		gImpostorProgram.unload();
-		gObjectSimpleAlphaMaskProgram.unload();
-		gObjectBumpProgram.unload();
-		gObjectSimpleWaterProgram.unload();
-		gObjectSimpleWaterAlphaMaskProgram.unload();
-		gObjectEmissiveProgram.unload();
-		gObjectEmissiveWaterProgram.unload();
-		gObjectFullbrightProgram.unload();
-		gObjectFullbrightAlphaMaskProgram.unload();
-		gObjectFullbrightWaterProgram.unload();
-		gObjectFullbrightWaterAlphaMaskProgram.unload();
-		gObjectShinyNonIndexedProgram.unload();
-		gObjectFullbrightShinyNonIndexedProgram.unload();
-		gObjectFullbrightShinyNonIndexedWaterProgram.unload();
-		gObjectShinyNonIndexedWaterProgram.unload();
-		gObjectSimpleNonIndexedTexGenProgram.unload();
-		gObjectSimpleNonIndexedTexGenWaterProgram.unload();
-		gObjectSimpleNonIndexedWaterProgram.unload();
-		gObjectAlphaMaskNonIndexedProgram.unload();
-		gObjectAlphaMaskNonIndexedWaterProgram.unload();
-		gObjectAlphaMaskNoColorProgram.unload();
-		gObjectAlphaMaskNoColorWaterProgram.unload();
-		gObjectFullbrightNonIndexedProgram.unload();
-		gObjectFullbrightNonIndexedWaterProgram.unload();
-		gObjectEmissiveNonIndexedProgram.unload();
-		gObjectEmissiveNonIndexedWaterProgram.unload();
-		gSkinnedObjectSimpleProgram.unload();
-		gSkinnedObjectFullbrightProgram.unload();
-		gSkinnedObjectEmissiveProgram.unload();
-		gSkinnedObjectFullbrightShinyProgram.unload();
-		gSkinnedObjectShinySimpleProgram.unload();
-		gSkinnedObjectSimpleWaterProgram.unload();
-		gSkinnedObjectFullbrightWaterProgram.unload();
-		gSkinnedObjectEmissiveWaterProgram.unload();
-		gSkinnedObjectFullbrightShinyWaterProgram.unload();
-		gSkinnedObjectShinySimpleWaterProgram.unload();
-		gTreeProgram.unload();
-		gTreeWaterProgram.unload();
-	
-		return TRUE;
-	}
 
-	if (success)
-	{
-		gObjectSimpleNonIndexedProgram.mName = "Non indexed Shader";
-		gObjectSimpleNonIndexedProgram.mFeatures.calculatesLighting = true;
-		gObjectSimpleNonIndexedProgram.mFeatures.calculatesAtmospherics = true;
-		gObjectSimpleNonIndexedProgram.mFeatures.hasGamma = true;
-		gObjectSimpleNonIndexedProgram.mFeatures.hasAtmospherics = true;
-		gObjectSimpleNonIndexedProgram.mFeatures.hasLighting = true;
-        gObjectSimpleNonIndexedProgram.mFeatures.hasAlphaMask = true; // Fix for MAINT-8836
-		gObjectSimpleNonIndexedProgram.mFeatures.disableTextureIndex = true;
-		gObjectSimpleNonIndexedProgram.mShaderFiles.clear();
-		gObjectSimpleNonIndexedProgram.mShaderFiles.push_back(make_pair("objects/simpleV.glsl", GL_VERTEX_SHADER_ARB));
-		gObjectSimpleNonIndexedProgram.mShaderFiles.push_back(make_pair("objects/simpleF.glsl", GL_FRAGMENT_SHADER_ARB));
-		gObjectSimpleNonIndexedProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT];
-		success = gObjectSimpleNonIndexedProgram.createShader(NULL, NULL);
-	}
-	
 	if (success)
 	{
 		gObjectSimpleNonIndexedTexGenProgram.mName = "Non indexed tex-gen Shader";
@@ -2869,24 +2861,6 @@ BOOL LLViewerShaderMgr::loadShadersObject()
 		success = gObjectSimpleNonIndexedTexGenProgram.createShader(NULL, NULL);
 	}
 	
-
-	if (success)
-	{
-		gObjectSimpleNonIndexedWaterProgram.mName = "Non indexed Water Shader";
-		gObjectSimpleNonIndexedWaterProgram.mFeatures.calculatesLighting = true;
-		gObjectSimpleNonIndexedWaterProgram.mFeatures.calculatesAtmospherics = true;
-		gObjectSimpleNonIndexedWaterProgram.mFeatures.hasWaterFog = true;
-		gObjectSimpleNonIndexedWaterProgram.mFeatures.hasAtmospherics = true;
-		gObjectSimpleNonIndexedWaterProgram.mFeatures.hasLighting = true;
-		gObjectSimpleNonIndexedWaterProgram.mFeatures.disableTextureIndex = true;
-		gObjectSimpleNonIndexedWaterProgram.mShaderFiles.clear();
-		gObjectSimpleNonIndexedWaterProgram.mShaderFiles.push_back(make_pair("objects/simpleV.glsl", GL_VERTEX_SHADER_ARB));
-		gObjectSimpleNonIndexedWaterProgram.mShaderFiles.push_back(make_pair("objects/simpleWaterF.glsl", GL_FRAGMENT_SHADER_ARB));
-		gObjectSimpleNonIndexedWaterProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT];
-		gObjectSimpleNonIndexedWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER;
-		success = gObjectSimpleNonIndexedWaterProgram.createShader(NULL, NULL);
-	}
-
 	if (success)
 	{
 		gObjectSimpleNonIndexedTexGenWaterProgram.mName = "Non indexed tex-gen Water Shader";
@@ -3009,70 +2983,6 @@ BOOL LLViewerShaderMgr::loadShadersObject()
 		success = gTreeWaterProgram.createShader(NULL, NULL);
 	}
 
-	if (success)
-	{
-		gObjectFullbrightNonIndexedProgram.mName = "Non Indexed Fullbright Shader";
-		gObjectFullbrightNonIndexedProgram.mFeatures.calculatesAtmospherics = true;
-		gObjectFullbrightNonIndexedProgram.mFeatures.hasGamma = true;
-		gObjectFullbrightNonIndexedProgram.mFeatures.hasTransport = true;
-		gObjectFullbrightNonIndexedProgram.mFeatures.isFullbright = true;
-		gObjectFullbrightNonIndexedProgram.mFeatures.disableTextureIndex = true;
-		gObjectFullbrightNonIndexedProgram.mShaderFiles.clear();
-		gObjectFullbrightNonIndexedProgram.mShaderFiles.push_back(make_pair("objects/fullbrightV.glsl", GL_VERTEX_SHADER_ARB));
-		gObjectFullbrightNonIndexedProgram.mShaderFiles.push_back(make_pair("objects/fullbrightF.glsl", GL_FRAGMENT_SHADER_ARB));
-		gObjectFullbrightNonIndexedProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT];
-		success = gObjectFullbrightNonIndexedProgram.createShader(NULL, NULL);
-	}
-
-	if (success)
-	{
-		gObjectFullbrightNonIndexedWaterProgram.mName = "Non Indexed Fullbright Water Shader";
-		gObjectFullbrightNonIndexedWaterProgram.mFeatures.calculatesAtmospherics = true;
-		gObjectFullbrightNonIndexedWaterProgram.mFeatures.isFullbright = true;
-		gObjectFullbrightNonIndexedWaterProgram.mFeatures.hasWaterFog = true;		
-		gObjectFullbrightNonIndexedWaterProgram.mFeatures.hasTransport = true;
-		gObjectFullbrightNonIndexedWaterProgram.mFeatures.disableTextureIndex = true;
-		gObjectFullbrightNonIndexedWaterProgram.mFeatures.hasSrgb = true;
-		gObjectFullbrightNonIndexedWaterProgram.mShaderFiles.clear();
-		gObjectFullbrightNonIndexedWaterProgram.mShaderFiles.push_back(make_pair("objects/fullbrightV.glsl", GL_VERTEX_SHADER_ARB));
-		gObjectFullbrightNonIndexedWaterProgram.mShaderFiles.push_back(make_pair("objects/fullbrightWaterF.glsl", GL_FRAGMENT_SHADER_ARB));
-		gObjectFullbrightNonIndexedWaterProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT];
-		gObjectFullbrightNonIndexedWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER;
-		success = gObjectFullbrightNonIndexedWaterProgram.createShader(NULL, NULL);
-	}
-
-	if (success)
-	{
-		gObjectEmissiveNonIndexedProgram.mName = "Non Indexed Emissive Shader";
-		gObjectEmissiveNonIndexedProgram.mFeatures.calculatesAtmospherics = true;
-		gObjectEmissiveNonIndexedProgram.mFeatures.hasGamma = true;
-		gObjectEmissiveNonIndexedProgram.mFeatures.hasTransport = true;
-		gObjectEmissiveNonIndexedProgram.mFeatures.isFullbright = true;
-		gObjectEmissiveNonIndexedProgram.mFeatures.disableTextureIndex = true;
-		gObjectEmissiveNonIndexedProgram.mFeatures.hasSrgb = true;
-		gObjectEmissiveNonIndexedProgram.mShaderFiles.clear();
-		gObjectEmissiveNonIndexedProgram.mShaderFiles.push_back(make_pair("objects/emissiveV.glsl", GL_VERTEX_SHADER_ARB));
-		gObjectEmissiveNonIndexedProgram.mShaderFiles.push_back(make_pair("objects/fullbrightF.glsl", GL_FRAGMENT_SHADER_ARB));
-		gObjectEmissiveNonIndexedProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT];
-		success = gObjectEmissiveNonIndexedProgram.createShader(NULL, NULL);
-	}
-
-	if (success)
-	{
-		gObjectEmissiveNonIndexedWaterProgram.mName = "Non Indexed Emissive Water Shader";
-		gObjectEmissiveNonIndexedWaterProgram.mFeatures.calculatesAtmospherics = true;
-		gObjectEmissiveNonIndexedWaterProgram.mFeatures.isFullbright = true;
-		gObjectEmissiveNonIndexedWaterProgram.mFeatures.hasWaterFog = true;		
-		gObjectEmissiveNonIndexedWaterProgram.mFeatures.hasTransport = true;
-		gObjectEmissiveNonIndexedWaterProgram.mFeatures.disableTextureIndex = true;
-		gObjectEmissiveNonIndexedWaterProgram.mShaderFiles.clear();
-		gObjectEmissiveNonIndexedWaterProgram.mShaderFiles.push_back(make_pair("objects/emissiveV.glsl", GL_VERTEX_SHADER_ARB));
-		gObjectEmissiveNonIndexedWaterProgram.mShaderFiles.push_back(make_pair("objects/fullbrightWaterF.glsl", GL_FRAGMENT_SHADER_ARB));
-		gObjectEmissiveNonIndexedWaterProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT];
-		gObjectEmissiveNonIndexedWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER;
-		success = gObjectEmissiveNonIndexedWaterProgram.createShader(NULL, NULL);
-	}
-
 	if (success)
 	{
 		gObjectFullbrightNoColorProgram.mName = "Non Indexed no color Fullbright Shader";
@@ -3105,73 +3015,6 @@ BOOL LLViewerShaderMgr::loadShadersObject()
 		success = gObjectFullbrightNoColorWaterProgram.createShader(NULL, NULL);
 	}
 
-	if (success)
-	{
-		gObjectShinyNonIndexedProgram.mName = "Non Indexed Shiny Shader";
-		gObjectShinyNonIndexedProgram.mFeatures.calculatesAtmospherics = true;
-		gObjectShinyNonIndexedProgram.mFeatures.calculatesLighting = true;
-		gObjectShinyNonIndexedProgram.mFeatures.hasGamma = true;
-		gObjectShinyNonIndexedProgram.mFeatures.hasAtmospherics = true;
-		gObjectShinyNonIndexedProgram.mFeatures.isShiny = true;
-		gObjectShinyNonIndexedProgram.mFeatures.disableTextureIndex = true;
-		gObjectShinyNonIndexedProgram.mShaderFiles.clear();
-		gObjectShinyNonIndexedProgram.mShaderFiles.push_back(make_pair("objects/shinyV.glsl", GL_VERTEX_SHADER_ARB));
-		gObjectShinyNonIndexedProgram.mShaderFiles.push_back(make_pair("objects/shinyF.glsl", GL_FRAGMENT_SHADER_ARB));		
-		gObjectShinyNonIndexedProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT];
-		success = gObjectShinyNonIndexedProgram.createShader(NULL, NULL);
-	}
-
-	if (success)
-	{
-		gObjectShinyNonIndexedWaterProgram.mName = "Non Indexed Shiny Water Shader";
-		gObjectShinyNonIndexedWaterProgram.mFeatures.calculatesAtmospherics = true;
-		gObjectShinyNonIndexedWaterProgram.mFeatures.calculatesLighting = true;
-		gObjectShinyNonIndexedWaterProgram.mFeatures.isShiny = true;
-		gObjectShinyNonIndexedWaterProgram.mFeatures.hasWaterFog = true;
-		gObjectShinyNonIndexedWaterProgram.mFeatures.hasAtmospherics = true;
-		gObjectShinyNonIndexedWaterProgram.mFeatures.disableTextureIndex = true;
-		gObjectShinyNonIndexedWaterProgram.mShaderFiles.clear();
-		gObjectShinyNonIndexedWaterProgram.mShaderFiles.push_back(make_pair("objects/shinyWaterF.glsl", GL_FRAGMENT_SHADER_ARB));
-		gObjectShinyNonIndexedWaterProgram.mShaderFiles.push_back(make_pair("objects/shinyV.glsl", GL_VERTEX_SHADER_ARB));
-		gObjectShinyNonIndexedWaterProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT];
-		gObjectShinyNonIndexedWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER;
-		success = gObjectShinyNonIndexedWaterProgram.createShader(NULL, NULL);
-	}
-	
-    if (success)
-	{
-		gObjectFullbrightShinyNonIndexedProgram.mName = "Non Indexed Fullbright Shiny Shader";
-		gObjectFullbrightShinyNonIndexedProgram.mFeatures.calculatesAtmospherics = true;
-		gObjectFullbrightShinyNonIndexedProgram.mFeatures.isFullbright = true;
-		gObjectFullbrightShinyNonIndexedProgram.mFeatures.isShiny = true;
-		gObjectFullbrightShinyNonIndexedProgram.mFeatures.hasGamma = true;
-		gObjectFullbrightShinyNonIndexedProgram.mFeatures.hasTransport = true;
-		gObjectFullbrightShinyNonIndexedProgram.mFeatures.disableTextureIndex = true;
-		gObjectFullbrightShinyNonIndexedProgram.mShaderFiles.clear();
-		gObjectFullbrightShinyNonIndexedProgram.mShaderFiles.push_back(make_pair("objects/fullbrightShinyV.glsl", GL_VERTEX_SHADER_ARB));
-		gObjectFullbrightShinyNonIndexedProgram.mShaderFiles.push_back(make_pair("objects/fullbrightShinyF.glsl", GL_FRAGMENT_SHADER_ARB));
-		gObjectFullbrightShinyNonIndexedProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT];
-		success = gObjectFullbrightShinyNonIndexedProgram.createShader(NULL, NULL);
-	}
-
-	if (success)
-	{
-		gObjectFullbrightShinyNonIndexedWaterProgram.mName = "Non Indexed Fullbright Shiny Water Shader";
-		gObjectFullbrightShinyNonIndexedWaterProgram.mFeatures.calculatesAtmospherics = true;
-		gObjectFullbrightShinyNonIndexedWaterProgram.mFeatures.isFullbright = true;
-		gObjectFullbrightShinyNonIndexedWaterProgram.mFeatures.isShiny = true;
-		gObjectFullbrightShinyNonIndexedWaterProgram.mFeatures.hasGamma = true;
-		gObjectFullbrightShinyNonIndexedWaterProgram.mFeatures.hasTransport = true;
-		gObjectFullbrightShinyNonIndexedWaterProgram.mFeatures.hasWaterFog = true;
-		gObjectFullbrightShinyNonIndexedWaterProgram.mFeatures.disableTextureIndex = true;
-		gObjectFullbrightShinyNonIndexedWaterProgram.mShaderFiles.clear();
-		gObjectFullbrightShinyNonIndexedWaterProgram.mShaderFiles.push_back(make_pair("objects/fullbrightShinyV.glsl", GL_VERTEX_SHADER_ARB));
-		gObjectFullbrightShinyNonIndexedWaterProgram.mShaderFiles.push_back(make_pair("objects/fullbrightShinyWaterF.glsl", GL_FRAGMENT_SHADER_ARB));
-		gObjectFullbrightShinyNonIndexedWaterProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT];
-		gObjectFullbrightShinyNonIndexedWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER;
-		success = gObjectFullbrightShinyNonIndexedWaterProgram.createShader(NULL, NULL);
-	}
-
 	if (success)
 	{
 		gImpostorProgram.mName = "Impostor Shader";
@@ -3215,7 +3058,8 @@ BOOL LLViewerShaderMgr::loadShadersObject()
 		gObjectSimpleProgram.mShaderFiles.push_back(make_pair("objects/simpleV.glsl", GL_VERTEX_SHADER_ARB));
 		gObjectSimpleProgram.mShaderFiles.push_back(make_pair("objects/simpleF.glsl", GL_FRAGMENT_SHADER_ARB));
 		gObjectSimpleProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT];
-		success = gObjectSimpleProgram.createShader(NULL, NULL);
+        success = make_rigged_variant(gObjectSimpleProgram, gSkinnedObjectSimpleProgram);
+		success = success && gObjectSimpleProgram.createShader(NULL, NULL);
 	}
 
 	if (success)
@@ -3235,8 +3079,8 @@ BOOL LLViewerShaderMgr::loadShadersObject()
 		gObjectSimpleImpostorProgram.mShaderFiles.push_back(make_pair("objects/simpleV.glsl", GL_VERTEX_SHADER_ARB));
 		gObjectSimpleImpostorProgram.mShaderFiles.push_back(make_pair("objects/simpleF.glsl", GL_FRAGMENT_SHADER_ARB));
 		gObjectSimpleImpostorProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT];
-		
-		success = gObjectSimpleImpostorProgram.createShader(NULL, NULL);
+        success = make_rigged_variant(gObjectSimpleImpostorProgram, gSkinnedObjectSimpleImpostorProgram);
+		success = success && gObjectSimpleImpostorProgram.createShader(NULL, NULL);
 	}
 
 	if (success)
@@ -3253,30 +3097,30 @@ BOOL LLViewerShaderMgr::loadShadersObject()
 		gObjectSimpleWaterProgram.mShaderFiles.push_back(make_pair("objects/simpleWaterF.glsl", GL_FRAGMENT_SHADER_ARB));
 		gObjectSimpleWaterProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT];
 		gObjectSimpleWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER;
+        make_rigged_variant(gObjectSimpleWaterProgram, gSkinnedObjectSimpleWaterProgram);
 		success = gObjectSimpleWaterProgram.createShader(NULL, NULL);
 	}
 	
 	if (success)
 	{
 		gObjectBumpProgram.mName = "Bump Shader";
-		/*gObjectBumpProgram.mFeatures.calculatesLighting = true;
-		gObjectBumpProgram.mFeatures.calculatesAtmospherics = true;
-		gObjectBumpProgram.mFeatures.hasGamma = true;
-		gObjectBumpProgram.mFeatures.hasAtmospherics = true;
-		gObjectBumpProgram.mFeatures.hasLighting = true;
-		gObjectBumpProgram.mFeatures.mIndexedTextureChannels = 0;*/
 		gObjectBumpProgram.mFeatures.encodesNormal = true;
 		gObjectBumpProgram.mShaderFiles.clear();
 		gObjectBumpProgram.mShaderFiles.push_back(make_pair("objects/bumpV.glsl", GL_VERTEX_SHADER_ARB));
 		gObjectBumpProgram.mShaderFiles.push_back(make_pair("objects/bumpF.glsl", GL_FRAGMENT_SHADER_ARB));
 		gObjectBumpProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT];
-		success = gObjectBumpProgram.createShader(NULL, NULL);
+        success = make_rigged_variant(gObjectBumpProgram, gSkinnedObjectBumpProgram);
+		success = success && gObjectBumpProgram.createShader(NULL, NULL);
 		if (success)
 		{ //lldrawpoolbump assumes "texture0" has channel 0 and "texture1" has channel 1
-			gObjectBumpProgram.bind();
-			gObjectBumpProgram.uniform1i(sTexture0, 0);
-			gObjectBumpProgram.uniform1i(sTexture1, 1);
-			gObjectBumpProgram.unbind();
+            LLGLSLShader* shader[] = { &gObjectBumpProgram, &gSkinnedObjectBumpProgram };
+            for (int i = 0; i < 2; ++i)
+            {
+                shader[i]->bind();
+                shader[i]->uniform1i(sTexture0, 0);
+                shader[i]->uniform1i(sTexture1, 1);
+                shader[i]->unbind();
+            }
 		}
 	}
 	
@@ -3295,7 +3139,8 @@ BOOL LLViewerShaderMgr::loadShadersObject()
 		gObjectSimpleAlphaMaskProgram.mShaderFiles.push_back(make_pair("objects/simpleV.glsl", GL_VERTEX_SHADER_ARB));
 		gObjectSimpleAlphaMaskProgram.mShaderFiles.push_back(make_pair("objects/simpleF.glsl", GL_FRAGMENT_SHADER_ARB));
 		gObjectSimpleAlphaMaskProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT];
-		success = gObjectSimpleAlphaMaskProgram.createShader(NULL, NULL);
+        success = make_rigged_variant(gObjectSimpleAlphaMaskProgram, gSkinnedObjectSimpleAlphaMaskProgram);
+		success = success && gObjectSimpleAlphaMaskProgram.createShader(NULL, NULL);
 	}
 
 	if (success)
@@ -3313,7 +3158,8 @@ BOOL LLViewerShaderMgr::loadShadersObject()
 		gObjectSimpleWaterAlphaMaskProgram.mShaderFiles.push_back(make_pair("objects/simpleWaterF.glsl", GL_FRAGMENT_SHADER_ARB));
 		gObjectSimpleWaterAlphaMaskProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT];
 		gObjectSimpleWaterAlphaMaskProgram.mShaderGroup = LLGLSLShader::SG_WATER;
-		success = gObjectSimpleWaterAlphaMaskProgram.createShader(NULL, NULL);
+        success = make_rigged_variant(gObjectSimpleWaterAlphaMaskProgram, gSkinnedObjectSimpleWaterAlphaMaskProgram);
+		success = success && gObjectSimpleWaterAlphaMaskProgram.createShader(NULL, NULL);
 	}
 
 	if (success)
@@ -3329,7 +3175,8 @@ BOOL LLViewerShaderMgr::loadShadersObject()
 		gObjectFullbrightProgram.mShaderFiles.push_back(make_pair("objects/fullbrightV.glsl", GL_VERTEX_SHADER_ARB));
 		gObjectFullbrightProgram.mShaderFiles.push_back(make_pair("objects/fullbrightF.glsl", GL_FRAGMENT_SHADER_ARB));
 		gObjectFullbrightProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT];
-		success = gObjectFullbrightProgram.createShader(NULL, NULL);
+        success = make_rigged_variant(gObjectFullbrightProgram, gSkinnedObjectFullbrightProgram);
+        success = success && gObjectFullbrightProgram.createShader(NULL, NULL);
 	}
 
 	if (success)
@@ -3337,7 +3184,7 @@ BOOL LLViewerShaderMgr::loadShadersObject()
 		gObjectFullbrightWaterProgram.mName = "Fullbright Water Shader";
 		gObjectFullbrightWaterProgram.mFeatures.calculatesAtmospherics = true;
 		gObjectFullbrightWaterProgram.mFeatures.isFullbright = true;
-		gObjectFullbrightWaterProgram.mFeatures.hasWaterFog = true;		
+		gObjectFullbrightWaterProgram.mFeatures.hasWaterFog = true;
 		gObjectFullbrightWaterProgram.mFeatures.hasTransport = true;
 		gObjectFullbrightWaterProgram.mFeatures.mIndexedTextureChannels = 0;
 		gObjectFullbrightWaterProgram.mShaderFiles.clear();
@@ -3345,7 +3192,8 @@ BOOL LLViewerShaderMgr::loadShadersObject()
 		gObjectFullbrightWaterProgram.mShaderFiles.push_back(make_pair("objects/fullbrightWaterF.glsl", GL_FRAGMENT_SHADER_ARB));
 		gObjectFullbrightWaterProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT];
 		gObjectFullbrightWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER;
-		success = gObjectFullbrightWaterProgram.createShader(NULL, NULL);
+        success = make_rigged_variant(gObjectFullbrightWaterProgram, gSkinnedObjectFullbrightWaterProgram);
+		success = success && gObjectFullbrightWaterProgram.createShader(NULL, NULL);
 	}
 
 	if (success)
@@ -3361,7 +3209,8 @@ BOOL LLViewerShaderMgr::loadShadersObject()
 		gObjectEmissiveProgram.mShaderFiles.push_back(make_pair("objects/emissiveV.glsl", GL_VERTEX_SHADER_ARB));
 		gObjectEmissiveProgram.mShaderFiles.push_back(make_pair("objects/fullbrightF.glsl", GL_FRAGMENT_SHADER_ARB));
 		gObjectEmissiveProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT];
-		success = gObjectEmissiveProgram.createShader(NULL, NULL);
+        success = make_rigged_variant(gObjectEmissiveProgram, gSkinnedObjectEmissiveProgram);
+		success = success && gObjectEmissiveProgram.createShader(NULL, NULL);
 	}
 
 	if (success)
@@ -3377,7 +3226,8 @@ BOOL LLViewerShaderMgr::loadShadersObject()
 		gObjectEmissiveWaterProgram.mShaderFiles.push_back(make_pair("objects/fullbrightWaterF.glsl", GL_FRAGMENT_SHADER_ARB));
 		gObjectEmissiveWaterProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT];
 		gObjectEmissiveWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER;
-		success = gObjectEmissiveWaterProgram.createShader(NULL, NULL);
+        success = make_rigged_variant(gObjectEmissiveWaterProgram, gSkinnedObjectEmissiveWaterProgram);
+		success = success && gObjectEmissiveWaterProgram.createShader(NULL, NULL);
 	}
 
 	if (success)
@@ -3394,12 +3244,13 @@ BOOL LLViewerShaderMgr::loadShadersObject()
 		gObjectFullbrightAlphaMaskProgram.mShaderFiles.push_back(make_pair("objects/fullbrightV.glsl", GL_VERTEX_SHADER_ARB));
 		gObjectFullbrightAlphaMaskProgram.mShaderFiles.push_back(make_pair("objects/fullbrightF.glsl", GL_FRAGMENT_SHADER_ARB));
 		gObjectFullbrightAlphaMaskProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT];
-		success = gObjectFullbrightAlphaMaskProgram.createShader(NULL, NULL);
+        success = make_rigged_variant(gObjectFullbrightAlphaMaskProgram, gSkinnedObjectFullbrightAlphaMaskProgram);
+		success = success && gObjectFullbrightAlphaMaskProgram.createShader(NULL, NULL);
 	}
 
 	if (success)
 	{
-		gObjectFullbrightWaterAlphaMaskProgram.mName = "Fullbright Water Shader";
+		gObjectFullbrightWaterAlphaMaskProgram.mName = "Fullbright Water Alpha Mask Shader";
 		gObjectFullbrightWaterAlphaMaskProgram.mFeatures.calculatesAtmospherics = true;
 		gObjectFullbrightWaterAlphaMaskProgram.mFeatures.isFullbright = true;
 		gObjectFullbrightWaterAlphaMaskProgram.mFeatures.hasWaterFog = true;		
@@ -3411,7 +3262,8 @@ BOOL LLViewerShaderMgr::loadShadersObject()
 		gObjectFullbrightWaterAlphaMaskProgram.mShaderFiles.push_back(make_pair("objects/fullbrightWaterF.glsl", GL_FRAGMENT_SHADER_ARB));
 		gObjectFullbrightWaterAlphaMaskProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT];
 		gObjectFullbrightWaterAlphaMaskProgram.mShaderGroup = LLGLSLShader::SG_WATER;
-		success = gObjectFullbrightWaterAlphaMaskProgram.createShader(NULL, NULL);
+        success = make_rigged_variant(gObjectFullbrightWaterAlphaMaskProgram, gSkinnedObjectFullbrightWaterAlphaMaskProgram);
+		success = success && gObjectFullbrightWaterAlphaMaskProgram.createShader(NULL, NULL);
 	}
 
 	if (success)
@@ -3427,7 +3279,8 @@ BOOL LLViewerShaderMgr::loadShadersObject()
 		gObjectShinyProgram.mShaderFiles.push_back(make_pair("objects/shinyV.glsl", GL_VERTEX_SHADER_ARB));
 		gObjectShinyProgram.mShaderFiles.push_back(make_pair("objects/shinyF.glsl", GL_FRAGMENT_SHADER_ARB));		
 		gObjectShinyProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT];
-		success = gObjectShinyProgram.createShader(NULL, NULL);
+        success = make_rigged_variant(gObjectShinyProgram, gSkinnedObjectShinyProgram);
+		success = success && gObjectShinyProgram.createShader(NULL, NULL);
 	}
 
 	if (success)
@@ -3444,7 +3297,8 @@ BOOL LLViewerShaderMgr::loadShadersObject()
 		gObjectShinyWaterProgram.mShaderFiles.push_back(make_pair("objects/shinyV.glsl", GL_VERTEX_SHADER_ARB));
 		gObjectShinyWaterProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT];
 		gObjectShinyWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER;
-		success = gObjectShinyWaterProgram.createShader(NULL, NULL);
+        success = make_rigged_variant(gObjectShinyWaterProgram, gSkinnedObjectShinyWaterProgram);
+		success = success && gObjectShinyWaterProgram.createShader(NULL, NULL);
 	}
 	
 	if (success)
@@ -3460,7 +3314,8 @@ BOOL LLViewerShaderMgr::loadShadersObject()
 		gObjectFullbrightShinyProgram.mShaderFiles.push_back(make_pair("objects/fullbrightShinyV.glsl", GL_VERTEX_SHADER_ARB));
 		gObjectFullbrightShinyProgram.mShaderFiles.push_back(make_pair("objects/fullbrightShinyF.glsl", GL_FRAGMENT_SHADER_ARB));
 		gObjectFullbrightShinyProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT];
-		success = gObjectFullbrightShinyProgram.createShader(NULL, NULL);
+        success = make_rigged_variant(gObjectFullbrightShinyProgram, gSkinnedObjectFullbrightShinyProgram);
+		success = success && gObjectFullbrightShinyProgram.createShader(NULL, NULL);
 	}
 
 	if (success)
@@ -3478,196 +3333,8 @@ BOOL LLViewerShaderMgr::loadShadersObject()
 		gObjectFullbrightShinyWaterProgram.mShaderFiles.push_back(make_pair("objects/fullbrightShinyWaterF.glsl", GL_FRAGMENT_SHADER_ARB));
 		gObjectFullbrightShinyWaterProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT];
 		gObjectFullbrightShinyWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER;
-		success = gObjectFullbrightShinyWaterProgram.createShader(NULL, NULL);
-	}
-
-	if (mShaderLevel[SHADER_AVATAR] > 0)
-	{ //load hardware skinned attachment shaders
-		if (success)
-		{
-			gSkinnedObjectSimpleProgram.mName = "Skinned Simple Shader";
-			gSkinnedObjectSimpleProgram.mFeatures.calculatesLighting = true;
-			gSkinnedObjectSimpleProgram.mFeatures.calculatesAtmospherics = true;
-			gSkinnedObjectSimpleProgram.mFeatures.hasGamma = true;
-			gSkinnedObjectSimpleProgram.mFeatures.hasAtmospherics = true;
-			gSkinnedObjectSimpleProgram.mFeatures.hasLighting = true;
-			gSkinnedObjectSimpleProgram.mFeatures.hasObjectSkinning = true;
-			gSkinnedObjectSimpleProgram.mFeatures.hasAlphaMask = true;
-			gSkinnedObjectSimpleProgram.mFeatures.disableTextureIndex = true;
-			gSkinnedObjectSimpleProgram.mShaderFiles.clear();
-			gSkinnedObjectSimpleProgram.mShaderFiles.push_back(make_pair("objects/simpleSkinnedV.glsl", GL_VERTEX_SHADER_ARB));
-			gSkinnedObjectSimpleProgram.mShaderFiles.push_back(make_pair("objects/simpleF.glsl", GL_FRAGMENT_SHADER_ARB));
-			gSkinnedObjectSimpleProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT];
-			success = gSkinnedObjectSimpleProgram.createShader(NULL, NULL);
-		}
-
-		if (success)
-		{
-			gSkinnedObjectFullbrightProgram.mName = "Skinned Fullbright Shader";
-			gSkinnedObjectFullbrightProgram.mFeatures.calculatesAtmospherics = true;
-			gSkinnedObjectFullbrightProgram.mFeatures.hasGamma = true;
-			gSkinnedObjectFullbrightProgram.mFeatures.hasTransport = true;
-			gSkinnedObjectFullbrightProgram.mFeatures.isFullbright = true;
-			gSkinnedObjectFullbrightProgram.mFeatures.hasObjectSkinning = true;
-			gSkinnedObjectFullbrightProgram.mFeatures.hasAlphaMask = true;			
-			gSkinnedObjectFullbrightProgram.mFeatures.disableTextureIndex = true;
-			gSkinnedObjectFullbrightProgram.mFeatures.hasSrgb = true;
-			gSkinnedObjectFullbrightProgram.mShaderFiles.clear();
-			gSkinnedObjectFullbrightProgram.mShaderFiles.push_back(make_pair("objects/fullbrightSkinnedV.glsl", GL_VERTEX_SHADER_ARB));
-			gSkinnedObjectFullbrightProgram.mShaderFiles.push_back(make_pair("objects/fullbrightF.glsl", GL_FRAGMENT_SHADER_ARB));
-			gSkinnedObjectFullbrightProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT];
-			success = gSkinnedObjectFullbrightProgram.createShader(NULL, NULL);
-		}
-
-		if (success)
-		{
-			gSkinnedObjectEmissiveProgram.mName = "Skinned Emissive Shader";
-			gSkinnedObjectEmissiveProgram.mFeatures.calculatesAtmospherics = true;
-			gSkinnedObjectEmissiveProgram.mFeatures.hasGamma = true;
-			gSkinnedObjectEmissiveProgram.mFeatures.hasTransport = true;
-			gSkinnedObjectEmissiveProgram.mFeatures.isFullbright = true;
-			gSkinnedObjectEmissiveProgram.mFeatures.hasObjectSkinning = true;
-			gSkinnedObjectEmissiveProgram.mFeatures.disableTextureIndex = true;
-            gSkinnedObjectEmissiveProgram.mFeatures.hasSrgb = true;
-			gSkinnedObjectEmissiveProgram.mShaderFiles.clear();
-			gSkinnedObjectEmissiveProgram.mShaderFiles.push_back(make_pair("objects/emissiveSkinnedV.glsl", GL_VERTEX_SHADER_ARB));
-			gSkinnedObjectEmissiveProgram.mShaderFiles.push_back(make_pair("objects/fullbrightF.glsl", GL_FRAGMENT_SHADER_ARB));
-			gSkinnedObjectEmissiveProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT];
-			success = gSkinnedObjectEmissiveProgram.createShader(NULL, NULL);
-		}
-
-		if (success)
-		{
-			gSkinnedObjectEmissiveWaterProgram.mName = "Skinned Emissive Water Shader";
-			gSkinnedObjectEmissiveWaterProgram.mFeatures.calculatesAtmospherics = true;
-			gSkinnedObjectEmissiveWaterProgram.mFeatures.hasGamma = true;
-			gSkinnedObjectEmissiveWaterProgram.mFeatures.hasTransport = true;
-			gSkinnedObjectEmissiveWaterProgram.mFeatures.isFullbright = true;
-			gSkinnedObjectEmissiveWaterProgram.mFeatures.hasObjectSkinning = true;
-			gSkinnedObjectEmissiveWaterProgram.mFeatures.disableTextureIndex = true;
-			gSkinnedObjectEmissiveWaterProgram.mFeatures.hasWaterFog = true;
-			gSkinnedObjectEmissiveWaterProgram.mShaderFiles.clear();
-			gSkinnedObjectEmissiveWaterProgram.mShaderFiles.push_back(make_pair("objects/emissiveSkinnedV.glsl", GL_VERTEX_SHADER_ARB));
-			gSkinnedObjectEmissiveWaterProgram.mShaderFiles.push_back(make_pair("objects/fullbrightWaterF.glsl", GL_FRAGMENT_SHADER_ARB));
-			gSkinnedObjectEmissiveWaterProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT];
-			success = gSkinnedObjectEmissiveWaterProgram.createShader(NULL, NULL);
-		}
-
-		if (success)
-		{
-			gSkinnedObjectFullbrightShinyProgram.mName = "Skinned Fullbright Shiny Shader";
-			gSkinnedObjectFullbrightShinyProgram.mFeatures.calculatesAtmospherics = true;
-			gSkinnedObjectFullbrightShinyProgram.mFeatures.hasGamma = true;
-			gSkinnedObjectFullbrightShinyProgram.mFeatures.hasTransport = true;
-			gSkinnedObjectFullbrightShinyProgram.mFeatures.isShiny = true;
-			gSkinnedObjectFullbrightShinyProgram.mFeatures.isFullbright = true;
-			gSkinnedObjectFullbrightShinyProgram.mFeatures.hasObjectSkinning = true;
-			gSkinnedObjectFullbrightShinyProgram.mFeatures.hasAlphaMask = true;
-			gSkinnedObjectFullbrightShinyProgram.mFeatures.disableTextureIndex = true;
-			gSkinnedObjectFullbrightShinyProgram.mShaderFiles.clear();
-			gSkinnedObjectFullbrightShinyProgram.mShaderFiles.push_back(make_pair("objects/fullbrightShinySkinnedV.glsl", GL_VERTEX_SHADER_ARB));
-			gSkinnedObjectFullbrightShinyProgram.mShaderFiles.push_back(make_pair("objects/fullbrightShinyF.glsl", GL_FRAGMENT_SHADER_ARB));
-			gSkinnedObjectFullbrightShinyProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT];
-			success = gSkinnedObjectFullbrightShinyProgram.createShader(NULL, NULL);
-		}
-
-		if (success)
-		{
-			gSkinnedObjectShinySimpleProgram.mName = "Skinned Shiny Simple Shader";
-			gSkinnedObjectShinySimpleProgram.mFeatures.calculatesLighting = true;
-			gSkinnedObjectShinySimpleProgram.mFeatures.calculatesAtmospherics = true;
-			gSkinnedObjectShinySimpleProgram.mFeatures.hasGamma = true;
-			gSkinnedObjectShinySimpleProgram.mFeatures.hasAtmospherics = true;
-			gSkinnedObjectShinySimpleProgram.mFeatures.hasObjectSkinning = true;
-			gSkinnedObjectShinySimpleProgram.mFeatures.hasAlphaMask = true;
-			gSkinnedObjectShinySimpleProgram.mFeatures.isShiny = true;
-			gSkinnedObjectShinySimpleProgram.mFeatures.disableTextureIndex = true;
-			gSkinnedObjectShinySimpleProgram.mShaderFiles.clear();
-			gSkinnedObjectShinySimpleProgram.mShaderFiles.push_back(make_pair("objects/shinySimpleSkinnedV.glsl", GL_VERTEX_SHADER_ARB));
-			gSkinnedObjectShinySimpleProgram.mShaderFiles.push_back(make_pair("objects/shinyF.glsl", GL_FRAGMENT_SHADER_ARB));
-			gSkinnedObjectShinySimpleProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT];
-			success = gSkinnedObjectShinySimpleProgram.createShader(NULL, NULL);
-		}
-
-		if (success)
-		{
-			gSkinnedObjectSimpleWaterProgram.mName = "Skinned Simple Water Shader";
-			gSkinnedObjectSimpleWaterProgram.mFeatures.calculatesLighting = true;
-			gSkinnedObjectSimpleWaterProgram.mFeatures.calculatesAtmospherics = true;
-			gSkinnedObjectSimpleWaterProgram.mFeatures.hasGamma = true;
-			gSkinnedObjectSimpleWaterProgram.mFeatures.hasAtmospherics = true;
-			gSkinnedObjectSimpleWaterProgram.mFeatures.hasLighting = true;
-			gSkinnedObjectSimpleWaterProgram.mFeatures.disableTextureIndex = true;
-			gSkinnedObjectSimpleWaterProgram.mFeatures.hasWaterFog = true;
-			gSkinnedObjectSimpleWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER;
-			gSkinnedObjectSimpleWaterProgram.mFeatures.hasObjectSkinning = true;
-			gSkinnedObjectSimpleWaterProgram.mFeatures.disableTextureIndex = true;
-			gSkinnedObjectSimpleWaterProgram.mFeatures.hasAlphaMask = true;
-			gSkinnedObjectSimpleWaterProgram.mShaderFiles.clear();
-			gSkinnedObjectSimpleWaterProgram.mShaderFiles.push_back(make_pair("objects/simpleSkinnedV.glsl", GL_VERTEX_SHADER_ARB));
-			gSkinnedObjectSimpleWaterProgram.mShaderFiles.push_back(make_pair("objects/simpleWaterF.glsl", GL_FRAGMENT_SHADER_ARB));
-			gSkinnedObjectSimpleWaterProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT];
-			success = gSkinnedObjectSimpleWaterProgram.createShader(NULL, NULL);
-		}
-
-		if (success)
-		{
-			gSkinnedObjectFullbrightWaterProgram.mName = "Skinned Fullbright Water Shader";
-			gSkinnedObjectFullbrightWaterProgram.mFeatures.calculatesAtmospherics = true;
-			gSkinnedObjectFullbrightWaterProgram.mFeatures.hasGamma = true;
-			gSkinnedObjectFullbrightWaterProgram.mFeatures.hasTransport = true;
-			gSkinnedObjectFullbrightWaterProgram.mFeatures.isFullbright = true;
-			gSkinnedObjectFullbrightWaterProgram.mFeatures.hasObjectSkinning = true;
-			gSkinnedObjectFullbrightWaterProgram.mFeatures.hasAlphaMask = true;
-			gSkinnedObjectFullbrightWaterProgram.mFeatures.hasWaterFog = true;
-			gSkinnedObjectFullbrightWaterProgram.mFeatures.disableTextureIndex = true;
-			gSkinnedObjectFullbrightWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER;
-			gSkinnedObjectFullbrightWaterProgram.mShaderFiles.clear();
-			gSkinnedObjectFullbrightWaterProgram.mShaderFiles.push_back(make_pair("objects/fullbrightSkinnedV.glsl", GL_VERTEX_SHADER_ARB));
-			gSkinnedObjectFullbrightWaterProgram.mShaderFiles.push_back(make_pair("objects/fullbrightWaterF.glsl", GL_FRAGMENT_SHADER_ARB));
-			gSkinnedObjectFullbrightWaterProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT];
-			success = gSkinnedObjectFullbrightWaterProgram.createShader(NULL, NULL);
-		}
-
-		if (success)
-		{
-			gSkinnedObjectFullbrightShinyWaterProgram.mName = "Skinned Fullbright Shiny Water Shader";
-			gSkinnedObjectFullbrightShinyWaterProgram.mFeatures.calculatesAtmospherics = true;
-			gSkinnedObjectFullbrightShinyWaterProgram.mFeatures.hasGamma = true;
-			gSkinnedObjectFullbrightShinyWaterProgram.mFeatures.hasTransport = true;
-			gSkinnedObjectFullbrightShinyWaterProgram.mFeatures.isShiny = true;
-			gSkinnedObjectFullbrightShinyWaterProgram.mFeatures.isFullbright = true;
-			gSkinnedObjectFullbrightShinyWaterProgram.mFeatures.hasObjectSkinning = true;
-			gSkinnedObjectFullbrightShinyWaterProgram.mFeatures.hasAlphaMask = true;
-			gSkinnedObjectFullbrightShinyWaterProgram.mFeatures.hasWaterFog = true;
-			gSkinnedObjectFullbrightShinyWaterProgram.mFeatures.disableTextureIndex = true;
-			gSkinnedObjectFullbrightShinyWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER;
-			gSkinnedObjectFullbrightShinyWaterProgram.mShaderFiles.clear();
-			gSkinnedObjectFullbrightShinyWaterProgram.mShaderFiles.push_back(make_pair("objects/fullbrightShinySkinnedV.glsl", GL_VERTEX_SHADER_ARB));
-			gSkinnedObjectFullbrightShinyWaterProgram.mShaderFiles.push_back(make_pair("objects/fullbrightShinyWaterF.glsl", GL_FRAGMENT_SHADER_ARB));
-			gSkinnedObjectFullbrightShinyWaterProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT];
-			success = gSkinnedObjectFullbrightShinyWaterProgram.createShader(NULL, NULL);
-		}
-
-		if (success)
-		{
-			gSkinnedObjectShinySimpleWaterProgram.mName = "Skinned Shiny Simple Water Shader";
-			gSkinnedObjectShinySimpleWaterProgram.mFeatures.calculatesLighting = true;
-			gSkinnedObjectShinySimpleWaterProgram.mFeatures.calculatesAtmospherics = true;
-			gSkinnedObjectShinySimpleWaterProgram.mFeatures.hasGamma = true;
-			gSkinnedObjectShinySimpleWaterProgram.mFeatures.hasAtmospherics = true;
-			gSkinnedObjectShinySimpleWaterProgram.mFeatures.hasObjectSkinning = true;
-			gSkinnedObjectShinySimpleWaterProgram.mFeatures.hasAlphaMask = true;
-			gSkinnedObjectShinySimpleWaterProgram.mFeatures.isShiny = true;
-			gSkinnedObjectShinySimpleWaterProgram.mFeatures.hasWaterFog = true;
-			gSkinnedObjectShinySimpleWaterProgram.mFeatures.disableTextureIndex = true;
-			gSkinnedObjectShinySimpleWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER;
-			gSkinnedObjectShinySimpleWaterProgram.mShaderFiles.clear();
-			gSkinnedObjectShinySimpleWaterProgram.mShaderFiles.push_back(make_pair("objects/shinySimpleSkinnedV.glsl", GL_VERTEX_SHADER_ARB));
-			gSkinnedObjectShinySimpleWaterProgram.mShaderFiles.push_back(make_pair("objects/shinyWaterF.glsl", GL_FRAGMENT_SHADER_ARB));
-			gSkinnedObjectShinySimpleWaterProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT];
-			success = gSkinnedObjectShinySimpleWaterProgram.createShader(NULL, NULL);
-		}
+        success = make_rigged_variant(gObjectFullbrightShinyWaterProgram, gSkinnedObjectFullbrightShinyWaterProgram);
+		success = success && gObjectFullbrightShinyWaterProgram.createShader(NULL, NULL);
 	}
 
 	if( !success )
@@ -3995,9 +3662,21 @@ BOOL LLViewerShaderMgr::loadShadersInterface()
 		gOcclusionProgram.mShaderFiles.push_back(make_pair("interface/occlusionV.glsl", GL_VERTEX_SHADER_ARB));
 		gOcclusionProgram.mShaderFiles.push_back(make_pair("interface/occlusionF.glsl", GL_FRAGMENT_SHADER_ARB));
 		gOcclusionProgram.mShaderLevel = mShaderLevel[SHADER_INTERFACE];
+        gOcclusionProgram.mRiggedVariant = &gSkinnedOcclusionProgram;
 		success = gOcclusionProgram.createShader(NULL, NULL);
 	}
 
+    if (success)
+    {
+        gSkinnedOcclusionProgram.mName = "Skinned Occlusion Shader";
+        gSkinnedOcclusionProgram.mFeatures.hasObjectSkinning = true;
+        gSkinnedOcclusionProgram.mShaderFiles.clear();
+        gSkinnedOcclusionProgram.mShaderFiles.push_back(make_pair("interface/occlusionSkinnedV.glsl", GL_VERTEX_SHADER_ARB));
+        gSkinnedOcclusionProgram.mShaderFiles.push_back(make_pair("interface/occlusionF.glsl", GL_FRAGMENT_SHADER_ARB));
+        gSkinnedOcclusionProgram.mShaderLevel = mShaderLevel[SHADER_INTERFACE];
+        success = gSkinnedOcclusionProgram.createShader(NULL, NULL);
+    }
+
 	if (success)
 	{
 		gOcclusionCubeProgram.mName = "Occlusion Cube Shader";
@@ -4014,10 +3693,22 @@ BOOL LLViewerShaderMgr::loadShadersInterface()
 		gDebugProgram.mShaderFiles.clear();
 		gDebugProgram.mShaderFiles.push_back(make_pair("interface/debugV.glsl", GL_VERTEX_SHADER_ARB));
 		gDebugProgram.mShaderFiles.push_back(make_pair("interface/debugF.glsl", GL_FRAGMENT_SHADER_ARB));
+        gDebugProgram.mRiggedVariant = &gSkinnedDebugProgram;
 		gDebugProgram.mShaderLevel = mShaderLevel[SHADER_INTERFACE];
 		success = gDebugProgram.createShader(NULL, NULL);
 	}
 
+    if (success)
+    {
+        gSkinnedDebugProgram.mName = "Skinned Debug Shader";
+        gSkinnedDebugProgram.mFeatures.hasObjectSkinning = true;
+        gSkinnedDebugProgram.mShaderFiles.clear();
+        gSkinnedDebugProgram.mShaderFiles.push_back(make_pair("interface/debugSkinnedV.glsl", GL_VERTEX_SHADER_ARB));
+        gSkinnedDebugProgram.mShaderFiles.push_back(make_pair("interface/debugF.glsl", GL_FRAGMENT_SHADER_ARB));
+        gSkinnedDebugProgram.mShaderLevel = mShaderLevel[SHADER_INTERFACE];
+        success = gSkinnedDebugProgram.createShader(NULL, NULL);
+    }
+
 	if (success)
 	{
 		gClipProgram.mName = "Clip Shader";
diff --git a/indra/newview/llviewershadermgr.h b/indra/newview/llviewershadermgr.h
index 081221f15b..297cfb6e68 100644
--- a/indra/newview/llviewershadermgr.h
+++ b/indra/newview/llviewershadermgr.h
@@ -184,10 +184,8 @@ extern LLGLSLShader			gObjectPreviewProgram;
 extern LLGLSLShader			gObjectSimpleAlphaMaskProgram;
 extern LLGLSLShader			gObjectSimpleWaterProgram;
 extern LLGLSLShader			gObjectSimpleWaterAlphaMaskProgram;
-extern LLGLSLShader			gObjectSimpleNonIndexedProgram;
 extern LLGLSLShader			gObjectSimpleNonIndexedTexGenProgram;
 extern LLGLSLShader			gObjectSimpleNonIndexedTexGenWaterProgram;
-extern LLGLSLShader			gObjectSimpleNonIndexedWaterProgram;
 extern LLGLSLShader			gObjectAlphaMaskNonIndexedProgram;
 extern LLGLSLShader			gObjectAlphaMaskNonIndexedWaterProgram;
 extern LLGLSLShader			gObjectAlphaMaskNoColorProgram;
@@ -200,8 +198,6 @@ extern LLGLSLShader			gObjectEmissiveProgram;
 extern LLGLSLShader			gObjectEmissiveWaterProgram;
 extern LLGLSLShader			gObjectFullbrightAlphaMaskProgram;
 extern LLGLSLShader			gObjectFullbrightWaterAlphaMaskProgram;
-extern LLGLSLShader			gObjectFullbrightNonIndexedProgram;
-extern LLGLSLShader			gObjectFullbrightNonIndexedWaterProgram;
 extern LLGLSLShader			gObjectEmissiveNonIndexedProgram;
 extern LLGLSLShader			gObjectEmissiveNonIndexedWaterProgram;
 extern LLGLSLShader			gObjectBumpProgram;
@@ -213,25 +209,9 @@ extern LLGLSLShader			gObjectFullbrightLODProgram;
 
 extern LLGLSLShader			gObjectFullbrightShinyProgram;
 extern LLGLSLShader			gObjectFullbrightShinyWaterProgram;
-extern LLGLSLShader			gObjectFullbrightShinyNonIndexedProgram;
-extern LLGLSLShader			gObjectFullbrightShinyNonIndexedWaterProgram;
 
 extern LLGLSLShader			gObjectShinyProgram;
 extern LLGLSLShader			gObjectShinyWaterProgram;
-extern LLGLSLShader			gObjectShinyNonIndexedProgram;
-extern LLGLSLShader			gObjectShinyNonIndexedWaterProgram;
-
-extern LLGLSLShader			gSkinnedObjectSimpleProgram;
-extern LLGLSLShader			gSkinnedObjectFullbrightProgram;
-extern LLGLSLShader			gSkinnedObjectEmissiveProgram;
-extern LLGLSLShader			gSkinnedObjectFullbrightShinyProgram;
-extern LLGLSLShader			gSkinnedObjectShinySimpleProgram;
-
-extern LLGLSLShader			gSkinnedObjectSimpleWaterProgram;
-extern LLGLSLShader			gSkinnedObjectFullbrightWaterProgram;
-extern LLGLSLShader			gSkinnedObjectEmissiveWaterProgram;
-extern LLGLSLShader			gSkinnedObjectFullbrightShinyWaterProgram;
-extern LLGLSLShader			gSkinnedObjectShinySimpleWaterProgram;
 
 //environment shaders
 extern LLGLSLShader			gTerrainProgram;
@@ -281,9 +261,6 @@ extern LLGLSLShader			gDeferredDiffuseAlphaMaskProgram;
 extern LLGLSLShader			gDeferredNonIndexedDiffuseAlphaMaskProgram;
 extern LLGLSLShader			gDeferredNonIndexedDiffuseAlphaMaskNoColorProgram;
 extern LLGLSLShader			gDeferredNonIndexedDiffuseProgram;
-extern LLGLSLShader			gDeferredSkinnedDiffuseProgram;
-extern LLGLSLShader			gDeferredSkinnedBumpProgram;
-extern LLGLSLShader			gDeferredSkinnedAlphaProgram;
 extern LLGLSLShader			gDeferredBumpProgram;
 extern LLGLSLShader			gDeferredTerrainProgram;
 extern LLGLSLShader			gDeferredTerrainWaterProgram;
@@ -330,8 +307,6 @@ extern LLGLSLShader			gDeferredWLSunProgram;
 extern LLGLSLShader			gDeferredWLMoonProgram;
 extern LLGLSLShader			gDeferredStarProgram;
 extern LLGLSLShader			gDeferredFullbrightShinyProgram;
-extern LLGLSLShader			gDeferredSkinnedFullbrightShinyProgram;
-extern LLGLSLShader			gDeferredSkinnedFullbrightProgram;
 extern LLGLSLShader			gNormalMapGenProgram;
 
 // Deferred materials shaders
diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp
index 310a6a2adb..84bb67a03d 100644
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -111,6 +111,7 @@
 #include "llsdserialize.h"
 #include "llcallstack.h"
 #include "llrendersphere.h"
+#include "llskinningutil.h"
 
 #include <boost/lexical_cast.hpp>
 
@@ -9445,6 +9446,54 @@ LLViewerTexture* LLVOAvatar::getBakedTexture(const U8 te)
 	
 }
 
+const LLVOAvatar::MatrixPaletteCache& LLVOAvatar::updateSkinInfoMatrixPalette(const LLMeshSkinInfo* skin, LLVOVolume* requesting_obj)
+{
+    U64 hash = skin->mHash;
+    MatrixPaletteCache& entry = mMatrixPaletteCache[hash];
+
+    if (entry.mFrame != gFrameCount)
+    {
+        LL_PROFILE_ZONE_SCOPED;
+
+        entry.mFrame = gFrameCount;
+
+        //build matrix palette
+        U32 count = LLSkinningUtil::getMeshJointCount(skin);
+        entry.mMatrixPalette.resize(count);
+        LLSkinningUtil::initSkinningMatrixPalette(&(entry.mMatrixPalette[0]), count, skin, this);
+
+        const LLMatrix4a* mat = &(entry.mMatrixPalette[0]);
+
+        entry.mGLMp.resize(count * 12);
+
+        F32* mp = &(entry.mGLMp[0]);
+
+        for (U32 i = 0; i < count; ++i)
+        {
+            F32* m = (F32*)mat[i].mMatrix[0].getF32ptr();
+
+            U32 idx = i * 12;
+
+            mp[idx + 0] = m[0];
+            mp[idx + 1] = m[1];
+            mp[idx + 2] = m[2];
+            mp[idx + 3] = m[12];
+
+            mp[idx + 4] = m[4];
+            mp[idx + 5] = m[5];
+            mp[idx + 6] = m[6];
+            mp[idx + 7] = m[13];
+
+            mp[idx + 8] = m[8];
+            mp[idx + 9] = m[9];
+            mp[idx + 10] = m[10];
+            mp[idx + 11] = m[14];
+        }
+    }
+
+    return entry;
+}
+
 // static
 void LLVOAvatar::getAnimLabels( std::vector<std::string>* labels )
 {
diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h
index aeac23ad92..b85400866e 100644
--- a/indra/newview/llvoavatar.h
+++ b/indra/newview/llvoavatar.h
@@ -53,6 +53,8 @@
 #include "llviewerstats.h"
 #include "llvovolume.h"
 #include "llavatarrendernotifier.h"
+#include "llmodel.h"
+
 
 extern const LLUUID ANIM_AGENT_BODY_NOISE;
 extern const LLUUID ANIM_AGENT_BREATHE_ROT;
@@ -77,6 +79,7 @@ class LLViewerJointMesh;
 
 const F32 MAX_AVATAR_LOD_FACTOR = 1.0f;
 
+extern U32 gFrameCount;
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // LLVOAvatar
@@ -746,6 +749,26 @@ public:
 	void			updateMeshVisibility();
 	LLViewerTexture*		getBakedTexture(const U8 te);
 
+    class alignas(16) MatrixPaletteCache
+    {
+    public:
+        U32 mFrame;
+        LLMeshSkinInfo::matrix_list_t mMatrixPalette;
+
+        // Float array ready to be sent to GL
+        std::vector<F32> mGLMp;
+
+        MatrixPaletteCache() :
+            mFrame(gFrameCount - 1)
+        {
+        }
+    };
+
+    const MatrixPaletteCache& updateSkinInfoMatrixPalette(const LLMeshSkinInfo* skinInfo, LLVOVolume* requesting_obj = nullptr);
+
+    typedef std::unordered_map<U64, MatrixPaletteCache> matrix_palette_cache_t;
+    matrix_palette_cache_t mMatrixPaletteCache;
+
 protected:
 	void 			releaseMeshData();
 	virtual void restoreMeshData();
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index 755a70599a..f4f9154fed 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -1740,7 +1740,17 @@ BOOL LLVOVolume::genBBoxes(BOOL force_global)
 		}
 	}
 
-    if (any_valid_boxes)
+    if (isRiggedMesh())
+    {
+        min.set(-1, -1, -1, 0);
+        max.set(1, 1, 1, 0);
+
+        mDrawable->setSpatialExtents(min, max);
+        mDrawable->setPositionGroup(LLVector4a(0, 0, 0));
+        updateRadius();
+        mDrawable->movePartition();
+    }
+    else if (any_valid_boxes)
     {
         if (rebuild)
         {
@@ -5010,13 +5020,13 @@ bool can_batch_texture(LLFace* facep)
 
 const static U32 MAX_FACE_COUNT = 4096U;
 int32_t LLVolumeGeometryManager::sInstanceCount = 0;
-LLFace** LLVolumeGeometryManager::sFullbrightFaces = NULL;
-LLFace** LLVolumeGeometryManager::sBumpFaces = NULL;
-LLFace** LLVolumeGeometryManager::sSimpleFaces = NULL;
-LLFace** LLVolumeGeometryManager::sNormFaces = NULL;
-LLFace** LLVolumeGeometryManager::sSpecFaces = NULL;
-LLFace** LLVolumeGeometryManager::sNormSpecFaces = NULL;
-LLFace** LLVolumeGeometryManager::sAlphaFaces = NULL;
+LLFace** LLVolumeGeometryManager::sFullbrightFaces[2] = { NULL };
+LLFace** LLVolumeGeometryManager::sBumpFaces[2] = { NULL };
+LLFace** LLVolumeGeometryManager::sSimpleFaces[2] = { NULL };
+LLFace** LLVolumeGeometryManager::sNormFaces[2] = { NULL };
+LLFace** LLVolumeGeometryManager::sSpecFaces[2] = { NULL };
+LLFace** LLVolumeGeometryManager::sNormSpecFaces[2] = { NULL };
+LLFace** LLVolumeGeometryManager::sAlphaFaces[2] = { NULL };
 
 LLVolumeGeometryManager::LLVolumeGeometryManager()
 	: LLGeometryManager()
@@ -5044,32 +5054,38 @@ LLVolumeGeometryManager::~LLVolumeGeometryManager()
 
 void LLVolumeGeometryManager::allocateFaces(U32 pMaxFaceCount)
 {
-	sFullbrightFaces = static_cast<LLFace**>(ll_aligned_malloc<64>(pMaxFaceCount*sizeof(LLFace*)));
-	sBumpFaces = static_cast<LLFace**>(ll_aligned_malloc<64>(pMaxFaceCount*sizeof(LLFace*)));
-	sSimpleFaces = static_cast<LLFace**>(ll_aligned_malloc<64>(pMaxFaceCount*sizeof(LLFace*)));
-	sNormFaces = static_cast<LLFace**>(ll_aligned_malloc<64>(pMaxFaceCount*sizeof(LLFace*)));
-	sSpecFaces = static_cast<LLFace**>(ll_aligned_malloc<64>(pMaxFaceCount*sizeof(LLFace*)));
-	sNormSpecFaces = static_cast<LLFace**>(ll_aligned_malloc<64>(pMaxFaceCount*sizeof(LLFace*)));
-	sAlphaFaces = static_cast<LLFace**>(ll_aligned_malloc<64>(pMaxFaceCount*sizeof(LLFace*)));
+    for (int i = 0; i < 2; ++i)
+    {
+        sFullbrightFaces[i] = static_cast<LLFace**>(ll_aligned_malloc<64>(pMaxFaceCount * sizeof(LLFace*)));
+        sBumpFaces[i] = static_cast<LLFace**>(ll_aligned_malloc<64>(pMaxFaceCount * sizeof(LLFace*)));
+        sSimpleFaces[i] = static_cast<LLFace**>(ll_aligned_malloc<64>(pMaxFaceCount * sizeof(LLFace*)));
+        sNormFaces[i] = static_cast<LLFace**>(ll_aligned_malloc<64>(pMaxFaceCount * sizeof(LLFace*)));
+        sSpecFaces[i] = static_cast<LLFace**>(ll_aligned_malloc<64>(pMaxFaceCount * sizeof(LLFace*)));
+        sNormSpecFaces[i] = static_cast<LLFace**>(ll_aligned_malloc<64>(pMaxFaceCount * sizeof(LLFace*)));
+        sAlphaFaces[i] = static_cast<LLFace**>(ll_aligned_malloc<64>(pMaxFaceCount * sizeof(LLFace*)));
+    }
 }
 
 void LLVolumeGeometryManager::freeFaces()
 {
-	ll_aligned_free<64>(sFullbrightFaces);
-	ll_aligned_free<64>(sBumpFaces);
-	ll_aligned_free<64>(sSimpleFaces);
-	ll_aligned_free<64>(sNormFaces);
-	ll_aligned_free<64>(sSpecFaces);
-	ll_aligned_free<64>(sNormSpecFaces);
-	ll_aligned_free<64>(sAlphaFaces);
-
-	sFullbrightFaces = NULL;
-	sBumpFaces = NULL;
-	sSimpleFaces = NULL;
-	sNormFaces = NULL;
-	sSpecFaces = NULL;
-	sNormSpecFaces = NULL;
-	sAlphaFaces = NULL;
+    for (int i = 0; i < 2; ++i)
+    {
+        ll_aligned_free<64>(sFullbrightFaces[i]);
+        ll_aligned_free<64>(sBumpFaces[i]);
+        ll_aligned_free<64>(sSimpleFaces[i]);
+        ll_aligned_free<64>(sNormFaces[i]);
+        ll_aligned_free<64>(sSpecFaces[i]);
+        ll_aligned_free<64>(sNormSpecFaces[i]);
+        ll_aligned_free<64>(sAlphaFaces[i]);
+
+        sFullbrightFaces[i] = NULL;
+        sBumpFaces[i] = NULL;
+        sSimpleFaces[i] = NULL;
+        sNormFaces[i] = NULL;
+        sSpecFaces[i] = NULL;
+        sNormSpecFaces[i] = NULL;
+        sAlphaFaces[i] = NULL;
+    }
 }
 
 void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep, U32 type)
@@ -5090,8 +5106,18 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep,
 		return;
 	}
 
+    U32 passType = type;
+
+    bool rigged = facep->isState(LLFace::RIGGED);
+
+    if (rigged && type != LLRenderPass::PASS_ALPHA)
+    {
+        // hacky, should probably clean up -- if this face is rigged, put it in "type + 1"
+        // See LLRenderPass PASS_foo enum
+        passType += 1;
+    }
 	//add face to drawmap
-	LLSpatialGroup::drawmap_elem_t& draw_vec = group->mDrawMap[type];	
+	LLSpatialGroup::drawmap_elem_t& draw_vec = group->mDrawMap[passType];
 
 	S32 idx = draw_vec.size()-1;
 
@@ -5117,7 +5143,12 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep,
 
 	LLDrawable* drawable = facep->getDrawable();
 	
-	if (drawable->isState(LLDrawable::ANIMATED_CHILD))
+    if (rigged)
+    {
+        // rigged meshes ignore their model matrix
+        model_mat = nullptr;
+    }
+	else if (drawable->isState(LLDrawable::ANIMATED_CHILD))
 	{
 		model_mat = &drawable->getWorldMatrix();
 	}
@@ -5191,7 +5222,7 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep,
 		draw_vec[idx]->mEnd - draw_vec[idx]->mStart + facep->getGeomCount() <= (U32) gGLManager.mGLMaxVertexRange &&
 		draw_vec[idx]->mCount + facep->getIndicesCount() <= (U32) gGLManager.mGLMaxIndexRange &&
 #endif
-		draw_vec[idx]->mMaterial == mat &&
+		//draw_vec[idx]->mMaterial == mat &&
 		draw_vec[idx]->mMaterialID == mat_id &&
 		draw_vec[idx]->mFullbright == fullbright &&
 		draw_vec[idx]->mBump == bump &&
@@ -5199,7 +5230,9 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep,
 		draw_vec[idx]->mTextureMatrix == tex_mat &&
 		draw_vec[idx]->mModelMatrix == model_mat &&
 		draw_vec[idx]->mShaderMask == shader_mask &&
-		draw_vec[idx]->mSelected == selected)
+		draw_vec[idx]->mSelected == selected &&
+        draw_vec[idx]->mAvatar == facep->mAvatar &&
+        draw_vec[idx]->getSkinHash() == facep->getSkinHash())
 	{
 		draw_vec[idx]->mCount += facep->getIndicesCount();
 		draw_vec[idx]->mEnd += facep->getGeomCount();
@@ -5245,6 +5278,8 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep,
 		draw_info->mSpecularMap = NULL;
 		draw_info->mMaterial = mat;
 		draw_info->mShaderMask = shader_mask;
+        draw_info->mAvatar = facep->mAvatar;
+        draw_info->mSkinInfo = facep->mSkinInfo;
 
 		if (mat)
 		{
@@ -5411,11 +5446,21 @@ void handleRenderAutoMuteByteLimitChanged(const LLSD& new_value)
 
 // add a face pointer to a list of face pointers without going over MAX_COUNT faces
 template<typename T>
-static inline void add_face(T** list, U32& count, T* face)
+static inline void add_face(T*** list, U32* count, T* face)
 {
-    if (count < MAX_FACE_COUNT)
+    if (face->isState(LLFace::RIGGED))
+    {
+        if (count[1] < MAX_FACE_COUNT)
+        {
+            list[1][count[1]++] = face;
+        }
+    }
+    else
     {
-        list[count++] = face;
+        if (count[0] < MAX_FACE_COUNT)
+        {
+            list[0][count[0]++] = face;
+        }
     }
 }
 
@@ -5465,14 +5510,13 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 
 	mFaceList.clear();
 
-	U32 fullbright_count = 0;
-	U32 bump_count = 0;
-	U32 simple_count = 0;
-	U32 alpha_count = 0;
-	U32 norm_count = 0;
-	U32 spec_count = 0;
-	U32 normspec_count = 0;
-
+    U32 fullbright_count[2] = { 0 };
+	U32 bump_count[2] = { 0 };
+	U32 simple_count[2] = { 0 };
+	U32 alpha_count[2] = { 0 };
+	U32 norm_count[2] = { 0 };
+	U32 spec_count[2] = { 0 };
+	U32 normspec_count[2] = { 0 };
 
 	U32 useage = group->getSpatialPartition()->mBufferUsage;
 
@@ -5521,7 +5565,8 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 
             std::string vobj_name = llformat("Vol%p", vobj);
 
-			if (vobj->isMesh() &&
+            bool is_mesh = vobj->isMesh();
+			if (is_mesh &&
 				((vobj->getVolume() && !vobj->getVolume()->isMeshAssetLoaded()) || !gMeshRepo.meshRezEnabled()))
 			{
 				continue;
@@ -5534,7 +5579,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 				group->mSurfaceArea += volume->getSurfaceArea() * llmax(llmax(scale.mV[0], scale.mV[1]), scale.mV[2]);
 			}
 
-            bool is_mesh = vobj->isMesh();
+            
             F32 est_tris = vobj->getEstTrianglesMax();
 
             vobj->updateControlAvatar();
@@ -5558,15 +5603,32 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 
 			drawablep->clearState(LLDrawable::HAS_ALPHA);
 
-            if (vobj->isRiggedMesh() &&
-                ((vobj->isAnimatedObject() && vobj->getControlAvatar()) ||
-                 (!vobj->isAnimatedObject() && vobj->getAvatar())))
+            LLVOAvatar* avatar = nullptr;
+            const LLMeshSkinInfo* skinInfo = nullptr;
+            if (is_mesh)
+            {
+                skinInfo = vobj->getSkinInfo();
+            }
+
+            if (skinInfo)
+            {
+                if (vobj->isAnimatedObject())
+                {
+                    avatar = vobj->getControlAvatar();
+                }
+                else
+                {
+                    avatar = vobj->getAvatar();
+                }
+            }
+
+            if (avatar != nullptr)
             {
-                vobj->getAvatar()->addAttachmentOverridesForObject(vobj, NULL, false);
+                avatar->addAttachmentOverridesForObject(vobj, NULL, false);
             }
             
             // Standard rigged mesh attachments: 
-			bool rigged = !vobj->isAnimatedObject() && vobj->isRiggedMesh() && vobj->isAttachment();
+			bool rigged = !vobj->isAnimatedObject() && skinInfo && vobj->isAttachment();
             // Animated objects. Have to check for isRiggedMesh() to
             // exclude static objects in animated object linksets.
 			rigged = rigged || (vobj->isAnimatedObject() && vobj->isRiggedMesh() &&
@@ -5590,183 +5652,19 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 			
 				//sum up face verts and indices
 				drawablep->updateFaceSize(i);
-			
-				if (rigged)
-				{
-					if (!facep->isState(LLFace::RIGGED))
-					{ //completely reset vertex buffer
-						facep->clearVertexBuffer();
-					}
-		
-					facep->setState(LLFace::RIGGED);
-					any_rigged_face = true;
-				
-					//get drawpool of avatar with rigged face
-					LLDrawPoolAvatar* pool = get_avatar_drawpool(vobj);				
-					
-					if (pool)
-					{
-						const LLTextureEntry* te = facep->getTextureEntry();
-
-						//remove face from old pool if it exists
-						LLDrawPool* old_pool = facep->getPool();
-						if (old_pool
-							&& (old_pool->getType() == LLDrawPool::POOL_AVATAR || old_pool->getType() == LLDrawPool::POOL_CONTROL_AV))
-						{
-							((LLDrawPoolAvatar*) old_pool)->removeRiggedFace(facep);
-						}
-
-						//add face to new pool
-						LLViewerTexture* tex = facep->getTexture();
-						U32 type = gPipeline.getPoolTypeFromTE(te, tex);
-
-                        F32 te_alpha = te->getColor().mV[3];
-
-						if (te->getGlow())
-						{
-							pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_GLOW);
-						}
-
-						LLMaterial* mat = te->getMaterialParams().get();
-                        bool fullbright = te->getFullbright();
-
-						if (mat && LLPipeline::sRenderDeferred)
-						{
-							U8 alpha_mode = mat->getDiffuseAlphaMode();
-
-							bool is_alpha = type == LLDrawPool::POOL_ALPHA &&
-								(alpha_mode == LLMaterial::DIFFUSE_ALPHA_MODE_BLEND ||
-								te_alpha < 0.999f);
-
-							if (is_alpha)
-							{ //this face needs alpha blending, override alpha mode
-								alpha_mode = LLMaterial::DIFFUSE_ALPHA_MODE_BLEND;
-							}
-
-                            if (fullbright && (alpha_mode == LLMaterial::DIFFUSE_ALPHA_MODE_NONE))
-                            {
-                                pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_FULLBRIGHT);
-                            }
-							else if (!is_alpha || te_alpha > 0.f)  // //only add the face if it will actually be visible
-							{ 
-								U32 mask = mat->getShaderMask(alpha_mode);
-								pool->addRiggedFace(facep, mask);
-							}
-
-							if(vobj->isAnimatedObject() && vobj->isRiggedMesh())
-							{
-								pool->updateRiggedVertexBuffers(vobj->getAvatar());
-							}
-						}
-						else if (mat)
-						{							
-							bool is_alpha = type == LLDrawPool::POOL_ALPHA;
-							U8 mode = mat->getDiffuseAlphaMode();
-							bool can_be_shiny = mode == LLMaterial::DIFFUSE_ALPHA_MODE_NONE ||
-												mode == LLMaterial::DIFFUSE_ALPHA_MODE_EMISSIVE;
-							
-							if (mode == LLMaterial::DIFFUSE_ALPHA_MODE_MASK && te->getColor().mV[3] >= 0.999f)
-							{
-								pool->addRiggedFace(facep, fullbright ? LLDrawPoolAvatar::RIGGED_FULLBRIGHT : LLDrawPoolAvatar::RIGGED_SIMPLE);
-							}
-							else if (is_alpha || (te->getColor().mV[3] < 0.999f))
-							{
-								if (te->getColor().mV[3] > 0.f)
-								{
-									pool->addRiggedFace(facep, fullbright ? LLDrawPoolAvatar::RIGGED_FULLBRIGHT_ALPHA : LLDrawPoolAvatar::RIGGED_ALPHA);
-								}
-							}
-							else if (gPipeline.canUseVertexShaders()
-								&& LLPipeline::sRenderBump 
-								&& te->getShiny() 
-								&& can_be_shiny)
-							{
-								pool->addRiggedFace(facep, fullbright ? LLDrawPoolAvatar::RIGGED_FULLBRIGHT_SHINY : LLDrawPoolAvatar::RIGGED_SHINY);
-							}
-							else
-							{
-								pool->addRiggedFace(facep, fullbright ? LLDrawPoolAvatar::RIGGED_FULLBRIGHT : LLDrawPoolAvatar::RIGGED_SIMPLE);
-							}
-						}
-						else
-						{
-						if (type == LLDrawPool::POOL_ALPHA)
-						{
-							if (te->getColor().mV[3] > 0.f)
-							{
-								if (te->getFullbright())
-								{
-									pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_FULLBRIGHT_ALPHA);
-								}
-								else
-								{
-									pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_ALPHA);
-								}
-							}
-						}
-						else if (te->getShiny())
-						{
-							if (te->getFullbright())
-							{
-								pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_FULLBRIGHT_SHINY);
-							}
-							else
-							{
-								if (LLPipeline::sRenderDeferred)
-								{
-									pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_SIMPLE);
-								}
-								else
-								{
-									pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_SHINY);
-								}
-							}
-						}
-						else
-						{
-							if (te->getFullbright())
-							{
-								pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_FULLBRIGHT);
-							}
-							else
-							{
-								pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_SIMPLE);
-							}
-						}
-
-
-						if (LLPipeline::sRenderDeferred)
-						{
-							if (type != LLDrawPool::POOL_ALPHA && !te->getFullbright())
-							{
-								if (te->getBumpmap())
-								{
-									pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_DEFERRED_BUMP);
-								}
-								else
-								{
-									pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_DEFERRED_SIMPLE);
-								}
-							}
-						}
-					}
-					}
 
-					continue;
-				}
-				else
-				{
-					if (facep->isState(LLFace::RIGGED))
-					{ //face is not rigged but used to be, remove from rigged face pool
-						LLDrawPoolAvatar* pool = (LLDrawPoolAvatar*) facep->getPool();
-						if (pool)
-						{
-							pool->removeRiggedFace(facep);
-						}
-						facep->clearState(LLFace::RIGGED);
-					}
-				}
+                if (rigged)
+                {
+                    if (!facep->isState(LLFace::RIGGED))
+                    { //completely reset vertex buffer
+                        facep->clearVertexBuffer();
+                    }
 
+                    facep->setState(LLFace::RIGGED);
+                    facep->mSkinInfo = (LLMeshSkinInfo*) skinInfo; // TODO -- fix ugly de-consting here
+                    facep->mAvatar = avatar;
+                    any_rigged_face = true;
+                }
 
 				if (cur_total > max_total || facep->getIndicesCount() <= 0 || facep->getGeomCount() <= 0)
 				{
@@ -5776,7 +5674,9 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 
 				cur_total += facep->getGeomCount();
 
-				if (facep->hasGeometry() && facep->getPixelArea() > FORCE_CULL_AREA)
+				if (facep->hasGeometry() && 
+                    (rigged ||  // <-- HACK FIXME -- getPixelArea might be incorrect for rigged objects
+                        facep->getPixelArea() > FORCE_CULL_AREA)) // <-- don't render tiny faces
 				{
 					const LLTextureEntry* te = facep->getTextureEntry();
 					LLViewerTexture* tex = facep->getTexture();
@@ -5966,6 +5866,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 
 	BOOL batch_textures = LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_OBJECT) > 1;
 
+    // add extra vertex data for deferred rendering (not necessarily for batching textures)
 	if (batch_textures)
 	{
 		bump_mask = bump_mask | LLVertexBuffer::MAP_TANGENT;
@@ -5978,13 +5879,23 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 
 	U32 geometryBytes = 0;
 
-	geometryBytes += genDrawInfo(group, simple_mask | LLVertexBuffer::MAP_TEXTURE_INDEX, sSimpleFaces, simple_count, FALSE, batch_textures, FALSE);
-	geometryBytes += genDrawInfo(group, fullbright_mask | LLVertexBuffer::MAP_TEXTURE_INDEX, sFullbrightFaces, fullbright_count, FALSE, batch_textures);
-	geometryBytes += genDrawInfo(group, alpha_mask | LLVertexBuffer::MAP_TEXTURE_INDEX, sAlphaFaces, alpha_count, TRUE, batch_textures);
-	geometryBytes += genDrawInfo(group, bump_mask | LLVertexBuffer::MAP_TEXTURE_INDEX, sBumpFaces, bump_count, FALSE, FALSE);
-	geometryBytes += genDrawInfo(group, norm_mask | LLVertexBuffer::MAP_TEXTURE_INDEX, sNormFaces, norm_count, FALSE, FALSE);
-	geometryBytes += genDrawInfo(group, spec_mask | LLVertexBuffer::MAP_TEXTURE_INDEX, sSpecFaces, spec_count, FALSE, FALSE);
-	geometryBytes += genDrawInfo(group, normspec_mask | LLVertexBuffer::MAP_TEXTURE_INDEX, sNormSpecFaces, normspec_count, FALSE, FALSE);
+    U32 extra_mask = LLVertexBuffer::MAP_TEXTURE_INDEX;
+	geometryBytes += genDrawInfo(group, simple_mask | extra_mask, sSimpleFaces[0], simple_count[0], FALSE, batch_textures);
+	geometryBytes += genDrawInfo(group, fullbright_mask | extra_mask, sFullbrightFaces[0], fullbright_count[0], FALSE, batch_textures);
+	geometryBytes += genDrawInfo(group, alpha_mask | extra_mask, sAlphaFaces[0], alpha_count[0], TRUE, batch_textures);
+	geometryBytes += genDrawInfo(group, bump_mask | extra_mask, sBumpFaces[0], bump_count[0], FALSE, FALSE);
+	geometryBytes += genDrawInfo(group, norm_mask | extra_mask, sNormFaces[0], norm_count[0], FALSE, FALSE);
+	geometryBytes += genDrawInfo(group, spec_mask | extra_mask, sSpecFaces[0], spec_count[0], FALSE, FALSE);
+	geometryBytes += genDrawInfo(group, normspec_mask | extra_mask, sNormSpecFaces[0], normspec_count[0], FALSE, FALSE);
+
+    extra_mask |= LLVertexBuffer::MAP_WEIGHT4;
+    geometryBytes += genDrawInfo(group, simple_mask | extra_mask, sSimpleFaces[1], simple_count[1], FALSE, batch_textures, TRUE);
+    geometryBytes += genDrawInfo(group, fullbright_mask | extra_mask, sFullbrightFaces[1], fullbright_count[1], FALSE, batch_textures, TRUE);
+    geometryBytes += genDrawInfo(group, alpha_mask | extra_mask, sAlphaFaces[1], alpha_count[1], TRUE, batch_textures, TRUE);
+    geometryBytes += genDrawInfo(group, bump_mask | extra_mask, sBumpFaces[1], bump_count[1], FALSE, TRUE);
+    geometryBytes += genDrawInfo(group, norm_mask | extra_mask, sNormFaces[1], norm_count[1], FALSE, TRUE);
+    geometryBytes += genDrawInfo(group, spec_mask | extra_mask, sSpecFaces[1], spec_count[1], FALSE, TRUE);
+    geometryBytes += genDrawInfo(group, normspec_mask | extra_mask, sNormSpecFaces[1], normspec_count[1], FALSE, TRUE);
 
 	group->mGeometryBytes = geometryBytes;
 
@@ -6146,7 +6057,7 @@ struct CompareBatchBreakerModified
 		const LLTextureEntry* lte = lhs->getTextureEntry();
 		const LLTextureEntry* rte = rhs->getTextureEntry();
 
-		if (lte->getBumpmap() != rte->getBumpmap())
+        if (lte->getBumpmap() != rte->getBumpmap())
 		{
 			return lte->getBumpmap() < rte->getBumpmap();
 		}
@@ -6169,8 +6080,43 @@ struct CompareBatchBreakerModified
 	}
 };
 
+struct CompareBatchBreakerRigged
+{
+    bool operator()(const LLFace* const& lhs, const LLFace* const& rhs)
+    {
+        const LLTextureEntry* lte = lhs->getTextureEntry();
+        const LLTextureEntry* rte = rhs->getTextureEntry();
+
+        if (lhs->mAvatar != rhs->mAvatar)
+        {
+            return lhs->mAvatar < rhs->mAvatar;
+        }
+        else if (lhs->mSkinInfo->mHash != rhs->mSkinInfo->mHash)
+        {
+            return lhs->mSkinInfo->mHash < rhs->mSkinInfo->mHash;
+        }
+        else if (lhs->getTexture() != rhs->getTexture())
+        {
+            return lhs->getTexture() < rhs->getTexture();
+        }
+        else if (lte->getBumpmap() != rte->getBumpmap())
+        {
+            return lte->getBumpmap() < rte->getBumpmap();
+        }
+        else if (LLPipeline::sRenderDeferred && lte->getMaterialID() != rte->getMaterialID())
+        {
+            return lte->getMaterialID() < rte->getMaterialID();
+        }
+        else // if (LLPipeline::sRenderDeferred && (lte->getMaterialParams() == rte->getMaterialParams()) && (lte->getShiny() != rte->getShiny()))
+        {
+            return lte->getShiny() < rte->getShiny();
+        }
+        
+    }
+};
+
 
-U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace** faces, U32 face_count, BOOL distance_sort, BOOL batch_textures, BOOL no_materials)
+U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace** faces, U32 face_count, BOOL distance_sort, BOOL batch_textures, BOOL rigged)
 {
     LL_PROFILE_ZONE_SCOPED;
 
@@ -6205,11 +6151,17 @@ U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace
 
 	{
         LL_PROFILE_ZONE_NAMED("genDrawInfo - sort");
-		if (!distance_sort)
-		{
-			//sort faces by things that break batches
-			std::sort(faces, faces+face_count, CompareBatchBreakerModified());
-		}
+        
+        if (rigged)
+        {
+            //sort faces by things that break batches, including avatar and mesh id
+            std::sort(faces, faces + face_count, CompareBatchBreakerRigged());
+        }
+        else if (!distance_sort)
+        {
+            //sort faces by things that break batches, not including avatar and mesh id
+            std::sort(faces, faces + face_count, CompareBatchBreakerModified());
+        }
 		else
 		{
 			//sort faces by distance
@@ -6226,11 +6178,6 @@ U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace
 	LLViewerTexture* last_tex = NULL;
 	S32 buffer_index = 0;
 
-	if (distance_sort)
-	{
-		buffer_index = -1;
-	}
-
 	S32 texture_index_channels = 1;
 	
 	if (gGLManager.mGLSLVersionMajor > 1 || gGLManager.mGLSLVersionMinor >= 30)
@@ -6242,6 +6189,16 @@ U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace
 	{
 		texture_index_channels = gDeferredAlphaProgram.mFeatures.mIndexedTextureChannels;
 	}
+    
+    if (rigged)
+    { //don't attempt distance sorting on rigged meshes, not likely to succeed and breaks batches
+        distance_sort = FALSE;
+    }
+
+    if (distance_sort)
+    {
+        buffer_index = -1;
+    }
 
 	static LLCachedControl<U32> max_texture_index(gSavedSettings, "RenderMaxTextureIndex", 16);
 	texture_index_channels = llmin(texture_index_channels, (S32) max_texture_index);
@@ -6256,7 +6213,9 @@ U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace
 		//pull off next face
 		LLFace* facep = *face_iter;
 		LLViewerTexture* tex = facep->getTexture();
-		LLMaterialPtr mat = facep->getTextureEntry()->getMaterialParams();
+        const LLTextureEntry* te = facep->getTextureEntry();
+		LLMaterialPtr mat = te->getMaterialParams();
+        LLMaterialID matId = te->getMaterialID();
 
 		if (distance_sort)
 		{
@@ -6379,11 +6338,14 @@ U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace
 				while (i != end_faces && 
 					(LLPipeline::sTextureBindTest || 
 						(distance_sort || 
-							((*i)->getTexture() == tex &&
-							((*i)->getTextureEntry()->getMaterialParams() == mat)))))
+							((*i)->getTexture() == tex))))
 				{
 					facep = *i;
-			
+                    const LLTextureEntry* nextTe = facep->getTextureEntry();
+                    if (nextTe->getMaterialID() != matId)
+                    {
+                        break;
+                    }
 
 					//face has no texture index
 					facep->mDrawInfo = NULL;
@@ -6473,8 +6435,6 @@ U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace
 
 					U32 te_idx = facep->getTEOffset();
 
-					llassert(!facep->isState(LLFace::RIGGED));
-
 					if (!facep->getGeometryVolume(*volume, te_idx, 
 						vobj->getRelativeXform(), vobj->getRelativeXformInvTrans(), index_offset,true))
 					{
@@ -6571,10 +6531,6 @@ U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace
 						}
 					}
 				}
-				else if (no_materials)
-				{
-					registerFace(group, facep, LLRenderPass::PASS_SIMPLE);
-				}
 				else if (transparent)
 				{
 					registerFace(group, facep, LLRenderPass::PASS_ALPHA);
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index cb54b1eaed..4710fdb085 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -7408,32 +7408,91 @@ void LLPipeline::doResetVertexBuffers(bool forced)
 	LLVOPartGroup::restoreGL();
 }
 
-void LLPipeline::renderObjects(U32 type, U32 mask, bool texture, bool batch_texture)
+void LLPipeline::renderObjects(U32 type, U32 mask, bool texture, bool batch_texture, bool rigged)
 {
 	assertInitialized();
 	gGL.loadMatrix(gGLModelView);
 	gGLLastMatrix = NULL;
-	mSimplePool->pushBatches(type, mask, texture, batch_texture);
+    if (rigged)
+    {
+        mSimplePool->pushRiggedBatches(type + 1, mask, texture, batch_texture);
+    }
+    else
+    {
+        mSimplePool->pushBatches(type, mask, texture, batch_texture);
+    }
 	gGL.loadMatrix(gGLModelView);
 	gGLLastMatrix = NULL;		
 }
 
-void LLPipeline::renderMaskedObjects(U32 type, U32 mask, bool texture, bool batch_texture)
+void LLPipeline::renderAlphaObjects(U32 mask, bool texture, bool batch_texture, bool rigged)
+{
+    LL_PROFILE_ZONE_SCOPED;
+    assertInitialized();
+    gGL.loadMatrix(gGLModelView);
+    gGLLastMatrix = NULL;
+    U32 type = LLRenderPass::PASS_ALPHA;
+    LLVOAvatar* lastAvatar = nullptr;
+    U64 lastMeshId = 0;
+    for (LLCullResult::drawinfo_iterator i = gPipeline.beginRenderMap(type); i != gPipeline.endRenderMap(type); ++i)
+    {
+        LLDrawInfo* pparams = *i;
+        if (pparams)
+        {
+            if (rigged)
+            {
+                if (pparams->mAvatar != nullptr)
+                {
+                    if (lastAvatar != pparams->mAvatar || lastMeshId != pparams->mSkinInfo->mHash)
+                    {
+                        mSimplePool->uploadMatrixPalette(*pparams);
+                        lastAvatar = pparams->mAvatar;
+                        lastMeshId = pparams->mSkinInfo->mHash;
+                    }
+
+                    mSimplePool->pushBatch(*pparams, mask | LLVertexBuffer::MAP_WEIGHT4, texture, batch_texture);
+                }
+            }
+            else if (pparams->mAvatar == nullptr)
+            {
+                mSimplePool->pushBatch(*pparams, mask, texture, batch_texture);
+            }
+        }
+    }
+    gGL.loadMatrix(gGLModelView);
+    gGLLastMatrix = NULL;
+}
+
+void LLPipeline::renderMaskedObjects(U32 type, U32 mask, bool texture, bool batch_texture, bool rigged)
 {
 	assertInitialized();
 	gGL.loadMatrix(gGLModelView);
 	gGLLastMatrix = NULL;
-	mAlphaMaskPool->pushMaskBatches(type, mask, texture, batch_texture);
+    if (rigged)
+    {
+        mAlphaMaskPool->pushRiggedMaskBatches(type+1, mask, texture, batch_texture);
+    }
+    else
+    {
+        mAlphaMaskPool->pushMaskBatches(type, mask, texture, batch_texture);
+    }
 	gGL.loadMatrix(gGLModelView);
 	gGLLastMatrix = NULL;		
 }
 
-void LLPipeline::renderFullbrightMaskedObjects(U32 type, U32 mask, bool texture, bool batch_texture)
+void LLPipeline::renderFullbrightMaskedObjects(U32 type, U32 mask, bool texture, bool batch_texture, bool rigged)
 {
 	assertInitialized();
 	gGL.loadMatrix(gGLModelView);
 	gGLLastMatrix = NULL;
-	mFullbrightAlphaMaskPool->pushMaskBatches(type, mask, texture, batch_texture);
+    if (rigged)
+    {
+        mFullbrightAlphaMaskPool->pushRiggedMaskBatches(type+1, mask, texture, batch_texture);
+    }
+    else
+    {
+        mFullbrightAlphaMaskPool->pushMaskBatches(type, mask, texture, batch_texture);
+    }
 	gGL.loadMatrix(gGLModelView);
 	gGLLastMatrix = NULL;		
 }
@@ -9587,198 +9646,207 @@ static LLTrace::BlockTimerStatHandle FTM_SHADOW_ALPHA_TREE("Alpha Tree");
 static LLTrace::BlockTimerStatHandle FTM_SHADOW_ALPHA_GRASS("Alpha Grass");
 static LLTrace::BlockTimerStatHandle FTM_SHADOW_FULLBRIGHT_ALPHA_MASKED("Fullbright Alpha Masked");
 
-void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera& shadow_cam, LLCullResult &result, bool use_shader, bool use_occlusion, U32 target_width)
+void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera& shadow_cam, LLCullResult& result, bool use_shader, bool use_occlusion, U32 target_width)
 {
-	LL_RECORD_BLOCK_TIME(FTM_SHADOW_RENDER);
+    LL_RECORD_BLOCK_TIME(FTM_SHADOW_RENDER);
 
-	//clip out geometry on the same side of water as the camera
-	S32 occlude = LLPipeline::sUseOcclusion;
-	if (!use_occlusion)
-	{
-		LLPipeline::sUseOcclusion = 0;
-	}
-	LLPipeline::sShadowRender = true;
-	
-	static const U32 types[] = { 
-		LLRenderPass::PASS_SIMPLE, 
-		LLRenderPass::PASS_FULLBRIGHT, 
-		LLRenderPass::PASS_SHINY, 
-		LLRenderPass::PASS_BUMP, 
-		LLRenderPass::PASS_FULLBRIGHT_SHINY ,
-		LLRenderPass::PASS_MATERIAL,
-		LLRenderPass::PASS_MATERIAL_ALPHA_EMISSIVE,
-		LLRenderPass::PASS_SPECMAP,
-		LLRenderPass::PASS_SPECMAP_EMISSIVE,
-		LLRenderPass::PASS_NORMMAP,
-		LLRenderPass::PASS_NORMMAP_EMISSIVE,
-		LLRenderPass::PASS_NORMSPEC,
-		LLRenderPass::PASS_NORMSPEC_EMISSIVE,
-	};
+    //clip out geometry on the same side of water as the camera
+    S32 occlude = LLPipeline::sUseOcclusion;
+    if (!use_occlusion)
+    {
+        LLPipeline::sUseOcclusion = 0;
+    }
+    LLPipeline::sShadowRender = true;
+
+    static const U32 types[] = {
+        LLRenderPass::PASS_SIMPLE,
+        LLRenderPass::PASS_FULLBRIGHT,
+        LLRenderPass::PASS_SHINY,
+        LLRenderPass::PASS_BUMP,
+        LLRenderPass::PASS_FULLBRIGHT_SHINY ,
+        LLRenderPass::PASS_MATERIAL,
+        LLRenderPass::PASS_MATERIAL_ALPHA_EMISSIVE,
+        LLRenderPass::PASS_SPECMAP,
+        LLRenderPass::PASS_SPECMAP_EMISSIVE,
+        LLRenderPass::PASS_NORMMAP,
+        LLRenderPass::PASS_NORMMAP_EMISSIVE,
+        LLRenderPass::PASS_NORMSPEC,
+        LLRenderPass::PASS_NORMSPEC_EMISSIVE,
+    };
+
+    LLGLEnable cull(GL_CULL_FACE);
+
+    //enable depth clamping if available
+    LLGLEnable depth_clamp(gGLManager.mHasDepthClamp ? GL_DEPTH_CLAMP : 0);
+
+    if (use_shader)
+    {
+        gDeferredShadowCubeProgram.bind();
+    }
 
-	LLGLEnable cull(GL_CULL_FACE);
+    LLRenderTarget& occlusion_target = mShadowOcclusion[LLViewerCamera::sCurCameraID - 1];
 
-	//enable depth clamping if available
-	LLGLEnable depth_clamp(gGLManager.mHasDepthClamp ? GL_DEPTH_CLAMP : 0);
+    occlusion_target.bindTarget();
+    updateCull(shadow_cam, result);
+    occlusion_target.flush();
 
-	if (use_shader)
-	{
-		gDeferredShadowCubeProgram.bind();
-	}
+    stateSort(shadow_cam, result);
 
-	LLRenderTarget& occlusion_target = mShadowOcclusion[LLViewerCamera::sCurCameraID-1];
 
-	occlusion_target.bindTarget();
-	updateCull(shadow_cam, result);
-	occlusion_target.flush();
+    //generate shadow map
+    gGL.matrixMode(LLRender::MM_PROJECTION);
+    gGL.pushMatrix();
+    gGL.loadMatrix(proj.m);
+    gGL.matrixMode(LLRender::MM_MODELVIEW);
+    gGL.pushMatrix();
+    gGL.loadMatrix(view.m);
 
-	stateSort(shadow_cam, result);
-	
-	
-	//generate shadow map
-	gGL.matrixMode(LLRender::MM_PROJECTION);
-	gGL.pushMatrix();
-	gGL.loadMatrix(proj.m);
-	gGL.matrixMode(LLRender::MM_MODELVIEW);
-	gGL.pushMatrix();
-	gGL.loadMatrix(view.m);
+    stop_glerror();
+    gGLLastMatrix = NULL;
 
-	stop_glerror();
-	gGLLastMatrix = NULL;
+    gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+
+    stop_glerror();
 
-	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
-	
-	stop_glerror();
-	
     LLEnvironment& environment = LLEnvironment::instance();
 
-	LLVertexBuffer::unbind();
+    LLVertexBuffer::unbind();
 
-	{
-		if (!use_shader)
-		{ //occlusion program is general purpose depth-only no-textures
-			gOcclusionProgram.bind();
-		}
-		else
-		{
-			gDeferredShadowProgram.bind();
-            gDeferredShadowProgram.uniform1i(LLShaderMgr::SUN_UP_FACTOR, environment.getIsSunUp() ? 1 : 0);
-		}
+    for (int j = 0; j < 2; ++j) // 0 -- static, 1 -- rigged
+    {
+        bool rigged = j == 1;
+        if (!use_shader)
+        { //occlusion program is general purpose depth-only no-textures
+            gOcclusionProgram.bind(rigged);
+        }
+        else
+        {
+            gDeferredShadowProgram.bind(rigged);
+            LLGLSLShader::sCurBoundShaderPtr->uniform1i(LLShaderMgr::SUN_UP_FACTOR, environment.getIsSunUp() ? 1 : 0);
+        }
 
-		gGL.diffuseColor4f(1,1,1,1);
+        gGL.diffuseColor4f(1, 1, 1, 1);
 
         S32 shadow_detail = gSavedSettings.getS32("RenderShadowDetail");
 
         // if not using VSM, disable color writes
         if (shadow_detail <= 2)
         {
-		gGL.setColorMask(false, false);
+            gGL.setColorMask(false, false);
         }
-	
-		LL_RECORD_BLOCK_TIME(FTM_SHADOW_SIMPLE);
-		
-		gGL.getTexUnit(0)->disable();
-		for (U32 i = 0; i < sizeof(types)/sizeof(U32); ++i)
-		{
-			renderObjects(types[i], LLVertexBuffer::MAP_VERTEX, FALSE);
-		}
-		gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE);
-		if (!use_shader)
-		{
-			gOcclusionProgram.unbind();
-		}
-	}
-	
-	if (use_shader)
-	{
+
+        LL_RECORD_BLOCK_TIME(FTM_SHADOW_SIMPLE);
+
+        gGL.getTexUnit(0)->disable();
+        for (U32 i = 0; i < sizeof(types) / sizeof(U32); ++i)
+        {
+            renderObjects(types[i], LLVertexBuffer::MAP_VERTEX, FALSE, FALSE, rigged);
+        }
+        gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE);
+        if (!use_shader)
+        {
+            gOcclusionProgram.unbind();
+        }
+
+
+    }
+
+    if (use_shader)
+    {
         LL_RECORD_BLOCK_TIME(FTM_SHADOW_GEOM);
 
-		gDeferredShadowProgram.unbind();
-		renderGeomShadow(shadow_cam);
-		gDeferredShadowProgram.bind();
+        gDeferredShadowProgram.unbind();
+        renderGeomShadow(shadow_cam);
+        gDeferredShadowProgram.bind();
         gDeferredShadowProgram.uniform1i(LLShaderMgr::SUN_UP_FACTOR, environment.getIsSunUp() ? 1 : 0);
-	}
-	else
-	{
+    }
+    else
+    {
         LL_RECORD_BLOCK_TIME(FTM_SHADOW_GEOM);
 
-		renderGeomShadow(shadow_cam);
-	}
+        renderGeomShadow(shadow_cam);
+    }
 
-	{
-		LL_RECORD_BLOCK_TIME(FTM_SHADOW_ALPHA);
+    {
+        LL_RECORD_BLOCK_TIME(FTM_SHADOW_ALPHA);
 
-		gDeferredShadowAlphaMaskProgram.bind();
-		gDeferredShadowAlphaMaskProgram.uniform1f(LLShaderMgr::DEFERRED_SHADOW_TARGET_WIDTH, (float)target_width);
-        gDeferredShadowAlphaMaskProgram.uniform1i(LLShaderMgr::SUN_UP_FACTOR, environment.getIsSunUp() ? 1 : 0);
+        for (int i = 0; i < 2; ++i)
+        {
+            bool rigged = i == 1;
 
-		U32 mask =	LLVertexBuffer::MAP_VERTEX | 
-					LLVertexBuffer::MAP_TEXCOORD0 | 
-					LLVertexBuffer::MAP_COLOR | 
-					LLVertexBuffer::MAP_TEXTURE_INDEX;
+            gDeferredShadowAlphaMaskProgram.bind(rigged);
+            LLGLSLShader::sCurBoundShaderPtr->uniform1f(LLShaderMgr::DEFERRED_SHADOW_TARGET_WIDTH, (float)target_width);
+            LLGLSLShader::sCurBoundShaderPtr->uniform1i(LLShaderMgr::SUN_UP_FACTOR, environment.getIsSunUp() ? 1 : 0);
 
-        {
-            LL_RECORD_BLOCK_TIME(FTM_SHADOW_ALPHA_MASKED);
-		renderMaskedObjects(LLRenderPass::PASS_ALPHA_MASK, mask, TRUE, TRUE);
-        }
+            U32 mask = LLVertexBuffer::MAP_VERTEX |
+                LLVertexBuffer::MAP_TEXCOORD0 |
+                LLVertexBuffer::MAP_COLOR |
+                LLVertexBuffer::MAP_TEXTURE_INDEX;
 
-        {
-            LL_RECORD_BLOCK_TIME(FTM_SHADOW_ALPHA_BLEND);
-		gDeferredShadowAlphaMaskProgram.setMinimumAlpha(0.598f);
-		renderObjects(LLRenderPass::PASS_ALPHA, mask, TRUE, TRUE);
-        }
+            {
+                LL_RECORD_BLOCK_TIME(FTM_SHADOW_ALPHA_MASKED);
+                renderMaskedObjects(LLRenderPass::PASS_ALPHA_MASK, mask, TRUE, TRUE, rigged);
+            }
 
-        {
-            LL_RECORD_BLOCK_TIME(FTM_SHADOW_FULLBRIGHT_ALPHA_MASKED);
-            gDeferredShadowFullbrightAlphaMaskProgram.bind();
-            gDeferredShadowFullbrightAlphaMaskProgram.uniform1f(LLShaderMgr::DEFERRED_SHADOW_TARGET_WIDTH, (float)target_width);
-            gDeferredShadowFullbrightAlphaMaskProgram.uniform1i(LLShaderMgr::SUN_UP_FACTOR, environment.getIsSunUp() ? 1 : 0);
-            renderFullbrightMaskedObjects(LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK, mask, TRUE, TRUE);
-        }
+            {
+                LL_RECORD_BLOCK_TIME(FTM_SHADOW_ALPHA_BLEND);
+                LLGLSLShader::sCurBoundShaderPtr->setMinimumAlpha(0.598f);
+                renderAlphaObjects(mask, TRUE, TRUE, rigged);
+            }
 
-		mask = mask & ~LLVertexBuffer::MAP_TEXTURE_INDEX;
 
-        {
-            LL_RECORD_BLOCK_TIME(FTM_SHADOW_ALPHA_TREE);
-		gDeferredTreeShadowProgram.bind();
-            gDeferredTreeShadowProgram.uniform1i(LLShaderMgr::SUN_UP_FACTOR, environment.getIsSunUp() ? 1 : 0);
-		renderMaskedObjects(LLRenderPass::PASS_NORMSPEC_MASK, mask);
-		renderMaskedObjects(LLRenderPass::PASS_MATERIAL_ALPHA_MASK, mask);
-		renderMaskedObjects(LLRenderPass::PASS_SPECMAP_MASK, mask);
-		renderMaskedObjects(LLRenderPass::PASS_NORMMAP_MASK, mask);
+            {
+                LL_RECORD_BLOCK_TIME(FTM_SHADOW_FULLBRIGHT_ALPHA_MASKED);
+                gDeferredShadowFullbrightAlphaMaskProgram.bind(rigged);
+                LLGLSLShader::sCurBoundShaderPtr->uniform1f(LLShaderMgr::DEFERRED_SHADOW_TARGET_WIDTH, (float)target_width);
+                LLGLSLShader::sCurBoundShaderPtr->uniform1i(LLShaderMgr::SUN_UP_FACTOR, environment.getIsSunUp() ? 1 : 0);
+                renderFullbrightMaskedObjects(LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK, mask, TRUE, TRUE, rigged);
+            }
+
+
+            {
+                LL_RECORD_BLOCK_TIME(FTM_SHADOW_ALPHA_GRASS);
+                gDeferredTreeShadowProgram.bind(rigged);
+                if (i == 0)
+                {
+                    LLGLSLShader::sCurBoundShaderPtr->setMinimumAlpha(0.598f);
+                    renderObjects(LLRenderPass::PASS_GRASS, LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0, TRUE);
+                }
+
+                U32 no_idx_mask = mask & ~LLVertexBuffer::MAP_TEXTURE_INDEX;
+                renderMaskedObjects(LLRenderPass::PASS_NORMSPEC_MASK, no_idx_mask, true, false, rigged);
+                renderMaskedObjects(LLRenderPass::PASS_MATERIAL_ALPHA_MASK, no_idx_mask, true, false, rigged);
+                renderMaskedObjects(LLRenderPass::PASS_SPECMAP_MASK, no_idx_mask, true, false, rigged);
+                renderMaskedObjects(LLRenderPass::PASS_NORMMAP_MASK, no_idx_mask, true, false, rigged);
+            }
         }
-		
-        {
-            LL_RECORD_BLOCK_TIME(FTM_SHADOW_ALPHA_GRASS);
-		gDeferredTreeShadowProgram.setMinimumAlpha(0.598f);
-		renderObjects(LLRenderPass::PASS_GRASS, LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0, TRUE);
-	}
     }
 
-	//glCullFace(GL_BACK);
+    //glCullFace(GL_BACK);
 
-	gDeferredShadowCubeProgram.bind();
-	gGLLastMatrix = NULL;
-	gGL.loadMatrix(gGLModelView);
+    gDeferredShadowCubeProgram.bind();
+    gGLLastMatrix = NULL;
+    gGL.loadMatrix(gGLModelView);
 
-	LLRenderTarget& occlusion_source = mShadow[LLViewerCamera::sCurCameraID-1];
+    LLRenderTarget& occlusion_source = mShadow[LLViewerCamera::sCurCameraID - 1];
 
-	doOcclusion(shadow_cam, occlusion_source, occlusion_target);
+    doOcclusion(shadow_cam, occlusion_source, occlusion_target);
 
-	if (use_shader)
-	{
-		gDeferredShadowProgram.unbind();
-	}
-	
-	gGL.setColorMask(true, true);
-			
-	gGL.matrixMode(LLRender::MM_PROJECTION);
-	gGL.popMatrix();
-	gGL.matrixMode(LLRender::MM_MODELVIEW);
-	gGL.popMatrix();
-	gGLLastMatrix = NULL;
+    if (use_shader)
+    {
+        gDeferredShadowProgram.unbind();
+    }
 
-	LLPipeline::sUseOcclusion = occlude;
-	LLPipeline::sShadowRender = false;
+    gGL.setColorMask(true, true);
+
+    gGL.matrixMode(LLRender::MM_PROJECTION);
+    gGL.popMatrix();
+    gGL.matrixMode(LLRender::MM_MODELVIEW);
+    gGL.popMatrix();
+    gGLLastMatrix = NULL;
+
+    LLPipeline::sUseOcclusion = occlude;
+    LLPipeline::sShadowRender = false;
 }
 
 bool LLPipeline::getVisiblePointCloud(LLCamera& camera, LLVector3& min, LLVector3& max, std::vector<LLVector3>& fp, LLVector3 light_dir)
@@ -10109,6 +10177,29 @@ void LLPipeline::generateSunShadow(LLCamera& camera)
 					LLPipeline::RENDER_TYPE_PASS_NORMSPEC_BLEND,
 					LLPipeline::RENDER_TYPE_PASS_NORMSPEC_MASK,
 					LLPipeline::RENDER_TYPE_PASS_NORMSPEC_EMISSIVE,
+                    LLPipeline::RENDER_TYPE_PASS_ALPHA_MASK_RIGGED,
+                    LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_ALPHA_MASK_RIGGED,
+                    LLPipeline::RENDER_TYPE_PASS_SIMPLE_RIGGED,
+                    LLPipeline::RENDER_TYPE_PASS_BUMP_RIGGED,
+                    LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_RIGGED,
+                    LLPipeline::RENDER_TYPE_PASS_SHINY_RIGGED,
+                    LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_SHINY_RIGGED,
+                    LLPipeline::RENDER_TYPE_PASS_MATERIAL_RIGGED,
+                    LLPipeline::RENDER_TYPE_PASS_MATERIAL_ALPHA_RIGGED,
+                    LLPipeline::RENDER_TYPE_PASS_MATERIAL_ALPHA_MASK_RIGGED,
+                    LLPipeline::RENDER_TYPE_PASS_MATERIAL_ALPHA_EMISSIVE_RIGGED,
+                    LLPipeline::RENDER_TYPE_PASS_SPECMAP_RIGGED,
+                    LLPipeline::RENDER_TYPE_PASS_SPECMAP_BLEND_RIGGED,
+                    LLPipeline::RENDER_TYPE_PASS_SPECMAP_MASK_RIGGED,
+                    LLPipeline::RENDER_TYPE_PASS_SPECMAP_EMISSIVE_RIGGED,
+                    LLPipeline::RENDER_TYPE_PASS_NORMMAP_RIGGED,
+                    LLPipeline::RENDER_TYPE_PASS_NORMMAP_BLEND_RIGGED,
+                    LLPipeline::RENDER_TYPE_PASS_NORMMAP_MASK_RIGGED,
+                    LLPipeline::RENDER_TYPE_PASS_NORMMAP_EMISSIVE_RIGGED,
+                    LLPipeline::RENDER_TYPE_PASS_NORMSPEC_RIGGED,
+                    LLPipeline::RENDER_TYPE_PASS_NORMSPEC_BLEND_RIGGED,
+                    LLPipeline::RENDER_TYPE_PASS_NORMSPEC_MASK_RIGGED,
+                    LLPipeline::RENDER_TYPE_PASS_NORMSPEC_EMISSIVE_RIGGED,
 					END_RENDER_TYPES);
 
 	gGL.setColorMask(false, false);
@@ -10835,6 +10926,21 @@ void LLPipeline::renderGroups(LLRenderPass* pass, U32 type, U32 mask, bool textu
 	}
 }
 
+void LLPipeline::renderRiggedGroups(LLRenderPass* pass, U32 type, U32 mask, bool texture)
+{
+    for (LLCullResult::sg_iterator i = sCull->beginVisibleGroups(); i != sCull->endVisibleGroups(); ++i)
+    {
+        LLSpatialGroup* group = *i;
+        if (!group->isDead() &&
+            (!sUseOcclusion || !group->isOcclusionState(LLSpatialGroup::OCCLUDED)) &&
+            gPipeline.hasRenderType(group->getSpatialPartition()->mDrawableType) &&
+            group->mDrawMap.find(type) != group->mDrawMap.end())
+        {
+            pass->renderRiggedGroup(group, type, mask, texture);
+        }
+    }
+}
+
 static LLTrace::BlockTimerStatHandle FTM_GENERATE_IMPOSTOR("Generate Impostor");
 
 void LLPipeline::generateImpostor(LLVOAvatar* avatar)
@@ -10870,37 +10976,31 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar)
 	
 	if (visually_muted || too_complex)
 	{
+        // only show jelly doll geometry
 		andRenderTypeMask(LLPipeline::RENDER_TYPE_AVATAR,
 							LLPipeline::RENDER_TYPE_CONTROL_AV,
 							END_RENDER_TYPES);
 	}
 	else
 	{
-		andRenderTypeMask(LLPipeline::RENDER_TYPE_ALPHA,
-			LLPipeline::RENDER_TYPE_FULLBRIGHT,
-			LLPipeline::RENDER_TYPE_VOLUME,
-			LLPipeline::RENDER_TYPE_GLOW,
-						LLPipeline::RENDER_TYPE_BUMP,
-						LLPipeline::RENDER_TYPE_PASS_SIMPLE,
-						LLPipeline::RENDER_TYPE_PASS_ALPHA,
-						LLPipeline::RENDER_TYPE_PASS_ALPHA_MASK,
-			LLPipeline::RENDER_TYPE_PASS_BUMP,
-			LLPipeline::RENDER_TYPE_PASS_POST_BUMP,
-						LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT,
-						LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_ALPHA_MASK,
-						LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_SHINY,
-			LLPipeline::RENDER_TYPE_PASS_GLOW,
-			LLPipeline::RENDER_TYPE_PASS_GRASS,
-						LLPipeline::RENDER_TYPE_PASS_SHINY,
-						LLPipeline::RENDER_TYPE_PASS_INVISIBLE,
-						LLPipeline::RENDER_TYPE_PASS_INVISI_SHINY,
-			LLPipeline::RENDER_TYPE_AVATAR,
-			LLPipeline::RENDER_TYPE_CONTROL_AV,
-			LLPipeline::RENDER_TYPE_ALPHA_MASK,
-			LLPipeline::RENDER_TYPE_FULLBRIGHT_ALPHA_MASK,
-			LLPipeline::RENDER_TYPE_INVISIBLE,
-			LLPipeline::RENDER_TYPE_SIMPLE,
-						END_RENDER_TYPES);
+        //hide world geometry
+        clearRenderTypeMask(
+            RENDER_TYPE_SKY,
+            RENDER_TYPE_WL_SKY,
+            RENDER_TYPE_GROUND,
+            RENDER_TYPE_TERRAIN,
+            RENDER_TYPE_GRASS,
+            RENDER_TYPE_CONTROL_AV, // Animesh
+            RENDER_TYPE_TREE,
+            RENDER_TYPE_VOIDWATER,
+            RENDER_TYPE_WATER,
+            RENDER_TYPE_PASS_GRASS,
+            RENDER_TYPE_HUD,
+            RENDER_TYPE_PARTICLES,
+            RENDER_TYPE_CLOUDS,
+            RENDER_TYPE_HUD_PARTICLES,
+            END_RENDER_TYPES
+         );
 	}
 	
 	S32 occlusion = sUseOcclusion;
diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h
index b87a726647..110df8c979 100644
--- a/indra/newview/pipeline.h
+++ b/indra/newview/pipeline.h
@@ -266,11 +266,13 @@ public:
     void touchTextures(LLDrawInfo* info);
 	void forAllVisibleDrawables(void (*func)(LLDrawable*));
 
-	void renderObjects(U32 type, U32 mask, bool texture = true, bool batch_texture = false);
-	void renderMaskedObjects(U32 type, U32 mask, bool texture = true, bool batch_texture = false);
-    void renderFullbrightMaskedObjects(U32 type, U32 mask, bool texture = true, bool batch_texture = false);
+    void renderObjects(U32 type, U32 mask, bool texture = true, bool batch_texture = false, bool rigged = false);
+    void renderAlphaObjects(U32 mask, bool texture = true, bool batch_texture = false, bool rigged = false);
+	void renderMaskedObjects(U32 type, U32 mask, bool texture = true, bool batch_texture = false, bool rigged = false);
+    void renderFullbrightMaskedObjects(U32 type, U32 mask, bool texture = true, bool batch_texture = false, bool rigged = false);
 
 	void renderGroups(LLRenderPass* pass, U32 type, U32 mask, bool texture);
+    void renderRiggedGroups(LLRenderPass* pass, U32 type, U32 mask, bool texture);
 
 	void grabReferences(LLCullResult& result);
 	void clearReferences();
@@ -457,34 +459,61 @@ public:
  		RENDER_TYPE_ALPHA						= LLDrawPool::POOL_ALPHA,
 		RENDER_TYPE_GLOW						= LLDrawPool::POOL_GLOW,
 		RENDER_TYPE_PASS_SIMPLE 				= LLRenderPass::PASS_SIMPLE,
+        RENDER_TYPE_PASS_SIMPLE_RIGGED = LLRenderPass::PASS_SIMPLE_RIGGED,
 		RENDER_TYPE_PASS_GRASS					= LLRenderPass::PASS_GRASS,
 		RENDER_TYPE_PASS_FULLBRIGHT				= LLRenderPass::PASS_FULLBRIGHT,
+        RENDER_TYPE_PASS_FULLBRIGHT_RIGGED = LLRenderPass::PASS_FULLBRIGHT,
 		RENDER_TYPE_PASS_INVISIBLE				= LLRenderPass::PASS_INVISIBLE,
+        RENDER_TYPE_PASS_INVISIBLE_RIGGED = LLRenderPass::PASS_INVISIBLE_RIGGED,
 		RENDER_TYPE_PASS_INVISI_SHINY			= LLRenderPass::PASS_INVISI_SHINY,
+        RENDER_TYPE_PASS_INVISI_SHINY_RIGGED = LLRenderPass::PASS_INVISI_SHINY_RIGGED,
 		RENDER_TYPE_PASS_FULLBRIGHT_SHINY		= LLRenderPass::PASS_FULLBRIGHT_SHINY,
+        RENDER_TYPE_PASS_FULLBRIGHT_SHINY_RIGGED = LLRenderPass::PASS_FULLBRIGHT_SHINY_RIGGED,
 		RENDER_TYPE_PASS_SHINY					= LLRenderPass::PASS_SHINY,
+        RENDER_TYPE_PASS_SHINY_RIGGED = LLRenderPass::PASS_SHINY_RIGGED,
 		RENDER_TYPE_PASS_BUMP					= LLRenderPass::PASS_BUMP,
+        RENDER_TYPE_PASS_BUMP_RIGGED = LLRenderPass::PASS_BUMP_RIGGED,
 		RENDER_TYPE_PASS_POST_BUMP				= LLRenderPass::PASS_POST_BUMP,
+        RENDER_TYPE_PASS_POST_BUMP_RIGGED = LLRenderPass::PASS_POST_BUMP_RIGGED,
 		RENDER_TYPE_PASS_GLOW					= LLRenderPass::PASS_GLOW,
+        RENDER_TYPE_PASS_GLOW_RIGGED = LLRenderPass::PASS_GLOW_RIGGED,
 		RENDER_TYPE_PASS_ALPHA					= LLRenderPass::PASS_ALPHA,
 		RENDER_TYPE_PASS_ALPHA_MASK				= LLRenderPass::PASS_ALPHA_MASK,
+        RENDER_TYPE_PASS_ALPHA_MASK_RIGGED = LLRenderPass::PASS_ALPHA_MASK_RIGGED,
 		RENDER_TYPE_PASS_FULLBRIGHT_ALPHA_MASK	= LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK,
+        RENDER_TYPE_PASS_FULLBRIGHT_ALPHA_MASK_RIGGED = LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK_RIGGED,
 		RENDER_TYPE_PASS_MATERIAL				= LLRenderPass::PASS_MATERIAL,
+        RENDER_TYPE_PASS_MATERIAL_RIGGED = LLRenderPass::PASS_MATERIAL_RIGGED,
 		RENDER_TYPE_PASS_MATERIAL_ALPHA			= LLRenderPass::PASS_MATERIAL_ALPHA,
+        RENDER_TYPE_PASS_MATERIAL_ALPHA_RIGGED = LLRenderPass::PASS_MATERIAL_ALPHA_RIGGED,
 		RENDER_TYPE_PASS_MATERIAL_ALPHA_MASK	= LLRenderPass::PASS_MATERIAL_ALPHA_MASK,
+        RENDER_TYPE_PASS_MATERIAL_ALPHA_MASK_RIGGED = LLRenderPass::PASS_MATERIAL_ALPHA_MASK_RIGGED,
 		RENDER_TYPE_PASS_MATERIAL_ALPHA_EMISSIVE= LLRenderPass::PASS_MATERIAL_ALPHA_EMISSIVE,
+        RENDER_TYPE_PASS_MATERIAL_ALPHA_EMISSIVE_RIGGED = LLRenderPass::PASS_MATERIAL_ALPHA_EMISSIVE_RIGGED,
 		RENDER_TYPE_PASS_SPECMAP				= LLRenderPass::PASS_SPECMAP,
+        RENDER_TYPE_PASS_SPECMAP_RIGGED = LLRenderPass::PASS_SPECMAP_RIGGED,
 		RENDER_TYPE_PASS_SPECMAP_BLEND			= LLRenderPass::PASS_SPECMAP_BLEND,
+        RENDER_TYPE_PASS_SPECMAP_BLEND_RIGGED = LLRenderPass::PASS_SPECMAP_BLEND_RIGGED,
 		RENDER_TYPE_PASS_SPECMAP_MASK			= LLRenderPass::PASS_SPECMAP_MASK,
+        RENDER_TYPE_PASS_SPECMAP_MASK_RIGGED = LLRenderPass::PASS_SPECMAP_MASK_RIGGED,
 		RENDER_TYPE_PASS_SPECMAP_EMISSIVE		= LLRenderPass::PASS_SPECMAP_EMISSIVE,
+        RENDER_TYPE_PASS_SPECMAP_EMISSIVE_RIGGED = LLRenderPass::PASS_SPECMAP_EMISSIVE_RIGGED,
 		RENDER_TYPE_PASS_NORMMAP				= LLRenderPass::PASS_NORMMAP,
+        RENDER_TYPE_PASS_NORMMAP_RIGGED = LLRenderPass::PASS_NORMMAP_RIGGED,
 		RENDER_TYPE_PASS_NORMMAP_BLEND			= LLRenderPass::PASS_NORMMAP_BLEND,
+        RENDER_TYPE_PASS_NORMMAP_BLEND_RIGGED = LLRenderPass::PASS_NORMMAP_BLEND_RIGGED,
 		RENDER_TYPE_PASS_NORMMAP_MASK			= LLRenderPass::PASS_NORMMAP_MASK,
+        RENDER_TYPE_PASS_NORMMAP_MASK_RIGGED = LLRenderPass::PASS_NORMMAP_MASK_RIGGED,
 		RENDER_TYPE_PASS_NORMMAP_EMISSIVE		= LLRenderPass::PASS_NORMMAP_EMISSIVE,
+        RENDER_TYPE_PASS_NORMMAP_EMISSIVE_RIGGED = LLRenderPass::PASS_NORMMAP_EMISSIVE_RIGGED,
 		RENDER_TYPE_PASS_NORMSPEC				= LLRenderPass::PASS_NORMSPEC,
+        RENDER_TYPE_PASS_NORMSPEC_RIGGED = LLRenderPass::PASS_NORMSPEC_RIGGED,
 		RENDER_TYPE_PASS_NORMSPEC_BLEND			= LLRenderPass::PASS_NORMSPEC_BLEND,
+        RENDER_TYPE_PASS_NORMSPEC_BLEND_RIGGED = LLRenderPass::PASS_NORMSPEC_BLEND_RIGGED,
 		RENDER_TYPE_PASS_NORMSPEC_MASK			= LLRenderPass::PASS_NORMSPEC_MASK,
+        RENDER_TYPE_PASS_NORMSPEC_MASK_RIGGED = LLRenderPass::PASS_NORMSPEC_MASK_RIGGED,
 		RENDER_TYPE_PASS_NORMSPEC_EMISSIVE		= LLRenderPass::PASS_NORMSPEC_EMISSIVE,
+        RENDER_TYPE_PASS_NORMSPEC_EMISSIVE_RIGGED = LLRenderPass::PASS_NORMSPEC_EMISSIVE_RIGGED,
 		// Following are object types (only used in drawable mRenderType)
 		RENDER_TYPE_HUD = LLRenderPass::NUM_RENDER_TYPES,
 		RENDER_TYPE_VOLUME,
-- 
cgit v1.2.3


From 40f2e70875db857c70b08369410046da6d873967 Mon Sep 17 00:00:00 2001
From: Mnikolenko ProductEngine <mnikolenko@productengine.com>
Date: Mon, 22 Nov 2021 16:01:19 +0200
Subject: mac build fix

---
 indra/newview/lldrawpoolbump.h   | 30 +++++++++++++++---------------
 indra/newview/lldrawpoolsimple.h |  2 +-
 indra/newview/llvovolume.cpp     | 28 ----------------------------
 3 files changed, 16 insertions(+), 44 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/lldrawpoolbump.h b/indra/newview/lldrawpoolbump.h
index d76e925eb0..624dbe3034 100644
--- a/indra/newview/lldrawpoolbump.h
+++ b/indra/newview/lldrawpoolbump.h
@@ -48,19 +48,19 @@ public:
 	static U32 sVertexMask;
 	BOOL mShiny;
 	
-	virtual U32 getVertexDataMask() { return sVertexMask; }
+	virtual U32 getVertexDataMask() override { return sVertexMask; }
 
 	LLDrawPoolBump();
 
-	virtual void render(S32 pass = 0);
-	virtual void beginRenderPass( S32 pass );
-	virtual void endRenderPass( S32 pass );
-	virtual S32	 getNumPasses();
-	/*virtual*/ void prerender();
+	virtual void render(S32 pass = 0) override;
+	virtual void beginRenderPass( S32 pass ) override;
+	virtual void endRenderPass( S32 pass ) override;
+	virtual S32	 getNumPasses() override;
+	/*virtual*/ void prerender() override;
 	void pushBatch(LLDrawInfo& params, U32 mask, BOOL texture, BOOL batch_textures = FALSE) override;
 
 	void renderBump(U32 type, U32 mask);
-	void renderGroup(LLSpatialGroup* group, U32 type, U32 mask, BOOL texture);
+	void renderGroup(LLSpatialGroup* group, U32 type, U32 mask, BOOL texture) override;
 		
 	S32 numBumpPasses();
 	
@@ -79,15 +79,15 @@ public:
 	static void bindCubeMap(LLGLSLShader* shader, S32 shader_level, S32& diffuse_channel, S32& cube_channel, bool invisible);
 	static void unbindCubeMap(LLGLSLShader* shader, S32 shader_level, S32& diffuse_channel, S32& cube_channel, bool invisible);
 
-	virtual S32 getNumDeferredPasses();
-	/*virtual*/ void beginDeferredPass(S32 pass);
-	/*virtual*/ void endDeferredPass(S32 pass);
-	/*virtual*/ void renderDeferred(S32 pass);
+	virtual S32 getNumDeferredPasses() override;
+	/*virtual*/ void beginDeferredPass(S32 pass) override;
+	/*virtual*/ void endDeferredPass(S32 pass) override;
+	/*virtual*/ void renderDeferred(S32 pass) override;
 
-	virtual S32 getNumPostDeferredPasses() { return 4; }
-	/*virtual*/ void beginPostDeferredPass(S32 pass);
-	/*virtual*/ void endPostDeferredPass(S32 pass);
-	/*virtual*/ void renderPostDeferred(S32 pass);
+    virtual S32 getNumPostDeferredPasses() override { return 4; }
+	/*virtual*/ void beginPostDeferredPass(S32 pass) override;
+	/*virtual*/ void endPostDeferredPass(S32 pass) override;
+	/*virtual*/ void renderPostDeferred(S32 pass) override;
 
 	static BOOL bindBumpMap(LLDrawInfo& params, S32 channel = -2);
 	static BOOL bindBumpMap(LLFace* face, S32 channel = -2);
diff --git a/indra/newview/lldrawpoolsimple.h b/indra/newview/lldrawpoolsimple.h
index 9ef9ea910d..d6fecdd23c 100644
--- a/indra/newview/lldrawpoolsimple.h
+++ b/indra/newview/lldrawpoolsimple.h
@@ -41,7 +41,7 @@ public:
 							LLVertexBuffer::MAP_TEXCOORD0 |
 							LLVertexBuffer::MAP_COLOR
 	};
-	virtual U32 getVertexDataMask() { return VERTEX_DATA_MASK; }
+	virtual U32 getVertexDataMask() override { return VERTEX_DATA_MASK; }
 
 	LLDrawPoolSimple();
 	
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index f4f9154fed..6c3f026087 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -5341,34 +5341,6 @@ void LLVolumeGeometryManager::getGeometry(LLSpatialGroup* group)
 
 }
 
-static LLDrawPoolAvatar* get_avatar_drawpool(LLViewerObject* vobj)
-{
-	LLVOAvatar* avatar = vobj->getAvatar();
-					
-	if (avatar)
-	{
-		LLDrawable* drawable = avatar->mDrawable;
-		if (drawable && drawable->getNumFaces() > 0)
-		{
-			LLFace* face = drawable->getFace(0);
-			if (face)
-			{
-				LLDrawPool* drawpool = face->getPool();
-				if (drawpool)
-				{
-					if (drawpool->getType() == LLDrawPool::POOL_AVATAR
-						|| drawpool->getType() == LLDrawPool::POOL_CONTROL_AV)
-					{
-						return (LLDrawPoolAvatar*) drawpool;
-					}
-				}
-			}
-		}
-	}
-
-	return NULL;
-}
-
 void handleRenderAutoMuteByteLimitChanged(const LLSD& new_value)
 {
 	static LLCachedControl<U32> render_auto_mute_byte_limit(gSavedSettings, "RenderAutoMuteByteLimit", 0U);
-- 
cgit v1.2.3


From cc34e26ef7e74845e4af9e5c5d450c0b12a268e0 Mon Sep 17 00:00:00 2001
From: Runitai Linden <davep@lindenlab.com>
Date: Mon, 22 Nov 2021 11:51:03 -0600
Subject: SL-16094 Add WorkQueue profile hooks

---
 indra/llcommon/workqueue.cpp | 2 ++
 indra/llcommon/workqueue.h   | 3 +++
 2 files changed, 5 insertions(+)

(limited to 'indra')

diff --git a/indra/llcommon/workqueue.cpp b/indra/llcommon/workqueue.cpp
index 633594ceea..fbdbea2051 100644
--- a/indra/llcommon/workqueue.cpp
+++ b/indra/llcommon/workqueue.cpp
@@ -60,6 +60,7 @@ void LL::WorkQueue::runUntilClose()
     {
         for (;;)
         {
+            LL_PROFILE_ZONE_SCOPED;
             callWork(mQueue.pop());
         }
     }
@@ -90,6 +91,7 @@ bool LL::WorkQueue::runOne()
 
 bool LL::WorkQueue::runUntil(const TimePoint& until)
 {
+    LL_PROFILE_ZONE_SCOPED;
     // Should we subtract some slop to allow for typical Work execution time?
     // How much slop?
     Work work;
diff --git a/indra/llcommon/workqueue.h b/indra/llcommon/workqueue.h
index c25d787425..96574a18b9 100644
--- a/indra/llcommon/workqueue.h
+++ b/indra/llcommon/workqueue.h
@@ -260,6 +260,7 @@ namespace LL
         template <typename Rep, typename Period>
         bool runFor(const std::chrono::duration<Rep, Period>& timeslice)
         {
+            LL_PROFILE_ZONE_SCOPED;
             return runUntil(TimePoint::clock::now() + timeslice);
         }
 
@@ -431,6 +432,7 @@ namespace LL
     bool WorkQueue::postTo(weak_t target,
                            const TimePoint& time, CALLABLE&& callable, FOLLOWUP&& callback)
     {
+        LL_PROFILE_ZONE_SCOPED;
         // We're being asked to post to the WorkQueue at target.
         // target is a weak_ptr: have to lock it to check it.
         auto tptr = target.lock();
@@ -479,6 +481,7 @@ namespace LL
     template <typename CALLABLE>
     bool WorkQueue::postMaybe(weak_t target, const TimePoint& time, CALLABLE&& callable)
     {
+        LL_PROFILE_ZONE_SCOPED;
         // target is a weak_ptr: have to lock it to check it
         auto tptr = target.lock();
         if (tptr)
-- 
cgit v1.2.3


From bb379cb8ccb1d8622b5f5e0a63a0c1116cd57d91 Mon Sep 17 00:00:00 2001
From: Dave Houlton <euclid@lindenlab.com>
Date: Fri, 12 Nov 2021 15:11:08 -0700
Subject: SL-13565 disable reflection render pass when all non-void water is
 occluded

---
 indra/llrender/llgl.cpp           |   3 +-
 indra/newview/lldrawpoolwater.cpp |   9 +-
 indra/newview/llvieweroctree.cpp  | 287 +++++++++++++++++++-------------------
 3 files changed, 153 insertions(+), 146 deletions(-)

(limited to 'indra')

diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp
index c7f85aec21..b49b14615f 100644
--- a/indra/llrender/llgl.cpp
+++ b/indra/llrender/llgl.cpp
@@ -1095,8 +1095,7 @@ void LLGLManager::initExtensions()
 	mHasSync = ExtensionExists("GL_ARB_sync", gGLHExts.mSysExts);
 	mHasMapBufferRange = ExtensionExists("GL_ARB_map_buffer_range", gGLHExts.mSysExts);
 	mHasFlushBufferRange = ExtensionExists("GL_APPLE_flush_buffer_range", gGLHExts.mSysExts);
-	//mHasDepthClamp = ExtensionExists("GL_ARB_depth_clamp", gGLHExts.mSysExts) || ExtensionExists("GL_NV_depth_clamp", gGLHExts.mSysExts);
-	mHasDepthClamp = FALSE;
+	mHasDepthClamp = ExtensionExists("GL_ARB_depth_clamp", gGLHExts.mSysExts) || ExtensionExists("GL_NV_depth_clamp", gGLHExts.mSysExts);
 	// mask out FBO support when packed_depth_stencil isn't there 'cause we need it for LLRenderTarget -Brad
 #ifdef GL_ARB_framebuffer_object
 	mHasFramebufferObject = ExtensionExists("GL_ARB_framebuffer_object", gGLHExts.mSysExts);
diff --git a/indra/newview/lldrawpoolwater.cpp b/indra/newview/lldrawpoolwater.cpp
index 2f3c52ecd2..1e638f3088 100644
--- a/indra/newview/lldrawpoolwater.cpp
+++ b/indra/newview/lldrawpoolwater.cpp
@@ -649,7 +649,6 @@ void LLDrawPoolWater::shade2(bool edge, LLGLSLShader* shader, const LLColor3& li
                         bool edge_patch = water->getIsEdgePatch();
                         if (edge_patch)
                         {
-                            //sNeedsReflectionUpdate = TRUE;
                             face->renderIndexed();
                         }
                     }
@@ -671,8 +670,12 @@ void LLDrawPoolWater::shade2(bool edge, LLGLSLShader* shader, const LLColor3& li
                         bool edge_patch = water->getIsEdgePatch();
                         if (!edge_patch)
                         {
-                            sNeedsReflectionUpdate = TRUE;
-                            sNeedsDistortionUpdate = TRUE;
+                            if (!LLPipeline::sUseOcclusion)
+                            {
+                                // If occlusion is enabled, these are set within LLOcclusionCullingGroup::checkOcclusion()
+                                sNeedsReflectionUpdate = TRUE;
+                                sNeedsDistortionUpdate = TRUE;
+                            }
                             face->renderIndexed();
                         }
                     }
diff --git a/indra/newview/llvieweroctree.cpp b/indra/newview/llvieweroctree.cpp
index 868cf75d11..62243cbde8 100644
--- a/indra/newview/llvieweroctree.cpp
+++ b/indra/newview/llvieweroctree.cpp
@@ -32,6 +32,7 @@
 #include "llappviewer.h"
 #include "llglslshader.h"
 #include "llviewershadermgr.h"
+#include "lldrawpoolwater.h"
 
 //-----------------------------------------------------------------------------------
 //static variables definitions
@@ -931,47 +932,53 @@ void LLOcclusionCullingGroup::releaseOcclusionQueryObjectNames()
 	}
 }
 
-void LLOcclusionCullingGroup::setOcclusionState(U32 state, S32 mode) 
-{
-	if (mode > STATE_MODE_SINGLE)
-	{
-		if (mode == STATE_MODE_DIFF)
-		{
-			LLSpatialSetOcclusionStateDiff setter(state);
-			setter.traverse(mOctreeNode);
-		}
-		else if (mode == STATE_MODE_BRANCH)
-		{
-			LLSpatialSetOcclusionState setter(state);
-			setter.traverse(mOctreeNode);
-		}
-		else
-		{
-			for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; i++)
-			{
-				mOcclusionState[i] |= state;
-
-				if ((state & DISCARD_QUERY) && mOcclusionQuery[i])
-				{
-					releaseOcclusionQueryObjectName(mOcclusionQuery[i]);
-					mOcclusionQuery[i] = 0;
-				}
-			}
-		}
-	}
-	else
-	{
-		if (state & OCCLUDED)
-		{
-			add(sNumObjectsOccluded, 1);
-		}
-		mOcclusionState[LLViewerCamera::sCurCameraID] |= state;
-		if ((state & DISCARD_QUERY) && mOcclusionQuery[LLViewerCamera::sCurCameraID])
-		{
-			releaseOcclusionQueryObjectName(mOcclusionQuery[LLViewerCamera::sCurCameraID]);
-			mOcclusionQuery[LLViewerCamera::sCurCameraID] = 0;
-		}
-	}
+void LLOcclusionCullingGroup::setOcclusionState(U32 state, S32 mode /* = STATE_MODE_SINGLE */ ) 
+{
+    switch (mode)
+    {
+    case STATE_MODE_SINGLE:
+        if (state & OCCLUDED)
+        {
+            add(sNumObjectsOccluded, 1);
+        }
+        mOcclusionState[LLViewerCamera::sCurCameraID] |= state;
+        if ((state & DISCARD_QUERY) && mOcclusionQuery[LLViewerCamera::sCurCameraID])
+        {
+            releaseOcclusionQueryObjectName(mOcclusionQuery[LLViewerCamera::sCurCameraID]);
+            mOcclusionQuery[LLViewerCamera::sCurCameraID] = 0;
+        }
+        break;
+
+    case STATE_MODE_DIFF:
+        {
+            LLSpatialSetOcclusionStateDiff setter(state);
+            setter.traverse(mOctreeNode);
+        }
+        break;
+
+    case STATE_MODE_BRANCH:
+        {
+            LLSpatialSetOcclusionState setter(state);
+            setter.traverse(mOctreeNode);
+        }
+        break;
+
+    case STATE_MODE_ALL_CAMERAS:
+        for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; i++)
+        {
+            mOcclusionState[i] |= state;
+
+            if ((state & DISCARD_QUERY) && mOcclusionQuery[i])
+            {
+                releaseOcclusionQueryObjectName(mOcclusionQuery[i]);
+                mOcclusionQuery[i] = 0;
+            }
+        }
+        break;
+
+    default:
+        break;
+    }
 }
 
 class LLSpatialClearOcclusionState : public OctreeTraveler
@@ -1006,36 +1013,42 @@ public:
 	}
 };
 
-void LLOcclusionCullingGroup::clearOcclusionState(U32 state, S32 mode)
-{
-	if (mode > STATE_MODE_SINGLE)
-	{
-		if (mode == STATE_MODE_DIFF)
-		{
-			LLSpatialClearOcclusionStateDiff clearer(state);
-			clearer.traverse(mOctreeNode);
-		}
-		else if (mode == STATE_MODE_BRANCH)
-		{
-			LLSpatialClearOcclusionState clearer(state);
-			clearer.traverse(mOctreeNode);
-		}
-		else
-		{
-			for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; i++)
-			{
-				mOcclusionState[i] &= ~state;
-			}
-		}
-	}
-	else
-	{
-		if (state & OCCLUDED)
-		{
-			add(sNumObjectsUnoccluded, 1);
-		}
-		mOcclusionState[LLViewerCamera::sCurCameraID] &= ~state;
-	}
+void LLOcclusionCullingGroup::clearOcclusionState(U32 state, S32 mode /* = STATE_MODE_SINGLE */)
+{
+    switch (mode)
+    {
+        case STATE_MODE_SINGLE:
+            if (state & OCCLUDED)
+            {
+                add(sNumObjectsUnoccluded, 1);
+            }
+            mOcclusionState[LLViewerCamera::sCurCameraID] &= ~state;
+            break;
+
+        case STATE_MODE_DIFF:
+            {
+                LLSpatialClearOcclusionStateDiff clearer(state);
+                clearer.traverse(mOctreeNode);
+            }
+            break;
+
+        case STATE_MODE_BRANCH:
+            {
+                LLSpatialClearOcclusionState clearer(state);
+                clearer.traverse(mOctreeNode);
+            }
+            break;
+
+        case STATE_MODE_ALL_CAMERAS:
+            for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; i++)
+            {
+                mOcclusionState[i] &= ~state;
+            }
+            break;
+
+        default:
+            break;
+    }
 }
 
 BOOL LLOcclusionCullingGroup::earlyFail(LLCamera* camera, const LLVector4a* bounds)
@@ -1089,75 +1102,67 @@ U32 LLOcclusionCullingGroup::getLastOcclusionIssuedTime()
 
 void LLOcclusionCullingGroup::checkOcclusion()
 {
-	if (LLPipeline::sUseOcclusion > 1)
-	{
-        LL_PROFILE_ZONE_SCOPED;
-		LLOcclusionCullingGroup* parent = (LLOcclusionCullingGroup*)getParent();
-		if (parent && parent->isOcclusionState(LLOcclusionCullingGroup::OCCLUDED))
-		{	//if the parent has been marked as occluded, the child is implicitly occluded
-			clearOcclusionState(QUERY_PENDING | DISCARD_QUERY);
-		}
-		else if (isOcclusionState(QUERY_PENDING))
-		{	//otherwise, if a query is pending, read it back
+    if (LLPipeline::sUseOcclusion < 2) return;  // 0 - NoOcclusion, 1 = ReadOnly, 2 = ModifyOcclusionState  TODO: DJH 11-2021 ENUM this
 
-			GLuint available = 0;
-			if (mOcclusionQuery[LLViewerCamera::sCurCameraID])
-			{
-                LL_PROFILE_ZONE_NAMED("co - query available")
-				glGetQueryObjectuivARB(mOcclusionQuery[LLViewerCamera::sCurCameraID], GL_QUERY_RESULT_AVAILABLE_ARB, &available);
-			}
-			else
-			{
-				available = 1;
-			}
-
-			if (available)
-			{ //result is available, read it back, otherwise wait until next frame
-				GLuint res = 1;
-				if (!isOcclusionState(DISCARD_QUERY) && mOcclusionQuery[LLViewerCamera::sCurCameraID])
-				{
-                    LL_PROFILE_ZONE_NAMED("co - query result")
-					glGetQueryObjectuivARB(mOcclusionQuery[LLViewerCamera::sCurCameraID], GL_QUERY_RESULT_ARB, &res);	
+    LL_PROFILE_ZONE_SCOPED;
+    LLOcclusionCullingGroup* parent = (LLOcclusionCullingGroup*)getParent();
+    if (parent && parent->isOcclusionState(LLOcclusionCullingGroup::OCCLUDED))
+    {	//if the parent has been marked as occluded, the child is implicitly occluded
+        clearOcclusionState(QUERY_PENDING | DISCARD_QUERY);
+        return;
+    }
+
+    if (mOcclusionQuery[LLViewerCamera::sCurCameraID] && isOcclusionState(QUERY_PENDING))
+    {	
+        if (isOcclusionState(DISCARD_QUERY))
+        {   // delete the query to avoid holding onto hundreds of pending queries
+            releaseOcclusionQueryObjectName(mOcclusionQuery[LLViewerCamera::sCurCameraID]);
+            mOcclusionQuery[LLViewerCamera::sCurCameraID] = 0;
+            // mark non-occluded
+            clearOcclusionState(LLOcclusionCullingGroup::OCCLUDED, LLOcclusionCullingGroup::STATE_MODE_DIFF);
+            clearOcclusionState(QUERY_PENDING | DISCARD_QUERY);
+        }
+        else
+        {
+            GLuint available;
+            glGetQueryObjectuivARB(mOcclusionQuery[LLViewerCamera::sCurCameraID], GL_QUERY_RESULT_AVAILABLE_ARB, &available);
+
+            if (available)
+            {   
+                GLuint query_result;    // Will be # samples drawn, or a boolean depending on mHasOcclusionQuery2 (both are type GLuint)
+                glGetQueryObjectuivARB(mOcclusionQuery[LLViewerCamera::sCurCameraID], GL_QUERY_RESULT_ARB, &query_result);
 #if LL_TRACK_PENDING_OCCLUSION_QUERIES
-					sPendingQueries.erase(mOcclusionQuery[LLViewerCamera::sCurCameraID]);
+                sPendingQueries.erase(mOcclusionQuery[LLViewerCamera::sCurCameraID]);
 #endif
-				}
-				else if (mOcclusionQuery[LLViewerCamera::sCurCameraID])
-				{ //delete the query to avoid holding onto hundreds of pending queries
-					releaseOcclusionQueryObjectName(mOcclusionQuery[LLViewerCamera::sCurCameraID]);
-					mOcclusionQuery[LLViewerCamera::sCurCameraID] = 0;
-				}
-				
-				if (isOcclusionState(DISCARD_QUERY))
-				{
-					res = 2;
-				}
-
-				if (res > 0)
-				{
-					assert_states_valid(this);
-					clearOcclusionState(LLOcclusionCullingGroup::OCCLUDED, LLOcclusionCullingGroup::STATE_MODE_DIFF);
-					assert_states_valid(this);
-				}
-				else
-				{
-					assert_states_valid(this);
-					
-					setOcclusionState(LLOcclusionCullingGroup::OCCLUDED, LLOcclusionCullingGroup::STATE_MODE_DIFF);
-					
-					assert_states_valid(this);
-				}
-
-				clearOcclusionState(QUERY_PENDING | DISCARD_QUERY);
-			}
-		}
-		else if (mSpatialPartition->isOcclusionEnabled() && isOcclusionState(LLOcclusionCullingGroup::OCCLUDED))
-		{	//check occlusion has been issued for occluded node that has not had a query issued
-			assert_states_valid(this);
-			clearOcclusionState(LLOcclusionCullingGroup::OCCLUDED, LLOcclusionCullingGroup::STATE_MODE_DIFF);
-			assert_states_valid(this);
-		}
-	}
+                if (LLPipeline::RENDER_TYPE_WATER == mSpatialPartition->mDrawableType)
+                {
+                    // Note any unoccluded water, for deciding on reflection/distortion passes
+                    // (If occlusion is disabled, these are set within LLDrawPoolWater::render)
+                    if (query_result > 0)
+                    {
+                        LLDrawPoolWater::sNeedsReflectionUpdate = TRUE;
+                        LLDrawPoolWater::sNeedsDistortionUpdate = TRUE;
+                    }
+                }
+ 
+                if (query_result > 0)
+                {
+                    clearOcclusionState(LLOcclusionCullingGroup::OCCLUDED, LLOcclusionCullingGroup::STATE_MODE_DIFF);
+                }
+                else
+                {
+                    setOcclusionState(LLOcclusionCullingGroup::OCCLUDED, LLOcclusionCullingGroup::STATE_MODE_DIFF);
+                }
+                clearOcclusionState(QUERY_PENDING);
+            }
+        }
+    }
+    else if (mSpatialPartition->isOcclusionEnabled() && isOcclusionState(LLOcclusionCullingGroup::OCCLUDED))
+    {	//check occlusion has been issued for occluded node that has not had a query issued
+        assert_states_valid(this);
+        clearOcclusionState(LLOcclusionCullingGroup::OCCLUDED, LLOcclusionCullingGroup::STATE_MODE_DIFF);
+        assert_states_valid(this);
+    }
 }
 
 void LLOcclusionCullingGroup::doOcclusion(LLCamera* camera, const LLVector4a* shift)
@@ -1175,7 +1180,7 @@ void LLOcclusionCullingGroup::doOcclusion(LLCamera* camera, const LLVector4a* sh
 		}
 
 		F32 OCCLUSION_FUDGE_Z = SG_OCCLUSION_FUDGE; //<-- #Solution #2
-		if (LLDrawPool::POOL_WATER == mSpatialPartition->mDrawableType)
+		if (LLPipeline::RENDER_TYPE_VOIDWATER == mSpatialPartition->mDrawableType)
 		{
 			OCCLUSION_FUDGE_Z = 1.;
 		}
@@ -1205,8 +1210,8 @@ void LLOcclusionCullingGroup::doOcclusion(LLCamera* camera, const LLVector4a* sh
 					// behind the far clip plane, and in the case of edge water to avoid
 					// it being culled while still visible.
 					bool const use_depth_clamp = gGLManager.mHasDepthClamp &&
-												(mSpatialPartition->mDrawableType == LLDrawPool::POOL_WATER ||						
-												mSpatialPartition->mDrawableType == LLDrawPool::POOL_VOIDWATER);
+												(mSpatialPartition->mDrawableType == LLPipeline::RENDER_TYPE_WATER ||
+												mSpatialPartition->mDrawableType == LLPipeline::RENDER_TYPE_VOIDWATER);
 
 					LLGLEnable clamp(use_depth_clamp ? GL_DEPTH_CLAMP : 0);				
 						
@@ -1237,7 +1242,7 @@ void LLOcclusionCullingGroup::doOcclusion(LLCamera* camera, const LLVector4a* sh
 																 bounds[1][1]+SG_OCCLUSION_FUDGE, 
 																 bounds[1][2]+OCCLUSION_FUDGE_Z);
 
-						if (!use_depth_clamp && mSpatialPartition->mDrawableType == LLDrawPool::POOL_VOIDWATER)
+						if (!use_depth_clamp && mSpatialPartition->mDrawableType == LLPipeline::RENDER_TYPE_VOIDWATER)
 						{
                             LL_PROFILE_ZONE_NAMED("doOcclusion - draw water");
 
-- 
cgit v1.2.3


From 100f53dd5a0453af4c2509033d0f93d8c4b0691d Mon Sep 17 00:00:00 2001
From: Dave Houlton <euclid@lindenlab.com>
Date: Fri, 12 Nov 2021 15:20:59 -0700
Subject: SL-13565 refactor (consolidate getters) water drawing

---
 indra/newview/lldrawpoolwater.cpp | 475 +++++++++++++++-----------------------
 indra/newview/lldrawpoolwater.h   |   3 +-
 2 files changed, 193 insertions(+), 285 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/lldrawpoolwater.cpp b/indra/newview/lldrawpoolwater.cpp
index 1e638f3088..e2d3f67e46 100644
--- a/indra/newview/lldrawpoolwater.cpp
+++ b/indra/newview/lldrawpoolwater.cpp
@@ -50,8 +50,6 @@
 #include "llsettingssky.h"
 #include "llsettingswater.h"
 
-static float sTime;
-
 BOOL deferred_render = FALSE;
 
 BOOL LLDrawPoolWater::sSkipScreenCopy = FALSE;
@@ -146,7 +144,7 @@ void LLDrawPoolWater::renderDeferred(S32 pass)
     }
 
 	deferred_render = TRUE;
-	shade();
+	renderWater();
 	deferred_render = FALSE;
 }
 
@@ -182,7 +180,7 @@ void LLDrawPoolWater::render(S32 pass)
 
 	if ((mShaderLevel > 0) && !sSkipScreenCopy)
 	{
-		shade();
+		renderWater();
 		return;
 	}
 
@@ -485,335 +483,246 @@ void LLDrawPoolWater::renderReflection(LLFace* face)
 	face->renderIndexed();
 }
 
-void LLDrawPoolWater::shade2(bool edge, LLGLSLShader* shader, const LLColor3& light_diffuse, const LLVector3& light_dir, F32 light_exp)
+void LLDrawPoolWater::renderWater()
 {
     LL_PROFILE_ZONE_SCOPED;
-    F32  water_height  = LLEnvironment::instance().getWaterHeight(); 
-    F32  camera_height = LLViewerCamera::getInstance()->getOrigin().mV[2];
-    F32  eyedepth      = camera_height - water_height;
-    bool underwater    = eyedepth <= 0.0f;
-
-    LLEnvironment& environment = LLEnvironment::instance();
-    LLSettingsWater::ptr_t pwater = environment.getCurrentWater();
-    LLSettingsSky::ptr_t   psky   = environment.getCurrentSky();
-
-    shader->bind();
-
-// bind textures for water rendering
-	if (deferred_render)
-	{
-        if (shader->getUniformLocation(LLShaderMgr::DEFERRED_NORM_MATRIX) >= 0)
-	    {
-		    glh::matrix4f norm_mat = get_current_modelview().inverse().transpose();
-		    shader->uniformMatrix4fv(LLShaderMgr::DEFERRED_NORM_MATRIX, 1, FALSE, norm_mat.m);
-	    }
-	}
-
-    LLColor4 specular(psky->getIsSunUp() ? psky->getSunlightColor() : psky->getMoonlightColor());
-    shader->uniform4fv(LLShaderMgr::SPECULAR_COLOR, 1, specular.mV);
-
-	sTime = (F32)LLFrameTimer::getElapsedSeconds() * 0.5f;
-	
-	S32 reftex = shader->enableTexture(LLShaderMgr::WATER_REFTEX);
-		
-	if (reftex > -1)
-	{
-		gGL.getTexUnit(reftex)->activate();
-		gGL.getTexUnit(reftex)->bind(&gPipeline.mWaterRef);
-		gGL.getTexUnit(0)->activate();
-	}	
+    if (!deferred_render)
+    {
+        gGL.setColorMask(true, true);
+    }
 
-	//bind normal map
-	S32 bumpTex  = shader->enableTexture(LLViewerShaderMgr::BUMP_MAP);
-    S32 bumpTex2 = shader->enableTexture(LLViewerShaderMgr::BUMP_MAP2);
+    LLGLDisable blend(GL_BLEND);
 
-    LLViewerTexture* tex_a = mWaterNormp[0];
-    LLViewerTexture* tex_b = mWaterNormp[1];
+    LLColor3 light_diffuse(0, 0, 0);
+    F32      light_exp = 0.0f;
 
-    F32 blend_factor = LLEnvironment::instance().getCurrentWater()->getBlendFactor();
-	
-    gGL.getTexUnit(bumpTex)->unbind(LLTexUnit::TT_TEXTURE);
-    gGL.getTexUnit(bumpTex2)->unbind(LLTexUnit::TT_TEXTURE);
+    LLEnvironment &        environment     = LLEnvironment::instance();
+    LLSettingsWater::ptr_t pwater          = environment.getCurrentWater();
+    LLSettingsSky::ptr_t   psky            = environment.getCurrentSky();
+    LLVector3              light_dir       = environment.getLightDirection();
+    bool                   sun_up          = environment.getIsSunUp();
+    bool                   moon_up         = environment.getIsMoonUp();
+    bool                   has_normal_mips = gSavedSettings.getBOOL("RenderWaterMipNormal");
+    bool                   underwater      = LLViewerCamera::getInstance()->cameraUnderWater();
 
-    if (tex_a && (!tex_b || (tex_a == tex_b)))
-    {
-		gGL.getTexUnit(bumpTex)->bind(tex_a);
-        blend_factor = 0; // only one tex provided, no blending
-    }
-    else if (tex_b && !tex_a)
+    if (sun_up)
     {
-        gGL.getTexUnit(bumpTex)->bind(tex_b);
-        blend_factor = 0; // only one tex provided, no blending
+        light_diffuse += psky->getSunlightColor();
     }
-    else if (tex_b != tex_a)
+    // moonlight is several orders of magnitude less bright than sunlight,
+    // so only use this color when the moon alone is showing
+    else if (moon_up)
     {
-        gGL.getTexUnit(bumpTex)->bind(tex_a);
-        gGL.getTexUnit(bumpTex2)->bind(tex_b);
+        light_diffuse += psky->getMoonlightColor();
     }
-	
-    // bind reflection texture from RenderTarget
-	S32 screentex = shader->enableTexture(LLShaderMgr::WATER_SCREENTEX);
-	F32 screenRes[] = 
-	{
-		1.f/gGLViewport[2],
-		1.f/gGLViewport[3]
-	};
-		
-	S32 diffTex = shader->enableTexture(LLShaderMgr::DIFFUSE_MAP);
-	stop_glerror();
-
-// set uniforms for water rendering
-    shader->uniform2fv(LLShaderMgr::DEFERRED_SCREEN_RES, 1, screenRes);
-    shader->uniform1f(LLShaderMgr::BLEND_FACTOR, blend_factor);
-
-    LLColor4 fog_color(pwater->getWaterFogColor(), 0.0f);
-    F32      fog_density = pwater->getModifiedWaterFogDensity(underwater);
 
-    if (screentex > -1)
-	{
-		shader->uniform1f(LLShaderMgr::WATER_FOGDENSITY, fog_density);
-		gGL.getTexUnit(screentex)->bind(&gPipeline.mWaterDis);
-	}
-    
-    if (mShaderLevel == 1)
-    {
-        //F32 fog_density_slider_value = param_mgr->mDensitySliderValue;
-		//sWaterFogColor.mV[3] = fog_density_slider_value;
-        fog_color.mV[VW] = log(fog_density) / log(2);
-	}
-
-    shader->uniform4fv(LLShaderMgr::WATER_FOGCOLOR, 1, fog_color.mV);
-
-	//shader->uniformMatrix4fv("inverse_ref", 1, GL_FALSE, (GLfloat*) gGLObliqueProjectionInverse.mMatrix);
-	shader->uniform1f(LLShaderMgr::WATER_WATERHEIGHT, eyedepth);
-	shader->uniform1f(LLShaderMgr::WATER_TIME, sTime);
-	shader->uniform3fv(LLShaderMgr::WATER_EYEVEC, 1, LLViewerCamera::getInstance()->getOrigin().mV);
-	shader->uniform3fv(LLShaderMgr::WATER_SPECULAR, 1, light_diffuse.mV);
-	shader->uniform1f(LLShaderMgr::WATER_SPECULAR_EXP, light_exp);
-    if (LLEnvironment::instance().isCloudScrollPaused())
+    // Apply magic numbers translating light direction into intensities
+    light_dir.normalize();
+    F32 ground_proj_sq = light_dir.mV[0] * light_dir.mV[0] + light_dir.mV[1] * light_dir.mV[1];
+    light_exp          = llmax(32.f, 256.f * powf(ground_proj_sq, 16.0f));
+    if (0.f < light_diffuse.normalize())  // Normalizing a color? Puzzling...
     {
-        static const std::array<F32, 2> zerowave{ {0.0f, 0.0f} };
-        
-        shader->uniform2fv(LLShaderMgr::WATER_WAVE_DIR1, 1, zerowave.data());
-        shader->uniform2fv(LLShaderMgr::WATER_WAVE_DIR2, 1, zerowave.data());
+        light_diffuse *= (1.5f + (6.f * ground_proj_sq));
     }
-    else
+
+    // set up normal maps filtering
+    for (auto norm_map : mWaterNormp)
     {
-        shader->uniform2fv(LLShaderMgr::WATER_WAVE_DIR1, 1, pwater->getWave1Dir().mV);
-        shader->uniform2fv(LLShaderMgr::WATER_WAVE_DIR2, 1, pwater->getWave2Dir().mV);
+        if (norm_map) norm_map->setFilteringOption(has_normal_mips ? LLTexUnit::TFO_ANISOTROPIC : LLTexUnit::TFO_POINT);
     }
-	shader->uniform3fv(LLShaderMgr::WATER_LIGHT_DIR, 1, light_dir.mV);
 
-	shader->uniform3fv(LLShaderMgr::WATER_NORM_SCALE, 1, pwater->getNormalScale().mV);
-	shader->uniform1f(LLShaderMgr::WATER_FRESNEL_SCALE, pwater->getFresnelScale());
-	shader->uniform1f(LLShaderMgr::WATER_FRESNEL_OFFSET, pwater->getFresnelOffset());
-    shader->uniform1f(LLShaderMgr::WATER_BLUR_MULTIPLIER, pwater->getBlurMultiplier());
+    LLColor4      specular(sun_up ? psky->getSunlightColor() : psky->getMoonlightColor());
+    F32           phase_time = (F32) LLFrameTimer::getElapsedSeconds() * 0.5f;
+    bool          edge       = false;
+    LLGLSLShader *shader     = nullptr;
+    do  // twice through, once with normal shader bound & once with edge shader bound
+    {
+        // select shader
+        if (underwater && LLPipeline::sWaterReflections)
+        {
+            shader = deferred_render ? &gDeferredUnderWaterProgram : &gUnderWaterProgram;
+        }
+        else
+        {
+            if (edge && !deferred_render)
+            {
+                shader = &gWaterEdgeProgram;
+            }
+            else
+            {
+                shader = deferred_render ? &gDeferredWaterProgram : &gWaterProgram;
+            }
+        }
+        shader->bind();
 
-	F32 sunAngle = llmax(0.f, light_dir.mV[1]);
-	F32 scaledAngle = 1.f - sunAngle;
+        // bind textures for water rendering
+        S32 reftex = shader->enableTexture(LLShaderMgr::WATER_REFTEX);
+        if (reftex > -1)
+        {
+            gGL.getTexUnit(reftex)->activate();
+            gGL.getTexUnit(reftex)->bind(&gPipeline.mWaterRef);
+            gGL.getTexUnit(0)->activate();
+        }
 
-    shader->uniform1i(LLShaderMgr::SUN_UP_FACTOR, environment.getIsSunUp() ? 1 : 0);
-	shader->uniform1f(LLShaderMgr::WATER_SUN_ANGLE, sunAngle);
-	shader->uniform1f(LLShaderMgr::WATER_SCALED_ANGLE, scaledAngle);
-	shader->uniform1f(LLShaderMgr::WATER_SUN_ANGLE2, 0.1f + 0.2f*sunAngle);
-    shader->uniform1i(LLShaderMgr::WATER_EDGE_FACTOR, edge ? 1 : 0);
+        // bind normal map
+        S32 bumpTex  = shader->enableTexture(LLViewerShaderMgr::BUMP_MAP);
+        S32 bumpTex2 = shader->enableTexture(LLViewerShaderMgr::BUMP_MAP2);
 
-    LLVector4 rotated_light_direction = LLEnvironment::instance().getRotatedLightNorm();
-    shader->uniform4fv(LLViewerShaderMgr::LIGHTNORM, 1, rotated_light_direction.mV);
-    shader->uniform3fv(LLShaderMgr::WL_CAMPOSLOCAL, 1, LLViewerCamera::getInstance()->getOrigin().mV);
+        LLViewerTexture *tex_a = mWaterNormp[0];
+        LLViewerTexture *tex_b = mWaterNormp[1];
 
-	if (LLViewerCamera::getInstance()->cameraUnderWater())
-	{
-		shader->uniform1f(LLShaderMgr::WATER_REFSCALE, pwater->getScaleBelow());
-	}
-	else
-	{
-		shader->uniform1f(LLShaderMgr::WATER_REFSCALE, pwater->getScaleAbove());
-	}
+        F32 blend_factor = pwater->getBlendFactor();
 
-	{		
-		LLGLDisable cullface(GL_CULL_FACE);
+        gGL.getTexUnit(bumpTex)->unbind(LLTexUnit::TT_TEXTURE);
+        gGL.getTexUnit(bumpTex2)->unbind(LLTexUnit::TT_TEXTURE);
 
-        if (edge)
+        if (tex_a && (!tex_b || (tex_a == tex_b)))
         {
-            for (std::vector<LLFace*>::iterator iter = mDrawFace.begin(); iter != mDrawFace.end(); iter++)
-		    {
-			    LLFace *face = *iter;
-                if (face)
-                {
-                    LLVOWater* water = (LLVOWater*) face->getViewerObject();
-			        gGL.getTexUnit(diffTex)->bind(face->getTexture());
-
-                    if (water)
-                    {
-                        bool edge_patch = water->getIsEdgePatch();
-                        if (edge_patch)
-                        {
-                            face->renderIndexed();
-                        }
-                    }
-                }
-		    }
+            gGL.getTexUnit(bumpTex)->bind(tex_a);
+            blend_factor = 0;  // only one tex provided, no blending
         }
-        else
+        else if (tex_b && !tex_a)
         {
-            for (std::vector<LLFace*>::iterator iter = mDrawFace.begin(); iter != mDrawFace.end(); iter++)
-		    {
-			    LLFace *face = *iter;
-                if (face)
-                {
-                    LLVOWater* water = (LLVOWater*) face->getViewerObject();
-			        gGL.getTexUnit(diffTex)->bind(face->getTexture());
-
-                    if (water)
-                    {
-                        bool edge_patch = water->getIsEdgePatch();
-                        if (!edge_patch)
-                        {
-                            if (!LLPipeline::sUseOcclusion)
-                            {
-                                // If occlusion is enabled, these are set within LLOcclusionCullingGroup::checkOcclusion()
-                                sNeedsReflectionUpdate = TRUE;
-                                sNeedsDistortionUpdate = TRUE;
-                            }
-                            face->renderIndexed();
-                        }
-                    }
-                }
-		    }
+            gGL.getTexUnit(bumpTex)->bind(tex_b);
+            blend_factor = 0;  // only one tex provided, no blending
+        }
+        else if (tex_b != tex_a)
+        {
+            gGL.getTexUnit(bumpTex)->bind(tex_a);
+            gGL.getTexUnit(bumpTex2)->bind(tex_b);
         }
-    }
 
-    gGL.getTexUnit(bumpTex)->unbind(LLTexUnit::TT_TEXTURE);
-    gGL.getTexUnit(bumpTex2)->unbind(LLTexUnit::TT_TEXTURE);
+        // bind reflection texture from RenderTarget
+        S32 screentex   = shader->enableTexture(LLShaderMgr::WATER_SCREENTEX);
+        F32 screenRes[] = {1.f / gGLViewport[2], 1.f / gGLViewport[3]};
 
-	shader->disableTexture(LLShaderMgr::ENVIRONMENT_MAP, LLTexUnit::TT_CUBE_MAP);
-	shader->disableTexture(LLShaderMgr::WATER_SCREENTEX);	
-	shader->disableTexture(LLShaderMgr::BUMP_MAP);
-	shader->disableTexture(LLShaderMgr::DIFFUSE_MAP);
-	shader->disableTexture(LLShaderMgr::WATER_REFTEX);
-	shader->disableTexture(LLShaderMgr::WATER_SCREENDEPTH);
+        S32 diffTex = shader->enableTexture(LLShaderMgr::DIFFUSE_MAP);
 
-	shader->unbind();
-}
+        // set uniforms for shader
+        if (deferred_render)
+        {
+            if (shader->getUniformLocation(LLShaderMgr::DEFERRED_NORM_MATRIX) >= 0)
+            {
+                glh::matrix4f norm_mat = get_current_modelview().inverse().transpose();
+                shader->uniformMatrix4fv(LLShaderMgr::DEFERRED_NORM_MATRIX, 1, FALSE, norm_mat.m);
+            }
+        }
 
-void LLDrawPoolWater::shade()
-{
-    LL_PROFILE_ZONE_SCOPED;
-    if (!deferred_render)
-	{
-		gGL.setColorMask(true, true);
-	}
+        shader->uniform2fv(LLShaderMgr::DEFERRED_SCREEN_RES, 1, screenRes);
+        shader->uniform1f(LLShaderMgr::BLEND_FACTOR, blend_factor);
 
-	LLVOSky *voskyp = gSky.mVOSkyp;
+        LLColor4 fog_color(pwater->getWaterFogColor(), 0.0f);
+        F32      fog_density = pwater->getModifiedWaterFogDensity(underwater);
 
-	if(voskyp == NULL) 
-	{
-		return;
-	}
+        if (screentex > -1)
+        {
+            shader->uniform1f(LLShaderMgr::WATER_FOGDENSITY, fog_density);
+            gGL.getTexUnit(screentex)->bind(&gPipeline.mWaterDis);
+        }
 
-	LLGLDisable blend(GL_BLEND);
+        if (mShaderLevel == 1)
+        {
+            fog_color.mV[VW] = log(fog_density) / log(2);
+        }
 
-	LLColor3 light_diffuse(0,0,0);
-	F32 light_exp = 0.0f;
-	LLVector3 light_dir;
+        F32 water_height  = environment.getWaterHeight();
+        F32 camera_height = LLViewerCamera::getInstance()->getOrigin().mV[2];
+        shader->uniform1f(LLShaderMgr::WATER_WATERHEIGHT, camera_height - water_height);
+        shader->uniform1f(LLShaderMgr::WATER_TIME, phase_time);
+        shader->uniform3fv(LLShaderMgr::WATER_EYEVEC, 1, LLViewerCamera::getInstance()->getOrigin().mV);
 
-    LLEnvironment& environment = LLEnvironment::instance();
-    LLSettingsWater::ptr_t pwater = environment.getCurrentWater();
-    LLSettingsSky::ptr_t   psky   = environment.getCurrentSky();
+        shader->uniform4fv(LLShaderMgr::SPECULAR_COLOR, 1, specular.mV);
+        shader->uniform4fv(LLShaderMgr::WATER_FOGCOLOR, 1, fog_color.mV);
 
-    light_dir = environment.getLightDirection();
-    light_dir.normalize();
+        shader->uniform3fv(LLShaderMgr::WATER_SPECULAR, 1, light_diffuse.mV);
+        shader->uniform1f(LLShaderMgr::WATER_SPECULAR_EXP, light_exp);
+        if (LLEnvironment::instance().isCloudScrollPaused())
+        {
+            static const std::array<F32, 2> zerowave {{0.0f, 0.0f}};
 
-    bool sun_up  = environment.getIsSunUp();
-    bool moon_up = environment.getIsMoonUp();
+            shader->uniform2fv(LLShaderMgr::WATER_WAVE_DIR1, 1, zerowave.data());
+            shader->uniform2fv(LLShaderMgr::WATER_WAVE_DIR2, 1, zerowave.data());
+        }
+        else
+        {
+            shader->uniform2fv(LLShaderMgr::WATER_WAVE_DIR1, 1, pwater->getWave1Dir().mV);
+            shader->uniform2fv(LLShaderMgr::WATER_WAVE_DIR2, 1, pwater->getWave2Dir().mV);
+        }
+        shader->uniform3fv(LLShaderMgr::WATER_LIGHT_DIR, 1, light_dir.mV);
 
-    if (sun_up)
-    {
-        light_diffuse += voskyp->getSun().getColorCached();
-    }
-    // moonlight is several orders of magnitude less bright than sunlight,
-    // so only use this color when the moon alone is showing
-    else if (moon_up)
-    {        
-        light_diffuse += psky->getMoonDiffuse(); 
-    }
+        shader->uniform3fv(LLShaderMgr::WATER_NORM_SCALE, 1, pwater->getNormalScale().mV);
+        shader->uniform1f(LLShaderMgr::WATER_FRESNEL_SCALE, pwater->getFresnelScale());
+        shader->uniform1f(LLShaderMgr::WATER_FRESNEL_OFFSET, pwater->getFresnelOffset());
+        shader->uniform1f(LLShaderMgr::WATER_BLUR_MULTIPLIER, pwater->getBlurMultiplier());
 
-    light_exp = light_dir * LLVector3(light_dir.mV[0], light_dir.mV[1], 0.f);
+        F32 sunAngle    = llmax(0.f, light_dir.mV[1]);
+        F32 scaledAngle = 1.f - sunAngle;
 
-    light_diffuse.normalize();
-    light_diffuse *= (light_exp + 0.25f);
+        shader->uniform1i(LLShaderMgr::SUN_UP_FACTOR, sun_up ? 1 : 0);
+        shader->uniform1f(LLShaderMgr::WATER_SUN_ANGLE, sunAngle);
+        shader->uniform1f(LLShaderMgr::WATER_SCALED_ANGLE, scaledAngle);
+        shader->uniform1f(LLShaderMgr::WATER_SUN_ANGLE2, 0.1f + 0.2f * sunAngle);
+        shader->uniform1i(LLShaderMgr::WATER_EDGE_FACTOR, edge ? 1 : 0);
 
-	light_exp *= light_exp;
-	light_exp *= light_exp;
-	light_exp *= light_exp;
-	light_exp *= light_exp;
-	light_exp *= 256.f;
-	light_exp = light_exp > 32.f ? light_exp : 32.f;
+        LLVector4 rotated_light_direction = LLEnvironment::instance().getRotatedLightNorm();
+        shader->uniform4fv(LLViewerShaderMgr::LIGHTNORM, 1, rotated_light_direction.mV);
+        shader->uniform3fv(LLShaderMgr::WL_CAMPOSLOCAL, 1, LLViewerCamera::getInstance()->getOrigin().mV);
 
-    light_diffuse *= 6.f;
+        if (LLViewerCamera::getInstance()->cameraUnderWater())
+        {
+            shader->uniform1f(LLShaderMgr::WATER_REFSCALE, pwater->getScaleBelow());
+        }
+        else
+        {
+            shader->uniform1f(LLShaderMgr::WATER_REFSCALE, pwater->getScaleAbove());
+        }
 
-	LLGLSLShader* shader = nullptr;
-    LLGLSLShader* edge_shader = nullptr;
+        LLGLDisable cullface(GL_CULL_FACE);
 
-	F32 eyedepth = LLViewerCamera::getInstance()->getOrigin().mV[2] - LLEnvironment::instance().getWaterHeight();
-	
-	if (eyedepth < 0.f && LLPipeline::sWaterReflections)
-	{
-	    if (deferred_render)
-	    {
-            shader = &gDeferredUnderWaterProgram;
-	    }
-		else
+        LLVOWater *water = nullptr;
+        for (LLFace *const &face : mDrawFace)
         {
-	        shader = &gUnderWaterProgram;
-        }
-	}
-	else if (deferred_render)
-	{
-		shader = &gDeferredWaterProgram;
-        edge_shader = nullptr;
-	}
-	else
-	{
-		shader = &gWaterProgram;
-        edge_shader = &gWaterEdgeProgram;
-	}
+            if (!face) continue;
+            water = static_cast<LLVOWater *>(face->getViewerObject());
+            if (!water) continue;
 
-    if (mWaterNormp[0])
-    {
-	    if (gSavedSettings.getBOOL("RenderWaterMipNormal"))
-	    {
-		    mWaterNormp[0]->setFilteringOption(LLTexUnit::TFO_ANISOTROPIC);
-	    }
-	    else 
-	    {
-		    mWaterNormp[0]->setFilteringOption(LLTexUnit::TFO_POINT);
-	    }
-	}
+            gGL.getTexUnit(diffTex)->bind(face->getTexture());
 
-    if (mWaterNormp[1])
-    {
-	    if (gSavedSettings.getBOOL("RenderWaterMipNormal"))
-	    {
-            mWaterNormp[1]->setFilteringOption(LLTexUnit::TFO_ANISOTROPIC);
-	    }
-	    else 
-	    {
-            mWaterNormp[1]->setFilteringOption(LLTexUnit::TFO_POINT);
-	    }
-	}
+            if (edge == (bool) water->getIsEdgePatch())
+            {
+                face->renderIndexed();
 
-    shade2(false, shader, light_diffuse, light_dir, light_exp);
-    shade2(true, edge_shader ? edge_shader : shader, light_diffuse, light_dir, light_exp);
+                // If not occlusion culling, record non-void water being drawn
+                // (If occlusion is enabled, these are set within LLOcclusionCullingGroup::checkOcclusion() )
+                if (!edge && !LLPipeline::sUseOcclusion)
+                {
+                    sNeedsReflectionUpdate = TRUE;
+                    sNeedsDistortionUpdate = TRUE;
+                }
+            }
+        }
 
-	gGL.getTexUnit(0)->activate();
-	gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE);
-	if (!deferred_render)
-	{
-		gGL.setColorMask(true, false);
-	}
+        shader->disableTexture(LLShaderMgr::ENVIRONMENT_MAP, LLTexUnit::TT_CUBE_MAP);
+        shader->disableTexture(LLShaderMgr::WATER_SCREENTEX);
+        shader->disableTexture(LLShaderMgr::BUMP_MAP);
+        shader->disableTexture(LLShaderMgr::DIFFUSE_MAP);
+        shader->disableTexture(LLShaderMgr::WATER_REFTEX);
+        shader->disableTexture(LLShaderMgr::WATER_SCREENDEPTH);
+
+        // clean up
+        shader->unbind();
+        gGL.getTexUnit(bumpTex)->unbind(LLTexUnit::TT_TEXTURE);
+        gGL.getTexUnit(bumpTex2)->unbind(LLTexUnit::TT_TEXTURE);
+
+        edge = !edge;
+    } while (!edge);
 
+    gGL.getTexUnit(0)->activate();
+    gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE);
+    if (!deferred_render)
+    {
+        gGL.setColorMask(true, false);
+    }
 }
 
 LLViewerTexture *LLDrawPoolWater::getDebugTexture()
diff --git a/indra/newview/lldrawpoolwater.h b/indra/newview/lldrawpoolwater.h
index a5d163e0d7..6f2fc3271d 100644
--- a/indra/newview/lldrawpoolwater.h
+++ b/indra/newview/lldrawpoolwater.h
@@ -78,8 +78,7 @@ public:
 	/*virtual*/ LLColor3 getDebugColor() const; // For AGP debug display
 
 	void renderReflection(LLFace* face);
-	void shade();
-    void shade2(bool edge, LLGLSLShader* shader, const LLColor3& light_diffuse, const LLVector3& light_dir, F32 light_exp);
+	void renderWater();
 
     void setTransparentTextures(const LLUUID& transparentTextureId, const LLUUID& nextTransparentTextureId);
     void setOpaqueTexture(const LLUUID& opaqueTextureId);
-- 
cgit v1.2.3


From 8425c6429299590653d6a40cd127d9fbed4c76d7 Mon Sep 17 00:00:00 2001
From: Dave Houlton <euclid@lindenlab.com>
Date: Fri, 19 Nov 2021 15:51:53 -0700
Subject: SL-13565 restore the trampled tracy zones

---
 indra/newview/llvieweroctree.cpp | 10 ++++++++--
 indra/newview/llworld.cpp        |  1 +
 2 files changed, 9 insertions(+), 2 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llvieweroctree.cpp b/indra/newview/llvieweroctree.cpp
index 62243cbde8..b7d0e06116 100644
--- a/indra/newview/llvieweroctree.cpp
+++ b/indra/newview/llvieweroctree.cpp
@@ -1125,12 +1125,18 @@ void LLOcclusionCullingGroup::checkOcclusion()
         else
         {
             GLuint available;
-            glGetQueryObjectuivARB(mOcclusionQuery[LLViewerCamera::sCurCameraID], GL_QUERY_RESULT_AVAILABLE_ARB, &available);
+            {
+                LL_PROFILE_ZONE_NAMED("co - query available");
+                glGetQueryObjectuivARB(mOcclusionQuery[LLViewerCamera::sCurCameraID], GL_QUERY_RESULT_AVAILABLE_ARB, &available);
+            }
 
             if (available)
             {   
                 GLuint query_result;    // Will be # samples drawn, or a boolean depending on mHasOcclusionQuery2 (both are type GLuint)
-                glGetQueryObjectuivARB(mOcclusionQuery[LLViewerCamera::sCurCameraID], GL_QUERY_RESULT_ARB, &query_result);
+                {
+                    LL_PROFILE_ZONE_NAMED("co - query result");
+                    glGetQueryObjectuivARB(mOcclusionQuery[LLViewerCamera::sCurCameraID], GL_QUERY_RESULT_ARB, &query_result);
+                }
 #if LL_TRACK_PENDING_OCCLUSION_QUERIES
                 sPendingQueries.erase(mOcclusionQuery[LLViewerCamera::sCurCameraID]);
 #endif
diff --git a/indra/newview/llworld.cpp b/indra/newview/llworld.cpp
index d5cce6a52a..d7f16713d2 100644
--- a/indra/newview/llworld.cpp
+++ b/indra/newview/llworld.cpp
@@ -885,6 +885,7 @@ void LLWorld::waterHeightRegionInfo(std::string const& sim_name, F32 water_heigh
 
 void LLWorld::precullWaterObjects(LLCamera& camera, LLCullResult* cull, bool include_void_water)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	if (!gAgent.getRegion())
 	{
 		return;
-- 
cgit v1.2.3


From 9b0d8c7e629597fd8e6dfb91a6b8f625b34ab274 Mon Sep 17 00:00:00 2001
From: Runitai Linden <davep@lindenlab.com>
Date: Mon, 22 Nov 2021 18:42:56 -0600
Subject: SL-16094 More profile hooks for threading code, remove redundant
 wglCreateContextAttribs call

---
 indra/llcommon/llthreadsafequeue.h  | 18 ++++++++++++++++++
 indra/llcommon/threadpool.cpp       |  6 +++++-
 indra/llcommon/threadsafeschedule.h | 34 ++++++++++++++++++++++++++++++----
 indra/llrender/llimagegl.cpp        |  2 ++
 indra/llwindow/llwindowwin32.cpp    |  2 +-
 5 files changed, 56 insertions(+), 6 deletions(-)

(limited to 'indra')

diff --git a/indra/llcommon/llthreadsafequeue.h b/indra/llcommon/llthreadsafequeue.h
index 5c934791fe..2806506550 100644
--- a/indra/llcommon/llthreadsafequeue.h
+++ b/indra/llcommon/llthreadsafequeue.h
@@ -275,6 +275,7 @@ template <typename ElementT, typename QueueT>
 template <typename CALLABLE>
 bool LLThreadSafeQueue<ElementT, QueueT>::tryLock(CALLABLE&& callable)
 {
+    LL_PROFILE_ZONE_SCOPED;
     lock_t lock1(mLock, std::defer_lock);
     if (!lock1.try_lock())
         return false;
@@ -291,6 +292,7 @@ bool LLThreadSafeQueue<ElementT, QueueT>::tryLockUntil(
     const std::chrono::time_point<Clock, Duration>& until,
     CALLABLE&& callable)
 {
+    LL_PROFILE_ZONE_SCOPED;
     lock_t lock1(mLock, std::defer_lock);
     if (!lock1.try_lock_until(until))
         return false;
@@ -304,6 +306,7 @@ template <typename ElementT, typename QueueT>
 template <typename T>
 bool LLThreadSafeQueue<ElementT, QueueT>::push_(lock_t& lock, T&& element)
 {
+    LL_PROFILE_ZONE_SCOPED;
     if (mStorage.size() >= mCapacity)
         return false;
 
@@ -319,6 +322,7 @@ template <typename ElementT, typename QueueT>
 template <typename T>
 bool LLThreadSafeQueue<ElementT, QueueT>::pushIfOpen(T&& element)
 {
+    LL_PROFILE_ZONE_SCOPED;
     lock_t lock1(mLock);
     while (true)
     {
@@ -341,6 +345,7 @@ template <typename ElementT, typename QueueT>
 template<typename T>
 void LLThreadSafeQueue<ElementT, QueueT>::push(T&& element)
 {
+    LL_PROFILE_ZONE_SCOPED;
     if (! pushIfOpen(std::forward<T>(element)))
     {
         LLTHROW(LLThreadSafeQueueInterrupt());
@@ -352,6 +357,7 @@ template<typename ElementT, typename QueueT>
 template<typename T>
 bool LLThreadSafeQueue<ElementT, QueueT>::tryPush(T&& element)
 {
+    LL_PROFILE_ZONE_SCOPED;
     return tryLock(
         [this, element=std::move(element)](lock_t& lock)
         {
@@ -368,6 +374,7 @@ bool LLThreadSafeQueue<ElementT, QueueT>::tryPushFor(
     const std::chrono::duration<Rep, Period>& timeout,
     T&& element)
 {
+    LL_PROFILE_ZONE_SCOPED;
     // 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,
@@ -381,6 +388,7 @@ bool LLThreadSafeQueue<ElementT, QueueT>::tryPushUntil(
     const std::chrono::time_point<Clock, Duration>& until,
     T&& element)
 {
+    LL_PROFILE_ZONE_SCOPED;
     return tryLockUntil(
         until,
         [this, until, element=std::move(element)](lock_t& lock)
@@ -413,6 +421,7 @@ template <typename ElementT, typename QueueT>
 typename LLThreadSafeQueue<ElementT, QueueT>::pop_result
 LLThreadSafeQueue<ElementT, QueueT>::pop_(lock_t& lock, ElementT& element)
 {
+    LL_PROFILE_ZONE_SCOPED;
     // If mStorage is empty, there's no head element.
     if (mStorage.empty())
         return mClosed? DONE : EMPTY;
@@ -434,6 +443,7 @@ LLThreadSafeQueue<ElementT, QueueT>::pop_(lock_t& lock, ElementT& element)
 template<typename ElementT, typename QueueT>
 ElementT LLThreadSafeQueue<ElementT, QueueT>::pop(void)
 {
+    LL_PROFILE_ZONE_SCOPED;
     lock_t lock1(mLock);
     ElementT value;
     while (true)
@@ -462,6 +472,7 @@ ElementT LLThreadSafeQueue<ElementT, QueueT>::pop(void)
 template<typename ElementT, typename QueueT>
 bool LLThreadSafeQueue<ElementT, QueueT>::tryPop(ElementT & element)
 {
+    LL_PROFILE_ZONE_SCOPED;
     return tryLock(
         [this, &element](lock_t& lock)
         {
@@ -479,6 +490,7 @@ bool LLThreadSafeQueue<ElementT, QueueT>::tryPopFor(
     const std::chrono::duration<Rep, Period>& timeout,
     ElementT& element)
 {
+    LL_PROFILE_ZONE_SCOPED;
     // 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);
@@ -491,6 +503,7 @@ bool LLThreadSafeQueue<ElementT, QueueT>::tryPopUntil(
     const std::chrono::time_point<Clock, Duration>& until,
     ElementT& element)
 {
+    LL_PROFILE_ZONE_SCOPED;
     return tryLockUntil(
         until,
         [this, until, &element](lock_t& lock)
@@ -510,6 +523,7 @@ LLThreadSafeQueue<ElementT, QueueT>::tryPopUntil_(
     const std::chrono::time_point<Clock, Duration>& until,
     ElementT& element)
 {
+    LL_PROFILE_ZONE_SCOPED;
     while (true)
     {
         pop_result popped = pop_(lock, element);
@@ -536,6 +550,7 @@ LLThreadSafeQueue<ElementT, QueueT>::tryPopUntil_(
 template<typename ElementT, typename QueueT>
 size_t LLThreadSafeQueue<ElementT, QueueT>::size(void)
 {
+    LL_PROFILE_ZONE_SCOPED;
     lock_t lock(mLock);
     return mStorage.size();
 }
@@ -544,6 +559,7 @@ size_t LLThreadSafeQueue<ElementT, QueueT>::size(void)
 template<typename ElementT, typename QueueT>
 void LLThreadSafeQueue<ElementT, QueueT>::close()
 {
+    LL_PROFILE_ZONE_SCOPED;
     lock_t lock(mLock);
     mClosed = true;
     lock.unlock();
@@ -557,6 +573,7 @@ void LLThreadSafeQueue<ElementT, QueueT>::close()
 template<typename ElementT, typename QueueT>
 bool LLThreadSafeQueue<ElementT, QueueT>::isClosed()
 {
+    LL_PROFILE_ZONE_SCOPED;
     lock_t lock(mLock);
     return mClosed;
 }
@@ -565,6 +582,7 @@ bool LLThreadSafeQueue<ElementT, QueueT>::isClosed()
 template<typename ElementT, typename QueueT>
 bool LLThreadSafeQueue<ElementT, QueueT>::done()
 {
+    LL_PROFILE_ZONE_SCOPED;
     lock_t lock(mLock);
     return mClosed && mStorage.empty();
 }
diff --git a/indra/llcommon/threadpool.cpp b/indra/llcommon/threadpool.cpp
index cf25cc838e..06e0dc5bfc 100644
--- a/indra/llcommon/threadpool.cpp
+++ b/indra/llcommon/threadpool.cpp
@@ -28,7 +28,11 @@ LL::ThreadPool::ThreadPool(const std::string& name, size_t threads, size_t capac
     for (size_t i = 0; i < threads; ++i)
     {
         std::string tname{ STRINGIZE(mName << ':' << (i+1) << '/' << threads) };
-        mThreads.emplace_back(tname, [this, tname](){ run(tname); });
+        mThreads.emplace_back(tname, [this, tname]()
+            {
+                LL_PROFILER_SET_THREAD_NAME(tname.c_str());
+                run(tname);
+            });
     }
     // Listen on "LLApp", and when the app is shutting down, close the queue
     // and join the workers.
diff --git a/indra/llcommon/threadsafeschedule.h b/indra/llcommon/threadsafeschedule.h
index c8ad23532b..601681d550 100644
--- a/indra/llcommon/threadsafeschedule.h
+++ b/indra/llcommon/threadsafeschedule.h
@@ -98,12 +98,14 @@ namespace LL
         // we could minimize redundancy by breaking out a common base class...
         void push(const DataTuple& tuple)
         {
+            LL_PROFILE_ZONE_SCOPED;
             push(tuple_cons(Clock::now(), tuple));
         }
 
         /// individually pass each component of the TimeTuple
         void push(const TimePoint& time, Args&&... args)
         {
+            LL_PROFILE_ZONE_SCOPED;
             push(TimeTuple(time, std::forward<Args>(args)...));
         }
 
@@ -114,6 +116,7 @@ namespace LL
         // and call that overload.
         void push(Args&&... args)
         {
+            LL_PROFILE_ZONE_SCOPED;
             push(Clock::now(), std::forward<Args>(args)...);
         }
 
@@ -124,18 +127,21 @@ namespace LL
         /// DataTuple with implicit now
         bool tryPush(const DataTuple& tuple)
         {
+            LL_PROFILE_ZONE_SCOPED;
             return tryPush(tuple_cons(Clock::now(), tuple));
         }
 
         /// individually pass components
         bool tryPush(const TimePoint& time, Args&&... args)
         {
+            LL_PROFILE_ZONE_SCOPED;
             return tryPush(TimeTuple(time, std::forward<Args>(args)...));
         }
 
         /// individually pass components with implicit now
         bool tryPush(Args&&... args)
         {
+            LL_PROFILE_ZONE_SCOPED;
             return tryPush(Clock::now(), std::forward<Args>(args)...);
         }
 
@@ -148,6 +154,7 @@ namespace LL
         bool tryPushFor(const std::chrono::duration<Rep, Period>& timeout,
                         const DataTuple& tuple)
         {
+            LL_PROFILE_ZONE_SCOPED;
             return tryPushFor(timeout, tuple_cons(Clock::now(), tuple));
         }
 
@@ -156,6 +163,7 @@ namespace LL
         bool tryPushFor(const std::chrono::duration<Rep, Period>& timeout,
                         const TimePoint& time, Args&&... args)
         {
+            LL_PROFILE_ZONE_SCOPED;
             return tryPushFor(TimeTuple(time, std::forward<Args>(args)...));
         }
 
@@ -164,6 +172,7 @@ namespace LL
         bool tryPushFor(const std::chrono::duration<Rep, Period>& timeout,
                         Args&&... args)
         {
+            LL_PROFILE_ZONE_SCOPED;
             return tryPushFor(Clock::now(), std::forward<Args>(args)...);
         }
 
@@ -176,6 +185,7 @@ namespace LL
         bool tryPushUntil(const std::chrono::time_point<Clock, Duration>& until,
                           const DataTuple& tuple)
         {
+            LL_PROFILE_ZONE_SCOPED;
             return tryPushUntil(until, tuple_cons(Clock::now(), tuple));
         }
 
@@ -184,6 +194,7 @@ namespace LL
         bool tryPushUntil(const std::chrono::time_point<Clock, Duration>& until,
                           const TimePoint& time, Args&&... args)
         {
+            LL_PROFILE_ZONE_SCOPED;
             return tryPushUntil(until, TimeTuple(time, std::forward<Args>(args)...));
         }
 
@@ -192,6 +203,7 @@ namespace LL
         bool tryPushUntil(const std::chrono::time_point<Clock, Duration>& until,
                           Args&&... args)
         {
+            LL_PROFILE_ZONE_SCOPED;
             return tryPushUntil(until, Clock::now(), std::forward<Args>(args)...);
         }
 
@@ -209,12 +221,14 @@ namespace LL
         // haven't yet jumped through those hoops.
         DataTuple pop()
         {
+            LL_PROFILE_ZONE_SCOPED;
             return tuple_cdr(popWithTime());
         }
 
         /// pop TimeTuple by value
         TimeTuple popWithTime()
         {
+            LL_PROFILE_ZONE_SCOPED;
             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*
@@ -254,6 +268,7 @@ namespace LL
         /// tryPop(DataTuple&)
         bool tryPop(DataTuple& tuple)
         {
+            LL_PROFILE_ZONE_SCOPED;
             TimeTuple tt;
             if (! super::tryPop(tt))
                 return false;
@@ -264,6 +279,7 @@ namespace LL
         /// for when Args has exactly one type
         bool tryPop(typename std::tuple_element<1, TimeTuple>::type& value)
         {
+            LL_PROFILE_ZONE_SCOPED;
             TimeTuple tt;
             if (! super::tryPop(tt))
                 return false;
@@ -275,6 +291,7 @@ namespace LL
         template <typename Rep, typename Period, typename Tuple>
         bool tryPopFor(const std::chrono::duration<Rep, Period>& timeout, Tuple& tuple)
         {
+            LL_PROFILE_ZONE_SCOPED;
             // It's important to use OUR tryPopUntil() implementation, rather
             // than delegating immediately to our base class.
             return tryPopUntil(Clock::now() + timeout, tuple);
@@ -285,6 +302,7 @@ namespace LL
         bool tryPopUntil(const std::chrono::time_point<Clock, Duration>& until,
                          TimeTuple& tuple)
         {
+            LL_PROFILE_ZONE_SCOPED;
             // 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
@@ -304,20 +322,25 @@ namespace LL
 
         pop_result tryPopUntil_(lock_t& lock, const TimePoint& until, TimeTuple& tuple)
         {
+            LL_PROFILE_ZONE_SCOPED;
             TimePoint adjusted = until;
             if (! super::mStorage.empty())
             {
+                LL_PROFILE_ZONE_NAMED("tpu - adjust");
                 // use whichever is earlier: the head item's timestamp, or
                 // the caller's limit
                 adjusted = min(std::get<0>(super::mStorage.front()), adjusted);
             }
             // now delegate to base-class tryPopUntil_()
             pop_result popped;
-            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.
+                LL_PROFILE_ZONE_NAMED("tpu - super");
+                while ((popped = pop_result(super::tryPopUntil_(lock, adjusted, tuple))) == WAITING)
+                {
+                    // If super::tryPopUntil_() returns WAITING, it means there's
+                    // a head item, but it's not yet time. But it's worth looping
+                    // back to recheck.
+                }
             }
             return popped;
         }
@@ -327,6 +350,7 @@ namespace LL
         bool tryPopUntil(const std::chrono::time_point<Clock, Duration>& until,
                          DataTuple& tuple)
         {
+            LL_PROFILE_ZONE_SCOPED;
             TimeTuple tt;
             if (! tryPopUntil(until, tt))
                 return false;
@@ -339,6 +363,7 @@ namespace LL
         bool tryPopUntil(const std::chrono::time_point<Clock, Duration>& until,
                          typename std::tuple_element<1, TimeTuple>::type& value)
         {
+            LL_PROFILE_ZONE_SCOPED;
             TimeTuple tt;
             if (! tryPopUntil(until, tt))
                 return false;
@@ -362,6 +387,7 @@ namespace LL
         // considering whether to deliver the current head element
         bool canPop(const TimeTuple& head) const override
         {
+            LL_PROFILE_ZONE_SCOPED;
             // 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();
diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp
index 1b6920fe3b..e623baa653 100644
--- a/indra/llrender/llimagegl.cpp
+++ b/indra/llrender/llimagegl.cpp
@@ -2257,6 +2257,7 @@ LLImageGLThread::LLImageGLThread(LLWindow* window)
     : ThreadPool("LLImageGL", 1, 1024*1024)
     , mWindow(window)
 {
+    LL_PROFILE_ZONE_SCOPED;
     mFinished = false;
 
     mContext = mWindow->createSharedContext();
@@ -2264,6 +2265,7 @@ LLImageGLThread::LLImageGLThread(LLWindow* window)
 
 void LLImageGLThread::run()
 {
+    LL_PROFILE_ZONE_SCOPED;
     // We must perform setup on this thread before actually servicing our
     // WorkQueue, likewise cleanup afterwards.
     mWindow->makeContextCurrent(mContext);
diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp
index b845f75ce4..777117b7c8 100644
--- a/indra/llwindow/llwindowwin32.cpp
+++ b/indra/llwindow/llwindowwin32.cpp
@@ -1697,7 +1697,7 @@ void* LLWindowWin32::createSharedContext()
         0
     };
 
-    HGLRC rc = wglCreateContextAttribsARB(mhDC, mhRC, attribs);
+    HGLRC rc = 0;
 
     bool done = false;
     while (!done)
-- 
cgit v1.2.3


From 744646eb71fd9d1d1161ae1132bfe8a9a2c7dd9d Mon Sep 17 00:00:00 2001
From: Runitai Linden <davep@lindenlab.com>
Date: Mon, 22 Nov 2021 19:12:39 -0600
Subject: SL-16400 Fix for grey textures (hack).

---
 indra/llrender/llimagegl.cpp | 4 ++++
 indra/llrender/llimagegl.h   | 2 +-
 2 files changed, 5 insertions(+), 1 deletion(-)

(limited to 'indra')

diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp
index e623baa653..eda61d3c74 100644
--- a/indra/llrender/llimagegl.cpp
+++ b/indra/llrender/llimagegl.cpp
@@ -2268,6 +2268,10 @@ void LLImageGLThread::run()
     LL_PROFILE_ZONE_SCOPED;
     // We must perform setup on this thread before actually servicing our
     // WorkQueue, likewise cleanup afterwards.
+    while (mContext == nullptr)
+    { // HACK -- wait for mContext to be initialized since this thread will usually start before mContext is set
+        std::this_thread::sleep_for(std::chrono::milliseconds(1));
+    }
     mWindow->makeContextCurrent(mContext);
     gGL.init();
     ThreadPool::run();
diff --git a/indra/llrender/llimagegl.h b/indra/llrender/llimagegl.h
index 27496def1d..ae773bb362 100644
--- a/indra/llrender/llimagegl.h
+++ b/indra/llrender/llimagegl.h
@@ -324,7 +324,7 @@ public:
 
 private:
     LLWindow* mWindow;
-    void* mContext;
+    void* mContext = nullptr;
     LLAtomicBool mFinished;
 };
 
-- 
cgit v1.2.3


From a32a45163d18f9b5998e469a356f870dbdb034ad Mon Sep 17 00:00:00 2001
From: Nat Goodspeed <nat@lindenlab.com>
Date: Tue, 23 Nov 2021 09:58:54 -0500
Subject: SL-16094: Extend stringize() to support variadic arguments.

It's useful to be able to say STRINGIZE(item0 << item1 << item2), and we use
that a lot in our code base. But weird syntax aside, there are a couple
advantages to being able to write stringize(item0, item1, item2).

First, it allows stringize() to be used from within some other variadic
function, without having to make that function a macro that accepts an
arbitrary insertion-operator expression. There's no such thing as a member
macro.

Second, particularly for variadic functions, it allows us to optimize the
single-argument case stringize(item0). A macro can't do that. When item0 is
already a string of the desired char type, instead of streaming it into a
std::ostringstream and retrieving it again, we can simply return the input
string. When it's a pointer to the desired char type, we can directly
construct the result string without the help of std::ostringstream. When it's
a string of some other char type, we can engage ll_convert() to perform needed
conversions.

We generalize and optimize the generic gstringize() function, retaining the
role of stringize() and wstringize() as thin wrappers that merely provide the
desired char type.

Optimizing the single-argument case requires separately defining gstringize()
with two or more arguments: the general case. Then gstringize(arg) is
delegated to a gstringize_impl class template so we can partially specialize
to recognize a std::basic_string<desired_char_type> argument, as well as
desired_char_type*. Both these specializations engage ll_convert(), which
already handles the trivial case when no conversion is required.

Use of ll_convert() in this role supercedes and generalizes the previous
wstring_to_utf8str() and utf8str_to_wstring() overloads.

Also introduce stream_to(std::ostream&, ...) to support variadic streaming to
other destinations, e.g. a file, std::cout, ...
---
 indra/llcommon/stringize.h | 109 +++++++++++++++++++++++++++++++++------------
 1 file changed, 80 insertions(+), 29 deletions(-)

(limited to 'indra')

diff --git a/indra/llcommon/stringize.h b/indra/llcommon/stringize.h
index 38dd198ad3..bc91f188e4 100644
--- a/indra/llcommon/stringize.h
+++ b/indra/llcommon/stringize.h
@@ -31,58 +31,109 @@
 
 #include <sstream>
 #include <llstring.h>
+#include <boost/call_traits.hpp>
 
 /**
- * gstringize(item) encapsulates an idiom we use constantly, using
- * operator<<(std::ostringstream&, TYPE) followed by std::ostringstream::str()
- * or their wstring equivalents
- * to render a string expressing some item.
+ * stream_to(std::ostream&, items, ...) streams each item in the parameter list
+ * to the passed std::ostream using the insertion operator <<. This can be
+ * used, for instance, to make a simple print() function, e.g.:
+ *
+ * @code
+ * template <typename... Items>
+ * void print(Items&&... items)
+ * {
+ *     stream_to(std::cout, std::forward<Items>(items)...);
+ * }
+ * @endcode
  */
-template <typename CHARTYPE, typename T>
-std::basic_string<CHARTYPE> gstringize(const T& item)
+// recursion tail
+template <typename CHARTYPE>
+void stream_to(std::basic_ostream<CHARTYPE>& out) {}
+// stream one or more items
+template <typename CHARTYPE, typename T, typename... Items>
+void stream_to(std::basic_ostream<CHARTYPE>& out, T&& item, Items&&... items)
 {
-    std::basic_ostringstream<CHARTYPE> out;
-    out << item;
-    return out.str();
+    out << std::move(item);
+    stream_to(out, std::forward<Items>(items)...);
 }
 
+// why we use function overloads, not function template specializations:
+// http://www.gotw.ca/publications/mill17.htm
+
 /**
- *partial specialization of stringize for handling wstring
- *TODO: we should have similar specializations for wchar_t[] but not until it is needed.
+ * gstringize(item, ...) encapsulates an idiom we use constantly, using
+ * operator<<(std::ostringstream&, TYPE) followed by std::ostringstream::str()
+ * or their wstring equivalents to render a string expressing one or more items.
  */
-inline std::string stringize(const std::wstring& item)
+// two or more args - the case of a single argument is handled separately
+template <typename CHARTYPE, typename T0, typename T1, typename... Items>
+auto gstringize(T0&& item0, T1&& item1, Items&&... items)
 {
-    return wstring_to_utf8str(item);
+    std::basic_ostringstream<CHARTYPE> out;
+    stream_to(out, std::forward<T0>(item0), std::forward<T1>(item1),
+              std::forward<Items>(items)...);
+    return out.str();
 }
 
-/**
- * Specialization of gstringize for std::string return types
- */
-template <typename T>
-std::string stringize(const T& item)
+// generic single argument: stream to out, as above
+template <typename CHARTYPE, typename T>
+struct gstringize_impl
 {
-    return gstringize<char>(item);
+    auto operator()(typename boost::call_traits<T>::param_type arg)
+    {
+        std::basic_ostringstream<CHARTYPE> out;
+        out << arg;
+        return out.str();
+    }
+};
+
+// partially specialize for a single STRING argument -
+// note that ll_convert<T>(T) already handles the trivial case
+template <typename OUTCHAR, typename INCHAR>
+struct gstringize_impl<OUTCHAR, std::basic_string<INCHAR>>
+{
+    auto operator()(const std::basic_string<INCHAR>& arg)
+    {
+        return ll_convert<std::basic_string<OUTCHAR>>(arg);
+    }
+};
+
+// partially specialize for a single CHARTYPE* argument -
+// since it's not a basic_string and we do want to optimize this common case
+template <typename OUTCHAR, typename INCHAR>
+struct gstringize_impl<OUTCHAR, INCHAR*>
+{
+    auto operator()(const INCHAR* arg)
+    {
+        return ll_convert<std::basic_string<OUTCHAR>>(arg);
+    }
+};
+
+// gstringize(single argument)
+template <typename CHARTYPE, typename T>
+auto gstringize(T&& item)
+{
+    // use decay<T> so we don't require separate specializations for T, const
+    // T, T&, const T& ...
+    return gstringize_impl<CHARTYPE, std::decay_t<T>>()(std::forward<T>(item));
 }
 
 /**
- * Specialization for generating wstring from string.
- * Both a convenience function and saves a miniscule amount of overhead.
+ * Specialization of gstringize for std::string return types
  */
-inline std::wstring wstringize(const std::string& item)
+template <typename... Items>
+auto stringize(Items&&... items)
 {
-    // utf8str_to_wstring() returns LLWString, which isn't necessarily the
-    // same as std::wstring
-    LLWString s(utf8str_to_wstring(item));
-    return std::wstring(s.begin(), s.end());
+    return gstringize<char>(std::forward<Items>(items)...);
 }
 
 /**
  * Specialization of gstringize for std::wstring return types
  */
-template <typename T>
-std::wstring wstringize(const T& item)
+template <typename... Items>
+auto wstringize(Items&&... items)
 {
-    return gstringize<wchar_t>(item);
+    return gstringize<wchar_t>(std::forward<Items>(items)...);
 }
 
 /**
-- 
cgit v1.2.3


From adc2666dbb2444194a5df84711207def7eba074c Mon Sep 17 00:00:00 2001
From: Nat Goodspeed <nat@lindenlab.com>
Date: Tue, 23 Nov 2021 10:11:16 -0500
Subject: SL-16094: Tweak llstring merge

---
 indra/llcommon/stringize.h | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

(limited to 'indra')

diff --git a/indra/llcommon/stringize.h b/indra/llcommon/stringize.h
index 8501beb16d..12df693910 100644
--- a/indra/llcommon/stringize.h
+++ b/indra/llcommon/stringize.h
@@ -53,7 +53,7 @@ void stream_to(std::basic_ostream<CHARTYPE>& out) {}
 template <typename CHARTYPE, typename T, typename... Items>
 void stream_to(std::basic_ostream<CHARTYPE>& out, T&& item, Items&&... items)
 {
-    out << std::move(item);
+    out << std::forward<T>(item);
     stream_to(out, std::forward<Items>(items)...);
 }
 
@@ -113,8 +113,8 @@ struct gstringize_impl<OUTCHAR, INCHAR*>
 template <typename CHARTYPE, typename T>
 auto gstringize(T&& item)
 {
-    // use decay<T> so we don't require separate specializations for T, const
-    // T, T&, const T& ...
+    // use decay<T> so we don't require separate specializations
+    // for T, const T, T&, const T& ...
     return gstringize_impl<CHARTYPE, std::decay_t<T>>()(std::forward<T>(item));
 }
 
-- 
cgit v1.2.3


From 408ac8f18cfb8f1c29381b0285f9cae91f5b685a Mon Sep 17 00:00:00 2001
From: Dave Parks <davep@lindenlab.com>
Date: Tue, 23 Nov 2021 16:35:14 +0000
Subject: SL-16401 Fix for rendering above water things into the water
 refraction render target.

---
 indra/newview/pipeline.cpp | 14 +++++++++-----
 1 file changed, 9 insertions(+), 5 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index 4710fdb085..d9d97ac1e5 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -2348,6 +2348,15 @@ void LLPipeline::updateCull(LLCamera& camera, LLCullResult& result, S32 water_cl
 
 	LL_RECORD_BLOCK_TIME(FTM_CULL);
 
+    if (planep != nullptr)
+    {
+        camera.setUserClipPlane(*planep);
+    }
+    else
+    {
+        camera.disableUserClipPlane();
+    }
+
 	grabReferences(result);
 
 	sCull->clear();
@@ -2402,11 +2411,6 @@ void LLPipeline::updateCull(LLCamera& camera, LLCullResult& result, S32 water_cl
 		mCubeVB->setBuffer(LLVertexBuffer::MAP_VERTEX);
 	}
 	
-    if (!sReflectionRender)
-    {
-        camera.disableUserClipPlane();
-    }
-
 	for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); 
 			iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
 	{
-- 
cgit v1.2.3


From 30cf50e6af3183680bd6413573eecd95b1f4fbb5 Mon Sep 17 00:00:00 2001
From: Nat Goodspeed <nat@lindenlab.com>
Date: Tue, 23 Nov 2021 14:25:16 -0500
Subject: SL-16094: Support ll_convert<std::string>(const char*)

and correspondingly, ll_convert<std::wstring>(const wchar_t*).

Now that we're using ll_convert() for single-argument stringize(arg), make
sure it can efficiently handle the simple case of constructing a string from a
const char pointer.
---
 indra/llcommon/llstring.h | 7 +++++++
 1 file changed, 7 insertions(+)

(limited to 'indra')

diff --git a/indra/llcommon/llstring.h b/indra/llcommon/llstring.h
index 54e3f9ee63..d94f549480 100644
--- a/indra/llcommon/llstring.h
+++ b/indra/llcommon/llstring.h
@@ -529,6 +529,13 @@ struct ll_convert_impl<T, T>
     T operator()(const T& in) const { return in; }
 };
 
+// simple construction from char*
+template<typename T>
+struct ll_convert_impl<T, const typename T::value_type*>
+{
+    T operator()(const typename T::value_type* in) const { return { in }; }
+};
+
 // specialize ll_convert_impl<TO, FROM> to return EXPR
 #define ll_convert_alias(TO, FROM, EXPR)                    \
 template<>                                                  \
-- 
cgit v1.2.3


From 37900e593d65e93913774f118a9aa461eeb8ef58 Mon Sep 17 00:00:00 2001
From: Nat Goodspeed <nat@lindenlab.com>
Date: Tue, 23 Nov 2021 15:40:36 -0500
Subject: SL-16094: Fix second startup hang.

Add LLWindowWin32Thread::Post(), like post() except it uses PostMessage() to
send the work item to the window thread. Support this in mainWindowProc().

Move LLWindowWin32::recreateWindow()'s destroy_window_handler() call onto the
window thread. Delaying destruction of the old HWND ensures that we can use
PostMessage() and GetMessage() with that HWND to pass the lambda work item.
Moreover, it's likely to be less buggy to call DestroyWindow() on the same
thread that created the window.

Make recreateWindow()'s window thread lambda bind the window class parameters
by value, rather than binding 'this' and back-referencing LLWindowWin32
members.

Make recreateWindow() construct the window thread lambda and then decide
whether to pass it to the window thread using post() or Post(), depending on
whether we have a current HWND -- therefore whether the window thread is
blocked on GetMessage(). That means we can eliminate the kickWindowThread()
call.

Make destroy_window_handler() accept HWND by value rather than by non-const
reference. Since it doesn't attempt to modify the caller's value, this is a
better match for the function's semantics anyway -- but importantly, it lets
us pass a const HWND.
---
 indra/llwindow/llwindowwin32.cpp | 193 +++++++++++++++++++++++++++++++++------
 1 file changed, 166 insertions(+), 27 deletions(-)

(limited to 'indra')

diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp
index b845f75ce4..162c38b862 100644
--- a/indra/llwindow/llwindowwin32.cpp
+++ b/indra/llwindow/llwindowwin32.cpp
@@ -46,6 +46,7 @@
 #include "llsdutil.h"
 #include "llglslshader.h"
 #include "llthreadsafequeue.h"
+#include "stringize.h"
 
 // System includes
 #include <commdlg.h>
@@ -55,7 +56,9 @@
 #include <shellapi.h>
 #include <fstream>
 #include <Imm.h>
+#include <iomanip>
 #include <future>
+#include <sstream>
 #include <utility>                  // std::pair
 
 // Require DirectInput version 8
@@ -80,6 +83,10 @@ const F32	ICON_FLASH_TIME = 0.5f;
 #define USER_DEFAULT_SCREEN_DPI 96 // Win7
 #endif
 
+// Claim a couple unused GetMessage() message IDs
+const UINT WM_DUMMY_(WM_USER + 0x0017);
+const UINT WM_POST_FUNCTION_(WM_USER + 0x0018);
+
 extern BOOL gDebugWindowProc;
 
 static std::thread::id sWindowThreadId;
@@ -340,12 +347,42 @@ struct LLWindowWin32::LLWindowWin32Thread : public LL::ThreadPool
 
     void run() override;
 
+    /// called by main thread to post work to this window thread
     template <typename CALLABLE>
     void post(CALLABLE&& func)
     {
         getQueue().post(std::forward<CALLABLE>(func));
     }
 
+    /**
+     * Like post(), Post() is a way of conveying a single work item to this
+     * thread. Its virtue is that it will definitely be executed "soon" rather
+     * than potentially waiting for the next frame: it uses PostMessage() to
+     * break us out of the window thread's blocked GetMessage() call. It's
+     * more expensive, though, not only from the Windows API latency of
+     * PostMessage() and GetMessage(), but also because it involves heap
+     * allocation and release.
+     *
+     * Require HWND from caller, even though we store an HWND locally.
+     * Otherwise, if our mWindowHandle was accessed from both threads, we'd
+     * have to protect it with a mutex.
+     */
+    template <typename CALLABLE>
+    void Post(HWND windowHandle, CALLABLE&& func)
+    {
+        // Move func to the heap. If we knew FuncType could fit into LPARAM,
+        // we could simply instantiate FuncType and pass it by value. But
+        // since we don't, we must put that on the heap as well as the
+        // internal heap allocation it likely requires to store func.
+        auto ptr = new FuncType(std::move(func));
+        WPARAM wparam{ 0xF1C };
+        LL_DEBUGS("Window") << "PostMessage(" << std::hex << windowHandle
+                            << ", " << WM_POST_FUNCTION_
+                            << ", " << wparam << std::dec << LL_ENDL;
+        PostMessage(windowHandle, WM_POST_FUNCTION_, wparam, LPARAM(ptr));
+    }
+
+    using FuncType = std::function<void()>;
     // call GetMessage() and pull enqueue messages for later processing
     void gatherInput();
     HWND mWindowHandle = NULL;
@@ -757,7 +794,7 @@ void LLWindowWin32::restore()
 // I'm turning off optimizations for this part to be sure code executes as intended
 // (it is a straw, but I have no idea why else __try can get overruled)
 #pragma optimize("", off)
-bool destroy_window_handler(HWND &hWnd)
+bool destroy_window_handler(HWND hWnd)
 {
     bool res;
     __try
@@ -1630,18 +1667,36 @@ void LLWindowWin32::recreateWindow(RECT window_rect, DWORD dw_ex_style, DWORD dw
     mWindowHandle = 0;
     mhDC = 0;
 
-    if (oldHandle && !destroy_window_handler(oldHandle))
-    {
-        LL_WARNS("Window") << "Failed to properly close window before recreating it!" << LL_ENDL;
-    }
-
     std::promise<std::pair<HWND, HDC>> promise;
-    mWindowThread->post(
-        [this, window_rect, dw_ex_style, dw_style, &promise]()
+    // What follows must be done on the window thread.
+    auto window_work =
+        [self=mWindowThread,
+         oldHandle,
+         // bind CreateWindowEx() parameters by value instead of
+         // back-referencing LLWindowWin32 members
+         windowClassName=mWindowClassName,
+         windowTitle=mWindowTitle,
+         hInstance=mhInstance,
+         window_rect,
+         dw_ex_style,
+         dw_style,
+         &promise]
+        ()
         {
+            LL_DEBUGS("Window") << "recreateWindow(): window_work entry" << LL_ENDL;
+            self->mWindowHandle = 0;
+            self->mhDC = 0;
+
+            // important to call DestroyWindow() from the window thread
+            if (oldHandle && !destroy_window_handler(oldHandle))
+            {
+                LL_WARNS("Window") << "Failed to properly close window before recreating it!"
+                                   << LL_ENDL;
+            }
+
             auto handle = CreateWindowEx(dw_ex_style,
-                mWindowClassName,
-                mWindowTitle,
+                windowClassName,
+                windowTitle,
                 WS_CLIPSIBLINGS | WS_CLIPCHILDREN | dw_style,
                 window_rect.left,								// x pos
                 window_rect.top,								// y pos
@@ -1649,34 +1704,44 @@ void LLWindowWin32::recreateWindow(RECT window_rect, DWORD dw_ex_style, DWORD dw
                 window_rect.bottom - window_rect.top,			// height
                 NULL,
                 NULL,
-                mhInstance,
+                hInstance,
                 NULL);
 
             if (! handle)
             {
                 // Failed to create window: clear the variables. This
                 // assignment is valid because we're running on mWindowThread.
-                mWindowThread->mWindowHandle = NULL;
-                mWindowThread->mhDC = 0;
+                self->mWindowHandle = NULL;
+                self->mhDC = 0;
             }
             else
             {
                 // Update mWindowThread's own mWindowHandle and mhDC.
-                mWindowThread->mWindowHandle = handle;
-                mWindowThread->mhDC = GetDC(handle);
+                self->mWindowHandle = handle;
+                self->mhDC = GetDC(handle);
             }
                 
             // It's important to wake up the future either way.
-            promise.set_value(std::make_pair(mWindowThread->mWindowHandle, mWindowThread->mhDC));
-        }
-    );
-
-    // Having posted work to mWindowThread, bump it out of blocked
-    // GetMessage() call. Normally we could just wait for the next
-    // gatherInput() call to notice the pending work item and call
-    // kickWindowThread(), but that would be on THIS calling thread, and we're
-    // about to block this thread until we get a result from mWindowThread.
-    kickWindowThread(oldHandle);
+            promise.set_value(std::make_pair(self->mWindowHandle, self->mhDC));
+            LL_DEBUGS("Window") << "recreateWindow(): window_work done" << LL_ENDL;
+        };
+    // But how we pass window_work to the window thread depends on whether we
+    // already have a window handle.
+    if (! oldHandle)
+    {
+        // Pass window_work using the WorkQueue: without an existing window
+        // handle, the window thread can't call GetMessage().
+        LL_DEBUGS("Window") << "posting window_work to WorkQueue" << LL_ENDL;
+        mWindowThread->post(window_work);
+    }
+    else
+    {
+        // Pass window_work using PostMessage(). We can still
+        // PostMessage(oldHandle) because oldHandle won't be destroyed until
+        // the window thread has retrieved and executed window_work.
+        LL_DEBUGS("Window") << "posting window_work to message queue" << LL_ENDL;
+        mWindowThread->Post(oldHandle, window_work);
+    }
 
     auto future = promise.get_future();
     // This blocks until mWindowThread processes CreateWindowEx() and calls
@@ -2116,6 +2181,23 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
     ASSERT_WINDOW_THREAD();
     LL_PROFILE_ZONE_SCOPED;
 
+    LL_DEBUGS("Window") << "mainWindowProc(" << std::hex << h_wnd
+                        << ", " << u_msg
+                        << ", " << w_param << ")" << std::dec << LL_ENDL;
+
+    if (u_msg == WM_POST_FUNCTION_)
+    {
+        LL_DEBUGS("Window") << "WM_POST_FUNCTION_" << LL_ENDL;
+        // from LLWindowWin32Thread::Post()
+        // Cast l_param back to the pointer to the heap FuncType
+        // allocated by Post(). Capture in unique_ptr so we'll delete
+        // once we're done with it.
+        std::unique_ptr<LLWindowWin32Thread::FuncType>
+            ptr(reinterpret_cast<LLWindowWin32Thread::FuncType*>(l_param));
+        (*ptr)();
+        return 0;
+    }
+
     // 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;
@@ -4415,14 +4497,61 @@ inline LLWindowWin32::LLWindowWin32Thread::LLWindowWin32Thread()
 {
 }
 
+/**
+ * LogChange is to log changes in status while trying to avoid spamming the
+ * log with repeated messages, especially in a tight loop. It refuses to log
+ * a continuous run of identical messages, but logs every time the message
+ * changes. (It will happily spam when messages quickly bounce back and
+ * forth.)
+ */
+class LogChange
+{
+public:
+    LogChange(const std::string& tag):
+        mTag(tag)
+    {}
+
+    template <typename... Items>
+    void always(Items&&... items)
+    {
+        // This odd construct ensures that the stringize() call is only
+        // executed if DEBUG logging is enabled for the passed tag.
+        LL_DEBUGS(mTag.c_str());
+        log(LL_CONT, stringize(std::forward<Items>(items)...));
+        LL_ENDL;
+    }
+
+    template <typename... Items>
+    void onChange(Items&&... items)
+    {
+        LL_DEBUGS(mTag.c_str());
+        auto str = stringize(std::forward<Items>(items)...);
+        if (str != mPrev)
+        {
+            log(LL_CONT, str);
+        }
+        LL_ENDL;
+    }
+
+private:
+    void log(std::ostream& out, const std::string& message)
+    {
+        mPrev = message;
+        out << message;
+    }
+    std::string mTag;
+    std::string mPrev;
+};
+
 void LLWindowWin32::LLWindowWin32Thread::run()
 {
     sWindowThreadId = std::this_thread::get_id();
+    LogChange logger("Window");
+
     while (! getQueue().done())
     {
         LL_PROFILE_ZONE_SCOPED;
 
-
         if (mWindowHandle != 0)
         {
             MSG msg;
@@ -4430,15 +4559,19 @@ void LLWindowWin32::LLWindowWin32Thread::run()
             if (mhDC == 0)
             {
                 LL_PROFILE_ZONE_NAMED("w32t - PeekMessage");
+                logger.onChange("PeekMessage(", std::hex, mWindowHandle, ")");
                 status = PeekMessage(&msg, mWindowHandle, 0, 0, PM_REMOVE);
             }
             else
             {
                 LL_PROFILE_ZONE_NAMED("w32t - GetMessage");
+                logger.always("GetMessage(", std::hex, mWindowHandle, ")");
                 status = GetMessage(&msg, mWindowHandle, 0, 0);
             }
             if (status > 0)
             {
+                logger.always("got MSG (", std::hex, msg.hwnd, ", ", msg.message,
+                              ", ", msg.wParam, ")");
                 TranslateMessage(&msg);
                 DispatchMessage(&msg);
 
@@ -4448,6 +4581,7 @@ void LLWindowWin32::LLWindowWin32Thread::run()
 
         {
             LL_PROFILE_ZONE_NAMED("w32t - Function Queue");
+            logger.onChange("runPending()");
             //process any pending functions
             getQueue().runPending();
         }
@@ -4455,6 +4589,7 @@ void LLWindowWin32::LLWindowWin32Thread::run()
 #if 0
         {
             LL_PROFILE_ZONE_NAMED("w32t - Sleep");
+            logger.always("sleep(1)");
             std::this_thread::sleep_for(std::chrono::milliseconds(1));
         }
 #endif
@@ -4480,6 +4615,10 @@ void LLWindowWin32::kickWindowThread(HWND windowHandle)
         // post a nonsense user message to wake up the Window Thread in
         // case any functions are pending and no windows events came
         // through this frame
-        PostMessage(windowHandle, WM_USER + 0x0017, 0xB0B0, 0x1337);
+        WPARAM wparam{ 0xB0B0 };
+        LL_DEBUGS("Window") << "PostMessage(" << std::hex << windowHandle
+                            << ", " << WM_DUMMY_
+                            << ", " << wparam << ")" << std::dec << LL_ENDL;
+        PostMessage(windowHandle, WM_DUMMY_, wparam, 0x1337);
     }
 }
-- 
cgit v1.2.3


From 724193e5b01e5c1ae879a6364f54601cdb22c2c1 Mon Sep 17 00:00:00 2001
From: Dave Parks <davep@lindenlab.com>
Date: Tue, 23 Nov 2021 20:46:27 +0000
Subject: SL-16239 Fix for slowdown on AMD GPUs (disable core profile and
 remove volatile members from LLVertexBuffer)

---
 indra/llrender/llvertexbuffer.cpp | 54 ++++++++++++++++++++++-----------------
 indra/llrender/llvertexbuffer.h   | 22 ++++++++--------
 indra/newview/featuretable.txt    |  4 ++-
 3 files changed, 45 insertions(+), 35 deletions(-)

(limited to 'indra')

diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp
index 5ea07ddcb1..46654cc5b9 100644
--- a/indra/llrender/llvertexbuffer.cpp
+++ b/indra/llrender/llvertexbuffer.cpp
@@ -157,12 +157,12 @@ LLVBOPool::LLVBOPool(U32 vboUsage, U32 vboType)
 	std::fill(mMissCount.begin(), mMissCount.end(), 0);
 }
 
-volatile U8* LLVBOPool::allocate(U32& name, U32 size, bool for_seed)
+U8* LLVBOPool::allocate(U32& name, U32 size, bool for_seed)
 {
 	LL_PROFILE_ZONE_SCOPED
 	llassert(vbo_block_size(size) == size);
 	
-	volatile U8* ret = NULL;
+	U8* ret = NULL;
 
 	U32 i = vbo_block_index(size);
 
@@ -256,7 +256,7 @@ volatile U8* LLVBOPool::allocate(U32& name, U32 size, bool for_seed)
 	return ret;
 }
 
-void LLVBOPool::release(U32 name, volatile U8* buffer, U32 size)
+void LLVBOPool::release(U32 name, U8* buffer, U32 size)
 {
 	llassert(vbo_block_size(size) == size);
 
@@ -749,7 +749,7 @@ void LLVertexBuffer::drawRangeFast(U32 mode, U32 start, U32 end, U32 count, U32
     mMappable = false;
     gGL.syncMatrices();
 
-    U16* idx = ((U16*)(U8*)mAlignedIndexOffset) + indices_offset;
+    U16* idx = ((U16*)getIndicesPointer()) + indices_offset;
 
     LL_PROFILER_GPU_ZONEC("gl.DrawRangeElements", 0xFFFF00)
         glDrawRangeElements(sGLMode[mode], start, end, count, GL_UNSIGNED_SHORT,
@@ -1539,7 +1539,7 @@ bool expand_region(LLVertexBuffer::MappedRegion& region, S32 index, S32 count)
 
 
 // Map for data access
-volatile U8* LLVertexBuffer::mapVertexBuffer(S32 type, S32 index, S32 count, bool map_range)
+U8* LLVertexBuffer::mapVertexBuffer(S32 type, S32 index, S32 count, bool map_range)
 {
     LL_PROFILE_ZONE_SCOPED;
 	bindGLBuffer(true);
@@ -1601,7 +1601,7 @@ volatile U8* LLVertexBuffer::mapVertexBuffer(S32 type, S32 index, S32 count, boo
 			}
 			else
 			{
-				volatile U8* src = NULL;
+				U8* src = NULL;
 				waitFence();
 				if (gGLManager.mHasMapBufferRange)
 				{
@@ -1660,7 +1660,7 @@ volatile U8* LLVertexBuffer::mapVertexBuffer(S32 type, S32 index, S32 count, boo
 
 				llassert(src != NULL);
 
-				mMappedData = LL_NEXT_ALIGNED_ADDRESS<volatile U8>(src);
+				mMappedData = LL_NEXT_ALIGNED_ADDRESS<U8>(src);
 				mAlignedOffset = mMappedData - src;
 			
 				stop_glerror();
@@ -1716,7 +1716,7 @@ volatile U8* LLVertexBuffer::mapVertexBuffer(S32 type, S32 index, S32 count, boo
 }
 
 
-volatile U8* LLVertexBuffer::mapIndexBuffer(S32 index, S32 count, bool map_range)
+U8* LLVertexBuffer::mapIndexBuffer(S32 index, S32 count, bool map_range)
 {
     LL_PROFILE_ZONE_SCOPED;
 	bindGLIndices(true);
@@ -1786,7 +1786,7 @@ volatile U8* LLVertexBuffer::mapIndexBuffer(S32 index, S32 count, bool map_range
 			}
 			else
 			{
-				volatile U8* src = NULL;
+				U8* src = NULL;
 				waitFence();
 				if (gGLManager.mHasMapBufferRange)
 				{
@@ -2068,7 +2068,7 @@ template <class T,S32 type> struct VertexBufferStrider
 	{
 		if (type == LLVertexBuffer::TYPE_INDEX)
 		{
-			volatile U8* ptr = vbo.mapIndexBuffer(index, count, map_range);
+			U8* ptr = vbo.mapIndexBuffer(index, count, map_range);
 
 			if (ptr == NULL)
 			{
@@ -2084,7 +2084,7 @@ template <class T,S32 type> struct VertexBufferStrider
 		{
 			S32 stride = LLVertexBuffer::sTypeSize[type];
 
-			volatile U8* ptr = vbo.mapVertexBuffer(type, index, count, map_range);
+			U8* ptr = vbo.mapVertexBuffer(type, index, count, map_range);
 
 			if (ptr == NULL)
 			{
@@ -2454,29 +2454,37 @@ 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);
+    if (useVBOs())
+    {
+        //set up pointers if the data mask is different ...
+        bool setup = (sLastMask != data_mask);
 
-    
-    const bool bindBuffer = bindGLBufferFast();
-    const bool bindIndices = bindGLIndicesFast();
+        const bool bindBuffer = bindGLBufferFast();
+        const bool bindIndices = bindGLIndicesFast();
 
-    setup = setup || bindBuffer || bindIndices;
+        setup = setup || bindBuffer || bindIndices;
+        
+        setupClientArrays(data_mask);
 
-    setupClientArrays(data_mask);
-  
-    if (data_mask && setup)
+        if (data_mask && setup)
+        {
+            setupVertexBufferFast(data_mask);
+            sSetCount++;
+        }
+    }
+    else
     {
-        setupVertexBufferFast(data_mask);
-        sSetCount++;
+        //fallback to slow path when not using VBOs
+        setBuffer(data_mask);
     }
 }
 
+
 // virtual (default)
 void LLVertexBuffer::setupVertexBuffer(U32 data_mask)
 {
 	stop_glerror();
-	volatile U8* base = useVBOs() ? (U8*) mAlignedOffset : mMappedData;
+	U8* base = useVBOs() ? (U8*) mAlignedOffset : mMappedData;
 
 	if (gDebugGL && ((data_mask & mTypeMask) != data_mask))
 	{
diff --git a/indra/llrender/llvertexbuffer.h b/indra/llrender/llvertexbuffer.h
index 1b400b3aad..baf8407fc6 100644
--- a/indra/llrender/llvertexbuffer.h
+++ b/indra/llrender/llvertexbuffer.h
@@ -64,10 +64,10 @@ public:
 	const U32 mType;
 
 	//size MUST be a power of 2
-	volatile U8* allocate(U32& name, U32 size, bool for_seed = false);
+	U8* allocate(U32& name, U32 size, bool for_seed = false);
 	
 	//size MUST be the size provided to allocate that returned the given name
-	void release(U32 name, volatile U8* buffer, U32 size);
+	void release(U32 name, U8* buffer, U32 size);
 	
 	//batch allocate buffers to be provided to the application on demand
 	void seedPool();
@@ -82,7 +82,7 @@ public:
 	{
 	public:
 		U32 mGLName;
-		volatile U8* mClientData;
+		U8* mClientData;
 	};
 
 	typedef std::list<Record> record_list_t;
@@ -234,8 +234,8 @@ public:
 	LLVertexBuffer(U32 typemask, S32 usage);
 	
 	// map for data access
-	volatile U8*		mapVertexBuffer(S32 type, S32 index, S32 count, bool map_range);
-	volatile U8*		mapIndexBuffer(S32 index, S32 count, bool map_range);
+	U8*		mapVertexBuffer(S32 type, S32 index, S32 count, bool map_range);
+	U8*		mapIndexBuffer(S32 index, S32 count, bool map_range);
 
 	void bindForFeedback(U32 channel, U32 type, U32 index, U32 count);
 
@@ -278,14 +278,14 @@ public:
 	S32 getNumVerts() const					{ return mNumVerts; }
 	S32 getNumIndices() const				{ return mNumIndices; }
 	
-	volatile U8* getIndicesPointer() const			{ return useVBOs() ? (U8*) mAlignedIndexOffset : mMappedIndexData; }
-	volatile U8* getVerticesPointer() const			{ return useVBOs() ? (U8*) mAlignedOffset : mMappedData; }
+	U8* getIndicesPointer() const			{ return useVBOs() ? (U8*) mAlignedIndexOffset : mMappedIndexData; }
+	U8* getVerticesPointer() const			{ return useVBOs() ? (U8*) mAlignedOffset : mMappedData; }
 	U32 getTypeMask() const					{ return mTypeMask; }
 	bool hasDataType(S32 type) const		{ return ((1 << type) & getTypeMask()); }
 	S32 getSize() const;
 	S32 getIndicesSize() const				{ return mIndicesSize; }
-	volatile U8* getMappedData() const				{ return mMappedData; }
-	volatile U8* getMappedIndices() const			{ return mMappedIndexData; }
+	U8* getMappedData() const				{ return mMappedData; }
+	U8* getMappedIndices() const			{ return mMappedIndexData; }
 	S32 getOffset(S32 type) const			{ return mOffsets[type]; }
 	S32 getUsage() const					{ return mUsage; }
 	bool isWriteable() const				{ return (mMappable || mUsage == GL_STREAM_DRAW_ARB) ? true : false; }
@@ -318,8 +318,8 @@ protected:
 	U32		mGLIndices;		// GL IBO handle
 	U32		mGLArray;		// GL VAO handle
 	
-	volatile U8* mMappedData;	// pointer to currently mapped data (NULL if unmapped)
-	volatile U8* mMappedIndexData;	// pointer to currently mapped indices (NULL if unmapped)
+	U8* mMappedData;	// pointer to currently mapped data (NULL if unmapped)
+	U8* mMappedIndexData;	// pointer to currently mapped indices (NULL if unmapped)
 
 	U32		mMappedDataUsingVBOs : 1;
 	U32		mMappedIndexDataUsingVBOs : 1;
diff --git a/indra/newview/featuretable.txt b/indra/newview/featuretable.txt
index f1bf8d76c2..bd66641db9 100644
--- a/indra/newview/featuretable.txt
+++ b/indra/newview/featuretable.txt
@@ -70,6 +70,7 @@ RenderShadowDetail			1	2
 RenderUseStreamVBO			1	1
 RenderFSAASamples			1	16
 RenderMaxTextureIndex		1	16
+RenderGLCoreProfile         1   1
 
 //
 // Low Graphics Settings (fixed function)
@@ -619,9 +620,10 @@ RenderAvatarCloth			0	0
 RenderVBOEnable				1	0
 
 // ATI cards generally perform better when not using VBOs for streaming data
-
+// ATI cards also prefer an OpenGL Compatibility Profile Context
 list ATI
 RenderUseStreamVBO			1	0
+RenderGLCoreProfile         1   0
 
 // Disable vertex buffer objects by default for ATI cards with little video memory
 list ATIVramLT256
-- 
cgit v1.2.3


From fecbe73fca8cefc1cd189226e12aab14daaedc3c Mon Sep 17 00:00:00 2001
From: Mnikolenko Productengine <mnikolenko@productengine.com>
Date: Tue, 23 Nov 2021 22:52:58 +0200
Subject: SL-16368 Fix for crashing on right-clicking mesh avatar on 32bit
 viewer

---
 indra/newview/llvovolume.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'indra')

diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index 6c3f026087..4a9bec8df9 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -4827,6 +4827,7 @@ void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, cons
 	LLMatrix4a mat[kMaxJoints];
 	U32 maxJoints = LLSkinningUtil::getMeshJointCount(skin);
     LLSkinningUtil::initSkinningMatrixPalette(mat, maxJoints, skin, avatar);
+    const LLMatrix4a bind_shape_matrix = skin->mBindShapeMatrix;
 
     S32 rigged_vert_count = 0;
     S32 rigged_face_count = 0;
@@ -4842,7 +4843,6 @@ void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, cons
 		if ( weight )
 		{
             LLSkinningUtil::checkSkinWeights(weight, dst_face.mNumVertices, skin);
-			const LLMatrix4a& bind_shape_matrix = skin->mBindShapeMatrix;
 
 			LLVector4a* pos = dst_face.mPositions;
 
-- 
cgit v1.2.3


From 8852cb9cbd25df8d25fa43cf39b222ab8381ebd6 Mon Sep 17 00:00:00 2001
From: Dave Parks <davep@lindenlab.com>
Date: Tue, 23 Nov 2021 21:33:21 +0000
Subject: SL-9436 Fix for glow disappearing when 100% transparent.

---
 indra/newview/llvovolume.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'indra')

diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index 4a9bec8df9..464e6efd2e 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -5711,7 +5711,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 						}
 						else
 						{
-                            if (te->getColor().mV[3] > 0.f)
+                            if (te->getColor().mV[3] > 0.f || te->getGlow() > 0.f)
                             { //only treat as alpha in the pipeline if < 100% transparent
                                 drawablep->setState(LLDrawable::HAS_ALPHA);
                                 add_face(sAlphaFaces, alpha_count, facep);
-- 
cgit v1.2.3


From 2b96f89c2a374d72c0a8bc28a7b06ad4db7eae6e Mon Sep 17 00:00:00 2001
From: Nat Goodspeed <nat@lindenlab.com>
Date: Tue, 23 Nov 2021 20:39:32 -0500
Subject: SL-16400: Add ThreadPool::start() method, and call it.

It's sometimes important to finish other initialization before launching the
threads in the ThreadPool, so make that an explicit step. In particular, we
were launching the LLImageGL texture thread before initializing the GL
context, resulting in all gray textures.
---
 indra/llcommon/threadpool.cpp    | 10 +++++++---
 indra/llcommon/threadpool.h      |  9 +++++++++
 indra/llrender/llimagegl.cpp     |  5 +----
 indra/llwindow/llwindowwin32.cpp |  1 +
 4 files changed, 18 insertions(+), 7 deletions(-)

(limited to 'indra')

diff --git a/indra/llcommon/threadpool.cpp b/indra/llcommon/threadpool.cpp
index 06e0dc5bfc..ba914035e2 100644
--- a/indra/llcommon/threadpool.cpp
+++ b/indra/llcommon/threadpool.cpp
@@ -23,11 +23,15 @@
 
 LL::ThreadPool::ThreadPool(const std::string& name, size_t threads, size_t capacity):
     mQueue(name, capacity),
-    mName("ThreadPool:" + name)
+    mName("ThreadPool:" + name),
+    mThreadCount(threads)
+{}
+
+void LL::ThreadPool::start()
 {
-    for (size_t i = 0; i < threads; ++i)
+    for (size_t i = 0; i < mThreadCount; ++i)
     {
-        std::string tname{ STRINGIZE(mName << ':' << (i+1) << '/' << threads) };
+        std::string tname{ stringize(mName, ':', (i+1), '/', mThreadCount) };
         mThreads.emplace_back(tname, [this, tname]()
             {
                 LL_PROFILER_SET_THREAD_NAME(tname.c_str());
diff --git a/indra/llcommon/threadpool.h b/indra/llcommon/threadpool.h
index 1ca24aec58..b79c9b9090 100644
--- a/indra/llcommon/threadpool.h
+++ b/indra/llcommon/threadpool.h
@@ -32,6 +32,14 @@ namespace LL
         ThreadPool(const std::string& name, size_t threads=1, size_t capacity=1024);
         virtual ~ThreadPool();
 
+        /**
+         * Launch the ThreadPool. Until this call, a constructed ThreadPool
+         * launches no threads. That permits coders to derive from ThreadPool,
+         * or store it as a member of some other class, but refrain from
+         * launching it until all other construction is complete.
+         */
+        void start();
+
         /**
          * ThreadPool listens for application shutdown messages on the "LLApp"
          * LLEventPump. Call close() to shut down this ThreadPool early.
@@ -54,6 +62,7 @@ namespace LL
 
         WorkQueue mQueue;
         std::string mName;
+        size_t mThreadCount;
         std::vector<std::pair<std::string, std::thread>> mThreads;
     };
 
diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp
index eda61d3c74..894eb8c773 100644
--- a/indra/llrender/llimagegl.cpp
+++ b/indra/llrender/llimagegl.cpp
@@ -2261,6 +2261,7 @@ LLImageGLThread::LLImageGLThread(LLWindow* window)
     mFinished = false;
 
     mContext = mWindow->createSharedContext();
+    ThreadPool::start();
 }
 
 void LLImageGLThread::run()
@@ -2268,10 +2269,6 @@ void LLImageGLThread::run()
     LL_PROFILE_ZONE_SCOPED;
     // We must perform setup on this thread before actually servicing our
     // WorkQueue, likewise cleanup afterwards.
-    while (mContext == nullptr)
-    { // HACK -- wait for mContext to be initialized since this thread will usually start before mContext is set
-        std::this_thread::sleep_for(std::chrono::milliseconds(1));
-    }
     mWindow->makeContextCurrent(mContext);
     gGL.init();
     ThreadPool::run();
diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp
index 51fd228619..af7b8d91f0 100644
--- a/indra/llwindow/llwindowwin32.cpp
+++ b/indra/llwindow/llwindowwin32.cpp
@@ -4495,6 +4495,7 @@ std::vector<std::string> LLWindowWin32::getDynamicFallbackFontList()
 inline LLWindowWin32::LLWindowWin32Thread::LLWindowWin32Thread()
     : ThreadPool("Window Thread", 1, MAX_QUEUE_SIZE)
 {
+    ThreadPool::start();
 }
 
 /**
-- 
cgit v1.2.3


From 67ace0df9953ce3264048c3946720a9df492edfa Mon Sep 17 00:00:00 2001
From: Nat Goodspeed <nat@lindenlab.com>
Date: Tue, 23 Nov 2021 20:48:44 -0500
Subject: SL-16400: Address a couple shutdown crashes.

It can happen that we try to post() work for LLWindowWin32's window thread
after the thread's WorkQueue has been closed.

Also, instead of giving the "General" ThreadPool static lifespan, put it on
the heap, anchored with a static unique_ptr.
---
 indra/llwindow/llwindowwin32.cpp | 10 +++++++++-
 indra/newview/llstartup.cpp      | 32 ++++++++++++++------------------
 indra/newview/llstartup.h        |  8 ++++----
 3 files changed, 27 insertions(+), 23 deletions(-)

(limited to 'indra')

diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp
index af7b8d91f0..7f8f88a749 100644
--- a/indra/llwindow/llwindowwin32.cpp
+++ b/indra/llwindow/llwindowwin32.cpp
@@ -351,7 +351,15 @@ struct LLWindowWin32::LLWindowWin32Thread : public LL::ThreadPool
     template <typename CALLABLE>
     void post(CALLABLE&& func)
     {
-        getQueue().post(std::forward<CALLABLE>(func));
+        try
+        {
+            getQueue().post(std::forward<CALLABLE>(func));
+        }
+        catch (const LLThreadSafeQueueInterrupt&)
+        {
+            // Shutdown timing is tricky. The main thread can end up trying
+            // to post a cursor position after having closed the WorkQueue.
+        }
     }
 
     /**
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index 9a4149948c..2b94ab76ba 100644
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -35,6 +35,7 @@
 #else
 #	include <sys/stat.h>		// mkdir()
 #endif
+#include <memory>                   // std::unique_ptr
 
 #include "llviewermedia_streamingaudio.h"
 #include "llaudioengine.h"
@@ -255,9 +256,10 @@ static bool mBenefitsSuccessfullyInit = false;
 
 const F32 STATE_AGENT_WAIT_TIMEOUT = 240; //seconds
 
-boost::scoped_ptr<LLEventPump> LLStartUp::sStateWatcher(new LLEventStream("StartupState"));
-boost::scoped_ptr<LLStartupListener> LLStartUp::sListener(new LLStartupListener());
-boost::scoped_ptr<LLViewerStats::PhaseMap> LLStartUp::sPhases(new LLViewerStats::PhaseMap);
+std::unique_ptr<LLEventPump> LLStartUp::sStateWatcher(new LLEventStream("StartupState"));
+std::unique_ptr<LLStartupListener> LLStartUp::sListener(new LLStartupListener());
+std::unique_ptr<LLViewerStats::PhaseMap> LLStartUp::sPhases(new LLViewerStats::PhaseMap);
+std::unique_ptr<LL::ThreadPool> gGeneralThreadPool;
 
 //
 // local function declaration
@@ -304,20 +306,6 @@ void callback_cache_name(const LLUUID& id, const std::string& full_name, bool is
 // local classes
 //
 
-void launchThreadPool()
-{
-    LLSD poolSizes{ gSavedSettings.getLLSD("ThreadPoolSizes") };
-    LLSD sizeSpec{ poolSizes["General"] };
-    LLSD::Integer size{ sizeSpec.isInteger()? sizeSpec.asInteger() : 3 };
-    LL_DEBUGS("ThreadPool") << "Instantiating General pool with "
-                            << size << " threads" << LL_ENDL;
-    // Use a function-static ThreadPool: static duration, but instantiated
-    // only on demand.
-    // We don't want anyone, especially the main thread, to have to block
-    // due to this ThreadPool being full.
-    static LL::ThreadPool pool("General", size, 1024*1024);
-}
-
 void update_texture_fetch()
 {
 	LLAppViewer::getTextureCache()->update(1); // unpauses the texture cache thread
@@ -1507,7 +1495,15 @@ bool idle_startup()
 		display_startup();
 
 		// start up the ThreadPool we'll use for textures et al.
-		launchThreadPool();
+		LLSD poolSizes{ gSavedSettings.getLLSD("ThreadPoolSizes") };
+		LLSD sizeSpec{ poolSizes["General"] };
+		LLSD::Integer poolSize{ sizeSpec.isInteger()? sizeSpec.asInteger() : 3 };
+		LL_DEBUGS("ThreadPool") << "Instantiating General pool with "
+								<< poolSize << " threads" << LL_ENDL;
+		// We don't want anyone, especially the main thread, to have to block
+		// due to this ThreadPool being full.
+		gGeneralThreadPool.reset(new LL::ThreadPool("General", poolSize, 1024*1024));
+		gGeneralThreadPool->start();
 
 		// Initialize global class data needed for surfaces (i.e. textures)
 		LL_DEBUGS("AppInit") << "Initializing sky..." << LL_ENDL;
diff --git a/indra/newview/llstartup.h b/indra/newview/llstartup.h
index 116aeb36a7..fe8e215f76 100644
--- a/indra/newview/llstartup.h
+++ b/indra/newview/llstartup.h
@@ -27,7 +27,7 @@
 #ifndef LL_LLSTARTUP_H
 #define LL_LLSTARTUP_H
 
-#include <boost/scoped_ptr.hpp>
+#include <memory>                   // unique_ptr
 
 class LLViewerTexture ;
 class LLEventPump;
@@ -130,9 +130,9 @@ private:
 
 	static std::string startupStateToString(EStartupState state);
 	static EStartupState gStartupState; // Do not set directly, use LLStartup::setStartupState
-	static boost::scoped_ptr<LLEventPump> sStateWatcher;
-	static boost::scoped_ptr<LLStartupListener> sListener;
-	static boost::scoped_ptr<LLViewerStats::PhaseMap> sPhases;
+	static std::unique_ptr<LLEventPump> sStateWatcher;
+	static std::unique_ptr<LLStartupListener> sListener;
+	static std::unique_ptr<LLViewerStats::PhaseMap> sPhases;
 };
 
 
-- 
cgit v1.2.3


From 877a02dba1df8a5d7d9f40b04d6be834ed9864da Mon Sep 17 00:00:00 2001
From: Nat Goodspeed <nat@lindenlab.com>
Date: Wed, 24 Nov 2021 09:38:56 -0500
Subject: SL-16094: Fix merge glitches from previous revert.

---
 indra/llcommon/llthreadsafequeue.h | 19 +++++++++++--------
 1 file changed, 11 insertions(+), 8 deletions(-)

(limited to 'indra')

diff --git a/indra/llcommon/llthreadsafequeue.h b/indra/llcommon/llthreadsafequeue.h
index a588175074..2806506550 100644
--- a/indra/llcommon/llthreadsafequeue.h
+++ b/indra/llcommon/llthreadsafequeue.h
@@ -85,8 +85,8 @@ public:
 	LLThreadSafeQueue(U32 capacity = 1024);
 	virtual ~LLThreadSafeQueue() {}
 
-	// Add an element to the queue (will block if the queue has
-	// reached capacity).
+	// 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.
@@ -95,6 +95,11 @@ public:
 	// legacy name
 	void pushFront(ElementT const & element) { return push(element); }
 
+	// Add an element to the queue (will block if the queue has reached
+	// capacity). Return false if the queue is closed before push is possible.
+	template <typename T>
+	bool pushIfOpen(T&& element);
+
 	// Try to add an element to the queue without blocking. Returns
 	// true only if the element was actually added.
 	template <typename T>
@@ -314,8 +319,8 @@ bool LLThreadSafeQueue<ElementT, QueueT>::push_(lock_t& lock, T&& element)
 
 
 template <typename ElementT, typename QueueT>
-template<typename T>
-void LLThreadSafeQueue<ElementT, QueueT>::push(T&& element)
+template <typename T>
+bool LLThreadSafeQueue<ElementT, QueueT>::pushIfOpen(T&& element)
 {
     LL_PROFILE_ZONE_SCOPED;
     lock_t lock1(mLock);
@@ -325,12 +330,10 @@ void LLThreadSafeQueue<ElementT, QueueT>::push(T&& element)
         // drained or not: the moment either end calls close(), further push()
         // operations will fail.
         if (mClosed)
-        {
-            LLTHROW(LLThreadSafeQueueInterrupt());
-        }
+            return false;
 
         if (push_(lock1, std::forward<T>(element)))
-            return;
+            return true;
 
         // Storage Full. Wait for signal.
         mCapacityCond.wait(lock1);
-- 
cgit v1.2.3


From 78d837789a3741c65c3334934d96a505a522ee43 Mon Sep 17 00:00:00 2001
From: Nat Goodspeed <nat@lindenlab.com>
Date: Wed, 24 Nov 2021 09:43:37 -0500
Subject: SL-16400: Make WorkQueue::runFor() and runUntil() stop when done.

runFor(interval) and runUntil(timestamp) are intended, and documented, to run
*no longer than* the specified time. Instead, the initial implementation
always waited the full specified time, hoping for work to arrive. Fix that:
once we clear work that's already pending, return right away.
---
 indra/llcommon/workqueue.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

(limited to 'indra')

diff --git a/indra/llcommon/workqueue.cpp b/indra/llcommon/workqueue.cpp
index 1e89d87cff..e7d40354aa 100644
--- a/indra/llcommon/workqueue.cpp
+++ b/indra/llcommon/workqueue.cpp
@@ -78,8 +78,8 @@ bool LL::WorkQueue::runUntil(const TimePoint& until)
     LL_PROFILE_ZONE_SCOPED;
     // 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))
+    // runUntil() is simply a time-bounded runPending().
+    for (Work work; TimePoint::clock::now() < until && mQueue.tryPop(work); )
     {
         callWork(work);
     }
-- 
cgit v1.2.3


From 0b066539fe68dc5750900c3452189645c40adb45 Mon Sep 17 00:00:00 2001
From: Nat Goodspeed <nat@lindenlab.com>
Date: Wed, 24 Nov 2021 10:47:54 -0500
Subject: DRTVWR-546, SL-16220, SL-16094: Undo previous glthread branch revert.

Reverting a merge is sticky: it tells git you never want to see that branch
again. Merging the DRTVWR-546 branch, which contained the revert, into the
glthread branch undid much of the development work on that branch. To restore
it we must revert the revert.

This reverts commit 029b41c0419e975bbb28454538b46dc69ce5d2ba.
---
 indra/llcommon/CMakeLists.txt                    |   3 +-
 indra/llcommon/llsingleton.h                     |  14 +-
 indra/llcommon/tests/threadsafeschedule_test.cpp |   4 +-
 indra/llcommon/tests/workqueue_test.cpp          |  72 ++++-
 indra/llcommon/timing.cpp                        |  25 --
 indra/llcommon/workqueue.cpp                     |  30 ++-
 indra/llcommon/workqueue.h                       | 197 +++++++++-----
 indra/llrender/llimagegl.cpp                     |  89 ++-----
 indra/llrender/llimagegl.h                       |  27 +-
 indra/llwindow/llwindowwin32.cpp                 | 321 +++--------------------
 indra/llwindow/llwindowwin32.h                   |  36 +--
 indra/newview/CMakeLists.txt                     |   3 +-
 indra/newview/app_settings/settings.xml          |  25 ++
 indra/newview/llappviewer.cpp                    |  51 +---
 indra/newview/llmainlooprepeater.cpp             |  88 -------
 indra/newview/llmainlooprepeater.h               |  64 -----
 indra/newview/llstartup.cpp                      |  17 ++
 indra/newview/llviewertexture.cpp                |  34 ++-
 indra/newview/llviewertexture.h                  |   4 +
 19 files changed, 371 insertions(+), 733 deletions(-)
 delete mode 100644 indra/llcommon/timing.cpp
 delete mode 100644 indra/newview/llmainlooprepeater.cpp
 delete mode 100644 indra/newview/llmainlooprepeater.h

(limited to 'indra')

diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt
index 9defa6b6c1..782f656406 100644
--- a/indra/llcommon/CMakeLists.txt
+++ b/indra/llcommon/CMakeLists.txt
@@ -119,8 +119,8 @@ set(llcommon_SOURCE_FILES
     lluriparser.cpp
     lluuid.cpp
     llworkerthread.cpp
-    timing.cpp
     u64.cpp
+    threadpool.cpp
     workqueue.cpp
     StackWalker.cpp
     )
@@ -256,6 +256,7 @@ set(llcommon_HEADER_FILES
     lockstatic.h
     stdtypes.h
     stringize.h
+    threadpool.h
     threadsafeschedule.h
     timer.h
     tuple.h
diff --git a/indra/llcommon/llsingleton.h b/indra/llcommon/llsingleton.h
index f85f961287..6042c0906c 100644
--- a/indra/llcommon/llsingleton.h
+++ b/indra/llcommon/llsingleton.h
@@ -847,14 +847,13 @@ template<class T>
 class LLSimpleton
 {
 public:
-    static T* sInstance;
-    
-    static void createInstance() 
-    { 
+    template <typename... ARGS>
+    static void createInstance(ARGS&&... args)
+    {
         llassert(sInstance == nullptr);
-        sInstance = new T(); 
+        sInstance = new T(std::forward<ARGS>(args)...);
     }
-    
+
     static inline T* getInstance() { return sInstance; }
     static inline T& instance() { return *getInstance(); }
     static inline bool instanceExists() { return sInstance != nullptr; }
@@ -864,6 +863,9 @@ public:
         delete sInstance;
         sInstance = nullptr;
     }
+
+private:
+    static T* sInstance;
 };
 
 template <class T>
diff --git a/indra/llcommon/tests/threadsafeschedule_test.cpp b/indra/llcommon/tests/threadsafeschedule_test.cpp
index af67b9f492..c421cc7b1c 100644
--- a/indra/llcommon/tests/threadsafeschedule_test.cpp
+++ b/indra/llcommon/tests/threadsafeschedule_test.cpp
@@ -46,11 +46,11 @@ namespace tut
         // 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"));
+        queue.push(Queue::TimeTuple(Queue::Clock::now() + 200ms, "ghi"));
         // Given the various push() overloads, you have to match the type
         // exactly: conversions are ambiguous.
         queue.push("abc"s);
-        queue.push(Queue::Clock::now() + 10ms, "def");
+        queue.push(Queue::Clock::now() + 100ms, "def");
         queue.close();
         auto entry = queue.pop();
         ensure_equals("failed to pop first", std::get<0>(entry), "abc"s);
diff --git a/indra/llcommon/tests/workqueue_test.cpp b/indra/llcommon/tests/workqueue_test.cpp
index d5405400fd..bea3ad911b 100644
--- a/indra/llcommon/tests/workqueue_test.cpp
+++ b/indra/llcommon/tests/workqueue_test.cpp
@@ -20,7 +20,10 @@
 // external library headers
 // other Linden headers
 #include "../test/lltut.h"
+#include "../test/catch_and_store_what_in.h"
 #include "llcond.h"
+#include "llcoros.h"
+#include "lleventcoro.h"
 #include "llstring.h"
 #include "stringize.h"
 
@@ -138,7 +141,8 @@ namespace tut
             [](){ 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.
+            // on the invoking thread. (Of course the bound variable must
+            // survive until the callback is called.)
             [&result](int i){ result = i; });
         // this should post the callback to main
         qptr->runOne();
@@ -156,4 +160,70 @@ namespace tut
         main.runPending();
         ensure_equals("failed to run string callback", alpha, "abc");
     }
+
+    template<> template<>
+    void object::test<5>()
+    {
+        set_test_name("postTo with void return");
+        WorkQueue main("main");
+        auto qptr = WorkQueue::getInstance("queue");
+        std::string observe;
+        main.postTo(
+            qptr,
+            // The ONLY reason we can get away with binding a reference to
+            // 'observe' in our work callable is because we're directly
+            // calling qptr->runOne() on this same thread. It would be a
+            // mistake to do that if some other thread were servicing 'queue'.
+            [&observe](){ observe = "queue"; },
+            [&observe](){ observe.append(";main"); });
+        qptr->runOne();
+        main.runOne();
+        ensure_equals("failed to run both lambdas", observe, "queue;main");
+    }
+
+    template<> template<>
+    void object::test<6>()
+    {
+        set_test_name("waitForResult");
+        std::string stored;
+        // Try to call waitForResult() on this thread's main coroutine. It
+        // should throw because the main coroutine must service the queue.
+        auto what{ catch_what<WorkQueue::Error>(
+                [this, &stored](){ stored = queue.waitForResult(
+                        [](){ return "should throw"; }); }) };
+        ensure("lambda should not have run", stored.empty());
+        ensure_not("waitForResult() should have thrown", what.empty());
+        ensure(STRINGIZE("should mention waitForResult: " << what),
+               what.find("waitForResult") != std::string::npos);
+
+        // Call waitForResult() on a coroutine, with a string result.
+        LLCoros::instance().launch(
+            "waitForResult string",
+            [this, &stored]()
+            { stored = queue.waitForResult(
+                    [](){ return "string result"; }); });
+        llcoro::suspend();
+        // Nothing will have happened yet because, even if the coroutine did
+        // run immediately, all it did was to queue the inner lambda on
+        // 'queue'. Service it.
+        queue.runOne();
+        llcoro::suspend();
+        ensure_equals("bad waitForResult return", stored, "string result");
+
+        // Call waitForResult() on a coroutine, with a void callable.
+        stored.clear();
+        bool done = false;
+        LLCoros::instance().launch(
+            "waitForResult void",
+            [this, &stored, &done]()
+            {
+                queue.waitForResult([&stored](){ stored = "ran"; });
+                done = true;
+            });
+        llcoro::suspend();
+        queue.runOne();
+        llcoro::suspend();
+        ensure_equals("didn't run coroutine", stored, "ran");
+        ensure("void waitForResult() didn't return", done);
+    }
 } // namespace tut
diff --git a/indra/llcommon/timing.cpp b/indra/llcommon/timing.cpp
deleted file mode 100644
index c2dc695ef3..0000000000
--- a/indra/llcommon/timing.cpp
+++ /dev/null
@@ -1,25 +0,0 @@
-/** 
- * @file timing.cpp
- * @brief This file will be deprecated in the future.
- *
- * $LicenseInfo:firstyear=2000&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$
- */
diff --git a/indra/llcommon/workqueue.cpp b/indra/llcommon/workqueue.cpp
index e7d40354aa..c74dada2e4 100644
--- a/indra/llcommon/workqueue.cpp
+++ b/indra/llcommon/workqueue.cpp
@@ -26,8 +26,9 @@
 using Mutex = LLCoros::Mutex;
 using Lock  = LLCoros::LockType;
 
-LL::WorkQueue::WorkQueue(const std::string& name):
-    super(makeName(name))
+LL::WorkQueue::WorkQueue(const std::string& name, size_t capacity):
+    super(makeName(name)),
+    mQueue(capacity)
 {
     // TODO: register for "LLApp" events so we can implicitly close() on
     // viewer shutdown.
@@ -38,6 +39,21 @@ void LL::WorkQueue::close()
     mQueue.close();
 }
 
+size_t LL::WorkQueue::size()
+{
+    return mQueue.size();
+}
+
+bool LL::WorkQueue::isClosed()
+{
+    return mQueue.isClosed();
+}
+
+bool LL::WorkQueue::done()
+{
+    return mQueue.done();
+}
+
 void LL::WorkQueue::runUntilClose()
 {
     try
@@ -130,3 +146,13 @@ void LL::WorkQueue::error(const std::string& msg)
 {
     LL_ERRS("WorkQueue") << msg << LL_ENDL;
 }
+
+void LL::WorkQueue::checkCoroutine(const std::string& method)
+{
+    // By convention, the default coroutine on each thread has an empty name
+    // string. See also LLCoros::logname().
+    if (LLCoros::getName().empty())
+    {
+        LLTHROW(Error("Do not call " + method + " from a thread's default coroutine"));
+    }
+}
diff --git a/indra/llcommon/workqueue.h b/indra/llcommon/workqueue.h
index 8e4b38c2f3..96574a18b9 100644
--- a/indra/llcommon/workqueue.h
+++ b/indra/llcommon/workqueue.h
@@ -12,14 +12,14 @@
 #if ! defined(LL_WORKQUEUE_H)
 #define LL_WORKQUEUE_H
 
+#include "llcoros.h"
+#include "llexception.h"
 #include "llinstancetracker.h"
 #include "threadsafeschedule.h"
 #include <chrono>
+#include <exception>                // std::current_exception
 #include <functional>               // std::function
-#include <queue>
 #include <string>
-#include <utility>                  // std::pair
-#include <vector>
 
 namespace LL
 {
@@ -45,11 +45,16 @@ namespace LL
         using TimedWork = Queue::TimeTuple;
         using Closed    = Queue::Closed;
 
+        struct Error: public LLException
+        {
+            Error(const std::string& what): LLException(what) {}
+        };
+
         /**
          * You may omit the WorkQueue name, in which case a unique name is
          * synthesized; for practical purposes that makes it anonymous.
          */
-        WorkQueue(const std::string& name = std::string());
+        WorkQueue(const std::string& name = std::string(), size_t capacity=1024);
 
         /**
          * Since the point of WorkQueue is to pass work to some other worker
@@ -59,15 +64,36 @@ namespace LL
          */
         void close();
 
+        /**
+         * WorkQueue supports multiple producers and multiple consumers. In
+         * the general case it's misleading to test size(), since any other
+         * thread might change it the nanosecond the lock is released. On that
+         * basis, some might argue against publishing a size() method at all.
+         *
+         * But there are two specific cases in which a test based on size()
+         * might be reasonable:
+         *
+         * * If you're the only producer, noticing that size() == 0 is
+         *   meaningful.
+         * * If you're the only consumer, noticing that size() > 0 is
+         *   meaningful.
+         */
+        size_t size();
+        /// producer end: are we prevented from pushing any additional items?
+        bool isClosed();
+        /// consumer end: are we done, is the queue entirely drained?
+        bool done();
+
         /*---------------------- fire and forget API -----------------------*/
 
         /// fire-and-forget, but at a particular (future?) time
         template <typename CALLABLE>
         void post(const TimePoint& time, CALLABLE&& callable)
         {
-            // Defer reifying an arbitrary CALLABLE until we hit this method.
-            // All other methods should accept CALLABLEs of arbitrary type to
-            // avoid multiple levels of std::function indirection.
+            // Defer reifying an arbitrary CALLABLE until we hit this or
+            // postIfOpen(). All other methods should accept CALLABLEs of
+            // arbitrary type to avoid multiple levels of std::function
+            // indirection.
             mQueue.push(TimedWork(time, std::move(callable)));
         }
 
@@ -82,6 +108,47 @@ namespace LL
             post(TimePoint::clock::now(), std::move(callable));
         }
 
+        /**
+         * post work for a particular time, unless the queue is closed before
+         * we can post
+         */
+        template <typename CALLABLE>
+        bool postIfOpen(const TimePoint& time, CALLABLE&& callable)
+        {
+            // Defer reifying an arbitrary CALLABLE until we hit this or
+            // post(). All other methods should accept CALLABLEs of arbitrary
+            // type to avoid multiple levels of std::function indirection.
+            return mQueue.pushIfOpen(TimedWork(time, std::move(callable)));
+        }
+
+        /**
+         * post work, unless the queue is closed before we can post
+         */
+        template <typename CALLABLE>
+        bool postIfOpen(CALLABLE&& callable)
+        {
+            return postIfOpen(TimePoint::clock::now(), std::move(callable));
+        }
+
+        /**
+         * Post work to be run at a specified time to another WorkQueue, which
+         * may or may not still exist and be open. Return true if we were able
+         * to post.
+         */
+        template <typename CALLABLE>
+        static bool postMaybe(weak_t target, const TimePoint& time, CALLABLE&& callable);
+
+        /**
+         * Post work to another WorkQueue, which may or may not still exist
+         * and be open. Return true if we were able to post.
+         */
+        template <typename CALLABLE>
+        static bool postMaybe(weak_t target, CALLABLE&& callable)
+        {
+            return postMaybe(target, TimePoint::clock::now(),
+                             std::forward<CALLABLE>(callable));
+        }
+
         /**
          * Launch a callable returning bool that will trigger repeatedly at
          * specified interval, until the callable returns false.
@@ -115,63 +182,8 @@ namespace LL
         // 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;
-        }
+        bool postTo(weak_t target,
+                    const TimePoint& time, CALLABLE&& callable, FOLLOWUP&& callback);
 
         /**
          * Post work to another WorkQueue, requesting a specific callback to
@@ -181,10 +193,36 @@ namespace LL
          * inaccessible.
          */
         template <typename CALLABLE, typename FOLLOWUP>
-        bool postTo(WorkQueue::weak_t target,
-                    CALLABLE&& callable, FOLLOWUP&& callback)
+        bool postTo(weak_t target, CALLABLE&& callable, FOLLOWUP&& callback)
+        {
+            return postTo(target, TimePoint::clock::now(),
+                          std::move(callable), std::move(callback));
+        }
+
+        /**
+         * Post work to another WorkQueue to be run at a specified time,
+         * blocking the calling coroutine until then, returning the result to
+         * caller on completion.
+         *
+         * In general, we assume that each thread's default coroutine is busy
+         * servicing its WorkQueue or whatever. To try to prevent mistakes, we
+         * forbid calling waitForResult() from a thread's default coroutine.
+         */
+        template <typename CALLABLE>
+        auto waitForResult(const TimePoint& time, CALLABLE&& callable);
+
+        /**
+         * Post work to another WorkQueue, blocking the calling coroutine
+         * until then, returning the result to caller on completion.
+         *
+         * In general, we assume that each thread's default coroutine is busy
+         * servicing its WorkQueue or whatever. To try to prevent mistakes, we
+         * forbid calling waitForResult() from a thread's default coroutine.
+         */
+        template <typename CALLABLE>
+        auto waitForResult(CALLABLE&& callable)
         {
-            return postTo(target, TimePoint::clock::now(), std::move(callable), std::move(callback));
+            return waitForResult(TimePoint::clock::now(), std::move(callable));
         }
 
         /*--------------------------- worker API ---------------------------*/
@@ -233,6 +271,23 @@ namespace LL
         bool runUntil(const TimePoint& until);
 
     private:
+        template <typename CALLABLE, typename FOLLOWUP>
+        static auto makeReplyLambda(CALLABLE&& callable, FOLLOWUP&& callback);
+        /// general case: arbitrary C++ return type
+        template <typename CALLABLE, typename FOLLOWUP, typename RETURNTYPE>
+        struct MakeReplyLambda;
+        /// specialize for CALLABLE returning void
+        template <typename CALLABLE, typename FOLLOWUP>
+        struct MakeReplyLambda<CALLABLE, FOLLOWUP, void>;
+
+        /// general case: arbitrary C++ return type
+        template <typename CALLABLE, typename RETURNTYPE>
+        struct WaitForResult;
+        /// specialize for CALLABLE returning void
+        template <typename CALLABLE>
+        struct WaitForResult<CALLABLE, void>;
+
+        static void checkCoroutine(const std::string& method);
         static void error(const std::string& msg);
         static std::string makeName(const std::string& name);
         void callWork(const Queue::DataTuple& work);
@@ -254,8 +309,8 @@ namespace LL
     {
     public:
         // bind the desired data
-        BackJack(WorkQueue::weak_t target,
-                 const WorkQueue::TimePoint& start,
+        BackJack(weak_t target,
+                 const TimePoint& start,
                  const std::chrono::duration<Rep, Period>& interval,
                  CALLABLE&& callable):
             mTarget(target),
@@ -302,8 +357,8 @@ namespace LL
         }
 
     private:
-        WorkQueue::weak_t mTarget;
-        WorkQueue::TimePoint mStart;
+        weak_t mTarget;
+        TimePoint mStart;
         std::chrono::duration<Rep, Period> mInterval;
         CALLABLE mCallable;
     };
diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp
index ed0e3fb345..894eb8c773 100644
--- a/indra/llrender/llimagegl.cpp
+++ b/indra/llrender/llimagegl.cpp
@@ -172,31 +172,19 @@ BOOL is_little_endian()
 	return (*c == 0x78) ;
 }
 
-LLImageGLThread* LLImageGLThread::sInstance = nullptr;
-
 //static 
 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();
+    LLImageGLThread::createInstance(window);
 }
 
 //static 
 void LLImageGL::cleanupClass() 
 {
     LL_PROFILE_ZONE_SCOPED;
-    LLImageGLThread::sInstance->mFunctionQueue.close();
-    delete LLImageGLThread::sInstance;
-    LLImageGLThread::sInstance = nullptr;
+    LLImageGLThread::deleteSingleton();
 }
 
 //static
@@ -504,6 +492,9 @@ void LLImageGL::init(BOOL usemipmaps)
 #endif
 
 	mCategory = -1;
+
+	// Sometimes we have to post work for the main thread.
+	mMainQueue = LL::WorkQueue::getInstance("mainloop");
 }
 
 void LLImageGL::cleanup()
@@ -1536,8 +1527,7 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_
     }
 
     //if we're on the image loading thread, be sure to delete old_texname and update mTexName on the main thread
-    if (LLImageGLThread::sInstance != nullptr && 
-        LLThread::currentID() == LLImageGLThread::sInstance->getID())
+    if (! on_main_thread())
     {
         {
             LL_PROFILE_ZONE_NAMED("cglt - sync");
@@ -1554,7 +1544,9 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_
         }
 
         ref();
-        LLImageGLThread::sInstance->postCallback([=]()
+        LL::WorkQueue::postMaybe(
+            mMainQueue,
+            [=]()
             {
                 LL_PROFILE_ZONE_NAMED("cglt - delete callback");
                 if (old_texname != 0)
@@ -2259,7 +2251,11 @@ void LLImageGL::resetCurTexSizebar()
 */  
 
 LLImageGLThread::LLImageGLThread(LLWindow* window)
-    : LLThread("LLImageGL"), mWindow(window)
+    // We want exactly one thread, but a very large capacity: we never want
+    // anyone, especially inner-loop render code, to have to block on post()
+    // because we're full.
+    : ThreadPool("LLImageGL", 1, 1024*1024)
+    , mWindow(window)
 {
     LL_PROFILE_ZONE_SCOPED;
     mFinished = false;
@@ -2268,61 +2264,6 @@ LLImageGLThread::LLImageGLThread(LLWindow* window)
     ThreadPool::start();
 }
 
-// post a function to be executed on the LLImageGL background thread
-
-bool LLImageGLThread::post(const std::function<void()>& func)
-{
-    try
-    {
-        mFunctionQueue.post(func);
-    }
-    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
-    {
-        if (!mCallbackQueue.tryPost(callback))
-        {
-            mPendingCallbackQ.push(callback);
-        }
-    }
-    catch (LLThreadSafeQueueInterrupt e)
-    {
-        //thread is closing, drop request
-        return false;
-    }
-
-    return true;
-}
-
-void LLImageGLThread::executeCallbacks()
-{
-    LL_PROFILE_ZONE_SCOPED;
-    //executed from main thread
-    mCallbackQueue.runPending();
-
-    while (!mPendingCallbackQ.empty())
-    {
-        if (mCallbackQueue.tryPost(mPendingCallbackQ.front()))
-        {
-            mPendingCallbackQ.pop();
-        }
-        else
-        {
-            break;
-        }
-    }
-}
-
 void LLImageGLThread::run()
 {
     LL_PROFILE_ZONE_SCOPED;
@@ -2330,7 +2271,7 @@ void LLImageGLThread::run()
     // WorkQueue, likewise cleanup afterwards.
     mWindow->makeContextCurrent(mContext);
     gGL.init();
-    mFunctionQueue.runUntilClose();
+    ThreadPool::run();
     gGL.shutdown();
     mWindow->destroySharedContext(mContext);
 }
diff --git a/indra/llrender/llimagegl.h b/indra/llrender/llimagegl.h
index bb46dbc639..ae773bb362 100644
--- a/indra/llrender/llimagegl.h
+++ b/indra/llrender/llimagegl.h
@@ -37,6 +37,7 @@
 #include "llunits.h"
 #include "llthreadsafequeue.h"
 #include "llrender.h"
+#include "threadpool.h"
 #include "workqueue.h"
 
 class LLTextureAtlas ;
@@ -198,6 +199,7 @@ private:
 	void freePickMask();
 
 	LLPointer<LLImageRaw> mSaveData; // used for destroyGL/restoreGL
+	LL::WorkQueue::weak_t mMainQueue;
 	U8* mPickMask;  //downsampled bitmap approximation of alpha channel.  NULL if no alpha channel
 	U16 mPickMaskWidth;
 	U16 mPickMaskHeight;
@@ -271,7 +273,6 @@ public:
 
 public:
 	static void initClass(LLWindow* window, S32 num_catagories, BOOL skip_analyze_alpha = false); 
-    static void updateClass();
 	static void cleanupClass() ;
 
 private:
@@ -307,34 +308,24 @@ public:
 
 };
 
-class LLImageGLThread : public LLThread
+class LLImageGLThread : public LLSimpleton<LLImageGLThread>, LL::ThreadPool
 {
 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();
+    template <typename CALLABLE>
+    bool post(CALLABLE&& func)
+    {
+        return getQueue().postIfOpen(std::forward<CALLABLE>(func));
+    }
 
     void run() override;
 
-    // Work Queue for background thread
-    LL::WorkQueue mFunctionQueue;
-
-    // Work Queue for main thread (run from updateClass)
-    LL::WorkQueue mCallbackQueue;
-
+private:
     LLWindow* mWindow;
     void* mContext = nullptr;
     LLAtomicBool mFinished;
-
-    std::queue<std::function<void()>> mPendingCallbackQ;
-
-    static LLImageGLThread* sInstance;
 };
 
 
diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp
index 149a92ffff..062dd02903 100644
--- a/indra/llwindow/llwindowwin32.cpp
+++ b/indra/llwindow/llwindowwin32.cpp
@@ -183,23 +183,19 @@ DWORD	LLWindowWin32::sWinIMESentenceMode = IME_SMODE_AUTOMATIC;
 LLCoordWindow LLWindowWin32::sWinIMEWindowPosition(-1,-1);
 
 // The following class LLWinImm delegates Windows IMM APIs.
-// We need this because some language versions of Windows,
-// e.g., US version of Windows XP, doesn't install IMM32.DLL
-// as a default, and we can't link against imm32.lib statically.
-// I believe DLL loading of this type is best suited to do
-// in a static initialization of a class.  What I'm not sure is
-// whether it follows the Linden Conding Standard... 
-// See http://wiki.secondlife.com/wiki/Coding_standards#Static_Members
+// It was originally introduced to support US Windows XP, on which we needed
+// to dynamically load IMM32.DLL and use GetProcAddress to resolve its entry
+// points. Now that that's moot, we retain this wrapper only for hooks for
+// metrics.
 
 class LLWinImm
 {
 public:
-	static bool		isAvailable() { return sTheInstance.mHImmDll != NULL; }
+	static bool		isAvailable() { return true; }
 
 public:
 	// Wrappers for IMM API.
 	static BOOL		isIME(HKL hkl);															
-	static HWND		getDefaultIMEWnd(HWND hwnd);
 	static HIMC		getContext(HWND hwnd);													
 	static BOOL		releaseContext(HWND hwnd, HIMC himc);
 	static BOOL		getOpenStatus(HIMC himc);												
@@ -213,236 +209,96 @@ public:
 	static BOOL		setCompositionFont(HIMC himc, LPLOGFONTW logfont);
 	static BOOL		setCandidateWindow(HIMC himc, LPCANDIDATEFORM candidate_form);
 	static BOOL		notifyIME(HIMC himc, DWORD action, DWORD index, DWORD value);
-
-private:
-	LLWinImm();
-	~LLWinImm();
-
-private:
-	// Pointers to IMM API.
-	BOOL	 	(WINAPI *mImmIsIME)(HKL);
-	HWND		(WINAPI *mImmGetDefaultIMEWnd)(HWND);
-	HIMC		(WINAPI *mImmGetContext)(HWND);
-	BOOL		(WINAPI *mImmReleaseContext)(HWND, HIMC);
-	BOOL		(WINAPI *mImmGetOpenStatus)(HIMC);
-	BOOL		(WINAPI *mImmSetOpenStatus)(HIMC, BOOL);
-	BOOL		(WINAPI *mImmGetConversionStatus)(HIMC, LPDWORD, LPDWORD);
-	BOOL		(WINAPI *mImmSetConversionStatus)(HIMC, DWORD, DWORD);
-	BOOL		(WINAPI *mImmGetCompostitionWindow)(HIMC, LPCOMPOSITIONFORM);
-	BOOL		(WINAPI *mImmSetCompostitionWindow)(HIMC, LPCOMPOSITIONFORM);
-	LONG		(WINAPI *mImmGetCompositionString)(HIMC, DWORD, LPVOID, DWORD);
-	BOOL		(WINAPI *mImmSetCompositionString)(HIMC, DWORD, LPVOID, DWORD, LPVOID, DWORD);
-	BOOL		(WINAPI *mImmSetCompositionFont)(HIMC, LPLOGFONTW);
-	BOOL		(WINAPI *mImmSetCandidateWindow)(HIMC, LPCANDIDATEFORM);
-	BOOL		(WINAPI *mImmNotifyIME)(HIMC, DWORD, DWORD, DWORD);
-
-private:
-	HMODULE		mHImmDll;
-	static LLWinImm sTheInstance;
 };
 
-LLWinImm LLWinImm::sTheInstance;
-
-LLWinImm::LLWinImm() : mHImmDll(NULL)
-{
-	// Check system metrics 
-	if ( !GetSystemMetrics( SM_IMMENABLED ) )
-		return;
-
-	mHImmDll = LoadLibraryA("Imm32");
-	if (mHImmDll != NULL)
-	{
-		mImmIsIME               = (BOOL (WINAPI *)(HKL))                    GetProcAddress(mHImmDll, "ImmIsIME");
-		mImmGetDefaultIMEWnd	= (HWND (WINAPI *)(HWND))					GetProcAddress(mHImmDll, "ImmGetDefaultIMEWnd");
-		mImmGetContext          = (HIMC (WINAPI *)(HWND))                   GetProcAddress(mHImmDll, "ImmGetContext");
-		mImmReleaseContext      = (BOOL (WINAPI *)(HWND, HIMC))             GetProcAddress(mHImmDll, "ImmReleaseContext");
-		mImmGetOpenStatus       = (BOOL (WINAPI *)(HIMC))                   GetProcAddress(mHImmDll, "ImmGetOpenStatus");
-		mImmSetOpenStatus       = (BOOL (WINAPI *)(HIMC, BOOL))             GetProcAddress(mHImmDll, "ImmSetOpenStatus");
-		mImmGetConversionStatus = (BOOL (WINAPI *)(HIMC, LPDWORD, LPDWORD)) GetProcAddress(mHImmDll, "ImmGetConversionStatus");
-		mImmSetConversionStatus = (BOOL (WINAPI *)(HIMC, DWORD, DWORD))     GetProcAddress(mHImmDll, "ImmSetConversionStatus");
-		mImmGetCompostitionWindow = (BOOL (WINAPI *)(HIMC, LPCOMPOSITIONFORM))   GetProcAddress(mHImmDll, "ImmGetCompositionWindow");
-		mImmSetCompostitionWindow = (BOOL (WINAPI *)(HIMC, LPCOMPOSITIONFORM))   GetProcAddress(mHImmDll, "ImmSetCompositionWindow");
-		mImmGetCompositionString= (LONG (WINAPI *)(HIMC, DWORD, LPVOID, DWORD))					GetProcAddress(mHImmDll, "ImmGetCompositionStringW");
-		mImmSetCompositionString= (BOOL (WINAPI *)(HIMC, DWORD, LPVOID, DWORD, LPVOID, DWORD))	GetProcAddress(mHImmDll, "ImmSetCompositionStringW");
-		mImmSetCompositionFont  = (BOOL (WINAPI *)(HIMC, LPLOGFONTW))		GetProcAddress(mHImmDll, "ImmSetCompositionFontW");
-		mImmSetCandidateWindow  = (BOOL (WINAPI *)(HIMC, LPCANDIDATEFORM))  GetProcAddress(mHImmDll, "ImmSetCandidateWindow");
-		mImmNotifyIME			= (BOOL (WINAPI *)(HIMC, DWORD, DWORD, DWORD))	GetProcAddress(mHImmDll, "ImmNotifyIME");
-
-		if (mImmIsIME == NULL ||
-			mImmGetDefaultIMEWnd == NULL ||
-			mImmGetContext == NULL ||
-			mImmReleaseContext == NULL ||
-			mImmGetOpenStatus == NULL ||
-			mImmSetOpenStatus == NULL ||
-			mImmGetConversionStatus == NULL ||
-			mImmSetConversionStatus == NULL ||
-			mImmGetCompostitionWindow == NULL ||
-			mImmSetCompostitionWindow == NULL ||
-			mImmGetCompositionString == NULL ||
-			mImmSetCompositionString == NULL ||
-			mImmSetCompositionFont == NULL ||
-			mImmSetCandidateWindow == NULL ||
-			mImmNotifyIME == NULL)
-		{
-			// If any of the above API entires are not found, we can't use IMM API.  
-			// So, turn off the IMM support.  We should log some warning message in 
-			// the case, since it is very unusual; these APIs are available from 
-			// the beginning, and all versions of IMM32.DLL should have them all.  
-			// Unfortunately, this code may be executed before initialization of 
-			// the logging channel (LL_WARNS()), and we can't do it here...  Yes, this 
-			// is one of disadvantages to use static constraction to DLL loading. 
-			FreeLibrary(mHImmDll);
-			mHImmDll = NULL;
-
-			// If we unload the library, make sure all the function pointers are cleared
-			mImmIsIME = NULL;
-			mImmGetDefaultIMEWnd = NULL;
-			mImmGetContext = NULL;
-			mImmReleaseContext = NULL;
-			mImmGetOpenStatus = NULL;
-			mImmSetOpenStatus = NULL;
-			mImmGetConversionStatus = NULL;
-			mImmSetConversionStatus = NULL;
-			mImmGetCompostitionWindow = NULL;
-			mImmSetCompostitionWindow = NULL;
-			mImmGetCompositionString = NULL;
-			mImmSetCompositionString = NULL;
-			mImmSetCompositionFont = NULL;
-			mImmSetCandidateWindow = NULL;
-			mImmNotifyIME = NULL;
-		}
-	}
-}
-
-
 // static 
 BOOL	LLWinImm::isIME(HKL hkl)
 { 
-	if ( sTheInstance.mImmIsIME )
-		return sTheInstance.mImmIsIME(hkl); 
-	return FALSE;
+	return ImmIsIME(hkl);
 }
 
 // static 
 HIMC		LLWinImm::getContext(HWND hwnd)
 {
-	if ( sTheInstance.mImmGetContext )
-		return sTheInstance.mImmGetContext(hwnd); 
-	return 0;
+	return ImmGetContext(hwnd);
 }
 
 //static 
 BOOL		LLWinImm::releaseContext(HWND hwnd, HIMC himc)
 { 
-	if ( sTheInstance.mImmIsIME )
-		return sTheInstance.mImmReleaseContext(hwnd, himc); 
-	return FALSE;
+	return ImmReleaseContext(hwnd, himc);
 }
 
 // static 
 BOOL		LLWinImm::getOpenStatus(HIMC himc)
 { 
-	if ( sTheInstance.mImmGetOpenStatus )
-		return sTheInstance.mImmGetOpenStatus(himc); 
-	return FALSE;
+	return ImmGetOpenStatus(himc);
 }
 
 // static 
 BOOL		LLWinImm::setOpenStatus(HIMC himc, BOOL status)
 { 
-	if ( sTheInstance.mImmSetOpenStatus )
-		return sTheInstance.mImmSetOpenStatus(himc, status); 
-	return FALSE;
+	return ImmSetOpenStatus(himc, status);
 }
 
 // static 
 BOOL		LLWinImm::getConversionStatus(HIMC himc, LPDWORD conversion, LPDWORD sentence)	
 { 
-	if ( sTheInstance.mImmGetConversionStatus )
-		return sTheInstance.mImmGetConversionStatus(himc, conversion, sentence); 
-	return FALSE;
+	return ImmGetConversionStatus(himc, conversion, sentence);
 }
 
 // static 
 BOOL		LLWinImm::setConversionStatus(HIMC himc, DWORD conversion, DWORD sentence)		
 { 
-	if ( sTheInstance.mImmSetConversionStatus )
-		return sTheInstance.mImmSetConversionStatus(himc, conversion, sentence); 
-	return FALSE;
+	return ImmSetConversionStatus(himc, conversion, sentence);
 }
 
 // static 
 BOOL		LLWinImm::getCompositionWindow(HIMC himc, LPCOMPOSITIONFORM form)					
 { 
-	if ( sTheInstance.mImmGetCompostitionWindow )
-		return sTheInstance.mImmGetCompostitionWindow(himc, form);	
-	return FALSE;
+	return ImmGetCompositionWindow(himc, form);
 }
 
 // static 
 BOOL		LLWinImm::setCompositionWindow(HIMC himc, LPCOMPOSITIONFORM form)					
 { 
-	if ( sTheInstance.mImmSetCompostitionWindow )
-		return sTheInstance.mImmSetCompostitionWindow(himc, form);	
-	return FALSE;
+	return ImmSetCompositionWindow(himc, form);
 }
 
 
 // static 
 LONG		LLWinImm::getCompositionString(HIMC himc, DWORD index, LPVOID data, DWORD length)					
 { 
-	if ( sTheInstance.mImmGetCompositionString )
-		return sTheInstance.mImmGetCompositionString(himc, index, data, length);	
-	return FALSE;
+	return ImmGetCompositionString(himc, index, data, length);
 }
 
 
 // static 
 BOOL		LLWinImm::setCompositionString(HIMC himc, DWORD index, LPVOID pComp, DWORD compLength, LPVOID pRead, DWORD readLength)					
 { 
-	if ( sTheInstance.mImmSetCompositionString )
-		return sTheInstance.mImmSetCompositionString(himc, index, pComp, compLength, pRead, readLength);	
-	return FALSE;
+	return ImmSetCompositionString(himc, index, pComp, compLength, pRead, readLength);
 }
 
 // static 
 BOOL		LLWinImm::setCompositionFont(HIMC himc, LPLOGFONTW pFont)					
 { 
-	if ( sTheInstance.mImmSetCompositionFont )
-		return sTheInstance.mImmSetCompositionFont(himc, pFont);	
-	return FALSE;
+	return ImmSetCompositionFont(himc, pFont);
 }
 
 // static 
 BOOL		LLWinImm::setCandidateWindow(HIMC himc, LPCANDIDATEFORM form)					
 { 
-	if ( sTheInstance.mImmSetCandidateWindow )
-		return sTheInstance.mImmSetCandidateWindow(himc, form);	
-	return FALSE;
+	return ImmSetCandidateWindow(himc, form);
 }
 
 // static 
 BOOL		LLWinImm::notifyIME(HIMC himc, DWORD action, DWORD index, DWORD value)					
 { 
-	if ( sTheInstance.mImmNotifyIME )
-		return sTheInstance.mImmNotifyIME(himc, action, index, value);	
-	return FALSE;
+	return ImmNotifyIME(himc, action, index, value);
 }
 
 
 
-
-// ----------------------------------------------------------------------------------------
-LLWinImm::~LLWinImm()
-{
-	if (mHImmDll != NULL)
-	{
-		FreeLibrary(mHImmDll);
-		mHImmDll = NULL;
-	}
-}
-
-
 class LLMonitorInfo
 {
 public:
@@ -552,8 +408,7 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks,
 	: LLWindow(callbacks, fullscreen, flags)
 {
     sMainThreadId = LLThread::currentID();
-    mWindowThread = new LLWindowWin32Thread(this);
-    mWindowThread->start();
+    mWindowThread = new LLWindowWin32Thread();
 	//MAINT-516 -- force a load of opengl32.dll just in case windows went sideways 
 	LoadLibrary(L"opengl32.dll");
 
@@ -624,7 +479,6 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks,
 
 	// Make an instance of our window then define the window class
 	mhInstance = GetModuleHandle(NULL);
-	mWndProc = NULL;
 
     // Init Direct Input - needed for joystick / Spacemouse
 
@@ -1048,17 +902,13 @@ void LLWindowWin32::close()
                 // 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())
-    {
-        //nudge window thread
-        PostMessage(mWindowHandle, WM_USER + 0x0017, 0xB0B0, 0x1337);
-        std::this_thread::sleep_for(std::chrono::milliseconds(1));
-    }
+    // Even though the above lambda might not yet have run, we've already
+    // bound mWindowHandle into it by value, which should suffice for the
+    // operations we're asking. That's the last time WE should touch it.
+    mWindowHandle = NULL;
+    mWindowThread->close();
 }
 
 BOOL LLWindowWin32::isValid()
@@ -1351,51 +1201,7 @@ BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen& size, BO
         << " Fullscreen: " << mFullscreen
         << LL_ENDL;
 
-    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 = 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;
-    }
+	recreateWindow(window_rect, dw_ex_style, dw_style);
 
 	if (mWindowHandle)
 	{
@@ -1723,48 +1529,7 @@ 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 (oldHandle && !destroy_window_handler(oldHandle))
-        {
-            LL_WARNS("Window") << "Failed to properly close window!" << LL_ENDL;
-        }		
-
-        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;
-        }
+		recreateWindow(window_rect, dw_ex_style, dw_style);
 
 		if (mWindowHandle)
 		{
@@ -2347,7 +2112,7 @@ void LLWindowWin32::gatherInput()
     }
 
 
-    if (mWindowThread->mFunctionQueue.size() > 0)
+    if (mWindowThread->getQueue().size())
     {
         LL_PROFILE_ZONE_NAMED("gi - PostMessage");
         kickWindowThread();
@@ -2455,17 +2220,6 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
 
     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;
-            }
-        }
-
         // 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));
@@ -4746,10 +4500,8 @@ std::vector<std::string> LLWindowWin32::getDynamicFallbackFontList()
 
 #endif // LL_WINDOWS
 
-inline LLWindowWin32Thread::LLWindowWin32Thread(LLWindowWin32* window)
-    : LLThread("Window Thread"), 
-    mWindow(window),
-    mFunctionQueue(MAX_QUEUE_SIZE)
+inline LLWindowWin32::LLWindowWin32Thread::LLWindowWin32Thread()
+    : ThreadPool("Window Thread", 1, MAX_QUEUE_SIZE)
 {
     ThreadPool::start();
 }
@@ -4813,7 +4565,7 @@ void LLWindowWin32::LLWindowWin32Thread::run()
         {
             MSG msg;
             BOOL status;
-            if (mWindow->mhDC == 0)
+            if (mhDC == 0)
             {
                 LL_PROFILE_ZONE_NAMED("w32t - PeekMessage");
                 logger.onChange("PeekMessage(", std::hex, mWindowHandle, ")");
@@ -4840,11 +4592,7 @@ void LLWindowWin32::LLWindowWin32Thread::run()
             LL_PROFILE_ZONE_NAMED("w32t - Function Queue");
             logger.onChange("runPending()");
             //process any pending functions
-            std::function<void()> curFunc;
-            while (mFunctionQueue.tryPopBack(curFunc))
-            {
-                curFunc();
-            }
+            getQueue().runPending();
         }
         
 #if 0
@@ -4857,11 +4605,6 @@ void LLWindowWin32::LLWindowWin32Thread::run()
     }
 }
 
-void LLWindowWin32Thread::post(const std::function<void()>& func)
-{
-    mFunctionQueue.pushFront(func);
-}
-
 void LLWindowWin32::post(const std::function<void()>& func)
 {
     mFunctionQueue.pushFront(func);
diff --git a/indra/llwindow/llwindowwin32.h b/indra/llwindow/llwindowwin32.h
index 8d0193abc8..b02815e990 100644
--- a/indra/llwindow/llwindowwin32.h
+++ b/indra/llwindow/llwindowwin32.h
@@ -36,44 +36,12 @@
 #include "llthread.h"
 #include "llthreadsafequeue.h"
 #include "llmutex.h"
+#include "workqueue.h"
 
 // Hack for async host by name
 #define LL_WM_HOST_RESOLVED      (WM_APP + 1)
 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:
@@ -218,7 +186,6 @@ protected:
 	HGLRC		mhRC = 0;			// OpenGL rendering context
 	HDC			mhDC = 0;			// Windows Device context handle
 	HINSTANCE	mhInstance;		// handle to application instance
-	WNDPROC		mWndProc;		// user-installable window proc
 	RECT		mOldMouseClip;  // Screen rect to which the mouse cursor was globally constrained before we changed it in clipMouse()
 	WPARAM		mLastSizeWParam;
 	F32			mOverrideAspectRatio;
@@ -280,7 +247,6 @@ protected:
 	void kickWindowThread(HWND windowHandle=0);
 
 	friend class LLWindowManager;
-    friend class LLWindowWin32Thread;
 };
 
 class LLSplashScreenWin32 : public LLSplashScreen
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 9b636e5e5d..5f085bb9ad 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -393,7 +393,6 @@ set(viewer_SOURCE_FILES
     llloginhandler.cpp
     lllogininstance.cpp
     llmachineid.cpp
-    llmainlooprepeater.cpp
     llmanip.cpp
     llmaniprotate.cpp
     llmanipscale.cpp
@@ -1032,7 +1031,6 @@ set(viewer_HEADER_FILES
     llloginhandler.h
     lllogininstance.h
     llmachineid.h
-    llmainlooprepeater.h
     llmanip.h
     llmaniprotate.h
     llmanipscale.h
@@ -1604,6 +1602,7 @@ if (WINDOWS)
         ${WINDOWS_LIBRARIES}
         comdlg32
         dxguid
+        imm32
         kernel32
         odbc32
         odbccp32
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 2d821b7451..058da4b66d 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -3871,6 +3871,17 @@
         <key>Value</key>
         <integer>1</integer>
     </map>
+    <key>MainWorkTime</key>
+    <map>
+        <key>Comment</key>
+        <string>Max time per frame devoted to mainloop work queue (in milliseconds)</string>
+        <key>Persist</key>
+        <integer>1</integer>
+        <key>Type</key>
+        <string>F32</string>
+        <key>Value</key>
+        <real>0.1</real>
+    </map>
     <key>QueueInventoryFetchTimeout</key>
     <map>
         <key>Comment</key>
@@ -12667,6 +12678,20 @@
       <key>Value</key>
       <string />
     </map>
+    <key>ThreadPoolSizes</key>
+    <map>
+      <key>Comment</key>
+      <string>Map of size overrides for specific thread pools.</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>LLSD</string>
+      <key>Value</key>
+      <map>
+        <key>General</key>
+        <integer>4</integer>
+      </map>
+    </map>
     <key>ThrottleBandwidthKBPS</key>
     <map>
       <key>Comment</key>
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 5b3cbff9b8..e13c0a2472 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -233,11 +233,12 @@
 #include "llavatariconctrl.h"
 #include "llgroupiconctrl.h"
 #include "llviewerassetstats.h"
+#include "workqueue.h"
+using namespace LL;
 
 // Include for security api initialization
 #include "llsecapi.h"
 #include "llmachineid.h"
-#include "llmainlooprepeater.h"
 #include "llcleanup.h"
 
 #include "llcoproceduremanager.h"
@@ -366,6 +367,10 @@ BOOL gLogoutInProgress = FALSE;
 
 BOOL gSimulateMemLeak = FALSE;
 
+// We don't want anyone, especially threads working on the graphics pipeline,
+// to have to block due to this WorkQueue being full.
+WorkQueue gMainloopWork("mainloop", 1024*1024);
+
 ////////////////////////////////////////////////////////////
 // Internal globals... that should be removed.
 static std::string gArgs;
@@ -381,42 +386,6 @@ static std::string gLaunchFileOnQuit;
 // Used on Win32 for other apps to identify our window (eg, win_setup)
 const char* const VIEWER_WINDOW_CLASSNAME = "Second Life";
 
-//-- LLDeferredTaskList ------------------------------------------------------
-
-/**
- * A list of deferred tasks.
- *
- * We sometimes need to defer execution of some code until the viewer gets idle,
- * e.g. removing an inventory item from within notifyObservers() may not work out.
- *
- * Tasks added to this list will be executed in the next LLAppViewer::idle() iteration.
- * All tasks are executed only once.
- */
-class LLDeferredTaskList: public LLSingleton<LLDeferredTaskList>
-{
-	LLSINGLETON_EMPTY_CTOR(LLDeferredTaskList);
-	LOG_CLASS(LLDeferredTaskList);
-
-	friend class LLAppViewer;
-	typedef boost::signals2::signal<void()> signal_t;
-
-	void addTask(const signal_t::slot_type& cb)
-	{
-		mSignal.connect(cb);
-	}
-
-	void run()
-	{
-		if (!mSignal.empty())
-		{
-			mSignal();
-			mSignal.disconnect_all_slots();
-		}
-	}
-
-	signal_t mSignal;
-};
-
 //----------------------------------------------------------------------------
 
 // List of entries from strings.xml to always replace
@@ -973,9 +942,6 @@ bool LLAppViewer::init()
 	}
 	LL_INFOS("InitInfo") << "Cache initialization is done." << LL_ENDL ;
 
-	// Initialize the repeater service.
-	LLMainLoopRepeater::instance().start();
-
     // Initialize event recorder
     LLViewerEventRecorder::createInstance();
 
@@ -2217,8 +2183,6 @@ bool LLAppViewer::cleanup()
 	SUBSYSTEM_CLEANUP(LLProxy);
     LLCore::LLHttp::cleanup();
 
-	LLMainLoopRepeater::instance().stop();
-
 	ll_close_fail_log();
 
 	LLError::LLCallStacks::cleanup();
@@ -4550,7 +4514,7 @@ bool LLAppViewer::initCache()
 
 void LLAppViewer::addOnIdleCallback(const boost::function<void()>& cb)
 {
-	LLDeferredTaskList::instance().addTask(cb);
+	gMainloopWork.post(cb);
 }
 
 void LLAppViewer::loadKeyBindings()
@@ -4948,7 +4912,6 @@ 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();
diff --git a/indra/newview/llmainlooprepeater.cpp b/indra/newview/llmainlooprepeater.cpp
deleted file mode 100644
index 6736e9a950..0000000000
--- a/indra/newview/llmainlooprepeater.cpp
+++ /dev/null
@@ -1,88 +0,0 @@
-/** 
- * @file llmachineid.cpp
- * @brief retrieves unique machine ids
- *
- * $LicenseInfo:firstyear=2009&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- * 
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- * 
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
- * $/LicenseInfo$
- */
-
-#include "llviewerprecompiledheaders.h"
-#include "llapr.h"
-#include "llevents.h"
-#include "llmainlooprepeater.h"
-
-
-
-// LLMainLoopRepeater
-//-----------------------------------------------------------------------------
-
-
-LLMainLoopRepeater::LLMainLoopRepeater(void):
-	mQueue(0)
-{
-	; // No op.
-}
-
-
-void LLMainLoopRepeater::start(void)
-{
-	if(mQueue != 0) return;
-
-	mQueue = new LLThreadSafeQueue<LLSD>(1024);
-	mMainLoopConnection = LLEventPumps::instance().
-		obtain("mainloop").listen(LLEventPump::inventName(), boost::bind(&LLMainLoopRepeater::onMainLoop, this, _1));
-	mRepeaterConnection = LLEventPumps::instance().
-		obtain("mainlooprepeater").listen(LLEventPump::inventName(), boost::bind(&LLMainLoopRepeater::onMessage, this, _1));
-}
-
-
-void LLMainLoopRepeater::stop(void)
-{
-	mMainLoopConnection.release();
-	mRepeaterConnection.release();
-
-	delete mQueue;
-	mQueue = 0;
-}
-
-
-bool LLMainLoopRepeater::onMainLoop(LLSD const &)
-{
-	LLSD message;
-	while(mQueue->tryPopBack(message)) {
-		std::string pump = message["pump"].asString();
-		if(pump.length() == 0 ) continue; // No pump.
-		LLEventPumps::instance().obtain(pump).post(message["payload"]);
-	}
-	return false;
-}
-
-
-bool LLMainLoopRepeater::onMessage(LLSD const & event)
-{
-	try {
-		mQueue->pushFront(event);
-	} catch(LLThreadSafeQueueError & e) {
-		LL_WARNS() << "could not repeat message (" << e.what() << ")" << 
-			event.asString() << LL_ENDL;
-	}
-	return false;
-}
diff --git a/indra/newview/llmainlooprepeater.h b/indra/newview/llmainlooprepeater.h
deleted file mode 100644
index 2ec3a74e4a..0000000000
--- a/indra/newview/llmainlooprepeater.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/** 
- * @file llmainlooprepeater.h
- * @brief a service for repeating messages on the main loop.
- *
- * $LicenseInfo:firstyear=2010&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- * 
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- * 
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
- * $/LicenseInfo$
- */
-
-#ifndef LL_LLMAINLOOPREPEATER_H
-#define LL_LLMAINLOOPREPEATER_H
-
-
-#include "llsd.h"
-#include "llthreadsafequeue.h"
-
-
-//
-// A service which creates the pump 'mainlooprepeater' to which any thread can
-// post a message that will be re-posted on the main loop.
-//
-// The posted message should contain two map elements: pump and payload.  The
-// pump value is a string naming the pump to which the message should be
-// re-posted.  The payload value is what will be posted to the designated pump.
-//
-class LLMainLoopRepeater:
-	public LLSingleton<LLMainLoopRepeater>
-{
-	LLSINGLETON(LLMainLoopRepeater);
-public:
-	// Start the repeater service.
-	void start(void);
-	
-	// Stop the repeater service.
-	void stop(void);
-	
-private:
-	LLTempBoundListener mMainLoopConnection;
-	LLTempBoundListener mRepeaterConnection;
-	LLThreadSafeQueue<LLSD> * mQueue;
-	
-	bool onMainLoop(LLSD const &);
-	bool onMessage(LLSD const & event);
-};
-
-
-#endif
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index 8d21b04511..df066fb7ed 100644
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -206,6 +206,9 @@
 
 #include "llstacktrace.h"
 
+#include "threadpool.h"
+
+
 #if LL_WINDOWS
 #include "lldxhardware.h"
 #endif
@@ -303,6 +306,20 @@ void callback_cache_name(const LLUUID& id, const std::string& full_name, bool is
 // local classes
 //
 
+void launchThreadPool()
+{
+    LLSD poolSizes{ gSavedSettings.getLLSD("ThreadPoolSizes") };
+    LLSD sizeSpec{ poolSizes["General"] };
+    LLSD::Integer size{ sizeSpec.isInteger()? sizeSpec.asInteger() : 3 };
+    LL_DEBUGS("ThreadPool") << "Instantiating General pool with "
+                            << size << " threads" << LL_ENDL;
+    // Use a function-static ThreadPool: static duration, but instantiated
+    // only on demand.
+    // We don't want anyone, especially the main thread, to have to block
+    // due to this ThreadPool being full.
+    static LL::ThreadPool pool("General", size, 1024*1024);
+}
+
 void update_texture_fetch()
 {
 	LLAppViewer::getTextureCache()->update(1); // unpauses the texture cache thread
diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp
index e6ac701644..f932acd48c 100644
--- a/indra/newview/llviewertexture.cpp
+++ b/indra/newview/llviewertexture.cpp
@@ -679,6 +679,9 @@ void LLViewerTexture::init(bool firstinit)
 	
 	mVolumeList[LLRender::LIGHT_TEX].clear();
 	mVolumeList[LLRender::SCULPT_TEX].clear();
+
+	mMainQueue	= LL::WorkQueue::getInstance("mainloop");
+	mImageQueue = LL::WorkQueue::getInstance("LLImageGL");
 }
 
 //virtual 
@@ -1622,17 +1625,26 @@ void LLViewerFetchedTexture::scheduleCreateTexture()
     {
         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();
-                LLImageGLThread::sInstance->postCallback([this]()
-                    {
-                        //finalize on main thread
-                        postCreateTexture();
-                        unref();
-                    });
-            }))
+        auto mainq = mMainQueue.lock();
+        if (mainq)
+        {
+            mainq->postTo(
+                mImageQueue,
+                // work to be done on LLImageGL worker thread
+                [this]()
+                {
+                    //actually create the texture on a background thread
+                    createTexture();
+                },
+                // callback to be run on main thread
+                [this]()
+                {
+                    //finalize on main thread
+                    postCreateTexture();
+                    unref();
+                });
+        }
+        else
 #endif
         {
             gTextureList.mCreateTextureList.insert(this);
diff --git a/indra/newview/llviewertexture.h b/indra/newview/llviewertexture.h
index f9f1bfef44..4cd4c7cd39 100644
--- a/indra/newview/llviewertexture.h
+++ b/indra/newview/llviewertexture.h
@@ -35,6 +35,7 @@
 #include "llrender.h"
 #include "llmetricperformancetester.h"
 #include "httpcommon.h"
+#include "workqueue.h"
 
 #include <map>
 #include <list>
@@ -213,6 +214,9 @@ protected:
 	//do not use LLPointer here.
 	LLViewerMediaTexture* mParcelMedia ;
 
+	LL::WorkQueue::weak_t mMainQueue;
+	LL::WorkQueue::weak_t mImageQueue;
+
 	static F32 sTexelPixelRatio;
 public:
 	static const U32 sCurrentFileVersion;	
-- 
cgit v1.2.3


From 04ebc11a2d8a2e59abda5061e35e504fc30504d2 Mon Sep 17 00:00:00 2001
From: Nat Goodspeed <nat@lindenlab.com>
Date: Wed, 24 Nov 2021 12:56:48 -0500
Subject: SL-16094: Fix WorkQueue test for correct behavior of runFor().

Turns out that one of our WorkQueue integration tests was relying on the
incorrect runFor() behavior that we just fixed, so the test broke. Now that
runFor() doesn't wait around for work to be posted, use an explicit wait loop
instead.

To support this, add LLCond::get(functor), where functor must accept a const
reference to the stored data. This new get() returns whatever the functor
returns, allowing a caller to peek at the stored data.

Also use universal references for all remaining LLCond functor arguments.
---
 indra/llcommon/llcond.h                 | 52 +++++++++++++++++++++++----------
 indra/llcommon/tests/workqueue_test.cpp | 12 ++++++--
 2 files changed, 45 insertions(+), 19 deletions(-)

(limited to 'indra')

diff --git a/indra/llcommon/llcond.h b/indra/llcommon/llcond.h
index c08acb66a1..da6e6affe1 100644
--- a/indra/llcommon/llcond.h
+++ b/indra/llcommon/llcond.h
@@ -67,15 +67,30 @@ public:
     LLCond(const LLCond&) = delete;
     LLCond& operator=(const LLCond&) = delete;
 
-    /// 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().
+    /**
+     * get() returns the stored DATA by value -- so to use get(), DATA must
+     * be copyable. The only way to get a non-const reference -- to modify
+     * the stored DATA -- is via update_one() or update_all().
+     */
     value_type get()
     {
         LockType lk(mMutex);
         return mData;
     }
 
+    /**
+     * get(functor) returns whatever the functor returns. It allows us to peek
+     * at the stored DATA without copying the whole thing. The functor must
+     * accept a const reference to DATA. If you want to modify DATA, call
+     * update_one() or update_all() instead.
+     */
+    template <typename FUNC>
+    auto get(FUNC&& func)
+    {
+        LockType lk(mMutex);
+        return std::forward<FUNC>(func)(const_data());
+    }
+
     /**
      * Pass update_one() an invocable accepting non-const (DATA&). The
      * invocable will presumably modify the referenced DATA. update_one()
@@ -86,11 +101,11 @@ public:
      * update_one() when DATA is a struct or class.
      */
     template <typename MODIFY>
-    void update_one(MODIFY modify)
+    void update_one(MODIFY&& modify)
     {
         { // scope of lock can/should end before notify_one()
             LockType lk(mMutex);
-            modify(mData);
+            std::forward<MODIFY>(modify)(mData);
         }
         mCond.notify_one();
     }
@@ -105,11 +120,11 @@ public:
      * update_all() when DATA is a struct or class.
      */
     template <typename MODIFY>
-    void update_all(MODIFY modify)
+    void update_all(MODIFY&& modify)
     {
         { // scope of lock can/should end before notify_all()
             LockType lk(mMutex);
-            modify(mData);
+            std::forward<MODIFY>(modify)(mData);
         }
         mCond.notify_all();
     }
@@ -122,7 +137,7 @@ public:
      * wait() on the condition_variable.
      */
     template <typename Pred>
-    void wait(Pred pred)
+    void wait(Pred&& pred)
     {
         LockType lk(mMutex);
         // We must iterate explicitly since the predicate accepted by
@@ -133,7 +148,7 @@ public:
         // But what if they instead pass a predicate accepting non-const
         // (DATA&)? Such a predicate could modify mData, which would be Bad.
         // Forbid that.
-        while (! pred(const_cast<const value_type&>(mData)))
+        while (! std::forward<Pred>(pred)(const_data()))
         {
             mCond.wait(lk);
         }
@@ -150,7 +165,7 @@ public:
      * returning true.
      */
     template <typename Rep, typename Period, typename Pred>
-    bool wait_for(const std::chrono::duration<Rep, Period>& timeout_duration, Pred pred)
+    bool wait_for(const std::chrono::duration<Rep, Period>& timeout_duration, Pred&& pred)
     {
         // Instead of replicating wait_until() logic, convert duration to
         // time_point and just call wait_until().
@@ -159,7 +174,8 @@ public:
         // wrong! We'd keep pushing the timeout time farther and farther into
         // the future. This way, we establish a definite timeout time and
         // stick to it.
-        return wait_until(std::chrono::steady_clock::now() + timeout_duration, pred);
+        return wait_until(std::chrono::steady_clock::now() + timeout_duration,
+                          std::forward<Pred>(pred));
     }
 
     /**
@@ -169,9 +185,9 @@ public:
      * generic wait_for() method.
      */
     template <typename Pred>
-    bool wait_for(F32Milliseconds timeout_duration, Pred pred)
+    bool wait_for(F32Milliseconds timeout_duration, Pred&& pred)
     {
-        return wait_for(convert(timeout_duration), pred);
+        return wait_for(convert(timeout_duration), std::forward<Pred>(pred));
     }
 
 protected:
@@ -189,6 +205,10 @@ protected:
     }
 
 private:
+    // It's important to pass a const ref to certain user-specified functors
+    // that aren't supposed to be able to modify mData.
+    const value_type& const_data() const { return mData; }
+
     /**
      * Pass wait_until() a chrono::time_point, indicating the time at which we
      * should stop waiting, and a predicate accepting (const DATA&), returning
@@ -209,21 +229,21 @@ private:
      * honoring a fixed timeout.
      */
     template <typename Clock, typename Duration, typename Pred>
-    bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time, Pred pred)
+    bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time, Pred&& pred)
     {
         LockType lk(mMutex);
         // We advise the caller to pass a predicate accepting (const DATA&).
         // But what if they instead pass a predicate accepting non-const
         // (DATA&)? Such a predicate could modify mData, which would be Bad.
         // Forbid that.
-        while (! pred(const_cast<const value_type&>(mData)))
+        while (! std::forward<Pred>(pred)(const_data()))
         {
             if (cv_status::timeout == mCond.wait_until(lk, timeout_time))
             {
                 // It's possible that wait_until() timed out AND the predicate
                 // became true more or less simultaneously. Even though
                 // wait_until() timed out, check the predicate one more time.
-                return pred(const_cast<const value_type&>(mData));
+                return std::forward<Pred>(pred)(const_data());
             }
         }
         return true;
diff --git a/indra/llcommon/tests/workqueue_test.cpp b/indra/llcommon/tests/workqueue_test.cpp
index bea3ad911b..1d73f7aa0d 100644
--- a/indra/llcommon/tests/workqueue_test.cpp
+++ b/indra/llcommon/tests/workqueue_test.cpp
@@ -99,9 +99,15 @@ namespace tut
                 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);
+        // postEvery() running, so run until we have exhausted the iterations
+        // or we time out waiting
+        for (auto finish = start + 10*interval;
+             WorkQueue::TimePoint::clock::now() < finish &&
+             data.get([](const Shared& data){ return data.size(); }) < 3; )
+        {
+            queue.runPending();
+            std::this_thread::sleep_for(interval/10);
+        }
         // Take a copy of the captured deque.
         Shared result = data.get();
         ensure_equals("called wrong number of times", result.size(), 3);
-- 
cgit v1.2.3


From bd653fb69382e5a94417ff13c4041b2bc7efdc1f Mon Sep 17 00:00:00 2001
From: Nat Goodspeed <nat@lindenlab.com>
Date: Wed, 24 Nov 2021 15:20:47 -0500
Subject: SL-16094: Clean up a bit more merge cruft.

---
 indra/newview/llstartup.cpp | 14 --------------
 1 file changed, 14 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index df066fb7ed..adfa1b0c10 100644
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -306,20 +306,6 @@ void callback_cache_name(const LLUUID& id, const std::string& full_name, bool is
 // local classes
 //
 
-void launchThreadPool()
-{
-    LLSD poolSizes{ gSavedSettings.getLLSD("ThreadPoolSizes") };
-    LLSD sizeSpec{ poolSizes["General"] };
-    LLSD::Integer size{ sizeSpec.isInteger()? sizeSpec.asInteger() : 3 };
-    LL_DEBUGS("ThreadPool") << "Instantiating General pool with "
-                            << size << " threads" << LL_ENDL;
-    // Use a function-static ThreadPool: static duration, but instantiated
-    // only on demand.
-    // We don't want anyone, especially the main thread, to have to block
-    // due to this ThreadPool being full.
-    static LL::ThreadPool pool("General", size, 1024*1024);
-}
-
 void update_texture_fetch()
 {
 	LLAppViewer::getTextureCache()->update(1); // unpauses the texture cache thread
-- 
cgit v1.2.3


From f7258b49b20cb306804db8276b1caf7d9bb75e23 Mon Sep 17 00:00:00 2001
From: Mnikolenko Productengine <mnikolenko@productengine.com>
Date: Thu, 25 Nov 2021 17:33:13 +0200
Subject: SL-16408 Fix for crashing on disconnect

---
 indra/newview/llappviewer.cpp | 3 ++-
 indra/newview/pipeline.cpp    | 7 +++++--
 2 files changed, 7 insertions(+), 3 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 177558d38f..58e15c3630 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -1768,6 +1768,8 @@ bool LLAppViewer::cleanup()
 	//ditch LLVOAvatarSelf instance
 	gAgentAvatarp = NULL;
 
+    LLViewerCamera::deleteSingleton();
+
     LLNotifications::instance().clear();
 
 	// workaround for DEV-35406 crash on shutdown
@@ -5722,7 +5724,6 @@ void LLAppViewer::disconnectViewer()
 		LLWorld::getInstance()->destroyClass();
 	}
 	LLVOCache::deleteSingleton();
-    LLViewerCamera::deleteSingleton();
 
 	// call all self-registered classes
 	LLDestroyClassList::instance().fireCallbacks();
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index d9d97ac1e5..5b6de5874b 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -4010,8 +4010,11 @@ void render_hud_elements()
 		// Draw the tracking overlays
 		LLTracker::render3D();
 		
-		// Show the property lines
-		LLWorld::getInstance()->renderPropertyLines();
+        if (LLWorld::instanceExists())
+        {
+            // Show the property lines
+            LLWorld::getInstance()->renderPropertyLines();
+        }
 		LLViewerParcelMgr::getInstance()->render();
 		LLViewerParcelMgr::getInstance()->renderParcelCollision();
 	
-- 
cgit v1.2.3


From 5641f9612cfadaac697a54a4c80b4bb08815bc5b Mon Sep 17 00:00:00 2001
From: Mnikolenko Productengine <mnikolenko@productengine.com>
Date: Mon, 29 Nov 2021 17:52:11 +0200
Subject: SL-16408 fixed regression - crash on exit

---
 indra/newview/llappviewer.cpp | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 58e15c3630..13670b7f13 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -1768,9 +1768,7 @@ bool LLAppViewer::cleanup()
 	//ditch LLVOAvatarSelf instance
 	gAgentAvatarp = NULL;
 
-    LLViewerCamera::deleteSingleton();
-
-    LLNotifications::instance().clear();
+     LLNotifications::instance().clear();
 
 	// workaround for DEV-35406 crash on shutdown
 	LLEventPumps::instance().reset();
@@ -1811,6 +1809,7 @@ bool LLAppViewer::cleanup()
     LLPluginProcessParent::shutdown();
 
 	disconnectViewer();
+    LLViewerCamera::deleteSingleton();
 
 	LL_INFOS() << "Viewer disconnected" << LL_ENDL;
 	
-- 
cgit v1.2.3


From 39733ba1cdd137941f42ce135103877ba769aafc Mon Sep 17 00:00:00 2001
From: Dave Houlton <euclid@lindenlab.com>
Date: Mon, 29 Nov 2021 15:18:53 -0700
Subject: DRTVWR-542 merge, purge GLOD copyrights from xml

---
 indra/newview/skins/default/xui/da/floater_about.xml | 1 -
 indra/newview/skins/default/xui/de/floater_about.xml | 1 -
 indra/newview/skins/default/xui/es/floater_about.xml | 1 -
 indra/newview/skins/default/xui/fr/floater_about.xml | 1 -
 indra/newview/skins/default/xui/it/floater_about.xml | 1 -
 indra/newview/skins/default/xui/ja/floater_about.xml | 1 -
 indra/newview/skins/default/xui/pt/floater_about.xml | 1 -
 indra/newview/skins/default/xui/ru/floater_about.xml | 1 -
 indra/newview/skins/default/xui/tr/floater_about.xml | 1 -
 indra/newview/skins/default/xui/zh/floater_about.xml | 1 -
 10 files changed, 10 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/skins/default/xui/da/floater_about.xml b/indra/newview/skins/default/xui/da/floater_about.xml
index 7654f0dcd6..b322e67bb7 100644
--- a/indra/newview/skins/default/xui/da/floater_about.xml
+++ b/indra/newview/skins/default/xui/da/floater_about.xml
@@ -60,7 +60,6 @@ DBus/dbus-glib Copyright (C) 2002, 2003  CodeFactory AB / Copyright (C) 2003, 20
 expat Copyright (C) 1998, 1999, 2000 Thai Open Source Software Center Ltd.
 FreeType Copyright (C) 1996-2002, The FreeType Project (www.freetype.org).
 GL Copyright (C) 1999-2004 Brian Paul.
-GLOD Copyright (C) 2003-04 Jonathan Cohen, Nat Duca, Chris Niski, Johns Hopkins University and David Luebke, Brenden Schubert, University of Virginia.
 google-perftools Copyright (c) 2005, Google Inc.
 Havok.com(TM) Copyright (C) 1999-2001, Telekinesys Research Limited.
 jpeg2000 Copyright (C) 2001, David Taubman, The University of New South Wales (UNSW)
diff --git a/indra/newview/skins/default/xui/de/floater_about.xml b/indra/newview/skins/default/xui/de/floater_about.xml
index 42e23b2089..b2708f7141 100644
--- a/indra/newview/skins/default/xui/de/floater_about.xml
+++ b/indra/newview/skins/default/xui/de/floater_about.xml
@@ -19,7 +19,6 @@ mit Open-Source-Beiträgen von:</text>
         expat Copyright (C) 1998, 1999, 2000 Thai Open Source Software Center Ltd.
         FreeType Copyright (C) 1996-2002, 2006 David Turner, Robert Wilhelm und Werner Lemberg.
         GL Copyright (C) 1999-2004 Brian Paul.
-        GLOD Copyright (C) 2003-04 Jonathan Cohen, Nat Duca, Chris Niski, Johns Hopkins University sowie David Luebke, Brenden Schubert, University of Virginia.
         google-perftools Copyright (c) 2005, Google Inc.
         Havok.com(TM) Copyright (C) 1999-2001, Telekinesys Research Limited.
         jpeg2000 Copyright (C) 2001, David Taubman, The University of New South Wales (UNSW).
diff --git a/indra/newview/skins/default/xui/es/floater_about.xml b/indra/newview/skins/default/xui/es/floater_about.xml
index 8f143cf072..f59f534908 100644
--- a/indra/newview/skins/default/xui/es/floater_about.xml
+++ b/indra/newview/skins/default/xui/es/floater_about.xml
@@ -19,7 +19,6 @@ con contribuciones de código abierto de:</text>
         expat Copyright (C) 1998, 1999, 2000 Thai Open Source Software Center Ltd.
         FreeType Copyright (C) 1996-2002, 2006 David Turner, Robert Wilhelm y Werner Lemberg.
         GL Copyright (C) 1999-2004 Brian Paul.
-        GLOD Copyright (C) 2003-04 Jonathan Cohen, Nat Duca, Chris Niski, Johns Hopkins University y David Luebke, Brenden Schubert, University of Virginia.
         google-perftools Copyright (c) 2005, Google Inc.
         Havok.com(TM) Copyright (C) 1999-2001, Telekinesys Research Limited.
         jpeg2000 Copyright (C) 2001, David Taubman, The University of New South Wales (UNSW)
diff --git a/indra/newview/skins/default/xui/fr/floater_about.xml b/indra/newview/skins/default/xui/fr/floater_about.xml
index 1e2a14ab3e..df6b61e293 100644
--- a/indra/newview/skins/default/xui/fr/floater_about.xml
+++ b/indra/newview/skins/default/xui/fr/floater_about.xml
@@ -19,7 +19,6 @@ avec les contributions Open Source de :</text>
         expat Copyright (C) 1998, 1999, 2000 Thai Open Source Software Center Ltd.
         FreeType Copyright (C) 1996-2002, 2006 David Turner, Robert Wilhelm et Werner Lemberg.
         GL Copyright (C) 1999-2004 Brian Paul.
-        GLOD Copyright (C) 2003-04 Jonathan Cohen, Nat Duca, Chris Niski, Johns Hopkins University, et David Luebke, Brenden Schubert, University of Virginia.
         google-perftools Copyright (c) 2005, Google Inc.
         Havok.com(TM) Copyright (C) 1999-2001, Telekinesys Research Limited.
         jpeg2000 Copyright (C) 2001, David Taubman, The University of New South Wales (UNSW)
diff --git a/indra/newview/skins/default/xui/it/floater_about.xml b/indra/newview/skins/default/xui/it/floater_about.xml
index 9603238b66..edb334e13e 100644
--- a/indra/newview/skins/default/xui/it/floater_about.xml
+++ b/indra/newview/skins/default/xui/it/floater_about.xml
@@ -19,7 +19,6 @@ con contributi open source da:</text>
         expat Copyright (C) 1998, 1999, 2000 Thai Open Source Software Center Ltd.
         FreeType Copyright (C) 1996-2002, 2006 David Turner, Robert Wilhelm e Werner Lemberg.
         GL Copyright (C) 1999-2004 Brian Paul.
-        GLOD Copyright (C) 2003-04 Jonathan Cohen, Nat Duca, Chris Niski, Johns Hopkins University e David Luebke, Brenden Schubert, University of Virginia.
         google-perftools Copyright (c) 2005, Google Inc.
         Havok.com(TM) Copyright (C) 1999-2001, Telekinesys Research Limited.
         jpeg2000 Copyright (C) 2001, David Taubman, The University of New South Wales (UNSW)
diff --git a/indra/newview/skins/default/xui/ja/floater_about.xml b/indra/newview/skins/default/xui/ja/floater_about.xml
index cf5e97bd8d..6a39d057e2 100644
--- a/indra/newview/skins/default/xui/ja/floater_about.xml
+++ b/indra/newview/skins/default/xui/ja/floater_about.xml
@@ -19,7 +19,6 @@ DBus/dbus-glib Copyright (C) 2002, 2003  CodeFactory AB / Copyright (C) 2003, 20
 expat Copyright (C) 1998, 1999, 2000 Thai Open Source Software Center Ltd.
 FreeType Copyright (C) 1996-2002, 2006 David Turner, Robert Wilhelm, and Werner Lemberg.
 GL Copyright (C) 1999-2004 Brian Paul.
-GLOD Copyright (C) 2003-04 Jonathan Cohen, Nat Duca, Chris Niski, Johns Hopkins University and David Luebke, Brenden Schubert, University of Virginia.
 google-perftools Copyright (c) 2005, Google Inc.
 Havok.com(TM) Copyright (C) 1999-2001, Telekinesys Research Limited.
 jpeg2000 Copyright (C) 2001, David Taubman, The University of New South Wales (UNSW)
diff --git a/indra/newview/skins/default/xui/pt/floater_about.xml b/indra/newview/skins/default/xui/pt/floater_about.xml
index 65c457f822..3c0ca332ac 100644
--- a/indra/newview/skins/default/xui/pt/floater_about.xml
+++ b/indra/newview/skins/default/xui/pt/floater_about.xml
@@ -19,7 +19,6 @@ com contribuições de código aberto de:</text>
         expat Copyright (C) 1998, 1999, 2000 Thai Open Source Software Center Ltd.
         FreeType Copyright (C) 1996-2002, 2006 David Turner, Robert Wilhelm, and Werner Lemberg.
         GL Copyright (C) 1999-2004 Brian Paul.
-        GLOD Copyright (C) 2003-04 Jonathan Cohen, Nat Duca, Chris Niski, Johns Hopkins University e David Luebke, Brenden Schubert, University of Virginia.
         google-perftools Copyright (c) 2005, Google Inc.
         Havok.com(TM) Copyright (C) 1999-2001, Telekinesys Research Limited.
         jpeg2000 Copyright (C) 2001, David Taubman, The University of New South Wales (UNSW)
diff --git a/indra/newview/skins/default/xui/ru/floater_about.xml b/indra/newview/skins/default/xui/ru/floater_about.xml
index ee9f82847d..44216e0430 100644
--- a/indra/newview/skins/default/xui/ru/floater_about.xml
+++ b/indra/newview/skins/default/xui/ru/floater_about.xml
@@ -19,7 +19,6 @@
         expat (C) 1998, 1999, 2000 Thai Open Source Software Center Ltd.
         FreeType (C) 1996-2002, 2006 David Turner, Robert Wilhelm и Werner Lemberg.
         GL (C) 1999-2004 Brian Paul.
-        GLOD (C) 2003-04 Jonathan Cohen, Nat Duca, Chris Niski, Университет Джона Гопкинса и David Luebke, Brenden Schubert, Университет Вирджинии.
         google-perftools (c) 2005, Google Inc.
         Havok.com(TM) (C) 1999-2001, Telekinesys Research Limited.
         jpeg2000 (C) 2001, David Taubman, Университет Нового Южного Уэльса (UNSW)
diff --git a/indra/newview/skins/default/xui/tr/floater_about.xml b/indra/newview/skins/default/xui/tr/floater_about.xml
index b91575954b..faa504a996 100644
--- a/indra/newview/skins/default/xui/tr/floater_about.xml
+++ b/indra/newview/skins/default/xui/tr/floater_about.xml
@@ -19,7 +19,6 @@ açık kaynak kod katkısında bulunanlar şunlardır:</text>
         expat Telif Hakkı (C) 1998, 1999, 2000 Thai Open Source Software Center Ltd.
         FreeType Telif Hakkı (C) 1996-2002, 2006 David Turner, Robert Wilhelm ve Werner Lemberg.
         GL Telif Hakkı (C) 1999-2004 Brian Paul.
-        GLOD Telif Hakkı (C) 2003-04 Jonathan Cohen, Nat Duca, Chris Niski, Johns Hopkins University ve David Luebke, Brenden Schubert, University of Virginia.
         google-perftools Telif Hakkı (c) 2005, Google Inc.
         Havok.com(TM) Telif Hakkı (C) 1999-2001, Telekinesys Research Limited.
         jpeg2000 Telif Hakkı (C) 2001, David Taubman, The University of New South Wales (UNSW)
diff --git a/indra/newview/skins/default/xui/zh/floater_about.xml b/indra/newview/skins/default/xui/zh/floater_about.xml
index 9f6b4421a9..d7d2a52750 100644
--- a/indra/newview/skins/default/xui/zh/floater_about.xml
+++ b/indra/newview/skins/default/xui/zh/floater_about.xml
@@ -19,7 +19,6 @@
         expat Copyright (C) 1998, 1999, 2000 Thai Open Source Software Center Ltd.
         FreeType Copyright (C) 1996-2002, 2006 David Turner, Robert Wilhelm, and Werner Lemberg.
         GL Copyright (C) 1999-2004 Brian Paul.
-        GLOD Copyright (C) 2003-04 Jonathan Cohen, Nat Duca, Chris Niski, Johns Hopkins University and David Luebke, Brenden Schubert, University of Virginia.
         google-perftools Copyright (c) 2005, Google Inc.
         Havok.com(TM) Copyright (C) 1999-2001, Telekinesys Research Limited.
         jpeg2000 Copyright (C) 2001, David Taubman, The University of New South Wales (UNSW)
-- 
cgit v1.2.3


From bc9552900339526b241cfd6ee4fb90a498868fd6 Mon Sep 17 00:00:00 2001
From: Mnikolenko Productengine <mnikolenko@productengine.com>
Date: Tue, 30 Nov 2021 19:01:33 +0200
Subject: SL-16369 Remove Hardware Skinning setting

---
 indra/newview/app_settings/high_graphics.xml       |  2 -
 indra/newview/app_settings/low_graphics.xml        |  2 -
 indra/newview/app_settings/mid_graphics.xml        |  2 -
 indra/newview/app_settings/settings.xml            | 11 -----
 indra/newview/app_settings/ultra_graphics.xml      |  2 -
 indra/newview/llfloaterpreference.cpp              | 49 +---------------------
 indra/newview/llviewercontrol.cpp                  |  1 -
 indra/newview/llviewershadermgr.cpp                | 16 ++-----
 indra/newview/pipeline.cpp                         |  4 --
 indra/newview/pipeline.h                           |  1 -
 .../en/floater_preferences_graphics_advanced.xml   | 16 +------
 11 files changed, 6 insertions(+), 100 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/app_settings/high_graphics.xml b/indra/newview/app_settings/high_graphics.xml
index 662f7e39dd..f64937f443 100644
--- a/indra/newview/app_settings/high_graphics.xml
+++ b/indra/newview/app_settings/high_graphics.xml
@@ -6,8 +6,6 @@
 	<RenderAvatarLODFactor value="1.0"/>
 	<!--Default for now-->
 	<RenderAvatarPhysicsLODFactor value="0.9"/>
-	<!--NO SHADERS-->
-	<RenderAvatarVP value="TRUE"/>
 	<!--Short Range-->
 	<RenderFarClip value="128"/>
 	<!--Default for now-->
diff --git a/indra/newview/app_settings/low_graphics.xml b/indra/newview/app_settings/low_graphics.xml
index 0ee8e7a059..b31a040d67 100644
--- a/indra/newview/app_settings/low_graphics.xml
+++ b/indra/newview/app_settings/low_graphics.xml
@@ -6,8 +6,6 @@
 	<RenderAvatarLODFactor value="0.5"/>
 	<!--Default for now-->
 	<RenderAvatarPhysicsLODFactor value="0.0"/>
-	<!--NO SHADERS-->
-	<RenderAvatarVP value="FALSE"/>
 	<!--Short Range-->
 	<RenderFarClip value="64"/>
 	<!--Default for now-->
diff --git a/indra/newview/app_settings/mid_graphics.xml b/indra/newview/app_settings/mid_graphics.xml
index c89e060307..9c2c17fc60 100644
--- a/indra/newview/app_settings/mid_graphics.xml
+++ b/indra/newview/app_settings/mid_graphics.xml
@@ -6,8 +6,6 @@
 	<RenderAvatarLODFactor value="0.5"/>
 	<!--Default for now-->
 	<RenderAvatarPhysicsLODFactor value="0.75"/>
-	<!--NO SHADERS-->
-	<RenderAvatarVP value="TRUE"/>
 	<!--Short Range-->
 	<RenderFarClip value="96"/>
 	<!--Default for now-->
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 058da4b66d..167483783e 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -8840,17 +8840,6 @@
       <key>Value</key>
       <real>1.0</real>
     </map>
-    <key>RenderAvatarVP</key>
-    <map>
-      <key>Comment</key>
-      <string>Use vertex programs to perform hardware skinning of avatar</string>
-      <key>Persist</key>
-      <integer>1</integer>
-      <key>Type</key>
-      <string>Boolean</string>
-      <key>Value</key>
-      <integer>1</integer>
-    </map>
   <key>RenderCompressTextures</key>
   <map>
     <key>Comment</key>
diff --git a/indra/newview/app_settings/ultra_graphics.xml b/indra/newview/app_settings/ultra_graphics.xml
index eb2cd356d9..8462df207b 100644
--- a/indra/newview/app_settings/ultra_graphics.xml
+++ b/indra/newview/app_settings/ultra_graphics.xml
@@ -6,8 +6,6 @@
 	<RenderAvatarLODFactor value="1.0"/>
 	<!--Default for now-->
 	<RenderAvatarPhysicsLODFactor value="1.0"/>
-	<!--NO SHADERS-->
-	<RenderAvatarVP value="TRUE"/>
 	<!--Short Range-->
 	<RenderFarClip value="256"/>
 	<!--Default for now-->
diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp
index 12b4d6a1cd..735744661e 100644
--- a/indra/newview/llfloaterpreference.cpp
+++ b/indra/newview/llfloaterpreference.cpp
@@ -1204,7 +1204,6 @@ void LLFloaterPreference::refreshEnabledState()
 						bumpshiny &&
 						shaders && 
 						gGLManager.mHasFramebufferObject &&
-						gSavedSettings.getBOOL("RenderAvatarVP") &&
 						(ctrl_wind_light->get()) ? TRUE : FALSE;
 
 	ctrl_deferred->setEnabled(enabled);
@@ -1231,28 +1230,8 @@ void LLFloaterPreferenceGraphicsAdvanced::refreshEnabledState()
 	bumpshiny_ctrl->setEnabled(bumpshiny ? TRUE : FALSE);
     
 	// Avatar Mode
-	// Enable Avatar Shaders
-	LLCheckBoxCtrl* ctrl_avatar_vp = getChild<LLCheckBoxCtrl>("AvatarVertexProgram");
 	// Avatar Render Mode
-	LLCheckBoxCtrl* ctrl_avatar_cloth = getChild<LLCheckBoxCtrl>("AvatarCloth");
-	
-	bool avatar_vp_enabled = LLFeatureManager::getInstance()->isFeatureAvailable("RenderAvatarVP");
-	if (LLViewerShaderMgr::sInitialized)
-	{
-		S32 max_avatar_shader = LLViewerShaderMgr::instance()->mMaxAvatarShaderLevel;
-		avatar_vp_enabled = (max_avatar_shader > 0) ? TRUE : FALSE;
-	}
-
-	ctrl_avatar_vp->setEnabled(avatar_vp_enabled);
-	
-    if (gSavedSettings.getBOOL("RenderAvatarVP") == FALSE)
-    {
-        ctrl_avatar_cloth->setEnabled(FALSE);
-    } 
-    else
-    {
-        ctrl_avatar_cloth->setEnabled(TRUE);
-    }
+    getChild<LLCheckBoxCtrl>("AvatarCloth")->setEnabled(TRUE);
 
     // Vertex Shaders, Global Shader Enable
     // SL-12594 Basic shaders are always enabled. DJH TODO clean up now-orphaned state handling code
@@ -1276,7 +1255,6 @@ void LLFloaterPreferenceGraphicsAdvanced::refreshEnabledState()
     BOOL enabled = LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferred") &&
                         ((bumpshiny_ctrl && bumpshiny_ctrl->get()) ? TRUE : FALSE) &&
                         gGLManager.mHasFramebufferObject &&
-                        gSavedSettings.getBOOL("RenderAvatarVP") &&
                         (ctrl_wind_light->get()) ? TRUE : FALSE;
 
     ctrl_deferred->setEnabled(enabled);
@@ -1375,7 +1353,6 @@ void LLFloaterPreferenceGraphicsAdvanced::disableUnavailableSettings()
 {	
 	LLComboBox* ctrl_reflections   = getChild<LLComboBox>("Reflections");
 	LLTextBox* reflections_text = getChild<LLTextBox>("ReflectionsText");
-	LLCheckBoxCtrl* ctrl_avatar_vp     = getChild<LLCheckBoxCtrl>("AvatarVertexProgram");
 	LLCheckBoxCtrl* ctrl_avatar_cloth  = getChild<LLCheckBoxCtrl>("AvatarCloth");
 	LLCheckBoxCtrl* ctrl_wind_light    = getChild<LLCheckBoxCtrl>("WindLightUseAtmosShaders");
 	LLCheckBoxCtrl* ctrl_deferred = getChild<LLCheckBoxCtrl>("UseLightShaders");
@@ -1451,30 +1428,6 @@ void LLFloaterPreferenceGraphicsAdvanced::disableUnavailableSettings()
 		reflections_text->setEnabled(FALSE);
 	}
 	
-	// disabled av
-	if (!LLFeatureManager::getInstance()->isFeatureAvailable("RenderAvatarVP"))
-	{
-		ctrl_avatar_vp->setEnabled(FALSE);
-		ctrl_avatar_vp->setValue(FALSE);
-		
-		ctrl_avatar_cloth->setEnabled(FALSE);
-		ctrl_avatar_cloth->setValue(FALSE);
-
-		//deferred needs AvatarVP, disable deferred
-		ctrl_shadows->setEnabled(FALSE);
-		ctrl_shadows->setValue(0);
-		shadows_text->setEnabled(FALSE);
-		
-		ctrl_ssao->setEnabled(FALSE);
-		ctrl_ssao->setValue(FALSE);
-
-		ctrl_dof->setEnabled(FALSE);
-		ctrl_dof->setValue(FALSE);
-
-		ctrl_deferred->setEnabled(FALSE);
-		ctrl_deferred->setValue(FALSE);
-	}
-
 	// disabled cloth
 	if (!LLFeatureManager::getInstance()->isFeatureAvailable("RenderAvatarCloth"))
 	{
diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp
index 9f76543647..3c6c9c905a 100644
--- a/indra/newview/llviewercontrol.cpp
+++ b/indra/newview/llviewercontrol.cpp
@@ -659,7 +659,6 @@ void settings_setup_listeners()
 	gSavedSettings.getControl("OctreeAttachmentSizeFactor")->getSignal()->connect(boost::bind(&handleRepartition, _2));
 	gSavedSettings.getControl("RenderMaxTextureIndex")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _2));
 	gSavedSettings.getControl("RenderUseTriStrips")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _2));
-	gSavedSettings.getControl("RenderAvatarVP")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _2));
 	gSavedSettings.getControl("RenderUIBuffer")->getSignal()->connect(boost::bind(&handleWindowResized, _2));
 	gSavedSettings.getControl("RenderDepthOfField")->getSignal()->connect(boost::bind(&handleReleaseGLBufferChanged, _2));
 	gSavedSettings.getControl("RenderFSAASamples")->getSignal()->connect(boost::bind(&handleReleaseGLBufferChanged, _2));
diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp
index a1f532dd35..b626a8ebea 100644
--- a/indra/newview/llviewershadermgr.cpp
+++ b/indra/newview/llviewershadermgr.cpp
@@ -480,7 +480,7 @@ void LLViewerShaderMgr::setShaders()
     bool hasWindLightShaders     = LLFeatureManager::getInstance()->isFeatureAvailable("WindLightUseAtmosShaders");
     S32 shadow_detail            = gSavedSettings.getS32("RenderShadowDetail");
     bool doingWindLight          = hasWindLightShaders && gSavedSettings.getBOOL("WindLightUseAtmosShaders");
-    bool useRenderDeferred       = doingWindLight && canRenderDeferred && gSavedSettings.getBOOL("RenderDeferred") && gSavedSettings.getBOOL("RenderAvatarVP");
+    bool useRenderDeferred       = doingWindLight && canRenderDeferred && gSavedSettings.getBOOL("RenderDeferred");
 
     //using shaders, disable fixed function
     LLGLSLShader::sNoFixedFunction = true;
@@ -655,7 +655,7 @@ void LLViewerShaderMgr::setShaders()
             mShaderLevel[SHADER_AVATAR] = 3;
             mMaxAvatarShaderLevel = 3;
                 
-            if (gSavedSettings.getBOOL("RenderAvatarVP") && loadShadersObject())
+            if (loadShadersObject())
             { //hardware skinning is enabled and rigged attachment shaders loaded correctly
                 BOOL avatar_cloth = gSavedSettings.getBOOL("RenderAvatarCloth");
 
@@ -670,10 +670,6 @@ void LLViewerShaderMgr::setShaders()
 
                 if (mShaderLevel[SHADER_AVATAR] != avatar_class)
                 {
-                    if (mShaderLevel[SHADER_AVATAR] == 0)
-                    {
-                        gSavedSettings.setBOOL("RenderAvatarVP", FALSE);
-                    }
                     if(llmax(mShaderLevel[SHADER_AVATAR]-1,0) >= 3)
                     {
                         avatar_cloth = true;
@@ -690,12 +686,8 @@ void LLViewerShaderMgr::setShaders()
                 mShaderLevel[SHADER_AVATAR] = 0;
                 mShaderLevel[SHADER_DEFERRED] = 0;
 
-                if (gSavedSettings.getBOOL("RenderAvatarVP"))
-                {
-                    gSavedSettings.setBOOL("RenderDeferred", FALSE);
-                    gSavedSettings.setBOOL("RenderAvatarCloth", FALSE);
-                    gSavedSettings.setBOOL("RenderAvatarVP", FALSE);
-                }
+                gSavedSettings.setBOOL("RenderDeferred", FALSE);
+                gSavedSettings.setBOOL("RenderAvatarCloth", FALSE);
 
                 loadShadersAvatar(); // unloads
 
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index 5b6de5874b..1f4fdca2e7 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -142,7 +142,6 @@
 bool gShiftFrame = false;
 
 //cached settings
-bool LLPipeline::RenderAvatarVP;
 bool LLPipeline::WindLightUseAtmosShaders;
 bool LLPipeline::RenderDeferred;
 F32 LLPipeline::RenderDeferredSunWash;
@@ -537,7 +536,6 @@ void LLPipeline::init()
 	connectRefreshCachedSettingsSafe("RenderAvatarMaxNonImpostors");
 	connectRefreshCachedSettingsSafe("RenderDelayVBUpdate");
 	connectRefreshCachedSettingsSafe("UseOcclusion");
-	connectRefreshCachedSettingsSafe("RenderAvatarVP");
 	connectRefreshCachedSettingsSafe("WindLightUseAtmosShaders");
 	connectRefreshCachedSettingsSafe("RenderDeferred");
 	connectRefreshCachedSettingsSafe("RenderDeferredSunWash");
@@ -1047,7 +1045,6 @@ void LLPipeline::updateRenderDeferred()
                       RenderDeferred &&
                       LLRenderTarget::sUseFBO &&
                       LLPipeline::sRenderBump &&
-                      RenderAvatarVP &&
                       WindLightUseAtmosShaders &&
                       (bool) LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferred");
 }
@@ -1069,7 +1066,6 @@ void LLPipeline::refreshCachedSettings()
 			&& gSavedSettings.getBOOL("UseOcclusion") 
 			&& gGLManager.mHasOcclusionQuery) ? 2 : 0;
 	
-	RenderAvatarVP = gSavedSettings.getBOOL("RenderAvatarVP");
 	WindLightUseAtmosShaders = gSavedSettings.getBOOL("WindLightUseAtmosShaders");
 	RenderDeferred = gSavedSettings.getBOOL("RenderDeferred");
 	RenderDeferredSunWash = gSavedSettings.getF32("RenderDeferredSunWash");
diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h
index 110df8c979..d82f8bd64b 100644
--- a/indra/newview/pipeline.h
+++ b/indra/newview/pipeline.h
@@ -904,7 +904,6 @@ public:
 
 	//cached settings
 	static bool WindLightUseAtmosShaders;
-	static bool RenderAvatarVP;
 	static bool RenderDeferred;
 	static F32 RenderDeferredSunWash;
 	static U32 RenderFSAASamples;
diff --git a/indra/newview/skins/default/xui/en/floater_preferences_graphics_advanced.xml b/indra/newview/skins/default/xui/en/floater_preferences_graphics_advanced.xml
index 4f355cce00..d1e167df64 100644
--- a/indra/newview/skins/default/xui/en/floater_preferences_graphics_advanced.xml
+++ b/indra/newview/skins/default/xui/en/floater_preferences_graphics_advanced.xml
@@ -660,20 +660,6 @@
        Low
   </text>
 
-  <check_box
-    control_name="RenderAvatarVP"
-    height="16"
-    initial_value="true"
-    label="Avatar Hardware skinning"
-    layout="topleft"
-    left="440"
-    name="AvatarVertexProgram"
-    top_delta="16"
-    width="280">
-    <check_box.commit_callback
-      function="Pref.RenderOptionUpdate" />
-  </check_box>
-
   <check_box
     control_name="RenderAvatarCloth"
     height="16"
@@ -885,7 +871,7 @@
       layout="topleft"
       left="13"
       name="horiz_border"
-      top_pad="5"
+      top_pad="21"
       top_delta="5"
       width="774"/>
   <button
-- 
cgit v1.2.3


From cb85a4aaee714fee90a0f610532b9e6e0d2b7a10 Mon Sep 17 00:00:00 2001
From: Nat Goodspeed <nat@lindenlab.com>
Date: Tue, 30 Nov 2021 13:51:29 -0500
Subject: SL-16421: Unify LLAppViewer class declaration alignment.

Use hard tabs as most of the class declaration already uses those.
---
 indra/newview/llappviewer.h | 88 ++++++++++++++++++++++-----------------------
 1 file changed, 44 insertions(+), 44 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h
index 37119aeef9..d23a00be7f 100644
--- a/indra/newview/llappviewer.h
+++ b/indra/newview/llappviewer.h
@@ -67,13 +67,13 @@ public:
 	LLAppViewer();
 	virtual ~LLAppViewer();
 
-    /**
-     * @brief Access to the LLAppViewer singleton.
-     * 
-     * The LLAppViewer singleton is created in main()/WinMain().
-     * So don't use it in pre-entry (static initialization) code.
-     */
-    static LLAppViewer* instance() {return sInstance; } 
+	/**
+	 * @brief Access to the LLAppViewer singleton.
+	 * 
+	 * The LLAppViewer singleton is created in main()/WinMain().
+	 * So don't use it in pre-entry (static initialization) code.
+	 */
+	static LLAppViewer* instance() {return sInstance; } 
 
 	//
 	// Main application logic
@@ -91,12 +91,12 @@ public:
     void earlyExit(const std::string& name, 
 				   const LLSD& substitutions = LLSD()); // Display an error dialog and forcibly quit.
 	void earlyExitNoNotify(); // Do not display error dialog then forcibly quit.
-    void abortQuit();  // Called to abort a quit request.
+	void abortQuit();  // Called to abort a quit request.
 
-    bool quitRequested() { return mQuitRequested; }
-    bool logoutRequestSent() { return mLogoutRequestSent; }
+	bool quitRequested() { return mQuitRequested; }
+	bool logoutRequestSent() { return mLogoutRequestSent; }
 	bool isSecondInstance() { return mSecondInstance; }
-    bool isUpdaterMissing() { return mUpdaterNotFound; }
+	bool isUpdaterMissing() { return mUpdaterNotFound; }
 
 	void writeDebugInfo(bool isStatic=true);
 
@@ -110,7 +110,7 @@ public:
 	virtual bool restoreErrorTrap() = 0; // Require platform specific override to reset error handling mechanism.
 	                                     // return false if the error trap needed restoration.
 	static void handleViewerCrash(); // Hey! The viewer crashed. Do this, soon.
-    void checkForCrash();
+	void checkForCrash();
     
 	// Thread accessors
 	static LLTextureCache* getTextureCache() { return sTextureCache; }
@@ -121,37 +121,37 @@ public:
 	static U32 getObjectCacheVersion() ;
 
 	const std::string& getSerialNumber() { return mSerialNumber; }
-	
+
 	bool getPurgeCache() const { return mPurgeCache; }
-	
+
 	std::string getSecondLifeTitle() const; // The Second Life title.
 	std::string getWindowTitle() const; // The window display name.
 
-    void forceDisconnect(const std::string& msg); // Force disconnection, with a message to the user.
-    void badNetworkHandler(); // Cause a crash state due to bad network packet.
+	void forceDisconnect(const std::string& msg); // Force disconnection, with a message to the user.
+	void badNetworkHandler(); // Cause a crash state due to bad network packet.
 
 	bool hasSavedFinalSnapshot() { return mSavedFinalSnapshot; }
 	void saveFinalSnapshot(); 
 
-    void loadNameCache();
-    void saveNameCache();
+	void loadNameCache();
+	void saveNameCache();
 
 	void loadExperienceCache();
 	void saveExperienceCache();
 
 	void removeMarkerFiles();
-	
+
 	void removeDumpDir();
-    // LLAppViewer testing helpers.
-    // *NOTE: These will potentially crash the viewer. Only for debugging.
-    virtual void forceErrorLLError();
-    virtual void forceErrorBreakpoint();
-    virtual void forceErrorBadMemoryAccess();
-    virtual void forceErrorInfiniteLoop();
-    virtual void forceErrorSoftwareException();
-    virtual void forceErrorDriverCrash();
-    virtual void forceErrorCoroutineCrash();
-    virtual void forceErrorThreadCrash();
+	// LLAppViewer testing helpers.
+	// *NOTE: These will potentially crash the viewer. Only for debugging.
+	virtual void forceErrorLLError();
+	virtual void forceErrorBreakpoint();
+	virtual void forceErrorBadMemoryAccess();
+	virtual void forceErrorInfiniteLoop();
+	virtual void forceErrorSoftwareException();
+	virtual void forceErrorDriverCrash();
+	virtual void forceErrorCoroutineCrash();
+	virtual void forceErrorThreadCrash();
 
 	// The list is found in app_settings/settings_files.xml
 	// but since they are used explicitly in code,
@@ -184,7 +184,7 @@ public:
 	// *NOTE:Mani Fix this for login abstraction!!
 	void handleLoginComplete();
 
-    LLAllocator & getAllocator() { return mAlloc; }
+	LLAllocator & getAllocator() { return mAlloc; }
 
 	// On LoginCompleted callback
 	typedef boost::signals2::signal<void (void)> login_completed_signal_t;
@@ -199,7 +199,7 @@ public:
 	S32  updateTextureThreads(F32 max_time);
 
 	void loadKeyBindings();
-	
+
 	// mute/unmute the system's master audio
 	virtual void setMasterSystemAudioMute(bool mute);
 	virtual bool getMasterSystemAudioMute();	
@@ -211,7 +211,7 @@ public:
 	// llcorehttp init/shutdown/config information.
 	LLAppCoreHttp & getAppCoreHttp()			{ return mAppCoreHttp; }
 
-    void updateNameLookupUrl(const LLViewerRegion* regionp);
+	void updateNameLookupUrl(const LLViewerRegion* regionp);
 
 protected:
 	virtual bool initWindow(); // Initialize the viewer's window.
@@ -222,7 +222,7 @@ protected:
 	virtual bool sendURLToOtherInstance(const std::string& url);
 
 	virtual bool initParseCommandLine(LLCommandLineParser& clp) 
-        { return true; } // Allow platforms to specify the command line args.
+		{ return true; } // Allow platforms to specify the command line args.
 
 	virtual std::string generateSerialNumber() = 0; // Platforms specific classes generate this.
 
@@ -250,22 +250,22 @@ private:
 	void processMarkerFiles(); 
 	static void recordMarkerVersion(LLAPRFile& marker_file);
 	bool markerIsSameVersion(const std::string& marker_name) const;
-	
-    void idle(); 
-    void idleShutdown();
+
+	void idle(); 
+	void idleShutdown();
 	// update avatar SLID and display name caches
 	void idleExperienceCache();
 	void idleNameCache();
-    void idleNetwork();
+	void idleNetwork();
 
-    void sendLogoutRequest();
-    void disconnectViewer();
+	void sendLogoutRequest();
+	void disconnectViewer();
 
 	// *FIX: the app viewer class should be some sort of singleton, no?
 	// Perhaps its child class is the singleton and this should be an abstract base.
 	static LLAppViewer* sInstance; 
 
-    bool mSecondInstance; // Is this a second instance of the app?
+	bool mSecondInstance; // Is this a second instance of the app?
 	bool mUpdaterNotFound; // True when attempt to start updater failed
 
 	std::string mMarkerFileName;
@@ -296,8 +296,8 @@ private:
 
 	boost::optional<U32> mForceGraphicsLevel;
 
-    bool mQuitRequested;				// User wants to quit, may have modified documents open.
-    bool mLogoutRequestSent;			// Disconnect message sent to simulator, no longer safe to send messages to the sim.
+	bool mQuitRequested;				// User wants to quit, may have modified documents open.
+	bool mLogoutRequestSent;			// Disconnect message sent to simulator, no longer safe to send messages to the sim.
 	U32 mLastAgentControlFlags;
 	F32 mLastAgentForceUpdate;
 	struct SettingsFiles* mSettingsLocationList;
@@ -311,12 +311,12 @@ private:
 	bool mAgentRegionLastAlive;
 	LLUUID mAgentRegionLastID;
 
-    LLAllocator mAlloc;
+	LLAllocator mAlloc;
 
 	// llcorehttp library init/shutdown helper
 	LLAppCoreHttp mAppCoreHttp;
 
-    bool mIsFirstRun;
+	bool mIsFirstRun;
 };
 
 // consts from viewer.h
-- 
cgit v1.2.3


From 9be88050e67edcb8578ce6edbee255ba66e553a1 Mon Sep 17 00:00:00 2001
From: Nat Goodspeed <nat@lindenlab.com>
Date: Tue, 30 Nov 2021 14:05:35 -0500
Subject: SL-16421: Unify LLAppViewer::cleanup() indentation.

Use hard tabs because most of the existing function uses those.
---
 indra/newview/llappviewer.cpp | 77 +++++++++++++++++++++----------------------
 1 file changed, 38 insertions(+), 39 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index d6c6eb6a98..529db397b2 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -1729,12 +1729,12 @@ void LLAppViewer::flushVFSIO()
 
 bool LLAppViewer::cleanup()
 {
-    LLAtmosphere::cleanupClass();
+	LLAtmosphere::cleanupClass();
 
 	//ditch LLVOAvatarSelf instance
 	gAgentAvatarp = NULL;
 
-     LLNotifications::instance().clear();
+	 LLNotifications::instance().clear();
 
 	// workaround for DEV-35406 crash on shutdown
 	LLEventPumps::instance().reset();
@@ -1771,14 +1771,14 @@ bool LLAppViewer::cleanup()
 	// to ensure shutdown order
 	LLMortician::setZealous(TRUE);
 
-    // Give any remaining SLPlugin instances a chance to exit cleanly.
-    LLPluginProcessParent::shutdown();
+	// Give any remaining SLPlugin instances a chance to exit cleanly.
+	LLPluginProcessParent::shutdown();
 
 	disconnectViewer();
-    LLViewerCamera::deleteSingleton();
+	LLViewerCamera::deleteSingleton();
 
 	LL_INFOS() << "Viewer disconnected" << LL_ENDL;
-	
+
 	if (gKeyboard)
 	{
 		gKeyboard->resetKeys();
@@ -1843,15 +1843,15 @@ bool LLAppViewer::cleanup()
 
 	if (gAudiop)
 	{
-        // be sure to stop the internet stream cleanly BEFORE destroying the interface to stop it.
-        gAudiop->stopInternetStream();
-        // shut down the streaming audio sub-subsystem first, in case it relies on not outliving the general audio subsystem.
-        LLStreamingAudioInterface *sai = gAudiop->getStreamingAudioImpl();
+		// be sure to stop the internet stream cleanly BEFORE destroying the interface to stop it.
+		gAudiop->stopInternetStream();
+		// shut down the streaming audio sub-subsystem first, in case it relies on not outliving the general audio subsystem.
+		LLStreamingAudioInterface *sai = gAudiop->getStreamingAudioImpl();
 		delete sai;
 		gAudiop->setStreamingAudioImpl(NULL);
 
-        // shut down the audio subsystem
-        gAudiop->shutdown();
+		// shut down the audio subsystem
+		gAudiop->shutdown();
 
 		delete gAudiop;
 		gAudiop = NULL;
@@ -1920,11 +1920,11 @@ bool LLAppViewer::cleanup()
 	delete gKeyboard;
 	gKeyboard = NULL;
 
-    if (LLViewerJoystick::instanceExists())
-    {
-        // Turn off Space Navigator and similar devices
-        LLViewerJoystick::getInstance()->terminate();
-    }
+	if (LLViewerJoystick::instanceExists())
+	{
+		// Turn off Space Navigator and similar devices
+		LLViewerJoystick::getInstance()->terminate();
+	}
 
 	LL_INFOS() << "Cleaning up Objects" << LL_ENDL;
 
@@ -1976,11 +1976,11 @@ bool LLAppViewer::cleanup()
 	// Store the time of our current logoff
 	gSavedPerAccountSettings.setU32("LastLogoff", time_corrected());
 
-    if (LLEnvironment::instanceExists())
-    {
-        //Store environment settings if nessesary
-        LLEnvironment::getInstance()->saveToSettings();
-    }
+	if (LLEnvironment::instanceExists())
+	{
+		//Store environment settings if necessary
+		LLEnvironment::getInstance()->saveToSettings();
+	}
 
 	// Must do this after all panels have been deleted because panels that have persistent rects
 	// save their rects on delete.
@@ -2030,7 +2030,7 @@ bool LLAppViewer::cleanup()
 		LLConversationLog::instance().cache();
     }
 
-    clearSecHandler();
+	clearSecHandler();
 
 	if (mPurgeCacheOnExit)
 	{
@@ -2073,13 +2073,13 @@ bool LLAppViewer::cleanup()
 		}
 	}
 
-    if (mPurgeUserDataOnExit)
-    {
-        // Ideally we should not save anything from this session since it is going to be purged now,
-        // but this is a very 'rare' case (user deleting himself), not worth overcomplicating 'save&cleanup' code
-        std::string user_path = gDirUtilp->getOSUserAppDir() + gDirUtilp->getDirDelimiter() + LLStartUp::getUserId();
-        gDirUtilp->deleteDirAndContents(user_path);
-    }
+	if (mPurgeUserDataOnExit)
+	{
+		// Ideally we should not save anything from this session since it is going to be purged now,
+		// but this is a very 'rare' case (user deleting himself), not worth overcomplicating 'save&cleanup' code
+		std::string user_path = gDirUtilp->getOSUserAppDir() + gDirUtilp->getDirDelimiter() + LLStartUp::getUserId();
+		gDirUtilp->deleteDirAndContents(user_path);
+	}
 
 	// Delete workers first
 	// shotdown all worker threads before deleting them in case of co-dependencies
@@ -2102,11 +2102,11 @@ bool LLAppViewer::cleanup()
 
 	//MUST happen AFTER SUBSYSTEM_CLEANUP(LLCurl)
 	delete sTextureCache;
-    sTextureCache = NULL;
+	sTextureCache = NULL;
 	delete sTextureFetch;
-    sTextureFetch = NULL;
+	sTextureFetch = NULL;
 	delete sImageDecodeThread;
-    sImageDecodeThread = NULL;
+	sImageDecodeThread = NULL;
 	delete mFastTimerLogThread;
 	mFastTimerLogThread = NULL;
 
@@ -2182,15 +2182,15 @@ bool LLAppViewer::cleanup()
 	// make sure nothing uses applyProxySettings by this point.
 	LL_INFOS() << "Cleaning up LLProxy." << LL_ENDL;
 	SUBSYSTEM_CLEANUP(LLProxy);
-    LLCore::LLHttp::cleanup();
+	LLCore::LLHttp::cleanup();
 
 	ll_close_fail_log();
 
 	LLError::LLCallStacks::cleanup();
 
-    LLEnvironment::deleteSingleton();
-    LLSelectMgr::deleteSingleton();
-    LLViewerEventRecorder::deleteSingleton();
+	LLEnvironment::deleteSingleton();
+	LLSelectMgr::deleteSingleton();
+	LLViewerEventRecorder::deleteSingleton();
 
 	// It's not at first obvious where, in this long sequence, a generic cleanup
 	// call OUGHT to go. So let's say this: as we migrate cleanup from
@@ -2203,8 +2203,7 @@ bool LLAppViewer::cleanup()
 	// deleteSingleton() methods.
 	LLSingletonBase::deleteAll();
 
-
-    LL_INFOS() << "Goodbye!" << LL_ENDL;
+	LL_INFOS() << "Goodbye!" << LL_ENDL;
 
 	removeDumpDir();
 
-- 
cgit v1.2.3


From 01317a2faded53c79db7e0814426f1d8b2fd12fc Mon Sep 17 00:00:00 2001
From: Nat Goodspeed <nat@lindenlab.com>
Date: Tue, 30 Nov 2021 15:22:26 -0500
Subject: SL-16421: Destroy the "General" ThreadPool as soon as cleanup starts.

Introduce LLAppViewer::onCleanup(), a method that accepts a nullary callable
to execute once viewer shutdown begins. Fire the collected callables in
LLAppViewer::cleanup().

In llstartup.cpp, instead of declaring a static unique_ptr and relying on
static object destruction to clean up the "General" ThreadPool, bind the
pointer to the new ThreadPool into an onCleanup() lambda that will delete it
when called. ~ThreadPool() takes care of orderly shutdown.
---
 indra/newview/llappviewer.cpp |  5 +++++
 indra/newview/llappviewer.h   | 14 +++++++++++++-
 indra/newview/llstartup.cpp   | 23 +++++++++++++----------
 3 files changed, 31 insertions(+), 11 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 529db397b2..a5d32ba243 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -1729,6 +1729,11 @@ void LLAppViewer::flushVFSIO()
 
 bool LLAppViewer::cleanup()
 {
+	// Since we don't know what functions are going to be queued by
+	// onCleanup(), we have to assume they might rely on some of the things
+	// we're about to destroy below. Run them first.
+	mOnCleanup();
+
 	LLAtmosphere::cleanupClass();
 
 	//ditch LLVOAvatarSelf instance
diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h
index d23a00be7f..f456cbbd36 100644
--- a/indra/newview/llappviewer.h
+++ b/indra/newview/llappviewer.h
@@ -49,6 +49,8 @@
 #include "lltimer.h"
 #include "llappcorehttp.h"
 
+#include <boost/signals2.hpp>
+
 class LLCommandLineParser;
 class LLFrameTimer;
 class LLPumpIO;
@@ -189,10 +191,20 @@ public:
 	// On LoginCompleted callback
 	typedef boost::signals2::signal<void (void)> login_completed_signal_t;
 	login_completed_signal_t mOnLoginCompleted;
-	boost::signals2::connection setOnLoginCompletedCallback( const login_completed_signal_t::slot_type& cb ) { return mOnLoginCompleted.connect(cb); } 
+	boost::signals2::connection setOnLoginCompletedCallback( const login_completed_signal_t::slot_type& cb )
+	{
+		return mOnLoginCompleted.connect(cb);
+	}
 
 	void addOnIdleCallback(const boost::function<void()>& cb); // add a callback to fire (once) when idle
 
+	typedef boost::signals2::signal<void()> cleanup_signal_t;
+	cleanup_signal_t mOnCleanup;
+	boost::signals2::connection onCleanup(const cleanup_signal_t::slot_type& cb)
+	{
+		return mOnCleanup.connect(cb);
+	}
+
 	void purgeUserDataOnExit() { mPurgeUserDataOnExit = true; }
 	void purgeCache(); // Clear the local cache. 
 	void purgeCacheImmediate(); //clear local cache immediately.
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index adfa1b0c10..d8e68dbc1e 100644
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -259,7 +259,6 @@ const F32 STATE_AGENT_WAIT_TIMEOUT = 240; //seconds
 std::unique_ptr<LLEventPump> LLStartUp::sStateWatcher(new LLEventStream("StartupState"));
 std::unique_ptr<LLStartupListener> LLStartUp::sListener(new LLStartupListener());
 std::unique_ptr<LLViewerStats::PhaseMap> LLStartUp::sPhases(new LLViewerStats::PhaseMap);
-std::unique_ptr<LL::ThreadPool> gGeneralThreadPool;
 
 //
 // local function declaration
@@ -1495,15 +1494,19 @@ bool idle_startup()
 		display_startup();
 
 		// start up the ThreadPool we'll use for textures et al.
-		LLSD poolSizes{ gSavedSettings.getLLSD("ThreadPoolSizes") };
-		LLSD sizeSpec{ poolSizes["General"] };
-		LLSD::Integer poolSize{ sizeSpec.isInteger()? sizeSpec.asInteger() : 3 };
-		LL_DEBUGS("ThreadPool") << "Instantiating General pool with "
-								<< poolSize << " threads" << LL_ENDL;
-		// We don't want anyone, especially the main thread, to have to block
-		// due to this ThreadPool being full.
-		gGeneralThreadPool.reset(new LL::ThreadPool("General", poolSize, 1024*1024));
-		gGeneralThreadPool->start();
+		{
+			LLSD poolSizes{ gSavedSettings.getLLSD("ThreadPoolSizes") };
+			LLSD sizeSpec{ poolSizes["General"] };
+			LLSD::Integer poolSize{ sizeSpec.isInteger()? sizeSpec.asInteger() : 3 };
+			LL_DEBUGS("ThreadPool") << "Instantiating General pool with "
+									<< poolSize << " threads" << LL_ENDL;
+			// We don't want anyone, especially the main thread, to have to block
+			// due to this ThreadPool being full.
+			auto pool = new LL::ThreadPool("General", poolSize, 1024*1024);
+			pool->start();
+			// Once we start shutting down, destroy this ThreadPool.
+			LLAppViewer::instance()->onCleanup([pool](){ delete pool; });
+		}
 
 		// Initialize global class data needed for surfaces (i.e. textures)
 		LL_DEBUGS("AppInit") << "Initializing sky..." << LL_ENDL;
-- 
cgit v1.2.3


From 68e09edad0d863d57ba06e2842b9399f3ff21618 Mon Sep 17 00:00:00 2001
From: Dave Houlton <euclid@lindenlab.com>
Date: Mon, 29 Nov 2021 17:07:25 -0700
Subject: SL-16386 remove references to (const true)
 LLGLSLShader::sNoFixedFunction

---
 indra/llappearance/lltexlayer.cpp       | 115 ++-------
 indra/llrender/llcubemap.cpp            |  34 ---
 indra/llrender/llgl.cpp                 | 221 ++---------------
 indra/llrender/llgl.h                   |   1 -
 indra/llrender/llglslshader.cpp         |   1 -
 indra/llrender/llglslshader.h           |   1 -
 indra/llrender/llrender.cpp             | 416 ++------------------------------
 indra/llrender/llrender.h               |   5 +-
 indra/llrender/llrender2dutils.cpp      |  80 +-----
 indra/llrender/llshadermgr.cpp          |  38 ---
 indra/llrender/llvertexbuffer.cpp       | 353 ++++++++-------------------
 indra/llwindow/llwindowwin32.cpp        |   8 -
 indra/newview/lldrawpoolavatar.cpp      |  17 +-
 indra/newview/lldrawpoolbump.cpp        |  18 +-
 indra/newview/lldrawpoolsky.cpp         |  12 +-
 indra/newview/lldrawpoolterrain.cpp     |  21 +-
 indra/newview/lldrawpooltree.cpp        |   2 +-
 indra/newview/lldrawpoolwater.cpp       |  19 +-
 indra/newview/lldrawpoolwlsky.cpp       |  25 +-
 indra/newview/llfloaterbvhpreview.cpp   |   5 +-
 indra/newview/llfloaterimagepreview.cpp |  20 +-
 indra/newview/llglsandbox.cpp           |  10 +-
 indra/newview/llhudtext.cpp             |   2 -
 indra/newview/lllegacyatmospherics.cpp  |  31 ---
 indra/newview/llmaniprotate.cpp         |  21 +-
 indra/newview/llmaniptranslate.cpp      |   7 +-
 indra/newview/llmodelpreview.cpp        |  23 +-
 indra/newview/llscenemonitor.cpp        |   9 +-
 indra/newview/llspatialpartition.cpp    |  14 +-
 indra/newview/lltoolmorph.cpp           |   5 +-
 indra/newview/llviewercontrol.cpp       |   2 +-
 indra/newview/llviewerdisplay.cpp       |  30 +--
 indra/newview/llviewerjointmesh.cpp     |   4 +-
 indra/newview/llviewershadermgr.cpp     |  32 +--
 indra/newview/llviewerwindow.cpp        |  36 +--
 indra/newview/llvoavatar.cpp            |  20 --
 indra/newview/llvosurfacepatch.cpp      |  59 +----
 indra/newview/llvowater.cpp             |   2 +-
 indra/newview/pipeline.cpp              | 335 +++++++------------------
 39 files changed, 320 insertions(+), 1734 deletions(-)

(limited to 'indra')

diff --git a/indra/llappearance/lltexlayer.cpp b/indra/llappearance/lltexlayer.cpp
index 26e0ae9086..9af59c7da4 100644
--- a/indra/llappearance/lltexlayer.cpp
+++ b/indra/llappearance/lltexlayer.cpp
@@ -144,17 +144,8 @@ BOOL LLTexLayerSetBuffer::renderTexLayerSet(LLRenderTarget* bound_target)
 
 	BOOL success = TRUE;
 	
-	bool use_shaders = LLGLSLShader::sNoFixedFunction;
-
-	if (use_shaders)
-	{
-		gAlphaMaskProgram.bind();
-		gAlphaMaskProgram.setMinimumAlpha(0.004f);
-	}
-	else
-	{
-		gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.00f);
-	}
+	gAlphaMaskProgram.bind();
+	gAlphaMaskProgram.setMinimumAlpha(0.004f);
 
 	LLVertexBuffer::unbind();
 
@@ -166,10 +157,7 @@ BOOL LLTexLayerSetBuffer::renderTexLayerSet(LLRenderTarget* bound_target)
 
 	midRenderTexLayerSet(success);
 
-	if (use_shaders)
-	{
-		gAlphaMaskProgram.unbind();
-	}
+	gAlphaMaskProgram.unbind();
 
 	LLVertexBuffer::unbind();
 	
@@ -392,8 +380,6 @@ BOOL LLTexLayerSet::render( S32 x, S32 y, S32 width, S32 height, LLRenderTarget*
 		}
 	}
 
-	bool use_shaders = LLGLSLShader::sNoFixedFunction;
-
 	LLGLSUIDefault gls_ui;
 	LLGLDepthTest gls_depth(GL_FALSE, GL_FALSE);
 	gGL.setColorMask(true, true);
@@ -402,20 +388,14 @@ BOOL LLTexLayerSet::render( S32 x, S32 y, S32 width, S32 height, LLRenderTarget*
 	{
 		gGL.flush();
 		LLGLDisable no_alpha(GL_ALPHA_TEST);
-		if (use_shaders)
-		{
-			gAlphaMaskProgram.setMinimumAlpha(0.0f);
-		}
+		gAlphaMaskProgram.setMinimumAlpha(0.0f);
 		gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 		gGL.color4f( 0.f, 0.f, 0.f, 1.f );
 
 		gl_rect_2d_simple( width, height );
 
 		gGL.flush();
-		if (use_shaders)
-		{
-			gAlphaMaskProgram.setMinimumAlpha(0.004f);
-		}
+		gAlphaMaskProgram.setMinimumAlpha(0.004f);
 	}
 
 	if (mIsVisible)
@@ -442,10 +422,7 @@ BOOL LLTexLayerSet::render( S32 x, S32 y, S32 width, S32 height, LLRenderTarget*
 
 		gGL.setSceneBlendType(LLRender::BT_REPLACE);
 		LLGLDisable no_alpha(GL_ALPHA_TEST);
-		if (use_shaders)
-		{
-			gAlphaMaskProgram.setMinimumAlpha(0.f);
-		}
+		gAlphaMaskProgram.setMinimumAlpha(0.f);
 
 		gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 		gGL.color4f( 0.f, 0.f, 0.f, 0.f );
@@ -454,10 +431,7 @@ BOOL LLTexLayerSet::render( S32 x, S32 y, S32 width, S32 height, LLRenderTarget*
 		gGL.setSceneBlendType(LLRender::BT_ALPHA);
 
 		gGL.flush();
-		if (use_shaders)
-		{
-			gAlphaMaskProgram.setMinimumAlpha(0.004f);
-		}
+		gAlphaMaskProgram.setMinimumAlpha(0.004f);
 	}
 
 	return success;
@@ -542,8 +516,6 @@ void LLTexLayerSet::renderAlphaMaskTextures(S32 x, S32 y, S32 width, S32 height,
     LL_PROFILE_ZONE_SCOPED;
 	const LLTexLayerSetInfo *info = getInfo();
 	
-	bool use_shaders = LLGLSLShader::sNoFixedFunction;
-
 	gGL.setColorMask(false, true);
 	gGL.setSceneBlendType(LLRender::BT_REPLACE);
 	
@@ -568,20 +540,14 @@ void LLTexLayerSet::renderAlphaMaskTextures(S32 x, S32 y, S32 width, S32 height,
 		// Set the alpha channel to one (clean up after previous blending)
 		gGL.flush();
 		LLGLDisable no_alpha(GL_ALPHA_TEST);
-		if (use_shaders)
-		{
-			gAlphaMaskProgram.setMinimumAlpha(0.f);
-		}
+		gAlphaMaskProgram.setMinimumAlpha(0.f);
 		gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 		gGL.color4f( 0.f, 0.f, 0.f, 1.f );
 		
 		gl_rect_2d_simple( width, height );
 		
 		gGL.flush();
-		if (use_shaders)
-		{
-			gAlphaMaskProgram.setMinimumAlpha(0.004f);
-		}
+		gAlphaMaskProgram.setMinimumAlpha(0.004f);
 	}
 	
 	// (Optional) Mask out part of the baked texture with alpha masks
@@ -1128,13 +1094,6 @@ BOOL LLTexLayer::render(S32 x, S32 y, S32 width, S32 height, LLRenderTarget* bou
 	// *TODO: Is this correct?
 	//gPipeline.disableLights();
 	stop_glerror();
-	if (!LLGLSLShader::sNoFixedFunction)
-	{
-		glDisable(GL_LIGHTING);
-	}
-	stop_glerror();
-
-	bool use_shaders = LLGLSLShader::sNoFixedFunction;
 
 	LLColor4 net_color;
 	BOOL color_specified = findNetColor(&net_color);
@@ -1221,10 +1180,7 @@ BOOL LLTexLayer::render(S32 x, S32 y, S32 width, S32 height, LLRenderTarget* bou
 					LLGLDisable alpha_test(no_alpha_test ? GL_ALPHA_TEST : 0);
 					if (no_alpha_test)
 					{
-						if (use_shaders)
-						{
-							gAlphaMaskProgram.setMinimumAlpha(0.f);
-						}
+						gAlphaMaskProgram.setMinimumAlpha(0.f);
 					}
 					
 					LLTexUnit::eTextureAddressMode old_mode = tex->getAddressMode();
@@ -1238,10 +1194,7 @@ BOOL LLTexLayer::render(S32 x, S32 y, S32 width, S32 height, LLRenderTarget* bou
 					gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 					if (no_alpha_test)
 					{
-						if (use_shaders)
-						{
-							gAlphaMaskProgram.setMinimumAlpha(0.004f);
-						}
+						gAlphaMaskProgram.setMinimumAlpha(0.004f);
 					}
 				}
 			}
@@ -1275,18 +1228,12 @@ BOOL LLTexLayer::render(S32 x, S32 y, S32 width, S32 height, LLRenderTarget* bou
 		color_specified )
 	{
 		LLGLDisable no_alpha(GL_ALPHA_TEST);
-		if (use_shaders)
-		{
-			gAlphaMaskProgram.setMinimumAlpha(0.000f);
-		}
+		gAlphaMaskProgram.setMinimumAlpha(0.000f);
 
 		gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 		gGL.color4fv( net_color.mV );
 		gl_rect_2d_simple( width, height );
-		if (use_shaders)
-		{
-			gAlphaMaskProgram.setMinimumAlpha(0.004f);
-		}
+		gAlphaMaskProgram.setMinimumAlpha(0.004f);
 	}
 
 	if( alpha_mask_specified || getInfo()->mWriteAllChannels )
@@ -1374,25 +1321,17 @@ BOOL LLTexLayer::blendAlphaTexture(S32 x, S32 y, S32 width, S32 height)
 
 	gGL.flush();
 	
-	bool use_shaders = LLGLSLShader::sNoFixedFunction;
-
 	if( !getInfo()->mStaticImageFileName.empty() )
 	{
 		LLGLTexture* tex = LLTexLayerStaticImageList::getInstance()->getTexture( getInfo()->mStaticImageFileName, getInfo()->mStaticImageIsMask );
 		if( tex )
 		{
 			LLGLSNoAlphaTest gls_no_alpha_test;
-			if (use_shaders)
-			{
-				gAlphaMaskProgram.setMinimumAlpha(0.f);
-			}
+			gAlphaMaskProgram.setMinimumAlpha(0.f);
 			gGL.getTexUnit(0)->bind(tex, TRUE);
 			gl_rect_2d_simple_tex( width, height );
 			gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
-			if (use_shaders)
-			{
-				gAlphaMaskProgram.setMinimumAlpha(0.004f);
-			}
+			gAlphaMaskProgram.setMinimumAlpha(0.004f);
 		}
 		else
 		{
@@ -1407,18 +1346,11 @@ BOOL LLTexLayer::blendAlphaTexture(S32 x, S32 y, S32 width, S32 height)
 			if (tex)
 			{
 				LLGLSNoAlphaTest gls_no_alpha_test;
-				if (use_shaders)
-				{
-					gAlphaMaskProgram.setMinimumAlpha(0.f);
-				}
+				gAlphaMaskProgram.setMinimumAlpha(0.f);
 				gGL.getTexUnit(0)->bind(tex);
 				gl_rect_2d_simple_tex( width, height );
 				gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
-				success = TRUE;
-				if (use_shaders)
-				{
-					gAlphaMaskProgram.setMinimumAlpha(0.004f);
-				}
+				gAlphaMaskProgram.setMinimumAlpha(0.004f);
 			}
 		}
 	}
@@ -1443,13 +1375,7 @@ void LLTexLayer::renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLC
 
 	llassert( !mParamAlphaList.empty() );
 
-	bool use_shaders = LLGLSLShader::sNoFixedFunction;
-
-	if (use_shaders)
-	{
-		gAlphaMaskProgram.setMinimumAlpha(0.f);
-	}
-
+	gAlphaMaskProgram.setMinimumAlpha(0.f);
 	gGL.setColorMask(false, true);
 
 	LLTexLayerParamAlpha* first_param = *mParamAlphaList.begin();
@@ -1534,10 +1460,7 @@ void LLTexLayer::renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLC
 		gl_rect_2d_simple( width, height );
 	}
 
-	if (use_shaders)
-	{
-		gAlphaMaskProgram.setMinimumAlpha(0.004f);
-	}
+	gAlphaMaskProgram.setMinimumAlpha(0.004f);
 
 	LLGLSUIDefault gls_ui;
 
diff --git a/indra/llrender/llcubemap.cpp b/indra/llrender/llcubemap.cpp
index d7f7b2f58e..d2faa5f3ae 100644
--- a/indra/llrender/llcubemap.cpp
+++ b/indra/llrender/llcubemap.cpp
@@ -195,26 +195,6 @@ void LLCubeMap::enableTexture(S32 stage)
 void LLCubeMap::enableTextureCoords(S32 stage)
 {
 	mTextureCoordStage = stage;
-	if (!LLGLSLShader::sNoFixedFunction && gGLManager.mHasCubeMap && stage >= 0 && LLCubeMap::sUseCubeMaps)
-	{
-		if (stage > 0)
-		{
-			gGL.getTexUnit(stage)->activate();
-		}
-		
-		glEnable(GL_TEXTURE_GEN_R);
-		glEnable(GL_TEXTURE_GEN_S);
-		glEnable(GL_TEXTURE_GEN_T);
-
-		glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP);
-		glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP);
-		glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP);
-		
-		if (stage > 0)
-		{
-			gGL.getTexUnit(0)->activate();
-		}
-	}
 }
 
 void LLCubeMap::disable(void)
@@ -237,20 +217,6 @@ void LLCubeMap::disableTexture(void)
 
 void LLCubeMap::disableTextureCoords(void)
 {
-	if (!LLGLSLShader::sNoFixedFunction && gGLManager.mHasCubeMap && mTextureCoordStage >= 0 && LLCubeMap::sUseCubeMaps)
-	{
-		if (mTextureCoordStage > 0)
-		{
-			gGL.getTexUnit(mTextureCoordStage)->activate();
-		}
-		glDisable(GL_TEXTURE_GEN_S);
-		glDisable(GL_TEXTURE_GEN_T);
-		glDisable(GL_TEXTURE_GEN_R);
-		if (mTextureCoordStage > 0)
-		{
-			gGL.getTexUnit(0)->activate();
-		}
-	}
 }
 
 void LLCubeMap::setMatrix(S32 stage)
diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp
index b49b14615f..58183adfce 100644
--- a/indra/llrender/llgl.cpp
+++ b/indra/llrender/llgl.cpp
@@ -1936,207 +1936,30 @@ void LLGLState::checkTextureChannels(const std::string& msg)
 #endif
 }
 
-void LLGLState::checkClientArrays(const std::string& msg, U32 data_mask)
-{
-	if (!gDebugGL || LLGLSLShader::sNoFixedFunction)
-	{
-		return;
-	}
-
-	stop_glerror();
-	BOOL error = FALSE;
-
-	GLint active_texture;
-	glGetIntegerv(GL_CLIENT_ACTIVE_TEXTURE_ARB, &active_texture);
-
-	if (active_texture != GL_TEXTURE0_ARB)
-	{
-		LL_WARNS() << "Client active texture corrupted: " << active_texture << LL_ENDL;
-		if (gDebugSession)
-		{
-			gFailLog << "Client active texture corrupted: " << active_texture << std::endl;
-		}
-		error = TRUE;
-	}
-
-	/*glGetIntegerv(GL_ACTIVE_TEXTURE_ARB, &active_texture);
-	if (active_texture != GL_TEXTURE0_ARB)
-	{
-		LL_WARNS() << "Active texture corrupted: " << active_texture << LL_ENDL;
-		if (gDebugSession)
-		{
-			gFailLog << "Active texture corrupted: " << active_texture << std::endl;
-		}
-		error = TRUE;
-	}*/
-
-	static const char* label[] =
-	{
-		"GL_VERTEX_ARRAY",
-		"GL_NORMAL_ARRAY",
-		"GL_COLOR_ARRAY",
-		"GL_TEXTURE_COORD_ARRAY"
-	};
-
-	static GLint value[] =
-	{
-		GL_VERTEX_ARRAY,
-		GL_NORMAL_ARRAY,
-		GL_COLOR_ARRAY,
-		GL_TEXTURE_COORD_ARRAY
-	};
-
-	static const U32 mask[] = 
-	{ //copied from llvertexbuffer.h
-		0x0001, //MAP_VERTEX,
-		0x0002, //MAP_NORMAL,
-		0x0010, //MAP_COLOR,
-		0x0004, //MAP_TEXCOORD
-	};
-
-
-	for (S32 j = 1; j < 4; j++)
-	{
-		if (glIsEnabled(value[j]))
-		{
-			if (!(mask[j] & data_mask))
-			{
-				error = TRUE;
-				LL_WARNS("RenderState") << "GL still has " << label[j] << " enabled." << LL_ENDL;
-				if (gDebugSession)
-				{
-					gFailLog << "GL still has " << label[j] << " enabled." << std::endl;
-				}
-			}
-		}
-		else
-		{
-			if (mask[j] & data_mask)
-			{
-				error = TRUE;
-				LL_WARNS("RenderState") << "GL does not have " << label[j] << " enabled." << LL_ENDL;
-				if (gDebugSession)
-				{
-					gFailLog << "GL does not have " << label[j] << " enabled." << std::endl;
-				}
-			}
-		}
-	}
-
-	glClientActiveTextureARB(GL_TEXTURE1_ARB);
-	gGL.getTexUnit(1)->activate();
-	if (glIsEnabled(GL_TEXTURE_COORD_ARRAY))
-	{
-		if (!(data_mask & 0x0008))
-		{
-			error = TRUE;
-			LL_WARNS("RenderState") << "GL still has GL_TEXTURE_COORD_ARRAY enabled on channel 1." << LL_ENDL;
-			if (gDebugSession)
-			{
-				gFailLog << "GL still has GL_TEXTURE_COORD_ARRAY enabled on channel 1." << std::endl;
-			}
-		}
-	}
-	else
-	{
-		if (data_mask & 0x0008)
-		{
-			error = TRUE;
-			LL_WARNS("RenderState") << "GL does not have GL_TEXTURE_COORD_ARRAY enabled on channel 1." << LL_ENDL;
-			if (gDebugSession)
-			{
-				gFailLog << "GL does not have GL_TEXTURE_COORD_ARRAY enabled on channel 1." << std::endl;
-			}
-		}
-	}
-
-	/*if (glIsEnabled(GL_TEXTURE_2D))
-	{
-		if (!(data_mask & 0x0008))
-		{
-			error = TRUE;
-			LL_WARNS("RenderState") << "GL still has GL_TEXTURE_2D enabled on channel 1." << LL_ENDL;
-			if (gDebugSession)
-			{
-				gFailLog << "GL still has GL_TEXTURE_2D enabled on channel 1." << std::endl;
-			}
-		}
-	}
-	else
-	{
-		if (data_mask & 0x0008)
-		{
-			error = TRUE;
-			LL_WARNS("RenderState") << "GL does not have GL_TEXTURE_2D enabled on channel 1." << LL_ENDL;
-			if (gDebugSession)
-			{
-				gFailLog << "GL does not have GL_TEXTURE_2D enabled on channel 1." << std::endl;
-			}
-		}
-	}*/
-
-	glClientActiveTextureARB(GL_TEXTURE0_ARB);
-	gGL.getTexUnit(0)->activate();
-
-	if (LLGLSLShader::sNoFixedFunction)
-	{	//make sure vertex attribs are all disabled
-		GLint count;
-		glGetIntegerv(GL_MAX_VERTEX_ATTRIBS_ARB, &count);
-		for (GLint i = 0; i < count; i++)
-		{
-			GLint enabled;
-			glGetVertexAttribivARB((GLuint) i, GL_VERTEX_ATTRIB_ARRAY_ENABLED_ARB, &enabled);
-			if (enabled)
-			{
-				error = TRUE;
-				LL_WARNS("RenderState") << "GL still has vertex attrib array " << i << " enabled." << LL_ENDL;
-				if (gDebugSession)
-				{
-					gFailLog <<  "GL still has vertex attrib array " << i << " enabled." << std::endl;
-				}
-			}
-		}
-	}
-
-	if (error)
-	{
-		if (gDebugSession)
-		{
-			ll_fail("LLGLState::checkClientArrays failed.");
-		}
-		else
-		{
-			LL_GL_ERRS << "GL client array corruption detected.  " << msg << LL_ENDL;
-		}
-	}
-}
-
 ///////////////////////////////////////////////////////////////////////
 
 LLGLState::LLGLState(LLGLenum state, S32 enabled) :
 	mState(state), mWasEnabled(FALSE), mIsEnabled(FALSE)
 {
     LL_PROFILE_ZONE_SCOPED;
-	if (LLGLSLShader::sNoFixedFunction)
-	{ //always ignore state that's deprecated post GL 3.0
-		switch (state)
-		{
-			case GL_ALPHA_TEST:
-			case GL_NORMALIZE:
-			case GL_TEXTURE_GEN_R:
-			case GL_TEXTURE_GEN_S:
-			case GL_TEXTURE_GEN_T:
-			case GL_TEXTURE_GEN_Q:
-			case GL_LIGHTING:
-			case GL_COLOR_MATERIAL:
-			case GL_FOG:
-			case GL_LINE_STIPPLE:
-			case GL_POLYGON_STIPPLE:
-				mState = 0;
-				break;
-		}
+	switch (state)
+	{
+		case GL_ALPHA_TEST:
+		case GL_NORMALIZE:
+		case GL_TEXTURE_GEN_R:
+		case GL_TEXTURE_GEN_S:
+		case GL_TEXTURE_GEN_T:
+		case GL_TEXTURE_GEN_Q:
+		case GL_LIGHTING:
+		case GL_COLOR_MATERIAL:
+		case GL_FOG:
+		case GL_LINE_STIPPLE:
+		case GL_POLYGON_STIPPLE:
+			mState = 0;
+			break;
 	}
 
+
 	stop_glerror();
 	if (mState)
 	{
@@ -2688,22 +2511,10 @@ LLGLSPipelineSkyBox::LLGLSPipelineSkyBox()
 , mCullFace(GL_CULL_FACE)
 , mSquashClip()
 { 
-    if (!LLGLSLShader::sNoFixedFunction)
-    {
-        glDisable(GL_LIGHTING);
-        glDisable(GL_FOG);
-        glDisable(GL_CLIP_PLANE0);
-    }
 }
 
 LLGLSPipelineSkyBox::~LLGLSPipelineSkyBox()
 {
-    if (!LLGLSLShader::sNoFixedFunction)
-    {
-        glEnable(GL_LIGHTING);
-        glEnable(GL_FOG);
-        glEnable(GL_CLIP_PLANE0);
-    }
 }
 
 LLGLSPipelineDepthTestSkyBox::LLGLSPipelineDepthTestSkyBox(bool depth_test, bool depth_write)
diff --git a/indra/llrender/llgl.h b/indra/llrender/llgl.h
index 6e1f5e6deb..386d12d70a 100644
--- a/indra/llrender/llgl.h
+++ b/indra/llrender/llgl.h
@@ -266,7 +266,6 @@ public:
 	static void dumpStates();
 	static void checkStates(const std::string& msg = "");
 	static void checkTextureChannels(const std::string& msg = "");
-	static void checkClientArrays(const std::string& msg = "", U32 data_mask = 0);
 	
 protected:
 	static boost::unordered_map<LLGLenum, LLGLboolean> sStateMap;
diff --git a/indra/llrender/llglslshader.cpp b/indra/llrender/llglslshader.cpp
index 2f1ce0eec9..220e88386a 100644
--- a/indra/llrender/llglslshader.cpp
+++ b/indra/llrender/llglslshader.cpp
@@ -50,7 +50,6 @@ using std::string;
 GLhandleARB LLGLSLShader::sCurBoundShader = 0;
 LLGLSLShader* LLGLSLShader::sCurBoundShaderPtr = NULL;
 S32 LLGLSLShader::sIndexedTextureChannels = 0;
-bool LLGLSLShader::sNoFixedFunction = false;
 bool LLGLSLShader::sProfileEnabled = false;
 std::set<LLGLSLShader*> LLGLSLShader::sInstances;
 U64 LLGLSLShader::sTotalTimeElapsed = 0;
diff --git a/indra/llrender/llglslshader.h b/indra/llrender/llglslshader.h
index 6fdb789087..85e83dbcb9 100644
--- a/indra/llrender/llglslshader.h
+++ b/indra/llrender/llglslshader.h
@@ -148,7 +148,6 @@ public:
 	static GLhandleARB sCurBoundShader;
 	static LLGLSLShader* sCurBoundShaderPtr;
 	static S32 sIndexedTextureChannels;
-	static bool sNoFixedFunction;
 
 	static void initProfile();
 	static void finishProfile(bool emit_report = true);
diff --git a/indra/llrender/llrender.cpp b/indra/llrender/llrender.cpp
index 0c180ed50d..899c61ccb7 100644
--- a/indra/llrender/llrender.cpp
+++ b/indra/llrender/llrender.cpp
@@ -128,29 +128,12 @@ void LLTexUnit::refreshState(void)
 	
 	glActiveTextureARB(GL_TEXTURE0_ARB + mIndex);
 
-	//
-	// Per apple spec, don't call glEnable/glDisable when index exceeds max texture units
-	// http://www.mailinglistarchive.com/html/mac-opengl@lists.apple.com/2008-07/msg00653.html
-	//
-	bool enableDisable = !LLGLSLShader::sNoFixedFunction && 
-		(mIndex < gGLManager.mNumTextureUnits) && mCurrTexType != LLTexUnit::TT_MULTISAMPLE_TEXTURE;
-		
 	if (mCurrTexType != TT_NONE)
 	{
-		if (enableDisable)
-		{
-			glEnable(sGLTextureType[mCurrTexType]);
-		}
-		
 		glBindTexture(sGLTextureType[mCurrTexType], mCurrTexture);
 	}
 	else
 	{
-		if (enableDisable)
-		{
-			glDisable(GL_TEXTURE_2D);
-		}
-		
 		glBindTexture(GL_TEXTURE_2D, 0);	
 	}
 
@@ -158,11 +141,6 @@ void LLTexUnit::refreshState(void)
 	{
 		setTextureBlendType(mCurrBlendType);
 	}
-	else
-	{
-		setTextureCombiner(mCurrColorOp, mCurrColorSrc1, mCurrColorSrc2, false);
-		setTextureCombiner(mCurrAlphaOp, mCurrAlphaSrc1, mCurrAlphaSrc2, true);
-	}
 
     setTextureColorSpace(mTexColorSpace);
 }
@@ -196,14 +174,6 @@ void LLTexUnit::enable(eTextureType type)
 		mCurrTexType = type;
 
 		gGL.flush();
-		if (!LLGLSLShader::sNoFixedFunction && 
-			type != LLTexUnit::TT_MULTISAMPLE_TEXTURE &&
-			mIndex < gGLManager.mNumTextureUnits)
-		{
-			stop_glerror();
-			glEnable(sGLTextureType[type]);
-			stop_glerror();
-		}
 	}
 }
 
@@ -216,13 +186,6 @@ void LLTexUnit::disable(void)
 		activate();
 		unbind(mCurrTexType);
 		gGL.flush();
-		if (!LLGLSLShader::sNoFixedFunction &&
-			mCurrTexType != LLTexUnit::TT_MULTISAMPLE_TEXTURE &&
-			mIndex < gGLManager.mNumTextureUnits)
-		{
-			glDisable(sGLTextureType[mCurrTexType]);
-		}
-
         setTextureColorSpace(TCS_LINEAR);
 		
 		mCurrTexType = TT_NONE;
@@ -465,7 +428,7 @@ void LLTexUnit::unbind(eTextureType type)
 
         // Always make sure our texture color space is reset to linear.  SRGB sampling should be opt-in in the vast majority of cases.  Also prevents color space "popping".
         mTexColorSpace = TCS_LINEAR;
-		if (LLGLSLShader::sNoFixedFunction && type == LLTexUnit::TT_TEXTURE)
+		if (type == LLTexUnit::TT_TEXTURE)
 		{
 			glBindTexture(sGLTextureType[type], sWhiteTexture);
 		}
@@ -579,51 +542,6 @@ void LLTexUnit::setTextureFilteringOption(LLTexUnit::eTextureFilterOptions optio
 
 void LLTexUnit::setTextureBlendType(eTextureBlendType type)
 {
-	if (LLGLSLShader::sNoFixedFunction)
-	{ //texture blend type means nothing when using shaders
-		return;
-	}
-
-	if (mIndex < 0) return;
-
-	// Do nothing if it's already correctly set.
-	if (mCurrBlendType == type && !gGL.mDirty)
-	{
-		return;
-	}
-
-	gGL.flush();
-
-	activate();
-	mCurrBlendType = type;
-	S32 scale_amount = 1;
-	switch (type) 
-	{
-		case TB_REPLACE:
-			glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
-			break;
-		case TB_ADD:
-			glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_ADD);
-			break;
-		case TB_MULT:
-			glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
-			break;
-		case TB_MULT_X2:
-			glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
-			scale_amount = 2;
-			break;
-		case TB_ALPHA_BLEND:
-			glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
-			break;
-		case TB_COMBINE:
-			glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);
-			break;
-		default:
-			LL_ERRS() << "Unknown Texture Blend Type: " << type << LL_ENDL;
-			break;
-	}
-	setColorScale(scale_amount);
-	setAlphaScale(1);
 }
 
 GLint LLTexUnit::getTextureSource(eTextureBlendSrc src)
@@ -702,159 +620,6 @@ GLint LLTexUnit::getTextureSourceType(eTextureBlendSrc src, bool isAlpha)
 	}
 }
 
-void LLTexUnit::setTextureCombiner(eTextureBlendOp op, eTextureBlendSrc src1, eTextureBlendSrc src2, bool isAlpha)
-{
-	if (LLGLSLShader::sNoFixedFunction)
-	{ //register combiners do nothing when not using fixed function
-		return;
-	}	
-
-	if (mIndex < 0) return;
-
-	activate();
-	if (mCurrBlendType != TB_COMBINE || gGL.mDirty)
-	{
-		mCurrBlendType = TB_COMBINE;
-		gGL.flush();
-		glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);
-	}
-	
-	// We want an early out, because this function does a LOT of stuff.
-	if ( ( (isAlpha && (mCurrAlphaOp == op) && (mCurrAlphaSrc1 == src1) && (mCurrAlphaSrc2 == src2))
-			|| (!isAlpha && (mCurrColorOp == op) && (mCurrColorSrc1 == src1) && (mCurrColorSrc2 == src2)) ) && !gGL.mDirty)
-	{
-		return;
-	}
-
-	gGL.flush();
-
-	// Get the gl source enums according to the eTextureBlendSrc sources passed in
-	GLint source1 = getTextureSource(src1);
-	GLint source2 = getTextureSource(src2);
-	// Get the gl operand enums according to the eTextureBlendSrc sources passed in
-	GLint operand1 = getTextureSourceType(src1, isAlpha);
-	GLint operand2 = getTextureSourceType(src2, isAlpha);
-	// Default the scale amount to 1
-	S32 scale_amount = 1;
-	GLenum comb_enum, src0_enum, src1_enum, src2_enum, operand0_enum, operand1_enum, operand2_enum;
-	
-	if (isAlpha)
-	{
-		// Set enums to ALPHA ones
-		comb_enum = GL_COMBINE_ALPHA_ARB;
-		src0_enum = GL_SOURCE0_ALPHA_ARB;
-		src1_enum = GL_SOURCE1_ALPHA_ARB;
-		src2_enum = GL_SOURCE2_ALPHA_ARB;
-		operand0_enum = GL_OPERAND0_ALPHA_ARB;
-		operand1_enum = GL_OPERAND1_ALPHA_ARB;
-		operand2_enum = GL_OPERAND2_ALPHA_ARB;
-
-		// cache current combiner
-		mCurrAlphaOp = op;
-		mCurrAlphaSrc1 = src1;
-		mCurrAlphaSrc2 = src2;
-	}
-	else 
-	{
-		// Set enums to RGB ones
-		comb_enum = GL_COMBINE_RGB_ARB;
-		src0_enum = GL_SOURCE0_RGB_ARB;
-		src1_enum = GL_SOURCE1_RGB_ARB;
-		src2_enum = GL_SOURCE2_RGB_ARB;
-		operand0_enum = GL_OPERAND0_RGB_ARB;
-		operand1_enum = GL_OPERAND1_RGB_ARB;
-		operand2_enum = GL_OPERAND2_RGB_ARB;
-
-		// cache current combiner
-		mCurrColorOp = op;
-		mCurrColorSrc1 = src1;
-		mCurrColorSrc2 = src2;
-	}
-
-	switch(op)
-	{
-		case TBO_REPLACE:
-			// Slightly special syntax (no second sources), just set all and return.
-			glTexEnvi(GL_TEXTURE_ENV, comb_enum, GL_REPLACE);
-			glTexEnvi(GL_TEXTURE_ENV, src0_enum, source1);
-			glTexEnvi(GL_TEXTURE_ENV, operand0_enum, operand1);
-			(isAlpha) ? setAlphaScale(1) : setColorScale(1);
-			return;
-
-		case TBO_MULT:
-			glTexEnvi(GL_TEXTURE_ENV, comb_enum, GL_MODULATE);
-			break;
-
-		case TBO_MULT_X2:
-			glTexEnvi(GL_TEXTURE_ENV, comb_enum, GL_MODULATE);
-			scale_amount = 2;
-			break;
-
-		case TBO_MULT_X4:
-			glTexEnvi(GL_TEXTURE_ENV, comb_enum, GL_MODULATE);
-			scale_amount = 4;
-			break;
-
-		case TBO_ADD:
-			glTexEnvi(GL_TEXTURE_ENV, comb_enum, GL_ADD);
-			break;
-
-		case TBO_ADD_SIGNED:
-			glTexEnvi(GL_TEXTURE_ENV, comb_enum, GL_ADD_SIGNED_ARB);
-			break;
-
-		case TBO_SUBTRACT:
-			glTexEnvi(GL_TEXTURE_ENV, comb_enum, GL_SUBTRACT_ARB);
-			break;
-
-		case TBO_LERP_VERT_ALPHA:
-			glTexEnvi(GL_TEXTURE_ENV, comb_enum, GL_INTERPOLATE);
-			glTexEnvi(GL_TEXTURE_ENV, src2_enum, GL_PRIMARY_COLOR_ARB);
-			glTexEnvi(GL_TEXTURE_ENV, operand2_enum, GL_SRC_ALPHA);
-			break;
-
-		case TBO_LERP_TEX_ALPHA:
-			glTexEnvi(GL_TEXTURE_ENV, comb_enum, GL_INTERPOLATE);
-			glTexEnvi(GL_TEXTURE_ENV, src2_enum, GL_TEXTURE);
-			glTexEnvi(GL_TEXTURE_ENV, operand2_enum, GL_SRC_ALPHA);
-			break;
-
-		case TBO_LERP_PREV_ALPHA:
-			glTexEnvi(GL_TEXTURE_ENV, comb_enum, GL_INTERPOLATE);
-			glTexEnvi(GL_TEXTURE_ENV, src2_enum, GL_PREVIOUS_ARB);
-			glTexEnvi(GL_TEXTURE_ENV, operand2_enum, GL_SRC_ALPHA);
-			break;
-
-		case TBO_LERP_CONST_ALPHA:
-			glTexEnvi(GL_TEXTURE_ENV, comb_enum, GL_INTERPOLATE);
-			glTexEnvi(GL_TEXTURE_ENV, src2_enum, GL_CONSTANT_ARB);
-			glTexEnvi(GL_TEXTURE_ENV, operand2_enum, GL_SRC_ALPHA);
-			break;
-
-		case TBO_LERP_VERT_COLOR:
-			glTexEnvi(GL_TEXTURE_ENV, comb_enum, GL_INTERPOLATE);
-			glTexEnvi(GL_TEXTURE_ENV, src2_enum, GL_PRIMARY_COLOR_ARB);
-			glTexEnvi(GL_TEXTURE_ENV, operand2_enum, (isAlpha) ? GL_SRC_ALPHA : GL_SRC_COLOR);
-			break;
-
-		default:
-			LL_WARNS() << "Unknown eTextureBlendOp: " << op << ".  Setting op to replace." << LL_ENDL;
-			// Slightly special syntax (no second sources), just set all and return.
-			glTexEnvi(GL_TEXTURE_ENV, comb_enum, GL_REPLACE);
-			glTexEnvi(GL_TEXTURE_ENV, src0_enum, source1);
-			glTexEnvi(GL_TEXTURE_ENV, operand0_enum, operand1);
-			(isAlpha) ? setAlphaScale(1) : setColorScale(1);
-			return;
-	}
-
-	// Set sources, operands, and scale accordingly
-	glTexEnvi(GL_TEXTURE_ENV, src0_enum, source1);
-	glTexEnvi(GL_TEXTURE_ENV, operand0_enum, operand1);
-	glTexEnvi(GL_TEXTURE_ENV, src1_enum, source2);
-	glTexEnvi(GL_TEXTURE_ENV, operand1_enum, operand2);
-	(isAlpha) ? setAlphaScale(scale_amount) : setColorScale(scale_amount);
-}
-
 void LLTexUnit::setColorScale(S32 scale)
 {
 	if (mCurrColorScale != scale || gGL.mDirty)
@@ -943,26 +708,12 @@ LLLightState::LLLightState(S32 index)
 
 void LLLightState::enable()
 {
-	if (!mEnabled)
-	{
-		if (!LLGLSLShader::sNoFixedFunction)
-		{
-			glEnable(GL_LIGHT0+mIndex);
-		}
-		mEnabled = true;
-	}
+	mEnabled = true;
 }
 
 void LLLightState::disable()
 {
-	if (mEnabled)
-	{
-		if (!LLGLSLShader::sNoFixedFunction)
-		{
-			glDisable(GL_LIGHT0+mIndex);
-		}
-		mEnabled = false;
-	}
+	mEnabled = false;
 }
 
 void LLLightState::setDiffuse(const LLColor4& diffuse)
@@ -971,10 +722,6 @@ void LLLightState::setDiffuse(const LLColor4& diffuse)
 	{
 		++gGL.mLightHash;
 		mDiffuse = diffuse;
-		if (!LLGLSLShader::sNoFixedFunction)
-		{
-			glLightfv(GL_LIGHT0+mIndex, GL_DIFFUSE, mDiffuse.mV);
-		}
 	}
 }
 
@@ -1002,10 +749,6 @@ void LLLightState::setAmbient(const LLColor4& ambient)
 	{
 		++gGL.mLightHash;
 		mAmbient = ambient;
-		if (!LLGLSLShader::sNoFixedFunction)
-		{
-			glLightfv(GL_LIGHT0+mIndex, GL_AMBIENT, mAmbient.mV);
-		}
 	}
 }
 
@@ -1015,10 +758,6 @@ void LLLightState::setSpecular(const LLColor4& specular)
 	{
 		++gGL.mLightHash;
 		mSpecular = specular;
-		if (!LLGLSLShader::sNoFixedFunction)
-		{
-			glLightfv(GL_LIGHT0+mIndex, GL_SPECULAR, mSpecular.mV);
-		}
 	}
 }
 
@@ -1027,20 +766,11 @@ void LLLightState::setPosition(const LLVector4& position)
 	//always set position because modelview matrix may have changed
 	++gGL.mLightHash;
 	mPosition = position;
-	if (!LLGLSLShader::sNoFixedFunction)
-	{
-		glLightfv(GL_LIGHT0+mIndex, GL_POSITION, mPosition.mV);
-	}
-	else
-	{ //transform position by current modelview matrix
-		glh::vec4f pos(position.mV);
-
-		const glh::matrix4f& mat = gGL.getModelviewMatrix();
-		mat.mult_matrix_vec(pos);
-
-		mPosition.set(pos.v);
-	}
-
+	//transform position by current modelview matrix
+	glh::vec4f pos(position.mV);
+	const glh::matrix4f& mat = gGL.getModelviewMatrix();
+	mat.mult_matrix_vec(pos);
+	mPosition.set(pos.v);
 }
 
 void LLLightState::setConstantAttenuation(const F32& atten)
@@ -1049,10 +779,6 @@ void LLLightState::setConstantAttenuation(const F32& atten)
 	{
 		mConstantAtten = atten;
 		++gGL.mLightHash;
-		if (!LLGLSLShader::sNoFixedFunction)
-		{
-			glLightf(GL_LIGHT0+mIndex, GL_CONSTANT_ATTENUATION, atten);
-		}
 	}
 }
 
@@ -1062,10 +788,6 @@ void LLLightState::setLinearAttenuation(const F32& atten)
 	{
 		++gGL.mLightHash;
 		mLinearAtten = atten;
-		if (!LLGLSLShader::sNoFixedFunction)
-		{
-			glLightf(GL_LIGHT0+mIndex, GL_LINEAR_ATTENUATION, atten);
-		}
 	}
 }
 
@@ -1075,10 +797,6 @@ void LLLightState::setQuadraticAttenuation(const F32& atten)
 	{
 		++gGL.mLightHash;
 		mQuadraticAtten = atten;
-		if (!LLGLSLShader::sNoFixedFunction)
-		{
-			glLightf(GL_LIGHT0+mIndex, GL_QUADRATIC_ATTENUATION, atten);
-		}
 	}
 }
 
@@ -1088,10 +806,6 @@ void LLLightState::setSpotExponent(const F32& exponent)
 	{
 		++gGL.mLightHash;
 		mSpotExponent = exponent;
-		if (!LLGLSLShader::sNoFixedFunction)
-		{
-			glLightf(GL_LIGHT0+mIndex, GL_SPOT_EXPONENT, exponent);
-		}
 	}
 }
 
@@ -1101,10 +815,6 @@ void LLLightState::setSpotCutoff(const F32& cutoff)
 	{
 		++gGL.mLightHash;
 		mSpotCutoff = cutoff;
-		if (!LLGLSLShader::sNoFixedFunction)
-		{
-			glLightf(GL_LIGHT0+mIndex, GL_SPOT_CUTOFF, cutoff);
-		}
 	}
 }
 
@@ -1113,19 +823,12 @@ void LLLightState::setSpotDirection(const LLVector3& direction)
 	//always set direction because modelview matrix may have changed
 	++gGL.mLightHash;
 	mSpotDirection = direction;
-	if (!LLGLSLShader::sNoFixedFunction)
-	{
-		glLightfv(GL_LIGHT0+mIndex, GL_SPOT_DIRECTION, direction.mV);
-	}
-	else
-	{ //transform direction by current modelview matrix
-		glh::vec3f dir(direction.mV);
-
-		const glh::matrix4f& mat = gGL.getModelviewMatrix();
-		mat.mult_matrix_dir(dir);
+	//transform direction by current modelview matrix
+	glh::vec3f dir(direction.mV);
+	const glh::matrix4f& mat = gGL.getModelviewMatrix();
+	mat.mult_matrix_dir(dir);
 
-		mSpotDirection.set(dir.v);
-	}
+	mSpotDirection.set(dir.v);
 }
 
 LLRender::LLRender()
@@ -1420,39 +1123,6 @@ void LLRender::syncMatrices()
 			syncLightState();
 		}
 	}
-	else if (!LLGLSLShader::sNoFixedFunction)
-	{
-		static const GLenum mode[] = 
-		{
-			GL_MODELVIEW,
-			GL_PROJECTION,
-			GL_TEXTURE,
-			GL_TEXTURE,
-			GL_TEXTURE,
-			GL_TEXTURE,
-		};
-
-		for (U32 i = 0; i < MM_TEXTURE0; ++i)
-		{
-			if (mMatHash[i] != mCurMatHash[i])
-			{
-				glMatrixMode(mode[i]);
-				glLoadMatrixf(mMatrix[i][mMatIdx[i]].m);
-				mCurMatHash[i] = mMatHash[i];
-			}
-		}
-
-		for (U32 i = MM_TEXTURE0; i < NUM_MATRIX_MODES; ++i)
-		{
-			if (mMatHash[i] != mCurMatHash[i])
-			{
-				gGL.getTexUnit(i-MM_TEXTURE0)->activate();
-				glMatrixMode(mode[i]);
-				glLoadMatrixf(mMatrix[i][mMatIdx[i]].m);
-				mCurMatHash[i] = mMatHash[i];
-			}
-		}
-	}
 }
 
 void LLRender::translatef(const GLfloat& x, const GLfloat& y, const GLfloat& z)
@@ -1771,50 +1441,6 @@ void LLRender::setSceneBlendType(eBlendType type)
 void LLRender::setAlphaRejectSettings(eCompareFunc func, F32 value)
 {
 	flush();
-
-	if (LLGLSLShader::sNoFixedFunction)
-	{ //glAlphaFunc is deprecated in OpenGL 3.3
-		return;
-	}
-
-	if (mCurrAlphaFunc != func ||
-		mCurrAlphaFuncVal != value)
-	{
-		mCurrAlphaFunc = func;
-		mCurrAlphaFuncVal = value;
-		if (func == CF_DEFAULT)
-		{
-			glAlphaFunc(GL_GREATER, 0.01f);
-		} 
-		else
-		{
-			glAlphaFunc(sGLCompareFunc[func], value);
-		}
-	}
-
-	if (gDebugGL)
-	{ //make sure cached state is correct
-		GLint cur_func = 0;
-		glGetIntegerv(GL_ALPHA_TEST_FUNC, &cur_func);
-
-		if (func == CF_DEFAULT)
-		{
-			func = CF_GREATER;
-		}
-
-		if (cur_func != sGLCompareFunc[func])
-		{
-			LL_ERRS() << "Alpha test function corrupted!" << LL_ENDL;
-		}
-
-		F32 ref = 0.f;
-		glGetFloatv(GL_ALPHA_TEST_REF, &ref);
-
-		if (ref != value)
-		{
-			LL_ERRS() << "Alpha test value corrupted!" << LL_ENDL;
-		}
-	}
 }
 
 void LLRender::blendFunc(eBlendFactor sfactor, eBlendFactor dfactor)
@@ -1889,10 +1515,6 @@ void LLRender::setAmbientLightColor(const LLColor4& color)
 	{
 		++mLightHash;
 		mAmbientLightColor = color;
-		if (!LLGLSLShader::sNoFixedFunction)
-		{
-			glLightModelfv(GL_LIGHT_MODEL_AMBIENT, color.mV);
-		}
 	}
 }
 
@@ -2345,7 +1967,7 @@ void LLRender::color3fv(const GLfloat* c)
 void LLRender::diffuseColor3f(F32 r, F32 g, F32 b)
 {
 	LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
-	llassert(!LLGLSLShader::sNoFixedFunction || shader != NULL);
+	llassert(shader != NULL);
 
 	if (shader)
 	{
@@ -2360,7 +1982,7 @@ void LLRender::diffuseColor3f(F32 r, F32 g, F32 b)
 void LLRender::diffuseColor3fv(const F32* c)
 {
 	LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
-	llassert(!LLGLSLShader::sNoFixedFunction || shader != NULL);
+	llassert(shader != NULL);
 
 	if (shader)
 	{
@@ -2375,7 +1997,7 @@ void LLRender::diffuseColor3fv(const F32* c)
 void LLRender::diffuseColor4f(F32 r, F32 g, F32 b, F32 a)
 {
 	LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
-	llassert(!LLGLSLShader::sNoFixedFunction || shader != NULL);
+	llassert(shader != NULL);
 
 	if (shader)
 	{
@@ -2390,7 +2012,7 @@ void LLRender::diffuseColor4f(F32 r, F32 g, F32 b, F32 a)
 void LLRender::diffuseColor4fv(const F32* c)
 {
 	LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
-	llassert(!LLGLSLShader::sNoFixedFunction || shader != NULL);
+	llassert(shader != NULL);
 
 	if (shader)
 	{
@@ -2405,7 +2027,7 @@ void LLRender::diffuseColor4fv(const F32* c)
 void LLRender::diffuseColor4ubv(const U8* c)
 {
 	LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
-	llassert(!LLGLSLShader::sNoFixedFunction || shader != NULL);
+	llassert(shader != NULL);
 
 	if (shader)
 	{
@@ -2420,7 +2042,7 @@ void LLRender::diffuseColor4ubv(const U8* c)
 void LLRender::diffuseColor4ub(U8 r, U8 g, U8 b, U8 a)
 {
 	LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
-	llassert(!LLGLSLShader::sNoFixedFunction || shader != NULL);
+	llassert(shader != NULL);
 
 	if (shader)
 	{
diff --git a/indra/llrender/llrender.h b/indra/llrender/llrender.h
index 7f19a45410..42aca6e665 100644
--- a/indra/llrender/llrender.h
+++ b/indra/llrender/llrender.h
@@ -204,11 +204,11 @@ public:
 	void setTextureBlendType(eTextureBlendType type);
 
 	inline void setTextureColorBlend(eTextureBlendOp op, eTextureBlendSrc src1, eTextureBlendSrc src2 = TBS_PREV_COLOR)
-	{ setTextureCombiner(op, src1, src2, false); }
+	{ /* setTextureCombiner(op, src1, src2, false); */ }
 
 	// NOTE: If *_COLOR enums are passed to src1 or src2, the corresponding *_ALPHA enum will be used instead.
 	inline void setTextureAlphaBlend(eTextureBlendOp op, eTextureBlendSrc src1, eTextureBlendSrc src2 = TBS_PREV_ALPHA)
-	{ setTextureCombiner(op, src1, src2, true); }
+	{ /* setTextureCombiner(op, src1, src2, true); */ }
 
 	static U32 getInternalType(eTextureType type);
 
@@ -243,7 +243,6 @@ protected:
 	void setAlphaScale(S32 scale);
 	GLint getTextureSource(eTextureBlendSrc src);
 	GLint getTextureSourceType(eTextureBlendSrc src, bool isAlpha = false);
-	void setTextureCombiner(eTextureBlendOp op, eTextureBlendSrc src1, eTextureBlendSrc src2, bool isAlpha = false);
 };
 
 class LLLightState
diff --git a/indra/llrender/llrender2dutils.cpp b/indra/llrender/llrender2dutils.cpp
index 5a942996be..ad21bd4f48 100644
--- a/indra/llrender/llrender2dutils.cpp
+++ b/indra/llrender/llrender2dutils.cpp
@@ -395,15 +395,7 @@ void gl_draw_scaled_image_with_border(S32 x, S32 y, S32 width, S32 height, LLTex
 
 	if (solid_color)
 	{
-		if (LLGLSLShader::sNoFixedFunction)
-		{
-			gSolidColorProgram.bind();
-		}
-		else
-		{
-			gGL.getTexUnit(0)->setTextureColorBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_PREV_COLOR);
-			gGL.getTexUnit(0)->setTextureAlphaBlend(LLTexUnit::TBO_MULT, LLTexUnit::TBS_TEX_ALPHA, LLTexUnit::TBS_VERT_ALPHA);
-		}
+		gSolidColorProgram.bind();
 	}
 
 	if (center_rect.mLeft == 0.f
@@ -650,14 +642,7 @@ void gl_draw_scaled_image_with_border(S32 x, S32 y, S32 width, S32 height, LLTex
 
 	if (solid_color)
 	{
-		if (LLGLSLShader::sNoFixedFunction)
-		{
-			gUIProgram.bind();
-		}
-		else
-		{
-			gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
-		}
+		gUIProgram.bind();
 	}
 }
 
@@ -774,10 +759,6 @@ void gl_draw_scaled_rotated_image(S32 x, S32 y, S32 width, S32 height, F32 degre
 
 void gl_stippled_line_3d( const LLVector3& start, const LLVector3& end, const LLColor4& color, F32 phase )
 {
-	phase = fmod(phase, 1.f);
-
-	S32 shift = S32(phase * 4.f) % 4;
-
 	// Stippled line
 	LLGLEnable stipple(GL_LINE_STIPPLE);
 	
@@ -786,11 +767,6 @@ void gl_stippled_line_3d( const LLVector3& start, const LLVector3& end, const LL
 	gGL.flush();
 	glLineWidth(2.5f);
 
-	if (!LLGLSLShader::sNoFixedFunction)
-	{
-		glLineStipple(2, 0x3333 << shift);
-	}
-
 	gGL.begin(LLRender::LINES);
 	{
 		gGL.vertex3fv( start.mV );
@@ -930,52 +906,16 @@ void gl_ring( F32 radius, F32 width, const LLColor4& center_color, const LLColor
 // Draw gray and white checkerboard with black border
 void gl_rect_2d_checkerboard(const LLRect& rect, GLfloat alpha)
 {
-	if (!LLGLSLShader::sNoFixedFunction)
-	{ 
-	// Initialize the first time this is called.
-	const S32 PIXELS = 32;
-	static GLubyte checkerboard[PIXELS * PIXELS];
-	static BOOL first = TRUE;
-	if( first )
-	{
-		for( S32 i = 0; i < PIXELS; i++ )
-		{
-			for( S32 j = 0; j < PIXELS; j++ )
-			{
-				checkerboard[i * PIXELS + j] = ((i & 1) ^ (j & 1)) * 0xFF;
-			}
-		}
-		first = FALSE;
-	}
-	
-	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+	//polygon stipple is deprecated, use "Checker" texture
+	LLPointer<LLUIImage> img = LLRender2D::getInstance()->getUIImage("Checker");
+	gGL.getTexUnit(0)->bind(img->getImage());
+	gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_WRAP);
+	gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
 
-	// ...white squares
-	gGL.color4f( 1.f, 1.f, 1.f, alpha );
-	gl_rect_2d(rect);
+	LLColor4 color(1.f, 1.f, 1.f, alpha);
+	LLRectf uv_rect(0, 0, rect.getWidth()/32.f, rect.getHeight()/32.f);
 
-	// ...gray squares
-	gGL.color4f( .7f, .7f, .7f, alpha );
-	gGL.flush();
-
-		glPolygonStipple( checkerboard );
-
-		LLGLEnable polygon_stipple(GL_POLYGON_STIPPLE);
-		gl_rect_2d(rect);
-	}
-	else
-	{ //polygon stipple is deprecated, use "Checker" texture
-		LLPointer<LLUIImage> img = LLRender2D::getInstance()->getUIImage("Checker");
-		gGL.getTexUnit(0)->bind(img->getImage());
-		gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_WRAP);
-		gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
-
-		LLColor4 color(1.f, 1.f, 1.f, alpha);
-		LLRectf uv_rect(0, 0, rect.getWidth()/32.f, rect.getHeight()/32.f);
-
-		gl_draw_scaled_image(rect.mLeft, rect.mBottom, rect.getWidth(), rect.getHeight(),
-			img->getImage(), color, uv_rect);
-	}
+	gl_draw_scaled_image(rect.mLeft, rect.mBottom, rect.getWidth(), rect.getHeight(), img->getImage(), color, uv_rect);
 	
 	gGL.flush();
 }
diff --git a/indra/llrender/llshadermgr.cpp b/indra/llrender/llshadermgr.cpp
index a9a4314afa..6a53662619 100644
--- a/indra/llrender/llshadermgr.cpp
+++ b/indra/llrender/llshadermgr.cpp
@@ -1054,43 +1054,6 @@ BOOL LLShaderMgr::linkProgramObject(GLhandleARB obj, BOOL suppress_errors)
 		LL_SHADER_LOADING_WARNS() << "GLSL Linker Error:" << LL_ENDL;
 	}
 
-#if LL_DARWIN
-
-	// For some reason this absolutely kills the frame rate when VBO's are enabled
-	if (0)
-	{
-		// Force an evaluation of the gl state so the driver can tell if the shader will run in hardware or software
-		// per Apple's suggestion
-		LLGLSLShader::sNoFixedFunction = false;
-		
-		glUseProgramObjectARB(obj);
-
-		gGL.begin(LLRender::TRIANGLES);
-		gGL.vertex3f(0.0f, 0.0f, 0.0f);
-		gGL.vertex3f(0.0f, 0.0f, 0.0f);
-		gGL.vertex3f(0.0f, 0.0f, 0.0f);
-		gGL.end();
-		gGL.flush();
-		
-		glUseProgramObjectARB(0);
-		
-		LLGLSLShader::sNoFixedFunction = true;
-
-		// Query whether the shader can or cannot run in hardware
-		// http://developer.apple.com/qa/qa2007/qa1502.html
-		GLint vertexGPUProcessing, fragmentGPUProcessing;
-		CGLContextObj ctx = CGLGetCurrentContext();
-		CGLGetParameter(ctx, kCGLCPGPUVertexProcessing, &vertexGPUProcessing);	
-		CGLGetParameter(ctx, kCGLCPGPUFragmentProcessing, &fragmentGPUProcessing);
-		if (!fragmentGPUProcessing || !vertexGPUProcessing)
-		{
-			LL_SHADER_LOADING_WARNS() << "GLSL Linker: Running in Software:" << LL_ENDL;
-			success = GL_FALSE;
-			suppress_errors = FALSE;		
-		}
-	}
-
-#else
 	std::string log = get_object_log(obj);
 	LLStringUtil::toLower(log);
 	if (log.find("software") != std::string::npos)
@@ -1099,7 +1062,6 @@ BOOL LLShaderMgr::linkProgramObject(GLhandleARB obj, BOOL suppress_errors)
 		success = GL_FALSE;
 		suppress_errors = FALSE;
 	}
-#endif
 	return success;
 }
 
diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp
index 46654cc5b9..dcce5a5a1d 100644
--- a/indra/llrender/llvertexbuffer.cpp
+++ b/indra/llrender/llvertexbuffer.cpp
@@ -441,135 +441,26 @@ void LLVertexBuffer::setupClientArrays(U32 data_mask)
 			data_mask = data_mask & ~MAP_TEXTURE_INDEX;
 		}
 
-		if (LLGLSLShader::sNoFixedFunction)
+		for (U32 i = 0; i < TYPE_MAX; ++i)
 		{
-			for (U32 i = 0; i < TYPE_MAX; ++i)
-			{
-				S32 loc = i;
+			S32 loc = i;
 										
-				U32 mask = 1 << i;
-
-				if (sLastMask & (1 << i))
-				{ //was enabled
-					if (!(data_mask & mask))
-					{ //needs to be disabled
-						glDisableVertexAttribArrayARB(loc);
-					}
-				}
-				else 
-				{	//was disabled
-					if (data_mask & mask)
-					{ //needs to be enabled
-						glEnableVertexAttribArrayARB(loc);
-					}
-				}
-			}
-		}
-		else
-		{
-
-			static const GLenum array[] =
-			{
-				GL_VERTEX_ARRAY,
-				GL_NORMAL_ARRAY,
-				GL_TEXTURE_COORD_ARRAY,
-				GL_COLOR_ARRAY,
-			};
-
-			static const GLenum mask[] = 
-			{
-				MAP_VERTEX,
-				MAP_NORMAL,
-				MAP_TEXCOORD0,
-				MAP_COLOR
-			};
-
-
-
-			for (U32 i = 0; i < 4; ++i)
-			{
-				if (sLastMask & mask[i])
-				{ //was enabled
-					if (!(data_mask & mask[i]))
-					{ //needs to be disabled
-						glDisableClientState(array[i]);
-					}
-					else if (gDebugGL)
-					{ //needs to be enabled, make sure it was (DEBUG)
-						if (!glIsEnabled(array[i]))
-						{
-							if (gDebugSession)
-							{
-								gFailLog << "Bad client state! " << array[i] << " disabled." << std::endl;
-							}
-							else
-							{
-								LL_ERRS() << "Bad client state! " << array[i] << " disabled." << LL_ENDL;
-							}
-						}
-					}
-				}
-				else 
-				{	//was disabled
-					if (data_mask & mask[i])
-					{ //needs to be enabled
-						glEnableClientState(array[i]);
-					}
-					else if (gDebugGL && glIsEnabled(array[i]))
-					{ //needs to be disabled, make sure it was (DEBUG TEMPORARY)
-						if (gDebugSession)
-						{
-							gFailLog << "Bad client state! " << array[i] << " enabled." << std::endl;
-						}
-						else
-						{
-							LL_ERRS() << "Bad client state! " << array[i] << " enabled." << LL_ENDL;
-						}
-					}
-				}
-			}
-		
-			static const U32 map_tc[] = 
-			{
-				MAP_TEXCOORD1,
-				MAP_TEXCOORD2,
-				MAP_TEXCOORD3
-			};
+			U32 mask = 1 << i;
 
-			for (U32 i = 0; i < 3; i++)
-			{
-				if (sLastMask & map_tc[i])
-				{
-					if (!(data_mask & map_tc[i]))
-					{ //disable
-						glClientActiveTextureARB(GL_TEXTURE1_ARB+i);
-						glDisableClientState(GL_TEXTURE_COORD_ARRAY);
-						glClientActiveTextureARB(GL_TEXTURE0_ARB);
-					}
-				}
-				else if (data_mask & map_tc[i])
-				{
-					glClientActiveTextureARB(GL_TEXTURE1_ARB+i);
-					glEnableClientState(GL_TEXTURE_COORD_ARRAY);
-					glClientActiveTextureARB(GL_TEXTURE0_ARB);
+			if (sLastMask & (1 << i))
+			{ //was enabled
+				if (!(data_mask & mask))
+				{ //needs to be disabled
+					glDisableVertexAttribArrayARB(loc);
 				}
 			}
-
-			if (sLastMask & MAP_TANGENT)
-			{
-				if (!(data_mask & MAP_TANGENT))
-				{
-					glClientActiveTextureARB(GL_TEXTURE2_ARB);
-					glDisableClientState(GL_TEXTURE_COORD_ARRAY);
-					glClientActiveTextureARB(GL_TEXTURE0_ARB);
+			else 
+			{	//was disabled
+				if (data_mask & mask)
+				{ //needs to be enabled
+					glEnableVertexAttribArrayARB(loc);
 				}
 			}
-			else if (data_mask & MAP_TANGENT)
-			{
-				glClientActiveTextureARB(GL_TEXTURE2_ARB);
-				glEnableClientState(GL_TEXTURE_COORD_ARRAY);
-				glClientActiveTextureARB(GL_TEXTURE0_ARB);
-			}
 		}
 				
 		sLastMask = data_mask;
@@ -593,7 +484,7 @@ void LLVertexBuffer::drawArrays(U32 mode, const std::vector<LLVector3>& pos)
 void LLVertexBuffer::drawElements(U32 mode, const LLVector4a* pos, const LLVector2* tc, S32 num_indices, const U16* indicesp)
 {
     LL_PROFILE_ZONE_SCOPED;
-	llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShaderPtr != NULL);
+	llassert(LLGLSLShader::sCurBoundShaderPtr != NULL);
 
 	gGL.syncMatrices();
 
@@ -690,7 +581,7 @@ void LLVertexBuffer::drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indi
 	gGL.syncMatrices();
 
 	llassert(mNumVerts >= 0);
-	llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShaderPtr != NULL);
+	llassert(LLGLSLShader::sCurBoundShaderPtr != NULL);
 
 	if (mGLArray)
 	{
@@ -758,7 +649,7 @@ void LLVertexBuffer::drawRangeFast(U32 mode, U32 start, U32 end, U32 count, U32
 
 void LLVertexBuffer::draw(U32 mode, U32 count, U32 indices_offset) const
 {
-	llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShaderPtr != NULL);
+	llassert(LLGLSLShader::sCurBoundShaderPtr != NULL);
 	mMappable = false;
 	gGL.syncMatrices();
 
@@ -809,7 +700,7 @@ void LLVertexBuffer::draw(U32 mode, U32 count, U32 indices_offset) const
 void LLVertexBuffer::drawArrays(U32 mode, U32 first, U32 count) const
 {
     LL_PROFILE_ZONE_SCOPED;
-    llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShaderPtr != NULL);
+    llassert(LLGLSLShader::sCurBoundShaderPtr != NULL);
     mMappable = false;
     gGL.syncMatrices();
 
@@ -2499,140 +2390,94 @@ void LLVertexBuffer::setupVertexBuffer(U32 data_mask)
 		LL_ERRS() << "LLVertexBuffer::setupVertexBuffer missing required components for supplied data mask." << LL_ENDL;
 	}
 
-	if (LLGLSLShader::sNoFixedFunction)
+	if (data_mask & MAP_NORMAL)
 	{
-		if (data_mask & MAP_NORMAL)
-		{
-			S32 loc = TYPE_NORMAL;
-			void* ptr = (void*)(base + mOffsets[TYPE_NORMAL]);
-			glVertexAttribPointerARB(loc, 3, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_NORMAL], ptr);
-		}
-		if (data_mask & MAP_TEXCOORD3)
-		{
-			S32 loc = TYPE_TEXCOORD3;
-			void* ptr = (void*)(base + mOffsets[TYPE_TEXCOORD3]);
-			glVertexAttribPointerARB(loc,2,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD3], ptr);
-		}
-		if (data_mask & MAP_TEXCOORD2)
-		{
-			S32 loc = TYPE_TEXCOORD2;
-			void* ptr = (void*)(base + mOffsets[TYPE_TEXCOORD2]);
-			glVertexAttribPointerARB(loc,2,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD2], ptr);
-		}
-		if (data_mask & MAP_TEXCOORD1)
-		{
-			S32 loc = TYPE_TEXCOORD1;
-			void* ptr = (void*)(base + mOffsets[TYPE_TEXCOORD1]);
-			glVertexAttribPointerARB(loc,2,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD1], ptr);
-		}
-		if (data_mask & MAP_TANGENT)
-		{
-			S32 loc = TYPE_TANGENT;
-			void* ptr = (void*)(base + mOffsets[TYPE_TANGENT]);
-			glVertexAttribPointerARB(loc, 4,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TANGENT], ptr);
-		}
-		if (data_mask & MAP_TEXCOORD0)
-		{
-			S32 loc = TYPE_TEXCOORD0;
-			void* ptr = (void*)(base + mOffsets[TYPE_TEXCOORD0]);
-			glVertexAttribPointerARB(loc,2,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD0], ptr);
-		}
-		if (data_mask & MAP_COLOR)
-		{
-			S32 loc = TYPE_COLOR;
-			//bind emissive instead of color pointer if emissive is present
-			void* ptr = (data_mask & MAP_EMISSIVE) ? (void*)(base + mOffsets[TYPE_EMISSIVE]) : (void*)(base + mOffsets[TYPE_COLOR]);
-			glVertexAttribPointerARB(loc, 4, GL_UNSIGNED_BYTE, GL_TRUE, LLVertexBuffer::sTypeSize[TYPE_COLOR], ptr);
-		}
-		if (data_mask & MAP_EMISSIVE)
-		{
-			S32 loc = TYPE_EMISSIVE;
-			void* ptr = (void*)(base + mOffsets[TYPE_EMISSIVE]);
-			glVertexAttribPointerARB(loc, 4, GL_UNSIGNED_BYTE, GL_TRUE, LLVertexBuffer::sTypeSize[TYPE_EMISSIVE], ptr);
+		S32 loc = TYPE_NORMAL;
+		void* ptr = (void*)(base + mOffsets[TYPE_NORMAL]);
+		glVertexAttribPointerARB(loc, 3, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_NORMAL], ptr);
+	}
+	if (data_mask & MAP_TEXCOORD3)
+	{
+		S32 loc = TYPE_TEXCOORD3;
+		void* ptr = (void*)(base + mOffsets[TYPE_TEXCOORD3]);
+		glVertexAttribPointerARB(loc,2,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD3], ptr);
+	}
+	if (data_mask & MAP_TEXCOORD2)
+	{
+		S32 loc = TYPE_TEXCOORD2;
+		void* ptr = (void*)(base + mOffsets[TYPE_TEXCOORD2]);
+		glVertexAttribPointerARB(loc,2,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD2], ptr);
+	}
+	if (data_mask & MAP_TEXCOORD1)
+	{
+		S32 loc = TYPE_TEXCOORD1;
+		void* ptr = (void*)(base + mOffsets[TYPE_TEXCOORD1]);
+		glVertexAttribPointerARB(loc,2,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD1], ptr);
+	}
+	if (data_mask & MAP_TANGENT)
+	{
+		S32 loc = TYPE_TANGENT;
+		void* ptr = (void*)(base + mOffsets[TYPE_TANGENT]);
+		glVertexAttribPointerARB(loc, 4,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TANGENT], ptr);
+	}
+	if (data_mask & MAP_TEXCOORD0)
+	{
+		S32 loc = TYPE_TEXCOORD0;
+		void* ptr = (void*)(base + mOffsets[TYPE_TEXCOORD0]);
+		glVertexAttribPointerARB(loc,2,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD0], ptr);
+	}
+	if (data_mask & MAP_COLOR)
+	{
+		S32 loc = TYPE_COLOR;
+		//bind emissive instead of color pointer if emissive is present
+		void* ptr = (data_mask & MAP_EMISSIVE) ? (void*)(base + mOffsets[TYPE_EMISSIVE]) : (void*)(base + mOffsets[TYPE_COLOR]);
+		glVertexAttribPointerARB(loc, 4, GL_UNSIGNED_BYTE, GL_TRUE, LLVertexBuffer::sTypeSize[TYPE_COLOR], ptr);
+	}
+	if (data_mask & MAP_EMISSIVE)
+	{
+		S32 loc = TYPE_EMISSIVE;
+		void* ptr = (void*)(base + mOffsets[TYPE_EMISSIVE]);
+		glVertexAttribPointerARB(loc, 4, GL_UNSIGNED_BYTE, GL_TRUE, LLVertexBuffer::sTypeSize[TYPE_EMISSIVE], ptr);
 
-			if (!(data_mask & MAP_COLOR))
-			{ //map emissive to color channel when color is not also being bound to avoid unnecessary shader swaps
-				loc = TYPE_COLOR;
-				glVertexAttribPointerARB(loc, 4, GL_UNSIGNED_BYTE, GL_TRUE, LLVertexBuffer::sTypeSize[TYPE_EMISSIVE], ptr);
-			}
-		}
-		if (data_mask & MAP_WEIGHT)
-		{
-			S32 loc = TYPE_WEIGHT;
-			void* ptr = (void*)(base + mOffsets[TYPE_WEIGHT]);
-			glVertexAttribPointerARB(loc, 1, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_WEIGHT], ptr);
-		}
-		if (data_mask & MAP_WEIGHT4)
-		{
-			S32 loc = TYPE_WEIGHT4;
-			void* ptr = (void*)(base+mOffsets[TYPE_WEIGHT4]);
-			glVertexAttribPointerARB(loc, 4, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_WEIGHT4], ptr);
-		}
-		if (data_mask & MAP_CLOTHWEIGHT)
-		{
-			S32 loc = TYPE_CLOTHWEIGHT;
-			void* ptr = (void*)(base + mOffsets[TYPE_CLOTHWEIGHT]);
-			glVertexAttribPointerARB(loc, 4, GL_FLOAT, GL_TRUE,  LLVertexBuffer::sTypeSize[TYPE_CLOTHWEIGHT], ptr);
+		if (!(data_mask & MAP_COLOR))
+		{ //map emissive to color channel when color is not also being bound to avoid unnecessary shader swaps
+			loc = TYPE_COLOR;
+			glVertexAttribPointerARB(loc, 4, GL_UNSIGNED_BYTE, GL_TRUE, LLVertexBuffer::sTypeSize[TYPE_EMISSIVE], ptr);
 		}
-		if (data_mask & MAP_TEXTURE_INDEX && 
-				(gGLManager.mGLSLVersionMajor >= 2 || gGLManager.mGLSLVersionMinor >= 30)) //indexed texture rendering requires GLSL 1.30 or later
-		{
+	}
+	if (data_mask & MAP_WEIGHT)
+	{
+		S32 loc = TYPE_WEIGHT;
+		void* ptr = (void*)(base + mOffsets[TYPE_WEIGHT]);
+		glVertexAttribPointerARB(loc, 1, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_WEIGHT], ptr);
+	}
+	if (data_mask & MAP_WEIGHT4)
+	{
+		S32 loc = TYPE_WEIGHT4;
+		void* ptr = (void*)(base+mOffsets[TYPE_WEIGHT4]);
+		glVertexAttribPointerARB(loc, 4, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_WEIGHT4], ptr);
+	}
+	if (data_mask & MAP_CLOTHWEIGHT)
+	{
+		S32 loc = TYPE_CLOTHWEIGHT;
+		void* ptr = (void*)(base + mOffsets[TYPE_CLOTHWEIGHT]);
+		glVertexAttribPointerARB(loc, 4, GL_FLOAT, GL_TRUE,  LLVertexBuffer::sTypeSize[TYPE_CLOTHWEIGHT], ptr);
+	}
+	if (data_mask & MAP_TEXTURE_INDEX && 
+			(gGLManager.mGLSLVersionMajor >= 2 || gGLManager.mGLSLVersionMinor >= 30)) //indexed texture rendering requires GLSL 1.30 or later
+	{
 #if !LL_DARWIN
-			S32 loc = TYPE_TEXTURE_INDEX;
-			void *ptr = (void*) (base + mOffsets[TYPE_VERTEX] + 12);
-			glVertexAttribIPointer(loc, 1, GL_UNSIGNED_INT, LLVertexBuffer::sTypeSize[TYPE_VERTEX], ptr);
+		S32 loc = TYPE_TEXTURE_INDEX;
+		void *ptr = (void*) (base + mOffsets[TYPE_VERTEX] + 12);
+		glVertexAttribIPointer(loc, 1, GL_UNSIGNED_INT, LLVertexBuffer::sTypeSize[TYPE_VERTEX], ptr);
 #endif
-		}
-		if (data_mask & MAP_VERTEX)
-		{
-			S32 loc = TYPE_VERTEX;
-			void* ptr = (void*)(base + mOffsets[TYPE_VERTEX]);
-			glVertexAttribPointerARB(loc, 3,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_VERTEX], ptr);
-		}	
-	}	
-	else
-	{
-		if (data_mask & MAP_NORMAL)
-		{
-			glNormalPointer(GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_NORMAL], (void*)(base + mOffsets[TYPE_NORMAL]));
-		}
-		if (data_mask & MAP_TEXCOORD3)
-		{
-			glClientActiveTextureARB(GL_TEXTURE3_ARB);
-			glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD3], (void*)(base + mOffsets[TYPE_TEXCOORD3]));
-			glClientActiveTextureARB(GL_TEXTURE0_ARB);
-		}
-		if (data_mask & MAP_TEXCOORD2)
-		{
-			glClientActiveTextureARB(GL_TEXTURE2_ARB);
-			glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD2], (void*)(base + mOffsets[TYPE_TEXCOORD2]));
-			glClientActiveTextureARB(GL_TEXTURE0_ARB);
-		}
-		if (data_mask & MAP_TEXCOORD1)
-		{
-			glClientActiveTextureARB(GL_TEXTURE1_ARB);
-			glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD1], (void*)(base + mOffsets[TYPE_TEXCOORD1]));
-			glClientActiveTextureARB(GL_TEXTURE0_ARB);
-		}
-		if (data_mask & MAP_TANGENT)
-		{
-			glClientActiveTextureARB(GL_TEXTURE2_ARB);
-			glTexCoordPointer(4,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TANGENT], (void*)(base + mOffsets[TYPE_TANGENT]));
-			glClientActiveTextureARB(GL_TEXTURE0_ARB);
-		}
-		if (data_mask & MAP_TEXCOORD0)
-		{
-			glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD0], (void*)(base + mOffsets[TYPE_TEXCOORD0]));
-		}
-		if (data_mask & MAP_COLOR)
-		{
-			glColorPointer(4, GL_UNSIGNED_BYTE, LLVertexBuffer::sTypeSize[TYPE_COLOR], (void*)(base + mOffsets[TYPE_COLOR]));
-		}
-		if (data_mask & MAP_VERTEX)
-		{
-			glVertexPointer(3,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_VERTEX], (void*)(base + 0));
-		}	
 	}
+	if (data_mask & MAP_VERTEX)
+	{
+		S32 loc = TYPE_VERTEX;
+		void* ptr = (void*)(base + mOffsets[TYPE_VERTEX]);
+		glVertexAttribPointerARB(loc, 3,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_VERTEX], ptr);
+	}	
 
 	llglassertok();
 }
diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp
index 062dd02903..b8bfa92279 100644
--- a/indra/llwindow/llwindowwin32.cpp
+++ b/indra/llwindow/llwindowwin32.cpp
@@ -1798,14 +1798,6 @@ void* LLWindowWin32::createSharedContext()
             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;
-            }
         }
     }
 
diff --git a/indra/newview/lldrawpoolavatar.cpp b/indra/newview/lldrawpoolavatar.cpp
index 125cd3fd5b..f9fdbac9ab 100644
--- a/indra/newview/lldrawpoolavatar.cpp
+++ b/indra/newview/lldrawpoolavatar.cpp
@@ -497,11 +497,8 @@ void LLDrawPoolAvatar::beginImpostor()
 		LLVOAvatar::sNumVisibleAvatars = 0;
 	}
 
-	if (LLGLSLShader::sNoFixedFunction)
-	{
-		gImpostorProgram.bind();
-		gImpostorProgram.setMinimumAlpha(0.01f);
-	}
+	gImpostorProgram.bind();
+	gImpostorProgram.setMinimumAlpha(0.01f);
 
 	gPipeline.enableLightsFullbright();
 	sDiffuseChannel = 0;
@@ -511,10 +508,7 @@ void LLDrawPoolAvatar::endImpostor()
 {
     LL_PROFILE_ZONE_SCOPED
 
-	if (LLGLSLShader::sNoFixedFunction)
-	{
-		gImpostorProgram.unbind();
-	}
+	gImpostorProgram.unbind();
 	gPipeline.enableLightsDynamic();
 }
 
@@ -686,10 +680,7 @@ void LLDrawPoolAvatar::beginSkinned()
 		}
 	}
 
-	if (LLGLSLShader::sNoFixedFunction)
-	{
-		sVertexProgram->setMinimumAlpha(LLDrawPoolAvatar::sMinimumAlpha);
-	}
+	sVertexProgram->setMinimumAlpha(LLDrawPoolAvatar::sMinimumAlpha);
 }
 
 void LLDrawPoolAvatar::endSkinned()
diff --git a/indra/newview/lldrawpoolbump.cpp b/indra/newview/lldrawpoolbump.cpp
index af8b194f38..2d26ee9f65 100644
--- a/indra/newview/lldrawpoolbump.cpp
+++ b/indra/newview/lldrawpoolbump.cpp
@@ -745,23 +745,9 @@ void LLDrawPoolBump::renderBump(U32 pass)
 //static
 void LLDrawPoolBump::endBump(U32 pass)
 {
-	if (LLGLSLShader::sNoFixedFunction)
-	{
-		gObjectBumpProgram.unbind();
-	}
-	else
-	{
-		// Disable texture blending on unit 1
-		gGL.getTexUnit(1)->activate();
-		gGL.getTexUnit(1)->disable();
-		gGL.getTexUnit(1)->setTextureBlendType(LLTexUnit::TB_MULT);
+    gObjectBumpProgram.unbind();
 
-		// Disable texture blending on unit 0
-		gGL.getTexUnit(0)->activate();
-		gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
-	}
-	
-	gGL.setSceneBlendType(LLRender::BT_ALPHA);
+    gGL.setSceneBlendType(LLRender::BT_ALPHA);
 }
 
 S32 LLDrawPoolBump::getNumDeferredPasses()
diff --git a/indra/newview/lldrawpoolsky.cpp b/indra/newview/lldrawpoolsky.cpp
index b1eefaab81..3a1efec91b 100644
--- a/indra/newview/lldrawpoolsky.cpp
+++ b/indra/newview/lldrawpoolsky.cpp
@@ -76,16 +76,8 @@ void LLDrawPoolSky::render(S32 pass)
 	}
 
 
-	if (LLGLSLShader::sNoFixedFunction)
-	{ //just use the UI shader (generic single texture no lighting)
-		gOneTextureNoColorProgram.bind();
-	}
-	else
-	{
-		LLGLSLShader::bindNoShader();
-		mShader = NULL;
-	}
-	
+    //just use the UI shader (generic single texture no lighting)
+	gOneTextureNoColorProgram.bind();
 
 	LLGLSPipelineDepthTestSkyBox gls_skybox(true, false);
 
diff --git a/indra/newview/lldrawpoolterrain.cpp b/indra/newview/lldrawpoolterrain.cpp
index 9cea8f5460..c71ebaffb9 100644
--- a/indra/newview/lldrawpoolterrain.cpp
+++ b/indra/newview/lldrawpoolterrain.cpp
@@ -837,20 +837,8 @@ void LLDrawPoolTerrain::renderSimple()
 	tp0.setVec(tscale, 0.f, 0.0f, -1.f*(origin_agent.mV[0]/256.f));
 	tp1.setVec(0.f, tscale, 0.0f, -1.f*(origin_agent.mV[1]/256.f));
 	
-	if (LLGLSLShader::sNoFixedFunction)
-	{
-		sShader->uniform4fv(LLShaderMgr::OBJECT_PLANE_S, 1, tp0.mV);
-		sShader->uniform4fv(LLShaderMgr::OBJECT_PLANE_T, 1, tp1.mV);
-	}
-	else
-	{
-		glEnable(GL_TEXTURE_GEN_S);
-		glEnable(GL_TEXTURE_GEN_T);
-		glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
-		glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
-		glTexGenfv(GL_S, GL_OBJECT_PLANE, tp0.mV);
-		glTexGenfv(GL_T, GL_OBJECT_PLANE, tp1.mV);
-	}
+	sShader->uniform4fv(LLShaderMgr::OBJECT_PLANE_S, 1, tp0.mV);
+	sShader->uniform4fv(LLShaderMgr::OBJECT_PLANE_T, 1, tp1.mV);
 
 	gGL.getTexUnit(0)->setTextureColorBlend(LLTexUnit::TBO_MULT, LLTexUnit::TBS_TEX_COLOR, LLTexUnit::TBS_VERT_COLOR);
 
@@ -861,11 +849,6 @@ void LLDrawPoolTerrain::renderSimple()
 	
 	gGL.getTexUnit(0)->activate();
 	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
-	if (!LLGLSLShader::sNoFixedFunction)
-	{
-		glDisable(GL_TEXTURE_GEN_S);
-		glDisable(GL_TEXTURE_GEN_T);
-	}
 	gGL.matrixMode(LLRender::MM_TEXTURE);
 	gGL.loadIdentity();
 	gGL.matrixMode(LLRender::MM_MODELVIEW);
diff --git a/indra/newview/lldrawpooltree.cpp b/indra/newview/lldrawpooltree.cpp
index 202f648e3f..e93852864e 100644
--- a/indra/newview/lldrawpooltree.cpp
+++ b/indra/newview/lldrawpooltree.cpp
@@ -90,7 +90,7 @@ void LLDrawPoolTree::render(S32 pass)
 		return;
 	}
 
-	LLGLState test(GL_ALPHA_TEST, LLGLSLShader::sNoFixedFunction ? 0 : 1);
+	LLGLState test(GL_ALPHA_TEST, 0);
 
 	gGL.getTexUnit(sDiffTex)->bind(mTexturep);
 				
diff --git a/indra/newview/lldrawpoolwater.cpp b/indra/newview/lldrawpoolwater.cpp
index e2d3f67e46..c0e82ead43 100644
--- a/indra/newview/lldrawpoolwater.cpp
+++ b/indra/newview/lldrawpoolwater.cpp
@@ -352,19 +352,16 @@ void LLDrawPoolWater::renderOpaqueLegacyWater()
     }
 
 	LLGLSLShader* shader = NULL;
-	if (LLGLSLShader::sNoFixedFunction)
+	if (LLPipeline::sUnderWaterRender)
 	{
-		if (LLPipeline::sUnderWaterRender)
-		{
-			shader = &gObjectSimpleNonIndexedTexGenWaterProgram;
-		}
-		else
-		{
-			shader = &gObjectSimpleNonIndexedTexGenProgram;
-		}
-
-		shader->bind();
+		shader = &gObjectSimpleNonIndexedTexGenWaterProgram;
 	}
+	else
+	{
+		shader = &gObjectSimpleNonIndexedTexGenProgram;
+	}
+
+	shader->bind();
 
 	stop_glerror();
 
diff --git a/indra/newview/lldrawpoolwlsky.cpp b/indra/newview/lldrawpoolwlsky.cpp
index 8c8dc3f3d2..44b12ceaca 100644
--- a/indra/newview/lldrawpoolwlsky.cpp
+++ b/indra/newview/lldrawpoolwlsky.cpp
@@ -266,33 +266,14 @@ void LLDrawPoolWLSky::renderStars(const LLVector3& camPosLocal) const
 	gGL.pushMatrix();
 	gGL.translatef(camPosLocal.mV[0], camPosLocal.mV[1], camPosLocal.mV[2]);
 	gGL.rotatef(gFrameTimeSeconds*0.01f, 0.f, 0.f, 1.f);
-	if (LLGLSLShader::sNoFixedFunction)
-	{
-		gCustomAlphaProgram.bind();
-		gCustomAlphaProgram.uniform1f(sCustomAlpha, star_alpha.mV[3]);
-	}
-	else
-	{
-		gGL.getTexUnit(0)->setTextureColorBlend(LLTexUnit::TBO_MULT, LLTexUnit::TBS_TEX_COLOR, LLTexUnit::TBS_VERT_COLOR);
-		gGL.getTexUnit(0)->setTextureAlphaBlend(LLTexUnit::TBO_MULT_X2, LLTexUnit::TBS_CONST_ALPHA, LLTexUnit::TBS_TEX_ALPHA);
-		glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, star_alpha.mV);
-	}
+	gCustomAlphaProgram.bind();
+	gCustomAlphaProgram.uniform1f(sCustomAlpha, star_alpha.mV[3]);
 
 	gSky.mVOWLSkyp->drawStars();
 
     gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
-
 	gGL.popMatrix();
-
-	if (LLGLSLShader::sNoFixedFunction)
-	{
-		gCustomAlphaProgram.unbind();
-	}
-	else
-	{
-		// and disable the combiner states
-		gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
-	}
+	gCustomAlphaProgram.unbind();
 }
 
 void LLDrawPoolWLSky::renderStarsDeferred(const LLVector3& camPosLocal) const
diff --git a/indra/newview/llfloaterbvhpreview.cpp b/indra/newview/llfloaterbvhpreview.cpp
index 131d9b077b..4f0d8b8eb0 100644
--- a/indra/newview/llfloaterbvhpreview.cpp
+++ b/indra/newview/llfloaterbvhpreview.cpp
@@ -1088,10 +1088,7 @@ BOOL	LLPreviewAnimation::render()
 	gGL.pushMatrix();
 	gGL.loadIdentity();
 
-	if (LLGLSLShader::sNoFixedFunction)
-	{
-		gUIProgram.bind();
-	}
+	gUIProgram.bind();
 
 	LLGLSUIDefault def;
 	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
diff --git a/indra/newview/llfloaterimagepreview.cpp b/indra/newview/llfloaterimagepreview.cpp
index 028c922a4d..89ba687d25 100644
--- a/indra/newview/llfloaterimagepreview.cpp
+++ b/indra/newview/llfloaterimagepreview.cpp
@@ -664,10 +664,7 @@ BOOL LLImagePreviewAvatar::render()
 	LLGLSUIDefault def;
 	gGL.color4f(0.15f, 0.2f, 0.3f, 1.f);
 
-	if (LLGLSLShader::sNoFixedFunction)
-	{
-		gUIProgram.bind();
-	}
+	gUIProgram.bind();
 
 	gl_rect_2d_simple( mFullWidth, mFullHeight );
 
@@ -866,10 +863,7 @@ BOOL LLImagePreviewSculpted::render()
 		
 	gGL.color4f(0.15f, 0.2f, 0.3f, 1.f);
 
-	if (LLGLSLShader::sNoFixedFunction)
-	{
-		gUIProgram.bind();
-	}
+	gUIProgram.bind();
 
 	gl_rect_2d_simple( mFullWidth, mFullHeight );
 	
@@ -903,10 +897,7 @@ BOOL LLImagePreviewSculpted::render()
 	
 	gPipeline.enableLightsAvatar();
 
-	if (LLGLSLShader::sNoFixedFunction)
-	{
-		gObjectPreviewProgram.bind();
-	}
+	gObjectPreviewProgram.bind();
 	gPipeline.enableLightsPreview();
 
 	gGL.pushMatrix();
@@ -920,10 +911,7 @@ BOOL LLImagePreviewSculpted::render()
 
 	gGL.popMatrix();
 
-	if (LLGLSLShader::sNoFixedFunction)
-	{
-		gObjectPreviewProgram.unbind();
-	}
+	gObjectPreviewProgram.unbind();
 
 	return TRUE;
 }
diff --git a/indra/newview/llglsandbox.cpp b/indra/newview/llglsandbox.cpp
index 91f314c115..a135ef0814 100644
--- a/indra/newview/llglsandbox.cpp
+++ b/indra/newview/llglsandbox.cpp
@@ -791,10 +791,7 @@ void LLViewerObjectList::renderObjectBeacons()
 
 	LLGLSUIDefault gls_ui;
 
-	if (LLGLSLShader::sNoFixedFunction)
-	{
-		gUIProgram.bind();
-	}
+	gUIProgram.bind();
 
 	{
 		gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
@@ -882,10 +879,7 @@ void LLViewerObjectList::renderObjectBeacons()
 void LLSky::renderSunMoonBeacons(const LLVector3& pos_agent, const LLVector3& direction, LLColor4 color)
 {
 	LLGLSUIDefault gls_ui;
-	if (LLGLSLShader::sNoFixedFunction)
-	{
-		gUIProgram.bind();
-	}
+	gUIProgram.bind();
 	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 
 	LLVector3 pos_end;
diff --git a/indra/newview/llhudtext.cpp b/indra/newview/llhudtext.cpp
index 7c957ac712..d01d25a75b 100644
--- a/indra/newview/llhudtext.cpp
+++ b/indra/newview/llhudtext.cpp
@@ -573,7 +573,6 @@ void LLHUDText::renderAllHUD()
 {
 	LLGLState::checkStates();
 	LLGLState::checkTextureChannels();
-	LLGLState::checkClientArrays();
 
 	{
 		LLGLEnable color_mat(GL_COLOR_MATERIAL);
@@ -591,7 +590,6 @@ void LLHUDText::renderAllHUD()
 
 	LLGLState::checkStates();
 	LLGLState::checkTextureChannels();
-	LLGLState::checkClientArrays();
 }
 
 void LLHUDText::shiftAll(const LLVector3& offset)
diff --git a/indra/newview/lllegacyatmospherics.cpp b/indra/newview/lllegacyatmospherics.cpp
index 238e9fe0e1..1364067949 100644
--- a/indra/newview/lllegacyatmospherics.cpp
+++ b/indra/newview/lllegacyatmospherics.cpp
@@ -383,12 +383,6 @@ void LLAtmospherics::updateFog(const F32 distance, const LLVector3& tosun_in)
 
 	if (!gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_FOG))
 	{
-		if (!LLGLSLShader::sNoFixedFunction)
-		{
-			glFogf(GL_FOG_DENSITY, 0);
-			glFogfv(GL_FOG_COLOR, (F32 *) &LLColor4::white.mV);
-			glFogf(GL_FOG_END, 1000000.f);
-		}
 		return;
 	}
 
@@ -484,10 +478,6 @@ void LLAtmospherics::updateFog(const F32 distance, const LLVector3& tosun_in)
 	if (camera_height > water_height)
 	{
 		LLColor4 fog(render_fog_color);
-		if (!LLGLSLShader::sNoFixedFunction)
-		{
-			glFogfv(GL_FOG_COLOR, fog.mV);
-		}
 		mGLFogCol = fog;
 
 		if (hide_clip_plane)
@@ -495,19 +485,11 @@ void LLAtmospherics::updateFog(const F32 distance, const LLVector3& tosun_in)
 			// For now, set the density to extend to the cull distance.
 			const F32 f_log = 2.14596602628934723963618357029f; // sqrt(fabs(log(0.01f)))
 			fog_density = f_log/fog_distance;
-			if (!LLGLSLShader::sNoFixedFunction)
-			{
-				glFogi(GL_FOG_MODE, GL_EXP2);
-			}
 		}
 		else
 		{
 			const F32 f_log = 4.6051701859880913680359829093687f; // fabs(log(0.01f))
 			fog_density = (f_log)/fog_distance;
-			if (!LLGLSLShader::sNoFixedFunction)
-			{
-				glFogi(GL_FOG_MODE, GL_EXP);
-			}
 		}
 	}
 	else
@@ -533,12 +515,6 @@ void LLAtmospherics::updateFog(const F32 distance, const LLVector3& tosun_in)
 
 		// set the density based on what the shaders use
 		fog_density = water_fog_density * gSavedSettings.getF32("WaterGLFogDensityScale");
-
-		if (!LLGLSLShader::sNoFixedFunction)
-		{
-			glFogfv(GL_FOG_COLOR, (F32 *) &fogCol.mV);
-			glFogi(GL_FOG_MODE, GL_EXP2);
-		}
 	}
 
 	mFogColor = sky_fog_color;
@@ -546,13 +522,6 @@ void LLAtmospherics::updateFog(const F32 distance, const LLVector3& tosun_in)
 
 	LLDrawPoolWater::sWaterFogEnd = fog_distance*2.2f;
 
-	if (!LLGLSLShader::sNoFixedFunction)
-	{
-		LLGLSFog gls_fog;
-		glFogf(GL_FOG_END, fog_distance*2.2f);
-		glFogf(GL_FOG_DENSITY, fog_density);
-		glHint(GL_FOG_HINT, GL_NICEST);
-	}
 	stop_glerror();
 }
 
diff --git a/indra/newview/llmaniprotate.cpp b/indra/newview/llmaniprotate.cpp
index 7c942e8b53..452762b09d 100644
--- a/indra/newview/llmaniprotate.cpp
+++ b/indra/newview/llmaniprotate.cpp
@@ -157,10 +157,7 @@ void LLManipRotate::render()
 		}
 		else
 		{
-			if (LLGLSLShader::sNoFixedFunction)
-			{
-				gDebugProgram.bind();
-			}
+			gDebugProgram.bind();
 
 			LLGLEnable cull_face(GL_CULL_FACE);
 			LLGLDepthTest gls_depth(GL_FALSE);
@@ -213,10 +210,7 @@ void LLManipRotate::render()
 			}
 			gGL.popMatrix();
 
-			if (LLGLSLShader::sNoFixedFunction)
-			{
-				gUIProgram.bind();
-			}
+			gUIProgram.bind();
 		}
 		
 		gGL.translatef( center.mV[VX], center.mV[VY], center.mV[VZ] );
@@ -234,10 +228,7 @@ void LLManipRotate::render()
 		gGL.rotatef(angle_radians * RAD_TO_DEG, x, y, z);
 
 
-		if (LLGLSLShader::sNoFixedFunction)
-		{
-			gDebugProgram.bind();
-		}
+		gDebugProgram.bind();
 
 		if (mManipPart == LL_ROT_Z)
 		{
@@ -355,11 +346,7 @@ void LLManipRotate::render()
 			
 		}
 
-		if (LLGLSLShader::sNoFixedFunction)
-		{
-			gUIProgram.bind();
-		}
-		
+		gUIProgram.bind();
 	}
 	gGL.popMatrix();
 	gGL.popMatrix();
diff --git a/indra/newview/llmaniptranslate.cpp b/indra/newview/llmaniptranslate.cpp
index 8736d3b51f..0b2a1ef389 100644
--- a/indra/newview/llmaniptranslate.cpp
+++ b/indra/newview/llmaniptranslate.cpp
@@ -1565,11 +1565,6 @@ void LLManipTranslate::renderSnapGuides()
 					LLGLEnable stipple(GL_LINE_STIPPLE);
 					gGL.flush();
 
-					if (!LLGLSLShader::sNoFixedFunction)
-					{
-						glLineStipple(1, 0x3333);
-					}
-		
 					switch (mManipPart)
 					{
 					  case LL_YZ_PLANE:
@@ -1633,7 +1628,7 @@ void LLManipTranslate::highlightIntersection(LLVector3 normal,
 											 LLQuaternion grid_rotation, 
 											 LLColor4 inner_color)
 {
-	if (!gSavedSettings.getBOOL("GridCrossSections") || !LLGLSLShader::sNoFixedFunction)
+	if (!gSavedSettings.getBOOL("GridCrossSections"))
 	{
 		return;
 	}
diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp
index d7e9e234ca..566a89e24d 100644
--- a/indra/newview/llmodelpreview.cpp
+++ b/indra/newview/llmodelpreview.cpp
@@ -2886,8 +2886,6 @@ BOOL LLModelPreview::render()
     LLMutexLock lock(this);
     mNeedsUpdate = FALSE;
 
-    bool use_shaders = LLGLSLShader::sNoFixedFunction;
-
     bool edges = mViewOption["show_edges"];
     bool joint_overrides = mViewOption["show_joint_overrides"];
     bool joint_positions = mViewOption["show_joint_positions"];
@@ -2905,10 +2903,8 @@ BOOL LLModelPreview::render()
     LLGLDisable fog(GL_FOG);
 
     {
-        if (use_shaders)
-        {
-            gUIProgram.bind();
-        }
+        gUIProgram.bind();
+
         //clear background to grey
         gGL.matrixMode(LLRender::MM_PROJECTION);
         gGL.pushMatrix();
@@ -2927,10 +2923,7 @@ BOOL LLModelPreview::render()
 
         gGL.matrixMode(LLRender::MM_MODELVIEW);
         gGL.popMatrix();
-        if (use_shaders)
-        {
-            gUIProgram.unbind();
-        }
+        gUIProgram.unbind();
     }
 
     LLFloaterModelPreview* fmp = LLFloaterModelPreview::sInstance;
@@ -3083,10 +3076,7 @@ BOOL LLModelPreview::render()
         refresh();
     }
 
-    if (use_shaders)
-    {
-        gObjectPreviewProgram.bind();
-    }
+    gObjectPreviewProgram.bind();
 
     gGL.loadIdentity();
     gPipeline.enableLightsPreview();
@@ -3587,10 +3577,7 @@ BOOL LLModelPreview::render()
         }
     }
 
-    if (use_shaders)
-    {
-        gObjectPreviewProgram.unbind();
-    }
+    gObjectPreviewProgram.unbind();
 
     gGL.popMatrix();
 
diff --git a/indra/newview/llscenemonitor.cpp b/indra/newview/llscenemonitor.cpp
index 177bc84cee..2e44dc1459 100644
--- a/indra/newview/llscenemonitor.cpp
+++ b/indra/newview/llscenemonitor.cpp
@@ -271,7 +271,7 @@ void LLSceneMonitor::capture()
 	static LLCachedControl<F32>  scene_load_sample_time(gSavedSettings, "SceneLoadingMonitorSampleTime");
 	static bool force_capture = true;
 
-	bool enabled = LLGLSLShader::sNoFixedFunction && (monitor_enabled || mDebugViewerVisible);
+	bool enabled = monitor_enabled || mDebugViewerVisible;
 	if(mEnabled != enabled)
 	{
 		if(mEnabled)
@@ -719,13 +719,6 @@ void LLSceneMonitorView::onTeleportFinished()
 
 void LLSceneMonitorView::onVisibilityChange(BOOL visible)
 {
-	if (!LLGLSLShader::sNoFixedFunction && visible)
-	{
-		visible = false;
-		// keep Scene monitor and its view in sycn
-		setVisible(false);
-		LL_WARNS("SceneMonitor") << "Incompatible graphical settings, Scene Monitor can't be turned on" << LL_ENDL; 
-	}
 	LLSceneMonitor::getInstance()->setDebugViewerVisible(visible);
 }
 
diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp
index 332fa73944..25d6106361 100644
--- a/indra/newview/llspatialpartition.cpp
+++ b/indra/newview/llspatialpartition.cpp
@@ -2612,7 +2612,7 @@ void renderPhysicsShape(LLDrawable* drawable, LLVOVolume* volume)
 				gGL.diffuseColor4fv(line_color.mV);
 				LLVertexBuffer::unbind();
 
-				llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShader != 0);
+				llassert(LLGLSLShader::sCurBoundShader != 0);
 				
                 LLVertexBuffer::drawElements(LLRender::TRIANGLES, phys_volume->mHullPoints, NULL, phys_volume->mNumHullIndices, phys_volume->mHullIndices);
 				
@@ -2694,7 +2694,7 @@ void renderPhysicsShape(LLDrawable* drawable, LLVOVolume* volume)
 		if (phys_volume->mHullPoints && phys_volume->mHullIndices)
 		{
 			glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
-			llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShader != 0);
+			llassert(LLGLSLShader::sCurBoundShader != 0);
 			LLVertexBuffer::unbind();
 			glVertexPointer(3, GL_FLOAT, 16, phys_volume->mHullPoints);
 			gGL.diffuseColor4fv(line_color.mV);
@@ -3796,10 +3796,7 @@ void LLSpatialPartition::renderDebug()
 		return;
 	}
 	
-	if (LLGLSLShader::sNoFixedFunction)
-	{
-		gDebugProgram.bind();
-	}
+	gDebugProgram.bind();
 
 	if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_PRIORITY))
 	{
@@ -3848,10 +3845,7 @@ void LLSpatialPartition::renderDebug()
 			glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
 		}
 	}
-	if (LLGLSLShader::sNoFixedFunction)
-	{
-		gDebugProgram.unbind();
-	}
+	gDebugProgram.unbind();
 }
 
 void LLSpatialGroup::drawObjectBox(LLColor4 col)
diff --git a/indra/newview/lltoolmorph.cpp b/indra/newview/lltoolmorph.cpp
index 06a2caf75b..9f0198029a 100644
--- a/indra/newview/lltoolmorph.cpp
+++ b/indra/newview/lltoolmorph.cpp
@@ -195,10 +195,7 @@ BOOL LLVisualParamHint::render()
 	gGL.pushMatrix();
 	gGL.loadIdentity();
 
-	if (LLGLSLShader::sNoFixedFunction)
-	{
-		gUIProgram.bind();
-	}
+	gUIProgram.bind();
 
 	LLGLSUIDefault gls_ui;
 	//LLGLState::verify(TRUE);
diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp
index 3c6c9c905a..19b25a01fe 100644
--- a/indra/newview/llviewercontrol.cpp
+++ b/indra/newview/llviewercontrol.cpp
@@ -388,7 +388,7 @@ static bool handleJoystickChanged(const LLSD& newvalue)
 
 static bool handleUseOcclusionChanged(const LLSD& newvalue)
 {
-	LLPipeline::sUseOcclusion = (newvalue.asBoolean() && gGLManager.mHasOcclusionQuery && LLGLSLShader::sNoFixedFunction
+	LLPipeline::sUseOcclusion = (newvalue.asBoolean() && gGLManager.mHasOcclusionQuery
 		&& LLFeatureManager::getInstance()->isFeatureAvailable("UseOcclusion") && !gUseWireframe) ? 2 : 0;
 	return true;
 }
diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp
index 38ac4275cf..60ba07d3af 100644
--- a/indra/newview/llviewerdisplay.cpp
+++ b/indra/newview/llviewerdisplay.cpp
@@ -717,7 +717,6 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 
 		LLGLState::checkStates();
 		LLGLState::checkTextureChannels();
-		LLGLState::checkClientArrays();
 
 		static LLCullResult result;
 		LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD;
@@ -727,8 +726,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 
 		LLGLState::checkStates();
 		LLGLState::checkTextureChannels();
-		LLGLState::checkClientArrays();
-
+		
 		LLAppViewer::instance()->pingMainloopTimeout("Display:Swap");
 		
 		{ 
@@ -744,7 +742,6 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 
 			LLGLState::checkStates();
 			LLGLState::checkTextureChannels();
-			LLGLState::checkClientArrays();
 
 			if (!for_snapshot)
 			{
@@ -758,7 +755,6 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 
 				LLGLState::checkStates();
 				LLGLState::checkTextureChannels();
-				LLGLState::checkClientArrays();
 
 				glh::matrix4f proj = get_current_projection();
 				glh::matrix4f mod = get_current_modelview();
@@ -777,14 +773,12 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 
 				LLGLState::checkStates();
 				LLGLState::checkTextureChannels();
-				LLGLState::checkClientArrays();
 
 			}
 			glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
 		}
 
 		LLGLState::checkStates();
-		LLGLState::checkClientArrays();
 
 		//if (!for_snapshot)
 		{
@@ -796,7 +790,6 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 		}
 
 		LLGLState::checkStates();
-		LLGLState::checkClientArrays();
 
 		//////////////////////////////////////
 		//
@@ -836,7 +829,6 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 		}
 
 		LLGLState::checkStates();
-		LLGLState::checkClientArrays();
 
 		///////////////////////////////////
 		//
@@ -868,7 +860,6 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 		LLSceneMonitor::getInstance()->fetchQueryResult();
 		
 		LLGLState::checkStates();
-		LLGLState::checkClientArrays();
 
 		LLPipeline::sUseOcclusion = occlusion;
 
@@ -927,7 +918,6 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 		LLPipeline::sUnderWaterRender = LLViewerCamera::getInstance()->cameraUnderWater() ? TRUE : FALSE;
 
 		LLGLState::checkStates();
-		LLGLState::checkClientArrays();
 
 		stop_glerror();
 
@@ -960,7 +950,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 			LL_PROFILE_ZONE_NAMED("display - 4")
 			LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD;
 
-			if (gSavedSettings.getBOOL("RenderDepthPrePass") && LLGLSLShader::sNoFixedFunction)
+			if (gSavedSettings.getBOOL("RenderDepthPrePass"))
 			{
 				gGL.setColorMask(false, false);
 
@@ -1450,10 +1440,7 @@ void render_ui_3d()
 
 	stop_glerror();
 	
-	if (LLGLSLShader::sNoFixedFunction)
-	{
-		gUIProgram.bind();
-	}
+	gUIProgram.bind();
 
 	// Coordinate axes
 	if (gSavedSettings.getBOOL("ShowAxes"))
@@ -1583,10 +1570,7 @@ void render_ui_2d()
 
 void render_disconnected_background()
 {
-	if (LLGLSLShader::sNoFixedFunction)
-	{
-		gUIProgram.bind();
-	}
+	gUIProgram.bind();
 
 	gGL.color4f(1,1,1,1);
 	if (!gDisconnectedImagep && gDisconnected)
@@ -1658,11 +1642,7 @@ void render_disconnected_background()
 	}
 	gGL.flush();
 
-	if (LLGLSLShader::sNoFixedFunction)
-	{
-		gUIProgram.unbind();
-	}
-
+	gUIProgram.unbind();
 }
 
 void display_cleanup()
diff --git a/indra/newview/llviewerjointmesh.cpp b/indra/newview/llviewerjointmesh.cpp
index 3e385a46e4..98d8f91116 100644
--- a/indra/newview/llviewerjointmesh.cpp
+++ b/indra/newview/llviewerjointmesh.cpp
@@ -225,7 +225,7 @@ U32 LLViewerJointMesh::drawShape( F32 pixelArea, BOOL first_pass, BOOL is_dummy)
 	if (!mValid || !mMesh || !mFace || !mVisible || 
 		!mFace->getVertexBuffer() ||
 		mMesh->getNumFaces() == 0 ||
-		(LLGLSLShader::sNoFixedFunction && LLGLSLShader::sCurBoundShaderPtr == NULL))
+		LLGLSLShader::sCurBoundShaderPtr == NULL)
 	{
 		return 0;
 	}
@@ -246,7 +246,7 @@ U32 LLViewerJointMesh::drawShape( F32 pixelArea, BOOL first_pass, BOOL is_dummy)
 
 	stop_glerror();
 	
-	LLGLSSpecular specular(LLColor4(1.f,1.f,1.f,1.f), (mFace->getPool()->getShaderLevel() > 0 || LLGLSLShader::sNoFixedFunction) ? 0.f : mShiny);
+	LLGLSSpecular specular(LLColor4(1.f,1.f,1.f,1.f), 0.f);
 
 	//----------------------------------------------------------------
 	// setup current texture
diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp
index b626a8ebea..d37678e24f 100644
--- a/indra/newview/llviewershadermgr.cpp
+++ b/indra/newview/llviewershadermgr.cpp
@@ -471,7 +471,6 @@ void LLViewerShaderMgr::setShaders()
     }
     mMaxAvatarShaderLevel = 0;
 
-    LLGLSLShader::sNoFixedFunction = false;
     LLVertexBuffer::unbind();
 
     llassert((gGLManager.mGLSLVersionMajor > 1 || gGLManager.mGLSLVersionMinor >= 10));
@@ -482,9 +481,6 @@ void LLViewerShaderMgr::setShaders()
     bool doingWindLight          = hasWindLightShaders && gSavedSettings.getBOOL("WindLightUseAtmosShaders");
     bool useRenderDeferred       = doingWindLight && canRenderDeferred && gSavedSettings.getBOOL("RenderDeferred");
 
-    //using shaders, disable fixed function
-    LLGLSLShader::sNoFixedFunction = true;
-
     S32 light_class = 3;
     S32 interface_class = 2;
     S32 env_class = 2;
@@ -556,12 +552,12 @@ void LLViewerShaderMgr::setShaders()
     }
     else
     {
-        LL_WARNS() << "Failed to load basic shaders." << LL_ENDL;
+        LL_ERRS() << "Unable to load basic shaders, verify graphics driver installed and current." << LL_ENDL;
         llassert(loaded);
+        reentrance = false; // For hygiene only, re-try probably helps nothing 
+        return;
     }
 
-    if (loaded)
-    {
         gPipeline.mVertexShadersEnabled = TRUE;
         gPipeline.mVertexShadersLoaded = 1;
 
@@ -686,8 +682,8 @@ void LLViewerShaderMgr::setShaders()
                 mShaderLevel[SHADER_AVATAR] = 0;
                 mShaderLevel[SHADER_DEFERRED] = 0;
 
-                gSavedSettings.setBOOL("RenderDeferred", FALSE);
-                gSavedSettings.setBOOL("RenderAvatarCloth", FALSE);
+                    gSavedSettings.setBOOL("RenderDeferred", FALSE);
+                    gSavedSettings.setBOOL("RenderAvatarCloth", FALSE);
 
                 loadShadersAvatar(); // unloads
 
@@ -718,21 +714,9 @@ void LLViewerShaderMgr::setShaders()
             setShaders();
             return;
         }
-    }
-    else
-    {
-        LLGLSLShader::sNoFixedFunction = false;
-        gPipeline.mVertexShadersEnabled = FALSE;
-        gPipeline.mVertexShadersLoaded = 0;
-        mShaderLevel[SHADER_LIGHTING] = 0;
-        mShaderLevel[SHADER_INTERFACE] = 0;
-        mShaderLevel[SHADER_ENVIRONMENT] = 0;
-        mShaderLevel[SHADER_WATER] = 0;
-        mShaderLevel[SHADER_OBJECT] = 0;
-        mShaderLevel[SHADER_EFFECT] = 0;
-        mShaderLevel[SHADER_WINDLIGHT] = 0;
-        mShaderLevel[SHADER_AVATAR] = 0;
-    }
+
+    // gPipeline.mVertexShadersEnabled = FALSE;
+    // gPipeline.mVertexShadersLoaded = 0;
     
     if (gViewerWindow)
     {
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index 198007aaa1..10631afd13 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -2065,20 +2065,6 @@ void LLViewerWindow::initGLDefaults()
 {
 	gGL.setSceneBlendType(LLRender::BT_ALPHA);
 
-	if (!LLGLSLShader::sNoFixedFunction)
-	{ //initialize fixed function state
-		glColorMaterial( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE );
-
-		glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT,LLColor4::black.mV);
-		glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE,LLColor4::white.mV);
-
-		// lights for objects
-		glShadeModel( GL_SMOOTH );
-
-		gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE);
-		gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
-	}
-
 	glPixelStorei(GL_PACK_ALIGNMENT,1);
 	glPixelStorei(GL_UNPACK_ALIGNMENT,1);
 
@@ -2694,10 +2680,7 @@ void LLViewerWindow::drawDebugText()
 	gGL.color4f(1,1,1,1);
 	gGL.pushMatrix();
 	gGL.pushUIMatrix();
-	if (LLGLSLShader::sNoFixedFunction)
-	{
-		gUIProgram.bind();
-	}
+	gUIProgram.bind();
 	{
 		// scale view by UI global scale factor and aspect ratio correction factor
 		gGL.scaleUI(mDisplayScale.mV[VX], mDisplayScale.mV[VY], 1.f);
@@ -2707,10 +2690,7 @@ void LLViewerWindow::drawDebugText()
 	gGL.popMatrix();
 
 	gGL.flush();
-	if (LLGLSLShader::sNoFixedFunction)
-	{
-		gUIProgram.unbind();
-	}
+	gUIProgram.unbind();
 }
 
 void LLViewerWindow::draw()
@@ -2756,10 +2736,7 @@ void LLViewerWindow::draw()
 	// Draw all nested UI views.
 	// No translation needed, this view is glued to 0,0
 
-	if (LLGLSLShader::sNoFixedFunction)
-	{
-		gUIProgram.bind();
-	}
+	gUIProgram.bind();
 
 	gGL.pushMatrix();
 	LLUI::pushMatrix();
@@ -2835,14 +2812,9 @@ void LLViewerWindow::draw()
 	LLUI::popMatrix();
 	gGL.popMatrix();
 
-	if (LLGLSLShader::sNoFixedFunction)
-	{
-		gUIProgram.unbind();
-	}
+	gUIProgram.unbind();
 
-//#if LL_DEBUG
 	LLView::sIsDrawing = FALSE;
-//#endif
 }
 
 // Takes a single keyup event, usually when UI is visible
diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp
index 84bb67a03d..da856beb6e 100644
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -5053,11 +5053,6 @@ U32 LLVOAvatar::renderSkinned()
 		bool should_alpha_mask = shouldAlphaMask();
 		LLGLState test(GL_ALPHA_TEST, should_alpha_mask);
 		
-		if (should_alpha_mask && !LLGLSLShader::sNoFixedFunction)
-		{
-			gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.5f);
-		}
-		
 		BOOL first_pass = TRUE;
 		if (!LLDrawPoolAvatar::sSkipOpaque)
 		{
@@ -5104,11 +5099,6 @@ U32 LLVOAvatar::renderSkinned()
 			}
 		}
 
-		if (should_alpha_mask && !LLGLSLShader::sNoFixedFunction)
-		{
-			gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
-		}
-
 		if (!LLDrawPoolAvatar::sSkipTransparent || LLPipeline::sImpostorRender)
 		{
 			LLGLState blend(GL_BLEND, !mIsDummy);
@@ -5193,11 +5183,6 @@ U32 LLVOAvatar::renderRigid()
 	bool should_alpha_mask = shouldAlphaMask();
 	LLGLState test(GL_ALPHA_TEST, should_alpha_mask);
 
-	if (should_alpha_mask && !LLGLSLShader::sNoFixedFunction)
-	{
-		gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.5f);
-	}
-
 	if (isTextureVisible(TEX_EYES_BAKED) || (getOverallAppearance() == AOA_JELLYDOLL && !isControlAvatar()) || isUIAvatar())
 	{
 		LLViewerJoint* eyeball_left = getViewerJoint(MESH_ID_EYEBALL_LEFT);
@@ -5212,11 +5197,6 @@ U32 LLVOAvatar::renderRigid()
 		}
 	}
 
-	if (should_alpha_mask && !LLGLSLShader::sNoFixedFunction)
-	{
-		gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
-	}
-	
 	return num_indices;
 }
 
diff --git a/indra/newview/llvosurfacepatch.cpp b/indra/newview/llvosurfacepatch.cpp
index 4d25e8c7bd..8fbecbc7d7 100644
--- a/indra/newview/llvosurfacepatch.cpp
+++ b/indra/newview/llvosurfacepatch.cpp
@@ -59,63 +59,8 @@ public:
 	// virtual
 	void setupVertexBuffer(U32 data_mask)
 	{	
-		if (LLGLSLShader::sNoFixedFunction)
-		{ //just use default if shaders are in play
-			LLVertexBuffer::setupVertexBuffer(data_mask & ~(MAP_TEXCOORD2 | MAP_TEXCOORD3));
-			return;
-		}
-
-		volatile U8* base = useVBOs() ? (U8*) mAlignedOffset : mMappedData;
-
-		//assume tex coords 2 and 3 are present
-		U32 type_mask = mTypeMask | MAP_TEXCOORD2 | MAP_TEXCOORD3;
-
-		if ((data_mask & type_mask) != data_mask)
-		{
-			LL_ERRS() << "LLVertexBuffer::setupVertexBuffer missing required components for supplied data mask." << LL_ENDL;
-		}
-
-		if (data_mask & MAP_NORMAL)
-		{
-			glNormalPointer(GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_NORMAL], (void*)(base + mOffsets[TYPE_NORMAL]));
-		}
-		if (data_mask & MAP_TEXCOORD3)
-		{ //substitute tex coord 1 for tex coord 3
-			glClientActiveTextureARB(GL_TEXTURE3_ARB);
-			glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD1], (void*)(base + mOffsets[TYPE_TEXCOORD1]));
-			glClientActiveTextureARB(GL_TEXTURE0_ARB);
-		}
-		if (data_mask & MAP_TEXCOORD2)
-		{ //substitute tex coord 0 for tex coord 2
-			glClientActiveTextureARB(GL_TEXTURE2_ARB);
-			glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD0], (void*)(base + mOffsets[TYPE_TEXCOORD0]));
-			glClientActiveTextureARB(GL_TEXTURE0_ARB);
-		}
-		if (data_mask & MAP_TEXCOORD1)
-		{
-			glClientActiveTextureARB(GL_TEXTURE1_ARB);
-			glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD1], (void*)(base + mOffsets[TYPE_TEXCOORD1]));
-			glClientActiveTextureARB(GL_TEXTURE0_ARB);
-		}
-		if (data_mask & MAP_TANGENT)
-		{
-			glClientActiveTextureARB(GL_TEXTURE2_ARB);
-			glTexCoordPointer(3,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TANGENT], (void*)(base + mOffsets[TYPE_TANGENT]));
-			glClientActiveTextureARB(GL_TEXTURE0_ARB);
-		}
-		if (data_mask & MAP_TEXCOORD0)
-		{
-			glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD0], (void*)(base + mOffsets[TYPE_TEXCOORD0]));
-		}
-		if (data_mask & MAP_COLOR)
-		{
-			glColorPointer(4, GL_UNSIGNED_BYTE, LLVertexBuffer::sTypeSize[TYPE_COLOR], (void*)(base + mOffsets[TYPE_COLOR]));
-		}
-		
-		if (data_mask & MAP_VERTEX)
-		{
-			glVertexPointer(3,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_VERTEX], (void*)(base + 0));
-		}
+		LLVertexBuffer::setupVertexBuffer(data_mask & ~(MAP_TEXCOORD2 | MAP_TEXCOORD3));
+		return;
 	}
 };
 
diff --git a/indra/newview/llvowater.cpp b/indra/newview/llvowater.cpp
index efe6aa158e..089a7712c0 100644
--- a/indra/newview/llvowater.cpp
+++ b/indra/newview/llvowater.cpp
@@ -143,7 +143,7 @@ BOOL LLVOWater::updateGeometry(LLDrawable *drawable)
 	static const unsigned int vertices_per_quad = 4;
 	static const unsigned int indices_per_quad = 6;
 
-	const S32 size = LLPipeline::sRenderTransparentWater && LLGLSLShader::sNoFixedFunction ? 16 : 1;
+	const S32 size = LLPipeline::sRenderTransparentWater ? 16 : 1;
 
 	const S32 num_quads = size * size;
 	face->setSize(vertices_per_quad * num_quads,
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index 1f4fdca2e7..8881b78593 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -1061,7 +1061,6 @@ void LLPipeline::refreshCachedSettings()
 
 	LLPipeline::sUseOcclusion = 
 			(!gUseWireframe
-			&& LLGLSLShader::sNoFixedFunction
 			&& LLFeatureManager::getInstance()->isFeatureAvailable("UseOcclusion") 
 			&& gSavedSettings.getBOOL("UseOcclusion") 
 			&& gGLManager.mHasOcclusionQuery) ? 2 : 0;
@@ -2338,8 +2337,7 @@ static LLTrace::BlockTimerStatHandle FTM_CULL("Object Culling");
 void LLPipeline::updateCull(LLCamera& camera, LLCullResult& result, S32 water_clip, LLPlane* planep)
 {
 	static LLCachedControl<bool> use_occlusion(gSavedSettings,"UseOcclusion");
-	static bool can_use_occlusion = LLGLSLShader::sNoFixedFunction
-									&& LLFeatureManager::getInstance()->isFeatureAvailable("UseOcclusion") 
+	static bool can_use_occlusion = LLFeatureManager::getInstance()->isFeatureAvailable("UseOcclusion") 
 									&& gGLManager.mHasOcclusionQuery;
 
 	LL_RECORD_BLOCK_TIME(FTM_CULL);
@@ -2650,7 +2648,7 @@ void LLPipeline::doOcclusion(LLCamera& camera)
 		LLGLDisable cull(GL_CULL_FACE);
 
 		
-		bool bind_shader = LLGLSLShader::sNoFixedFunction && LLGLSLShader::sCurBoundShader == 0;
+		bool bind_shader = (LLGLSLShader::sCurBoundShader == 0);
 		if (bind_shader)
 		{
 			if (LLPipeline::sShadowRender)
@@ -3992,10 +3990,7 @@ void render_hud_elements()
 	
 	gGL.color4f(1,1,1,1);
 	
-	if (LLGLSLShader::sNoFixedFunction)
-	{
-		gUIProgram.bind();
-	}
+	gUIProgram.bind();
 	LLGLDepthTest depth(GL_TRUE, GL_FALSE);
 
 	if (!LLPipeline::sReflectionRender && gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
@@ -4027,10 +4022,7 @@ void render_hud_elements()
 		LLHUDText::renderAllHUD();
 	}
 
-	if (LLGLSLShader::sNoFixedFunction)
-	{
-		gUIProgram.unbind();
-	}
+	gUIProgram.unbind();
 	gGL.flush();
 }
 
@@ -4062,10 +4054,7 @@ void LLPipeline::renderHighlights()
 
 		gGL.setColorMask(false, false);
 
-        if (LLGLSLShader::sNoFixedFunction)
-        {
-            gHighlightProgram.bind();
-        }
+        gHighlightProgram.bind();
 
 		for (std::set<HighlightItem>::iterator iter = mHighlightSet.begin(); iter != mHighlightSet.end(); ++iter)
 		{
@@ -4297,7 +4286,6 @@ void LLPipeline::renderGeom(LLCamera& camera, bool forceVBOUpdate)
 	// Do verification of GL state
 	LLGLState::checkStates();
 	LLGLState::checkTextureChannels();
-	LLGLState::checkClientArrays();
 	if (mRenderDebugMask & RENDER_DEBUG_VERIFY)
 	{
 		if (!verify())
@@ -4546,7 +4534,6 @@ void LLPipeline::renderGeomDeferred(LLCamera& camera)
 
 		LLGLState::checkStates();
 		LLGLState::checkTextureChannels();
-		LLGLState::checkClientArrays();
 
 		U32 cur_type = 0;
 
@@ -4819,10 +4806,7 @@ void LLPipeline::renderPhysicsDisplay()
 
 	gGL.setColorMask(true, false);
 
-	if (LLGLSLShader::sNoFixedFunction)
-	{
-		gDebugProgram.bind();
-	}
+	gDebugProgram.bind();
 
 	for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); 
 			iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
@@ -4843,11 +4827,7 @@ void LLPipeline::renderPhysicsDisplay()
 
 	gGL.flush();
 
-	if (LLGLSLShader::sNoFixedFunction)
-	{
-		gDebugProgram.unbind();
-	}
-
+	gDebugProgram.unbind();
 	mPhysicsDisplay.flush();
 }
 
@@ -4874,13 +4854,10 @@ void LLPipeline::renderDebug()
 
 				if ( pathfindingCharacter->getVisible() || gAgentCamera.cameraMouselook() )			
 				{	
-					if (LLGLSLShader::sNoFixedFunction)
-					{					
-						gPathfindingProgram.bind();			
-						gPathfindingProgram.uniform1f(sTint, 1.f);
-						gPathfindingProgram.uniform1f(sAmbiance, 1.f);
-						gPathfindingProgram.uniform1f(sAlphaScale, 1.f);
-					}
+					gPathfindingProgram.bind();			
+					gPathfindingProgram.uniform1f(sTint, 1.f);
+					gPathfindingProgram.uniform1f(sAmbiance, 1.f);
+					gPathfindingProgram.uniform1f(sAlphaScale, 1.f);
 
 					//Requried character physics capsule render parameters
 					LLUUID id;					
@@ -4889,21 +4866,14 @@ void LLPipeline::renderDebug()
 				
 					if ( pathfindingCharacter->isPhysicsCapsuleEnabled( id, pos, rot ) )
 					{
-						if (LLGLSLShader::sNoFixedFunction)
-						{					
-							//remove blending artifacts
-							gGL.setColorMask(false, false);
-							llPathingLibInstance->renderSimpleShapeCapsuleID( gGL, id, pos, rot );				
-							gGL.setColorMask(true, false);
-							LLGLEnable blend(GL_BLEND);
-							gPathfindingProgram.uniform1f(sAlphaScale, 0.90f);
-							llPathingLibInstance->renderSimpleShapeCapsuleID( gGL, id, pos, rot );
-							gPathfindingProgram.bind();
-						}
-						else
-						{
-							llPathingLibInstance->renderSimpleShapeCapsuleID( gGL, id, pos, rot );
-						}
+						//remove blending artifacts
+						gGL.setColorMask(false, false);
+						llPathingLibInstance->renderSimpleShapeCapsuleID( gGL, id, pos, rot );				
+						gGL.setColorMask(true, false);
+						LLGLEnable blend(GL_BLEND);
+						gPathfindingProgram.uniform1f(sAlphaScale, 0.90f);
+						llPathingLibInstance->renderSimpleShapeCapsuleID( gGL, id, pos, rot );
+						gPathfindingProgram.bind();
 					}
 				}
 			}
@@ -4919,14 +4889,11 @@ void LLPipeline::renderDebug()
 				{				
 					F32 ambiance = gSavedSettings.getF32("PathfindingAmbiance");
 
-					if (LLGLSLShader::sNoFixedFunction)
-					{					
-						gPathfindingProgram.bind();
+					gPathfindingProgram.bind();
 			
-						gPathfindingProgram.uniform1f(sTint, 1.f);
-						gPathfindingProgram.uniform1f(sAmbiance, ambiance);
-						gPathfindingProgram.uniform1f(sAlphaScale, 1.f);
-					}
+					gPathfindingProgram.uniform1f(sTint, 1.f);
+					gPathfindingProgram.uniform1f(sAmbiance, ambiance);
+					gPathfindingProgram.uniform1f(sAlphaScale, 1.f);
 
 					if ( !pathfindingConsole->isRenderWorld() )
 					{
@@ -4958,18 +4925,11 @@ void LLPipeline::renderDebug()
 						}
 						
 						//render edges
-						if (LLGLSLShader::sNoFixedFunction)
-						{
-							gPathfindingNoNormalsProgram.bind();
-							gPathfindingNoNormalsProgram.uniform1f(sTint, 1.f);
-							gPathfindingNoNormalsProgram.uniform1f(sAlphaScale, 1.f);
-							llPathingLibInstance->renderNavMeshEdges();
-							gPathfindingProgram.bind();
-						}
-						else
-						{
-							llPathingLibInstance->renderNavMeshEdges();
-						}
+						gPathfindingNoNormalsProgram.bind();
+						gPathfindingNoNormalsProgram.uniform1f(sTint, 1.f);
+						gPathfindingNoNormalsProgram.uniform1f(sAlphaScale, 1.f);
+						llPathingLibInstance->renderNavMeshEdges();
+						gPathfindingProgram.bind();
 
 						gGL.flush();
 						glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );	
@@ -4980,53 +4940,31 @@ void LLPipeline::renderDebug()
 					if ( LLPathfindingPathTool::getInstance()->isRenderPath() )
 					{
 						//The path
-						if (LLGLSLShader::sNoFixedFunction)
-						{
-							gUIProgram.bind();
-							gGL.getTexUnit(0)->bind(LLViewerFetchedTexture::sWhiteImagep);
-							llPathingLibInstance->renderPath();
-							gPathfindingProgram.bind();
-						}
-						else
-						{
-							llPathingLibInstance->renderPath();
-						}
-						//The bookends
-						if (LLGLSLShader::sNoFixedFunction)
-						{
-							//remove blending artifacts
-							gGL.setColorMask(false, false);
-							llPathingLibInstance->renderPathBookend( gGL, LLPathingLib::LLPL_START );
-							llPathingLibInstance->renderPathBookend( gGL, LLPathingLib::LLPL_END );
+						gUIProgram.bind();
+						gGL.getTexUnit(0)->bind(LLViewerFetchedTexture::sWhiteImagep);
+						llPathingLibInstance->renderPath();
+						gPathfindingProgram.bind();
+
+                        //The bookends
+						//remove blending artifacts
+						gGL.setColorMask(false, false);
+						llPathingLibInstance->renderPathBookend( gGL, LLPathingLib::LLPL_START );
+						llPathingLibInstance->renderPathBookend( gGL, LLPathingLib::LLPL_END );
 						
-							gGL.setColorMask(true, false);
-							//render the bookends
-							LLGLEnable blend(GL_BLEND);
-							gPathfindingProgram.uniform1f(sAlphaScale, 0.90f);
-							llPathingLibInstance->renderPathBookend( gGL, LLPathingLib::LLPL_START );
-							llPathingLibInstance->renderPathBookend( gGL, LLPathingLib::LLPL_END );
-							gPathfindingProgram.bind();
-						}
-						else
-						{
-							llPathingLibInstance->renderPathBookend( gGL, LLPathingLib::LLPL_START );
-							llPathingLibInstance->renderPathBookend( gGL, LLPathingLib::LLPL_END );
-						}
-					
+						gGL.setColorMask(true, false);
+						//render the bookends
+						LLGLEnable blend(GL_BLEND);
+						gPathfindingProgram.uniform1f(sAlphaScale, 0.90f);
+						llPathingLibInstance->renderPathBookend( gGL, LLPathingLib::LLPL_START );
+						llPathingLibInstance->renderPathBookend( gGL, LLPathingLib::LLPL_END );
+						gPathfindingProgram.bind();
 					}
 				
 					if ( pathfindingConsole->isRenderWaterPlane() )
 					{	
-						if (LLGLSLShader::sNoFixedFunction)
-						{
-							LLGLEnable blend(GL_BLEND);
-							gPathfindingProgram.uniform1f(sAlphaScale, 0.90f);
-							llPathingLibInstance->renderSimpleShapes( gGL, gAgent.getRegion()->getWaterHeight() );
-						}
-						else
-						{
-							llPathingLibInstance->renderSimpleShapes( gGL, gAgent.getRegion()->getWaterHeight() );					
-						}
+						LLGLEnable blend(GL_BLEND);
+						gPathfindingProgram.uniform1f(sAlphaScale, 0.90f);
+						llPathingLibInstance->renderSimpleShapes( gGL, gAgent.getRegion()->getWaterHeight() );
 					}
 				//physics/exclusion shapes
 				if ( pathfindingConsole->isRenderAnyShapes() )
@@ -5157,18 +5095,11 @@ void LLPipeline::renderDebug()
 						}
 
 						//render edges
-						if (LLGLSLShader::sNoFixedFunction)
-						{
-							gPathfindingNoNormalsProgram.bind();
-							gPathfindingNoNormalsProgram.uniform1f(sTint, gSavedSettings.getF32("PathfindingXRayTint"));
-							gPathfindingNoNormalsProgram.uniform1f(sAlphaScale, gSavedSettings.getF32("PathfindingXRayOpacity"));
-							llPathingLibInstance->renderNavMeshEdges();
-							gPathfindingProgram.bind();
-						}
-						else
-						{
-							llPathingLibInstance->renderNavMeshEdges();
-						}
+						gPathfindingNoNormalsProgram.bind();
+						gPathfindingNoNormalsProgram.uniform1f(sTint, gSavedSettings.getF32("PathfindingXRayTint"));
+						gPathfindingNoNormalsProgram.uniform1f(sAlphaScale, gSavedSettings.getF32("PathfindingXRayOpacity"));
+						llPathingLibInstance->renderNavMeshEdges();
+						gPathfindingProgram.bind();
 					
 						gGL.flush();
 						glLineWidth(1.0f);	
@@ -5177,10 +5108,7 @@ void LLPipeline::renderDebug()
 					glPolygonOffset(0.f, 0.f);
 
 					gGL.flush();
-					if (LLGLSLShader::sNoFixedFunction)
-					{
-						gPathfindingProgram.unbind();
-					}
+					gPathfindingProgram.unbind();
 				}
 			}
 		}
@@ -5195,10 +5123,7 @@ void LLPipeline::renderDebug()
 	
 	if (!hud_only && !mDebugBlips.empty())
 	{ //render debug blips
-		if (LLGLSLShader::sNoFixedFunction)
-		{
-			gUIProgram.bind();
-		}
+		gUIProgram.bind();
 
 		gGL.getTexUnit(0)->bind(LLViewerFetchedTexture::sWhiteImagep, true);
 
@@ -5262,7 +5187,7 @@ void LLPipeline::renderDebug()
 		}
 	}
 
-	if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_OCCLUSION) && LLGLSLShader::sNoFixedFunction)
+	if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_OCCLUSION))
 	{ //render visible selected group occlusion geometry
 		gDebugProgram.bind();
 		LLGLDepthTest depth(GL_TRUE, GL_FALSE);
@@ -5284,44 +5209,38 @@ void LLPipeline::renderDebug()
 
 	visible_selected_groups.clear();
 
-	if (LLGLSLShader::sNoFixedFunction)
-	{
-		gUIProgram.bind();
-	}
+	gUIProgram.bind();
 
 	if (hasRenderDebugMask(LLPipeline::RENDER_DEBUG_RAYCAST) && !hud_only)
 	{ //draw crosshairs on particle intersection
 		if (gDebugRaycastParticle)
 		{
-			if (LLGLSLShader::sNoFixedFunction)
-			{ //this debug display requires shaders
-				gDebugProgram.bind();
+			gDebugProgram.bind();
 
-				gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+			gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 
-				LLVector3 center(gDebugRaycastParticleIntersection.getF32ptr());
-				LLVector3 size(0.1f, 0.1f, 0.1f);
+			LLVector3 center(gDebugRaycastParticleIntersection.getF32ptr());
+			LLVector3 size(0.1f, 0.1f, 0.1f);
 
-				LLVector3 p[6];
+			LLVector3 p[6];
 
-				p[0] = center + size.scaledVec(LLVector3(1,0,0));
-				p[1] = center + size.scaledVec(LLVector3(-1,0,0));
-				p[2] = center + size.scaledVec(LLVector3(0,1,0));
-				p[3] = center + size.scaledVec(LLVector3(0,-1,0));
-				p[4] = center + size.scaledVec(LLVector3(0,0,1));
-				p[5] = center + size.scaledVec(LLVector3(0,0,-1));
+			p[0] = center + size.scaledVec(LLVector3(1,0,0));
+			p[1] = center + size.scaledVec(LLVector3(-1,0,0));
+			p[2] = center + size.scaledVec(LLVector3(0,1,0));
+			p[3] = center + size.scaledVec(LLVector3(0,-1,0));
+			p[4] = center + size.scaledVec(LLVector3(0,0,1));
+			p[5] = center + size.scaledVec(LLVector3(0,0,-1));
 				
-				gGL.begin(LLRender::LINES);
-				gGL.diffuseColor3f(1.f, 1.f, 0.f);
-				for (U32 i = 0; i < 6; i++)
-				{
-					gGL.vertex3fv(p[i].mV);
-				}
-				gGL.end();
-				gGL.flush();
-
-				gDebugProgram.unbind();
+			gGL.begin(LLRender::LINES);
+			gGL.diffuseColor3f(1.f, 1.f, 0.f);
+			for (U32 i = 0; i < 6; i++)
+			{
+				gGL.vertex3fv(p[i].mV);
 			}
+			gGL.end();
+			gGL.flush();
+
+			gDebugProgram.unbind();
 		}
 	}
 
@@ -5554,10 +5473,7 @@ void LLPipeline::renderDebug()
 	}
 
 	gGL.flush();
-	if (LLGLSLShader::sNoFixedFunction)
-	{
-		gUIProgram.unbind();
-	}
+	gUIProgram.unbind();
 }
 
 void LLPipeline::rebuildPools()
@@ -6226,11 +6142,6 @@ void LLPipeline::setupHWLights(LLDrawPool* pool)
     LLEnvironment& environment = LLEnvironment::instance();
     LLSettingsSky::ptr_t psky = environment.getCurrentSky();
 
-	if (!LLGLSLShader::sNoFixedFunction)
-	{
-		gGL.syncMatrices();
-	}
-
     // Ambient
     LLColor4 ambient = psky->getTotalAmbient();
 		gGL.setAmbientLightColor(ambient);
@@ -6429,11 +6340,6 @@ void LLPipeline::setupHWLights(LLDrawPool* pool)
     // prev site of forward (non-deferred) character light injection, removed by SL-13522 09/20
 
 	// Init GL state
-	if (!LLGLSLShader::sNoFixedFunction)
-	{
-		glDisable(GL_LIGHTING);
-	}
-
 	for (S32 i = 0; i < 8; ++i)
 	{
 		gGL.getLight(i)->disable();
@@ -6452,13 +6358,6 @@ void LLPipeline::enableLights(U32 mask)
 	if (mLightMask != mask)
 	{
 		stop_glerror();
-		if (!mLightMask)
-		{
-			if (!LLGLSLShader::sNoFixedFunction)
-			{
-				glEnable(GL_LIGHTING);
-			}
-		}
 		if (mask)
 		{
 			stop_glerror();
@@ -6478,13 +6377,6 @@ void LLPipeline::enableLights(U32 mask)
 			}
 			stop_glerror();
 		}
-		else
-		{
-			if (!LLGLSLShader::sNoFixedFunction)
-			{
-				glDisable(GL_LIGHTING);
-			}
-		}
 		mLightMask = mask;
 		stop_glerror();
 	}
@@ -6535,11 +6427,6 @@ void LLPipeline::enableLightsPreview()
 {
 	disableLights();
 
-	if (!LLGLSLShader::sNoFixedFunction)
-	{
-		glEnable(GL_LIGHTING);
-	}
-
 	LLColor4 ambient = PreviewAmbientColor;
 	gGL.setAmbientLightColor(ambient);
 
@@ -8093,18 +7980,7 @@ void LLPipeline::renderFinalize()
 
         LLGLDisable blend(GL_BLEND);
 
-        if (LLGLSLShader::sNoFixedFunction)
-        {
-            gGlowCombineProgram.bind();
-        }
-        else
-        {
-            // tex unit 0
-            gGL.getTexUnit(0)->setTextureColorBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_TEX_COLOR);
-            // tex unit 1
-            gGL.getTexUnit(1)->setTextureColorBlend(LLTexUnit::TBO_ADD, LLTexUnit::TBS_TEX_COLOR,
-                                                    LLTexUnit::TBS_PREV_COLOR);
-        }
+        gGlowCombineProgram.bind();
 
         gGL.getTexUnit(0)->bind(&mGlow[1]);
         gGL.getTexUnit(1)->bind(&mScreen);
@@ -8114,28 +7990,14 @@ void LLPipeline::renderFinalize()
         buff->setBuffer(mask);
         buff->drawArrays(LLRender::TRIANGLE_STRIP, 0, 3);
 
-        if (LLGLSLShader::sNoFixedFunction)
-        {
-            gGlowCombineProgram.unbind();
-        }
-        else
-        {
-            gGL.getTexUnit(1)->disable();
-            gGL.getTexUnit(1)->setTextureBlendType(LLTexUnit::TB_MULT);
-
-            gGL.getTexUnit(0)->activate();
-            gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
-        }
+        gGlowCombineProgram.unbind();
     }
 
     gGL.setSceneBlendType(LLRender::BT_ALPHA);
 
     if (hasRenderDebugMask(LLPipeline::RENDER_DEBUG_PHYSICS_SHAPES))
     {
-        if (LLGLSLShader::sNoFixedFunction)
-        {
-            gSplatTextureRectProgram.bind();
-        }
+        gSplatTextureRectProgram.bind();
 
         gGL.setColorMask(true, false);
 
@@ -8161,10 +8023,7 @@ void LLPipeline::renderFinalize()
         gGL.end();
         gGL.flush();
 
-        if (LLGLSLShader::sNoFixedFunction)
-        {
-            gSplatTextureRectProgram.unbind();
-        }
+        gSplatTextureRectProgram.unbind();
     }
 
     if (LLRenderTarget::sUseFBO)
@@ -9502,17 +9361,11 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in)
                     renderGeom(camera);
                 }
 
-                if (LLGLSLShader::sNoFixedFunction)
-                {
-                    gUIProgram.bind();
-                }
+                gUIProgram.bind();
 
                 LLWorld::getInstance()->renderPropertyLines();
 
-                if (LLGLSLShader::sNoFixedFunction)
-                {
-                    gUIProgram.unbind();
-                }
+                gUIProgram.unbind();
 
                 mWaterDis.flush();
             }
@@ -10066,10 +9919,7 @@ void LLPipeline::generateHighlight(LLCamera& camera)
 		gGL.setColorMask(true, true);
 		mHighlight.clear();
 
-        if (LLGLSLShader::sNoFixedFunction)
-        {
-            gHighlightProgram.bind();
-        }
+        gHighlightProgram.bind();
 
 		gGL.getTexUnit(0)->bind(LLViewerFetchedTexture::sWhiteImagep);
 		for (std::set<HighlightItem>::iterator iter = mHighlightSet.begin(); iter != mHighlightSet.end(); )
@@ -10951,7 +10801,6 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar)
     LL_RECORD_BLOCK_TIME(FTM_GENERATE_IMPOSTOR);
 	LLGLState::checkStates();
 	LLGLState::checkTextureChannels();
-	LLGLState::checkClientArrays();
 
 	static LLCullResult result;
 	result.clear();
@@ -11210,11 +11059,7 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar)
 
 		static const F32 clip_plane = 0.99999f;
 
-		if (LLGLSLShader::sNoFixedFunction)
-		{
-			gDebugProgram.bind();
-		}
-
+		gDebugProgram.bind();
 
 		if (visually_muted)
 		{	// Visually muted avatar
@@ -11228,7 +11073,6 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar)
 			gGL.diffuseColor4fv(LLColor4::pink.mV );
 		}
 
-		{
 		gGL.begin(LLRender::QUADS);
 		gGL.vertex3f(-1, -1, clip_plane);
 		gGL.vertex3f(1, -1, clip_plane);
@@ -11236,12 +11080,8 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar)
 		gGL.vertex3f(-1, 1, clip_plane);
 		gGL.end();
 		gGL.flush();
-		}
 
-		if (LLGLSLShader::sNoFixedFunction)
-		{
-			gDebugProgram.unbind();
-		}
+		gDebugProgram.unbind();
 
 		gGL.popMatrix();
 		gGL.matrixMode(LLRender::MM_MODELVIEW);
@@ -11270,7 +11110,6 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar)
 	LLVertexBuffer::unbind();
 	LLGLState::checkStates();
 	LLGLState::checkTextureChannels();
-	LLGLState::checkClientArrays();
 }
 
 bool LLPipeline::hasRenderBatches(const U32 type) const
-- 
cgit v1.2.3


From 5fcea00c4f88561021fa2ab4ee8d72fff2b5ff83 Mon Sep 17 00:00:00 2001
From: Dave Houlton <euclid@lindenlab.com>
Date: Tue, 30 Nov 2021 11:19:41 -0700
Subject: SL-16386 purge no-op fxn LLTexUnit::setTextureBlendType()

---
 indra/llappearance/lltexlayer.cpp   |  3 ---
 indra/llrender/llrender.cpp         |  9 ---------
 indra/llrender/llrender.h           |  2 --
 indra/newview/lldrawpoolbump.cpp    | 12 ------------
 indra/newview/lldrawpoolterrain.cpp |  4 ----
 indra/newview/lldrawpoolwater.cpp   |  7 -------
 indra/newview/llhudnametag.cpp      |  2 --
 indra/newview/llhudtext.cpp         |  3 ---
 indra/newview/llviewerdisplay.cpp   |  3 ---
 indra/newview/llviewerjointmesh.cpp |  5 -----
 10 files changed, 50 deletions(-)

(limited to 'indra')

diff --git a/indra/llappearance/lltexlayer.cpp b/indra/llappearance/lltexlayer.cpp
index 9af59c7da4..de10560b22 100644
--- a/indra/llappearance/lltexlayer.cpp
+++ b/indra/llappearance/lltexlayer.cpp
@@ -529,7 +529,6 @@ void LLTexLayerSet::renderAlphaMaskTextures(S32 x, S32 y, S32 width, S32 height,
 			{
 				LLGLSUIDefault gls_ui;
 				gGL.getTexUnit(0)->bind(tex);
-				gGL.getTexUnit(0)->setTextureBlendType( LLTexUnit::TB_REPLACE );
 				gl_rect_2d_simple_tex( width, height );
 			}
 		}
@@ -555,7 +554,6 @@ void LLTexLayerSet::renderAlphaMaskTextures(S32 x, S32 y, S32 width, S32 height,
 	if (mMaskLayerList.size() > 0)
 	{
 		gGL.setSceneBlendType(LLRender::BT_MULT_ALPHA);
-		gGL.getTexUnit(0)->setTextureBlendType( LLTexUnit::TB_REPLACE );
 		for (layer_list_t::iterator iter = mMaskLayerList.begin(); iter != mMaskLayerList.end(); iter++)
 		{
 			LLTexLayerInterface* layer = *iter;
@@ -568,7 +566,6 @@ void LLTexLayerSet::renderAlphaMaskTextures(S32 x, S32 y, S32 width, S32 height,
 	
 	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 	
-	gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
 	gGL.setColorMask(true, true);
 	gGL.setSceneBlendType(LLRender::BT_ALPHA);
 }
diff --git a/indra/llrender/llrender.cpp b/indra/llrender/llrender.cpp
index 899c61ccb7..14abd9b83e 100644
--- a/indra/llrender/llrender.cpp
+++ b/indra/llrender/llrender.cpp
@@ -137,11 +137,6 @@ void LLTexUnit::refreshState(void)
 		glBindTexture(GL_TEXTURE_2D, 0);	
 	}
 
-	if (mCurrBlendType != TB_COMBINE)
-	{
-		setTextureBlendType(mCurrBlendType);
-	}
-
     setTextureColorSpace(mTexColorSpace);
 }
 
@@ -540,10 +535,6 @@ void LLTexUnit::setTextureFilteringOption(LLTexUnit::eTextureFilterOptions optio
 	}
 }
 
-void LLTexUnit::setTextureBlendType(eTextureBlendType type)
-{
-}
-
 GLint LLTexUnit::getTextureSource(eTextureBlendSrc src)
 {
 	switch(src)
diff --git a/indra/llrender/llrender.h b/indra/llrender/llrender.h
index 42aca6e665..2feb8f955b 100644
--- a/indra/llrender/llrender.h
+++ b/indra/llrender/llrender.h
@@ -201,8 +201,6 @@ public:
 	// make sure you want to permanently change the filtering for the bound texture.
 	void setTextureFilteringOption(LLTexUnit::eTextureFilterOptions option);
 
-	void setTextureBlendType(eTextureBlendType type);
-
 	inline void setTextureColorBlend(eTextureBlendOp op, eTextureBlendSrc src1, eTextureBlendSrc src2 = TBS_PREV_COLOR)
 	{ /* setTextureCombiner(op, src1, src2, false); */ }
 
diff --git a/indra/newview/lldrawpoolbump.cpp b/indra/newview/lldrawpoolbump.cpp
index 2d26ee9f65..3b039cd505 100644
--- a/indra/newview/lldrawpoolbump.cpp
+++ b/indra/newview/lldrawpoolbump.cpp
@@ -593,21 +593,9 @@ void LLDrawPoolBump::endFullbrightShiny()
 	if( cube_map )
 	{
 		cube_map->disable();
-
-        /*if (diffuse_channel != 0)
-		{
-			shader->disableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
-		}
-		gGL.getTexUnit(0)->activate();
-		gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE);*/
-
 		shader->unbind();
-		//gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
 	}
 	
-	//gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
-	//gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
-
 	diffuse_channel = -1;
 	cube_channel = 0;
 	mShiny = FALSE;
diff --git a/indra/newview/lldrawpoolterrain.cpp b/indra/newview/lldrawpoolterrain.cpp
index c71ebaffb9..cc21f13678 100644
--- a/indra/newview/lldrawpoolterrain.cpp
+++ b/indra/newview/lldrawpoolterrain.cpp
@@ -627,8 +627,6 @@ void LLDrawPoolTerrain::renderFull4TU()
 	gGL.matrixMode(LLRender::MM_TEXTURE);
 	gGL.loadIdentity();
 	gGL.matrixMode(LLRender::MM_MODELVIEW);
-
-	gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
 }
 
 void LLDrawPoolTerrain::renderFull2TU()
@@ -814,7 +812,6 @@ void LLDrawPoolTerrain::renderFull2TU()
 	gGL.matrixMode(LLRender::MM_TEXTURE);
 	gGL.loadIdentity();
 	gGL.matrixMode(LLRender::MM_MODELVIEW);
-	gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
 }
 
 
@@ -852,7 +849,6 @@ void LLDrawPoolTerrain::renderSimple()
 	gGL.matrixMode(LLRender::MM_TEXTURE);
 	gGL.loadIdentity();
 	gGL.matrixMode(LLRender::MM_MODELVIEW);
-	gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
 }
 
 //============================================================================
diff --git a/indra/newview/lldrawpoolwater.cpp b/indra/newview/lldrawpoolwater.cpp
index c0e82ead43..4023d59776 100644
--- a/indra/newview/lldrawpoolwater.cpp
+++ b/indra/newview/lldrawpoolwater.cpp
@@ -299,8 +299,6 @@ void LLDrawPoolWater::render(S32 pass)
 		gGL.matrixMode(LLRender::MM_MODELVIEW);
 		LLOverrideFaceColor overrid(this, 1.f, 1.f, 1.f,  0.5f*up_dot);
 
-		gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
-
 		for (std::vector<LLFace*>::iterator iter = mDrawFace.begin();
 			 iter != mDrawFace.end(); iter++)
 		{
@@ -317,8 +315,6 @@ void LLDrawPoolWater::render(S32 pass)
 			}
 		}
 
-		gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
-
 		gSky.mVOSkyp->getCubeMap()->disable();
 		
 		gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
@@ -336,8 +332,6 @@ void LLDrawPoolWater::render(S32 pass)
 		glStencilFunc(GL_NOTEQUAL, 0, 0xFFFFFFFF);
 		renderReflection(refl_face);
 	}
-
-	gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
 }
 
 // for low end hardware
@@ -447,7 +441,6 @@ void LLDrawPoolWater::renderOpaqueLegacyWater()
 	}
 
 	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
-	gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
 }
 
 
diff --git a/indra/newview/llhudnametag.cpp b/indra/newview/llhudnametag.cpp
index 55a4b5a457..8e296321d2 100644
--- a/indra/newview/llhudnametag.cpp
+++ b/indra/newview/llhudnametag.cpp
@@ -323,8 +323,6 @@ void LLHUDNameTag::renderText(BOOL for_select)
 		
 	// Render label
 	{
-		//gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
-
 		for(std::vector<LLHUDTextSegment>::iterator segment_iter = mLabelSegments.begin();
 			segment_iter != mLabelSegments.end(); ++segment_iter )
 		{
diff --git a/indra/newview/llhudtext.cpp b/indra/newview/llhudtext.cpp
index d01d25a75b..9d8bf7f51c 100644
--- a/indra/newview/llhudtext.cpp
+++ b/indra/newview/llhudtext.cpp
@@ -188,9 +188,6 @@ void LLHUDText::renderText()
 	F32 y_offset = (F32)mOffsetY;
 		
 	// Render label
-	{
-		gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
-	}
 
 	// Render text
 	{
diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp
index 60ba07d3af..046187cf4f 100644
--- a/indra/newview/llviewerdisplay.cpp
+++ b/indra/newview/llviewerdisplay.cpp
@@ -166,8 +166,6 @@ void display_startup()
 
 	if (gViewerWindow)
 	gViewerWindow->setup2DRender();
-	gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
-
 	gGL.color4f(1,1,1,1);
 	if (gViewerWindow)
 	gViewerWindow->draw();
@@ -1480,7 +1478,6 @@ void render_ui_2d()
 	}
 
 	stop_glerror();
-	//gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
 
 	// render outline for HUD
 	if (isAgentAvatarValid() && gAgentCamera.mHUDCurZoom < 0.98f)
diff --git a/indra/newview/llviewerjointmesh.cpp b/indra/newview/llviewerjointmesh.cpp
index 98d8f91116..640e54c2e1 100644
--- a/indra/newview/llviewerjointmesh.cpp
+++ b/indra/newview/llviewerjointmesh.cpp
@@ -328,11 +328,6 @@ U32 LLViewerJointMesh::drawShape( F32 pixelArea, BOOL first_pass, BOOL is_dummy)
 
 	triangle_count += count;
 	
-	if (mTestImageName)
-	{
-		gGL.getTexUnit(diffuse_channel)->setTextureBlendType(LLTexUnit::TB_MULT);
-	}
-
 	return triangle_count;
 }
 
-- 
cgit v1.2.3


From 3d1901dd4c6e549ec78bef6cea8682d12946c063 Mon Sep 17 00:00:00 2001
From: Dave Houlton <euclid@lindenlab.com>
Date: Tue, 30 Nov 2021 11:42:37 -0700
Subject: SL-16386 purge no-op fxn LLTexUnit::setTextureColorBlend()

---
 indra/llrender/llrender.h           |  8 +-------
 indra/newview/lldrawpoolbump.cpp    |  1 -
 indra/newview/lldrawpoolterrain.cpp | 24 ------------------------
 indra/newview/lldrawpoolwater.cpp   |  1 -
 indra/newview/llviewerjointmesh.cpp |  1 -
 5 files changed, 1 insertion(+), 34 deletions(-)

(limited to 'indra')

diff --git a/indra/llrender/llrender.h b/indra/llrender/llrender.h
index 2feb8f955b..08a906a89b 100644
--- a/indra/llrender/llrender.h
+++ b/indra/llrender/llrender.h
@@ -105,10 +105,7 @@ public:
 		TBO_LERP_VERT_ALPHA,		// Interpolate based on Vertex Alpha (VA): ( Source1 * VA + Source2 * (1-VA) )
 		TBO_LERP_TEX_ALPHA,			// Interpolate based on Texture Alpha (TA): ( Source1 * TA + Source2 * (1-TA) )
 		TBO_LERP_PREV_ALPHA,		// Interpolate based on Previous Alpha (PA): ( Source1 * PA + Source2 * (1-PA) )
-		TBO_LERP_CONST_ALPHA,		// Interpolate based on Const Alpha (CA): ( Source1 * CA + Source2 * (1-CA) )
-		TBO_LERP_VERT_COLOR			// Interpolate based on Vertex Col (VC): ( Source1 * VC + Source2 * (1-VC) )
-										// *Note* TBO_LERP_VERTEX_COLOR only works with setTextureColorBlend(),
-										// and falls back to TBO_LERP_VERTEX_ALPHA for setTextureAlphaBlend().
+		TBO_LERP_CONST_ALPHA		// Interpolate based on Const Alpha (CA): ( Source1 * CA + Source2 * (1-CA) )
 	} eTextureBlendOp;
 
 	typedef enum 
@@ -201,9 +198,6 @@ public:
 	// make sure you want to permanently change the filtering for the bound texture.
 	void setTextureFilteringOption(LLTexUnit::eTextureFilterOptions option);
 
-	inline void setTextureColorBlend(eTextureBlendOp op, eTextureBlendSrc src1, eTextureBlendSrc src2 = TBS_PREV_COLOR)
-	{ /* setTextureCombiner(op, src1, src2, false); */ }
-
 	// NOTE: If *_COLOR enums are passed to src1 or src2, the corresponding *_ALPHA enum will be used instead.
 	inline void setTextureAlphaBlend(eTextureBlendOp op, eTextureBlendSrc src1, eTextureBlendSrc src2 = TBS_PREV_ALPHA)
 	{ /* setTextureCombiner(op, src1, src2, true); */ }
diff --git a/indra/newview/lldrawpoolbump.cpp b/indra/newview/lldrawpoolbump.cpp
index 3b039cd505..6fd6fc06c6 100644
--- a/indra/newview/lldrawpoolbump.cpp
+++ b/indra/newview/lldrawpoolbump.cpp
@@ -403,7 +403,6 @@ void LLDrawPoolBump::bindCubeMap(LLGLSLShader* shader, S32 shader_level, S32& di
 			cube_map->enable(0);
 			gGL.getTexUnit(0)->bind(cube_map);
 
-			gGL.getTexUnit(0)->setTextureColorBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_TEX_COLOR);
 			gGL.getTexUnit(0)->setTextureAlphaBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_VERT_ALPHA);
 		}
 	}
diff --git a/indra/newview/lldrawpoolterrain.cpp b/indra/newview/lldrawpoolterrain.cpp
index cc21f13678..5db816d003 100644
--- a/indra/newview/lldrawpoolterrain.cpp
+++ b/indra/newview/lldrawpoolterrain.cpp
@@ -467,8 +467,6 @@ void LLDrawPoolTerrain::renderFull4TU()
 	glTexGenfv(GL_S, GL_OBJECT_PLANE, tp0.mV);
 	glTexGenfv(GL_T, GL_OBJECT_PLANE, tp1.mV);
 
-	gGL.getTexUnit(0)->setTextureColorBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_TEX_COLOR);
-
 	//
 	// Stage 1: Generate alpha ramp for detail0/detail1 transition
 	//
@@ -478,7 +476,6 @@ void LLDrawPoolTerrain::renderFull4TU()
 	gGL.getTexUnit(1)->activate();
 	
 	// Care about alpha only
-	gGL.getTexUnit(1)->setTextureColorBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_PREV_COLOR);
 	gGL.getTexUnit(1)->setTextureAlphaBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_TEX_ALPHA);
 
 	//
@@ -495,8 +492,6 @@ void LLDrawPoolTerrain::renderFull4TU()
 	glTexGenfv(GL_S, GL_OBJECT_PLANE, tp0.mV);
 	glTexGenfv(GL_T, GL_OBJECT_PLANE, tp1.mV);
 
-	gGL.getTexUnit(2)->setTextureColorBlend(LLTexUnit::TBO_LERP_PREV_ALPHA, LLTexUnit::TBS_PREV_COLOR, LLTexUnit::TBS_TEX_COLOR);
-
 	//
 	// Stage 3: Modulate with primary (vertex) color for lighting
 	//
@@ -504,9 +499,6 @@ void LLDrawPoolTerrain::renderFull4TU()
 	gGL.getTexUnit(3)->enable(LLTexUnit::TT_TEXTURE);
 	gGL.getTexUnit(3)->activate();
 	
-	// Set alpha texture and do lighting modulation
-	gGL.getTexUnit(3)->setTextureColorBlend(LLTexUnit::TBO_MULT, LLTexUnit::TBS_PREV_COLOR, LLTexUnit::TBS_VERT_COLOR);
-
 	gGL.getTexUnit(0)->activate();
 	
 	// GL_BLEND disabled by default
@@ -527,8 +519,6 @@ void LLDrawPoolTerrain::renderFull4TU()
 	glTexGenfv(GL_S, GL_OBJECT_PLANE, tp0.mV);
 	glTexGenfv(GL_T, GL_OBJECT_PLANE, tp1.mV);
 
-	gGL.getTexUnit(0)->setTextureColorBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_TEX_COLOR);
-
 	//
 	// Stage 1: Generate alpha ramp for detail2/detail3 transition
 	//
@@ -542,7 +532,6 @@ void LLDrawPoolTerrain::renderFull4TU()
 	gGL.translatef(-2.f, 0.f, 0.f);
 
 	// Care about alpha only
-	gGL.getTexUnit(1)->setTextureColorBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_PREV_COLOR);
 	gGL.getTexUnit(1)->setTextureAlphaBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_TEX_ALPHA);
 
 	//
@@ -559,8 +548,6 @@ void LLDrawPoolTerrain::renderFull4TU()
 	glTexGenfv(GL_S, GL_OBJECT_PLANE, tp0.mV);
 	glTexGenfv(GL_T, GL_OBJECT_PLANE, tp1.mV);
 
-	gGL.getTexUnit(2)->setTextureColorBlend(LLTexUnit::TBO_LERP_PREV_ALPHA, LLTexUnit::TBS_TEX_COLOR, LLTexUnit::TBS_PREV_COLOR);	
-
 	//
 	// Stage 3: Generate alpha ramp for detail1/detail2 transition
 	//
@@ -575,7 +562,6 @@ void LLDrawPoolTerrain::renderFull4TU()
 	gGL.matrixMode(LLRender::MM_MODELVIEW);
 
 	// Set alpha texture and do lighting modulation
-	gGL.getTexUnit(3)->setTextureColorBlend(LLTexUnit::TBO_MULT, LLTexUnit::TBS_PREV_COLOR, LLTexUnit::TBS_VERT_COLOR);
 	gGL.getTexUnit(3)->setTextureAlphaBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_TEX_ALPHA);
 
 	gGL.getTexUnit(0)->activate();
@@ -665,8 +651,6 @@ void LLDrawPoolTerrain::renderFull2TU()
 	glTexGenfv(GL_S, GL_OBJECT_PLANE, tp0.mV);
 	glTexGenfv(GL_T, GL_OBJECT_PLANE, tp1.mV);
 
-	gGL.getTexUnit(0)->setTextureColorBlend(LLTexUnit::TBO_MULT, LLTexUnit::TBS_TEX_COLOR, LLTexUnit::TBS_VERT_COLOR);
-
 	drawLoop();
 
 	//----------------------------------------------------------------------------
@@ -681,7 +665,6 @@ void LLDrawPoolTerrain::renderFull2TU()
 	glDisable(GL_TEXTURE_GEN_T);
 	
 	// Care about alpha only
-	gGL.getTexUnit(0)->setTextureColorBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_PREV_COLOR);
 	gGL.getTexUnit(0)->setTextureAlphaBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_TEX_ALPHA);
 
 
@@ -699,7 +682,6 @@ void LLDrawPoolTerrain::renderFull2TU()
 	glTexGenfv(GL_S, GL_OBJECT_PLANE, tp0.mV);
 	glTexGenfv(GL_T, GL_OBJECT_PLANE, tp1.mV);
 
-	gGL.getTexUnit(1)->setTextureColorBlend(LLTexUnit::TBO_MULT, LLTexUnit::TBS_TEX_COLOR, LLTexUnit::TBS_VERT_COLOR);
 	gGL.getTexUnit(1)->setTextureAlphaBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_PREV_ALPHA);
 
 	gGL.getTexUnit(0)->activate();
@@ -722,7 +704,6 @@ void LLDrawPoolTerrain::renderFull2TU()
 	gGL.matrixMode(LLRender::MM_MODELVIEW);
 
 	// Care about alpha only
-	gGL.getTexUnit(0)->setTextureColorBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_PREV_COLOR);
 	gGL.getTexUnit(0)->setTextureAlphaBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_TEX_ALPHA);
 
 	//
@@ -739,7 +720,6 @@ void LLDrawPoolTerrain::renderFull2TU()
 	glTexGenfv(GL_S, GL_OBJECT_PLANE, tp0.mV);
 	glTexGenfv(GL_T, GL_OBJECT_PLANE, tp1.mV);
 
-	gGL.getTexUnit(1)->setTextureColorBlend(LLTexUnit::TBO_MULT, LLTexUnit::TBS_TEX_COLOR, LLTexUnit::TBS_VERT_COLOR);
 	gGL.getTexUnit(1)->setTextureAlphaBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_PREV_ALPHA);
 
 	{
@@ -762,7 +742,6 @@ void LLDrawPoolTerrain::renderFull2TU()
 	gGL.matrixMode(LLRender::MM_MODELVIEW);
 
 	// Care about alpha only
-	gGL.getTexUnit(0)->setTextureColorBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_PREV_COLOR);
 	gGL.getTexUnit(0)->setTextureAlphaBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_TEX_ALPHA);
 
 	// Stage 1: Write detail3
@@ -777,7 +756,6 @@ void LLDrawPoolTerrain::renderFull2TU()
 	glTexGenfv(GL_S, GL_OBJECT_PLANE, tp0.mV);
 	glTexGenfv(GL_T, GL_OBJECT_PLANE, tp1.mV);
 
-	gGL.getTexUnit(1)->setTextureColorBlend(LLTexUnit::TBO_MULT, LLTexUnit::TBS_TEX_COLOR, LLTexUnit::TBS_VERT_COLOR);
 	gGL.getTexUnit(1)->setTextureAlphaBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_PREV_ALPHA);
 
 	gGL.getTexUnit(0)->activate();
@@ -837,8 +815,6 @@ void LLDrawPoolTerrain::renderSimple()
 	sShader->uniform4fv(LLShaderMgr::OBJECT_PLANE_S, 1, tp0.mV);
 	sShader->uniform4fv(LLShaderMgr::OBJECT_PLANE_T, 1, tp1.mV);
 
-	gGL.getTexUnit(0)->setTextureColorBlend(LLTexUnit::TBO_MULT, LLTexUnit::TBS_TEX_COLOR, LLTexUnit::TBS_VERT_COLOR);
-
 	drawLoop();
 
 	//----------------------------------------------------------------------------
diff --git a/indra/newview/lldrawpoolwater.cpp b/indra/newview/lldrawpoolwater.cpp
index 4023d59776..53aca91e5c 100644
--- a/indra/newview/lldrawpoolwater.cpp
+++ b/indra/newview/lldrawpoolwater.cpp
@@ -239,7 +239,6 @@ void LLDrawPoolWater::render(S32 pass)
 	glTexGenfv(GL_S, GL_OBJECT_PLANE, tp0);
 	glTexGenfv(GL_T, GL_OBJECT_PLANE, tp1);
 
-	gGL.getTexUnit(1)->setTextureColorBlend(LLTexUnit::TBO_MULT, LLTexUnit::TBS_TEX_COLOR, LLTexUnit::TBS_PREV_COLOR);
 	gGL.getTexUnit(1)->setTextureAlphaBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_PREV_ALPHA);
 
 	gGL.getTexUnit(0)->activate();
diff --git a/indra/newview/llviewerjointmesh.cpp b/indra/newview/llviewerjointmesh.cpp
index 640e54c2e1..f3b0e82b3a 100644
--- a/indra/newview/llviewerjointmesh.cpp
+++ b/indra/newview/llviewerjointmesh.cpp
@@ -265,7 +265,6 @@ U32 LLViewerJointMesh::drawShape( F32 pixelArea, BOOL first_pass, BOOL is_dummy)
 		else
 		{
 			gGL.diffuseColor4f(0.7f, 0.6f, 0.3f, 1.f);
-			gGL.getTexUnit(diffuse_channel)->setTextureColorBlend(LLTexUnit::TBO_LERP_TEX_ALPHA, LLTexUnit::TBS_TEX_COLOR, LLTexUnit::TBS_PREV_COLOR);
 		}
 	}
 	else if( !is_dummy && layerset )
-- 
cgit v1.2.3


From fab60f242ef7e3aac299c8373f486cb9fa92494c Mon Sep 17 00:00:00 2001
From: Dave Houlton <euclid@lindenlab.com>
Date: Tue, 30 Nov 2021 12:06:23 -0700
Subject: SL-16386 purge no-op fxn LLTexUnit::setTextureAlphaBlend()

---
 indra/llrender/llrender.h           |  4 ----
 indra/newview/lldrawpoolbump.cpp    |  2 --
 indra/newview/lldrawpoolterrain.cpp | 25 -------------------------
 indra/newview/lldrawpoolwater.cpp   |  2 --
 4 files changed, 33 deletions(-)

(limited to 'indra')

diff --git a/indra/llrender/llrender.h b/indra/llrender/llrender.h
index 08a906a89b..d594c455d6 100644
--- a/indra/llrender/llrender.h
+++ b/indra/llrender/llrender.h
@@ -198,10 +198,6 @@ public:
 	// make sure you want to permanently change the filtering for the bound texture.
 	void setTextureFilteringOption(LLTexUnit::eTextureFilterOptions option);
 
-	// NOTE: If *_COLOR enums are passed to src1 or src2, the corresponding *_ALPHA enum will be used instead.
-	inline void setTextureAlphaBlend(eTextureBlendOp op, eTextureBlendSrc src1, eTextureBlendSrc src2 = TBS_PREV_ALPHA)
-	{ /* setTextureCombiner(op, src1, src2, true); */ }
-
 	static U32 getInternalType(eTextureType type);
 
 	U32 getCurrTexture(void) { return mCurrTexture; }
diff --git a/indra/newview/lldrawpoolbump.cpp b/indra/newview/lldrawpoolbump.cpp
index 6fd6fc06c6..cd4aada822 100644
--- a/indra/newview/lldrawpoolbump.cpp
+++ b/indra/newview/lldrawpoolbump.cpp
@@ -402,8 +402,6 @@ void LLDrawPoolBump::bindCubeMap(LLGLSLShader* shader, S32 shader_level, S32& di
 			gGL.getTexUnit(0)->disable();
 			cube_map->enable(0);
 			gGL.getTexUnit(0)->bind(cube_map);
-
-			gGL.getTexUnit(0)->setTextureAlphaBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_VERT_ALPHA);
 		}
 	}
 }
diff --git a/indra/newview/lldrawpoolterrain.cpp b/indra/newview/lldrawpoolterrain.cpp
index 5db816d003..adea1909a3 100644
--- a/indra/newview/lldrawpoolterrain.cpp
+++ b/indra/newview/lldrawpoolterrain.cpp
@@ -475,9 +475,6 @@ void LLDrawPoolTerrain::renderFull4TU()
 	gGL.getTexUnit(1)->enable(LLTexUnit::TT_TEXTURE);
 	gGL.getTexUnit(1)->activate();
 	
-	// Care about alpha only
-	gGL.getTexUnit(1)->setTextureAlphaBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_TEX_ALPHA);
-
 	//
 	// Stage 2: Interpolate detail1 with existing based on ramp
 	//
@@ -531,9 +528,6 @@ void LLDrawPoolTerrain::renderFull4TU()
 	gGL.loadIdentity();
 	gGL.translatef(-2.f, 0.f, 0.f);
 
-	// Care about alpha only
-	gGL.getTexUnit(1)->setTextureAlphaBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_TEX_ALPHA);
-
 	//
 	// Stage 2: Interpolate detail2 with existing based on ramp
 	//
@@ -561,9 +555,6 @@ void LLDrawPoolTerrain::renderFull4TU()
 	gGL.translatef(-1.f, 0.f, 0.f);
 	gGL.matrixMode(LLRender::MM_MODELVIEW);
 
-	// Set alpha texture and do lighting modulation
-	gGL.getTexUnit(3)->setTextureAlphaBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_TEX_ALPHA);
-
 	gGL.getTexUnit(0)->activate();
 	{
 		LLGLEnable blend(GL_BLEND);
@@ -664,10 +655,6 @@ void LLDrawPoolTerrain::renderFull2TU()
 	glDisable(GL_TEXTURE_GEN_S);
 	glDisable(GL_TEXTURE_GEN_T);
 	
-	// Care about alpha only
-	gGL.getTexUnit(0)->setTextureAlphaBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_TEX_ALPHA);
-
-
 	//
 	// Stage 1: Write detail1
 	//
@@ -682,8 +669,6 @@ void LLDrawPoolTerrain::renderFull2TU()
 	glTexGenfv(GL_S, GL_OBJECT_PLANE, tp0.mV);
 	glTexGenfv(GL_T, GL_OBJECT_PLANE, tp1.mV);
 
-	gGL.getTexUnit(1)->setTextureAlphaBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_PREV_ALPHA);
-
 	gGL.getTexUnit(0)->activate();
 	{
 		LLGLEnable blend(GL_BLEND);
@@ -703,9 +688,6 @@ void LLDrawPoolTerrain::renderFull2TU()
 	gGL.translatef(-1.f, 0.f, 0.f);
 	gGL.matrixMode(LLRender::MM_MODELVIEW);
 
-	// Care about alpha only
-	gGL.getTexUnit(0)->setTextureAlphaBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_TEX_ALPHA);
-
 	//
 	// Stage 1: Write detail2
 	//
@@ -720,8 +702,6 @@ void LLDrawPoolTerrain::renderFull2TU()
 	glTexGenfv(GL_S, GL_OBJECT_PLANE, tp0.mV);
 	glTexGenfv(GL_T, GL_OBJECT_PLANE, tp1.mV);
 
-	gGL.getTexUnit(1)->setTextureAlphaBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_PREV_ALPHA);
-
 	{
 		LLGLEnable blend(GL_BLEND);
 		drawLoop();
@@ -741,9 +721,6 @@ void LLDrawPoolTerrain::renderFull2TU()
 	gGL.translatef(-2.f, 0.f, 0.f);
 	gGL.matrixMode(LLRender::MM_MODELVIEW);
 
-	// Care about alpha only
-	gGL.getTexUnit(0)->setTextureAlphaBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_TEX_ALPHA);
-
 	// Stage 1: Write detail3
 	gGL.getTexUnit(1)->bind(detail_texture3p);
 	gGL.getTexUnit(1)->enable(LLTexUnit::TT_TEXTURE);
@@ -756,8 +733,6 @@ void LLDrawPoolTerrain::renderFull2TU()
 	glTexGenfv(GL_S, GL_OBJECT_PLANE, tp0.mV);
 	glTexGenfv(GL_T, GL_OBJECT_PLANE, tp1.mV);
 
-	gGL.getTexUnit(1)->setTextureAlphaBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_PREV_ALPHA);
-
 	gGL.getTexUnit(0)->activate();
 	{
 		LLGLEnable blend(GL_BLEND);
diff --git a/indra/newview/lldrawpoolwater.cpp b/indra/newview/lldrawpoolwater.cpp
index 53aca91e5c..590385472b 100644
--- a/indra/newview/lldrawpoolwater.cpp
+++ b/indra/newview/lldrawpoolwater.cpp
@@ -239,8 +239,6 @@ void LLDrawPoolWater::render(S32 pass)
 	glTexGenfv(GL_S, GL_OBJECT_PLANE, tp0);
 	glTexGenfv(GL_T, GL_OBJECT_PLANE, tp1);
 
-	gGL.getTexUnit(1)->setTextureAlphaBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_PREV_ALPHA);
-
 	gGL.getTexUnit(0)->activate();
 	
 	glClearStencil(1);
-- 
cgit v1.2.3


From 4d6963bd812b45c713ab83d5e90367e04d3ab5b1 Mon Sep 17 00:00:00 2001
From: Dave Houlton <euclid@lindenlab.com>
Date: Tue, 30 Nov 2021 12:37:51 -0700
Subject: SL-16386 purge write-only state member LLCubeMap::mTextureCoordStage

---
 indra/llrender/llcubemap.cpp     | 12 ------------
 indra/llrender/llcubemap.h       |  3 ---
 indra/newview/lldrawpoolbump.cpp |  2 --
 3 files changed, 17 deletions(-)

(limited to 'indra')

diff --git a/indra/llrender/llcubemap.cpp b/indra/llrender/llcubemap.cpp
index d2faa5f3ae..834084674e 100644
--- a/indra/llrender/llcubemap.cpp
+++ b/indra/llrender/llcubemap.cpp
@@ -47,7 +47,6 @@ bool LLCubeMap::sUseCubeMaps = true;
 
 LLCubeMap::LLCubeMap(bool init_as_srgb)
 	: mTextureStage(0),
-	  mTextureCoordStage(0),
 	  mMatrixStage(0),
 	  mIssRGB(init_as_srgb)
 {
@@ -180,7 +179,6 @@ void LLCubeMap::bind()
 void LLCubeMap::enable(S32 stage)
 {
 	enableTexture(stage);
-	enableTextureCoords(stage);
 }
 
 void LLCubeMap::enableTexture(S32 stage)
@@ -192,15 +190,9 @@ void LLCubeMap::enableTexture(S32 stage)
 	}
 }
 
-void LLCubeMap::enableTextureCoords(S32 stage)
-{
-	mTextureCoordStage = stage;
-}
-
 void LLCubeMap::disable(void)
 {
 	disableTexture();
-	disableTextureCoords();
 }
 
 void LLCubeMap::disableTexture(void)
@@ -215,10 +207,6 @@ void LLCubeMap::disableTexture(void)
 	}
 }
 
-void LLCubeMap::disableTextureCoords(void)
-{
-}
-
 void LLCubeMap::setMatrix(S32 stage)
 {
 	mMatrixStage = stage;
diff --git a/indra/llrender/llcubemap.h b/indra/llrender/llcubemap.h
index 95b6d12099..a01636d8d4 100644
--- a/indra/llrender/llcubemap.h
+++ b/indra/llrender/llcubemap.h
@@ -48,12 +48,10 @@ public:
 	void enable(S32 stage);
 	
 	void enableTexture(S32 stage);
-	void enableTextureCoords(S32 stage);
 	S32	 getStage(void) { return mTextureStage; }
 	
 	void disable(void);
 	void disableTexture(void);
-	void disableTextureCoords(void);
 	void setMatrix(S32 stage);
 	void restoreMatrix();
 	void setReflection (void);
@@ -80,7 +78,6 @@ protected:
 	LLPointer<LLImageGL> mImages[6];
 	LLPointer<LLImageRaw> mRawImages[6];
 	S32 mTextureStage;
-	S32 mTextureCoordStage;
 	S32 mMatrixStage;
 };
 
diff --git a/indra/newview/lldrawpoolbump.cpp b/indra/newview/lldrawpoolbump.cpp
index cd4aada822..9d19ff44db 100644
--- a/indra/newview/lldrawpoolbump.cpp
+++ b/indra/newview/lldrawpoolbump.cpp
@@ -383,7 +383,6 @@ void LLDrawPoolBump::bindCubeMap(LLGLSLShader* shader, S32 shader_level, S32& di
 				// the cube map in the one pass shiny shaders
 				cube_channel = shader->enableTexture(LLViewerShaderMgr::ENVIRONMENT_MAP, LLTexUnit::TT_CUBE_MAP);
 				cube_map->enableTexture(cube_channel);
-				cube_map->enableTextureCoords(1);
 				diffuse_channel = shader->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
 			}
 			else
@@ -534,7 +533,6 @@ void LLDrawPoolBump::beginFullbrightShiny()
 		gGL.getTexUnit(1)->disable();
 		cube_channel = shader->enableTexture(LLViewerShaderMgr::ENVIRONMENT_MAP, LLTexUnit::TT_CUBE_MAP);
 		cube_map->enableTexture(cube_channel);
-		cube_map->enableTextureCoords(1);
 		diffuse_channel = shader->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
 
 		gGL.getTexUnit(cube_channel)->bind(cube_map);
-- 
cgit v1.2.3


From 8b92652806ddc239e8d2627151ce2dab6faf138f Mon Sep 17 00:00:00 2001
From: Dave Houlton <euclid@lindenlab.com>
Date: Tue, 30 Nov 2021 12:53:17 -0700
Subject: SL-16386 replace gutted LLRender::setAlphaRejectSettings() with
 explicit flush()

---
 indra/llrender/llrender.cpp        |  7 +------
 indra/llrender/llrender.h          |  2 --
 indra/newview/lldrawpool.cpp       |  2 +-
 indra/newview/lldrawpoolsimple.cpp |  4 ++--
 indra/newview/lldrawpooltree.cpp   |  4 ++--
 indra/newview/llface.cpp           |  2 +-
 indra/newview/llnetmap.cpp         |  4 ++--
 indra/newview/llselectmgr.cpp      |  4 +---
 indra/newview/lltoolmorph.cpp      |  4 ++--
 indra/newview/llvoavatar.cpp       | 10 +++++-----
 indra/newview/llworldmapview.cpp   |  9 +++------
 11 files changed, 20 insertions(+), 32 deletions(-)

(limited to 'indra')

diff --git a/indra/llrender/llrender.cpp b/indra/llrender/llrender.cpp
index 14abd9b83e..c426c769f3 100644
--- a/indra/llrender/llrender.cpp
+++ b/indra/llrender/llrender.cpp
@@ -926,7 +926,7 @@ void LLRender::refreshState(void)
 
 	setColorMask(mCurrColorMask[0], mCurrColorMask[1], mCurrColorMask[2], mCurrColorMask[3]);
 	
-	setAlphaRejectSettings(mCurrAlphaFunc, mCurrAlphaFuncVal);
+    flush();
 
 	mDirty = false;
 }
@@ -1429,11 +1429,6 @@ void LLRender::setSceneBlendType(eBlendType type)
 	}
 }
 
-void LLRender::setAlphaRejectSettings(eCompareFunc func, F32 value)
-{
-	flush();
-}
-
 void LLRender::blendFunc(eBlendFactor sfactor, eBlendFactor dfactor)
 {
 	llassert(sfactor < BF_UNDEF);
diff --git a/indra/llrender/llrender.h b/indra/llrender/llrender.h
index d594c455d6..cdf4075244 100644
--- a/indra/llrender/llrender.h
+++ b/indra/llrender/llrender.h
@@ -431,8 +431,6 @@ public:
 	void setColorMask(bool writeColorR, bool writeColorG, bool writeColorB, bool writeAlpha);
 	void setSceneBlendType(eBlendType type);
 
-	void setAlphaRejectSettings(eCompareFunc func, F32 value = 0.01f);
-
 	// applies blend func to both color and alpha
 	void blendFunc(eBlendFactor sfactor, eBlendFactor dfactor);
 	// applies separate blend functions to color and alpha
diff --git a/indra/newview/lldrawpool.cpp b/indra/newview/lldrawpool.cpp
index 92a9bed504..bad0c66fb1 100644
--- a/indra/newview/lldrawpool.cpp
+++ b/indra/newview/lldrawpool.cpp
@@ -493,7 +493,7 @@ void LLRenderPass::pushRiggedMaskBatches(U32 type, U32 mask, BOOL texture, BOOL
             }
             else
             {
-                gGL.setAlphaRejectSettings(LLRender::CF_GREATER, pparams->mAlphaMaskCutoff);
+                gGL.flush();
             }
 
             if (lastAvatar != pparams->mAvatar || lastMeshId != pparams->mSkinInfo->mHash)
diff --git a/indra/newview/lldrawpoolsimple.cpp b/indra/newview/lldrawpoolsimple.cpp
index ca4e20ae9b..a1d769bc83 100644
--- a/indra/newview/lldrawpoolsimple.cpp
+++ b/indra/newview/lldrawpoolsimple.cpp
@@ -591,7 +591,7 @@ void LLDrawPoolGrass::beginRenderPass(S32 pass)
 	}
 	else 
 	{
-		gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.5f);
+        gGL.flush();
 		LLGLSLShader::bindNoShader();
 	}
 }
@@ -607,7 +607,7 @@ void LLDrawPoolGrass::endRenderPass(S32 pass)
 	}
 	else
 	{
-		gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
+		gGL.flush();
 	}
 }
 
diff --git a/indra/newview/lldrawpooltree.cpp b/indra/newview/lldrawpooltree.cpp
index e93852864e..c84178c6cd 100644
--- a/indra/newview/lldrawpooltree.cpp
+++ b/indra/newview/lldrawpooltree.cpp
@@ -77,7 +77,7 @@ void LLDrawPoolTree::beginRenderPass(S32 pass)
 	else
 	{
 		gPipeline.enableLightsDynamic();
-		gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.5f);
+		gGL.flush();
 	}
 }
 
@@ -134,7 +134,7 @@ void LLDrawPoolTree::endRenderPass(S32 pass)
 	
 	if (mShaderLevel <= 0)
 	{
-		gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
+        gGL.flush();
 	}
 }
 
diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp
index 39ca7961d8..54a043482b 100644
--- a/indra/newview/llface.cpp
+++ b/indra/newview/llface.cpp
@@ -653,7 +653,7 @@ void LLFace::renderOneWireframe(const LLColor4 &color, F32 fogCfx, bool wirefram
             glFogf(GL_FOG_END, d*(1 + (LLViewerCamera::getInstance()->getView() / LLViewerCamera::getInstance()->getDefaultFOV())));
             glFogfv(GL_FOG_COLOR, fogCol.mV);
 
-            gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
+            gGL.flush();
             {
                 gGL.diffuseColor4f(color.mV[VRED], color.mV[VGREEN], color.mV[VBLUE], 0.4f);
                 renderFace(mDrawablep, this);
diff --git a/indra/newview/llnetmap.cpp b/indra/newview/llnetmap.cpp
index 111b45612e..937f36b6fc 100644
--- a/indra/newview/llnetmap.cpp
+++ b/indra/newview/llnetmap.cpp
@@ -259,7 +259,7 @@ void LLNetMap::draw()
 			gGL.end();
 
 			// Draw water
-			gGL.setAlphaRejectSettings(LLRender::CF_GREATER, ABOVE_WATERLINE_ALPHA / 255.f);
+            gGL.flush();
 			{
 				if (regionp->getLand().getWaterTexture())
 				{
@@ -276,7 +276,7 @@ void LLNetMap::draw()
 					gGL.end();
 				}
 			}
-			gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
+            gGL.flush();
 		}
 
 		// Redraw object layer periodically
diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp
index 6f136e50e0..b3d3e9e0da 100644
--- a/indra/newview/llselectmgr.cpp
+++ b/indra/newview/llselectmgr.cpp
@@ -5894,8 +5894,6 @@ void LLSelectMgr::updateSilhouettes()
 		LLViewerObject* objectp = *iter;
 		objectp->clearChanged(LLXform::MOVED | LLXform::SILHOUETTE);
 	}
-	
-	//gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
 }
 
 void LLSelectMgr::updateSelectionSilhouette(LLObjectSelectionHandle object_handle, S32& num_sils_genned, std::vector<LLViewerObject*>& changed_objects)
@@ -6620,7 +6618,7 @@ void LLSelectNode::renderOneSilhouette(const LLColor4 &color)
 			glFogfv(GL_FOG_COLOR, fogCol.mV);
 
 			LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE, GL_GEQUAL);
-			gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
+            gGL.flush();
 			gGL.begin(LLRender::LINES);
 			{
 				gGL.color4f(color.mV[VRED], color.mV[VGREEN], color.mV[VBLUE], 0.4f);
diff --git a/indra/newview/lltoolmorph.cpp b/indra/newview/lltoolmorph.cpp
index 9f0198029a..b2e8348ffd 100644
--- a/indra/newview/lltoolmorph.cpp
+++ b/indra/newview/lltoolmorph.cpp
@@ -244,11 +244,11 @@ BOOL LLVisualParamHint::render()
 	{
 		LLDrawPoolAvatar *avatarPoolp = (LLDrawPoolAvatar *)gAgentAvatarp->mDrawable->getFace(0)->getPool();
 		LLGLDepthTest gls_depth(GL_TRUE, GL_TRUE);
-		gGL.setAlphaRejectSettings(LLRender::CF_ALWAYS);
+        gGL.flush();
 		gGL.setSceneBlendType(LLRender::BT_REPLACE);
 		avatarPoolp->renderAvatars(gAgentAvatarp);  // renders only one avatar
 		gGL.setSceneBlendType(LLRender::BT_ALPHA);
-		gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
+        gGL.flush();
 	}
 	gAgentAvatarp->setVisualParamWeight(mVisualParam->getID(), mLastParamWeight);
 	mWearablePtr->setVisualParamWeight(mVisualParam->getID(), mLastParamWeight);
diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp
index da856beb6e..8e4e008738 100644
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -5114,21 +5114,21 @@ U32 LLVOAvatar::renderTransparent(BOOL first_pass)
 	U32 num_indices = 0;
 	if( isWearingWearableType( LLWearableType::WT_SKIRT ) && (isUIAvatar() || isTextureVisible(TEX_SKIRT_BAKED)) )
 	{
-		gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.25f);
+        gGL.flush();
 		LLViewerJoint* skirt_mesh = getViewerJoint(MESH_ID_SKIRT);
 		if (skirt_mesh)
 		{
 			num_indices += skirt_mesh->render(mAdjustedPixelArea, FALSE);
 		}
 		first_pass = FALSE;
-		gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
+        gGL.flush();
 	}
 
 	if (!isSelf() || gAgent.needsRenderHead() || LLPipeline::sShadowRender)
 	{
 		if (LLPipeline::sImpostorRender)
 		{
-			gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.5f);
+            gGL.flush();
 		}
 		
 		if (isTextureVisible(TEX_HEAD_BAKED))
@@ -5151,7 +5151,7 @@ U32 LLVOAvatar::renderTransparent(BOOL first_pass)
 		}
 		if (LLPipeline::sImpostorRender)
 		{
-			gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
+            gGL.flush();
 		}
 	}
 	
@@ -5247,7 +5247,7 @@ U32 LLVOAvatar::renderImpostor(LLColor4U color, S32 diffuse_channel)
 	}
 	{
 	LLGLEnable test(GL_ALPHA_TEST);
-	gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.f);
+    gGL.flush();
 
 	gGL.color4ubv(color.mV);
 	gGL.getTexUnit(diffuse_channel)->bind(&mImpostor);
diff --git a/indra/newview/llworldmapview.cpp b/indra/newview/llworldmapview.cpp
index a6df079223..59ac4554d7 100644
--- a/indra/newview/llworldmapview.cpp
+++ b/indra/newview/llworldmapview.cpp
@@ -321,22 +321,19 @@ void LLWorldMapView::draw()
 		// Clear the background alpha to 0
 		gGL.flush();
 		gGL.setColorMask(false, true);
-		gGL.setAlphaRejectSettings(LLRender::CF_GREATER_EQUAL, 0.f);
+        gGL.flush();
 		gGL.setSceneBlendType(LLRender::BT_REPLACE);
 		gGL.color4f(0.0f, 0.0f, 0.0f, 0.0f);
 		gl_rect_2d(0, height, width, 0);
 	}
 
 	gGL.flush();
-
-	gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
 	gGL.setColorMask(true, true);
 
 	// Draw the image tiles
 	drawMipmap(width, height);
 	gGL.flush();
 
-	gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
 	gGL.setColorMask(true, true);
 
 	// Draw per sim overlayed information (names, mature, offline...)
@@ -480,13 +477,13 @@ void LLWorldMapView::draw()
 	LLGLSUIDefault gls_ui;
 	{
 		gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
-		gGL.setAlphaRejectSettings(LLRender::CF_GREATER_EQUAL, 0.f);
+        gGL.flush();
 		gGL.blendFunc(LLRender::BF_ONE_MINUS_DEST_ALPHA, LLRender::BF_DEST_ALPHA);
 		gGL.color4fv( mBackgroundColor.mV );
 		gl_rect_2d(0, height, width, 0);
 	}
 
-	gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
+    gGL.flush();
 	gGL.setSceneBlendType(LLRender::BT_ALPHA);
 
 	// Draw item infos if we're not zoomed out too much and there's something to draw
-- 
cgit v1.2.3


From 08f0f6d8330e0eb654e1661f8c661d5222992933 Mon Sep 17 00:00:00 2001
From: Dave Houlton <euclid@lindenlab.com>
Date: Tue, 30 Nov 2021 15:01:40 -0700
Subject: SL-16386 remove references to (const true)
 LLPipeline::mVertexShadersEnabled

---
 indra/newview/llviewershadermgr.cpp | 220 ++++++++++++++++++------------------
 indra/newview/llviewerwindow.cpp    |   6 -
 indra/newview/pipeline.cpp          |   6 +-
 indra/newview/pipeline.h            |   2 -
 4 files changed, 110 insertions(+), 124 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp
index d37678e24f..26592adc0a 100644
--- a/indra/newview/llviewershadermgr.cpp
+++ b/indra/newview/llviewershadermgr.cpp
@@ -558,164 +558,162 @@ void LLViewerShaderMgr::setShaders()
         return;
     }
 
-        gPipeline.mVertexShadersEnabled = TRUE;
-        gPipeline.mVertexShadersLoaded = 1;
+    gPipeline.mVertexShadersLoaded = 1;
 
-        // Load all shaders to set max levels
-        loaded = loadShadersEnvironment();
+    // Load all shaders to set max levels
+    loaded = loadShadersEnvironment();
 
+    if (loaded)
+    {
+        LL_INFOS() << "Loaded environment shaders." << LL_ENDL;
+    }
+    else
+    {
+        LL_WARNS() << "Failed to load environment shaders." << LL_ENDL;
+        llassert(loaded);
+    }
+
+    if (loaded)
+    {
+        loaded = loadShadersWater();
         if (loaded)
         {
-            LL_INFOS() << "Loaded environment shaders." << LL_ENDL;
+            LL_INFOS() << "Loaded water shaders." << LL_ENDL;
         }
         else
         {
-            LL_WARNS() << "Failed to load environment shaders." << LL_ENDL;
+            LL_WARNS() << "Failed to load water shaders." << LL_ENDL;
             llassert(loaded);
         }
+    }
 
+    if (loaded)
+    {
+        loaded = loadShadersWindLight();
         if (loaded)
         {
-            loaded = loadShadersWater();
-            if (loaded)
-            {
-                LL_INFOS() << "Loaded water shaders." << LL_ENDL;
-            }
-            else
-            {
-                LL_WARNS() << "Failed to load water shaders." << LL_ENDL;
-                llassert(loaded);
-            }
+            LL_INFOS() << "Loaded windlight shaders." << LL_ENDL;
         }
-
-        if (loaded)
+        else
         {
-            loaded = loadShadersWindLight();
-            if (loaded)
-            {
-                LL_INFOS() << "Loaded windlight shaders." << LL_ENDL;
-            }
-            else
-            {
-                LL_WARNS() << "Failed to load windlight shaders." << LL_ENDL;
-                llassert(loaded);
-            }
+            LL_WARNS() << "Failed to load windlight shaders." << LL_ENDL;
+            llassert(loaded);
         }
+    }
 
+    if (loaded)
+    {
+        loaded = loadShadersEffects();
         if (loaded)
         {
-            loaded = loadShadersEffects();
-            if (loaded)
-            {
-                LL_INFOS() << "Loaded effects shaders." << LL_ENDL;
-            }
-            else
-            {
-                LL_WARNS() << "Failed to load effects shaders." << LL_ENDL;
-                llassert(loaded);
-            }
+            LL_INFOS() << "Loaded effects shaders." << LL_ENDL;
         }
-
-        if (loaded)
+        else
         {
-            loaded = loadShadersInterface();
-            if (loaded)
-            {
-                LL_INFOS() << "Loaded interface shaders." << LL_ENDL;
-            }
-            else
-            {
-                LL_WARNS() << "Failed to load interface shaders." << LL_ENDL;
-                llassert(loaded);
-            }
+            LL_WARNS() << "Failed to load effects shaders." << LL_ENDL;
+            llassert(loaded);
         }
+    }
 
+    if (loaded)
+    {
+        loaded = loadShadersInterface();
         if (loaded)
-
         {
-            loaded = loadTransformShaders();
-            if (loaded)
-            {
-                LL_INFOS() << "Loaded transform shaders." << LL_ENDL;
-            }
-            else
-            {
-                LL_WARNS() << "Failed to load transform shaders." << LL_ENDL;
-                llassert(loaded);
-            }
+            LL_INFOS() << "Loaded interface shaders." << LL_ENDL;
+        }
+        else
+        {
+            LL_WARNS() << "Failed to load interface shaders." << LL_ENDL;
+            llassert(loaded);
         }
+    }
 
+    if (loaded)
+
+    {
+        loaded = loadTransformShaders();
         if (loaded)
         {
-            // Load max avatar shaders to set the max level
-            mShaderLevel[SHADER_AVATAR] = 3;
-            mMaxAvatarShaderLevel = 3;
+            LL_INFOS() << "Loaded transform shaders." << LL_ENDL;
+        }
+        else
+        {
+            LL_WARNS() << "Failed to load transform shaders." << LL_ENDL;
+            llassert(loaded);
+        }
+    }
+
+    if (loaded)
+    {
+        // Load max avatar shaders to set the max level
+        mShaderLevel[SHADER_AVATAR] = 3;
+        mMaxAvatarShaderLevel = 3;
                 
             if (loadShadersObject())
-            { //hardware skinning is enabled and rigged attachment shaders loaded correctly
-                BOOL avatar_cloth = gSavedSettings.getBOOL("RenderAvatarCloth");
+        { //hardware skinning is enabled and rigged attachment shaders loaded correctly
+            BOOL avatar_cloth = gSavedSettings.getBOOL("RenderAvatarCloth");
 
-                // cloth is a class3 shader
-                S32 avatar_class = avatar_cloth ? 3 : 1;
+            // cloth is a class3 shader
+            S32 avatar_class = avatar_cloth ? 3 : 1;
                 
-                // Set the actual level
-                mShaderLevel[SHADER_AVATAR] = avatar_class;
+            // Set the actual level
+            mShaderLevel[SHADER_AVATAR] = avatar_class;
 
-                loaded = loadShadersAvatar();
-                llassert(loaded);
+            loaded = loadShadersAvatar();
+            llassert(loaded);
 
-                if (mShaderLevel[SHADER_AVATAR] != avatar_class)
+            if (mShaderLevel[SHADER_AVATAR] != avatar_class)
+            {
+                if(llmax(mShaderLevel[SHADER_AVATAR]-1,0) >= 3)
                 {
-                    if(llmax(mShaderLevel[SHADER_AVATAR]-1,0) >= 3)
-                    {
-                        avatar_cloth = true;
-                    }
-                    else
-                    {
-                        avatar_cloth = false;
-                    }
-                    gSavedSettings.setBOOL("RenderAvatarCloth", avatar_cloth);
+                    avatar_cloth = true;
                 }
+                else
+                {
+                    avatar_cloth = false;
+                }
+                gSavedSettings.setBOOL("RenderAvatarCloth", avatar_cloth);
             }
-            else
-            { //hardware skinning not possible, neither is deferred rendering
-                mShaderLevel[SHADER_AVATAR] = 0;
-                mShaderLevel[SHADER_DEFERRED] = 0;
+        }
+        else
+        { //hardware skinning not possible, neither is deferred rendering
+            mShaderLevel[SHADER_AVATAR] = 0;
+            mShaderLevel[SHADER_DEFERRED] = 0;
 
-                    gSavedSettings.setBOOL("RenderDeferred", FALSE);
-                    gSavedSettings.setBOOL("RenderAvatarCloth", FALSE);
+                gSavedSettings.setBOOL("RenderDeferred", FALSE);
+                gSavedSettings.setBOOL("RenderAvatarCloth", FALSE);
 
-                loadShadersAvatar(); // unloads
+            loadShadersAvatar(); // unloads
 
-                loaded = loadShadersObject();
-                llassert(loaded);
-            }
+            loaded = loadShadersObject();
+            llassert(loaded);
         }
+    }
 
-        if (!loaded)
-        { //some shader absolutely could not load, try to fall back to a simpler setting
-            if (gSavedSettings.getBOOL("WindLightUseAtmosShaders"))
-            { //disable windlight and try again
-                gSavedSettings.setBOOL("WindLightUseAtmosShaders", FALSE);
-                LL_WARNS() << "Falling back to no windlight shaders." << LL_ENDL;
-                reentrance = false;
-                setShaders();
-                return;
-            }
-        }       
-
-        llassert(loaded);
-
-        if (loaded && !loadShadersDeferred())
-        { //everything else succeeded but deferred failed, disable deferred and try again
-            gSavedSettings.setBOOL("RenderDeferred", FALSE);
-            LL_WARNS() << "Falling back to no deferred shaders." << LL_ENDL;
+    if (!loaded)
+    { //some shader absolutely could not load, try to fall back to a simpler setting
+        if (gSavedSettings.getBOOL("WindLightUseAtmosShaders"))
+        { //disable windlight and try again
+            gSavedSettings.setBOOL("WindLightUseAtmosShaders", FALSE);
+            LL_WARNS() << "Falling back to no windlight shaders." << LL_ENDL;
             reentrance = false;
             setShaders();
             return;
         }
+    }       
+
+    llassert(loaded);
+
+    if (loaded && !loadShadersDeferred())
+    { //everything else succeeded but deferred failed, disable deferred and try again
+        gSavedSettings.setBOOL("RenderDeferred", FALSE);
+        LL_WARNS() << "Falling back to no deferred shaders." << LL_ENDL;
+        reentrance = false;
+        setShaders();
+        return;
+    }
 
-    // gPipeline.mVertexShadersEnabled = FALSE;
     // gPipeline.mVertexShadersLoaded = 0;
     
     if (gViewerWindow)
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index 10631afd13..6462ec019b 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -608,12 +608,6 @@ public:
 		{
 			LLTrace::Recording& last_frame_recording = LLTrace::get_frame_recording().getLastRecording();
 
-			if (gPipeline.getUseVertexShaders() == 0)
-			{
-				addText(xpos, ypos, "Shaders Disabled");
-				ypos += y_inc;
-			}
-
 			if (gGLManager.mHasATIMemInfo)
 			{
 				S32 meminfo[4];
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index 8881b78593..63e101a290 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -376,7 +376,6 @@ LLPipeline::LLPipeline() :
 	mNumVisibleFaces(0),
 
 	mInitialized(false),
-	mVertexShadersEnabled(false),
 	mVertexShadersLoaded(0),
 	mTransformFeedbackPrimitives(0),
 	mRenderDebugFeatureMask(0),
@@ -1364,10 +1363,7 @@ void LLPipeline::restoreGL()
 {
 	assertInitialized();
 
-	if (mVertexShadersEnabled)
-	{
-		LLViewerShaderMgr::instance()->setShaders();
-	}
+	LLViewerShaderMgr::instance()->setShaders();
 
 	for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); 
 			iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h
index d82f8bd64b..50a730077e 100644
--- a/indra/newview/pipeline.h
+++ b/indra/newview/pipeline.h
@@ -226,7 +226,6 @@ public:
 	S32			getMaxLightingDetail() const;
 		
 	void		setUseVertexShaders(bool use_shaders);
-	bool		getUseVertexShaders() const { return mVertexShadersEnabled; }
 	bool		canUseVertexShaders();
 	bool		canUseWindLightShaders() const;
 	bool		canUseWindLightShadersOnObjects() const;
@@ -702,7 +701,6 @@ public:
     LLVector4			mTransformedMoonDir;
 
 	bool					mInitialized;
-	bool					mVertexShadersEnabled;
 	S32						mVertexShadersLoaded; // 0 = no, 1 = yes, -1 = failed
 
 	U32						mTransformFeedbackPrimitives; //number of primitives expected to be generated by transform feedback
-- 
cgit v1.2.3


From 7a5ef999d01b05dd1574004d167dbd693cc56d1d Mon Sep 17 00:00:00 2001
From: Dave Houlton <euclid@lindenlab.com>
Date: Tue, 30 Nov 2021 15:32:54 -0700
Subject: SL-16386 consolidate all VertexShader capability checks to a single
 LLPipeline::shadersLoaded()

---
 indra/newview/lldrawpoolavatar.cpp  |  6 +++---
 indra/newview/lldrawpoolbump.cpp    |  4 ++--
 indra/newview/lldrawpooltree.cpp    |  2 +-
 indra/newview/lldrawpoolwlsky.cpp   |  2 +-
 indra/newview/llviewershadermgr.cpp |  6 ++----
 indra/newview/llviewerstats.cpp     |  2 +-
 indra/newview/llvovolume.cpp        |  6 +++---
 indra/newview/pipeline.cpp          | 27 +++++++++------------------
 indra/newview/pipeline.h            |  5 ++---
 9 files changed, 24 insertions(+), 36 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/lldrawpoolavatar.cpp b/indra/newview/lldrawpoolavatar.cpp
index f9fdbac9ab..fa67b9902d 100644
--- a/indra/newview/lldrawpoolavatar.cpp
+++ b/indra/newview/lldrawpoolavatar.cpp
@@ -516,7 +516,7 @@ void LLDrawPoolAvatar::beginRigid()
 {
     LL_PROFILE_ZONE_SCOPED
 
-	if (gPipeline.canUseVertexShaders())
+	if (gPipeline.shadersLoaded())
 	{
 		if (LLPipeline::sUnderWaterRender)
 		{
@@ -664,7 +664,7 @@ void LLDrawPoolAvatar::beginSkinned()
 	}
 	else
 	{
-		if(gPipeline.canUseVertexShaders())
+		if(gPipeline.shadersLoaded())
 		{
 			// software skinning, use a basic shader for windlight.
 			// TODO: find a better fallback method for software skinning.
@@ -698,7 +698,7 @@ void LLDrawPoolAvatar::endSkinned()
 	}
 	else
 	{
-		if(gPipeline.canUseVertexShaders())
+		if(gPipeline.shadersLoaded())
 		{
 			// software skinning, use a basic shader for windlight.
 			// TODO: find a better fallback method for software skinning.
diff --git a/indra/newview/lldrawpoolbump.cpp b/indra/newview/lldrawpoolbump.cpp
index 9d19ff44db..dc52fc7680 100644
--- a/indra/newview/lldrawpoolbump.cpp
+++ b/indra/newview/lldrawpoolbump.cpp
@@ -1510,7 +1510,7 @@ void LLDrawPoolInvisible::render(S32 pass)
 { //render invisiprims
 	LL_RECORD_BLOCK_TIME(FTM_RENDER_INVISIBLE);
   
-	if (gPipeline.canUseVertexShaders())
+	if (gPipeline.shadersLoaded())
 	{
 		gOcclusionProgram.bind();
 	}
@@ -1522,7 +1522,7 @@ void LLDrawPoolInvisible::render(S32 pass)
 	gGL.setColorMask(true, false);
 	glStencilMask(0xFFFFFFFF);
 
-	if (gPipeline.canUseVertexShaders())
+	if (gPipeline.shadersLoaded())
 	{
 		gOcclusionProgram.unbind();
 	}
diff --git a/indra/newview/lldrawpooltree.cpp b/indra/newview/lldrawpooltree.cpp
index c84178c6cd..ac957f1cbd 100644
--- a/indra/newview/lldrawpooltree.cpp
+++ b/indra/newview/lldrawpooltree.cpp
@@ -68,7 +68,7 @@ void LLDrawPoolTree::beginRenderPass(S32 pass)
 		shader = &gTreeProgram;
 	}
 
-	if (gPipeline.canUseVertexShaders())
+	if (gPipeline.shadersLoaded())
 	{
 		shader->bind();
 		shader->setMinimumAlpha(0.5f);
diff --git a/indra/newview/lldrawpoolwlsky.cpp b/indra/newview/lldrawpoolwlsky.cpp
index 44b12ceaca..80a65947f6 100644
--- a/indra/newview/lldrawpoolwlsky.cpp
+++ b/indra/newview/lldrawpoolwlsky.cpp
@@ -460,7 +460,7 @@ void LLDrawPoolWLSky::renderHeavenlyBodies()
 	LLFace * face = gSky.mVOSkyp->mFace[LLVOSky::FACE_SUN];
 
     F32 blend_factor = LLEnvironment::instance().getCurrentSky()->getBlendFactor();
-    bool can_use_vertex_shaders = gPipeline.canUseVertexShaders();
+    bool can_use_vertex_shaders = gPipeline.shadersLoaded();
     bool can_use_windlight_shaders = gPipeline.canUseWindLightShaders();
 
 
diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp
index 26592adc0a..8669abf284 100644
--- a/indra/newview/llviewershadermgr.cpp
+++ b/indra/newview/llviewershadermgr.cpp
@@ -558,7 +558,7 @@ void LLViewerShaderMgr::setShaders()
         return;
     }
 
-    gPipeline.mVertexShadersLoaded = 1;
+    gPipeline.mShadersLoaded = true;
 
     // Load all shaders to set max levels
     loaded = loadShadersEnvironment();
@@ -714,8 +714,6 @@ void LLViewerShaderMgr::setShaders()
         return;
     }
 
-    // gPipeline.mVertexShadersLoaded = 0;
-    
     if (gViewerWindow)
     {
         gViewerWindow->setCursor(UI_CURSOR_ARROW);
@@ -845,7 +843,7 @@ void LLViewerShaderMgr::unloadShaders()
 	mShaderLevel[SHADER_WINDLIGHT] = 0;
 	mShaderLevel[SHADER_TRANSFORM] = 0;
 
-	gPipeline.mVertexShadersLoaded = 0;
+	gPipeline.mShadersLoaded = false;
 }
 
 BOOL LLViewerShaderMgr::loadBasicShaders()
diff --git a/indra/newview/llviewerstats.cpp b/indra/newview/llviewerstats.cpp
index 1fda2fb20e..37b6244635 100644
--- a/indra/newview/llviewerstats.cpp
+++ b/indra/newview/llviewerstats.cpp
@@ -541,7 +541,7 @@ void send_viewer_stats(bool include_preferences)
 	{
 		shader_level = 2;
 	}
-	else if (gPipeline.canUseVertexShaders())
+	else if (gPipeline.shadersLoaded())
 	{
 		shader_level = 1;
 	}
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index 464e6efd2e..2f554bc9b8 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -6567,7 +6567,7 @@ U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace
 				{
 					registerFace(group, facep, LLRenderPass::PASS_ALPHA);
 				}
-				else if (gPipeline.canUseVertexShaders()
+				else if (gPipeline.shadersLoaded()
 					&& LLPipeline::sRenderBump 
 					&& te->getShiny() 
 					&& can_be_shiny)
@@ -6602,7 +6602,7 @@ U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace
 					registerFace(group, facep, LLRenderPass::PASS_ALPHA);
 				}
 			}
-			else if (gPipeline.canUseVertexShaders()
+			else if (gPipeline.shadersLoaded()
 				&& LLPipeline::sRenderBump 
 				&& te->getShiny() 
 				&& can_be_shiny)
@@ -6683,7 +6683,7 @@ U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace
 				}
 				
 				
-				if (!gPipeline.canUseVertexShaders() && 
+				if (!gPipeline.shadersLoaded() && 
 					!is_alpha && 
 					te->getShiny() && 
 					LLPipeline::sRenderBump)
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index 63e101a290..c122b4f43e 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -376,7 +376,7 @@ LLPipeline::LLPipeline() :
 	mNumVisibleFaces(0),
 
 	mInitialized(false),
-	mVertexShadersLoaded(0),
+	mShadersLoaded(false),
 	mTransformFeedbackPrimitives(0),
 	mRenderDebugFeatureMask(0),
 	mRenderDebugMask(0),
@@ -737,7 +737,7 @@ void LLPipeline::resizeShadowTexture()
 
 void LLPipeline::resizeScreenTexture()
 {
-	if (gPipeline.canUseVertexShaders() && assertInitialized())
+	if (gPipeline.shadersLoaded())
 	{
 		GLuint resX = gViewerWindow->getWorldViewWidthRaw();
 		GLuint resY = gViewerWindow->getWorldViewHeightRaw();
@@ -748,8 +748,8 @@ void LLPipeline::resizeScreenTexture()
             releaseShadowTargets();
 		    allocateScreenBuffer(resX,resY);
             gResizeScreenTexture = FALSE;
-				}
-			}
+		}
+	}
 }
 
 void LLPipeline::allocatePhysicsBuffer()
@@ -1380,17 +1380,9 @@ void LLPipeline::restoreGL()
 	}
 }
 
-
-bool LLPipeline::canUseVertexShaders()
+bool LLPipeline::shadersLoaded()
 {
-	if ((assertInitialized() && mVertexShadersLoaded != 1) )
-	{
-		return false;
-	}
-	else
-	{
-		return true;
-	}
+    return (assertInitialized() && mShadersLoaded);
 }
 
 bool LLPipeline::canUseWindLightShaders() const
@@ -1413,8 +1405,7 @@ bool LLPipeline::canUseAntiAliasing() const
 void LLPipeline::unloadShaders()
 {
 	LLViewerShaderMgr::instance()->unloadShaders();
-
-	mVertexShadersLoaded = 0;
+	mShadersLoaded = false;
 }
 
 void LLPipeline::assertInitializedDoError()
@@ -2351,7 +2342,7 @@ void LLPipeline::updateCull(LLCamera& camera, LLCullResult& result, S32 water_cl
 
 	sCull->clear();
 
-	bool to_texture = LLPipeline::sUseOcclusion > 1 && gPipeline.canUseVertexShaders();
+	bool to_texture = LLPipeline::sUseOcclusion > 1 && gPipeline.shadersLoaded();
 
 	if (to_texture)
 	{
@@ -2385,7 +2376,7 @@ void LLPipeline::updateCull(LLCamera& camera, LLCullResult& result, S32 water_cl
 	LLGLDepthTest depth(GL_TRUE, GL_FALSE);
 
 	bool bound_shader = false;
-	if (gPipeline.canUseVertexShaders() && LLGLSLShader::sCurBoundShader == 0)
+	if (gPipeline.shadersLoaded() && LLGLSLShader::sCurBoundShader == 0)
 	{ //if no shader is currently bound, use the occlusion shader instead of fixed function if we can
 		// (shadow render uses a special shader that clamps to clip planes)
 		bound_shader = true;
diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h
index 50a730077e..3ac3e3ce01 100644
--- a/indra/newview/pipeline.h
+++ b/indra/newview/pipeline.h
@@ -225,8 +225,7 @@ public:
 	S32			getLightingDetail() const { return mLightingDetail; }
 	S32			getMaxLightingDetail() const;
 		
-	void		setUseVertexShaders(bool use_shaders);
-	bool		canUseVertexShaders();
+	bool		shadersLoaded();
 	bool		canUseWindLightShaders() const;
 	bool		canUseWindLightShadersOnObjects() const;
 	bool		canUseAntiAliasing() const;
@@ -701,7 +700,7 @@ public:
     LLVector4			mTransformedMoonDir;
 
 	bool					mInitialized;
-	S32						mVertexShadersLoaded; // 0 = no, 1 = yes, -1 = failed
+	bool					mShadersLoaded;
 
 	U32						mTransformFeedbackPrimitives; //number of primitives expected to be generated by transform feedback
 protected:
-- 
cgit v1.2.3


From abd7d80048529fd971e1b65ea3afe0f7e78bd356 Mon Sep 17 00:00:00 2001
From: Dave Houlton <euclid@lindenlab.com>
Date: Tue, 30 Nov 2021 17:15:27 -0700
Subject: SL-16386 skip void return

---
 indra/newview/llvosurfacepatch.cpp | 1 -
 1 file changed, 1 deletion(-)

(limited to 'indra')

diff --git a/indra/newview/llvosurfacepatch.cpp b/indra/newview/llvosurfacepatch.cpp
index 8fbecbc7d7..b0af565867 100644
--- a/indra/newview/llvosurfacepatch.cpp
+++ b/indra/newview/llvosurfacepatch.cpp
@@ -60,7 +60,6 @@ public:
 	void setupVertexBuffer(U32 data_mask)
 	{	
 		LLVertexBuffer::setupVertexBuffer(data_mask & ~(MAP_TEXCOORD2 | MAP_TEXCOORD3));
-		return;
 	}
 };
 
-- 
cgit v1.2.3


From 06c94c83feac1f7c3ee3e71d9654f6acd8679f24 Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Wed, 1 Dec 2021 22:13:17 +0200
Subject: SL-16420 Upload's physics LODs are broken in preview

---
 indra/newview/llmodelpreview.cpp | 17 +++++++----------
 1 file changed, 7 insertions(+), 10 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp
index 566a89e24d..1ce15e04da 100644
--- a/indra/newview/llmodelpreview.cpp
+++ b/indra/newview/llmodelpreview.cpp
@@ -2661,6 +2661,8 @@ void LLModelPreview::genBuffers(S32 lod, bool include_skin_weights)
                 *(index_strider++) = vf.mIndices[i];
             }
 
+            vb->flush();
+
             mVertexBuffer[lod][mdl].push_back(vb);
 
             vertex_count += num_vertices;
@@ -3136,6 +3138,11 @@ BOOL LLModelPreview::render()
             genBuffers(mPreviewLOD, skin_weight);
         }
 
+        if (physics && mVertexBuffer[LLModel::LOD_PHYSICS].empty())
+        {
+            genBuffers(LLModel::LOD_PHYSICS, false);
+        }
+
         if (!skin_weight)
         {
             for (LLMeshUploadThread::instance_list::iterator iter = mUploadData.begin(); iter != mUploadData.end(); ++iter)
@@ -3290,11 +3297,6 @@ BOOL LLModelPreview::render()
 
                         if (render_mesh)
                         {
-                            if (mVertexBuffer[LLModel::LOD_PHYSICS].empty())
-                            {
-                                genBuffers(LLModel::LOD_PHYSICS, false);
-                            }
-
                             U32 num_models = mVertexBuffer[LLModel::LOD_PHYSICS][model].size();
                             if (pass > 0){
                                 for (U32 i = 0; i < num_models; ++i)
@@ -3358,11 +3360,6 @@ BOOL LLModelPreview::render()
 
                                 if (physics.mHull.empty())
                                 {
-                                    if (mVertexBuffer[LLModel::LOD_PHYSICS].empty())
-                                    {
-                                        genBuffers(LLModel::LOD_PHYSICS, false);
-                                    }
-
                                     U32 num_models = mVertexBuffer[LLModel::LOD_PHYSICS][model].size();
                                     for (U32 v = 0; v < num_models; ++v)
                                     {
-- 
cgit v1.2.3


From 7929230c045f2daf6de53e880f3d716044b96792 Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Thu, 2 Dec 2021 01:14:07 +0200
Subject: mac build fix

remove unused variable
---
 indra/llrender/llrender.cpp | 19 +------------------
 indra/llrender/llrender.h   |  9 ---------
 2 files changed, 1 insertion(+), 27 deletions(-)

(limited to 'indra')

diff --git a/indra/llrender/llrender.cpp b/indra/llrender/llrender.cpp
index c426c769f3..235f8a8eb0 100644
--- a/indra/llrender/llrender.cpp
+++ b/indra/llrender/llrender.cpp
@@ -71,18 +71,6 @@ static const GLint sGLAddressMode[] =
 	GL_CLAMP_TO_EDGE
 };
 
-static const GLenum sGLCompareFunc[] =
-{
-	GL_NEVER,
-	GL_ALWAYS,
-	GL_LESS,
-	GL_LEQUAL,
-	GL_EQUAL,
-	GL_NOTEQUAL,
-	GL_GEQUAL,
-	GL_GREATER
-};
-
 const U32 immediate_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_COLOR | LLVertexBuffer::MAP_TEXCOORD0;
 
 static const GLenum sGLBlendFactor[] =
@@ -102,10 +90,7 @@ static const GLenum sGLBlendFactor[] =
 };
 
 LLTexUnit::LLTexUnit(S32 index)
-	: mCurrTexType(TT_NONE), mCurrBlendType(TB_MULT), 
-	mCurrColorOp(TBO_MULT), mCurrAlphaOp(TBO_MULT),
-	mCurrColorSrc1(TBS_TEX_COLOR), mCurrColorSrc2(TBS_PREV_COLOR),
-	mCurrAlphaSrc1(TBS_TEX_ALPHA), mCurrAlphaSrc2(TBS_PREV_ALPHA),
+	: mCurrTexType(TT_NONE),
     mCurrColorScale(1), mCurrAlphaScale(1), mCurrTexture(0), mTexColorSpace(TCS_LINEAR),
 	mHasMipMaps(false),
 	mIndex(index)
@@ -847,8 +832,6 @@ LLRender::LLRender()
 		mCurrColorMask[i] = true;
 	}
 
-	mCurrAlphaFunc = CF_DEFAULT;
-	mCurrAlphaFuncVal = 0.01f;
 	mCurrBlendColorSFactor = BF_UNDEF;
 	mCurrBlendAlphaSFactor = BF_UNDEF;
 	mCurrBlendColorDFactor = BF_UNDEF;
diff --git a/indra/llrender/llrender.h b/indra/llrender/llrender.h
index cdf4075244..e2489876e4 100644
--- a/indra/llrender/llrender.h
+++ b/indra/llrender/llrender.h
@@ -214,13 +214,6 @@ protected:
 	const S32			mIndex;
 	U32					mCurrTexture;
 	eTextureType		mCurrTexType;
-	eTextureBlendType	mCurrBlendType;
-	eTextureBlendOp		mCurrColorOp;
-	eTextureBlendSrc	mCurrColorSrc1;
-	eTextureBlendSrc	mCurrColorSrc2;
-	eTextureBlendOp		mCurrAlphaOp;
-	eTextureBlendSrc	mCurrAlphaSrc1;
-	eTextureBlendSrc	mCurrAlphaSrc2;
     eTextureColorSpace  mTexColorSpace;
 	S32					mCurrColorScale;
 	S32					mCurrAlphaScale;
@@ -481,8 +474,6 @@ private:
 	U32				mMode;
 	U32				mCurrTextureUnitIndex;
 	bool				mCurrColorMask[4];
-	eCompareFunc			mCurrAlphaFunc;
-	F32				mCurrAlphaFuncVal;
 
 	LLPointer<LLVertexBuffer>	mBuffer;
 	LLStrider<LLVector3>		mVerticesp;
-- 
cgit v1.2.3


From 1cd1d3fbe2a5aae2e5736bb62c1b4aa413eba7fb Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Thu, 2 Dec 2021 02:28:29 +0200
Subject: SL-16420 Upload's physics LODs are broken in preview #2

---
 indra/newview/llmodelpreview.cpp | 5 +++++
 1 file changed, 5 insertions(+)

(limited to 'indra')

diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp
index 1ce15e04da..e22a04006e 100644
--- a/indra/newview/llmodelpreview.cpp
+++ b/indra/newview/llmodelpreview.cpp
@@ -3204,6 +3204,7 @@ BOOL LLModelPreview::render()
                         glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
                         glLineWidth(1.f);
                     }
+                    buffer->flush();
                 }
                 gGL.popMatrix();
             }
@@ -3316,6 +3317,8 @@ BOOL LLModelPreview::render()
 
                                     glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
                                     glLineWidth(1.f);
+
+                                    buffer->flush();
                                 }
                             }
                         }
@@ -3386,6 +3389,8 @@ BOOL LLModelPreview::render()
                                                 buffer->draw(LLRender::POINTS, 3, i);
                                             }
                                         }
+
+                                        buffer->flush();
                                     }
                                 }
                             }
-- 
cgit v1.2.3


From 2ed229473d7473593e8d502003991487bb622018 Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Thu, 2 Dec 2021 17:35:03 +0200
Subject: SL-14403 Remove unused shader binds

remains from glod
---
 indra/newview/llmodelpreview.cpp | 12 ------------
 1 file changed, 12 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp
index e22a04006e..907b5ec418 100644
--- a/indra/newview/llmodelpreview.cpp
+++ b/indra/newview/llmodelpreview.cpp
@@ -1691,12 +1691,6 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d
         end = which_lod;
     }
 
-    LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
-    if (shader)
-    {
-        shader->unbind();
-    }
-
     for (S32 lod = start; lod >= end; --lod)
     {
         if (which_lod == -1)
@@ -1855,12 +1849,6 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d
     }
 
     mResourceCost = calcResourceCost();
-
-    LLVertexBuffer::unbind();
-    if (shader)
-    {
-        shader->bind();
-    }
 }
 
 void LLModelPreview::updateStatusMessages()
-- 
cgit v1.2.3


From 511de439a35ddb22c6f174b85c599d4881b9c139 Mon Sep 17 00:00:00 2001
From: Dave Parks <davep@lindenlab.com>
Date: Thu, 2 Dec 2021 20:11:43 +0000
Subject: =?UTF-8?q?SL-16405=20Remove=20=E2=80=9Cpass=20=3D=3D=20<magic=20n?=
 =?UTF-8?q?umber>=E2=80=9D=20anti-pattern=20from=20various=20drawpools.?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 indra/newview/lldrawpoolalpha.cpp  | 352 ++++++++------------
 indra/newview/lldrawpoolalpha.h    |  16 +-
 indra/newview/lldrawpoolbump.cpp   | 346 ++++++-------------
 indra/newview/lldrawpoolbump.h     |  27 +-
 indra/newview/lldrawpoolsimple.cpp | 659 ++++++++++---------------------------
 indra/newview/lldrawpoolsimple.h   |  34 +-
 6 files changed, 437 insertions(+), 997 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/lldrawpoolalpha.cpp b/indra/newview/lldrawpoolalpha.cpp
index 9b298b120a..cecdefd7e8 100644
--- a/indra/newview/lldrawpoolalpha.cpp
+++ b/indra/newview/lldrawpoolalpha.cpp
@@ -80,213 +80,162 @@ void LLDrawPoolAlpha::prerender()
 
 S32 LLDrawPoolAlpha::getNumPostDeferredPasses() 
 { 
-	if (LLPipeline::sImpostorRender)
-	{ //skip depth buffer filling pass when rendering impostors
-		return 1;
-	}
-	else if (gSavedSettings.getBOOL("RenderDepthOfField"))
-	{
-		return 2; 
-	}
-	else
-	{
-		return 1;
-	}
+    return 1;
 }
 
-void LLDrawPoolAlpha::beginPostDeferredPass(S32 pass) 
-{ 
-    LL_PROFILE_ZONE_SCOPED;
-
-    F32 gamma = gSavedSettings.getF32("RenderDeferredDisplayGamma");
+// set some common parameters on the given shader to prepare for alpha rendering
+static void prepare_alpha_shader(LLGLSLShader* shader, bool textureGamma)
+{
+    static LLCachedControl<F32> displayGamma(gSavedSettings, "RenderDeferredDisplayGamma");
+    F32 gamma = displayGamma;
 
-    emissive_shader[0] = (LLPipeline::sUnderWaterRender) ? &gObjectEmissiveWaterProgram : &gObjectEmissiveProgram;
-    emissive_shader[1] = emissive_shader[0]->mRiggedVariant;
+    shader->bind();
+    shader->uniform1i(LLShaderMgr::NO_ATMO, (LLPipeline::sRenderingHUDs) ? 1 : 0);
+    shader->uniform1f(LLShaderMgr::DISPLAY_GAMMA, (gamma > 0.1f) ? 1.0f / gamma : (1.0f / 2.2f));
 
-    for (int i = 0; i < 2; ++i)
+    if (LLPipeline::sImpostorRender)
     {
-        emissive_shader[i]->bind();
-        emissive_shader[i]->uniform1i(LLShaderMgr::NO_ATMO, (LLPipeline::sRenderingHUDs) ? 1 : 0);
-        emissive_shader[i]->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 2.2f);
-        emissive_shader[i]->uniform1f(LLShaderMgr::DISPLAY_GAMMA, (gamma > 0.1f) ? 1.0f / gamma : (1.0f / 2.2f));
+        shader->setMinimumAlpha(0.5f);
+    }
+    else
+    {
+        shader->setMinimumAlpha(0.f);
+    }
+    if (textureGamma)
+    {
+        shader->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 2.2f);
     }
 
-	if (pass == 0)
-	{
-        fullbright_shader[0] = (LLPipeline::sImpostorRender) ? &gDeferredFullbrightProgram :
-                (LLPipeline::sUnderWaterRender) ? &gDeferredFullbrightWaterProgram : &gDeferredFullbrightProgram;
-        fullbright_shader[1] = fullbright_shader[0]->mRiggedVariant;
- 
-        for (int i = 0; i < 2; ++i)
-        {
-            fullbright_shader[i]->bind();
-            fullbright_shader[i]->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 2.2f);
-            fullbright_shader[i]->uniform1f(LLShaderMgr::DISPLAY_GAMMA, (gamma > 0.1f) ? 1.0f / gamma : (1.0f / 2.2f));
-            fullbright_shader[i]->uniform1i(LLShaderMgr::NO_ATMO, LLPipeline::sRenderingHUDs ? 1 : 0);
-            fullbright_shader[i]->unbind();
-        }
-
-        simple_shader[0] = (LLPipeline::sImpostorRender) ? &gDeferredAlphaImpostorProgram :
-                (LLPipeline::sUnderWaterRender) ? &gDeferredAlphaWaterProgram : &gDeferredAlphaProgram;
-        simple_shader[1] = simple_shader[0]->mRiggedVariant;
-
-		//prime simple shader (loads shadow relevant uniforms)
-        for (int i = 0; i < 2; ++i)
-        {
-            gPipeline.bindDeferredShader(*simple_shader[i]);
-            simple_shader[i]->uniform1f(LLShaderMgr::DISPLAY_GAMMA, (gamma > 0.1f) ? 1.0f / gamma : (1.0f / 2.2f));
-            simple_shader[i]->uniform1i(LLShaderMgr::NO_ATMO, LLPipeline::sRenderingHUDs ? 1 : 0);
-        }
-	}
-	else if (!LLPipeline::sImpostorRender)
-	{
-		//update depth buffer sampler
-		gPipeline.mScreen.flush();
-		gPipeline.mDeferredDepth.copyContents(gPipeline.mDeferredScreen, 0, 0, gPipeline.mDeferredScreen.getWidth(), gPipeline.mDeferredScreen.getHeight(),
-							0, 0, gPipeline.mDeferredDepth.getWidth(), gPipeline.mDeferredDepth.getHeight(), GL_DEPTH_BUFFER_BIT, GL_NEAREST);	
-		gPipeline.mDeferredDepth.bindTarget();
-		simple_shader[0] = fullbright_shader[0] = &gObjectFullbrightAlphaMaskProgram;
-        simple_shader[1] = fullbright_shader[1] = simple_shader[0]->mRiggedVariant;
-        
-        for (int i = 0; i < 2; ++i)
-        {
-            simple_shader[i]->bind();
-            simple_shader[i]->setMinimumAlpha(0.33f);
-        }
-	}
-
-	deferred_render = TRUE;
-	if (mShaderLevel > 0)
-	{
-		// Start out with no shaders.
-		target_shader = NULL;
-	}
-	gPipeline.enableLightsDynamic();
+    //also prepare rigged variant
+    if (shader->mRiggedVariant && shader->mRiggedVariant != shader)
+    { 
+        prepare_alpha_shader(shader->mRiggedVariant, textureGamma);
+    }
 }
 
-void LLDrawPoolAlpha::endPostDeferredPass(S32 pass) 
+void LLDrawPoolAlpha::renderPostDeferred(S32 pass) 
 { 
     LL_PROFILE_ZONE_SCOPED;
+    deferred_render = TRUE;
 
-	if (pass == 1 && !LLPipeline::sImpostorRender)
-	{
-		gPipeline.mDeferredDepth.flush();
-		gPipeline.mScreen.bindTarget();
-		LLGLSLShader::sCurBoundShaderPtr->unbind();
-	}
+    // first pass, regular forward alpha rendering
+    {
+        emissive_shader = (LLPipeline::sUnderWaterRender) ? &gObjectEmissiveWaterProgram : &gObjectEmissiveProgram;
+        prepare_alpha_shader(emissive_shader, true);
 
-	deferred_render = FALSE;
-	endRenderPass(pass);
+        fullbright_shader = (LLPipeline::sImpostorRender) ? &gDeferredFullbrightProgram :
+            (LLPipeline::sUnderWaterRender) ? &gDeferredFullbrightWaterProgram : &gDeferredFullbrightProgram;
+        prepare_alpha_shader(fullbright_shader, true);
+
+        simple_shader = (LLPipeline::sImpostorRender) ? &gDeferredAlphaImpostorProgram :
+            (LLPipeline::sUnderWaterRender) ? &gDeferredAlphaWaterProgram : &gDeferredAlphaProgram;
+        prepare_alpha_shader(simple_shader, false);
+        
+        forwardRender();
+    }
+
+    // second pass, render to depth for depth of field effects
+    if (!LLPipeline::sImpostorRender && gSavedSettings.getBOOL("RenderDepthOfField"))
+    { 
+        //update depth buffer sampler
+        gPipeline.mScreen.flush();
+        gPipeline.mDeferredDepth.copyContents(gPipeline.mDeferredScreen, 0, 0, gPipeline.mDeferredScreen.getWidth(), gPipeline.mDeferredScreen.getHeight(),
+            0, 0, gPipeline.mDeferredDepth.getWidth(), gPipeline.mDeferredDepth.getHeight(), GL_DEPTH_BUFFER_BIT, GL_NEAREST);
+        gPipeline.mDeferredDepth.bindTarget();
+        simple_shader = fullbright_shader = &gObjectFullbrightAlphaMaskProgram;
+
+        simple_shader->bind();
+        simple_shader->setMinimumAlpha(0.33f);
+
+        // mask off color buffer writes as we're only writing to depth buffer
+        gGL.setColorMask(false, false);
+
+        // If the face is more than 90% transparent, then don't update the Depth buffer for Dof
+        // We don't want the nearly invisible objects to cause of DoF effects
+        renderAlpha(getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX | LLVertexBuffer::MAP_TANGENT | LLVertexBuffer::MAP_TEXCOORD1 | LLVertexBuffer::MAP_TEXCOORD2, 
+            true); // <--- discard mostly transparent faces
+
+        gPipeline.mDeferredDepth.flush();
+        gPipeline.mScreen.bindTarget();
+        gGL.setColorMask(true, false);
+    }
+
+    renderDebugAlpha();
+
+    deferred_render = FALSE;
 }
 
-void LLDrawPoolAlpha::renderPostDeferred(S32 pass) 
-{ 
-    LL_PROFILE_ZONE_SCOPED;
-	render(pass); 
+//set some generic parameters for forward (non-deferred) rendering
+static void prepare_forward_shader(LLGLSLShader* shader, F32 minimum_alpha)
+{
+    shader->bind();
+    shader->setMinimumAlpha(minimum_alpha);
+    shader->uniform1i(LLShaderMgr::NO_ATMO, LLPipeline::sRenderingHUDs ? 1 : 0);
+
+    //also prepare rigged variant
+    if (shader->mRiggedVariant && shader->mRiggedVariant != shader)
+    {
+        prepare_forward_shader(shader->mRiggedVariant, minimum_alpha);
+    }
 }
 
-void LLDrawPoolAlpha::beginRenderPass(S32 pass)
+void LLDrawPoolAlpha::render(S32 pass)
 {
-    LL_PROFILE_ZONE_SCOPED;
-	
-    simple_shader[0]     = (LLPipeline::sImpostorRender)   ? &gObjectSimpleImpostorProgram  :
-                        (LLPipeline::sUnderWaterRender) ? &gObjectSimpleWaterProgram     : &gObjectSimpleProgram;
+    LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA);
 
-    fullbright_shader[0] = (LLPipeline::sImpostorRender)   ? &gObjectFullbrightProgram      :
-                        (LLPipeline::sUnderWaterRender) ? &gObjectFullbrightWaterProgram : &gObjectFullbrightProgram;
+    simple_shader = (LLPipeline::sImpostorRender) ? &gObjectSimpleImpostorProgram :
+        (LLPipeline::sUnderWaterRender) ? &gObjectSimpleWaterProgram : &gObjectSimpleProgram;
 
-    emissive_shader[0]   = (LLPipeline::sImpostorRender)   ? &gObjectEmissiveProgram        :
-                        (LLPipeline::sUnderWaterRender) ? &gObjectEmissiveWaterProgram   : &gObjectEmissiveProgram;
+    fullbright_shader = (LLPipeline::sImpostorRender) ? &gObjectFullbrightProgram :
+        (LLPipeline::sUnderWaterRender) ? &gObjectFullbrightWaterProgram : &gObjectFullbrightProgram;
 
-    simple_shader[1] = simple_shader[0]->mRiggedVariant;
-    fullbright_shader[1] = fullbright_shader[0]->mRiggedVariant;
-    emissive_shader[1] = emissive_shader[0]->mRiggedVariant;
+    emissive_shader = (LLPipeline::sImpostorRender) ? &gObjectEmissiveProgram :
+        (LLPipeline::sUnderWaterRender) ? &gObjectEmissiveWaterProgram : &gObjectEmissiveProgram;
 
+    F32 minimum_alpha = 0.f;
     if (LLPipeline::sImpostorRender)
-	{
-        for (int i = 0; i < 2; ++i)
-        {
-            fullbright_shader[i]->bind();
-            fullbright_shader[i]->setMinimumAlpha(0.5f);
-            fullbright_shader[i]->uniform1i(LLShaderMgr::NO_ATMO, LLPipeline::sRenderingHUDs ? 1 : 0);
-            simple_shader[i]->bind();
-            simple_shader[i]->setMinimumAlpha(0.5f);
-            simple_shader[i]->uniform1i(LLShaderMgr::NO_ATMO, LLPipeline::sRenderingHUDs ? 1 : 0);
-        }
-	}
-    else
-	{
-        for (int i = 0; i < 2; ++i)
-        {
-            fullbright_shader[i]->bind();
-            fullbright_shader[i]->setMinimumAlpha(0.f);
-            fullbright_shader[i]->uniform1i(LLShaderMgr::NO_ATMO, LLPipeline::sRenderingHUDs ? 1 : 0);
-            simple_shader[i]->bind();
-            simple_shader[i]->setMinimumAlpha(0.f);
-            simple_shader[i]->uniform1i(LLShaderMgr::NO_ATMO, LLPipeline::sRenderingHUDs ? 1 : 0);
-        }
+    {
+        minimum_alpha = 0.5f;
     }
-	gPipeline.enableLightsDynamic();
+    prepare_forward_shader(fullbright_shader, minimum_alpha);
+    prepare_forward_shader(simple_shader, minimum_alpha);
 
-    LLGLSLShader::bindNoShader();
-}
-
-void LLDrawPoolAlpha::endRenderPass( S32 pass )
-{
-    LL_PROFILE_ZONE_SCOPED;
-	LLRenderPass::endRenderPass(pass);
+    forwardRender();
 
-	if(gPipeline.canUseWindLightShaders()) 
-	{
-		LLGLSLShader::bindNoShader();
-	}
+    renderDebugAlpha();
 }
 
-void LLDrawPoolAlpha::render(S32 pass)
+void LLDrawPoolAlpha::forwardRender()
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA);
+    gPipeline.enableLightsDynamic();
 
-	LLGLSPipelineAlpha gls_pipeline_alpha;
+    LLGLSPipelineAlpha gls_pipeline_alpha;
 
-	if (deferred_render && pass == 1)
-	{ //depth only
-		gGL.setColorMask(false, false);
-	}
-	else
-	{
-		gGL.setColorMask(true, true);
-	}
-	
-	bool write_depth = LLDrawPoolWater::sSkipScreenCopy
-						 || (deferred_render && pass == 1)
-						 // we want depth written so that rendered alpha will
-						 // contribute to the alpha mask used for impostors
-						 || LLPipeline::sImpostorRenderAlphaDepthPass;
+    //enable writing to alpha for emissive effects
+    gGL.setColorMask(true, true);
 
-	LLGLDepthTest depth(GL_TRUE, write_depth ? GL_TRUE : GL_FALSE);
+    bool write_depth = LLDrawPoolWater::sSkipScreenCopy
+        // we want depth written so that rendered alpha will
+        // contribute to the alpha mask used for impostors
+        || LLPipeline::sImpostorRenderAlphaDepthPass;
 
-	if (deferred_render && pass == 1)
-	{
-		gGL.blendFunc(LLRender::BF_SOURCE_ALPHA, LLRender::BF_ONE_MINUS_SOURCE_ALPHA);
-	}
-	else
-	{
-		mColorSFactor = LLRender::BF_SOURCE_ALPHA;           // } regular alpha blend
-		mColorDFactor = LLRender::BF_ONE_MINUS_SOURCE_ALPHA; // }
-		mAlphaSFactor = LLRender::BF_ZERO;                         // } glow suppression
-		mAlphaDFactor = LLRender::BF_ONE_MINUS_SOURCE_ALPHA;       // }
-		gGL.blendFunc(mColorSFactor, mColorDFactor, mAlphaSFactor, mAlphaDFactor);
-	}
+    LLGLDepthTest depth(GL_TRUE, write_depth ? GL_TRUE : GL_FALSE);
 
-	renderAlpha(getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX | LLVertexBuffer::MAP_TANGENT | LLVertexBuffer::MAP_TEXCOORD1 | LLVertexBuffer::MAP_TEXCOORD2, pass);
+    mColorSFactor = LLRender::BF_SOURCE_ALPHA;           // } regular alpha blend
+    mColorDFactor = LLRender::BF_ONE_MINUS_SOURCE_ALPHA; // }
+    mAlphaSFactor = LLRender::BF_ZERO;                         // } glow suppression
+    mAlphaDFactor = LLRender::BF_ONE_MINUS_SOURCE_ALPHA;       // }
+    gGL.blendFunc(mColorSFactor, mColorDFactor, mAlphaSFactor, mAlphaDFactor);
 
-	gGL.setColorMask(true, false);
+    // If the face is more than 90% transparent, then don't update the Depth buffer for Dof
+    // We don't want the nearly invisible objects to cause of DoF effects
+    renderAlpha(getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX | LLVertexBuffer::MAP_TANGENT | LLVertexBuffer::MAP_TEXCOORD1 | LLVertexBuffer::MAP_TEXCOORD2);
 
-	if (deferred_render && pass == 1)
-	{
-		gGL.setSceneBlendType(LLRender::BT_ALPHA);
-	}
+    gGL.setColorMask(true, false);
+}
 
+void LLDrawPoolAlpha::renderDebugAlpha()
+{
 	if (sShowDebugAlpha)
 	{
 		gHighlightProgram.bind();
@@ -403,7 +352,7 @@ bool LLDrawPoolAlpha::TexSetup(LLDrawInfo* draw, bool use_material)
 			current_shader->bindTexture(LLShaderMgr::SPECULAR_MAP, draw->mSpecularMap);
 		} 
     }
-    else if (current_shader == simple_shader[0] || current_shader == simple_shader[1])
+    else if (current_shader == simple_shader || current_shader == simple_shader->mRiggedVariant)
     {
         current_shader->bindTexture(LLShaderMgr::BUMP_MAP, LLViewerFetchedTexture::sFlatNormalImagep);
 	    current_shader->bindTexture(LLShaderMgr::SPECULAR_MAP, LLViewerFetchedTexture::sWhiteImagep);
@@ -470,14 +419,8 @@ void LLDrawPoolAlpha::drawEmissive(U32 mask, LLDrawInfo* draw)
 
 void LLDrawPoolAlpha::renderEmissives(U32 mask, std::vector<LLDrawInfo*>& emissives)
 {
-    emissive_shader[0]->bind();
-    emissive_shader[0]->uniform1f(LLShaderMgr::EMISSIVE_BRIGHTNESS, 1.f);
-
-    gPipeline.enableLightsDynamic();
-
-    // install glow-accumulating blend mode
-    // don't touch color, add to alpha (glow)
-    gGL.blendFunc(LLRender::BF_ZERO, LLRender::BF_ONE, LLRender::BF_ONE, LLRender::BF_ONE);
+    emissive_shader->bind();
+    emissive_shader->uniform1f(LLShaderMgr::EMISSIVE_BRIGHTNESS, 1.f);
 
     for (LLDrawInfo* draw : emissives)
     {
@@ -485,24 +428,13 @@ void LLDrawPoolAlpha::renderEmissives(U32 mask, std::vector<LLDrawInfo*>& emissi
         drawEmissive(mask, draw);
         RestoreTexSetup(tex_setup);
     }
-
-    // restore our alpha blend mode
-    gGL.blendFunc(mColorSFactor, mColorDFactor, mAlphaSFactor, mAlphaDFactor);
-
-    emissive_shader[0]->unbind();
 }
 
 void LLDrawPoolAlpha::renderRiggedEmissives(U32 mask, std::vector<LLDrawInfo*>& emissives)
 {
-    emissive_shader[1]->bind();
-    emissive_shader[1]->uniform1f(LLShaderMgr::EMISSIVE_BRIGHTNESS, 1.f);
-
-    gPipeline.enableLightsDynamic();
-
-    mask |= LLVertexBuffer::MAP_WEIGHT4;
-    // 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);
+    LLGLSLShader* shader = emissive_shader->mRiggedVariant;
+    shader->bind();
+    shader->uniform1f(LLShaderMgr::EMISSIVE_BRIGHTNESS, 1.f);
 
     LLVOAvatar* lastAvatar = nullptr;
     U64 lastMeshId = 0;
@@ -522,14 +454,9 @@ void LLDrawPoolAlpha::renderRiggedEmissives(U32 mask, std::vector<LLDrawInfo*>&
         drawEmissive(mask, draw);
         RestoreTexSetup(tex_setup);
     }
-
-    // restore our alpha blend mode
-    gGL.blendFunc(mColorSFactor, mColorDFactor, mAlphaSFactor, mAlphaDFactor);
-
-    emissive_shader[1]->unbind();
 }
 
-void LLDrawPoolAlpha::renderAlpha(U32 mask, S32 pass)
+void LLDrawPoolAlpha::renderAlpha(U32 mask, bool depth_only)
 {
     LL_PROFILE_ZONE_SCOPED;
     BOOL initialized_lighting = FALSE;
@@ -577,17 +504,15 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, S32 pass)
 					continue;
 				}
 
-				// Fix for bug - NORSPEC-271
-				// If the face is more than 90% transparent, then don't update the Depth buffer for Dof
-				// We don't want the nearly invisible objects to cause of DoF effects
-				if(pass == 1 && !LLPipeline::sImpostorRender)
+				if(depth_only)
 				{
+                    // when updating depth buffer, discard faces that are more than 90% transparent
 					LLFace*	face = params.mFace;
 					if(face)
 					{
 						const LLTextureEntry* tep = face->getTextureEntry();
 						if(tep)
-						{
+						{ // don't render faces that are more than 90% transparent
 							if(tep->getColor().mV[3] < 0.1f)
 								continue;
 						}
@@ -609,7 +534,7 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, S32 pass)
 					if (light_enabled || !initialized_lighting)
 					{
 						initialized_lighting = TRUE;
-						target_shader = fullbright_shader[0];
+						target_shader = fullbright_shader;
 
 						light_enabled = FALSE;
 					}
@@ -618,7 +543,7 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, S32 pass)
 				else if (!light_enabled || !initialized_lighting)
 				{
 					initialized_lighting = TRUE;
-					target_shader = simple_shader[0];
+					target_shader = simple_shader;
 					light_enabled = TRUE;
 				}
 
@@ -647,11 +572,11 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, S32 pass)
 				}
 				else if (!params.mFullbright)
 				{
-					target_shader = simple_shader[0];
+					target_shader = simple_shader;
 				}
 				else
 				{
-					target_shader = fullbright_shader[0];
+					target_shader = fullbright_shader;
 				}
 				
                 if (params.mAvatar != nullptr)
@@ -748,7 +673,15 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, S32 pass)
 				}
 			}
 
+            // render emissive faces into alpha channel for bloom effects
+            if (!depth_only)
             {
+                gPipeline.enableLightsDynamic();
+
+                // install glow-accumulating blend mode
+                // don't touch color, add to alpha (glow)
+                gGL.blendFunc(LLRender::BF_ZERO, LLRender::BF_ONE, LLRender::BF_ONE, LLRender::BF_ONE);
+
                 bool rebind = false;
                 LLGLSLShader* lastShader = current_shader;
                 if (!emissives.empty())
@@ -765,6 +698,9 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, S32 pass)
                     rebind = true;
                 }
 
+                // restore our alpha blend mode
+                gGL.blendFunc(mColorSFactor, mColorDFactor, mAlphaSFactor, mAlphaDFactor);
+
                 if (lastShader && rebind)
                 {
                     lastShader->bind();
diff --git a/indra/newview/lldrawpoolalpha.h b/indra/newview/lldrawpoolalpha.h
index 64c17c3fef..1f6909e282 100644
--- a/indra/newview/lldrawpoolalpha.h
+++ b/indra/newview/lldrawpoolalpha.h
@@ -51,19 +51,17 @@ public:
 	/*virtual*/ ~LLDrawPoolAlpha();
 
 	/*virtual*/ S32 getNumPostDeferredPasses();
-	/*virtual*/ void beginPostDeferredPass(S32 pass);
-	/*virtual*/ void endPostDeferredPass(S32 pass);
 	/*virtual*/ void renderPostDeferred(S32 pass);
-
-	/*virtual*/ void beginRenderPass(S32 pass = 0);
-	/*virtual*/ void endRenderPass( S32 pass );
 	/*virtual*/ S32	 getNumPasses() { return 1; }
 
 	virtual void render(S32 pass = 0);
+    void forwardRender();
 	/*virtual*/ void prerender();
 
+    void renderDebugAlpha();
+
 	void renderGroupAlpha(LLSpatialGroup* group, U32 type, U32 mask, BOOL texture = TRUE);
-	void renderAlpha(U32 mask, S32 pass);
+	void renderAlpha(U32 mask, bool depth_only = false);
 	void renderAlphaHighlight(U32 mask);
     bool uploadMatrixPalette(const LLDrawInfo& params);
 
@@ -73,9 +71,9 @@ private:
 	LLGLSLShader* target_shader;
 
     // setup by beginFooPass, [0] is static variant, [1] is rigged variant
-    LLGLSLShader* simple_shader[2] = { nullptr };
-	LLGLSLShader* fullbright_shader[2] = { nullptr };
-	LLGLSLShader* emissive_shader[2] = { nullptr };
+    LLGLSLShader* simple_shader = nullptr;
+    LLGLSLShader* fullbright_shader = nullptr;
+    LLGLSLShader* emissive_shader = nullptr;
 
     void drawEmissive(U32 mask, LLDrawInfo* draw);
     void renderEmissives(U32 mask, std::vector<LLDrawInfo*>& emissives);
diff --git a/indra/newview/lldrawpoolbump.cpp b/indra/newview/lldrawpoolbump.cpp
index dc52fc7680..b01450bba9 100644
--- a/indra/newview/lldrawpoolbump.cpp
+++ b/indra/newview/lldrawpoolbump.cpp
@@ -200,21 +200,7 @@ void LLDrawPoolBump::prerender()
 // static
 S32 LLDrawPoolBump::numBumpPasses()
 {
-	if (gSavedSettings.getBOOL("RenderObjectBump"))
-	{
-		if (mShaderLevel > 1)
-		{
-			return 6;
-		}
-		else
-		{
-			return 4;
-		}
-	}
-    else
-	{
-		return 0;
-	}
+    return 1;
 }
 
 S32 LLDrawPoolBump::getNumPasses()
@@ -222,108 +208,49 @@ S32 LLDrawPoolBump::getNumPasses()
 	return numBumpPasses();
 }
 
-void LLDrawPoolBump::beginRenderPass(S32 pass)
-{
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_BUMP);
-    mRigged = ((pass % 2) == 1);
-    pass /= 2;
-	switch( pass )
-	{
-		case 0:
-			beginShiny();
-			break;
-		case 1:
-			if (mShaderLevel > 1)
-			{
-				beginFullbrightShiny();
-			}
-			else 
-			{
-				beginBump();
-			}
-			break;
-		case 2:
-			beginBump();
-			break;
-		default:
-			llassert(0);
-			break;
-	}
-}
-
 void LLDrawPoolBump::render(S32 pass)
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_BUMP);
-	
-	if (!gPipeline.hasRenderType(LLDrawPool::POOL_SIMPLE))
-	{
-		return;
-	}
-    pass /= 2;
-	switch( pass )
-	{
-		case 0:
-			renderShiny();
-			break;
-		case 1:
-			if (mShaderLevel > 1)
-			{
-				renderFullbrightShiny();
-			}
-			else 
-			{
-				renderBump(); 
-			}
-			break;
-		case 2:
-			renderBump();
-			break;
-		default:
-			llassert(0);
-			break;
-	}
-}
+    LL_RECORD_BLOCK_TIME(FTM_RENDER_BUMP);
 
-void LLDrawPoolBump::endRenderPass(S32 pass)
-{
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_BUMP);
-    pass /= 2;
-	switch( pass )
-	{
-		case 0:
-			endShiny();
-			break;
-		case 1:
-			if (mShaderLevel > 1)
-			{
-				endFullbrightShiny();
-			}
-			else 
-			{
-				endBump();
-			}
-			break;
-		case 2:
-			endBump();
-			break;
-		default:
-			llassert(0);
-			break;
-	}
+    if (!gPipeline.hasRenderType(LLDrawPool::POOL_SIMPLE))
+    {
+        return;
+    }
+
+    for (int i = 0; i < 2; ++i)
+    {
+        mRigged = i == 1;
+
+        // first pass -- shiny
+        beginShiny();
+        renderShiny();
+        endShiny();
+
+        //second pass -- fullbright shiny
+        if (mShaderLevel > 1)
+        {
+            beginFullbrightShiny();
+            renderFullbrightShiny();
+            endFullbrightShiny();
+        }
 
-	//to cleanup texture channels
-	LLRenderPass::endRenderPass(pass);
+        //third pass -- bump
+        beginBump();
+        renderBump(LLRenderPass::PASS_BUMP);
+        endBump();
+    }
 }
 
+
 //static
-void LLDrawPoolBump::beginShiny(bool invisible)
+void LLDrawPoolBump::beginShiny()
 {
 	LL_RECORD_BLOCK_TIME(FTM_RENDER_SHINY);
 	
 	mShiny = TRUE;
 	sVertexMask = VERTEX_MASK_SHINY;
 	// Second pass: environment map
-	if (!invisible && mShaderLevel > 1)
+	if (mShaderLevel > 1)
 	{
 		sVertexMask = VERTEX_MASK_SHINY | LLVertexBuffer::MAP_TEXCOORD0;
 	}
@@ -353,7 +280,7 @@ void LLDrawPoolBump::beginShiny(bool invisible)
         shader->uniform1i(LLShaderMgr::NO_ATMO, 0);
     }
 
-	bindCubeMap(shader, mShaderLevel, diffuse_channel, cube_channel, invisible);
+	bindCubeMap(shader, mShaderLevel, diffuse_channel, cube_channel);
 
 	if (mShaderLevel > 1)
 	{ //indexed texture rendering, channel 0 is always diffuse
@@ -362,12 +289,12 @@ void LLDrawPoolBump::beginShiny(bool invisible)
 }
 
 //static
-void LLDrawPoolBump::bindCubeMap(LLGLSLShader* shader, S32 shader_level, S32& diffuse_channel, S32& cube_channel, bool invisible)
+void LLDrawPoolBump::bindCubeMap(LLGLSLShader* shader, S32 shader_level, S32& diffuse_channel, S32& cube_channel)
 {
 	LLCubeMap* cube_map = gSky.mVOSkyp ? gSky.mVOSkyp->getCubeMap() : NULL;
 	if( cube_map )
 	{
-		if (!invisible && shader )
+		if (shader )
 		{
 			LLMatrix4 mat;
 			mat.initRows(LLVector4(gGLModelView+0),
@@ -405,14 +332,14 @@ void LLDrawPoolBump::bindCubeMap(LLGLSLShader* shader, S32 shader_level, S32& di
 	}
 }
 
-void LLDrawPoolBump::renderShiny(bool invisible)
+void LLDrawPoolBump::renderShiny()
 {
 	LL_RECORD_BLOCK_TIME(FTM_RENDER_SHINY);
 	
 	if( gSky.mVOSkyp->getCubeMap() )
 	{
 		LLGLEnable blend_enable(GL_BLEND);
-		if (!invisible && mShaderLevel > 1)
+		if (mShaderLevel > 1)
 		{
             if (mRigged)
             {
@@ -423,7 +350,7 @@ void LLDrawPoolBump::renderShiny(bool invisible)
                 LLRenderPass::pushBatches(LLRenderPass::PASS_SHINY, sVertexMask | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
             }
 		}
-		else if (!invisible)
+		else
 		{
             if (mRigged)
             {
@@ -438,12 +365,12 @@ void LLDrawPoolBump::renderShiny(bool invisible)
 }
 
 //static
-void LLDrawPoolBump::unbindCubeMap(LLGLSLShader* shader, S32 shader_level, S32& diffuse_channel, S32& cube_channel, bool invisible)
+void LLDrawPoolBump::unbindCubeMap(LLGLSLShader* shader, S32 shader_level, S32& diffuse_channel, S32& cube_channel)
 {
 	LLCubeMap* cube_map = gSky.mVOSkyp ? gSky.mVOSkyp->getCubeMap() : NULL;
 	if( cube_map )
 	{
-		if (!invisible && shader_level > 1)
+		if (shader_level > 1)
 		{
 			shader->disableTexture(LLViewerShaderMgr::ENVIRONMENT_MAP, LLTexUnit::TT_CUBE_MAP);
 					
@@ -461,11 +388,11 @@ void LLDrawPoolBump::unbindCubeMap(LLGLSLShader* shader, S32 shader_level, S32&
 	}
 }
 
-void LLDrawPoolBump::endShiny(bool invisible)
+void LLDrawPoolBump::endShiny()
 {
 	LL_RECORD_BLOCK_TIME(FTM_RENDER_SHINY);
 
-	unbindCubeMap(shader, mShaderLevel, diffuse_channel, cube_channel, invisible);
+	unbindCubeMap(shader, mShaderLevel, diffuse_channel, cube_channel);
 	if (shader)
 	{
 		shader->unbind();
@@ -737,7 +664,7 @@ S32 LLDrawPoolBump::getNumDeferredPasses()
 { 
 	if (gSavedSettings.getBOOL("RenderObjectBump"))
 	{
-		return 2;
+		return 1;
 	}
 	else
 	{
@@ -745,122 +672,81 @@ S32 LLDrawPoolBump::getNumDeferredPasses()
 	}
 }
 
-void LLDrawPoolBump::beginDeferredPass(S32 pass)
-{
-	if (!gPipeline.hasRenderBatches( pass == 0 ? LLRenderPass::PASS_BUMP : LLRenderPass::PASS_BUMP_RIGGED))
-	{
-		return;
-	}
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_BUMP);
-	mShiny = TRUE;
-	gDeferredBumpProgram.bind(pass == 1);
-	diffuse_channel = LLGLSLShader::sCurBoundShaderPtr->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
-	bump_channel = LLGLSLShader::sCurBoundShaderPtr->enableTexture(LLViewerShaderMgr::BUMP_MAP);
-	gGL.getTexUnit(diffuse_channel)->unbind(LLTexUnit::TT_TEXTURE);
-	gGL.getTexUnit(bump_channel)->unbind(LLTexUnit::TT_TEXTURE);
-}
-
-void LLDrawPoolBump::endDeferredPass(S32 pass)
-{
-	if (!gPipeline.hasRenderBatches(pass == 0 ? LLRenderPass::PASS_BUMP : LLRenderPass::PASS_BUMP_RIGGED))
-	{
-		return;
-	}
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_BUMP);
-	mShiny = FALSE;
-    LLGLSLShader::sCurBoundShaderPtr->disableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
-    LLGLSLShader::sCurBoundShaderPtr->disableTexture(LLViewerShaderMgr::BUMP_MAP);
-    LLGLSLShader::sCurBoundShaderPtr->unbind();
-	gGL.getTexUnit(0)->activate();
-}
-
 void LLDrawPoolBump::renderDeferred(S32 pass)
 {
-    if (!gPipeline.hasRenderBatches(pass == 0 ? LLRenderPass::PASS_BUMP : LLRenderPass::PASS_BUMP_RIGGED))
-	{
-		return;
-	}
 	LL_RECORD_BLOCK_TIME(FTM_RENDER_BUMP);
 
-    bool rigged = pass == 1;
-    U32 type = rigged ? LLRenderPass::PASS_BUMP_RIGGED : LLRenderPass::PASS_BUMP;
-    LLCullResult::drawinfo_iterator begin = gPipeline.beginRenderMap(type);
-    LLCullResult::drawinfo_iterator end = gPipeline.endRenderMap(type);
+    mShiny = TRUE;
+    for (int i = 0; i < 2; ++i)
+    {
+        bool rigged = i == 1;
+        gDeferredBumpProgram.bind(rigged);
+        diffuse_channel = LLGLSLShader::sCurBoundShaderPtr->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
+        bump_channel = LLGLSLShader::sCurBoundShaderPtr->enableTexture(LLViewerShaderMgr::BUMP_MAP);
+        gGL.getTexUnit(diffuse_channel)->unbind(LLTexUnit::TT_TEXTURE);
+        gGL.getTexUnit(bump_channel)->unbind(LLTexUnit::TT_TEXTURE);
 
-    U32 mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_TANGENT | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_COLOR;
+        U32 type = rigged ? LLRenderPass::PASS_BUMP_RIGGED : LLRenderPass::PASS_BUMP;
+        LLCullResult::drawinfo_iterator begin = gPipeline.beginRenderMap(type);
+        LLCullResult::drawinfo_iterator end = gPipeline.endRenderMap(type);
 
-    LLVOAvatar* avatar = nullptr;
-    U64 skin = 0;
-
-    for (LLCullResult::drawinfo_iterator i = begin; i != end; ++i)
-    {
-        LLDrawInfo& params = **i;
+        U32 mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_TANGENT | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_COLOR;
 
-        LLGLSLShader::sCurBoundShaderPtr->setMinimumAlpha(params.mAlphaMaskCutoff);
-        LLDrawPoolBump::bindBumpMap(params, bump_channel);
+        LLVOAvatar* avatar = nullptr;
+        U64 skin = 0;
 
-        if (rigged)
+        for (LLCullResult::drawinfo_iterator i = begin; i != end; ++i)
         {
-            if (avatar != params.mAvatar || skin != params.mSkinInfo->mHash)
+            LLDrawInfo& params = **i;
+
+            LLGLSLShader::sCurBoundShaderPtr->setMinimumAlpha(params.mAlphaMaskCutoff);
+            LLDrawPoolBump::bindBumpMap(params, bump_channel);
+
+            if (rigged)
             {
-                uploadMatrixPalette(params);
-                avatar = params.mAvatar;
-                skin = params.mSkinInfo->mHash;
+                if (avatar != params.mAvatar || skin != params.mSkinInfo->mHash)
+                {
+                    uploadMatrixPalette(params);
+                    avatar = params.mAvatar;
+                    skin = params.mSkinInfo->mHash;
+                }
+                pushBatch(params, mask | LLVertexBuffer::MAP_WEIGHT4, TRUE, FALSE);
+            }
+            else
+            {
+                pushBatch(params, mask, TRUE, FALSE);
             }
-            pushBatch(params, mask | LLVertexBuffer::MAP_WEIGHT4, TRUE, FALSE);
-        }
-        else
-        {
-            pushBatch(params, mask, TRUE, FALSE);
         }
+
+        LLGLSLShader::sCurBoundShaderPtr->disableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
+        LLGLSLShader::sCurBoundShaderPtr->disableTexture(LLViewerShaderMgr::BUMP_MAP);
+        LLGLSLShader::sCurBoundShaderPtr->unbind();
+        gGL.getTexUnit(0)->activate();
     }
-}
 
-void LLDrawPoolBump::beginPostDeferredPass(S32 pass)
-{
-    mRigged = ((pass % 2) == 1);
-    pass /= 2;
-	switch (pass)
-	{
-	case 0:
-		beginFullbrightShiny();
-		break;
-	case 1:
-		beginBump();
-		break;
-	}
+    mShiny = FALSE;
 }
 
-void LLDrawPoolBump::endPostDeferredPass(S32 pass)
-{
-	switch (pass)
-	{
-	case 0:
-		endFullbrightShiny();
-		break;
-	case 1:
-		endBump(LLRenderPass::PASS_POST_BUMP);
-		break;
-	}
-
-	//to disable texture channels
-	LLRenderPass::endRenderPass(pass);
-}
 
 void LLDrawPoolBump::renderPostDeferred(S32 pass)
 {
-    pass /= 2;
-	switch (pass)
-	{
-	case 0:
-		renderFullbrightShiny();
-		break;
-	case 1:
-		renderBump(LLRenderPass::PASS_POST_BUMP);
-		break;
-	}
+    for (int i = 0; i < 2; ++i)
+    { // two passes -- static and rigged
+        mRigged = (i == 1);
+
+        // render shiny
+        beginFullbrightShiny();
+        renderFullbrightShiny();
+        endFullbrightShiny();
+
+        //render bump
+        beginBump();
+        renderBump(LLRenderPass::PASS_POST_BUMP);
+        endBump();
+    }
 }
 
+
 ////////////////////////////////////////////////////////////////
 // List of bump-maps created from other textures.
 
@@ -1526,44 +1412,4 @@ void LLDrawPoolInvisible::render(S32 pass)
 	{
 		gOcclusionProgram.unbind();
 	}
-
-	if (gPipeline.hasRenderBatches(LLRenderPass::PASS_INVISI_SHINY))
-	{
-		beginShiny(true);
-		renderShiny(true);
-		endShiny(true);
-	}
-}
-
-void LLDrawPoolInvisible::beginDeferredPass(S32 pass)
-{
-	beginRenderPass(pass);
-}
-
-void LLDrawPoolInvisible::endDeferredPass( S32 pass )
-{
-	endRenderPass(pass);
-}
-
-void LLDrawPoolInvisible::renderDeferred( S32 pass )
-{ //render invisiprims; this doesn't work becaue it also blocks all the post-deferred stuff
-#if 0 
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_INVISIBLE);
-  
-	U32 invisi_mask = LLVertexBuffer::MAP_VERTEX;
-	glStencilMask(0);
-	glStencilOp(GL_ZERO, GL_KEEP, GL_REPLACE);
-	gGL.setColorMask(false, false);
-	pushBatches(LLRenderPass::PASS_INVISIBLE, invisi_mask, FALSE);
-	gGL.setColorMask(true, true);
-	glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
-	glStencilMask(0xFFFFFFFF);
-	
-	if (gPipeline.hasRenderBatches(LLRenderPass::PASS_INVISI_SHINY))
-	{
-		beginShiny(true);
-		renderShiny(true);
-		endShiny(true);
-	}
-#endif
 }
diff --git a/indra/newview/lldrawpoolbump.h b/indra/newview/lldrawpoolbump.h
index 624dbe3034..38744a7d98 100644
--- a/indra/newview/lldrawpoolbump.h
+++ b/indra/newview/lldrawpoolbump.h
@@ -53,8 +53,6 @@ public:
 	LLDrawPoolBump();
 
 	virtual void render(S32 pass = 0) override;
-	virtual void beginRenderPass( S32 pass ) override;
-	virtual void endRenderPass( S32 pass ) override;
 	virtual S32	 getNumPasses() override;
 	/*virtual*/ void prerender() override;
 	void pushBatch(LLDrawInfo& params, U32 mask, BOOL texture, BOOL batch_textures = FALSE) override;
@@ -64,9 +62,9 @@ public:
 		
 	S32 numBumpPasses();
 	
-	void beginShiny(bool invisible = false);
-	void renderShiny(bool invisible = false);
-	void endShiny(bool invisible = false);
+	void beginShiny();
+	void renderShiny();
+	void endShiny();
 	
 	void beginFullbrightShiny();
 	void renderFullbrightShiny();
@@ -76,17 +74,13 @@ public:
 	void renderBump(U32 pass = LLRenderPass::PASS_BUMP);
 	void endBump(U32 pass = LLRenderPass::PASS_BUMP);
 
-	static void bindCubeMap(LLGLSLShader* shader, S32 shader_level, S32& diffuse_channel, S32& cube_channel, bool invisible);
-	static void unbindCubeMap(LLGLSLShader* shader, S32 shader_level, S32& diffuse_channel, S32& cube_channel, bool invisible);
+	static void bindCubeMap(LLGLSLShader* shader, S32 shader_level, S32& diffuse_channel, S32& cube_channel);
+	static void unbindCubeMap(LLGLSLShader* shader, S32 shader_level, S32& diffuse_channel, S32& cube_channel);
 
 	virtual S32 getNumDeferredPasses() override;
-	/*virtual*/ void beginDeferredPass(S32 pass) override;
-	/*virtual*/ void endDeferredPass(S32 pass) override;
 	/*virtual*/ void renderDeferred(S32 pass) override;
 
-    virtual S32 getNumPostDeferredPasses() override { return 4; }
-	/*virtual*/ void beginPostDeferredPass(S32 pass) override;
-	/*virtual*/ void endPostDeferredPass(S32 pass) override;
+    virtual S32 getNumPostDeferredPasses() override { return 1; }
 	/*virtual*/ void renderPostDeferred(S32 pass) override;
 
 	static BOOL bindBumpMap(LLDrawInfo& params, S32 channel = -2);
@@ -171,10 +165,10 @@ private:
 
 extern LLBumpImageList gBumpImageList;
 
-class LLDrawPoolInvisible : public LLDrawPoolBump
+class LLDrawPoolInvisible : public LLRenderPass
 {
 public:
-	LLDrawPoolInvisible() : LLDrawPoolBump(LLDrawPool::POOL_INVISIBLE) { }
+	LLDrawPoolInvisible() : LLRenderPass(LLDrawPool::POOL_INVISIBLE) { }
 
 	enum
 	{
@@ -189,11 +183,6 @@ public:
 	virtual void beginRenderPass( S32 pass ) { }
 	virtual void endRenderPass( S32 pass ) { }
 	virtual S32	 getNumPasses() {return 1;}
-
-	virtual S32 getNumDeferredPasses() { return 1; }
-	/*virtual*/ void beginDeferredPass(S32 pass);
-	/*virtual*/ void endDeferredPass(S32 pass);
-	/*virtual*/ void renderDeferred(S32 pass);
 };
 
 
diff --git a/indra/newview/lldrawpoolsimple.cpp b/indra/newview/lldrawpoolsimple.cpp
index a1d769bc83..4ada753355 100644
--- a/indra/newview/lldrawpoolsimple.cpp
+++ b/indra/newview/lldrawpoolsimple.cpp
@@ -38,83 +38,54 @@
 #include "llrender.h"
 
 static LLGLSLShader* simple_shader = NULL;
-static LLGLSLShader* fullbright_shader = NULL;
 
 static LLTrace::BlockTimerStatHandle FTM_RENDER_SIMPLE_DEFERRED("Deferred Simple");
 static LLTrace::BlockTimerStatHandle FTM_RENDER_GRASS_DEFERRED("Deferred Grass");
 
-void LLDrawPoolGlow::beginPostDeferredPass(S32 pass)
+
+static void setup_simple_shader(LLGLSLShader* shader)
 {
-    if (pass == 0)
+    shader->bind();
+
+    if (LLPipeline::sRenderingHUDs)
     {
-        gDeferredEmissiveProgram.bind();
+        shader->uniform1i(LLShaderMgr::NO_ATMO, 1);
     }
     else
     {
-        llassert(gDeferredEmissiveProgram.mRiggedVariant);
-        gDeferredEmissiveProgram.mRiggedVariant->bind();
+        shader->uniform1i(LLShaderMgr::NO_ATMO, 0);
     }
-
-	LLGLSLShader::sCurBoundShaderPtr->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 2.2f);
-    if (LLPipeline::sRenderingHUDs)
-	{
-        LLGLSLShader::sCurBoundShaderPtr->uniform1i(LLShaderMgr::NO_ATMO, 1);
-	}
-	else
-	{
-        LLGLSLShader::sCurBoundShaderPtr->uniform1i(LLShaderMgr::NO_ATMO, 0);
-	}
 }
 
-void LLDrawPoolGlow::renderPostDeferred(S32 pass)
+static void setup_glow_shader(LLGLSLShader* shader)
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_GLOW);
-	LLGLEnable blend(GL_BLEND);
-	LLGLDisable test(GL_ALPHA_TEST);
-	gGL.flush();
-	/// Get rid of z-fighting with non-glow pass.
-	LLGLEnable polyOffset(GL_POLYGON_OFFSET_FILL);
-	glPolygonOffset(-1.0f, -1.0f);
-	gGL.setSceneBlendType(LLRender::BT_ADD);
-	
-	LLGLDepthTest depth(GL_TRUE, GL_FALSE);
-	gGL.setColorMask(false, true);
-
-    if (pass == 0)
+    setup_simple_shader(shader);
+    if (LLPipeline::sRenderDeferred && !LLPipeline::sRenderingHUDs)
     {
-        pushBatches(LLRenderPass::PASS_GLOW, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
+        shader->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 2.2f);
     }
     else
     {
-        pushRiggedBatches(LLRenderPass::PASS_GLOW_RIGGED, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
+        shader->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 1.f);
     }
-	
-	gGL.setColorMask(true, false);
-	gGL.setSceneBlendType(LLRender::BT_ALPHA);	
 }
 
-void LLDrawPoolGlow::endPostDeferredPass(S32 pass)
+static void setup_fullbright_shader(LLGLSLShader* shader)
 {
-    LLGLSLShader::sCurBoundShaderPtr->unbind();
-
-	LLRenderPass::endRenderPass(pass);
+    setup_glow_shader(shader);
+    shader->uniform1f(LLViewerShaderMgr::FULLBRIGHT, 1.f);
 }
 
-S32 LLDrawPoolGlow::getNumPasses()
+
+void LLDrawPoolGlow::renderPostDeferred(S32 pass)
 {
-	if (LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_OBJECT) > 0)
-	{
-		return 2;
-	}
-	else
-	{
-		return 0;
-	}
+    LL_RECORD_BLOCK_TIME(FTM_RENDER_GLOW);
+    render(&gDeferredEmissiveProgram);
 }
 
-void LLDrawPoolGlow::render(S32 pass)
+void LLDrawPoolGlow::render(LLGLSLShader* shader)
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_GLOW);
+    LL_RECORD_BLOCK_TIME(FTM_RENDER_GLOW);
 	LLGLEnable blend(GL_BLEND);
 	LLGLDisable test(GL_ALPHA_TEST);
 	gGL.flush();
@@ -123,55 +94,32 @@ void LLDrawPoolGlow::render(S32 pass)
 	glPolygonOffset(-1.0f, -1.0f);
 	gGL.setSceneBlendType(LLRender::BT_ADD);
 	
-	U32 shader_level = LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_OBJECT);
-
-	//should never get here without basic shaders enabled
-	llassert(shader_level > 0);
-	
-	LLGLSLShader* shader = LLPipeline::sUnderWaterRender ? &gObjectEmissiveWaterProgram : &gObjectEmissiveProgram;
-    if (pass == 1)
-    {
-        llassert(shader->mRiggedVariant);
-        shader = shader->mRiggedVariant;
-    }
-	shader->bind();
-	if (LLPipeline::sRenderDeferred)
-	{
-		shader->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 2.2f);
-	}
-	else
-	{
-		shader->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 1.f);
-	}
-
-    if (LLPipeline::sRenderingHUDs)
-	{
-		shader->uniform1i(LLShaderMgr::NO_ATMO, 1);
-	}
-	else
-	{
-		shader->uniform1i(LLShaderMgr::NO_ATMO, 0);
-	}
-
 	LLGLDepthTest depth(GL_TRUE, GL_FALSE);
 	gGL.setColorMask(false, true);
 
-    if (pass == 0)
-    {
-        pushBatches(LLRenderPass::PASS_GLOW, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
-    }
-    else
-    {
-        pushRiggedBatches(LLRenderPass::PASS_GLOW_RIGGED, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
-    }
-	
-	gGL.setColorMask(true, false);
-	gGL.setSceneBlendType(LLRender::BT_ALPHA);
-	
-	if (shader_level > 0 && fullbright_shader)
-	{
-		shader->unbind();
-	}
+    //first pass -- static objects
+    setup_glow_shader(shader);
+    pushBatches(LLRenderPass::PASS_GLOW, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
+        
+    // second pass -- rigged objects
+    shader = shader->mRiggedVariant;
+    setup_glow_shader(shader);
+    pushRiggedBatches(LLRenderPass::PASS_GLOW_RIGGED, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
+ 
+    gGL.setColorMask(true, false);
+    gGL.setSceneBlendType(LLRender::BT_ALPHA);	
+}
+
+S32 LLDrawPoolGlow::getNumPasses()
+{
+    return 1;
+}
+
+void LLDrawPoolGlow::render(S32 pass)
+{
+    LL_PROFILE_ZONE_SCOPED;
+    LLGLSLShader* shader = LLPipeline::sUnderWaterRender ? &gObjectEmissiveWaterProgram : &gObjectEmissiveProgram;
+    render(shader);
 }
 
 LLDrawPoolSimple::LLDrawPoolSimple() :
@@ -186,65 +134,38 @@ void LLDrawPoolSimple::prerender()
 
 S32 LLDrawPoolSimple::getNumPasses()
 {
-    return 2;
+    return 1;
 }
 
-void LLDrawPoolSimple::beginRenderPass(S32 pass)
+void LLDrawPoolSimple::render(S32 pass)
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_SIMPLE);
+    LL_RECORD_BLOCK_TIME(FTM_RENDER_SIMPLE);
 
+	LLGLDisable blend(GL_BLEND);
+	
+    LLGLSLShader* shader = nullptr;
     if (LLPipeline::sImpostorRender)
     {
-        simple_shader = &gObjectSimpleImpostorProgram;
+        shader = &gObjectSimpleImpostorProgram;
     }
     else if (LLPipeline::sUnderWaterRender)
     {
-        simple_shader = &gObjectSimpleWaterProgram;
+        shader = &gObjectSimpleWaterProgram;
     }
     else
     {
-        simple_shader = &gObjectSimpleProgram;
-    }
- 
-    if (pass == 1)
-    {
-        llassert(simple_shader->mRiggedVariant);
-        simple_shader = simple_shader->mRiggedVariant;
+        shader = &gObjectSimpleProgram;
     }
 
-	simple_shader->bind();
-
-    if (LLPipeline::sRenderingHUDs)
-	{
-		simple_shader->uniform1i(LLShaderMgr::NO_ATMO, 1);
-	}
-	else
-	{
-		simple_shader->uniform1i(LLShaderMgr::NO_ATMO, 0);
-	}
-}
-
-void LLDrawPoolSimple::endRenderPass(S32 pass)
-{
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_SIMPLE);
-	stop_glerror();
-	LLRenderPass::endRenderPass(pass);
-	stop_glerror();
-	simple_shader->unbind();
-}
-
-void LLDrawPoolSimple::render(S32 pass)
-{
-	LLGLDisable blend(GL_BLEND);
-	
 	{ //render simple
-		LL_RECORD_BLOCK_TIME(FTM_RENDER_SIMPLE);
+	
 		gPipeline.enableLightsDynamic();
 
 		U32 mask = getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX;
 
-        if (pass == 0)
+        // first pass -- static objects
         {
+            setup_simple_shader(shader);
             pushBatches(LLRenderPass::PASS_SIMPLE, mask, TRUE, TRUE);
 
             if (LLPipeline::sRenderDeferred)
@@ -257,8 +178,11 @@ void LLDrawPoolSimple::render(S32 pass)
                 pushBatches(LLRenderPass::PASS_NORMSPEC, mask, TRUE, TRUE);
             }
         }
-        else
+        
+        //second pass, rigged
         {
+            shader = shader->mRiggedVariant;
+            setup_simple_shader(shader);
             pushRiggedBatches(LLRenderPass::PASS_SIMPLE_RIGGED, mask, TRUE, TRUE);
 
             if (LLPipeline::sRenderDeferred)
@@ -275,9 +199,6 @@ void LLDrawPoolSimple::render(S32 pass)
 }
 
 
-
-
-
 static LLTrace::BlockTimerStatHandle FTM_RENDER_ALPHA_MASK("Alpha Mask");
 
 LLDrawPoolAlphaMask::LLDrawPoolAlphaMask() :
@@ -290,84 +211,36 @@ void LLDrawPoolAlphaMask::prerender()
 	mShaderLevel = LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_OBJECT);
 }
 
-void LLDrawPoolAlphaMask::beginRenderPass(S32 pass)
+void LLDrawPoolAlphaMask::render(S32 pass)
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_MASK);
-
+	LLGLDisable blend(GL_BLEND);
+    LL_PROFILE_ZONE_SCOPED;
+	
+    LLGLSLShader* shader = nullptr;
     if (LLPipeline::sUnderWaterRender)
     {
-        simple_shader = &gObjectSimpleWaterAlphaMaskProgram;
+        shader = &gObjectSimpleWaterAlphaMaskProgram;
     }
     else
     {
-        simple_shader = &gObjectSimpleAlphaMaskProgram;
+        shader = &gObjectSimpleAlphaMaskProgram;
     }
 
-    if (pass == 1)
-    {
-        llassert(simple_shader->mRiggedVariant);
-        simple_shader = simple_shader->mRiggedVariant;
-    }
-
-    simple_shader->bind();
-
-    if (LLPipeline::sRenderingHUDs)
-    {
-	    simple_shader->uniform1i(LLShaderMgr::NO_ATMO, 1);
-    }
-    else
-    {
-	    simple_shader->uniform1i(LLShaderMgr::NO_ATMO, 0);
-    }
-}
-
-void LLDrawPoolAlphaMask::endRenderPass(S32 pass)
-{
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_MASK);
-	stop_glerror();
-	LLRenderPass::endRenderPass(pass);
-	stop_glerror();
-	if (mShaderLevel > 0)
-	{
-		simple_shader->unbind();
-	}
-}
-
-void LLDrawPoolAlphaMask::render(S32 pass)
-{
-	LLGLDisable blend(GL_BLEND);
-    LL_PROFILE_ZONE_SCOPED;
-	
-	
-
-	simple_shader->bind();
-	simple_shader->setMinimumAlpha(0.33f);
-
-    if (LLPipeline::sRenderingHUDs)
-	{
-		simple_shader->uniform1i(LLShaderMgr::NO_ATMO, 1);
-	}
-	else
-	{
-		simple_shader->uniform1i(LLShaderMgr::NO_ATMO, 0);
-	}
+    // render static
+    setup_simple_shader(shader);
+    pushMaskBatches(LLRenderPass::PASS_ALPHA_MASK, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
+	pushMaskBatches(LLRenderPass::PASS_MATERIAL_ALPHA_MASK, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
+	pushMaskBatches(LLRenderPass::PASS_SPECMAP_MASK, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
+	pushMaskBatches(LLRenderPass::PASS_NORMMAP_MASK, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
+	pushMaskBatches(LLRenderPass::PASS_NORMSPEC_MASK, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
 
-    if (pass == 0)
-    {
-		pushMaskBatches(LLRenderPass::PASS_ALPHA_MASK, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
-		pushMaskBatches(LLRenderPass::PASS_MATERIAL_ALPHA_MASK, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
-		pushMaskBatches(LLRenderPass::PASS_SPECMAP_MASK, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
-		pushMaskBatches(LLRenderPass::PASS_NORMMAP_MASK, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
-		pushMaskBatches(LLRenderPass::PASS_NORMSPEC_MASK, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
-	}
-	else
-	{
-        pushRiggedMaskBatches(LLRenderPass::PASS_ALPHA_MASK_RIGGED, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
-        pushRiggedMaskBatches(LLRenderPass::PASS_MATERIAL_ALPHA_MASK_RIGGED, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
-        pushRiggedMaskBatches(LLRenderPass::PASS_SPECMAP_MASK_RIGGED, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
-        pushRiggedMaskBatches(LLRenderPass::PASS_NORMMAP_MASK_RIGGED, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
-        pushRiggedMaskBatches(LLRenderPass::PASS_NORMSPEC_MASK_RIGGED, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
-	}
+    // render rigged
+    setup_simple_shader(shader->mRiggedVariant);
+    pushRiggedMaskBatches(LLRenderPass::PASS_ALPHA_MASK_RIGGED, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
+    pushRiggedMaskBatches(LLRenderPass::PASS_MATERIAL_ALPHA_MASK_RIGGED, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
+    pushRiggedMaskBatches(LLRenderPass::PASS_SPECMAP_MASK_RIGGED, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
+    pushRiggedMaskBatches(LLRenderPass::PASS_NORMMAP_MASK_RIGGED, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
+    pushRiggedMaskBatches(LLRenderPass::PASS_NORMSPEC_MASK_RIGGED, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
 }
 
 LLDrawPoolFullbrightAlphaMask::LLDrawPoolFullbrightAlphaMask() :
@@ -380,61 +253,27 @@ void LLDrawPoolFullbrightAlphaMask::prerender()
 	mShaderLevel = LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_OBJECT);
 }
 
-void LLDrawPoolFullbrightAlphaMask::beginRenderPass(S32 pass)
-{
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_MASK);
-
-    bool rigged = (pass == 1);
-	if (LLPipeline::sUnderWaterRender)
-	{
-        gObjectFullbrightWaterAlphaMaskProgram.bind(rigged);
-	}
-	else
-	{
-		gObjectFullbrightAlphaMaskProgram.bind(rigged);
-	}
-
-    if (LLPipeline::sRenderingHUDs)
-	{
-		LLGLSLShader::sCurBoundShaderPtr->uniform1i(LLShaderMgr::NO_ATMO, 1);
-        LLGLSLShader::sCurBoundShaderPtr->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 1.f);
-	}
-	else
-	{
-        LLGLSLShader::sCurBoundShaderPtr->uniform1i(LLShaderMgr::NO_ATMO, 0);
-        if (LLPipeline::sRenderDeferred)
-        {
-            LLGLSLShader::sCurBoundShaderPtr->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 2.2f);
-        }
-        else
-        {
-            LLGLSLShader::sCurBoundShaderPtr->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 1.0f);
-        }
-	}
-}
-
-void LLDrawPoolFullbrightAlphaMask::endRenderPass(S32 pass)
-{
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_MASK);
-	stop_glerror();
-	LLRenderPass::endRenderPass(pass);
-	stop_glerror();
-    LLGLSLShader::sCurBoundShaderPtr->unbind();
-}
-
 void LLDrawPoolFullbrightAlphaMask::render(S32 pass)
 {
 	LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_MASK);
 
-    if (pass == 0)
+    LLGLSLShader* shader = nullptr;
+    if (LLPipeline::sUnderWaterRender)
     {
-        pushMaskBatches(LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
+        shader = &gObjectFullbrightWaterAlphaMaskProgram;
     }
     else
     {
-        pushRiggedMaskBatches(LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK_RIGGED, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
+        shader = &gObjectFullbrightAlphaMaskProgram;
     }
-	
+
+    // render static
+    setup_fullbright_shader(shader);
+    pushMaskBatches(LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
+
+    // render rigged
+    setup_fullbright_shader(shader->mRiggedVariant);
+    pushRiggedMaskBatches(LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK_RIGGED, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
 }
 
 //===============================
@@ -443,112 +282,41 @@ void LLDrawPoolFullbrightAlphaMask::render(S32 pass)
 
 S32 LLDrawPoolSimple::getNumDeferredPasses()
 {
-    if (LLPipeline::sRenderingHUDs)
-    {
-        return 1;
-    }
-    else
-    {
-        return 2;
-    }
-}
-void LLDrawPoolSimple::beginDeferredPass(S32 pass)
-{
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_SIMPLE_DEFERRED);
-
-    mShader = &gDeferredDiffuseProgram;
-    
-    if (pass == 1)
-    {
-        llassert(mShader->mRiggedVariant != nullptr);
-        mShader = mShader->mRiggedVariant;
-    }
-    
-
-    mShader->bind();
-
-    if (LLPipeline::sRenderingHUDs)
-	{
-		mShader->uniform1i(LLShaderMgr::NO_ATMO, 1);
-	}
-	else
-	{
-		mShader->uniform1i(LLShaderMgr::NO_ATMO, 0);
-	}
-}
-
-void LLDrawPoolSimple::endDeferredPass(S32 pass)
-{
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_SIMPLE_DEFERRED);
-	LLRenderPass::endRenderPass(pass);
-
-	mShader->unbind();
+    return 1;
 }
 
 void LLDrawPoolSimple::renderDeferred(S32 pass)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_RECORD_BLOCK_TIME(FTM_RENDER_SIMPLE_DEFERRED);
 	LLGLDisable blend(GL_BLEND);
 	LLGLDisable alpha_test(GL_ALPHA_TEST);
 
-    if (pass == 0)
-	{ //render simple
-		LL_RECORD_BLOCK_TIME(FTM_RENDER_SIMPLE_DEFERRED);
-		pushBatches(LLRenderPass::PASS_SIMPLE, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
-	}
-    else
-    {
-        //render simple rigged
-        pushRiggedBatches(LLRenderPass::PASS_SIMPLE_RIGGED, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
-    }
+	//render static
+    setup_simple_shader(&gDeferredDiffuseProgram);
+	pushBatches(LLRenderPass::PASS_SIMPLE, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
+	
+    //render rigged
+    setup_simple_shader(gDeferredDiffuseProgram.mRiggedVariant);
+    pushRiggedBatches(LLRenderPass::PASS_SIMPLE_RIGGED, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
 }
 
 static LLTrace::BlockTimerStatHandle FTM_RENDER_ALPHA_MASK_DEFERRED("Deferred Alpha Mask");
 
-void LLDrawPoolAlphaMask::beginDeferredPass(S32 pass)
-{
-    if (pass == 0)
-    {
-        gDeferredDiffuseAlphaMaskProgram.bind();
-    }
-    else
-    {
-        llassert(gDeferredDiffuseAlphaMaskProgram.mRiggedVariant);
-        gDeferredDiffuseAlphaMaskProgram.mRiggedVariant->bind();
-    }
-
-}
-
-void LLDrawPoolAlphaMask::endDeferredPass(S32 pass)
-{
-    LLGLSLShader::sCurBoundShaderPtr->unbind();
-}
 
 void LLDrawPoolAlphaMask::renderDeferred(S32 pass)
 {
 	LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_MASK_DEFERRED);
-	LLGLSLShader::sCurBoundShaderPtr->setMinimumAlpha(0.33f);
+    LLGLSLShader* shader = &gDeferredDiffuseAlphaMaskProgram;
 
-    if (LLPipeline::sRenderingHUDs)
-	{
-        LLGLSLShader::sCurBoundShaderPtr->uniform1i(LLShaderMgr::NO_ATMO, 1);
-	}
-	else
-	{
-        LLGLSLShader::sCurBoundShaderPtr->uniform1i(LLShaderMgr::NO_ATMO, 0);
-	}
+    //render static
+    setup_simple_shader(shader);
+    pushMaskBatches(LLRenderPass::PASS_ALPHA_MASK, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
 
-    if (pass == 0)
-    {
-        pushMaskBatches(LLRenderPass::PASS_ALPHA_MASK, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
-    }
-    else
-    {
-        pushRiggedMaskBatches(LLRenderPass::PASS_ALPHA_MASK_RIGGED, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
-    }
+    //render rigged
+    setup_simple_shader(shader->mRiggedVariant);
+    pushRiggedMaskBatches(LLRenderPass::PASS_ALPHA_MASK_RIGGED, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
 }
 
-
 // grass drawpool
 LLDrawPoolGrass::LLDrawPoolGrass() :
  LLRenderPass(POOL_GRASS)
@@ -667,83 +435,31 @@ void LLDrawPoolFullbright::prerender()
 	mShaderLevel = LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_OBJECT);
 }
 
-void LLDrawPoolFullbright::beginPostDeferredPass(S32 pass)
-{
-    bool rigged = (pass == 1);
-	if (LLPipeline::sUnderWaterRender)
-	{
-		gDeferredFullbrightWaterProgram.bind(rigged);
-	}
-	else
-	{
-		gDeferredFullbrightProgram.bind(rigged);
-
-        if (LLPipeline::sRenderingHUDs)
-	    {
-            LLGLSLShader::sCurBoundShaderPtr->uniform1i(LLShaderMgr::NO_ATMO, 1);
-	    }
-	    else
-	    {
-            LLGLSLShader::sCurBoundShaderPtr->uniform1i(LLShaderMgr::NO_ATMO, 0);
-	    }
-	}
-}
 
 void LLDrawPoolFullbright::renderPostDeferred(S32 pass)
 {
 	LL_RECORD_BLOCK_TIME(FTM_RENDER_FULLBRIGHT);
-	
-	gGL.setSceneBlendType(LLRender::BT_ALPHA);
-	U32 fullbright_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_COLOR | LLVertexBuffer::MAP_TEXTURE_INDEX;
-    if (pass == 0)
+
+    LLGLSLShader* shader = nullptr;
+    if (LLPipeline::sUnderWaterRender)
     {
-        pushBatches(LLRenderPass::PASS_FULLBRIGHT, fullbright_mask, TRUE, TRUE);
+        shader = &gDeferredFullbrightWaterProgram;
     }
     else
     {
-        pushRiggedBatches(LLRenderPass::PASS_FULLBRIGHT_RIGGED, fullbright_mask, TRUE, TRUE);
+        shader = &gDeferredFullbrightProgram;
     }
-}
 
-void LLDrawPoolFullbright::endPostDeferredPass(S32 pass)
-{
-    LLGLSLShader::sCurBoundShaderPtr->unbind();
-	LLRenderPass::endRenderPass(pass);
-}
-
-void LLDrawPoolFullbright::beginRenderPass(S32 pass)
-{
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_FULLBRIGHT);
-	
-	if (LLPipeline::sUnderWaterRender)
-	{
-		fullbright_shader = &gObjectFullbrightWaterProgram;
-	}
-	else
-	{
-		fullbright_shader = &gObjectFullbrightProgram;
-	}
-
-    if (pass == 1)
-    {
-        llassert(fullbright_shader->mRiggedVariant);
-        fullbright_shader = fullbright_shader->mRiggedVariant;
-    }
-}
-
-void LLDrawPoolFullbright::endRenderPass(S32 pass)
-{
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_FULLBRIGHT);
-	LLRenderPass::endRenderPass(pass);
-
-	stop_glerror();
-
-	if (mShaderLevel > 0)
-	{
-		fullbright_shader->unbind();
-	}
-
-	stop_glerror();
+	gGL.setSceneBlendType(LLRender::BT_ALPHA);
+	U32 fullbright_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_COLOR | LLVertexBuffer::MAP_TEXTURE_INDEX;
+    
+    // render static
+    setup_fullbright_shader(shader);
+    pushBatches(LLRenderPass::PASS_FULLBRIGHT, fullbright_mask, TRUE, TRUE);
+    
+    // render rigged
+    setup_fullbright_shader(shader->mRiggedVariant);
+    pushRiggedBatches(LLRenderPass::PASS_FULLBRIGHT_RIGGED, fullbright_mask, TRUE, TRUE);
 }
 
 void LLDrawPoolFullbright::render(S32 pass)
@@ -752,102 +468,75 @@ void LLDrawPoolFullbright::render(S32 pass)
 	gGL.setSceneBlendType(LLRender::BT_ALPHA);
 
 	stop_glerror();
+    LLGLSLShader* shader = nullptr;
+    if (LLPipeline::sUnderWaterRender)
+    {
+        shader = &gObjectFullbrightWaterProgram;
+    }
+    else
+    {
+        shader = &gObjectFullbrightProgram;
+    }
 
-	if (mShaderLevel > 0)
-	{
-		fullbright_shader->bind();
-		fullbright_shader->uniform1f(LLViewerShaderMgr::FULLBRIGHT, 1.f);
-		fullbright_shader->uniform1f(LLViewerShaderMgr::TEXTURE_GAMMA, 1.f);
-
-        if (LLPipeline::sRenderingHUDs)
-	    {
-		    fullbright_shader->uniform1i(LLShaderMgr::NO_ATMO, 1);
-	    }
-	    else
-	    {
-		    fullbright_shader->uniform1i(LLShaderMgr::NO_ATMO, 0);
-	    }
-
-		U32 fullbright_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_COLOR | LLVertexBuffer::MAP_TEXTURE_INDEX;
 
-        if (pass == 0)
-        {
-            pushBatches(LLRenderPass::PASS_FULLBRIGHT, fullbright_mask, TRUE, TRUE);
-            pushBatches(LLRenderPass::PASS_MATERIAL_ALPHA_EMISSIVE, fullbright_mask, TRUE, TRUE);
-            pushBatches(LLRenderPass::PASS_SPECMAP_EMISSIVE, fullbright_mask, TRUE, TRUE);
-            pushBatches(LLRenderPass::PASS_NORMMAP_EMISSIVE, fullbright_mask, TRUE, TRUE);
-            pushBatches(LLRenderPass::PASS_NORMSPEC_EMISSIVE, fullbright_mask, TRUE, TRUE);
-        }
-        else
-        {
-            pushRiggedBatches(LLRenderPass::PASS_FULLBRIGHT_RIGGED, fullbright_mask, TRUE, TRUE);
-            pushRiggedBatches(LLRenderPass::PASS_MATERIAL_ALPHA_EMISSIVE_RIGGED, fullbright_mask, TRUE, TRUE);
-            pushRiggedBatches(LLRenderPass::PASS_SPECMAP_EMISSIVE_RIGGED, fullbright_mask, TRUE, TRUE);
-            pushRiggedBatches(LLRenderPass::PASS_NORMMAP_EMISSIVE_RIGGED, fullbright_mask, TRUE, TRUE);
-            pushRiggedBatches(LLRenderPass::PASS_NORMSPEC_EMISSIVE_RIGGED, fullbright_mask, TRUE, TRUE);
-        }
-	}
+	U32 mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_COLOR | LLVertexBuffer::MAP_TEXTURE_INDEX;
 
-	stop_glerror();
+    // render static
+    setup_fullbright_shader(shader);
+    pushBatches(LLRenderPass::PASS_FULLBRIGHT, mask, TRUE, TRUE);
+    pushBatches(LLRenderPass::PASS_MATERIAL_ALPHA_EMISSIVE, mask, TRUE, TRUE);
+    pushBatches(LLRenderPass::PASS_SPECMAP_EMISSIVE, mask, TRUE, TRUE);
+    pushBatches(LLRenderPass::PASS_NORMMAP_EMISSIVE, mask, TRUE, TRUE);
+    pushBatches(LLRenderPass::PASS_NORMSPEC_EMISSIVE, mask, TRUE, TRUE);
+ 
+    // render rigged
+    setup_fullbright_shader(shader->mRiggedVariant);
+    pushRiggedBatches(LLRenderPass::PASS_FULLBRIGHT_RIGGED, mask, TRUE, TRUE);
+    pushRiggedBatches(LLRenderPass::PASS_MATERIAL_ALPHA_EMISSIVE_RIGGED, mask, TRUE, TRUE);
+    pushRiggedBatches(LLRenderPass::PASS_SPECMAP_EMISSIVE_RIGGED, mask, TRUE, TRUE);
+    pushRiggedBatches(LLRenderPass::PASS_NORMMAP_EMISSIVE_RIGGED, mask, TRUE, TRUE);
+    pushRiggedBatches(LLRenderPass::PASS_NORMSPEC_EMISSIVE_RIGGED, mask, TRUE, TRUE);
 }
 
 S32 LLDrawPoolFullbright::getNumPasses()
 { 
-	return 2;
+	return 1;
 }
 
-
-void LLDrawPoolFullbrightAlphaMask::beginPostDeferredPass(S32 pass)
+void LLDrawPoolFullbrightAlphaMask::renderPostDeferred(S32 pass)
 {
-    bool rigged = (pass == 1);
+	LL_RECORD_BLOCK_TIME(FTM_RENDER_FULLBRIGHT);
+    
+    LLGLSLShader* shader = nullptr;
     if (LLPipeline::sRenderingHUDs)
     {
-        gObjectFullbrightAlphaMaskProgram.bind(rigged);
-		LLGLSLShader::sCurBoundShaderPtr->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 1.0f);
-        LLGLSLShader::sCurBoundShaderPtr->uniform1i(LLShaderMgr::NO_ATMO, 1);
+        shader = &gObjectFullbrightAlphaMaskProgram;
     }
-	else if (LLPipeline::sRenderDeferred)
-	{
+    else if (LLPipeline::sRenderDeferred)
+    {
         if (LLPipeline::sUnderWaterRender)
-		{
-            gDeferredFullbrightAlphaMaskWaterProgram.bind(rigged);
-            LLGLSLShader::sCurBoundShaderPtr->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 2.2f);
-            LLGLSLShader::sCurBoundShaderPtr->uniform1i(LLShaderMgr::NO_ATMO, 1);
-		}
-		else
-		{
-			gDeferredFullbrightAlphaMaskProgram.bind(rigged);
-            LLGLSLShader::sCurBoundShaderPtr->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 2.2f);
-            LLGLSLShader::sCurBoundShaderPtr->uniform1i(LLShaderMgr::NO_ATMO, 0);
-		}
+        {
+            shader = &gDeferredFullbrightAlphaMaskWaterProgram;
+        }
+        else
+        {
+            shader = &gDeferredFullbrightAlphaMaskProgram;
+        }
     }
     else
     {
-		gObjectFullbrightAlphaMaskProgram.bind(rigged);
-        LLGLSLShader::sCurBoundShaderPtr->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 1.0f);
-        LLGLSLShader::sCurBoundShaderPtr->uniform1i(LLShaderMgr::NO_ATMO, 0);
-	}
-}
+        shader = &gObjectFullbrightAlphaMaskProgram;
+    }
 
-void LLDrawPoolFullbrightAlphaMask::renderPostDeferred(S32 pass)
-{
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_FULLBRIGHT);
 	LLGLDisable blend(GL_BLEND);
 	U32 fullbright_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_COLOR | LLVertexBuffer::MAP_TEXTURE_INDEX;
-    if (pass == 0)
-    {
-        pushMaskBatches(LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK, fullbright_mask, TRUE, TRUE);
-    }
-    else
-    {
-        pushRiggedMaskBatches(LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK_RIGGED, fullbright_mask, TRUE, TRUE);
-    }
-}
-
-void LLDrawPoolFullbrightAlphaMask::endPostDeferredPass(S32 pass)
-{
-    LLGLSLShader::sCurBoundShaderPtr->unbind();
-	LLRenderPass::endRenderPass(pass);
+    
+    // render static
+    setup_fullbright_shader(shader);
+    pushMaskBatches(LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK, fullbright_mask, TRUE, TRUE);
+    
+    // render rigged
+    setup_fullbright_shader(shader->mRiggedVariant);
+    pushRiggedMaskBatches(LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK_RIGGED, fullbright_mask, TRUE, TRUE);
 }
 
-
diff --git a/indra/newview/lldrawpoolsimple.h b/indra/newview/lldrawpoolsimple.h
index d6fecdd23c..cccbe5e495 100644
--- a/indra/newview/lldrawpoolsimple.h
+++ b/indra/newview/lldrawpoolsimple.h
@@ -46,18 +46,12 @@ public:
 	LLDrawPoolSimple();
 	
     S32 getNumDeferredPasses() override;
-	void beginDeferredPass(S32 pass) override;
-	void endDeferredPass(S32 pass) override;
 	void renderDeferred(S32 pass) override;
 
-	void beginRenderPass(S32 pass) override;
-	void endRenderPass(S32 pass) override;
 	/// We need two passes so we can handle emissive materials separately.
     S32	 getNumPasses() override;
 	void render(S32 pass = 0) override;
 	void prerender() override;
-
-    LLGLSLShader* mShader = nullptr;
 };
 
 class LLDrawPoolGrass : public LLRenderPass
@@ -101,14 +95,10 @@ public:
 
 	LLDrawPoolAlphaMask();
 
-	/*virtual*/ S32 getNumDeferredPasses() { return 2; }
-	/*virtual*/ void beginDeferredPass(S32 pass);
-	/*virtual*/ void endDeferredPass(S32 pass);
+	/*virtual*/ S32 getNumDeferredPasses() { return 1; }
 	/*virtual*/ void renderDeferred(S32 pass);
 
-	/*virtual*/ S32	 getNumPasses() { return 2; }
-	/*virtual*/ void beginRenderPass(S32 pass);
-	/*virtual*/ void endRenderPass(S32 pass);
+	/*virtual*/ S32	 getNumPasses() { return 1; }
 	/*virtual*/ void render(S32 pass = 0);
 	/*virtual*/ void prerender();
 
@@ -127,14 +117,10 @@ public:
 
 	LLDrawPoolFullbrightAlphaMask();
 	
-	/*virtual*/ S32 getNumPostDeferredPasses() { return 2; }
-	/*virtual*/ void beginPostDeferredPass(S32 pass);
-	/*virtual*/ void endPostDeferredPass(S32 pass);
+	/*virtual*/ S32 getNumPostDeferredPasses() { return 1; }
 	/*virtual*/ void renderPostDeferred(S32 pass);
 
-	/*virtual*/ S32	 getNumPasses() { return 2; }
-	/*virtual*/ void beginRenderPass(S32 pass);
-	/*virtual*/ void endRenderPass(S32 pass);
+	/*virtual*/ S32	 getNumPasses() { return 1; }
 	/*virtual*/ void render(S32 pass = 0);
 	/*virtual*/ void prerender();
 };
@@ -153,13 +139,9 @@ public:
 
 	LLDrawPoolFullbright();
 	
-	/*virtual*/ S32 getNumPostDeferredPasses() { return 2; }
-	/*virtual*/ void beginPostDeferredPass(S32 pass);
-	/*virtual*/ void endPostDeferredPass(S32 pass);
+	/*virtual*/ S32 getNumPostDeferredPasses() { return 1; }
 	/*virtual*/ void renderPostDeferred(S32 pass);
 
-	/*virtual*/ void beginRenderPass(S32 pass);
-	/*virtual*/ void endRenderPass(S32 pass);
 	/*virtual*/ S32	 getNumPasses();
 	/*virtual*/ void render(S32 pass = 0);
 	/*virtual*/ void prerender();
@@ -182,11 +164,11 @@ public:
 
 	virtual void prerender() { }
 
-	/*virtual*/ S32 getNumPostDeferredPasses() { return 2; }
-	/*virtual*/ void beginPostDeferredPass(S32 pass); 
-	/*virtual*/ void endPostDeferredPass(S32 pass);
+	/*virtual*/ S32 getNumPostDeferredPasses() { return 1; }
 	/*virtual*/ void renderPostDeferred(S32 pass);
 
+    void render(LLGLSLShader* shader);
+
 	/*virtual*/ S32 getNumPasses();
 
 	void render(S32 pass = 0);
-- 
cgit v1.2.3


From e7830b39f01d9f9c82e9e2029634dffb8386b24e Mon Sep 17 00:00:00 2001
From: Dave Parks <davep@lindenlab.com>
Date: Fri, 3 Dec 2021 15:07:31 +0000
Subject: SL-16436 and SL-16327 Fix for RenderDebugGL test failures and fix for
 grey textures

---
 indra/llrender/llgl.cpp                            |  44 ++-
 indra/llrender/llimagegl.cpp                       |  34 +-
 indra/llrender/llimagegl.h                         |  10 +-
 indra/llrender/llrender.cpp                        |   6 +-
 indra/newview/CMakeLists.txt                       |   4 -
 .../class1/deferred/avatarAlphaShadowF.glsl        |   4 +-
 .../class1/deferred/avatarAlphaShadowV.glsl        |   3 -
 indra/newview/lldrawable.h                         |   5 +-
 indra/newview/lldrawpooltree.cpp                   |  10 +-
 indra/newview/llface.h                             |   1 -
 indra/newview/llglsandbox.cpp                      |  15 +
 indra/newview/llspatialpartition.cpp               | 130 +------
 indra/newview/llspatialpartition.h                 |  40 +-
 indra/newview/lltextureatlas.cpp                   | 416 ---------------------
 indra/newview/lltextureatlas.h                     |  90 -----
 indra/newview/lltextureatlasmanager.cpp            | 268 -------------
 indra/newview/lltextureatlasmanager.h              | 105 ------
 indra/newview/llviewertexture.cpp                  |  71 ++--
 indra/newview/llvovolume.cpp                       |  11 +-
 indra/newview/pipeline.cpp                         |  28 +-
 indra/newview/pipeline.h                           |   3 +
 21 files changed, 166 insertions(+), 1132 deletions(-)
 delete mode 100644 indra/newview/lltextureatlas.cpp
 delete mode 100644 indra/newview/lltextureatlas.h
 delete mode 100644 indra/newview/lltextureatlasmanager.cpp
 delete mode 100644 indra/newview/lltextureatlasmanager.h

(limited to 'indra')

diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp
index 58183adfce..f24bf6ec78 100644
--- a/indra/llrender/llgl.cpp
+++ b/indra/llrender/llgl.cpp
@@ -88,24 +88,32 @@ void APIENTRY gl_debug_callback(GLenum source,
 {
 	if (gGLDebugLoggingEnabled)
 	{
-	if (severity == GL_DEBUG_SEVERITY_HIGH_ARB)
-	{
-		LL_WARNS() << "----- GL ERROR --------" << LL_ENDL;
-	}
-	else
-	{
-		LL_WARNS() << "----- GL WARNING -------" << LL_ENDL;
-	}
-	LL_WARNS() << "Type: " << std::hex << type << LL_ENDL;
-	LL_WARNS() << "ID: " << std::hex << id << LL_ENDL;
-	LL_WARNS() << "Severity: " << std::hex << severity << LL_ENDL;
-	LL_WARNS() << "Message: " << message << LL_ENDL;
-	LL_WARNS() << "-----------------------" << LL_ENDL;
-	if (severity == GL_DEBUG_SEVERITY_HIGH_ARB)
-	{
-		LL_ERRS() << "Halting on GL Error" << LL_ENDL;
-	}
-}
+
+        if (severity != GL_DEBUG_SEVERITY_HIGH_ARB &&
+            severity != GL_DEBUG_SEVERITY_MEDIUM_ARB &&
+            severity != GL_DEBUG_SEVERITY_LOW_ARB)
+        { //suppress out-of-spec messages sent by nvidia driver (mostly vertexbuffer hints)
+            return;
+        }
+
+	    if (severity == GL_DEBUG_SEVERITY_HIGH_ARB)
+	    {
+		    LL_WARNS() << "----- GL ERROR --------" << LL_ENDL;
+	    }
+	    else
+	    {
+		    LL_WARNS() << "----- GL WARNING -------" << LL_ENDL;
+	    }
+	    LL_WARNS() << "Type: " << std::hex << type << LL_ENDL;
+	    LL_WARNS() << "ID: " << std::hex << id << LL_ENDL;
+	    LL_WARNS() << "Severity: " << std::hex << severity << LL_ENDL;
+	    LL_WARNS() << "Message: " << message << LL_ENDL;
+	    LL_WARNS() << "-----------------------" << LL_ENDL;
+	    if (severity == GL_DEBUG_SEVERITY_HIGH_ARB)
+	    {
+		    LL_ERRS() << "Halting on GL Error" << LL_ENDL;
+	    }
+    }
 }
 #endif
 
diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp
index 894eb8c773..d3af27272b 100644
--- a/indra/llrender/llimagegl.cpp
+++ b/indra/llrender/llimagegl.cpp
@@ -41,6 +41,10 @@
 #include "llrender.h"
 #include "llwindow.h"
 
+#if !LL_IMAGEGL_THREAD_CHECK
+#define checkActiveThread()
+#endif
+
 //----------------------------------------------------------------------------
 const F32 MIN_TEXTURE_LIFETIME = 10.f;
 
@@ -437,6 +441,10 @@ LLImageGL::~LLImageGL()
 
 void LLImageGL::init(BOOL usemipmaps)
 {
+#if LL_IMAGEGL_THREAD_CHECK
+    mActiveThread = LLThread::currentID();
+#endif
+
 	// keep these members in the same order as declared in llimagehl.h
 	// so that it is obvious by visual inspection if we forgot to
 	// init a field.
@@ -1317,6 +1325,8 @@ void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 widt
 BOOL LLImageGL::createGLTexture()
 {
     LL_PROFILE_ZONE_SCOPED;
+    checkActiveThread();
+
 	if (gGLManager.mIsDisabled)
 	{
 		LL_WARNS() << "Trying to create a texture while GL is disabled!" << LL_ENDL;
@@ -1349,6 +1359,8 @@ BOOL LLImageGL::createGLTexture()
 BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename/*=0*/, BOOL to_create, S32 category)
 {
     LL_PROFILE_ZONE_SCOPED;
+    checkActiveThread();
+
 	if (gGLManager.mIsDisabled)
 	{
 		LL_WARNS() << "Trying to create a texture while GL is disabled!" << LL_ENDL;
@@ -1462,6 +1474,8 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S
 BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_hasmips, S32 usename)
 {
     LL_PROFILE_ZONE_SCOPED;
+    checkActiveThread();
+
     llassert(data_in);
     stop_glerror();
 
@@ -1576,6 +1590,7 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_
     // mark this as bound at this point, so we don't throw it out immediately
     mLastBindTime = sLastFrameTime;
 
+    checkActiveThread();
     return TRUE;
 }
 
@@ -1690,18 +1705,10 @@ BOOL LLImageGL::readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool compre
 	return TRUE ;
 }
 
-void LLImageGL::deleteDeadTextures()
-{
-	bool reset = false;
-
-	if (reset)
-	{
-		gGL.getTexUnit(0)->activate();
-	}
-}
-		
 void LLImageGL::destroyGLTexture()
 {
+    checkActiveThread();
+
 	if (mTexName != 0)
 	{
 		if(mTextureMemory != S32Bytes(0))
@@ -1720,6 +1727,7 @@ void LLImageGL::destroyGLTexture()
 //force to invalidate the gl texture, most likely a sculpty texture
 void LLImageGL::forceToInvalidateGLTexture()
 {
+    checkActiveThread();
 	if (mTexName != 0)
 	{
 		destroyGLTexture();
@@ -2196,6 +2204,12 @@ void LLImageGL::resetCurTexSizebar()
 	sCurTexPickSize = -1 ;
 }
 //----------------------------------------------------------------------------
+#if LL_IMAGEGL_THREAD_CHECK
+void LLImageGL::checkActiveThread()
+{
+    llassert(mActiveThread == LLThread::currentID());
+}
+#endif
 
 //----------------------------------------------------------------------------
 
diff --git a/indra/llrender/llimagegl.h b/indra/llrender/llimagegl.h
index ae773bb362..28996a554a 100644
--- a/indra/llrender/llimagegl.h
+++ b/indra/llrender/llimagegl.h
@@ -40,7 +40,8 @@
 #include "threadpool.h"
 #include "workqueue.h"
 
-class LLTextureAtlas ;
+#define LL_IMAGEGL_THREAD_CHECK 0 //set to 1 to enable thread debugging for ImageGL
+
 class LLWindow;
 
 #define BYTES_TO_MEGA_BYTES(x) ((x) >> 20)
@@ -54,7 +55,6 @@ public:
 	// These 2 functions replace glGenTextures() and glDeleteTextures()
 	static void generateTextures(S32 numTextures, U32 *textures);
 	static void deleteTextures(S32 numTextures, const U32 *textures);
-	static void deleteDeadTextures();
 
 	// Size calculation
 	static S32 dataFormatBits(S32 dataformat);
@@ -189,6 +189,12 @@ public:
 	BOOL preAddToAtlas(S32 discard_level, const LLImageRaw* raw_image);
 	void postAddToAtlas() ;	
 
+#if LL_IMAGEGL_THREAD_CHECK
+    // thread debugging
+    std::thread::id mActiveThread;
+    void checkActiveThread();
+#endif
+
 public:
 	// Various GL/Rendering options
 	S32Bytes mTextureMemory;
diff --git a/indra/llrender/llrender.cpp b/indra/llrender/llrender.cpp
index 235f8a8eb0..8b4f250894 100644
--- a/indra/llrender/llrender.cpp
+++ b/indra/llrender/llrender.cpp
@@ -181,7 +181,11 @@ void LLTexUnit::bindFast(LLTexture* texture)
     mCurrTexture = gl_tex->getTexName();
     if (!mCurrTexture)
     {
-        mCurrTexture = LLImageGL::sDefaultGLTexture->getTexName();
+        LL_PROFILE_ZONE_NAMED("MISSING TEXTURE");
+        //if deleted, will re-generate it immediately
+        texture->forceImmediateUpdate();
+        gl_tex->forceUpdateBindStats();
+        texture->bindDefaultImage(mIndex);
     }
     glBindTexture(sGLTextureType[gl_tex->getTarget()], mCurrTexture);
     mHasMipMaps = gl_tex->mHasMipMaps;
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 4a7f17f15b..8157d1566a 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -590,8 +590,6 @@ set(viewer_SOURCE_FILES
     llsyswellwindow.cpp
     llteleporthistory.cpp
     llteleporthistorystorage.cpp
-    lltextureatlas.cpp
-    lltextureatlasmanager.cpp
     lltexturecache.cpp
     lltexturectrl.cpp
     lltexturefetch.cpp
@@ -1219,8 +1217,6 @@ set(viewer_HEADER_FILES
     lltable.h
     llteleporthistory.h
     llteleporthistorystorage.h
-    lltextureatlas.h
-    lltextureatlasmanager.h
     lltexturecache.h
     lltexturectrl.h
     lltexturefetch.h
diff --git a/indra/newview/app_settings/shaders/class1/deferred/avatarAlphaShadowF.glsl b/indra/newview/app_settings/shaders/class1/deferred/avatarAlphaShadowF.glsl
index ef49b6f4e8..1b16e4eb09 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/avatarAlphaShadowF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/avatarAlphaShadowF.glsl
@@ -40,11 +40,11 @@ VARYING vec4 post_pos;
 VARYING float pos_w;
 VARYING float target_pos_x;
 VARYING vec2 vary_texcoord0;
-VARYING vec4 vertex_color;
+uniform vec4 color;
 
 void main() 
 {
-	float alpha = texture2D(diffuseMap, vary_texcoord0.xy).a * vertex_color.a;
+	float alpha = texture2D(diffuseMap, vary_texcoord0.xy).a * color.a;
 
 	if (alpha < 0.05) // treat as totally transparent
 	{
diff --git a/indra/newview/app_settings/shaders/class1/deferred/avatarAlphaShadowV.glsl b/indra/newview/app_settings/shaders/class1/deferred/avatarAlphaShadowV.glsl
index d1d7ece6fe..1c5b142ebd 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/avatarAlphaShadowV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/avatarAlphaShadowV.glsl
@@ -30,7 +30,6 @@ uniform float shadow_target_width;
 mat4 getSkinnedTransform();
 void passTextureIndex();
 
-ATTRIBUTE vec4 diffuse_color;
 ATTRIBUTE vec3 position;
 ATTRIBUTE vec3 normal;
 ATTRIBUTE vec2 texcoord0;
@@ -41,7 +40,6 @@ VARYING vec4 post_pos;
 VARYING float pos_w;
 VARYING float target_pos_x;
 VARYING vec2 vary_texcoord0;
-VARYING vec4 vertex_color;
 
 void main()
 {
@@ -68,7 +66,6 @@ void main()
 
 	vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy;
 
-	vertex_color = diffuse_color;
 #if !DEPTH_CLAMP
 	post_pos = pos;
 
diff --git a/indra/newview/lldrawable.h b/indra/newview/lldrawable.h
index 6002e3e0dd..9a9f6cf7c2 100644
--- a/indra/newview/lldrawable.h
+++ b/indra/newview/lldrawable.h
@@ -64,6 +64,8 @@ class LLDrawable
 {
     LL_ALIGN_NEW;
 public:
+    typedef std::vector<LLFace*> face_list_t;
+
 	LLDrawable(const LLDrawable& rhs) 
         : LLViewerOctreeEntryData(rhs)
 	{
@@ -129,6 +131,7 @@ public:
 	
 	inline LLFace*      getFace(const S32 i) const;
 	inline S32			getNumFaces()      	 const;
+    face_list_t& getFaces() { return mFaces; }
 
 	//void                removeFace(const S32 i); // SJB: Avoid using this, it's slow
 	LLFace*				addFace(LLFacePool *poolp, LLViewerTexture *texturep);
@@ -297,8 +300,6 @@ public:
 	static F32 sCurPixelAngle; //current pixels per radian
 
 private:
-	typedef std::vector<LLFace*> face_list_t;
-	
 	U32				mState;
 	S32				mRenderType;
 	LLPointer<LLViewerObject> mVObjp;
diff --git a/indra/newview/lldrawpooltree.cpp b/indra/newview/lldrawpooltree.cpp
index ac957f1cbd..facfb235c9 100644
--- a/indra/newview/lldrawpooltree.cpp
+++ b/indra/newview/lldrawpooltree.cpp
@@ -92,8 +92,9 @@ void LLDrawPoolTree::render(S32 pass)
 
 	LLGLState test(GL_ALPHA_TEST, 0);
 
-	gGL.getTexUnit(sDiffTex)->bind(mTexturep);
-				
+	gGL.getTexUnit(sDiffTex)->bindFast(mTexturep);
+    gPipeline.touchTexture(mTexturep, 1024.f * 1024.f); // <=== keep Linden tree textures at full res
+
 	for (std::vector<LLFace*>::iterator iter = mDrawFace.begin();
 		 iter != mDrawFace.end(); iter++)
 	{
@@ -116,9 +117,8 @@ void LLDrawPoolTree::render(S32 pass)
 				gPipeline.mMatrixOpCount++;
 			}
 
-			buff->setBuffer(LLDrawPoolTree::VERTEX_DATA_MASK);
-			buff->drawRange(LLRender::TRIANGLES, 0, buff->getNumVerts()-1, buff->getNumIndices(), 0); 
-			gPipeline.addTrianglesDrawn(buff->getNumIndices());
+			buff->setBufferFast(LLDrawPoolTree::VERTEX_DATA_MASK);
+			buff->drawRangeFast(LLRender::TRIANGLES, 0, buff->getNumVerts()-1, buff->getNumIndices(), 0); 
 		}
 	}
 }
diff --git a/indra/newview/llface.h b/indra/newview/llface.h
index c533edede4..79f50f2273 100644
--- a/indra/newview/llface.h
+++ b/indra/newview/llface.h
@@ -47,7 +47,6 @@ class LLTextureEntry;
 class LLVertexProgram;
 class LLViewerTexture;
 class LLGeometryManager;
-class LLTextureAtlasSlot;
 class LLDrawInfo;
 class LLMeshSkinInfo;
 
diff --git a/indra/newview/llglsandbox.cpp b/indra/newview/llglsandbox.cpp
index a135ef0814..0b5064c77d 100644
--- a/indra/newview/llglsandbox.cpp
+++ b/indra/newview/llglsandbox.cpp
@@ -1115,6 +1115,14 @@ F32 gpu_benchmark()
 	// ensure matched pair of bind() and unbind() calls
 	ShaderBinder binder(gBenchmarkProgram);
 
+    U32 glarray = 0;
+
+    if (LLRender::sGLCoreProfile)
+    {
+        glGenVertexArrays(1, &glarray);
+        glBindVertexArray(glarray);
+    }
+
 	buff->setBuffer(LLVertexBuffer::MAP_VERTEX);
 	glFinish();
 
@@ -1147,6 +1155,13 @@ F32 gpu_benchmark()
 		}
 	}
 
+    if (LLRender::sGLCoreProfile)
+    {
+        glBindVertexArray(0);
+        glDeleteVertexArrays(1, &glarray);
+    }
+
+
 	std::sort(results.begin(), results.end());
 
 	F32 gbps = results[results.size()/2];
diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp
index 25d6106361..48e9f3726f 100644
--- a/indra/newview/llspatialpartition.cpp
+++ b/indra/newview/llspatialpartition.cpp
@@ -51,7 +51,6 @@
 #include "llphysicsshapebuilderutil.h"
 #include "llvoavatar.h"
 #include "llvolumemgr.h"
-#include "lltextureatlas.h"
 #include "llviewershadermgr.h"
 #include "llcontrolavatar.h"
 
@@ -128,129 +127,6 @@ LLSpatialGroup::~LLSpatialGroup()
 	sNodeCount--;
 
 	clearDrawMap();
-	clearAtlasList() ;
-}
-
-BOOL LLSpatialGroup::hasAtlas(LLTextureAtlas* atlasp)
-{
-	S8 type = atlasp->getComponents() - 1 ;
-	for(std::list<LLTextureAtlas*>::iterator iter = mAtlasList[type].begin(); iter != mAtlasList[type].end() ; ++iter)
-	{
-		if(atlasp == *iter)
-		{
-			return TRUE ;
-		}
-	}
-	return FALSE ;
-}
-
-void LLSpatialGroup::addAtlas(LLTextureAtlas* atlasp, S8 recursive_level) 
-{		
-	if(!hasAtlas(atlasp))
-	{
-		mAtlasList[atlasp->getComponents() - 1].push_back(atlasp) ;
-		atlasp->addSpatialGroup(this) ;
-	}
-	
-	--recursive_level;
-	if(recursive_level)//levels propagating up.
-	{
-		LLSpatialGroup* parent = getParent() ;
-		if(parent)
-		{
-			parent->addAtlas(atlasp, recursive_level) ;
-		}
-	}	
-}
-
-void LLSpatialGroup::removeAtlas(LLTextureAtlas* atlasp, BOOL remove_group, S8 recursive_level) 
-{
-	mAtlasList[atlasp->getComponents() - 1].remove(atlasp) ;
-	if(remove_group)
-	{
-		atlasp->removeSpatialGroup(this) ;
-	}
-
-	--recursive_level;
-	if(recursive_level)//levels propagating up.
-	{
-		LLSpatialGroup* parent = getParent() ;
-		if(parent)
-		{
-			parent->removeAtlas(atlasp, recursive_level) ;
-		}
-	}	
-}
-
-void LLSpatialGroup::clearAtlasList() 
-{
-	std::list<LLTextureAtlas*>::iterator iter ;
-	for(S8 i = 0 ; i < 4 ; i++)
-	{
-		if(mAtlasList[i].size() > 0)
-		{
-			for(iter = mAtlasList[i].begin(); iter != mAtlasList[i].end() ; ++iter)
-			{
-				((LLTextureAtlas*)*iter)->removeSpatialGroup(this) ;			
-			}
-			mAtlasList[i].clear() ;
-		}
-	}
-}
-
-LLTextureAtlas* LLSpatialGroup::getAtlas(S8 ncomponents, S8 to_be_reserved, S8 recursive_level)
-{
-	S8 type = ncomponents - 1 ;
-	if(mAtlasList[type].size() > 0)
-	{
-		for(std::list<LLTextureAtlas*>::iterator iter = mAtlasList[type].begin(); iter != mAtlasList[type].end() ; ++iter)
-		{
-			if(!((LLTextureAtlas*)*iter)->isFull(to_be_reserved))
-			{
-				return *iter ;
-			}
-		}
-	}
-
-	--recursive_level;
-	if(recursive_level)
-	{
-		LLSpatialGroup* parent = getParent() ;
-		if(parent)
-		{
-			return parent->getAtlas(ncomponents, to_be_reserved, recursive_level) ;
-		}
-	}
-	return NULL ;
-}
-
-void LLSpatialGroup::setCurUpdatingSlot(LLTextureAtlasSlot* slotp) 
-{ 
-	mCurUpdatingSlotp = slotp;
-
-	//if(!hasAtlas(mCurUpdatingSlotp->getAtlas()))
-	//{
-	//	addAtlas(mCurUpdatingSlotp->getAtlas()) ;
-	//}
-}
-
-LLTextureAtlasSlot* LLSpatialGroup::getCurUpdatingSlot(LLViewerTexture* imagep, S8 recursive_level) 
-{ 
-	if(gFrameCount && mCurUpdatingTime == gFrameCount && mCurUpdatingTexture == imagep)
-	{
-		return mCurUpdatingSlotp ;
-	}
-
-	//--recursive_level ;
-	//if(recursive_level)
-	//{
-	//	LLSpatialGroup* parent = getParent() ;
-	//	if(parent)
-	//	{
-	//		return parent->getCurUpdatingSlot(imagep, recursive_level) ;
-	//	}
-	//}
-	return NULL ;
 }
 
 void LLSpatialGroup::clearDrawMap()
@@ -665,11 +541,7 @@ LLSpatialGroup::LLSpatialGroup(OctreeNode* node, LLSpatialPartition* part) : LLO
 	mDistance(0.f),
 	mDepth(0.f),
 	mLastUpdateDistance(-1.f), 
-	mLastUpdateTime(gFrameTimeSeconds),
-	mAtlasList(4),
-	mCurUpdatingTime(0),
-	mCurUpdatingSlotp(NULL),
-	mCurUpdatingTexture (NULL)
+	mLastUpdateTime(gFrameTimeSeconds)
 {
 	ll_assert_aligned(this,16);
 	
diff --git a/indra/newview/llspatialpartition.h b/indra/newview/llspatialpartition.h
index 5fca516f19..58d821353a 100644
--- a/indra/newview/llspatialpartition.h
+++ b/indra/newview/llspatialpartition.h
@@ -50,8 +50,6 @@ class LLViewerOctreePartition;
 class LLSpatialPartition;
 class LLSpatialBridge;
 class LLSpatialGroup;
-class LLTextureAtlas;
-class LLTextureAtlasSlot;
 class LLViewerRegion;
 
 void pushVerts(LLFace* face, U32 mask);
@@ -91,6 +89,10 @@ public:
 	LLPointer<LLViewerTexture>     mTexture;
 	std::vector<LLPointer<LLViewerTexture> > mTextureList;
 
+    // virtual size of mTexture and mTextureList textures
+    // used to update the decode priority of textures in this DrawInfo
+    std::vector<F32> mTextureListVSize;
+
 	S32 mDebugColor;
 	const LLMatrix4* mTextureMatrix;
 	const LLMatrix4* mModelMatrix;
@@ -304,49 +306,15 @@ public:
 	virtual void handleDestruction(const TreeNode* node);
 	virtual void handleChildAddition(const OctreeNode* parent, OctreeNode* child);
 
-//-------------------
-//for atlas use
-//-------------------
-	//atlas	
-	void setCurUpdatingTime(U32 t) {mCurUpdatingTime = t ;}
-	U32  getCurUpdatingTime() const { return mCurUpdatingTime ;}
-	
-	void setCurUpdatingSlot(LLTextureAtlasSlot* slotp) ;
-	LLTextureAtlasSlot* getCurUpdatingSlot(LLViewerTexture* imagep, S8 recursive_level = 3) ;
-
-	void setCurUpdatingTexture(LLViewerTexture* tex){ mCurUpdatingTexture = tex ;}
-	LLViewerTexture* getCurUpdatingTexture() const { return mCurUpdatingTexture ;}
-	
-	BOOL hasAtlas(LLTextureAtlas* atlasp) ;
-	LLTextureAtlas* getAtlas(S8 ncomponents, S8 to_be_reserved, S8 recursive_level = 3) ;
-	void addAtlas(LLTextureAtlas* atlasp, S8 recursive_level = 3) ;
-	void removeAtlas(LLTextureAtlas* atlasp, BOOL remove_group = TRUE, S8 recursive_level = 3) ;
-	void clearAtlasList() ;
-
 public:
-
 	LL_ALIGN_16(LLVector4a mViewAngle);
 	LL_ALIGN_16(LLVector4a mLastUpdateViewAngle);
 
 	F32 mObjectBoxSize; //cached mObjectBounds[1].getLength3()
-		
-private:
-	U32                     mCurUpdatingTime ;
-	//do not make the below two to use LLPointer
-	//because mCurUpdatingTime invalidates them automatically.
-	LLTextureAtlasSlot* mCurUpdatingSlotp ;
-	LLViewerTexture*          mCurUpdatingTexture ;
-
-	std::vector< std::list<LLTextureAtlas*> > mAtlasList ; 
-//-------------------
-//end for atlas use
-//-------------------
 
 protected:
 	virtual ~LLSpatialGroup();
 
-	static S32 sLODSeed;
-
 public:
 	bridge_list_t mBridgeList;
 	buffer_map_t mBufferMap; //used by volume buffers to attempt to reuse vertex buffers
diff --git a/indra/newview/lltextureatlas.cpp b/indra/newview/lltextureatlas.cpp
deleted file mode 100644
index 1c8e4f796e..0000000000
--- a/indra/newview/lltextureatlas.cpp
+++ /dev/null
@@ -1,416 +0,0 @@
-/** 
- * @file lltextureatlas.cpp
- * @brief LLTextureAtlas class implementation.
- *
- * $LicenseInfo:firstyear=2002&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- * 
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- * 
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
- * $/LicenseInfo$
- */
-#include "llviewerprecompiledheaders.h"
-#include "linden_common.h"
-#include "llerror.h"
-#include "llimage.h"
-#include "llmath.h"
-#include "llgl.h"
-#include "llrender.h"
-#include "lltextureatlas.h"
-
-//-------------------
-S16 LLTextureAtlas::sMaxSubTextureSize = 64 ;
-S16 LLTextureAtlas::sSlotSize = 32 ;
-
-#ifndef DEBUG_ATLAS
-#define DEBUG_ATLAS 0
-#endif
-
-#ifndef DEBUG_USAGE_BITS
-#define DEBUG_USAGE_BITS 0
-#endif
-//**************************************************************************************************************
-LLTextureAtlas::LLTextureAtlas(U8 ncomponents, S16 atlas_dim) : 
-    LLViewerTexture(atlas_dim * sSlotSize, atlas_dim * sSlotSize, ncomponents, TRUE),
-	mAtlasDim(atlas_dim),
-	mNumSlotsReserved(0),
-	mMaxSlotsInAtlas(atlas_dim * atlas_dim)
-{
-	generateEmptyUsageBits() ;
-
-	//generate an empty texture
-	generateGLTexture() ;
-	LLPointer<LLImageRaw> image_raw = new LLImageRaw(mFullWidth, mFullHeight, mComponents);
-	createGLTexture(0, image_raw, 0);
-	image_raw = NULL;
-}
-
-LLTextureAtlas::~LLTextureAtlas() 
-{
-	if(mSpatialGroupList.size() > 0)
-	{
-		LL_ERRS() << "Not clean up the spatial groups!" << LL_ENDL ;
-	}
-	releaseUsageBits() ;
-}
-
-//virtual 
-S8 LLTextureAtlas::getType() const
-{
-	return 0; //LLViewerTexture::ATLAS_TEXTURE ;
-}
-
-void LLTextureAtlas::getTexCoordOffset(S16 col, S16 row, F32& xoffset, F32& yoffset)
-{
-	xoffset = (F32)col / mAtlasDim ;
-	yoffset = (F32)row / mAtlasDim ;	
-}
-
-void LLTextureAtlas::getTexCoordScale(S32 w, S32 h, F32& xscale, F32& yscale)
-{
-	xscale = (F32)w / (mAtlasDim * sSlotSize) ;
-	yscale = (F32)h / (mAtlasDim * sSlotSize) ;	
-}
-
-//insert a texture piece into the atlas
-LLGLuint LLTextureAtlas::insertSubTexture(LLImageGL* source_gl_tex, S32 discard_level, const LLImageRaw* raw_image, S16 slot_col, S16 slot_row)
-{
-	if(!getTexName())
-	{
-		return 0 ;
-	}
-
-	S32 w = raw_image->getWidth() ;
-	S32 h = raw_image->getHeight() ;
-	if(w < 8 || w > sMaxSubTextureSize || h < 8 || h > sMaxSubTextureSize)
-	{
-		//size overflow
-		return 0 ;
-	}
-
-	BOOL res = gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, getTexName());
-	if (!res) 
-	{
-		LL_ERRS() << "bindTexture failed" << LL_ENDL;
-	}
-	
-	GLint xoffset = sSlotSize * slot_col ;
-	GLint yoffset = sSlotSize * slot_row ;
-
-	if(!source_gl_tex->preAddToAtlas(discard_level, raw_image))
-	{
-		return 0 ;
-	}
-
-	glTexSubImage2D(GL_TEXTURE_2D, 0, xoffset, yoffset, w, h,
-						mGLTexturep->getPrimaryFormat(), mGLTexturep->getFormatType(), raw_image->getData());
-	
-	source_gl_tex->postAddToAtlas() ;
-	return getTexName();
-}
-	
-//release a sub-texture slot from the atlas
-void LLTextureAtlas::releaseSlot(S16 slot_col, S16 slot_row, S8 slot_width)
-{
-	unmarkUsageBits(slot_width, slot_col, slot_row) ;
-	mNumSlotsReserved -= slot_width * slot_width ;
-}
-
-BOOL LLTextureAtlas::isEmpty() const 
-{
-	return !mNumSlotsReserved ;
-}
-	
-BOOL LLTextureAtlas::isFull(S8 to_be_reserved) const 
-{
-	return mNumSlotsReserved + to_be_reserved > mMaxSlotsInAtlas ;
-}
-F32  LLTextureAtlas::getFullness() const 
-{
-	return (F32)mNumSlotsReserved / mMaxSlotsInAtlas ;
-}
-
-void LLTextureAtlas::addSpatialGroup(LLSpatialGroup* groupp) 
-{
-	if(groupp && !hasSpatialGroup(groupp))
-	{
-		mSpatialGroupList.push_back(groupp);
-	}
-}
-
-void LLTextureAtlas::removeSpatialGroup(LLSpatialGroup* groupp) 
-{
-	if(groupp)
-	{
-		mSpatialGroupList.remove(groupp);
-	}
-}
-
-void LLTextureAtlas::clearSpatialGroup() 
-{
-	mSpatialGroupList.clear();
-}
-void LLTextureAtlas::removeLastSpatialGroup() 
-{
-	mSpatialGroupList.pop_back() ;
-}
-
-LLSpatialGroup* LLTextureAtlas::getLastSpatialGroup() 
-{
-	if(mSpatialGroupList.size() > 0)
-	{
-		return mSpatialGroupList.back() ;
-	}
-	return NULL ;
-}
-
-BOOL LLTextureAtlas::hasSpatialGroup(LLSpatialGroup* groupp) 
-{
-	for(std::list<LLSpatialGroup*>::iterator iter = mSpatialGroupList.begin(); iter != mSpatialGroupList.end() ; ++iter)
-	{
-		if(*iter == groupp)
-		{
-			return TRUE ;
-		}
-	}
-	return FALSE ;
-}
-
-//--------------------------------------------------------------------------------------
-//private
-void LLTextureAtlas::generateEmptyUsageBits()
-{
-	S32 col_len = (mAtlasDim + 7) >> 3 ;
-	mUsageBits = new U8*[mAtlasDim] ;
-	*mUsageBits = new U8[mAtlasDim * col_len] ;
-
-	mUsageBits[0] = *mUsageBits ;
-	for(S32 i = 1 ; i < mAtlasDim ; i++)
-	{
-	   mUsageBits[i] = mUsageBits[i-1] + col_len ;
-
-	   for(S32 j = 0 ; j < col_len ; j++)
-	   {
-		   //init by 0 for all bits.
-		   mUsageBits[i][j] = 0 ;
-	   }
-	}
-
-	//do not forget mUsageBits[0]!
-	for(S32 j = 0 ; j < col_len ; j++)
-	{
-		//init by 0 for all bits.
-		mUsageBits[0][j] = 0 ;
-	}
-
-	mTestBits = NULL ;
-#if DEBUG_USAGE_BITS
-	//------------
-	//test
-	mTestBits = new U8*[mAtlasDim] ;
-	*mTestBits = new U8[mAtlasDim * mAtlasDim] ;
-	mTestBits[0] = *mTestBits ;
-	for(S32 i = 1 ; i < mAtlasDim ; i++)
-	{
-	   mTestBits[i] = mTestBits[i-1] + mAtlasDim ;
-
-	   for(S32 j = 0 ; j < mAtlasDim ; j++)
-	   {
-		   //init by 0 for all bits.
-		   mTestBits[i][j] = 0 ;
-	   }
-	}
-
-	for(S32 j = 0 ; j < mAtlasDim ; j++)
-	{
-		//init by 0 for all bits.
-		mTestBits[0][j] = 0 ;
-	}
-#endif
-}
-
-void LLTextureAtlas::releaseUsageBits()
-{
-   if(mUsageBits)
-   {
-       delete[] *mUsageBits ;
-       delete[] mUsageBits ;
-   }
-   mUsageBits = NULL ;
-
-   //test
-   if( mTestBits)
-   {
-	   delete[] *mTestBits;
-	   delete[]  mTestBits;
-   }
-    mTestBits = NULL ;
-}
-
-void LLTextureAtlas::markUsageBits(S8 bits_len, U8 mask, S16 col, S16 row)
-{
-	S16 x = col >> 3 ;
-	
-	for(S8 i = 0 ; i < bits_len ; i++)
-	{
-		mUsageBits[row + i][x] |= mask ;
-	}
-
-#if DEBUG_USAGE_BITS
-	//test
-	for(S8 i = row ; i < row + bits_len ; i++)
-	{
-		for(S8 j = col ; j < col + bits_len ; j++)
-		{
-			mTestBits[i][j] = 1 ;
-		}
-	}
-#endif
-}
-
-void LLTextureAtlas::unmarkUsageBits(S8 bits_len, S16 col, S16 row)
-{
-	S16 x = col >> 3 ;
-	U8  mask = 1 ;
-	for(S8 i = 1 ; i < bits_len ; i++)
-	{
-		mask |= (1 << i) ;
-	}
-	mask <<= (col & 7) ;
-	mask = ~mask ;
-	
-	for(S8 i = 0 ; i < bits_len ; i++)
-	{
-		mUsageBits[row + i][x] &= mask ;
-	}
-
-#if DEBUG_USAGE_BITS
-	//test
-	for(S8 i = row ; i < row + bits_len ; i++)
-	{
-		for(S8 j = col ; j < col + bits_len ; j++)
-		{
-			mTestBits[i][j] = 0 ;
-		}
-	}
-#endif
-}
-
-//return true if any of bits in the range marked.
-BOOL LLTextureAtlas::areUsageBitsMarked(S8 bits_len, U8 mask, S16 col, S16 row)
-{
-	BOOL ret = FALSE ;	
-	S16 x = col >> 3 ;
-	
-	for(S8 i = 0 ; i < bits_len ; i++)
-	{
-		if(mUsageBits[row + i][x] & mask)
-		{
-			ret = TRUE ;
-			break ;
-			//return TRUE ;
-		}
-	}
-
-#if DEBUG_USAGE_BITS
-	//test
-	BOOL ret2 = FALSE ;
-	for(S8 i = row ; i < row + bits_len ; i++)
-	{
-		for(S8 j = col ; j < col + bits_len ; j++)
-		{
-			if(mTestBits[i][j])
-			{
-				ret2 = TRUE ;
-			}
-		}
-	}
-
-	if(ret != ret2)
-	{
-		LL_ERRS() << "bits map corrupted." << LL_ENDL ;
-	}
-#endif
-	return ret ;//FALSE ;
-}
-
-//----------------------------------------------------------------------
-//
-//index order: Z order, i.e.: 
-// |-----|-----|-----|-----|
-// |  10 |  11 | 14  | 15  |
-// |-----|-----|-----|-----|
-// |   8 |   9 | 12  | 13  |
-// |-----|-----|-----|-----|
-// |   2 |   3 |   6 |   7 |
-// |-----|-----|-----|-----|
-// |   0 |   1 |   4 |   5 |
-// |-----|-----|-----|-----|
-void LLTextureAtlas::getPositionFromIndex(S16 index, S16& col, S16& row)
-{
-	col = 0 ;
-	row = 0 ;
-
-	S16 index_copy = index ;
-	for(S16 i = 0 ; index_copy && i < 16 ; i += 2)
-	{
-		col |= ((index & (1 << i)) >> i) << (i >> 1) ;
-		row |= ((index & (1 << (i + 1))) >> (i + 1)) << (i >> 1) ;
-		index_copy >>= 2 ;
-	}
-}
-void LLTextureAtlas::getIndexFromPosition(S16 col, S16 row, S16& index)
-{
-	index = 0 ;
-	S16 col_copy = col ;
-	S16 row_copy = row ;
-	for(S16 i = 0 ; (col_copy || row_copy) && i < 16 ; i++)
-	{
-		index |= ((col & 1 << i) << i) | ((row & 1 << i) << ( i + 1)) ;
-		col_copy >>= 1 ;
-		row_copy >>= 1 ;
-	}
-}
-//----------------------------------------------------------------------
-//return TRUE if succeeds.
-BOOL LLTextureAtlas::getNextAvailableSlot(S8 bits_len, S16& col, S16& row)
-{
-    S16 index_step = bits_len * bits_len ;
-
-    U8 mask = 1 ;
-	for(S8 i = 1 ; i < bits_len ; i++)
-	{
-		mask |= (1 << i) ;
-	}	
-   
-	U8 cur_mask ;
-	for(S16 index = 0 ; index < mMaxSlotsInAtlas ; index += index_step)
-    {
-		getPositionFromIndex(index, col, row) ;
-		
-		cur_mask = mask << (col & 7) ;
-		if(!areUsageBitsMarked(bits_len, cur_mask, col, row))
-		{
-			markUsageBits(bits_len, cur_mask, col, row) ;
-			mNumSlotsReserved += bits_len * bits_len ;
-			
-			return TRUE ;
-		}
-    }
-
-   return FALSE ;
-}
diff --git a/indra/newview/lltextureatlas.h b/indra/newview/lltextureatlas.h
deleted file mode 100644
index 6b36eb7fe4..0000000000
--- a/indra/newview/lltextureatlas.h
+++ /dev/null
@@ -1,90 +0,0 @@
-/** 
- * @file lltextureatlas.h
- * @brief LLTextureAtlas base class.
- *
- * $LicenseInfo:firstyear=2002&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- * 
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- * 
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
- * $/LicenseInfo$
- */
-
-
-#ifndef LL_TEXTUREATLAS_H
-#define LL_TEXTUREATLAS_H
-
-#include "llviewertexture.h"
-class LLSpatialGroup ;
-
-class LLTextureAtlas : public LLViewerTexture
-{
-protected:
-	/*virtual*/ ~LLTextureAtlas() ;
-
-public:
-	LLTextureAtlas(U8 ncomponents, S16 atlas_dim = 16) ;	
-
-	/*virtual*/ S8 getType() const;
-
-	LLGLuint insertSubTexture(LLImageGL* source_gl_tex, S32 discard_level, const LLImageRaw* raw_image, S16 slot_col, S16 slot_row) ;
-	void releaseSlot(S16 slot_col, S16 slot_row, S8 slot_width);
-
-	BOOL getNextAvailableSlot(S8 bits_len, S16& col, S16& row) ;
-	void getTexCoordOffset(S16 col, S16 row, F32& xoffset, F32& yOffset) ;
-	void getTexCoordScale(S32 w, S32 h, F32& xscale, F32& yscale) ;
-
-	BOOL isEmpty() const ;
-	BOOL isFull(S8 to_be_reserved = 1) const ;
-	F32  getFullness() const ;
-
-	void addSpatialGroup(LLSpatialGroup* groupp) ;
-	void removeSpatialGroup(LLSpatialGroup* groupp) ;
-	LLSpatialGroup* getLastSpatialGroup() ;
-	void removeLastSpatialGroup() ;
-	BOOL hasSpatialGroup(LLSpatialGroup* groupp) ;
-	void clearSpatialGroup() ;
-	std::list<LLSpatialGroup*>* getSpatialGroupList() {return &mSpatialGroupList;}
-private:
-	void generateEmptyUsageBits() ;
-	void releaseUsageBits() ;
-
-	void markUsageBits(S8 bits_len, U8 mask, S16 col, S16 row) ;
-	void unmarkUsageBits(S8 bits_len, S16 col, S16 row) ;
-
-	void getPositionFromIndex(S16 index, S16& col, S16& row) ;
-	void getIndexFromPosition(S16 col, S16 row, S16& index) ;
-	BOOL areUsageBitsMarked(S8 bits_len, U8 mask, S16 col, S16 row) ;
-
-private:	
-	S16 mAtlasDim ; //number of slots per edge, i.e, there are "mAtlasDim * mAtlasDim" total slots in the atlas. 
-	S16 mNumSlotsReserved ;
-	S16 mMaxSlotsInAtlas ;
-	U8  **mUsageBits ;	
-	std::list<LLSpatialGroup*> mSpatialGroupList ;
-
-public:
-	//debug use only
-	U8  **mTestBits ;
-
-public:
-	static S16 sMaxSubTextureSize ;
-	static S16 sSlotSize ;
-};
-
-#endif
-
diff --git a/indra/newview/lltextureatlasmanager.cpp b/indra/newview/lltextureatlasmanager.cpp
deleted file mode 100644
index ca9d6da4db..0000000000
--- a/indra/newview/lltextureatlasmanager.cpp
+++ /dev/null
@@ -1,268 +0,0 @@
-/** 
- * @file lltextureatlasmanager.cpp
- * @brief LLTextureAtlasManager class implementation.
- *
- * $LicenseInfo:firstyear=2002&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- * 
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- * 
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
- * $/LicenseInfo$
- */
-#include "llviewerprecompiledheaders.h"
-#include "linden_common.h"
-#include "llerror.h"
-#include "llmath.h"
-#include "lltextureatlas.h"
-#include "lltextureatlasmanager.h"
-#include "llspatialpartition.h"
-
-const S8 MAX_NUM_EMPTY_ATLAS = 2 ;
-const F32 MIN_ATLAS_FULLNESS = 0.6f ;
-
-//*********************************************************************************************
-//implementation of class LLTextureAtlasInfo
-//*********************************************************************************************
-LLTextureAtlasSlot::LLTextureAtlasSlot(LLTextureAtlas* atlasp, LLSpatialGroup* groupp, S16 col, S16 row, F32 xoffset, F32 yoffset, S8 slot_width) : 
-	mAtlasp(atlasp),
-	mGroupp(groupp),
-	mCol(col),
-	mRow(row),
-	mReservedSlotWidth(slot_width),
-	mValid(FALSE),
-	mUpdatedTime(0),
-	mTexCoordOffset(xoffset, yoffset),
-	mTexCoordScale(1.f, 1.f)
-{
-	llassert_always(mAtlasp || mGroupp || mReservedSlotWidth) ;
-}
-
-LLTextureAtlasSlot::~LLTextureAtlasSlot()
-{
-	if(mAtlasp)
-	{
-		mAtlasp->releaseSlot(mCol, mRow, mReservedSlotWidth) ;
-		if(mAtlasp->isEmpty())
-		{
-			LLTextureAtlasManager::getInstance()->releaseAtlas(mAtlasp) ;
-		}
-		mAtlasp = NULL ;
-	}
-}
-
-//void LLTextureAtlasSlot::setAtlas(LLTextureAtlas* atlasp) 
-//{
-//	mAtlasp = atlasp ;
-//}
-//void LLTextureAtlasSlot::setSlotPos(S16 col, S16 row) 
-//{
-//	mCol = col ;
-//	mRow = row ;
-//}
-//void LLTextureAtlasSlot::setSlotWidth(S8 width) 
-//{
-//	//slot is a square with each edge length a power-of-two number
-//	mReservedSlotWidth = width ;
-//}
-//void LLTextureAtlasSlot::setTexCoordOffset(F32 xoffset, F32 yoffset) 
-//{
-//	mTexCoordOffset.mV[0] = xoffset ;
-//	mTexCoordOffset.mV[1] = yoffset ;
-//}
-
-void LLTextureAtlasSlot::setSpatialGroup(LLSpatialGroup* groupp) 
-{
-	mGroupp = groupp ;
-}
-void LLTextureAtlasSlot::setTexCoordScale(F32 xscale, F32 yscale) 
-{
-	mTexCoordScale.mV[0] = xscale ;
-	mTexCoordScale.mV[1] = yscale ;
-}
-//*********************************************************************************************
-//END of implementation of class LLTextureAtlasInfo
-//*********************************************************************************************
-
-//*********************************************************************************************
-//implementation of class LLTextureAtlasManager
-//*********************************************************************************************
-LLTextureAtlasManager::LLTextureAtlasManager() :
-	mAtlasMap(4),
-	mEmptyAtlasMap(4) 
-{
-}
-
-LLTextureAtlasManager::~LLTextureAtlasManager()
-{
-	for(S32 i = 0 ; i < 4 ; i++)
-	{
-		for(ll_texture_atlas_list_t::iterator j = mAtlasMap[i].begin() ; j != mAtlasMap[i].end() ; ++j)
-		{
-			*j = NULL ;
-		}
-		for(ll_texture_atlas_list_t::iterator j = mEmptyAtlasMap[i].begin() ; j != mEmptyAtlasMap[i].end() ; ++j)
-		{
-			*j = NULL ;
-		}
-
-		mAtlasMap[i].clear() ;
-		mEmptyAtlasMap[i].clear() ;
-	}
-	mAtlasMap.clear() ;
-	mEmptyAtlasMap.clear() ;
-}
-
-//return TRUE if qualified
-BOOL LLTextureAtlasManager::canAddToAtlas(S32 w, S32 h, S8 ncomponents, LLGLenum target) 
-{
-	if(ncomponents < 1 || ncomponents > 4)
-	{
-		return FALSE ;
-	}
-	//only support GL_TEXTURE_2D
-	if(GL_TEXTURE_2D != target)
-	{
-		return FALSE ;
-	}
-	//real image size overflows
-	if(w < 8 || w > LLTextureAtlas::sMaxSubTextureSize || h < 8 || h > LLTextureAtlas::sMaxSubTextureSize)
-	{
-		return FALSE ;
-	}
-
-	//if non-power-of-two number
-	if((w & (w - 1)) || (h & (h - 1)))
-	{
-		return FALSE ;
-	}
-
-	return TRUE ;
-}
-
-void LLTextureAtlasManager::releaseAtlas(LLTextureAtlas* atlasp)
-{	
-	LLSpatialGroup* groupp = atlasp->getLastSpatialGroup() ;
-	while(groupp)
-	{
-		groupp->removeAtlas(atlasp, FALSE) ;
-		atlasp->removeLastSpatialGroup() ;
-
-		groupp = atlasp->getLastSpatialGroup() ;
-	}
-
-	S8 type = atlasp->getComponents() - 1 ;	
-	//insert to the empty list
-	if(mEmptyAtlasMap[type].size() < MAX_NUM_EMPTY_ATLAS)
-	{					
-		mEmptyAtlasMap[type].push_back(atlasp) ;
-	}
-		
-	//delete the atlasp
-	mAtlasMap[type].remove(atlasp) ;
-}
-
-//
-//this function reserves an appropriate slot from atlas pool for an image.
-//return non-NULL if succeeds.
-//Note:
-//1, this function does not check if the image this slot assigned for qualifies for atlas or not, 
-//       call LLTextureAtlasManager::canAddToAtlas(...) to do the check before calling this function.
-//2, this function also dose not check if the image is already in atlas. It always assigns a new slot anyway.
-//3, this function tries to group sub-textures from same spatial group into ONE atlas to improve render batching.
-//
-LLPointer<LLTextureAtlasSlot> LLTextureAtlasManager::reserveAtlasSlot(S32 sub_texture_size, S8 ncomponents, 
-																		  LLSpatialGroup* groupp, LLViewerTexture* imagep)
-{
-	if(!groupp)
-	{
-		//do not insert to atlas if does not have a group.
-		return NULL ;
-	}
-
-	//bits_len must <= 8 and is a power of two number, i.e.: must be one of these numbers: 1, 2, 4, 8.
-	if(sub_texture_size > LLTextureAtlas::sMaxSubTextureSize)
-	{
-		sub_texture_size = LLTextureAtlas::sMaxSubTextureSize ;
-	}
-	S8 bits_len = sub_texture_size / LLTextureAtlas::sSlotSize ;
-	if(bits_len < 1)
-	{
-	   bits_len = 1 ;
-	}
-		
-	S16 col = -1, row = -1;
-	S8 total_bits = bits_len * bits_len ;
-
-	//insert to the atlas reserved by the same spatial group
-	LLPointer<LLTextureAtlas> atlasp = groupp->getAtlas(ncomponents, total_bits) ;
-	if(atlasp.notNull())
-	{
-		if(!atlasp->getNextAvailableSlot(bits_len, col, row))
-		{
-			//failed
-			atlasp = NULL ;
-		}		
-	}
-
-   //search an atlas to fit for 'size'
-	if(!atlasp)
-	{
-		S8 atlas_index = ncomponents - 1 ;
-		ll_texture_atlas_list_t::iterator iter = mAtlasMap[atlas_index].begin() ;
-		for(; iter != mAtlasMap[atlas_index].end(); ++iter) 
-		{
-			LLTextureAtlas* cur = (LLTextureAtlas*)*iter ;
-			if(cur->getFullness() < MIN_ATLAS_FULLNESS)//this atlas is empty enough for this group to insert more sub-textures later if necessary.
-			{
-				if(cur->getNextAvailableSlot(bits_len, col, row))
-				{
-					atlasp = cur ;
-					groupp->addAtlas(atlasp) ;				
-					break ;
-				}
-			}
-		}
-	}
-
-	//create a new atlas if necessary
-	if(!atlasp)
-	{
-		if(mEmptyAtlasMap[ncomponents - 1].size() > 0)
-		{
-			//there is an empty one
-			atlasp = mEmptyAtlasMap[ncomponents - 1].back() ;
-			mEmptyAtlasMap[ncomponents - 1].pop_back() ;
-		}
-		else
-		{
-			atlasp = new LLTextureAtlas(ncomponents, 16) ;
-		}
-		mAtlasMap[ncomponents - 1].push_back(atlasp) ;
-		atlasp->getNextAvailableSlot(bits_len, col, row) ;		
-		groupp->addAtlas(atlasp) ;
-	}
-
-	F32 xoffset, yoffset ;
-	atlasp->getTexCoordOffset(col, row, xoffset, yoffset) ;
-	LLPointer<LLTextureAtlasSlot> slot_infop = new LLTextureAtlasSlot(atlasp, groupp, col, row, xoffset, yoffset, bits_len) ;
-	
-	return slot_infop ;
-}
-
-//*********************************************************************************************
-//END of implementation of class LLTextureAtlasManager
-//*********************************************************************************************
diff --git a/indra/newview/lltextureatlasmanager.h b/indra/newview/lltextureatlasmanager.h
deleted file mode 100644
index 1b8df708c6..0000000000
--- a/indra/newview/lltextureatlasmanager.h
+++ /dev/null
@@ -1,105 +0,0 @@
-/** 
- * @file lltextureatlasmanager.h
- * @brief LLTextureAtlasManager base class.
- *
- * $LicenseInfo:firstyear=2002&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- * 
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- * 
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
- * $/LicenseInfo$
- */
-
-
-#ifndef LL_TEXTUREATLASMANAGER_H
-#define LL_TEXTUREATLASMANAGER_H
-
-#include "llmemory.h"
-
-class LLSpatialGroup ;
-class LLViewerTexture ;
-
-//just use it as a structure.
-class LLTextureAtlasSlot : public LLRefCount
-{
-public:
-	LLTextureAtlasSlot(LLTextureAtlas* atlasp, LLSpatialGroup* groupp, S16 col, S16 row, F32 xoffset, F32 yoffset, S8 slot_width) ;
-
-protected:
-	virtual ~LLTextureAtlasSlot();
-	
-public:
-
-	//
-	//do not allow to change those values
-	//
-	//void setAtlas(LLTextureAtlas* atlasp) ;	
-	//void setSlotPos(S16 col, S16 row) ;
-	//void setSlotWidth(S8 width) ;
-	//void setTexCoordOffset(F32 xoffser, F32 yoffset) ;
-	//
-
-	void setSpatialGroup(LLSpatialGroup* groupp) ;
-	void setTexCoordScale(F32 xscale, F32 yscale) ;
-	void setValid() {mValid = TRUE ;}
-
-	LLTextureAtlas* getAtlas()const {return mAtlasp;}
-	LLSpatialGroup* getSpatialGroup() const {return mGroupp ;} 
-	S16             getSlotCol()const {return mCol;}
-	S16             getSlotRow()const {return mRow;}
-	S8              getSlotWidth()const{return mReservedSlotWidth;}
-	BOOL            isValid()const { return mValid;}
-	const LLVector2*      getTexCoordOffset()const {return &mTexCoordOffset;}
-	const LLVector2*      getTexCoordScale() const {return &mTexCoordScale;}
-
-	void setUpdatedTime(U32 t) {mUpdatedTime = t;}
-	U32  getUpdatedTime()const {return mUpdatedTime;}
-
-private:
-	LLTextureAtlas* mAtlasp;
-	S16             mCol ;//col of the slot
-	S16             mRow ;//row of the slot
-	S8              mReservedSlotWidth ; //slot is a square with each edge length a power-of-two number	
-	LLSpatialGroup* mGroupp ;
-	BOOL            mValid ;
-
-	LLVector2       mTexCoordOffset ;
-	LLVector2       mTexCoordScale ;
-
-	U32             mUpdatedTime ;	
-} ;
-
-class LLTextureAtlasManager : public LLSingleton<LLTextureAtlasManager>
-{
-	LLSINGLETON(LLTextureAtlasManager);
-	~LLTextureAtlasManager();
-	typedef std::list<LLPointer<LLTextureAtlas> > ll_texture_atlas_list_t ;
-
-public:
-
-	LLPointer<LLTextureAtlasSlot> reserveAtlasSlot(S32 sub_texture_size, S8 ncomponents, 
-		LLSpatialGroup* groupp, LLViewerTexture* imagep) ;
-	void releaseAtlas(LLTextureAtlas* atlasp);
-
-	BOOL canAddToAtlas(S32 w, S32 h, S8 ncomponents, LLGLenum target) ;
-
-private:	
-	std::vector<ll_texture_atlas_list_t> mAtlasMap ;
-	std::vector<ll_texture_atlas_list_t> mEmptyAtlasMap ; //delay some empty atlases deletion to avoid possible creation of new atlas immediately.
-};
-
-#endif
diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp
index f932acd48c..37ed2e9f20 100644
--- a/indra/newview/llviewertexture.cpp
+++ b/indra/newview/llviewertexture.cpp
@@ -1476,6 +1476,10 @@ void LLViewerFetchedTexture::addToCreateTexture()
 BOOL LLViewerFetchedTexture::preCreateTexture(S32 usename/*= 0*/)
 {
     LL_PROFILE_ZONE_SCOPED;
+#if LL_IMAGEGL_THREAD_CHECK
+    mGLTexturep->checkActiveThread();
+#endif
+
     if (!mNeedsCreateTexture)
     {
         destroyRawImage();
@@ -1603,6 +1607,9 @@ void LLViewerFetchedTexture::postCreateTexture()
     {
         return;
     }
+#if LL_IMAGEGL_THREAD_CHECK
+    mGLTexturep->checkActiveThread();
+#endif
 
     notifyAboutCreatingTexture();
 
@@ -1619,36 +1626,45 @@ void LLViewerFetchedTexture::postCreateTexture()
 
 void LLViewerFetchedTexture::scheduleCreateTexture()
 {
-    ref();
-    mNeedsCreateTexture = TRUE;
-    if (preCreateTexture())
+    if (!mNeedsCreateTexture)
     {
+        ref();
         mNeedsCreateTexture = TRUE;
-#if LL_WINDOWS //flip to 0 to revert to single-threaded OpenGL texture uploads
-        auto mainq = mMainQueue.lock();
-        if (mainq)
+        if (preCreateTexture())
         {
-            mainq->postTo(
-                mImageQueue,
-                // work to be done on LLImageGL worker thread
-                [this]()
-                {
-                    //actually create the texture on a background thread
-                    createTexture();
-                },
-                // callback to be run on main thread
-                [this]()
-                {
-                    //finalize on main thread
-                    postCreateTexture();
-                    unref();
-                });
-        }
-        else
+            mNeedsCreateTexture = TRUE;
+#if LL_WINDOWS //flip to 0 to revert to single-threaded OpenGL texture uploads
+            auto mainq = mMainQueue.lock();
+            if (mainq)
+            {
+                mainq->postTo(
+                    mImageQueue,
+                    // work to be done on LLImageGL worker thread
+                    [this]()
+                    {
+#if LL_IMAGEGL_THREAD_CHECK
+                        mGLTexturep->mActiveThread = LLThread::currentID();
 #endif
-        {
-            gTextureList.mCreateTextureList.insert(this);
-            unref();
+                        //actually create the texture on a background thread
+                        createTexture();
+                    },
+                    // callback to be run on main thread
+                        [this]()
+                    {
+#if LL_IMAGEGL_THREAD_CHECK
+                        mGLTexturep->mActiveThread = LLThread::currentID();
+#endif
+                        //finalize on main thread
+                        postCreateTexture();
+                        unref();
+                    });
+            }
+            else
+#endif
+            {
+                gTextureList.mCreateTextureList.insert(this);
+                unref();
+            }
         }
     }
 }
@@ -2967,7 +2983,8 @@ void LLViewerFetchedTexture::destroyRawImage()
 void LLViewerFetchedTexture::switchToCachedImage()
 {
     LL_PROFILE_ZONE_SCOPED;
-	if(mCachedRawImage.notNull())
+	if(mCachedRawImage.notNull() && 
+        !mNeedsCreateTexture) // <--- texture creation is pending, don't step on it
 	{
 		mRawImage = mCachedRawImage;
 						
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index 2f554bc9b8..4e7eb4df5d 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -5189,6 +5189,7 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep,
 		}
 	}
 
+    F32 vsize = facep->getVirtualSize(); //TODO -- adjust by texture scale?
 
 	if (index < FACE_DO_NOT_BATCH_TEXTURES && idx >= 0)
 	{
@@ -5202,10 +5203,12 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep,
 			{
 				batchable = true;
 				draw_vec[idx]->mTextureList[index] = tex;
+                draw_vec[idx]->mTextureListVSize[index] = vsize;
 			}
 			else if (draw_vec[idx]->mTextureList[index] == tex)
 			{ //this face's texture index can be used with this batch
 				batchable = true;
+                draw_vec[idx]->mTextureListVSize[index] = llmax(vsize, draw_vec[idx]->mTextureListVSize[index]);
 			}
 		}
 		else
@@ -5236,12 +5239,14 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep,
 	{
 		draw_vec[idx]->mCount += facep->getIndicesCount();
 		draw_vec[idx]->mEnd += facep->getGeomCount();
-		draw_vec[idx]->mVSize = llmax(draw_vec[idx]->mVSize, facep->getVirtualSize());
+		draw_vec[idx]->mVSize = llmax(draw_vec[idx]->mVSize, vsize);
 
 		if (index < FACE_DO_NOT_BATCH_TEXTURES && index >= draw_vec[idx]->mTextureList.size())
 		{
 			draw_vec[idx]->mTextureList.resize(index+1);
 			draw_vec[idx]->mTextureList[index] = tex;
+            draw_vec[idx]->mTextureListVSize.resize(index + 1);
+            draw_vec[idx]->mTextureListVSize[index] = vsize;
 		}
 		draw_vec[idx]->validate();
 		update_min_max(draw_vec[idx]->mExtents[0], draw_vec[idx]->mExtents[1], facep->mExtents[0]);
@@ -5256,7 +5261,7 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep,
 		LLPointer<LLDrawInfo> draw_info = new LLDrawInfo(start,end,count,offset, tex, 
 			facep->getVertexBuffer(), selected, fullbright, bump);
 		draw_info->mGroup = group;
-		draw_info->mVSize = facep->getVirtualSize();
+		draw_info->mVSize = vsize;
 		draw_vec.push_back(draw_info);
 		draw_info->mTextureMatrix = tex_mat;
 		draw_info->mModelMatrix = model_mat;
@@ -5331,6 +5336,8 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep,
 		{ //initialize texture list for texture batching
 			draw_info->mTextureList.resize(index+1);
 			draw_info->mTextureList[index] = tex;
+            draw_info->mTextureListVSize.resize(index + 1);
+            draw_info->mTextureListVSize[index] = vsize;
 		}
 		draw_info->validate();
 	}
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index c122b4f43e..df676b30fc 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -3711,25 +3711,31 @@ void renderSoundHighlights(LLDrawable* drawablep)
 }
 }
 
-void LLPipeline::touchTextures(LLDrawInfo* info)
+void LLPipeline::touchTexture(LLViewerTexture* tex, F32 vsize)
 {
-    LL_PROFILE_ZONE_SCOPED;
-    for (auto& tex : info->mTextureList)
+    if (tex)
     {
-        if (tex.notNull())
+        LLImageGL* gl_tex = tex->getGLTexture();
+        if (gl_tex && gl_tex->updateBindStats(gl_tex->mTextureMemory))
         {
-            LLImageGL* gl_tex = tex->getGLTexture();
-            if (gl_tex && gl_tex->updateBindStats(gl_tex->mTextureMemory))
-            {
-                tex->setActive();
-            }
+            tex->setActive();
+            tex->addTextureStats(vsize);
         }
     }
 
-    if (info->mTexture.notNull())
+
+}
+void LLPipeline::touchTextures(LLDrawInfo* info)
+{
+    LL_PROFILE_ZONE_SCOPED;
+    for (int i = 0; i < info->mTextureList.size(); ++i)
     {
-        info->mTexture->addTextureStats(info->mVSize);
+        touchTexture(info->mTextureList[i], info->mTextureListVSize[i]);
     }
+
+    touchTexture(info->mTexture, info->mVSize);
+    touchTexture(info->mSpecularMap, info->mVSize);
+    touchTexture(info->mNormalMap, info->mVSize);
 }
 
 void LLPipeline::postSort(LLCamera& camera)
diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h
index 3ac3e3ce01..794d806d0c 100644
--- a/indra/newview/pipeline.h
+++ b/indra/newview/pipeline.h
@@ -260,8 +260,11 @@ public:
 	void stateSort(LLSpatialBridge* bridge, LLCamera& camera, BOOL fov_changed = FALSE);
 	void stateSort(LLDrawable* drawablep, LLCamera& camera);
 	void postSort(LLCamera& camera);
+    
     //update stats for textures in given DrawInfo
     void touchTextures(LLDrawInfo* info);
+    void touchTexture(LLViewerTexture* tex, F32 vsize);
+
 	void forAllVisibleDrawables(void (*func)(LLDrawable*));
 
     void renderObjects(U32 type, U32 mask, bool texture = true, bool batch_texture = false, bool rigged = false);
-- 
cgit v1.2.3


From 5e5be92d79b6ad49f971e7b2f2ddd359d762c163 Mon Sep 17 00:00:00 2001
From: Dave Parks <davep@lindenlab.com>
Date: Mon, 6 Dec 2021 15:29:34 +0000
Subject: SL-16202 Put Multi-threaded GL behind a feature flag and update
 featuretable (decruftify settings, compatibility pass).

---
 indra/llrender/llgl.cpp                 |  95 +-------
 indra/llrender/llgl.h                   |   7 +-
 indra/llrender/llimagegl.cpp            |  20 +-
 indra/llrender/llimagegl.h              |   5 +-
 indra/llrender/llrender2dutils.cpp      |  61 +----
 indra/llrender/llshadermgr.cpp          |   2 +-
 indra/newview/app_settings/settings.xml |  11 +
 indra/newview/featuretable.txt          | 420 +-------------------------------
 indra/newview/featuretable_mac.txt      | 318 +-----------------------
 indra/newview/llappviewer.cpp           |   2 +-
 indra/newview/lldynamictexture.cpp      |   4 +-
 indra/newview/llfeaturemanager.cpp      |  55 +----
 indra/newview/llglsandbox.cpp           |   4 +
 indra/newview/llviewertexture.cpp       |   4 +-
 indra/newview/llviewertexturelist.cpp   |   2 +-
 indra/newview/llviewerwindow.cpp        |   2 +-
 indra/newview/pipeline.cpp              |   2 +-
 17 files changed, 67 insertions(+), 947 deletions(-)

(limited to 'indra')

diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp
index f24bf6ec78..64db095dec 100644
--- a/indra/llrender/llgl.cpp
+++ b/indra/llrender/llgl.cpp
@@ -161,7 +161,6 @@ LLMatrix4 gGLObliqueProjectionInverse;
 std::list<LLGLUpdate*> LLGLUpdate::sGLQ;
 
 #if (LL_WINDOWS || LL_LINUX)  && !LL_MESA_HEADLESS
-// ATI prototypes
 
 #if LL_WINDOWS
 PFNGLGETSTRINGIPROC glGetStringi = NULL;
@@ -208,21 +207,6 @@ PFNGLGETSYNCIVPROC				glGetSynciv = NULL;
 PFNGLBUFFERPARAMETERIAPPLEPROC	glBufferParameteriAPPLE = NULL;
 PFNGLFLUSHMAPPEDBUFFERRANGEAPPLEPROC glFlushMappedBufferRangeAPPLE = NULL;
 
-// vertex object prototypes
-PFNGLNEWOBJECTBUFFERATIPROC			glNewObjectBufferATI = NULL;
-PFNGLISOBJECTBUFFERATIPROC			glIsObjectBufferATI = NULL;
-PFNGLUPDATEOBJECTBUFFERATIPROC		glUpdateObjectBufferATI = NULL;
-PFNGLGETOBJECTBUFFERFVATIPROC		glGetObjectBufferfvATI = NULL;
-PFNGLGETOBJECTBUFFERIVATIPROC		glGetObjectBufferivATI = NULL;
-PFNGLFREEOBJECTBUFFERATIPROC		glFreeObjectBufferATI = NULL;
-PFNGLARRAYOBJECTATIPROC				glArrayObjectATI = NULL;
-PFNGLVERTEXATTRIBARRAYOBJECTATIPROC	glVertexAttribArrayObjectATI = NULL;
-PFNGLGETARRAYOBJECTFVATIPROC		glGetArrayObjectfvATI = NULL;
-PFNGLGETARRAYOBJECTIVATIPROC		glGetArrayObjectivATI = NULL;
-PFNGLVARIANTARRAYOBJECTATIPROC		glVariantObjectArrayATI = NULL;
-PFNGLGETVARIANTARRAYOBJECTFVATIPROC	glGetVariantArrayObjectfvATI = NULL;
-PFNGLGETVARIANTARRAYOBJECTIVATIPROC	glGetVariantArrayObjectivATI = NULL;
-
 // GL_ARB_occlusion_query
 PFNGLGENQUERIESARBPROC glGenQueriesARB = NULL;
 PFNGLDELETEQUERIESARBPROC glDeleteQueriesARB = NULL;
@@ -462,14 +446,9 @@ LLGLManager::LLGLManager() :
 	mHasCubeMap(FALSE),
 	mHasDebugOutput(FALSE),
 
-	mIsATI(FALSE),
+	mIsAMD(FALSE),
 	mIsNVIDIA(FALSE),
 	mIsIntel(FALSE),
-	mIsGF2or4MX(FALSE),
-	mIsGF3(FALSE),
-	mIsGFFX(FALSE),
-	mATIOffsetVerticalLines(FALSE),
-	mATIOldDriver(FALSE),
 #if LL_DARWIN
 	mIsMobileGF(FALSE),
 #endif
@@ -628,59 +607,17 @@ bool LLGLManager::initGL()
 	
 	// Trailing space necessary to keep "nVidia Corpor_ati_on" cards
 	// from being recognized as ATI.
+    // NOTE: AMD has been pretty good about not breaking this check, do not rename without good reason
 	if (mGLVendor.substr(0,4) == "ATI ")
 	{
-		mGLVendorShort = "ATI";
+		mGLVendorShort = "AMD";
 		// *TODO: Fix this?
-		mIsATI = TRUE;
-
-#if LL_WINDOWS && !LL_MESA_HEADLESS
-		if (mDriverVersionRelease < 3842)
-		{
-			mATIOffsetVerticalLines = TRUE;
-		}
-#endif // LL_WINDOWS
-
-#if (LL_WINDOWS || LL_LINUX) && !LL_MESA_HEADLESS
-		// count any pre OpenGL 3.0 implementation as an old driver
-		if (mGLVersion < 3.f) 
-		{
-			mATIOldDriver = TRUE;
-		}
-#endif // (LL_WINDOWS || LL_LINUX) && !LL_MESA_HEADLESS
+		mIsAMD = TRUE;
 	}
 	else if (mGLVendor.find("NVIDIA ") != std::string::npos)
 	{
 		mGLVendorShort = "NVIDIA";
 		mIsNVIDIA = TRUE;
-		if (   mGLRenderer.find("GEFORCE4 MX") != std::string::npos
-			|| mGLRenderer.find("GEFORCE2") != std::string::npos
-			|| mGLRenderer.find("GEFORCE 2") != std::string::npos
-			|| mGLRenderer.find("GEFORCE4 460 GO") != std::string::npos
-			|| mGLRenderer.find("GEFORCE4 440 GO") != std::string::npos
-			|| mGLRenderer.find("GEFORCE4 420 GO") != std::string::npos)
-		{
-			mIsGF2or4MX = TRUE;
-		}
-		else if (mGLRenderer.find("GEFORCE FX") != std::string::npos
-				 || mGLRenderer.find("QUADRO FX") != std::string::npos
-				 || mGLRenderer.find("NV34") != std::string::npos)
-		{
-			mIsGFFX = TRUE;
-		}
-		else if(mGLRenderer.find("GEFORCE3") != std::string::npos)
-		{
-			mIsGF3 = TRUE;
-		}
-#if LL_DARWIN
-		else if ((mGLRenderer.find("9400M") != std::string::npos)
-			  || (mGLRenderer.find("9600M") != std::string::npos)
-			  || (mGLRenderer.find("9800M") != std::string::npos))
-		{
-			mIsMobileGF = TRUE;
-		}
-#endif
-
 	}
 	else if (mGLVendor.find("INTEL") != std::string::npos
 #if LL_LINUX
@@ -834,12 +771,6 @@ bool LLGLManager::initGL()
 	//HACK always disable texture multisample, use FXAA instead
 	mHasTextureMultisample = FALSE;
 #if LL_WINDOWS
-	if (mIsATI)
-	{ //using multisample textures on ATI results in black screen for some reason
-		mHasTextureMultisample = FALSE;
-	}
-
-
 	if (mIsIntel && mGLVersion <= 3.f)
 	{ //never try to use framebuffer objects on older intel drivers (crashy)
 		mHasFramebufferObject = FALSE;
@@ -1004,14 +935,9 @@ void LLGLManager::asLLSD(LLSD& info)
     info["has_texture_srgb_decode"] = mHasTexturesRGBDecode;
 
 	// Vendor-specific extensions
-	info["is_ati"] = mIsATI;
+	info["is_ati"] = mIsAMD;  // note, do not rename is_ati to is_amd without coordinating with DW
 	info["is_nvidia"] = mIsNVIDIA;
 	info["is_intel"] = mIsIntel;
-	info["is_gf2or4mx"] = mIsGF2or4MX;
-	info["is_gf3"] = mIsGF3;
-	info["is_gf_gfx"] = mIsGFFX;
-	info["ati_offset_vertical_lines"] = mATIOffsetVerticalLines;
-	info["ati_old_driver"] = mATIOldDriver;
 
 	// Other fields
 	info["has_requirements"] = mHasRequirements;
@@ -1138,7 +1064,7 @@ void LLGLManager::initExtensions()
 	mHasDebugOutput = ExtensionExists("GL_ARB_debug_output", gGLHExts.mSysExts);
 	mHasTransformFeedback = mGLVersion >= 4.f ? TRUE : FALSE;
 #if !LL_DARWIN
-	mHasPointParameters = !mIsATI && ExtensionExists("GL_ARB_point_parameters", gGLHExts.mSysExts);
+	mHasPointParameters = ExtensionExists("GL_ARB_point_parameters", gGLHExts.mSysExts);
 #endif
 #endif
 
@@ -1256,14 +1182,7 @@ void LLGLManager::initExtensions()
 		LL_INFOS("RenderInit") << "Disabling mip-map generation for Intel GPUs" << LL_ENDL;
 		mHasMipMapGeneration = FALSE;
 	}
-#if !LL_DARWIN
-	if (mIsATI && mHasMipMapGeneration)
-	{
-		LL_INFOS("RenderInit") << "Disabling mip-map generation for ATI GPUs (performance opt)" << LL_ENDL;
-		mHasMipMapGeneration = FALSE;
-	}
-#endif
-	
+
 	// Misc
 	glGetIntegerv(GL_MAX_ELEMENTS_VERTICES, (GLint*) &mGLMaxVertexRange);
 	glGetIntegerv(GL_MAX_ELEMENTS_INDICES, (GLint*) &mGLMaxIndexRange);
diff --git a/indra/llrender/llgl.h b/indra/llrender/llgl.h
index 386d12d70a..ec97eb0faa 100644
--- a/indra/llrender/llgl.h
+++ b/indra/llrender/llgl.h
@@ -119,14 +119,9 @@ public:
     BOOL mHasTexturesRGBDecode;
 
 	// Vendor-specific extensions
-	BOOL mIsATI;
+	BOOL mIsAMD;
 	BOOL mIsNVIDIA;
 	BOOL mIsIntel;
-	BOOL mIsGF2or4MX;
-	BOOL mIsGF3;
-	BOOL mIsGFFX;
-	BOOL mATIOffsetVerticalLines;
-	BOOL mATIOldDriver;
 
 #if LL_DARWIN
 	// Needed to distinguish problem cards on older Macs that break with Materials
diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp
index d3af27272b..6cdd6a3460 100644
--- a/indra/llrender/llimagegl.cpp
+++ b/indra/llrender/llimagegl.cpp
@@ -66,9 +66,11 @@ F32 LLImageGL::sLastFrameTime			= 0.f;
 BOOL LLImageGL::sAllowReadBackRaw       = FALSE ;
 LLImageGL* LLImageGL::sDefaultGLTexture = NULL ;
 bool LLImageGL::sCompressTextures = false;
-
 std::set<LLImageGL*> LLImageGL::sImageList;
 
+
+bool LLImageGLThread::sEnabled = false;
+
 //****************************************************************************************************
 //The below for texture auditing use only
 //****************************************************************************************************
@@ -177,11 +179,15 @@ BOOL is_little_endian()
 }
 
 //static 
-void LLImageGL::initClass(LLWindow* window, S32 num_catagories, BOOL skip_analyze_alpha /* = false */)
+void LLImageGL::initClass(LLWindow* window, S32 num_catagories, BOOL skip_analyze_alpha /* = false */, bool multi_threaded /* = false */)
 {
     LL_PROFILE_ZONE_SCOPED;
 	sSkipAnalyzeAlpha = skip_analyze_alpha;
-    LLImageGLThread::createInstance(window);
+
+    if (multi_threaded)
+    {
+        LLImageGLThread::createInstance(window);
+    }
 }
 
 //static 
@@ -1511,13 +1517,6 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_
     if (mUseMipMaps)
     {
         mAutoGenMips = gGLManager.mHasMipMapGeneration;
-#if LL_DARWIN
-        // On the Mac GF2 and GF4MX drivers, auto mipmap generation doesn't work right with alpha-only textures.
-        if (gGLManager.mIsGF2or4MX && (mFormatInternal == GL_ALPHA8) && (mFormatPrimary == GL_ALPHA))
-        {
-            mAutoGenMips = FALSE;
-        }
-#endif
     }
 
     mCurrentDiscardLevel = discard_level;
@@ -2272,6 +2271,7 @@ LLImageGLThread::LLImageGLThread(LLWindow* window)
     , mWindow(window)
 {
     LL_PROFILE_ZONE_SCOPED;
+    sEnabled = true;
     mFinished = false;
 
     mContext = mWindow->createSharedContext();
diff --git a/indra/llrender/llimagegl.h b/indra/llrender/llimagegl.h
index 28996a554a..d6f4b13a51 100644
--- a/indra/llrender/llimagegl.h
+++ b/indra/llrender/llimagegl.h
@@ -278,7 +278,7 @@ public:
 #endif
 
 public:
-	static void initClass(LLWindow* window, S32 num_catagories, BOOL skip_analyze_alpha = false); 
+	static void initClass(LLWindow* window, S32 num_catagories, BOOL skip_analyze_alpha = false, bool multi_threaded = false); 
 	static void cleanupClass() ;
 
 private:
@@ -317,6 +317,9 @@ public:
 class LLImageGLThread : public LLSimpleton<LLImageGLThread>, LL::ThreadPool
 {
 public:
+    // follows gSavedSettings "RenderGLMultiThreaded"
+    static bool sEnabled;
+
     LLImageGLThread(LLWindow* window);
 
     // post a function to be executed on the LLImageGL background thread
diff --git a/indra/llrender/llrender2dutils.cpp b/indra/llrender/llrender2dutils.cpp
index ad21bd4f48..ad0c6262a4 100644
--- a/indra/llrender/llrender2dutils.cpp
+++ b/indra/llrender/llrender2dutils.cpp
@@ -132,40 +132,15 @@ void gl_rect_2d(S32 left, S32 top, S32 right, S32 bottom, BOOL filled )
 	}
 	else
 	{
-		if( gGLManager.mATIOffsetVerticalLines )
-		{
-			// Work around bug in ATI driver: vertical lines are offset by (-1,-1)
-			gGL.begin( LLRender::LINES );
-
-				// Verticals 
-				gGL.vertex2i(left + 1, top);
-				gGL.vertex2i(left + 1, bottom);
-
-				gGL.vertex2i(right, bottom);
-				gGL.vertex2i(right, top);
-
-				// Horizontals
-				top--;
-				right--;
-				gGL.vertex2i(left, bottom);
-				gGL.vertex2i(right, bottom);
-
-				gGL.vertex2i(left, top);
-				gGL.vertex2i(right, top);
-			gGL.end();
-		}
-		else
-		{
-			top--;
-			right--;
-			gGL.begin( LLRender::LINE_STRIP );
-				gGL.vertex2i(left, top);
-				gGL.vertex2i(left, bottom);
-				gGL.vertex2i(right, bottom);
-				gGL.vertex2i(right, top);
-				gGL.vertex2i(left, top);
-			gGL.end();
-		}
+		top--;
+		right--;
+		gGL.begin( LLRender::LINE_STRIP );
+			gGL.vertex2i(left, top);
+			gGL.vertex2i(left, bottom);
+			gGL.vertex2i(right, bottom);
+			gGL.vertex2i(right, top);
+			gGL.vertex2i(left, top);
+		gGL.end();
 	}
 	stop_glerror();
 }
@@ -250,15 +225,6 @@ void gl_drop_shadow(S32 left, S32 top, S32 right, S32 bottom, const LLColor4 &st
 
 void gl_line_2d(S32 x1, S32 y1, S32 x2, S32 y2 )
 {
-	// Work around bug in ATI driver: vertical lines are offset by (-1,-1)
-	if( (x1 == x2) && gGLManager.mATIOffsetVerticalLines )
-	{
-		x1++;
-		x2++;
-		y1++;
-		y2++;
-	}
-
 	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 	
 	gGL.begin(LLRender::LINES);
@@ -269,15 +235,6 @@ void gl_line_2d(S32 x1, S32 y1, S32 x2, S32 y2 )
 
 void gl_line_2d(S32 x1, S32 y1, S32 x2, S32 y2, const LLColor4 &color )
 {
-	// Work around bug in ATI driver: vertical lines are offset by (-1,-1)
-	if( (x1 == x2) && gGLManager.mATIOffsetVerticalLines )
-	{
-		x1++;
-		x2++;
-		y1++;
-		y2++;
-	}
-
 	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 
 	gGL.color4fv( color.mV );
diff --git a/indra/llrender/llshadermgr.cpp b/indra/llrender/llshadermgr.cpp
index 6a53662619..c100c182dd 100644
--- a/indra/llrender/llshadermgr.cpp
+++ b/indra/llrender/llshadermgr.cpp
@@ -782,7 +782,7 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade
 		}
 	}
 
-	if( gGLManager.mIsATI )
+	if( gGLManager.mIsAMD )
 	{
 		extra_code_text[extra_code_count++] = strdup( "#define IS_AMD_CARD 1\n" );
 	}
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 167483783e..526d898b33 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -9818,7 +9818,18 @@
       <key>Type</key>
       <string>Boolean</string>
       <key>Value</key>
+      <integer>0</integer>
+    </map>
+    <key>RenderGLMultiThreaded</key>
+    <map>
+      <key>Comment</key>
+      <string>Allow OpenGL to use multiple render contexts (reduces frame stutters from loading textures, doesn't play nice with Intel drivers).</string>
+      <key>Persist</key>
       <integer>1</integer>
+      <key>Type</key>
+      <string>Boolean</string>
+      <key>Value</key>
+      <integer>0</integer>
     </map>
     <key>RenderGlow</key>
     <map>
diff --git a/indra/newview/featuretable.txt b/indra/newview/featuretable.txt
index bd66641db9..4e56141fde 100644
--- a/indra/newview/featuretable.txt
+++ b/indra/newview/featuretable.txt
@@ -1,4 +1,4 @@
-version 33
+version 34
 // The version number above should be incremented IF AND ONLY IF some
 // change has been made that is sufficiently important to justify
 // resetting the graphics preferences of all users to the recommended
@@ -71,37 +71,8 @@ RenderUseStreamVBO			1	1
 RenderFSAASamples			1	16
 RenderMaxTextureIndex		1	16
 RenderGLCoreProfile         1   1
+RenderGLMultiThreaded       1   1
 
-//
-// Low Graphics Settings (fixed function)
-//
-list LowFixedFunction
-RenderAnisotropic			1	0
-RenderAvatarCloth			1	0
-RenderAvatarLODFactor		1	0
-RenderAvatarPhysicsLODFactor 1	0
-RenderAvatarMaxNonImpostors 1   3
-RenderAvatarMaxComplexity          1	25000
-RenderAvatarVP				1	0
-RenderFarClip				1	64
-RenderFlexTimeFactor		1	0
-RenderGlowResolutionPow		1	8
-RenderLocalLights			1	0
-RenderMaxPartCount			1	0
-RenderObjectBump			1	0
-RenderReflectionDetail		1	0
-RenderTerrainDetail			1	0
-RenderTerrainLODFactor		1	1
-RenderTransparentWater		1	0
-RenderTreeLODFactor			1	0
-RenderVolumeLODFactor		1	1.125
-WindLightUseAtmosShaders	1	0
-RenderDeferred				1	0
-RenderDeferredSSAO			1	0
-RenderUseAdvancedAtmospherics 1 0
-RenderShadowDetail			1	0
-WLSkyDetail					1	48
-RenderFSAASamples			1	0
 
 //
 // Low Graphics Settings
@@ -113,7 +84,6 @@ RenderAvatarLODFactor		1	0
 RenderAvatarPhysicsLODFactor 1	0
 RenderAvatarMaxNonImpostors 1   3
 RenderAvatarMaxComplexity          1	35000
-RenderAvatarVP				1	0
 RenderFarClip				1	64
 RenderFlexTimeFactor		1	0
 RenderGlowResolutionPow		1	8
@@ -143,7 +113,6 @@ RenderAvatarCloth			1	0
 RenderAvatarLODFactor		1	0.5
 RenderAvatarMaxComplexity   1	100000
 RenderAvatarPhysicsLODFactor 1	0.75
-RenderAvatarVP				1	1
 RenderFarClip				1	96
 RenderFlexTimeFactor		1	1.0
 RenderGlowResolutionPow		1	8
@@ -173,7 +142,6 @@ RenderAvatarCloth			1	0
 RenderAvatarLODFactor		1	1.0
 RenderAvatarMaxComplexity   1	200000
 RenderAvatarPhysicsLODFactor 1	1.0
-RenderAvatarVP				1	1
 RenderFarClip				1	128
 RenderFlexTimeFactor		1	1.0
 RenderGlowResolutionPow		1	9
@@ -203,7 +171,6 @@ RenderAvatarCloth			1	0
 RenderAvatarLODFactor		1	1.0
 RenderAvatarMaxComplexity   1	250000
 RenderAvatarPhysicsLODFactor 1	1.0
-RenderAvatarVP				1	1
 RenderFarClip				1	128
 RenderFlexTimeFactor		1	1.0
 RenderGlowResolutionPow		1	9
@@ -233,7 +200,6 @@ RenderAvatarCloth			1	0
 RenderAvatarLODFactor		1	1.0
 RenderAvatarMaxComplexity   1	300000
 RenderAvatarPhysicsLODFactor 1	1.0
-RenderAvatarVP				1	1
 RenderFarClip				1	128
 RenderFlexTimeFactor		1	1.0
 RenderGlowResolutionPow		1	9
@@ -263,7 +229,6 @@ RenderAvatarCloth			1	0
 RenderAvatarLODFactor		1	1.0
 RenderAvatarMaxComplexity   1	350000
 RenderAvatarPhysicsLODFactor 1	1.0
-RenderAvatarVP				1	1
 RenderFarClip				1	128
 RenderFlexTimeFactor		1	1.0
 RenderGlowResolutionPow		1	9
@@ -292,7 +257,6 @@ RenderAnisotropic			1	1
 RenderAvatarCloth			1	1
 RenderAvatarLODFactor		1	1.0
 RenderAvatarPhysicsLODFactor 1	1.0
-RenderAvatarVP				1	1
 RenderFarClip				1	256
 RenderFlexTimeFactor		1	1.0
 RenderGlowResolutionPow		1	9
@@ -317,415 +281,45 @@ RenderFSAASamples			1	2
 // Class Unknown Hardware (unknown)
 //
 list Unknown
-RenderVBOEnable				1	0
 RenderShadowDetail			1	0
 RenderDeferred				1	0
 RenderDeferredSSAO			1	0
 RenderUseAdvancedAtmospherics 1 0
 
-//
-// Class 0 Hardware (just old)
-//
-list Class0
-RenderVBOEnable				1	1
-
-//
-// Class 1 Hardware
-//
-list Class1
-RenderVBOEnable				1	1
-
-//
-// Class 2 Hardware
-//
-list Class2
-RenderVBOEnable				1	1
-
-//
-// Class 3 Hardware
-//
-list Class3
-RenderVBOEnable				1	1
-
-//
-// Class 4 Hardware
-//
-list Class4
-RenderVBOEnable				1	1
-
-//
-// Class 5 Hardware
-//
-list Class5
-RenderVBOEnable				1	1
-
 //
 // VRAM > 512MB
 //
 list VRAMGT512
 RenderCompressTextures		1	0
 
-//
-// No Pixel Shaders available
-//
-list NoPixelShaders
-RenderAvatarVP				0	0
-RenderAvatarCloth			0	0
-RenderReflectionDetail		0	0
-WindLightUseAtmosShaders	0	0
-RenderDeferred				0	0
-RenderDeferredSSAO			0	0
-RenderShadowDetail			0	0
-RenderUseAdvancedAtmospherics 0 0
-
-//
-// No Vertex Shaders available
-//
-list NoVertexShaders
-RenderAvatarVP				0	0
-RenderAvatarCloth			0	0
-RenderReflectionDetail		0	0
-WindLightUseAtmosShaders	0	0
-RenderDeferred				0	0
-RenderDeferredSSAO			0	0
-RenderShadowDetail			0	0
-RenderUseAdvancedAtmospherics 0 0
-
-//
-// GL_ARB_map_buffer_range exists
-//
-list MapBufferRange
-RenderVBOMappingDisable		1	1
-
-
 //
 // "Default" setups for safe, low, medium, high
 //
 list safe
 RenderAnisotropic			1	0
 RenderAvatarCloth			0	0
-RenderAvatarVP				0	0
 RenderAvatarMaxNonImpostors 1	16
 RenderAvatarMaxComplexity          1	80000
 RenderObjectBump			0	0
 RenderLocalLights			1	0
 RenderMaxPartCount			1	1024
 RenderTerrainDetail 		1	0
-RenderVBOEnable				1	0
 RenderReflectionDetail		0	0
 WindLightUseAtmosShaders	0	0
 RenderDeferred				0	0
 RenderDeferredSSAO			0	0
 RenderShadowDetail			0	0
 
-//
-// CPU based feature masks
-//
-
-// 1Ghz or less (equiv)
-list CPUSlow
-RenderMaxPartCount			1	1024
-
-//
-// RAM based feature masks
-//
-list RAM256MB
-RenderObjectBump			0	0
-
-//
-// Graphics card based feature masks
-//
-list OpenGLPre15
-RenderVBOEnable				1	0
-
-list OpenGLPre30
-RenderDeferred				0	0
-RenderMaxTextureIndex		1	1
-
 list Intel
 RenderAnisotropic			1	0
-RenderVBOEnable				1	0
 RenderFSAASamples			1	0
+RenderGLMultiThreaded       1   0
+RenderGLCoreProfile         1   0
 
-list GeForce2
-RenderAnisotropic			1	0
-RenderMaxPartCount			1	2048
-RenderTerrainDetail			1	0
-RenderVBOEnable				1	1
-
-list SiS
-UseOcclusion				0	0
-
-
-list Intel_830M
-RenderTerrainDetail			1	0
-RenderVBOEnable				1	0
-
-list Intel_845G					
-RenderTerrainDetail			1	0
-RenderVBOEnable				1	0
-
-list Intel_855GM				
-RenderTerrainDetail			1	0
-RenderVBOEnable				1	0
-
-list Intel_865G			
-RenderTerrainDetail			1	0
-RenderVBOEnable				1	0
-
-list Intel_900		
-RenderTerrainDetail			1	0
-RenderVBOEnable				1	0
-
-list Intel_915GM	
-RenderTerrainDetail			1	0
-RenderVBOEnable				1	0
-
-list Intel_915G					
-RenderTerrainDetail			1	0
-RenderVBOEnable				1	0
-
-list Intel_945GM			
-RenderTerrainDetail			1	0
-RenderVBOEnable				1	0
-
-list Intel_945G
-RenderTerrainDetail			1	0
-RenderVBOEnable				1	0
-
-list Intel_950
-RenderTerrainDetail			1	0
-RenderVBOEnable				1	0
-
-list Intel_965
-RenderTerrainDetail			1	0
-RenderVBOEnable				1	0
-UseOcclusion				0	0
-
-list Intel_G33
-RenderTerrainDetail			1	0
-RenderVBOEnable				1	0
-
-list Intel_G45
-WindLightUseAtmosShaders		0	0
-
-list Intel_Bear_Lake	
-RenderTerrainDetail			1	0
-RenderVBOEnable				1	0
-
-list Intel_Broadwater 
-RenderTerrainDetail			1	0
-RenderVBOEnable				1	0
-
-list Intel_Brookdale	
-RenderTerrainDetail			1	0
-RenderVBOEnable				1	0
-
-list Intel_Eaglelake
-WindLightUseAtmosShaders	0	0
-
-list Intel_Montara
-RenderTerrainDetail			1	0
-RenderVBOEnable				1	0
-
-list Intel_Springdale
-RenderTerrainDetail			1	0
-RenderVBOEnable				1	0
-
-
-list ATI_FireGL_5200
-RenderVBOEnable				1	0
-WindLightUseAtmosShaders	0	0
-
-
-list ATI_Mobility_Radeon_7xxx
-RenderVBOEnable				0	0
-
-list ATI_Radeon_7xxx
-RenderVBOEnable				0	0
-
-list ATI_All-in-Wonder_Radeon
-RenderVBOEnable				0	0
-
-list ATI_All-in-Wonder_7500
-RenderVBOEnable				0	0
-
-list ATI_Mobility_Radeon_9600
-Disregard96DefaultDrawDistance	1	0
-
-
-/// tweaked ATI to 96 Draw distance
-
-list ATI_Radeon_9000
-Disregard96DefaultDrawDistance	1	0
-list ATI_Radeon_9200
-Disregard96DefaultDrawDistance	1	0
-list ATI_Radeon_9500
-Disregard96DefaultDrawDistance	1	0
-list ATI_Radeon_9600
-Disregard96DefaultDrawDistance	1	0
-
-/// tweaked ATI to 128 draw distance
-
-list ATI_Radeon_X300 
-Disregard128DefaultDrawDistance	1	0
-RenderVBOEnable				1	0
-list ATI_Radeon_X400 
-Disregard128DefaultDrawDistance	1	0
-RenderVBOEnable				1	0
-list ATI_Radeon_X500 
-Disregard128DefaultDrawDistance	1	0
-RenderVBOEnable				1	0
-list ATI_Radeon_X600 
-Disregard128DefaultDrawDistance	1	0
-RenderVBOEnable				1	0
-list ATI_Radeon_X700 
-Disregard128DefaultDrawDistance	1	0
-RenderVBOEnable				1	0
-list ATI_Radeon_X1300 
-Disregard128DefaultDrawDistance	1	0
-RenderVBOEnable				1	0
-UseStartScreen					0	0
-list ATI_Radeon_X1400 
-Disregard128DefaultDrawDistance	1	0
-RenderVBOEnable				1	0
-list ATI_Radeon_X1500 
-Disregard128DefaultDrawDistance	1	0
-RenderVBOEnable				1	0
-UseStartScreen					0	0
-list ATI_Radeon_X1600 
-Disregard128DefaultDrawDistance	1	0
-RenderVBOEnable				1	0
-list ATI_Radeon_X1700 
-Disregard128DefaultDrawDistance	1	0
-RenderVBOEnable				1	0
-list ATI_Mobility_Radeon_X1xxx
-Disregard128DefaultDrawDistance	1	0
-RenderVBOEnable				1	0
-
-list ATI_Radeon_HD_2300
-Disregard128DefaultDrawDistance	1	0
-list ATI_Radeon_HD_2400
-Disregard128DefaultDrawDistance	1	0
-list ATI_ASUS_AH24xx
-Disregard128DefaultDrawDistance	1	0
-
-
-// Avatar hardware skinning causes invisible avatars
-// on various ATI chipsets on drivers before 8.2
-
-list ATIOldDriver
-RenderAvatarVP				0	0
-RenderAvatarCloth			0	0
-RenderVBOEnable				1	0
-
-// ATI cards generally perform better when not using VBOs for streaming data
-// ATI cards also prefer an OpenGL Compatibility Profile Context
-list ATI
+// AMD cards generally perform better when not using VBOs for streaming data
+// AMD cards also prefer an OpenGL Compatibility Profile Context
+list AMD
 RenderUseStreamVBO			1	0
 RenderGLCoreProfile         1   0
 
-// Disable vertex buffer objects by default for ATI cards with little video memory
-list ATIVramLT256
-RenderVBOEnable				1	0
-
-/// Tweaked NVIDIA
-
-list NVIDIA_GeForce_FX_5100
-Disregard96DefaultDrawDistance	1	0
-list NVIDIA_GeForce_FX_5200
-Disregard96DefaultDrawDistance	1	0
-list NVIDIA_GeForce_FX_5500
-Disregard96DefaultDrawDistance	1	0
-list NVIDIA_GeForce_FX_5600
-Disregard96DefaultDrawDistance	1	0
-
-list NVIDIA_GeForce_FX_Go5100
-Disregard96DefaultDrawDistance	1	0
-list NVIDIA_GeForce_FX_Go5200
-Disregard96DefaultDrawDistance	1	0
-list NVIDIA_GeForce_FX_Go5300
-Disregard96DefaultDrawDistance	1	0
-list NVIDIA_GeForce_FX_Go5500
-Disregard96DefaultDrawDistance	1	0
-list NVIDIA_GeForce_FX_Go5600
-Disregard96DefaultDrawDistance	1	0
-
-list NVIDIA_GeForce_6100
-Disregard128DefaultDrawDistance	1	0
-list NVIDIA_GeForce_6200
-Disregard128DefaultDrawDistance	1	0
-list NVIDIA_GeForce_6500
-Disregard128DefaultDrawDistance	1	0
-list NVIDIA_GeForce_6600
-Disregard128DefaultDrawDistance	1	0
-
-list NVIDIA_G73
-Disregard128DefaultDrawDistance	1	0
-
-list NVIDIA_GeForce_Go_6100
-RenderVBOEnable				1	0
-Disregard128DefaultDrawDistance	1	0
-list NVIDIA_GeForce_Go_6200
-RenderVBOEnable				1	0
-Disregard128DefaultDrawDistance	1	0
-list NVIDIA_GeForce_Go_6500
-RenderVBOEnable				1	0
-Disregard128DefaultDrawDistance	1	0
-list NVIDIA_GeForce_Go_6600
-RenderVBOEnable				1	0
-Disregard128DefaultDrawDistance	1	0
-list NVIDIA_GeForce_Go_6700
-RenderVBOEnable				1	0
-Disregard128DefaultDrawDistance	1	0
-list NVIDIA_GeForce_Go_6800
-RenderVBOEnable				1	0
-Disregard128DefaultDrawDistance	1	0
-list NVIDIA_GeForce_Go_6
-RenderVBOEnable				1	0
-Disregard128DefaultDrawDistance	1	0
-
-list NVIDIA_GeForce_7000
-RenderShaderLightingMaxLevel	1	2
-list NVIDIA_GeForce_7100
-RenderShaderLightingMaxLevel	1	2
-list NVIDIA_GeForce_7200
-Disregard128DefaultDrawDistance	1	0
-RenderShaderLightingMaxLevel	1	2
-list NVIDIA_GeForce_7300
-Disregard128DefaultDrawDistance	1	0
-RenderShaderLightingMaxLevel	1	2
-list NVIDIA_GeForce_7400
-Disregard128DefaultDrawDistance	1	0
-RenderShaderLightingMaxLevel	1	2
-list NVIDIA_GeForce_7500
-RenderShaderLightingMaxLevel	1	2
-list NVIDIA_GeForce_7600
-RenderShaderLightingMaxLevel	1	2
-list NVIDIA_GeForce_7700
-RenderShaderLightingMaxLevel	1	2
-list NVIDIA_GeForce_7800
-RenderShaderLightingMaxLevel	1	2
-list NVIDIA_GeForce_7900
-RenderShaderLightingMaxLevel	1	2
-
-list NVIDIA_GeForce_Go_7200
-Disregard128DefaultDrawDistance	1	0
-RenderShaderLightingMaxLevel	1	2
-list NVIDIA_GeForce_Go_7300
-Disregard128DefaultDrawDistance	1	0
-RenderShaderLightingMaxLevel	1	2
-list NVIDIA_GeForce_Go_7300_LE
-RenderShaderLightingMaxLevel	1	2
-list NVIDIA_GeForce_Go_7400
-Disregard128DefaultDrawDistance	1	0
-RenderShaderLightingMaxLevel	1	2
-list NVIDIA_GeForce_Go_7600
-RenderShaderLightingMaxLevel	1	2
-list NVIDIA_GeForce_Go_7700
-RenderShaderLightingMaxLevel	1	2
-list NVIDIA_GeForce_Go_7800
-RenderShaderLightingMaxLevel	1	2
-list NVIDIA_GeForce_Go_7900
-RenderShaderLightingMaxLevel	1	2
 
diff --git a/indra/newview/featuretable_mac.txt b/indra/newview/featuretable_mac.txt
index bac6fd5708..13ede23a91 100644
--- a/indra/newview/featuretable_mac.txt
+++ b/indra/newview/featuretable_mac.txt
@@ -1,4 +1,4 @@
-version 37
+version 38
 // The version number above should be incremented IF AND ONLY IF some
 // change has been made that is sufficiently important to justify
 // resetting the graphics preferences of all users to the recommended
@@ -70,37 +70,8 @@ RenderShadowDetail			1	2
 RenderUseStreamVBO			1	1
 RenderFSAASamples			1	16
 RenderMaxTextureIndex		1	16
-
-//
-// Low Graphics Settings (fixed function)
-//
-list LowFixedFunction
-RenderAnisotropic			1	0
-RenderAvatarCloth			1	0
-RenderAvatarLODFactor		1	0
-RenderAvatarPhysicsLODFactor 1	0
-RenderAvatarMaxNonImpostors 1   3
-RenderAvatarMaxComplexity          1	25000
-RenderAvatarVP				1	0
-RenderFarClip				1	64
-RenderFlexTimeFactor		1	0
-RenderGlowResolutionPow		1	8
-RenderLocalLights			1	0
-RenderMaxPartCount			1	0
-RenderObjectBump			1	0
-RenderReflectionDetail		1	0
-RenderTerrainDetail			1	0
-RenderTerrainLODFactor		1	1
-RenderTransparentWater		1	0
-RenderTreeLODFactor			1	0
-RenderVolumeLODFactor		1	0.5
-WindLightUseAtmosShaders	1	0
-RenderDeferred				1	0
-RenderDeferredSSAO			1	0
-RenderUseAdvancedAtmospherics 1 0
-RenderShadowDetail			1	0
-WLSkyDetail					1	48
-RenderFSAASamples			1	0
+RenderGLCoreProfile         1   0
+RenderGLMultiThreaded       1   0
 
 //
 // Low Graphics Settings
@@ -112,7 +83,6 @@ RenderAvatarLODFactor		1	0
 RenderAvatarPhysicsLODFactor 1	0
 RenderAvatarMaxNonImpostors 1   3
 RenderAvatarMaxComplexity          1	35000
-RenderAvatarVP				1	0
 RenderFarClip				1	64
 RenderFlexTimeFactor		1	0
 RenderGlowResolutionPow		1	8
@@ -142,7 +112,6 @@ RenderAvatarCloth			1	0
 RenderAvatarLODFactor		1	0.5
 RenderAvatarMaxComplexity   1	100000
 RenderAvatarPhysicsLODFactor 1	0.75
-RenderAvatarVP				1	1
 RenderFarClip				1	96
 RenderFlexTimeFactor		1	1.0
 RenderGlowResolutionPow		1	8
@@ -172,7 +141,6 @@ RenderAvatarCloth			1	0
 RenderAvatarLODFactor		1	1.0
 RenderAvatarMaxComplexity   1	200000
 RenderAvatarPhysicsLODFactor 1	1.0
-RenderAvatarVP				1	1
 RenderFarClip				1	128
 RenderFlexTimeFactor		1	1.0
 RenderGlowResolutionPow		1	9
@@ -202,7 +170,6 @@ RenderAvatarCloth			1	0
 RenderAvatarLODFactor		1	1.0
 RenderAvatarMaxComplexity   1	250000
 RenderAvatarPhysicsLODFactor 1	1.0
-RenderAvatarVP				1	1
 RenderFarClip				1	128
 RenderFlexTimeFactor		1	1.0
 RenderGlowResolutionPow		1	9
@@ -232,7 +199,6 @@ RenderAvatarCloth			1	0
 RenderAvatarLODFactor		1	1.0
 RenderAvatarMaxComplexity   1	300000
 RenderAvatarPhysicsLODFactor 1	1.0
-RenderAvatarVP				1	1
 RenderFarClip				1	128
 RenderFlexTimeFactor		1	1.0
 RenderGlowResolutionPow		1	9
@@ -262,7 +228,6 @@ RenderAvatarCloth			1	0
 RenderAvatarLODFactor		1	1.0
 RenderAvatarMaxComplexity   1	350000
 RenderAvatarPhysicsLODFactor 1	1.0
-RenderAvatarVP				1	1
 RenderFarClip				1	128
 RenderFlexTimeFactor		1	1.0
 RenderGlowResolutionPow		1	9
@@ -291,7 +256,6 @@ RenderAnisotropic			1	1
 RenderAvatarCloth			1	1
 RenderAvatarLODFactor		1	1.0
 RenderAvatarPhysicsLODFactor 1	1.0
-RenderAvatarVP				1	1
 RenderFarClip				1	256
 RenderFlexTimeFactor		1	1.0
 RenderGlowResolutionPow		1	9
@@ -316,73 +280,11 @@ RenderFSAASamples			1	2
 // Class Unknown Hardware (unknown)
 //
 list Unknown
-RenderVBOEnable				1	0
 RenderShadowDetail			1	0
 RenderDeferred				1	0
 RenderDeferredSSAO			1	0
 RenderUseAdvancedAtmospherics 1 0
 
-//
-// Class 0 Hardware (just old)
-//
-list Class0
-RenderVBOEnable				1	1
-
-//
-// Class 1 Hardware
-//
-list Class1
-RenderVBOEnable				1	1
-
-//
-// Class 2 Hardware
-//
-list Class2
-RenderVBOEnable				1	1
-
-//
-// Class 3 Hardware
-//
-list Class3
-RenderVBOEnable				1	1
-
-//
-// Class 4 Hardware
-//
-list Class4
-RenderVBOEnable				1	1
-
-//
-// Class 5 Hardware
-//
-list Class5
-RenderVBOEnable				1	1
-
-//
-// No Pixel Shaders available
-//
-list NoPixelShaders
-RenderAvatarVP				0	0
-RenderAvatarCloth			0	0
-RenderReflectionDetail		0	0
-WindLightUseAtmosShaders	0	0
-RenderDeferred				0	0
-RenderDeferredSSAO			0	0
-RenderUseAdvancedAtmospherics 0 0
-RenderShadowDetail			0	0
-
-//
-// No Vertex Shaders available
-//
-list NoVertexShaders
-RenderAvatarVP				0	0
-RenderAvatarCloth			0	0
-RenderReflectionDetail		0	0
-WindLightUseAtmosShaders	0	0
-RenderDeferred				0	0
-RenderDeferredSSAO			0	0
-RenderUseAdvancedAtmospherics 0 0
-RenderShadowDetail			0	0
 
 //
 // VRAM > 512MB
@@ -396,14 +298,12 @@ RenderCompressTextures		1	0
 list safe
 RenderAnisotropic			1	0
 RenderAvatarCloth			0	0
-RenderAvatarVP				0	0
 RenderAvatarMaxNonImpostors 1	16
 RenderAvatarMaxComplexity          1	80000
 RenderObjectBump			0	0
 RenderLocalLights			1	0
 RenderMaxPartCount			1	1024
 RenderTerrainDetail 		1	0
-RenderVBOEnable				1	0
 RenderReflectionDetail		0	0
 WindLightUseAtmosShaders	0	0
 RenderDeferred				0	0
@@ -411,31 +311,10 @@ RenderDeferredSSAO			0	0
 RenderUseAdvancedAtmospherics 0 0
 RenderShadowDetail			0	0
 
-//
-// CPU based feature masks
-//
-
-// 1Ghz or less (equiv)
-list CPUSlow
-RenderMaxPartCount			1	1024
-
-//
-// RAM based feature masks
-//
-list RAM256MB
-RenderObjectBump			0	0
-
-//
-// Graphics card based feature masks
-//
-list OpenGLPre15
-RenderVBOEnable				1	0
-
-
 list TexUnit8orLess
 RenderDeferredSSAO			0	0
 
-list ATI
+list AMD
 RenderDeferredSSAO			1	0
 
 list Intel
@@ -443,195 +322,6 @@ RenderAnisotropic			1	0
 RenderLocalLights			1	0
 RenderFSAASamples			1	0
 
-list GeForce2
-RenderAnisotropic			1	0
-RenderLocalLights			1	0
-RenderMaxPartCount			1	2048
-RenderTerrainDetail			1	0
-RenderVBOEnable				1	1
-
-list Intel_830M
-RenderTerrainDetail			1	0
-RenderVBOEnable				1	0
-
-list Intel_845G					
-RenderTerrainDetail			1	0
-RenderVBOEnable				1	0
-
-list Intel_855GM				
-RenderTerrainDetail			1	0
-RenderVBOEnable				1	0
-
-list Intel_865G			
-RenderTerrainDetail			1	0
-RenderVBOEnable				1	0
-
-list Intel_900		
-RenderTerrainDetail			1	0
-RenderVBOEnable				1	0
-
-list Intel_915GM	
-RenderTerrainDetail			1	0
-RenderVBOEnable				1	0
-
-list Intel_915G					
-RenderTerrainDetail			1	0
-RenderVBOEnable				1	0
-
-list Intel_945GM			
-RenderTerrainDetail			1	0
-RenderVBOEnable				1	0
-
-list Intel_945G
-RenderTerrainDetail			1	0
-RenderVBOEnable				1	0
-
-list Intel_950
-RenderTerrainDetail			1	0
-RenderVBOEnable				1	0
-RenderGround				1	0
-
-list Intel_965
-RenderTerrainDetail			1	0
-RenderVBOEnable				1	0
-UseOcclusion				0	0
-
-list Intel_G33
-RenderTerrainDetail			1	0
-RenderVBOEnable				1	0
-
-list Intel_Bear_Lake	
-RenderTerrainDetail			1	0
-RenderVBOEnable				1	0
-
-list Intel_Broadwater 
-RenderTerrainDetail			1	0
-RenderVBOEnable				1	0
-
-list Intel_Brookdale	
-RenderTerrainDetail			1	0
-RenderVBOEnable				1	0
-
-list Intel_X3100
-WindLightUseAtmosShaders	0	0
-
-list Intel_Montara
-RenderTerrainDetail			1	0
-RenderVBOEnable				1	0
-
-list Intel_Springdale
-RenderTerrainDetail			1	0
-RenderVBOEnable				1	0
-
-list ATI_Mobility_Radeon_9600
-Disregard96DefaultDrawDistance	1	0
-
-list NVIDIA_GeForce_8600
-RenderTextureMemoryMultiple			1	1	
-UseOcclusion				0	0
-
-/// tweaked ATI to 96 Draw distance
-
-list ATI_Radeon_9000
-Disregard96DefaultDrawDistance	1	0
-list ATI_Radeon_9200
-Disregard96DefaultDrawDistance	1	0
-list ATI_Radeon_9500
-Disregard96DefaultDrawDistance	1	0
-list ATI_Radeon_9600
-Disregard96DefaultDrawDistance	1	0
-
-/// tweaked ATI to 128 draw distance
-
-list ATI_Radeon_X300 
-Disregard128DefaultDrawDistance	1	0
-list ATI_Radeon_X400 
-Disregard128DefaultDrawDistance	1	0
-list ATI_Radeon_X500 
-Disregard128DefaultDrawDistance	1	0
-list ATI_Radeon_X600 
-Disregard128DefaultDrawDistance	1	0
-list ATI_Radeon_X700 
-Disregard128DefaultDrawDistance	1	0
-list ATI_Radeon_X1300 
-Disregard128DefaultDrawDistance	1	0
-list ATI_Radeon_X1400 
-Disregard128DefaultDrawDistance	1	0
-list ATI_Radeon_X1500 
-Disregard128DefaultDrawDistance	1	0
-list ATI_Radeon_X1600 
-Disregard128DefaultDrawDistance	1	0
-list ATI_Radeon_X1700 
-Disregard128DefaultDrawDistance	1	0
-list ATI_Mobility_Radeon_X1xxx
-Disregard128DefaultDrawDistance	1	0
-
-/// Tweaked NVIDIA
-
-list NVIDIA_GeForce_FX_5100
-Disregard96DefaultDrawDistance	1	0
-list NVIDIA_GeForce_FX_5200
-Disregard96DefaultDrawDistance	1	0
-list NVIDIA_GeForce_FX_5500
-Disregard96DefaultDrawDistance	1	0
-
-list NVIDIA_GeForce_FX_Go5100
-Disregard96DefaultDrawDistance	1	0
-list NVIDIA_GeForce_FX_Go5200
-Disregard96DefaultDrawDistance	1	0
-list NVIDIA_GeForce_FX_Go5300
-Disregard96DefaultDrawDistance	1	0
-list NVIDIA_GeForce_FX_Go5500
-Disregard96DefaultDrawDistance	1	0
-list NVIDIA_GeForce_FX_Go5600
-Disregard96DefaultDrawDistance	1	0
-
-list NVIDIA_GeForce_6100
-Disregard128DefaultDrawDistance	1	0
-list NVIDIA_GeForce_6200
-Disregard128DefaultDrawDistance	1	0
-list NVIDIA_GeForce_6500
-Disregard128DefaultDrawDistance	1	0
-list NVIDIA_GeForce_6600
-Disregard128DefaultDrawDistance	1	0
-
-
-list NVIDIA_GeForce_Go_6100
-RenderVBOEnable				1	0
-Disregard128DefaultDrawDistance	1	0
-list NVIDIA_GeForce_Go_6200
-RenderVBOEnable				1	0
-Disregard128DefaultDrawDistance	1	0
-list NVIDIA_GeForce_Go_6500
-RenderVBOEnable				1	0
-Disregard128DefaultDrawDistance	1	0
-list NVIDIA_GeForce_Go_6600
-RenderVBOEnable				1	0
-Disregard128DefaultDrawDistance	1	0
-list NVIDIA_GeForce_Go_6700
-RenderVBOEnable				1	0
-Disregard128DefaultDrawDistance	1	0
-list NVIDIA_GeForce_Go_6800
-RenderVBOEnable				1	0
-Disregard128DefaultDrawDistance	1	0
-list NVIDIA_GeForce_Go_6
-RenderVBOEnable				1	0
-Disregard128DefaultDrawDistance	1	0
-
-list NVIDIA_GeForce_7200
-Disregard128DefaultDrawDistance	1	0
-list NVIDIA_GeForce_7300
-Disregard128DefaultDrawDistance	1	0
-list NVIDIA_GeForce_7400
-Disregard128DefaultDrawDistance	1	0
-
-list NVIDIA_GeForce_Go_7200
-Disregard128DefaultDrawDistance	1	0
-list NVIDIA_GeForce_Go_7300
-Disregard128DefaultDrawDistance	1	0
-list NVIDIA_GeForce_Go_7400
-Disregard128DefaultDrawDistance	1	0
-
 list OSX_10_6_8
 RenderDeferred 0 0
 
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index a5d32ba243..22d986a27e 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -1104,7 +1104,7 @@ bool LLAppViewer::init()
 		{
 			url = LLTrans::getString("NvidiaDriverPage");
 		}
-		else if (gGLManager.mIsATI)
+		else if (gGLManager.mIsAMD)
 		{
 			url = LLTrans::getString("AMDDriverPage");
 		}
diff --git a/indra/newview/lldynamictexture.cpp b/indra/newview/lldynamictexture.cpp
index 31ca2531ba..63e7887d81 100644
--- a/indra/newview/lldynamictexture.cpp
+++ b/indra/newview/lldynamictexture.cpp
@@ -125,7 +125,7 @@ void LLViewerDynamicTexture::preRender(BOOL clear_depth)
 		llassert(mFullHeight <= static_cast<S32>(gPipeline.mPhysicsDisplay.getHeight()));
 	}
 
-	if (gGLManager.mHasFramebufferObject && gPipeline.mPhysicsDisplay.isComplete() && !gGLManager.mIsATI)
+	if (gGLManager.mHasFramebufferObject && gPipeline.mPhysicsDisplay.isComplete() && !gGLManager.mIsAMD)
 	{ //using offscreen render target, just use the bottom left corner
 		mOrigin.set(0, 0);
 	}
@@ -212,7 +212,7 @@ BOOL LLViewerDynamicTexture::updateAllInstances()
 		return TRUE;
 	}
 
-	bool use_fbo = gGLManager.mHasFramebufferObject && gPipeline.mBake.isComplete() && !gGLManager.mIsATI;
+	bool use_fbo = gGLManager.mHasFramebufferObject && gPipeline.mBake.isComplete() && !gGLManager.mIsAMD;
 
 	if (use_fbo)
 	{
diff --git a/indra/newview/llfeaturemanager.cpp b/indra/newview/llfeaturemanager.cpp
index 98c8531cd6..47bc666083 100644
--- a/indra/newview/llfeaturemanager.cpp
+++ b/indra/newview/llfeaturemanager.cpp
@@ -607,22 +607,6 @@ void LLFeatureManager::setGraphicsLevel(U32 level, bool skipFeatures)
 
     // if we're passed an invalid level, default to "Low"
     std::string features(isValidGraphicsLevel(level)? getNameForGraphicsLevel(level) : "Low");
-    if (features == "Low")
-    {
-#if LL_DARWIN
-        // This Mac-specific change is to insure that we force 'Basic Shaders' for all Mac
-        // systems which support them instead of falling back to fixed-function unnecessarily
-        // MAINT-2157
-        if (gGLManager.mGLVersion < 2.1f)
-#else
-        // only use fixed function by default if GL version < 3.0 or this is an intel graphics chip
-        if (gGLManager.mGLVersion < 3.f || gGLManager.mIsIntel)
-#endif
-        {
-            // same as Low, but with "Basic Shaders" disabled
-            features = "LowFixedFunction";
-        }
-    }
 
     maskFeatures(features);
 
@@ -670,42 +654,18 @@ void LLFeatureManager::applyBaseMasks()
 	}
 
 	// now all those wacky ones
-	if (!mGPUSupported)
-	{
-		maskFeatures("NoVertexShaders");
-	}
 	if (gGLManager.mIsNVIDIA)
 	{
 		maskFeatures("NVIDIA");
 	}
-	if (gGLManager.mIsGF2or4MX)
-	{
-		maskFeatures("GeForce2");
-	}
-	if (gGLManager.mIsATI)
+	if (gGLManager.mIsAMD)
 	{
-		maskFeatures("ATI");
-	}
-	if (gGLManager.mHasATIMemInfo && gGLManager.mVRAM < 256)
-	{
-		maskFeatures("ATIVramLT256");
-	}
-	if (gGLManager.mATIOldDriver)
-	{
-		maskFeatures("ATIOldDriver");
-	}
-	if (gGLManager.mIsGFFX)
-	{
-		maskFeatures("GeForceFX");
+		maskFeatures("AMD");
 	}
 	if (gGLManager.mIsIntel)
 	{
 		maskFeatures("Intel");
 	}
-	if (gGLManager.mGLVersion < 1.5f)
-	{
-		maskFeatures("OpenGLPre15");
-	}
 	if (gGLManager.mGLVersion < 3.f)
 	{
 		maskFeatures("OpenGLPre30");
@@ -745,17 +705,6 @@ void LLFeatureManager::applyBaseMasks()
 	//LL_INFOS() << "Masking features from gpu table match: " << gpustr << LL_ENDL;
 	maskFeatures(gpustr);
 
-	// now mask cpu type ones
-	if (gSysMemory.getPhysicalMemoryKB() <= U32Megabytes(256))
-	{
-		maskFeatures("RAM256MB");
-	}
-	
-	if (gSysCPU.getMHz() < 1100)
-	{
-		maskFeatures("CPUSlow");
-	}
-
 	if (isSafe())
 	{
 		maskFeatures("safe");
diff --git a/indra/newview/llglsandbox.cpp b/indra/newview/llglsandbox.cpp
index 0b5064c77d..175f1849cf 100644
--- a/indra/newview/llglsandbox.cpp
+++ b/indra/newview/llglsandbox.cpp
@@ -1115,6 +1115,7 @@ F32 gpu_benchmark()
 	// ensure matched pair of bind() and unbind() calls
 	ShaderBinder binder(gBenchmarkProgram);
 
+#ifdef GL_ARB_vertex_array_object
     U32 glarray = 0;
 
     if (LLRender::sGLCoreProfile)
@@ -1122,6 +1123,7 @@ F32 gpu_benchmark()
         glGenVertexArrays(1, &glarray);
         glBindVertexArray(glarray);
     }
+#endif
 
 	buff->setBuffer(LLVertexBuffer::MAP_VERTEX);
 	glFinish();
@@ -1155,11 +1157,13 @@ F32 gpu_benchmark()
 		}
 	}
 
+#ifdef GL_ARB_vertex_array_object
     if (LLRender::sGLCoreProfile)
     {
         glBindVertexArray(0);
         glDeleteVertexArrays(1, &glarray);
     }
+#endif
 
 
 	std::sort(results.begin(), results.end());
diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp
index 37ed2e9f20..1e0dd2df51 100644
--- a/indra/newview/llviewertexture.cpp
+++ b/indra/newview/llviewertexture.cpp
@@ -1633,8 +1633,7 @@ void LLViewerFetchedTexture::scheduleCreateTexture()
         if (preCreateTexture())
         {
             mNeedsCreateTexture = TRUE;
-#if LL_WINDOWS //flip to 0 to revert to single-threaded OpenGL texture uploads
-            auto mainq = mMainQueue.lock();
+            auto mainq = LLImageGLThread::sEnabled ? mMainQueue.lock() : nullptr;
             if (mainq)
             {
                 mainq->postTo(
@@ -1660,7 +1659,6 @@ void LLViewerFetchedTexture::scheduleCreateTexture()
                     });
             }
             else
-#endif
             {
                 gTextureList.mCreateTextureList.insert(this);
                 unref();
diff --git a/indra/newview/llviewertexturelist.cpp b/indra/newview/llviewertexturelist.cpp
index fe26cd67a4..dc506d325b 100644
--- a/indra/newview/llviewertexturelist.cpp
+++ b/indra/newview/llviewertexturelist.cpp
@@ -1361,7 +1361,7 @@ S32Megabytes LLViewerTextureList::getMaxVideoRamSetting(bool get_recommended, fl
 		//  - it's going to be swapping constantly regardless
 		S32Megabytes max_vram(gGLManager.mVRAM);
 
-		if(gGLManager.mIsATI)
+		if(gGLManager.mIsAMD)
 		{
 			//shrink the availabe vram for ATI cards because some of them do not handel texture swapping well.
 			max_vram = max_vram * 0.75f; 
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index 6462ec019b..46204bc642 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -2022,7 +2022,7 @@ 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(mWindow, LLViewerTexture::MAX_GL_IMAGE_CATEGORY) ;
+	LLImageGL::initClass(mWindow, LLViewerTexture::MAX_GL_IMAGE_CATEGORY, false, gSavedSettings.getBOOL("RenderGLMultiThreaded"));
 	gTextureList.init();
 	LLViewerTextureManager::init() ;
 	gBumpImageList.init();
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index df676b30fc..d3b2443116 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -890,7 +890,7 @@ bool LLPipeline::allocateScreenBuffer(U32 resX, U32 resY, U32 samples)
 		if (!addDeferredAttachments(mDeferredScreen)) return false;
 	
 		GLuint screenFormat = GL_RGBA16;
-		if (gGLManager.mIsATI)
+		if (gGLManager.mIsAMD)
 		{
 			screenFormat = GL_RGBA12;
 		}
-- 
cgit v1.2.3


From c614674ee66df5bca4e0c62c504f66ec73732be4 Mon Sep 17 00:00:00 2001
From: Mnikolenko Productengine <mnikolenko@productengine.com>
Date: Mon, 6 Dec 2021 19:20:49 +0200
Subject: SL-16282 FIXED Friend thumbnails are flickering

---
 indra/llrender/llimagegl.cpp | 6 ------
 1 file changed, 6 deletions(-)

(limited to 'indra')

diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp
index 6cdd6a3460..9931ce7d3e 100644
--- a/indra/llrender/llimagegl.cpp
+++ b/indra/llrender/llimagegl.cpp
@@ -556,12 +556,6 @@ bool LLImageGL::setSize(S32 width, S32 height, S32 ncomponents, S32 discard_leve
 			return false;
 		}
 		
-		if (mTexName)
-		{
-// 			LL_WARNS() << "Setting Size of LLImageGL with existing mTexName = " << mTexName << LL_ENDL;
-			destroyGLTexture();
-		}
-
 		// pickmask validity depends on old image size, delete it
 		freePickMask();
 
-- 
cgit v1.2.3


From d4707b7ef31355278e57a258a1bb19ef014376ce Mon Sep 17 00:00:00 2001
From: Runitai Linden <davep@lindenlab.com>
Date: Mon, 6 Dec 2021 16:49:29 -0600
Subject: SL-16451 Fix for rigged meshes disappearing when rendered as static.

---
 indra/newview/llvovolume.cpp | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

(limited to 'indra')

diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index 4e7eb4df5d..c1f83ed0ae 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -1699,6 +1699,7 @@ BOOL LLVOVolume::genBBoxes(BOOL force_global)
     {
         LL_DEBUGS("RiggedBox") << "rebuilding box, volume face count " << getVolume()->getNumVolumeFaces() << " drawable face count " << mDrawable->getNumFaces() << LL_ENDL;
     }
+
     // There's no guarantee that getVolume()->getNumFaces() == mDrawable->getNumFaces()
 	for (S32 i = 0;
 		 i < getVolume()->getNumVolumeFaces() && i < mDrawable->getNumFaces() && i < getNumTEs();
@@ -1740,7 +1741,18 @@ BOOL LLVOVolume::genBBoxes(BOOL force_global)
 		}
 	}
 
-    if (isRiggedMesh())
+    bool rigged = false;
+    
+    if (!isAnimatedObject())
+    {
+        rigged = isRiggedMesh() && isAttachment();
+    }
+    else
+    {
+        rigged = isRiggedMesh() && getControlAvatar() && getControlAvatar()->mPlaying;
+    }
+
+    if (rigged)
     {
         min.set(-1, -1, -1, 0);
         max.set(1, 1, 1, 0);
-- 
cgit v1.2.3


From 72cd3ffde708d6434bd45a35d3934584a101cc40 Mon Sep 17 00:00:00 2001
From: Runitai Linden <davep@lindenlab.com>
Date: Mon, 6 Dec 2021 17:02:41 -0600
Subject: SL-16447 Fix for broken benchmark.

---
 indra/llrender/llvertexbuffer.cpp | 2 ++
 1 file changed, 2 insertions(+)

(limited to 'indra')

diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp
index dcce5a5a1d..9926447ef8 100644
--- a/indra/llrender/llvertexbuffer.cpp
+++ b/indra/llrender/llvertexbuffer.cpp
@@ -734,10 +734,12 @@ void LLVertexBuffer::drawArrays(U32 mode, U32 first, U32 count) const
     }
 #endif
 
+    LLGLSLShader::startProfile();
     {
         LL_PROFILER_GPU_ZONEC("gl.DrawArrays", 0xFF4040)
             glDrawArrays(sGLMode[mode], first, count);
     }
+    LLGLSLShader::stopProfile(count, mode);
 
     stop_glerror();
     placeFence();
-- 
cgit v1.2.3


From 66d88733ee987362dd9efb807faa6198ec655175 Mon Sep 17 00:00:00 2001
From: Mnikolenko Productengine <mnikolenko@productengine.com>
Date: Tue, 7 Dec 2021 19:15:50 +0200
Subject: SL-16454 FIXED Performance viewer login screen is black after a
 Release viewer session.

---
 indra/newview/llfeaturemanager.cpp | 3 ---
 1 file changed, 3 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llfeaturemanager.cpp b/indra/newview/llfeaturemanager.cpp
index 47bc666083..3240f169b3 100644
--- a/indra/newview/llfeaturemanager.cpp
+++ b/indra/newview/llfeaturemanager.cpp
@@ -520,7 +520,6 @@ void LLFeatureManager::initSingleton()
 
 void LLFeatureManager::applyRecommendedSettings()
 {
-	loadGPUClass();
 	// apply saved settings
 	// cap the level at 2 (high)
 	U32 level = llmax(GPU_CLASS_0, llmin(mGPUClass, GPU_CLASS_5));
@@ -719,11 +718,9 @@ LLSD LLFeatureManager::getRecommendedSettingsMap()
 
 	LLSD map(LLSD::emptyMap());
 
-	loadGPUClass();
 	U32 level = llmax(GPU_CLASS_0, llmin(mGPUClass, GPU_CLASS_5));
 	LL_INFOS("RenderInit") << "Getting the map of recommended settings for level " << level << LL_ENDL;
 
-	applyBaseMasks();
 	std::string features(isValidGraphicsLevel(level) ? getNameForGraphicsLevel(level) : "Low");
 
 	maskFeatures(features);
-- 
cgit v1.2.3


From 8a18b5e427e261ccc60eeb673f140eff3690bf7b Mon Sep 17 00:00:00 2001
From: Runitai Linden <davep@lindenlab.com>
Date: Tue, 7 Dec 2021 16:32:38 -0600
Subject: SL-16462 Fix for broken water clip plane during water
 reflection/refraction map render.

---
 indra/llrender/llgl.cpp           |  3 ++-
 indra/newview/llviewerdisplay.cpp | 17 +-------------
 indra/newview/pipeline.cpp        | 48 ++++++++++++++++++++++++++-------------
 indra/newview/pipeline.h          |  2 +-
 4 files changed, 36 insertions(+), 34 deletions(-)

(limited to 'indra')

diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp
index 64db095dec..18a79d5264 100644
--- a/indra/llrender/llgl.cpp
+++ b/indra/llrender/llgl.cpp
@@ -2112,7 +2112,8 @@ LLGLUserClipPlane::LLGLUserClipPlane(const LLPlane& p, const glh::matrix4f& mode
 		mModelview = modelview;
 		mProjection = projection;
 
-		setPlane(p[0], p[1], p[2], p[3]);
+        //flip incoming LLPlane to get consistent behavior compared to frustum culling
+		setPlane(-p[0], -p[1], -p[2], -p[3]);
 	}
 }
 
diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp
index 046187cf4f..c84a8c70fa 100644
--- a/indra/newview/llviewerdisplay.cpp
+++ b/indra/newview/llviewerdisplay.cpp
@@ -683,21 +683,6 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 		
 		stop_glerror();
 
-		S32 water_clip = 0;
-		if ((LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_ENVIRONMENT) > 1) &&
-			 (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_WATER) || 
-			  gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_VOIDWATER)))
-		{
-			if (LLViewerCamera::getInstance()->cameraUnderWater())
-			{
-				water_clip = -1;
-			}
-			else
-			{
-				water_clip = 1;
-			}
-		}
-		
 		LLAppViewer::instance()->pingMainloopTimeout("Display:Cull");
 		
 		//Increment drawable frame counter
@@ -719,7 +704,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 		static LLCullResult result;
 		LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD;
 		LLPipeline::sUnderWaterRender = LLViewerCamera::getInstance()->cameraUnderWater();
-		gPipeline.updateCull(*LLViewerCamera::getInstance(), result, water_clip);
+		gPipeline.updateCull(*LLViewerCamera::getInstance(), result);
 		stop_glerror();
 
 		LLGLState::checkStates();
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index d3b2443116..dce63e06fb 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -2321,7 +2321,7 @@ bool LLPipeline::getVisibleExtents(LLCamera& camera, LLVector3& min, LLVector3&
 
 static LLTrace::BlockTimerStatHandle FTM_CULL("Object Culling");
 
-void LLPipeline::updateCull(LLCamera& camera, LLCullResult& result, S32 water_clip, LLPlane* planep)
+void LLPipeline::updateCull(LLCamera& camera, LLCullResult& result, LLPlane* planep)
 {
 	static LLCachedControl<bool> use_occlusion(gSavedSettings,"UseOcclusion");
 	static bool can_use_occlusion = LLFeatureManager::getInstance()->isFeatureAvailable("UseOcclusion") 
@@ -2413,7 +2413,7 @@ void LLPipeline::updateCull(LLCamera& camera, LLCullResult& result, S32 water_cl
 		LLVOCachePartition* vo_part = region->getVOCachePartition();
 		if(vo_part)
 		{
-            bool do_occlusion_cull = can_use_occlusion && use_occlusion && !gUseWireframe; // && 0 > water_clip
+            bool do_occlusion_cull = can_use_occlusion && use_occlusion && !gUseWireframe;
 			vo_part->cull(camera, do_occlusion_cull);
 		}
 	}
@@ -9158,22 +9158,20 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in)
         //plane params
         LLPlane plane;
         LLVector3 pnorm;
-        S32 water_clip = 0;
-        if (!camera_is_underwater)
+
+        if (camera_is_underwater)
         {
-            //camera is above water, clip plane points up
-            pnorm.setVec(0,0,1);
-            plane.setVec(pnorm, -water_height);
-            water_clip = 1;
+            //camera is below water, cull above water
+            pnorm.setVec(0, 0, 1);
         }
         else
         {
-            //camera is below water, clip plane points down
-            pnorm = LLVector3(0,0,-1);
-            plane.setVec(pnorm, water_height);
-            water_clip = -1;
+            //camera is above water, cull below water
+            pnorm = LLVector3(0, 0, -1);
         }
 
+        plane.setVec(LLVector3(0, 0, water_height), pnorm);
+
         if (!camera_is_underwater)
         {
             //generate planar reflection map
@@ -9271,7 +9269,7 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in)
 
                             LLGLUserClipPlane clip_plane(plane, mReflectionModelView, saved_projection);
                             LLGLDisable cull(GL_CULL_FACE);
-                            updateCull(camera, mReflectedObjects, -water_clip, &plane);
+                            updateCull(camera, mReflectedObjects, &plane);
                             stateSort(camera, mReflectedObjects);
                             renderGeom(camera);
                         }
@@ -9336,11 +9334,29 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in)
                 mWaterDis.clear();
                 gGL.setColorMask(true, false);
 
-                F32 water_dist = water_height * LLPipeline::sDistortionWaterClipPlaneMargin;
+                F32 water_dist = water_height;
 
                 //clip out geometry on the same side of water as the camera w/ enough margin to not include the water geo itself,
                 // but not so much as to clip out parts of avatars that should be seen under the water in the distortion map
-                LLPlane plane(-pnorm, camera_is_underwater ? -water_height : water_dist);
+                LLPlane plane;
+
+                if (camera_is_underwater)
+                {
+                    //nudge clip plane below water to avoid visible holes in objects intersecting water surface
+                    water_dist /= LLPipeline::sDistortionWaterClipPlaneMargin;
+                    //camera is below water, clip plane points up
+                    pnorm.setVec(0, 0, -1);
+                }
+                else
+                {
+                    //nudge clip plane above water to avoid visible holes in objects intersecting water surface
+                    water_dist *= LLPipeline::sDistortionWaterClipPlaneMargin;
+                    //camera is above water, clip plane points down
+                    pnorm = LLVector3(0, 0, 1);
+                }
+
+                plane.setVec(LLVector3(0, 0, water_dist), pnorm);
+
                 LLGLUserClipPlane clip_plane(plane, saved_modelview, saved_projection);
 
                 gGL.setColorMask(true, true);
@@ -9349,7 +9365,7 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in)
 
                 if (reflection_detail >= WATER_REFLECT_NONE_WATER_TRANSPARENT)
                 {
-                    updateCull(camera, mRefractedObjects, water_clip, &plane);
+                    updateCull(camera, mRefractedObjects, &plane);
                     stateSort(camera, mRefractedObjects);
                     renderGeom(camera);
                 }
diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h
index 794d806d0c..fdc3738472 100644
--- a/indra/newview/pipeline.h
+++ b/indra/newview/pipeline.h
@@ -240,7 +240,7 @@ public:
 	bool visibleObjectsInFrustum(LLCamera& camera);
 	bool getVisibleExtents(LLCamera& camera, LLVector3 &min, LLVector3& max);
 	bool getVisiblePointCloud(LLCamera& camera, LLVector3 &min, LLVector3& max, std::vector<LLVector3>& fp, LLVector3 light_dir = LLVector3(0,0,0));
-	void updateCull(LLCamera& camera, LLCullResult& result, S32 water_clip = 0, LLPlane* plane = NULL);  //if water_clip is 0, ignore water plane, 1, cull to above plane, -1, cull to below plane
+	void updateCull(LLCamera& camera, LLCullResult& result, LLPlane* plane = NULL);  //if water_clip is 0, ignore water plane, 1, cull to above plane, -1, cull to below plane
 	void createObjects(F32 max_dtime);
 	void createObject(LLViewerObject* vobj);
 	void processPartitionQ();
-- 
cgit v1.2.3


From 25e993cd3a961a08d625ac18c31e92a0342a1fe1 Mon Sep 17 00:00:00 2001
From: Runitai Linden <davep@lindenlab.com>
Date: Wed, 8 Dec 2021 08:40:26 -0600
Subject: SL-16469 Fix for reflection/refraction passes breaking occlusion
 queries.

---
 indra/newview/pipeline.cpp | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

(limited to 'indra')

diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index dce63e06fb..56fe4ac5af 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -9122,6 +9122,10 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in)
 
     if (LLPipeline::sWaterReflections && LLDrawPoolWater::sNeedsReflectionUpdate)
     {
+        //disable occlusion culling for reflection/refraction passes (save setting to restore later)
+        S32 occlude = LLPipeline::sUseOcclusion;
+        LLPipeline::sUseOcclusion = 0;
+
         bool skip_avatar_update = false;
         if (!isAgentAvatarValid() || gAgentCamera.getCameraAnimating() || gAgentCamera.getCameraMode() != CAMERA_MODE_MOUSELOOK || !LLVOAvatar::sVisibleInFirstPerson)
         {
@@ -9408,6 +9412,9 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in)
         }
 
         LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD;
+
+        // restore occlusion culling
+        LLPipeline::sUseOcclusion = occlude;
     }
     else
     {
@@ -9515,7 +9522,7 @@ void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera
 {
     LL_RECORD_BLOCK_TIME(FTM_SHADOW_RENDER);
 
-    //clip out geometry on the same side of water as the camera
+    //disable occlusion culling for shadow passes (save setting to restore later)
     S32 occlude = LLPipeline::sUseOcclusion;
     if (!use_occlusion)
     {
-- 
cgit v1.2.3


From 1a6ef9a1fbecadaff00b733c51fd6b980905f102 Mon Sep 17 00:00:00 2001
From: Runitai Linden <davep@lindenlab.com>
Date: Wed, 8 Dec 2021 15:35:25 -0600
Subject: SL-16468 Fix for crash when enabling highlight transparent (add
 rigged mesh support to highlight transparent).

---
 .../shaders/class1/interface/highlightV.glsl       | 13 ++++++
 indra/newview/lldrawpoolalpha.cpp                  | 47 ++++++++++++++++------
 indra/newview/llviewershadermgr.cpp                | 11 ++---
 3 files changed, 51 insertions(+), 20 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/app_settings/shaders/class1/interface/highlightV.glsl b/indra/newview/app_settings/shaders/class1/interface/highlightV.glsl
index 9bf7b60eb7..0b362cf46c 100644
--- a/indra/newview/app_settings/shaders/class1/interface/highlightV.glsl
+++ b/indra/newview/app_settings/shaders/class1/interface/highlightV.glsl
@@ -31,10 +31,23 @@ ATTRIBUTE vec2 texcoord0;
 
 VARYING vec2 vary_texcoord0;
 
+#ifdef HAS_SKIN
+mat4 getObjectSkinnedTransform();
+uniform mat4 projection_matrix;
+uniform mat4 modelview_matrix;
+#endif
+
 void main()
 {
 	//transform vertex
+#ifdef HAS_SKIN
+    mat4 mat = getObjectSkinnedTransform();
+    mat = modelview_matrix * mat;
+    vec4 pos = mat * vec4(position.xyz,1.0);
+    gl_Position = projection_matrix * pos;
+#else
 	gl_Position = modelview_projection_matrix * vec4(position.xyz, 1.0);
+#endif
 	vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy;
 }
 
diff --git a/indra/newview/lldrawpoolalpha.cpp b/indra/newview/lldrawpoolalpha.cpp
index cecdefd7e8..5eb5c6caad 100644
--- a/indra/newview/lldrawpoolalpha.cpp
+++ b/indra/newview/lldrawpoolalpha.cpp
@@ -160,8 +160,6 @@ void LLDrawPoolAlpha::renderPostDeferred(S32 pass)
         gGL.setColorMask(true, false);
     }
 
-    renderDebugAlpha();
-
     deferred_render = FALSE;
 }
 
@@ -201,8 +199,6 @@ void LLDrawPoolAlpha::render(S32 pass)
     prepare_forward_shader(simple_shader, minimum_alpha);
 
     forwardRender();
-
-    renderDebugAlpha();
 }
 
 void LLDrawPoolAlpha::forwardRender()
@@ -232,20 +228,21 @@ void LLDrawPoolAlpha::forwardRender()
     renderAlpha(getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX | LLVertexBuffer::MAP_TANGENT | LLVertexBuffer::MAP_TEXCOORD1 | LLVertexBuffer::MAP_TEXCOORD2);
 
     gGL.setColorMask(true, false);
+
+    renderDebugAlpha();
 }
 
 void LLDrawPoolAlpha::renderDebugAlpha()
 {
 	if (sShowDebugAlpha)
 	{
-		gHighlightProgram.bind();
-		
-		gGL.diffuseColor4f(1,0,0,1);
-				
-		LLViewerFetchedTexture::sSmokeImagep->addTextureStats(1024.f*1024.f);
-		gGL.getTexUnit(0)->bindFast(LLViewerFetchedTexture::sSmokeImagep);
-		renderAlphaHighlight(LLVertexBuffer::MAP_VERTEX |
-							LLVertexBuffer::MAP_TEXCOORD0);
+        gHighlightProgram.bind();
+        gGL.diffuseColor4f(1, 0, 0, 1);
+        LLViewerFetchedTexture::sSmokeImagep->addTextureStats(1024.f * 1024.f);
+        gGL.getTexUnit(0)->bindFast(LLViewerFetchedTexture::sSmokeImagep);
+
+        renderAlphaHighlight(LLVertexBuffer::MAP_VERTEX |
+            LLVertexBuffer::MAP_TEXCOORD0);
 
 		pushBatches(LLRenderPass::PASS_ALPHA_MASK, LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0, FALSE);
 		pushBatches(LLRenderPass::PASS_ALPHA_INVISIBLE, LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0, FALSE);
@@ -283,6 +280,9 @@ void LLDrawPoolAlpha::renderDebugAlpha()
 
 void LLDrawPoolAlpha::renderAlphaHighlight(U32 mask)
 {
+    LLVOAvatar* lastAvatar = nullptr;
+    U64 lastMeshId = 0;
+
 	for (LLCullResult::sg_iterator i = gPipeline.beginAlphaGroups(); i != gPipeline.endAlphaGroups(); ++i)
 	{
 		LLSpatialGroup* group = *i;
@@ -300,16 +300,37 @@ void LLDrawPoolAlpha::renderAlphaHighlight(U32 mask)
 					continue;
 				}
 
+                bool rigged = (params.mAvatar != nullptr);
+                gHighlightProgram.bind(rigged);
+                gGL.diffuseColor4f(1, 0, 0, 1);
+
+                if (rigged)
+                {
+                    if (lastAvatar != params.mAvatar ||
+                        lastMeshId != params.mSkinInfo->mHash)
+                    {
+                        if (!uploadMatrixPalette(params))
+                        {
+                            continue;
+                        }
+                        lastAvatar = params.mAvatar;
+                        lastMeshId = params.mSkinInfo->mHash;
+                    }
+                }
+
 				LLRenderPass::applyModelMatrix(params);
 				if (params.mGroup)
 				{
 					params.mGroup->rebuildMesh();
 				}
-				params.mVertexBuffer->setBufferFast(mask);
+				params.mVertexBuffer->setBufferFast(rigged ?  mask | LLVertexBuffer::MAP_WEIGHT4 : mask);
 				params.mVertexBuffer->drawRangeFast(params.mDrawMode, params.mStart, params.mEnd, params.mCount, params.mOffset);
 			}
 		}
 	}
+
+    // make sure static version of highlight shader is bound before returning
+    gHighlightProgram.bind();
 }
 
 inline bool IsFullbright(LLDrawInfo& params)
diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp
index 8669abf284..d37e86fa5e 100644
--- a/indra/newview/llviewershadermgr.cpp
+++ b/indra/newview/llviewershadermgr.cpp
@@ -151,6 +151,7 @@ LLGLSLShader		gUnderWaterProgram;
 
 //interface shaders
 LLGLSLShader		gHighlightProgram;
+LLGLSLShader        gSkinnedHighlightProgram;
 LLGLSLShader		gHighlightNormalProgram;
 LLGLSLShader		gHighlightSpecularProgram;
 
@@ -807,6 +808,7 @@ void LLViewerShaderMgr::unloadShaders()
 	gAvatarEyeballProgram.unload();
 	gAvatarPickProgram.unload();
 	gHighlightProgram.unload();
+    gSkinnedHighlightProgram.unload();
 	gHighlightNormalProgram.unload();
 	gHighlightSpecularProgram.unload();
 
@@ -3419,12 +3421,6 @@ BOOL LLViewerShaderMgr::loadShadersInterface()
 {
 	BOOL success = TRUE;
 
-	if (mShaderLevel[SHADER_INTERFACE] == 0)
-	{
-		gHighlightProgram.unload();
-		return TRUE;
-	}
-	
 	if (success)
 	{
 		gHighlightProgram.mName = "Highlight Shader";
@@ -3432,7 +3428,8 @@ BOOL LLViewerShaderMgr::loadShadersInterface()
 		gHighlightProgram.mShaderFiles.push_back(make_pair("interface/highlightV.glsl", GL_VERTEX_SHADER_ARB));
 		gHighlightProgram.mShaderFiles.push_back(make_pair("interface/highlightF.glsl", GL_FRAGMENT_SHADER_ARB));
 		gHighlightProgram.mShaderLevel = mShaderLevel[SHADER_INTERFACE];
-		success = gHighlightProgram.createShader(NULL, NULL);
+        success = make_rigged_variant(gHighlightProgram, gSkinnedHighlightProgram);
+		success = success && gHighlightProgram.createShader(NULL, NULL);
 	}
 
 	if (success)
-- 
cgit v1.2.3


From 9e38e5a187574279b46dc76d9d0fb2c7b2f816f6 Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Wed, 8 Dec 2021 22:58:27 +0200
Subject: SL-16471 Removed unneeded MeshOpt generation method

---
 indra/newview/llfloatermodelpreview.cpp                  |  2 --
 indra/newview/llmodelpreview.cpp                         |  9 ---------
 indra/newview/llmodelpreview.h                           |  5 ++---
 .../skins/default/xui/en/floater_model_preview.xml       | 16 ----------------
 4 files changed, 2 insertions(+), 30 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp
index aec4e4b8d9..ad9b4c84b4 100644
--- a/indra/newview/llfloatermodelpreview.cpp
+++ b/indra/newview/llfloatermodelpreview.cpp
@@ -727,7 +727,6 @@ void LLFloaterModelPreview::onLODParamCommit(S32 lod, bool enforce_tri_limit)
     switch (mode)
     {
     case LLModelPreview::MESH_OPTIMIZER_AUTO:
-    case LLModelPreview::MESH_OPTIMIZER:
     case LLModelPreview::MESH_OPTIMIZER_SLOPPY:
     case LLModelPreview::MESH_OPTIMIZER_COMBINE:
         mModelPreview->onLODMeshOptimizerParamCommit(lod, enforce_tri_limit, mode);
@@ -1736,7 +1735,6 @@ void LLFloaterModelPreview::onLoDSourceCommit(S32 lod)
 	LLComboBox* lod_source_combo = getChild<LLComboBox>("lod_source_" + lod_name[lod]);
     S32 index = lod_source_combo->getCurrentIndex();
 	if (index == LLModelPreview::MESH_OPTIMIZER_AUTO
-        || index == LLModelPreview::MESH_OPTIMIZER
         || index == LLModelPreview::MESH_OPTIMIZER_SLOPPY
         || index == LLModelPreview::MESH_OPTIMIZER_COMBINE)
 	{ //rebuild LoD to update triangle counts
diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp
index 907b5ec418..0d297a8559 100644
--- a/indra/newview/llmodelpreview.cpp
+++ b/indra/newview/llmodelpreview.cpp
@@ -1748,15 +1748,6 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d
                     }
                 }
             }
-            
-            if (model_meshopt_mode == MESH_OPTIMIZER)
-            {
-                // Run meshoptimizer for each face
-                for (U32 face_idx = 0; face_idx < base->getNumVolumeFaces(); ++face_idx)
-                {
-                    genMeshOptimizerPerFace(base, target_model, face_idx, indices_decimator, lod_error_threshold, false);
-                }
-            }
 
             if (model_meshopt_mode == MESH_OPTIMIZER_SLOPPY)
             {
diff --git a/indra/newview/llmodelpreview.h b/indra/newview/llmodelpreview.h
index 7d4507ccf2..9361acfc49 100644
--- a/indra/newview/llmodelpreview.h
+++ b/indra/newview/llmodelpreview.h
@@ -125,9 +125,8 @@ public:
     {
         LOD_FROM_FILE = 0,
         MESH_OPTIMIZER_AUTO, // automatically selects method based on model or face
-        MESH_OPTIMIZER_COMBINE,
-        MESH_OPTIMIZER,
-        MESH_OPTIMIZER_SLOPPY,
+        MESH_OPTIMIZER_COMBINE, // combines faces into a single model, simplifies, then splits back into faces
+        MESH_OPTIMIZER_SLOPPY, // uses sloppy method, works per face
         USE_LOD_ABOVE,
     } eLoDMode;
 
diff --git a/indra/newview/skins/default/xui/en/floater_model_preview.xml b/indra/newview/skins/default/xui/en/floater_model_preview.xml
index d08bc92e5d..f10cc61826 100644
--- a/indra/newview/skins/default/xui/en/floater_model_preview.xml
+++ b/indra/newview/skins/default/xui/en/floater_model_preview.xml
@@ -194,10 +194,6 @@
                  name="MeshOptCombine"
                  label="Generate Precise"
                  value="MeshOptCombine" />
-                <item
-                 name="MeshOpt"
-                 label="Generate per face"
-                 value="MeshOpt" />
                 <item
                  name="MeshOptSloppy"
                  label="Generate Sloppy"
@@ -335,10 +331,6 @@
                  name="MeshOptCombine"
                  label="Generate Precise"
                  value="MeshOptCombine" />
-                <item
-                 name="MeshOpt"
-                 label="Generate per face"
-                 value="MeshOpt" />
                 <item
                  name="MeshOptSloppy"
                  label="Generate Sloppy"
@@ -480,10 +472,6 @@
                  name="MeshOptCombine"
                  label="Generate Precise"
                  value="MeshOptCombine" />
-                <item
-                 name="MeshOpt"
-                 label="Generate per face"
-                 value="MeshOpt" />
                 <item
                  name="MeshOptSloppy"
                  label="Generate Sloppy"
@@ -625,10 +613,6 @@
                  name="MeshOptCombine"
                  label="Generate Precise"
                  value="MeshOptCombine" />
-                <item
-                 name="MeshOpt"
-                 label="Generate per face"
-                 value="MeshOpt" />
                 <item
                  name="MeshOptSloppy"
                  label="Generate Sloppy"
-- 
cgit v1.2.3


From d718f25f7d40f571dd372da05fb228561cae2e13 Mon Sep 17 00:00:00 2001
From: Dave Houlton <euclid@lindenlab.com>
Date: Wed, 8 Dec 2021 13:38:09 -0700
Subject: SL-16461 disable occlusion-based reflection update

---
 indra/newview/lldrawpoolwater.cpp | 5 ++---
 indra/newview/llvieweroctree.cpp  | 6 +++++-
 2 files changed, 7 insertions(+), 4 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/lldrawpoolwater.cpp b/indra/newview/lldrawpoolwater.cpp
index 590385472b..62706feae3 100644
--- a/indra/newview/lldrawpoolwater.cpp
+++ b/indra/newview/lldrawpoolwater.cpp
@@ -679,9 +679,8 @@ void LLDrawPoolWater::renderWater()
             {
                 face->renderIndexed();
 
-                // If not occlusion culling, record non-void water being drawn
-                // (If occlusion is enabled, these are set within LLOcclusionCullingGroup::checkOcclusion() )
-                if (!edge && !LLPipeline::sUseOcclusion)
+                // Note non-void water being drawn, updates required
+                if (!edge)  // SL-16461 remove !LLPipeline::sUseOcclusion check
                 {
                     sNeedsReflectionUpdate = TRUE;
                     sNeedsDistortionUpdate = TRUE;
diff --git a/indra/newview/llvieweroctree.cpp b/indra/newview/llvieweroctree.cpp
index b7d0e06116..8d6f4d2729 100644
--- a/indra/newview/llvieweroctree.cpp
+++ b/indra/newview/llvieweroctree.cpp
@@ -1140,6 +1140,10 @@ void LLOcclusionCullingGroup::checkOcclusion()
 #if LL_TRACK_PENDING_OCCLUSION_QUERIES
                 sPendingQueries.erase(mOcclusionQuery[LLViewerCamera::sCurCameraID]);
 #endif
+
+#if 0   // (12/2021) occasional false-negative occlusion tests produce water reflection errors, SL-16461
+        // If/when water occlusion queries become 100% reliable, re-enable this optimization
+
                 if (LLPipeline::RENDER_TYPE_WATER == mSpatialPartition->mDrawableType)
                 {
                     // Note any unoccluded water, for deciding on reflection/distortion passes
@@ -1150,7 +1154,7 @@ void LLOcclusionCullingGroup::checkOcclusion()
                         LLDrawPoolWater::sNeedsDistortionUpdate = TRUE;
                     }
                 }
- 
+#endif
                 if (query_result > 0)
                 {
                     clearOcclusionState(LLOcclusionCullingGroup::OCCLUDED, LLOcclusionCullingGroup::STATE_MODE_DIFF);
-- 
cgit v1.2.3


From 0a9ade4687dd53e9973ebfdf1ef948f04f5ac8c1 Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Thu, 9 Dec 2021 19:52:05 +0200
Subject: SL-16479 'sloppy' precision in automated mode.

---
 indra/newview/llmodelpreview.cpp | 45 ++++++++++++++++++++++++++++++++--------
 indra/newview/llmodelpreview.h   |  6 +++++-
 2 files changed, 41 insertions(+), 10 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp
index 0d297a8559..1da9e6c651 100644
--- a/indra/newview/llmodelpreview.cpp
+++ b/indra/newview/llmodelpreview.cpp
@@ -1380,6 +1380,7 @@ F32 LLModelPreview::genMeshOptimizerPerModel(LLModel *base_model, LLModel *targe
     S32 buf_positions_copied = 0;
     S32 buf_indices_copied = 0;
     indices_idx_shift = 0;
+    S32 valid_faces = 0;
 
     // Crude method to copy indices back into face
     for (U32 face_idx = 0; face_idx < base_model->getNumVolumeFaces(); ++face_idx)
@@ -1478,6 +1479,8 @@ F32 LLModelPreview::genMeshOptimizerPerModel(LLModel *base_model, LLModel *targe
 
             U32 tex_size = (buf_positions_copied * sizeof(LLVector2) + 0xF)&~0xF;
             LLVector4a::memcpyNonAliased16((F32*)new_face.mTexCoords, (F32*)buffer_tex_coords, tex_size);
+
+            valid_faces++;
         }
 
         indices_idx_shift += face.mNumVertices;
@@ -1490,7 +1493,7 @@ F32 LLModelPreview::genMeshOptimizerPerModel(LLModel *base_model, LLModel *targe
     ll_aligned_free_16(buffer_indices);
     ll_aligned_free_32(combined_indices);
 
-    if (new_indices < 3)
+    if (new_indices < 3 || valid_faces == 0)
     {
         // Model should have at least one visible triangle
 
@@ -1734,7 +1737,7 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d
             // but combine all submodels with origin model as well
             if (model_meshopt_mode == MESH_OPTIMIZER_COMBINE)
             {
-                // Run meshoptimizer for each model/object, up to 8 faces in one model
+                // Run meshoptimizer for each model/object, up to 8 faces in one model.
 
                 // Ideally this should run not per model,
                 // but combine all submodels with origin model as well
@@ -1756,10 +1759,15 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d
                 {
                     genMeshOptimizerPerFace(base, target_model, face_idx, indices_decimator, lod_error_threshold, true);
                 }
+
+                LL_INFOS() << "Model " << target_model->getName()
+                    << " lod " << which_lod
+                    << " simplified using per face method." << LL_ENDL;
             }
 
             if (model_meshopt_mode == MESH_OPTIMIZER_AUTO)
             {
+                // Switches between 'combine' method and 'per model sloppy' based on combine's result.
                 F32 allowed_ratio_drift = 2.f;
                 F32 res_ratio = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, false);
 
@@ -1770,25 +1778,44 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d
                     {
                         genMeshOptimizerPerFace(base, target_model, face_idx, indices_decimator, lod_error_threshold, false);
                     }
-                    LL_INFOS() << "Model " << target_model->getName()
-                        << " lod " << which_lod
-                        << " per model method overflow, defaulting to per face." << LL_ENDL;
                 }
                 else if (res_ratio * allowed_ratio_drift < indices_decimator)
                 {
                     // Try sloppy variant if normal one failed to simplify model enough.
                     res_ratio = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, true);
-                    LL_INFOS() << "Model " << target_model->getName()
-                        << " lod " << which_lod
-                        << " sloppily simplified using per model method." << LL_ENDL;
+
+                    // Sloppy has a tendecy to error into lower side, so a request for 100
+                    // triangles turns into ~70, so check for significant difference from target decimation
+                    F32 sloppy_ratio_drift = 1.4f;
+                    if (lod_mode == LIMIT_TRIANGLES
+                        && (res_ratio > indices_decimator * sloppy_ratio_drift || res_ratio < 0))
+                    {
+                        // Apply a correction to compensate.
+
+                        // (indices_decimator / res_ratio) by itself is likely to overshoot to a differend
+                        // side due to overal lack of precision, and we don't need an ideal result, which
+                        // likely does not exist, just a better one, so a partial correction is enough.
+                        F32 sloppy_decimator = indices_decimator * (indices_decimator / res_ratio + 1) / 2;
+                        res_ratio = genMeshOptimizerPerModel(base, target_model, sloppy_decimator, lod_error_threshold, true);
+                    }
 
 
                     if (res_ratio < 0)
                     {
                         // Sloppy variant failed to generate triangles.
                         // Can happen with models that are too simple as is.
-                        // Fallback to normal method.
+                        // Fallback to normal method or use lower decimator.
                         genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, false);
+
+                        LL_INFOS() << "Model " << target_model->getName()
+                            << " lod " << which_lod
+                            << " simplified using per model method." << LL_ENDL;
+                    }
+                    else
+                    {
+                        LL_INFOS() << "Model " << target_model->getName()
+                            << " lod " << which_lod
+                            << " sloppily simplified using per model method." << LL_ENDL;
                     }
                 }
                 else
diff --git a/indra/newview/llmodelpreview.h b/indra/newview/llmodelpreview.h
index 9361acfc49..48d6d362eb 100644
--- a/indra/newview/llmodelpreview.h
+++ b/indra/newview/llmodelpreview.h
@@ -225,8 +225,12 @@ private:
     // Count amount of original models, excluding sub-models
     static U32 countRootModels(LLModelLoader::model_list models);
 
-    // functions for meshoptimizer, return reached simplification ratio
+    // Merges faces into single mesh, simplifies using mesh optimizer,
+    // then splits back into faces.
+    // Returns reached simplification ratio. -1 in case of a failure.
     F32 genMeshOptimizerPerModel(LLModel *base_model, LLModel *target_model, F32 indices_ratio, F32 error_threshold, bool sloppy);
+    // Simplifies specified face using mesh optimizer.
+    // Returns reached simplification ratio. -1 in case of a failure.
     F32 genMeshOptimizerPerFace(LLModel *base_model, LLModel *target_model, U32 face_idx, F32 indices_ratio, F32 error_threshold, bool sloppy);
 
 protected:
-- 
cgit v1.2.3


From 9689e606f4da78dd5654124b3e90913b4e934b1a Mon Sep 17 00:00:00 2001
From: Runitai Linden <davep@lindenlab.com>
Date: Thu, 9 Dec 2021 14:01:41 -0600
Subject: SL-16480 Fix for window not saving its position on exit.

---
 indra/llwindow/llwindowwin32.cpp | 154 +++++++++++++++++++--------------------
 indra/llwindow/llwindowwin32.h   |   5 ++
 2 files changed, 82 insertions(+), 77 deletions(-)

(limited to 'indra')

diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp
index b8bfa92279..4deebea7e8 100644
--- a/indra/llwindow/llwindowwin32.cpp
+++ b/indra/llwindow/llwindowwin32.cpp
@@ -955,49 +955,22 @@ BOOL LLWindowWin32::getFullscreen()
 
 BOOL LLWindowWin32::getPosition(LLCoordScreen *position)
 {
-	RECT window_rect;
-
-	if (!mWindowHandle ||
-		!GetWindowRect(mWindowHandle, &window_rect) ||
-		NULL == position)
-	{
-		return FALSE;
-	}
-
-	position->mX = window_rect.left;
-	position->mY = window_rect.top;
+    position->mX = mRect.left;
+	position->mY = mRect.top;
 	return TRUE;
 }
 
 BOOL LLWindowWin32::getSize(LLCoordScreen *size)
 {
-	RECT window_rect;
-
-	if (!mWindowHandle ||
-		!GetWindowRect(mWindowHandle, &window_rect) ||
-		NULL == size)
-	{
-		return FALSE;
-	}
-
-	size->mX = window_rect.right - window_rect.left;
-	size->mY = window_rect.bottom - window_rect.top;
+	size->mX = mRect.right - mRect.left;
+	size->mY = mRect.bottom - mRect.top;
 	return TRUE;
 }
 
 BOOL LLWindowWin32::getSize(LLCoordWindow *size)
 {
-	RECT client_rect;
-
-	if (!mWindowHandle ||
-		!GetClientRect(mWindowHandle, &client_rect) ||
-		NULL == size)
-	{
-		return FALSE;
-	}
-
-	size->mX = client_rect.right - client_rect.left;
-	size->mY = client_rect.bottom - client_rect.top;
+	size->mX = mClientRect.right - mClientRect.left;
+	size->mY = mClientRect.bottom - mClientRect.top;
 	return TRUE;
 }
 
@@ -1024,14 +997,17 @@ BOOL LLWindowWin32::setSizeImpl(const LLCoordScreen size)
 		return FALSE;
 	}
 
-	WINDOWPLACEMENT placement;
-	placement.length = sizeof(WINDOWPLACEMENT);
-
-	if (!GetWindowPlacement(mWindowHandle, &placement)) return FALSE;
-
-	placement.showCmd = SW_RESTORE;
+    mWindowThread->post([=]()
+        {
+            WINDOWPLACEMENT placement;
+            placement.length = sizeof(WINDOWPLACEMENT);
 
-	if (!SetWindowPlacement(mWindowHandle, &placement)) return FALSE;
+            if (GetWindowPlacement(mWindowHandle, &placement))
+            {
+                placement.showCmd = SW_RESTORE;
+                SetWindowPlacement(mWindowHandle, &placement);
+            }
+        });
 
 	moveWindow(position, size);
 	return TRUE;
@@ -1043,7 +1019,7 @@ BOOL LLWindowWin32::setSizeImpl(const LLCoordWindow size)
 	DWORD dw_ex_style = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
 	DWORD dw_style = WS_OVERLAPPEDWINDOW;
 
-	AdjustWindowRectEx(&window_rect, dw_style, FALSE, dw_ex_style);
+    AdjustWindowRectEx(&window_rect, dw_style, FALSE, dw_ex_style);
 
 	return setSizeImpl(LLCoordScreen(window_rect.right - window_rect.left, window_rect.bottom - window_rect.top));
 }
@@ -1852,14 +1828,20 @@ void LLWindowWin32::moveWindow( const LLCoordScreen& position, const LLCoordScre
 	// THIS CAUSES DEV-15484 and DEV-15949 
 	//ShowWindow(mWindowHandle, SW_RESTORE);
 	// NOW we can call MoveWindow
-	MoveWindow(mWindowHandle, position.mX, position.mY, size.mX, size.mY, TRUE);
+    mWindowThread->post([=]()
+        {
+            MoveWindow(mWindowHandle, position.mX, position.mY, size.mX, size.mY, TRUE);
+        });
 }
 
 void LLWindowWin32::setTitle(const std::string title)
 {
     // TODO: Do we need to use the wide string version of this call
     // to support non-ascii usernames (and region names?)
-    SetWindowTextA(mWindowHandle, title.c_str());
+    mWindowThread->post([=]()
+        {
+            SetWindowTextA(mWindowHandle, title.c_str());
+        });
 }
 
 BOOL LLWindowWin32::setCursorPosition(const LLCoordWindow position)
@@ -2889,12 +2871,19 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
             return 0;
         }
 
+        case WM_MOVE:
+        {
+            window_imp->updateWindowRect();
+            return 0;
+        }
         case WM_SIZE:
         {
             LL_PROFILE_ZONE_NAMED("mwp - WM_SIZE");
+            window_imp->updateWindowRect();
             S32 width = S32(LOWORD(l_param));
             S32 height = S32(HIWORD(l_param));
 
+            
             if (debug_window_proc)
             {
                 BOOL maximized = (w_param == SIZE_MAXIMIZED);
@@ -3047,12 +3036,12 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
                 }
             }
         }
+
         //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;
@@ -3291,43 +3280,30 @@ void LLWindowWin32::setMouseClipping( BOOL b )
 
 BOOL LLWindowWin32::getClientRectInScreenSpace( RECT* rectp )
 {
-	BOOL success = FALSE;
+    S32 offsetx = mRect.left - mClientRect.left;
+    S32 offsety = mRect.top - mClientRect.top;
 
-	RECT client_rect;
-	if( mWindowHandle && GetClientRect(mWindowHandle, &client_rect) )
-	{
-		POINT top_left;
-		top_left.x = client_rect.left;
-		top_left.y = client_rect.top;
-		ClientToScreen(mWindowHandle, &top_left); 
-
-		POINT bottom_right;
-		bottom_right.x = client_rect.right;
-		bottom_right.y = client_rect.bottom;
-		ClientToScreen(mWindowHandle, &bottom_right); 
-
-		SetRect( rectp,
-			top_left.x,
-			top_left.y,
-			bottom_right.x,
-			bottom_right.y );
-
-		success = TRUE;
-	}
+    rectp->left += offsetx;
+    rectp->right += offsetx;
+    rectp->bottom += offsety;
+    rectp->bottom += offsety;
 
-	return success;
+    return TRUE;
 }
 
 void LLWindowWin32::flashIcon(F32 seconds)
 {
-	FLASHWINFO flash_info;
-
-	flash_info.cbSize = sizeof(FLASHWINFO);
-	flash_info.hwnd = mWindowHandle;
-	flash_info.dwFlags = FLASHW_TRAY;
-	flash_info.uCount = UINT(seconds / ICON_FLASH_TIME);
-	flash_info.dwTimeout = DWORD(1000.f * ICON_FLASH_TIME); // milliseconds
-	FlashWindowEx(&flash_info);
+    mWindowThread->post([=]()
+        {
+            FLASHWINFO flash_info;
+
+            flash_info.cbSize = sizeof(FLASHWINFO);
+            flash_info.hwnd = mWindowHandle;
+            flash_info.dwFlags = FLASHW_TRAY;
+            flash_info.uCount = UINT(seconds / ICON_FLASH_TIME);
+            flash_info.dwTimeout = DWORD(1000.f * ICON_FLASH_TIME); // milliseconds
+            FlashWindowEx(&flash_info);
+        });
 }
 
 F32 LLWindowWin32::getGamma()
@@ -3783,13 +3759,19 @@ void *LLWindowWin32::getPlatformWindow()
 
 void LLWindowWin32::bringToFront()
 {
-	BringWindowToTop(mWindowHandle);
+    mWindowThread->post([=]()
+        {
+            BringWindowToTop(mWindowHandle);
+        });
 }
 
 // set (OS) window focus back to the client
 void LLWindowWin32::focusClient()
 {
-	SetFocus ( mWindowHandle );
+    mWindowThread->post([=]()
+        {
+            SetFocus(mWindowHandle);
+        });
 }
 
 void LLWindowWin32::allowLanguageTextInput(LLPreeditor *preeditor, BOOL b)
@@ -4623,3 +4605,21 @@ void LLWindowWin32::kickWindowThread(HWND windowHandle)
         PostMessage(windowHandle, WM_DUMMY_, wparam, 0x1337);
     }
 }
+
+void LLWindowWin32::updateWindowRect()
+{
+    LL_PROFILE_ZONE_SCOPED;
+    //called from window thread
+    RECT rect;
+    RECT client_rect;
+    
+    if (GetWindowRect(mWindowHandle, &rect) &&
+        GetClientRect(mWindowHandle, &client_rect))
+    {
+        post([=] 
+            {
+                mRect = rect;
+                mClientRect = client_rect;
+            });
+    }
+}
diff --git a/indra/llwindow/llwindowwin32.h b/indra/llwindow/llwindowwin32.h
index b02815e990..9367f49510 100644
--- a/indra/llwindow/llwindowwin32.h
+++ b/indra/llwindow/llwindowwin32.h
@@ -237,6 +237,11 @@ protected:
 
 	BOOL			mMouseVanish;
 
+    // Cached values of GetWindowRect and GetClientRect to be used by app thread
+    void updateWindowRect();
+    RECT mRect; 
+    RECT mClientRect;
+
 	struct LLWindowWin32Thread;
 	LLWindowWin32Thread* mWindowThread = nullptr;
 	LLThreadSafeQueue<std::function<void()>> mFunctionQueue;
-- 
cgit v1.2.3


From 7683477547131c8cb371e1357b3d25ca07b2feb4 Mon Sep 17 00:00:00 2001
From: Runitai Linden <davep@lindenlab.com>
Date: Thu, 9 Dec 2021 16:44:44 -0600
Subject: SL-16480 Followup -- fix for unintialized mRect/mClientRect and bad
 getClientRectInScreenSpace

---
 indra/llwindow/llwindowwin32.cpp | 37 ++++++++++++++++++++++++++++---------
 1 file changed, 28 insertions(+), 9 deletions(-)

(limited to 'indra')

diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp
index 4deebea7e8..86eca6872e 100644
--- a/indra/llwindow/llwindowwin32.cpp
+++ b/indra/llwindow/llwindowwin32.cpp
@@ -1654,7 +1654,8 @@ void LLWindowWin32::recreateWindow(RECT window_rect, DWORD dw_ex_style, DWORD dw
     std::promise<std::pair<HWND, HDC>> promise;
     // What follows must be done on the window thread.
     auto window_work =
-        [self=mWindowThread,
+        [this,
+         self=mWindowThread,
          oldHandle,
          // bind CreateWindowEx() parameters by value instead of
          // back-referencing LLWindowWin32 members
@@ -1704,7 +1705,9 @@ void LLWindowWin32::recreateWindow(RECT window_rect, DWORD dw_ex_style, DWORD dw
                 self->mWindowHandle = handle;
                 self->mhDC = GetDC(handle);
             }
-                
+            
+            updateWindowRect();
+
             // It's important to wake up the future either way.
             promise.set_value(std::make_pair(self->mWindowHandle, self->mhDC));
             LL_DEBUGS("Window") << "recreateWindow(): window_work done" << LL_ENDL;
@@ -3280,15 +3283,31 @@ void LLWindowWin32::setMouseClipping( BOOL b )
 
 BOOL LLWindowWin32::getClientRectInScreenSpace( RECT* rectp )
 {
-    S32 offsetx = mRect.left - mClientRect.left;
-    S32 offsety = mRect.top - mClientRect.top;
+    BOOL success = FALSE;
 
-    rectp->left += offsetx;
-    rectp->right += offsetx;
-    rectp->bottom += offsety;
-    rectp->bottom += offsety;
+    RECT client_rect;
+    if (mWindowHandle && GetClientRect(mWindowHandle, &client_rect))
+    {
+        POINT top_left;
+        top_left.x = client_rect.left;
+        top_left.y = client_rect.top;
+        ClientToScreen(mWindowHandle, &top_left);
+
+        POINT bottom_right;
+        bottom_right.x = client_rect.right;
+        bottom_right.y = client_rect.bottom;
+        ClientToScreen(mWindowHandle, &bottom_right);
+
+        SetRect(rectp,
+            top_left.x,
+            top_left.y,
+            bottom_right.x,
+            bottom_right.y);
+
+        success = TRUE;
+    }
 
-    return TRUE;
+    return success;
 }
 
 void LLWindowWin32::flashIcon(F32 seconds)
-- 
cgit v1.2.3


From c21dad82072c417d9a8b1af8c83a5af02a0a4845 Mon Sep 17 00:00:00 2001
From: Mnikolenko Productengine <mnikolenko@productengine.com>
Date: Mon, 13 Dec 2021 12:14:14 +0200
Subject: SL-16467 FIXED "Keyboard layout" is not switched

---
 indra/llwindow/llwindowwin32.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'indra')

diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp
index 86eca6872e..0064ee26d2 100644
--- a/indra/llwindow/llwindowwin32.cpp
+++ b/indra/llwindow/llwindowwin32.cpp
@@ -4568,7 +4568,7 @@ void LLWindowWin32::LLWindowWin32Thread::run()
             {
                 LL_PROFILE_ZONE_NAMED("w32t - GetMessage");
                 logger.always("GetMessage(", std::hex, mWindowHandle, ")");
-                status = GetMessage(&msg, mWindowHandle, 0, 0);
+                status = GetMessage(&msg, NULL, 0, 0);
             }
             if (status > 0)
             {
-- 
cgit v1.2.3


From e3d86e4599ee5944eaa2cfe0147d1a117495b2de Mon Sep 17 00:00:00 2001
From: Runitai Linden <davep@lindenlab.com>
Date: Mon, 13 Dec 2021 13:14:41 -0600
Subject: SL-16487 Fix for broken bounding boxes on rigged meshes (still
 broken, but not more broken than release).

---
 indra/newview/llvovolume.cpp | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index c1f83ed0ae..c312ebb307 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -1754,10 +1754,9 @@ BOOL LLVOVolume::genBBoxes(BOOL force_global)
 
     if (rigged)
     {
-        min.set(-1, -1, -1, 0);
-        max.set(1, 1, 1, 0);
-
         mDrawable->setSpatialExtents(min, max);
+        // always use the same octree node position for any given rigged mesh so it doesn't switch nodes
+        // while animating (and thus rebuild its vertex buffer)
         mDrawable->setPositionGroup(LLVector4a(0, 0, 0));
         updateRadius();
         mDrawable->movePartition();
@@ -4363,6 +4362,7 @@ void LLVOVolume::updateSpatialExtents(LLVector4a& newMin, LLVector4a& newMax)
 
 F32 LLVOVolume::getBinRadius()
 {
+    LL_PROFILE_ZONE_SCOPED;
 	F32 radius;
 	
 	F32 scale = 1.f;
-- 
cgit v1.2.3


From 2d0d7c71e6f807a459d5e69899139772841d22ae Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Fri, 10 Dec 2021 18:12:06 +0200
Subject: SL-16485 Crash at memcpyNonAliased16

---
 indra/newview/llmodelpreview.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp
index 1da9e6c651..5d81d2c9b3 100644
--- a/indra/newview/llmodelpreview.cpp
+++ b/indra/newview/llmodelpreview.cpp
@@ -1325,8 +1325,8 @@ F32 LLModelPreview::genMeshOptimizerPerModel(LLModel *base_model, LLModel *targe
         LLVector4a::memcpyNonAliased16((F32*)(combined_normals + combined_positions_shift), (F32*)face.mNormals, copy_bytes);
 
         // tex coords
-        copy_bytes = (face.mNumVertices * sizeof(LLVector2) + 0xF) & ~0xF;
-        LLVector4a::memcpyNonAliased16((F32*)(combined_tex_coords + combined_positions_shift), (F32*)face.mTexCoords, copy_bytes);
+        copy_bytes = face.mNumVertices * sizeof(LLVector2);
+        memcpy((void*)(combined_tex_coords + combined_positions_shift), (void*)face.mTexCoords, copy_bytes);
 
         combined_positions_shift += face.mNumVertices;
 
-- 
cgit v1.2.3


From 915376b37988f93704553aeda103d525420997ea Mon Sep 17 00:00:00 2001
From: Mnikolenko Productengine <mnikolenko@productengine.com>
Date: Wed, 15 Dec 2021 16:20:28 +0200
Subject: SL-16495 FIXED Crash when unchecking "Animated Mesh" setting

---
 indra/newview/llvovolume.cpp | 13 +++++++++++++
 1 file changed, 13 insertions(+)

(limited to 'indra')

diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index c312ebb307..e7d4ae49f0 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -5656,6 +5656,19 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
                     facep->mAvatar = avatar;
                     any_rigged_face = true;
                 }
+                else
+                {
+                    if (facep->isState(LLFace::RIGGED))
+                    { 
+                        //face is not rigged but used to be, remove from rigged face pool
+                        LLDrawPoolAvatar* pool = (LLDrawPoolAvatar*) facep->getPool();
+                        if (pool)
+                        {
+                            pool->removeFace(facep);
+                        }
+                        facep->clearState(LLFace::RIGGED);
+                    }
+                }
 
 				if (cur_total > max_total || facep->getIndicesCount() <= 0 || facep->getGeomCount() <= 0)
 				{
-- 
cgit v1.2.3


From 6164d465af3f71ff1295d0170fda22d2862c496c Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Wed, 15 Dec 2021 10:38:18 -0800
Subject: SL-16493: Fix non-fullbright partial alpha objects not being lit by
 sun broken in 511de439a3

---
 indra/newview/lldrawpoolalpha.cpp | 21 +++++++++++++++------
 1 file changed, 15 insertions(+), 6 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/lldrawpoolalpha.cpp b/indra/newview/lldrawpoolalpha.cpp
index 5eb5c6caad..3de9fda945 100644
--- a/indra/newview/lldrawpoolalpha.cpp
+++ b/indra/newview/lldrawpoolalpha.cpp
@@ -84,12 +84,21 @@ S32 LLDrawPoolAlpha::getNumPostDeferredPasses()
 }
 
 // set some common parameters on the given shader to prepare for alpha rendering
-static void prepare_alpha_shader(LLGLSLShader* shader, bool textureGamma)
+static void prepare_alpha_shader(LLGLSLShader* shader, bool textureGamma, bool deferredEnvironment)
 {
     static LLCachedControl<F32> displayGamma(gSavedSettings, "RenderDeferredDisplayGamma");
     F32 gamma = displayGamma;
 
-    shader->bind();
+    // Deferred shader needs environment uniforms set such as sun_dir, etc. ?
+    // i.e. shaders\class1\deferred\alphaF.glsl
+    if (deferredEnvironment)
+    {
+        gPipeline.bindDeferredShader( *shader );
+    }
+    else
+    {
+        shader->bind();
+    }
     shader->uniform1i(LLShaderMgr::NO_ATMO, (LLPipeline::sRenderingHUDs) ? 1 : 0);
     shader->uniform1f(LLShaderMgr::DISPLAY_GAMMA, (gamma > 0.1f) ? 1.0f / gamma : (1.0f / 2.2f));
 
@@ -109,7 +118,7 @@ static void prepare_alpha_shader(LLGLSLShader* shader, bool textureGamma)
     //also prepare rigged variant
     if (shader->mRiggedVariant && shader->mRiggedVariant != shader)
     { 
-        prepare_alpha_shader(shader->mRiggedVariant, textureGamma);
+        prepare_alpha_shader(shader->mRiggedVariant, textureGamma, deferredEnvironment);
     }
 }
 
@@ -121,15 +130,15 @@ void LLDrawPoolAlpha::renderPostDeferred(S32 pass)
     // first pass, regular forward alpha rendering
     {
         emissive_shader = (LLPipeline::sUnderWaterRender) ? &gObjectEmissiveWaterProgram : &gObjectEmissiveProgram;
-        prepare_alpha_shader(emissive_shader, true);
+        prepare_alpha_shader(emissive_shader, true, false);
 
         fullbright_shader = (LLPipeline::sImpostorRender) ? &gDeferredFullbrightProgram :
             (LLPipeline::sUnderWaterRender) ? &gDeferredFullbrightWaterProgram : &gDeferredFullbrightProgram;
-        prepare_alpha_shader(fullbright_shader, true);
+        prepare_alpha_shader(fullbright_shader, true, false);
 
         simple_shader = (LLPipeline::sImpostorRender) ? &gDeferredAlphaImpostorProgram :
             (LLPipeline::sUnderWaterRender) ? &gDeferredAlphaWaterProgram : &gDeferredAlphaProgram;
-        prepare_alpha_shader(simple_shader, false);
+        prepare_alpha_shader(simple_shader, false, true); //prime simple shader (loads shadow relevant uniforms)
         
         forwardRender();
     }
-- 
cgit v1.2.3


From 8bf5597db2f10c4a423af5df333ff0f1c7fd9c99 Mon Sep 17 00:00:00 2001
From: Runitai Linden <davep@lindenlab.com>
Date: Wed, 15 Dec 2021 13:43:58 -0600
Subject: SL-16487 Fix for rigged attachment bounding boxes being too tight.

---
 indra/newview/lldrawable.cpp |  39 ++++++++---
 indra/newview/llvoavatar.cpp |   2 +-
 indra/newview/llvoavatar.h   |  11 +++-
 indra/newview/llvovolume.cpp | 151 +++++++++++++++++++++++--------------------
 4 files changed, 121 insertions(+), 82 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/lldrawable.cpp b/indra/newview/lldrawable.cpp
index 7e99b99284..7c3c230cff 100644
--- a/indra/newview/lldrawable.cpp
+++ b/indra/newview/lldrawable.cpp
@@ -1162,21 +1162,26 @@ void LLDrawable::setGroup(LLViewerOctreeGroup *groupp)
 	LLViewerOctreeEntryData::setGroup(groupp);
 }
 
+/*
+* Get the SpatialPartition this Drawable should use.  
+* Checks current SpatialPartition assignment and corrects if it is invalid.
+*/
 LLSpatialPartition* LLDrawable::getSpatialPartition()
 { 
 	LL_PROFILE_ZONE_SCOPED
 
 	LLSpatialPartition* retval = NULL;
-	
+
 	if (!mVObjp || 
 		!getVOVolume() ||
 		isStatic())
 	{
-		retval = gPipeline.getSpatialPartition((LLViewerObject*) mVObjp);
+        retval = gPipeline.getSpatialPartition((LLViewerObject*)mVObjp);
 	}
 	else if (isRoot())
 	{
-		if (mSpatialBridge)
+        // determine if the spatial bridge has changed
+        if (mSpatialBridge)
 		{
 			U32 partition_type = mSpatialBridge->asPartition()->mPartitionType;
 			bool is_hud = mVObjp->isHUDAttachment();
@@ -1193,14 +1198,14 @@ LLSpatialPartition* LLDrawable::getSpatialPartition()
 			{
 				// Was/became part of animesh
 				// remove obsolete bridge
-				mSpatialBridge->markDead();
+                mSpatialBridge->markDead();
 				setSpatialBridge(NULL);
 			}
 			else if ((partition_type == LLViewerRegion::PARTITION_AVATAR) != is_attachment)
 			{
 				// Was/became part of avatar
 				// remove obsolete bridge
-				mSpatialBridge->markDead();
+                mSpatialBridge->markDead();
 				setSpatialBridge(NULL);
 			}
 		}
@@ -1211,17 +1216,20 @@ LLSpatialPartition* LLDrawable::getSpatialPartition()
 			{
 				setSpatialBridge(new LLHUDBridge(this, getRegion()));
 			}
-			else if (mVObjp->isAnimatedObject() && mVObjp->getControlAvatar())
-			{
-				setSpatialBridge(new LLControlAVBridge(this, getRegion()));
-			}
+            else if (mVObjp->isAnimatedObject() && mVObjp->getControlAvatar())
+            {
+                setSpatialBridge(new LLControlAVBridge(this, getRegion()));
+            }
 			// check HUD first, because HUD is also attachment
 			else if (mVObjp->isAttachment())
 			{
+                // Attachment
+                // Use AvatarBridge of root object in attachment linkset
 				setSpatialBridge(new LLAvatarBridge(this, getRegion()));
 			}
 			else
 			{
+                // Moving linkset, use VolumeBridge of root object in linkset
 				setSpatialBridge(new LLVolumeBridge(this, getRegion()));
 			}
 		}
@@ -1395,10 +1403,21 @@ LLCamera LLSpatialBridge::transformCamera(LLCamera& camera)
 
 	ret.setOrigin(delta);
 	ret.setAxes(lookAt, left_axis, up_axis);
-		
+
 	return ret;
 }
 
+void LLSpatialBridge::transformExtents(const LLVector4a* src, LLVector4a* dst)
+{
+    LLMatrix4 mat = mDrawable->getXform()->getWorldMatrix();
+    mat.invert();
+
+    LLMatrix4a world_to_bridge(mat);
+
+    matMulBoundBox(world_to_bridge, src, dst);
+}
+
+
 void LLDrawable::setVisible(LLCamera& camera, std::vector<LLDrawable*>* results, BOOL for_select)
 {
 	LLViewerOctreeEntryData::setVisible();
diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp
index 8e4e008738..db274aa5ad 100644
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -9426,7 +9426,7 @@ LLViewerTexture* LLVOAvatar::getBakedTexture(const U8 te)
 	
 }
 
-const LLVOAvatar::MatrixPaletteCache& LLVOAvatar::updateSkinInfoMatrixPalette(const LLMeshSkinInfo* skin, LLVOVolume* requesting_obj)
+const LLVOAvatar::MatrixPaletteCache& LLVOAvatar::updateSkinInfoMatrixPalette(const LLMeshSkinInfo* skin)
 {
     U64 hash = skin->mHash;
     MatrixPaletteCache& entry = mMatrixPaletteCache[hash];
diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h
index b85400866e..ab2a2daf49 100644
--- a/indra/newview/llvoavatar.h
+++ b/indra/newview/llvoavatar.h
@@ -55,7 +55,6 @@
 #include "llavatarrendernotifier.h"
 #include "llmodel.h"
 
-
 extern const LLUUID ANIM_AGENT_BODY_NOISE;
 extern const LLUUID ANIM_AGENT_BREATHE_ROT;
 extern const LLUUID ANIM_AGENT_PHYSICS_MOTION;
@@ -749,10 +748,14 @@ public:
 	void			updateMeshVisibility();
 	LLViewerTexture*		getBakedTexture(const U8 te);
 
+    // Matrix palette cache entry
     class alignas(16) MatrixPaletteCache
     {
     public:
+        // Last frame this entry was updated
         U32 mFrame;
+
+        // List of Matrix4a's for this entry
         LLMeshSkinInfo::matrix_list_t mMatrixPalette;
 
         // Float array ready to be sent to GL
@@ -764,8 +767,12 @@ public:
         }
     };
 
-    const MatrixPaletteCache& updateSkinInfoMatrixPalette(const LLMeshSkinInfo* skinInfo, LLVOVolume* requesting_obj = nullptr);
+    // Accessor for Matrix Palette Cache
+    // Will do a map lookup for the entry associated with the given MeshSkinInfo
+    // Will update said entry if it hasn't been updated yet this frame
+    const MatrixPaletteCache& updateSkinInfoMatrixPalette(const LLMeshSkinInfo* skinInfo);
 
+    // Map of LLMeshSkinInfo::mHash to MatrixPaletteCache
     typedef std::unordered_map<U64, MatrixPaletteCache> matrix_palette_cache_t;
     matrix_palette_cache_t mMatrixPaletteCache;
 
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index c312ebb307..a4f217bbcb 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -1667,15 +1667,14 @@ void LLVOVolume::regenFaces()
 
 BOOL LLVOVolume::genBBoxes(BOOL force_global)
 {
-    LL_PROFILE_ZONE_SCOPED;
-	BOOL res = TRUE;
+    BOOL res = TRUE;
 
-	LLVector4a min,max;
+    LLVector4a min, max;
 
-	min.clear();
-	max.clear();
+    min.clear();
+    max.clear();
 
-	BOOL rebuild = mDrawable->isState(LLDrawable::REBUILD_VOLUME | LLDrawable::REBUILD_POSITION | LLDrawable::REBUILD_RIGGED);
+    BOOL rebuild = mDrawable->isState(LLDrawable::REBUILD_VOLUME | LLDrawable::REBUILD_POSITION | LLDrawable::REBUILD_RIGGED);
 
     if (getRiggedVolume())
     {
@@ -1686,93 +1685,107 @@ BOOL LLVOVolume::genBBoxes(BOOL force_global)
         // Without the flag, this will remove unused rigged volumes, which we are not currently very aggressive about.
         updateRiggedVolume();
     }
-    
-	LLVolume* volume = mRiggedVolume;
-	if (!volume)
-	{
-		volume = getVolume();
-	}
+
+    LLVolume* volume = mRiggedVolume;
+    if (!volume)
+    {
+        volume = getVolume();
+    }
 
     bool any_valid_boxes = false;
-    
+
     if (getRiggedVolume())
     {
         LL_DEBUGS("RiggedBox") << "rebuilding box, volume face count " << getVolume()->getNumVolumeFaces() << " drawable face count " << mDrawable->getNumFaces() << LL_ENDL;
     }
-
     // There's no guarantee that getVolume()->getNumFaces() == mDrawable->getNumFaces()
-	for (S32 i = 0;
-		 i < getVolume()->getNumVolumeFaces() && i < mDrawable->getNumFaces() && i < getNumTEs();
-		 i++)
-	{
-		LLFace *face = mDrawable->getFace(i);
-		if (!face)
-		{
-			continue;
-		}
+    for (S32 i = 0;
+        i < getVolume()->getNumVolumeFaces() && i < mDrawable->getNumFaces() && i < getNumTEs();
+        i++)
+    {
+        LLFace* face = mDrawable->getFace(i);
+        if (!face)
+        {
+            continue;
+        }
 
         BOOL face_res = face->genVolumeBBoxes(*volume, i,
-                                              mRelativeXform, 
-                                              (mVolumeImpl && mVolumeImpl->isVolumeGlobal()) || force_global);
+            mRelativeXform,
+            (mVolumeImpl && mVolumeImpl->isVolumeGlobal()) || force_global);
         res &= face_res; // note that this result is never used
-		
+
         // MAINT-8264 - ignore bboxes of ill-formed faces.
         if (!face_res)
         {
             continue;
         }
-		if (rebuild)
-		{
+        if (rebuild)
+        {
             if (getRiggedVolume())
             {
                 LL_DEBUGS("RiggedBox") << "rebuilding box, face " << i << " extents " << face->mExtents[0] << ", " << face->mExtents[1] << LL_ENDL;
             }
-			if (!any_valid_boxes)
-			{
-				min = face->mExtents[0];
-				max = face->mExtents[1];
+            if (!any_valid_boxes)
+            {
+                min = face->mExtents[0];
+                max = face->mExtents[1];
                 any_valid_boxes = true;
-			}
-			else
-			{
-				min.setMin(min, face->mExtents[0]);
-				max.setMax(max, face->mExtents[1]);
-			}
-		}
-	}
-
-    bool rigged = false;
-    
-    if (!isAnimatedObject())
-    {
-        rigged = isRiggedMesh() && isAttachment();
-    }
-    else
-    {
-        rigged = isRiggedMesh() && getControlAvatar() && getControlAvatar()->mPlaying;
+            }
+            else
+            {
+                min.setMin(min, face->mExtents[0]);
+                max.setMax(max, face->mExtents[1]);
+            }
+        }
     }
 
-    if (rigged)
-    {
-        mDrawable->setSpatialExtents(min, max);
-        // always use the same octree node position for any given rigged mesh so it doesn't switch nodes
-        // while animating (and thus rebuild its vertex buffer)
-        mDrawable->setPositionGroup(LLVector4a(0, 0, 0));
-        updateRadius();
-        mDrawable->movePartition();
-    }
-    else if (any_valid_boxes)
+    if (any_valid_boxes)
     {
         if (rebuild)
         {
-            if (getRiggedVolume())
+            //get the Avatar associated with this object if there is one
+            LLVOAvatar* avatar = nullptr;
+            if (isRiggedMesh())
             {
-                LL_DEBUGS("RiggedBox") << "rebuilding got extents " << min << ", " << max << LL_ENDL;
+                if (!isAnimatedObject())
+                {
+                    if (isAttachment())
+                    {
+                        avatar = getAvatar();
+                    }
+                }
+                else
+                {
+                    LLControlAvatar* controlAvatar = getControlAvatar();
+                    if (controlAvatar && controlAvatar->mPlaying)
+                    {
+                        avatar = controlAvatar;
+                    }
+                }
+            }
+
+            LLSpatialBridge* bridge = mDrawable->getSpatialBridge();
+            if (avatar && bridge)
+            {
+                //use avatar bounding box for visibility culling
+                LLDrawable* ref = avatar->mDrawable;
+
+                LLVector4a extents[2];
+
+                bridge->transformExtents(ref->getSpatialExtents(), extents);
+                
+                mDrawable->setSpatialExtents(extents[0], extents[1]);
+                // don't switch octree node based on bounding box center to avoid breaking batches and rebuilding vertex buffers
+                mDrawable->setPositionGroup(LLVector4a(0, 0, 0, 0));
+                LL_DEBUGS("RiggedBox") << "rebuilding got extents " << extents[0] << ", " << extents[1] << LL_ENDL;
+            }
+            else
+            {
+                mDrawable->setSpatialExtents(min, max);
+                min.add(max);
+                min.mul(0.5f);
+                mDrawable->setPositionGroup(min);
             }
-            mDrawable->setSpatialExtents(min,max);
-            min.add(max);
-            min.mul(0.5f);
-            mDrawable->setPositionGroup(min);	
         }
 
         updateRadius();
@@ -1782,8 +1795,8 @@ BOOL LLVOVolume::genBBoxes(BOOL force_global)
     {
         LL_DEBUGS("RiggedBox") << "genBBoxes failed to find any valid face boxes" << LL_ENDL;
     }
-				
-	return res;
+
+    return res;
 }
 
 void LLVOVolume::preRebuild()
@@ -4817,7 +4830,7 @@ void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, cons
 
 	if (copy)
 	{
-		copyVolumeFaces(volume);	
+		copyVolumeFaces(volume);
 	}
     else
     {
-- 
cgit v1.2.3


From 20345827eb5b9ebc658ac506f0d41f2a149d895d Mon Sep 17 00:00:00 2001
From: Runitai Linden <davep@lindenlab.com>
Date: Wed, 15 Dec 2021 15:43:23 -0600
Subject: SL-16489 Fix for rigged attachment glow showing up near origin.

---
 .../app_settings/shaders/class1/deferred/emissiveV.glsl | 17 ++++++++++++++---
 1 file changed, 14 insertions(+), 3 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/app_settings/shaders/class1/deferred/emissiveV.glsl b/indra/newview/app_settings/shaders/class1/deferred/emissiveV.glsl
index 5e4f08b017..08b1147ab0 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/emissiveV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/emissiveV.glsl
@@ -40,15 +40,26 @@ vec3 atmosAffectDirectionalLight(float lightIntensity);
 VARYING vec4 vertex_color;
 VARYING vec2 vary_texcoord0;
 
+#ifdef HAS_SKIN
+mat4 getObjectSkinnedTransform();
+uniform mat4 projection_matrix;
+#endif
 
 void main()
 {
 	//transform vertex
-	vec4 vert = vec4(position.xyz, 1.0);
-	vec4 pos = (modelview_matrix * vert);
 	passTextureIndex();
 
-	gl_Position = modelview_projection_matrix*vec4(position.xyz, 1.0);
+#ifdef HAS_SKIN
+    mat4 mat = getObjectSkinnedTransform();
+    mat = modelview_matrix * mat;
+
+    vec4 pos = mat * vec4(position.xyz, 1.0);
+    gl_Position = projection_matrix * pos;
+#else
+	gl_Position = modelview_projection_matrix * vec4(position.xyz, 1.0);
+    vec4 pos = (modelview_matrix * vec4(position.xyz, 1.0));
+#endif
 	
 	vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy;
 	
-- 
cgit v1.2.3


From 828e58432981e7c256618bd293f77906abaae699 Mon Sep 17 00:00:00 2001
From: Runitai Linden <davep@lindenlab.com>
Date: Wed, 15 Dec 2021 15:57:59 -0600
Subject: SL-16487 Build fix (whoops)

---
 indra/newview/llspatialpartition.h | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

(limited to 'indra')

diff --git a/indra/newview/llspatialpartition.h b/indra/newview/llspatialpartition.h
index 58d821353a..666c025347 100644
--- a/indra/newview/llspatialpartition.h
+++ b/indra/newview/llspatialpartition.h
@@ -439,8 +439,11 @@ public:
 	virtual void cleanupReferences();
 	virtual LLSpatialPartition* asPartition()		{ return this; }
 		
+    //transform agent space camera into this Spatial Bridge's coordinate frame
 	virtual LLCamera transformCamera(LLCamera& camera);
-	
+
+    //transform agent space bounding box into this Spatial Bridge's coordinate frame
+    void transformExtents(const LLVector4a* src, LLVector4a* dst);
 	LLDrawable* mDrawable;
 };
 
-- 
cgit v1.2.3


From 9ac89bca2cb8cf3bc55cc26113d400b7b3473335 Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Wed, 15 Dec 2021 14:11:02 -0800
Subject: SL-16493: Add comment about using deferred shaders even though we are
 in a post deferred state (forward pass rendering for transparency)

---
 indra/newview/lldrawpoolalpha.cpp | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

(limited to 'indra')

diff --git a/indra/newview/lldrawpoolalpha.cpp b/indra/newview/lldrawpoolalpha.cpp
index 3de9fda945..ee1a640f2d 100644
--- a/indra/newview/lldrawpoolalpha.cpp
+++ b/indra/newview/lldrawpoolalpha.cpp
@@ -89,7 +89,9 @@ static void prepare_alpha_shader(LLGLSLShader* shader, bool textureGamma, bool d
     static LLCachedControl<F32> displayGamma(gSavedSettings, "RenderDeferredDisplayGamma");
     F32 gamma = displayGamma;
 
-    // Deferred shader needs environment uniforms set such as sun_dir, etc. ?
+    // Does this deferred shader need environment uniforms set such as sun_dir, etc. ?
+    // NOTE: We don't actually need a gbuffer since we are doing forward rendering (for transparency) post deferred rendering
+    // TODO: bindDeferredShader() probably should have the updating of the environment uniforms factored out into updateShaderEnvironmentUniforms()
     // i.e. shaders\class1\deferred\alphaF.glsl
     if (deferredEnvironment)
     {
-- 
cgit v1.2.3


From 752bcc16fc57070a06a572eae2fce18fc181136d Mon Sep 17 00:00:00 2001
From: Dave Houlton <euclid@lindenlab.com>
Date: Thu, 16 Dec 2021 10:20:14 -0700
Subject: DRTVWR-546 remove dead fxn that breaks Mac build

---
 indra/newview/llviewercontrol.cpp | 11 -----------
 1 file changed, 11 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp
index fcacc933e0..41c477f678 100644
--- a/indra/newview/llviewercontrol.cpp
+++ b/indra/newview/llviewercontrol.cpp
@@ -166,17 +166,6 @@ static bool handleSetShaderChanged(const LLSD& newvalue)
 	return true;
 }
 
-static bool handleAvatarVPChanged(const LLSD& newvalue)
-{
-    LLRenderTarget::sUseFBO = newvalue.asBoolean()
-                                && gSavedSettings.getBOOL("RenderObjectBump")
-                                && gSavedSettings.getBOOL("RenderTransparentWater")
-                                && gSavedSettings.getBOOL("RenderDeferred");
-
-    handleSetShaderChanged(LLSD());
-    return true;
-}
-
 static bool handleRenderPerfTestChanged(const LLSD& newvalue)
 {
        bool status = !newvalue.asBoolean();
-- 
cgit v1.2.3


From bebdeb430ba72ab1c7eddc2f10d43b36f1992827 Mon Sep 17 00:00:00 2001
From: Dave Houlton <euclid@lindenlab.com>
Date: Thu, 16 Dec 2021 10:50:49 -0700
Subject: DRTVWR-546 fix dead setting merge error

---
 indra/newview/llviewercontrol.cpp | 1 -
 1 file changed, 1 deletion(-)

(limited to 'indra')

diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp
index 41c477f678..a4f8963dc3 100644
--- a/indra/newview/llviewercontrol.cpp
+++ b/indra/newview/llviewercontrol.cpp
@@ -467,7 +467,6 @@ static bool handleRenderBumpChanged(const LLSD& newval)
 {
     LLRenderTarget::sUseFBO = newval.asBoolean() 
                                 && gSavedSettings.getBOOL("RenderTransparentWater") 
-                                && gSavedSettings.getBOOL("RenderAvatarVP")
                                 && gSavedSettings.getBOOL("RenderDeferred");
 	if (gPipeline.isInit())
 	{
-- 
cgit v1.2.3


From 0fd7d20949a3f471e7ebb78731612013dfad7b0d Mon Sep 17 00:00:00 2001
From: Dave Houlton <euclid@lindenlab.com>
Date: Thu, 16 Dec 2021 11:14:14 -0700
Subject: DRTVWR-546 fix sUseFBO merge errors

---
 indra/newview/llappviewer.cpp     | 15 ++++++++-------
 indra/newview/llviewercontrol.cpp |  4 +---
 2 files changed, 9 insertions(+), 10 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 0a8780b1e1..89e0da3ea7 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -566,13 +566,14 @@ static void settings_to_globals()
 
 static void settings_modify()
 {
-	LLPipeline::sRenderTransparentWater	= gSavedSettings.getBOOL("RenderTransparentWater");
-	LLPipeline::sRenderBump				= gSavedSettings.getBOOL("RenderObjectBump");
-	LLPipeline::sRenderDeferred		= 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;
-	gDebugPipeline = gSavedSettings.getBOOL("RenderDebugPipeline");
+    LLPipeline::sRenderTransparentWater = gSavedSettings.getBOOL("RenderTransparentWater");
+    LLPipeline::sRenderBump             = gSavedSettings.getBOOL("RenderObjectBump");
+    LLPipeline::sRenderDeferred         = LLPipeline::sRenderBump && gSavedSettings.getBOOL("RenderDeferred");
+    LLRenderTarget::sUseFBO             = LLPipeline::sRenderDeferred;
+    LLVOSurfacePatch::sLODFactor        = gSavedSettings.getF32("RenderTerrainLODFactor");
+    LLVOSurfacePatch::sLODFactor *= LLVOSurfacePatch::sLODFactor;  // square lod factor to get exponential range of [1,4]
+    gDebugGL       = gSavedSettings.getBOOL("RenderDebugGL") || gDebugSession;
+    gDebugPipeline = gSavedSettings.getBOOL("RenderDebugPipeline");
 }
 
 class LLFastTimerLogThread : public LLThread
diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp
index a4f8963dc3..e53f988c6e 100644
--- a/indra/newview/llviewercontrol.cpp
+++ b/indra/newview/llviewercontrol.cpp
@@ -465,9 +465,7 @@ static bool handleRenderDeferredChanged(const LLSD& newvalue)
 //
 static bool handleRenderBumpChanged(const LLSD& newval)
 {
-    LLRenderTarget::sUseFBO = newval.asBoolean() 
-                                && gSavedSettings.getBOOL("RenderTransparentWater") 
-                                && gSavedSettings.getBOOL("RenderDeferred");
+    LLRenderTarget::sUseFBO = newval.asBoolean() && gSavedSettings.getBOOL("RenderDeferred");
 	if (gPipeline.isInit())
 	{
 		gPipeline.updateRenderBump();
-- 
cgit v1.2.3


From 3ac21ebbf6b354e16ead2d095a61152c95a7243c Mon Sep 17 00:00:00 2001
From: Mnikolenko Productengine <mnikolenko@productengine.com>
Date: Fri, 17 Dec 2021 13:07:23 +0200
Subject: SL-16454 FIXED Performance viewer login screen is black

---
 indra/llwindow/llwindowwin32.cpp | 13 +++++++++++++
 1 file changed, 13 insertions(+)

(limited to 'indra')

diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp
index 0064ee26d2..e4d771978a 100644
--- a/indra/llwindow/llwindowwin32.cpp
+++ b/indra/llwindow/llwindowwin32.cpp
@@ -427,6 +427,9 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks,
 	memset(mPrevGammaRamp, 0, sizeof(mPrevGammaRamp));
 	mCustomGammaSet = FALSE;
 	mWindowHandle = NULL;
+
+    mRect = {0, 0, 0, 0};
+    mClientRect = {0, 0, 0, 0};
 	
 	if (!SystemParametersInfo(SPI_GETMOUSEVANISH, 0, &mMouseVanish, 0))
 	{
@@ -1506,6 +1509,16 @@ const	S32   max_format  = (S32)num_formats - 1;
 		}
 
 		recreateWindow(window_rect, dw_ex_style, dw_style);
+        
+        RECT rect;
+        RECT client_rect;
+        //initialize immediately on main thread
+        if (GetWindowRect(mWindowHandle, &rect) &&
+            GetClientRect(mWindowHandle, &client_rect))
+        {
+            mRect = rect;
+            mClientRect = client_rect;
+        };
 
 		if (mWindowHandle)
 		{
-- 
cgit v1.2.3


From dd032467357a4aaf69c752c13e53122aff6c4755 Mon Sep 17 00:00:00 2001
From: Runitai Linden <davep@lindenlab.com>
Date: Fri, 17 Dec 2021 09:26:44 -0600
Subject: SL-16478 Fix for octree and render batch debug display not working
 with rigged meshes.

---
 .../shaders/class1/interface/debugSkinnedV.glsl    | 41 ----------------------
 .../shaders/class1/interface/debugV.glsl           | 13 +++++++
 indra/newview/lldrawpool.cpp                       |  8 ++++-
 indra/newview/lldrawpool.h                         |  3 ++
 indra/newview/llspatialpartition.cpp               | 41 ++++++++++++++++++++--
 indra/newview/llviewershadermgr.cpp                | 14 ++------
 indra/newview/llviewerwindow.cpp                   |  1 +
 7 files changed, 64 insertions(+), 57 deletions(-)
 delete mode 100644 indra/newview/app_settings/shaders/class1/interface/debugSkinnedV.glsl

(limited to 'indra')

diff --git a/indra/newview/app_settings/shaders/class1/interface/debugSkinnedV.glsl b/indra/newview/app_settings/shaders/class1/interface/debugSkinnedV.glsl
deleted file mode 100644
index 74f22aec4f..0000000000
--- a/indra/newview/app_settings/shaders/class1/interface/debugSkinnedV.glsl
+++ /dev/null
@@ -1,41 +0,0 @@
-/** 
- * @file debugSkinnedV.glsl
- *
- * $LicenseInfo:firstyear=2021&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2011, Linden Research, Inc.
- * 
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- * 
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
- * $/LicenseInfo$
- */
-
-uniform mat4 projection_matrix;
-uniform mat4 modelview_matrix;
-
-mat4 getObjectSkinnedTransform();
-
-ATTRIBUTE vec3 position;
-
-void main()
-{
-    mat4 mat = getObjectSkinnedTransform();
-    mat = modelview_matrix * mat;
-    vec3 pos = (mat*vec4(position.xyz, 1.0)).xyz;
-
-    gl_Position = projection_matrix*vec4(pos, 1.0);
-}
-
diff --git a/indra/newview/app_settings/shaders/class1/interface/debugV.glsl b/indra/newview/app_settings/shaders/class1/interface/debugV.glsl
index f4d704577a..153998f1d5 100644
--- a/indra/newview/app_settings/shaders/class1/interface/debugV.glsl
+++ b/indra/newview/app_settings/shaders/class1/interface/debugV.glsl
@@ -27,8 +27,21 @@ uniform mat4 modelview_projection_matrix;
 
 ATTRIBUTE vec3 position;
 
+#ifdef HAS_SKIN
+mat4 getObjectSkinnedTransform();
+uniform mat4 projection_matrix;
+uniform mat4 modelview_matrix;
+#endif
+
 void main()
 {
+#ifdef HAS_SKIN
+    mat4 mat = getObjectSkinnedTransform();
+    mat = modelview_matrix * mat;
+    vec4 pos = mat * vec4(position.xyz,1.0);
+    gl_Position = projection_matrix * pos;
+#else
 	gl_Position = modelview_projection_matrix * vec4(position.xyz, 1.0);
+#endif
 }
 
diff --git a/indra/newview/lldrawpool.cpp b/indra/newview/lldrawpool.cpp
index bad0c66fb1..503ee6d08d 100644
--- a/indra/newview/lldrawpool.cpp
+++ b/indra/newview/lldrawpool.cpp
@@ -590,7 +590,13 @@ void LLRenderPass::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture, BOOL ba
 bool LLRenderPass::uploadMatrixPalette(LLDrawInfo& params)
 {
     // upload matrix palette to shader
-    const LLVOAvatar::MatrixPaletteCache& mpc = params.mAvatar->updateSkinInfoMatrixPalette(params.mSkinInfo);
+    return uploadMatrixPalette(params.mAvatar, params.mSkinInfo);
+}
+
+//static
+bool LLRenderPass::uploadMatrixPalette(LLVOAvatar* avatar, LLMeshSkinInfo* skinInfo)
+{
+    const LLVOAvatar::MatrixPaletteCache& mpc = avatar->updateSkinInfoMatrixPalette(skinInfo);
     U32 count = mpc.mMatrixPalette.size();
 
     if (count == 0)
diff --git a/indra/newview/lldrawpool.h b/indra/newview/lldrawpool.h
index 6d49b0254b..d4f30fc51a 100644
--- a/indra/newview/lldrawpool.h
+++ b/indra/newview/lldrawpool.h
@@ -37,6 +37,8 @@ class LLViewerTexture;
 class LLViewerFetchedTexture;
 class LLSpatialGroup;
 class LLDrawInfo;
+class LLVOAvatar;
+class LLMeshSkinInfo;
 
 class LLDrawPool
 {
@@ -204,6 +206,7 @@ public:
     virtual void pushRiggedMaskBatches(U32 type, U32 mask, BOOL texture = TRUE, BOOL batch_textures = FALSE);
 	virtual void pushBatch(LLDrawInfo& params, U32 mask, BOOL texture, BOOL batch_textures = FALSE);
     static bool uploadMatrixPalette(LLDrawInfo& params);
+    static bool uploadMatrixPalette(LLVOAvatar* avatar, LLMeshSkinInfo* skinInfo);
 	virtual void renderGroup(LLSpatialGroup* group, U32 type, U32 mask, BOOL texture = TRUE);
     virtual void renderRiggedGroup(LLSpatialGroup* group, U32 type, U32 mask, BOOL texture = TRUE);
 };
diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp
index 48e9f3726f..c802e62e40 100644
--- a/indra/newview/llspatialpartition.cpp
+++ b/indra/newview/llspatialpartition.cpp
@@ -1593,10 +1593,14 @@ void renderOctree(LLSpatialGroup* group)
 			gGL.flush();
 			glLineWidth(1.f);
 			gGL.flush();
+
+            LLVOAvatar* lastAvatar = nullptr;
+            U64 lastMeshId = 0;
+
 			for (LLSpatialGroup::element_iter i = group->getDataBegin(); i != group->getDataEnd(); ++i)
 			{
 				LLDrawable* drawable = (LLDrawable*)(*i)->getDrawable();
-				if(!drawable)
+				if(!drawable || drawable->getNumFaces() == 0)
 				{
 					continue;
 				}
@@ -1607,6 +1611,27 @@ void renderOctree(LLSpatialGroup* group)
 					gGL.translatef(trans.mV[0], trans.mV[1], trans.mV[2]);
 				}
 				
+                LLFace* face = drawable->getFace(0);
+                bool rigged = face->isState(LLFace::RIGGED);
+                gDebugProgram.bind(rigged);
+
+                gGL.diffuseColor4f(1, 0, 0, 1);
+
+                if (rigged)
+                {
+                    gGL.pushMatrix();
+                    gGL.loadMatrix(gGLModelView);
+                    if (lastAvatar != face->mAvatar ||
+                        lastMeshId != face->mSkinInfo->mHash)
+                    {
+                        if (!LLRenderPass::uploadMatrixPalette(face->mAvatar, face->mSkinInfo))
+                        {
+                            continue;
+                        }
+                        lastAvatar = face->mAvatar;
+                        lastMeshId = face->mSkinInfo->mHash;
+                    }
+                }
 				for (S32 j = 0; j < drawable->getNumFaces(); j++)
 				{
 					LLFace* face = drawable->getFace(j);
@@ -1625,19 +1650,25 @@ void renderOctree(LLSpatialGroup* group)
 							continue;
 						}
 
-						face->getVertexBuffer()->setBuffer(LLVertexBuffer::MAP_VERTEX);
+						face->getVertexBuffer()->setBuffer(LLVertexBuffer::MAP_VERTEX | (rigged ? LLVertexBuffer::MAP_WEIGHT4 : 0));
 						//drawBox((face->mExtents[0] + face->mExtents[1])*0.5f,
 						//		(face->mExtents[1]-face->mExtents[0])*0.5f);
 						face->getVertexBuffer()->draw(LLRender::TRIANGLES, face->getIndicesCount(), face->getIndicesStart());
 					}
 				}
 
+                if (rigged)
+                {
+                    gGL.popMatrix();
+                }
+
 				if (!group->getSpatialPartition()->isBridge())
 				{
 					gGL.popMatrix();
 				}
 			}
 			glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+            gDebugProgram.bind(); // make sure non-rigged variant is bound
 			gGL.diffuseColor4f(1,1,1,1);
 		}
 	}
@@ -2778,6 +2809,8 @@ void renderBatchSize(LLDrawInfo* params)
     bool bind = false;
     if (params->mAvatar)
     { 
+        gGL.pushMatrix();
+        gGL.loadMatrix(gGLModelView);
         bind = true;
         old_shader->mRiggedVariant->bind();
         LLRenderPass::uploadMatrixPalette(*params);
@@ -2789,6 +2822,7 @@ void renderBatchSize(LLDrawInfo* params)
 
     if (bind)
     {
+        gGL.popMatrix();
         old_shader->bind();
     }
 }
@@ -3941,7 +3975,8 @@ LLDrawInfo::LLDrawInfo(U16 start, U16 end, U32 count, U32 offset,
 {
 	mVertexBuffer->validateRange(mStart, mEnd, mCount, mOffset);
 	
-	mDebugColor = (rand() << 16) + rand();
+    mDebugColor = (rand() << 16) + rand();
+    ((U8*)&mDebugColor)[3] = 200;
 }
 
 LLDrawInfo::~LLDrawInfo()	
diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp
index d37e86fa5e..829e7f8add 100644
--- a/indra/newview/llviewershadermgr.cpp
+++ b/indra/newview/llviewershadermgr.cpp
@@ -3664,20 +3664,10 @@ BOOL LLViewerShaderMgr::loadShadersInterface()
 		gDebugProgram.mShaderFiles.push_back(make_pair("interface/debugF.glsl", GL_FRAGMENT_SHADER_ARB));
         gDebugProgram.mRiggedVariant = &gSkinnedDebugProgram;
 		gDebugProgram.mShaderLevel = mShaderLevel[SHADER_INTERFACE];
-		success = gDebugProgram.createShader(NULL, NULL);
+        success = make_rigged_variant(gDebugProgram, gSkinnedDebugProgram);
+		success = success && gDebugProgram.createShader(NULL, NULL);
 	}
 
-    if (success)
-    {
-        gSkinnedDebugProgram.mName = "Skinned Debug Shader";
-        gSkinnedDebugProgram.mFeatures.hasObjectSkinning = true;
-        gSkinnedDebugProgram.mShaderFiles.clear();
-        gSkinnedDebugProgram.mShaderFiles.push_back(make_pair("interface/debugSkinnedV.glsl", GL_VERTEX_SHADER_ARB));
-        gSkinnedDebugProgram.mShaderFiles.push_back(make_pair("interface/debugF.glsl", GL_FRAGMENT_SHADER_ARB));
-        gSkinnedDebugProgram.mShaderLevel = mShaderLevel[SHADER_INTERFACE];
-        success = gSkinnedDebugProgram.createShader(NULL, NULL);
-    }
-
 	if (success)
 	{
 		gClipProgram.mName = "Clip Shader";
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index 46204bc642..dbb1a1eea0 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -1767,6 +1767,7 @@ void LLViewerWindow::handleDataCopy(LLWindow *window, S32 data_type, void *data)
 
 BOOL LLViewerWindow::handleTimerEvent(LLWindow *window)
 {
+    //TODO: just call this every frame from gatherInput instead of using a convoluted 30fps timer callback
 	if (LLViewerJoystick::getInstance()->getOverrideCamera())
 	{
 		LLViewerJoystick::getInstance()->updateStatus();
-- 
cgit v1.2.3


From f22d659c6f2d9d99749be532730c09d283598e2e Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Fri, 17 Dec 2021 19:12:36 +0200
Subject: SL-16517 Dragging a physic object momentarily moves it to an
 incorrect location.

---
 indra/newview/lltoolgrab.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/lltoolgrab.cpp b/indra/newview/lltoolgrab.cpp
index f01b374db1..a0229b4edf 100644
--- a/indra/newview/lltoolgrab.cpp
+++ b/indra/newview/lltoolgrab.cpp
@@ -529,8 +529,8 @@ void LLToolGrabBase::handleHoverActive(S32 x, S32 y, MASK mask)
 	const F32 RADIANS_PER_PIXEL_X = 0.01f;
 	const F32 RADIANS_PER_PIXEL_Y = 0.01f;
 
-	S32 dx = x - (gViewerWindow->getWorldViewWidthScaled() / 2);
-	S32 dy = y - (gViewerWindow->getWorldViewHeightScaled() / 2);
+    S32 dx = gViewerWindow->getCurrentMouseDX() / 2;
+    S32 dy = gViewerWindow->getCurrentMouseDY() / 2;
 
 	if (dx != 0 || dy != 0)
 	{
-- 
cgit v1.2.3


From 8d98804ba4f58dc7fef850ee7534af6e216b1d9c Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Fri, 17 Dec 2021 13:12:41 -0800
Subject: SL-16492: Fix for HAS_ALPHA_MASK permutation not being set for
 fullbrightF.glsl when rigged mesh has alpha mask.

---
 indra/newview/llviewershadermgr.cpp | 2 ++
 1 file changed, 2 insertions(+)

(limited to 'indra')

diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp
index 829e7f8add..c97b1d914b 100644
--- a/indra/newview/llviewershadermgr.cpp
+++ b/indra/newview/llviewershadermgr.cpp
@@ -264,10 +264,12 @@ bool make_rigged_variant(LLGLSLShader& shader, LLGLSLShader& riggedShader)
     riggedShader.mName = llformat("Skinned %s", shader.mName.c_str());
     riggedShader.mFeatures = shader.mFeatures;
     riggedShader.mFeatures.hasObjectSkinning = true;
+    riggedShader.mDefines = shader.mDefines;    // NOTE: Must come before addPermutation
     riggedShader.addPermutation("HAS_SKIN", "1");
     riggedShader.mShaderFiles = shader.mShaderFiles;
     riggedShader.mShaderLevel = shader.mShaderLevel;
     riggedShader.mShaderGroup = shader.mShaderGroup;
+
     shader.mRiggedVariant = &riggedShader;
     return riggedShader.createShader(NULL, NULL);
 }
-- 
cgit v1.2.3


From 91940a0e2ce7324288aa38aefd4e5050de3a9263 Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Fri, 17 Dec 2021 19:12:36 +0200
Subject: SL-16517 Dragging a physic object #2

mLastMouseX/Y might need to be assigned from gViewerWindow->getCurrentMouseX();
---
 indra/newview/lltoolgrab.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/lltoolgrab.cpp b/indra/newview/lltoolgrab.cpp
index a0229b4edf..6216899dc6 100644
--- a/indra/newview/lltoolgrab.cpp
+++ b/indra/newview/lltoolgrab.cpp
@@ -529,8 +529,8 @@ void LLToolGrabBase::handleHoverActive(S32 x, S32 y, MASK mask)
 	const F32 RADIANS_PER_PIXEL_X = 0.01f;
 	const F32 RADIANS_PER_PIXEL_Y = 0.01f;
 
-    S32 dx = gViewerWindow->getCurrentMouseDX() / 2;
-    S32 dy = gViewerWindow->getCurrentMouseDY() / 2;
+    S32 dx = gViewerWindow->getCurrentMouseDX();
+    S32 dy = gViewerWindow->getCurrentMouseDY();
 
 	if (dx != 0 || dy != 0)
 	{
-- 
cgit v1.2.3


From 936fd8ce491ee7110a8bf611eabf200182dcb943 Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Tue, 11 Jan 2022 17:31:17 +0200
Subject: SL-16626 Performance Viewer, bump minor version number to 6.6

---
 indra/newview/VIEWER_VERSION.txt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'indra')

diff --git a/indra/newview/VIEWER_VERSION.txt b/indra/newview/VIEWER_VERSION.txt
index 5e3ec53ea6..826f5ce030 100644
--- a/indra/newview/VIEWER_VERSION.txt
+++ b/indra/newview/VIEWER_VERSION.txt
@@ -1 +1 @@
-6.5.2
+6.6.0
-- 
cgit v1.2.3


From 04edc151851b7689853069b0748af9c64e94283f Mon Sep 17 00:00:00 2001
From: Dave Parks <davep@lindenlab.com>
Date: Thu, 13 Jan 2022 17:04:46 +0000
Subject: SL-16544 Fix for rigged mesh bounding boxes

---
 indra/newview/llcontrolavatar.cpp         |  2 --
 indra/newview/lldrawable.cpp              | 11 +++++++
 indra/newview/lldrawable.h                | 55 +++++++++++++++----------------
 indra/newview/llspatialpartition.cpp      |  4 +++
 indra/newview/llviewerjointattachment.cpp |  6 +---
 indra/newview/llvieweroctree.cpp          |  1 +
 indra/newview/llvoavatar.cpp              | 53 ++++++++++++++++++++---------
 indra/newview/llvovolume.cpp              | 41 ++++++++++++++---------
 indra/newview/pipeline.cpp                |  3 ++
 9 files changed, 108 insertions(+), 68 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llcontrolavatar.cpp b/indra/newview/llcontrolavatar.cpp
index 606e670805..4a87273372 100644
--- a/indra/newview/llcontrolavatar.cpp
+++ b/indra/newview/llcontrolavatar.cpp
@@ -299,7 +299,6 @@ void LLControlAvatar::updateVolumeGeom()
 	mRootVolp->mDrawable->makeActive();
 	gPipeline.markMoved(mRootVolp->mDrawable);
 	gPipeline.markTextured(mRootVolp->mDrawable); // face may need to change draw pool to/from POOL_HUD
-	mRootVolp->mDrawable->setState(LLDrawable::USE_BACKLIGHT);
 
 	LLViewerObject::const_child_list_t& child_list = mRootVolp->getChildren();
 	for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin();
@@ -308,7 +307,6 @@ void LLControlAvatar::updateVolumeGeom()
 		LLViewerObject* childp = *iter;
 		if (childp && childp->mDrawable.notNull())
 		{
-			childp->mDrawable->setState(LLDrawable::USE_BACKLIGHT);
 			gPipeline.markTextured(childp->mDrawable); // face may need to change draw pool to/from POOL_HUD
 			gPipeline.markMoved(childp->mDrawable);
         }
diff --git a/indra/newview/lldrawable.cpp b/indra/newview/lldrawable.cpp
index 7c3c230cff..b274fd56b6 100644
--- a/indra/newview/lldrawable.cpp
+++ b/indra/newview/lldrawable.cpp
@@ -1749,6 +1749,17 @@ void LLDrawable::updateFaceSize(S32 idx)
 	}
 }
 
+LLDrawable* LLDrawable::getRoot()
+{
+    LLDrawable* ret = this;
+    while (!ret->isRoot())
+    {
+        ret = ret->getParent();
+    }
+
+    return ret;
+}
+
 LLBridgePartition::LLBridgePartition(LLViewerRegion* regionp)
 : LLSpatialPartition(0, FALSE, 0, regionp) 
 { 
diff --git a/indra/newview/lldrawable.h b/indra/newview/lldrawable.h
index 9a9f6cf7c2..2372ea01a6 100644
--- a/indra/newview/lldrawable.h
+++ b/indra/newview/lldrawable.h
@@ -121,6 +121,7 @@ public:
 
 	BOOL				isAvatar()	const			{ return mVObjp.notNull() && mVObjp->isAvatar(); }
 	BOOL				isRoot() const				{ return !mParent || mParent->isAvatar(); }
+    LLDrawable*         getRoot();
 	BOOL				isSpatialRoot() const		{ return !mParent || mParent->isAvatar(); }
 	virtual BOOL		isSpatialBridge() const		{ return FALSE; }
 	virtual LLSpatialPartition* asPartition()		{ return NULL; }
@@ -255,38 +256,34 @@ public:
 	{
  		IN_REBUILD_Q1	= 0x00000001,
  		IN_REBUILD_Q2	= 0x00000002,
- 		IN_LIGHT_Q		= 0x00000004,
-		EARLY_MOVE		= 0x00000008,
-		MOVE_UNDAMPED	= 0x00000010,
-		ON_MOVE_LIST	= 0x00000020,
-		USE_BACKLIGHT	= 0x00000040,
-		UV				= 0x00000080,
-		UNLIT			= 0x00000100,
-		LIGHT			= 0x00000200,
-		LIGHTING_BUILT	= 0x00000400,
-		REBUILD_VOLUME  = 0x00000800,	//volume changed LOD or parameters, or vertex buffer changed
-		REBUILD_TCOORD	= 0x00001000,	//texture coordinates changed
-		REBUILD_COLOR	= 0x00002000,	//color changed
-		REBUILD_POSITION= 0x00004000,	//vertex positions/normals changed
+		EARLY_MOVE		= 0x00000004,
+		MOVE_UNDAMPED	= 0x00000008,
+		ON_MOVE_LIST	= 0x00000010,
+		UV				= 0x00000020,
+		UNLIT			= 0x00000040,
+		LIGHT			= 0x00000080,
+		REBUILD_VOLUME  = 0x00000100,	//volume changed LOD or parameters, or vertex buffer changed
+		REBUILD_TCOORD	= 0x00000200,	//texture coordinates changed
+		REBUILD_COLOR	= 0x00000400,	//color changed
+		REBUILD_POSITION= 0x00000800,	//vertex positions/normals changed
 		REBUILD_GEOMETRY= REBUILD_POSITION|REBUILD_TCOORD|REBUILD_COLOR,
 		REBUILD_MATERIAL= REBUILD_TCOORD|REBUILD_COLOR,
 		REBUILD_ALL		= REBUILD_GEOMETRY|REBUILD_VOLUME,
-		REBUILD_RIGGED	= 0x00008000,
-		ON_SHIFT_LIST	= 0x00010000,
-		BLOCKER			= 0x00020000,
-		ACTIVE			= 0x00040000,
-		DEAD			= 0x00080000,
-		INVISIBLE		= 0x00100000, // stay invisible until flag is cleared
- 		NEARBY_LIGHT	= 0x00200000, // In gPipeline.mNearbyLightSet
-		BUILT			= 0x00400000,
-		FORCE_INVISIBLE = 0x00800000, // stay invis until CLEAR_INVISIBLE is set (set of orphaned)
-		REBUILD_SHADOW =  0x02000000,
-		HAS_ALPHA		= 0x04000000,
-		RIGGED			= 0x08000000,
-		PARTITION_MOVE	= 0x10000000,
-		ANIMATED_CHILD  = 0x20000000,
-		ACTIVE_CHILD	= 0x40000000,
-		FOR_UNLOAD		= 0x80000000, //should be unload from memory
+		REBUILD_RIGGED	= 0x00001000,
+		ON_SHIFT_LIST	= 0x00002000,
+		ACTIVE			= 0x00004000,
+		DEAD			= 0x00008000,
+		INVISIBLE		= 0x00010000, // stay invisible until flag is cleared
+ 		NEARBY_LIGHT	= 0x00020000, // In gPipeline.mNearbyLightSet
+		BUILT			= 0x00040000,
+		FORCE_INVISIBLE = 0x00080000, // stay invis until CLEAR_INVISIBLE is set (set of orphaned)
+		HAS_ALPHA		= 0x00100000,
+		RIGGED			= 0x00200000, //has a rigged face
+        RIGGED_CHILD    = 0x00400000, //has a child with a rigged face
+		PARTITION_MOVE	= 0x00800000,
+		ANIMATED_CHILD  = 0x01000000,
+		ACTIVE_CHILD	= 0x02000000,
+		FOR_UNLOAD		= 0x04000000, //should be unload from memory
 	} EDrawableFlags;
 
 public:
diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp
index c802e62e40..1869370ac7 100644
--- a/indra/newview/llspatialpartition.cpp
+++ b/indra/newview/llspatialpartition.cpp
@@ -218,6 +218,7 @@ void LLSpatialGroup::validateDrawMap()
 
 BOOL LLSpatialGroup::updateInGroup(LLDrawable *drawablep, BOOL immediate)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	drawablep->updateSpatialExtents();
 
 	OctreeNode* parent = mOctreeNode->getOctParent();
@@ -853,6 +854,7 @@ LLSpatialPartition::~LLSpatialPartition()
 
 LLSpatialGroup *LLSpatialPartition::put(LLDrawable *drawablep, BOOL was_visible)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	drawablep->updateSpatialExtents();
 
 	//keep drawable from being garbage collected
@@ -878,6 +880,7 @@ LLSpatialGroup *LLSpatialPartition::put(LLDrawable *drawablep, BOOL was_visible)
 
 BOOL LLSpatialPartition::remove(LLDrawable *drawablep, LLSpatialGroup *curp)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	if (!curp->removeObject(drawablep))
 	{
 		OCT_ERRS << "Failed to remove drawable from octree!" << LL_ENDL;
@@ -894,6 +897,7 @@ BOOL LLSpatialPartition::remove(LLDrawable *drawablep, LLSpatialGroup *curp)
 
 void LLSpatialPartition::move(LLDrawable *drawablep, LLSpatialGroup *curp, BOOL immediate)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	// sanity check submitted by open source user bushing Spatula
 	// who was seeing crashing here. (See VWR-424 reported by Bunny Mayne)
 	if (!drawablep)
diff --git a/indra/newview/llviewerjointattachment.cpp b/indra/newview/llviewerjointattachment.cpp
index 8a597ed7e6..fd314ed3dc 100644
--- a/indra/newview/llviewerjointattachment.cpp
+++ b/indra/newview/llviewerjointattachment.cpp
@@ -121,8 +121,7 @@ void LLViewerJointAttachment::setupDrawable(LLViewerObject *object)
 	object->mDrawable->mXform.setRotation(current_rot);
 	gPipeline.markMoved(object->mDrawable);
 	gPipeline.markTextured(object->mDrawable); // face may need to change draw pool to/from POOL_HUD
-	object->mDrawable->setState(LLDrawable::USE_BACKLIGHT);
-	
+
 	if(mIsHUDAttachment)
 	{
 		for (S32 face_num = 0; face_num < object->mDrawable->getNumFaces(); face_num++)
@@ -142,7 +141,6 @@ void LLViewerJointAttachment::setupDrawable(LLViewerObject *object)
 		LLViewerObject* childp = *iter;
 		if (childp && childp->mDrawable.notNull())
 		{
-			childp->mDrawable->setState(LLDrawable::USE_BACKLIGHT);
 			gPipeline.markTextured(childp->mDrawable); // face may need to change draw pool to/from POOL_HUD
 			gPipeline.markMoved(childp->mDrawable);
 
@@ -256,7 +254,6 @@ void LLViewerJointAttachment::removeObject(LLViewerObject *object)
 		object->mDrawable->mXform.setRotation(cur_rotation);
 		gPipeline.markMoved(object->mDrawable, TRUE);
 		gPipeline.markTextured(object->mDrawable); // face may need to change draw pool to/from POOL_HUD
-		object->mDrawable->clearState(LLDrawable::USE_BACKLIGHT);
 
 		if (mIsHUDAttachment)
 		{
@@ -278,7 +275,6 @@ void LLViewerJointAttachment::removeObject(LLViewerObject *object)
 		LLViewerObject* childp = *iter;
 		if (childp && childp->mDrawable.notNull())
 		{
-			childp->mDrawable->clearState(LLDrawable::USE_BACKLIGHT);
 			gPipeline.markTextured(childp->mDrawable); // face may need to change draw pool to/from POOL_HUD
 			if (mIsHUDAttachment)
 			{
diff --git a/indra/newview/llvieweroctree.cpp b/indra/newview/llvieweroctree.cpp
index 8d6f4d2729..b5bf4f0354 100644
--- a/indra/newview/llvieweroctree.cpp
+++ b/indra/newview/llvieweroctree.cpp
@@ -516,6 +516,7 @@ bool LLViewerOctreeGroup::removeFromGroup(LLViewerOctreeEntry* entry)
 //virtual 
 void LLViewerOctreeGroup::unbound()
 {
+    LL_PROFILE_ZONE_SCOPED;
 	if (isDirty())
 	{
 		return;
diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp
index f8506f8981..c8c85d404d 100644
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -1430,7 +1430,7 @@ void LLVOAvatar::calculateSpatialExtents(LLVector4a& newMin, LLVector4a& newMax)
                             continue;
                         }
                         LLDrawable* drawable = attached_object->mDrawable;
-                        if (drawable && !drawable->isState(LLDrawable::RIGGED))
+                        if (drawable && !drawable->isState(LLDrawable::RIGGED | LLDrawable::RIGGED_CHILD)) // <-- don't extend bounding box if any rigged objects are present
                         {
                             LLSpatialBridge* bridge = drawable->getSpatialBridge();
                             if (bridge)
@@ -2777,6 +2777,14 @@ void LLVOAvatar::idleUpdateVoiceVisualizer(bool voice_enabled)
 	}//if ( voiceEnabled )
 }		
 
+static void override_bbox(LLDrawable* drawable, LLVector4a* extents)
+{
+    LL_PROFILE_ZONE_SCOPED;
+    drawable->setSpatialExtents(extents[0], extents[1]);
+    drawable->setPositionGroup(LLVector4a(0, 0, 0));
+    drawable->movePartition();
+}
+
 void LLVOAvatar::idleUpdateMisc(bool detailed_update)
 {
     LL_PROFILE_ZONE_SCOPED;
@@ -2810,21 +2818,34 @@ void LLVOAvatar::idleUpdateMisc(bool detailed_update)
 				
 				if (visibleAttachment && attached_object && !attached_object->isDead() && attachment->getValid())
 				{
-					// if selecting any attachments, update all of them as non-damped
-					if (LLSelectMgr::getInstance()->getSelection()->getObjectCount() && LLSelectMgr::getInstance()->getSelection()->isAttachment())
-					{
-						gPipeline.updateMoveNormalAsync(attached_object->mDrawable);
-					}
-					else
-					{
-						gPipeline.updateMoveDampedAsync(attached_object->mDrawable);
-					}
-					
-					LLSpatialBridge* bridge = attached_object->mDrawable->getSpatialBridge();
-					if (bridge)
-					{
-						gPipeline.updateMoveNormalAsync(bridge);
-					}
+
+                    //override rigged attachments' octree spatial extents with this avatar's bounding box
+                    LLSpatialBridge* bridge = attached_object->mDrawable->getSpatialBridge();
+                    bool rigged = false;
+                    if (bridge)
+                    {
+                        //transform avatar bounding box into attachment's coordinate frame
+                        LLVector4a extents[2];
+                        bridge->transformExtents(mDrawable->getSpatialExtents(), extents);
+
+                        if (attached_object->mDrawable->isState(LLDrawable::RIGGED | LLDrawable::RIGGED_CHILD))
+                        {
+                            rigged = true;
+                            override_bbox(attached_object->mDrawable, extents);
+                        }
+                    }
+
+                    
+                    attached_object->mDrawable->makeActive();
+                    attached_object->mDrawable->updateXform(TRUE);
+                    
+                    if (!rigged)
+                    {
+                        if (bridge)
+                        {
+                            gPipeline.updateMoveNormalAsync(bridge);
+                        }
+                    }
 					attached_object->updateText();	
 				}
 			}
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index d20bf3e871..c49ac895ca 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -1667,6 +1667,7 @@ void LLVOVolume::regenFaces()
 
 BOOL LLVOVolume::genBBoxes(BOOL force_global)
 {
+    LL_PROFILE_ZONE_SCOPED;
     BOOL res = TRUE;
 
     LLVector4a min, max;
@@ -1698,6 +1699,7 @@ BOOL LLVOVolume::genBBoxes(BOOL force_global)
     {
         LL_DEBUGS("RiggedBox") << "rebuilding box, volume face count " << getVolume()->getNumVolumeFaces() << " drawable face count " << mDrawable->getNumFaces() << LL_ENDL;
     }
+
     // There's no guarantee that getVolume()->getNumFaces() == mDrawable->getNumFaces()
     for (S32 i = 0;
         i < getVolume()->getNumVolumeFaces() && i < mDrawable->getNumFaces() && i < getNumTEs();
@@ -1739,11 +1741,22 @@ BOOL LLVOVolume::genBBoxes(BOOL force_global)
         }
     }
 
+    bool rigged = false;
+
+    if (!isAnimatedObject())
+    {
+        rigged = isRiggedMesh() && isAttachment();
+    }
+    else
+    {
+        rigged = isRiggedMesh() && getControlAvatar() && getControlAvatar()->mPlaying;
+    }
+
     if (any_valid_boxes)
     {
         if (rebuild)
         {
-            //get the Avatar associated with this object if there is one
+            //get the Avatar associated with this object if it's rigged
             LLVOAvatar* avatar = nullptr;
             if (isRiggedMesh())
             {
@@ -1764,30 +1777,21 @@ BOOL LLVOVolume::genBBoxes(BOOL force_global)
                 }
             }
 
-            LLSpatialBridge* bridge = mDrawable->getSpatialBridge();
-            if (avatar && bridge)
-            {
-                //use avatar bounding box for visibility culling
-                LLDrawable* ref = avatar->mDrawable;
-
-                LLVector4a extents[2];
+            mDrawable->setSpatialExtents(min, max);
 
-                bridge->transformExtents(ref->getSpatialExtents(), extents);
-                
-                mDrawable->setSpatialExtents(extents[0], extents[1]);
-                // don't switch octree node based on bounding box center to avoid breaking batches and rebuilding vertex buffers
-                mDrawable->setPositionGroup(LLVector4a(0, 0, 0, 0));
-                LL_DEBUGS("RiggedBox") << "rebuilding got extents " << extents[0] << ", " << extents[1] << LL_ENDL;
+            if (avatar)
+            {
+                // put all rigged drawables in the same octree node for better batching
+                mDrawable->setPositionGroup(LLVector4a(0, 0, 0));
             }
             else
             {
-                mDrawable->setSpatialExtents(min, max);
                 min.add(max);
                 min.mul(0.5f);
                 mDrawable->setPositionGroup(min);
             }
         }
-
+        
         updateRadius();
         mDrawable->movePartition();
     }
@@ -5844,6 +5848,11 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 				if (!drawablep->isState(LLDrawable::RIGGED))
 				{
 					drawablep->setState(LLDrawable::RIGGED);
+                    LLDrawable* root = drawablep->getRoot();
+                    if (root != drawablep)
+                    {
+                        root->setState(LLDrawable::RIGGED_CHILD);
+                    }
 
 					//first time this is drawable is being marked as rigged,
 					// do another LoD update to use avatar bounding box
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index 56fe4ac5af..d5f9772b85 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -1876,6 +1876,7 @@ void LLPipeline::resetFrameStats()
 //external functions for asynchronous updating
 void LLPipeline::updateMoveDampedAsync(LLDrawable* drawablep)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	if (FreezeTime)
 	{
 		return;
@@ -1906,6 +1907,7 @@ void LLPipeline::updateMoveDampedAsync(LLDrawable* drawablep)
 
 void LLPipeline::updateMoveNormalAsync(LLDrawable* drawablep)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	if (FreezeTime)
 	{
 		return;
@@ -1936,6 +1938,7 @@ void LLPipeline::updateMoveNormalAsync(LLDrawable* drawablep)
 
 void LLPipeline::updateMovedList(LLDrawable::drawable_vector_t& moved_list)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	for (LLDrawable::drawable_vector_t::iterator iter = moved_list.begin();
 		 iter != moved_list.end(); )
 	{
-- 
cgit v1.2.3


From c3aab3abe1f9871c1afa24dc8747ead6c64490e3 Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Thu, 13 Jan 2022 10:02:27 -0800
Subject: SL-16606: Add categories

---
 indra/llcommon/CMakeLists.txt         |   1 +
 indra/llcommon/llprofilercategories.h | 280 ++++++++++++++++++++++++++++++++++
 2 files changed, 281 insertions(+)
 create mode 100644 indra/llcommon/llprofilercategories.h

(limited to 'indra')

diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt
index 782f656406..ca8b5e946f 100644
--- a/indra/llcommon/CMakeLists.txt
+++ b/indra/llcommon/CMakeLists.txt
@@ -202,6 +202,7 @@ set(llcommon_HEADER_FILES
     llnametable.h
     llpointer.h
     llprofiler.h
+    llprofilercategories.h
     llpounceable.h
     llpredicate.h
     llpreprocessor.h
diff --git a/indra/llcommon/llprofilercategories.h b/indra/llcommon/llprofilercategories.h
new file mode 100644
index 0000000000..8db29468cc
--- /dev/null
+++ b/indra/llcommon/llprofilercategories.h
@@ -0,0 +1,280 @@
+/**
+ * @file llprofiler_ategories.h
+ * @brief Profiling categories to minimize Tracy memory usage when viewing captures.
+ *
+ * $LicenseInfo:firstyear=2022&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2022, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_PROFILER_CATEGORIES_H
+#define LL_PROFILER_CATEGORIES_H
+
+// A Tracy capture can quickly consume memory.  Use these defines to selectively turn on/off Tracy profiling for these categories.
+// The biggest memory usage ones are:
+//
+//    LL_PROFILER_CATEGORY_ENABLE_DRAWPOOL
+//    LL_PROFILER_CATEGORY_ENABLE_LLSD
+//    LL_PROFILER_CATEGORY_ENABLE_MEMORY
+//    LL_PROFILER_CATEGORY_ENABLE_SHADERS
+//
+// NOTE: You can still manually use:
+//     LL_PROFILE_ZONE_SCOPED();
+//     LL_PROFILE_ZONE_NAMED("name");
+// but just be aware that those will ALWAYS show up in a Tracy capture
+//  a) using more memory, and
+//  b) adding visual clutter.
+#define LL_PROFILER_CATEGORY_ENABLE_APP         1
+#define LL_PROFILER_CATEGORY_ENABLE_AVATAR      1
+#define LL_PROFILER_CATEGORY_ENABLE_DISPLAY     1
+#define LL_PROFILER_CATEGORY_ENABLE_DRAWABLE    1
+#define LL_PROFILER_CATEGORY_ENABLE_DRAWPOOL    1
+#define LL_PROFILER_CATEGORY_ENABLE_ENVIRONMENT 1
+#define LL_PROFILER_CATEGORY_ENABLE_FACE        1
+#define LL_PROFILER_CATEGORY_ENABLE_LLSD        1
+#define LL_PROFILER_CATEGORY_ENABLE_LOGGING     1
+#define LL_PROFILER_CATEGORY_ENABLE_MATERIAL    1
+#define LL_PROFILER_CATEGORY_ENABLE_MEDIA       1
+#define LL_PROFILER_CATEGORY_ENABLE_MEMORY      1
+#define LL_PROFILER_CATEGORY_ENABLE_NETWORK     1
+#define LL_PROFILER_CATEGORY_ENABLE_OCTREE      1
+#define LL_PROFILER_CATEGORY_ENABLE_PIPELINE    1
+#define LL_PROFILER_CATEGORY_ENABLE_SHADER      1
+#define LL_PROFILER_CATEGORY_ENABLE_SPATIAL     1
+#define LL_PROFILER_CATEGORY_ENABLE_STATS       1
+#define LL_PROFILER_CATEGORY_ENABLE_STRING      1
+#define LL_PROFILER_CATEGORY_ENABLE_TEXTURE     1
+#define LL_PROFILER_CATEGORY_ENABLE_THREAD      1
+#define LL_PROFILER_CATEGORY_ENABLE_UI          1
+#define LL_PROFILER_CATEGORY_ENABLE_VIEWER      1
+#define LL_PROFILER_CATEGORY_ENABLE_VERTEX      1
+#define LL_PROFILER_CATEGORY_ENABLE_VOLUME      1
+#define LL_PROFILER_CATEGORY_ENABLE_WIN32       1
+
+#if LL_PROFILER_CATEGORY_ENABLE_APP
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_APP  LL_PROFILE_ZONE_NAMED
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_APP LL_PROFILE_ZONE_SCOPED
+#else
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_APP(name)
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_APP
+#endif
+
+#if LL_PROFILER_CATEGORY_ENABLE_AVATAR
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_AVATAR  LL_PROFILE_ZONE_NAMED
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR LL_PROFILE_ZONE_SCOPED
+#else
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_AVATAR(name)
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR
+#endif
+
+#if LL_PROFILER_CATEGORY_ENABLE_DISPLAY
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY  LL_PROFILE_ZONE_NAMED
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_DISPLAY LL_PROFILE_ZONE_SCOPED
+#else
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY(name)
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_DISPLAY
+#endif
+
+#if LL_PROFILER_CATEGORY_ENABLE_DRAWABLE
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWABLE  LL_PROFILE_ZONE_NAMED
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE LL_PROFILE_ZONE_SCOPED
+#else
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWABLE(name)
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE
+#endif
+
+#if LL_PROFILER_CATEGORY_ENABLE_DRAWPOOL
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWPOOL  LL_PROFILE_ZONE_NAMED
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL LL_PROFILE_ZONE_SCOPED
+#else
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWPOOL(name)
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL
+#endif
+
+#if LL_PROFILER_CATEGORY_ENABLE_ENVIRONMENT
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_ENVIRONMENT  LL_PROFILE_ZONE_NAMED
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_ENVIRONMENT LL_PROFILE_ZONE_SCOPED
+#else
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_ENVIRONMENT(name)
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_ENVIRONMENT
+#endif
+
+#if LL_PROFILER_CATEGORY_ENABLE_FACE
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_FACE  LL_PROFILE_ZONE_NAMED
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_FACE LL_PROFILE_ZONE_SCOPED
+#else
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_FACE(name)
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_FACE
+#endif
+
+#if LL_PROFILER_CATEGORY_ENABLE_LLSD
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_LLSD  LL_PROFILE_ZONE_NAMED
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD LL_PROFILE_ZONE_SCOPED
+#else
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_LLSD(name)
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD
+#endif
+
+#if LL_PROFILER_CATEGORY_ENABLE_LOGGING
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_LOGGING  LL_PROFILE_ZONE_NAMED
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING LL_PROFILE_ZONE_SCOPED
+#else
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_LOGGING(name)
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING
+#endif
+
+#if LL_PROFILER_CATEGORY_ENABLE_MATERIAL
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_MATERIAL  LL_PROFILE_ZONE_NAMED
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_MATERIAL LL_PROFILE_ZONE_SCOPED
+#else
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_MATERIAL(name)
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_MATERIAL
+#endif
+
+#if LL_PROFILER_CATEGORY_ENABLE_MEDIA
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_MEDIA  LL_PROFILE_ZONE_NAMED
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_MEDIA LL_PROFILE_ZONE_SCOPED
+#else
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_MEDIA(name)
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_MEDIA
+#endif
+
+#if LL_PROFILER_CATEGORY_ENABLE_MEMORY
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_MEMORY  LL_PROFILE_ZONE_NAMED
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY LL_PROFILE_ZONE_SCOPED
+#else
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_MEMORY(name)
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY
+#endif
+
+#if LL_PROFILER_CATEGORY_ENABLE_NETWORK
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_NETWORK  LL_PROFILE_ZONE_NAMED
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK LL_PROFILE_ZONE_SCOPED
+#else
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_NETWORK(name)
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK
+#endif
+
+#if LL_PROFILER_CATEGORY_ENABLE_OCTREE
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_OCTREE  LL_PROFILE_ZONE_NAMED
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_OCTREE LL_PROFILE_ZONE_SCOPED
+#else
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_OCTREE(name)
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_OCTREE
+#endif
+
+#if LL_PROFILER_CATEGORY_ENABLE_PIPELINE
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE  LL_PROFILE_ZONE_NAMED
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE LL_PROFILE_ZONE_SCOPED
+#else
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE(name)
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE
+#endif
+
+#if LL_PROFILER_CATEGORY_ENABLE_SHADER
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_SHADER  LL_PROFILE_ZONE_NAMED
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER LL_PROFILE_ZONE_SCOPED
+#else
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_SHADER(name)
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER
+#endif
+
+#if LL_PROFILER_CATEGORY_ENABLE_SPATIAL
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_SPATIAL  LL_PROFILE_ZONE_NAMED
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_SPATIAL LL_PROFILE_ZONE_SCOPED
+#else
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_SPATIAL(name)
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_SPATIAL
+#endif
+
+#if LL_PROFILER_CATEGORY_ENABLE_STATS
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_STATS  LL_PROFILE_ZONE_NAMED
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS LL_PROFILE_ZONE_SCOPED
+#else
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_STATS(name)
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS
+#endif
+
+#if LL_PROFILER_CATEGORY_ENABLE_STRING
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_STRING  LL_PROFILE_ZONE_NAMED
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_STRING LL_PROFILE_ZONE_SCOPED
+#else
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_STRING(name)
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_STRING
+#endif
+
+#if LL_PROFILER_CATEGORY_ENABLE_TEXTURE
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE  LL_PROFILE_ZONE_NAMED
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE LL_PROFILE_ZONE_SCOPED
+#else
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE(name)
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE
+#endif
+
+#if LL_PROFILER_CATEGORY_ENABLE_THREAD
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_THREAD  LL_PROFILE_ZONE_NAMED
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD LL_PROFILE_ZONE_SCOPED
+#else
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_THREAD(name)
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
+#endif
+
+#if LL_PROFILER_CATEGORY_ENABLE_UI
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_UI  LL_PROFILE_ZONE_NAMED
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_UI LL_PROFILE_ZONE_SCOPED
+#else
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_UI(name)
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_UI
+#endif
+
+#if LL_PROFILER_CATEGORY_ENABLE_VERTEX
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX  LL_PROFILE_ZONE_NAMED
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX LL_PROFILE_ZONE_SCOPED
+#else
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX(name)
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX
+#endif
+
+#if LL_PROFILER_CATEGORY_ENABLE_VIEWER
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_VIEWER  LL_PROFILE_ZONE_NAMED
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_VIEWER LL_PROFILE_ZONE_SCOPED
+#else
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_VIEWER(name)
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_VIEWER
+#endif
+
+#if LL_PROFILER_CATEGORY_ENABLE_VOLUME
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_VOLUME  LL_PROFILE_ZONE_NAMED
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME LL_PROFILE_ZONE_SCOPED
+#else
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_VOLUME(name)
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME
+#endif
+
+#if LL_PROFILER_CATEGORY_ENABLE_WIN32
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32  LL_PROFILE_ZONE_NAMED
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_WIN32 LL_PROFILE_ZONE_SCOPED
+#else
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32(name)
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_WIN32
+#endif
+
+#endif // LL_PROFILER_CATEGORIES_H
+
-- 
cgit v1.2.3


From ca9a33a24bc2ff073240974a6bd0ffa5e9895b5d Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Thu, 13 Jan 2022 11:22:56 -0800
Subject: SL-16606: Include profiler categories automatically

---
 indra/llcommon/llprofiler.h | 40 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 40 insertions(+)

(limited to 'indra')

diff --git a/indra/llcommon/llprofiler.h b/indra/llcommon/llprofiler.h
index ca60d23248..f9d7ae7ce4 100644
--- a/indra/llcommon/llprofiler.h
+++ b/indra/llcommon/llprofiler.h
@@ -27,6 +27,44 @@
 #ifndef LL_PROFILER_H
 #define LL_PROFILER_H
 
+// If you use the default macros LL_PROFILE_ZONE_SCOPED and LL_PROFILE_ZONE_NAMED to profile code ...
+//
+//     void foo()
+//     {
+//         LL_PROFILE_ZONE_SCOPED;
+//         :
+//
+//         {
+//             LL_PROFILE_ZONE_NAMED("widget bar");
+//             :
+//         }
+//         {
+//             LL_PROFILE_ZONE_NAMED("widget qux");
+//             :
+//         }
+//     }
+//
+// ... please be aware that ALL these will show up in a Tracy capture which can quickly exhaust memory.
+// Instead, use LL_PROFILE_ZONE_SCOPED_CATEGORY_* and LL_PROFILE_ZONE_NAMED_CATEGORY_* to profile code ...
+//
+//     void foo()
+//     {
+//         LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
+//         :
+//
+//         {
+//             LL_PROFILE_ZONE_NAMED_CATEGORY_UI("widget bar");
+//             :
+//         }
+//         {
+//             LL_PROFILE_ZONE_NAMED_CATEGORY_UI("widget qux");
+//             :
+//         }
+//     }
+//
+// ... as these can be selectively turned on/off.  This will minimize memory usage and visual clutter in a Tracy capture.
+// See llprofiler_categories.h for more details on profiling categories.
+
 #define LL_PROFILER_CONFIG_NONE             0  // No profiling
 #define LL_PROFILER_CONFIG_FAST_TIMER       1  // Profiling on: Only Fast Timers
 #define LL_PROFILER_CONFIG_TRACY            2  // Profiling on: Only Tracy
@@ -108,4 +146,6 @@ extern thread_local bool gProfilerEnabled;
     #define LL_PROFILER_SET_THREAD_NAME( name ) (void)(name)
 #endif // LL_PROFILER
 
+#include "llprofilercategories.h"
+
 #endif // LL_PROFILER_H
-- 
cgit v1.2.3


From 1e5be6a43a225db43690834e0b7e983b200ba67e Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Thu, 13 Jan 2022 11:25:52 -0800
Subject: SL-16606: Add profiler category APP

---
 indra/newview/llappviewer.cpp | 53 +++++++++++++++++++++++--------------------
 1 file changed, 29 insertions(+), 24 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 89e0da3ea7..dc973e9154 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -1391,7 +1391,7 @@ bool LLAppViewer::doFrame()
 	LLSD newFrame;
 
 	{
-        LL_PROFILE_ZONE_NAMED("df LLTrace");
+        LL_PROFILE_ZONE_NAMED_CATEGORY_APP("df LLTrace");
         if (LLFloaterReg::instanceVisible("block_timers"))
         {
 	LLTrace::BlockTimer::processTimes();
@@ -1407,7 +1407,7 @@ bool LLAppViewer::doFrame()
 	LL_CLEAR_CALLSTACKS();
 
 	{
-		LL_PROFILE_ZONE_NAMED( "df processMiscNativeEvents" )
+		LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df processMiscNativeEvents" )
 		pingMainloopTimeout("Main:MiscNativeWindowEvents");
 
 		if (gViewerWindow)
@@ -1417,7 +1417,7 @@ bool LLAppViewer::doFrame()
 		}
 
 		{
-			LL_PROFILE_ZONE_NAMED( "df gatherInput" )
+			LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df gatherInput" )
 		pingMainloopTimeout("Main:GatherInput");
 		}
 
@@ -1444,20 +1444,20 @@ bool LLAppViewer::doFrame()
 		}
 
 		{
-			LL_PROFILE_ZONE_NAMED( "df mainloop" )
+			LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df mainloop" )
 		// canonical per-frame event
 		mainloop.post(newFrame);
 		}
 
 		{
-			LL_PROFILE_ZONE_NAMED( "df suspend" )
+			LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df suspend" )
 		// give listeners a chance to run
 		llcoro::suspend();
 		}
 
 		if (!LLApp::isExiting())
 		{
-			LL_PROFILE_ZONE_NAMED( "df JoystickKeyboard" )
+			LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df JoystickKeyboard" )
 			pingMainloopTimeout("Main:JoystickKeyboard");
 
 			// Scan keyboard for movement keys.  Command keys and typing
@@ -1479,17 +1479,19 @@ bool LLAppViewer::doFrame()
 			// Update state based on messages, user input, object idle.
 			{
 				{
-					LL_PROFILE_ZONE_NAMED( "df pauseMainloopTimeout" )
-				pauseMainloopTimeout(); // *TODO: Remove. Messages shouldn't be stalling for 20+ seconds!
+					LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df pauseMainloopTimeout" )
+					pauseMainloopTimeout(); // *TODO: Remove. Messages shouldn't be stalling for 20+ seconds!
 				}
 
-				LL_RECORD_BLOCK_TIME(FTM_IDLE);
-				idle();
+				{
+					LL_PROFILE_ZONE_NAMED_CATEGORY_APP("df idle"); //LL_RECORD_BLOCK_TIME(FTM_IDLE);
+					idle();
+				}
 
 				{
-					LL_PROFILE_ZONE_NAMED( "df resumeMainloopTimeout" )
-				resumeMainloopTimeout();
-			}
+					LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df resumeMainloopTimeout" )
+					resumeMainloopTimeout();
+				}
 			}
 
 			if (gDoDisconnect && (LLStartUp::getStartupState() == STATE_STARTED))
@@ -1510,14 +1512,14 @@ 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" )
+				LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df Display" )
 				pingMainloopTimeout("Main:Display");
 				gGLActive = TRUE;
 
 				display();
 
 				{
-					LL_PROFILE_ZONE_NAMED( "df Snapshot" )
+					LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df Snapshot" )
 				pingMainloopTimeout("Main:Snapshot");
 				LLFloaterSnapshot::update(); // take snapshots
 					LLFloaterOutfitSnapshot::update();
@@ -1527,7 +1529,7 @@ bool LLAppViewer::doFrame()
 		}
 
 		{
-			LL_PROFILE_ZONE_NAMED( "df pauseMainloopTimeout" )
+			LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df pauseMainloopTimeout" )
 		pingMainloopTimeout("Main:Sleep");
 
 		pauseMainloopTimeout();
@@ -1612,27 +1614,27 @@ bool LLAppViewer::doFrame()
 			}
 
 			{
-				LL_PROFILE_ZONE_NAMED( "df gMeshRepo" )
+				LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df gMeshRepo" )
 			gMeshRepo.update() ;
 			}
 
 			if(!total_work_pending) //pause texture fetching threads if nothing to process.
 			{
-				LL_PROFILE_ZONE_NAMED( "df getTextureCache" )
+				LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df getTextureCache" )
 				LLAppViewer::getTextureCache()->pause();
 				LLAppViewer::getImageDecodeThread()->pause();
 				LLAppViewer::getTextureFetch()->pause();
 			}
 			if(!total_io_pending) //pause file threads if nothing to process.
 			{
-				LL_PROFILE_ZONE_NAMED( "df LLVFSThread" )
+				LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df LLVFSThread" )
 				LLLFSThread::sLocal->pause();
 			}
 
 			//texture fetching debugger
 			if(LLTextureFetchDebugger::isEnabled())
 			{
-				LL_PROFILE_ZONE_NAMED( "df tex_fetch_debugger_instance" )
+				LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df tex_fetch_debugger_instance" )
 				LLFloaterTextureFetchDebugger* tex_fetch_debugger_instance =
 					LLFloaterReg::findTypedInstance<LLFloaterTextureFetchDebugger>("tex_fetch_debugger");
 				if(tex_fetch_debugger_instance)
@@ -1642,7 +1644,7 @@ bool LLAppViewer::doFrame()
 			}
 
 			{
-				LL_PROFILE_ZONE_NAMED( "df resumeMainloopTimeout" )
+				LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df resumeMainloopTimeout" )
 			resumeMainloopTimeout();
 			}
 			pingMainloopTimeout("Main:End");
@@ -4701,6 +4703,7 @@ static LLTrace::BlockTimerStatHandle FTM_HUD_EFFECTS("HUD Effects");
 ///////////////////////////////////////////////////////
 void LLAppViewer::idle()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_APP;
 	pingMainloopTimeout("Main:Idle");
 
 	// Update frame timers
@@ -5051,8 +5054,10 @@ void LLAppViewer::idle()
 	// Here, particles are updated and drawables are moved.
 	//
 
-	LL_RECORD_BLOCK_TIME(FTM_WORLD_UPDATE);
-	gPipeline.updateMove();
+	{
+		LL_PROFILE_ZONE_NAMED_CATEGORY_APP("world update"); //LL_RECORD_BLOCK_TIME(FTM_WORLD_UPDATE);
+		gPipeline.updateMove();
+	}
 
 	LLWorld::getInstance()->updateParticles();
 
@@ -5091,7 +5096,7 @@ void LLAppViewer::idle()
 	LLAvatarRenderInfoAccountant::getInstance()->idle();
 
 	{
-		LL_RECORD_BLOCK_TIME(FTM_AUDIO_UPDATE);
+		LL_PROFILE_ZONE_NAMED_CATEGORY_APP("audio update"); //LL_RECORD_BLOCK_TIME(FTM_AUDIO_UPDATE);
 
 		if (gAudiop)
 		{
-- 
cgit v1.2.3


From 6b05518a6b9eafecb2ee8605772207274e4b2c54 Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Thu, 13 Jan 2022 11:31:39 -0800
Subject: SL-16606: Add profiler category AVATAR

---
 indra/llcharacter/llcharacter.cpp          |  2 +-
 indra/llcharacter/llheadrotmotion.cpp      |  4 +-
 indra/llcharacter/llkeyframefallmotion.cpp |  2 +-
 indra/llcharacter/llmotioncontroller.cpp   | 14 +++----
 indra/newview/lldrawpoolavatar.cpp         | 64 +++++++++++++++---------------
 indra/newview/llmeshrepository.cpp         |  2 +-
 indra/newview/llphysicsmotion.cpp          |  2 +-
 indra/newview/llskinningutil.cpp           |  4 +-
 indra/newview/llvoavatar.cpp               | 34 ++++++++--------
 9 files changed, 64 insertions(+), 64 deletions(-)

(limited to 'indra')

diff --git a/indra/llcharacter/llcharacter.cpp b/indra/llcharacter/llcharacter.cpp
index 8874df32f5..376f096642 100644
--- a/indra/llcharacter/llcharacter.cpp
+++ b/indra/llcharacter/llcharacter.cpp
@@ -190,7 +190,7 @@ void LLCharacter::requestStopMotion( LLMotion* motion)
 //-----------------------------------------------------------------------------
 void LLCharacter::updateMotions(e_update_t update_type)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
 	if (update_type == HIDDEN_UPDATE)
 	{
 		mMotionController.updateMotionsMinimal();
diff --git a/indra/llcharacter/llheadrotmotion.cpp b/indra/llcharacter/llheadrotmotion.cpp
index fdf97266a3..07a3aaebb6 100644
--- a/indra/llcharacter/llheadrotmotion.cpp
+++ b/indra/llcharacter/llheadrotmotion.cpp
@@ -175,7 +175,7 @@ BOOL LLHeadRotMotion::onActivate()
 //-----------------------------------------------------------------------------
 BOOL LLHeadRotMotion::onUpdate(F32 time, U8* joint_mask)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
 	LLQuaternion	targetHeadRotWorld;
 	LLQuaternion	currentRootRotWorld = mRootJoint->getWorldRotation();
 	LLQuaternion	currentInvRootRotWorld = ~currentRootRotWorld;
@@ -459,7 +459,7 @@ void LLEyeMotion::adjustEyeTarget(LLVector3* targetPos, LLJointState& left_eye_s
 //-----------------------------------------------------------------------------
 BOOL LLEyeMotion::onUpdate(F32 time, U8* joint_mask)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
 	//calculate jitter
 	if (mEyeJitterTimer.getElapsedTimeF32() > mEyeJitterTime)
 	{
diff --git a/indra/llcharacter/llkeyframefallmotion.cpp b/indra/llcharacter/llkeyframefallmotion.cpp
index 9a41ba4d3d..e8bb2bf95d 100644
--- a/indra/llcharacter/llkeyframefallmotion.cpp
+++ b/indra/llcharacter/llkeyframefallmotion.cpp
@@ -121,7 +121,7 @@ BOOL LLKeyframeFallMotion::onActivate()
 //-----------------------------------------------------------------------------
 BOOL LLKeyframeFallMotion::onUpdate(F32 activeTime, U8* joint_mask)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
 	BOOL result = LLKeyframeMotion::onUpdate(activeTime, joint_mask);
 	F32  slerp_amt = clamp_rescale(activeTime / getDuration(), 0.5f, 0.75f, 0.f, 1.f);
 
diff --git a/indra/llcharacter/llmotioncontroller.cpp b/indra/llcharacter/llmotioncontroller.cpp
index d4546ce901..e66714388a 100644
--- a/indra/llcharacter/llmotioncontroller.cpp
+++ b/indra/llcharacter/llmotioncontroller.cpp
@@ -503,7 +503,7 @@ void LLMotionController::resetJointSignatures()
 //-----------------------------------------------------------------------------
 void LLMotionController::updateIdleMotion(LLMotion* motionp)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
 	if (motionp->isStopped() && mAnimTime > motionp->getStopTime() + motionp->getEaseOutDuration())
 	{
 		deactivateMotionInstance(motionp);
@@ -542,7 +542,7 @@ void LLMotionController::updateIdleMotion(LLMotion* motionp)
 //-----------------------------------------------------------------------------
 void LLMotionController::updateIdleActiveMotions()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
 	for (motion_list_t::iterator iter = mActiveMotions.begin();
 		 iter != mActiveMotions.end(); )
 	{
@@ -557,7 +557,7 @@ void LLMotionController::updateIdleActiveMotions()
 //-----------------------------------------------------------------------------
 void LLMotionController::updateMotionsByType(LLMotion::LLMotionBlendType anim_type)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
 	BOOL update_result = TRUE;
 	U8 last_joint_signature[LL_CHARACTER_MAX_ANIMATED_JOINTS];
 
@@ -768,7 +768,7 @@ void LLMotionController::updateMotionsByType(LLMotion::LLMotionBlendType anim_ty
 //-----------------------------------------------------------------------------
 void LLMotionController::updateLoadingMotions()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
 	// query pending motions for completion
 	for (motion_set_t::iterator iter = mLoadingMotions.begin();
 		 iter != mLoadingMotions.end(); )
@@ -816,7 +816,7 @@ void LLMotionController::updateLoadingMotions()
 //-----------------------------------------------------------------------------
 void LLMotionController::updateMotions(bool force_update)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
     // SL-763: "Distant animated objects run at super fast speed"
     // The use_quantum optimization or possibly the associated code in setTimeStamp()
     // does not work as implemented.
@@ -909,7 +909,7 @@ void LLMotionController::updateMotions(bool force_update)
 //-----------------------------------------------------------------------------
 void LLMotionController::updateMotionsMinimal()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
 	// Always update mPrevTimerElapsed
 	mPrevTimerElapsed = mTimer.getElapsedTimeF32();
 
@@ -927,7 +927,7 @@ void LLMotionController::updateMotionsMinimal()
 //-----------------------------------------------------------------------------
 BOOL LLMotionController::activateMotionInstance(LLMotion *motion, F32 time)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
 	// It's not clear why the getWeight() line seems to be crashing this, but
 	// hopefully this fixes it.
 	if (motion == NULL || motion->getPose() == NULL)
diff --git a/indra/newview/lldrawpoolavatar.cpp b/indra/newview/lldrawpoolavatar.cpp
index e1e57ef319..4a9a3caaec 100644
--- a/indra/newview/lldrawpoolavatar.cpp
+++ b/indra/newview/lldrawpoolavatar.cpp
@@ -119,7 +119,7 @@ LLDrawPoolAvatar::~LLDrawPoolAvatar()
 // virtual
 BOOL LLDrawPoolAvatar::isDead()
 {
-    LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR
 
     if (!LLFacePool::isDead())
     {
@@ -131,14 +131,14 @@ BOOL LLDrawPoolAvatar::isDead()
 
 S32 LLDrawPoolAvatar::getShaderLevel() const
 {
-    LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR
 
 	return (S32) LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_AVATAR);
 }
 
 void LLDrawPoolAvatar::prerender()
 {
-    LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR
 
 	mShaderLevel = LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_AVATAR);
 	
@@ -156,7 +156,7 @@ void LLDrawPoolAvatar::prerender()
 
 LLMatrix4& LLDrawPoolAvatar::getModelView()
 {
-    LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR
 
 	static LLMatrix4 ret;
 
@@ -176,7 +176,7 @@ LLMatrix4& LLDrawPoolAvatar::getModelView()
 
 void LLDrawPoolAvatar::beginDeferredPass(S32 pass)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
 	
 	sSkipTransparent = TRUE;
 	is_deferred_render = true;
@@ -202,7 +202,7 @@ void LLDrawPoolAvatar::beginDeferredPass(S32 pass)
 
 void LLDrawPoolAvatar::endDeferredPass(S32 pass)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
 
 	sSkipTransparent = FALSE;
 	is_deferred_render = false;
@@ -228,7 +228,7 @@ void LLDrawPoolAvatar::endDeferredPass(S32 pass)
 
 void LLDrawPoolAvatar::renderDeferred(S32 pass)
 {
-    LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR
 
 	render(pass);
 }
@@ -240,7 +240,7 @@ S32 LLDrawPoolAvatar::getNumPostDeferredPasses()
 
 void LLDrawPoolAvatar::beginPostDeferredPass(S32 pass)
 {
-    LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR
 
 	sSkipOpaque = TRUE;
 	sShaderLevel = mShaderLevel;
@@ -256,7 +256,7 @@ void LLDrawPoolAvatar::beginPostDeferredPass(S32 pass)
 
 void LLDrawPoolAvatar::endPostDeferredPass(S32 pass)
 {
-    LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR
 	// if we're in software-blending, remember to set the fence _after_ we draw so we wait till this rendering is done
 	sRenderingSkinned = FALSE;
 	sSkipOpaque = FALSE;
@@ -268,7 +268,7 @@ void LLDrawPoolAvatar::endPostDeferredPass(S32 pass)
 
 void LLDrawPoolAvatar::renderPostDeferred(S32 pass)
 {
-    LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR
 
     is_post_deferred_render = true;
 	if (LLPipeline::sImpostorRender)
@@ -291,7 +291,7 @@ S32 LLDrawPoolAvatar::getNumShadowPasses()
 
 void LLDrawPoolAvatar::beginShadowPass(S32 pass)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
 
 	if (pass == SHADOW_PASS_AVATAR_OPAQUE)
 	{
@@ -349,7 +349,7 @@ void LLDrawPoolAvatar::beginShadowPass(S32 pass)
 
 void LLDrawPoolAvatar::endShadowPass(S32 pass)
 {
-	LL_PROFILE_ZONE_SCOPED;
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
 
     if (sShaderLevel > 0)
 	{			
@@ -362,7 +362,7 @@ void LLDrawPoolAvatar::endShadowPass(S32 pass)
 
 void LLDrawPoolAvatar::renderShadow(S32 pass)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
 
 	if (mDrawFace.empty())
 	{
@@ -424,7 +424,7 @@ S32 LLDrawPoolAvatar::getNumDeferredPasses()
 
 void LLDrawPoolAvatar::render(S32 pass)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
 	if (LLPipeline::sImpostorRender)
 	{
 		renderAvatars(NULL, pass+2);
@@ -436,7 +436,7 @@ void LLDrawPoolAvatar::render(S32 pass)
 
 void LLDrawPoolAvatar::beginRenderPass(S32 pass)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
 	//reset vertex buffer mappings
 	LLVertexBuffer::unbind();
 
@@ -466,7 +466,7 @@ void LLDrawPoolAvatar::beginRenderPass(S32 pass)
 
 void LLDrawPoolAvatar::endRenderPass(S32 pass)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
 
 	if (LLPipeline::sImpostorRender)
 	{
@@ -489,7 +489,7 @@ void LLDrawPoolAvatar::endRenderPass(S32 pass)
 
 void LLDrawPoolAvatar::beginImpostor()
 {
-    LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR
 
 	if (!LLPipeline::sReflectionRender)
 	{
@@ -506,7 +506,7 @@ void LLDrawPoolAvatar::beginImpostor()
 
 void LLDrawPoolAvatar::endImpostor()
 {
-    LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR
 
 		gImpostorProgram.unbind();
 	gPipeline.enableLightsDynamic();
@@ -514,7 +514,7 @@ void LLDrawPoolAvatar::endImpostor()
 
 void LLDrawPoolAvatar::beginRigid()
 {
-    LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR
 
 	if (gPipeline.shadersLoaded())
 	{
@@ -549,7 +549,7 @@ void LLDrawPoolAvatar::beginRigid()
 
 void LLDrawPoolAvatar::endRigid()
 {
-    LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR
 
 	sShaderLevel = mShaderLevel;
 	if (sVertexProgram != NULL)
@@ -560,7 +560,7 @@ void LLDrawPoolAvatar::endRigid()
 
 void LLDrawPoolAvatar::beginDeferredImpostor()
 {
-    LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR
 
 	if (!LLPipeline::sReflectionRender)
 	{
@@ -578,7 +578,7 @@ void LLDrawPoolAvatar::beginDeferredImpostor()
 
 void LLDrawPoolAvatar::endDeferredImpostor()
 {
-    LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR
 
 	sShaderLevel = mShaderLevel;
 	sVertexProgram->disableTexture(LLViewerShaderMgr::DEFERRED_NORMAL);
@@ -591,7 +591,7 @@ void LLDrawPoolAvatar::endDeferredImpostor()
 
 void LLDrawPoolAvatar::beginDeferredRigid()
 {
-    LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR
 
 	sVertexProgram = &gDeferredNonIndexedDiffuseAlphaMaskNoColorProgram;
 	sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
@@ -609,7 +609,7 @@ void LLDrawPoolAvatar::beginDeferredRigid()
 
 void LLDrawPoolAvatar::endDeferredRigid()
 {
-    LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR
 
 	sShaderLevel = mShaderLevel;
 	sVertexProgram->disableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
@@ -620,7 +620,7 @@ void LLDrawPoolAvatar::endDeferredRigid()
 
 void LLDrawPoolAvatar::beginSkinned()
 {
-    LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR
 
 	if (sShaderLevel > 0)
 	{
@@ -685,7 +685,7 @@ void LLDrawPoolAvatar::beginSkinned()
 
 void LLDrawPoolAvatar::endSkinned()
 {
-    LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR
 
 	// if we're in software-blending, remember to set the fence _after_ we draw so we wait till this rendering is done
 	if (sShaderLevel > 0)
@@ -711,7 +711,7 @@ void LLDrawPoolAvatar::endSkinned()
 
 void LLDrawPoolAvatar::beginDeferredSkinned()
 {
-    LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR
 
 	sShaderLevel = mShaderLevel;
 	sVertexProgram = &gDeferredAvatarProgram;
@@ -734,7 +734,7 @@ void LLDrawPoolAvatar::beginDeferredSkinned()
 
 void LLDrawPoolAvatar::endDeferredSkinned()
 {
-    LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR
 
 	// if we're in software-blending, remember to set the fence _after_ we draw so we wait till this rendering is done
 	sRenderingSkinned = FALSE;
@@ -749,6 +749,8 @@ void LLDrawPoolAvatar::endDeferredSkinned()
 
 void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR; //LL_RECORD_BLOCK_TIME(FTM_RENDER_CHARACTERS);
+
 	if (pass == -1)
 	{
 		for (S32 i = 1; i < getNumPasses(); i++)
@@ -788,8 +790,6 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass)
 		return;
 	}
 
-    LL_RECORD_BLOCK_TIME(FTM_RENDER_CHARACTERS);
-
 	if (!single_avatar && !avatarp->isFullyLoaded() )
 	{
 		if (pass==0 && (!gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_PARTICLES) || LLViewerPartSim::getMaxPartCount() <= 0))
@@ -908,7 +908,7 @@ static LLTrace::BlockTimerStatHandle FTM_RIGGED_VBO("Rigged VBO");
 //-----------------------------------------------------------------------------
 LLViewerTexture *LLDrawPoolAvatar::getDebugTexture()
 {
-    LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR
 
 	if (mReferences.empty())
 	{
@@ -936,7 +936,7 @@ LLVertexBufferAvatar::LLVertexBufferAvatar()
 : LLVertexBuffer(sDataMask, 
 	GL_STREAM_DRAW_ARB) //avatars are always stream draw due to morph targets
 {
-    LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR
 }
 
 
diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp
index 61418ba547..8cec08394d 100644
--- a/indra/newview/llmeshrepository.cpp
+++ b/indra/newview/llmeshrepository.cpp
@@ -4070,7 +4070,7 @@ S32 LLMeshRepository::getActualMeshLOD(const LLVolumeParams& mesh_params, S32 lo
 
 const LLMeshSkinInfo* LLMeshRepository::getSkinInfo(const LLUUID& mesh_id, const LLVOVolume* requesting_obj)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
     if (mesh_id.notNull())
     {
         skin_map::iterator iter = mSkinMap.find(mesh_id);
diff --git a/indra/newview/llphysicsmotion.cpp b/indra/newview/llphysicsmotion.cpp
index 30ca7ae539..03a02ba26f 100644
--- a/indra/newview/llphysicsmotion.cpp
+++ b/indra/newview/llphysicsmotion.cpp
@@ -453,7 +453,7 @@ F32 LLPhysicsMotion::calculateAcceleration_local(const F32 velocity_local, const
 
 BOOL LLPhysicsMotionController::onUpdate(F32 time, U8* joint_mask)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
         // Skip if disabled globally.
         if (!gSavedSettings.getBOOL("AvatarPhysics"))
         {
diff --git a/indra/newview/llskinningutil.cpp b/indra/newview/llskinningutil.cpp
index dc12de29fb..cf3519c1c7 100644
--- a/indra/newview/llskinningutil.cpp
+++ b/indra/newview/llskinningutil.cpp
@@ -125,7 +125,7 @@ void LLSkinningUtil::initSkinningMatrixPalette(
     const LLMeshSkinInfo* skin,
     LLVOAvatar *avatar)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
 
     initJointNums(const_cast<LLMeshSkinInfo*>(skin), avatar);
 
@@ -270,7 +270,7 @@ void LLSkinningUtil::initJointNums(LLMeshSkinInfo* skin, LLVOAvatar *avatar)
 {
     if (!skin->mJointNumsInitialized)
     {
-        LL_PROFILE_ZONE_SCOPED;
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
         for (U32 j = 0; j < skin->mJointNames.size(); ++j)
         {
     #if DEBUG_SKINNING     
diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp
index f8506f8981..d1074b3d3c 100644
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -332,7 +332,7 @@ public:
 	// must return FALSE when the motion is completed.
 	virtual BOOL onUpdate(F32 time, U8* joint_mask)
 	{
-        LL_PROFILE_ZONE_SCOPED;
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
 		F32 nx[2];
 		nx[0]=time*TORSO_NOISE_SPEED;
 		nx[1]=0.0f;
@@ -453,7 +453,7 @@ public:
 	// must return FALSE when the motion is completed.
 	virtual BOOL onUpdate(F32 time, U8* joint_mask)
 	{
-        LL_PROFILE_ZONE_SCOPED;
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
 		mBreatheRate = 1.f;
 
 		F32 breathe_amt = (sinf(mBreatheRate * time) * BREATHE_ROT_MOTION_STRENGTH);
@@ -555,7 +555,7 @@ public:
 	// must return FALSE when the motion is completed.
 	virtual BOOL onUpdate(F32 time, U8* joint_mask)
 	{
-        LL_PROFILE_ZONE_SCOPED;
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
 		mPelvisState->setPosition(LLVector3::zero);
 
 		return TRUE;
@@ -1327,7 +1327,7 @@ void LLVOAvatar::updateSpatialExtents(LLVector4a& newMin, LLVector4a &newMax)
 
 void LLVOAvatar::calculateSpatialExtents(LLVector4a& newMin, LLVector4a& newMax)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
 
     S32 box_detail = gSavedSettings.getS32("AvatarBoundingBoxComplexity");
     if (getOverallAppearance() != AOA_NORMAL)
@@ -2528,7 +2528,7 @@ void LLVOAvatar::dumpAnimationState()
 //------------------------------------------------------------------------
 void LLVOAvatar::idleUpdate(LLAgent &agent, const F64 &time)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
 
 	if (isDead())
 	{
@@ -2779,7 +2779,7 @@ void LLVOAvatar::idleUpdateVoiceVisualizer(bool voice_enabled)
 
 void LLVOAvatar::idleUpdateMisc(bool detailed_update)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
 	if (LLVOAvatar::sJointDebug)
 	{
 		LL_INFOS() << getFullname() << ": joint touches: " << LLJoint::sNumTouches << " updates: " << LLJoint::sNumUpdates << LL_ENDL;
@@ -3132,7 +3132,7 @@ void LLVOAvatar::idleUpdateWindEffect()
 
 void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
 
 	// update chat bubble
 	//--------------------------------------------------------------------
@@ -4882,7 +4882,7 @@ bool LLVOAvatar::shouldAlphaMask()
 //-----------------------------------------------------------------------------
 U32 LLVOAvatar::renderSkinned()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
 
 	U32 num_indices = 0;
 
@@ -7099,7 +7099,7 @@ void LLVOAvatar::updateGL()
 {
 	if (mMeshTexturesDirty)
 	{
-		LL_PROFILE_ZONE_SCOPED
+		LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR
 		updateMeshTextures();
 		mMeshTexturesDirty = FALSE;
 	}
@@ -7110,7 +7110,7 @@ void LLVOAvatar::updateGL()
 //-----------------------------------------------------------------------------
 BOOL LLVOAvatar::updateGeometry(LLDrawable *drawable)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
 	if (!(gPipeline.hasRenderType(mIsControlAvatar ? LLPipeline::RENDER_TYPE_CONTROL_AV : LLPipeline::RENDER_TYPE_AVATAR)))
 	{
 		return TRUE;
@@ -7844,7 +7844,7 @@ void LLVOAvatar::onGlobalColorChanged(const LLTexGlobalColor* global_color)
 // Do rigged mesh attachments display with this av?
 bool LLVOAvatar::shouldRenderRigged() const
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
 
 	if (getOverallAppearance() == AOA_NORMAL)
 	{
@@ -8356,7 +8356,7 @@ void LLVOAvatar::updateMeshVisibility()
 // virtual
 void LLVOAvatar::updateMeshTextures()
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR
 	static S32 update_counter = 0;
 	mBakedTextureDebugText.clear();
 	
@@ -9432,7 +9432,7 @@ const LLVOAvatar::MatrixPaletteCache& LLVOAvatar::updateSkinInfoMatrixPalette(co
 
     if (entry.mFrame != gFrameCount)
     {
-        LL_PROFILE_ZONE_SCOPED;
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
 
         entry.mFrame = gFrameCount;
 
@@ -10236,7 +10236,7 @@ void showRigInfoTabExtents(LLVOAvatar *avatar, LLJointRiggingInfoTab& tab, S32&
 
 void LLVOAvatar::getAssociatedVolumes(std::vector<LLVOVolume*>& volumes)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
 	for ( LLVOAvatar::attachment_map_t::iterator iter = mAttachmentPoints.begin(); iter != mAttachmentPoints.end(); ++iter )
 	{
 		LLViewerJointAttachment* attachment = iter->second;
@@ -10297,7 +10297,7 @@ void LLVOAvatar::getAssociatedVolumes(std::vector<LLVOVolume*>& volumes)
 // virtual
 void LLVOAvatar::updateRiggingInfo()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
 
     LL_DEBUGS("RigSpammish") << getFullname() << " updating rig tab" << LL_ENDL;
 
@@ -10468,7 +10468,7 @@ void LLVOAvatar::updateImpostorRendering(U32 newMaxNonImpostorsValue)
 
 void LLVOAvatar::idleUpdateRenderComplexity()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
     if (isControlAvatar())
     {
         LLControlAvatar *cav = dynamic_cast<LLControlAvatar*>(this);
@@ -10996,7 +10996,7 @@ void LLVOAvatar::updateOverallAppearanceAnimations()
 // Based on isVisuallyMuted(), but has 3 possible results.
 LLVOAvatar::AvatarOverallAppearance LLVOAvatar::getOverallAppearance() const
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
 	AvatarOverallAppearance result = AOA_NORMAL;
 
 	// Priority order (highest priority first)
-- 
cgit v1.2.3


From f787c7455dc6310729c1f76978589b55e687c5b5 Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Thu, 13 Jan 2022 11:35:00 -0800
Subject: SL-16606: Add profiler category DISPLAY

---
 indra/newview/llviewerdisplay.cpp | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp
index c84a8c70fa..f28edd10c5 100644
--- a/indra/newview/llviewerdisplay.cpp
+++ b/indra/newview/llviewerdisplay.cpp
@@ -211,7 +211,7 @@ void display_stats()
 	F32 fps_log_freq = gSavedSettings.getF32("FPSLogFrequency");
 	if (fps_log_freq > 0.f && gRecentFPSTime.getElapsedTimeF32() >= fps_log_freq)
 	{
-		LL_PROFILE_ZONE_NAMED("DS - FPS");
+		LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("DS - FPS");
 		F32 fps = gRecentFrameCount / fps_log_freq;
 		LL_INFOS() << llformat("FPS: %.02f", fps) << LL_ENDL;
 		gRecentFrameCount = 0;
@@ -220,7 +220,7 @@ void display_stats()
 	F32 mem_log_freq = gSavedSettings.getF32("MemoryLogFrequency");
 	if (mem_log_freq > 0.f && gRecentMemoryTime.getElapsedTimeF32() >= mem_log_freq)
 	{
-		LL_PROFILE_ZONE_NAMED("DS - Memory");
+		LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("DS - Memory");
 		gMemoryAllocated = U64Bytes(LLMemory::getCurrentRSS());
 		U32Megabytes memory = gMemoryAllocated;
 		LL_INFOS() << "MEMORY: " << memory << LL_ENDL;
@@ -230,7 +230,7 @@ void display_stats()
     F32 asset_storage_log_freq = gSavedSettings.getF32("AssetStorageLogFrequency");
     if (asset_storage_log_freq > 0.f && gAssetStorageLogTime.getElapsedTimeF32() >= asset_storage_log_freq)
     {
-		LL_PROFILE_ZONE_NAMED("DS - Asset Storage");
+		LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("DS - Asset Storage");
         gAssetStorageLogTime.reset();
         gAssetStorage->logAssetStorageInfo();
     }
@@ -637,7 +637,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 	
 	if (!gDisconnected)
 	{
-		LL_PROFILE_ZONE_NAMED("display - 1");
+		LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("display - 1");
 		LLAppViewer::instance()->pingMainloopTimeout("Display:Update");
 		if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD))
 		{ //don't draw hud objects in this frame
@@ -713,7 +713,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 		LLAppViewer::instance()->pingMainloopTimeout("Display:Swap");
 		
 		{ 
-			LL_PROFILE_ZONE_NAMED("display - 2")
+			LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("display - 2")
 			if (gResizeScreenTexture)
 			{
 				gResizeScreenTexture = FALSE;
@@ -765,7 +765,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 
 		//if (!for_snapshot)
 		{
-			LL_PROFILE_ZONE_NAMED("display - 3")
+			LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("display - 3")
 			LLAppViewer::instance()->pingMainloopTimeout("Display:Imagery");
 			gPipeline.generateWaterReflection(*LLViewerCamera::getInstance());
 			gPipeline.generateHighlight(*LLViewerCamera::getInstance());
@@ -823,7 +823,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 		//
 		LLAppViewer::instance()->pingMainloopTimeout("Display:StateSort");
 		{
-			LL_PROFILE_ZONE_NAMED("display - 3")
+			LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("display - 4")
 			LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD;
 			gPipeline.stateSort(*LLViewerCamera::getInstance(), result);
 			stop_glerror();
@@ -930,7 +930,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")
+			LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("display - 5")
 			LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD;
 
 			if (gSavedSettings.getBOOL("RenderDepthPrePass"))
-- 
cgit v1.2.3


From fd6203f12a48c8108dcbab55f67fdb3f9700bfc6 Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Thu, 13 Jan 2022 11:37:38 -0800
Subject: SL-16606: Add profiler category DRAWABLE

---
 indra/newview/lldrawable.cpp         | 46 ++++++++++++++++++------------------
 indra/newview/llviewerobjectlist.cpp |  6 ++---
 indra/newview/llvosky.cpp            |  2 +-
 indra/newview/pipeline.cpp           |  2 +-
 4 files changed, 28 insertions(+), 28 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/lldrawable.cpp b/indra/newview/lldrawable.cpp
index 7c3c230cff..6773969e65 100644
--- a/indra/newview/lldrawable.cpp
+++ b/indra/newview/lldrawable.cpp
@@ -98,7 +98,7 @@ LLDrawable::LLDrawable(LLViewerObject *vobj, bool new_entry)
 
 void LLDrawable::init(bool new_entry)
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE
 
 	// mXform
 	mParent = NULL;
@@ -247,7 +247,7 @@ BOOL LLDrawable::isLight() const
 
 void LLDrawable::cleanupReferences()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE;
 	
 	
 	std::for_each(mFaces.begin(), mFaces.end(), DeletePointer());
@@ -308,7 +308,7 @@ S32 LLDrawable::findReferences(LLDrawable *drawablep)
 
 LLFace*	LLDrawable::addFace(LLFacePool *poolp, LLViewerTexture *texturep)
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE
 	
 	LLFace *face;
 	{
@@ -336,7 +336,7 @@ LLFace*	LLDrawable::addFace(LLFacePool *poolp, LLViewerTexture *texturep)
 
 LLFace*	LLDrawable::addFace(const LLTextureEntry *te, LLViewerTexture *texturep)
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE
 
 	LLFace *face;
 
@@ -359,7 +359,7 @@ LLFace*	LLDrawable::addFace(const LLTextureEntry *te, LLViewerTexture *texturep)
 
 LLFace*	LLDrawable::addFace(const LLTextureEntry *te, LLViewerTexture *texturep, LLViewerTexture *normalp)
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE
 
 	LLFace *face;
 	face = new LLFace(this, mVObjp);
@@ -382,7 +382,7 @@ LLFace*	LLDrawable::addFace(const LLTextureEntry *te, LLViewerTexture *texturep,
 
 LLFace*	LLDrawable::addFace(const LLTextureEntry *te, LLViewerTexture *texturep, LLViewerTexture *normalp, LLViewerTexture *specularp)
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE
 
 	LLFace *face;
 	face = new LLFace(this, mVObjp);
@@ -406,7 +406,7 @@ LLFace*	LLDrawable::addFace(const LLTextureEntry *te, LLViewerTexture *texturep,
 
 void LLDrawable::setNumFaces(const S32 newFaces, LLFacePool *poolp, LLViewerTexture *texturep)
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE
 
 	if (newFaces == (S32)mFaces.size())
 	{
@@ -431,7 +431,7 @@ void LLDrawable::setNumFaces(const S32 newFaces, LLFacePool *poolp, LLViewerText
 
 void LLDrawable::setNumFacesFast(const S32 newFaces, LLFacePool *poolp, LLViewerTexture *texturep)
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE
 
 	if (newFaces <= (S32)mFaces.size() && newFaces >= (S32)mFaces.size()/2)
 	{
@@ -456,7 +456,7 @@ void LLDrawable::setNumFacesFast(const S32 newFaces, LLFacePool *poolp, LLViewer
 
 void LLDrawable::mergeFaces(LLDrawable* src)
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE
 
 	U32 face_count = mFaces.size() + src->mFaces.size();
 
@@ -491,7 +491,7 @@ void LLDrawable::updateMaterial()
 
 void LLDrawable::makeActive()
 {		
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE
 
 #if !LL_RELEASE_FOR_DOWNLOAD
 	if (mVObjp.notNull())
@@ -556,7 +556,7 @@ void LLDrawable::makeActive()
 
 void LLDrawable::makeStatic(BOOL warning_enabled)
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE
 
 	if (isState(ACTIVE) && 
 		!isState(ACTIVE_CHILD) && 
@@ -604,7 +604,7 @@ void LLDrawable::makeStatic(BOOL warning_enabled)
 // Returns "distance" between target destination and resulting xfrom
 F32 LLDrawable::updateXform(BOOL undamped)
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE
 
 	BOOL damped = !undamped;
 
@@ -757,7 +757,7 @@ void LLDrawable::moveUpdatePipeline(BOOL moved)
 
 void LLDrawable::movePartition()
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE
 
 	LLSpatialPartition* part = getSpatialPartition();
 	if (part)
@@ -803,7 +803,7 @@ BOOL LLDrawable::updateMoveUndamped()
 
 void LLDrawable::updatePartition()
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE
 
 	if (!getVOVolume())
 	{
@@ -822,7 +822,7 @@ void LLDrawable::updatePartition()
 
 BOOL LLDrawable::updateMoveDamped()
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE
 
 	F32 dist_squared = updateXform(FALSE);
 
@@ -847,7 +847,7 @@ BOOL LLDrawable::updateMoveDamped()
 
 void LLDrawable::updateDistance(LLCamera& camera, bool force_update)
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE
 
 	if (LLViewerCamera::sCurCameraID != LLViewerCamera::CAMERA_WORLD)
 	{
@@ -953,7 +953,7 @@ void LLDrawable::updateTexture()
 
 BOOL LLDrawable::updateGeometry(BOOL priority)
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE
 
 	llassert(mVObjp.notNull());
 	BOOL res = mVObjp->updateGeometry(this);
@@ -1032,7 +1032,7 @@ const LLVector3& LLDrawable::getBounds(LLVector3& min, LLVector3& max) const
 
 void LLDrawable::updateSpatialExtents()
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE
 
 	if (mVObjp)
 	{
@@ -1168,7 +1168,7 @@ void LLDrawable::setGroup(LLViewerOctreeGroup *groupp)
 */
 LLSpatialPartition* LLDrawable::getSpatialPartition()
 { 
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE
 
 	LLSpatialPartition* retval = NULL;
 
@@ -1257,7 +1257,7 @@ 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
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE
 
 	mBridge = this;
 	mDrawable = root;
@@ -1304,7 +1304,7 @@ void LLSpatialBridge::destroyTree()
 
 void LLSpatialBridge::updateSpatialExtents()
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE
 
 	LLSpatialGroup* root = (LLSpatialGroup*) mOctree->getListener(0);
 	
@@ -1477,7 +1477,7 @@ public:
 
 void LLSpatialBridge::setVisible(LLCamera& camera_in, std::vector<LLDrawable*>* results, BOOL for_select)
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE
 
 	if (!gPipeline.hasRenderType(mDrawableType))
 	{
@@ -1576,7 +1576,7 @@ void LLSpatialBridge::setVisible(LLCamera& camera_in, std::vector<LLDrawable*>*
 
 void LLSpatialBridge::updateDistance(LLCamera& camera_in, bool force_update)
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE
 
 	if (mDrawable == NULL)
 	{
diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp
index 971a355a65..630861f6be 100644
--- a/indra/newview/llviewerobjectlist.cpp
+++ b/indra/newview/llviewerobjectlist.cpp
@@ -1350,7 +1350,7 @@ void LLViewerObjectList::cleanupReferences(LLViewerObject *objectp)
 
 void LLViewerObjectList::removeDrawable(LLDrawable* drawablep)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE;
 
 	if (!drawablep)
 	{
@@ -1526,7 +1526,7 @@ void LLViewerObjectList::removeFromActiveList(LLViewerObject* objectp)
 
 void LLViewerObjectList::updateActive(LLViewerObject *objectp)
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE;
 
 	if (objectp->isDead())
 	{
@@ -2100,7 +2100,7 @@ LLViewerObject *LLViewerObjectList::replaceObject(const LLUUID &id, const LLPCod
 
 S32 LLViewerObjectList::findReferences(LLDrawable *drawablep) const
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE;
 
 	LLViewerObject *objectp;
 	S32 num_refs = 0;
diff --git a/indra/newview/llvosky.cpp b/indra/newview/llvosky.cpp
index 72ec8390a4..2e6d8adc05 100644
--- a/indra/newview/llvosky.cpp
+++ b/indra/newview/llvosky.cpp
@@ -972,7 +972,7 @@ void LLVOSky::setBloomTextures(const LLUUID& bloom_texture, const LLUUID& bloom_
 
 BOOL LLVOSky::updateGeometry(LLDrawable *drawable)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE;
 	if (mFace[FACE_REFLECTION] == NULL)
 	{
 		LLDrawPoolWater *poolp = (LLDrawPoolWater*) gPipeline.getPool(LLDrawPool::POOL_WATER);
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index 56fe4ac5af..2e9d3dbccc 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -3373,7 +3373,7 @@ void LLPipeline::stateSort(LLCamera& camera, LLCullResult &result)
 	}
 	
 	{
-		LL_RECORD_BLOCK_TIME(FTM_STATESORT_DRAWABLE);
+		LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWABLE("stateSort"); // LL_RECORD_BLOCK_TIME(FTM_STATESORT_DRAWABLE);
 		for (LLCullResult::drawable_iterator iter = sCull->beginVisibleList();
 			 iter != sCull->endVisibleList(); ++iter)
 		{
-- 
cgit v1.2.3


From 09b65074040d81c77302c705794f14295227e78c Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Thu, 13 Jan 2022 11:57:12 -0800
Subject: SL-16606: Add profiler category DRAWPOOL

---
 indra/newview/lldrawpool.cpp        | 14 +++++++-------
 indra/newview/lldrawpoolalpha.cpp   | 10 +++++-----
 indra/newview/lldrawpoolbump.cpp    | 36 ++++++++++++++++++------------------
 indra/newview/lldrawpoolsimple.cpp  | 32 +++++++++++++++++---------------
 indra/newview/lldrawpoolterrain.cpp | 20 ++++++++++----------
 indra/newview/lldrawpoolwater.cpp   | 10 +++++-----
 indra/newview/lldrawpoolwlsky.cpp   |  4 ++--
 indra/newview/llsettingsvo.cpp      |  2 +-
 indra/newview/pipeline.cpp          | 14 +++++++-------
 9 files changed, 72 insertions(+), 70 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/lldrawpool.cpp b/indra/newview/lldrawpool.cpp
index 503ee6d08d..faa5f71da4 100644
--- a/indra/newview/lldrawpool.cpp
+++ b/indra/newview/lldrawpool.cpp
@@ -389,7 +389,7 @@ LLRenderPass::~LLRenderPass()
 
 void LLRenderPass::renderGroup(LLSpatialGroup* group, U32 type, U32 mask, BOOL texture)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
 	LLSpatialGroup::drawmap_elem_t& draw_info = group->mDrawMap[type];
 	
 	for (LLSpatialGroup::drawmap_elem_t::iterator k = draw_info.begin(); k != draw_info.end(); ++k)	
@@ -404,7 +404,7 @@ void LLRenderPass::renderGroup(LLSpatialGroup* group, U32 type, U32 mask, BOOL t
 
 void LLRenderPass::renderRiggedGroup(LLSpatialGroup* group, U32 type, U32 mask, BOOL texture)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
     LLSpatialGroup::drawmap_elem_t& draw_info = group->mDrawMap[type];
     LLVOAvatar* lastAvatar = nullptr;
     U64 lastMeshId = 0;
@@ -429,7 +429,7 @@ void LLRenderPass::renderRiggedGroup(LLSpatialGroup* group, U32 type, U32 mask,
 
 void LLRenderPass::pushBatches(U32 type, U32 mask, BOOL texture, BOOL batch_textures)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
 	for (LLCullResult::drawinfo_iterator i = gPipeline.beginRenderMap(type); i != gPipeline.endRenderMap(type); ++i)	
 	{
 		LLDrawInfo* pparams = *i;
@@ -442,7 +442,7 @@ void LLRenderPass::pushBatches(U32 type, U32 mask, BOOL texture, BOOL batch_text
 
 void LLRenderPass::pushRiggedBatches(U32 type, U32 mask, BOOL texture, BOOL batch_textures)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
     LLVOAvatar* lastAvatar = nullptr;
     U64 lastMeshId = 0;
     mask |= LLVertexBuffer::MAP_WEIGHT4;
@@ -465,7 +465,7 @@ void LLRenderPass::pushRiggedBatches(U32 type, U32 mask, BOOL texture, BOOL batc
 
 void LLRenderPass::pushMaskBatches(U32 type, U32 mask, BOOL texture, BOOL batch_textures)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
 	for (LLCullResult::drawinfo_iterator i = gPipeline.beginRenderMap(type); i != gPipeline.endRenderMap(type); ++i)	
 	{
 		LLDrawInfo* pparams = *i;
@@ -479,7 +479,7 @@ void LLRenderPass::pushMaskBatches(U32 type, U32 mask, BOOL texture, BOOL batch_
 
 void LLRenderPass::pushRiggedMaskBatches(U32 type, U32 mask, BOOL texture, BOOL batch_textures)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
     LLVOAvatar* lastAvatar = nullptr;
     U64 lastMeshId = 0;
     for (LLCullResult::drawinfo_iterator i = gPipeline.beginRenderMap(type); i != gPipeline.endRenderMap(type); ++i)
@@ -525,7 +525,7 @@ void LLRenderPass::applyModelMatrix(const LLDrawInfo& params)
 
 void LLRenderPass::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture, BOOL batch_textures)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
     if (!params.mCount)
     {
         return;
diff --git a/indra/newview/lldrawpoolalpha.cpp b/indra/newview/lldrawpoolalpha.cpp
index ee1a640f2d..9da20cc375 100644
--- a/indra/newview/lldrawpoolalpha.cpp
+++ b/indra/newview/lldrawpoolalpha.cpp
@@ -126,7 +126,7 @@ static void prepare_alpha_shader(LLGLSLShader* shader, bool textureGamma, bool d
 
 void LLDrawPoolAlpha::renderPostDeferred(S32 pass) 
 { 
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
     deferred_render = TRUE;
 
     // first pass, regular forward alpha rendering
@@ -190,7 +190,7 @@ static void prepare_forward_shader(LLGLSLShader* shader, F32 minimum_alpha)
 
 void LLDrawPoolAlpha::render(S32 pass)
 {
-    LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
 
     simple_shader = (LLPipeline::sImpostorRender) ? &gObjectSimpleImpostorProgram :
         (LLPipeline::sUnderWaterRender) ? &gObjectSimpleWaterProgram : &gObjectSimpleProgram;
@@ -490,7 +490,7 @@ void LLDrawPoolAlpha::renderRiggedEmissives(U32 mask, std::vector<LLDrawInfo*>&
 
 void LLDrawPoolAlpha::renderAlpha(U32 mask, bool depth_only)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
     BOOL initialized_lighting = FALSE;
 	BOOL light_enabled = TRUE;
 
@@ -500,7 +500,7 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, bool depth_only)
 
     for (LLCullResult::sg_iterator i = gPipeline.beginAlphaGroups(); i != gPipeline.endAlphaGroups(); ++i)
 	{
-        LL_PROFILE_ZONE_NAMED("renderAlpha - group");
+        LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWPOOL("renderAlpha - group");
 		LLSpatialGroup* group = *i;
 		llassert(group);
 		llassert(group->getSpatialPartition());
@@ -525,7 +525,7 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, bool depth_only)
 
 			for (LLSpatialGroup::drawmap_elem_t::iterator k = draw_info.begin(); k != draw_info.end(); ++k)	
 			{
-                LL_PROFILE_ZONE_NAMED("ra - push batch")
+                LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWPOOL("ra - push batch")
 				LLDrawInfo& params = **k;
                 U32 have_mask = params.mVertexBuffer->getTypeMask() & mask;
 				if (have_mask != mask)
diff --git a/indra/newview/lldrawpoolbump.cpp b/indra/newview/lldrawpoolbump.cpp
index b01450bba9..471b0e2c48 100644
--- a/indra/newview/lldrawpoolbump.cpp
+++ b/indra/newview/lldrawpoolbump.cpp
@@ -210,7 +210,7 @@ S32 LLDrawPoolBump::getNumPasses()
 
 void LLDrawPoolBump::render(S32 pass)
 {
-    LL_RECORD_BLOCK_TIME(FTM_RENDER_BUMP);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_BUMP);
 
     if (!gPipeline.hasRenderType(LLDrawPool::POOL_SIMPLE))
     {
@@ -245,7 +245,7 @@ void LLDrawPoolBump::render(S32 pass)
 //static
 void LLDrawPoolBump::beginShiny()
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_SHINY);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_SHINY);
 	
 	mShiny = TRUE;
 	sVertexMask = VERTEX_MASK_SHINY;
@@ -334,7 +334,7 @@ void LLDrawPoolBump::bindCubeMap(LLGLSLShader* shader, S32 shader_level, S32& di
 
 void LLDrawPoolBump::renderShiny()
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_SHINY);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_SHINY);
 	
 	if( gSky.mVOSkyp->getCubeMap() )
 	{
@@ -390,7 +390,7 @@ void LLDrawPoolBump::unbindCubeMap(LLGLSLShader* shader, S32 shader_level, S32&
 
 void LLDrawPoolBump::endShiny()
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_SHINY);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_SHINY);
 
 	unbindCubeMap(shader, mShaderLevel, diffuse_channel, cube_channel);
 	if (shader)
@@ -405,7 +405,7 @@ void LLDrawPoolBump::endShiny()
 
 void LLDrawPoolBump::beginFullbrightShiny()
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_SHINY);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_SHINY);
 	
 	sVertexMask = VERTEX_MASK_SHINY | LLVertexBuffer::MAP_TEXCOORD0;
 
@@ -476,7 +476,7 @@ void LLDrawPoolBump::beginFullbrightShiny()
 
 void LLDrawPoolBump::renderFullbrightShiny()
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_SHINY);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_SHINY);
 
 	if( gSky.mVOSkyp->getCubeMap() )
 	{
@@ -509,7 +509,7 @@ void LLDrawPoolBump::renderFullbrightShiny()
 
 void LLDrawPoolBump::endFullbrightShiny()
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_SHINY);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_SHINY);
 
 	LLCubeMap* cube_map = gSky.mVOSkyp ? gSky.mVOSkyp->getCubeMap() : NULL;
 	if( cube_map )
@@ -568,7 +568,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;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
 	//Note: texture atlas does not support bump texture now.
 	LLViewerFetchedTexture* tex = LLViewerTextureManager::staticCastToFetchedTexture(texture) ;
 	if(!tex)
@@ -618,9 +618,9 @@ BOOL LLDrawPoolBump::bindBumpMap(U8 bump_code, LLViewerTexture* texture, F32 vsi
 
 //static
 void LLDrawPoolBump::beginBump()
-{	
+{
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_BUMP);
 	sVertexMask = VERTEX_MASK_BUMP;
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_BUMP);
 	// Optional second pass: emboss bump map
 	stop_glerror();
 
@@ -641,7 +641,7 @@ void LLDrawPoolBump::beginBump()
 //static
 void LLDrawPoolBump::renderBump(U32 pass)
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_BUMP);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_BUMP);
 	LLGLDisable fog(GL_FOG);
 	LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE, GL_LEQUAL);
 	LLGLEnable blend(GL_BLEND);
@@ -674,7 +674,7 @@ S32 LLDrawPoolBump::getNumDeferredPasses()
 
 void LLDrawPoolBump::renderDeferred(S32 pass)
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_BUMP);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_BUMP);
 
     mShiny = TRUE;
     for (int i = 0; i < 2; ++i)
@@ -879,7 +879,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;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
 	llassert( (bump_code == BE_BRIGHTNESS) || (bump_code == BE_DARKNESS) );
 
 	LLViewerTexture* bump = NULL;
@@ -935,7 +935,7 @@ LLViewerTexture* LLBumpImageList::getBrightnessDarknessImage(LLViewerFetchedText
 // static
 void LLBumpImageList::onSourceBrightnessLoaded( BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata )
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
 	LLUUID* source_asset_id = (LLUUID*)userdata;
 	LLBumpImageList::onSourceLoaded( success, src_vi, src, *source_asset_id, BE_BRIGHTNESS );
 	if( final )
@@ -959,7 +959,7 @@ void LLBumpImageList::onSourceStandardLoaded( BOOL success, LLViewerFetchedTextu
 {
 	if (success && LLPipeline::sRenderDeferred)
 	{
-        LL_PROFILE_ZONE_SCOPED;
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
 		LLPointer<LLImageRaw> nrm_image = new LLImageRaw(src->getWidth(), src->getHeight(), 4);
 		{
 			generateNormalMapFromAlpha(src, nrm_image);
@@ -1031,7 +1031,7 @@ void LLBumpImageList::onSourceLoaded( BOOL success, LLViewerTexture *src_vi, LLI
 {
 	if( success )
 	{
-        LL_PROFILE_ZONE_SCOPED;
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
 
 
 		bump_image_map_t& entries_list(bump_code == BE_BRIGHTNESS ? gBumpImageList.mBrightnessEntries : gBumpImageList.mDarknessEntries );
@@ -1318,7 +1318,7 @@ void LLDrawPoolBump::renderBump(U32 type, U32 mask)
 
 void LLDrawPoolBump::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture, BOOL batch_textures)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
 	applyModelMatrix(params);
 
 	bool tex_setup = false;
@@ -1394,7 +1394,7 @@ void LLDrawPoolBump::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture, BOOL
 
 void LLDrawPoolInvisible::render(S32 pass)
 { //render invisiprims
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_INVISIBLE);
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_INVISIBLE);
   
 	if (gPipeline.shadersLoaded())
 	{
diff --git a/indra/newview/lldrawpoolsimple.cpp b/indra/newview/lldrawpoolsimple.cpp
index 4ada753355..e324a663f4 100644
--- a/indra/newview/lldrawpoolsimple.cpp
+++ b/indra/newview/lldrawpoolsimple.cpp
@@ -79,13 +79,13 @@ static void setup_fullbright_shader(LLGLSLShader* shader)
 
 void LLDrawPoolGlow::renderPostDeferred(S32 pass)
 {
-    LL_RECORD_BLOCK_TIME(FTM_RENDER_GLOW);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_GLOW);
     render(&gDeferredEmissiveProgram);
 }
 
 void LLDrawPoolGlow::render(LLGLSLShader* shader)
 {
-    LL_RECORD_BLOCK_TIME(FTM_RENDER_GLOW);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_GLOW);
 	LLGLEnable blend(GL_BLEND);
 	LLGLDisable test(GL_ALPHA_TEST);
 	gGL.flush();
@@ -117,7 +117,7 @@ S32 LLDrawPoolGlow::getNumPasses()
 
 void LLDrawPoolGlow::render(S32 pass)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
     LLGLSLShader* shader = LLPipeline::sUnderWaterRender ? &gObjectEmissiveWaterProgram : &gObjectEmissiveProgram;
     render(shader);
 }
@@ -139,7 +139,7 @@ S32 LLDrawPoolSimple::getNumPasses()
 
 void LLDrawPoolSimple::render(S32 pass)
 {
-    LL_RECORD_BLOCK_TIME(FTM_RENDER_SIMPLE);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_SIMPLE);
 
 	LLGLDisable blend(GL_BLEND);
 	
@@ -213,8 +213,8 @@ void LLDrawPoolAlphaMask::prerender()
 
 void LLDrawPoolAlphaMask::render(S32 pass)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
 	LLGLDisable blend(GL_BLEND);
-    LL_PROFILE_ZONE_SCOPED;
 	
     LLGLSLShader* shader = nullptr;
     if (LLPipeline::sUnderWaterRender)
@@ -255,7 +255,7 @@ void LLDrawPoolFullbrightAlphaMask::prerender()
 
 void LLDrawPoolFullbrightAlphaMask::render(S32 pass)
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_MASK);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_MASK);
 
     LLGLSLShader* shader = nullptr;
     if (LLPipeline::sUnderWaterRender)
@@ -287,7 +287,7 @@ S32 LLDrawPoolSimple::getNumDeferredPasses()
 
 void LLDrawPoolSimple::renderDeferred(S32 pass)
 {
-    LL_RECORD_BLOCK_TIME(FTM_RENDER_SIMPLE_DEFERRED);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_SIMPLE_DEFERRED);
 	LLGLDisable blend(GL_BLEND);
 	LLGLDisable alpha_test(GL_ALPHA_TEST);
 
@@ -305,7 +305,7 @@ static LLTrace::BlockTimerStatHandle FTM_RENDER_ALPHA_MASK_DEFERRED("Deferred Al
 
 void LLDrawPoolAlphaMask::renderDeferred(S32 pass)
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_MASK_DEFERRED);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_MASK_DEFERRED);
     LLGLSLShader* shader = &gDeferredDiffuseAlphaMaskProgram;
 
     //render static
@@ -332,7 +332,7 @@ void LLDrawPoolGrass::prerender()
 
 void LLDrawPoolGrass::beginRenderPass(S32 pass)
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_GRASS);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_GRASS);
 	stop_glerror();
 
 	if (LLPipeline::sUnderWaterRender)
@@ -366,7 +366,7 @@ void LLDrawPoolGrass::beginRenderPass(S32 pass)
 
 void LLDrawPoolGrass::endRenderPass(S32 pass)
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_GRASS);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_GRASS);
 	LLRenderPass::endRenderPass(pass);
 
 	if (mShaderLevel > 0)
@@ -381,10 +381,11 @@ void LLDrawPoolGrass::endRenderPass(S32 pass)
 
 void LLDrawPoolGrass::render(S32 pass)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
 	LLGLDisable blend(GL_BLEND);
 	
 	{
-		LL_RECORD_BLOCK_TIME(FTM_RENDER_GRASS);
+		//LL_RECORD_BLOCK_TIME(FTM_RENDER_GRASS);
 		LLGLEnable test(GL_ALPHA_TEST);
 		gGL.setSceneBlendType(LLRender::BT_ALPHA);
 		//render grass
@@ -404,8 +405,9 @@ void LLDrawPoolGrass::endDeferredPass(S32 pass)
 
 void LLDrawPoolGrass::renderDeferred(S32 pass)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
 	{
-		LL_RECORD_BLOCK_TIME(FTM_RENDER_GRASS_DEFERRED);
+		//LL_RECORD_BLOCK_TIME(FTM_RENDER_GRASS_DEFERRED);
 		gDeferredNonIndexedDiffuseAlphaMaskProgram.bind();
 		gDeferredNonIndexedDiffuseAlphaMaskProgram.setMinimumAlpha(0.5f);
 
@@ -438,7 +440,7 @@ void LLDrawPoolFullbright::prerender()
 
 void LLDrawPoolFullbright::renderPostDeferred(S32 pass)
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_FULLBRIGHT);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_FULLBRIGHT);
 
     LLGLSLShader* shader = nullptr;
     if (LLPipeline::sUnderWaterRender)
@@ -464,7 +466,7 @@ void LLDrawPoolFullbright::renderPostDeferred(S32 pass)
 
 void LLDrawPoolFullbright::render(S32 pass)
 { //render fullbright
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_FULLBRIGHT);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_FULLBRIGHT);
 	gGL.setSceneBlendType(LLRender::BT_ALPHA);
 
 	stop_glerror();
@@ -505,7 +507,7 @@ S32 LLDrawPoolFullbright::getNumPasses()
 
 void LLDrawPoolFullbrightAlphaMask::renderPostDeferred(S32 pass)
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_FULLBRIGHT);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_FULLBRIGHT);
     
     LLGLSLShader* shader = nullptr;
     if (LLPipeline::sRenderingHUDs)
diff --git a/indra/newview/lldrawpoolterrain.cpp b/indra/newview/lldrawpoolterrain.cpp
index adea1909a3..cc5cb667f0 100644
--- a/indra/newview/lldrawpoolterrain.cpp
+++ b/indra/newview/lldrawpoolterrain.cpp
@@ -111,7 +111,7 @@ void LLDrawPoolTerrain::prerender()
 
 void LLDrawPoolTerrain::beginRenderPass( S32 pass )
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_TERRAIN);
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_TERRAIN);
 	LLFacePool::beginRenderPass(pass);
 
 	sShader = LLPipeline::sUnderWaterRender ? 
@@ -126,7 +126,7 @@ void LLDrawPoolTerrain::beginRenderPass( S32 pass )
 
 void LLDrawPoolTerrain::endRenderPass( S32 pass )
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_TERRAIN);
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_TERRAIN);
 	//LLFacePool::endRenderPass(pass);
 
 	if (mShaderLevel > 1 && sShader->mShaderLevel > 0) {
@@ -154,7 +154,7 @@ void LLDrawPoolTerrain::boostTerrainDetailTextures()
 
 void LLDrawPoolTerrain::render(S32 pass)
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_TERRAIN);
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_TERRAIN);
 	
 	if (mDrawFace.empty())
 	{
@@ -213,7 +213,7 @@ void LLDrawPoolTerrain::render(S32 pass)
 
 void LLDrawPoolTerrain::beginDeferredPass(S32 pass)
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_TERRAIN);
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_TERRAIN);
 	LLFacePool::beginRenderPass(pass);
 
 	sShader = LLPipeline::sUnderWaterRender ? &gDeferredTerrainWaterProgram : &gDeferredTerrainProgram;
@@ -223,14 +223,14 @@ void LLDrawPoolTerrain::beginDeferredPass(S32 pass)
 
 void LLDrawPoolTerrain::endDeferredPass(S32 pass)
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_TERRAIN);
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_TERRAIN);
 	LLFacePool::endRenderPass(pass);
 	sShader->unbind();
 }
 
 void LLDrawPoolTerrain::renderDeferred(S32 pass)
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_TERRAIN);
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_TERRAIN);
 	if (mDrawFace.empty())
 	{
 		return;
@@ -250,7 +250,7 @@ void LLDrawPoolTerrain::renderDeferred(S32 pass)
 
 void LLDrawPoolTerrain::beginShadowPass(S32 pass)
 {
-	LL_RECORD_BLOCK_TIME(FTM_SHADOW_TERRAIN);
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_SHADOW_TERRAIN);
 	LLFacePool::beginRenderPass(pass);
 	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 	gDeferredShadowProgram.bind();
@@ -261,14 +261,14 @@ void LLDrawPoolTerrain::beginShadowPass(S32 pass)
 
 void LLDrawPoolTerrain::endShadowPass(S32 pass)
 {
-	LL_RECORD_BLOCK_TIME(FTM_SHADOW_TERRAIN);
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_SHADOW_TERRAIN);
 	LLFacePool::endRenderPass(pass);
 	gDeferredShadowProgram.unbind();
 }
 
 void LLDrawPoolTerrain::renderShadow(S32 pass)
 {
-	LL_RECORD_BLOCK_TIME(FTM_SHADOW_TERRAIN);
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_SHADOW_TERRAIN);
 	if (mDrawFace.empty())
 	{
 		return;
@@ -850,7 +850,7 @@ void LLDrawPoolTerrain::renderOwnership()
 
 void LLDrawPoolTerrain::dirtyTextures(const std::set<LLViewerFetchedTexture*>& textures)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
 	LLViewerFetchedTexture* tex = LLViewerTextureManager::staticCastToFetchedTexture(mTexturep) ;
 	if (tex && textures.find(tex) != textures.end())
 	{
diff --git a/indra/newview/lldrawpoolwater.cpp b/indra/newview/lldrawpoolwater.cpp
index 62706feae3..0f2bcf4708 100644
--- a/indra/newview/lldrawpoolwater.cpp
+++ b/indra/newview/lldrawpoolwater.cpp
@@ -134,7 +134,7 @@ void LLDrawPoolWater::endPostDeferredPass(S32 pass)
 //===============================
 void LLDrawPoolWater::renderDeferred(S32 pass)
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_WATER);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_WATER);
 
     if (!LLPipeline::sRenderTransparentWater)
     {
@@ -152,7 +152,7 @@ void LLDrawPoolWater::renderDeferred(S32 pass)
 
 void LLDrawPoolWater::render(S32 pass)
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_WATER);
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_WATER);
 	if (mDrawFace.empty() || LLDrawable::getCurrentFrame() <= 1)
 	{
 		return;
@@ -334,7 +334,7 @@ void LLDrawPoolWater::render(S32 pass)
 // for low end hardware
 void LLDrawPoolWater::renderOpaqueLegacyWater()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
     LLVOSky *voskyp = gSky.mVOSkyp;
 
     if (voskyp == NULL)
@@ -443,7 +443,7 @@ void LLDrawPoolWater::renderOpaqueLegacyWater()
 
 void LLDrawPoolWater::renderReflection(LLFace* face)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
 	LLVOSky *voskyp = gSky.mVOSkyp;
 
 	if (!voskyp)
@@ -472,7 +472,7 @@ void LLDrawPoolWater::renderReflection(LLFace* face)
 
 void LLDrawPoolWater::renderWater()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
     if (!deferred_render)
     {
         gGL.setColorMask(true, true);
diff --git a/indra/newview/lldrawpoolwlsky.cpp b/indra/newview/lldrawpoolwlsky.cpp
index 80a65947f6..9873846669 100644
--- a/indra/newview/lldrawpoolwlsky.cpp
+++ b/indra/newview/lldrawpoolwlsky.cpp
@@ -566,11 +566,11 @@ void LLDrawPoolWLSky::renderHeavenlyBodies()
 
 void LLDrawPoolWLSky::renderDeferred(S32 pass)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_WL_SKY);
 	if (!gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_SKY))
 	{
 		return;
 	}
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_WL_SKY);
 
     const F32 camHeightLocal = LLEnvironment::instance().getCamHeight();
 
@@ -590,11 +590,11 @@ void LLDrawPoolWLSky::renderDeferred(S32 pass)
 
 void LLDrawPoolWLSky::render(S32 pass)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_WL_SKY);
 	if (!gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_SKY))
 	{
 		return;
 	}
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_WL_SKY);
 
     const F32 camHeightLocal = LLEnvironment::instance().getCamHeight();
     LLVector3 const & origin = LLViewerCamera::getInstance()->getOrigin();
diff --git a/indra/newview/llsettingsvo.cpp b/indra/newview/llsettingsvo.cpp
index 6415da4e4a..b6a3f68e63 100644
--- a/indra/newview/llsettingsvo.cpp
+++ b/indra/newview/llsettingsvo.cpp
@@ -966,7 +966,7 @@ void LLSettingsVOWater::applySpecial(void *ptarget, bool force)
 
 void LLSettingsVOWater::updateSettings()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
     // base class clears dirty flag so as to not trigger recursive update
     LLSettingsBase::updateSettings();
 
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index 2e9d3dbccc..52b8153980 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -4335,7 +4335,7 @@ void LLPipeline::renderGeom(LLCamera& camera, bool forceVBOUpdate)
 	}
 
 	{
-		LL_RECORD_BLOCK_TIME(FTM_POOLS);
+		LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWPOOL("pools"); //LL_RECORD_BLOCK_TIME(FTM_POOLS);
 		
 		// HACK: don't calculate local lights if we're rendering the HUD!
 		//    Removing this check will cause bad flickering when there are 
@@ -4371,7 +4371,7 @@ void LLPipeline::renderGeom(LLCamera& camera, bool forceVBOUpdate)
 			pool_set_t::iterator iter2 = iter1;
 			if (hasRenderType(poolp->getType()) && poolp->getNumPasses() > 0)
 			{
-				LL_RECORD_BLOCK_TIME(FTM_POOLRENDER);
+				LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWPOOL("pool render"); //LL_RECORD_BLOCK_TIME(FTM_POOLRENDER);
 
 				gGLLastMatrix = NULL;
 				gGL.loadMatrix(gGLModelView);
@@ -4501,14 +4501,14 @@ void LLPipeline::renderGeomDeferred(LLCamera& camera)
 {
 	LLAppViewer::instance()->pingMainloopTimeout("Pipeline:RenderGeomDeferred");
 
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_GEOMETRY);
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_GEOMETRY);
 	{
 		// SL-15709 -- NOTE: Tracy only allows one ZoneScoped per function.
 		// Solutions are:
 		// 1. Use a new scope
 		// 2. Use named zones
 		// 3. Use transient zones
-		LL_RECORD_BLOCK_TIME(FTM_DEFERRED_POOLS);
+		LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWPOOL("deferred pools"); //LL_RECORD_BLOCK_TIME(FTM_DEFERRED_POOLS);
 
 		LLGLEnable cull(GL_CULL_FACE);
 
@@ -4543,7 +4543,7 @@ void LLPipeline::renderGeomDeferred(LLCamera& camera)
 			pool_set_t::iterator iter2 = iter1;
 			if (hasRenderType(poolp->getType()) && poolp->getNumDeferredPasses() > 0)
 			{
-				LL_RECORD_BLOCK_TIME(FTM_DEFERRED_POOLRENDER);
+				LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWPOOL("deferred pool render"); //LL_RECORD_BLOCK_TIME(FTM_DEFERRED_POOLRENDER);
 
 				gGLLastMatrix = NULL;
 				gGL.loadMatrix(gGLModelView);
@@ -4598,7 +4598,7 @@ void LLPipeline::renderGeomDeferred(LLCamera& camera)
 
 void LLPipeline::renderGeomPostDeferred(LLCamera& camera, bool do_occlusion)
 {
-	LL_RECORD_BLOCK_TIME(FTM_POST_DEFERRED_POOLS);
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_POST_DEFERRED_POOLS);
 	U32 cur_type = 0;
 
 	LLGLEnable cull(GL_CULL_FACE);
@@ -4632,7 +4632,7 @@ void LLPipeline::renderGeomPostDeferred(LLCamera& camera, bool do_occlusion)
 		pool_set_t::iterator iter2 = iter1;
 		if (hasRenderType(poolp->getType()) && poolp->getNumPostDeferredPasses() > 0)
 		{
-			LL_RECORD_BLOCK_TIME(FTM_POST_DEFERRED_POOLRENDER);
+			LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWPOOL("deferred poolrender"); //LL_RECORD_BLOCK_TIME(FTM_POST_DEFERRED_POOLRENDER);
 
 			gGLLastMatrix = NULL;
 			gGL.loadMatrix(gGLModelView);
-- 
cgit v1.2.3


From b08e142bd722b9a15790731810d35f734f4921b0 Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Thu, 13 Jan 2022 11:59:34 -0800
Subject: SL-16606: Add profiler category ENVIRONMENT

---
 indra/llinventory/llsettingsbase.cpp | 8 ++++----
 indra/llinventory/llsettingssky.cpp  | 8 ++++----
 indra/newview/llenvironment.cpp      | 6 +++---
 indra/newview/llsettingsvo.cpp       | 2 +-
 indra/newview/llviewerdisplay.cpp    | 2 +-
 indra/newview/llvosky.cpp            | 4 ++--
 6 files changed, 15 insertions(+), 15 deletions(-)

(limited to 'indra')

diff --git a/indra/llinventory/llsettingsbase.cpp b/indra/llinventory/llsettingsbase.cpp
index aed972b150..936b166409 100644
--- a/indra/llinventory/llsettingsbase.cpp
+++ b/indra/llinventory/llsettingsbase.cpp
@@ -683,7 +683,7 @@ bool LLSettingsBase::Validator::verifyStringLength(LLSD &value, U32, S32 length)
 //=========================================================================
 void LLSettingsBlender::update(const LLSettingsBase::BlendFactor& blendf)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_ENVIRONMENT;
     F64 res = setBlendFactor(blendf);
     llassert(res >= 0.0 && res <= 1.0);
     (void)res;
@@ -714,7 +714,7 @@ F64 LLSettingsBlender::setBlendFactor(const LLSettingsBase::BlendFactor& blendf_
 
 void LLSettingsBlender::triggerComplete()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_ENVIRONMENT;
     if (mTarget)
         mTarget->replaceSettings(mFinal->getSettings());
     LLSettingsBlender::ptr_t hold = shared_from_this();   // prevents this from deleting too soon
@@ -727,13 +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;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_ENVIRONMENT;
     return LLSettingsBase::BlendFactor(fmod((F64)spanpos, (F64)spanlen) / (F64)spanlen);
 }
 
 bool LLSettingsBlenderTimeDelta::applyTimeDelta(const LLSettingsBase::Seconds& timedelta)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_ENVIRONMENT;
     mTimeSpent += timedelta;
 
     if (mTimeSpent > mBlendSpan)
diff --git a/indra/llinventory/llsettingssky.cpp b/indra/llinventory/llsettingssky.cpp
index 979a284744..83a92f08d0 100644
--- a/indra/llinventory/llsettingssky.cpp
+++ b/indra/llinventory/llsettingssky.cpp
@@ -439,7 +439,7 @@ void LLSettingsSky::replaceWithSky(LLSettingsSky::ptr_t pother)
 
 void LLSettingsSky::blend(const LLSettingsBase::ptr_t &end, F64 blendf) 
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_ENVIRONMENT;
     llassert(getSettingsType() == end->getSettingsType());
 
     LLSettingsSky::ptr_t other = PTR_NAMESPACE::dynamic_pointer_cast<LLSettingsSky>(end);
@@ -935,7 +935,7 @@ LLSD LLSettingsSky::translateLegacySettings(const LLSD& legacy)
 
 void LLSettingsSky::updateSettings()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_ENVIRONMENT;
 
     // base class clears dirty flag so as to not trigger recursive update
     LLSettingsBase::updateSettings();
@@ -1018,7 +1018,7 @@ LLColor3 LLSettingsSky::getLightDiffuse() const
 
 LLColor3 LLSettingsSky::getColor(const std::string& key, const LLColor3& default_value) const
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_ENVIRONMENT;
     if (mSettings.has(SETTING_LEGACY_HAZE) && mSettings[SETTING_LEGACY_HAZE].has(key))
     {
         return LLColor3(mSettings[SETTING_LEGACY_HAZE][key]);
@@ -1032,7 +1032,7 @@ LLColor3 LLSettingsSky::getColor(const std::string& key, const LLColor3& default
 
 F32 LLSettingsSky::getFloat(const std::string& key, F32 default_value) const
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_ENVIRONMENT;
     if (mSettings.has(SETTING_LEGACY_HAZE) && mSettings[SETTING_LEGACY_HAZE].has(key))
     {
         return mSettings[SETTING_LEGACY_HAZE][key].asReal();
diff --git a/indra/newview/llenvironment.cpp b/indra/newview/llenvironment.cpp
index 4bec7fa111..f232ca47e0 100644
--- a/indra/newview/llenvironment.cpp
+++ b/indra/newview/llenvironment.cpp
@@ -1470,7 +1470,7 @@ LLEnvironment::DayInstance::ptr_t LLEnvironment::getSharedEnvironmentInstance()
 
 void LLEnvironment::updateEnvironment(LLSettingsBase::Seconds transition, bool forced)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_ENVIRONMENT;
     DayInstance::ptr_t pinstance = getSelectedEnvironmentInstance();
 
     if ((mCurrentEnvironment != pinstance) || forced)
@@ -1596,7 +1596,7 @@ LLVector4 LLEnvironment::getRotatedLightNorm() const
 //-------------------------------------------------------------------------
 void LLEnvironment::update(const LLViewerCamera * cam)
 {
-    LL_RECORD_BLOCK_TIME(FTM_ENVIRONMENT_UPDATE);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_ENVIRONMENT; //LL_RECORD_BLOCK_TIME(FTM_ENVIRONMENT_UPDATE);
     //F32Seconds now(LLDate::now().secondsSinceEpoch());
     static LLFrameTimer timer;
 
@@ -2657,7 +2657,7 @@ LLEnvironment::DayInstance::ptr_t LLEnvironment::DayInstance::clone() const
 
 bool LLEnvironment::DayInstance::applyTimeDelta(const LLSettingsBase::Seconds& delta)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_ENVIRONMENT;
     ptr_t keeper(shared_from_this());   // makes sure that this does not go away while it is being worked on.
 
     bool changed(false);
diff --git a/indra/newview/llsettingsvo.cpp b/indra/newview/llsettingsvo.cpp
index b6a3f68e63..217d45de68 100644
--- a/indra/newview/llsettingsvo.cpp
+++ b/indra/newview/llsettingsvo.cpp
@@ -637,7 +637,7 @@ LLSD LLSettingsVOSky::convertToLegacy(const LLSettingsSky::ptr_t &psky, bool isA
 //-------------------------------------------------------------------------
 void LLSettingsVOSky::updateSettings()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_ENVIRONMENT;
     LLSettingsSky::updateSettings();
     LLVector3 sun_direction  = getSunDirection();
     LLVector3 moon_direction = getMoonDirection();
diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp
index f28edd10c5..e2c831bb1c 100644
--- a/indra/newview/llviewerdisplay.cpp
+++ b/indra/newview/llviewerdisplay.cpp
@@ -848,7 +848,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 
 		{
 			LLAppViewer::instance()->pingMainloopTimeout("Display:Sky");
-			LL_RECORD_BLOCK_TIME(FTM_UPDATE_SKY);	
+			LL_PROFILE_ZONE_NAMED_CATEGORY_ENVIRONMENT("update sky"); //LL_RECORD_BLOCK_TIME(FTM_UPDATE_SKY);	
 			gSky.updateSky();
 		}
 
diff --git a/indra/newview/llvosky.cpp b/indra/newview/llvosky.cpp
index 2e6d8adc05..01312d65cc 100644
--- a/indra/newview/llvosky.cpp
+++ b/indra/newview/llvosky.cpp
@@ -510,7 +510,7 @@ void LLVOSky::cacheEnvironment(LLSettingsSky::ptr_t psky,AtmosphericsVars& atmos
 
 void LLVOSky::calc()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_ENVIRONMENT;
     LLSettingsSky::ptr_t psky = LLEnvironment::instance().getCurrentSky();
     cacheEnvironment(psky,m_atmosphericsVars);
 
@@ -681,7 +681,7 @@ bool LLVOSky::updateSky()
 		return TRUE;
 	}
 
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_ENVIRONMENT;
 
 	static S32 next_frame = 0;
 
-- 
cgit v1.2.3


From fd5afa5e367aa525bca8509a10935fd602e3effa Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Thu, 13 Jan 2022 12:01:31 -0800
Subject: SL-16606: Add profiler category FACE

---
 indra/newview/llface.cpp | 66 ++++++++++++++++++++++++------------------------
 1 file changed, 33 insertions(+), 33 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp
index 54a043482b..b54c2105dd 100644
--- a/indra/newview/llface.cpp
+++ b/indra/newview/llface.cpp
@@ -129,7 +129,7 @@ void planarProjection(LLVector2 &tc, const LLVector4a& normal,
 
 void LLFace::init(LLDrawable* drawablep, LLViewerObject* objp)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_FACE;
 	mLastUpdateTime = gFrameTimeSeconds;
 	mLastMoveTime = 0.f;
 	mLastSkinTime = gFrameTimeSeconds;
@@ -237,7 +237,7 @@ void LLFace::setPool(LLFacePool* pool)
 
 void LLFace::setPool(LLFacePool* new_pool, LLViewerTexture *texturep)
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_FACE
 
 	if (!new_pool)
 	{
@@ -318,7 +318,7 @@ void LLFace::setSpecularMap(LLViewerTexture* tex)
 
 void LLFace::dirtyTexture()
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_FACE
 
 	LLDrawable* drawablep = getDrawable();
 
@@ -535,7 +535,7 @@ void LLFace::updateCenterAgent()
 
 void LLFace::renderSelected(LLViewerTexture *imagep, const LLColor4& color)
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_FACE
 
 	if (mDrawablep == NULL || mDrawablep->getSpatialGroup() == NULL)
 	{
@@ -608,7 +608,7 @@ void LLFace::renderSelected(LLViewerTexture *imagep, const LLColor4& color)
 
 void renderFace(LLDrawable* drawable, LLFace *face)
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_FACE
 
     LLVOVolume* vobj = drawable->getVOVolume();
     if (vobj)
@@ -896,7 +896,7 @@ 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
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_FACE
 
 	//get bounding box
 	if (mDrawablep->isState(LLDrawable::REBUILD_VOLUME | LLDrawable::REBUILD_POSITION | LLDrawable::REBUILD_RIGGED))
@@ -1205,7 +1205,7 @@ bool LLFace::canRenderAsMask()
 //static 
 void LLFace::cacheFaceInVRAM(const LLVolumeFace& vf)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_FACE;
 	U32 mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 |
 				LLVertexBuffer::MAP_TANGENT | LLVertexBuffer::MAP_NORMAL;
 	
@@ -1273,7 +1273,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 								const U16 &index_offset,
 								bool force_rebuild)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_FACE;
 	llassert(verify());
 
 	if (volume.getNumVolumeFaces() <= f) {
@@ -1416,7 +1416,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 	// INDICES
 	if (full_rebuild)
 	{
-        LL_PROFILE_ZONE_NAMED("getGeometryVolume - indices");
+        LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - indices");
 		mVertexBuffer->getIndexStrider(indicesp, mIndicesIndex, mIndicesCount, map_range);
 
 		volatile __m128i* dst = (__m128i*) indicesp.get();
@@ -1432,7 +1432,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 		}
 
 		{
-            LL_PROFILE_ZONE_NAMED("getGeometryVolume - indices tail");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - indices tail");
 			U16* idx = (U16*) dst;
 
 			for (S32 i = end*8; i < num_indices; ++i)
@@ -1501,7 +1501,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 
     if (rebuild_normal || rebuild_tangent)
     { //override mat_normal with inverse of skin->mBindShapeMatrix
-        LL_PROFILE_ZONE_NAMED("getGeometryVolume - norm mat override");
+        LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - norm mat override");
         if (rigged)
         {
             if (skin == nullptr)
@@ -1532,7 +1532,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 	{ //use transform feedback to pack vertex buffer
 		//gGLDebugLoggingEnabled = TRUE;
 
-        LL_PROFILE_ZONE_NAMED("getGeometryVolume - transform feedback");
+        LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - transform feedback");
 		LLGLEnable discard(GL_RASTERIZER_DISCARD);
 		LLVertexBuffer* buff = (LLVertexBuffer*) vf.mVertexBuffer.get();
 
@@ -1550,7 +1550,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 
 		if (rebuild_pos)
 		{
-            LL_PROFILE_ZONE_NAMED("getGeometryVolume - tf position");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - tf position");
 			gTransformPositionProgram.bind();
 
 			mVertexBuffer->bindForFeedback(0, LLVertexBuffer::TYPE_VERTEX, mGeomIndex, mGeomCount);
@@ -1575,7 +1575,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 
 		if (rebuild_color)
 		{
-            LL_PROFILE_ZONE_NAMED("getGeometryVolume - tf color");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - tf color");
 			gTransformColorProgram.bind();
 			
 			mVertexBuffer->bindForFeedback(0, LLVertexBuffer::TYPE_COLOR, mGeomIndex, mGeomCount);
@@ -1591,7 +1591,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 
 		if (rebuild_emissive)
 		{
-            LL_PROFILE_ZONE_NAMED("getGeometryVolume - tf emissive");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - tf emissive");
 			gTransformColorProgram.bind();
 			
 			mVertexBuffer->bindForFeedback(0, LLVertexBuffer::TYPE_EMISSIVE, mGeomIndex, mGeomCount);
@@ -1612,7 +1612,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 
 		if (rebuild_normal)
 		{
-            LL_PROFILE_ZONE_NAMED("getGeometryVolume - tf normal");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - tf normal");
 			gTransformNormalProgram.bind();
 			
 			mVertexBuffer->bindForFeedback(0, LLVertexBuffer::TYPE_NORMAL, mGeomIndex, mGeomCount);
@@ -1625,7 +1625,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 
 		if (rebuild_tangent)
 		{
-            LL_PROFILE_ZONE_NAMED("getGeometryVolume - tf tangent");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - tf tangent");
 			gTransformTangentProgram.bind();
 			
 			mVertexBuffer->bindForFeedback(0, LLVertexBuffer::TYPE_TANGENT, mGeomIndex, mGeomCount);
@@ -1638,7 +1638,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 
 		if (rebuild_tcoord)
 		{
-            LL_PROFILE_ZONE_NAMED("getGeometryVolume - tf tcoord");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - tf tcoord");
 			gTransformTexCoordProgram.bind();
 			
 			mVertexBuffer->bindForFeedback(0, LLVertexBuffer::TYPE_TEXCOORD0, mGeomIndex, mGeomCount);
@@ -1677,7 +1677,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 
 		if (rebuild_tcoord)
 		{
-            LL_PROFILE_ZONE_NAMED("getGeometryVolume - tcoord");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - tcoord");
 									
 			//bump setup
 			LLVector4a binormal_dir( -sin_ang, cos_ang, 0.f );
@@ -1800,18 +1800,18 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 
 				if (texgen != LLTextureEntry::TEX_GEN_PLANAR)
 				{
-                    LL_PROFILE_ZONE_NAMED("getGeometryVolume - texgen");
+                    LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - texgen");
 					if (!do_tex_mat)
 					{
 						if (!do_xform)
 						{
-                            LL_PROFILE_ZONE_NAMED("ggv - texgen 1");
+                            LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("ggv - texgen 1");
 							S32 tc_size = (num_vertices*2*sizeof(F32)+0xF) & ~0xF;
 							LLVector4a::memcpyNonAliased16((F32*) tex_coords0.get(), (F32*) vf.mTexCoords, tc_size);
 						}
 						else
 						{
-                            LL_PROFILE_ZONE_NAMED("ggv - texgen 2");
+                            LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("ggv - texgen 2");
 							F32* dst = (F32*) tex_coords0.get();
 							LLVector4a* src = (LLVector4a*) vf.mTexCoords;
 
@@ -1862,7 +1862,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 				}
 				else
 				{ //no bump, tex gen planar
-                    LL_PROFILE_ZONE_NAMED("getGeometryVolume - texgen planar");
+                    LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - texgen planar");
 					if (do_tex_mat)
 					{
 						for (S32 i = 0; i < num_vertices; i++)
@@ -1907,7 +1907,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 			}
 			else
 			{ //bump mapped or has material, just do the whole expensive loop
-                LL_PROFILE_ZONE_NAMED("getGeometryVolume - texgen default");
+                LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - texgen default");
 
 				std::vector<LLVector2> bump_tc;
 		
@@ -2122,7 +2122,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 
 		if (rebuild_normal)
 		{
-            LL_PROFILE_ZONE_NAMED("getGeometryVolume - normal");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - normal");
 
 			mVertexBuffer->getNormalStrider(norm, mGeomIndex, mGeomCount, map_range);
 			F32* normals = (F32*) norm.get();
@@ -2145,7 +2145,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 		
 		if (rebuild_tangent)
 		{
-            LL_PROFILE_ZONE_NAMED("getGeometryVolume - tangent");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - tangent");
 			mVertexBuffer->getTangentStrider(tangent, mGeomIndex, mGeomCount, map_range);
 			F32* tangents = (F32*) tangent.get();
 			
@@ -2178,7 +2178,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 	
 		if (rebuild_weights && vf.mWeights)
 		{
-            LL_PROFILE_ZONE_NAMED("getGeometryVolume - weight");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - weight");
 			mVertexBuffer->getWeight4Strider(wght, mGeomIndex, mGeomCount, map_range);
 			F32* weights = (F32*) wght.get();
 			LLVector4a::memcpyNonAliased16(weights, (F32*) vf.mWeights, num_vertices*4*sizeof(F32));
@@ -2190,7 +2190,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 
 		if (rebuild_color && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_COLOR) )
 		{
-            LL_PROFILE_ZONE_NAMED("getGeometryVolume - color");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - color");
 			mVertexBuffer->getColorStrider(colors, mGeomIndex, mGeomCount, map_range);
 
 			LLVector4a src;
@@ -2221,7 +2221,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 
 		if (rebuild_emissive)
 		{
-            LL_PROFILE_ZONE_NAMED("getGeometryVolume - emissive");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - emissive");
 			LLStrider<LLColor4U> emissive;
 			mVertexBuffer->getEmissiveStrider(emissive, mGeomIndex, mGeomCount, map_range);
 
@@ -2352,7 +2352,7 @@ F32 LLFace::getTextureVirtualSize()
 
 BOOL LLFace::calcPixelArea(F32& cos_angle_to_view_dir, F32& radius)
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_FACE
 
 	//VECTORIZE THIS
 	//get area of circle around face
@@ -2633,7 +2633,7 @@ const LLMatrix4& LLFace::getRenderMatrix() const
 
 S32 LLFace::renderElements(const U16 *index_array) const
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_FACE
 
 	S32 ret = 0;
 	
@@ -2654,7 +2654,7 @@ S32 LLFace::renderElements(const U16 *index_array) const
 
 S32 LLFace::renderIndexed()
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_FACE
 
 	if(mDrawablep == NULL || mDrawPoolp == NULL)
 	{
@@ -2666,7 +2666,7 @@ S32 LLFace::renderIndexed()
 
 S32 LLFace::renderIndexed(U32 mask)
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_FACE
 
 	if (mVertexBuffer.isNull())
 	{
-- 
cgit v1.2.3


From 015fade832e8c1ab58e42ae7ead7e5e4b02bb336 Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Thu, 13 Jan 2022 12:19:23 -0800
Subject: SL-16606: Add profiler category LLSD

---
 indra/llcommon/llsd.cpp | 22 +++++++++++-----------
 indra/llcommon/llsd.h   | 14 +++++++-------
 indra/llxml/llcontrol.h |  2 +-
 3 files changed, 19 insertions(+), 19 deletions(-)

(limited to 'indra')

diff --git a/indra/llcommon/llsd.cpp b/indra/llcommon/llsd.cpp
index 605f6bf0e3..807b3d13f8 100644
--- a/indra/llcommon/llsd.cpp
+++ b/indra/llcommon/llsd.cpp
@@ -400,7 +400,7 @@ namespace
 	
 	ImplMap& ImplMap::makeMap(LLSD::Impl*& var)
 	{
-        LL_PROFILE_ZONE_SCOPED;
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD;
 		if (shared())
 		{
 			ImplMap* i = new ImplMap(mData);
@@ -415,21 +415,21 @@ namespace
 	
 	bool ImplMap::has(const LLSD::String& k) const
 	{
-        LL_PROFILE_ZONE_SCOPED;
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD;
 		DataMap::const_iterator i = mData.find(k);
 		return i != mData.end();
 	}
 	
 	LLSD ImplMap::get(const LLSD::String& k) const
 	{
-        LL_PROFILE_ZONE_SCOPED;
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD;
 		DataMap::const_iterator i = mData.find(k);
 		return (i != mData.end()) ? i->second : LLSD();
 	}
 
 	LLSD ImplMap::getKeys() const
 	{ 
-        LL_PROFILE_ZONE_SCOPED;
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD;
 		LLSD keys = LLSD::emptyArray();
 		DataMap::const_iterator iter = mData.begin();
 		while (iter != mData.end())
@@ -442,13 +442,13 @@ namespace
 
 	void ImplMap::insert(const LLSD::String& k, const LLSD& v)
 	{
-        LL_PROFILE_ZONE_SCOPED;
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD;
 		mData.insert(DataMap::value_type(k, v));
 	}
 	
 	void ImplMap::erase(const LLSD::String& k)
 	{
-        LL_PROFILE_ZONE_SCOPED;
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD;
 		mData.erase(k);
 	}
 	
@@ -690,7 +690,7 @@ const LLSD::Impl& LLSD::Impl::safe(const Impl* impl)
 
 ImplMap& LLSD::Impl::makeMap(Impl*& var)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD;
 	ImplMap* im = new ImplMap;
 	reset(var, im);
 	return *im;
@@ -896,12 +896,12 @@ void LLSD::erase(const String& k)		{ makeMap(impl).erase(k); }
 
 LLSD& LLSD::operator[](const String& k)
 { 
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD;
     return makeMap(impl).ref(k); 
 }
 const LLSD& LLSD::operator[](const String& k) const
 { 
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD;
     return safe(impl).ref(k); 
 }
 
@@ -928,12 +928,12 @@ void LLSD::erase(Integer i)				{ makeArray(impl).erase(i); }
 
 LLSD& LLSD::operator[](Integer i)
 { 
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD;
     return makeArray(impl).ref(i); 
 }
 const LLSD& LLSD::operator[](Integer i) const
 { 
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD;
     return safe(impl).ref(i);
 }
 
diff --git a/indra/llcommon/llsd.h b/indra/llcommon/llsd.h
index b8ddf21596..24cb9bbce1 100644
--- a/indra/llcommon/llsd.h
+++ b/indra/llcommon/llsd.h
@@ -290,16 +290,16 @@ public:
 		LLSD& with(const String&, const LLSD&);
 		
 		LLSD& operator[](const String&);
-		LLSD& operator[](const char* c)			
-        { 
-            LL_PROFILE_ZONE_SCOPED;
-            return (*this)[String(c)]; 
+		LLSD& operator[](const char* c)
+        {
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD;
+            return (*this)[String(c)];
         }
 		const LLSD& operator[](const String&) const;
 		const LLSD& operator[](const char* c) const	
-        { 
-            LL_PROFILE_ZONE_SCOPED;
-            return (*this)[String(c)]; 
+        {
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD;
+            return (*this)[String(c)];
         }
 	//@}
 	
diff --git a/indra/llxml/llcontrol.h b/indra/llxml/llcontrol.h
index 088502c017..0839c02c50 100644
--- a/indra/llxml/llcontrol.h
+++ b/indra/llxml/llcontrol.h
@@ -247,7 +247,7 @@ public:
 	// generic getter
 	template<typename T> T get(const std::string& name)
 	{
-        LL_PROFILE_ZONE_SCOPED;
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD;
 		LLControlVariable* control = getControl(name);
 		LLSD value;
 		eControlType type = TYPE_COUNT;
-- 
cgit v1.2.3


From caf6b7e35d7dd9dedd8162409d98d45a2d8c81f8 Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Thu, 13 Jan 2022 12:20:12 -0800
Subject: SL-16606: Add profiler category LOGGING

---
 indra/llcommon/llerror.cpp | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)

(limited to 'indra')

diff --git a/indra/llcommon/llerror.cpp b/indra/llcommon/llerror.cpp
index 17a5ec5776..2fae9fdfaa 100644
--- a/indra/llcommon/llerror.cpp
+++ b/indra/llcommon/llerror.cpp
@@ -109,7 +109,7 @@ namespace {
 		virtual void recordMessage(LLError::ELevel level,
 									const std::string& message) override
 		{
-            LL_PROFILE_ZONE_SCOPED
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING
 			int syslogPriority = LOG_CRIT;
 			switch (level) {
 				case LLError::LEVEL_DEBUG:	syslogPriority = LOG_DEBUG;	break;
@@ -167,7 +167,7 @@ namespace {
         virtual void recordMessage(LLError::ELevel level,
                                     const std::string& message) override
         {
-            LL_PROFILE_ZONE_SCOPED
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING
             if (LLError::getAlwaysFlush())
             {
                 mFile << message << std::endl;
@@ -234,7 +234,7 @@ namespace {
 		virtual void recordMessage(LLError::ELevel level,
 					   const std::string& message) override
 		{
-            LL_PROFILE_ZONE_SCOPED
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING
             // The default colors for error, warn and debug are now a bit more pastel
             // and easier to read on the default (black) terminal background but you 
             // now have the option to set the color of each via an environment variables:
@@ -274,7 +274,7 @@ namespace {
 
         LL_FORCE_INLINE void writeANSI(const std::string& ansi_code, const std::string& message)
 		{
-            LL_PROFILE_ZONE_SCOPED
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING
             static std::string s_ansi_bold = createBoldANSI();  // bold text
             static std::string s_ansi_reset = createResetANSI();  // reset
 			// ANSI color code escape sequence, message, and reset in one fprintf call
@@ -311,7 +311,7 @@ namespace {
 		virtual void recordMessage(LLError::ELevel level,
 								   const std::string& message) override
 		{
-            LL_PROFILE_ZONE_SCOPED
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING
 			mBuffer->addLine(message);
 		}
 	
@@ -338,7 +338,7 @@ namespace {
 		virtual void recordMessage(LLError::ELevel level,
 								   const std::string& message) override
 		{
-            LL_PROFILE_ZONE_SCOPED
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING
 			debugger_print(message);
 		}
 	};
@@ -1220,7 +1220,7 @@ namespace
 
 	void writeToRecorders(const LLError::CallSite& site, const std::string& message)
 	{
-        LL_PROFILE_ZONE_SCOPED
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING
 		LLError::ELevel level = site.mLevel;
 		SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig();
 
@@ -1355,7 +1355,7 @@ namespace LLError
 
 	bool Log::shouldLog(CallSite& site)
 	{
-        LL_PROFILE_ZONE_SCOPED
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING
 		LLMutexTrylock lock(getMutex<LOG_MUTEX>(), 5);
 		if (!lock.isLocked())
 		{
@@ -1400,7 +1400,7 @@ namespace LLError
 
 	void Log::flush(const std::ostringstream& out, const CallSite& site)
 	{
-        LL_PROFILE_ZONE_SCOPED
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING
 		LLMutexTrylock lock(getMutex<LOG_MUTEX>(),5);
 		if (!lock.isLocked())
 		{
-- 
cgit v1.2.3


From a0e18190893a4f722c5b718040736f0a122fb026 Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Thu, 13 Jan 2022 12:21:27 -0800
Subject: SL-16606: Add profiler category MATERIAL

---
 indra/newview/lldrawpoolmaterials.cpp | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/lldrawpoolmaterials.cpp b/indra/newview/lldrawpoolmaterials.cpp
index fd5850084b..135770c99c 100644
--- a/indra/newview/lldrawpoolmaterials.cpp
+++ b/indra/newview/lldrawpoolmaterials.cpp
@@ -54,6 +54,8 @@ S32 LLDrawPoolMaterials::getNumDeferredPasses()
 
 void LLDrawPoolMaterials::beginDeferredPass(S32 pass)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_MATERIAL;
+
     bool rigged = false;
     if (pass >= 12)
     { 
@@ -108,13 +110,11 @@ void LLDrawPoolMaterials::beginDeferredPass(S32 pass)
     }
 
 	diffuse_channel = mShader->enableTexture(LLShaderMgr::DIFFUSE_MAP);
-		
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_MATERIALS);
 }
 
 void LLDrawPoolMaterials::endDeferredPass(S32 pass)
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_MATERIALS);
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_MATERIAL;
 
 	mShader->unbind();
 
@@ -123,7 +123,7 @@ void LLDrawPoolMaterials::endDeferredPass(S32 pass)
 
 void LLDrawPoolMaterials::renderDeferred(S32 pass)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_MATERIAL;
 	static const U32 type_list[] = 
 	{
 		LLRenderPass::PASS_MATERIAL,
@@ -187,7 +187,7 @@ void LLDrawPoolMaterials::renderDeferred(S32 pass)
 		mShader->uniform1f(LLShaderMgr::EMISSIVE_BRIGHTNESS, params.mFullbright ? 1.f : 0.f);
 
         {
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_MATERIAL;
             pushMaterialsBatch(params, mask, rigged);
         }
 	}
@@ -205,7 +205,7 @@ void LLDrawPoolMaterials::bindNormalMap(LLViewerTexture* tex)
 
 void LLDrawPoolMaterials::pushMaterialsBatch(LLDrawInfo& params, U32 mask, bool rigged)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_MATERIAL;
 	applyModelMatrix(params);
 	
 	bool tex_setup = false;
-- 
cgit v1.2.3


From 18381104f0c6da7d150cfa89d49cb2b4ea24b844 Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Thu, 13 Jan 2022 12:24:07 -0800
Subject: SL-16606: Add profiler category MEDIA

---
 indra/newview/llviewermedia.cpp | 20 ++++++++++----------
 1 file changed, 10 insertions(+), 10 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp
index 0a0a3f905a..63f57e81cc 100644
--- a/indra/newview/llviewermedia.cpp
+++ b/indra/newview/llviewermedia.cpp
@@ -649,7 +649,7 @@ void LLViewerMedia::onIdle(void *dummy_arg)
 //////////////////////////////////////////////////////////////////////////////////////////
 void LLViewerMedia::updateMedia(void *dummy_arg)
 {
-	LL_RECORD_BLOCK_TIME(FTM_MEDIA_UPDATE);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_MEDIA; //LL_RECORD_BLOCK_TIME(FTM_MEDIA_UPDATE);
 
 	// Enable/disable the plugin read thread
 	LLPluginProcessParent::setUseReadThread(gSavedSettings.getBOOL("PluginUseReadThread"));
@@ -666,7 +666,7 @@ void LLViewerMedia::updateMedia(void *dummy_arg)
 	impl_list::iterator end = sViewerMediaImplList.end();
 
 	{
-		LL_RECORD_BLOCK_TIME(FTM_MEDIA_UPDATE_INTEREST);
+        LL_PROFILE_ZONE_NAMED_CATEGORY_MEDIA("media update interest"); //LL_RECORD_BLOCK_TIME(FTM_MEDIA_UPDATE_INTEREST);
 		for(; iter != end;)
 		{
 			LLViewerMediaImpl* pimpl = *iter++;
@@ -678,12 +678,12 @@ void LLViewerMedia::updateMedia(void *dummy_arg)
 	// Let the spare media source actually launch
 	if(mSpareBrowserMediaSource)
 	{
-		LL_RECORD_BLOCK_TIME(FTM_MEDIA_SPARE_IDLE);
+        LL_PROFILE_ZONE_NAMED_CATEGORY_MEDIA("media spare idle"); //LL_RECORD_BLOCK_TIME(FTM_MEDIA_SPARE_IDLE);
 		mSpareBrowserMediaSource->idle();
 	}
 
 	{
-		LL_RECORD_BLOCK_TIME(FTM_MEDIA_SORT);
+        LL_PROFILE_ZONE_NAMED_CATEGORY_MEDIA("media sort"); //LL_RECORD_BLOCK_TIME(FTM_MEDIA_SORT);
 		// Sort the static instance list using our interest criteria
 		sViewerMediaImplList.sort(priorityComparitor);
 	}
@@ -715,7 +715,7 @@ void LLViewerMedia::updateMedia(void *dummy_arg)
 	// If max_normal + max_low is less than max_instances, things will tend to get unloaded instead of being set to slideshow.
 
 	{
-		LL_RECORD_BLOCK_TIME(FTM_MEDIA_MISC);
+        LL_PROFILE_ZONE_NAMED_CATEGORY_MEDIA("media misc"); //LL_RECORD_BLOCK_TIME(FTM_MEDIA_MISC);
 		for(; iter != end; iter++)
 		{
 			LLViewerMediaImpl* pimpl = *iter;
@@ -900,7 +900,7 @@ void LLViewerMedia::updateMedia(void *dummy_arg)
 	}
 	else
 	{
-		LL_RECORD_BLOCK_TIME(FTM_MEDIA_SORT2);
+        LL_PROFILE_ZONE_NAMED_CATEGORY_MEDIA("media sort2"); // LL_RECORD_BLOCK_TIME(FTM_MEDIA_SORT2);
 		// Use a distance-based sort for proximity values.
 		std::stable_sort(proximity_order.begin(), proximity_order.end(), proximity_comparitor);
 	}
@@ -2798,7 +2798,7 @@ static LLTrace::BlockTimerStatHandle FTM_MEDIA_SET_SUBIMAGE("Set Subimage");
 
 void LLViewerMediaImpl::update()
 {
-	LL_RECORD_BLOCK_TIME(FTM_MEDIA_DO_UPDATE);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_MEDIA; //LL_RECORD_BLOCK_TIME(FTM_MEDIA_DO_UPDATE);
 	if(mMediaSource == NULL)
 	{
 		if(mPriority == LLPluginClassMedia::PRIORITY_UNLOADED)
@@ -2896,7 +2896,7 @@ void LLViewerMediaImpl::update()
 
 				U8* data = NULL;
 				{
-					LL_RECORD_BLOCK_TIME(FTM_MEDIA_GET_DATA);
+					LL_PROFILE_ZONE_NAMED_CATEGORY_MEDIA("media get data"); //LL_RECORD_BLOCK_TIME(FTM_MEDIA_GET_DATA);
 					data = mMediaSource->getBitsData();
 				}
 
@@ -2907,7 +2907,7 @@ void LLViewerMediaImpl::update()
 					data += ( y_pos * mMediaSource->getTextureDepth() );
 
 					{
-						LL_RECORD_BLOCK_TIME(FTM_MEDIA_SET_SUBIMAGE);
+						LL_PROFILE_ZONE_NAMED_CATEGORY_MEDIA("media set subimage"); //LL_RECORD_BLOCK_TIME(FTM_MEDIA_SET_SUBIMAGE);
 									placeholder_image->setSubImage(
 									data,
 									mMediaSource->getBitsWidth(),
@@ -3515,7 +3515,7 @@ static LLTrace::BlockTimerStatHandle FTM_MEDIA_CALCULATE_INTEREST("Calculate Int
 
 void LLViewerMediaImpl::calculateInterest()
 {
-	LL_RECORD_BLOCK_TIME(FTM_MEDIA_CALCULATE_INTEREST);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_MEDIA; //LL_RECORD_BLOCK_TIME(FTM_MEDIA_CALCULATE_INTEREST);
 	LLViewerMediaTexture* texture = LLViewerTextureManager::findMediaTexture( mTextureId );
 
 	if(texture != NULL)
-- 
cgit v1.2.3


From 7200f9fb2dfb106e0afe36b54cbc9fb826de7344 Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Thu, 13 Jan 2022 12:25:21 -0800
Subject: SL-16606: Add profiler category MEMORY

---
 indra/llcommon/llcommon.cpp |  4 ++--
 indra/llcommon/llmemory.h   | 20 ++++++++++----------
 2 files changed, 12 insertions(+), 12 deletions(-)

(limited to 'indra')

diff --git a/indra/llcommon/llcommon.cpp b/indra/llcommon/llcommon.cpp
index 25a809dad2..d2c4e66160 100644
--- a/indra/llcommon/llcommon.cpp
+++ b/indra/llcommon/llcommon.cpp
@@ -42,7 +42,7 @@ void *operator new(size_t size)
     void* ptr;
     if (gProfilerEnabled)
     {
-        LL_PROFILE_ZONE_SCOPED;
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY;
         ptr = (malloc)(size);
     }
     else
@@ -62,7 +62,7 @@ void operator delete(void *ptr) noexcept
     TracyFree(ptr);
     if (gProfilerEnabled)
     {
-        LL_PROFILE_ZONE_SCOPED;
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY;
         (free)(ptr);
     }
     else
diff --git a/indra/llcommon/llmemory.h b/indra/llcommon/llmemory.h
index 41023b4ba4..ac6c969d70 100644
--- a/indra/llcommon/llmemory.h
+++ b/indra/llcommon/llmemory.h
@@ -136,7 +136,7 @@ public:                                     \
 #else
 	inline void* ll_aligned_malloc_fallback( size_t size, int align )
 	{
-        LL_PROFILE_ZONE_SCOPED;
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY;
 	#if defined(LL_WINDOWS)
         void* ret = _aligned_malloc(size, align);
 	#else
@@ -157,7 +157,7 @@ public:                                     \
 
 	inline void ll_aligned_free_fallback( void* ptr )
 	{
-        LL_PROFILE_ZONE_SCOPED;
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY;
         LL_PROFILE_FREE(ptr);
 	#if defined(LL_WINDOWS)
 		_aligned_free(ptr);
@@ -174,7 +174,7 @@ public:                                     \
 
 inline void* ll_aligned_malloc_16(size_t size) // returned hunk MUST be freed with ll_aligned_free_16().
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY;
 #if defined(LL_WINDOWS)
 	void* ret = _aligned_malloc(size, 16);
 #elif defined(LL_DARWIN)
@@ -190,7 +190,7 @@ inline void* ll_aligned_malloc_16(size_t size) // returned hunk MUST be freed wi
 
 inline void ll_aligned_free_16(void *p)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY;
     LL_PROFILE_FREE(p);
 #if defined(LL_WINDOWS)
 	_aligned_free(p);
@@ -203,7 +203,7 @@ inline void ll_aligned_free_16(void *p)
 
 inline void* ll_aligned_realloc_16(void* ptr, size_t size, size_t old_size) // returned hunk MUST be freed with ll_aligned_free_16().
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY;
     LL_PROFILE_FREE(ptr);
 #if defined(LL_WINDOWS)
 	void* ret = _aligned_realloc(ptr, size, 16);
@@ -228,7 +228,7 @@ inline void* ll_aligned_realloc_16(void* ptr, size_t size, size_t old_size) // r
 
 inline void* ll_aligned_malloc_32(size_t size) // returned hunk MUST be freed with ll_aligned_free_32().
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY;
 #if defined(LL_WINDOWS)
 	void* ret = _aligned_malloc(size, 32);
 #elif defined(LL_DARWIN)
@@ -244,7 +244,7 @@ inline void* ll_aligned_malloc_32(size_t size) // returned hunk MUST be freed wi
 
 inline void ll_aligned_free_32(void *p)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY;
     LL_PROFILE_FREE(p);
 #if defined(LL_WINDOWS)
 	_aligned_free(p);
@@ -259,7 +259,7 @@ inline void ll_aligned_free_32(void *p)
 template<size_t ALIGNMENT>
 LL_FORCE_INLINE void* ll_aligned_malloc(size_t size)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY;
     void* ret;
 	if (LL_DEFAULT_HEAP_ALIGN % ALIGNMENT == 0)
 	{
@@ -284,7 +284,7 @@ LL_FORCE_INLINE void* ll_aligned_malloc(size_t size)
 template<size_t ALIGNMENT>
 LL_FORCE_INLINE void ll_aligned_free(void* ptr)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY;
 	if (ALIGNMENT == LL_DEFAULT_HEAP_ALIGN)
 	{
         LL_PROFILE_FREE(ptr);
@@ -309,7 +309,7 @@ LL_FORCE_INLINE void ll_aligned_free(void* ptr)
 //
 inline void ll_memcpy_nonaliased_aligned_16(char* __restrict dst, const char* __restrict src, size_t bytes)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY;
 	assert(src != NULL);
 	assert(dst != NULL);
 	assert(bytes > 0);
-- 
cgit v1.2.3


From b54d922ad64b1b87463a28d40dda8661bca1b0dc Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Thu, 13 Jan 2022 12:28:20 -0800
Subject: SL-16606: Add profiler category NETWORK

---
 indra/llmessage/llpumpio.cpp         |  6 +++---
 indra/newview/llappviewer.cpp        |  7 ++++---
 indra/newview/llmeshrepository.cpp   |  8 ++++----
 indra/newview/llviewerobjectlist.cpp | 14 +++++++-------
 indra/newview/llworld.cpp            |  6 +++---
 5 files changed, 21 insertions(+), 20 deletions(-)

(limited to 'indra')

diff --git a/indra/llmessage/llpumpio.cpp b/indra/llmessage/llpumpio.cpp
index 35365665f6..44720f0015 100644
--- a/indra/llmessage/llpumpio.cpp
+++ b/indra/llmessage/llpumpio.cpp
@@ -428,7 +428,7 @@ LLPumpIO::current_chain_t LLPumpIO::removeRunningChain(LLPumpIO::current_chain_t
 //timeout is in microseconds
 void LLPumpIO::pump(const S32& poll_timeout)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
 	//LL_INFOS() << "LLPumpIO::pump()" << LL_ENDL;
 
 	// Run any pending runners.
@@ -506,7 +506,7 @@ void LLPumpIO::pump(const S32& poll_timeout)
 		S32 count = 0;
 		S32 client_id = 0;
         {
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
             apr_pollset_poll(mPollset, poll_timeout, &count, &poll_fd);
         }
 		PUMP_DEBUG;
@@ -736,7 +736,7 @@ bool LLPumpIO::respond(
 
 void LLPumpIO::callback()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
 	//LL_INFOS() << "LLPumpIO::callback()" << LL_ENDL;
 	if(true)
 	{
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index dc973e9154..a2391ef889 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -4785,7 +4785,7 @@ void LLAppViewer::idle()
 
 	if (!gDisconnected)
 	{
-		LL_RECORD_BLOCK_TIME(FTM_NETWORK);
+		LL_PROFILE_ZONE_NAMED_CATEGORY_NETWORK("network"); //LL_RECORD_BLOCK_TIME(FTM_NETWORK);
 		// Update spaceserver timeinfo
 	    LLWorld::getInstance()->setSpaceTimeUSec(LLWorld::getInstance()->getSpaceTimeUSec() + LLUnits::Seconds::fromValue(dt_raw));
 
@@ -4817,7 +4817,7 @@ void LLAppViewer::idle()
 							|| (agent_force_update_time > (1.0f / (F32) AGENT_FORCE_UPDATES_PER_SECOND));
 		if (force_update || (agent_update_time > (1.0f / (F32) AGENT_UPDATES_PER_SECOND)))
 		{
-			LL_RECORD_BLOCK_TIME(FTM_AGENT_UPDATE);
+			LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; //LL_RECORD_BLOCK_TIME(FTM_AGENT_UPDATE);
 			// Send avatar and camera info
 			mLastAgentControlFlags = gAgent.getControlFlags();
 			mLastAgentForceUpdate = force_update ? 0 : agent_force_update_time;
@@ -5337,6 +5337,7 @@ static LLTrace::BlockTimerStatHandle FTM_CHECK_REGION_CIRCUIT("Check Region Circ
 
 void LLAppViewer::idleNetwork()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
 	pingMainloopTimeout("idleNetwork");
 
 	gObjectList.mNumNewObjects = 0;
@@ -5344,7 +5345,7 @@ void LLAppViewer::idleNetwork()
 
 	if (!gSavedSettings.getBOOL("SpeedTest"))
 	{
-		LL_RECORD_BLOCK_TIME(FTM_IDLE_NETWORK); // decode
+		LL_PROFILE_ZONE_NAMED_CATEGORY_NETWORK("idle network"); //LL_RECORD_BLOCK_TIME(FTM_IDLE_NETWORK); // decode
 
 		LLTimer check_message_timer;
 		//  Read all available packets from network
diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp
index 8cec08394d..d28e929b48 100644
--- a/indra/newview/llmeshrepository.cpp
+++ b/indra/newview/llmeshrepository.cpp
@@ -3639,7 +3639,7 @@ S32 LLMeshRepository::update()
 
 S32 LLMeshRepository::loadMesh(LLVOVolume* vobj, const LLVolumeParams& mesh_params, S32 detail, S32 last_lod)
 {
-	LL_RECORD_BLOCK_TIME(FTM_MESH_FETCH);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; //LL_LL_RECORD_BLOCK_TIME(FTM_MESH_FETCH);
 	
 	// Manage time-to-load metrics for mesh download operations.
 	metricsProgress(1);
@@ -3722,7 +3722,7 @@ S32 LLMeshRepository::loadMesh(LLVOVolume* vobj, const LLVolumeParams& mesh_para
 
 void LLMeshRepository::notifyLoadedMeshes()
 { //called from main thread
-	LL_RECORD_BLOCK_TIME(FTM_MESH_FETCH);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; //LL_RECORD_BLOCK_TIME(FTM_MESH_FETCH);
 
     // GetMesh2 operation with keepalives, etc.  With pipelining,
     // we'll increase this.  See llappcorehttp and llcorehttp for
@@ -4097,7 +4097,7 @@ const LLMeshSkinInfo* LLMeshRepository::getSkinInfo(const LLUUID& mesh_id, const
 
 void LLMeshRepository::fetchPhysicsShape(const LLUUID& mesh_id)
 {
-	LL_RECORD_BLOCK_TIME(FTM_MESH_FETCH);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; //LL_RECORD_BLOCK_TIME(FTM_MESH_FETCH);
 
 	if (mesh_id.notNull())
 	{
@@ -4126,7 +4126,7 @@ void LLMeshRepository::fetchPhysicsShape(const LLUUID& mesh_id)
 
 LLModel::Decomposition* LLMeshRepository::getDecomposition(const LLUUID& mesh_id)
 {
-	LL_RECORD_BLOCK_TIME(FTM_MESH_FETCH);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; //LL_RECORD_BLOCK_TIME(FTM_MESH_FETCH);
 
 	LLModel::Decomposition* ret = NULL;
 
diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp
index 630861f6be..0e585f13fc 100644
--- a/indra/newview/llviewerobjectlist.cpp
+++ b/indra/newview/llviewerobjectlist.cpp
@@ -169,7 +169,7 @@ U64 LLViewerObjectList::getIndex(const U32 local_id,
 
 BOOL LLViewerObjectList::removeFromLocalIDTable(const LLViewerObject* objectp)
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
 
 	if(objectp && objectp->getRegion())
 	{
@@ -306,7 +306,7 @@ static LLTrace::BlockTimerStatHandle FTM_PROCESS_OBJECTS("Process Objects");
 
 LLViewerObject* LLViewerObjectList::processObjectUpdateFromCache(LLVOCacheEntry* entry, LLViewerRegion* regionp)
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
 
 	LLDataPacker *cached_dpp = entry->getDP();
 
@@ -851,7 +851,7 @@ void LLViewerObjectList::updateApparentAngles(LLAgent &agent)
 
 void LLViewerObjectList::update(LLAgent &agent)
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
 
 	// Update globals
 	LLViewerObject::setVelocityInterpolate( gSavedSettings.getBOOL("VelocityInterpolate") );
@@ -1296,7 +1296,7 @@ void LLViewerObjectList::clearDebugText()
 
 void LLViewerObjectList::cleanupReferences(LLViewerObject *objectp)
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
 
 	bool new_dead_object = true;
 	if (mDeadObjects.find(objectp->mID) != mDeadObjects.end())
@@ -1641,7 +1641,7 @@ void LLViewerObjectList::onPhysicsFlagsFetchFailure(const LLUUID& object_id)
 
 void LLViewerObjectList::shiftObjects(const LLVector3 &offset)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
 	// This is called when we shift our origin when we cross region boundaries...
 	// We need to update many object caches, I'll document this more as I dig through the code
 	// cleaning things out...
@@ -1838,7 +1838,7 @@ void LLViewerObjectList::renderObjectBounds(const LLVector3 &center)
 
 void LLViewerObjectList::generatePickList(LLCamera &camera)
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
 
 		LLViewerObject *objectp;
 		S32 i;
@@ -2165,7 +2165,7 @@ void LLViewerObjectList::orphanize(LLViewerObject *childp, U32 parent_id, U32 ip
 
 void LLViewerObjectList::findOrphans(LLViewerObject* objectp, U32 ip, U32 port)
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
 
 	if (objectp->isDead())
 	{
diff --git a/indra/newview/llworld.cpp b/indra/newview/llworld.cpp
index d7f16713d2..343aea5721 100644
--- a/indra/newview/llworld.cpp
+++ b/indra/newview/llworld.cpp
@@ -1152,7 +1152,7 @@ void LLWorld::disconnectRegions()
 
 void process_enable_simulator(LLMessageSystem *msg, void **user_data)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
 	// enable the appropriate circuit for this simulator and 
 	// add its values into the gSimulator structure
 	U64		handle;
@@ -1227,7 +1227,7 @@ public:
 // Called in response to "DisableSimulator" message.
 void process_disable_simulator(LLMessageSystem *mesgsys, void **user_data)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
 
     LLHost host = mesgsys->getSender();
 
@@ -1289,7 +1289,7 @@ void send_agent_pause()
 
 void send_agent_resume()
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK
 	// Note: used to check for LLWorld initialization before it became a singleton.
 	// Rather than just remove this check I'm changing it to assure that the message 
 	// system has been initialized. -MG
-- 
cgit v1.2.3


From e613e30499467090ed2f613ca0518173cfa91d21 Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Thu, 13 Jan 2022 12:30:39 -0800
Subject: SL-16606: Add profiler category OCTREE

---
 indra/newview/llvieweroctree.cpp | 24 ++++++++++++------------
 1 file changed, 12 insertions(+), 12 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llvieweroctree.cpp b/indra/newview/llvieweroctree.cpp
index 8d6f4d2729..5faab21ef1 100644
--- a/indra/newview/llvieweroctree.cpp
+++ b/indra/newview/llvieweroctree.cpp
@@ -544,7 +544,7 @@ void LLViewerOctreeGroup::unbound()
 //virtual 
 void LLViewerOctreeGroup::rebound()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_OCTREE;
 	if (!isDirty())
 	{	
 		return;
@@ -1053,7 +1053,7 @@ void LLOcclusionCullingGroup::clearOcclusionState(U32 state, S32 mode /* = STATE
 
 BOOL LLOcclusionCullingGroup::earlyFail(LLCamera* camera, const LLVector4a* bounds)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_OCTREE;
 	if (camera->getOrigin().isExactlyZero())
 	{
 		return FALSE;
@@ -1104,7 +1104,7 @@ void LLOcclusionCullingGroup::checkOcclusion()
 {
     if (LLPipeline::sUseOcclusion < 2) return;  // 0 - NoOcclusion, 1 = ReadOnly, 2 = ModifyOcclusionState  TODO: DJH 11-2021 ENUM this
 
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_OCTREE;
     LLOcclusionCullingGroup* parent = (LLOcclusionCullingGroup*)getParent();
     if (parent && parent->isOcclusionState(LLOcclusionCullingGroup::OCCLUDED))
     {	//if the parent has been marked as occluded, the child is implicitly occluded
@@ -1126,7 +1126,7 @@ void LLOcclusionCullingGroup::checkOcclusion()
         {
             GLuint available;
             {
-                LL_PROFILE_ZONE_NAMED("co - query available");
+                LL_PROFILE_ZONE_NAMED_CATEGORY_OCTREE("co - query available");
                 glGetQueryObjectuivARB(mOcclusionQuery[LLViewerCamera::sCurCameraID], GL_QUERY_RESULT_AVAILABLE_ARB, &available);
             }
 
@@ -1134,7 +1134,7 @@ void LLOcclusionCullingGroup::checkOcclusion()
             {   
                 GLuint query_result;    // Will be # samples drawn, or a boolean depending on mHasOcclusionQuery2 (both are type GLuint)
                 {
-                    LL_PROFILE_ZONE_NAMED("co - query result");
+                    LL_PROFILE_ZONE_NAMED_CATEGORY_OCTREE("co - query result");
                     glGetQueryObjectuivARB(mOcclusionQuery[LLViewerCamera::sCurCameraID], GL_QUERY_RESULT_ARB, &query_result);
                 }
 #if LL_TRACK_PENDING_OCCLUSION_QUERIES
@@ -1177,7 +1177,7 @@ void LLOcclusionCullingGroup::checkOcclusion()
 
 void LLOcclusionCullingGroup::doOcclusion(LLCamera* camera, const LLVector4a* shift)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_OCTREE;
 	if (mSpatialPartition->isOcclusionEnabled() && LLPipeline::sUseOcclusion > 1)
 	{
 		//move mBounds to the agent space if necessary
@@ -1198,7 +1198,7 @@ void LLOcclusionCullingGroup::doOcclusion(LLCamera* camera, const LLVector4a* sh
 		// Don't cull hole/edge water, unless we have the GL_ARB_depth_clamp extension
 		if (earlyFail(camera, bounds))
 		{
-            LL_PROFILE_ZONE_NAMED("doOcclusion - early fail");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_OCTREE("doOcclusion - early fail");
 			setOcclusionState(LLOcclusionCullingGroup::DISCARD_QUERY);
 			assert_states_valid(this);
 			clearOcclusionState(LLOcclusionCullingGroup::OCCLUDED, LLOcclusionCullingGroup::STATE_MODE_DIFF);
@@ -1209,7 +1209,7 @@ void LLOcclusionCullingGroup::doOcclusion(LLCamera* camera, const LLVector4a* sh
 			if (!isOcclusionState(QUERY_PENDING) || isOcclusionState(DISCARD_QUERY))
 			{
 				{ //no query pending, or previous query to be discarded
-                    LL_PROFILE_ZONE_NAMED("doOcclusion - render");
+                    LL_PROFILE_ZONE_NAMED_CATEGORY_OCTREE("doOcclusion - render");
 
 					if (!mOcclusionQuery[LLViewerCamera::sCurCameraID])
 					{
@@ -1237,7 +1237,7 @@ void LLOcclusionCullingGroup::doOcclusion(LLCamera* camera, const LLVector4a* sh
 					add(sOcclusionQueries, 1);
 
 					{
-                        LL_PROFILE_ZONE_NAMED("doOcclusion - push");
+                        LL_PROFILE_ZONE_NAMED_CATEGORY_OCTREE("doOcclusion - push");
 						
 						//store which frame this query was issued on
 						mOcclusionIssued[LLViewerCamera::sCurCameraID] = gFrameCount;
@@ -1254,7 +1254,7 @@ void LLOcclusionCullingGroup::doOcclusion(LLCamera* camera, const LLVector4a* sh
 
 						if (!use_depth_clamp && mSpatialPartition->mDrawableType == LLPipeline::RENDER_TYPE_VOIDWATER)
 						{
-                            LL_PROFILE_ZONE_NAMED("doOcclusion - draw water");
+                            LL_PROFILE_ZONE_NAMED_CATEGORY_OCTREE("doOcclusion - draw water");
 
 							LLGLSquashToFarClip squash;
 							if (camera->getOrigin().isExactlyZero())
@@ -1269,7 +1269,7 @@ void LLOcclusionCullingGroup::doOcclusion(LLCamera* camera, const LLVector4a* sh
 						}
 						else
 						{
-                            LL_PROFILE_ZONE_NAMED("doOcclusion - draw");
+                            LL_PROFILE_ZONE_NAMED_CATEGORY_OCTREE("doOcclusion - draw");
 							if (camera->getOrigin().isExactlyZero())
 							{ //origin is invalid, draw entire box
 								gPipeline.mCubeVB->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, 0);
@@ -1286,7 +1286,7 @@ void LLOcclusionCullingGroup::doOcclusion(LLCamera* camera, const LLVector4a* sh
 				}
 
 				{
-                    LL_PROFILE_ZONE_NAMED("doOcclusion - set state");
+                    LL_PROFILE_ZONE_NAMED_CATEGORY_OCTREE("doOcclusion - set state");
 					setOcclusionState(LLOcclusionCullingGroup::QUERY_PENDING);
 					clearOcclusionState(LLOcclusionCullingGroup::DISCARD_QUERY);
 				}
-- 
cgit v1.2.3


From 7cd173cd13f68cbe3d25e0290845d6fee370937a Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Thu, 13 Jan 2022 12:34:23 -0800
Subject: SL-16606: Add profiler category PIPELINE

---
 indra/llrender/llgl.cpp     |   6 +--
 indra/llrender/llrender.cpp |   6 +--
 indra/newview/llworld.cpp   |   4 +-
 indra/newview/pipeline.cpp  | 102 ++++++++++++++++++++++----------------------
 4 files changed, 59 insertions(+), 59 deletions(-)

(limited to 'indra')

diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp
index 18a79d5264..12da961cef 100644
--- a/indra/llrender/llgl.cpp
+++ b/indra/llrender/llgl.cpp
@@ -1868,7 +1868,7 @@ void LLGLState::checkTextureChannels(const std::string& msg)
 LLGLState::LLGLState(LLGLenum state, S32 enabled) :
 	mState(state), mWasEnabled(FALSE), mIsEnabled(FALSE)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
 	switch (state)
 	{
 		case GL_ALPHA_TEST:
@@ -1925,7 +1925,7 @@ void LLGLState::setEnabled(S32 enabled)
 
 LLGLState::~LLGLState() 
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
 	stop_glerror();
 	if (mState)
 	{
@@ -2184,7 +2184,7 @@ void LLGLNamePool::cleanup()
 
 GLuint LLGLNamePool::allocate()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
 #if LL_GL_NAME_POOLING
 	for (name_list_t::iterator iter = mNameList.begin(); iter != mNameList.end(); ++iter)
 	{
diff --git a/indra/llrender/llrender.cpp b/indra/llrender/llrender.cpp
index 8b4f250894..3b46eef1b4 100644
--- a/indra/llrender/llrender.cpp
+++ b/indra/llrender/llrender.cpp
@@ -193,7 +193,7 @@ void LLTexUnit::bindFast(LLTexture* texture)
 
 bool LLTexUnit::bind(LLTexture* texture, bool for_rendering, bool forceBind)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
 	stop_glerror();
 	if (mIndex >= 0)
 	{
@@ -1483,7 +1483,7 @@ LLLightState* LLRender::getLight(U32 index)
 
 void LLRender::setAmbientLightColor(const LLColor4& color)
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE
 	if (color != mAmbientLightColor)
 	{
 		++mLightHash;
@@ -1558,7 +1558,7 @@ void LLRender::flush()
 {
 	if (mCount > 0)
 	{
-        LL_PROFILE_ZONE_SCOPED;
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
 		if (!mUIOffset.empty())
 		{
 			sUICalls++;
diff --git a/indra/newview/llworld.cpp b/indra/newview/llworld.cpp
index 343aea5721..6746a3a902 100644
--- a/indra/newview/llworld.cpp
+++ b/indra/newview/llworld.cpp
@@ -885,7 +885,7 @@ void LLWorld::waterHeightRegionInfo(std::string const& sim_name, F32 water_heigh
 
 void LLWorld::precullWaterObjects(LLCamera& camera, LLCullResult* cull, bool include_void_water)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
 	if (!gAgent.getRegion())
 	{
 		return;
@@ -1079,7 +1079,7 @@ void LLWorld::updateWaterObjects()
 
 void LLWorld::shiftRegions(const LLVector3& offset)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
 	for (region_list_t::const_iterator i = getRegionList().begin(); i != getRegionList().end(); ++i)
 	{
 		LLViewerRegion* region = *i;
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index 52b8153980..b342c46ce1 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -1224,7 +1224,7 @@ void LLPipeline::releaseShadowTargets()
 
 void LLPipeline::createGLBuffers()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
     stop_glerror();
 	assertInitialized();
 
@@ -1491,7 +1491,7 @@ public:
 // Called when a texture changes # of channels (causes faces to move to alpha pool)
 void LLPipeline::dirtyPoolObjectTextures(const std::set<LLViewerFetchedTexture*>& textures)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
 	assertInitialized();
 
 	// *TODO: This is inefficient and causes frame spikes; need a better way to do this
@@ -1705,7 +1705,7 @@ void LLPipeline::allocDrawable(LLViewerObject *vobj)
 
 void LLPipeline::unlinkDrawable(LLDrawable *drawable)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
 
 	assertInitialized();
 
@@ -1770,7 +1770,7 @@ void LLPipeline::unlinkDrawable(LLDrawable *drawable)
 //static
 void LLPipeline::removeMutedAVsLights(LLVOAvatar* muted_avatar)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
 	for (light_set_t::iterator iter = gPipeline.mNearbyLights.begin();
 		 iter != gPipeline.mNearbyLights.end(); iter++)
 	{
@@ -1798,7 +1798,7 @@ U32 LLPipeline::addObject(LLViewerObject *vobj)
 
 void LLPipeline::createObjects(F32 max_dtime)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
 
 	LLTimer update_timer;
 
@@ -1822,7 +1822,7 @@ void LLPipeline::createObjects(F32 max_dtime)
 
 void LLPipeline::createObject(LLViewerObject* vobj)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
 	LLDrawable* drawablep = vobj->mDrawable;
 
 	if (!drawablep)
@@ -1860,7 +1860,7 @@ void LLPipeline::createObject(LLViewerObject* vobj)
 
 void LLPipeline::resetFrameStats()
 {
-	LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
 	assertInitialized();
 
 	sCompiles        = 0;
@@ -1971,7 +1971,7 @@ void LLPipeline::updateMovedList(LLDrawable::drawable_vector_t& moved_list)
 
 void LLPipeline::updateMove()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
 
 	if (FreezeTime)
 	{
@@ -2073,7 +2073,7 @@ void LLPipeline::grabReferences(LLCullResult& result)
 
 void LLPipeline::clearReferences()
 {
-	LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
 	sCull = NULL;
 	mGroupSaveQ1.clear();
 }
@@ -2327,7 +2327,7 @@ void LLPipeline::updateCull(LLCamera& camera, LLCullResult& result, LLPlane* pla
 	static bool can_use_occlusion = LLFeatureManager::getInstance()->isFeatureAvailable("UseOcclusion") 
 									&& gGLManager.mHasOcclusionQuery;
 
-	LL_RECORD_BLOCK_TIME(FTM_CULL);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE; //LL_RECORD_BLOCK_TIME(FTM_CULL);
 
     if (planep != nullptr)
     {
@@ -2613,7 +2613,7 @@ void LLPipeline::doOcclusion(LLCamera& camera, LLRenderTarget& source, LLRenderT
 
 void LLPipeline::doOcclusion(LLCamera& camera)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
     if (LLPipeline::sUseOcclusion > 1 && !LLSpatialPartition::sTeleportRequested &&
 		(sCull->hasOcclusionGroups() || LLVOCachePartition::sNeedsOcclusionCheck))
 	{
@@ -2700,7 +2700,7 @@ bool LLPipeline::updateDrawableGeom(LLDrawable* drawablep, bool priority)
 
 void LLPipeline::updateGL()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
 	{
 		while (!LLGLUpdate::sGLQ.empty())
 		{
@@ -2718,7 +2718,7 @@ void LLPipeline::updateGL()
 
 void LLPipeline::clearRebuildGroups()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
 	LLSpatialGroup::sg_vector_t	hudGroups;
 
 	mGroupQ1Locked = true;
@@ -2823,7 +2823,7 @@ void LLPipeline::clearRebuildDrawables()
 
 void LLPipeline::rebuildPriorityGroups()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
 	LLTimer update_timer;
 	assertInitialized();
 
@@ -2852,7 +2852,7 @@ void LLPipeline::rebuildGroups()
 		return;
 	}
 
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
 	mGroupQ2Locked = true;
 	// Iterate through some drawables on the non-priority build queue
 	S32 size = (S32) mGroupQ2.size();
@@ -3100,7 +3100,7 @@ void LLPipeline::markShift(LLDrawable *drawablep)
 
 void LLPipeline::shiftObjects(const LLVector3 &offset)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
 	assertInitialized();
 
 	glClear(GL_DEPTH_BUFFER_BIT);
@@ -3171,7 +3171,7 @@ void LLPipeline::markPartitionMove(LLDrawable* drawable)
 
 void LLPipeline::processPartitionQ()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
 	for (LLDrawable::drawable_list_t::iterator iter = mPartitionQ.begin(); iter != mPartitionQ.end(); ++iter)
 	{
 		LLDrawable* drawable = *iter;
@@ -3273,6 +3273,8 @@ void LLPipeline::markRebuild(LLDrawable *drawablep, LLDrawable::EDrawableFlags f
 
 void LLPipeline::stateSort(LLCamera& camera, LLCullResult &result)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
+
 	if (hasAnyRenderType(LLPipeline::RENDER_TYPE_AVATAR,
 					  LLPipeline::RENDER_TYPE_CONTROL_AV,
 					  LLPipeline::RENDER_TYPE_GROUND,
@@ -3287,8 +3289,6 @@ void LLPipeline::stateSort(LLCamera& camera, LLCullResult &result)
 		gPipeline.resetDrawOrders();
 	}
 
-	LL_RECORD_BLOCK_TIME(FTM_STATESORT);
-
 	//LLVertexBuffer::unbind();
 
 	grabReferences(result);
@@ -3407,7 +3407,7 @@ void LLPipeline::stateSort(LLSpatialGroup* group, LLCamera& camera)
 
 void LLPipeline::stateSort(LLSpatialBridge* bridge, LLCamera& camera, BOOL fov_changed)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
     if (bridge->getSpatialGroup()->changeLOD() || fov_changed)
 	{
 		bool force_update = false;
@@ -3417,7 +3417,7 @@ void LLPipeline::stateSort(LLSpatialBridge* bridge, LLCamera& camera, BOOL fov_c
 
 void LLPipeline::stateSort(LLDrawable* drawablep, LLCamera& camera)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
     if (!drawablep
 		|| drawablep->isDead() 
 		|| !hasRenderType(drawablep->getRenderType()))
@@ -3727,7 +3727,7 @@ void LLPipeline::touchTexture(LLViewerTexture* tex, F32 vsize)
 }
 void LLPipeline::touchTextures(LLDrawInfo* info)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
     for (int i = 0; i < info->mTextureList.size(); ++i)
     {
         touchTexture(info->mTextureList[i], info->mTextureListVSize[i]);
@@ -3740,7 +3740,7 @@ void LLPipeline::touchTextures(LLDrawInfo* info)
 
 void LLPipeline::postSort(LLCamera& camera)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
 
 	assertInitialized();
 
@@ -4249,7 +4249,7 @@ U32 LLPipeline::sCurRenderPoolType = 0 ;
 
 void LLPipeline::renderGeom(LLCamera& camera, bool forceVBOUpdate)
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_GEOMETRY);
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE; //LL_RECORD_BLOCK_TIME(FTM_RENDER_GEOMETRY);
 
 	assertInitialized();
 
@@ -4693,7 +4693,7 @@ void LLPipeline::renderGeomPostDeferred(LLCamera& camera, bool do_occlusion)
 
 void LLPipeline::renderGeomShadow(LLCamera& camera)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
     U32 cur_type = 0;
 	
 	LLGLEnable cull(GL_CULL_FACE);
@@ -4759,7 +4759,7 @@ void LLPipeline::renderGeomShadow(LLCamera& camera)
 
 void LLPipeline::addTrianglesDrawn(S32 index_count, U32 render_type)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
 	assertInitialized();
 	S32 count = 0;
 	if (render_type == LLRender::TRIANGLE_STRIP)
@@ -5471,7 +5471,7 @@ void LLPipeline::renderDebug()
 
 void LLPipeline::rebuildPools()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
 
 	assertInitialized();
 
@@ -5815,7 +5815,7 @@ void LLPipeline::removeFromQuickLookup( LLDrawPool* poolp )
 
 void LLPipeline::resetDrawOrders()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
 	assertInitialized();
 	// Iterate through all of the draw pools and rebuild them.
 	for (pool_set_t::iterator iter = mPools.begin(); iter != mPools.end(); ++iter)
@@ -7221,7 +7221,7 @@ void LLPipeline::doResetVertexBuffers(bool forced)
 		}
 	}
 
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
 	mResetVertexBuffers = false;
 
 	mCubeVB = NULL;
@@ -7310,7 +7310,7 @@ void LLPipeline::renderObjects(U32 type, U32 mask, bool texture, bool batch_text
 
 void LLPipeline::renderAlphaObjects(U32 mask, bool texture, bool batch_texture, bool rigged)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
     assertInitialized();
     gGL.loadMatrix(gGLModelView);
     gGLLastMatrix = NULL;
@@ -8039,7 +8039,7 @@ void LLPipeline::renderFinalize()
 
 void LLPipeline::bindDeferredShader(LLGLSLShader& shader, LLRenderTarget* light_target)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
 
     LLRenderTarget* deferred_target       = &mDeferredScreen;
     LLRenderTarget* deferred_depth_target = &mDeferredDepth;
@@ -8301,7 +8301,7 @@ LLVector4 pow4fsrgb(LLVector4 v, F32 f)
 
 void LLPipeline::renderDeferredLighting(LLRenderTarget *screen_target)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
     if (!sCull)
     {
         return;
@@ -8312,7 +8312,7 @@ void LLPipeline::renderDeferredLighting(LLRenderTarget *screen_target)
     LLRenderTarget *deferred_light_target = &mDeferredLight;
 
     {
-        LL_RECORD_BLOCK_TIME(FTM_RENDER_DEFERRED);
+        LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("deferred"); //LL_RECORD_BLOCK_TIME(FTM_RENDER_DEFERRED);
         LLViewerCamera *camera = LLViewerCamera::getInstance();
         {
             LLGLDepthTest depth(GL_TRUE);
@@ -8378,7 +8378,7 @@ void LLPipeline::renderDeferredLighting(LLRenderTarget *screen_target)
         {
             deferred_light_target->bindTarget();
             {  // paint shadow/SSAO light map (direct lighting lightmap)
-                LL_PROFILE_ZONE_NAMED("renderDeferredLighting - sun shadow");
+                LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("renderDeferredLighting - sun shadow");
                 bindDeferredShader(gDeferredSunProgram, deferred_light_target);
                 mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX);
                 glClearColor(1, 1, 1, 1);
@@ -8424,7 +8424,7 @@ void LLPipeline::renderDeferredLighting(LLRenderTarget *screen_target)
 
         if (RenderDeferredSSAO)
         {  // soften direct lighting lightmap
-            LL_PROFILE_ZONE_NAMED("renderDeferredLighting - soften shadow");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("renderDeferredLighting - soften shadow");
             // blur lightmap
             screen_target->bindTarget();
             glClearColor(1, 1, 1, 1);
@@ -8502,7 +8502,7 @@ void LLPipeline::renderDeferredLighting(LLRenderTarget *screen_target)
         {  // apply sunlight contribution
             LLGLSLShader &soften_shader = LLPipeline::sUnderWaterRender ? gDeferredSoftenWaterProgram : gDeferredSoftenProgram;
 
-            LL_PROFILE_ZONE_NAMED("renderDeferredLighting - atmospherics");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("renderDeferredLighting - atmospherics");
             bindDeferredShader(soften_shader);
 
             LLEnvironment &environment = LLEnvironment::instance();
@@ -8568,7 +8568,7 @@ void LLPipeline::renderDeferredLighting(LLRenderTarget *screen_target)
             LLVertexBuffer::unbind();
 
             {
-                LL_PROFILE_ZONE_NAMED("renderDeferredLighting - local lights");
+                LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("renderDeferredLighting - local lights");
                 bindDeferredShader(gDeferredLightProgram);
 
                 if (mCubeVB.isNull())
@@ -8674,7 +8674,7 @@ void LLPipeline::renderDeferredLighting(LLRenderTarget *screen_target)
 
             if (!spot_lights.empty())
             {
-                LL_PROFILE_ZONE_NAMED("renderDeferredLighting - projectors");
+                LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("renderDeferredLighting - projectors");
                 LLGLDepthTest depth(GL_TRUE, GL_FALSE);
                 bindDeferredShader(gDeferredSpotLightProgram);
 
@@ -8719,7 +8719,7 @@ void LLPipeline::renderDeferredLighting(LLRenderTarget *screen_target)
             vert[2].set(3, 1, 0);
 
             {
-                LL_PROFILE_ZONE_NAMED("renderDeferredLighting - fullscreen lights");
+                LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("renderDeferredLighting - fullscreen lights");
                 LLGLDepthTest depth(GL_FALSE);
 
                 // full screen blit
@@ -9113,7 +9113,7 @@ inline float sgn(float a)
 
 void LLPipeline::generateWaterReflection(LLCamera& camera_in)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
 
     if (!assertInitialized())
     {
@@ -9520,7 +9520,7 @@ static LLTrace::BlockTimerStatHandle FTM_SHADOW_FULLBRIGHT_ALPHA_MASKED("Fullbri
 
 void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera& shadow_cam, LLCullResult& result, bool use_shader, bool use_occlusion, U32 target_width)
 {
-    LL_RECORD_BLOCK_TIME(FTM_SHADOW_RENDER);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE; //LL_RECORD_BLOCK_TIME(FTM_SHADOW_RENDER);
 
     //disable occlusion culling for shadow passes (save setting to restore later)
     S32 occlude = LLPipeline::sUseOcclusion;
@@ -9607,7 +9607,7 @@ void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera
             gGL.setColorMask(false, false);
         }
 
-        LL_RECORD_BLOCK_TIME(FTM_SHADOW_SIMPLE);
+        LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("shadow simple"); //LL_RECORD_BLOCK_TIME(FTM_SHADOW_SIMPLE);
 
         gGL.getTexUnit(0)->disable();
         for (U32 i = 0; i < sizeof(types) / sizeof(U32); ++i)
@@ -9625,7 +9625,7 @@ void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera
 
     if (use_shader)
     {
-        LL_RECORD_BLOCK_TIME(FTM_SHADOW_GEOM);
+        LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("shadow geom"); //LL_RECORD_BLOCK_TIME(FTM_SHADOW_GEOM);
 
         gDeferredShadowProgram.unbind();
         renderGeomShadow(shadow_cam);
@@ -9634,13 +9634,13 @@ void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera
     }
     else
     {
-        LL_RECORD_BLOCK_TIME(FTM_SHADOW_GEOM);
+        LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("shadow geom"); //LL_RECORD_BLOCK_TIME(FTM_SHADOW_GEOM);
 
         renderGeomShadow(shadow_cam);
     }
 
     {
-        LL_RECORD_BLOCK_TIME(FTM_SHADOW_ALPHA);
+        LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("shadow alpha"); //LL_RECORD_BLOCK_TIME(FTM_SHADOW_ALPHA);
 
         for (int i = 0; i < 2; ++i)
         {
@@ -9656,19 +9656,19 @@ void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera
                 LLVertexBuffer::MAP_TEXTURE_INDEX;
 
             {
-                LL_RECORD_BLOCK_TIME(FTM_SHADOW_ALPHA_MASKED);
+                LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("shadow alpha masked"); //LL_RECORD_BLOCK_TIME(FTM_SHADOW_ALPHA_MASKED);
                 renderMaskedObjects(LLRenderPass::PASS_ALPHA_MASK, mask, TRUE, TRUE, rigged);
             }
 
             {
-                LL_RECORD_BLOCK_TIME(FTM_SHADOW_ALPHA_BLEND);
+                LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("shadow alpha blend"); //LL_RECORD_BLOCK_TIME(FTM_SHADOW_ALPHA_BLEND);
                 LLGLSLShader::sCurBoundShaderPtr->setMinimumAlpha(0.598f);
                 renderAlphaObjects(mask, TRUE, TRUE, rigged);
             }
 
 
             {
-                LL_RECORD_BLOCK_TIME(FTM_SHADOW_FULLBRIGHT_ALPHA_MASKED);
+                LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("shadow fullbright alpha masked"); //LL_RECORD_BLOCK_TIME(FTM_SHADOW_FULLBRIGHT_ALPHA_MASKED);
                 gDeferredShadowFullbrightAlphaMaskProgram.bind(rigged);
                 LLGLSLShader::sCurBoundShaderPtr->uniform1f(LLShaderMgr::DEFERRED_SHADOW_TARGET_WIDTH, (float)target_width);
                 LLGLSLShader::sCurBoundShaderPtr->uniform1i(LLShaderMgr::SUN_UP_FACTOR, environment.getIsSunUp() ? 1 : 0);
@@ -9677,7 +9677,7 @@ void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera
 
 
             {
-                LL_RECORD_BLOCK_TIME(FTM_SHADOW_ALPHA_GRASS);
+                LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("shadow alpha grass"); //LL_RECORD_BLOCK_TIME(FTM_SHADOW_ALPHA_GRASS);
                 gDeferredTreeShadowProgram.bind(rigged);
                 if (i == 0)
                 {
@@ -9723,7 +9723,7 @@ void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera
 
 bool LLPipeline::getVisiblePointCloud(LLCamera& camera, LLVector3& min, LLVector3& max, std::vector<LLVector3>& fp, LLVector3 light_dir)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
 	//get point cloud of intersection of frust and min, max
 
 	if (getVisibleExtents(camera, min, max))
@@ -9986,7 +9986,7 @@ void LLPipeline::generateSunShadow(LLCamera& camera)
 		return;
 	}
 
-	LL_RECORD_BLOCK_TIME(FTM_GEN_SUN_SHADOW);
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE; //LL_RECORD_BLOCK_TIME(FTM_GEN_SUN_SHADOW);
 
 	bool skip_avatar_update = false;
 	if (!isAgentAvatarValid() || gAgentCamera.getCameraAnimating() || gAgentCamera.getCameraMode() != CAMERA_MODE_MOUSELOOK || !LLVOAvatar::sVisibleInFirstPerson)
-- 
cgit v1.2.3


From 352bcf3df60a99e259c9bdc2d5d5117384aa5c35 Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Thu, 13 Jan 2022 12:40:39 -0800
Subject: SL-16606: Add profiler category SHADER

---
 indra/llrender/llglslshader.cpp | 52 ++++++++++++++++++++---------------------
 indra/newview/llenvironment.cpp |  4 ++--
 indra/newview/llsettingsvo.cpp  |  4 ++--
 3 files changed, 30 insertions(+), 30 deletions(-)

(limited to 'indra')

diff --git a/indra/llrender/llglslshader.cpp b/indra/llrender/llglslshader.cpp
index 220e88386a..185c1450c8 100644
--- a/indra/llrender/llglslshader.cpp
+++ b/indra/llrender/llglslshader.cpp
@@ -207,7 +207,7 @@ void LLGLSLShader::dumpStats()
 //static
 void LLGLSLShader::startProfile()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
     if (sProfileEnabled && sCurBoundShaderPtr)
     {
         sCurBoundShaderPtr->placeProfileQuery();
@@ -218,7 +218,7 @@ void LLGLSLShader::startProfile()
 //static
 void LLGLSLShader::stopProfile(U32 count, U32 mode)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
     if (sProfileEnabled && sCurBoundShaderPtr)
     {
         sCurBoundShaderPtr->readProfileQuery(count, mode);
@@ -385,7 +385,7 @@ BOOL LLGLSLShader::createShader(std::vector<LLStaticHashedString> * attributes,
                                 U32 varying_count,
                                 const char** varyings)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
 
     unloadInternal();
 
@@ -591,7 +591,7 @@ void LLGLSLShader::attachObjects(GLhandleARB* objects, S32 count)
 
 BOOL LLGLSLShader::mapAttributes(const std::vector<LLStaticHashedString> * attributes)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
 
     //before linking, make sure reserved attributes always have consistent locations
     for (U32 i = 0; i < LLShaderMgr::instance()->mReservedAttribs.size(); i++)
@@ -654,7 +654,7 @@ BOOL LLGLSLShader::mapAttributes(const std::vector<LLStaticHashedString> * attri
 
 void LLGLSLShader::mapUniform(GLint index, const vector<LLStaticHashedString> * uniforms)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
 
     if (index == -1)
     {
@@ -777,7 +777,7 @@ void LLGLSLShader::removePermutation(std::string name)
 
 GLint LLGLSLShader::mapUniformTextureChannel(GLint location, GLenum type)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
 
     if ((type >= GL_SAMPLER_1D_ARB && type <= GL_SAMPLER_2D_RECT_SHADOW_ARB) ||
         type == GL_SAMPLER_2D_MULTISAMPLE)
@@ -791,7 +791,7 @@ GLint LLGLSLShader::mapUniformTextureChannel(GLint location, GLenum type)
 
 BOOL LLGLSLShader::mapUniforms(const vector<LLStaticHashedString> * uniforms)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
 
     BOOL res = TRUE;
 
@@ -936,7 +936,7 @@ BOOL LLGLSLShader::mapUniforms(const vector<LLStaticHashedString> * uniforms)
 
 BOOL LLGLSLShader::link(BOOL suppress_errors)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
 
     BOOL success = LLShaderMgr::instance()->linkProgramObject(mProgramObject, suppress_errors);
 
@@ -950,7 +950,7 @@ BOOL LLGLSLShader::link(BOOL suppress_errors)
 
 void LLGLSLShader::bind()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
 
     gGL.flush();
 
@@ -984,7 +984,7 @@ void LLGLSLShader::bind(bool rigged)
 
 void LLGLSLShader::unbind()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
 
     gGL.flush();
     stop_glerror();
@@ -997,7 +997,7 @@ void LLGLSLShader::unbind()
 
 void LLGLSLShader::bindNoShader(void)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
 
     LLVertexBuffer::unbind();
     glUseProgramObjectARB(0);
@@ -1007,7 +1007,7 @@ void LLGLSLShader::bindNoShader(void)
 
 S32 LLGLSLShader::bindTexture(const std::string &uniform, LLTexture *texture, LLTexUnit::eTextureType mode, LLTexUnit::eTextureColorSpace colorspace)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
 
     S32 channel = 0;
     channel = getUniformLocation(uniform);
@@ -1017,7 +1017,7 @@ 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;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
 
     if (uniform < 0 || uniform >= (S32)mTexture.size())
     {
@@ -1038,7 +1038,7 @@ S32 LLGLSLShader::bindTexture(S32 uniform, LLTexture *texture, LLTexUnit::eTextu
 
 S32 LLGLSLShader::unbindTexture(const std::string &uniform, LLTexUnit::eTextureType mode)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
 
     S32 channel = 0;
     channel = getUniformLocation(uniform);
@@ -1048,7 +1048,7 @@ S32 LLGLSLShader::unbindTexture(const std::string &uniform, LLTexUnit::eTextureT
 
 S32 LLGLSLShader::unbindTexture(S32 uniform, LLTexUnit::eTextureType mode)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
 
     if (uniform < 0 || uniform >= (S32)mTexture.size())
     {
@@ -1068,7 +1068,7 @@ S32 LLGLSLShader::unbindTexture(S32 uniform, LLTexUnit::eTextureType mode)
 
 S32 LLGLSLShader::enableTexture(S32 uniform, LLTexUnit::eTextureType mode, LLTexUnit::eTextureColorSpace space)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
 
     if (uniform < 0 || uniform >= (S32)mTexture.size())
     {
@@ -1087,7 +1087,7 @@ S32 LLGLSLShader::enableTexture(S32 uniform, LLTexUnit::eTextureType mode, LLTex
 
 S32 LLGLSLShader::disableTexture(S32 uniform, LLTexUnit::eTextureType mode, LLTexUnit::eTextureColorSpace space)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
 
     if (uniform < 0 || uniform >= (S32)mTexture.size())
     {
@@ -1116,7 +1116,7 @@ S32 LLGLSLShader::disableTexture(S32 uniform, LLTexUnit::eTextureType mode, LLTe
 
 void LLGLSLShader::uniform1i(U32 index, GLint x)
 {
-    LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER
     if (mProgramObject)
     {   
         if (mUniform.size() <= index)
@@ -1139,7 +1139,7 @@ void LLGLSLShader::uniform1i(U32 index, GLint x)
 
 void LLGLSLShader::uniform1f(U32 index, GLfloat x)
 {
-    LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER
     if (mProgramObject)
     {   
         if (mUniform.size() <= index)
@@ -1337,7 +1337,7 @@ void LLGLSLShader::uniform4fv(U32 index, U32 count, const GLfloat* v)
             LLVector4 vec(v[0],v[1],v[2],v[3]);
             if (iter == mValue.end() || shouldChange(iter->second,vec) || count != 1)
             {
-                LL_PROFILE_ZONE_SCOPED;
+                LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
                 glUniform4fvARB(mUniform[index], count, v);
                 mValue[mUniform[index]] = vec;
             }
@@ -1381,7 +1381,7 @@ 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;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
 
 	if (mProgramObject)
 	{	
@@ -1417,7 +1417,7 @@ void LLGLSLShader::uniformMatrix4fv(U32 index, U32 count, GLboolean transpose, c
 
 GLint LLGLSLShader::getUniformLocation(const LLStaticHashedString& uniform)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
 
     GLint ret = -1;
     if (mProgramObject)
@@ -1443,7 +1443,7 @@ GLint LLGLSLShader::getUniformLocation(const LLStaticHashedString& uniform)
 
 GLint LLGLSLShader::getUniformLocation(U32 index)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
 
     GLint ret = -1;
     if (mProgramObject)
@@ -1461,7 +1461,7 @@ GLint LLGLSLShader::getUniformLocation(U32 index)
 
 GLint LLGLSLShader::getAttribLocation(U32 attrib)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
 
     if (attrib < mAttribute.size())
     {
@@ -1613,7 +1613,7 @@ void LLGLSLShader::uniform4fv(const LLStaticHashedString& uniform, U32 count, co
         const auto& iter = mValue.find(location);
         if (iter == mValue.end() || shouldChange(iter->second,vec) || count != 1)
         {
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
             glUniform4fvARB(location, count, v);
             mValue[location] = vec;
         }
@@ -1657,7 +1657,7 @@ void LLGLSLShader::setMinimumAlpha(F32 minimum)
 
 void LLShaderUniforms::apply(LLGLSLShader* shader)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
     for (auto& uniform : mIntegers)
     {
         shader->uniform1i(uniform.mUniform, uniform.mValue);
diff --git a/indra/newview/llenvironment.cpp b/indra/newview/llenvironment.cpp
index f232ca47e0..0cdafcba81 100644
--- a/indra/newview/llenvironment.cpp
+++ b/indra/newview/llenvironment.cpp
@@ -1654,7 +1654,7 @@ void LLEnvironment::updateCloudScroll()
 // static
 void LLEnvironment::updateGLVariablesForSettings(LLShaderUniforms* uniforms, const LLSettingsBase::ptr_t &psetting)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
 
     for (int i = 0; i < LLGLSLShader::SG_COUNT; ++i)
     {
@@ -1725,7 +1725,7 @@ void LLEnvironment::updateGLVariablesForSettings(LLShaderUniforms* uniforms, con
 
 void LLEnvironment::updateShaderUniforms(LLGLSLShader* shader)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
 
     // apply uniforms that should be applied to all shaders
     mSkyUniforms[LLGLSLShader::SG_ANY].apply(shader);
diff --git a/indra/newview/llsettingsvo.cpp b/indra/newview/llsettingsvo.cpp
index 217d45de68..14a9f4aa30 100644
--- a/indra/newview/llsettingsvo.cpp
+++ b/indra/newview/llsettingsvo.cpp
@@ -666,7 +666,7 @@ void LLSettingsVOSky::updateSettings()
 
 void LLSettingsVOSky::applySpecial(void *ptarget, bool force)
 {
-    LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
     LLVector4 light_direction = LLEnvironment::instance().getClampedLightNorm();
 
     LLShaderUniforms* shader = &((LLShaderUniforms*)ptarget)[LLGLSLShader::SG_DEFAULT];
@@ -909,7 +909,7 @@ LLSD LLSettingsVOWater::convertToLegacy(const LLSettingsWater::ptr_t &pwater)
 //-------------------------------------------------------------------------
 void LLSettingsVOWater::applySpecial(void *ptarget, bool force)
 {
-    LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
 
     LLEnvironment& env = LLEnvironment::instance();
 
-- 
cgit v1.2.3


From ac9689fc2faef9e7979e7b02bdee99636e324868 Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Thu, 13 Jan 2022 12:42:08 -0800
Subject: SL-16606: Add profiler category SPATIAL

---
 indra/newview/llspatialpartition.cpp | 22 ++++++++++++----------
 1 file changed, 12 insertions(+), 10 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp
index c802e62e40..c25ada8d8c 100644
--- a/indra/newview/llspatialpartition.cpp
+++ b/indra/newview/llspatialpartition.cpp
@@ -295,7 +295,7 @@ void LLSpatialPartition::rebuildGeom(LLSpatialGroup* group)
 		group->mLastUpdateViewAngle = group->mViewAngle;
 	}
 	
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_SPATIAL;
 
 	group->clearDrawMap();
 	
@@ -366,7 +366,7 @@ LLSpatialGroup* LLSpatialGroup::getParent()
 
 BOOL LLSpatialGroup::removeObject(LLDrawable *drawablep, BOOL from_octree)
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_SPATIAL
 
 	if(!drawablep)
 	{
@@ -455,7 +455,7 @@ public:
 
 void LLSpatialGroup::setState(U32 state, S32 mode) 
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_SPATIAL
 
 	llassert(state <= LLSpatialGroup::STATE_MASK);
 	
@@ -504,7 +504,7 @@ public:
 
 void LLSpatialGroup::clearState(U32 state, S32 mode)
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_SPATIAL
 
 	llassert(state <= LLSpatialGroup::STATE_MASK);
 
@@ -588,7 +588,7 @@ void LLSpatialGroup::updateDistance(LLCamera &camera)
 
 F32 LLSpatialPartition::calcDistance(LLSpatialGroup* group, LLCamera& camera)
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_SPATIAL
 
 	LLVector4a eye;
 	LLVector4a origin;
@@ -647,9 +647,11 @@ F32 LLSpatialPartition::calcDistance(LLSpatialGroup* group, LLCamera& camera)
 		dist = eye.getLength3().getF32();
 	}
 
+#if !LL_RELEASE
     LL_DEBUGS("RiggedBox") << "calcDistance, group " << group << " camera " << origin << " obj bounds " 
                            << group->mObjectBounds[0] << ", " << group->mObjectBounds[1] 
                            << " dist " << dist << " radius " << group->mRadius << LL_ENDL;
+#endif
 
 	if (dist < 16.f)
 	{
@@ -681,7 +683,7 @@ F32 LLSpatialGroup::getUpdateUrgency() const
 
 BOOL LLSpatialGroup::changeLOD()
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_SPATIAL
 
 	if (hasState(ALPHA_DIRTY | OBJECT_DIRTY))
 	{
@@ -775,7 +777,7 @@ void LLSpatialGroup::handleDestruction(const TreeNode* node)
 
 void LLSpatialGroup::handleChildAddition(const OctreeNode* parent, OctreeNode* child) 
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_SPATIAL
 
 	if (child->getListenerCount() == 0)
 	{
@@ -1347,7 +1349,7 @@ void LLSpatialPartition::resetVertexBuffers()
 
 BOOL LLSpatialPartition::getVisibleExtents(LLCamera& camera, LLVector3& visMin, LLVector3& visMax)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_SPATIAL;
 	LLVector4a visMina, visMaxa;
 	visMina.load3(visMin.mV);
 	visMaxa.load3(visMax.mV);
@@ -1374,7 +1376,7 @@ BOOL LLSpatialPartition::visibleObjectsInFrustum(LLCamera& camera)
 
 S32 LLSpatialPartition::cull(LLCamera &camera, std::vector<LLDrawable *>* results, BOOL for_select)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_SPATIAL;
 #if LL_OCTREE_PARANOIA_CHECK
 	((LLSpatialGroup*)mOctree->getListener(0))->checkStates();
 #endif
@@ -1395,7 +1397,7 @@ S32 LLSpatialPartition::cull(LLCamera &camera, std::vector<LLDrawable *>* result
 	
 S32 LLSpatialPartition::cull(LLCamera &camera, bool do_occlusion)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_SPATIAL;
 #if LL_OCTREE_PARANOIA_CHECK
 	((LLSpatialGroup*)mOctree->getListener(0))->checkStates();
 #endif
-- 
cgit v1.2.3


From 0f3f8fc8c013e3364851374e923878f9e577b583 Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Thu, 13 Jan 2022 12:47:54 -0800
Subject: SL-16606: Add profiler category STATS

---
 indra/llcommon/llfasttimer.cpp         |   4 +-
 indra/llcommon/lltrace.h               |  18 +++---
 indra/llcommon/lltraceaccumulators.cpp |  20 +++----
 indra/llcommon/lltraceaccumulators.h   |  26 ++++-----
 indra/llcommon/lltracerecording.cpp    | 100 ++++++++++++++++-----------------
 indra/llcommon/lltracerecording.h      |  46 +++++++--------
 6 files changed, 107 insertions(+), 107 deletions(-)

(limited to 'indra')

diff --git a/indra/llcommon/llfasttimer.cpp b/indra/llcommon/llfasttimer.cpp
index d38946004f..2612d0f07c 100644
--- a/indra/llcommon/llfasttimer.cpp
+++ b/indra/llcommon/llfasttimer.cpp
@@ -222,7 +222,7 @@ void BlockTimer::bootstrapTimerTree()
 // this preserves partial order derived from current frame's observations
 void BlockTimer::incrementalUpdateTimerTree()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	for(block_timer_tree_df_post_iterator_t it = begin_block_timer_tree_df_post(BlockTimer::getRootTimeBlock());
 		it != end_block_timer_tree_df_post();
 		++it)
@@ -263,7 +263,7 @@ void BlockTimer::incrementalUpdateTimerTree()
 
 void BlockTimer::updateTimes()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	// walk up stack of active timers and accumulate current time while leaving timing structures active
 	BlockTimerStackRecord* stack_record	= LLThreadLocalSingletonPointer<BlockTimerStackRecord>::getInstance();
 	if (!stack_record) return;
diff --git a/indra/llcommon/lltrace.h b/indra/llcommon/lltrace.h
index 4051c558a4..fcd8753f75 100644
--- a/indra/llcommon/lltrace.h
+++ b/indra/llcommon/lltrace.h
@@ -227,7 +227,7 @@ public:
 
 	void setName(const char* name)
 	{
-        LL_PROFILE_ZONE_SCOPED;
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 		mName = name;
 		setKey(name);
 	}
@@ -236,13 +236,13 @@ public:
 
 	StatType<MemAccumulator::AllocationFacet>& allocations() 
 	{
-        LL_PROFILE_ZONE_SCOPED;
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 		return static_cast<StatType<MemAccumulator::AllocationFacet>&>(*(StatType<MemAccumulator>*)this);
 	}
 
 	StatType<MemAccumulator::DeallocationFacet>& deallocations() 
 	{
-        LL_PROFILE_ZONE_SCOPED;
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 		return static_cast<StatType<MemAccumulator::DeallocationFacet>&>(*(StatType<MemAccumulator>*)this);
 	}
 };
@@ -264,7 +264,7 @@ struct MeasureMem<T, typename T::mem_trackable_tag_t, IS_BYTES>
 {
 	static size_t measureFootprint(const T& value)
 	{
-        LL_PROFILE_ZONE_SCOPED;
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 		return sizeof(T) + value.getMemFootprint();
 	}
 };
@@ -274,7 +274,7 @@ struct MeasureMem<T, IS_MEM_TRACKABLE, typename T::is_unit_t>
 {
 	static size_t measureFootprint(const T& value)
 	{
-        LL_PROFILE_ZONE_SCOPED;
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 		return U32Bytes(value).value();
 	}
 };
@@ -284,7 +284,7 @@ struct MeasureMem<T*, IS_MEM_TRACKABLE, IS_BYTES>
 {
 	static size_t measureFootprint(const T* value)
 	{
-        LL_PROFILE_ZONE_SCOPED;
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 		if (!value)
 		{
 			return 0;
@@ -329,7 +329,7 @@ struct MeasureMem<std::basic_string<T>, IS_MEM_TRACKABLE, IS_BYTES>
 {
 	static size_t measureFootprint(const std::basic_string<T>& value)
 	{
-        LL_PROFILE_ZONE_SCOPED;
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 		return value.capacity() * sizeof(T);
 	}
 };
@@ -338,7 +338,7 @@ struct MeasureMem<std::basic_string<T>, IS_MEM_TRACKABLE, IS_BYTES>
 template<typename T>
 inline void claim_alloc(MemStatHandle& measurement, const T& value)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 #if LL_TRACE_ENABLED
 	S32 size = MeasureMem<T>::measureFootprint(value);
 	if(size == 0) return;
@@ -351,7 +351,7 @@ inline void claim_alloc(MemStatHandle& measurement, const T& value)
 template<typename T>
 inline void disclaim_alloc(MemStatHandle& measurement, const T& value)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 #if LL_TRACE_ENABLED
 	S32 size = MeasureMem<T>::measureFootprint(value);
 	if(size == 0) return;
diff --git a/indra/llcommon/lltraceaccumulators.cpp b/indra/llcommon/lltraceaccumulators.cpp
index 8e9aaee0e6..34299f5a29 100644
--- a/indra/llcommon/lltraceaccumulators.cpp
+++ b/indra/llcommon/lltraceaccumulators.cpp
@@ -41,7 +41,7 @@ extern MemStatHandle gTraceMemStat;
 
 AccumulatorBufferGroup::AccumulatorBufferGroup() 
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	claim_alloc(gTraceMemStat, mCounts.capacity() * sizeof(CountAccumulator));
 	claim_alloc(gTraceMemStat, mSamples.capacity() * sizeof(SampleAccumulator));
 	claim_alloc(gTraceMemStat, mEvents.capacity() * sizeof(EventAccumulator));
@@ -56,7 +56,7 @@ AccumulatorBufferGroup::AccumulatorBufferGroup(const AccumulatorBufferGroup& oth
 	mStackTimers(other.mStackTimers),
 	mMemStats(other.mMemStats)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	claim_alloc(gTraceMemStat, mCounts.capacity() * sizeof(CountAccumulator));
 	claim_alloc(gTraceMemStat, mSamples.capacity() * sizeof(SampleAccumulator));
 	claim_alloc(gTraceMemStat, mEvents.capacity() * sizeof(EventAccumulator));
@@ -66,7 +66,7 @@ AccumulatorBufferGroup::AccumulatorBufferGroup(const AccumulatorBufferGroup& oth
 
 AccumulatorBufferGroup::~AccumulatorBufferGroup()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	disclaim_alloc(gTraceMemStat, mCounts.capacity() * sizeof(CountAccumulator));
 	disclaim_alloc(gTraceMemStat, mSamples.capacity() * sizeof(SampleAccumulator));
 	disclaim_alloc(gTraceMemStat, mEvents.capacity() * sizeof(EventAccumulator));
@@ -76,7 +76,7 @@ AccumulatorBufferGroup::~AccumulatorBufferGroup()
 
 void AccumulatorBufferGroup::handOffTo(AccumulatorBufferGroup& other)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	other.mCounts.reset(&mCounts);
 	other.mSamples.reset(&mSamples);
 	other.mEvents.reset(&mEvents);
@@ -86,7 +86,7 @@ void AccumulatorBufferGroup::handOffTo(AccumulatorBufferGroup& other)
 
 void AccumulatorBufferGroup::makeCurrent()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	mCounts.makeCurrent();
 	mSamples.makeCurrent();
 	mEvents.makeCurrent();
@@ -109,7 +109,7 @@ void AccumulatorBufferGroup::makeCurrent()
 //static
 void AccumulatorBufferGroup::clearCurrent()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	AccumulatorBuffer<CountAccumulator>::clearCurrent();	
 	AccumulatorBuffer<SampleAccumulator>::clearCurrent();
 	AccumulatorBuffer<EventAccumulator>::clearCurrent();
@@ -124,7 +124,7 @@ bool AccumulatorBufferGroup::isCurrent() const
 
 void AccumulatorBufferGroup::append( const AccumulatorBufferGroup& other )
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	mCounts.addSamples(other.mCounts, SEQUENTIAL);
 	mSamples.addSamples(other.mSamples, SEQUENTIAL);
 	mEvents.addSamples(other.mEvents, SEQUENTIAL);
@@ -134,7 +134,7 @@ void AccumulatorBufferGroup::append( const AccumulatorBufferGroup& other )
 
 void AccumulatorBufferGroup::merge( const AccumulatorBufferGroup& other)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	mCounts.addSamples(other.mCounts, NON_SEQUENTIAL);
 	mSamples.addSamples(other.mSamples, NON_SEQUENTIAL);
 	mEvents.addSamples(other.mEvents, NON_SEQUENTIAL);
@@ -145,7 +145,7 @@ void AccumulatorBufferGroup::merge( const AccumulatorBufferGroup& other)
 
 void AccumulatorBufferGroup::reset(AccumulatorBufferGroup* other)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	mCounts.reset(other ? &other->mCounts : NULL);
 	mSamples.reset(other ? &other->mSamples : NULL);
 	mEvents.reset(other ? &other->mEvents : NULL);
@@ -155,7 +155,7 @@ void AccumulatorBufferGroup::reset(AccumulatorBufferGroup* other)
 
 void AccumulatorBufferGroup::sync()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	if (isCurrent())
 	{
 		F64SecondsImplicit time_stamp = LLTimer::getTotalSeconds();
diff --git a/indra/llcommon/lltraceaccumulators.h b/indra/llcommon/lltraceaccumulators.h
index b183fcd14a..7267a44300 100644
--- a/indra/llcommon/lltraceaccumulators.h
+++ b/indra/llcommon/lltraceaccumulators.h
@@ -66,7 +66,7 @@ namespace LLTrace
 			: mStorageSize(0),
 			mStorage(NULL)
 		{
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			const AccumulatorBuffer& other = *getDefaultBuffer();
 			resize(sNextStorageSlot);
 			for (S32 i = 0; i < sNextStorageSlot; i++)
@@ -77,7 +77,7 @@ namespace LLTrace
 
 		~AccumulatorBuffer()
 		{
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			if (isCurrent())
 			{
 				LLThreadLocalSingletonPointer<ACCUMULATOR>::setInstance(NULL);
@@ -100,7 +100,7 @@ namespace LLTrace
 			: mStorageSize(0),
 			mStorage(NULL)
 		{
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			resize(sNextStorageSlot);
 			for (S32 i = 0; i < sNextStorageSlot; i++)
 			{
@@ -110,7 +110,7 @@ namespace LLTrace
 
 		void addSamples(const AccumulatorBuffer<ACCUMULATOR>& other, EBufferAppendType append_type)
 		{
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			llassert(mStorageSize >= sNextStorageSlot && other.mStorageSize >= sNextStorageSlot);
 			for (size_t i = 0; i < sNextStorageSlot; i++)
 			{
@@ -120,7 +120,7 @@ namespace LLTrace
 
 		void copyFrom(const AccumulatorBuffer<ACCUMULATOR>& other)
 		{
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			llassert(mStorageSize >= sNextStorageSlot && other.mStorageSize >= sNextStorageSlot);
 			for (size_t i = 0; i < sNextStorageSlot; i++)
 			{
@@ -130,7 +130,7 @@ namespace LLTrace
 
 		void reset(const AccumulatorBuffer<ACCUMULATOR>* other = NULL)
 		{
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			llassert(mStorageSize >= sNextStorageSlot);
 			for (size_t i = 0; i < sNextStorageSlot; i++)
 			{
@@ -140,7 +140,7 @@ namespace LLTrace
 
 		void sync(F64SecondsImplicit time_stamp)
 		{
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			llassert(mStorageSize >= sNextStorageSlot);
 			for (size_t i = 0; i < sNextStorageSlot; i++)
 			{
@@ -166,7 +166,7 @@ namespace LLTrace
 		// NOTE: this is not thread-safe.  We assume that slots are reserved in the main thread before any child threads are spawned
 		size_t reserveSlot()
 		{
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			size_t next_slot = sNextStorageSlot++;
 			if (next_slot >= mStorageSize)
 			{
@@ -180,7 +180,7 @@ namespace LLTrace
 
 		void resize(size_t new_size)
 		{
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			if (new_size <= mStorageSize) return;
 
 			ACCUMULATOR* old_storage = mStorage;
@@ -221,7 +221,7 @@ namespace LLTrace
 
 		static self_t* getDefaultBuffer()
 		{
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			static bool sInitialized = false;
 			if (!sInitialized)
 			{
@@ -336,7 +336,7 @@ namespace LLTrace
 
 		void sample(F64 value)
 		{
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			F64SecondsImplicit time_stamp = LLTimer::getTotalSeconds();
 
 			// store effect of last value
@@ -550,7 +550,7 @@ namespace LLTrace
 
 		void addSamples(const MemAccumulator& other, EBufferAppendType append_type)
 		{
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			mAllocations.addSamples(other.mAllocations, append_type);
 			mDeallocations.addSamples(other.mDeallocations, append_type);
 
@@ -569,7 +569,7 @@ namespace LLTrace
 
 		void reset(const MemAccumulator* other)
 		{
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			mSize.reset(other ? &other->mSize : NULL);
 			mAllocations.reset(other ? &other->mAllocations : NULL);
 			mDeallocations.reset(other ? &other->mDeallocations : NULL);
diff --git a/indra/llcommon/lltracerecording.cpp b/indra/llcommon/lltracerecording.cpp
index 5ce1b337fe..1613af1dcf 100644
--- a/indra/llcommon/lltracerecording.cpp
+++ b/indra/llcommon/lltracerecording.cpp
@@ -50,7 +50,7 @@ Recording::Recording(EPlayState state)
 :	mElapsedSeconds(0),
 	mActiveBuffers(NULL)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	claim_alloc(gTraceMemStat, this);
 	mBuffers = new AccumulatorBufferGroup();
 	claim_alloc(gTraceMemStat, mBuffers);
@@ -60,14 +60,14 @@ Recording::Recording(EPlayState state)
 Recording::Recording( const Recording& other )
 :	mActiveBuffers(NULL)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	claim_alloc(gTraceMemStat, this);
 	*this = other;
 }
 
 Recording& Recording::operator = (const Recording& other)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	// this will allow us to seamlessly start without affecting any data we've acquired from other
 	setPlayState(PAUSED);
 
@@ -88,7 +88,7 @@ Recording& Recording::operator = (const Recording& other)
 
 Recording::~Recording()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	disclaim_alloc(gTraceMemStat, this);
 	disclaim_alloc(gTraceMemStat, mBuffers);
 
@@ -107,7 +107,7 @@ void Recording::update()
 #if LL_TRACE_ENABLED
 	if (isStarted())
 	{
-        LL_PROFILE_ZONE_SCOPED;
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 		mElapsedSeconds += mSamplingTimer.getElapsedTimeF64();
 
 		// must have 
@@ -128,7 +128,7 @@ void Recording::update()
 
 void Recording::handleReset()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 #if LL_TRACE_ENABLED
 	mBuffers.write()->reset();
 
@@ -139,7 +139,7 @@ void Recording::handleReset()
 
 void Recording::handleStart()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 #if LL_TRACE_ENABLED
 	mSamplingTimer.reset();
 	mBuffers.setStayUnique(true);
@@ -151,7 +151,7 @@ void Recording::handleStart()
 
 void Recording::handleStop()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 #if LL_TRACE_ENABLED
 	mElapsedSeconds += mSamplingTimer.getElapsedTimeF64();
 	// must have thread recorder running on this thread
@@ -583,20 +583,20 @@ PeriodicRecording::PeriodicRecording( S32 num_periods, EPlayState state)
 	mNumRecordedPeriods(0),
 	mRecordingPeriods(num_periods ? num_periods : 1)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	setPlayState(state);
 	claim_alloc(gTraceMemStat, this);
 }
 
 PeriodicRecording::~PeriodicRecording()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	disclaim_alloc(gTraceMemStat, this);
 }
 
 void PeriodicRecording::nextPeriod()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	if (mAutoResize)
 	{
 		mRecordingPeriods.push_back(Recording());
@@ -611,7 +611,7 @@ void PeriodicRecording::nextPeriod()
 
 void PeriodicRecording::appendRecording(Recording& recording)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	getCurRecording().appendRecording(recording);
 	nextPeriod();
 }
@@ -619,7 +619,7 @@ void PeriodicRecording::appendRecording(Recording& recording)
 
 void PeriodicRecording::appendPeriodicRecording( PeriodicRecording& other )
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	if (other.mRecordingPeriods.empty()) return;
 
 	getCurRecording().update();
@@ -693,7 +693,7 @@ void PeriodicRecording::appendPeriodicRecording( PeriodicRecording& other )
 
 F64Seconds PeriodicRecording::getDuration() const
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	F64Seconds duration;
 	S32 num_periods = mRecordingPeriods.size();
 	for (S32 i = 1; i <= num_periods; i++)
@@ -707,7 +707,7 @@ F64Seconds PeriodicRecording::getDuration() const
 
 LLTrace::Recording PeriodicRecording::snapshotCurRecording() const
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	Recording recording_copy(getCurRecording());
 	recording_copy.stop();
 	return recording_copy;
@@ -750,19 +750,19 @@ const Recording& PeriodicRecording::getPrevRecording( S32 offset ) const
 
 void PeriodicRecording::handleStart()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	getCurRecording().start();
 }
 
 void PeriodicRecording::handleStop()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	getCurRecording().pause();
 }
 
 void PeriodicRecording::handleReset()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	getCurRecording().stop();
 
 	if (mAutoResize)
@@ -786,13 +786,13 @@ void PeriodicRecording::handleReset()
 
 void PeriodicRecording::handleSplitTo(PeriodicRecording& other)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	getCurRecording().splitTo(other.getCurRecording());
 }
 
 F64 PeriodicRecording::getPeriodMin( const StatType<EventAccumulator>& stat, S32 num_periods /*= S32_MAX*/ )
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	num_periods = llmin(num_periods, getNumRecordedPeriods());
 
 	bool has_value = false;
@@ -814,7 +814,7 @@ F64 PeriodicRecording::getPeriodMin( const StatType<EventAccumulator>& stat, S32
 
 F64 PeriodicRecording::getPeriodMax( const StatType<EventAccumulator>& stat, S32 num_periods /*= S32_MAX*/ )
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	num_periods = llmin(num_periods, getNumRecordedPeriods());
 
 	bool has_value = false;
@@ -837,7 +837,7 @@ F64 PeriodicRecording::getPeriodMax( const StatType<EventAccumulator>& stat, S32
 // calculates means using aggregates per period
 F64 PeriodicRecording::getPeriodMean( const StatType<EventAccumulator>& stat, S32 num_periods /*= S32_MAX*/ )
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	num_periods = llmin(num_periods, getNumRecordedPeriods());
 
 	F64 mean = 0;
@@ -860,7 +860,7 @@ F64 PeriodicRecording::getPeriodMean( const StatType<EventAccumulator>& stat, S3
 
 F64 PeriodicRecording::getPeriodStandardDeviation( const StatType<EventAccumulator>& stat, S32 num_periods /*= S32_MAX*/ )
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	num_periods = llmin(num_periods, getNumRecordedPeriods());
 
 	F64 period_mean = getPeriodMean(stat, num_periods);
@@ -885,7 +885,7 @@ F64 PeriodicRecording::getPeriodStandardDeviation( const StatType<EventAccumulat
 
 F64 PeriodicRecording::getPeriodMin( const StatType<SampleAccumulator>& stat, S32 num_periods /*= S32_MAX*/ )
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	num_periods = llmin(num_periods, getNumRecordedPeriods());
 
 	bool has_value = false;
@@ -907,7 +907,7 @@ F64 PeriodicRecording::getPeriodMin( const StatType<SampleAccumulator>& stat, S3
 
 F64 PeriodicRecording::getPeriodMax(const StatType<SampleAccumulator>& stat, S32 num_periods /*= S32_MAX*/)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	num_periods = llmin(num_periods, getNumRecordedPeriods());
 
 	bool has_value = false;
@@ -930,7 +930,7 @@ F64 PeriodicRecording::getPeriodMax(const StatType<SampleAccumulator>& stat, S32
 
 F64 PeriodicRecording::getPeriodMean( const StatType<SampleAccumulator>& stat, S32 num_periods /*= S32_MAX*/ )
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	num_periods = llmin(num_periods, getNumRecordedPeriods());
 
 	S32 valid_period_count = 0;
@@ -953,7 +953,7 @@ F64 PeriodicRecording::getPeriodMean( const StatType<SampleAccumulator>& stat, S
 
 F64 PeriodicRecording::getPeriodMedian( const StatType<SampleAccumulator>& stat, S32 num_periods /*= S32_MAX*/ )
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	num_periods = llmin(num_periods, getNumRecordedPeriods());
 
 	std::vector<F64> buf;
@@ -979,7 +979,7 @@ F64 PeriodicRecording::getPeriodMedian( const StatType<SampleAccumulator>& stat,
 
 F64 PeriodicRecording::getPeriodStandardDeviation( const StatType<SampleAccumulator>& stat, S32 num_periods /*= S32_MAX*/ )
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	num_periods = llmin(num_periods, getNumRecordedPeriods());
 
 	F64 period_mean = getPeriodMean(stat, num_periods);
@@ -1005,7 +1005,7 @@ F64 PeriodicRecording::getPeriodStandardDeviation( const StatType<SampleAccumula
 
 F64Kilobytes PeriodicRecording::getPeriodMin( const StatType<MemAccumulator>& stat, S32 num_periods /*= S32_MAX*/ )
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	num_periods = llmin(num_periods, getNumRecordedPeriods());
 
 	F64Kilobytes min_val(std::numeric_limits<F64>::max());
@@ -1025,7 +1025,7 @@ F64Kilobytes PeriodicRecording::getPeriodMin(const MemStatHandle& stat, S32 num_
 
 F64Kilobytes PeriodicRecording::getPeriodMax(const StatType<MemAccumulator>& stat, S32 num_periods /*= S32_MAX*/)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	num_periods = llmin(num_periods, getNumRecordedPeriods());
 
 	F64Kilobytes max_val(0.0);
@@ -1045,7 +1045,7 @@ F64Kilobytes PeriodicRecording::getPeriodMax(const MemStatHandle& stat, S32 num_
 
 F64Kilobytes PeriodicRecording::getPeriodMean( const StatType<MemAccumulator>& stat, S32 num_periods /*= S32_MAX*/ )
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	num_periods = llmin(num_periods, getNumRecordedPeriods());
 
 	F64Kilobytes mean(0);
@@ -1066,7 +1066,7 @@ F64Kilobytes PeriodicRecording::getPeriodMean(const MemStatHandle& stat, S32 num
 
 F64Kilobytes PeriodicRecording::getPeriodStandardDeviation( const StatType<MemAccumulator>& stat, S32 num_periods /*= S32_MAX*/ )
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	num_periods = llmin(num_periods, getNumRecordedPeriods());
 
 	F64Kilobytes period_mean = getPeriodMean(stat, num_periods);
@@ -1100,7 +1100,7 @@ F64Kilobytes PeriodicRecording::getPeriodStandardDeviation(const MemStatHandle&
 
 void ExtendableRecording::extend()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	// push the data back to accepted recording
 	mAcceptedRecording.appendRecording(mPotentialRecording);
 	// flush data, so we can start from scratch
@@ -1109,26 +1109,26 @@ void ExtendableRecording::extend()
 
 void ExtendableRecording::handleStart()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	mPotentialRecording.start();
 }
 
 void ExtendableRecording::handleStop()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	mPotentialRecording.pause();
 }
 
 void ExtendableRecording::handleReset()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	mAcceptedRecording.reset();
 	mPotentialRecording.reset();
 }
 
 void ExtendableRecording::handleSplitTo(ExtendableRecording& other)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	mPotentialRecording.splitTo(other.mPotentialRecording);
 }
 
@@ -1145,7 +1145,7 @@ ExtendablePeriodicRecording::ExtendablePeriodicRecording()
 
 void ExtendablePeriodicRecording::extend()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	// push the data back to accepted recording
 	mAcceptedRecording.appendPeriodicRecording(mPotentialRecording);
 	// flush data, so we can start from scratch
@@ -1155,26 +1155,26 @@ void ExtendablePeriodicRecording::extend()
 
 void ExtendablePeriodicRecording::handleStart()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	mPotentialRecording.start();
 }
 
 void ExtendablePeriodicRecording::handleStop()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	mPotentialRecording.pause();
 }
 
 void ExtendablePeriodicRecording::handleReset()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	mAcceptedRecording.reset();
 	mPotentialRecording.reset();
 }
 
 void ExtendablePeriodicRecording::handleSplitTo(ExtendablePeriodicRecording& other)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	mPotentialRecording.splitTo(other.mPotentialRecording);
 }
 
@@ -1189,7 +1189,7 @@ PeriodicRecording& get_frame_recording()
 
 void LLStopWatchControlsMixinCommon::start()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	switch (mPlayState)
 	{
 	case STOPPED:
@@ -1211,7 +1211,7 @@ void LLStopWatchControlsMixinCommon::start()
 
 void LLStopWatchControlsMixinCommon::stop()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	switch (mPlayState)
 	{
 	case STOPPED:
@@ -1231,7 +1231,7 @@ void LLStopWatchControlsMixinCommon::stop()
 
 void LLStopWatchControlsMixinCommon::pause()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	switch (mPlayState)
 	{
 	case STOPPED:
@@ -1251,7 +1251,7 @@ void LLStopWatchControlsMixinCommon::pause()
 
 void LLStopWatchControlsMixinCommon::unpause()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	switch (mPlayState)
 	{
 	case STOPPED:
@@ -1271,7 +1271,7 @@ void LLStopWatchControlsMixinCommon::unpause()
 
 void LLStopWatchControlsMixinCommon::resume()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	switch (mPlayState)
 	{
 	case STOPPED:
@@ -1292,7 +1292,7 @@ void LLStopWatchControlsMixinCommon::resume()
 
 void LLStopWatchControlsMixinCommon::restart()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	switch (mPlayState)
 	{
 	case STOPPED:
@@ -1316,13 +1316,13 @@ void LLStopWatchControlsMixinCommon::restart()
 
 void LLStopWatchControlsMixinCommon::reset()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	handleReset();
 }
 
 void LLStopWatchControlsMixinCommon::setPlayState( EPlayState state )
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	switch(state)
 	{
 	case STOPPED:
diff --git a/indra/llcommon/lltracerecording.h b/indra/llcommon/lltracerecording.h
index 1f3d37336a..556b7470cf 100644
--- a/indra/llcommon/lltracerecording.h
+++ b/indra/llcommon/lltracerecording.h
@@ -355,7 +355,7 @@ namespace LLTrace
 		template <typename T>
 		S32 getSampleCount(const StatType<T>& stat, S32 num_periods = S32_MAX)
         {
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			num_periods = llmin(num_periods, getNumRecordedPeriods());
 
             S32 num_samples = 0;
@@ -375,7 +375,7 @@ namespace LLTrace
 		template <typename T>
 		typename T::value_t getPeriodMin(const StatType<T>& stat, S32 num_periods = S32_MAX)
 		{
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			num_periods = llmin(num_periods, getNumRecordedPeriods());
 
 			bool has_value = false;
@@ -398,7 +398,7 @@ namespace LLTrace
 		template<typename T>
 		T getPeriodMin(const CountStatHandle<T>& stat, S32 num_periods = S32_MAX)
 		{
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			return T(getPeriodMin(static_cast<const StatType<CountAccumulator>&>(stat), num_periods));
 		}
 
@@ -406,7 +406,7 @@ namespace LLTrace
 		template<typename T>
 		T getPeriodMin(const SampleStatHandle<T>& stat, S32 num_periods = S32_MAX)
 		{
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			return T(getPeriodMin(static_cast<const StatType<SampleAccumulator>&>(stat), num_periods));
 		}
 
@@ -414,7 +414,7 @@ namespace LLTrace
 		template<typename T>
 		T getPeriodMin(const EventStatHandle<T>& stat, S32 num_periods = S32_MAX)
 		{
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			return T(getPeriodMin(static_cast<const StatType<EventAccumulator>&>(stat), num_periods));
 		}
 
@@ -424,7 +424,7 @@ namespace LLTrace
 		template <typename T>
 		typename RelatedTypes<typename T::value_t>::fractional_t getPeriodMinPerSec(const StatType<T>& stat, S32 num_periods = S32_MAX)
 		{
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			num_periods = llmin(num_periods, getNumRecordedPeriods());
 
 			typename RelatedTypes<typename T::value_t>::fractional_t min_val(std::numeric_limits<F64>::max());
@@ -439,7 +439,7 @@ namespace LLTrace
 		template<typename T>
 		typename RelatedTypes<T>::fractional_t getPeriodMinPerSec(const CountStatHandle<T>& stat, S32 num_periods = S32_MAX)
 		{
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			return typename RelatedTypes<T>::fractional_t(getPeriodMinPerSec(static_cast<const StatType<CountAccumulator>&>(stat), num_periods));
 		}
 
@@ -451,7 +451,7 @@ namespace LLTrace
 		template <typename T>
 		typename T::value_t getPeriodMax(const StatType<T>& stat, S32 num_periods = S32_MAX)
 		{
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			num_periods = llmin(num_periods, getNumRecordedPeriods());
 
 			bool has_value = false;
@@ -474,7 +474,7 @@ namespace LLTrace
 		template<typename T>
 		T getPeriodMax(const CountStatHandle<T>& stat, S32 num_periods = S32_MAX)
 		{
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			return T(getPeriodMax(static_cast<const StatType<CountAccumulator>&>(stat), num_periods));
 		}
 
@@ -482,7 +482,7 @@ namespace LLTrace
 		template<typename T>
 		T getPeriodMax(const SampleStatHandle<T>& stat, S32 num_periods = S32_MAX)
 		{
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			return T(getPeriodMax(static_cast<const StatType<SampleAccumulator>&>(stat), num_periods));
 		}
 
@@ -490,7 +490,7 @@ namespace LLTrace
 		template<typename T>
 		T getPeriodMax(const EventStatHandle<T>& stat, S32 num_periods = S32_MAX)
 		{
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			return T(getPeriodMax(static_cast<const StatType<EventAccumulator>&>(stat), num_periods));
 		}
 
@@ -500,7 +500,7 @@ namespace LLTrace
 		template <typename T>
 		typename RelatedTypes<typename T::value_t>::fractional_t getPeriodMaxPerSec(const StatType<T>& stat, S32 num_periods = S32_MAX)
 		{
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			num_periods = llmin(num_periods, getNumRecordedPeriods());
 
 			F64 max_val = std::numeric_limits<F64>::min();
@@ -515,7 +515,7 @@ namespace LLTrace
 		template<typename T>
 		typename RelatedTypes<T>::fractional_t getPeriodMaxPerSec(const CountStatHandle<T>& stat, S32 num_periods = S32_MAX)
 		{
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			return typename RelatedTypes<T>::fractional_t(getPeriodMaxPerSec(static_cast<const StatType<CountAccumulator>&>(stat), num_periods));
 		}
 
@@ -527,7 +527,7 @@ namespace LLTrace
 		template <typename T>
 		typename RelatedTypes<typename T::value_t>::fractional_t getPeriodMean(const StatType<T >& stat, S32 num_periods = S32_MAX)
 		{
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			num_periods = llmin(num_periods, getNumRecordedPeriods());
 
 			typename RelatedTypes<typename T::value_t>::fractional_t mean(0);
@@ -548,14 +548,14 @@ namespace LLTrace
 		template<typename T>
 		typename RelatedTypes<T>::fractional_t getPeriodMean(const CountStatHandle<T>& stat, S32 num_periods = S32_MAX)
 		{
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			return typename RelatedTypes<T>::fractional_t(getPeriodMean(static_cast<const StatType<CountAccumulator>&>(stat), num_periods));
 		}
 		F64 getPeriodMean(const StatType<SampleAccumulator>& stat, S32 num_periods = S32_MAX);
 		template<typename T> 
 		typename RelatedTypes<T>::fractional_t getPeriodMean(const SampleStatHandle<T>& stat, S32 num_periods = S32_MAX)
 		{
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			return typename RelatedTypes<T>::fractional_t(getPeriodMean(static_cast<const StatType<SampleAccumulator>&>(stat), num_periods));
 		}
 
@@ -563,7 +563,7 @@ namespace LLTrace
 		template<typename T>
 		typename RelatedTypes<T>::fractional_t getPeriodMean(const EventStatHandle<T>& stat, S32 num_periods = S32_MAX)
 		{
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			return typename RelatedTypes<T>::fractional_t(getPeriodMean(static_cast<const StatType<EventAccumulator>&>(stat), num_periods));
 		}
 
@@ -573,7 +573,7 @@ namespace LLTrace
 		template <typename T>
 		typename RelatedTypes<typename T::value_t>::fractional_t getPeriodMeanPerSec(const StatType<T>& stat, S32 num_periods = S32_MAX)
 		{
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			num_periods = llmin(num_periods, getNumRecordedPeriods());
 
 			typename RelatedTypes<typename T::value_t>::fractional_t mean = 0;
@@ -595,7 +595,7 @@ namespace LLTrace
 		template<typename T>
 		typename RelatedTypes<T>::fractional_t getPeriodMeanPerSec(const CountStatHandle<T>& stat, S32 num_periods = S32_MAX)
 		{
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			return typename RelatedTypes<T>::fractional_t(getPeriodMeanPerSec(static_cast<const StatType<CountAccumulator>&>(stat), num_periods));
 		}
 
@@ -604,7 +604,7 @@ namespace LLTrace
         template <typename T>
         typename RelatedTypes<typename T::value_t>::fractional_t getPeriodMedianPerSec(const StatType<T>& stat, S32 num_periods = S32_MAX)
         {
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
             num_periods = llmin(num_periods, getNumRecordedPeriods());
 
             std::vector <typename RelatedTypes<typename T::value_t>::fractional_t> buf;
@@ -624,7 +624,7 @@ namespace LLTrace
         template<typename T>
         typename RelatedTypes<T>::fractional_t getPeriodMedianPerSec(const CountStatHandle<T>& stat, S32 num_periods = S32_MAX)
         {
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
             return typename RelatedTypes<T>::fractional_t(getPeriodMedianPerSec(static_cast<const StatType<CountAccumulator>&>(stat), num_periods));
         }
 
@@ -637,7 +637,7 @@ namespace LLTrace
 		template<typename T> 
 		typename RelatedTypes<T>::fractional_t getPeriodStandardDeviation(const SampleStatHandle<T>& stat, S32 num_periods = S32_MAX)
 		{
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			return typename RelatedTypes<T>::fractional_t(getPeriodStandardDeviation(static_cast<const StatType<SampleAccumulator>&>(stat), num_periods));
 		}
 
@@ -645,7 +645,7 @@ namespace LLTrace
 		template<typename T>
 		typename RelatedTypes<T>::fractional_t getPeriodStandardDeviation(const EventStatHandle<T>& stat, S32 num_periods = S32_MAX)
 		{
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			return typename RelatedTypes<T>::fractional_t(getPeriodStandardDeviation(static_cast<const StatType<EventAccumulator>&>(stat), num_periods));
 		}
 
-- 
cgit v1.2.3


From 90a0eeffeb689dded526f429ede19d957c85f1f6 Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Thu, 13 Jan 2022 12:49:11 -0800
Subject: SL-16606: Add profiler category STRING

---
 indra/llcommon/llstring.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

(limited to 'indra')

diff --git a/indra/llcommon/llstring.cpp b/indra/llcommon/llstring.cpp
index bdea1e76ea..7f501f2e77 100644
--- a/indra/llcommon/llstring.cpp
+++ b/indra/llcommon/llstring.cpp
@@ -1317,7 +1317,7 @@ bool LLStringUtil::formatDatetime(std::string& replacement, std::string token,
 template<> 
 S32 LLStringUtil::format(std::string& s, const format_map_t& substitutions)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STRING;
 	S32 res = 0;
 
 	std::string output;
@@ -1390,7 +1390,7 @@ S32 LLStringUtil::format(std::string& s, const format_map_t& substitutions)
 template<> 
 S32 LLStringUtil::format(std::string& s, const LLSD& substitutions)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STRING;
 	S32 res = 0;
 
 	if (!substitutions.isMap()) 
-- 
cgit v1.2.3


From bcc46f7df8fb783d87387474677d231dc43770a5 Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Thu, 13 Jan 2022 12:52:28 -0800
Subject: SL-16606: Add profiler category TEXTURE

---
 indra/llimage/llimageworker.cpp       |  8 ++--
 indra/llrender/llgltexture.cpp        |  4 +-
 indra/llrender/llimagegl.cpp          | 28 ++++++------
 indra/newview/llviewertexture.cpp     | 60 +++++++++++++-------------
 indra/newview/llviewertexturelist.cpp | 80 +++++++++++++++++------------------
 5 files changed, 90 insertions(+), 90 deletions(-)

(limited to 'indra')

diff --git a/indra/llimage/llimageworker.cpp b/indra/llimage/llimageworker.cpp
index 33f8dce6ee..0dbb744bcf 100644
--- a/indra/llimage/llimageworker.cpp
+++ b/indra/llimage/llimageworker.cpp
@@ -48,7 +48,7 @@ LLImageDecodeThread::~LLImageDecodeThread()
 // virtual
 S32 LLImageDecodeThread::update(F32 max_time_ms)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	LLMutexLock lock(mCreationMutex);
 	for (creation_list_t::iterator iter = mCreationList.begin();
 		 iter != mCreationList.end(); ++iter)
@@ -72,7 +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;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	LLMutexLock lock(mCreationMutex);
 	handle_t handle = generateHandle();
 	mCreationList.push_back(creation_info(handle, image, priority, discard, needs_aux, responder));
@@ -120,7 +120,7 @@ LLImageDecodeThread::ImageRequest::~ImageRequest()
 // Returns true when done, whether or not decode was successful.
 bool LLImageDecodeThread::ImageRequest::processRequest()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	const F32 decode_time_slice = .1f;
 	bool done = true;
 	if (!mDecodedRaw && mFormattedImage.notNull())
@@ -167,7 +167,7 @@ bool LLImageDecodeThread::ImageRequest::processRequest()
 
 void LLImageDecodeThread::ImageRequest::finishRequest(bool completed)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	if (mResponder.notNull())
 	{
 		bool success = completed && mDecodedRaw && (!mNeedsAux || mDecodedAux);
diff --git a/indra/llrender/llgltexture.cpp b/indra/llrender/llgltexture.cpp
index a279e85bae..b6a02f1c0a 100644
--- a/indra/llrender/llgltexture.cpp
+++ b/indra/llrender/llgltexture.cpp
@@ -262,7 +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;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	llassert(mGLTexturep.notNull()) ;
 
 	return mGLTexturep->setSubImage(imageraw, x_pos, y_pos, width, height) ;
@@ -270,7 +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;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	llassert(mGLTexturep.notNull()) ;
 
 	return mGLTexturep->setSubImage(datap, data_width, data_height, x_pos, y_pos, width, height) ;
diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp
index 9931ce7d3e..1e9b9f642e 100644
--- a/indra/llrender/llimagegl.cpp
+++ b/indra/llrender/llimagegl.cpp
@@ -181,7 +181,7 @@ BOOL is_little_endian()
 //static 
 void LLImageGL::initClass(LLWindow* window, S32 num_catagories, BOOL skip_analyze_alpha /* = false */, bool multi_threaded /* = false */)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	sSkipAnalyzeAlpha = skip_analyze_alpha;
 
     if (multi_threaded)
@@ -193,7 +193,7 @@ void LLImageGL::initClass(LLWindow* window, S32 num_catagories, BOOL skip_analyz
 //static 
 void LLImageGL::cleanupClass() 
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
     LLImageGLThread::deleteSingleton();
 }
 
@@ -277,7 +277,7 @@ S32 LLImageGL::dataFormatComponents(S32 dataformat)
 // static
 void LLImageGL::updateStats(F32 current_time)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	sLastFrameTime = current_time;
 	sBoundTextureMemory = sCurBoundTextureMemory;
 	sCurBoundTextureMemory = S32Bytes(0);
@@ -666,7 +666,7 @@ void LLImageGL::setExplicitFormat( LLGLint internal_format, LLGLenum primary_for
 
 void LLImageGL::setImage(const LLImageRaw* imageraw)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	llassert((imageraw->getWidth() == getWidth(mCurrentDiscardLevel)) &&
 			 (imageraw->getHeight() == getHeight(mCurrentDiscardLevel)) &&
 			 (imageraw->getComponents() == getComponents()));
@@ -676,7 +676,7 @@ void LLImageGL::setImage(const LLImageRaw* imageraw)
 
 BOOL LLImageGL::setImage(const U8* data_in, BOOL data_hasmips, S32 usename)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	bool is_compressed = false;
 
     switch (mFormatPrimary)
@@ -1071,7 +1071,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;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	if (!width || !height)
 	{
 		return TRUE;
@@ -1168,7 +1168,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;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	return setSubImage(imageraw->getData(), imageraw->getWidth(), imageraw->getHeight(), x_pos, y_pos, width, height, force_fast_update);
 }
 
@@ -1191,7 +1191,7 @@ BOOL LLImageGL::setSubImageFromFrameBuffer(S32 fb_x, S32 fb_y, S32 x_pos, S32 y_
 // static
 void LLImageGL::generateTextures(S32 numTextures, U32 *textures)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	glGenTextures(numTextures, textures);
 }
 
@@ -1207,7 +1207,7 @@ void LLImageGL::deleteTextures(S32 numTextures, const U32 *textures)
 // static
 void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 width, S32 height, U32 pixformat, U32 pixtype, const void* pixels, bool allow_compression)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
     bool use_scratch = false;
     U32* scratch = NULL;
     if (LLRender::sGLCoreProfile)
@@ -1324,7 +1324,7 @@ void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 widt
 //the texture is assiciate with some image by calling glTexImage outside LLImageGL
 BOOL LLImageGL::createGLTexture()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
     checkActiveThread();
 
 	if (gGLManager.mIsDisabled)
@@ -1358,7 +1358,7 @@ BOOL LLImageGL::createGLTexture()
 
 BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename/*=0*/, BOOL to_create, S32 category)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
     checkActiveThread();
 
 	if (gGLManager.mIsDisabled)
@@ -1473,7 +1473,7 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S
 
 BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_hasmips, S32 usename)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
     checkActiveThread();
 
     llassert(data_in);
@@ -2264,7 +2264,7 @@ LLImageGLThread::LLImageGLThread(LLWindow* window)
     : ThreadPool("LLImageGL", 1, 1024*1024)
     , mWindow(window)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
     sEnabled = true;
     mFinished = false;
 
@@ -2274,7 +2274,7 @@ LLImageGLThread::LLImageGLThread(LLWindow* window)
 
 void LLImageGLThread::run()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
     // We must perform setup on this thread before actually servicing our
     // WorkQueue, likewise cleanup afterwards.
     mWindow->makeContextCurrent(mContext);
diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp
index dcdc259b26..06f623f1f8 100644
--- a/indra/newview/llviewertexture.cpp
+++ b/indra/newview/llviewertexture.cpp
@@ -182,7 +182,7 @@ void LLViewerTextureManager::findFetchedTextures(const LLUUID& id, std::vector<L
 
 void  LLViewerTextureManager::findTextures(const LLUUID& id, std::vector<LLViewerTexture*> &output)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
     std::vector<LLViewerFetchedTexture*> fetched_output;
     gTextureList.findTexturesByID(id, fetched_output);
     std::vector<LLViewerFetchedTexture*>::iterator iter = fetched_output.begin();
@@ -207,7 +207,7 @@ void  LLViewerTextureManager::findTextures(const LLUUID& id, std::vector<LLViewe
 
 LLViewerFetchedTexture* LLViewerTextureManager::findFetchedTexture(const LLUUID& id, S32 tex_type)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
     return gTextureList.findImage(id, (ETexListType)tex_type);
 }
 
@@ -482,7 +482,7 @@ F32 texmem_middle_bound_scale = 0.925f;
 //static 
 bool LLViewerTexture::isMemoryForTextureLow()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
     // Note: we need to figure out a better source for 'min' values,
     // what is free for low end at minimal settings is 'nothing left'
     // for higher end gpus at high settings.
@@ -499,7 +499,7 @@ bool LLViewerTexture::isMemoryForTextureLow()
 //static
 bool LLViewerTexture::isMemoryForTextureSuficientlyFree()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
     const S32Megabytes DESIRED_FREE_TEXTURE_MEMORY(50);
     const S32Megabytes DESIRED_FREE_MAIN_MEMORY(200);
 
@@ -513,7 +513,7 @@ bool LLViewerTexture::isMemoryForTextureSuficientlyFree()
 //static
 void LLViewerTexture::getGPUMemoryForTextures(S32Megabytes &gpu, S32Megabytes &physical)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
     static LLFrameTimer timer;
     static S32Megabytes gpu_res = S32Megabytes(S32_MAX);
     static S32Megabytes physical_res = S32Megabytes(S32_MAX);
@@ -552,7 +552,7 @@ void LLViewerTexture::getGPUMemoryForTextures(S32Megabytes &gpu, S32Megabytes &p
 //static
 void LLViewerTexture::updateClass()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	sCurrentTime = gFrameTimeSeconds;
 
 	LLTexturePipelineTester* tester = (LLTexturePipelineTester*)LLMetricPerformanceTesterBasic::getTester(sTesterName);
@@ -701,7 +701,7 @@ void LLViewerTexture::cleanup()
 
 void LLViewerTexture::notifyAboutCreatingTexture()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	for(U32 ch = 0; ch < LLRender::NUM_TEXTURE_CHANNELS; ++ch)
 	{
 		for(U32 f = 0; f < mNumFaces[ch]; f++)
@@ -713,7 +713,7 @@ void LLViewerTexture::notifyAboutCreatingTexture()
 
 void LLViewerTexture::notifyAboutMissingAsset()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	for(U32 ch = 0; ch < LLRender::NUM_TEXTURE_CHANNELS; ++ch)
 	{
 		for(U32 f = 0; f < mNumFaces[ch]; f++)
@@ -726,7 +726,7 @@ void LLViewerTexture::notifyAboutMissingAsset()
 // virtual
 void LLViewerTexture::dump()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	LLGLTexture::dump();
 
 	LL_INFOS() << "LLViewerTexture"
@@ -762,7 +762,7 @@ bool LLViewerTexture::isActiveFetching()
 
 bool LLViewerTexture::bindDebugImage(const S32 stage)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	if (stage < 0) return false;
 
 	bool res = true;
@@ -781,7 +781,7 @@ bool LLViewerTexture::bindDebugImage(const S32 stage)
 
 bool LLViewerTexture::bindDefaultImage(S32 stage) 
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	if (stage < 0) return false;
 
 	bool res = true;
@@ -824,7 +824,7 @@ void LLViewerTexture::forceImmediateUpdate()
 
 void LLViewerTexture::addTextureStats(F32 virtual_size, BOOL needs_gltexture) const 
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	if(needs_gltexture)
 	{
 		mNeedsGLTexture = TRUE;
@@ -867,7 +867,7 @@ void LLViewerTexture::setKnownDrawSize(S32 width, S32 height)
 //virtual
 void LLViewerTexture::addFace(U32 ch, LLFace* facep) 
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	llassert(ch < LLRender::NUM_TEXTURE_CHANNELS);
 
 	if(mNumFaces[ch] >= mFaceList[ch].size())
@@ -883,7 +883,7 @@ void LLViewerTexture::addFace(U32 ch, LLFace* facep)
 //virtual
 void LLViewerTexture::removeFace(U32 ch, LLFace* facep) 
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	llassert(ch < LLRender::NUM_TEXTURE_CHANNELS);
 
 	if(mNumFaces[ch] > 1)
@@ -924,7 +924,7 @@ S32 LLViewerTexture::getNumFaces(U32 ch) const
 //virtual
 void LLViewerTexture::addVolume(U32 ch, LLVOVolume* volumep)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	if (mNumVolumes[ch] >= mVolumeList[ch].size())
 	{
 		mVolumeList[ch].resize(2 * mNumVolumes[ch] + 1);
@@ -938,7 +938,7 @@ void LLViewerTexture::addVolume(U32 ch, LLVOVolume* volumep)
 //virtual
 void LLViewerTexture::removeVolume(U32 ch, LLVOVolume* volumep)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	if (mNumVolumes[ch] > 1)
 	{
 		S32 index = volumep->getIndexInTex(ch); 
@@ -962,7 +962,7 @@ S32 LLViewerTexture::getNumVolumes(U32 ch) const
 
 void LLViewerTexture::reorganizeFaceList()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	static const F32 MAX_WAIT_TIME = 20.f; // seconds
 	static const U32 MAX_EXTRA_BUFFER_SIZE = 4;
 
@@ -986,7 +986,7 @@ void LLViewerTexture::reorganizeFaceList()
 
 void LLViewerTexture::reorganizeVolumeList()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	static const F32 MAX_WAIT_TIME = 20.f; // seconds
 	static const U32 MAX_EXTRA_BUFFER_SIZE = 4;
 
@@ -1189,7 +1189,7 @@ FTType LLViewerFetchedTexture::getFTType() const
 
 void LLViewerFetchedTexture::cleanup()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	for(callback_list_t::iterator iter = mLoadedCallbackList.begin();
 		iter != mLoadedCallbackList.end(); )
 	{
@@ -1215,7 +1215,7 @@ void LLViewerFetchedTexture::cleanup()
 //access the fast cache
 void LLViewerFetchedTexture::loadFromFastCache()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	if(!mInFastCacheList)
 	{
 		return; //no need to access the fast cache.
@@ -1361,7 +1361,7 @@ void LLViewerFetchedTexture::dump()
 // ONLY called from LLViewerFetchedTextureList
 void LLViewerFetchedTexture::destroyTexture() 
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	if(LLImageGL::sGlobalTextureMemory < sMaxDesiredTextureMem * 0.95f)//not ready to release unused memory.
 	{
 		return ;
@@ -1378,7 +1378,7 @@ void LLViewerFetchedTexture::destroyTexture()
 
 void LLViewerFetchedTexture::addToCreateTexture()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	bool force_update = false;
 	if (getComponents() != mRawImage->getComponents())
 	{
@@ -1420,7 +1420,7 @@ void LLViewerFetchedTexture::addToCreateTexture()
 	}
 	else
 	{	
-        LL_PROFILE_ZONE_SCOPED;
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 #if 1
 		//
 		//if mRequestedDiscardLevel > mDesiredDiscardLevel, we assume the required image res keep going up,
@@ -1473,7 +1473,7 @@ void LLViewerFetchedTexture::addToCreateTexture()
 // ONLY called from LLViewerTextureList
 BOOL LLViewerFetchedTexture::preCreateTexture(S32 usename/*= 0*/)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 #if LL_IMAGEGL_THREAD_CHECK
     mGLTexturep->checkActiveThread();
 #endif
@@ -1954,7 +1954,7 @@ void LLViewerFetchedTexture::setAdditionalDecodePriority(F32 priority)
 
 void LLViewerFetchedTexture::updateVirtualSize() 
 {	
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	if(!mMaxVirtualSizeResetCounter)
 	{
 		addTextureStats(0.f, FALSE);//reset
@@ -2046,7 +2046,7 @@ bool LLViewerFetchedTexture::isActiveFetching()
 
 bool LLViewerFetchedTexture::updateFetch()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	static LLCachedControl<bool> textures_decode_disabled(gSavedSettings,"TextureDecodeDisabled", false);
 	static LLCachedControl<F32>  sCameraMotionThreshold(gSavedSettings,"TextureCameraMotionThreshold", 0.2);
 	static LLCachedControl<S32>  sCameraMotionBoost(gSavedSettings,"TextureCameraMotionBoost", 3);
@@ -2627,7 +2627,7 @@ void LLViewerFetchedTexture::pauseLoadedCallbacks(const LLLoadedCallbackEntry::s
 
 bool LLViewerFetchedTexture::doLoadedCallbacks()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	static const F32 MAX_INACTIVE_TIME = 900.f ; //seconds
 	static const F32 MAX_IDLE_WAIT_TIME = 5.f ; //seconds
 
@@ -2978,7 +2978,7 @@ void LLViewerFetchedTexture::destroyRawImage()
 //virtual
 void LLViewerFetchedTexture::switchToCachedImage()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	if(mCachedRawImage.notNull() && 
         !mNeedsCreateTexture) // <--- texture creation is pending, don't step on it
 	{
@@ -3270,7 +3270,7 @@ bool LLViewerLODTexture::isUpdateFrozen()
 //virtual
 void LLViewerLODTexture::processTextureStats()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	updateVirtualSize();
 	
 	static LLCachedControl<bool> textures_fullres(gSavedSettings,"TextureLoadFullRes", false);
@@ -3434,7 +3434,7 @@ bool LLViewerLODTexture::scaleDown()
 //static
 void LLViewerMediaTexture::updateClass()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	static const F32 MAX_INACTIVE_TIME = 30.f;
 
 #if 0
diff --git a/indra/newview/llviewertexturelist.cpp b/indra/newview/llviewertexturelist.cpp
index db59976be2..dd18cdc9e8 100644
--- a/indra/newview/llviewertexturelist.cpp
+++ b/indra/newview/llviewertexturelist.cpp
@@ -111,7 +111,7 @@ void LLViewerTextureList::init()
 
 void LLViewerTextureList::doPreloadImages()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	LL_DEBUGS("ViewerImages") << "Preloading images..." << LL_ENDL;
 	
 	llassert_always(mInitialized) ;
@@ -203,7 +203,7 @@ static std::string get_texture_list_name()
 
 void LLViewerTextureList::doPrefetchImages()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	if (LLAppViewer::instance()->getPurgeCache())
 	{
 		// cache was purged, no point
@@ -257,7 +257,7 @@ LLViewerTextureList::~LLViewerTextureList()
 
 void LLViewerTextureList::shutdown()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	// clear out preloads
 	mImagePreloads.clear();
 
@@ -333,7 +333,7 @@ void LLViewerTextureList::shutdown()
 
 void LLViewerTextureList::dump()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	LL_INFOS() << "LLViewerTextureList::dump()" << LL_ENDL;
 	for (image_priority_list_t::iterator it = mImageList.begin(); it != mImageList.end(); ++it)
 	{
@@ -378,7 +378,7 @@ LLViewerFetchedTexture* LLViewerTextureList::getImageFromFile(const std::string&
 												   LLGLenum primary_format, 
 												   const LLUUID& force_id)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	if(!mInitialized)
 	{
 		return NULL ;
@@ -406,7 +406,7 @@ LLViewerFetchedTexture* LLViewerTextureList::getImageFromUrl(const std::string&
 												   LLGLenum primary_format, 
 												   const LLUUID& force_id)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	if(!mInitialized)
 	{
 		return NULL ;
@@ -495,7 +495,7 @@ LLViewerFetchedTexture* LLViewerTextureList::getImage(const LLUUID &image_id,
 												   LLGLenum primary_format,
 												   LLHost request_from_host)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	if(!mInitialized)
 	{
 		return NULL ;
@@ -558,7 +558,7 @@ LLViewerFetchedTexture* LLViewerTextureList::createImage(const LLUUID &image_id,
 												   LLGLenum primary_format,
 												   LLHost request_from_host)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	static LLCachedControl<bool> fast_cache_fetching_enabled(gSavedSettings, "FastCacheFetchEnabled", true);
 
 	LLPointer<LLViewerFetchedTexture> imagep ;
@@ -614,7 +614,7 @@ LLViewerFetchedTexture* LLViewerTextureList::createImage(const LLUUID &image_id,
 
 void LLViewerTextureList::findTexturesByID(const LLUUID &image_id, std::vector<LLViewerFetchedTexture*> &output)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
     LLTextureKey search_key(image_id, TEX_LIST_STANDARD);
     uuid_map_t::iterator iter = mUUIDMap.lower_bound(search_key);
     while (iter != mUUIDMap.end() && iter->first.textureId == image_id)
@@ -626,7 +626,7 @@ void LLViewerTextureList::findTexturesByID(const LLUUID &image_id, std::vector<L
 
 LLViewerFetchedTexture *LLViewerTextureList::findImage(const LLTextureKey &search_key)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
     uuid_map_t::iterator iter = mUUIDMap.find(search_key);
     if (iter == mUUIDMap.end())
         return NULL;
@@ -640,7 +640,7 @@ LLViewerFetchedTexture *LLViewerTextureList::findImage(const LLUUID &image_id, E
 
 void LLViewerTextureList::addImageToList(LLViewerFetchedTexture *image)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	assert_main_thread();
 	llassert_always(mInitialized) ;
 	llassert(image);
@@ -660,7 +660,7 @@ void LLViewerTextureList::addImageToList(LLViewerFetchedTexture *image)
 
 void LLViewerTextureList::removeImageFromList(LLViewerFetchedTexture *image)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	assert_main_thread();
 	llassert_always(mInitialized) ;
 	llassert(image);
@@ -709,7 +709,7 @@ void LLViewerTextureList::removeImageFromList(LLViewerFetchedTexture *image)
 
 void LLViewerTextureList::addImage(LLViewerFetchedTexture *new_image, ETexListType tex_type)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	if (!new_image)
 	{
 		return;
@@ -733,7 +733,7 @@ void LLViewerTextureList::addImage(LLViewerFetchedTexture *new_image, ETexListTy
 
 void LLViewerTextureList::deleteImage(LLViewerFetchedTexture *image)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	if( image)
 	{
 		if (image->hasCallbacks())
@@ -761,7 +761,7 @@ void LLViewerTextureList::dirtyImage(LLViewerFetchedTexture *image)
 
 void LLViewerTextureList::updateImages(F32 max_time)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	static BOOL cleared = FALSE;
 	if(gTeleportDisplay)
 	{
@@ -829,7 +829,7 @@ void LLViewerTextureList::updateImages(F32 max_time)
 
 void LLViewerTextureList::clearFetchingRequests()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	if (LLAppViewer::getTextureFetch()->getNumRequests() == 0)
 	{
 		return;
@@ -847,7 +847,7 @@ void LLViewerTextureList::clearFetchingRequests()
 
 void LLViewerTextureList::updateImagesDecodePriorities()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	// Update the decode priority for N images each frame
 	{
 		F32 lazy_flush_timeout = 30.f; // stop decoding
@@ -963,7 +963,7 @@ void LLViewerTextureList::updateImagesDecodePriorities()
 
 void LLViewerTextureList::setDebugFetching(LLViewerFetchedTexture* tex, S32 debug_level)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	if(!tex->setDebugFetching(debug_level))
 	{
 		return;
@@ -1012,7 +1012,7 @@ void LLViewerTextureList::setDebugFetching(LLViewerFetchedTexture* tex, S32 debu
 
 F32 LLViewerTextureList::updateImagesCreateTextures(F32 max_time)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	if (gGLManager.mIsDisabled) return 0.0f;
 	
 	//
@@ -1041,7 +1041,7 @@ F32 LLViewerTextureList::updateImagesCreateTextures(F32 max_time)
 
 F32 LLViewerTextureList::updateImagesLoadingFastCache(F32 max_time)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	if (gGLManager.mIsDisabled) return 0.0f;
 	if(mFastCacheList.empty())
 	{
@@ -1072,7 +1072,7 @@ F32 LLViewerTextureList::updateImagesLoadingFastCache(F32 max_time)
 
 void LLViewerTextureList::forceImmediateUpdate(LLViewerFetchedTexture* imagep)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	if(!imagep)
 	{
 		return ;
@@ -1092,7 +1092,7 @@ void LLViewerTextureList::forceImmediateUpdate(LLViewerFetchedTexture* imagep)
 
 F32 LLViewerTextureList::updateImagesFetchTextures(F32 max_time)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	LLTimer image_op_timer;
 	
 	// Update fetch for N images each frame
@@ -1168,7 +1168,7 @@ F32 LLViewerTextureList::updateImagesFetchTextures(F32 max_time)
 
 void LLViewerTextureList::updateImagesUpdateStats()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	if (mForceResetTextureStats)
 	{
 		for (image_priority_list_t::iterator iter = mImageList.begin();
@@ -1183,7 +1183,7 @@ void LLViewerTextureList::updateImagesUpdateStats()
 
 void LLViewerTextureList::decodeAllImages(F32 max_time)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	LLTimer timer;
 
 	//loading from fast cache 
@@ -1253,7 +1253,7 @@ BOOL LLViewerTextureList::createUploadFile(const std::string& filename,
 										 const std::string& out_filename,
 										 const U8 codec)
 {	
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	// Load the image
 	LLPointer<LLImageFormatted> image = LLImageFormatted::createFromType(codec);
 	if (image.isNull())
@@ -1307,7 +1307,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;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	raw_image->biasedScaleToPowerOfTwo(LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT);
 	LLPointer<LLImageJ2C> compressedImage = new LLImageJ2C();
 	
@@ -1341,7 +1341,7 @@ LLPointer<LLImageJ2C> LLViewerTextureList::convertToUploadFile(LLPointer<LLImage
 // Returns min setting for TextureMemory (in MB)
 S32Megabytes LLViewerTextureList::getMinVideoRamSetting()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	U32Megabytes system_ram = gSysMemory.getPhysicalMemoryKB();
 	//min texture mem sets to 64M if total physical mem is more than 1.5GB
 	return (system_ram > U32Megabytes(1500)) ? S32Megabytes(64) : gMinVideoRam ;
@@ -1351,7 +1351,7 @@ S32Megabytes LLViewerTextureList::getMinVideoRamSetting()
 // Returns max setting for TextureMemory (in MB)
 S32Megabytes LLViewerTextureList::getMaxVideoRamSetting(bool get_recommended, float mem_multiplier)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	S32Megabytes max_texmem;
 	if (gGLManager.mVRAM != 0)
 	{
@@ -1405,7 +1405,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;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	// Initialize the image pipeline VRAM settings
 	S32Megabytes cur_mem(gSavedSettings.getS32("TextureMemory"));
 	F32 mem_multiplier = gSavedSettings.getF32("RenderTextureMemoryMultiple");
@@ -1468,7 +1468,7 @@ void LLViewerTextureList::receiveImageHeader(LLMessageSystem *msg, void **user_d
 {
 	static LLCachedControl<bool> log_texture_traffic(gSavedSettings,"LogTextureNetworkTraffic", false) ;
 
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 
 	// Receive image header, copy into image object and decompresses 
 	// if this is a one-packet image. 
@@ -1540,7 +1540,7 @@ void LLViewerTextureList::receiveImagePacket(LLMessageSystem *msg, void **user_d
 {
 	static LLCachedControl<bool> log_texture_traffic(gSavedSettings,"LogTextureNetworkTraffic", false) ;
 
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	
 	// Receives image packet, copy into image object,
 	// checks if all packets received, decompresses if so. 
@@ -1613,7 +1613,7 @@ void LLViewerTextureList::receiveImagePacket(LLMessageSystem *msg, void **user_d
 // static
 void LLViewerTextureList::processImageNotInDatabase(LLMessageSystem *msg,void **user_data)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	LLUUID image_id;
 	msg->getUUIDFast(_PREHASH_ImageID, _PREHASH_ID, image_id);
 	
@@ -1646,7 +1646,7 @@ void LLUIImageList::cleanUp()
 
 LLUIImagePtr LLUIImageList::getUIImageByID(const LLUUID& image_id, S32 priority)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	// use id as image name
 	std::string image_name = image_id.asString();
 
@@ -1665,7 +1665,7 @@ LLUIImagePtr LLUIImageList::getUIImageByID(const LLUUID& image_id, S32 priority)
 
 LLUIImagePtr LLUIImageList::getUIImage(const std::string& image_name, S32 priority)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	// look for existing image
 	uuid_ui_image_map_t::iterator found_it = mUIImages.find(image_name);
 	if (found_it != mUIImages.end())
@@ -1683,7 +1683,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;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	if (boost_priority == LLGLTexture::BOOST_NONE)
 	{
 		boost_priority = LLGLTexture::BOOST_UI;
@@ -1696,7 +1696,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;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	if (boost_priority == LLGLTexture::BOOST_NONE)
 	{
 		boost_priority = LLGLTexture::BOOST_UI;
@@ -1708,7 +1708,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;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	if (!imagep) return NULL;
 
 	imagep->setAddressMode(LLTexUnit::TAM_CLAMP);
@@ -1746,7 +1746,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;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	// look for existing image
 	uuid_ui_image_map_t::iterator found_it = mUIImages.find(name);
 	if (found_it != mUIImages.end())
@@ -1761,7 +1761,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;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	if(!success || !user_data) 
 	{
 		return;
@@ -1863,7 +1863,7 @@ struct UIImageDeclarations : public LLInitParam::Block<UIImageDeclarations>
 
 bool LLUIImageList::initFromFile()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	// Look for textures.xml in all the right places. Pass
 	// constraint=LLDir::ALL_SKINS because we want to overlay textures.xml
 	// from all the skins directories.
-- 
cgit v1.2.3


From a8796a1054035fd5a83e451b9fe6363b181b7422 Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Thu, 13 Jan 2022 12:55:53 -0800
Subject: SL-16606: Add profiler category THREAD

---
 indra/llcommon/llmutex.cpp          | 24 ++++++++++----------
 indra/llcommon/llsingleton.h        |  2 +-
 indra/llcommon/llthread.cpp         | 14 ++++++------
 indra/llcommon/llthreadsafequeue.h  | 36 +++++++++++++++---------------
 indra/llcommon/threadsafeschedule.h | 44 ++++++++++++++++++-------------------
 indra/llcommon/workqueue.cpp        |  8 +++----
 6 files changed, 64 insertions(+), 64 deletions(-)

(limited to 'indra')

diff --git a/indra/llcommon/llmutex.cpp b/indra/llcommon/llmutex.cpp
index a49002b5dc..0273dd5970 100644
--- a/indra/llcommon/llmutex.cpp
+++ b/indra/llcommon/llmutex.cpp
@@ -44,7 +44,7 @@ LLMutex::~LLMutex()
 
 void LLMutex::lock()
 {
-    LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
 	if(isSelfLocked())
 	{ //redundant lock
 		mCount++;
@@ -66,7 +66,7 @@ void LLMutex::lock()
 
 void LLMutex::unlock()
 {
-    LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
 	if (mCount > 0)
 	{ //not the root unlock
 		mCount--;
@@ -87,7 +87,7 @@ void LLMutex::unlock()
 
 bool LLMutex::isLocked()
 {
-    LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
 	if (!mMutex.try_lock())
 	{
 		return true;
@@ -111,7 +111,7 @@ LLThread::id_t LLMutex::lockingThread() const
 
 bool LLMutex::trylock()
 {
-    LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
 	if(isSelfLocked())
 	{ //redundant lock
 		mCount++;
@@ -150,20 +150,20 @@ LLCondition::~LLCondition()
 
 void LLCondition::wait()
 {
-    LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
 	std::unique_lock< std::mutex > lock(mMutex);
 	mCond.wait(lock);
 }
 
 void LLCondition::signal()
 {
-    LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
 	mCond.notify_one();
 }
 
 void LLCondition::broadcast()
 {
-    LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
 	mCond.notify_all();
 }
 
@@ -173,7 +173,7 @@ LLMutexTrylock::LLMutexTrylock(LLMutex* mutex)
     : mMutex(mutex),
     mLocked(false)
 {
-    LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
     if (mMutex)
         mLocked = mMutex->trylock();
 }
@@ -182,7 +182,7 @@ LLMutexTrylock::LLMutexTrylock(LLMutex* mutex, U32 aTries, U32 delay_ms)
     : mMutex(mutex),
     mLocked(false)
 {
-    LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
     if (!mMutex)
         return;
 
@@ -197,7 +197,7 @@ LLMutexTrylock::LLMutexTrylock(LLMutex* mutex, U32 aTries, U32 delay_ms)
 
 LLMutexTrylock::~LLMutexTrylock()
 {
-    LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
     if (mMutex && mLocked)
         mMutex->unlock();
 }
@@ -209,7 +209,7 @@ LLMutexTrylock::~LLMutexTrylock()
 //
 LLScopedLock::LLScopedLock(std::mutex* mutex) : mMutex(mutex)
 {
-    LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
 	if(mutex)
 	{
 		mutex->lock();
@@ -228,7 +228,7 @@ LLScopedLock::~LLScopedLock()
 
 void LLScopedLock::unlock()
 {
-    LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
 	if(mLocked)
 	{
 		mMutex->unlock();
diff --git a/indra/llcommon/llsingleton.h b/indra/llcommon/llsingleton.h
index 6042c0906c..51ef514cf7 100644
--- a/indra/llcommon/llsingleton.h
+++ b/indra/llcommon/llsingleton.h
@@ -455,7 +455,7 @@ public:
 
     static DERIVED_TYPE* getInstance()
     {
-        LL_PROFILE_ZONE_SCOPED;
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
         // We know the viewer has LLSingleton dependency circularities. If you
         // feel strongly motivated to eliminate them, cheers and good luck.
         // (At that point we could consider a much simpler locking mechanism.)
diff --git a/indra/llcommon/llthread.cpp b/indra/llcommon/llthread.cpp
index 11f5a015f1..a807acc56e 100644
--- a/indra/llcommon/llthread.cpp
+++ b/indra/llcommon/llthread.cpp
@@ -333,7 +333,7 @@ bool LLThread::runCondition(void)
 // Stop thread execution if requested until unpaused.
 void LLThread::checkPause()
 {
-    LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
     mDataLock->lock();
 
     // This is in a while loop because the pthread API allows for spurious wakeups.
@@ -365,20 +365,20 @@ void LLThread::setQuitting()
 // static
 LLThread::id_t LLThread::currentID()
 {
-    LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
     return std::this_thread::get_id();
 }
 
 // static
 void LLThread::yield()
 {
-    LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
     std::this_thread::yield();
 }
 
 void LLThread::wake()
 {
-    LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
     mDataLock->lock();
     if(!shouldSleep())
     {
@@ -389,7 +389,7 @@ void LLThread::wake()
 
 void LLThread::wakeLocked()
 {
-    LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
     if(!shouldSleep())
     {
         mRunCondition->signal();
@@ -398,13 +398,13 @@ void LLThread::wakeLocked()
 
 void LLThread::lockData()
 {
-    LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
     mDataLock->lock();
 }
 
 void LLThread::unlockData()
 {
-    LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
     mDataLock->unlock();
 }
 
diff --git a/indra/llcommon/llthreadsafequeue.h b/indra/llcommon/llthreadsafequeue.h
index 2806506550..68d79cdd12 100644
--- a/indra/llcommon/llthreadsafequeue.h
+++ b/indra/llcommon/llthreadsafequeue.h
@@ -275,7 +275,7 @@ template <typename ElementT, typename QueueT>
 template <typename CALLABLE>
 bool LLThreadSafeQueue<ElementT, QueueT>::tryLock(CALLABLE&& callable)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
     lock_t lock1(mLock, std::defer_lock);
     if (!lock1.try_lock())
         return false;
@@ -292,7 +292,7 @@ bool LLThreadSafeQueue<ElementT, QueueT>::tryLockUntil(
     const std::chrono::time_point<Clock, Duration>& until,
     CALLABLE&& callable)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
     lock_t lock1(mLock, std::defer_lock);
     if (!lock1.try_lock_until(until))
         return false;
@@ -306,7 +306,7 @@ template <typename ElementT, typename QueueT>
 template <typename T>
 bool LLThreadSafeQueue<ElementT, QueueT>::push_(lock_t& lock, T&& element)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
     if (mStorage.size() >= mCapacity)
         return false;
 
@@ -322,7 +322,7 @@ template <typename ElementT, typename QueueT>
 template <typename T>
 bool LLThreadSafeQueue<ElementT, QueueT>::pushIfOpen(T&& element)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
     lock_t lock1(mLock);
     while (true)
     {
@@ -345,7 +345,7 @@ template <typename ElementT, typename QueueT>
 template<typename T>
 void LLThreadSafeQueue<ElementT, QueueT>::push(T&& element)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
     if (! pushIfOpen(std::forward<T>(element)))
     {
         LLTHROW(LLThreadSafeQueueInterrupt());
@@ -357,7 +357,7 @@ template<typename ElementT, typename QueueT>
 template<typename T>
 bool LLThreadSafeQueue<ElementT, QueueT>::tryPush(T&& element)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
     return tryLock(
         [this, element=std::move(element)](lock_t& lock)
         {
@@ -374,7 +374,7 @@ bool LLThreadSafeQueue<ElementT, QueueT>::tryPushFor(
     const std::chrono::duration<Rep, Period>& timeout,
     T&& element)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
     // Convert duration to time_point: passing the same timeout duration to
     // each of multiple calls is wrong.
     return tryPushUntil(std::chrono::steady_clock::now() + timeout,
@@ -388,7 +388,7 @@ bool LLThreadSafeQueue<ElementT, QueueT>::tryPushUntil(
     const std::chrono::time_point<Clock, Duration>& until,
     T&& element)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
     return tryLockUntil(
         until,
         [this, until, element=std::move(element)](lock_t& lock)
@@ -421,7 +421,7 @@ template <typename ElementT, typename QueueT>
 typename LLThreadSafeQueue<ElementT, QueueT>::pop_result
 LLThreadSafeQueue<ElementT, QueueT>::pop_(lock_t& lock, ElementT& element)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
     // If mStorage is empty, there's no head element.
     if (mStorage.empty())
         return mClosed? DONE : EMPTY;
@@ -443,7 +443,7 @@ LLThreadSafeQueue<ElementT, QueueT>::pop_(lock_t& lock, ElementT& element)
 template<typename ElementT, typename QueueT>
 ElementT LLThreadSafeQueue<ElementT, QueueT>::pop(void)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
     lock_t lock1(mLock);
     ElementT value;
     while (true)
@@ -472,7 +472,7 @@ ElementT LLThreadSafeQueue<ElementT, QueueT>::pop(void)
 template<typename ElementT, typename QueueT>
 bool LLThreadSafeQueue<ElementT, QueueT>::tryPop(ElementT & element)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
     return tryLock(
         [this, &element](lock_t& lock)
         {
@@ -490,7 +490,7 @@ bool LLThreadSafeQueue<ElementT, QueueT>::tryPopFor(
     const std::chrono::duration<Rep, Period>& timeout,
     ElementT& element)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
     // Convert duration to time_point: passing the same timeout duration to
     // each of multiple calls is wrong.
     return tryPopUntil(std::chrono::steady_clock::now() + timeout, element);
@@ -503,7 +503,7 @@ bool LLThreadSafeQueue<ElementT, QueueT>::tryPopUntil(
     const std::chrono::time_point<Clock, Duration>& until,
     ElementT& element)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
     return tryLockUntil(
         until,
         [this, until, &element](lock_t& lock)
@@ -523,7 +523,7 @@ LLThreadSafeQueue<ElementT, QueueT>::tryPopUntil_(
     const std::chrono::time_point<Clock, Duration>& until,
     ElementT& element)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
     while (true)
     {
         pop_result popped = pop_(lock, element);
@@ -550,7 +550,7 @@ LLThreadSafeQueue<ElementT, QueueT>::tryPopUntil_(
 template<typename ElementT, typename QueueT>
 size_t LLThreadSafeQueue<ElementT, QueueT>::size(void)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
     lock_t lock(mLock);
     return mStorage.size();
 }
@@ -559,7 +559,7 @@ size_t LLThreadSafeQueue<ElementT, QueueT>::size(void)
 template<typename ElementT, typename QueueT>
 void LLThreadSafeQueue<ElementT, QueueT>::close()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
     lock_t lock(mLock);
     mClosed = true;
     lock.unlock();
@@ -573,7 +573,7 @@ void LLThreadSafeQueue<ElementT, QueueT>::close()
 template<typename ElementT, typename QueueT>
 bool LLThreadSafeQueue<ElementT, QueueT>::isClosed()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
     lock_t lock(mLock);
     return mClosed;
 }
@@ -582,7 +582,7 @@ bool LLThreadSafeQueue<ElementT, QueueT>::isClosed()
 template<typename ElementT, typename QueueT>
 bool LLThreadSafeQueue<ElementT, QueueT>::done()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
     lock_t lock(mLock);
     return mClosed && mStorage.empty();
 }
diff --git a/indra/llcommon/threadsafeschedule.h b/indra/llcommon/threadsafeschedule.h
index 601681d550..3e0da94c02 100644
--- a/indra/llcommon/threadsafeschedule.h
+++ b/indra/llcommon/threadsafeschedule.h
@@ -98,14 +98,14 @@ namespace LL
         // we could minimize redundancy by breaking out a common base class...
         void push(const DataTuple& tuple)
         {
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
             push(tuple_cons(Clock::now(), tuple));
         }
 
         /// individually pass each component of the TimeTuple
         void push(const TimePoint& time, Args&&... args)
         {
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
             push(TimeTuple(time, std::forward<Args>(args)...));
         }
 
@@ -116,7 +116,7 @@ namespace LL
         // and call that overload.
         void push(Args&&... args)
         {
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
             push(Clock::now(), std::forward<Args>(args)...);
         }
 
@@ -127,21 +127,21 @@ namespace LL
         /// DataTuple with implicit now
         bool tryPush(const DataTuple& tuple)
         {
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
             return tryPush(tuple_cons(Clock::now(), tuple));
         }
 
         /// individually pass components
         bool tryPush(const TimePoint& time, Args&&... args)
         {
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
             return tryPush(TimeTuple(time, std::forward<Args>(args)...));
         }
 
         /// individually pass components with implicit now
         bool tryPush(Args&&... args)
         {
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
             return tryPush(Clock::now(), std::forward<Args>(args)...);
         }
 
@@ -154,7 +154,7 @@ namespace LL
         bool tryPushFor(const std::chrono::duration<Rep, Period>& timeout,
                         const DataTuple& tuple)
         {
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
             return tryPushFor(timeout, tuple_cons(Clock::now(), tuple));
         }
 
@@ -163,7 +163,7 @@ namespace LL
         bool tryPushFor(const std::chrono::duration<Rep, Period>& timeout,
                         const TimePoint& time, Args&&... args)
         {
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
             return tryPushFor(TimeTuple(time, std::forward<Args>(args)...));
         }
 
@@ -172,7 +172,7 @@ namespace LL
         bool tryPushFor(const std::chrono::duration<Rep, Period>& timeout,
                         Args&&... args)
         {
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
             return tryPushFor(Clock::now(), std::forward<Args>(args)...);
         }
 
@@ -185,7 +185,7 @@ namespace LL
         bool tryPushUntil(const std::chrono::time_point<Clock, Duration>& until,
                           const DataTuple& tuple)
         {
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
             return tryPushUntil(until, tuple_cons(Clock::now(), tuple));
         }
 
@@ -194,7 +194,7 @@ namespace LL
         bool tryPushUntil(const std::chrono::time_point<Clock, Duration>& until,
                           const TimePoint& time, Args&&... args)
         {
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
             return tryPushUntil(until, TimeTuple(time, std::forward<Args>(args)...));
         }
 
@@ -203,7 +203,7 @@ namespace LL
         bool tryPushUntil(const std::chrono::time_point<Clock, Duration>& until,
                           Args&&... args)
         {
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
             return tryPushUntil(until, Clock::now(), std::forward<Args>(args)...);
         }
 
@@ -221,14 +221,14 @@ namespace LL
         // haven't yet jumped through those hoops.
         DataTuple pop()
         {
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
             return tuple_cdr(popWithTime());
         }
 
         /// pop TimeTuple by value
         TimeTuple popWithTime()
         {
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
             lock_t lock(super::mLock);
             // We can't just sit around waiting forever, given that there may
             // be items in the queue that are not yet ready but will *become*
@@ -268,7 +268,7 @@ namespace LL
         /// tryPop(DataTuple&)
         bool tryPop(DataTuple& tuple)
         {
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
             TimeTuple tt;
             if (! super::tryPop(tt))
                 return false;
@@ -279,7 +279,7 @@ namespace LL
         /// for when Args has exactly one type
         bool tryPop(typename std::tuple_element<1, TimeTuple>::type& value)
         {
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
             TimeTuple tt;
             if (! super::tryPop(tt))
                 return false;
@@ -291,7 +291,7 @@ namespace LL
         template <typename Rep, typename Period, typename Tuple>
         bool tryPopFor(const std::chrono::duration<Rep, Period>& timeout, Tuple& tuple)
         {
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
             // It's important to use OUR tryPopUntil() implementation, rather
             // than delegating immediately to our base class.
             return tryPopUntil(Clock::now() + timeout, tuple);
@@ -302,7 +302,7 @@ namespace LL
         bool tryPopUntil(const std::chrono::time_point<Clock, Duration>& until,
                          TimeTuple& tuple)
         {
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
             // super::tryPopUntil() wakes up when an item becomes available or
             // we hit 'until', whichever comes first. Thing is, the current
             // head of the queue could become ready sooner than either of
@@ -322,7 +322,7 @@ namespace LL
 
         pop_result tryPopUntil_(lock_t& lock, const TimePoint& until, TimeTuple& tuple)
         {
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
             TimePoint adjusted = until;
             if (! super::mStorage.empty())
             {
@@ -350,7 +350,7 @@ namespace LL
         bool tryPopUntil(const std::chrono::time_point<Clock, Duration>& until,
                          DataTuple& tuple)
         {
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
             TimeTuple tt;
             if (! tryPopUntil(until, tt))
                 return false;
@@ -363,7 +363,7 @@ namespace LL
         bool tryPopUntil(const std::chrono::time_point<Clock, Duration>& until,
                          typename std::tuple_element<1, TimeTuple>::type& value)
         {
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
             TimeTuple tt;
             if (! tryPopUntil(until, tt))
                 return false;
@@ -387,7 +387,7 @@ namespace LL
         // considering whether to deliver the current head element
         bool canPop(const TimeTuple& head) const override
         {
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
             // an item with a future timestamp isn't yet ready to pop
             // (should we add some slop for overhead?)
             return std::get<0>(head) <= Clock::now();
diff --git a/indra/llcommon/workqueue.cpp b/indra/llcommon/workqueue.cpp
index c74dada2e4..eb06890468 100644
--- a/indra/llcommon/workqueue.cpp
+++ b/indra/llcommon/workqueue.cpp
@@ -60,7 +60,7 @@ void LL::WorkQueue::runUntilClose()
     {
         for (;;)
         {
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
             callWork(mQueue.pop());
         }
     }
@@ -71,7 +71,7 @@ void LL::WorkQueue::runUntilClose()
 
 bool LL::WorkQueue::runPending()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
     for (Work work; mQueue.tryPop(work); )
     {
         callWork(work);
@@ -91,7 +91,7 @@ bool LL::WorkQueue::runOne()
 
 bool LL::WorkQueue::runUntil(const TimePoint& until)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
     // Should we subtract some slop to allow for typical Work execution time?
     // How much slop?
     // runUntil() is simply a time-bounded runPending().
@@ -129,7 +129,7 @@ void LL::WorkQueue::callWork(const Queue::DataTuple& work)
 
 void LL::WorkQueue::callWork(const Work& work)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
     try
     {
         work();
-- 
cgit v1.2.3


From 78edf2444eea2ed2eeee9eb2bca42adf139781e5 Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Thu, 13 Jan 2022 13:00:10 -0800
Subject: SL-16606: Add profiler category UI

---
 indra/llrender/llfontgl.cpp        | 10 +++++-----
 indra/llrender/llrender2dutils.cpp |  6 +++---
 indra/llui/llfolderview.cpp        |  6 +++---
 indra/llui/lllayoutstack.cpp       |  2 +-
 indra/llui/llscrolllistctrl.cpp    |  6 +++---
 indra/llui/lltextbase.cpp          |  8 ++++----
 indra/llui/lltrans.cpp             |  8 ++++----
 indra/llui/lluictrl.cpp            |  4 ++--
 indra/llui/lluictrlfactory.cpp     |  6 +++---
 indra/llui/lluictrlfactory.h       |  4 ++--
 indra/llui/llview.cpp              |  2 +-
 indra/newview/llhudnametag.cpp     |  4 ++--
 indra/newview/llviewerdisplay.cpp  |  8 ++++----
 indra/newview/llviewerwindow.cpp   |  4 ++--
 indra/newview/pipeline.cpp         |  4 ++--
 15 files changed, 41 insertions(+), 41 deletions(-)

(limited to 'indra')

diff --git a/indra/llrender/llfontgl.cpp b/indra/llrender/llfontgl.cpp
index 7f734e41f3..1bf061bc8d 100644
--- a/indra/llrender/llfontgl.cpp
+++ b/indra/llrender/llfontgl.cpp
@@ -145,7 +145,7 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, const LLRectf& rec
 S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, const LLColor4 &color, HAlign halign, VAlign valign, U8 style, 
 					 ShadowType shadow, S32 max_chars, S32 max_pixels, F32* right_x, BOOL use_ellipses) const
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
 
 	if(!sDisplayFont) //do not display texts
 	{
@@ -547,7 +547,7 @@ F32 LLFontGL::getWidthF32(const llwchar* wchars, S32 begin_offset, S32 max_chars
 
 void LLFontGL::generateASCIIglyphs()
 {
-    LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_UI
     for (U32 i = 32; (i < 127); i++)
     {
         mFontFreetype->getGlyphInfo(i);
@@ -557,7 +557,7 @@ void LLFontGL::generateASCIIglyphs()
 // 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
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_UI
 	if (!wchars || !wchars[0] || max_chars == 0)
 	{
 		return 0;
@@ -848,7 +848,7 @@ void LLFontGL::initClass(F32 screen_dpi, F32 x_scale, F32 y_scale, const std::st
 // static
 bool LLFontGL::loadDefaultFonts()
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_UI
 	bool succ = true;
 	succ &= (NULL != getFontSansSerifSmall());
 	succ &= (NULL != getFontSansSerif());
@@ -861,7 +861,7 @@ bool LLFontGL::loadDefaultFonts()
 
 void LLFontGL::loadCommonFonts()
 {
-    LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_UI
     getFont(LLFontDescriptor("SansSerif", "Small", BOLD));
     getFont(LLFontDescriptor("SansSerif", "Large", BOLD));
     getFont(LLFontDescriptor("SansSerif", "Huge", BOLD));
diff --git a/indra/llrender/llrender2dutils.cpp b/indra/llrender/llrender2dutils.cpp
index ad0c6262a4..5cb1dc6b25 100644
--- a/indra/llrender/llrender2dutils.cpp
+++ b/indra/llrender/llrender2dutils.cpp
@@ -989,7 +989,7 @@ void gl_segmented_rect_2d_tex(const S32 left,
 							  const S32 border_size, 
 							  const U32 edges)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
 
 	S32 width = llabs(right - left);
 	S32 height = llabs(top - bottom);
@@ -1148,7 +1148,7 @@ void gl_segmented_rect_2d_fragment_tex(const LLRect& rect,
 	const F32 end_fragment, 
 	const U32 edges)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
 	const S32 left = rect.mLeft;
 	const S32 right = rect.mRight;
 	const S32 top = rect.mTop;
@@ -1335,7 +1335,7 @@ void gl_segmented_rect_2d_fragment_tex(const LLRect& rect,
 void gl_segmented_rect_3d_tex(const LLRectf& clip_rect, const LLRectf& center_uv_rect, const LLRectf& center_draw_rect, 
 							 const LLVector3& width_vec, const LLVector3& height_vec)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
 
 	gGL.begin(LLRender::QUADS);
 	{
diff --git a/indra/llui/llfolderview.cpp b/indra/llui/llfolderview.cpp
index 0996e82bf7..a685924d99 100644
--- a/indra/llui/llfolderview.cpp
+++ b/indra/llui/llfolderview.cpp
@@ -338,7 +338,7 @@ S32 LLFolderView::arrange( S32* unused_width, S32* unused_height )
 
 void LLFolderView::filter( LLFolderViewFilter& filter )
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
     static LLCachedControl<S32> time_visible(*LLUI::getInstance()->mSettingGroups["config"], "FilterItemsMaxTimePerFrameVisible", 10);
     static LLCachedControl<S32> time_invisible(*LLUI::getInstance()->mSettingGroups["config"], "FilterItemsMaxTimePerFrameUnvisible", 1);
     filter.resetTime(llclamp((mParentPanel.get()->getVisible() ? time_visible() : time_invisible()), 1, 100));
@@ -502,7 +502,7 @@ BOOL LLFolderView::changeSelection(LLFolderViewItem* selection, BOOL selected)
 
 void LLFolderView::sanitizeSelection()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
 	// store off current item in case it is automatically deselected
 	// and we want to preserve context
 	LLFolderViewItem* original_selected_item = getCurSelectedItem();
@@ -1624,7 +1624,7 @@ void LLFolderView::update()
 {
 	// If this is associated with the user's inventory, don't do anything
 	// until that inventory is loaded up.
-	LL_RECORD_BLOCK_TIME(FTM_INVENTORY);
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; //LL_RECORD_BLOCK_TIME(FTM_INVENTORY);
     
     // If there's no model, the view is in suspended state (being deleted) and shouldn't be updated
     if (getFolderViewModel() == NULL)
diff --git a/indra/llui/lllayoutstack.cpp b/indra/llui/lllayoutstack.cpp
index 528d2e70ad..aac28e04b9 100644
--- a/indra/llui/lllayoutstack.cpp
+++ b/indra/llui/lllayoutstack.cpp
@@ -367,7 +367,7 @@ private:
 
 void LLLayoutStack::updateLayout()
 {	
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
 
 	if (!mNeedsLayout) return;
 
diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp
index c70085b72f..f6071e12e5 100644
--- a/indra/llui/llscrolllistctrl.cpp
+++ b/indra/llui/llscrolllistctrl.cpp
@@ -3047,7 +3047,7 @@ LLScrollListColumn* LLScrollListCtrl::getColumn(const std::string& name)
 
 LLScrollListItem* LLScrollListCtrl::addElement(const LLSD& element, EAddPosition pos, void* userdata)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
 	LLScrollListItem::Params item_params;
 	LLParamSDParser parser;
 	parser.readSD(element, item_params);
@@ -3057,14 +3057,14 @@ LLScrollListItem* LLScrollListCtrl::addElement(const LLSD& element, EAddPosition
 
 LLScrollListItem* LLScrollListCtrl::addRow(const LLScrollListItem::Params& item_p, EAddPosition pos)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
 	LLScrollListItem *new_item = new LLScrollListItem(item_p);
 	return addRow(new_item, item_p, pos);
 }
 
 LLScrollListItem* LLScrollListCtrl::addRow(LLScrollListItem *new_item, const LLScrollListItem::Params& item_p, EAddPosition pos)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
 	if (!item_p.validateBlock() || !new_item) return NULL;
 	new_item->setNumColumns(mColumns.size());
 
diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp
index 3b0789892f..2827888b53 100644
--- a/indra/llui/lltextbase.cpp
+++ b/indra/llui/lltextbase.cpp
@@ -1492,7 +1492,7 @@ S32 LLTextBase::getLeftOffset(S32 width)
 
 void LLTextBase::reflow()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
 
 	updateSegments();
 
@@ -1839,7 +1839,7 @@ void LLTextBase::removeDocumentChild(LLView* view)
 
 void LLTextBase::updateSegments()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
 	createDefaultSegment();
 }
 
@@ -2102,7 +2102,7 @@ static LLUIImagePtr image_from_icon_name(const std::string& icon_name)
 
 void LLTextBase::appendTextImpl(const std::string &new_text, const LLStyle::Params& input_params)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
 	LLStyle::Params style_params(input_params);
 	style_params.fillFrom(getStyleParams());
 
@@ -2204,7 +2204,7 @@ void LLTextBase::setLastSegmentToolTip(const std::string &tooltip)
 
 void LLTextBase::appendText(const std::string &new_text, bool prepend_newline, const LLStyle::Params& input_params)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
 	if (new_text.empty()) 
 		return;
 
diff --git a/indra/llui/lltrans.cpp b/indra/llui/lltrans.cpp
index a1a8feedaa..a1ef34159d 100644
--- a/indra/llui/lltrans.cpp
+++ b/indra/llui/lltrans.cpp
@@ -147,7 +147,7 @@ std::string LLTrans::getString(const std::string &xml_desc, const LLStringUtil::
 {
 	// Don't care about time as much as call count.  Make sure we're not
 	// calling LLTrans::getString() in an inner loop. JC
-	LL_RECORD_BLOCK_TIME(FTM_GET_TRANS);
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
 	
 	if (def_string)
 	{
@@ -196,7 +196,7 @@ std::string LLTrans::getString(const std::string &xml_desc, const LLSD& msg_args
 {
 	// Don't care about time as much as call count.  Make sure we're not
 	// calling LLTrans::getString() in an inner loop. JC
-	LL_RECORD_BLOCK_TIME(FTM_GET_TRANS);
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
 
 	if (def_string)
 	{
@@ -237,7 +237,7 @@ std::string LLTrans::getDefString(const std::string &xml_desc, const LLSD& msg_a
 //static 
 bool LLTrans::findString(std::string &result, const std::string &xml_desc, const LLStringUtil::format_map_t& msg_args)
 {
-	LL_RECORD_BLOCK_TIME(FTM_GET_TRANS);
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
 	
 	template_map_t::iterator iter = sStringTemplates.find(xml_desc);
 	if (iter != sStringTemplates.end())
@@ -259,7 +259,7 @@ bool LLTrans::findString(std::string &result, const std::string &xml_desc, const
 //static
 bool LLTrans::findString(std::string &result, const std::string &xml_desc, const LLSD& msg_args)
 {
-	LL_RECORD_BLOCK_TIME(FTM_GET_TRANS);
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
 
 	template_map_t::iterator iter = sStringTemplates.find(xml_desc);
 	if (iter != sStringTemplates.end())
diff --git a/indra/llui/lluictrl.cpp b/indra/llui/lluictrl.cpp
index 51391bb5e8..2196ba201b 100644
--- a/indra/llui/lluictrl.cpp
+++ b/indra/llui/lluictrl.cpp
@@ -475,7 +475,7 @@ LLViewModel* LLUICtrl::getViewModel() const
 //virtual
 BOOL LLUICtrl::postBuild()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
 	//
 	// Find all of the children that want to be in front and move them to the front
 	//
@@ -783,7 +783,7 @@ BOOL LLUICtrl::getIsChrome() const
 
 BOOL LLUICtrl::focusFirstItem(BOOL prefer_text_fields, BOOL focus_flash)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
 	// try to select default tab group child
 	LLViewQuery query = getTabOrderQuery();
 	child_list_t result = query(this);
diff --git a/indra/llui/lluictrlfactory.cpp b/indra/llui/lluictrlfactory.cpp
index 2d0c0ea8aa..a85db17c7f 100644
--- a/indra/llui/lluictrlfactory.cpp
+++ b/indra/llui/lluictrlfactory.cpp
@@ -116,7 +116,7 @@ void LLUICtrlFactory::loadWidgetTemplate(const std::string& widget_tag, LLInitPa
 //static 
 void LLUICtrlFactory::createChildren(LLView* viewp, LLXMLNodePtr node, const widget_registry_t& registry, LLXMLNodePtr output_node)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
 	if (node.isNull()) return;
 
 	for (LLXMLNodePtr child_node = node->getFirstChild(); child_node.notNull(); child_node = child_node->getNextSibling())
@@ -159,7 +159,7 @@ void LLUICtrlFactory::createChildren(LLView* viewp, LLXMLNodePtr node, const wid
 bool LLUICtrlFactory::getLayeredXMLNode(const std::string &xui_filename, LLXMLNodePtr& root,
                                         LLDir::ESkinConstraint constraint)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
 	std::vector<std::string> paths =
 		gDirUtilp->findSkinnedFilenames(LLDir::XUI, xui_filename, constraint);
 
@@ -186,7 +186,7 @@ S32 LLUICtrlFactory::saveToXML(LLView* viewp, const std::string& filename)
 
 LLView *LLUICtrlFactory::createFromXML(LLXMLNodePtr node, LLView* parent, const std::string& filename, const widget_registry_t& registry, LLXMLNodePtr output_node)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
 	std::string ctrl_type = node->getName()->mString;
 	LLStringUtil::toLower(ctrl_type);
 
diff --git a/indra/llui/lluictrlfactory.h b/indra/llui/lluictrlfactory.h
index 3f24a3f1a5..6e585abfc0 100644
--- a/indra/llui/lluictrlfactory.h
+++ b/indra/llui/lluictrlfactory.h
@@ -209,7 +209,7 @@ private:
 	template<typename T>
 	static T* createWidgetImpl(const typename T::Params& params, LLView* parent = NULL)
 	{
-        LL_PROFILE_ZONE_SCOPED;
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
 		T* widget = NULL;
 
 		if (!params.validateBlock())
@@ -233,7 +233,7 @@ private:
 	template<typename T>
 	static T* defaultBuilder(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr output_node)
 	{
-        LL_PROFILE_ZONE_SCOPED;
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
 
 		typename T::Params params(getDefaultParams<T>());
 
diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp
index bd0b9d3db2..9ba71913d0 100644
--- a/indra/llui/llview.cpp
+++ b/indra/llui/llview.cpp
@@ -1598,7 +1598,7 @@ LLView* LLView::getChildView(const std::string& name, BOOL recurse) const
 
 LLView* LLView::findChildView(const std::string& name, BOOL recurse) const
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
 	
     // Look for direct children *first*
 	BOOST_FOREACH(LLView* childp, mChildList)
diff --git a/indra/newview/llhudnametag.cpp b/indra/newview/llhudnametag.cpp
index 8e296321d2..952fbf8e4b 100644
--- a/indra/newview/llhudnametag.cpp
+++ b/indra/newview/llhudnametag.cpp
@@ -224,7 +224,7 @@ BOOL LLHUDNameTag::lineSegmentIntersect(const LLVector4a& start, const LLVector4
 
 void LLHUDNameTag::render()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
 	if (sDisplayText)
 	{
 		LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE);
@@ -730,7 +730,7 @@ void LLHUDNameTag::updateSize()
 
 void LLHUDNameTag::updateAll()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
 	// iterate over all text objects, calculate their restoration forces,
 	// and add them to the visible set if they are on screen and close enough
 	sVisibleTextObjects.clear();
diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp
index e2c831bb1c..b5d3dc5d30 100644
--- a/indra/newview/llviewerdisplay.cpp
+++ b/indra/newview/llviewerdisplay.cpp
@@ -1242,7 +1242,7 @@ bool setup_hud_matrices(const LLRect& screen_region)
 
 void render_ui(F32 zoom_factor, int subfield)
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_UI);
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; //LL_RECORD_BLOCK_TIME(FTM_RENDER_UI);
 
 	LLGLState::checkStates();
 	
@@ -1274,7 +1274,7 @@ void render_ui(F32 zoom_factor, int subfield)
 		// 1. Use a new scope
 		// 2. Use named zones
 		// 3. Use transient zones
-		LL_RECORD_BLOCK_TIME(FTM_RENDER_HUD);
+		LL_PROFILE_ZONE_NAMED_CATEGORY_UI("HUD"); //LL_RECORD_BLOCK_TIME(FTM_RENDER_HUD);
 		render_hud_elements();
 		render_hud_attachments();
 
@@ -1290,7 +1290,7 @@ void render_ui(F32 zoom_factor, int subfield)
 			{
 				if (!gDisconnected)
 				{
-					LL_RECORD_BLOCK_TIME(FTM_RENDER_UI_3D);
+					LL_PROFILE_ZONE_NAMED_CATEGORY_UI("UI 3D"); //LL_RECORD_BLOCK_TIME(FTM_RENDER_UI_3D);
 					render_ui_3d();
 					LLGLState::checkStates();
 				}
@@ -1299,7 +1299,7 @@ void render_ui(F32 zoom_factor, int subfield)
 					render_disconnected_background();
 				}
 
-				LL_RECORD_BLOCK_TIME(FTM_RENDER_UI_2D);
+				LL_PROFILE_ZONE_NAMED_CATEGORY_UI("UI 2D"); //LL_RECORD_BLOCK_TIME(FTM_RENDER_UI_2D);
 				render_ui_2d();
 				LLGLState::checkStates();
 			}
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index 8d749c41cc..2fc4e9d0bd 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -3333,7 +3333,7 @@ static LLTrace::BlockTimerStatHandle ftm("Update UI");
 // event processing.
 void LLViewerWindow::updateUI()
 {
-	LL_RECORD_BLOCK_TIME(ftm);
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; //LL_RECORD_BLOCK_TIME(ftm);
 
 	static std::string last_handle_msg;
 
@@ -5384,7 +5384,7 @@ void LLViewerWindow::setup3DRender()
 
 void LLViewerWindow::setup3DViewport(S32 x_offset, S32 y_offset)
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_UI
 	gGLViewport[0] = mWorldViewRectRaw.mLeft + x_offset;
 	gGLViewport[1] = mWorldViewRectRaw.mBottom + y_offset;
 	gGLViewport[2] = mWorldViewRectRaw.getWidth();
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index b342c46ce1..5618f582a0 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -3970,8 +3970,8 @@ void LLPipeline::postSort(LLCamera& camera)
 
 void render_hud_elements()
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_UI);
-	gPipeline.disableLights();		
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; //LL_RECORD_BLOCK_TIME(FTM_RENDER_UI);
+	gPipeline.disableLights();
 	
 	LLGLDisable fog(GL_FOG);
 	LLGLSUIDefault gls_ui;
-- 
cgit v1.2.3


From 8f0ed30d890d843f3c3cd717dc89c11759e5ef4b Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Thu, 13 Jan 2022 13:02:37 -0800
Subject: SL-16606: Add profiler category VERTEX

---
 indra/llrender/llvertexbuffer.cpp | 40 +++++++++++++++++++--------------------
 1 file changed, 20 insertions(+), 20 deletions(-)

(limited to 'indra')

diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp
index 9926447ef8..6338cab96a 100644
--- a/indra/llrender/llvertexbuffer.cpp
+++ b/indra/llrender/llvertexbuffer.cpp
@@ -123,7 +123,7 @@ bool LLVertexBuffer::sPreferStreamDraw = false;
 
 U32 LLVBOPool::genBuffer()
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX
 
 	if (sNameIdx == 0)
 	{
@@ -136,7 +136,7 @@ U32 LLVBOPool::genBuffer()
 
 void LLVBOPool::deleteBuffer(U32 name)
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX
 	if (gGLManager.mInited)
 	{
 		LLVertexBuffer::unbind();
@@ -159,7 +159,7 @@ LLVBOPool::LLVBOPool(U32 vboUsage, U32 vboType)
 
 U8* LLVBOPool::allocate(U32& name, U32 size, bool for_seed)
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX
 	llassert(vbo_block_size(size) == size);
 	
 	U8* ret = NULL;
@@ -275,12 +275,12 @@ void LLVBOPool::release(U32 name, U8* buffer, U32 size)
 
 void LLVBOPool::seedPool()
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX
 	U32 dummy_name = 0;
 
 	if (mFreeList.size() < LL_VBO_POOL_SEED_COUNT)
 	{
-		LL_PROFILE_ZONE_NAMED("VBOPool Resize");
+		LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("VBOPool Resize");
 		mFreeList.resize(LL_VBO_POOL_SEED_COUNT);
 	}
 
@@ -421,7 +421,7 @@ void LLVertexBuffer::releaseVAOName(U32 name)
 //static
 void LLVertexBuffer::seedPools()
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX
 	sStreamVBOPool.seedPool();
 	sDynamicVBOPool.seedPool();
 	sDynamicCopyVBOPool.seedPool();
@@ -470,7 +470,7 @@ void LLVertexBuffer::setupClientArrays(U32 data_mask)
 //static
 void LLVertexBuffer::drawArrays(U32 mode, const std::vector<LLVector3>& pos)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX;
     gGL.begin(mode);
     for (auto& v : pos)
     {
@@ -483,7 +483,7 @@ void LLVertexBuffer::drawArrays(U32 mode, const std::vector<LLVector3>& pos)
 //static
 void LLVertexBuffer::drawElements(U32 mode, const LLVector4a* pos, const LLVector2* tc, S32 num_indices, const U16* indicesp)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX;
 	llassert(LLGLSLShader::sCurBoundShaderPtr != NULL);
 
 	gGL.syncMatrices();
@@ -699,7 +699,7 @@ void LLVertexBuffer::draw(U32 mode, U32 count, U32 indices_offset) const
 
 void LLVertexBuffer::drawArrays(U32 mode, U32 first, U32 count) const
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX;
     llassert(LLGLSLShader::sCurBoundShaderPtr != NULL);
     mMappable = false;
     gGL.syncMatrices();
@@ -1257,7 +1257,7 @@ void LLVertexBuffer::setupVertexArray()
 		return;
 	}
 
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX;
 #if GL_ARB_vertex_array_object
 	glBindVertexArray(mGLArray);
 #endif
@@ -1434,7 +1434,7 @@ bool expand_region(LLVertexBuffer::MappedRegion& region, S32 index, S32 count)
 // Map for data access
 U8* LLVertexBuffer::mapVertexBuffer(S32 type, S32 index, S32 count, bool map_range)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX;
 	bindGLBuffer(true);
 	if (mFinal)
 	{
@@ -1611,7 +1611,7 @@ U8* LLVertexBuffer::mapVertexBuffer(S32 type, S32 index, S32 count, bool map_ran
 
 U8* LLVertexBuffer::mapIndexBuffer(S32 index, S32 count, bool map_range)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX;
 	bindGLIndices(true);
 	if (mFinal)
 	{
@@ -1778,10 +1778,10 @@ void LLVertexBuffer::unmapBuffer()
 	}
 
 	bool updated_all = false;
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX;
 	if (mMappedData && mVertexLocked)
 	{
-        LL_PROFILE_ZONE_NAMED("unmapBuffer - vertex");
+        LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("unmapBuffer - vertex");
 		bindGLBuffer(true);
 		updated_all = mIndexLocked; //both vertex and index buffers done updating
 
@@ -1828,7 +1828,7 @@ void LLVertexBuffer::unmapBuffer()
 			{
 				if (!mMappedVertexRegions.empty())
 				{
-                    LL_PROFILE_ZONE_NAMED("unmapBuffer - flush vertex");
+                    LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("unmapBuffer - flush vertex");
 					for (U32 i = 0; i < mMappedVertexRegions.size(); ++i)
 					{
 						const MappedRegion& region = mMappedVertexRegions[i];
@@ -1864,7 +1864,7 @@ void LLVertexBuffer::unmapBuffer()
 	
 	if (mMappedIndexData && mIndexLocked)
 	{
-        LL_PROFILE_ZONE_NAMED("unmapBuffer - index");
+        LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("unmapBuffer - index");
 		bindGLIndices();
 		if(!mMappable)
 		{
@@ -1910,7 +1910,7 @@ void LLVertexBuffer::unmapBuffer()
 				{
 					for (U32 i = 0; i < mMappedIndexRegions.size(); ++i)
 					{
-                        LL_PROFILE_ZONE_NAMED("unmapBuffer - flush index");
+                        LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("unmapBuffer - flush index");
 						const MappedRegion& region = mMappedIndexRegions[i];
 						S32 offset = region.mIndex >= 0 ? sizeof(U16)*region.mIndex : 0;
 						S32 length = sizeof(U16)*region.mCount;
@@ -2063,7 +2063,7 @@ bool LLVertexBuffer::bindGLArray()
 	if (mGLArray && sGLRenderArray != mGLArray)
 	{
 		{
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX;
 #if GL_ARB_vertex_array_object
 			glBindVertexArray(mGLArray);
 #endif
@@ -2088,7 +2088,7 @@ bool LLVertexBuffer::bindGLBuffer(bool force_bind)
 
 	if (useVBOs() && (force_bind || (mGLBuffer && (mGLBuffer != sGLRenderBuffer || !sVBOActive))))
 	{
-        LL_PROFILE_ZONE_SCOPED;
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX;
 		glBindBufferARB(GL_ARRAY_BUFFER_ARB, mGLBuffer);
 		sGLRenderBuffer = mGLBuffer;
 		sBindCount++;
@@ -2119,7 +2119,7 @@ bool LLVertexBuffer::bindGLBufferFast()
 
 bool LLVertexBuffer::bindGLIndices(bool force_bind)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX;
 	bindGLArray();
 
 	bool ret = false;
-- 
cgit v1.2.3


From e6bf3f23af42c6d07bcd870dc3bbd435466025bf Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Thu, 13 Jan 2022 13:03:37 -0800
Subject: SL-16606: Add profiler category VOLUME

---
 indra/llmath/llvolume.cpp    | 26 +++++++++++++-------------
 indra/newview/llvovolume.cpp | 28 ++++++++++++++--------------
 2 files changed, 27 insertions(+), 27 deletions(-)

(limited to 'indra')

diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp
index c226315e5c..e9ccde5fae 100644
--- a/indra/llmath/llvolume.cpp
+++ b/indra/llmath/llvolume.cpp
@@ -383,7 +383,7 @@ public:
 	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
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME
 
 		LLVolumeOctreeListener* node = (LLVolumeOctreeListener*) branch->getListener(0);
 
@@ -823,7 +823,7 @@ 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
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME
 
 	if ((!mDirty) && (!is_sculpted))
 	{
@@ -1305,7 +1305,7 @@ 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
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME
 
 	// Generates a circular path, starting at (1, 0, 0), counterclockwise along the xz plane.
 	static const F32 tableScale[] = { 1, 1, 1, 0.5f, 0.707107f, 0.53f, 0.525f, 0.5f };
@@ -1541,7 +1541,7 @@ 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
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME
 
 	if ((!mDirty) && (!is_sculpted))
 	{
@@ -2119,7 +2119,7 @@ LLVolume::~LLVolume()
 
 BOOL LLVolume::generate()
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME
 
 	LL_CHECK_MEMORY
 	llassert_always(mProfilep);
@@ -2379,7 +2379,7 @@ bool LLVolumeFace::VertexData::compareNormal(const LLVolumeFace::VertexData& rhs
 
 bool LLVolume::unpackVolumeFaces(std::istream& is, S32 size)
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME
 
 	//input stream is now pointing at a zlib compressed block of LLSD
 	//decompress block
@@ -2766,7 +2766,7 @@ S32	LLVolume::getNumFaces() const
 
 void LLVolume::createVolumeFaces()
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME
 
 	if (mGenerateSingleFace)
 	{
@@ -3733,7 +3733,7 @@ void LLVolume::generateSilhouetteVertices(std::vector<LLVector3> &vertices,
 										  const LLMatrix3& norm_mat_in,
 										  S32 face_mask)
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME
 
 	LLMatrix4a mat;
 	mat.loadu(mat_in);
@@ -4861,7 +4861,7 @@ void LLVolumeFace::freeData()
 
 BOOL LLVolumeFace::create(LLVolume* volume, BOOL partial_build)
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME
 
 	//tree for this face is no longer valid
 	delete mOctree;
@@ -5531,7 +5531,7 @@ bool LLVolumeFace::cacheOptimize()
 
 void LLVolumeFace::createOctree(F32 scaler, const LLVector4a& center, const LLVector4a& size)
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME
 
 	if (mOctree)
 	{
@@ -6306,7 +6306,7 @@ void CalculateTangentArray(U32 vertexCount, const LLVector4a *vertex, const LLVe
 
 void LLVolumeFace::createTangents()
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME
 
 	if (!mTangents)
 	{
@@ -6503,7 +6503,7 @@ void LLVolumeFace::fillFromLegacyData(std::vector<LLVolumeFace::VertexData>& v,
 
 BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build)
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME
 
 	LL_CHECK_MEMORY
 	BOOL flat = mTypeMask & FLAT_MASK;
@@ -6997,7 +6997,7 @@ 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
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME
 
     //LLVector4a *tan1 = new LLVector4a[vertexCount * 2];
 	LLVector4a* tan1 = (LLVector4a*) ll_aligned_malloc_16(vertexCount*2*sizeof(LLVector4a));
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index d20bf3e871..5130775bd9 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -712,7 +712,7 @@ BOOL LLVOVolume::isVisible() const
 
 void LLVOVolume::updateTextureVirtualSize(bool forced)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME;
 	// Update the pixel area of all faces
 
     if (mDrawable.isNull())
@@ -991,7 +991,7 @@ LLDrawable *LLVOVolume::createDrawable(LLPipeline *pipeline)
 
 BOOL LLVOVolume::setVolume(const LLVolumeParams &params_in, const S32 detail, bool unique_volume)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME;
 	LLVolumeParams volume_params = params_in;
 
 	S32 last_lod = mVolumep.notNull() ? LLVolumeLODGroup::getVolumeDetailFromScale(mVolumep->getDetail()) : -1;
@@ -1619,7 +1619,7 @@ BOOL LLVOVolume::setParent(LLViewerObject* parent)
 // NOTE: regenFaces() MUST be followed by genTriangles()!
 void LLVOVolume::regenFaces()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME;
 	// remove existing faces
 	BOOL count_changed = mNumFaces != getNumTEs();
 	
@@ -1914,7 +1914,7 @@ void LLVOVolume::updateRelativeXform(bool force_identity)
 
 bool LLVOVolume::lodOrSculptChanged(LLDrawable *drawable, BOOL &compiled)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME;
 	bool regen_faces = false;
 
 	LLVolume *old_volumep, *new_volumep;
@@ -1978,7 +1978,7 @@ bool LLVOVolume::lodOrSculptChanged(LLDrawable *drawable, BOOL &compiled)
 
 BOOL LLVOVolume::updateGeometry(LLDrawable *drawable)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME;
 	
 	if (mDrawable->isState(LLDrawable::REBUILD_RIGGED))
 	{
@@ -3765,7 +3765,7 @@ void LLVOVolume::afterReparent()
 //----------------------------------------------------------------------------
 void LLVOVolume::updateRiggingInfo()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME;
     if (isRiggedMesh())
     {
         const LLMeshSkinInfo* skin = getSkinInfo();
@@ -4375,7 +4375,7 @@ void LLVOVolume::updateSpatialExtents(LLVector4a& newMin, LLVector4a& newMax)
 
 F32 LLVOVolume::getBinRadius()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME;
 	F32 radius;
 	
 	F32 scale = 1.f;
@@ -4771,7 +4771,7 @@ void LLVOVolume::clearRiggedVolume()
 
 void LLVOVolume::updateRiggedVolume(bool force_update)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME;
 	//Update mRiggedVolume to match current animation frame of avatar. 
 	//Also update position/size in octree.  
 
@@ -4809,7 +4809,7 @@ void LLVOVolume::updateRiggedVolume(bool force_update)
 
 void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, const LLVolume* volume)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME;
 	bool copy = false;
 	if (volume->getNumVolumeFaces() != getNumVolumeFaces())
 	{ 
@@ -5115,7 +5115,7 @@ void LLVolumeGeometryManager::freeFaces()
 
 void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep, U32 type)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME;
 	if (   type == LLRenderPass::PASS_ALPHA 
 		&& facep->getTextureEntry()->getMaterialParams().notNull() 
 		&& !facep->getVertexBuffer()->hasDataType(LLVertexBuffer::TYPE_TANGENT)
@@ -5470,7 +5470,7 @@ static inline void add_face(T*** list, U32* count, T* face)
 
 void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME;
 	if (group->changeLOD())
 	{
 		group->mLastUpdateDistance = group->mDistance;
@@ -5943,7 +5943,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 
 void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME;
 	llassert(group);
 	if (group && group->hasState(LLSpatialGroup::MESH_DIRTY) && !group->hasState(LLSpatialGroup::GEOM_DIRTY))
 	{
@@ -6135,7 +6135,7 @@ struct CompareBatchBreakerRigged
 
 U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace** faces, U32 face_count, BOOL distance_sort, BOOL batch_textures, BOOL rigged)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME;
 
 	U32 geometryBytes = 0;
 	U32 buffer_usage = group->mBufferUsage;
@@ -6774,7 +6774,7 @@ U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace
 
 void LLGeometryManager::addGeometryCount(LLSpatialGroup* group, U32 &vertex_count, U32 &index_count)
 {	
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME;
 
 	//initialize to default usage for this partition
 	U32 usage = group->getSpatialPartition()->mBufferUsage;
-- 
cgit v1.2.3


From dd3b8c22a9ab743775b77b548bb140ce08363a5c Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Thu, 13 Jan 2022 13:05:43 -0800
Subject: SL-16606: Add profiler category STATS

---
 indra/llcommon/lltracethreadrecorder.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'indra')

diff --git a/indra/llcommon/lltracethreadrecorder.cpp b/indra/llcommon/lltracethreadrecorder.cpp
index 7ae1e72784..090d3297a0 100644
--- a/indra/llcommon/lltracethreadrecorder.cpp
+++ b/indra/llcommon/lltracethreadrecorder.cpp
@@ -277,7 +277,7 @@ void ThreadRecorder::pushToParent()
 void ThreadRecorder::pullFromChildren()
 {
 #if LL_TRACE_ENABLED
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	if (mActiveRecordings.empty()) return;
 
 	{ LLMutexLock lock(&mChildListMutex);
-- 
cgit v1.2.3


From 9cfac7902394225b74606f5668b5421f2949e78d Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Thu, 13 Jan 2022 13:06:18 -0800
Subject: SL-16606: Add profiler category AVATAR

---
 indra/llcharacter/llkeyframemotion.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'indra')

diff --git a/indra/llcharacter/llkeyframemotion.cpp b/indra/llcharacter/llkeyframemotion.cpp
index 5a5aa2c83e..a25ff16786 100644
--- a/indra/llcharacter/llkeyframemotion.cpp
+++ b/indra/llcharacter/llkeyframemotion.cpp
@@ -677,7 +677,7 @@ BOOL LLKeyframeMotion::onActivate()
 //-----------------------------------------------------------------------------
 BOOL LLKeyframeMotion::onUpdate(F32 time, U8* joint_mask)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
 	// llassert(time >= 0.f);		// This will fire
 	time = llmax(0.f, time);
 
-- 
cgit v1.2.3


From c0ceab88ae020c0ec1bb2e432b3aeaf26f0a0f84 Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Thu, 13 Jan 2022 13:09:50 -0800
Subject: SL-16606: Add profiler category WIN32

---
 indra/llwindow/llwindowwin32.cpp | 130 +++++++++++++++++++--------------------
 1 file changed, 65 insertions(+), 65 deletions(-)

(limited to 'indra')

diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp
index e4d771978a..8c792daac0 100644
--- a/indra/llwindow/llwindowwin32.cpp
+++ b/indra/llwindow/llwindowwin32.cpp
@@ -1931,7 +1931,7 @@ void LLWindowWin32::hideCursor()
 
 void LLWindowWin32::showCursor()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_WIN32;
 
     ASSERT_MAIN_THREAD();
 	
@@ -2046,7 +2046,7 @@ void LLWindowWin32::initCursors()
 void LLWindowWin32::updateCursor()
 {
     ASSERT_MAIN_THREAD();
-    LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_WIN32
 	if (mNextCursor == UI_CURSOR_ARROW
 		&& mBusyCount > 0)
 	{
@@ -2076,7 +2076,7 @@ void LLWindowWin32::captureMouse()
 
 void LLWindowWin32::releaseMouse()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_WIN32;
 	ReleaseCapture();
 }
 
@@ -2090,7 +2090,7 @@ void LLWindowWin32::delayInputProcessing()
 void LLWindowWin32::gatherInput()
 {
     ASSERT_MAIN_THREAD();
-    LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_WIN32
     MSG msg;
 
     {
@@ -2104,13 +2104,13 @@ void LLWindowWin32::gatherInput()
 
     if (mWindowThread->getQueue().size())
     {
-        LL_PROFILE_ZONE_NAMED("gi - PostMessage");
+        LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("gi - PostMessage");
         kickWindowThread();
     }
         
     while (mWindowThread->mMessageQueue.tryPopBack(msg))
     {
-        LL_PROFILE_ZONE_NAMED("gi - message queue");
+        LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("gi - message queue");
         if (mInputProcessingPaused)
         {
             continue;
@@ -2119,13 +2119,13 @@ void LLWindowWin32::gatherInput()
         // For async host by name support.  Really hacky.
         if (gAsyncMsgCallback && (LL_WM_HOST_RESOLVED == msg.message))
         {
-            LL_PROFILE_ZONE_NAMED("gi - callback");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("gi - callback");
             gAsyncMsgCallback(msg);
         }
     }
 
     {
-        LL_PROFILE_ZONE_NAMED("gi - PeekMessage");
+        LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("gi - PeekMessage");
         S32 msg_count = 0;
         while ((msg_count < MAX_MESSAGE_PER_UPDATE) && PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_REMOVE))
         {
@@ -2136,7 +2136,7 @@ void LLWindowWin32::gatherInput()
     }
 
     {
-        LL_PROFILE_ZONE_NAMED("gi - function queue");
+        LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("gi - function queue");
         //process any pending functions
         std::function<void()> curFunc;
         while (mFunctionQueue.tryPopBack(curFunc))
@@ -2148,14 +2148,14 @@ void LLWindowWin32::gatherInput()
     // send one and only one mouse move event per frame BEFORE handling mouse button presses
     if (mLastCursorPosition != mCursorPosition)
     {
-        LL_PROFILE_ZONE_NAMED("gi - mouse move");
+        LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("gi - mouse move");
         mCallbacks->handleMouseMove(this, mCursorPosition.convert(), mMouseMask);
     }
     
     mLastCursorPosition = mCursorPosition;
 
     {
-        LL_PROFILE_ZONE_NAMED("gi - mouse queue");
+        LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("gi - mouse queue");
         // handle mouse button presses AFTER updating mouse cursor position
         std::function<void()> curFunc;
         while (mMouseQueue.tryPopBack(curFunc))
@@ -2177,7 +2177,7 @@ static LLTrace::BlockTimerStatHandle FTM_MOUSEHANDLER("Handle Mouse");
 LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_param, LPARAM l_param)
 {
     ASSERT_WINDOW_THREAD();
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_WIN32;
 
     LL_DEBUGS("Window") << "mainWindowProc(" << std::hex << h_wnd
                         << ", " << u_msg
@@ -2226,14 +2226,14 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
 
         case WM_TIMER:
         {
-            LL_PROFILE_ZONE_NAMED("mwp - WM_TIMER");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_TIMER");
             WINDOW_IMP_POST(window_imp->mCallbacks->handleTimerEvent(window_imp));
             break;
         }
 
         case WM_DEVICECHANGE:
         {
-            LL_PROFILE_ZONE_NAMED("mwp - WM_DEVICECHANGE");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_DEVICECHANGE");
             if (debug_window_proc)
             {
                 LL_INFOS("Window") << "  WM_DEVICECHANGE: wParam=" << w_param
@@ -2250,7 +2250,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
 
         case WM_PAINT:
         {
-            LL_PROFILE_ZONE_NAMED("mwp - WM_PAINT");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_PAINT");
             GetUpdateRect(window_imp->mWindowHandle, &update_rect, FALSE);
             update_width = update_rect.right - update_rect.left + 1;
             update_height = update_rect.bottom - update_rect.top + 1;
@@ -2266,7 +2266,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
 
         case WM_SETCURSOR:
         {
-            LL_PROFILE_ZONE_NAMED("mwp - WM_SETCURSOR");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_SETCURSOR");
             // This message is sent whenever the cursor is moved in a window.
             // You need to set the appropriate cursor appearance.
 
@@ -2281,21 +2281,21 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
         }
         case WM_ENTERMENULOOP:
         {
-            LL_PROFILE_ZONE_NAMED("mwp - WM_ENTERMENULOOP");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_ENTERMENULOOP");
             WINDOW_IMP_POST(window_imp->mCallbacks->handleWindowBlock(window_imp));
             break;
         }
 
         case WM_EXITMENULOOP:
         {
-            LL_PROFILE_ZONE_NAMED("mwp - WM_EXITMENULOOP");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_EXITMENULOOP");
             WINDOW_IMP_POST(window_imp->mCallbacks->handleWindowUnblock(window_imp));
             break;
         }
 
         case WM_ACTIVATEAPP:
         {
-            LL_PROFILE_ZONE_NAMED("mwp - WM_ACTIVATEAPP");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_ACTIVATEAPP");
             window_imp->post([=]()
                 {
                     // This message should be sent whenever the app gains or loses focus.
@@ -2338,7 +2338,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
         }
         case WM_ACTIVATE:
         {
-            LL_PROFILE_ZONE_NAMED("mwp - WM_ACTIVATE");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_ACTIVATE");
             window_imp->post([=]()
                 {
                     // Can be one of WA_ACTIVE, WA_CLICKACTIVE, or WA_INACTIVE
@@ -2372,7 +2372,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
 
         case WM_SYSCOMMAND:
         {
-            LL_PROFILE_ZONE_NAMED("mwp - WM_SYSCOMMAND");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_SYSCOMMAND");
             switch (w_param)
             {
             case SC_KEYMENU:
@@ -2388,7 +2388,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
         }
         case WM_CLOSE:
         {
-            LL_PROFILE_ZONE_NAMED("mwp - WM_CLOSE");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_CLOSE");
             window_imp->post([=]()
                 {
                     // Will the app allow the window to close?
@@ -2403,7 +2403,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
         }
         case WM_DESTROY:
         {
-            LL_PROFILE_ZONE_NAMED("mwp - WM_DESTROY");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_DESTROY");
             if (window_imp->shouldPostQuit())
             {
                 PostQuitMessage(0);  // Posts WM_QUIT with an exit code of 0
@@ -2412,7 +2412,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
         }
         case WM_COMMAND:
         {
-            LL_PROFILE_ZONE_NAMED("mwp - WM_COMMAND");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_COMMAND");
             if (!HIWORD(w_param)) // this message is from a menu
             {
                 WINDOW_IMP_POST(window_imp->mCallbacks->handleMenuSelect(window_imp, LOWORD(w_param)));
@@ -2421,13 +2421,13 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
         }
         case WM_SYSKEYDOWN:
         {
-            LL_PROFILE_ZONE_NAMED("mwp - WM_SYSKEYDOWN");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_SYSKEYDOWN");
             // allow system keys, such as ALT-F4 to be processed by Windows
             eat_keystroke = FALSE;
         }
         case WM_KEYDOWN:
         {
-            LL_PROFILE_ZONE_NAMED("mwp - WM_KEYDOWN");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_KEYDOWN");
             window_imp->post([=]()
                 {
                     window_imp->mKeyCharCode = 0; // don't know until wm_char comes in next
@@ -2454,7 +2454,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
             eat_keystroke = FALSE;
         case WM_KEYUP:
         {
-            LL_PROFILE_ZONE_NAMED("mwp - WM_KEYUP");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_KEYUP");
             window_imp->post([=]()
             {
                 window_imp->mKeyScanCode = (l_param >> 16) & 0xff;
@@ -2479,7 +2479,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
         }
         case WM_IME_SETCONTEXT:
         {
-            LL_PROFILE_ZONE_NAMED("mwp - WM_IME_SETCONTEXT");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_IME_SETCONTEXT");
             if (debug_window_proc)
             {
                 LL_INFOS("Window") << "WM_IME_SETCONTEXT" << LL_ENDL;
@@ -2493,7 +2493,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
         }
         case WM_IME_STARTCOMPOSITION:
         {
-            LL_PROFILE_ZONE_NAMED("mwp - WM_IME_STARTCOMPOSITION");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_IME_STARTCOMPOSITION");
             if (debug_window_proc)
             {
                 LL_INFOS() << "WM_IME_STARTCOMPOSITION" << LL_ENDL;
@@ -2507,7 +2507,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
         }
         case WM_IME_ENDCOMPOSITION:
         {
-            LL_PROFILE_ZONE_NAMED("mwp - WM_IME_ENDCOMPOSITION");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_IME_ENDCOMPOSITION");
             if (debug_window_proc)
             {
                 LL_INFOS() << "WM_IME_ENDCOMPOSITION" << LL_ENDL;
@@ -2520,7 +2520,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
         }
         case WM_IME_COMPOSITION:
         {
-            LL_PROFILE_ZONE_NAMED("mwp - WM_IME_COMPOSITION");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_IME_COMPOSITION");
             if (debug_window_proc)
             {
                 LL_INFOS() << "WM_IME_COMPOSITION" << LL_ENDL;
@@ -2534,7 +2534,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
         }
         case WM_IME_REQUEST:
         {
-            LL_PROFILE_ZONE_NAMED("mwp - WM_IME_REQUEST");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_IME_REQUEST");
             if (debug_window_proc)
             {
                 LL_INFOS() << "WM_IME_REQUEST" << LL_ENDL;
@@ -2549,7 +2549,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
         }
         case WM_CHAR:
         {
-            LL_PROFILE_ZONE_NAMED("mwp - WM_CHAR");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_CHAR");
             window_imp->post([=]()
                 {
                     window_imp->mKeyCharCode = w_param;
@@ -2581,7 +2581,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
         }
         case WM_NCLBUTTONDOWN:
         {
-            LL_PROFILE_ZONE_NAMED("mwp - WM_NCLBUTTONDOWN");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_NCLBUTTONDOWN");
             {
                 // A click in a non-client area, e.g. title bar or window border.
                 window_imp->post([=]()
@@ -2594,7 +2594,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
         }
         case WM_LBUTTONDOWN:
         {
-            LL_PROFILE_ZONE_NAMED("mwp - WM_LBUTTONDOWN");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_LBUTTONDOWN");
             {
                 LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER);
                 window_imp->postMouseButtonEvent([=]()
@@ -2619,7 +2619,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
 
         case WM_LBUTTONDBLCLK:
         {
-            LL_PROFILE_ZONE_NAMED("mwp - WM_LBUTTONDBLCLK");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_LBUTTONDBLCLK");
             window_imp->postMouseButtonEvent([=]()
                 {
                     //RN: ignore right button double clicks for now
@@ -2640,7 +2640,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
         }
         case WM_LBUTTONUP:
         {
-            LL_PROFILE_ZONE_NAMED("mwp - WM_LBUTTONUP");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_LBUTTONUP");
             {
                 window_imp->postMouseButtonEvent([=]()
                     {
@@ -2664,7 +2664,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
         case WM_RBUTTONDBLCLK:
         case WM_RBUTTONDOWN:
         {
-            LL_PROFILE_ZONE_NAMED("mwp - WM_RBUTTONDOWN");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_RBUTTONDOWN");
             {
                 LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER);
                 window_imp->post([=]()
@@ -2687,7 +2687,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
 
         case WM_RBUTTONUP:
         {
-            LL_PROFILE_ZONE_NAMED("mwp - WM_RBUTTONUP");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_RBUTTONUP");
             {
                 LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER);
                 window_imp->postMouseButtonEvent([=]()
@@ -2702,7 +2702,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
         case WM_MBUTTONDOWN:
             //		case WM_MBUTTONDBLCLK:
         {
-            LL_PROFILE_ZONE_NAMED("mwp - WM_MBUTTONDOWN");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_MBUTTONDOWN");
             {
                 LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER);
                 window_imp->postMouseButtonEvent([=]()
@@ -2721,7 +2721,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
 
         case WM_MBUTTONUP:
         {
-            LL_PROFILE_ZONE_NAMED("mwp - WM_MBUTTONUP");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_MBUTTONUP");
             {
                 LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER);
                 window_imp->postMouseButtonEvent([=]()
@@ -2734,7 +2734,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
         break;
         case WM_XBUTTONDOWN:
         {
-            LL_PROFILE_ZONE_NAMED("mwp - WM_XBUTTONDOWN");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_XBUTTONDOWN");
             window_imp->postMouseButtonEvent([=]()
                 {
                     LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER);
@@ -2754,7 +2754,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
 
         case WM_XBUTTONUP:
         {
-            LL_PROFILE_ZONE_NAMED("mwp - WM_XBUTTONUP");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_XBUTTONUP");
             window_imp->postMouseButtonEvent([=]()
                 {
 
@@ -2770,7 +2770,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
 
         case WM_MOUSEWHEEL:
         {
-            LL_PROFILE_ZONE_NAMED("mwp - WM_MOUSEWHEEL");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_MOUSEWHEEL");
             static short z_delta = 0;
 
             RECT	client_rect;
@@ -2827,7 +2827,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
         */
         case WM_MOUSEHWHEEL:
         {
-            LL_PROFILE_ZONE_NAMED("mwp - WM_MOUSEHWHEEL");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_MOUSEHWHEEL");
             static short h_delta = 0;
 
             RECT	client_rect;
@@ -2864,12 +2864,12 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
         // Handle mouse movement within the window
         case WM_MOUSEMOVE:
         {
-            LL_PROFILE_ZONE_NAMED("mwp - WM_MOUSEMOVE");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_MOUSEMOVE");
             // DO NOT use mouse event queue for move events to ensure cursor position is updated 
             // when button events are handled
             WINDOW_IMP_POST(
                 {
-                    LL_PROFILE_ZONE_NAMED("mwp - WM_MOUSEMOVE lambda");
+                    LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_MOUSEMOVE lambda");
 
                     MASK mask = gKeyboard->currentMask(TRUE);
                     window_imp->mMouseMask = mask;
@@ -2880,7 +2880,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
 
         case WM_GETMINMAXINFO:
         {
-            LL_PROFILE_ZONE_NAMED("mwp - WM_GETMINMAXINFO");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_GETMINMAXINFO");
             LPMINMAXINFO min_max = (LPMINMAXINFO)l_param;
             min_max->ptMinTrackSize.x = window_imp->mMinWindowWidth;
             min_max->ptMinTrackSize.y = window_imp->mMinWindowHeight;
@@ -2894,7 +2894,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
         }
         case WM_SIZE:
         {
-            LL_PROFILE_ZONE_NAMED("mwp - WM_SIZE");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_SIZE");
             window_imp->updateWindowRect();
             S32 width = S32(LOWORD(l_param));
             S32 height = S32(HIWORD(l_param));
@@ -2956,7 +2956,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
 
         case WM_DPICHANGED:
         {
-            LL_PROFILE_ZONE_NAMED("mwp - WM_DPICHANGED");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_DPICHANGED");
             LPRECT lprc_new_scale;
             F32 new_scale = F32(LOWORD(w_param)) / F32(USER_DEFAULT_SCREEN_DPI);
             lprc_new_scale = (LPRECT)l_param;
@@ -2977,7 +2977,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
 
         case WM_SETFOCUS:
         {
-            LL_PROFILE_ZONE_NAMED("mwp - WM_SETFOCUS");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_SETFOCUS");
             if (debug_window_proc)
             {
                 LL_INFOS("Window") << "WINDOWPROC SetFocus" << LL_ENDL;
@@ -2988,7 +2988,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
 
         case WM_KILLFOCUS:
         {
-            LL_PROFILE_ZONE_NAMED("mwp - WM_KILLFOCUS");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_KILLFOCUS");
             if (debug_window_proc)
             {
                 LL_INFOS("Window") << "WINDOWPROC KillFocus" << LL_ENDL;
@@ -2999,7 +2999,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
 
         case WM_COPYDATA:
         {
-            LL_PROFILE_ZONE_NAMED("mwp - WM_COPYDATA");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_COPYDATA");
             {
                 // received a URL
                 PCOPYDATASTRUCT myCDS = (PCOPYDATASTRUCT)l_param;
@@ -3019,7 +3019,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
         }
         case WM_SETTINGCHANGE:
         {
-            LL_PROFILE_ZONE_NAMED("mwp - WM_SETTINGCHANGE");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_SETTINGCHANGE");
             if (w_param == SPI_SETMOUSEVANISH)
             {
                 if (!SystemParametersInfo(SPI_GETMOUSEVANISH, 0, &window_imp->mMouseVanish, 0))
@@ -3032,7 +3032,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
         
         case WM_INPUT:
         {
-            LL_PROFILE_ZONE_NAMED("MWP - WM_INPUT");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("MWP - WM_INPUT");
             
             UINT dwSize = 0;
             GetRawInputData((HRAWINPUT)l_param, RID_INPUT, NULL, &dwSize, sizeof(RAWINPUTHEADER));
@@ -3064,7 +3064,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
 
         default:
         {
-            LL_PROFILE_ZONE_NAMED("mwp - default");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - default");
             if (debug_window_proc)
             {
                 LL_INFOS("Window") << "Unhandled windows message code: 0x" << std::hex << U32(u_msg) << LL_ENDL;
@@ -3082,7 +3082,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
     // pass unhandled messages down to Windows
     LRESULT ret;
     {
-        LL_PROFILE_ZONE_NAMED("mwp - DefWindowProc");
+        LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - DefWindowProc");
         ret = DefWindowProc(h_wnd, u_msg, w_param, l_param);
     }
     return ret;
@@ -3264,7 +3264,7 @@ BOOL LLWindowWin32::copyTextToClipboard(const LLWString& wstr)
 // Constrains the mouse to the window.
 void LLWindowWin32::setMouseClipping( BOOL b )
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_WIN32;
     ASSERT_MAIN_THREAD();
 	if( b != mIsMouseClipping )
 	{
@@ -3562,7 +3562,7 @@ BOOL LLWindowWin32::resetDisplayResolution()
 
 void LLWindowWin32::swapBuffers()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_WIN32;
     ASSERT_MAIN_THREAD();
 	SwapBuffers(mhDC);
 
@@ -4565,7 +4565,7 @@ void LLWindowWin32::LLWindowWin32Thread::run()
 
     while (! getQueue().done())
     {
-        LL_PROFILE_ZONE_SCOPED;
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_WIN32;
 
         if (mWindowHandle != 0)
         {
@@ -4573,13 +4573,13 @@ void LLWindowWin32::LLWindowWin32Thread::run()
             BOOL status;
             if (mhDC == 0)
             {
-                LL_PROFILE_ZONE_NAMED("w32t - PeekMessage");
+                LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("w32t - PeekMessage");
                 logger.onChange("PeekMessage(", std::hex, mWindowHandle, ")");
                 status = PeekMessage(&msg, mWindowHandle, 0, 0, PM_REMOVE);
             }
             else
             {
-                LL_PROFILE_ZONE_NAMED("w32t - GetMessage");
+                LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("w32t - GetMessage");
                 logger.always("GetMessage(", std::hex, mWindowHandle, ")");
                 status = GetMessage(&msg, NULL, 0, 0);
             }
@@ -4595,7 +4595,7 @@ void LLWindowWin32::LLWindowWin32Thread::run()
         }
 
         {
-            LL_PROFILE_ZONE_NAMED("w32t - Function Queue");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("w32t - Function Queue");
             logger.onChange("runPending()");
             //process any pending functions
             getQueue().runPending();
@@ -4603,7 +4603,7 @@ void LLWindowWin32::LLWindowWin32Thread::run()
         
 #if 0
         {
-            LL_PROFILE_ZONE_NAMED("w32t - Sleep");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("w32t - Sleep");
             logger.always("sleep(1)");
             std::this_thread::sleep_for(std::chrono::milliseconds(1));
         }
@@ -4640,7 +4640,7 @@ void LLWindowWin32::kickWindowThread(HWND windowHandle)
 
 void LLWindowWin32::updateWindowRect()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_WIN32;
     //called from window thread
     RECT rect;
     RECT client_rect;
-- 
cgit v1.2.3


From f5f124e3e67ff45a614132d029ecdd2499a7ec26 Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Thu, 13 Jan 2022 13:13:06 -0800
Subject: SL-16606: Add note about RP3

---
 indra/llcharacter/lljointsolverrp3.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'indra')

diff --git a/indra/llcharacter/lljointsolverrp3.cpp b/indra/llcharacter/lljointsolverrp3.cpp
index 69a7e3dc6e..cd25511881 100644
--- a/indra/llcharacter/lljointsolverrp3.cpp
+++ b/indra/llcharacter/lljointsolverrp3.cpp
@@ -1,6 +1,6 @@
 /** 
  * @file lljointsolverrp3.cpp
- * @brief Implementation of LLJointSolverRP3 class.
+ * @brief Implementation of Joint Solver in 3D Real Projective space (RP3). See: https://en.wikipedia.org/wiki/Real_projective_space
  *
  * $LicenseInfo:firstyear=2001&license=viewerlgpl$
  * Second Life Viewer Source Code
-- 
cgit v1.2.3


From cc798a53119d5e504911de25bbf97717a9f4adab Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Thu, 13 Jan 2022 13:16:01 -0800
Subject: SL-16606: Don't spam logging with debug joint info.

---
 indra/llcharacter/lljointsolverrp3.cpp | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

(limited to 'indra')

diff --git a/indra/llcharacter/lljointsolverrp3.cpp b/indra/llcharacter/lljointsolverrp3.cpp
index cd25511881..f3d5e2e324 100644
--- a/indra/llcharacter/lljointsolverrp3.cpp
+++ b/indra/llcharacter/lljointsolverrp3.cpp
@@ -35,6 +35,11 @@
 
 #define F_EPSILON 0.00001f
 
+#if LL_RELEASE
+    #define DEBUG_JOINT_SOLVER 0
+#else
+    #define DEBUG_JOINT_SOLVER 1
+#endif
 
 //-----------------------------------------------------------------------------
 // Constructor
@@ -150,6 +155,7 @@ void LLJointSolverRP3::solve()
 	LLVector3 cPos = mJointC->getWorldPosition();
 	LLVector3 gPos = mJointGoal->getWorldPosition();
 
+#if DEBUG_JOINT_SOLVER
 	LL_DEBUGS("JointSolver") << "LLJointSolverRP3::solve()" << LL_NEWLINE
 							<< "bPosLocal = " << mJointB->getPosition() << LL_NEWLINE
 							<< "cPosLocal = " << mJointC->getPosition() << LL_NEWLINE
@@ -159,6 +165,7 @@ void LLJointSolverRP3::solve()
 							<< "bPos : " << bPos << LL_NEWLINE
 							<< "cPos : " << cPos << LL_NEWLINE
 							<< "gPos : " << gPos << LL_ENDL;
+#endif
 
 	//-------------------------------------------------------------------------
 	// get the poleVector in world space
@@ -194,6 +201,7 @@ void LLJointSolverRP3::solve()
 	//-------------------------------------------------------------------------
 	LLVector3 abacCompOrthoVec = abVec - acVec * ((abVec * acVec)/(acVec * acVec));
 
+#if DEBUG_JOINT_SOLVER
 	LL_DEBUGS("JointSolver") << "abVec : " << abVec << LL_NEWLINE
 		<< "bcVec : " << bcVec << LL_NEWLINE
 		<< "acVec : " << acVec << LL_NEWLINE
@@ -202,6 +210,7 @@ void LLJointSolverRP3::solve()
 		<< "bcLen : " << bcLen << LL_NEWLINE
 		<< "agLen : " << agLen << LL_NEWLINE
 		<< "abacCompOrthoVec : " << abacCompOrthoVec << LL_ENDL;
+#endif
 
 	//-------------------------------------------------------------------------
 	// compute the normal of the original ABC plane (and store for later)
@@ -269,6 +278,7 @@ void LLJointSolverRP3::solve()
 
 	LLQuaternion bRot(theta - abbcAng, abbcOrthoVec);
 
+#if DEBUG_JOINT_SOLVER
 	LL_DEBUGS("JointSolver") << "abbcAng      : " << abbcAng << LL_NEWLINE
 							<< "abbcOrthoVec : " << abbcOrthoVec << LL_NEWLINE
 							<< "agLenSq      : " << agLenSq << LL_NEWLINE
@@ -280,6 +290,7 @@ void LLJointSolverRP3::solve()
 								<< abbcAng*180.0f/F_PI << " " 
 								<< (theta - abbcAng)*180.0f/F_PI 
 	<< LL_ENDL;
+#endif
 
 	//-------------------------------------------------------------------------
 	// compute rotation that rotates new A->C to A->G
@@ -293,9 +304,11 @@ void LLJointSolverRP3::solve()
 	LLQuaternion cgRot;
 	cgRot.shortestArc( acVec, agVec );
 
+#if DEBUG_JOINT_SOLVER
 	LL_DEBUGS("JointSolver") << "bcVec : " << bcVec << LL_NEWLINE
 							<< "acVec : " << acVec << LL_NEWLINE
 							<< "cgRot : " << cgRot << LL_ENDL;
+#endif
 
 	// update A->B and B->C with rotation from C to G
 	abVec = abVec * cgRot;
@@ -358,11 +371,13 @@ void LLJointSolverRP3::solve()
 	//-------------------------------------------------------------------------
 	LLQuaternion twistRot( mTwist, agVec );
 
+#if DEBUG_JOINT_SOLVER
 	LL_DEBUGS("JointSolver") << "abcNorm = " << abcNorm << LL_NEWLINE
 							<< "apgNorm = " << apgNorm << LL_NEWLINE
 							<< "pRot = " << pRot << LL_NEWLINE
 							<< "twist    : " << mTwist*180.0/F_PI << LL_NEWLINE
 							<< "twistRot : " << twistRot << LL_ENDL;
+#endif
 
 	//-------------------------------------------------------------------------
 	// compute rotation of A
-- 
cgit v1.2.3


From c37c727a9b196d6c4053cadcd4c27684a4d93b8e Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Thu, 13 Jan 2022 10:02:27 -0800
Subject: SL-16606: Add categories

---
 indra/llcommon/CMakeLists.txt         |   1 +
 indra/llcommon/llprofilercategories.h | 280 ++++++++++++++++++++++++++++++++++
 2 files changed, 281 insertions(+)
 create mode 100644 indra/llcommon/llprofilercategories.h

(limited to 'indra')

diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt
index 782f656406..ca8b5e946f 100644
--- a/indra/llcommon/CMakeLists.txt
+++ b/indra/llcommon/CMakeLists.txt
@@ -202,6 +202,7 @@ set(llcommon_HEADER_FILES
     llnametable.h
     llpointer.h
     llprofiler.h
+    llprofilercategories.h
     llpounceable.h
     llpredicate.h
     llpreprocessor.h
diff --git a/indra/llcommon/llprofilercategories.h b/indra/llcommon/llprofilercategories.h
new file mode 100644
index 0000000000..8db29468cc
--- /dev/null
+++ b/indra/llcommon/llprofilercategories.h
@@ -0,0 +1,280 @@
+/**
+ * @file llprofiler_ategories.h
+ * @brief Profiling categories to minimize Tracy memory usage when viewing captures.
+ *
+ * $LicenseInfo:firstyear=2022&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2022, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_PROFILER_CATEGORIES_H
+#define LL_PROFILER_CATEGORIES_H
+
+// A Tracy capture can quickly consume memory.  Use these defines to selectively turn on/off Tracy profiling for these categories.
+// The biggest memory usage ones are:
+//
+//    LL_PROFILER_CATEGORY_ENABLE_DRAWPOOL
+//    LL_PROFILER_CATEGORY_ENABLE_LLSD
+//    LL_PROFILER_CATEGORY_ENABLE_MEMORY
+//    LL_PROFILER_CATEGORY_ENABLE_SHADERS
+//
+// NOTE: You can still manually use:
+//     LL_PROFILE_ZONE_SCOPED();
+//     LL_PROFILE_ZONE_NAMED("name");
+// but just be aware that those will ALWAYS show up in a Tracy capture
+//  a) using more memory, and
+//  b) adding visual clutter.
+#define LL_PROFILER_CATEGORY_ENABLE_APP         1
+#define LL_PROFILER_CATEGORY_ENABLE_AVATAR      1
+#define LL_PROFILER_CATEGORY_ENABLE_DISPLAY     1
+#define LL_PROFILER_CATEGORY_ENABLE_DRAWABLE    1
+#define LL_PROFILER_CATEGORY_ENABLE_DRAWPOOL    1
+#define LL_PROFILER_CATEGORY_ENABLE_ENVIRONMENT 1
+#define LL_PROFILER_CATEGORY_ENABLE_FACE        1
+#define LL_PROFILER_CATEGORY_ENABLE_LLSD        1
+#define LL_PROFILER_CATEGORY_ENABLE_LOGGING     1
+#define LL_PROFILER_CATEGORY_ENABLE_MATERIAL    1
+#define LL_PROFILER_CATEGORY_ENABLE_MEDIA       1
+#define LL_PROFILER_CATEGORY_ENABLE_MEMORY      1
+#define LL_PROFILER_CATEGORY_ENABLE_NETWORK     1
+#define LL_PROFILER_CATEGORY_ENABLE_OCTREE      1
+#define LL_PROFILER_CATEGORY_ENABLE_PIPELINE    1
+#define LL_PROFILER_CATEGORY_ENABLE_SHADER      1
+#define LL_PROFILER_CATEGORY_ENABLE_SPATIAL     1
+#define LL_PROFILER_CATEGORY_ENABLE_STATS       1
+#define LL_PROFILER_CATEGORY_ENABLE_STRING      1
+#define LL_PROFILER_CATEGORY_ENABLE_TEXTURE     1
+#define LL_PROFILER_CATEGORY_ENABLE_THREAD      1
+#define LL_PROFILER_CATEGORY_ENABLE_UI          1
+#define LL_PROFILER_CATEGORY_ENABLE_VIEWER      1
+#define LL_PROFILER_CATEGORY_ENABLE_VERTEX      1
+#define LL_PROFILER_CATEGORY_ENABLE_VOLUME      1
+#define LL_PROFILER_CATEGORY_ENABLE_WIN32       1
+
+#if LL_PROFILER_CATEGORY_ENABLE_APP
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_APP  LL_PROFILE_ZONE_NAMED
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_APP LL_PROFILE_ZONE_SCOPED
+#else
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_APP(name)
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_APP
+#endif
+
+#if LL_PROFILER_CATEGORY_ENABLE_AVATAR
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_AVATAR  LL_PROFILE_ZONE_NAMED
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR LL_PROFILE_ZONE_SCOPED
+#else
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_AVATAR(name)
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR
+#endif
+
+#if LL_PROFILER_CATEGORY_ENABLE_DISPLAY
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY  LL_PROFILE_ZONE_NAMED
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_DISPLAY LL_PROFILE_ZONE_SCOPED
+#else
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY(name)
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_DISPLAY
+#endif
+
+#if LL_PROFILER_CATEGORY_ENABLE_DRAWABLE
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWABLE  LL_PROFILE_ZONE_NAMED
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE LL_PROFILE_ZONE_SCOPED
+#else
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWABLE(name)
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE
+#endif
+
+#if LL_PROFILER_CATEGORY_ENABLE_DRAWPOOL
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWPOOL  LL_PROFILE_ZONE_NAMED
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL LL_PROFILE_ZONE_SCOPED
+#else
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWPOOL(name)
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL
+#endif
+
+#if LL_PROFILER_CATEGORY_ENABLE_ENVIRONMENT
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_ENVIRONMENT  LL_PROFILE_ZONE_NAMED
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_ENVIRONMENT LL_PROFILE_ZONE_SCOPED
+#else
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_ENVIRONMENT(name)
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_ENVIRONMENT
+#endif
+
+#if LL_PROFILER_CATEGORY_ENABLE_FACE
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_FACE  LL_PROFILE_ZONE_NAMED
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_FACE LL_PROFILE_ZONE_SCOPED
+#else
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_FACE(name)
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_FACE
+#endif
+
+#if LL_PROFILER_CATEGORY_ENABLE_LLSD
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_LLSD  LL_PROFILE_ZONE_NAMED
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD LL_PROFILE_ZONE_SCOPED
+#else
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_LLSD(name)
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD
+#endif
+
+#if LL_PROFILER_CATEGORY_ENABLE_LOGGING
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_LOGGING  LL_PROFILE_ZONE_NAMED
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING LL_PROFILE_ZONE_SCOPED
+#else
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_LOGGING(name)
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING
+#endif
+
+#if LL_PROFILER_CATEGORY_ENABLE_MATERIAL
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_MATERIAL  LL_PROFILE_ZONE_NAMED
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_MATERIAL LL_PROFILE_ZONE_SCOPED
+#else
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_MATERIAL(name)
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_MATERIAL
+#endif
+
+#if LL_PROFILER_CATEGORY_ENABLE_MEDIA
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_MEDIA  LL_PROFILE_ZONE_NAMED
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_MEDIA LL_PROFILE_ZONE_SCOPED
+#else
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_MEDIA(name)
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_MEDIA
+#endif
+
+#if LL_PROFILER_CATEGORY_ENABLE_MEMORY
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_MEMORY  LL_PROFILE_ZONE_NAMED
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY LL_PROFILE_ZONE_SCOPED
+#else
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_MEMORY(name)
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY
+#endif
+
+#if LL_PROFILER_CATEGORY_ENABLE_NETWORK
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_NETWORK  LL_PROFILE_ZONE_NAMED
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK LL_PROFILE_ZONE_SCOPED
+#else
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_NETWORK(name)
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK
+#endif
+
+#if LL_PROFILER_CATEGORY_ENABLE_OCTREE
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_OCTREE  LL_PROFILE_ZONE_NAMED
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_OCTREE LL_PROFILE_ZONE_SCOPED
+#else
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_OCTREE(name)
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_OCTREE
+#endif
+
+#if LL_PROFILER_CATEGORY_ENABLE_PIPELINE
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE  LL_PROFILE_ZONE_NAMED
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE LL_PROFILE_ZONE_SCOPED
+#else
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE(name)
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE
+#endif
+
+#if LL_PROFILER_CATEGORY_ENABLE_SHADER
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_SHADER  LL_PROFILE_ZONE_NAMED
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER LL_PROFILE_ZONE_SCOPED
+#else
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_SHADER(name)
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER
+#endif
+
+#if LL_PROFILER_CATEGORY_ENABLE_SPATIAL
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_SPATIAL  LL_PROFILE_ZONE_NAMED
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_SPATIAL LL_PROFILE_ZONE_SCOPED
+#else
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_SPATIAL(name)
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_SPATIAL
+#endif
+
+#if LL_PROFILER_CATEGORY_ENABLE_STATS
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_STATS  LL_PROFILE_ZONE_NAMED
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS LL_PROFILE_ZONE_SCOPED
+#else
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_STATS(name)
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS
+#endif
+
+#if LL_PROFILER_CATEGORY_ENABLE_STRING
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_STRING  LL_PROFILE_ZONE_NAMED
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_STRING LL_PROFILE_ZONE_SCOPED
+#else
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_STRING(name)
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_STRING
+#endif
+
+#if LL_PROFILER_CATEGORY_ENABLE_TEXTURE
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE  LL_PROFILE_ZONE_NAMED
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE LL_PROFILE_ZONE_SCOPED
+#else
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE(name)
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE
+#endif
+
+#if LL_PROFILER_CATEGORY_ENABLE_THREAD
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_THREAD  LL_PROFILE_ZONE_NAMED
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD LL_PROFILE_ZONE_SCOPED
+#else
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_THREAD(name)
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
+#endif
+
+#if LL_PROFILER_CATEGORY_ENABLE_UI
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_UI  LL_PROFILE_ZONE_NAMED
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_UI LL_PROFILE_ZONE_SCOPED
+#else
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_UI(name)
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_UI
+#endif
+
+#if LL_PROFILER_CATEGORY_ENABLE_VERTEX
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX  LL_PROFILE_ZONE_NAMED
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX LL_PROFILE_ZONE_SCOPED
+#else
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX(name)
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX
+#endif
+
+#if LL_PROFILER_CATEGORY_ENABLE_VIEWER
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_VIEWER  LL_PROFILE_ZONE_NAMED
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_VIEWER LL_PROFILE_ZONE_SCOPED
+#else
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_VIEWER(name)
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_VIEWER
+#endif
+
+#if LL_PROFILER_CATEGORY_ENABLE_VOLUME
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_VOLUME  LL_PROFILE_ZONE_NAMED
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME LL_PROFILE_ZONE_SCOPED
+#else
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_VOLUME(name)
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME
+#endif
+
+#if LL_PROFILER_CATEGORY_ENABLE_WIN32
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32  LL_PROFILE_ZONE_NAMED
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_WIN32 LL_PROFILE_ZONE_SCOPED
+#else
+    #define LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32(name)
+    #define LL_PROFILE_ZONE_SCOPED_CATEGORY_WIN32
+#endif
+
+#endif // LL_PROFILER_CATEGORIES_H
+
-- 
cgit v1.2.3


From f9031ee02d19afe01023936eacc867dcdef01861 Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Thu, 13 Jan 2022 11:22:56 -0800
Subject: SL-16606: Include profiler categories automatically

---
 indra/llcommon/llprofiler.h | 40 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 40 insertions(+)

(limited to 'indra')

diff --git a/indra/llcommon/llprofiler.h b/indra/llcommon/llprofiler.h
index ca60d23248..f9d7ae7ce4 100644
--- a/indra/llcommon/llprofiler.h
+++ b/indra/llcommon/llprofiler.h
@@ -27,6 +27,44 @@
 #ifndef LL_PROFILER_H
 #define LL_PROFILER_H
 
+// If you use the default macros LL_PROFILE_ZONE_SCOPED and LL_PROFILE_ZONE_NAMED to profile code ...
+//
+//     void foo()
+//     {
+//         LL_PROFILE_ZONE_SCOPED;
+//         :
+//
+//         {
+//             LL_PROFILE_ZONE_NAMED("widget bar");
+//             :
+//         }
+//         {
+//             LL_PROFILE_ZONE_NAMED("widget qux");
+//             :
+//         }
+//     }
+//
+// ... please be aware that ALL these will show up in a Tracy capture which can quickly exhaust memory.
+// Instead, use LL_PROFILE_ZONE_SCOPED_CATEGORY_* and LL_PROFILE_ZONE_NAMED_CATEGORY_* to profile code ...
+//
+//     void foo()
+//     {
+//         LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
+//         :
+//
+//         {
+//             LL_PROFILE_ZONE_NAMED_CATEGORY_UI("widget bar");
+//             :
+//         }
+//         {
+//             LL_PROFILE_ZONE_NAMED_CATEGORY_UI("widget qux");
+//             :
+//         }
+//     }
+//
+// ... as these can be selectively turned on/off.  This will minimize memory usage and visual clutter in a Tracy capture.
+// See llprofiler_categories.h for more details on profiling categories.
+
 #define LL_PROFILER_CONFIG_NONE             0  // No profiling
 #define LL_PROFILER_CONFIG_FAST_TIMER       1  // Profiling on: Only Fast Timers
 #define LL_PROFILER_CONFIG_TRACY            2  // Profiling on: Only Tracy
@@ -108,4 +146,6 @@ extern thread_local bool gProfilerEnabled;
     #define LL_PROFILER_SET_THREAD_NAME( name ) (void)(name)
 #endif // LL_PROFILER
 
+#include "llprofilercategories.h"
+
 #endif // LL_PROFILER_H
-- 
cgit v1.2.3


From f268230902103fc68fb33c0a2a6b533369966447 Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Thu, 13 Jan 2022 11:25:52 -0800
Subject: SL-16606: Add profiler category APP

---
 indra/newview/llappviewer.cpp | 53 +++++++++++++++++++++++--------------------
 1 file changed, 29 insertions(+), 24 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 89e0da3ea7..dc973e9154 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -1391,7 +1391,7 @@ bool LLAppViewer::doFrame()
 	LLSD newFrame;
 
 	{
-        LL_PROFILE_ZONE_NAMED("df LLTrace");
+        LL_PROFILE_ZONE_NAMED_CATEGORY_APP("df LLTrace");
         if (LLFloaterReg::instanceVisible("block_timers"))
         {
 	LLTrace::BlockTimer::processTimes();
@@ -1407,7 +1407,7 @@ bool LLAppViewer::doFrame()
 	LL_CLEAR_CALLSTACKS();
 
 	{
-		LL_PROFILE_ZONE_NAMED( "df processMiscNativeEvents" )
+		LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df processMiscNativeEvents" )
 		pingMainloopTimeout("Main:MiscNativeWindowEvents");
 
 		if (gViewerWindow)
@@ -1417,7 +1417,7 @@ bool LLAppViewer::doFrame()
 		}
 
 		{
-			LL_PROFILE_ZONE_NAMED( "df gatherInput" )
+			LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df gatherInput" )
 		pingMainloopTimeout("Main:GatherInput");
 		}
 
@@ -1444,20 +1444,20 @@ bool LLAppViewer::doFrame()
 		}
 
 		{
-			LL_PROFILE_ZONE_NAMED( "df mainloop" )
+			LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df mainloop" )
 		// canonical per-frame event
 		mainloop.post(newFrame);
 		}
 
 		{
-			LL_PROFILE_ZONE_NAMED( "df suspend" )
+			LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df suspend" )
 		// give listeners a chance to run
 		llcoro::suspend();
 		}
 
 		if (!LLApp::isExiting())
 		{
-			LL_PROFILE_ZONE_NAMED( "df JoystickKeyboard" )
+			LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df JoystickKeyboard" )
 			pingMainloopTimeout("Main:JoystickKeyboard");
 
 			// Scan keyboard for movement keys.  Command keys and typing
@@ -1479,17 +1479,19 @@ bool LLAppViewer::doFrame()
 			// Update state based on messages, user input, object idle.
 			{
 				{
-					LL_PROFILE_ZONE_NAMED( "df pauseMainloopTimeout" )
-				pauseMainloopTimeout(); // *TODO: Remove. Messages shouldn't be stalling for 20+ seconds!
+					LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df pauseMainloopTimeout" )
+					pauseMainloopTimeout(); // *TODO: Remove. Messages shouldn't be stalling for 20+ seconds!
 				}
 
-				LL_RECORD_BLOCK_TIME(FTM_IDLE);
-				idle();
+				{
+					LL_PROFILE_ZONE_NAMED_CATEGORY_APP("df idle"); //LL_RECORD_BLOCK_TIME(FTM_IDLE);
+					idle();
+				}
 
 				{
-					LL_PROFILE_ZONE_NAMED( "df resumeMainloopTimeout" )
-				resumeMainloopTimeout();
-			}
+					LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df resumeMainloopTimeout" )
+					resumeMainloopTimeout();
+				}
 			}
 
 			if (gDoDisconnect && (LLStartUp::getStartupState() == STATE_STARTED))
@@ -1510,14 +1512,14 @@ 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" )
+				LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df Display" )
 				pingMainloopTimeout("Main:Display");
 				gGLActive = TRUE;
 
 				display();
 
 				{
-					LL_PROFILE_ZONE_NAMED( "df Snapshot" )
+					LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df Snapshot" )
 				pingMainloopTimeout("Main:Snapshot");
 				LLFloaterSnapshot::update(); // take snapshots
 					LLFloaterOutfitSnapshot::update();
@@ -1527,7 +1529,7 @@ bool LLAppViewer::doFrame()
 		}
 
 		{
-			LL_PROFILE_ZONE_NAMED( "df pauseMainloopTimeout" )
+			LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df pauseMainloopTimeout" )
 		pingMainloopTimeout("Main:Sleep");
 
 		pauseMainloopTimeout();
@@ -1612,27 +1614,27 @@ bool LLAppViewer::doFrame()
 			}
 
 			{
-				LL_PROFILE_ZONE_NAMED( "df gMeshRepo" )
+				LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df gMeshRepo" )
 			gMeshRepo.update() ;
 			}
 
 			if(!total_work_pending) //pause texture fetching threads if nothing to process.
 			{
-				LL_PROFILE_ZONE_NAMED( "df getTextureCache" )
+				LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df getTextureCache" )
 				LLAppViewer::getTextureCache()->pause();
 				LLAppViewer::getImageDecodeThread()->pause();
 				LLAppViewer::getTextureFetch()->pause();
 			}
 			if(!total_io_pending) //pause file threads if nothing to process.
 			{
-				LL_PROFILE_ZONE_NAMED( "df LLVFSThread" )
+				LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df LLVFSThread" )
 				LLLFSThread::sLocal->pause();
 			}
 
 			//texture fetching debugger
 			if(LLTextureFetchDebugger::isEnabled())
 			{
-				LL_PROFILE_ZONE_NAMED( "df tex_fetch_debugger_instance" )
+				LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df tex_fetch_debugger_instance" )
 				LLFloaterTextureFetchDebugger* tex_fetch_debugger_instance =
 					LLFloaterReg::findTypedInstance<LLFloaterTextureFetchDebugger>("tex_fetch_debugger");
 				if(tex_fetch_debugger_instance)
@@ -1642,7 +1644,7 @@ bool LLAppViewer::doFrame()
 			}
 
 			{
-				LL_PROFILE_ZONE_NAMED( "df resumeMainloopTimeout" )
+				LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df resumeMainloopTimeout" )
 			resumeMainloopTimeout();
 			}
 			pingMainloopTimeout("Main:End");
@@ -4701,6 +4703,7 @@ static LLTrace::BlockTimerStatHandle FTM_HUD_EFFECTS("HUD Effects");
 ///////////////////////////////////////////////////////
 void LLAppViewer::idle()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_APP;
 	pingMainloopTimeout("Main:Idle");
 
 	// Update frame timers
@@ -5051,8 +5054,10 @@ void LLAppViewer::idle()
 	// Here, particles are updated and drawables are moved.
 	//
 
-	LL_RECORD_BLOCK_TIME(FTM_WORLD_UPDATE);
-	gPipeline.updateMove();
+	{
+		LL_PROFILE_ZONE_NAMED_CATEGORY_APP("world update"); //LL_RECORD_BLOCK_TIME(FTM_WORLD_UPDATE);
+		gPipeline.updateMove();
+	}
 
 	LLWorld::getInstance()->updateParticles();
 
@@ -5091,7 +5096,7 @@ void LLAppViewer::idle()
 	LLAvatarRenderInfoAccountant::getInstance()->idle();
 
 	{
-		LL_RECORD_BLOCK_TIME(FTM_AUDIO_UPDATE);
+		LL_PROFILE_ZONE_NAMED_CATEGORY_APP("audio update"); //LL_RECORD_BLOCK_TIME(FTM_AUDIO_UPDATE);
 
 		if (gAudiop)
 		{
-- 
cgit v1.2.3


From 41894327c3c09eb96baa94e79bf4698efc5939c4 Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Thu, 13 Jan 2022 11:31:39 -0800
Subject: SL-16606: Add profiler category AVATAR

---
 indra/llcharacter/llcharacter.cpp          |  2 +-
 indra/llcharacter/llheadrotmotion.cpp      |  4 +-
 indra/llcharacter/llkeyframefallmotion.cpp |  2 +-
 indra/llcharacter/llmotioncontroller.cpp   | 14 +++----
 indra/newview/lldrawpoolavatar.cpp         | 64 +++++++++++++++---------------
 indra/newview/llmeshrepository.cpp         |  2 +-
 indra/newview/llphysicsmotion.cpp          |  2 +-
 indra/newview/llskinningutil.cpp           |  4 +-
 indra/newview/llvoavatar.cpp               | 34 ++++++++--------
 9 files changed, 64 insertions(+), 64 deletions(-)

(limited to 'indra')

diff --git a/indra/llcharacter/llcharacter.cpp b/indra/llcharacter/llcharacter.cpp
index 8874df32f5..376f096642 100644
--- a/indra/llcharacter/llcharacter.cpp
+++ b/indra/llcharacter/llcharacter.cpp
@@ -190,7 +190,7 @@ void LLCharacter::requestStopMotion( LLMotion* motion)
 //-----------------------------------------------------------------------------
 void LLCharacter::updateMotions(e_update_t update_type)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
 	if (update_type == HIDDEN_UPDATE)
 	{
 		mMotionController.updateMotionsMinimal();
diff --git a/indra/llcharacter/llheadrotmotion.cpp b/indra/llcharacter/llheadrotmotion.cpp
index fdf97266a3..07a3aaebb6 100644
--- a/indra/llcharacter/llheadrotmotion.cpp
+++ b/indra/llcharacter/llheadrotmotion.cpp
@@ -175,7 +175,7 @@ BOOL LLHeadRotMotion::onActivate()
 //-----------------------------------------------------------------------------
 BOOL LLHeadRotMotion::onUpdate(F32 time, U8* joint_mask)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
 	LLQuaternion	targetHeadRotWorld;
 	LLQuaternion	currentRootRotWorld = mRootJoint->getWorldRotation();
 	LLQuaternion	currentInvRootRotWorld = ~currentRootRotWorld;
@@ -459,7 +459,7 @@ void LLEyeMotion::adjustEyeTarget(LLVector3* targetPos, LLJointState& left_eye_s
 //-----------------------------------------------------------------------------
 BOOL LLEyeMotion::onUpdate(F32 time, U8* joint_mask)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
 	//calculate jitter
 	if (mEyeJitterTimer.getElapsedTimeF32() > mEyeJitterTime)
 	{
diff --git a/indra/llcharacter/llkeyframefallmotion.cpp b/indra/llcharacter/llkeyframefallmotion.cpp
index 9a41ba4d3d..e8bb2bf95d 100644
--- a/indra/llcharacter/llkeyframefallmotion.cpp
+++ b/indra/llcharacter/llkeyframefallmotion.cpp
@@ -121,7 +121,7 @@ BOOL LLKeyframeFallMotion::onActivate()
 //-----------------------------------------------------------------------------
 BOOL LLKeyframeFallMotion::onUpdate(F32 activeTime, U8* joint_mask)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
 	BOOL result = LLKeyframeMotion::onUpdate(activeTime, joint_mask);
 	F32  slerp_amt = clamp_rescale(activeTime / getDuration(), 0.5f, 0.75f, 0.f, 1.f);
 
diff --git a/indra/llcharacter/llmotioncontroller.cpp b/indra/llcharacter/llmotioncontroller.cpp
index d4546ce901..e66714388a 100644
--- a/indra/llcharacter/llmotioncontroller.cpp
+++ b/indra/llcharacter/llmotioncontroller.cpp
@@ -503,7 +503,7 @@ void LLMotionController::resetJointSignatures()
 //-----------------------------------------------------------------------------
 void LLMotionController::updateIdleMotion(LLMotion* motionp)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
 	if (motionp->isStopped() && mAnimTime > motionp->getStopTime() + motionp->getEaseOutDuration())
 	{
 		deactivateMotionInstance(motionp);
@@ -542,7 +542,7 @@ void LLMotionController::updateIdleMotion(LLMotion* motionp)
 //-----------------------------------------------------------------------------
 void LLMotionController::updateIdleActiveMotions()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
 	for (motion_list_t::iterator iter = mActiveMotions.begin();
 		 iter != mActiveMotions.end(); )
 	{
@@ -557,7 +557,7 @@ void LLMotionController::updateIdleActiveMotions()
 //-----------------------------------------------------------------------------
 void LLMotionController::updateMotionsByType(LLMotion::LLMotionBlendType anim_type)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
 	BOOL update_result = TRUE;
 	U8 last_joint_signature[LL_CHARACTER_MAX_ANIMATED_JOINTS];
 
@@ -768,7 +768,7 @@ void LLMotionController::updateMotionsByType(LLMotion::LLMotionBlendType anim_ty
 //-----------------------------------------------------------------------------
 void LLMotionController::updateLoadingMotions()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
 	// query pending motions for completion
 	for (motion_set_t::iterator iter = mLoadingMotions.begin();
 		 iter != mLoadingMotions.end(); )
@@ -816,7 +816,7 @@ void LLMotionController::updateLoadingMotions()
 //-----------------------------------------------------------------------------
 void LLMotionController::updateMotions(bool force_update)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
     // SL-763: "Distant animated objects run at super fast speed"
     // The use_quantum optimization or possibly the associated code in setTimeStamp()
     // does not work as implemented.
@@ -909,7 +909,7 @@ void LLMotionController::updateMotions(bool force_update)
 //-----------------------------------------------------------------------------
 void LLMotionController::updateMotionsMinimal()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
 	// Always update mPrevTimerElapsed
 	mPrevTimerElapsed = mTimer.getElapsedTimeF32();
 
@@ -927,7 +927,7 @@ void LLMotionController::updateMotionsMinimal()
 //-----------------------------------------------------------------------------
 BOOL LLMotionController::activateMotionInstance(LLMotion *motion, F32 time)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
 	// It's not clear why the getWeight() line seems to be crashing this, but
 	// hopefully this fixes it.
 	if (motion == NULL || motion->getPose() == NULL)
diff --git a/indra/newview/lldrawpoolavatar.cpp b/indra/newview/lldrawpoolavatar.cpp
index e1e57ef319..4a9a3caaec 100644
--- a/indra/newview/lldrawpoolavatar.cpp
+++ b/indra/newview/lldrawpoolavatar.cpp
@@ -119,7 +119,7 @@ LLDrawPoolAvatar::~LLDrawPoolAvatar()
 // virtual
 BOOL LLDrawPoolAvatar::isDead()
 {
-    LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR
 
     if (!LLFacePool::isDead())
     {
@@ -131,14 +131,14 @@ BOOL LLDrawPoolAvatar::isDead()
 
 S32 LLDrawPoolAvatar::getShaderLevel() const
 {
-    LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR
 
 	return (S32) LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_AVATAR);
 }
 
 void LLDrawPoolAvatar::prerender()
 {
-    LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR
 
 	mShaderLevel = LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_AVATAR);
 	
@@ -156,7 +156,7 @@ void LLDrawPoolAvatar::prerender()
 
 LLMatrix4& LLDrawPoolAvatar::getModelView()
 {
-    LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR
 
 	static LLMatrix4 ret;
 
@@ -176,7 +176,7 @@ LLMatrix4& LLDrawPoolAvatar::getModelView()
 
 void LLDrawPoolAvatar::beginDeferredPass(S32 pass)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
 	
 	sSkipTransparent = TRUE;
 	is_deferred_render = true;
@@ -202,7 +202,7 @@ void LLDrawPoolAvatar::beginDeferredPass(S32 pass)
 
 void LLDrawPoolAvatar::endDeferredPass(S32 pass)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
 
 	sSkipTransparent = FALSE;
 	is_deferred_render = false;
@@ -228,7 +228,7 @@ void LLDrawPoolAvatar::endDeferredPass(S32 pass)
 
 void LLDrawPoolAvatar::renderDeferred(S32 pass)
 {
-    LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR
 
 	render(pass);
 }
@@ -240,7 +240,7 @@ S32 LLDrawPoolAvatar::getNumPostDeferredPasses()
 
 void LLDrawPoolAvatar::beginPostDeferredPass(S32 pass)
 {
-    LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR
 
 	sSkipOpaque = TRUE;
 	sShaderLevel = mShaderLevel;
@@ -256,7 +256,7 @@ void LLDrawPoolAvatar::beginPostDeferredPass(S32 pass)
 
 void LLDrawPoolAvatar::endPostDeferredPass(S32 pass)
 {
-    LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR
 	// if we're in software-blending, remember to set the fence _after_ we draw so we wait till this rendering is done
 	sRenderingSkinned = FALSE;
 	sSkipOpaque = FALSE;
@@ -268,7 +268,7 @@ void LLDrawPoolAvatar::endPostDeferredPass(S32 pass)
 
 void LLDrawPoolAvatar::renderPostDeferred(S32 pass)
 {
-    LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR
 
     is_post_deferred_render = true;
 	if (LLPipeline::sImpostorRender)
@@ -291,7 +291,7 @@ S32 LLDrawPoolAvatar::getNumShadowPasses()
 
 void LLDrawPoolAvatar::beginShadowPass(S32 pass)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
 
 	if (pass == SHADOW_PASS_AVATAR_OPAQUE)
 	{
@@ -349,7 +349,7 @@ void LLDrawPoolAvatar::beginShadowPass(S32 pass)
 
 void LLDrawPoolAvatar::endShadowPass(S32 pass)
 {
-	LL_PROFILE_ZONE_SCOPED;
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
 
     if (sShaderLevel > 0)
 	{			
@@ -362,7 +362,7 @@ void LLDrawPoolAvatar::endShadowPass(S32 pass)
 
 void LLDrawPoolAvatar::renderShadow(S32 pass)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
 
 	if (mDrawFace.empty())
 	{
@@ -424,7 +424,7 @@ S32 LLDrawPoolAvatar::getNumDeferredPasses()
 
 void LLDrawPoolAvatar::render(S32 pass)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
 	if (LLPipeline::sImpostorRender)
 	{
 		renderAvatars(NULL, pass+2);
@@ -436,7 +436,7 @@ void LLDrawPoolAvatar::render(S32 pass)
 
 void LLDrawPoolAvatar::beginRenderPass(S32 pass)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
 	//reset vertex buffer mappings
 	LLVertexBuffer::unbind();
 
@@ -466,7 +466,7 @@ void LLDrawPoolAvatar::beginRenderPass(S32 pass)
 
 void LLDrawPoolAvatar::endRenderPass(S32 pass)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
 
 	if (LLPipeline::sImpostorRender)
 	{
@@ -489,7 +489,7 @@ void LLDrawPoolAvatar::endRenderPass(S32 pass)
 
 void LLDrawPoolAvatar::beginImpostor()
 {
-    LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR
 
 	if (!LLPipeline::sReflectionRender)
 	{
@@ -506,7 +506,7 @@ void LLDrawPoolAvatar::beginImpostor()
 
 void LLDrawPoolAvatar::endImpostor()
 {
-    LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR
 
 		gImpostorProgram.unbind();
 	gPipeline.enableLightsDynamic();
@@ -514,7 +514,7 @@ void LLDrawPoolAvatar::endImpostor()
 
 void LLDrawPoolAvatar::beginRigid()
 {
-    LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR
 
 	if (gPipeline.shadersLoaded())
 	{
@@ -549,7 +549,7 @@ void LLDrawPoolAvatar::beginRigid()
 
 void LLDrawPoolAvatar::endRigid()
 {
-    LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR
 
 	sShaderLevel = mShaderLevel;
 	if (sVertexProgram != NULL)
@@ -560,7 +560,7 @@ void LLDrawPoolAvatar::endRigid()
 
 void LLDrawPoolAvatar::beginDeferredImpostor()
 {
-    LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR
 
 	if (!LLPipeline::sReflectionRender)
 	{
@@ -578,7 +578,7 @@ void LLDrawPoolAvatar::beginDeferredImpostor()
 
 void LLDrawPoolAvatar::endDeferredImpostor()
 {
-    LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR
 
 	sShaderLevel = mShaderLevel;
 	sVertexProgram->disableTexture(LLViewerShaderMgr::DEFERRED_NORMAL);
@@ -591,7 +591,7 @@ void LLDrawPoolAvatar::endDeferredImpostor()
 
 void LLDrawPoolAvatar::beginDeferredRigid()
 {
-    LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR
 
 	sVertexProgram = &gDeferredNonIndexedDiffuseAlphaMaskNoColorProgram;
 	sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
@@ -609,7 +609,7 @@ void LLDrawPoolAvatar::beginDeferredRigid()
 
 void LLDrawPoolAvatar::endDeferredRigid()
 {
-    LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR
 
 	sShaderLevel = mShaderLevel;
 	sVertexProgram->disableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
@@ -620,7 +620,7 @@ void LLDrawPoolAvatar::endDeferredRigid()
 
 void LLDrawPoolAvatar::beginSkinned()
 {
-    LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR
 
 	if (sShaderLevel > 0)
 	{
@@ -685,7 +685,7 @@ void LLDrawPoolAvatar::beginSkinned()
 
 void LLDrawPoolAvatar::endSkinned()
 {
-    LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR
 
 	// if we're in software-blending, remember to set the fence _after_ we draw so we wait till this rendering is done
 	if (sShaderLevel > 0)
@@ -711,7 +711,7 @@ void LLDrawPoolAvatar::endSkinned()
 
 void LLDrawPoolAvatar::beginDeferredSkinned()
 {
-    LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR
 
 	sShaderLevel = mShaderLevel;
 	sVertexProgram = &gDeferredAvatarProgram;
@@ -734,7 +734,7 @@ void LLDrawPoolAvatar::beginDeferredSkinned()
 
 void LLDrawPoolAvatar::endDeferredSkinned()
 {
-    LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR
 
 	// if we're in software-blending, remember to set the fence _after_ we draw so we wait till this rendering is done
 	sRenderingSkinned = FALSE;
@@ -749,6 +749,8 @@ void LLDrawPoolAvatar::endDeferredSkinned()
 
 void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR; //LL_RECORD_BLOCK_TIME(FTM_RENDER_CHARACTERS);
+
 	if (pass == -1)
 	{
 		for (S32 i = 1; i < getNumPasses(); i++)
@@ -788,8 +790,6 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass)
 		return;
 	}
 
-    LL_RECORD_BLOCK_TIME(FTM_RENDER_CHARACTERS);
-
 	if (!single_avatar && !avatarp->isFullyLoaded() )
 	{
 		if (pass==0 && (!gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_PARTICLES) || LLViewerPartSim::getMaxPartCount() <= 0))
@@ -908,7 +908,7 @@ static LLTrace::BlockTimerStatHandle FTM_RIGGED_VBO("Rigged VBO");
 //-----------------------------------------------------------------------------
 LLViewerTexture *LLDrawPoolAvatar::getDebugTexture()
 {
-    LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR
 
 	if (mReferences.empty())
 	{
@@ -936,7 +936,7 @@ LLVertexBufferAvatar::LLVertexBufferAvatar()
 : LLVertexBuffer(sDataMask, 
 	GL_STREAM_DRAW_ARB) //avatars are always stream draw due to morph targets
 {
-    LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR
 }
 
 
diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp
index 61418ba547..8cec08394d 100644
--- a/indra/newview/llmeshrepository.cpp
+++ b/indra/newview/llmeshrepository.cpp
@@ -4070,7 +4070,7 @@ S32 LLMeshRepository::getActualMeshLOD(const LLVolumeParams& mesh_params, S32 lo
 
 const LLMeshSkinInfo* LLMeshRepository::getSkinInfo(const LLUUID& mesh_id, const LLVOVolume* requesting_obj)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
     if (mesh_id.notNull())
     {
         skin_map::iterator iter = mSkinMap.find(mesh_id);
diff --git a/indra/newview/llphysicsmotion.cpp b/indra/newview/llphysicsmotion.cpp
index 30ca7ae539..03a02ba26f 100644
--- a/indra/newview/llphysicsmotion.cpp
+++ b/indra/newview/llphysicsmotion.cpp
@@ -453,7 +453,7 @@ F32 LLPhysicsMotion::calculateAcceleration_local(const F32 velocity_local, const
 
 BOOL LLPhysicsMotionController::onUpdate(F32 time, U8* joint_mask)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
         // Skip if disabled globally.
         if (!gSavedSettings.getBOOL("AvatarPhysics"))
         {
diff --git a/indra/newview/llskinningutil.cpp b/indra/newview/llskinningutil.cpp
index dc12de29fb..cf3519c1c7 100644
--- a/indra/newview/llskinningutil.cpp
+++ b/indra/newview/llskinningutil.cpp
@@ -125,7 +125,7 @@ void LLSkinningUtil::initSkinningMatrixPalette(
     const LLMeshSkinInfo* skin,
     LLVOAvatar *avatar)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
 
     initJointNums(const_cast<LLMeshSkinInfo*>(skin), avatar);
 
@@ -270,7 +270,7 @@ void LLSkinningUtil::initJointNums(LLMeshSkinInfo* skin, LLVOAvatar *avatar)
 {
     if (!skin->mJointNumsInitialized)
     {
-        LL_PROFILE_ZONE_SCOPED;
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
         for (U32 j = 0; j < skin->mJointNames.size(); ++j)
         {
     #if DEBUG_SKINNING     
diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp
index c8c85d404d..60733b73a3 100644
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -332,7 +332,7 @@ public:
 	// must return FALSE when the motion is completed.
 	virtual BOOL onUpdate(F32 time, U8* joint_mask)
 	{
-        LL_PROFILE_ZONE_SCOPED;
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
 		F32 nx[2];
 		nx[0]=time*TORSO_NOISE_SPEED;
 		nx[1]=0.0f;
@@ -453,7 +453,7 @@ public:
 	// must return FALSE when the motion is completed.
 	virtual BOOL onUpdate(F32 time, U8* joint_mask)
 	{
-        LL_PROFILE_ZONE_SCOPED;
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
 		mBreatheRate = 1.f;
 
 		F32 breathe_amt = (sinf(mBreatheRate * time) * BREATHE_ROT_MOTION_STRENGTH);
@@ -555,7 +555,7 @@ public:
 	// must return FALSE when the motion is completed.
 	virtual BOOL onUpdate(F32 time, U8* joint_mask)
 	{
-        LL_PROFILE_ZONE_SCOPED;
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
 		mPelvisState->setPosition(LLVector3::zero);
 
 		return TRUE;
@@ -1327,7 +1327,7 @@ void LLVOAvatar::updateSpatialExtents(LLVector4a& newMin, LLVector4a &newMax)
 
 void LLVOAvatar::calculateSpatialExtents(LLVector4a& newMin, LLVector4a& newMax)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
 
     S32 box_detail = gSavedSettings.getS32("AvatarBoundingBoxComplexity");
     if (getOverallAppearance() != AOA_NORMAL)
@@ -2528,7 +2528,7 @@ void LLVOAvatar::dumpAnimationState()
 //------------------------------------------------------------------------
 void LLVOAvatar::idleUpdate(LLAgent &agent, const F64 &time)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
 
 	if (isDead())
 	{
@@ -2787,7 +2787,7 @@ static void override_bbox(LLDrawable* drawable, LLVector4a* extents)
 
 void LLVOAvatar::idleUpdateMisc(bool detailed_update)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
 	if (LLVOAvatar::sJointDebug)
 	{
 		LL_INFOS() << getFullname() << ": joint touches: " << LLJoint::sNumTouches << " updates: " << LLJoint::sNumUpdates << LL_ENDL;
@@ -3153,7 +3153,7 @@ void LLVOAvatar::idleUpdateWindEffect()
 
 void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
 
 	// update chat bubble
 	//--------------------------------------------------------------------
@@ -4903,7 +4903,7 @@ bool LLVOAvatar::shouldAlphaMask()
 //-----------------------------------------------------------------------------
 U32 LLVOAvatar::renderSkinned()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
 
 	U32 num_indices = 0;
 
@@ -7120,7 +7120,7 @@ void LLVOAvatar::updateGL()
 {
 	if (mMeshTexturesDirty)
 	{
-		LL_PROFILE_ZONE_SCOPED
+		LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR
 		updateMeshTextures();
 		mMeshTexturesDirty = FALSE;
 	}
@@ -7131,7 +7131,7 @@ void LLVOAvatar::updateGL()
 //-----------------------------------------------------------------------------
 BOOL LLVOAvatar::updateGeometry(LLDrawable *drawable)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
 	if (!(gPipeline.hasRenderType(mIsControlAvatar ? LLPipeline::RENDER_TYPE_CONTROL_AV : LLPipeline::RENDER_TYPE_AVATAR)))
 	{
 		return TRUE;
@@ -7865,7 +7865,7 @@ void LLVOAvatar::onGlobalColorChanged(const LLTexGlobalColor* global_color)
 // Do rigged mesh attachments display with this av?
 bool LLVOAvatar::shouldRenderRigged() const
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
 
 	if (getOverallAppearance() == AOA_NORMAL)
 	{
@@ -8377,7 +8377,7 @@ void LLVOAvatar::updateMeshVisibility()
 // virtual
 void LLVOAvatar::updateMeshTextures()
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR
 	static S32 update_counter = 0;
 	mBakedTextureDebugText.clear();
 	
@@ -9453,7 +9453,7 @@ const LLVOAvatar::MatrixPaletteCache& LLVOAvatar::updateSkinInfoMatrixPalette(co
 
     if (entry.mFrame != gFrameCount)
     {
-        LL_PROFILE_ZONE_SCOPED;
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
 
         entry.mFrame = gFrameCount;
 
@@ -10257,7 +10257,7 @@ void showRigInfoTabExtents(LLVOAvatar *avatar, LLJointRiggingInfoTab& tab, S32&
 
 void LLVOAvatar::getAssociatedVolumes(std::vector<LLVOVolume*>& volumes)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
 	for ( LLVOAvatar::attachment_map_t::iterator iter = mAttachmentPoints.begin(); iter != mAttachmentPoints.end(); ++iter )
 	{
 		LLViewerJointAttachment* attachment = iter->second;
@@ -10318,7 +10318,7 @@ void LLVOAvatar::getAssociatedVolumes(std::vector<LLVOVolume*>& volumes)
 // virtual
 void LLVOAvatar::updateRiggingInfo()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
 
     LL_DEBUGS("RigSpammish") << getFullname() << " updating rig tab" << LL_ENDL;
 
@@ -10489,7 +10489,7 @@ void LLVOAvatar::updateImpostorRendering(U32 newMaxNonImpostorsValue)
 
 void LLVOAvatar::idleUpdateRenderComplexity()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
     if (isControlAvatar())
     {
         LLControlAvatar *cav = dynamic_cast<LLControlAvatar*>(this);
@@ -11017,7 +11017,7 @@ void LLVOAvatar::updateOverallAppearanceAnimations()
 // Based on isVisuallyMuted(), but has 3 possible results.
 LLVOAvatar::AvatarOverallAppearance LLVOAvatar::getOverallAppearance() const
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
 	AvatarOverallAppearance result = AOA_NORMAL;
 
 	// Priority order (highest priority first)
-- 
cgit v1.2.3


From 8b7532105fdf97fb74b28ee6c6c81598c00d89f6 Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Thu, 13 Jan 2022 11:35:00 -0800
Subject: SL-16606: Add profiler category DISPLAY

---
 indra/newview/llviewerdisplay.cpp | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp
index c84a8c70fa..f28edd10c5 100644
--- a/indra/newview/llviewerdisplay.cpp
+++ b/indra/newview/llviewerdisplay.cpp
@@ -211,7 +211,7 @@ void display_stats()
 	F32 fps_log_freq = gSavedSettings.getF32("FPSLogFrequency");
 	if (fps_log_freq > 0.f && gRecentFPSTime.getElapsedTimeF32() >= fps_log_freq)
 	{
-		LL_PROFILE_ZONE_NAMED("DS - FPS");
+		LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("DS - FPS");
 		F32 fps = gRecentFrameCount / fps_log_freq;
 		LL_INFOS() << llformat("FPS: %.02f", fps) << LL_ENDL;
 		gRecentFrameCount = 0;
@@ -220,7 +220,7 @@ void display_stats()
 	F32 mem_log_freq = gSavedSettings.getF32("MemoryLogFrequency");
 	if (mem_log_freq > 0.f && gRecentMemoryTime.getElapsedTimeF32() >= mem_log_freq)
 	{
-		LL_PROFILE_ZONE_NAMED("DS - Memory");
+		LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("DS - Memory");
 		gMemoryAllocated = U64Bytes(LLMemory::getCurrentRSS());
 		U32Megabytes memory = gMemoryAllocated;
 		LL_INFOS() << "MEMORY: " << memory << LL_ENDL;
@@ -230,7 +230,7 @@ void display_stats()
     F32 asset_storage_log_freq = gSavedSettings.getF32("AssetStorageLogFrequency");
     if (asset_storage_log_freq > 0.f && gAssetStorageLogTime.getElapsedTimeF32() >= asset_storage_log_freq)
     {
-		LL_PROFILE_ZONE_NAMED("DS - Asset Storage");
+		LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("DS - Asset Storage");
         gAssetStorageLogTime.reset();
         gAssetStorage->logAssetStorageInfo();
     }
@@ -637,7 +637,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 	
 	if (!gDisconnected)
 	{
-		LL_PROFILE_ZONE_NAMED("display - 1");
+		LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("display - 1");
 		LLAppViewer::instance()->pingMainloopTimeout("Display:Update");
 		if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD))
 		{ //don't draw hud objects in this frame
@@ -713,7 +713,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 		LLAppViewer::instance()->pingMainloopTimeout("Display:Swap");
 		
 		{ 
-			LL_PROFILE_ZONE_NAMED("display - 2")
+			LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("display - 2")
 			if (gResizeScreenTexture)
 			{
 				gResizeScreenTexture = FALSE;
@@ -765,7 +765,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 
 		//if (!for_snapshot)
 		{
-			LL_PROFILE_ZONE_NAMED("display - 3")
+			LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("display - 3")
 			LLAppViewer::instance()->pingMainloopTimeout("Display:Imagery");
 			gPipeline.generateWaterReflection(*LLViewerCamera::getInstance());
 			gPipeline.generateHighlight(*LLViewerCamera::getInstance());
@@ -823,7 +823,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 		//
 		LLAppViewer::instance()->pingMainloopTimeout("Display:StateSort");
 		{
-			LL_PROFILE_ZONE_NAMED("display - 3")
+			LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("display - 4")
 			LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD;
 			gPipeline.stateSort(*LLViewerCamera::getInstance(), result);
 			stop_glerror();
@@ -930,7 +930,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")
+			LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("display - 5")
 			LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD;
 
 			if (gSavedSettings.getBOOL("RenderDepthPrePass"))
-- 
cgit v1.2.3


From 352b820258709489360ac8606983aff8a97f97da Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Thu, 13 Jan 2022 11:37:38 -0800
Subject: SL-16606: Add profiler category DRAWABLE

---
 indra/newview/lldrawable.cpp         | 46 ++++++++++++++++++------------------
 indra/newview/llviewerobjectlist.cpp |  6 ++---
 indra/newview/llvosky.cpp            |  2 +-
 indra/newview/pipeline.cpp           |  2 +-
 4 files changed, 28 insertions(+), 28 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/lldrawable.cpp b/indra/newview/lldrawable.cpp
index b274fd56b6..a163edf62c 100644
--- a/indra/newview/lldrawable.cpp
+++ b/indra/newview/lldrawable.cpp
@@ -98,7 +98,7 @@ LLDrawable::LLDrawable(LLViewerObject *vobj, bool new_entry)
 
 void LLDrawable::init(bool new_entry)
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE
 
 	// mXform
 	mParent = NULL;
@@ -247,7 +247,7 @@ BOOL LLDrawable::isLight() const
 
 void LLDrawable::cleanupReferences()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE;
 	
 	
 	std::for_each(mFaces.begin(), mFaces.end(), DeletePointer());
@@ -308,7 +308,7 @@ S32 LLDrawable::findReferences(LLDrawable *drawablep)
 
 LLFace*	LLDrawable::addFace(LLFacePool *poolp, LLViewerTexture *texturep)
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE
 	
 	LLFace *face;
 	{
@@ -336,7 +336,7 @@ LLFace*	LLDrawable::addFace(LLFacePool *poolp, LLViewerTexture *texturep)
 
 LLFace*	LLDrawable::addFace(const LLTextureEntry *te, LLViewerTexture *texturep)
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE
 
 	LLFace *face;
 
@@ -359,7 +359,7 @@ LLFace*	LLDrawable::addFace(const LLTextureEntry *te, LLViewerTexture *texturep)
 
 LLFace*	LLDrawable::addFace(const LLTextureEntry *te, LLViewerTexture *texturep, LLViewerTexture *normalp)
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE
 
 	LLFace *face;
 	face = new LLFace(this, mVObjp);
@@ -382,7 +382,7 @@ LLFace*	LLDrawable::addFace(const LLTextureEntry *te, LLViewerTexture *texturep,
 
 LLFace*	LLDrawable::addFace(const LLTextureEntry *te, LLViewerTexture *texturep, LLViewerTexture *normalp, LLViewerTexture *specularp)
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE
 
 	LLFace *face;
 	face = new LLFace(this, mVObjp);
@@ -406,7 +406,7 @@ LLFace*	LLDrawable::addFace(const LLTextureEntry *te, LLViewerTexture *texturep,
 
 void LLDrawable::setNumFaces(const S32 newFaces, LLFacePool *poolp, LLViewerTexture *texturep)
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE
 
 	if (newFaces == (S32)mFaces.size())
 	{
@@ -431,7 +431,7 @@ void LLDrawable::setNumFaces(const S32 newFaces, LLFacePool *poolp, LLViewerText
 
 void LLDrawable::setNumFacesFast(const S32 newFaces, LLFacePool *poolp, LLViewerTexture *texturep)
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE
 
 	if (newFaces <= (S32)mFaces.size() && newFaces >= (S32)mFaces.size()/2)
 	{
@@ -456,7 +456,7 @@ void LLDrawable::setNumFacesFast(const S32 newFaces, LLFacePool *poolp, LLViewer
 
 void LLDrawable::mergeFaces(LLDrawable* src)
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE
 
 	U32 face_count = mFaces.size() + src->mFaces.size();
 
@@ -491,7 +491,7 @@ void LLDrawable::updateMaterial()
 
 void LLDrawable::makeActive()
 {		
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE
 
 #if !LL_RELEASE_FOR_DOWNLOAD
 	if (mVObjp.notNull())
@@ -556,7 +556,7 @@ void LLDrawable::makeActive()
 
 void LLDrawable::makeStatic(BOOL warning_enabled)
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE
 
 	if (isState(ACTIVE) && 
 		!isState(ACTIVE_CHILD) && 
@@ -604,7 +604,7 @@ void LLDrawable::makeStatic(BOOL warning_enabled)
 // Returns "distance" between target destination and resulting xfrom
 F32 LLDrawable::updateXform(BOOL undamped)
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE
 
 	BOOL damped = !undamped;
 
@@ -757,7 +757,7 @@ void LLDrawable::moveUpdatePipeline(BOOL moved)
 
 void LLDrawable::movePartition()
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE
 
 	LLSpatialPartition* part = getSpatialPartition();
 	if (part)
@@ -803,7 +803,7 @@ BOOL LLDrawable::updateMoveUndamped()
 
 void LLDrawable::updatePartition()
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE
 
 	if (!getVOVolume())
 	{
@@ -822,7 +822,7 @@ void LLDrawable::updatePartition()
 
 BOOL LLDrawable::updateMoveDamped()
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE
 
 	F32 dist_squared = updateXform(FALSE);
 
@@ -847,7 +847,7 @@ BOOL LLDrawable::updateMoveDamped()
 
 void LLDrawable::updateDistance(LLCamera& camera, bool force_update)
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE
 
 	if (LLViewerCamera::sCurCameraID != LLViewerCamera::CAMERA_WORLD)
 	{
@@ -953,7 +953,7 @@ void LLDrawable::updateTexture()
 
 BOOL LLDrawable::updateGeometry(BOOL priority)
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE
 
 	llassert(mVObjp.notNull());
 	BOOL res = mVObjp->updateGeometry(this);
@@ -1032,7 +1032,7 @@ const LLVector3& LLDrawable::getBounds(LLVector3& min, LLVector3& max) const
 
 void LLDrawable::updateSpatialExtents()
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE
 
 	if (mVObjp)
 	{
@@ -1168,7 +1168,7 @@ void LLDrawable::setGroup(LLViewerOctreeGroup *groupp)
 */
 LLSpatialPartition* LLDrawable::getSpatialPartition()
 { 
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE
 
 	LLSpatialPartition* retval = NULL;
 
@@ -1257,7 +1257,7 @@ 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
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE
 
 	mBridge = this;
 	mDrawable = root;
@@ -1304,7 +1304,7 @@ void LLSpatialBridge::destroyTree()
 
 void LLSpatialBridge::updateSpatialExtents()
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE
 
 	LLSpatialGroup* root = (LLSpatialGroup*) mOctree->getListener(0);
 	
@@ -1477,7 +1477,7 @@ public:
 
 void LLSpatialBridge::setVisible(LLCamera& camera_in, std::vector<LLDrawable*>* results, BOOL for_select)
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE
 
 	if (!gPipeline.hasRenderType(mDrawableType))
 	{
@@ -1576,7 +1576,7 @@ void LLSpatialBridge::setVisible(LLCamera& camera_in, std::vector<LLDrawable*>*
 
 void LLSpatialBridge::updateDistance(LLCamera& camera_in, bool force_update)
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE
 
 	if (mDrawable == NULL)
 	{
diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp
index 971a355a65..630861f6be 100644
--- a/indra/newview/llviewerobjectlist.cpp
+++ b/indra/newview/llviewerobjectlist.cpp
@@ -1350,7 +1350,7 @@ void LLViewerObjectList::cleanupReferences(LLViewerObject *objectp)
 
 void LLViewerObjectList::removeDrawable(LLDrawable* drawablep)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE;
 
 	if (!drawablep)
 	{
@@ -1526,7 +1526,7 @@ void LLViewerObjectList::removeFromActiveList(LLViewerObject* objectp)
 
 void LLViewerObjectList::updateActive(LLViewerObject *objectp)
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE;
 
 	if (objectp->isDead())
 	{
@@ -2100,7 +2100,7 @@ LLViewerObject *LLViewerObjectList::replaceObject(const LLUUID &id, const LLPCod
 
 S32 LLViewerObjectList::findReferences(LLDrawable *drawablep) const
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE;
 
 	LLViewerObject *objectp;
 	S32 num_refs = 0;
diff --git a/indra/newview/llvosky.cpp b/indra/newview/llvosky.cpp
index 72ec8390a4..2e6d8adc05 100644
--- a/indra/newview/llvosky.cpp
+++ b/indra/newview/llvosky.cpp
@@ -972,7 +972,7 @@ void LLVOSky::setBloomTextures(const LLUUID& bloom_texture, const LLUUID& bloom_
 
 BOOL LLVOSky::updateGeometry(LLDrawable *drawable)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE;
 	if (mFace[FACE_REFLECTION] == NULL)
 	{
 		LLDrawPoolWater *poolp = (LLDrawPoolWater*) gPipeline.getPool(LLDrawPool::POOL_WATER);
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index d5f9772b85..0ec85b3831 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -3376,7 +3376,7 @@ void LLPipeline::stateSort(LLCamera& camera, LLCullResult &result)
 	}
 	
 	{
-		LL_RECORD_BLOCK_TIME(FTM_STATESORT_DRAWABLE);
+		LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWABLE("stateSort"); // LL_RECORD_BLOCK_TIME(FTM_STATESORT_DRAWABLE);
 		for (LLCullResult::drawable_iterator iter = sCull->beginVisibleList();
 			 iter != sCull->endVisibleList(); ++iter)
 		{
-- 
cgit v1.2.3


From cfd39c366344f10665e8d92df79aa51fc4ef5c66 Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Thu, 13 Jan 2022 11:57:12 -0800
Subject: SL-16606: Add profiler category DRAWPOOL

---
 indra/newview/lldrawpool.cpp        | 14 +++++++-------
 indra/newview/lldrawpoolalpha.cpp   | 10 +++++-----
 indra/newview/lldrawpoolbump.cpp    | 36 ++++++++++++++++++------------------
 indra/newview/lldrawpoolsimple.cpp  | 32 +++++++++++++++++---------------
 indra/newview/lldrawpoolterrain.cpp | 20 ++++++++++----------
 indra/newview/lldrawpoolwater.cpp   | 10 +++++-----
 indra/newview/lldrawpoolwlsky.cpp   |  4 ++--
 indra/newview/llsettingsvo.cpp      |  2 +-
 indra/newview/pipeline.cpp          | 14 +++++++-------
 9 files changed, 72 insertions(+), 70 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/lldrawpool.cpp b/indra/newview/lldrawpool.cpp
index 503ee6d08d..faa5f71da4 100644
--- a/indra/newview/lldrawpool.cpp
+++ b/indra/newview/lldrawpool.cpp
@@ -389,7 +389,7 @@ LLRenderPass::~LLRenderPass()
 
 void LLRenderPass::renderGroup(LLSpatialGroup* group, U32 type, U32 mask, BOOL texture)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
 	LLSpatialGroup::drawmap_elem_t& draw_info = group->mDrawMap[type];
 	
 	for (LLSpatialGroup::drawmap_elem_t::iterator k = draw_info.begin(); k != draw_info.end(); ++k)	
@@ -404,7 +404,7 @@ void LLRenderPass::renderGroup(LLSpatialGroup* group, U32 type, U32 mask, BOOL t
 
 void LLRenderPass::renderRiggedGroup(LLSpatialGroup* group, U32 type, U32 mask, BOOL texture)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
     LLSpatialGroup::drawmap_elem_t& draw_info = group->mDrawMap[type];
     LLVOAvatar* lastAvatar = nullptr;
     U64 lastMeshId = 0;
@@ -429,7 +429,7 @@ void LLRenderPass::renderRiggedGroup(LLSpatialGroup* group, U32 type, U32 mask,
 
 void LLRenderPass::pushBatches(U32 type, U32 mask, BOOL texture, BOOL batch_textures)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
 	for (LLCullResult::drawinfo_iterator i = gPipeline.beginRenderMap(type); i != gPipeline.endRenderMap(type); ++i)	
 	{
 		LLDrawInfo* pparams = *i;
@@ -442,7 +442,7 @@ void LLRenderPass::pushBatches(U32 type, U32 mask, BOOL texture, BOOL batch_text
 
 void LLRenderPass::pushRiggedBatches(U32 type, U32 mask, BOOL texture, BOOL batch_textures)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
     LLVOAvatar* lastAvatar = nullptr;
     U64 lastMeshId = 0;
     mask |= LLVertexBuffer::MAP_WEIGHT4;
@@ -465,7 +465,7 @@ void LLRenderPass::pushRiggedBatches(U32 type, U32 mask, BOOL texture, BOOL batc
 
 void LLRenderPass::pushMaskBatches(U32 type, U32 mask, BOOL texture, BOOL batch_textures)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
 	for (LLCullResult::drawinfo_iterator i = gPipeline.beginRenderMap(type); i != gPipeline.endRenderMap(type); ++i)	
 	{
 		LLDrawInfo* pparams = *i;
@@ -479,7 +479,7 @@ void LLRenderPass::pushMaskBatches(U32 type, U32 mask, BOOL texture, BOOL batch_
 
 void LLRenderPass::pushRiggedMaskBatches(U32 type, U32 mask, BOOL texture, BOOL batch_textures)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
     LLVOAvatar* lastAvatar = nullptr;
     U64 lastMeshId = 0;
     for (LLCullResult::drawinfo_iterator i = gPipeline.beginRenderMap(type); i != gPipeline.endRenderMap(type); ++i)
@@ -525,7 +525,7 @@ void LLRenderPass::applyModelMatrix(const LLDrawInfo& params)
 
 void LLRenderPass::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture, BOOL batch_textures)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
     if (!params.mCount)
     {
         return;
diff --git a/indra/newview/lldrawpoolalpha.cpp b/indra/newview/lldrawpoolalpha.cpp
index ee1a640f2d..9da20cc375 100644
--- a/indra/newview/lldrawpoolalpha.cpp
+++ b/indra/newview/lldrawpoolalpha.cpp
@@ -126,7 +126,7 @@ static void prepare_alpha_shader(LLGLSLShader* shader, bool textureGamma, bool d
 
 void LLDrawPoolAlpha::renderPostDeferred(S32 pass) 
 { 
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
     deferred_render = TRUE;
 
     // first pass, regular forward alpha rendering
@@ -190,7 +190,7 @@ static void prepare_forward_shader(LLGLSLShader* shader, F32 minimum_alpha)
 
 void LLDrawPoolAlpha::render(S32 pass)
 {
-    LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
 
     simple_shader = (LLPipeline::sImpostorRender) ? &gObjectSimpleImpostorProgram :
         (LLPipeline::sUnderWaterRender) ? &gObjectSimpleWaterProgram : &gObjectSimpleProgram;
@@ -490,7 +490,7 @@ void LLDrawPoolAlpha::renderRiggedEmissives(U32 mask, std::vector<LLDrawInfo*>&
 
 void LLDrawPoolAlpha::renderAlpha(U32 mask, bool depth_only)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
     BOOL initialized_lighting = FALSE;
 	BOOL light_enabled = TRUE;
 
@@ -500,7 +500,7 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, bool depth_only)
 
     for (LLCullResult::sg_iterator i = gPipeline.beginAlphaGroups(); i != gPipeline.endAlphaGroups(); ++i)
 	{
-        LL_PROFILE_ZONE_NAMED("renderAlpha - group");
+        LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWPOOL("renderAlpha - group");
 		LLSpatialGroup* group = *i;
 		llassert(group);
 		llassert(group->getSpatialPartition());
@@ -525,7 +525,7 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, bool depth_only)
 
 			for (LLSpatialGroup::drawmap_elem_t::iterator k = draw_info.begin(); k != draw_info.end(); ++k)	
 			{
-                LL_PROFILE_ZONE_NAMED("ra - push batch")
+                LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWPOOL("ra - push batch")
 				LLDrawInfo& params = **k;
                 U32 have_mask = params.mVertexBuffer->getTypeMask() & mask;
 				if (have_mask != mask)
diff --git a/indra/newview/lldrawpoolbump.cpp b/indra/newview/lldrawpoolbump.cpp
index b01450bba9..471b0e2c48 100644
--- a/indra/newview/lldrawpoolbump.cpp
+++ b/indra/newview/lldrawpoolbump.cpp
@@ -210,7 +210,7 @@ S32 LLDrawPoolBump::getNumPasses()
 
 void LLDrawPoolBump::render(S32 pass)
 {
-    LL_RECORD_BLOCK_TIME(FTM_RENDER_BUMP);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_BUMP);
 
     if (!gPipeline.hasRenderType(LLDrawPool::POOL_SIMPLE))
     {
@@ -245,7 +245,7 @@ void LLDrawPoolBump::render(S32 pass)
 //static
 void LLDrawPoolBump::beginShiny()
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_SHINY);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_SHINY);
 	
 	mShiny = TRUE;
 	sVertexMask = VERTEX_MASK_SHINY;
@@ -334,7 +334,7 @@ void LLDrawPoolBump::bindCubeMap(LLGLSLShader* shader, S32 shader_level, S32& di
 
 void LLDrawPoolBump::renderShiny()
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_SHINY);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_SHINY);
 	
 	if( gSky.mVOSkyp->getCubeMap() )
 	{
@@ -390,7 +390,7 @@ void LLDrawPoolBump::unbindCubeMap(LLGLSLShader* shader, S32 shader_level, S32&
 
 void LLDrawPoolBump::endShiny()
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_SHINY);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_SHINY);
 
 	unbindCubeMap(shader, mShaderLevel, diffuse_channel, cube_channel);
 	if (shader)
@@ -405,7 +405,7 @@ void LLDrawPoolBump::endShiny()
 
 void LLDrawPoolBump::beginFullbrightShiny()
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_SHINY);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_SHINY);
 	
 	sVertexMask = VERTEX_MASK_SHINY | LLVertexBuffer::MAP_TEXCOORD0;
 
@@ -476,7 +476,7 @@ void LLDrawPoolBump::beginFullbrightShiny()
 
 void LLDrawPoolBump::renderFullbrightShiny()
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_SHINY);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_SHINY);
 
 	if( gSky.mVOSkyp->getCubeMap() )
 	{
@@ -509,7 +509,7 @@ void LLDrawPoolBump::renderFullbrightShiny()
 
 void LLDrawPoolBump::endFullbrightShiny()
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_SHINY);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_SHINY);
 
 	LLCubeMap* cube_map = gSky.mVOSkyp ? gSky.mVOSkyp->getCubeMap() : NULL;
 	if( cube_map )
@@ -568,7 +568,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;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
 	//Note: texture atlas does not support bump texture now.
 	LLViewerFetchedTexture* tex = LLViewerTextureManager::staticCastToFetchedTexture(texture) ;
 	if(!tex)
@@ -618,9 +618,9 @@ BOOL LLDrawPoolBump::bindBumpMap(U8 bump_code, LLViewerTexture* texture, F32 vsi
 
 //static
 void LLDrawPoolBump::beginBump()
-{	
+{
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_BUMP);
 	sVertexMask = VERTEX_MASK_BUMP;
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_BUMP);
 	// Optional second pass: emboss bump map
 	stop_glerror();
 
@@ -641,7 +641,7 @@ void LLDrawPoolBump::beginBump()
 //static
 void LLDrawPoolBump::renderBump(U32 pass)
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_BUMP);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_BUMP);
 	LLGLDisable fog(GL_FOG);
 	LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE, GL_LEQUAL);
 	LLGLEnable blend(GL_BLEND);
@@ -674,7 +674,7 @@ S32 LLDrawPoolBump::getNumDeferredPasses()
 
 void LLDrawPoolBump::renderDeferred(S32 pass)
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_BUMP);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_BUMP);
 
     mShiny = TRUE;
     for (int i = 0; i < 2; ++i)
@@ -879,7 +879,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;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
 	llassert( (bump_code == BE_BRIGHTNESS) || (bump_code == BE_DARKNESS) );
 
 	LLViewerTexture* bump = NULL;
@@ -935,7 +935,7 @@ LLViewerTexture* LLBumpImageList::getBrightnessDarknessImage(LLViewerFetchedText
 // static
 void LLBumpImageList::onSourceBrightnessLoaded( BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata )
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
 	LLUUID* source_asset_id = (LLUUID*)userdata;
 	LLBumpImageList::onSourceLoaded( success, src_vi, src, *source_asset_id, BE_BRIGHTNESS );
 	if( final )
@@ -959,7 +959,7 @@ void LLBumpImageList::onSourceStandardLoaded( BOOL success, LLViewerFetchedTextu
 {
 	if (success && LLPipeline::sRenderDeferred)
 	{
-        LL_PROFILE_ZONE_SCOPED;
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
 		LLPointer<LLImageRaw> nrm_image = new LLImageRaw(src->getWidth(), src->getHeight(), 4);
 		{
 			generateNormalMapFromAlpha(src, nrm_image);
@@ -1031,7 +1031,7 @@ void LLBumpImageList::onSourceLoaded( BOOL success, LLViewerTexture *src_vi, LLI
 {
 	if( success )
 	{
-        LL_PROFILE_ZONE_SCOPED;
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
 
 
 		bump_image_map_t& entries_list(bump_code == BE_BRIGHTNESS ? gBumpImageList.mBrightnessEntries : gBumpImageList.mDarknessEntries );
@@ -1318,7 +1318,7 @@ void LLDrawPoolBump::renderBump(U32 type, U32 mask)
 
 void LLDrawPoolBump::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture, BOOL batch_textures)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
 	applyModelMatrix(params);
 
 	bool tex_setup = false;
@@ -1394,7 +1394,7 @@ void LLDrawPoolBump::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture, BOOL
 
 void LLDrawPoolInvisible::render(S32 pass)
 { //render invisiprims
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_INVISIBLE);
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_INVISIBLE);
   
 	if (gPipeline.shadersLoaded())
 	{
diff --git a/indra/newview/lldrawpoolsimple.cpp b/indra/newview/lldrawpoolsimple.cpp
index 4ada753355..e324a663f4 100644
--- a/indra/newview/lldrawpoolsimple.cpp
+++ b/indra/newview/lldrawpoolsimple.cpp
@@ -79,13 +79,13 @@ static void setup_fullbright_shader(LLGLSLShader* shader)
 
 void LLDrawPoolGlow::renderPostDeferred(S32 pass)
 {
-    LL_RECORD_BLOCK_TIME(FTM_RENDER_GLOW);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_GLOW);
     render(&gDeferredEmissiveProgram);
 }
 
 void LLDrawPoolGlow::render(LLGLSLShader* shader)
 {
-    LL_RECORD_BLOCK_TIME(FTM_RENDER_GLOW);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_GLOW);
 	LLGLEnable blend(GL_BLEND);
 	LLGLDisable test(GL_ALPHA_TEST);
 	gGL.flush();
@@ -117,7 +117,7 @@ S32 LLDrawPoolGlow::getNumPasses()
 
 void LLDrawPoolGlow::render(S32 pass)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
     LLGLSLShader* shader = LLPipeline::sUnderWaterRender ? &gObjectEmissiveWaterProgram : &gObjectEmissiveProgram;
     render(shader);
 }
@@ -139,7 +139,7 @@ S32 LLDrawPoolSimple::getNumPasses()
 
 void LLDrawPoolSimple::render(S32 pass)
 {
-    LL_RECORD_BLOCK_TIME(FTM_RENDER_SIMPLE);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_SIMPLE);
 
 	LLGLDisable blend(GL_BLEND);
 	
@@ -213,8 +213,8 @@ void LLDrawPoolAlphaMask::prerender()
 
 void LLDrawPoolAlphaMask::render(S32 pass)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
 	LLGLDisable blend(GL_BLEND);
-    LL_PROFILE_ZONE_SCOPED;
 	
     LLGLSLShader* shader = nullptr;
     if (LLPipeline::sUnderWaterRender)
@@ -255,7 +255,7 @@ void LLDrawPoolFullbrightAlphaMask::prerender()
 
 void LLDrawPoolFullbrightAlphaMask::render(S32 pass)
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_MASK);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_MASK);
 
     LLGLSLShader* shader = nullptr;
     if (LLPipeline::sUnderWaterRender)
@@ -287,7 +287,7 @@ S32 LLDrawPoolSimple::getNumDeferredPasses()
 
 void LLDrawPoolSimple::renderDeferred(S32 pass)
 {
-    LL_RECORD_BLOCK_TIME(FTM_RENDER_SIMPLE_DEFERRED);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_SIMPLE_DEFERRED);
 	LLGLDisable blend(GL_BLEND);
 	LLGLDisable alpha_test(GL_ALPHA_TEST);
 
@@ -305,7 +305,7 @@ static LLTrace::BlockTimerStatHandle FTM_RENDER_ALPHA_MASK_DEFERRED("Deferred Al
 
 void LLDrawPoolAlphaMask::renderDeferred(S32 pass)
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_MASK_DEFERRED);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_MASK_DEFERRED);
     LLGLSLShader* shader = &gDeferredDiffuseAlphaMaskProgram;
 
     //render static
@@ -332,7 +332,7 @@ void LLDrawPoolGrass::prerender()
 
 void LLDrawPoolGrass::beginRenderPass(S32 pass)
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_GRASS);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_GRASS);
 	stop_glerror();
 
 	if (LLPipeline::sUnderWaterRender)
@@ -366,7 +366,7 @@ void LLDrawPoolGrass::beginRenderPass(S32 pass)
 
 void LLDrawPoolGrass::endRenderPass(S32 pass)
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_GRASS);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_GRASS);
 	LLRenderPass::endRenderPass(pass);
 
 	if (mShaderLevel > 0)
@@ -381,10 +381,11 @@ void LLDrawPoolGrass::endRenderPass(S32 pass)
 
 void LLDrawPoolGrass::render(S32 pass)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
 	LLGLDisable blend(GL_BLEND);
 	
 	{
-		LL_RECORD_BLOCK_TIME(FTM_RENDER_GRASS);
+		//LL_RECORD_BLOCK_TIME(FTM_RENDER_GRASS);
 		LLGLEnable test(GL_ALPHA_TEST);
 		gGL.setSceneBlendType(LLRender::BT_ALPHA);
 		//render grass
@@ -404,8 +405,9 @@ void LLDrawPoolGrass::endDeferredPass(S32 pass)
 
 void LLDrawPoolGrass::renderDeferred(S32 pass)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
 	{
-		LL_RECORD_BLOCK_TIME(FTM_RENDER_GRASS_DEFERRED);
+		//LL_RECORD_BLOCK_TIME(FTM_RENDER_GRASS_DEFERRED);
 		gDeferredNonIndexedDiffuseAlphaMaskProgram.bind();
 		gDeferredNonIndexedDiffuseAlphaMaskProgram.setMinimumAlpha(0.5f);
 
@@ -438,7 +440,7 @@ void LLDrawPoolFullbright::prerender()
 
 void LLDrawPoolFullbright::renderPostDeferred(S32 pass)
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_FULLBRIGHT);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_FULLBRIGHT);
 
     LLGLSLShader* shader = nullptr;
     if (LLPipeline::sUnderWaterRender)
@@ -464,7 +466,7 @@ void LLDrawPoolFullbright::renderPostDeferred(S32 pass)
 
 void LLDrawPoolFullbright::render(S32 pass)
 { //render fullbright
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_FULLBRIGHT);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_FULLBRIGHT);
 	gGL.setSceneBlendType(LLRender::BT_ALPHA);
 
 	stop_glerror();
@@ -505,7 +507,7 @@ S32 LLDrawPoolFullbright::getNumPasses()
 
 void LLDrawPoolFullbrightAlphaMask::renderPostDeferred(S32 pass)
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_FULLBRIGHT);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_FULLBRIGHT);
     
     LLGLSLShader* shader = nullptr;
     if (LLPipeline::sRenderingHUDs)
diff --git a/indra/newview/lldrawpoolterrain.cpp b/indra/newview/lldrawpoolterrain.cpp
index adea1909a3..cc5cb667f0 100644
--- a/indra/newview/lldrawpoolterrain.cpp
+++ b/indra/newview/lldrawpoolterrain.cpp
@@ -111,7 +111,7 @@ void LLDrawPoolTerrain::prerender()
 
 void LLDrawPoolTerrain::beginRenderPass( S32 pass )
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_TERRAIN);
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_TERRAIN);
 	LLFacePool::beginRenderPass(pass);
 
 	sShader = LLPipeline::sUnderWaterRender ? 
@@ -126,7 +126,7 @@ void LLDrawPoolTerrain::beginRenderPass( S32 pass )
 
 void LLDrawPoolTerrain::endRenderPass( S32 pass )
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_TERRAIN);
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_TERRAIN);
 	//LLFacePool::endRenderPass(pass);
 
 	if (mShaderLevel > 1 && sShader->mShaderLevel > 0) {
@@ -154,7 +154,7 @@ void LLDrawPoolTerrain::boostTerrainDetailTextures()
 
 void LLDrawPoolTerrain::render(S32 pass)
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_TERRAIN);
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_TERRAIN);
 	
 	if (mDrawFace.empty())
 	{
@@ -213,7 +213,7 @@ void LLDrawPoolTerrain::render(S32 pass)
 
 void LLDrawPoolTerrain::beginDeferredPass(S32 pass)
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_TERRAIN);
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_TERRAIN);
 	LLFacePool::beginRenderPass(pass);
 
 	sShader = LLPipeline::sUnderWaterRender ? &gDeferredTerrainWaterProgram : &gDeferredTerrainProgram;
@@ -223,14 +223,14 @@ void LLDrawPoolTerrain::beginDeferredPass(S32 pass)
 
 void LLDrawPoolTerrain::endDeferredPass(S32 pass)
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_TERRAIN);
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_TERRAIN);
 	LLFacePool::endRenderPass(pass);
 	sShader->unbind();
 }
 
 void LLDrawPoolTerrain::renderDeferred(S32 pass)
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_TERRAIN);
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_TERRAIN);
 	if (mDrawFace.empty())
 	{
 		return;
@@ -250,7 +250,7 @@ void LLDrawPoolTerrain::renderDeferred(S32 pass)
 
 void LLDrawPoolTerrain::beginShadowPass(S32 pass)
 {
-	LL_RECORD_BLOCK_TIME(FTM_SHADOW_TERRAIN);
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_SHADOW_TERRAIN);
 	LLFacePool::beginRenderPass(pass);
 	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 	gDeferredShadowProgram.bind();
@@ -261,14 +261,14 @@ void LLDrawPoolTerrain::beginShadowPass(S32 pass)
 
 void LLDrawPoolTerrain::endShadowPass(S32 pass)
 {
-	LL_RECORD_BLOCK_TIME(FTM_SHADOW_TERRAIN);
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_SHADOW_TERRAIN);
 	LLFacePool::endRenderPass(pass);
 	gDeferredShadowProgram.unbind();
 }
 
 void LLDrawPoolTerrain::renderShadow(S32 pass)
 {
-	LL_RECORD_BLOCK_TIME(FTM_SHADOW_TERRAIN);
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_SHADOW_TERRAIN);
 	if (mDrawFace.empty())
 	{
 		return;
@@ -850,7 +850,7 @@ void LLDrawPoolTerrain::renderOwnership()
 
 void LLDrawPoolTerrain::dirtyTextures(const std::set<LLViewerFetchedTexture*>& textures)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
 	LLViewerFetchedTexture* tex = LLViewerTextureManager::staticCastToFetchedTexture(mTexturep) ;
 	if (tex && textures.find(tex) != textures.end())
 	{
diff --git a/indra/newview/lldrawpoolwater.cpp b/indra/newview/lldrawpoolwater.cpp
index 62706feae3..0f2bcf4708 100644
--- a/indra/newview/lldrawpoolwater.cpp
+++ b/indra/newview/lldrawpoolwater.cpp
@@ -134,7 +134,7 @@ void LLDrawPoolWater::endPostDeferredPass(S32 pass)
 //===============================
 void LLDrawPoolWater::renderDeferred(S32 pass)
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_WATER);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_WATER);
 
     if (!LLPipeline::sRenderTransparentWater)
     {
@@ -152,7 +152,7 @@ void LLDrawPoolWater::renderDeferred(S32 pass)
 
 void LLDrawPoolWater::render(S32 pass)
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_WATER);
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_WATER);
 	if (mDrawFace.empty() || LLDrawable::getCurrentFrame() <= 1)
 	{
 		return;
@@ -334,7 +334,7 @@ void LLDrawPoolWater::render(S32 pass)
 // for low end hardware
 void LLDrawPoolWater::renderOpaqueLegacyWater()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
     LLVOSky *voskyp = gSky.mVOSkyp;
 
     if (voskyp == NULL)
@@ -443,7 +443,7 @@ void LLDrawPoolWater::renderOpaqueLegacyWater()
 
 void LLDrawPoolWater::renderReflection(LLFace* face)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
 	LLVOSky *voskyp = gSky.mVOSkyp;
 
 	if (!voskyp)
@@ -472,7 +472,7 @@ void LLDrawPoolWater::renderReflection(LLFace* face)
 
 void LLDrawPoolWater::renderWater()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
     if (!deferred_render)
     {
         gGL.setColorMask(true, true);
diff --git a/indra/newview/lldrawpoolwlsky.cpp b/indra/newview/lldrawpoolwlsky.cpp
index 80a65947f6..9873846669 100644
--- a/indra/newview/lldrawpoolwlsky.cpp
+++ b/indra/newview/lldrawpoolwlsky.cpp
@@ -566,11 +566,11 @@ void LLDrawPoolWLSky::renderHeavenlyBodies()
 
 void LLDrawPoolWLSky::renderDeferred(S32 pass)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_WL_SKY);
 	if (!gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_SKY))
 	{
 		return;
 	}
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_WL_SKY);
 
     const F32 camHeightLocal = LLEnvironment::instance().getCamHeight();
 
@@ -590,11 +590,11 @@ void LLDrawPoolWLSky::renderDeferred(S32 pass)
 
 void LLDrawPoolWLSky::render(S32 pass)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_WL_SKY);
 	if (!gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_SKY))
 	{
 		return;
 	}
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_WL_SKY);
 
     const F32 camHeightLocal = LLEnvironment::instance().getCamHeight();
     LLVector3 const & origin = LLViewerCamera::getInstance()->getOrigin();
diff --git a/indra/newview/llsettingsvo.cpp b/indra/newview/llsettingsvo.cpp
index 6415da4e4a..b6a3f68e63 100644
--- a/indra/newview/llsettingsvo.cpp
+++ b/indra/newview/llsettingsvo.cpp
@@ -966,7 +966,7 @@ void LLSettingsVOWater::applySpecial(void *ptarget, bool force)
 
 void LLSettingsVOWater::updateSettings()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
     // base class clears dirty flag so as to not trigger recursive update
     LLSettingsBase::updateSettings();
 
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index 0ec85b3831..bff3afe70e 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -4338,7 +4338,7 @@ void LLPipeline::renderGeom(LLCamera& camera, bool forceVBOUpdate)
 	}
 
 	{
-		LL_RECORD_BLOCK_TIME(FTM_POOLS);
+		LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWPOOL("pools"); //LL_RECORD_BLOCK_TIME(FTM_POOLS);
 		
 		// HACK: don't calculate local lights if we're rendering the HUD!
 		//    Removing this check will cause bad flickering when there are 
@@ -4374,7 +4374,7 @@ void LLPipeline::renderGeom(LLCamera& camera, bool forceVBOUpdate)
 			pool_set_t::iterator iter2 = iter1;
 			if (hasRenderType(poolp->getType()) && poolp->getNumPasses() > 0)
 			{
-				LL_RECORD_BLOCK_TIME(FTM_POOLRENDER);
+				LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWPOOL("pool render"); //LL_RECORD_BLOCK_TIME(FTM_POOLRENDER);
 
 				gGLLastMatrix = NULL;
 				gGL.loadMatrix(gGLModelView);
@@ -4504,14 +4504,14 @@ void LLPipeline::renderGeomDeferred(LLCamera& camera)
 {
 	LLAppViewer::instance()->pingMainloopTimeout("Pipeline:RenderGeomDeferred");
 
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_GEOMETRY);
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_GEOMETRY);
 	{
 		// SL-15709 -- NOTE: Tracy only allows one ZoneScoped per function.
 		// Solutions are:
 		// 1. Use a new scope
 		// 2. Use named zones
 		// 3. Use transient zones
-		LL_RECORD_BLOCK_TIME(FTM_DEFERRED_POOLS);
+		LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWPOOL("deferred pools"); //LL_RECORD_BLOCK_TIME(FTM_DEFERRED_POOLS);
 
 		LLGLEnable cull(GL_CULL_FACE);
 
@@ -4546,7 +4546,7 @@ void LLPipeline::renderGeomDeferred(LLCamera& camera)
 			pool_set_t::iterator iter2 = iter1;
 			if (hasRenderType(poolp->getType()) && poolp->getNumDeferredPasses() > 0)
 			{
-				LL_RECORD_BLOCK_TIME(FTM_DEFERRED_POOLRENDER);
+				LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWPOOL("deferred pool render"); //LL_RECORD_BLOCK_TIME(FTM_DEFERRED_POOLRENDER);
 
 				gGLLastMatrix = NULL;
 				gGL.loadMatrix(gGLModelView);
@@ -4601,7 +4601,7 @@ void LLPipeline::renderGeomDeferred(LLCamera& camera)
 
 void LLPipeline::renderGeomPostDeferred(LLCamera& camera, bool do_occlusion)
 {
-	LL_RECORD_BLOCK_TIME(FTM_POST_DEFERRED_POOLS);
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_POST_DEFERRED_POOLS);
 	U32 cur_type = 0;
 
 	LLGLEnable cull(GL_CULL_FACE);
@@ -4635,7 +4635,7 @@ void LLPipeline::renderGeomPostDeferred(LLCamera& camera, bool do_occlusion)
 		pool_set_t::iterator iter2 = iter1;
 		if (hasRenderType(poolp->getType()) && poolp->getNumPostDeferredPasses() > 0)
 		{
-			LL_RECORD_BLOCK_TIME(FTM_POST_DEFERRED_POOLRENDER);
+			LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWPOOL("deferred poolrender"); //LL_RECORD_BLOCK_TIME(FTM_POST_DEFERRED_POOLRENDER);
 
 			gGLLastMatrix = NULL;
 			gGL.loadMatrix(gGLModelView);
-- 
cgit v1.2.3


From 2178d9fa57acddc62123a764e8313b835140748d Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Thu, 13 Jan 2022 11:59:34 -0800
Subject: SL-16606: Add profiler category ENVIRONMENT

---
 indra/llinventory/llsettingsbase.cpp | 8 ++++----
 indra/llinventory/llsettingssky.cpp  | 8 ++++----
 indra/newview/llenvironment.cpp      | 6 +++---
 indra/newview/llsettingsvo.cpp       | 2 +-
 indra/newview/llviewerdisplay.cpp    | 2 +-
 indra/newview/llvosky.cpp            | 4 ++--
 6 files changed, 15 insertions(+), 15 deletions(-)

(limited to 'indra')

diff --git a/indra/llinventory/llsettingsbase.cpp b/indra/llinventory/llsettingsbase.cpp
index aed972b150..936b166409 100644
--- a/indra/llinventory/llsettingsbase.cpp
+++ b/indra/llinventory/llsettingsbase.cpp
@@ -683,7 +683,7 @@ bool LLSettingsBase::Validator::verifyStringLength(LLSD &value, U32, S32 length)
 //=========================================================================
 void LLSettingsBlender::update(const LLSettingsBase::BlendFactor& blendf)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_ENVIRONMENT;
     F64 res = setBlendFactor(blendf);
     llassert(res >= 0.0 && res <= 1.0);
     (void)res;
@@ -714,7 +714,7 @@ F64 LLSettingsBlender::setBlendFactor(const LLSettingsBase::BlendFactor& blendf_
 
 void LLSettingsBlender::triggerComplete()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_ENVIRONMENT;
     if (mTarget)
         mTarget->replaceSettings(mFinal->getSettings());
     LLSettingsBlender::ptr_t hold = shared_from_this();   // prevents this from deleting too soon
@@ -727,13 +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;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_ENVIRONMENT;
     return LLSettingsBase::BlendFactor(fmod((F64)spanpos, (F64)spanlen) / (F64)spanlen);
 }
 
 bool LLSettingsBlenderTimeDelta::applyTimeDelta(const LLSettingsBase::Seconds& timedelta)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_ENVIRONMENT;
     mTimeSpent += timedelta;
 
     if (mTimeSpent > mBlendSpan)
diff --git a/indra/llinventory/llsettingssky.cpp b/indra/llinventory/llsettingssky.cpp
index 979a284744..83a92f08d0 100644
--- a/indra/llinventory/llsettingssky.cpp
+++ b/indra/llinventory/llsettingssky.cpp
@@ -439,7 +439,7 @@ void LLSettingsSky::replaceWithSky(LLSettingsSky::ptr_t pother)
 
 void LLSettingsSky::blend(const LLSettingsBase::ptr_t &end, F64 blendf) 
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_ENVIRONMENT;
     llassert(getSettingsType() == end->getSettingsType());
 
     LLSettingsSky::ptr_t other = PTR_NAMESPACE::dynamic_pointer_cast<LLSettingsSky>(end);
@@ -935,7 +935,7 @@ LLSD LLSettingsSky::translateLegacySettings(const LLSD& legacy)
 
 void LLSettingsSky::updateSettings()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_ENVIRONMENT;
 
     // base class clears dirty flag so as to not trigger recursive update
     LLSettingsBase::updateSettings();
@@ -1018,7 +1018,7 @@ LLColor3 LLSettingsSky::getLightDiffuse() const
 
 LLColor3 LLSettingsSky::getColor(const std::string& key, const LLColor3& default_value) const
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_ENVIRONMENT;
     if (mSettings.has(SETTING_LEGACY_HAZE) && mSettings[SETTING_LEGACY_HAZE].has(key))
     {
         return LLColor3(mSettings[SETTING_LEGACY_HAZE][key]);
@@ -1032,7 +1032,7 @@ LLColor3 LLSettingsSky::getColor(const std::string& key, const LLColor3& default
 
 F32 LLSettingsSky::getFloat(const std::string& key, F32 default_value) const
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_ENVIRONMENT;
     if (mSettings.has(SETTING_LEGACY_HAZE) && mSettings[SETTING_LEGACY_HAZE].has(key))
     {
         return mSettings[SETTING_LEGACY_HAZE][key].asReal();
diff --git a/indra/newview/llenvironment.cpp b/indra/newview/llenvironment.cpp
index 4bec7fa111..f232ca47e0 100644
--- a/indra/newview/llenvironment.cpp
+++ b/indra/newview/llenvironment.cpp
@@ -1470,7 +1470,7 @@ LLEnvironment::DayInstance::ptr_t LLEnvironment::getSharedEnvironmentInstance()
 
 void LLEnvironment::updateEnvironment(LLSettingsBase::Seconds transition, bool forced)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_ENVIRONMENT;
     DayInstance::ptr_t pinstance = getSelectedEnvironmentInstance();
 
     if ((mCurrentEnvironment != pinstance) || forced)
@@ -1596,7 +1596,7 @@ LLVector4 LLEnvironment::getRotatedLightNorm() const
 //-------------------------------------------------------------------------
 void LLEnvironment::update(const LLViewerCamera * cam)
 {
-    LL_RECORD_BLOCK_TIME(FTM_ENVIRONMENT_UPDATE);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_ENVIRONMENT; //LL_RECORD_BLOCK_TIME(FTM_ENVIRONMENT_UPDATE);
     //F32Seconds now(LLDate::now().secondsSinceEpoch());
     static LLFrameTimer timer;
 
@@ -2657,7 +2657,7 @@ LLEnvironment::DayInstance::ptr_t LLEnvironment::DayInstance::clone() const
 
 bool LLEnvironment::DayInstance::applyTimeDelta(const LLSettingsBase::Seconds& delta)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_ENVIRONMENT;
     ptr_t keeper(shared_from_this());   // makes sure that this does not go away while it is being worked on.
 
     bool changed(false);
diff --git a/indra/newview/llsettingsvo.cpp b/indra/newview/llsettingsvo.cpp
index b6a3f68e63..217d45de68 100644
--- a/indra/newview/llsettingsvo.cpp
+++ b/indra/newview/llsettingsvo.cpp
@@ -637,7 +637,7 @@ LLSD LLSettingsVOSky::convertToLegacy(const LLSettingsSky::ptr_t &psky, bool isA
 //-------------------------------------------------------------------------
 void LLSettingsVOSky::updateSettings()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_ENVIRONMENT;
     LLSettingsSky::updateSettings();
     LLVector3 sun_direction  = getSunDirection();
     LLVector3 moon_direction = getMoonDirection();
diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp
index f28edd10c5..e2c831bb1c 100644
--- a/indra/newview/llviewerdisplay.cpp
+++ b/indra/newview/llviewerdisplay.cpp
@@ -848,7 +848,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 
 		{
 			LLAppViewer::instance()->pingMainloopTimeout("Display:Sky");
-			LL_RECORD_BLOCK_TIME(FTM_UPDATE_SKY);	
+			LL_PROFILE_ZONE_NAMED_CATEGORY_ENVIRONMENT("update sky"); //LL_RECORD_BLOCK_TIME(FTM_UPDATE_SKY);	
 			gSky.updateSky();
 		}
 
diff --git a/indra/newview/llvosky.cpp b/indra/newview/llvosky.cpp
index 2e6d8adc05..01312d65cc 100644
--- a/indra/newview/llvosky.cpp
+++ b/indra/newview/llvosky.cpp
@@ -510,7 +510,7 @@ void LLVOSky::cacheEnvironment(LLSettingsSky::ptr_t psky,AtmosphericsVars& atmos
 
 void LLVOSky::calc()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_ENVIRONMENT;
     LLSettingsSky::ptr_t psky = LLEnvironment::instance().getCurrentSky();
     cacheEnvironment(psky,m_atmosphericsVars);
 
@@ -681,7 +681,7 @@ bool LLVOSky::updateSky()
 		return TRUE;
 	}
 
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_ENVIRONMENT;
 
 	static S32 next_frame = 0;
 
-- 
cgit v1.2.3


From 917e3caec64217bd91036a9159a5eaecb5fa4d51 Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Thu, 13 Jan 2022 12:01:31 -0800
Subject: SL-16606: Add profiler category FACE

---
 indra/newview/llface.cpp | 66 ++++++++++++++++++++++++------------------------
 1 file changed, 33 insertions(+), 33 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp
index 54a043482b..b54c2105dd 100644
--- a/indra/newview/llface.cpp
+++ b/indra/newview/llface.cpp
@@ -129,7 +129,7 @@ void planarProjection(LLVector2 &tc, const LLVector4a& normal,
 
 void LLFace::init(LLDrawable* drawablep, LLViewerObject* objp)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_FACE;
 	mLastUpdateTime = gFrameTimeSeconds;
 	mLastMoveTime = 0.f;
 	mLastSkinTime = gFrameTimeSeconds;
@@ -237,7 +237,7 @@ void LLFace::setPool(LLFacePool* pool)
 
 void LLFace::setPool(LLFacePool* new_pool, LLViewerTexture *texturep)
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_FACE
 
 	if (!new_pool)
 	{
@@ -318,7 +318,7 @@ void LLFace::setSpecularMap(LLViewerTexture* tex)
 
 void LLFace::dirtyTexture()
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_FACE
 
 	LLDrawable* drawablep = getDrawable();
 
@@ -535,7 +535,7 @@ void LLFace::updateCenterAgent()
 
 void LLFace::renderSelected(LLViewerTexture *imagep, const LLColor4& color)
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_FACE
 
 	if (mDrawablep == NULL || mDrawablep->getSpatialGroup() == NULL)
 	{
@@ -608,7 +608,7 @@ void LLFace::renderSelected(LLViewerTexture *imagep, const LLColor4& color)
 
 void renderFace(LLDrawable* drawable, LLFace *face)
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_FACE
 
     LLVOVolume* vobj = drawable->getVOVolume();
     if (vobj)
@@ -896,7 +896,7 @@ 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
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_FACE
 
 	//get bounding box
 	if (mDrawablep->isState(LLDrawable::REBUILD_VOLUME | LLDrawable::REBUILD_POSITION | LLDrawable::REBUILD_RIGGED))
@@ -1205,7 +1205,7 @@ bool LLFace::canRenderAsMask()
 //static 
 void LLFace::cacheFaceInVRAM(const LLVolumeFace& vf)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_FACE;
 	U32 mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 |
 				LLVertexBuffer::MAP_TANGENT | LLVertexBuffer::MAP_NORMAL;
 	
@@ -1273,7 +1273,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 								const U16 &index_offset,
 								bool force_rebuild)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_FACE;
 	llassert(verify());
 
 	if (volume.getNumVolumeFaces() <= f) {
@@ -1416,7 +1416,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 	// INDICES
 	if (full_rebuild)
 	{
-        LL_PROFILE_ZONE_NAMED("getGeometryVolume - indices");
+        LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - indices");
 		mVertexBuffer->getIndexStrider(indicesp, mIndicesIndex, mIndicesCount, map_range);
 
 		volatile __m128i* dst = (__m128i*) indicesp.get();
@@ -1432,7 +1432,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 		}
 
 		{
-            LL_PROFILE_ZONE_NAMED("getGeometryVolume - indices tail");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - indices tail");
 			U16* idx = (U16*) dst;
 
 			for (S32 i = end*8; i < num_indices; ++i)
@@ -1501,7 +1501,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 
     if (rebuild_normal || rebuild_tangent)
     { //override mat_normal with inverse of skin->mBindShapeMatrix
-        LL_PROFILE_ZONE_NAMED("getGeometryVolume - norm mat override");
+        LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - norm mat override");
         if (rigged)
         {
             if (skin == nullptr)
@@ -1532,7 +1532,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 	{ //use transform feedback to pack vertex buffer
 		//gGLDebugLoggingEnabled = TRUE;
 
-        LL_PROFILE_ZONE_NAMED("getGeometryVolume - transform feedback");
+        LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - transform feedback");
 		LLGLEnable discard(GL_RASTERIZER_DISCARD);
 		LLVertexBuffer* buff = (LLVertexBuffer*) vf.mVertexBuffer.get();
 
@@ -1550,7 +1550,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 
 		if (rebuild_pos)
 		{
-            LL_PROFILE_ZONE_NAMED("getGeometryVolume - tf position");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - tf position");
 			gTransformPositionProgram.bind();
 
 			mVertexBuffer->bindForFeedback(0, LLVertexBuffer::TYPE_VERTEX, mGeomIndex, mGeomCount);
@@ -1575,7 +1575,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 
 		if (rebuild_color)
 		{
-            LL_PROFILE_ZONE_NAMED("getGeometryVolume - tf color");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - tf color");
 			gTransformColorProgram.bind();
 			
 			mVertexBuffer->bindForFeedback(0, LLVertexBuffer::TYPE_COLOR, mGeomIndex, mGeomCount);
@@ -1591,7 +1591,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 
 		if (rebuild_emissive)
 		{
-            LL_PROFILE_ZONE_NAMED("getGeometryVolume - tf emissive");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - tf emissive");
 			gTransformColorProgram.bind();
 			
 			mVertexBuffer->bindForFeedback(0, LLVertexBuffer::TYPE_EMISSIVE, mGeomIndex, mGeomCount);
@@ -1612,7 +1612,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 
 		if (rebuild_normal)
 		{
-            LL_PROFILE_ZONE_NAMED("getGeometryVolume - tf normal");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - tf normal");
 			gTransformNormalProgram.bind();
 			
 			mVertexBuffer->bindForFeedback(0, LLVertexBuffer::TYPE_NORMAL, mGeomIndex, mGeomCount);
@@ -1625,7 +1625,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 
 		if (rebuild_tangent)
 		{
-            LL_PROFILE_ZONE_NAMED("getGeometryVolume - tf tangent");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - tf tangent");
 			gTransformTangentProgram.bind();
 			
 			mVertexBuffer->bindForFeedback(0, LLVertexBuffer::TYPE_TANGENT, mGeomIndex, mGeomCount);
@@ -1638,7 +1638,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 
 		if (rebuild_tcoord)
 		{
-            LL_PROFILE_ZONE_NAMED("getGeometryVolume - tf tcoord");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - tf tcoord");
 			gTransformTexCoordProgram.bind();
 			
 			mVertexBuffer->bindForFeedback(0, LLVertexBuffer::TYPE_TEXCOORD0, mGeomIndex, mGeomCount);
@@ -1677,7 +1677,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 
 		if (rebuild_tcoord)
 		{
-            LL_PROFILE_ZONE_NAMED("getGeometryVolume - tcoord");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - tcoord");
 									
 			//bump setup
 			LLVector4a binormal_dir( -sin_ang, cos_ang, 0.f );
@@ -1800,18 +1800,18 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 
 				if (texgen != LLTextureEntry::TEX_GEN_PLANAR)
 				{
-                    LL_PROFILE_ZONE_NAMED("getGeometryVolume - texgen");
+                    LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - texgen");
 					if (!do_tex_mat)
 					{
 						if (!do_xform)
 						{
-                            LL_PROFILE_ZONE_NAMED("ggv - texgen 1");
+                            LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("ggv - texgen 1");
 							S32 tc_size = (num_vertices*2*sizeof(F32)+0xF) & ~0xF;
 							LLVector4a::memcpyNonAliased16((F32*) tex_coords0.get(), (F32*) vf.mTexCoords, tc_size);
 						}
 						else
 						{
-                            LL_PROFILE_ZONE_NAMED("ggv - texgen 2");
+                            LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("ggv - texgen 2");
 							F32* dst = (F32*) tex_coords0.get();
 							LLVector4a* src = (LLVector4a*) vf.mTexCoords;
 
@@ -1862,7 +1862,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 				}
 				else
 				{ //no bump, tex gen planar
-                    LL_PROFILE_ZONE_NAMED("getGeometryVolume - texgen planar");
+                    LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - texgen planar");
 					if (do_tex_mat)
 					{
 						for (S32 i = 0; i < num_vertices; i++)
@@ -1907,7 +1907,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 			}
 			else
 			{ //bump mapped or has material, just do the whole expensive loop
-                LL_PROFILE_ZONE_NAMED("getGeometryVolume - texgen default");
+                LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - texgen default");
 
 				std::vector<LLVector2> bump_tc;
 		
@@ -2122,7 +2122,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 
 		if (rebuild_normal)
 		{
-            LL_PROFILE_ZONE_NAMED("getGeometryVolume - normal");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - normal");
 
 			mVertexBuffer->getNormalStrider(norm, mGeomIndex, mGeomCount, map_range);
 			F32* normals = (F32*) norm.get();
@@ -2145,7 +2145,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 		
 		if (rebuild_tangent)
 		{
-            LL_PROFILE_ZONE_NAMED("getGeometryVolume - tangent");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - tangent");
 			mVertexBuffer->getTangentStrider(tangent, mGeomIndex, mGeomCount, map_range);
 			F32* tangents = (F32*) tangent.get();
 			
@@ -2178,7 +2178,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 	
 		if (rebuild_weights && vf.mWeights)
 		{
-            LL_PROFILE_ZONE_NAMED("getGeometryVolume - weight");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - weight");
 			mVertexBuffer->getWeight4Strider(wght, mGeomIndex, mGeomCount, map_range);
 			F32* weights = (F32*) wght.get();
 			LLVector4a::memcpyNonAliased16(weights, (F32*) vf.mWeights, num_vertices*4*sizeof(F32));
@@ -2190,7 +2190,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 
 		if (rebuild_color && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_COLOR) )
 		{
-            LL_PROFILE_ZONE_NAMED("getGeometryVolume - color");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - color");
 			mVertexBuffer->getColorStrider(colors, mGeomIndex, mGeomCount, map_range);
 
 			LLVector4a src;
@@ -2221,7 +2221,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 
 		if (rebuild_emissive)
 		{
-            LL_PROFILE_ZONE_NAMED("getGeometryVolume - emissive");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - emissive");
 			LLStrider<LLColor4U> emissive;
 			mVertexBuffer->getEmissiveStrider(emissive, mGeomIndex, mGeomCount, map_range);
 
@@ -2352,7 +2352,7 @@ F32 LLFace::getTextureVirtualSize()
 
 BOOL LLFace::calcPixelArea(F32& cos_angle_to_view_dir, F32& radius)
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_FACE
 
 	//VECTORIZE THIS
 	//get area of circle around face
@@ -2633,7 +2633,7 @@ const LLMatrix4& LLFace::getRenderMatrix() const
 
 S32 LLFace::renderElements(const U16 *index_array) const
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_FACE
 
 	S32 ret = 0;
 	
@@ -2654,7 +2654,7 @@ S32 LLFace::renderElements(const U16 *index_array) const
 
 S32 LLFace::renderIndexed()
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_FACE
 
 	if(mDrawablep == NULL || mDrawPoolp == NULL)
 	{
@@ -2666,7 +2666,7 @@ S32 LLFace::renderIndexed()
 
 S32 LLFace::renderIndexed(U32 mask)
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_FACE
 
 	if (mVertexBuffer.isNull())
 	{
-- 
cgit v1.2.3


From 3a9ce9f22667cf3e0a1d6def9c478a66310ef0ad Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Thu, 13 Jan 2022 12:19:23 -0800
Subject: SL-16606: Add profiler category LLSD

---
 indra/llcommon/llsd.cpp | 22 +++++++++++-----------
 indra/llcommon/llsd.h   | 14 +++++++-------
 indra/llxml/llcontrol.h |  2 +-
 3 files changed, 19 insertions(+), 19 deletions(-)

(limited to 'indra')

diff --git a/indra/llcommon/llsd.cpp b/indra/llcommon/llsd.cpp
index 605f6bf0e3..807b3d13f8 100644
--- a/indra/llcommon/llsd.cpp
+++ b/indra/llcommon/llsd.cpp
@@ -400,7 +400,7 @@ namespace
 	
 	ImplMap& ImplMap::makeMap(LLSD::Impl*& var)
 	{
-        LL_PROFILE_ZONE_SCOPED;
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD;
 		if (shared())
 		{
 			ImplMap* i = new ImplMap(mData);
@@ -415,21 +415,21 @@ namespace
 	
 	bool ImplMap::has(const LLSD::String& k) const
 	{
-        LL_PROFILE_ZONE_SCOPED;
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD;
 		DataMap::const_iterator i = mData.find(k);
 		return i != mData.end();
 	}
 	
 	LLSD ImplMap::get(const LLSD::String& k) const
 	{
-        LL_PROFILE_ZONE_SCOPED;
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD;
 		DataMap::const_iterator i = mData.find(k);
 		return (i != mData.end()) ? i->second : LLSD();
 	}
 
 	LLSD ImplMap::getKeys() const
 	{ 
-        LL_PROFILE_ZONE_SCOPED;
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD;
 		LLSD keys = LLSD::emptyArray();
 		DataMap::const_iterator iter = mData.begin();
 		while (iter != mData.end())
@@ -442,13 +442,13 @@ namespace
 
 	void ImplMap::insert(const LLSD::String& k, const LLSD& v)
 	{
-        LL_PROFILE_ZONE_SCOPED;
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD;
 		mData.insert(DataMap::value_type(k, v));
 	}
 	
 	void ImplMap::erase(const LLSD::String& k)
 	{
-        LL_PROFILE_ZONE_SCOPED;
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD;
 		mData.erase(k);
 	}
 	
@@ -690,7 +690,7 @@ const LLSD::Impl& LLSD::Impl::safe(const Impl* impl)
 
 ImplMap& LLSD::Impl::makeMap(Impl*& var)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD;
 	ImplMap* im = new ImplMap;
 	reset(var, im);
 	return *im;
@@ -896,12 +896,12 @@ void LLSD::erase(const String& k)		{ makeMap(impl).erase(k); }
 
 LLSD& LLSD::operator[](const String& k)
 { 
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD;
     return makeMap(impl).ref(k); 
 }
 const LLSD& LLSD::operator[](const String& k) const
 { 
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD;
     return safe(impl).ref(k); 
 }
 
@@ -928,12 +928,12 @@ void LLSD::erase(Integer i)				{ makeArray(impl).erase(i); }
 
 LLSD& LLSD::operator[](Integer i)
 { 
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD;
     return makeArray(impl).ref(i); 
 }
 const LLSD& LLSD::operator[](Integer i) const
 { 
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD;
     return safe(impl).ref(i);
 }
 
diff --git a/indra/llcommon/llsd.h b/indra/llcommon/llsd.h
index b8ddf21596..24cb9bbce1 100644
--- a/indra/llcommon/llsd.h
+++ b/indra/llcommon/llsd.h
@@ -290,16 +290,16 @@ public:
 		LLSD& with(const String&, const LLSD&);
 		
 		LLSD& operator[](const String&);
-		LLSD& operator[](const char* c)			
-        { 
-            LL_PROFILE_ZONE_SCOPED;
-            return (*this)[String(c)]; 
+		LLSD& operator[](const char* c)
+        {
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD;
+            return (*this)[String(c)];
         }
 		const LLSD& operator[](const String&) const;
 		const LLSD& operator[](const char* c) const	
-        { 
-            LL_PROFILE_ZONE_SCOPED;
-            return (*this)[String(c)]; 
+        {
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD;
+            return (*this)[String(c)];
         }
 	//@}
 	
diff --git a/indra/llxml/llcontrol.h b/indra/llxml/llcontrol.h
index 088502c017..0839c02c50 100644
--- a/indra/llxml/llcontrol.h
+++ b/indra/llxml/llcontrol.h
@@ -247,7 +247,7 @@ public:
 	// generic getter
 	template<typename T> T get(const std::string& name)
 	{
-        LL_PROFILE_ZONE_SCOPED;
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD;
 		LLControlVariable* control = getControl(name);
 		LLSD value;
 		eControlType type = TYPE_COUNT;
-- 
cgit v1.2.3


From 6e306cd7ce77e75c98205360b7d8b38531319900 Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Thu, 13 Jan 2022 12:20:12 -0800
Subject: SL-16606: Add profiler category LOGGING

---
 indra/llcommon/llerror.cpp | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)

(limited to 'indra')

diff --git a/indra/llcommon/llerror.cpp b/indra/llcommon/llerror.cpp
index 17a5ec5776..2fae9fdfaa 100644
--- a/indra/llcommon/llerror.cpp
+++ b/indra/llcommon/llerror.cpp
@@ -109,7 +109,7 @@ namespace {
 		virtual void recordMessage(LLError::ELevel level,
 									const std::string& message) override
 		{
-            LL_PROFILE_ZONE_SCOPED
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING
 			int syslogPriority = LOG_CRIT;
 			switch (level) {
 				case LLError::LEVEL_DEBUG:	syslogPriority = LOG_DEBUG;	break;
@@ -167,7 +167,7 @@ namespace {
         virtual void recordMessage(LLError::ELevel level,
                                     const std::string& message) override
         {
-            LL_PROFILE_ZONE_SCOPED
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING
             if (LLError::getAlwaysFlush())
             {
                 mFile << message << std::endl;
@@ -234,7 +234,7 @@ namespace {
 		virtual void recordMessage(LLError::ELevel level,
 					   const std::string& message) override
 		{
-            LL_PROFILE_ZONE_SCOPED
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING
             // The default colors for error, warn and debug are now a bit more pastel
             // and easier to read on the default (black) terminal background but you 
             // now have the option to set the color of each via an environment variables:
@@ -274,7 +274,7 @@ namespace {
 
         LL_FORCE_INLINE void writeANSI(const std::string& ansi_code, const std::string& message)
 		{
-            LL_PROFILE_ZONE_SCOPED
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING
             static std::string s_ansi_bold = createBoldANSI();  // bold text
             static std::string s_ansi_reset = createResetANSI();  // reset
 			// ANSI color code escape sequence, message, and reset in one fprintf call
@@ -311,7 +311,7 @@ namespace {
 		virtual void recordMessage(LLError::ELevel level,
 								   const std::string& message) override
 		{
-            LL_PROFILE_ZONE_SCOPED
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING
 			mBuffer->addLine(message);
 		}
 	
@@ -338,7 +338,7 @@ namespace {
 		virtual void recordMessage(LLError::ELevel level,
 								   const std::string& message) override
 		{
-            LL_PROFILE_ZONE_SCOPED
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING
 			debugger_print(message);
 		}
 	};
@@ -1220,7 +1220,7 @@ namespace
 
 	void writeToRecorders(const LLError::CallSite& site, const std::string& message)
 	{
-        LL_PROFILE_ZONE_SCOPED
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING
 		LLError::ELevel level = site.mLevel;
 		SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig();
 
@@ -1355,7 +1355,7 @@ namespace LLError
 
 	bool Log::shouldLog(CallSite& site)
 	{
-        LL_PROFILE_ZONE_SCOPED
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING
 		LLMutexTrylock lock(getMutex<LOG_MUTEX>(), 5);
 		if (!lock.isLocked())
 		{
@@ -1400,7 +1400,7 @@ namespace LLError
 
 	void Log::flush(const std::ostringstream& out, const CallSite& site)
 	{
-        LL_PROFILE_ZONE_SCOPED
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING
 		LLMutexTrylock lock(getMutex<LOG_MUTEX>(),5);
 		if (!lock.isLocked())
 		{
-- 
cgit v1.2.3


From c647acfc4b6f9ac786d80c45aff322ee1ca10281 Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Thu, 13 Jan 2022 12:21:27 -0800
Subject: SL-16606: Add profiler category MATERIAL

---
 indra/newview/lldrawpoolmaterials.cpp | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/lldrawpoolmaterials.cpp b/indra/newview/lldrawpoolmaterials.cpp
index fd5850084b..135770c99c 100644
--- a/indra/newview/lldrawpoolmaterials.cpp
+++ b/indra/newview/lldrawpoolmaterials.cpp
@@ -54,6 +54,8 @@ S32 LLDrawPoolMaterials::getNumDeferredPasses()
 
 void LLDrawPoolMaterials::beginDeferredPass(S32 pass)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_MATERIAL;
+
     bool rigged = false;
     if (pass >= 12)
     { 
@@ -108,13 +110,11 @@ void LLDrawPoolMaterials::beginDeferredPass(S32 pass)
     }
 
 	diffuse_channel = mShader->enableTexture(LLShaderMgr::DIFFUSE_MAP);
-		
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_MATERIALS);
 }
 
 void LLDrawPoolMaterials::endDeferredPass(S32 pass)
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_MATERIALS);
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_MATERIAL;
 
 	mShader->unbind();
 
@@ -123,7 +123,7 @@ void LLDrawPoolMaterials::endDeferredPass(S32 pass)
 
 void LLDrawPoolMaterials::renderDeferred(S32 pass)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_MATERIAL;
 	static const U32 type_list[] = 
 	{
 		LLRenderPass::PASS_MATERIAL,
@@ -187,7 +187,7 @@ void LLDrawPoolMaterials::renderDeferred(S32 pass)
 		mShader->uniform1f(LLShaderMgr::EMISSIVE_BRIGHTNESS, params.mFullbright ? 1.f : 0.f);
 
         {
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_MATERIAL;
             pushMaterialsBatch(params, mask, rigged);
         }
 	}
@@ -205,7 +205,7 @@ void LLDrawPoolMaterials::bindNormalMap(LLViewerTexture* tex)
 
 void LLDrawPoolMaterials::pushMaterialsBatch(LLDrawInfo& params, U32 mask, bool rigged)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_MATERIAL;
 	applyModelMatrix(params);
 	
 	bool tex_setup = false;
-- 
cgit v1.2.3


From 36f037e2cb512923040972c69c00bbbed327489f Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Thu, 13 Jan 2022 12:24:07 -0800
Subject: SL-16606: Add profiler category MEDIA

---
 indra/newview/llviewermedia.cpp | 20 ++++++++++----------
 1 file changed, 10 insertions(+), 10 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp
index 0a0a3f905a..63f57e81cc 100644
--- a/indra/newview/llviewermedia.cpp
+++ b/indra/newview/llviewermedia.cpp
@@ -649,7 +649,7 @@ void LLViewerMedia::onIdle(void *dummy_arg)
 //////////////////////////////////////////////////////////////////////////////////////////
 void LLViewerMedia::updateMedia(void *dummy_arg)
 {
-	LL_RECORD_BLOCK_TIME(FTM_MEDIA_UPDATE);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_MEDIA; //LL_RECORD_BLOCK_TIME(FTM_MEDIA_UPDATE);
 
 	// Enable/disable the plugin read thread
 	LLPluginProcessParent::setUseReadThread(gSavedSettings.getBOOL("PluginUseReadThread"));
@@ -666,7 +666,7 @@ void LLViewerMedia::updateMedia(void *dummy_arg)
 	impl_list::iterator end = sViewerMediaImplList.end();
 
 	{
-		LL_RECORD_BLOCK_TIME(FTM_MEDIA_UPDATE_INTEREST);
+        LL_PROFILE_ZONE_NAMED_CATEGORY_MEDIA("media update interest"); //LL_RECORD_BLOCK_TIME(FTM_MEDIA_UPDATE_INTEREST);
 		for(; iter != end;)
 		{
 			LLViewerMediaImpl* pimpl = *iter++;
@@ -678,12 +678,12 @@ void LLViewerMedia::updateMedia(void *dummy_arg)
 	// Let the spare media source actually launch
 	if(mSpareBrowserMediaSource)
 	{
-		LL_RECORD_BLOCK_TIME(FTM_MEDIA_SPARE_IDLE);
+        LL_PROFILE_ZONE_NAMED_CATEGORY_MEDIA("media spare idle"); //LL_RECORD_BLOCK_TIME(FTM_MEDIA_SPARE_IDLE);
 		mSpareBrowserMediaSource->idle();
 	}
 
 	{
-		LL_RECORD_BLOCK_TIME(FTM_MEDIA_SORT);
+        LL_PROFILE_ZONE_NAMED_CATEGORY_MEDIA("media sort"); //LL_RECORD_BLOCK_TIME(FTM_MEDIA_SORT);
 		// Sort the static instance list using our interest criteria
 		sViewerMediaImplList.sort(priorityComparitor);
 	}
@@ -715,7 +715,7 @@ void LLViewerMedia::updateMedia(void *dummy_arg)
 	// If max_normal + max_low is less than max_instances, things will tend to get unloaded instead of being set to slideshow.
 
 	{
-		LL_RECORD_BLOCK_TIME(FTM_MEDIA_MISC);
+        LL_PROFILE_ZONE_NAMED_CATEGORY_MEDIA("media misc"); //LL_RECORD_BLOCK_TIME(FTM_MEDIA_MISC);
 		for(; iter != end; iter++)
 		{
 			LLViewerMediaImpl* pimpl = *iter;
@@ -900,7 +900,7 @@ void LLViewerMedia::updateMedia(void *dummy_arg)
 	}
 	else
 	{
-		LL_RECORD_BLOCK_TIME(FTM_MEDIA_SORT2);
+        LL_PROFILE_ZONE_NAMED_CATEGORY_MEDIA("media sort2"); // LL_RECORD_BLOCK_TIME(FTM_MEDIA_SORT2);
 		// Use a distance-based sort for proximity values.
 		std::stable_sort(proximity_order.begin(), proximity_order.end(), proximity_comparitor);
 	}
@@ -2798,7 +2798,7 @@ static LLTrace::BlockTimerStatHandle FTM_MEDIA_SET_SUBIMAGE("Set Subimage");
 
 void LLViewerMediaImpl::update()
 {
-	LL_RECORD_BLOCK_TIME(FTM_MEDIA_DO_UPDATE);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_MEDIA; //LL_RECORD_BLOCK_TIME(FTM_MEDIA_DO_UPDATE);
 	if(mMediaSource == NULL)
 	{
 		if(mPriority == LLPluginClassMedia::PRIORITY_UNLOADED)
@@ -2896,7 +2896,7 @@ void LLViewerMediaImpl::update()
 
 				U8* data = NULL;
 				{
-					LL_RECORD_BLOCK_TIME(FTM_MEDIA_GET_DATA);
+					LL_PROFILE_ZONE_NAMED_CATEGORY_MEDIA("media get data"); //LL_RECORD_BLOCK_TIME(FTM_MEDIA_GET_DATA);
 					data = mMediaSource->getBitsData();
 				}
 
@@ -2907,7 +2907,7 @@ void LLViewerMediaImpl::update()
 					data += ( y_pos * mMediaSource->getTextureDepth() );
 
 					{
-						LL_RECORD_BLOCK_TIME(FTM_MEDIA_SET_SUBIMAGE);
+						LL_PROFILE_ZONE_NAMED_CATEGORY_MEDIA("media set subimage"); //LL_RECORD_BLOCK_TIME(FTM_MEDIA_SET_SUBIMAGE);
 									placeholder_image->setSubImage(
 									data,
 									mMediaSource->getBitsWidth(),
@@ -3515,7 +3515,7 @@ static LLTrace::BlockTimerStatHandle FTM_MEDIA_CALCULATE_INTEREST("Calculate Int
 
 void LLViewerMediaImpl::calculateInterest()
 {
-	LL_RECORD_BLOCK_TIME(FTM_MEDIA_CALCULATE_INTEREST);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_MEDIA; //LL_RECORD_BLOCK_TIME(FTM_MEDIA_CALCULATE_INTEREST);
 	LLViewerMediaTexture* texture = LLViewerTextureManager::findMediaTexture( mTextureId );
 
 	if(texture != NULL)
-- 
cgit v1.2.3


From 9f2be2a0547f5e827a91cbcd9162cbe8f9cdfb53 Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Thu, 13 Jan 2022 12:25:21 -0800
Subject: SL-16606: Add profiler category MEMORY

---
 indra/llcommon/llcommon.cpp |  4 ++--
 indra/llcommon/llmemory.h   | 20 ++++++++++----------
 2 files changed, 12 insertions(+), 12 deletions(-)

(limited to 'indra')

diff --git a/indra/llcommon/llcommon.cpp b/indra/llcommon/llcommon.cpp
index 25a809dad2..d2c4e66160 100644
--- a/indra/llcommon/llcommon.cpp
+++ b/indra/llcommon/llcommon.cpp
@@ -42,7 +42,7 @@ void *operator new(size_t size)
     void* ptr;
     if (gProfilerEnabled)
     {
-        LL_PROFILE_ZONE_SCOPED;
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY;
         ptr = (malloc)(size);
     }
     else
@@ -62,7 +62,7 @@ void operator delete(void *ptr) noexcept
     TracyFree(ptr);
     if (gProfilerEnabled)
     {
-        LL_PROFILE_ZONE_SCOPED;
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY;
         (free)(ptr);
     }
     else
diff --git a/indra/llcommon/llmemory.h b/indra/llcommon/llmemory.h
index 41023b4ba4..ac6c969d70 100644
--- a/indra/llcommon/llmemory.h
+++ b/indra/llcommon/llmemory.h
@@ -136,7 +136,7 @@ public:                                     \
 #else
 	inline void* ll_aligned_malloc_fallback( size_t size, int align )
 	{
-        LL_PROFILE_ZONE_SCOPED;
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY;
 	#if defined(LL_WINDOWS)
         void* ret = _aligned_malloc(size, align);
 	#else
@@ -157,7 +157,7 @@ public:                                     \
 
 	inline void ll_aligned_free_fallback( void* ptr )
 	{
-        LL_PROFILE_ZONE_SCOPED;
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY;
         LL_PROFILE_FREE(ptr);
 	#if defined(LL_WINDOWS)
 		_aligned_free(ptr);
@@ -174,7 +174,7 @@ public:                                     \
 
 inline void* ll_aligned_malloc_16(size_t size) // returned hunk MUST be freed with ll_aligned_free_16().
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY;
 #if defined(LL_WINDOWS)
 	void* ret = _aligned_malloc(size, 16);
 #elif defined(LL_DARWIN)
@@ -190,7 +190,7 @@ inline void* ll_aligned_malloc_16(size_t size) // returned hunk MUST be freed wi
 
 inline void ll_aligned_free_16(void *p)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY;
     LL_PROFILE_FREE(p);
 #if defined(LL_WINDOWS)
 	_aligned_free(p);
@@ -203,7 +203,7 @@ inline void ll_aligned_free_16(void *p)
 
 inline void* ll_aligned_realloc_16(void* ptr, size_t size, size_t old_size) // returned hunk MUST be freed with ll_aligned_free_16().
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY;
     LL_PROFILE_FREE(ptr);
 #if defined(LL_WINDOWS)
 	void* ret = _aligned_realloc(ptr, size, 16);
@@ -228,7 +228,7 @@ inline void* ll_aligned_realloc_16(void* ptr, size_t size, size_t old_size) // r
 
 inline void* ll_aligned_malloc_32(size_t size) // returned hunk MUST be freed with ll_aligned_free_32().
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY;
 #if defined(LL_WINDOWS)
 	void* ret = _aligned_malloc(size, 32);
 #elif defined(LL_DARWIN)
@@ -244,7 +244,7 @@ inline void* ll_aligned_malloc_32(size_t size) // returned hunk MUST be freed wi
 
 inline void ll_aligned_free_32(void *p)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY;
     LL_PROFILE_FREE(p);
 #if defined(LL_WINDOWS)
 	_aligned_free(p);
@@ -259,7 +259,7 @@ inline void ll_aligned_free_32(void *p)
 template<size_t ALIGNMENT>
 LL_FORCE_INLINE void* ll_aligned_malloc(size_t size)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY;
     void* ret;
 	if (LL_DEFAULT_HEAP_ALIGN % ALIGNMENT == 0)
 	{
@@ -284,7 +284,7 @@ LL_FORCE_INLINE void* ll_aligned_malloc(size_t size)
 template<size_t ALIGNMENT>
 LL_FORCE_INLINE void ll_aligned_free(void* ptr)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY;
 	if (ALIGNMENT == LL_DEFAULT_HEAP_ALIGN)
 	{
         LL_PROFILE_FREE(ptr);
@@ -309,7 +309,7 @@ LL_FORCE_INLINE void ll_aligned_free(void* ptr)
 //
 inline void ll_memcpy_nonaliased_aligned_16(char* __restrict dst, const char* __restrict src, size_t bytes)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY;
 	assert(src != NULL);
 	assert(dst != NULL);
 	assert(bytes > 0);
-- 
cgit v1.2.3


From f571de9de4ef1d597f93680d92b0508c584a5fef Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Thu, 13 Jan 2022 12:28:20 -0800
Subject: SL-16606: Add profiler category NETWORK

---
 indra/llmessage/llpumpio.cpp         |  6 +++---
 indra/newview/llappviewer.cpp        |  7 ++++---
 indra/newview/llmeshrepository.cpp   |  8 ++++----
 indra/newview/llviewerobjectlist.cpp | 14 +++++++-------
 indra/newview/llworld.cpp            |  6 +++---
 5 files changed, 21 insertions(+), 20 deletions(-)

(limited to 'indra')

diff --git a/indra/llmessage/llpumpio.cpp b/indra/llmessage/llpumpio.cpp
index 35365665f6..44720f0015 100644
--- a/indra/llmessage/llpumpio.cpp
+++ b/indra/llmessage/llpumpio.cpp
@@ -428,7 +428,7 @@ LLPumpIO::current_chain_t LLPumpIO::removeRunningChain(LLPumpIO::current_chain_t
 //timeout is in microseconds
 void LLPumpIO::pump(const S32& poll_timeout)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
 	//LL_INFOS() << "LLPumpIO::pump()" << LL_ENDL;
 
 	// Run any pending runners.
@@ -506,7 +506,7 @@ void LLPumpIO::pump(const S32& poll_timeout)
 		S32 count = 0;
 		S32 client_id = 0;
         {
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
             apr_pollset_poll(mPollset, poll_timeout, &count, &poll_fd);
         }
 		PUMP_DEBUG;
@@ -736,7 +736,7 @@ bool LLPumpIO::respond(
 
 void LLPumpIO::callback()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
 	//LL_INFOS() << "LLPumpIO::callback()" << LL_ENDL;
 	if(true)
 	{
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index dc973e9154..a2391ef889 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -4785,7 +4785,7 @@ void LLAppViewer::idle()
 
 	if (!gDisconnected)
 	{
-		LL_RECORD_BLOCK_TIME(FTM_NETWORK);
+		LL_PROFILE_ZONE_NAMED_CATEGORY_NETWORK("network"); //LL_RECORD_BLOCK_TIME(FTM_NETWORK);
 		// Update spaceserver timeinfo
 	    LLWorld::getInstance()->setSpaceTimeUSec(LLWorld::getInstance()->getSpaceTimeUSec() + LLUnits::Seconds::fromValue(dt_raw));
 
@@ -4817,7 +4817,7 @@ void LLAppViewer::idle()
 							|| (agent_force_update_time > (1.0f / (F32) AGENT_FORCE_UPDATES_PER_SECOND));
 		if (force_update || (agent_update_time > (1.0f / (F32) AGENT_UPDATES_PER_SECOND)))
 		{
-			LL_RECORD_BLOCK_TIME(FTM_AGENT_UPDATE);
+			LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; //LL_RECORD_BLOCK_TIME(FTM_AGENT_UPDATE);
 			// Send avatar and camera info
 			mLastAgentControlFlags = gAgent.getControlFlags();
 			mLastAgentForceUpdate = force_update ? 0 : agent_force_update_time;
@@ -5337,6 +5337,7 @@ static LLTrace::BlockTimerStatHandle FTM_CHECK_REGION_CIRCUIT("Check Region Circ
 
 void LLAppViewer::idleNetwork()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
 	pingMainloopTimeout("idleNetwork");
 
 	gObjectList.mNumNewObjects = 0;
@@ -5344,7 +5345,7 @@ void LLAppViewer::idleNetwork()
 
 	if (!gSavedSettings.getBOOL("SpeedTest"))
 	{
-		LL_RECORD_BLOCK_TIME(FTM_IDLE_NETWORK); // decode
+		LL_PROFILE_ZONE_NAMED_CATEGORY_NETWORK("idle network"); //LL_RECORD_BLOCK_TIME(FTM_IDLE_NETWORK); // decode
 
 		LLTimer check_message_timer;
 		//  Read all available packets from network
diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp
index 8cec08394d..d28e929b48 100644
--- a/indra/newview/llmeshrepository.cpp
+++ b/indra/newview/llmeshrepository.cpp
@@ -3639,7 +3639,7 @@ S32 LLMeshRepository::update()
 
 S32 LLMeshRepository::loadMesh(LLVOVolume* vobj, const LLVolumeParams& mesh_params, S32 detail, S32 last_lod)
 {
-	LL_RECORD_BLOCK_TIME(FTM_MESH_FETCH);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; //LL_LL_RECORD_BLOCK_TIME(FTM_MESH_FETCH);
 	
 	// Manage time-to-load metrics for mesh download operations.
 	metricsProgress(1);
@@ -3722,7 +3722,7 @@ S32 LLMeshRepository::loadMesh(LLVOVolume* vobj, const LLVolumeParams& mesh_para
 
 void LLMeshRepository::notifyLoadedMeshes()
 { //called from main thread
-	LL_RECORD_BLOCK_TIME(FTM_MESH_FETCH);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; //LL_RECORD_BLOCK_TIME(FTM_MESH_FETCH);
 
     // GetMesh2 operation with keepalives, etc.  With pipelining,
     // we'll increase this.  See llappcorehttp and llcorehttp for
@@ -4097,7 +4097,7 @@ const LLMeshSkinInfo* LLMeshRepository::getSkinInfo(const LLUUID& mesh_id, const
 
 void LLMeshRepository::fetchPhysicsShape(const LLUUID& mesh_id)
 {
-	LL_RECORD_BLOCK_TIME(FTM_MESH_FETCH);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; //LL_RECORD_BLOCK_TIME(FTM_MESH_FETCH);
 
 	if (mesh_id.notNull())
 	{
@@ -4126,7 +4126,7 @@ void LLMeshRepository::fetchPhysicsShape(const LLUUID& mesh_id)
 
 LLModel::Decomposition* LLMeshRepository::getDecomposition(const LLUUID& mesh_id)
 {
-	LL_RECORD_BLOCK_TIME(FTM_MESH_FETCH);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; //LL_RECORD_BLOCK_TIME(FTM_MESH_FETCH);
 
 	LLModel::Decomposition* ret = NULL;
 
diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp
index 630861f6be..0e585f13fc 100644
--- a/indra/newview/llviewerobjectlist.cpp
+++ b/indra/newview/llviewerobjectlist.cpp
@@ -169,7 +169,7 @@ U64 LLViewerObjectList::getIndex(const U32 local_id,
 
 BOOL LLViewerObjectList::removeFromLocalIDTable(const LLViewerObject* objectp)
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
 
 	if(objectp && objectp->getRegion())
 	{
@@ -306,7 +306,7 @@ static LLTrace::BlockTimerStatHandle FTM_PROCESS_OBJECTS("Process Objects");
 
 LLViewerObject* LLViewerObjectList::processObjectUpdateFromCache(LLVOCacheEntry* entry, LLViewerRegion* regionp)
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
 
 	LLDataPacker *cached_dpp = entry->getDP();
 
@@ -851,7 +851,7 @@ void LLViewerObjectList::updateApparentAngles(LLAgent &agent)
 
 void LLViewerObjectList::update(LLAgent &agent)
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
 
 	// Update globals
 	LLViewerObject::setVelocityInterpolate( gSavedSettings.getBOOL("VelocityInterpolate") );
@@ -1296,7 +1296,7 @@ void LLViewerObjectList::clearDebugText()
 
 void LLViewerObjectList::cleanupReferences(LLViewerObject *objectp)
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
 
 	bool new_dead_object = true;
 	if (mDeadObjects.find(objectp->mID) != mDeadObjects.end())
@@ -1641,7 +1641,7 @@ void LLViewerObjectList::onPhysicsFlagsFetchFailure(const LLUUID& object_id)
 
 void LLViewerObjectList::shiftObjects(const LLVector3 &offset)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
 	// This is called when we shift our origin when we cross region boundaries...
 	// We need to update many object caches, I'll document this more as I dig through the code
 	// cleaning things out...
@@ -1838,7 +1838,7 @@ void LLViewerObjectList::renderObjectBounds(const LLVector3 &center)
 
 void LLViewerObjectList::generatePickList(LLCamera &camera)
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
 
 		LLViewerObject *objectp;
 		S32 i;
@@ -2165,7 +2165,7 @@ void LLViewerObjectList::orphanize(LLViewerObject *childp, U32 parent_id, U32 ip
 
 void LLViewerObjectList::findOrphans(LLViewerObject* objectp, U32 ip, U32 port)
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
 
 	if (objectp->isDead())
 	{
diff --git a/indra/newview/llworld.cpp b/indra/newview/llworld.cpp
index d7f16713d2..343aea5721 100644
--- a/indra/newview/llworld.cpp
+++ b/indra/newview/llworld.cpp
@@ -1152,7 +1152,7 @@ void LLWorld::disconnectRegions()
 
 void process_enable_simulator(LLMessageSystem *msg, void **user_data)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
 	// enable the appropriate circuit for this simulator and 
 	// add its values into the gSimulator structure
 	U64		handle;
@@ -1227,7 +1227,7 @@ public:
 // Called in response to "DisableSimulator" message.
 void process_disable_simulator(LLMessageSystem *mesgsys, void **user_data)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
 
     LLHost host = mesgsys->getSender();
 
@@ -1289,7 +1289,7 @@ void send_agent_pause()
 
 void send_agent_resume()
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK
 	// Note: used to check for LLWorld initialization before it became a singleton.
 	// Rather than just remove this check I'm changing it to assure that the message 
 	// system has been initialized. -MG
-- 
cgit v1.2.3


From 04248b0aedb086f454b94d35918126559f7fd618 Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Thu, 13 Jan 2022 12:30:39 -0800
Subject: SL-16606: Add profiler category OCTREE

---
 indra/newview/llvieweroctree.cpp | 24 ++++++++++++------------
 1 file changed, 12 insertions(+), 12 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llvieweroctree.cpp b/indra/newview/llvieweroctree.cpp
index b5bf4f0354..3cdef0ebff 100644
--- a/indra/newview/llvieweroctree.cpp
+++ b/indra/newview/llvieweroctree.cpp
@@ -545,7 +545,7 @@ void LLViewerOctreeGroup::unbound()
 //virtual 
 void LLViewerOctreeGroup::rebound()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_OCTREE;
 	if (!isDirty())
 	{	
 		return;
@@ -1054,7 +1054,7 @@ void LLOcclusionCullingGroup::clearOcclusionState(U32 state, S32 mode /* = STATE
 
 BOOL LLOcclusionCullingGroup::earlyFail(LLCamera* camera, const LLVector4a* bounds)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_OCTREE;
 	if (camera->getOrigin().isExactlyZero())
 	{
 		return FALSE;
@@ -1105,7 +1105,7 @@ void LLOcclusionCullingGroup::checkOcclusion()
 {
     if (LLPipeline::sUseOcclusion < 2) return;  // 0 - NoOcclusion, 1 = ReadOnly, 2 = ModifyOcclusionState  TODO: DJH 11-2021 ENUM this
 
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_OCTREE;
     LLOcclusionCullingGroup* parent = (LLOcclusionCullingGroup*)getParent();
     if (parent && parent->isOcclusionState(LLOcclusionCullingGroup::OCCLUDED))
     {	//if the parent has been marked as occluded, the child is implicitly occluded
@@ -1127,7 +1127,7 @@ void LLOcclusionCullingGroup::checkOcclusion()
         {
             GLuint available;
             {
-                LL_PROFILE_ZONE_NAMED("co - query available");
+                LL_PROFILE_ZONE_NAMED_CATEGORY_OCTREE("co - query available");
                 glGetQueryObjectuivARB(mOcclusionQuery[LLViewerCamera::sCurCameraID], GL_QUERY_RESULT_AVAILABLE_ARB, &available);
             }
 
@@ -1135,7 +1135,7 @@ void LLOcclusionCullingGroup::checkOcclusion()
             {   
                 GLuint query_result;    // Will be # samples drawn, or a boolean depending on mHasOcclusionQuery2 (both are type GLuint)
                 {
-                    LL_PROFILE_ZONE_NAMED("co - query result");
+                    LL_PROFILE_ZONE_NAMED_CATEGORY_OCTREE("co - query result");
                     glGetQueryObjectuivARB(mOcclusionQuery[LLViewerCamera::sCurCameraID], GL_QUERY_RESULT_ARB, &query_result);
                 }
 #if LL_TRACK_PENDING_OCCLUSION_QUERIES
@@ -1178,7 +1178,7 @@ void LLOcclusionCullingGroup::checkOcclusion()
 
 void LLOcclusionCullingGroup::doOcclusion(LLCamera* camera, const LLVector4a* shift)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_OCTREE;
 	if (mSpatialPartition->isOcclusionEnabled() && LLPipeline::sUseOcclusion > 1)
 	{
 		//move mBounds to the agent space if necessary
@@ -1199,7 +1199,7 @@ void LLOcclusionCullingGroup::doOcclusion(LLCamera* camera, const LLVector4a* sh
 		// Don't cull hole/edge water, unless we have the GL_ARB_depth_clamp extension
 		if (earlyFail(camera, bounds))
 		{
-            LL_PROFILE_ZONE_NAMED("doOcclusion - early fail");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_OCTREE("doOcclusion - early fail");
 			setOcclusionState(LLOcclusionCullingGroup::DISCARD_QUERY);
 			assert_states_valid(this);
 			clearOcclusionState(LLOcclusionCullingGroup::OCCLUDED, LLOcclusionCullingGroup::STATE_MODE_DIFF);
@@ -1210,7 +1210,7 @@ void LLOcclusionCullingGroup::doOcclusion(LLCamera* camera, const LLVector4a* sh
 			if (!isOcclusionState(QUERY_PENDING) || isOcclusionState(DISCARD_QUERY))
 			{
 				{ //no query pending, or previous query to be discarded
-                    LL_PROFILE_ZONE_NAMED("doOcclusion - render");
+                    LL_PROFILE_ZONE_NAMED_CATEGORY_OCTREE("doOcclusion - render");
 
 					if (!mOcclusionQuery[LLViewerCamera::sCurCameraID])
 					{
@@ -1238,7 +1238,7 @@ void LLOcclusionCullingGroup::doOcclusion(LLCamera* camera, const LLVector4a* sh
 					add(sOcclusionQueries, 1);
 
 					{
-                        LL_PROFILE_ZONE_NAMED("doOcclusion - push");
+                        LL_PROFILE_ZONE_NAMED_CATEGORY_OCTREE("doOcclusion - push");
 						
 						//store which frame this query was issued on
 						mOcclusionIssued[LLViewerCamera::sCurCameraID] = gFrameCount;
@@ -1255,7 +1255,7 @@ void LLOcclusionCullingGroup::doOcclusion(LLCamera* camera, const LLVector4a* sh
 
 						if (!use_depth_clamp && mSpatialPartition->mDrawableType == LLPipeline::RENDER_TYPE_VOIDWATER)
 						{
-                            LL_PROFILE_ZONE_NAMED("doOcclusion - draw water");
+                            LL_PROFILE_ZONE_NAMED_CATEGORY_OCTREE("doOcclusion - draw water");
 
 							LLGLSquashToFarClip squash;
 							if (camera->getOrigin().isExactlyZero())
@@ -1270,7 +1270,7 @@ void LLOcclusionCullingGroup::doOcclusion(LLCamera* camera, const LLVector4a* sh
 						}
 						else
 						{
-                            LL_PROFILE_ZONE_NAMED("doOcclusion - draw");
+                            LL_PROFILE_ZONE_NAMED_CATEGORY_OCTREE("doOcclusion - draw");
 							if (camera->getOrigin().isExactlyZero())
 							{ //origin is invalid, draw entire box
 								gPipeline.mCubeVB->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, 0);
@@ -1287,7 +1287,7 @@ void LLOcclusionCullingGroup::doOcclusion(LLCamera* camera, const LLVector4a* sh
 				}
 
 				{
-                    LL_PROFILE_ZONE_NAMED("doOcclusion - set state");
+                    LL_PROFILE_ZONE_NAMED_CATEGORY_OCTREE("doOcclusion - set state");
 					setOcclusionState(LLOcclusionCullingGroup::QUERY_PENDING);
 					clearOcclusionState(LLOcclusionCullingGroup::DISCARD_QUERY);
 				}
-- 
cgit v1.2.3


From 206a8bb30f894d5b7c05bad34f2700fc08bd4d3a Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Thu, 13 Jan 2022 12:34:23 -0800
Subject: SL-16606: Add profiler category PIPELINE

---
 indra/llrender/llgl.cpp     |   6 +--
 indra/llrender/llrender.cpp |   6 +--
 indra/newview/llworld.cpp   |   4 +-
 indra/newview/pipeline.cpp  | 102 ++++++++++++++++++++++----------------------
 4 files changed, 59 insertions(+), 59 deletions(-)

(limited to 'indra')

diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp
index 18a79d5264..12da961cef 100644
--- a/indra/llrender/llgl.cpp
+++ b/indra/llrender/llgl.cpp
@@ -1868,7 +1868,7 @@ void LLGLState::checkTextureChannels(const std::string& msg)
 LLGLState::LLGLState(LLGLenum state, S32 enabled) :
 	mState(state), mWasEnabled(FALSE), mIsEnabled(FALSE)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
 	switch (state)
 	{
 		case GL_ALPHA_TEST:
@@ -1925,7 +1925,7 @@ void LLGLState::setEnabled(S32 enabled)
 
 LLGLState::~LLGLState() 
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
 	stop_glerror();
 	if (mState)
 	{
@@ -2184,7 +2184,7 @@ void LLGLNamePool::cleanup()
 
 GLuint LLGLNamePool::allocate()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
 #if LL_GL_NAME_POOLING
 	for (name_list_t::iterator iter = mNameList.begin(); iter != mNameList.end(); ++iter)
 	{
diff --git a/indra/llrender/llrender.cpp b/indra/llrender/llrender.cpp
index 8b4f250894..3b46eef1b4 100644
--- a/indra/llrender/llrender.cpp
+++ b/indra/llrender/llrender.cpp
@@ -193,7 +193,7 @@ void LLTexUnit::bindFast(LLTexture* texture)
 
 bool LLTexUnit::bind(LLTexture* texture, bool for_rendering, bool forceBind)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
 	stop_glerror();
 	if (mIndex >= 0)
 	{
@@ -1483,7 +1483,7 @@ LLLightState* LLRender::getLight(U32 index)
 
 void LLRender::setAmbientLightColor(const LLColor4& color)
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE
 	if (color != mAmbientLightColor)
 	{
 		++mLightHash;
@@ -1558,7 +1558,7 @@ void LLRender::flush()
 {
 	if (mCount > 0)
 	{
-        LL_PROFILE_ZONE_SCOPED;
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
 		if (!mUIOffset.empty())
 		{
 			sUICalls++;
diff --git a/indra/newview/llworld.cpp b/indra/newview/llworld.cpp
index 343aea5721..6746a3a902 100644
--- a/indra/newview/llworld.cpp
+++ b/indra/newview/llworld.cpp
@@ -885,7 +885,7 @@ void LLWorld::waterHeightRegionInfo(std::string const& sim_name, F32 water_heigh
 
 void LLWorld::precullWaterObjects(LLCamera& camera, LLCullResult* cull, bool include_void_water)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
 	if (!gAgent.getRegion())
 	{
 		return;
@@ -1079,7 +1079,7 @@ void LLWorld::updateWaterObjects()
 
 void LLWorld::shiftRegions(const LLVector3& offset)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
 	for (region_list_t::const_iterator i = getRegionList().begin(); i != getRegionList().end(); ++i)
 	{
 		LLViewerRegion* region = *i;
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index bff3afe70e..c7dc710dd1 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -1224,7 +1224,7 @@ void LLPipeline::releaseShadowTargets()
 
 void LLPipeline::createGLBuffers()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
     stop_glerror();
 	assertInitialized();
 
@@ -1491,7 +1491,7 @@ public:
 // Called when a texture changes # of channels (causes faces to move to alpha pool)
 void LLPipeline::dirtyPoolObjectTextures(const std::set<LLViewerFetchedTexture*>& textures)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
 	assertInitialized();
 
 	// *TODO: This is inefficient and causes frame spikes; need a better way to do this
@@ -1705,7 +1705,7 @@ void LLPipeline::allocDrawable(LLViewerObject *vobj)
 
 void LLPipeline::unlinkDrawable(LLDrawable *drawable)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
 
 	assertInitialized();
 
@@ -1770,7 +1770,7 @@ void LLPipeline::unlinkDrawable(LLDrawable *drawable)
 //static
 void LLPipeline::removeMutedAVsLights(LLVOAvatar* muted_avatar)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
 	for (light_set_t::iterator iter = gPipeline.mNearbyLights.begin();
 		 iter != gPipeline.mNearbyLights.end(); iter++)
 	{
@@ -1798,7 +1798,7 @@ U32 LLPipeline::addObject(LLViewerObject *vobj)
 
 void LLPipeline::createObjects(F32 max_dtime)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
 
 	LLTimer update_timer;
 
@@ -1822,7 +1822,7 @@ void LLPipeline::createObjects(F32 max_dtime)
 
 void LLPipeline::createObject(LLViewerObject* vobj)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
 	LLDrawable* drawablep = vobj->mDrawable;
 
 	if (!drawablep)
@@ -1860,7 +1860,7 @@ void LLPipeline::createObject(LLViewerObject* vobj)
 
 void LLPipeline::resetFrameStats()
 {
-	LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
 	assertInitialized();
 
 	sCompiles        = 0;
@@ -1974,7 +1974,7 @@ void LLPipeline::updateMovedList(LLDrawable::drawable_vector_t& moved_list)
 
 void LLPipeline::updateMove()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
 
 	if (FreezeTime)
 	{
@@ -2076,7 +2076,7 @@ void LLPipeline::grabReferences(LLCullResult& result)
 
 void LLPipeline::clearReferences()
 {
-	LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
 	sCull = NULL;
 	mGroupSaveQ1.clear();
 }
@@ -2330,7 +2330,7 @@ void LLPipeline::updateCull(LLCamera& camera, LLCullResult& result, LLPlane* pla
 	static bool can_use_occlusion = LLFeatureManager::getInstance()->isFeatureAvailable("UseOcclusion") 
 									&& gGLManager.mHasOcclusionQuery;
 
-	LL_RECORD_BLOCK_TIME(FTM_CULL);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE; //LL_RECORD_BLOCK_TIME(FTM_CULL);
 
     if (planep != nullptr)
     {
@@ -2616,7 +2616,7 @@ void LLPipeline::doOcclusion(LLCamera& camera, LLRenderTarget& source, LLRenderT
 
 void LLPipeline::doOcclusion(LLCamera& camera)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
     if (LLPipeline::sUseOcclusion > 1 && !LLSpatialPartition::sTeleportRequested &&
 		(sCull->hasOcclusionGroups() || LLVOCachePartition::sNeedsOcclusionCheck))
 	{
@@ -2703,7 +2703,7 @@ bool LLPipeline::updateDrawableGeom(LLDrawable* drawablep, bool priority)
 
 void LLPipeline::updateGL()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
 	{
 		while (!LLGLUpdate::sGLQ.empty())
 		{
@@ -2721,7 +2721,7 @@ void LLPipeline::updateGL()
 
 void LLPipeline::clearRebuildGroups()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
 	LLSpatialGroup::sg_vector_t	hudGroups;
 
 	mGroupQ1Locked = true;
@@ -2826,7 +2826,7 @@ void LLPipeline::clearRebuildDrawables()
 
 void LLPipeline::rebuildPriorityGroups()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
 	LLTimer update_timer;
 	assertInitialized();
 
@@ -2855,7 +2855,7 @@ void LLPipeline::rebuildGroups()
 		return;
 	}
 
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
 	mGroupQ2Locked = true;
 	// Iterate through some drawables on the non-priority build queue
 	S32 size = (S32) mGroupQ2.size();
@@ -3103,7 +3103,7 @@ void LLPipeline::markShift(LLDrawable *drawablep)
 
 void LLPipeline::shiftObjects(const LLVector3 &offset)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
 	assertInitialized();
 
 	glClear(GL_DEPTH_BUFFER_BIT);
@@ -3174,7 +3174,7 @@ void LLPipeline::markPartitionMove(LLDrawable* drawable)
 
 void LLPipeline::processPartitionQ()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
 	for (LLDrawable::drawable_list_t::iterator iter = mPartitionQ.begin(); iter != mPartitionQ.end(); ++iter)
 	{
 		LLDrawable* drawable = *iter;
@@ -3276,6 +3276,8 @@ void LLPipeline::markRebuild(LLDrawable *drawablep, LLDrawable::EDrawableFlags f
 
 void LLPipeline::stateSort(LLCamera& camera, LLCullResult &result)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
+
 	if (hasAnyRenderType(LLPipeline::RENDER_TYPE_AVATAR,
 					  LLPipeline::RENDER_TYPE_CONTROL_AV,
 					  LLPipeline::RENDER_TYPE_GROUND,
@@ -3290,8 +3292,6 @@ void LLPipeline::stateSort(LLCamera& camera, LLCullResult &result)
 		gPipeline.resetDrawOrders();
 	}
 
-	LL_RECORD_BLOCK_TIME(FTM_STATESORT);
-
 	//LLVertexBuffer::unbind();
 
 	grabReferences(result);
@@ -3410,7 +3410,7 @@ void LLPipeline::stateSort(LLSpatialGroup* group, LLCamera& camera)
 
 void LLPipeline::stateSort(LLSpatialBridge* bridge, LLCamera& camera, BOOL fov_changed)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
     if (bridge->getSpatialGroup()->changeLOD() || fov_changed)
 	{
 		bool force_update = false;
@@ -3420,7 +3420,7 @@ void LLPipeline::stateSort(LLSpatialBridge* bridge, LLCamera& camera, BOOL fov_c
 
 void LLPipeline::stateSort(LLDrawable* drawablep, LLCamera& camera)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
     if (!drawablep
 		|| drawablep->isDead() 
 		|| !hasRenderType(drawablep->getRenderType()))
@@ -3730,7 +3730,7 @@ void LLPipeline::touchTexture(LLViewerTexture* tex, F32 vsize)
 }
 void LLPipeline::touchTextures(LLDrawInfo* info)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
     for (int i = 0; i < info->mTextureList.size(); ++i)
     {
         touchTexture(info->mTextureList[i], info->mTextureListVSize[i]);
@@ -3743,7 +3743,7 @@ void LLPipeline::touchTextures(LLDrawInfo* info)
 
 void LLPipeline::postSort(LLCamera& camera)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
 
 	assertInitialized();
 
@@ -4252,7 +4252,7 @@ U32 LLPipeline::sCurRenderPoolType = 0 ;
 
 void LLPipeline::renderGeom(LLCamera& camera, bool forceVBOUpdate)
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_GEOMETRY);
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE; //LL_RECORD_BLOCK_TIME(FTM_RENDER_GEOMETRY);
 
 	assertInitialized();
 
@@ -4696,7 +4696,7 @@ void LLPipeline::renderGeomPostDeferred(LLCamera& camera, bool do_occlusion)
 
 void LLPipeline::renderGeomShadow(LLCamera& camera)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
     U32 cur_type = 0;
 	
 	LLGLEnable cull(GL_CULL_FACE);
@@ -4762,7 +4762,7 @@ void LLPipeline::renderGeomShadow(LLCamera& camera)
 
 void LLPipeline::addTrianglesDrawn(S32 index_count, U32 render_type)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
 	assertInitialized();
 	S32 count = 0;
 	if (render_type == LLRender::TRIANGLE_STRIP)
@@ -5474,7 +5474,7 @@ void LLPipeline::renderDebug()
 
 void LLPipeline::rebuildPools()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
 
 	assertInitialized();
 
@@ -5818,7 +5818,7 @@ void LLPipeline::removeFromQuickLookup( LLDrawPool* poolp )
 
 void LLPipeline::resetDrawOrders()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
 	assertInitialized();
 	// Iterate through all of the draw pools and rebuild them.
 	for (pool_set_t::iterator iter = mPools.begin(); iter != mPools.end(); ++iter)
@@ -7224,7 +7224,7 @@ void LLPipeline::doResetVertexBuffers(bool forced)
 		}
 	}
 
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
 	mResetVertexBuffers = false;
 
 	mCubeVB = NULL;
@@ -7313,7 +7313,7 @@ void LLPipeline::renderObjects(U32 type, U32 mask, bool texture, bool batch_text
 
 void LLPipeline::renderAlphaObjects(U32 mask, bool texture, bool batch_texture, bool rigged)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
     assertInitialized();
     gGL.loadMatrix(gGLModelView);
     gGLLastMatrix = NULL;
@@ -8042,7 +8042,7 @@ void LLPipeline::renderFinalize()
 
 void LLPipeline::bindDeferredShader(LLGLSLShader& shader, LLRenderTarget* light_target)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
 
     LLRenderTarget* deferred_target       = &mDeferredScreen;
     LLRenderTarget* deferred_depth_target = &mDeferredDepth;
@@ -8304,7 +8304,7 @@ LLVector4 pow4fsrgb(LLVector4 v, F32 f)
 
 void LLPipeline::renderDeferredLighting(LLRenderTarget *screen_target)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
     if (!sCull)
     {
         return;
@@ -8315,7 +8315,7 @@ void LLPipeline::renderDeferredLighting(LLRenderTarget *screen_target)
     LLRenderTarget *deferred_light_target = &mDeferredLight;
 
     {
-        LL_RECORD_BLOCK_TIME(FTM_RENDER_DEFERRED);
+        LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("deferred"); //LL_RECORD_BLOCK_TIME(FTM_RENDER_DEFERRED);
         LLViewerCamera *camera = LLViewerCamera::getInstance();
         {
             LLGLDepthTest depth(GL_TRUE);
@@ -8381,7 +8381,7 @@ void LLPipeline::renderDeferredLighting(LLRenderTarget *screen_target)
         {
             deferred_light_target->bindTarget();
             {  // paint shadow/SSAO light map (direct lighting lightmap)
-                LL_PROFILE_ZONE_NAMED("renderDeferredLighting - sun shadow");
+                LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("renderDeferredLighting - sun shadow");
                 bindDeferredShader(gDeferredSunProgram, deferred_light_target);
                 mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX);
                 glClearColor(1, 1, 1, 1);
@@ -8427,7 +8427,7 @@ void LLPipeline::renderDeferredLighting(LLRenderTarget *screen_target)
 
         if (RenderDeferredSSAO)
         {  // soften direct lighting lightmap
-            LL_PROFILE_ZONE_NAMED("renderDeferredLighting - soften shadow");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("renderDeferredLighting - soften shadow");
             // blur lightmap
             screen_target->bindTarget();
             glClearColor(1, 1, 1, 1);
@@ -8505,7 +8505,7 @@ void LLPipeline::renderDeferredLighting(LLRenderTarget *screen_target)
         {  // apply sunlight contribution
             LLGLSLShader &soften_shader = LLPipeline::sUnderWaterRender ? gDeferredSoftenWaterProgram : gDeferredSoftenProgram;
 
-            LL_PROFILE_ZONE_NAMED("renderDeferredLighting - atmospherics");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("renderDeferredLighting - atmospherics");
             bindDeferredShader(soften_shader);
 
             LLEnvironment &environment = LLEnvironment::instance();
@@ -8571,7 +8571,7 @@ void LLPipeline::renderDeferredLighting(LLRenderTarget *screen_target)
             LLVertexBuffer::unbind();
 
             {
-                LL_PROFILE_ZONE_NAMED("renderDeferredLighting - local lights");
+                LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("renderDeferredLighting - local lights");
                 bindDeferredShader(gDeferredLightProgram);
 
                 if (mCubeVB.isNull())
@@ -8677,7 +8677,7 @@ void LLPipeline::renderDeferredLighting(LLRenderTarget *screen_target)
 
             if (!spot_lights.empty())
             {
-                LL_PROFILE_ZONE_NAMED("renderDeferredLighting - projectors");
+                LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("renderDeferredLighting - projectors");
                 LLGLDepthTest depth(GL_TRUE, GL_FALSE);
                 bindDeferredShader(gDeferredSpotLightProgram);
 
@@ -8722,7 +8722,7 @@ void LLPipeline::renderDeferredLighting(LLRenderTarget *screen_target)
             vert[2].set(3, 1, 0);
 
             {
-                LL_PROFILE_ZONE_NAMED("renderDeferredLighting - fullscreen lights");
+                LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("renderDeferredLighting - fullscreen lights");
                 LLGLDepthTest depth(GL_FALSE);
 
                 // full screen blit
@@ -9116,7 +9116,7 @@ inline float sgn(float a)
 
 void LLPipeline::generateWaterReflection(LLCamera& camera_in)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
 
     if (!assertInitialized())
     {
@@ -9523,7 +9523,7 @@ static LLTrace::BlockTimerStatHandle FTM_SHADOW_FULLBRIGHT_ALPHA_MASKED("Fullbri
 
 void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera& shadow_cam, LLCullResult& result, bool use_shader, bool use_occlusion, U32 target_width)
 {
-    LL_RECORD_BLOCK_TIME(FTM_SHADOW_RENDER);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE; //LL_RECORD_BLOCK_TIME(FTM_SHADOW_RENDER);
 
     //disable occlusion culling for shadow passes (save setting to restore later)
     S32 occlude = LLPipeline::sUseOcclusion;
@@ -9610,7 +9610,7 @@ void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera
             gGL.setColorMask(false, false);
         }
 
-        LL_RECORD_BLOCK_TIME(FTM_SHADOW_SIMPLE);
+        LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("shadow simple"); //LL_RECORD_BLOCK_TIME(FTM_SHADOW_SIMPLE);
 
         gGL.getTexUnit(0)->disable();
         for (U32 i = 0; i < sizeof(types) / sizeof(U32); ++i)
@@ -9628,7 +9628,7 @@ void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera
 
     if (use_shader)
     {
-        LL_RECORD_BLOCK_TIME(FTM_SHADOW_GEOM);
+        LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("shadow geom"); //LL_RECORD_BLOCK_TIME(FTM_SHADOW_GEOM);
 
         gDeferredShadowProgram.unbind();
         renderGeomShadow(shadow_cam);
@@ -9637,13 +9637,13 @@ void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera
     }
     else
     {
-        LL_RECORD_BLOCK_TIME(FTM_SHADOW_GEOM);
+        LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("shadow geom"); //LL_RECORD_BLOCK_TIME(FTM_SHADOW_GEOM);
 
         renderGeomShadow(shadow_cam);
     }
 
     {
-        LL_RECORD_BLOCK_TIME(FTM_SHADOW_ALPHA);
+        LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("shadow alpha"); //LL_RECORD_BLOCK_TIME(FTM_SHADOW_ALPHA);
 
         for (int i = 0; i < 2; ++i)
         {
@@ -9659,19 +9659,19 @@ void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera
                 LLVertexBuffer::MAP_TEXTURE_INDEX;
 
             {
-                LL_RECORD_BLOCK_TIME(FTM_SHADOW_ALPHA_MASKED);
+                LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("shadow alpha masked"); //LL_RECORD_BLOCK_TIME(FTM_SHADOW_ALPHA_MASKED);
                 renderMaskedObjects(LLRenderPass::PASS_ALPHA_MASK, mask, TRUE, TRUE, rigged);
             }
 
             {
-                LL_RECORD_BLOCK_TIME(FTM_SHADOW_ALPHA_BLEND);
+                LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("shadow alpha blend"); //LL_RECORD_BLOCK_TIME(FTM_SHADOW_ALPHA_BLEND);
                 LLGLSLShader::sCurBoundShaderPtr->setMinimumAlpha(0.598f);
                 renderAlphaObjects(mask, TRUE, TRUE, rigged);
             }
 
 
             {
-                LL_RECORD_BLOCK_TIME(FTM_SHADOW_FULLBRIGHT_ALPHA_MASKED);
+                LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("shadow fullbright alpha masked"); //LL_RECORD_BLOCK_TIME(FTM_SHADOW_FULLBRIGHT_ALPHA_MASKED);
                 gDeferredShadowFullbrightAlphaMaskProgram.bind(rigged);
                 LLGLSLShader::sCurBoundShaderPtr->uniform1f(LLShaderMgr::DEFERRED_SHADOW_TARGET_WIDTH, (float)target_width);
                 LLGLSLShader::sCurBoundShaderPtr->uniform1i(LLShaderMgr::SUN_UP_FACTOR, environment.getIsSunUp() ? 1 : 0);
@@ -9680,7 +9680,7 @@ void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera
 
 
             {
-                LL_RECORD_BLOCK_TIME(FTM_SHADOW_ALPHA_GRASS);
+                LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("shadow alpha grass"); //LL_RECORD_BLOCK_TIME(FTM_SHADOW_ALPHA_GRASS);
                 gDeferredTreeShadowProgram.bind(rigged);
                 if (i == 0)
                 {
@@ -9726,7 +9726,7 @@ void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera
 
 bool LLPipeline::getVisiblePointCloud(LLCamera& camera, LLVector3& min, LLVector3& max, std::vector<LLVector3>& fp, LLVector3 light_dir)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
 	//get point cloud of intersection of frust and min, max
 
 	if (getVisibleExtents(camera, min, max))
@@ -9989,7 +9989,7 @@ void LLPipeline::generateSunShadow(LLCamera& camera)
 		return;
 	}
 
-	LL_RECORD_BLOCK_TIME(FTM_GEN_SUN_SHADOW);
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE; //LL_RECORD_BLOCK_TIME(FTM_GEN_SUN_SHADOW);
 
 	bool skip_avatar_update = false;
 	if (!isAgentAvatarValid() || gAgentCamera.getCameraAnimating() || gAgentCamera.getCameraMode() != CAMERA_MODE_MOUSELOOK || !LLVOAvatar::sVisibleInFirstPerson)
-- 
cgit v1.2.3


From 97552d2e750745aa292ec4ee3d1bd830e88b7946 Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Thu, 13 Jan 2022 12:40:39 -0800
Subject: SL-16606: Add profiler category SHADER

---
 indra/llrender/llglslshader.cpp | 52 ++++++++++++++++++++---------------------
 indra/newview/llenvironment.cpp |  4 ++--
 indra/newview/llsettingsvo.cpp  |  4 ++--
 3 files changed, 30 insertions(+), 30 deletions(-)

(limited to 'indra')

diff --git a/indra/llrender/llglslshader.cpp b/indra/llrender/llglslshader.cpp
index 220e88386a..185c1450c8 100644
--- a/indra/llrender/llglslshader.cpp
+++ b/indra/llrender/llglslshader.cpp
@@ -207,7 +207,7 @@ void LLGLSLShader::dumpStats()
 //static
 void LLGLSLShader::startProfile()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
     if (sProfileEnabled && sCurBoundShaderPtr)
     {
         sCurBoundShaderPtr->placeProfileQuery();
@@ -218,7 +218,7 @@ void LLGLSLShader::startProfile()
 //static
 void LLGLSLShader::stopProfile(U32 count, U32 mode)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
     if (sProfileEnabled && sCurBoundShaderPtr)
     {
         sCurBoundShaderPtr->readProfileQuery(count, mode);
@@ -385,7 +385,7 @@ BOOL LLGLSLShader::createShader(std::vector<LLStaticHashedString> * attributes,
                                 U32 varying_count,
                                 const char** varyings)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
 
     unloadInternal();
 
@@ -591,7 +591,7 @@ void LLGLSLShader::attachObjects(GLhandleARB* objects, S32 count)
 
 BOOL LLGLSLShader::mapAttributes(const std::vector<LLStaticHashedString> * attributes)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
 
     //before linking, make sure reserved attributes always have consistent locations
     for (U32 i = 0; i < LLShaderMgr::instance()->mReservedAttribs.size(); i++)
@@ -654,7 +654,7 @@ BOOL LLGLSLShader::mapAttributes(const std::vector<LLStaticHashedString> * attri
 
 void LLGLSLShader::mapUniform(GLint index, const vector<LLStaticHashedString> * uniforms)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
 
     if (index == -1)
     {
@@ -777,7 +777,7 @@ void LLGLSLShader::removePermutation(std::string name)
 
 GLint LLGLSLShader::mapUniformTextureChannel(GLint location, GLenum type)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
 
     if ((type >= GL_SAMPLER_1D_ARB && type <= GL_SAMPLER_2D_RECT_SHADOW_ARB) ||
         type == GL_SAMPLER_2D_MULTISAMPLE)
@@ -791,7 +791,7 @@ GLint LLGLSLShader::mapUniformTextureChannel(GLint location, GLenum type)
 
 BOOL LLGLSLShader::mapUniforms(const vector<LLStaticHashedString> * uniforms)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
 
     BOOL res = TRUE;
 
@@ -936,7 +936,7 @@ BOOL LLGLSLShader::mapUniforms(const vector<LLStaticHashedString> * uniforms)
 
 BOOL LLGLSLShader::link(BOOL suppress_errors)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
 
     BOOL success = LLShaderMgr::instance()->linkProgramObject(mProgramObject, suppress_errors);
 
@@ -950,7 +950,7 @@ BOOL LLGLSLShader::link(BOOL suppress_errors)
 
 void LLGLSLShader::bind()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
 
     gGL.flush();
 
@@ -984,7 +984,7 @@ void LLGLSLShader::bind(bool rigged)
 
 void LLGLSLShader::unbind()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
 
     gGL.flush();
     stop_glerror();
@@ -997,7 +997,7 @@ void LLGLSLShader::unbind()
 
 void LLGLSLShader::bindNoShader(void)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
 
     LLVertexBuffer::unbind();
     glUseProgramObjectARB(0);
@@ -1007,7 +1007,7 @@ void LLGLSLShader::bindNoShader(void)
 
 S32 LLGLSLShader::bindTexture(const std::string &uniform, LLTexture *texture, LLTexUnit::eTextureType mode, LLTexUnit::eTextureColorSpace colorspace)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
 
     S32 channel = 0;
     channel = getUniformLocation(uniform);
@@ -1017,7 +1017,7 @@ 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;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
 
     if (uniform < 0 || uniform >= (S32)mTexture.size())
     {
@@ -1038,7 +1038,7 @@ S32 LLGLSLShader::bindTexture(S32 uniform, LLTexture *texture, LLTexUnit::eTextu
 
 S32 LLGLSLShader::unbindTexture(const std::string &uniform, LLTexUnit::eTextureType mode)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
 
     S32 channel = 0;
     channel = getUniformLocation(uniform);
@@ -1048,7 +1048,7 @@ S32 LLGLSLShader::unbindTexture(const std::string &uniform, LLTexUnit::eTextureT
 
 S32 LLGLSLShader::unbindTexture(S32 uniform, LLTexUnit::eTextureType mode)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
 
     if (uniform < 0 || uniform >= (S32)mTexture.size())
     {
@@ -1068,7 +1068,7 @@ S32 LLGLSLShader::unbindTexture(S32 uniform, LLTexUnit::eTextureType mode)
 
 S32 LLGLSLShader::enableTexture(S32 uniform, LLTexUnit::eTextureType mode, LLTexUnit::eTextureColorSpace space)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
 
     if (uniform < 0 || uniform >= (S32)mTexture.size())
     {
@@ -1087,7 +1087,7 @@ S32 LLGLSLShader::enableTexture(S32 uniform, LLTexUnit::eTextureType mode, LLTex
 
 S32 LLGLSLShader::disableTexture(S32 uniform, LLTexUnit::eTextureType mode, LLTexUnit::eTextureColorSpace space)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
 
     if (uniform < 0 || uniform >= (S32)mTexture.size())
     {
@@ -1116,7 +1116,7 @@ S32 LLGLSLShader::disableTexture(S32 uniform, LLTexUnit::eTextureType mode, LLTe
 
 void LLGLSLShader::uniform1i(U32 index, GLint x)
 {
-    LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER
     if (mProgramObject)
     {   
         if (mUniform.size() <= index)
@@ -1139,7 +1139,7 @@ void LLGLSLShader::uniform1i(U32 index, GLint x)
 
 void LLGLSLShader::uniform1f(U32 index, GLfloat x)
 {
-    LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER
     if (mProgramObject)
     {   
         if (mUniform.size() <= index)
@@ -1337,7 +1337,7 @@ void LLGLSLShader::uniform4fv(U32 index, U32 count, const GLfloat* v)
             LLVector4 vec(v[0],v[1],v[2],v[3]);
             if (iter == mValue.end() || shouldChange(iter->second,vec) || count != 1)
             {
-                LL_PROFILE_ZONE_SCOPED;
+                LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
                 glUniform4fvARB(mUniform[index], count, v);
                 mValue[mUniform[index]] = vec;
             }
@@ -1381,7 +1381,7 @@ 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;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
 
 	if (mProgramObject)
 	{	
@@ -1417,7 +1417,7 @@ void LLGLSLShader::uniformMatrix4fv(U32 index, U32 count, GLboolean transpose, c
 
 GLint LLGLSLShader::getUniformLocation(const LLStaticHashedString& uniform)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
 
     GLint ret = -1;
     if (mProgramObject)
@@ -1443,7 +1443,7 @@ GLint LLGLSLShader::getUniformLocation(const LLStaticHashedString& uniform)
 
 GLint LLGLSLShader::getUniformLocation(U32 index)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
 
     GLint ret = -1;
     if (mProgramObject)
@@ -1461,7 +1461,7 @@ GLint LLGLSLShader::getUniformLocation(U32 index)
 
 GLint LLGLSLShader::getAttribLocation(U32 attrib)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
 
     if (attrib < mAttribute.size())
     {
@@ -1613,7 +1613,7 @@ void LLGLSLShader::uniform4fv(const LLStaticHashedString& uniform, U32 count, co
         const auto& iter = mValue.find(location);
         if (iter == mValue.end() || shouldChange(iter->second,vec) || count != 1)
         {
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
             glUniform4fvARB(location, count, v);
             mValue[location] = vec;
         }
@@ -1657,7 +1657,7 @@ void LLGLSLShader::setMinimumAlpha(F32 minimum)
 
 void LLShaderUniforms::apply(LLGLSLShader* shader)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
     for (auto& uniform : mIntegers)
     {
         shader->uniform1i(uniform.mUniform, uniform.mValue);
diff --git a/indra/newview/llenvironment.cpp b/indra/newview/llenvironment.cpp
index f232ca47e0..0cdafcba81 100644
--- a/indra/newview/llenvironment.cpp
+++ b/indra/newview/llenvironment.cpp
@@ -1654,7 +1654,7 @@ void LLEnvironment::updateCloudScroll()
 // static
 void LLEnvironment::updateGLVariablesForSettings(LLShaderUniforms* uniforms, const LLSettingsBase::ptr_t &psetting)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
 
     for (int i = 0; i < LLGLSLShader::SG_COUNT; ++i)
     {
@@ -1725,7 +1725,7 @@ void LLEnvironment::updateGLVariablesForSettings(LLShaderUniforms* uniforms, con
 
 void LLEnvironment::updateShaderUniforms(LLGLSLShader* shader)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
 
     // apply uniforms that should be applied to all shaders
     mSkyUniforms[LLGLSLShader::SG_ANY].apply(shader);
diff --git a/indra/newview/llsettingsvo.cpp b/indra/newview/llsettingsvo.cpp
index 217d45de68..14a9f4aa30 100644
--- a/indra/newview/llsettingsvo.cpp
+++ b/indra/newview/llsettingsvo.cpp
@@ -666,7 +666,7 @@ void LLSettingsVOSky::updateSettings()
 
 void LLSettingsVOSky::applySpecial(void *ptarget, bool force)
 {
-    LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
     LLVector4 light_direction = LLEnvironment::instance().getClampedLightNorm();
 
     LLShaderUniforms* shader = &((LLShaderUniforms*)ptarget)[LLGLSLShader::SG_DEFAULT];
@@ -909,7 +909,7 @@ LLSD LLSettingsVOWater::convertToLegacy(const LLSettingsWater::ptr_t &pwater)
 //-------------------------------------------------------------------------
 void LLSettingsVOWater::applySpecial(void *ptarget, bool force)
 {
-    LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
 
     LLEnvironment& env = LLEnvironment::instance();
 
-- 
cgit v1.2.3


From 10e3837c5b2e11a378490c0c6278ce2339fa39cc Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Thu, 13 Jan 2022 12:42:08 -0800
Subject: SL-16606: Add profiler category SPATIAL

---
 indra/newview/llspatialpartition.cpp | 22 ++++++++++++----------
 1 file changed, 12 insertions(+), 10 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp
index 1869370ac7..eaf6186dae 100644
--- a/indra/newview/llspatialpartition.cpp
+++ b/indra/newview/llspatialpartition.cpp
@@ -296,7 +296,7 @@ void LLSpatialPartition::rebuildGeom(LLSpatialGroup* group)
 		group->mLastUpdateViewAngle = group->mViewAngle;
 	}
 	
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_SPATIAL;
 
 	group->clearDrawMap();
 	
@@ -367,7 +367,7 @@ LLSpatialGroup* LLSpatialGroup::getParent()
 
 BOOL LLSpatialGroup::removeObject(LLDrawable *drawablep, BOOL from_octree)
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_SPATIAL
 
 	if(!drawablep)
 	{
@@ -456,7 +456,7 @@ public:
 
 void LLSpatialGroup::setState(U32 state, S32 mode) 
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_SPATIAL
 
 	llassert(state <= LLSpatialGroup::STATE_MASK);
 	
@@ -505,7 +505,7 @@ public:
 
 void LLSpatialGroup::clearState(U32 state, S32 mode)
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_SPATIAL
 
 	llassert(state <= LLSpatialGroup::STATE_MASK);
 
@@ -589,7 +589,7 @@ void LLSpatialGroup::updateDistance(LLCamera &camera)
 
 F32 LLSpatialPartition::calcDistance(LLSpatialGroup* group, LLCamera& camera)
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_SPATIAL
 
 	LLVector4a eye;
 	LLVector4a origin;
@@ -648,9 +648,11 @@ F32 LLSpatialPartition::calcDistance(LLSpatialGroup* group, LLCamera& camera)
 		dist = eye.getLength3().getF32();
 	}
 
+#if !LL_RELEASE
     LL_DEBUGS("RiggedBox") << "calcDistance, group " << group << " camera " << origin << " obj bounds " 
                            << group->mObjectBounds[0] << ", " << group->mObjectBounds[1] 
                            << " dist " << dist << " radius " << group->mRadius << LL_ENDL;
+#endif
 
 	if (dist < 16.f)
 	{
@@ -682,7 +684,7 @@ F32 LLSpatialGroup::getUpdateUrgency() const
 
 BOOL LLSpatialGroup::changeLOD()
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_SPATIAL
 
 	if (hasState(ALPHA_DIRTY | OBJECT_DIRTY))
 	{
@@ -776,7 +778,7 @@ void LLSpatialGroup::handleDestruction(const TreeNode* node)
 
 void LLSpatialGroup::handleChildAddition(const OctreeNode* parent, OctreeNode* child) 
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_SPATIAL
 
 	if (child->getListenerCount() == 0)
 	{
@@ -1351,7 +1353,7 @@ void LLSpatialPartition::resetVertexBuffers()
 
 BOOL LLSpatialPartition::getVisibleExtents(LLCamera& camera, LLVector3& visMin, LLVector3& visMax)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_SPATIAL;
 	LLVector4a visMina, visMaxa;
 	visMina.load3(visMin.mV);
 	visMaxa.load3(visMax.mV);
@@ -1378,7 +1380,7 @@ BOOL LLSpatialPartition::visibleObjectsInFrustum(LLCamera& camera)
 
 S32 LLSpatialPartition::cull(LLCamera &camera, std::vector<LLDrawable *>* results, BOOL for_select)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_SPATIAL;
 #if LL_OCTREE_PARANOIA_CHECK
 	((LLSpatialGroup*)mOctree->getListener(0))->checkStates();
 #endif
@@ -1399,7 +1401,7 @@ S32 LLSpatialPartition::cull(LLCamera &camera, std::vector<LLDrawable *>* result
 	
 S32 LLSpatialPartition::cull(LLCamera &camera, bool do_occlusion)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_SPATIAL;
 #if LL_OCTREE_PARANOIA_CHECK
 	((LLSpatialGroup*)mOctree->getListener(0))->checkStates();
 #endif
-- 
cgit v1.2.3


From 31b0e8cef83780de19fc713791a30f56108b75f6 Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Thu, 13 Jan 2022 12:47:54 -0800
Subject: SL-16606: Add profiler category STATS

---
 indra/llcommon/llfasttimer.cpp         |   4 +-
 indra/llcommon/lltrace.h               |  18 +++---
 indra/llcommon/lltraceaccumulators.cpp |  20 +++----
 indra/llcommon/lltraceaccumulators.h   |  26 ++++-----
 indra/llcommon/lltracerecording.cpp    | 100 ++++++++++++++++-----------------
 indra/llcommon/lltracerecording.h      |  46 +++++++--------
 6 files changed, 107 insertions(+), 107 deletions(-)

(limited to 'indra')

diff --git a/indra/llcommon/llfasttimer.cpp b/indra/llcommon/llfasttimer.cpp
index d38946004f..2612d0f07c 100644
--- a/indra/llcommon/llfasttimer.cpp
+++ b/indra/llcommon/llfasttimer.cpp
@@ -222,7 +222,7 @@ void BlockTimer::bootstrapTimerTree()
 // this preserves partial order derived from current frame's observations
 void BlockTimer::incrementalUpdateTimerTree()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	for(block_timer_tree_df_post_iterator_t it = begin_block_timer_tree_df_post(BlockTimer::getRootTimeBlock());
 		it != end_block_timer_tree_df_post();
 		++it)
@@ -263,7 +263,7 @@ void BlockTimer::incrementalUpdateTimerTree()
 
 void BlockTimer::updateTimes()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	// walk up stack of active timers and accumulate current time while leaving timing structures active
 	BlockTimerStackRecord* stack_record	= LLThreadLocalSingletonPointer<BlockTimerStackRecord>::getInstance();
 	if (!stack_record) return;
diff --git a/indra/llcommon/lltrace.h b/indra/llcommon/lltrace.h
index 4051c558a4..fcd8753f75 100644
--- a/indra/llcommon/lltrace.h
+++ b/indra/llcommon/lltrace.h
@@ -227,7 +227,7 @@ public:
 
 	void setName(const char* name)
 	{
-        LL_PROFILE_ZONE_SCOPED;
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 		mName = name;
 		setKey(name);
 	}
@@ -236,13 +236,13 @@ public:
 
 	StatType<MemAccumulator::AllocationFacet>& allocations() 
 	{
-        LL_PROFILE_ZONE_SCOPED;
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 		return static_cast<StatType<MemAccumulator::AllocationFacet>&>(*(StatType<MemAccumulator>*)this);
 	}
 
 	StatType<MemAccumulator::DeallocationFacet>& deallocations() 
 	{
-        LL_PROFILE_ZONE_SCOPED;
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 		return static_cast<StatType<MemAccumulator::DeallocationFacet>&>(*(StatType<MemAccumulator>*)this);
 	}
 };
@@ -264,7 +264,7 @@ struct MeasureMem<T, typename T::mem_trackable_tag_t, IS_BYTES>
 {
 	static size_t measureFootprint(const T& value)
 	{
-        LL_PROFILE_ZONE_SCOPED;
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 		return sizeof(T) + value.getMemFootprint();
 	}
 };
@@ -274,7 +274,7 @@ struct MeasureMem<T, IS_MEM_TRACKABLE, typename T::is_unit_t>
 {
 	static size_t measureFootprint(const T& value)
 	{
-        LL_PROFILE_ZONE_SCOPED;
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 		return U32Bytes(value).value();
 	}
 };
@@ -284,7 +284,7 @@ struct MeasureMem<T*, IS_MEM_TRACKABLE, IS_BYTES>
 {
 	static size_t measureFootprint(const T* value)
 	{
-        LL_PROFILE_ZONE_SCOPED;
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 		if (!value)
 		{
 			return 0;
@@ -329,7 +329,7 @@ struct MeasureMem<std::basic_string<T>, IS_MEM_TRACKABLE, IS_BYTES>
 {
 	static size_t measureFootprint(const std::basic_string<T>& value)
 	{
-        LL_PROFILE_ZONE_SCOPED;
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 		return value.capacity() * sizeof(T);
 	}
 };
@@ -338,7 +338,7 @@ struct MeasureMem<std::basic_string<T>, IS_MEM_TRACKABLE, IS_BYTES>
 template<typename T>
 inline void claim_alloc(MemStatHandle& measurement, const T& value)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 #if LL_TRACE_ENABLED
 	S32 size = MeasureMem<T>::measureFootprint(value);
 	if(size == 0) return;
@@ -351,7 +351,7 @@ inline void claim_alloc(MemStatHandle& measurement, const T& value)
 template<typename T>
 inline void disclaim_alloc(MemStatHandle& measurement, const T& value)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 #if LL_TRACE_ENABLED
 	S32 size = MeasureMem<T>::measureFootprint(value);
 	if(size == 0) return;
diff --git a/indra/llcommon/lltraceaccumulators.cpp b/indra/llcommon/lltraceaccumulators.cpp
index 8e9aaee0e6..34299f5a29 100644
--- a/indra/llcommon/lltraceaccumulators.cpp
+++ b/indra/llcommon/lltraceaccumulators.cpp
@@ -41,7 +41,7 @@ extern MemStatHandle gTraceMemStat;
 
 AccumulatorBufferGroup::AccumulatorBufferGroup() 
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	claim_alloc(gTraceMemStat, mCounts.capacity() * sizeof(CountAccumulator));
 	claim_alloc(gTraceMemStat, mSamples.capacity() * sizeof(SampleAccumulator));
 	claim_alloc(gTraceMemStat, mEvents.capacity() * sizeof(EventAccumulator));
@@ -56,7 +56,7 @@ AccumulatorBufferGroup::AccumulatorBufferGroup(const AccumulatorBufferGroup& oth
 	mStackTimers(other.mStackTimers),
 	mMemStats(other.mMemStats)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	claim_alloc(gTraceMemStat, mCounts.capacity() * sizeof(CountAccumulator));
 	claim_alloc(gTraceMemStat, mSamples.capacity() * sizeof(SampleAccumulator));
 	claim_alloc(gTraceMemStat, mEvents.capacity() * sizeof(EventAccumulator));
@@ -66,7 +66,7 @@ AccumulatorBufferGroup::AccumulatorBufferGroup(const AccumulatorBufferGroup& oth
 
 AccumulatorBufferGroup::~AccumulatorBufferGroup()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	disclaim_alloc(gTraceMemStat, mCounts.capacity() * sizeof(CountAccumulator));
 	disclaim_alloc(gTraceMemStat, mSamples.capacity() * sizeof(SampleAccumulator));
 	disclaim_alloc(gTraceMemStat, mEvents.capacity() * sizeof(EventAccumulator));
@@ -76,7 +76,7 @@ AccumulatorBufferGroup::~AccumulatorBufferGroup()
 
 void AccumulatorBufferGroup::handOffTo(AccumulatorBufferGroup& other)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	other.mCounts.reset(&mCounts);
 	other.mSamples.reset(&mSamples);
 	other.mEvents.reset(&mEvents);
@@ -86,7 +86,7 @@ void AccumulatorBufferGroup::handOffTo(AccumulatorBufferGroup& other)
 
 void AccumulatorBufferGroup::makeCurrent()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	mCounts.makeCurrent();
 	mSamples.makeCurrent();
 	mEvents.makeCurrent();
@@ -109,7 +109,7 @@ void AccumulatorBufferGroup::makeCurrent()
 //static
 void AccumulatorBufferGroup::clearCurrent()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	AccumulatorBuffer<CountAccumulator>::clearCurrent();	
 	AccumulatorBuffer<SampleAccumulator>::clearCurrent();
 	AccumulatorBuffer<EventAccumulator>::clearCurrent();
@@ -124,7 +124,7 @@ bool AccumulatorBufferGroup::isCurrent() const
 
 void AccumulatorBufferGroup::append( const AccumulatorBufferGroup& other )
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	mCounts.addSamples(other.mCounts, SEQUENTIAL);
 	mSamples.addSamples(other.mSamples, SEQUENTIAL);
 	mEvents.addSamples(other.mEvents, SEQUENTIAL);
@@ -134,7 +134,7 @@ void AccumulatorBufferGroup::append( const AccumulatorBufferGroup& other )
 
 void AccumulatorBufferGroup::merge( const AccumulatorBufferGroup& other)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	mCounts.addSamples(other.mCounts, NON_SEQUENTIAL);
 	mSamples.addSamples(other.mSamples, NON_SEQUENTIAL);
 	mEvents.addSamples(other.mEvents, NON_SEQUENTIAL);
@@ -145,7 +145,7 @@ void AccumulatorBufferGroup::merge( const AccumulatorBufferGroup& other)
 
 void AccumulatorBufferGroup::reset(AccumulatorBufferGroup* other)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	mCounts.reset(other ? &other->mCounts : NULL);
 	mSamples.reset(other ? &other->mSamples : NULL);
 	mEvents.reset(other ? &other->mEvents : NULL);
@@ -155,7 +155,7 @@ void AccumulatorBufferGroup::reset(AccumulatorBufferGroup* other)
 
 void AccumulatorBufferGroup::sync()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	if (isCurrent())
 	{
 		F64SecondsImplicit time_stamp = LLTimer::getTotalSeconds();
diff --git a/indra/llcommon/lltraceaccumulators.h b/indra/llcommon/lltraceaccumulators.h
index b183fcd14a..7267a44300 100644
--- a/indra/llcommon/lltraceaccumulators.h
+++ b/indra/llcommon/lltraceaccumulators.h
@@ -66,7 +66,7 @@ namespace LLTrace
 			: mStorageSize(0),
 			mStorage(NULL)
 		{
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			const AccumulatorBuffer& other = *getDefaultBuffer();
 			resize(sNextStorageSlot);
 			for (S32 i = 0; i < sNextStorageSlot; i++)
@@ -77,7 +77,7 @@ namespace LLTrace
 
 		~AccumulatorBuffer()
 		{
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			if (isCurrent())
 			{
 				LLThreadLocalSingletonPointer<ACCUMULATOR>::setInstance(NULL);
@@ -100,7 +100,7 @@ namespace LLTrace
 			: mStorageSize(0),
 			mStorage(NULL)
 		{
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			resize(sNextStorageSlot);
 			for (S32 i = 0; i < sNextStorageSlot; i++)
 			{
@@ -110,7 +110,7 @@ namespace LLTrace
 
 		void addSamples(const AccumulatorBuffer<ACCUMULATOR>& other, EBufferAppendType append_type)
 		{
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			llassert(mStorageSize >= sNextStorageSlot && other.mStorageSize >= sNextStorageSlot);
 			for (size_t i = 0; i < sNextStorageSlot; i++)
 			{
@@ -120,7 +120,7 @@ namespace LLTrace
 
 		void copyFrom(const AccumulatorBuffer<ACCUMULATOR>& other)
 		{
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			llassert(mStorageSize >= sNextStorageSlot && other.mStorageSize >= sNextStorageSlot);
 			for (size_t i = 0; i < sNextStorageSlot; i++)
 			{
@@ -130,7 +130,7 @@ namespace LLTrace
 
 		void reset(const AccumulatorBuffer<ACCUMULATOR>* other = NULL)
 		{
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			llassert(mStorageSize >= sNextStorageSlot);
 			for (size_t i = 0; i < sNextStorageSlot; i++)
 			{
@@ -140,7 +140,7 @@ namespace LLTrace
 
 		void sync(F64SecondsImplicit time_stamp)
 		{
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			llassert(mStorageSize >= sNextStorageSlot);
 			for (size_t i = 0; i < sNextStorageSlot; i++)
 			{
@@ -166,7 +166,7 @@ namespace LLTrace
 		// NOTE: this is not thread-safe.  We assume that slots are reserved in the main thread before any child threads are spawned
 		size_t reserveSlot()
 		{
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			size_t next_slot = sNextStorageSlot++;
 			if (next_slot >= mStorageSize)
 			{
@@ -180,7 +180,7 @@ namespace LLTrace
 
 		void resize(size_t new_size)
 		{
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			if (new_size <= mStorageSize) return;
 
 			ACCUMULATOR* old_storage = mStorage;
@@ -221,7 +221,7 @@ namespace LLTrace
 
 		static self_t* getDefaultBuffer()
 		{
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			static bool sInitialized = false;
 			if (!sInitialized)
 			{
@@ -336,7 +336,7 @@ namespace LLTrace
 
 		void sample(F64 value)
 		{
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			F64SecondsImplicit time_stamp = LLTimer::getTotalSeconds();
 
 			// store effect of last value
@@ -550,7 +550,7 @@ namespace LLTrace
 
 		void addSamples(const MemAccumulator& other, EBufferAppendType append_type)
 		{
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			mAllocations.addSamples(other.mAllocations, append_type);
 			mDeallocations.addSamples(other.mDeallocations, append_type);
 
@@ -569,7 +569,7 @@ namespace LLTrace
 
 		void reset(const MemAccumulator* other)
 		{
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			mSize.reset(other ? &other->mSize : NULL);
 			mAllocations.reset(other ? &other->mAllocations : NULL);
 			mDeallocations.reset(other ? &other->mDeallocations : NULL);
diff --git a/indra/llcommon/lltracerecording.cpp b/indra/llcommon/lltracerecording.cpp
index 5ce1b337fe..1613af1dcf 100644
--- a/indra/llcommon/lltracerecording.cpp
+++ b/indra/llcommon/lltracerecording.cpp
@@ -50,7 +50,7 @@ Recording::Recording(EPlayState state)
 :	mElapsedSeconds(0),
 	mActiveBuffers(NULL)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	claim_alloc(gTraceMemStat, this);
 	mBuffers = new AccumulatorBufferGroup();
 	claim_alloc(gTraceMemStat, mBuffers);
@@ -60,14 +60,14 @@ Recording::Recording(EPlayState state)
 Recording::Recording( const Recording& other )
 :	mActiveBuffers(NULL)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	claim_alloc(gTraceMemStat, this);
 	*this = other;
 }
 
 Recording& Recording::operator = (const Recording& other)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	// this will allow us to seamlessly start without affecting any data we've acquired from other
 	setPlayState(PAUSED);
 
@@ -88,7 +88,7 @@ Recording& Recording::operator = (const Recording& other)
 
 Recording::~Recording()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	disclaim_alloc(gTraceMemStat, this);
 	disclaim_alloc(gTraceMemStat, mBuffers);
 
@@ -107,7 +107,7 @@ void Recording::update()
 #if LL_TRACE_ENABLED
 	if (isStarted())
 	{
-        LL_PROFILE_ZONE_SCOPED;
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 		mElapsedSeconds += mSamplingTimer.getElapsedTimeF64();
 
 		// must have 
@@ -128,7 +128,7 @@ void Recording::update()
 
 void Recording::handleReset()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 #if LL_TRACE_ENABLED
 	mBuffers.write()->reset();
 
@@ -139,7 +139,7 @@ void Recording::handleReset()
 
 void Recording::handleStart()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 #if LL_TRACE_ENABLED
 	mSamplingTimer.reset();
 	mBuffers.setStayUnique(true);
@@ -151,7 +151,7 @@ void Recording::handleStart()
 
 void Recording::handleStop()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 #if LL_TRACE_ENABLED
 	mElapsedSeconds += mSamplingTimer.getElapsedTimeF64();
 	// must have thread recorder running on this thread
@@ -583,20 +583,20 @@ PeriodicRecording::PeriodicRecording( S32 num_periods, EPlayState state)
 	mNumRecordedPeriods(0),
 	mRecordingPeriods(num_periods ? num_periods : 1)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	setPlayState(state);
 	claim_alloc(gTraceMemStat, this);
 }
 
 PeriodicRecording::~PeriodicRecording()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	disclaim_alloc(gTraceMemStat, this);
 }
 
 void PeriodicRecording::nextPeriod()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	if (mAutoResize)
 	{
 		mRecordingPeriods.push_back(Recording());
@@ -611,7 +611,7 @@ void PeriodicRecording::nextPeriod()
 
 void PeriodicRecording::appendRecording(Recording& recording)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	getCurRecording().appendRecording(recording);
 	nextPeriod();
 }
@@ -619,7 +619,7 @@ void PeriodicRecording::appendRecording(Recording& recording)
 
 void PeriodicRecording::appendPeriodicRecording( PeriodicRecording& other )
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	if (other.mRecordingPeriods.empty()) return;
 
 	getCurRecording().update();
@@ -693,7 +693,7 @@ void PeriodicRecording::appendPeriodicRecording( PeriodicRecording& other )
 
 F64Seconds PeriodicRecording::getDuration() const
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	F64Seconds duration;
 	S32 num_periods = mRecordingPeriods.size();
 	for (S32 i = 1; i <= num_periods; i++)
@@ -707,7 +707,7 @@ F64Seconds PeriodicRecording::getDuration() const
 
 LLTrace::Recording PeriodicRecording::snapshotCurRecording() const
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	Recording recording_copy(getCurRecording());
 	recording_copy.stop();
 	return recording_copy;
@@ -750,19 +750,19 @@ const Recording& PeriodicRecording::getPrevRecording( S32 offset ) const
 
 void PeriodicRecording::handleStart()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	getCurRecording().start();
 }
 
 void PeriodicRecording::handleStop()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	getCurRecording().pause();
 }
 
 void PeriodicRecording::handleReset()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	getCurRecording().stop();
 
 	if (mAutoResize)
@@ -786,13 +786,13 @@ void PeriodicRecording::handleReset()
 
 void PeriodicRecording::handleSplitTo(PeriodicRecording& other)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	getCurRecording().splitTo(other.getCurRecording());
 }
 
 F64 PeriodicRecording::getPeriodMin( const StatType<EventAccumulator>& stat, S32 num_periods /*= S32_MAX*/ )
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	num_periods = llmin(num_periods, getNumRecordedPeriods());
 
 	bool has_value = false;
@@ -814,7 +814,7 @@ F64 PeriodicRecording::getPeriodMin( const StatType<EventAccumulator>& stat, S32
 
 F64 PeriodicRecording::getPeriodMax( const StatType<EventAccumulator>& stat, S32 num_periods /*= S32_MAX*/ )
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	num_periods = llmin(num_periods, getNumRecordedPeriods());
 
 	bool has_value = false;
@@ -837,7 +837,7 @@ F64 PeriodicRecording::getPeriodMax( const StatType<EventAccumulator>& stat, S32
 // calculates means using aggregates per period
 F64 PeriodicRecording::getPeriodMean( const StatType<EventAccumulator>& stat, S32 num_periods /*= S32_MAX*/ )
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	num_periods = llmin(num_periods, getNumRecordedPeriods());
 
 	F64 mean = 0;
@@ -860,7 +860,7 @@ F64 PeriodicRecording::getPeriodMean( const StatType<EventAccumulator>& stat, S3
 
 F64 PeriodicRecording::getPeriodStandardDeviation( const StatType<EventAccumulator>& stat, S32 num_periods /*= S32_MAX*/ )
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	num_periods = llmin(num_periods, getNumRecordedPeriods());
 
 	F64 period_mean = getPeriodMean(stat, num_periods);
@@ -885,7 +885,7 @@ F64 PeriodicRecording::getPeriodStandardDeviation( const StatType<EventAccumulat
 
 F64 PeriodicRecording::getPeriodMin( const StatType<SampleAccumulator>& stat, S32 num_periods /*= S32_MAX*/ )
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	num_periods = llmin(num_periods, getNumRecordedPeriods());
 
 	bool has_value = false;
@@ -907,7 +907,7 @@ F64 PeriodicRecording::getPeriodMin( const StatType<SampleAccumulator>& stat, S3
 
 F64 PeriodicRecording::getPeriodMax(const StatType<SampleAccumulator>& stat, S32 num_periods /*= S32_MAX*/)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	num_periods = llmin(num_periods, getNumRecordedPeriods());
 
 	bool has_value = false;
@@ -930,7 +930,7 @@ F64 PeriodicRecording::getPeriodMax(const StatType<SampleAccumulator>& stat, S32
 
 F64 PeriodicRecording::getPeriodMean( const StatType<SampleAccumulator>& stat, S32 num_periods /*= S32_MAX*/ )
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	num_periods = llmin(num_periods, getNumRecordedPeriods());
 
 	S32 valid_period_count = 0;
@@ -953,7 +953,7 @@ F64 PeriodicRecording::getPeriodMean( const StatType<SampleAccumulator>& stat, S
 
 F64 PeriodicRecording::getPeriodMedian( const StatType<SampleAccumulator>& stat, S32 num_periods /*= S32_MAX*/ )
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	num_periods = llmin(num_periods, getNumRecordedPeriods());
 
 	std::vector<F64> buf;
@@ -979,7 +979,7 @@ F64 PeriodicRecording::getPeriodMedian( const StatType<SampleAccumulator>& stat,
 
 F64 PeriodicRecording::getPeriodStandardDeviation( const StatType<SampleAccumulator>& stat, S32 num_periods /*= S32_MAX*/ )
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	num_periods = llmin(num_periods, getNumRecordedPeriods());
 
 	F64 period_mean = getPeriodMean(stat, num_periods);
@@ -1005,7 +1005,7 @@ F64 PeriodicRecording::getPeriodStandardDeviation( const StatType<SampleAccumula
 
 F64Kilobytes PeriodicRecording::getPeriodMin( const StatType<MemAccumulator>& stat, S32 num_periods /*= S32_MAX*/ )
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	num_periods = llmin(num_periods, getNumRecordedPeriods());
 
 	F64Kilobytes min_val(std::numeric_limits<F64>::max());
@@ -1025,7 +1025,7 @@ F64Kilobytes PeriodicRecording::getPeriodMin(const MemStatHandle& stat, S32 num_
 
 F64Kilobytes PeriodicRecording::getPeriodMax(const StatType<MemAccumulator>& stat, S32 num_periods /*= S32_MAX*/)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	num_periods = llmin(num_periods, getNumRecordedPeriods());
 
 	F64Kilobytes max_val(0.0);
@@ -1045,7 +1045,7 @@ F64Kilobytes PeriodicRecording::getPeriodMax(const MemStatHandle& stat, S32 num_
 
 F64Kilobytes PeriodicRecording::getPeriodMean( const StatType<MemAccumulator>& stat, S32 num_periods /*= S32_MAX*/ )
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	num_periods = llmin(num_periods, getNumRecordedPeriods());
 
 	F64Kilobytes mean(0);
@@ -1066,7 +1066,7 @@ F64Kilobytes PeriodicRecording::getPeriodMean(const MemStatHandle& stat, S32 num
 
 F64Kilobytes PeriodicRecording::getPeriodStandardDeviation( const StatType<MemAccumulator>& stat, S32 num_periods /*= S32_MAX*/ )
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	num_periods = llmin(num_periods, getNumRecordedPeriods());
 
 	F64Kilobytes period_mean = getPeriodMean(stat, num_periods);
@@ -1100,7 +1100,7 @@ F64Kilobytes PeriodicRecording::getPeriodStandardDeviation(const MemStatHandle&
 
 void ExtendableRecording::extend()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	// push the data back to accepted recording
 	mAcceptedRecording.appendRecording(mPotentialRecording);
 	// flush data, so we can start from scratch
@@ -1109,26 +1109,26 @@ void ExtendableRecording::extend()
 
 void ExtendableRecording::handleStart()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	mPotentialRecording.start();
 }
 
 void ExtendableRecording::handleStop()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	mPotentialRecording.pause();
 }
 
 void ExtendableRecording::handleReset()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	mAcceptedRecording.reset();
 	mPotentialRecording.reset();
 }
 
 void ExtendableRecording::handleSplitTo(ExtendableRecording& other)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	mPotentialRecording.splitTo(other.mPotentialRecording);
 }
 
@@ -1145,7 +1145,7 @@ ExtendablePeriodicRecording::ExtendablePeriodicRecording()
 
 void ExtendablePeriodicRecording::extend()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	// push the data back to accepted recording
 	mAcceptedRecording.appendPeriodicRecording(mPotentialRecording);
 	// flush data, so we can start from scratch
@@ -1155,26 +1155,26 @@ void ExtendablePeriodicRecording::extend()
 
 void ExtendablePeriodicRecording::handleStart()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	mPotentialRecording.start();
 }
 
 void ExtendablePeriodicRecording::handleStop()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	mPotentialRecording.pause();
 }
 
 void ExtendablePeriodicRecording::handleReset()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	mAcceptedRecording.reset();
 	mPotentialRecording.reset();
 }
 
 void ExtendablePeriodicRecording::handleSplitTo(ExtendablePeriodicRecording& other)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	mPotentialRecording.splitTo(other.mPotentialRecording);
 }
 
@@ -1189,7 +1189,7 @@ PeriodicRecording& get_frame_recording()
 
 void LLStopWatchControlsMixinCommon::start()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	switch (mPlayState)
 	{
 	case STOPPED:
@@ -1211,7 +1211,7 @@ void LLStopWatchControlsMixinCommon::start()
 
 void LLStopWatchControlsMixinCommon::stop()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	switch (mPlayState)
 	{
 	case STOPPED:
@@ -1231,7 +1231,7 @@ void LLStopWatchControlsMixinCommon::stop()
 
 void LLStopWatchControlsMixinCommon::pause()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	switch (mPlayState)
 	{
 	case STOPPED:
@@ -1251,7 +1251,7 @@ void LLStopWatchControlsMixinCommon::pause()
 
 void LLStopWatchControlsMixinCommon::unpause()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	switch (mPlayState)
 	{
 	case STOPPED:
@@ -1271,7 +1271,7 @@ void LLStopWatchControlsMixinCommon::unpause()
 
 void LLStopWatchControlsMixinCommon::resume()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	switch (mPlayState)
 	{
 	case STOPPED:
@@ -1292,7 +1292,7 @@ void LLStopWatchControlsMixinCommon::resume()
 
 void LLStopWatchControlsMixinCommon::restart()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	switch (mPlayState)
 	{
 	case STOPPED:
@@ -1316,13 +1316,13 @@ void LLStopWatchControlsMixinCommon::restart()
 
 void LLStopWatchControlsMixinCommon::reset()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	handleReset();
 }
 
 void LLStopWatchControlsMixinCommon::setPlayState( EPlayState state )
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	switch(state)
 	{
 	case STOPPED:
diff --git a/indra/llcommon/lltracerecording.h b/indra/llcommon/lltracerecording.h
index 1f3d37336a..556b7470cf 100644
--- a/indra/llcommon/lltracerecording.h
+++ b/indra/llcommon/lltracerecording.h
@@ -355,7 +355,7 @@ namespace LLTrace
 		template <typename T>
 		S32 getSampleCount(const StatType<T>& stat, S32 num_periods = S32_MAX)
         {
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			num_periods = llmin(num_periods, getNumRecordedPeriods());
 
             S32 num_samples = 0;
@@ -375,7 +375,7 @@ namespace LLTrace
 		template <typename T>
 		typename T::value_t getPeriodMin(const StatType<T>& stat, S32 num_periods = S32_MAX)
 		{
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			num_periods = llmin(num_periods, getNumRecordedPeriods());
 
 			bool has_value = false;
@@ -398,7 +398,7 @@ namespace LLTrace
 		template<typename T>
 		T getPeriodMin(const CountStatHandle<T>& stat, S32 num_periods = S32_MAX)
 		{
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			return T(getPeriodMin(static_cast<const StatType<CountAccumulator>&>(stat), num_periods));
 		}
 
@@ -406,7 +406,7 @@ namespace LLTrace
 		template<typename T>
 		T getPeriodMin(const SampleStatHandle<T>& stat, S32 num_periods = S32_MAX)
 		{
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			return T(getPeriodMin(static_cast<const StatType<SampleAccumulator>&>(stat), num_periods));
 		}
 
@@ -414,7 +414,7 @@ namespace LLTrace
 		template<typename T>
 		T getPeriodMin(const EventStatHandle<T>& stat, S32 num_periods = S32_MAX)
 		{
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			return T(getPeriodMin(static_cast<const StatType<EventAccumulator>&>(stat), num_periods));
 		}
 
@@ -424,7 +424,7 @@ namespace LLTrace
 		template <typename T>
 		typename RelatedTypes<typename T::value_t>::fractional_t getPeriodMinPerSec(const StatType<T>& stat, S32 num_periods = S32_MAX)
 		{
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			num_periods = llmin(num_periods, getNumRecordedPeriods());
 
 			typename RelatedTypes<typename T::value_t>::fractional_t min_val(std::numeric_limits<F64>::max());
@@ -439,7 +439,7 @@ namespace LLTrace
 		template<typename T>
 		typename RelatedTypes<T>::fractional_t getPeriodMinPerSec(const CountStatHandle<T>& stat, S32 num_periods = S32_MAX)
 		{
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			return typename RelatedTypes<T>::fractional_t(getPeriodMinPerSec(static_cast<const StatType<CountAccumulator>&>(stat), num_periods));
 		}
 
@@ -451,7 +451,7 @@ namespace LLTrace
 		template <typename T>
 		typename T::value_t getPeriodMax(const StatType<T>& stat, S32 num_periods = S32_MAX)
 		{
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			num_periods = llmin(num_periods, getNumRecordedPeriods());
 
 			bool has_value = false;
@@ -474,7 +474,7 @@ namespace LLTrace
 		template<typename T>
 		T getPeriodMax(const CountStatHandle<T>& stat, S32 num_periods = S32_MAX)
 		{
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			return T(getPeriodMax(static_cast<const StatType<CountAccumulator>&>(stat), num_periods));
 		}
 
@@ -482,7 +482,7 @@ namespace LLTrace
 		template<typename T>
 		T getPeriodMax(const SampleStatHandle<T>& stat, S32 num_periods = S32_MAX)
 		{
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			return T(getPeriodMax(static_cast<const StatType<SampleAccumulator>&>(stat), num_periods));
 		}
 
@@ -490,7 +490,7 @@ namespace LLTrace
 		template<typename T>
 		T getPeriodMax(const EventStatHandle<T>& stat, S32 num_periods = S32_MAX)
 		{
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			return T(getPeriodMax(static_cast<const StatType<EventAccumulator>&>(stat), num_periods));
 		}
 
@@ -500,7 +500,7 @@ namespace LLTrace
 		template <typename T>
 		typename RelatedTypes<typename T::value_t>::fractional_t getPeriodMaxPerSec(const StatType<T>& stat, S32 num_periods = S32_MAX)
 		{
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			num_periods = llmin(num_periods, getNumRecordedPeriods());
 
 			F64 max_val = std::numeric_limits<F64>::min();
@@ -515,7 +515,7 @@ namespace LLTrace
 		template<typename T>
 		typename RelatedTypes<T>::fractional_t getPeriodMaxPerSec(const CountStatHandle<T>& stat, S32 num_periods = S32_MAX)
 		{
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			return typename RelatedTypes<T>::fractional_t(getPeriodMaxPerSec(static_cast<const StatType<CountAccumulator>&>(stat), num_periods));
 		}
 
@@ -527,7 +527,7 @@ namespace LLTrace
 		template <typename T>
 		typename RelatedTypes<typename T::value_t>::fractional_t getPeriodMean(const StatType<T >& stat, S32 num_periods = S32_MAX)
 		{
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			num_periods = llmin(num_periods, getNumRecordedPeriods());
 
 			typename RelatedTypes<typename T::value_t>::fractional_t mean(0);
@@ -548,14 +548,14 @@ namespace LLTrace
 		template<typename T>
 		typename RelatedTypes<T>::fractional_t getPeriodMean(const CountStatHandle<T>& stat, S32 num_periods = S32_MAX)
 		{
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			return typename RelatedTypes<T>::fractional_t(getPeriodMean(static_cast<const StatType<CountAccumulator>&>(stat), num_periods));
 		}
 		F64 getPeriodMean(const StatType<SampleAccumulator>& stat, S32 num_periods = S32_MAX);
 		template<typename T> 
 		typename RelatedTypes<T>::fractional_t getPeriodMean(const SampleStatHandle<T>& stat, S32 num_periods = S32_MAX)
 		{
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			return typename RelatedTypes<T>::fractional_t(getPeriodMean(static_cast<const StatType<SampleAccumulator>&>(stat), num_periods));
 		}
 
@@ -563,7 +563,7 @@ namespace LLTrace
 		template<typename T>
 		typename RelatedTypes<T>::fractional_t getPeriodMean(const EventStatHandle<T>& stat, S32 num_periods = S32_MAX)
 		{
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			return typename RelatedTypes<T>::fractional_t(getPeriodMean(static_cast<const StatType<EventAccumulator>&>(stat), num_periods));
 		}
 
@@ -573,7 +573,7 @@ namespace LLTrace
 		template <typename T>
 		typename RelatedTypes<typename T::value_t>::fractional_t getPeriodMeanPerSec(const StatType<T>& stat, S32 num_periods = S32_MAX)
 		{
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			num_periods = llmin(num_periods, getNumRecordedPeriods());
 
 			typename RelatedTypes<typename T::value_t>::fractional_t mean = 0;
@@ -595,7 +595,7 @@ namespace LLTrace
 		template<typename T>
 		typename RelatedTypes<T>::fractional_t getPeriodMeanPerSec(const CountStatHandle<T>& stat, S32 num_periods = S32_MAX)
 		{
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			return typename RelatedTypes<T>::fractional_t(getPeriodMeanPerSec(static_cast<const StatType<CountAccumulator>&>(stat), num_periods));
 		}
 
@@ -604,7 +604,7 @@ namespace LLTrace
         template <typename T>
         typename RelatedTypes<typename T::value_t>::fractional_t getPeriodMedianPerSec(const StatType<T>& stat, S32 num_periods = S32_MAX)
         {
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
             num_periods = llmin(num_periods, getNumRecordedPeriods());
 
             std::vector <typename RelatedTypes<typename T::value_t>::fractional_t> buf;
@@ -624,7 +624,7 @@ namespace LLTrace
         template<typename T>
         typename RelatedTypes<T>::fractional_t getPeriodMedianPerSec(const CountStatHandle<T>& stat, S32 num_periods = S32_MAX)
         {
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
             return typename RelatedTypes<T>::fractional_t(getPeriodMedianPerSec(static_cast<const StatType<CountAccumulator>&>(stat), num_periods));
         }
 
@@ -637,7 +637,7 @@ namespace LLTrace
 		template<typename T> 
 		typename RelatedTypes<T>::fractional_t getPeriodStandardDeviation(const SampleStatHandle<T>& stat, S32 num_periods = S32_MAX)
 		{
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			return typename RelatedTypes<T>::fractional_t(getPeriodStandardDeviation(static_cast<const StatType<SampleAccumulator>&>(stat), num_periods));
 		}
 
@@ -645,7 +645,7 @@ namespace LLTrace
 		template<typename T>
 		typename RelatedTypes<T>::fractional_t getPeriodStandardDeviation(const EventStatHandle<T>& stat, S32 num_periods = S32_MAX)
 		{
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			return typename RelatedTypes<T>::fractional_t(getPeriodStandardDeviation(static_cast<const StatType<EventAccumulator>&>(stat), num_periods));
 		}
 
-- 
cgit v1.2.3


From 12fd860636e8d45087f94c8252212c103f49e1ad Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Thu, 13 Jan 2022 12:49:11 -0800
Subject: SL-16606: Add profiler category STRING

---
 indra/llcommon/llstring.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

(limited to 'indra')

diff --git a/indra/llcommon/llstring.cpp b/indra/llcommon/llstring.cpp
index bdea1e76ea..7f501f2e77 100644
--- a/indra/llcommon/llstring.cpp
+++ b/indra/llcommon/llstring.cpp
@@ -1317,7 +1317,7 @@ bool LLStringUtil::formatDatetime(std::string& replacement, std::string token,
 template<> 
 S32 LLStringUtil::format(std::string& s, const format_map_t& substitutions)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STRING;
 	S32 res = 0;
 
 	std::string output;
@@ -1390,7 +1390,7 @@ S32 LLStringUtil::format(std::string& s, const format_map_t& substitutions)
 template<> 
 S32 LLStringUtil::format(std::string& s, const LLSD& substitutions)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STRING;
 	S32 res = 0;
 
 	if (!substitutions.isMap()) 
-- 
cgit v1.2.3


From bf0643e28ae67c46dd1fa4f01874907a60ab038f Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Thu, 13 Jan 2022 12:52:28 -0800
Subject: SL-16606: Add profiler category TEXTURE

---
 indra/llimage/llimageworker.cpp       |  8 ++--
 indra/llrender/llgltexture.cpp        |  4 +-
 indra/llrender/llimagegl.cpp          | 28 ++++++------
 indra/newview/llviewertexture.cpp     | 60 +++++++++++++-------------
 indra/newview/llviewertexturelist.cpp | 80 +++++++++++++++++------------------
 5 files changed, 90 insertions(+), 90 deletions(-)

(limited to 'indra')

diff --git a/indra/llimage/llimageworker.cpp b/indra/llimage/llimageworker.cpp
index 33f8dce6ee..0dbb744bcf 100644
--- a/indra/llimage/llimageworker.cpp
+++ b/indra/llimage/llimageworker.cpp
@@ -48,7 +48,7 @@ LLImageDecodeThread::~LLImageDecodeThread()
 // virtual
 S32 LLImageDecodeThread::update(F32 max_time_ms)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	LLMutexLock lock(mCreationMutex);
 	for (creation_list_t::iterator iter = mCreationList.begin();
 		 iter != mCreationList.end(); ++iter)
@@ -72,7 +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;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	LLMutexLock lock(mCreationMutex);
 	handle_t handle = generateHandle();
 	mCreationList.push_back(creation_info(handle, image, priority, discard, needs_aux, responder));
@@ -120,7 +120,7 @@ LLImageDecodeThread::ImageRequest::~ImageRequest()
 // Returns true when done, whether or not decode was successful.
 bool LLImageDecodeThread::ImageRequest::processRequest()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	const F32 decode_time_slice = .1f;
 	bool done = true;
 	if (!mDecodedRaw && mFormattedImage.notNull())
@@ -167,7 +167,7 @@ bool LLImageDecodeThread::ImageRequest::processRequest()
 
 void LLImageDecodeThread::ImageRequest::finishRequest(bool completed)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	if (mResponder.notNull())
 	{
 		bool success = completed && mDecodedRaw && (!mNeedsAux || mDecodedAux);
diff --git a/indra/llrender/llgltexture.cpp b/indra/llrender/llgltexture.cpp
index a279e85bae..b6a02f1c0a 100644
--- a/indra/llrender/llgltexture.cpp
+++ b/indra/llrender/llgltexture.cpp
@@ -262,7 +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;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	llassert(mGLTexturep.notNull()) ;
 
 	return mGLTexturep->setSubImage(imageraw, x_pos, y_pos, width, height) ;
@@ -270,7 +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;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	llassert(mGLTexturep.notNull()) ;
 
 	return mGLTexturep->setSubImage(datap, data_width, data_height, x_pos, y_pos, width, height) ;
diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp
index 9931ce7d3e..1e9b9f642e 100644
--- a/indra/llrender/llimagegl.cpp
+++ b/indra/llrender/llimagegl.cpp
@@ -181,7 +181,7 @@ BOOL is_little_endian()
 //static 
 void LLImageGL::initClass(LLWindow* window, S32 num_catagories, BOOL skip_analyze_alpha /* = false */, bool multi_threaded /* = false */)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	sSkipAnalyzeAlpha = skip_analyze_alpha;
 
     if (multi_threaded)
@@ -193,7 +193,7 @@ void LLImageGL::initClass(LLWindow* window, S32 num_catagories, BOOL skip_analyz
 //static 
 void LLImageGL::cleanupClass() 
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
     LLImageGLThread::deleteSingleton();
 }
 
@@ -277,7 +277,7 @@ S32 LLImageGL::dataFormatComponents(S32 dataformat)
 // static
 void LLImageGL::updateStats(F32 current_time)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	sLastFrameTime = current_time;
 	sBoundTextureMemory = sCurBoundTextureMemory;
 	sCurBoundTextureMemory = S32Bytes(0);
@@ -666,7 +666,7 @@ void LLImageGL::setExplicitFormat( LLGLint internal_format, LLGLenum primary_for
 
 void LLImageGL::setImage(const LLImageRaw* imageraw)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	llassert((imageraw->getWidth() == getWidth(mCurrentDiscardLevel)) &&
 			 (imageraw->getHeight() == getHeight(mCurrentDiscardLevel)) &&
 			 (imageraw->getComponents() == getComponents()));
@@ -676,7 +676,7 @@ void LLImageGL::setImage(const LLImageRaw* imageraw)
 
 BOOL LLImageGL::setImage(const U8* data_in, BOOL data_hasmips, S32 usename)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	bool is_compressed = false;
 
     switch (mFormatPrimary)
@@ -1071,7 +1071,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;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	if (!width || !height)
 	{
 		return TRUE;
@@ -1168,7 +1168,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;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	return setSubImage(imageraw->getData(), imageraw->getWidth(), imageraw->getHeight(), x_pos, y_pos, width, height, force_fast_update);
 }
 
@@ -1191,7 +1191,7 @@ BOOL LLImageGL::setSubImageFromFrameBuffer(S32 fb_x, S32 fb_y, S32 x_pos, S32 y_
 // static
 void LLImageGL::generateTextures(S32 numTextures, U32 *textures)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	glGenTextures(numTextures, textures);
 }
 
@@ -1207,7 +1207,7 @@ void LLImageGL::deleteTextures(S32 numTextures, const U32 *textures)
 // static
 void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 width, S32 height, U32 pixformat, U32 pixtype, const void* pixels, bool allow_compression)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
     bool use_scratch = false;
     U32* scratch = NULL;
     if (LLRender::sGLCoreProfile)
@@ -1324,7 +1324,7 @@ void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 widt
 //the texture is assiciate with some image by calling glTexImage outside LLImageGL
 BOOL LLImageGL::createGLTexture()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
     checkActiveThread();
 
 	if (gGLManager.mIsDisabled)
@@ -1358,7 +1358,7 @@ BOOL LLImageGL::createGLTexture()
 
 BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename/*=0*/, BOOL to_create, S32 category)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
     checkActiveThread();
 
 	if (gGLManager.mIsDisabled)
@@ -1473,7 +1473,7 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S
 
 BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_hasmips, S32 usename)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
     checkActiveThread();
 
     llassert(data_in);
@@ -2264,7 +2264,7 @@ LLImageGLThread::LLImageGLThread(LLWindow* window)
     : ThreadPool("LLImageGL", 1, 1024*1024)
     , mWindow(window)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
     sEnabled = true;
     mFinished = false;
 
@@ -2274,7 +2274,7 @@ LLImageGLThread::LLImageGLThread(LLWindow* window)
 
 void LLImageGLThread::run()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
     // We must perform setup on this thread before actually servicing our
     // WorkQueue, likewise cleanup afterwards.
     mWindow->makeContextCurrent(mContext);
diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp
index dcdc259b26..06f623f1f8 100644
--- a/indra/newview/llviewertexture.cpp
+++ b/indra/newview/llviewertexture.cpp
@@ -182,7 +182,7 @@ void LLViewerTextureManager::findFetchedTextures(const LLUUID& id, std::vector<L
 
 void  LLViewerTextureManager::findTextures(const LLUUID& id, std::vector<LLViewerTexture*> &output)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
     std::vector<LLViewerFetchedTexture*> fetched_output;
     gTextureList.findTexturesByID(id, fetched_output);
     std::vector<LLViewerFetchedTexture*>::iterator iter = fetched_output.begin();
@@ -207,7 +207,7 @@ void  LLViewerTextureManager::findTextures(const LLUUID& id, std::vector<LLViewe
 
 LLViewerFetchedTexture* LLViewerTextureManager::findFetchedTexture(const LLUUID& id, S32 tex_type)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
     return gTextureList.findImage(id, (ETexListType)tex_type);
 }
 
@@ -482,7 +482,7 @@ F32 texmem_middle_bound_scale = 0.925f;
 //static 
 bool LLViewerTexture::isMemoryForTextureLow()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
     // Note: we need to figure out a better source for 'min' values,
     // what is free for low end at minimal settings is 'nothing left'
     // for higher end gpus at high settings.
@@ -499,7 +499,7 @@ bool LLViewerTexture::isMemoryForTextureLow()
 //static
 bool LLViewerTexture::isMemoryForTextureSuficientlyFree()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
     const S32Megabytes DESIRED_FREE_TEXTURE_MEMORY(50);
     const S32Megabytes DESIRED_FREE_MAIN_MEMORY(200);
 
@@ -513,7 +513,7 @@ bool LLViewerTexture::isMemoryForTextureSuficientlyFree()
 //static
 void LLViewerTexture::getGPUMemoryForTextures(S32Megabytes &gpu, S32Megabytes &physical)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
     static LLFrameTimer timer;
     static S32Megabytes gpu_res = S32Megabytes(S32_MAX);
     static S32Megabytes physical_res = S32Megabytes(S32_MAX);
@@ -552,7 +552,7 @@ void LLViewerTexture::getGPUMemoryForTextures(S32Megabytes &gpu, S32Megabytes &p
 //static
 void LLViewerTexture::updateClass()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	sCurrentTime = gFrameTimeSeconds;
 
 	LLTexturePipelineTester* tester = (LLTexturePipelineTester*)LLMetricPerformanceTesterBasic::getTester(sTesterName);
@@ -701,7 +701,7 @@ void LLViewerTexture::cleanup()
 
 void LLViewerTexture::notifyAboutCreatingTexture()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	for(U32 ch = 0; ch < LLRender::NUM_TEXTURE_CHANNELS; ++ch)
 	{
 		for(U32 f = 0; f < mNumFaces[ch]; f++)
@@ -713,7 +713,7 @@ void LLViewerTexture::notifyAboutCreatingTexture()
 
 void LLViewerTexture::notifyAboutMissingAsset()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	for(U32 ch = 0; ch < LLRender::NUM_TEXTURE_CHANNELS; ++ch)
 	{
 		for(U32 f = 0; f < mNumFaces[ch]; f++)
@@ -726,7 +726,7 @@ void LLViewerTexture::notifyAboutMissingAsset()
 // virtual
 void LLViewerTexture::dump()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	LLGLTexture::dump();
 
 	LL_INFOS() << "LLViewerTexture"
@@ -762,7 +762,7 @@ bool LLViewerTexture::isActiveFetching()
 
 bool LLViewerTexture::bindDebugImage(const S32 stage)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	if (stage < 0) return false;
 
 	bool res = true;
@@ -781,7 +781,7 @@ bool LLViewerTexture::bindDebugImage(const S32 stage)
 
 bool LLViewerTexture::bindDefaultImage(S32 stage) 
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	if (stage < 0) return false;
 
 	bool res = true;
@@ -824,7 +824,7 @@ void LLViewerTexture::forceImmediateUpdate()
 
 void LLViewerTexture::addTextureStats(F32 virtual_size, BOOL needs_gltexture) const 
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	if(needs_gltexture)
 	{
 		mNeedsGLTexture = TRUE;
@@ -867,7 +867,7 @@ void LLViewerTexture::setKnownDrawSize(S32 width, S32 height)
 //virtual
 void LLViewerTexture::addFace(U32 ch, LLFace* facep) 
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	llassert(ch < LLRender::NUM_TEXTURE_CHANNELS);
 
 	if(mNumFaces[ch] >= mFaceList[ch].size())
@@ -883,7 +883,7 @@ void LLViewerTexture::addFace(U32 ch, LLFace* facep)
 //virtual
 void LLViewerTexture::removeFace(U32 ch, LLFace* facep) 
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	llassert(ch < LLRender::NUM_TEXTURE_CHANNELS);
 
 	if(mNumFaces[ch] > 1)
@@ -924,7 +924,7 @@ S32 LLViewerTexture::getNumFaces(U32 ch) const
 //virtual
 void LLViewerTexture::addVolume(U32 ch, LLVOVolume* volumep)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	if (mNumVolumes[ch] >= mVolumeList[ch].size())
 	{
 		mVolumeList[ch].resize(2 * mNumVolumes[ch] + 1);
@@ -938,7 +938,7 @@ void LLViewerTexture::addVolume(U32 ch, LLVOVolume* volumep)
 //virtual
 void LLViewerTexture::removeVolume(U32 ch, LLVOVolume* volumep)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	if (mNumVolumes[ch] > 1)
 	{
 		S32 index = volumep->getIndexInTex(ch); 
@@ -962,7 +962,7 @@ S32 LLViewerTexture::getNumVolumes(U32 ch) const
 
 void LLViewerTexture::reorganizeFaceList()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	static const F32 MAX_WAIT_TIME = 20.f; // seconds
 	static const U32 MAX_EXTRA_BUFFER_SIZE = 4;
 
@@ -986,7 +986,7 @@ void LLViewerTexture::reorganizeFaceList()
 
 void LLViewerTexture::reorganizeVolumeList()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	static const F32 MAX_WAIT_TIME = 20.f; // seconds
 	static const U32 MAX_EXTRA_BUFFER_SIZE = 4;
 
@@ -1189,7 +1189,7 @@ FTType LLViewerFetchedTexture::getFTType() const
 
 void LLViewerFetchedTexture::cleanup()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	for(callback_list_t::iterator iter = mLoadedCallbackList.begin();
 		iter != mLoadedCallbackList.end(); )
 	{
@@ -1215,7 +1215,7 @@ void LLViewerFetchedTexture::cleanup()
 //access the fast cache
 void LLViewerFetchedTexture::loadFromFastCache()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	if(!mInFastCacheList)
 	{
 		return; //no need to access the fast cache.
@@ -1361,7 +1361,7 @@ void LLViewerFetchedTexture::dump()
 // ONLY called from LLViewerFetchedTextureList
 void LLViewerFetchedTexture::destroyTexture() 
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	if(LLImageGL::sGlobalTextureMemory < sMaxDesiredTextureMem * 0.95f)//not ready to release unused memory.
 	{
 		return ;
@@ -1378,7 +1378,7 @@ void LLViewerFetchedTexture::destroyTexture()
 
 void LLViewerFetchedTexture::addToCreateTexture()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	bool force_update = false;
 	if (getComponents() != mRawImage->getComponents())
 	{
@@ -1420,7 +1420,7 @@ void LLViewerFetchedTexture::addToCreateTexture()
 	}
 	else
 	{	
-        LL_PROFILE_ZONE_SCOPED;
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 #if 1
 		//
 		//if mRequestedDiscardLevel > mDesiredDiscardLevel, we assume the required image res keep going up,
@@ -1473,7 +1473,7 @@ void LLViewerFetchedTexture::addToCreateTexture()
 // ONLY called from LLViewerTextureList
 BOOL LLViewerFetchedTexture::preCreateTexture(S32 usename/*= 0*/)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 #if LL_IMAGEGL_THREAD_CHECK
     mGLTexturep->checkActiveThread();
 #endif
@@ -1954,7 +1954,7 @@ void LLViewerFetchedTexture::setAdditionalDecodePriority(F32 priority)
 
 void LLViewerFetchedTexture::updateVirtualSize() 
 {	
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	if(!mMaxVirtualSizeResetCounter)
 	{
 		addTextureStats(0.f, FALSE);//reset
@@ -2046,7 +2046,7 @@ bool LLViewerFetchedTexture::isActiveFetching()
 
 bool LLViewerFetchedTexture::updateFetch()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	static LLCachedControl<bool> textures_decode_disabled(gSavedSettings,"TextureDecodeDisabled", false);
 	static LLCachedControl<F32>  sCameraMotionThreshold(gSavedSettings,"TextureCameraMotionThreshold", 0.2);
 	static LLCachedControl<S32>  sCameraMotionBoost(gSavedSettings,"TextureCameraMotionBoost", 3);
@@ -2627,7 +2627,7 @@ void LLViewerFetchedTexture::pauseLoadedCallbacks(const LLLoadedCallbackEntry::s
 
 bool LLViewerFetchedTexture::doLoadedCallbacks()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	static const F32 MAX_INACTIVE_TIME = 900.f ; //seconds
 	static const F32 MAX_IDLE_WAIT_TIME = 5.f ; //seconds
 
@@ -2978,7 +2978,7 @@ void LLViewerFetchedTexture::destroyRawImage()
 //virtual
 void LLViewerFetchedTexture::switchToCachedImage()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	if(mCachedRawImage.notNull() && 
         !mNeedsCreateTexture) // <--- texture creation is pending, don't step on it
 	{
@@ -3270,7 +3270,7 @@ bool LLViewerLODTexture::isUpdateFrozen()
 //virtual
 void LLViewerLODTexture::processTextureStats()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	updateVirtualSize();
 	
 	static LLCachedControl<bool> textures_fullres(gSavedSettings,"TextureLoadFullRes", false);
@@ -3434,7 +3434,7 @@ bool LLViewerLODTexture::scaleDown()
 //static
 void LLViewerMediaTexture::updateClass()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	static const F32 MAX_INACTIVE_TIME = 30.f;
 
 #if 0
diff --git a/indra/newview/llviewertexturelist.cpp b/indra/newview/llviewertexturelist.cpp
index db59976be2..dd18cdc9e8 100644
--- a/indra/newview/llviewertexturelist.cpp
+++ b/indra/newview/llviewertexturelist.cpp
@@ -111,7 +111,7 @@ void LLViewerTextureList::init()
 
 void LLViewerTextureList::doPreloadImages()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	LL_DEBUGS("ViewerImages") << "Preloading images..." << LL_ENDL;
 	
 	llassert_always(mInitialized) ;
@@ -203,7 +203,7 @@ static std::string get_texture_list_name()
 
 void LLViewerTextureList::doPrefetchImages()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	if (LLAppViewer::instance()->getPurgeCache())
 	{
 		// cache was purged, no point
@@ -257,7 +257,7 @@ LLViewerTextureList::~LLViewerTextureList()
 
 void LLViewerTextureList::shutdown()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	// clear out preloads
 	mImagePreloads.clear();
 
@@ -333,7 +333,7 @@ void LLViewerTextureList::shutdown()
 
 void LLViewerTextureList::dump()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	LL_INFOS() << "LLViewerTextureList::dump()" << LL_ENDL;
 	for (image_priority_list_t::iterator it = mImageList.begin(); it != mImageList.end(); ++it)
 	{
@@ -378,7 +378,7 @@ LLViewerFetchedTexture* LLViewerTextureList::getImageFromFile(const std::string&
 												   LLGLenum primary_format, 
 												   const LLUUID& force_id)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	if(!mInitialized)
 	{
 		return NULL ;
@@ -406,7 +406,7 @@ LLViewerFetchedTexture* LLViewerTextureList::getImageFromUrl(const std::string&
 												   LLGLenum primary_format, 
 												   const LLUUID& force_id)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	if(!mInitialized)
 	{
 		return NULL ;
@@ -495,7 +495,7 @@ LLViewerFetchedTexture* LLViewerTextureList::getImage(const LLUUID &image_id,
 												   LLGLenum primary_format,
 												   LLHost request_from_host)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	if(!mInitialized)
 	{
 		return NULL ;
@@ -558,7 +558,7 @@ LLViewerFetchedTexture* LLViewerTextureList::createImage(const LLUUID &image_id,
 												   LLGLenum primary_format,
 												   LLHost request_from_host)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	static LLCachedControl<bool> fast_cache_fetching_enabled(gSavedSettings, "FastCacheFetchEnabled", true);
 
 	LLPointer<LLViewerFetchedTexture> imagep ;
@@ -614,7 +614,7 @@ LLViewerFetchedTexture* LLViewerTextureList::createImage(const LLUUID &image_id,
 
 void LLViewerTextureList::findTexturesByID(const LLUUID &image_id, std::vector<LLViewerFetchedTexture*> &output)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
     LLTextureKey search_key(image_id, TEX_LIST_STANDARD);
     uuid_map_t::iterator iter = mUUIDMap.lower_bound(search_key);
     while (iter != mUUIDMap.end() && iter->first.textureId == image_id)
@@ -626,7 +626,7 @@ void LLViewerTextureList::findTexturesByID(const LLUUID &image_id, std::vector<L
 
 LLViewerFetchedTexture *LLViewerTextureList::findImage(const LLTextureKey &search_key)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
     uuid_map_t::iterator iter = mUUIDMap.find(search_key);
     if (iter == mUUIDMap.end())
         return NULL;
@@ -640,7 +640,7 @@ LLViewerFetchedTexture *LLViewerTextureList::findImage(const LLUUID &image_id, E
 
 void LLViewerTextureList::addImageToList(LLViewerFetchedTexture *image)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	assert_main_thread();
 	llassert_always(mInitialized) ;
 	llassert(image);
@@ -660,7 +660,7 @@ void LLViewerTextureList::addImageToList(LLViewerFetchedTexture *image)
 
 void LLViewerTextureList::removeImageFromList(LLViewerFetchedTexture *image)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	assert_main_thread();
 	llassert_always(mInitialized) ;
 	llassert(image);
@@ -709,7 +709,7 @@ void LLViewerTextureList::removeImageFromList(LLViewerFetchedTexture *image)
 
 void LLViewerTextureList::addImage(LLViewerFetchedTexture *new_image, ETexListType tex_type)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	if (!new_image)
 	{
 		return;
@@ -733,7 +733,7 @@ void LLViewerTextureList::addImage(LLViewerFetchedTexture *new_image, ETexListTy
 
 void LLViewerTextureList::deleteImage(LLViewerFetchedTexture *image)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	if( image)
 	{
 		if (image->hasCallbacks())
@@ -761,7 +761,7 @@ void LLViewerTextureList::dirtyImage(LLViewerFetchedTexture *image)
 
 void LLViewerTextureList::updateImages(F32 max_time)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	static BOOL cleared = FALSE;
 	if(gTeleportDisplay)
 	{
@@ -829,7 +829,7 @@ void LLViewerTextureList::updateImages(F32 max_time)
 
 void LLViewerTextureList::clearFetchingRequests()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	if (LLAppViewer::getTextureFetch()->getNumRequests() == 0)
 	{
 		return;
@@ -847,7 +847,7 @@ void LLViewerTextureList::clearFetchingRequests()
 
 void LLViewerTextureList::updateImagesDecodePriorities()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	// Update the decode priority for N images each frame
 	{
 		F32 lazy_flush_timeout = 30.f; // stop decoding
@@ -963,7 +963,7 @@ void LLViewerTextureList::updateImagesDecodePriorities()
 
 void LLViewerTextureList::setDebugFetching(LLViewerFetchedTexture* tex, S32 debug_level)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	if(!tex->setDebugFetching(debug_level))
 	{
 		return;
@@ -1012,7 +1012,7 @@ void LLViewerTextureList::setDebugFetching(LLViewerFetchedTexture* tex, S32 debu
 
 F32 LLViewerTextureList::updateImagesCreateTextures(F32 max_time)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	if (gGLManager.mIsDisabled) return 0.0f;
 	
 	//
@@ -1041,7 +1041,7 @@ F32 LLViewerTextureList::updateImagesCreateTextures(F32 max_time)
 
 F32 LLViewerTextureList::updateImagesLoadingFastCache(F32 max_time)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	if (gGLManager.mIsDisabled) return 0.0f;
 	if(mFastCacheList.empty())
 	{
@@ -1072,7 +1072,7 @@ F32 LLViewerTextureList::updateImagesLoadingFastCache(F32 max_time)
 
 void LLViewerTextureList::forceImmediateUpdate(LLViewerFetchedTexture* imagep)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	if(!imagep)
 	{
 		return ;
@@ -1092,7 +1092,7 @@ void LLViewerTextureList::forceImmediateUpdate(LLViewerFetchedTexture* imagep)
 
 F32 LLViewerTextureList::updateImagesFetchTextures(F32 max_time)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	LLTimer image_op_timer;
 	
 	// Update fetch for N images each frame
@@ -1168,7 +1168,7 @@ F32 LLViewerTextureList::updateImagesFetchTextures(F32 max_time)
 
 void LLViewerTextureList::updateImagesUpdateStats()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	if (mForceResetTextureStats)
 	{
 		for (image_priority_list_t::iterator iter = mImageList.begin();
@@ -1183,7 +1183,7 @@ void LLViewerTextureList::updateImagesUpdateStats()
 
 void LLViewerTextureList::decodeAllImages(F32 max_time)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	LLTimer timer;
 
 	//loading from fast cache 
@@ -1253,7 +1253,7 @@ BOOL LLViewerTextureList::createUploadFile(const std::string& filename,
 										 const std::string& out_filename,
 										 const U8 codec)
 {	
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	// Load the image
 	LLPointer<LLImageFormatted> image = LLImageFormatted::createFromType(codec);
 	if (image.isNull())
@@ -1307,7 +1307,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;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	raw_image->biasedScaleToPowerOfTwo(LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT);
 	LLPointer<LLImageJ2C> compressedImage = new LLImageJ2C();
 	
@@ -1341,7 +1341,7 @@ LLPointer<LLImageJ2C> LLViewerTextureList::convertToUploadFile(LLPointer<LLImage
 // Returns min setting for TextureMemory (in MB)
 S32Megabytes LLViewerTextureList::getMinVideoRamSetting()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	U32Megabytes system_ram = gSysMemory.getPhysicalMemoryKB();
 	//min texture mem sets to 64M if total physical mem is more than 1.5GB
 	return (system_ram > U32Megabytes(1500)) ? S32Megabytes(64) : gMinVideoRam ;
@@ -1351,7 +1351,7 @@ S32Megabytes LLViewerTextureList::getMinVideoRamSetting()
 // Returns max setting for TextureMemory (in MB)
 S32Megabytes LLViewerTextureList::getMaxVideoRamSetting(bool get_recommended, float mem_multiplier)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	S32Megabytes max_texmem;
 	if (gGLManager.mVRAM != 0)
 	{
@@ -1405,7 +1405,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;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	// Initialize the image pipeline VRAM settings
 	S32Megabytes cur_mem(gSavedSettings.getS32("TextureMemory"));
 	F32 mem_multiplier = gSavedSettings.getF32("RenderTextureMemoryMultiple");
@@ -1468,7 +1468,7 @@ void LLViewerTextureList::receiveImageHeader(LLMessageSystem *msg, void **user_d
 {
 	static LLCachedControl<bool> log_texture_traffic(gSavedSettings,"LogTextureNetworkTraffic", false) ;
 
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 
 	// Receive image header, copy into image object and decompresses 
 	// if this is a one-packet image. 
@@ -1540,7 +1540,7 @@ void LLViewerTextureList::receiveImagePacket(LLMessageSystem *msg, void **user_d
 {
 	static LLCachedControl<bool> log_texture_traffic(gSavedSettings,"LogTextureNetworkTraffic", false) ;
 
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	
 	// Receives image packet, copy into image object,
 	// checks if all packets received, decompresses if so. 
@@ -1613,7 +1613,7 @@ void LLViewerTextureList::receiveImagePacket(LLMessageSystem *msg, void **user_d
 // static
 void LLViewerTextureList::processImageNotInDatabase(LLMessageSystem *msg,void **user_data)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	LLUUID image_id;
 	msg->getUUIDFast(_PREHASH_ImageID, _PREHASH_ID, image_id);
 	
@@ -1646,7 +1646,7 @@ void LLUIImageList::cleanUp()
 
 LLUIImagePtr LLUIImageList::getUIImageByID(const LLUUID& image_id, S32 priority)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	// use id as image name
 	std::string image_name = image_id.asString();
 
@@ -1665,7 +1665,7 @@ LLUIImagePtr LLUIImageList::getUIImageByID(const LLUUID& image_id, S32 priority)
 
 LLUIImagePtr LLUIImageList::getUIImage(const std::string& image_name, S32 priority)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	// look for existing image
 	uuid_ui_image_map_t::iterator found_it = mUIImages.find(image_name);
 	if (found_it != mUIImages.end())
@@ -1683,7 +1683,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;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	if (boost_priority == LLGLTexture::BOOST_NONE)
 	{
 		boost_priority = LLGLTexture::BOOST_UI;
@@ -1696,7 +1696,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;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	if (boost_priority == LLGLTexture::BOOST_NONE)
 	{
 		boost_priority = LLGLTexture::BOOST_UI;
@@ -1708,7 +1708,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;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	if (!imagep) return NULL;
 
 	imagep->setAddressMode(LLTexUnit::TAM_CLAMP);
@@ -1746,7 +1746,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;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	// look for existing image
 	uuid_ui_image_map_t::iterator found_it = mUIImages.find(name);
 	if (found_it != mUIImages.end())
@@ -1761,7 +1761,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;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	if(!success || !user_data) 
 	{
 		return;
@@ -1863,7 +1863,7 @@ struct UIImageDeclarations : public LLInitParam::Block<UIImageDeclarations>
 
 bool LLUIImageList::initFromFile()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	// Look for textures.xml in all the right places. Pass
 	// constraint=LLDir::ALL_SKINS because we want to overlay textures.xml
 	// from all the skins directories.
-- 
cgit v1.2.3


From b504c692554d492113a10ef45427fe0ab0d8a85d Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Thu, 13 Jan 2022 12:55:53 -0800
Subject: SL-16606: Add profiler category THREAD

---
 indra/llcommon/llmutex.cpp          | 24 ++++++++++----------
 indra/llcommon/llsingleton.h        |  2 +-
 indra/llcommon/llthread.cpp         | 14 ++++++------
 indra/llcommon/llthreadsafequeue.h  | 36 +++++++++++++++---------------
 indra/llcommon/threadsafeschedule.h | 44 ++++++++++++++++++-------------------
 indra/llcommon/workqueue.cpp        |  8 +++----
 6 files changed, 64 insertions(+), 64 deletions(-)

(limited to 'indra')

diff --git a/indra/llcommon/llmutex.cpp b/indra/llcommon/llmutex.cpp
index a49002b5dc..0273dd5970 100644
--- a/indra/llcommon/llmutex.cpp
+++ b/indra/llcommon/llmutex.cpp
@@ -44,7 +44,7 @@ LLMutex::~LLMutex()
 
 void LLMutex::lock()
 {
-    LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
 	if(isSelfLocked())
 	{ //redundant lock
 		mCount++;
@@ -66,7 +66,7 @@ void LLMutex::lock()
 
 void LLMutex::unlock()
 {
-    LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
 	if (mCount > 0)
 	{ //not the root unlock
 		mCount--;
@@ -87,7 +87,7 @@ void LLMutex::unlock()
 
 bool LLMutex::isLocked()
 {
-    LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
 	if (!mMutex.try_lock())
 	{
 		return true;
@@ -111,7 +111,7 @@ LLThread::id_t LLMutex::lockingThread() const
 
 bool LLMutex::trylock()
 {
-    LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
 	if(isSelfLocked())
 	{ //redundant lock
 		mCount++;
@@ -150,20 +150,20 @@ LLCondition::~LLCondition()
 
 void LLCondition::wait()
 {
-    LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
 	std::unique_lock< std::mutex > lock(mMutex);
 	mCond.wait(lock);
 }
 
 void LLCondition::signal()
 {
-    LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
 	mCond.notify_one();
 }
 
 void LLCondition::broadcast()
 {
-    LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
 	mCond.notify_all();
 }
 
@@ -173,7 +173,7 @@ LLMutexTrylock::LLMutexTrylock(LLMutex* mutex)
     : mMutex(mutex),
     mLocked(false)
 {
-    LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
     if (mMutex)
         mLocked = mMutex->trylock();
 }
@@ -182,7 +182,7 @@ LLMutexTrylock::LLMutexTrylock(LLMutex* mutex, U32 aTries, U32 delay_ms)
     : mMutex(mutex),
     mLocked(false)
 {
-    LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
     if (!mMutex)
         return;
 
@@ -197,7 +197,7 @@ LLMutexTrylock::LLMutexTrylock(LLMutex* mutex, U32 aTries, U32 delay_ms)
 
 LLMutexTrylock::~LLMutexTrylock()
 {
-    LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
     if (mMutex && mLocked)
         mMutex->unlock();
 }
@@ -209,7 +209,7 @@ LLMutexTrylock::~LLMutexTrylock()
 //
 LLScopedLock::LLScopedLock(std::mutex* mutex) : mMutex(mutex)
 {
-    LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
 	if(mutex)
 	{
 		mutex->lock();
@@ -228,7 +228,7 @@ LLScopedLock::~LLScopedLock()
 
 void LLScopedLock::unlock()
 {
-    LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
 	if(mLocked)
 	{
 		mMutex->unlock();
diff --git a/indra/llcommon/llsingleton.h b/indra/llcommon/llsingleton.h
index 6042c0906c..51ef514cf7 100644
--- a/indra/llcommon/llsingleton.h
+++ b/indra/llcommon/llsingleton.h
@@ -455,7 +455,7 @@ public:
 
     static DERIVED_TYPE* getInstance()
     {
-        LL_PROFILE_ZONE_SCOPED;
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
         // We know the viewer has LLSingleton dependency circularities. If you
         // feel strongly motivated to eliminate them, cheers and good luck.
         // (At that point we could consider a much simpler locking mechanism.)
diff --git a/indra/llcommon/llthread.cpp b/indra/llcommon/llthread.cpp
index 11f5a015f1..a807acc56e 100644
--- a/indra/llcommon/llthread.cpp
+++ b/indra/llcommon/llthread.cpp
@@ -333,7 +333,7 @@ bool LLThread::runCondition(void)
 // Stop thread execution if requested until unpaused.
 void LLThread::checkPause()
 {
-    LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
     mDataLock->lock();
 
     // This is in a while loop because the pthread API allows for spurious wakeups.
@@ -365,20 +365,20 @@ void LLThread::setQuitting()
 // static
 LLThread::id_t LLThread::currentID()
 {
-    LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
     return std::this_thread::get_id();
 }
 
 // static
 void LLThread::yield()
 {
-    LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
     std::this_thread::yield();
 }
 
 void LLThread::wake()
 {
-    LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
     mDataLock->lock();
     if(!shouldSleep())
     {
@@ -389,7 +389,7 @@ void LLThread::wake()
 
 void LLThread::wakeLocked()
 {
-    LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
     if(!shouldSleep())
     {
         mRunCondition->signal();
@@ -398,13 +398,13 @@ void LLThread::wakeLocked()
 
 void LLThread::lockData()
 {
-    LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
     mDataLock->lock();
 }
 
 void LLThread::unlockData()
 {
-    LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
     mDataLock->unlock();
 }
 
diff --git a/indra/llcommon/llthreadsafequeue.h b/indra/llcommon/llthreadsafequeue.h
index 2806506550..68d79cdd12 100644
--- a/indra/llcommon/llthreadsafequeue.h
+++ b/indra/llcommon/llthreadsafequeue.h
@@ -275,7 +275,7 @@ template <typename ElementT, typename QueueT>
 template <typename CALLABLE>
 bool LLThreadSafeQueue<ElementT, QueueT>::tryLock(CALLABLE&& callable)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
     lock_t lock1(mLock, std::defer_lock);
     if (!lock1.try_lock())
         return false;
@@ -292,7 +292,7 @@ bool LLThreadSafeQueue<ElementT, QueueT>::tryLockUntil(
     const std::chrono::time_point<Clock, Duration>& until,
     CALLABLE&& callable)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
     lock_t lock1(mLock, std::defer_lock);
     if (!lock1.try_lock_until(until))
         return false;
@@ -306,7 +306,7 @@ template <typename ElementT, typename QueueT>
 template <typename T>
 bool LLThreadSafeQueue<ElementT, QueueT>::push_(lock_t& lock, T&& element)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
     if (mStorage.size() >= mCapacity)
         return false;
 
@@ -322,7 +322,7 @@ template <typename ElementT, typename QueueT>
 template <typename T>
 bool LLThreadSafeQueue<ElementT, QueueT>::pushIfOpen(T&& element)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
     lock_t lock1(mLock);
     while (true)
     {
@@ -345,7 +345,7 @@ template <typename ElementT, typename QueueT>
 template<typename T>
 void LLThreadSafeQueue<ElementT, QueueT>::push(T&& element)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
     if (! pushIfOpen(std::forward<T>(element)))
     {
         LLTHROW(LLThreadSafeQueueInterrupt());
@@ -357,7 +357,7 @@ template<typename ElementT, typename QueueT>
 template<typename T>
 bool LLThreadSafeQueue<ElementT, QueueT>::tryPush(T&& element)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
     return tryLock(
         [this, element=std::move(element)](lock_t& lock)
         {
@@ -374,7 +374,7 @@ bool LLThreadSafeQueue<ElementT, QueueT>::tryPushFor(
     const std::chrono::duration<Rep, Period>& timeout,
     T&& element)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
     // Convert duration to time_point: passing the same timeout duration to
     // each of multiple calls is wrong.
     return tryPushUntil(std::chrono::steady_clock::now() + timeout,
@@ -388,7 +388,7 @@ bool LLThreadSafeQueue<ElementT, QueueT>::tryPushUntil(
     const std::chrono::time_point<Clock, Duration>& until,
     T&& element)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
     return tryLockUntil(
         until,
         [this, until, element=std::move(element)](lock_t& lock)
@@ -421,7 +421,7 @@ template <typename ElementT, typename QueueT>
 typename LLThreadSafeQueue<ElementT, QueueT>::pop_result
 LLThreadSafeQueue<ElementT, QueueT>::pop_(lock_t& lock, ElementT& element)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
     // If mStorage is empty, there's no head element.
     if (mStorage.empty())
         return mClosed? DONE : EMPTY;
@@ -443,7 +443,7 @@ LLThreadSafeQueue<ElementT, QueueT>::pop_(lock_t& lock, ElementT& element)
 template<typename ElementT, typename QueueT>
 ElementT LLThreadSafeQueue<ElementT, QueueT>::pop(void)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
     lock_t lock1(mLock);
     ElementT value;
     while (true)
@@ -472,7 +472,7 @@ ElementT LLThreadSafeQueue<ElementT, QueueT>::pop(void)
 template<typename ElementT, typename QueueT>
 bool LLThreadSafeQueue<ElementT, QueueT>::tryPop(ElementT & element)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
     return tryLock(
         [this, &element](lock_t& lock)
         {
@@ -490,7 +490,7 @@ bool LLThreadSafeQueue<ElementT, QueueT>::tryPopFor(
     const std::chrono::duration<Rep, Period>& timeout,
     ElementT& element)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
     // Convert duration to time_point: passing the same timeout duration to
     // each of multiple calls is wrong.
     return tryPopUntil(std::chrono::steady_clock::now() + timeout, element);
@@ -503,7 +503,7 @@ bool LLThreadSafeQueue<ElementT, QueueT>::tryPopUntil(
     const std::chrono::time_point<Clock, Duration>& until,
     ElementT& element)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
     return tryLockUntil(
         until,
         [this, until, &element](lock_t& lock)
@@ -523,7 +523,7 @@ LLThreadSafeQueue<ElementT, QueueT>::tryPopUntil_(
     const std::chrono::time_point<Clock, Duration>& until,
     ElementT& element)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
     while (true)
     {
         pop_result popped = pop_(lock, element);
@@ -550,7 +550,7 @@ LLThreadSafeQueue<ElementT, QueueT>::tryPopUntil_(
 template<typename ElementT, typename QueueT>
 size_t LLThreadSafeQueue<ElementT, QueueT>::size(void)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
     lock_t lock(mLock);
     return mStorage.size();
 }
@@ -559,7 +559,7 @@ size_t LLThreadSafeQueue<ElementT, QueueT>::size(void)
 template<typename ElementT, typename QueueT>
 void LLThreadSafeQueue<ElementT, QueueT>::close()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
     lock_t lock(mLock);
     mClosed = true;
     lock.unlock();
@@ -573,7 +573,7 @@ void LLThreadSafeQueue<ElementT, QueueT>::close()
 template<typename ElementT, typename QueueT>
 bool LLThreadSafeQueue<ElementT, QueueT>::isClosed()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
     lock_t lock(mLock);
     return mClosed;
 }
@@ -582,7 +582,7 @@ bool LLThreadSafeQueue<ElementT, QueueT>::isClosed()
 template<typename ElementT, typename QueueT>
 bool LLThreadSafeQueue<ElementT, QueueT>::done()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
     lock_t lock(mLock);
     return mClosed && mStorage.empty();
 }
diff --git a/indra/llcommon/threadsafeschedule.h b/indra/llcommon/threadsafeschedule.h
index 601681d550..3e0da94c02 100644
--- a/indra/llcommon/threadsafeschedule.h
+++ b/indra/llcommon/threadsafeschedule.h
@@ -98,14 +98,14 @@ namespace LL
         // we could minimize redundancy by breaking out a common base class...
         void push(const DataTuple& tuple)
         {
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
             push(tuple_cons(Clock::now(), tuple));
         }
 
         /// individually pass each component of the TimeTuple
         void push(const TimePoint& time, Args&&... args)
         {
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
             push(TimeTuple(time, std::forward<Args>(args)...));
         }
 
@@ -116,7 +116,7 @@ namespace LL
         // and call that overload.
         void push(Args&&... args)
         {
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
             push(Clock::now(), std::forward<Args>(args)...);
         }
 
@@ -127,21 +127,21 @@ namespace LL
         /// DataTuple with implicit now
         bool tryPush(const DataTuple& tuple)
         {
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
             return tryPush(tuple_cons(Clock::now(), tuple));
         }
 
         /// individually pass components
         bool tryPush(const TimePoint& time, Args&&... args)
         {
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
             return tryPush(TimeTuple(time, std::forward<Args>(args)...));
         }
 
         /// individually pass components with implicit now
         bool tryPush(Args&&... args)
         {
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
             return tryPush(Clock::now(), std::forward<Args>(args)...);
         }
 
@@ -154,7 +154,7 @@ namespace LL
         bool tryPushFor(const std::chrono::duration<Rep, Period>& timeout,
                         const DataTuple& tuple)
         {
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
             return tryPushFor(timeout, tuple_cons(Clock::now(), tuple));
         }
 
@@ -163,7 +163,7 @@ namespace LL
         bool tryPushFor(const std::chrono::duration<Rep, Period>& timeout,
                         const TimePoint& time, Args&&... args)
         {
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
             return tryPushFor(TimeTuple(time, std::forward<Args>(args)...));
         }
 
@@ -172,7 +172,7 @@ namespace LL
         bool tryPushFor(const std::chrono::duration<Rep, Period>& timeout,
                         Args&&... args)
         {
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
             return tryPushFor(Clock::now(), std::forward<Args>(args)...);
         }
 
@@ -185,7 +185,7 @@ namespace LL
         bool tryPushUntil(const std::chrono::time_point<Clock, Duration>& until,
                           const DataTuple& tuple)
         {
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
             return tryPushUntil(until, tuple_cons(Clock::now(), tuple));
         }
 
@@ -194,7 +194,7 @@ namespace LL
         bool tryPushUntil(const std::chrono::time_point<Clock, Duration>& until,
                           const TimePoint& time, Args&&... args)
         {
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
             return tryPushUntil(until, TimeTuple(time, std::forward<Args>(args)...));
         }
 
@@ -203,7 +203,7 @@ namespace LL
         bool tryPushUntil(const std::chrono::time_point<Clock, Duration>& until,
                           Args&&... args)
         {
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
             return tryPushUntil(until, Clock::now(), std::forward<Args>(args)...);
         }
 
@@ -221,14 +221,14 @@ namespace LL
         // haven't yet jumped through those hoops.
         DataTuple pop()
         {
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
             return tuple_cdr(popWithTime());
         }
 
         /// pop TimeTuple by value
         TimeTuple popWithTime()
         {
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
             lock_t lock(super::mLock);
             // We can't just sit around waiting forever, given that there may
             // be items in the queue that are not yet ready but will *become*
@@ -268,7 +268,7 @@ namespace LL
         /// tryPop(DataTuple&)
         bool tryPop(DataTuple& tuple)
         {
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
             TimeTuple tt;
             if (! super::tryPop(tt))
                 return false;
@@ -279,7 +279,7 @@ namespace LL
         /// for when Args has exactly one type
         bool tryPop(typename std::tuple_element<1, TimeTuple>::type& value)
         {
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
             TimeTuple tt;
             if (! super::tryPop(tt))
                 return false;
@@ -291,7 +291,7 @@ namespace LL
         template <typename Rep, typename Period, typename Tuple>
         bool tryPopFor(const std::chrono::duration<Rep, Period>& timeout, Tuple& tuple)
         {
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
             // It's important to use OUR tryPopUntil() implementation, rather
             // than delegating immediately to our base class.
             return tryPopUntil(Clock::now() + timeout, tuple);
@@ -302,7 +302,7 @@ namespace LL
         bool tryPopUntil(const std::chrono::time_point<Clock, Duration>& until,
                          TimeTuple& tuple)
         {
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
             // super::tryPopUntil() wakes up when an item becomes available or
             // we hit 'until', whichever comes first. Thing is, the current
             // head of the queue could become ready sooner than either of
@@ -322,7 +322,7 @@ namespace LL
 
         pop_result tryPopUntil_(lock_t& lock, const TimePoint& until, TimeTuple& tuple)
         {
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
             TimePoint adjusted = until;
             if (! super::mStorage.empty())
             {
@@ -350,7 +350,7 @@ namespace LL
         bool tryPopUntil(const std::chrono::time_point<Clock, Duration>& until,
                          DataTuple& tuple)
         {
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
             TimeTuple tt;
             if (! tryPopUntil(until, tt))
                 return false;
@@ -363,7 +363,7 @@ namespace LL
         bool tryPopUntil(const std::chrono::time_point<Clock, Duration>& until,
                          typename std::tuple_element<1, TimeTuple>::type& value)
         {
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
             TimeTuple tt;
             if (! tryPopUntil(until, tt))
                 return false;
@@ -387,7 +387,7 @@ namespace LL
         // considering whether to deliver the current head element
         bool canPop(const TimeTuple& head) const override
         {
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
             // an item with a future timestamp isn't yet ready to pop
             // (should we add some slop for overhead?)
             return std::get<0>(head) <= Clock::now();
diff --git a/indra/llcommon/workqueue.cpp b/indra/llcommon/workqueue.cpp
index c74dada2e4..eb06890468 100644
--- a/indra/llcommon/workqueue.cpp
+++ b/indra/llcommon/workqueue.cpp
@@ -60,7 +60,7 @@ void LL::WorkQueue::runUntilClose()
     {
         for (;;)
         {
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
             callWork(mQueue.pop());
         }
     }
@@ -71,7 +71,7 @@ void LL::WorkQueue::runUntilClose()
 
 bool LL::WorkQueue::runPending()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
     for (Work work; mQueue.tryPop(work); )
     {
         callWork(work);
@@ -91,7 +91,7 @@ bool LL::WorkQueue::runOne()
 
 bool LL::WorkQueue::runUntil(const TimePoint& until)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
     // Should we subtract some slop to allow for typical Work execution time?
     // How much slop?
     // runUntil() is simply a time-bounded runPending().
@@ -129,7 +129,7 @@ void LL::WorkQueue::callWork(const Queue::DataTuple& work)
 
 void LL::WorkQueue::callWork(const Work& work)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
     try
     {
         work();
-- 
cgit v1.2.3


From b70614bd87414e1eb3206765ec5e0cfb3ba7fab7 Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Thu, 13 Jan 2022 13:00:10 -0800
Subject: SL-16606: Add profiler category UI

---
 indra/llrender/llfontgl.cpp        | 10 +++++-----
 indra/llrender/llrender2dutils.cpp |  6 +++---
 indra/llui/llfolderview.cpp        |  6 +++---
 indra/llui/lllayoutstack.cpp       |  2 +-
 indra/llui/llscrolllistctrl.cpp    |  6 +++---
 indra/llui/lltextbase.cpp          |  8 ++++----
 indra/llui/lltrans.cpp             |  8 ++++----
 indra/llui/lluictrl.cpp            |  4 ++--
 indra/llui/lluictrlfactory.cpp     |  6 +++---
 indra/llui/lluictrlfactory.h       |  4 ++--
 indra/llui/llview.cpp              |  2 +-
 indra/newview/llhudnametag.cpp     |  4 ++--
 indra/newview/llviewerdisplay.cpp  |  8 ++++----
 indra/newview/llviewerwindow.cpp   |  4 ++--
 indra/newview/pipeline.cpp         |  4 ++--
 15 files changed, 41 insertions(+), 41 deletions(-)

(limited to 'indra')

diff --git a/indra/llrender/llfontgl.cpp b/indra/llrender/llfontgl.cpp
index 7f734e41f3..1bf061bc8d 100644
--- a/indra/llrender/llfontgl.cpp
+++ b/indra/llrender/llfontgl.cpp
@@ -145,7 +145,7 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, const LLRectf& rec
 S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, const LLColor4 &color, HAlign halign, VAlign valign, U8 style, 
 					 ShadowType shadow, S32 max_chars, S32 max_pixels, F32* right_x, BOOL use_ellipses) const
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
 
 	if(!sDisplayFont) //do not display texts
 	{
@@ -547,7 +547,7 @@ F32 LLFontGL::getWidthF32(const llwchar* wchars, S32 begin_offset, S32 max_chars
 
 void LLFontGL::generateASCIIglyphs()
 {
-    LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_UI
     for (U32 i = 32; (i < 127); i++)
     {
         mFontFreetype->getGlyphInfo(i);
@@ -557,7 +557,7 @@ void LLFontGL::generateASCIIglyphs()
 // 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
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_UI
 	if (!wchars || !wchars[0] || max_chars == 0)
 	{
 		return 0;
@@ -848,7 +848,7 @@ void LLFontGL::initClass(F32 screen_dpi, F32 x_scale, F32 y_scale, const std::st
 // static
 bool LLFontGL::loadDefaultFonts()
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_UI
 	bool succ = true;
 	succ &= (NULL != getFontSansSerifSmall());
 	succ &= (NULL != getFontSansSerif());
@@ -861,7 +861,7 @@ bool LLFontGL::loadDefaultFonts()
 
 void LLFontGL::loadCommonFonts()
 {
-    LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_UI
     getFont(LLFontDescriptor("SansSerif", "Small", BOLD));
     getFont(LLFontDescriptor("SansSerif", "Large", BOLD));
     getFont(LLFontDescriptor("SansSerif", "Huge", BOLD));
diff --git a/indra/llrender/llrender2dutils.cpp b/indra/llrender/llrender2dutils.cpp
index ad0c6262a4..5cb1dc6b25 100644
--- a/indra/llrender/llrender2dutils.cpp
+++ b/indra/llrender/llrender2dutils.cpp
@@ -989,7 +989,7 @@ void gl_segmented_rect_2d_tex(const S32 left,
 							  const S32 border_size, 
 							  const U32 edges)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
 
 	S32 width = llabs(right - left);
 	S32 height = llabs(top - bottom);
@@ -1148,7 +1148,7 @@ void gl_segmented_rect_2d_fragment_tex(const LLRect& rect,
 	const F32 end_fragment, 
 	const U32 edges)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
 	const S32 left = rect.mLeft;
 	const S32 right = rect.mRight;
 	const S32 top = rect.mTop;
@@ -1335,7 +1335,7 @@ void gl_segmented_rect_2d_fragment_tex(const LLRect& rect,
 void gl_segmented_rect_3d_tex(const LLRectf& clip_rect, const LLRectf& center_uv_rect, const LLRectf& center_draw_rect, 
 							 const LLVector3& width_vec, const LLVector3& height_vec)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
 
 	gGL.begin(LLRender::QUADS);
 	{
diff --git a/indra/llui/llfolderview.cpp b/indra/llui/llfolderview.cpp
index 0996e82bf7..a685924d99 100644
--- a/indra/llui/llfolderview.cpp
+++ b/indra/llui/llfolderview.cpp
@@ -338,7 +338,7 @@ S32 LLFolderView::arrange( S32* unused_width, S32* unused_height )
 
 void LLFolderView::filter( LLFolderViewFilter& filter )
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
     static LLCachedControl<S32> time_visible(*LLUI::getInstance()->mSettingGroups["config"], "FilterItemsMaxTimePerFrameVisible", 10);
     static LLCachedControl<S32> time_invisible(*LLUI::getInstance()->mSettingGroups["config"], "FilterItemsMaxTimePerFrameUnvisible", 1);
     filter.resetTime(llclamp((mParentPanel.get()->getVisible() ? time_visible() : time_invisible()), 1, 100));
@@ -502,7 +502,7 @@ BOOL LLFolderView::changeSelection(LLFolderViewItem* selection, BOOL selected)
 
 void LLFolderView::sanitizeSelection()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
 	// store off current item in case it is automatically deselected
 	// and we want to preserve context
 	LLFolderViewItem* original_selected_item = getCurSelectedItem();
@@ -1624,7 +1624,7 @@ void LLFolderView::update()
 {
 	// If this is associated with the user's inventory, don't do anything
 	// until that inventory is loaded up.
-	LL_RECORD_BLOCK_TIME(FTM_INVENTORY);
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; //LL_RECORD_BLOCK_TIME(FTM_INVENTORY);
     
     // If there's no model, the view is in suspended state (being deleted) and shouldn't be updated
     if (getFolderViewModel() == NULL)
diff --git a/indra/llui/lllayoutstack.cpp b/indra/llui/lllayoutstack.cpp
index 528d2e70ad..aac28e04b9 100644
--- a/indra/llui/lllayoutstack.cpp
+++ b/indra/llui/lllayoutstack.cpp
@@ -367,7 +367,7 @@ private:
 
 void LLLayoutStack::updateLayout()
 {	
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
 
 	if (!mNeedsLayout) return;
 
diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp
index c70085b72f..f6071e12e5 100644
--- a/indra/llui/llscrolllistctrl.cpp
+++ b/indra/llui/llscrolllistctrl.cpp
@@ -3047,7 +3047,7 @@ LLScrollListColumn* LLScrollListCtrl::getColumn(const std::string& name)
 
 LLScrollListItem* LLScrollListCtrl::addElement(const LLSD& element, EAddPosition pos, void* userdata)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
 	LLScrollListItem::Params item_params;
 	LLParamSDParser parser;
 	parser.readSD(element, item_params);
@@ -3057,14 +3057,14 @@ LLScrollListItem* LLScrollListCtrl::addElement(const LLSD& element, EAddPosition
 
 LLScrollListItem* LLScrollListCtrl::addRow(const LLScrollListItem::Params& item_p, EAddPosition pos)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
 	LLScrollListItem *new_item = new LLScrollListItem(item_p);
 	return addRow(new_item, item_p, pos);
 }
 
 LLScrollListItem* LLScrollListCtrl::addRow(LLScrollListItem *new_item, const LLScrollListItem::Params& item_p, EAddPosition pos)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
 	if (!item_p.validateBlock() || !new_item) return NULL;
 	new_item->setNumColumns(mColumns.size());
 
diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp
index 3b0789892f..2827888b53 100644
--- a/indra/llui/lltextbase.cpp
+++ b/indra/llui/lltextbase.cpp
@@ -1492,7 +1492,7 @@ S32 LLTextBase::getLeftOffset(S32 width)
 
 void LLTextBase::reflow()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
 
 	updateSegments();
 
@@ -1839,7 +1839,7 @@ void LLTextBase::removeDocumentChild(LLView* view)
 
 void LLTextBase::updateSegments()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
 	createDefaultSegment();
 }
 
@@ -2102,7 +2102,7 @@ static LLUIImagePtr image_from_icon_name(const std::string& icon_name)
 
 void LLTextBase::appendTextImpl(const std::string &new_text, const LLStyle::Params& input_params)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
 	LLStyle::Params style_params(input_params);
 	style_params.fillFrom(getStyleParams());
 
@@ -2204,7 +2204,7 @@ void LLTextBase::setLastSegmentToolTip(const std::string &tooltip)
 
 void LLTextBase::appendText(const std::string &new_text, bool prepend_newline, const LLStyle::Params& input_params)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
 	if (new_text.empty()) 
 		return;
 
diff --git a/indra/llui/lltrans.cpp b/indra/llui/lltrans.cpp
index a1a8feedaa..a1ef34159d 100644
--- a/indra/llui/lltrans.cpp
+++ b/indra/llui/lltrans.cpp
@@ -147,7 +147,7 @@ std::string LLTrans::getString(const std::string &xml_desc, const LLStringUtil::
 {
 	// Don't care about time as much as call count.  Make sure we're not
 	// calling LLTrans::getString() in an inner loop. JC
-	LL_RECORD_BLOCK_TIME(FTM_GET_TRANS);
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
 	
 	if (def_string)
 	{
@@ -196,7 +196,7 @@ std::string LLTrans::getString(const std::string &xml_desc, const LLSD& msg_args
 {
 	// Don't care about time as much as call count.  Make sure we're not
 	// calling LLTrans::getString() in an inner loop. JC
-	LL_RECORD_BLOCK_TIME(FTM_GET_TRANS);
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
 
 	if (def_string)
 	{
@@ -237,7 +237,7 @@ std::string LLTrans::getDefString(const std::string &xml_desc, const LLSD& msg_a
 //static 
 bool LLTrans::findString(std::string &result, const std::string &xml_desc, const LLStringUtil::format_map_t& msg_args)
 {
-	LL_RECORD_BLOCK_TIME(FTM_GET_TRANS);
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
 	
 	template_map_t::iterator iter = sStringTemplates.find(xml_desc);
 	if (iter != sStringTemplates.end())
@@ -259,7 +259,7 @@ bool LLTrans::findString(std::string &result, const std::string &xml_desc, const
 //static
 bool LLTrans::findString(std::string &result, const std::string &xml_desc, const LLSD& msg_args)
 {
-	LL_RECORD_BLOCK_TIME(FTM_GET_TRANS);
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
 
 	template_map_t::iterator iter = sStringTemplates.find(xml_desc);
 	if (iter != sStringTemplates.end())
diff --git a/indra/llui/lluictrl.cpp b/indra/llui/lluictrl.cpp
index 51391bb5e8..2196ba201b 100644
--- a/indra/llui/lluictrl.cpp
+++ b/indra/llui/lluictrl.cpp
@@ -475,7 +475,7 @@ LLViewModel* LLUICtrl::getViewModel() const
 //virtual
 BOOL LLUICtrl::postBuild()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
 	//
 	// Find all of the children that want to be in front and move them to the front
 	//
@@ -783,7 +783,7 @@ BOOL LLUICtrl::getIsChrome() const
 
 BOOL LLUICtrl::focusFirstItem(BOOL prefer_text_fields, BOOL focus_flash)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
 	// try to select default tab group child
 	LLViewQuery query = getTabOrderQuery();
 	child_list_t result = query(this);
diff --git a/indra/llui/lluictrlfactory.cpp b/indra/llui/lluictrlfactory.cpp
index 2d0c0ea8aa..a85db17c7f 100644
--- a/indra/llui/lluictrlfactory.cpp
+++ b/indra/llui/lluictrlfactory.cpp
@@ -116,7 +116,7 @@ void LLUICtrlFactory::loadWidgetTemplate(const std::string& widget_tag, LLInitPa
 //static 
 void LLUICtrlFactory::createChildren(LLView* viewp, LLXMLNodePtr node, const widget_registry_t& registry, LLXMLNodePtr output_node)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
 	if (node.isNull()) return;
 
 	for (LLXMLNodePtr child_node = node->getFirstChild(); child_node.notNull(); child_node = child_node->getNextSibling())
@@ -159,7 +159,7 @@ void LLUICtrlFactory::createChildren(LLView* viewp, LLXMLNodePtr node, const wid
 bool LLUICtrlFactory::getLayeredXMLNode(const std::string &xui_filename, LLXMLNodePtr& root,
                                         LLDir::ESkinConstraint constraint)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
 	std::vector<std::string> paths =
 		gDirUtilp->findSkinnedFilenames(LLDir::XUI, xui_filename, constraint);
 
@@ -186,7 +186,7 @@ S32 LLUICtrlFactory::saveToXML(LLView* viewp, const std::string& filename)
 
 LLView *LLUICtrlFactory::createFromXML(LLXMLNodePtr node, LLView* parent, const std::string& filename, const widget_registry_t& registry, LLXMLNodePtr output_node)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
 	std::string ctrl_type = node->getName()->mString;
 	LLStringUtil::toLower(ctrl_type);
 
diff --git a/indra/llui/lluictrlfactory.h b/indra/llui/lluictrlfactory.h
index 3f24a3f1a5..6e585abfc0 100644
--- a/indra/llui/lluictrlfactory.h
+++ b/indra/llui/lluictrlfactory.h
@@ -209,7 +209,7 @@ private:
 	template<typename T>
 	static T* createWidgetImpl(const typename T::Params& params, LLView* parent = NULL)
 	{
-        LL_PROFILE_ZONE_SCOPED;
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
 		T* widget = NULL;
 
 		if (!params.validateBlock())
@@ -233,7 +233,7 @@ private:
 	template<typename T>
 	static T* defaultBuilder(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr output_node)
 	{
-        LL_PROFILE_ZONE_SCOPED;
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
 
 		typename T::Params params(getDefaultParams<T>());
 
diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp
index bd0b9d3db2..9ba71913d0 100644
--- a/indra/llui/llview.cpp
+++ b/indra/llui/llview.cpp
@@ -1598,7 +1598,7 @@ LLView* LLView::getChildView(const std::string& name, BOOL recurse) const
 
 LLView* LLView::findChildView(const std::string& name, BOOL recurse) const
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
 	
     // Look for direct children *first*
 	BOOST_FOREACH(LLView* childp, mChildList)
diff --git a/indra/newview/llhudnametag.cpp b/indra/newview/llhudnametag.cpp
index 8e296321d2..952fbf8e4b 100644
--- a/indra/newview/llhudnametag.cpp
+++ b/indra/newview/llhudnametag.cpp
@@ -224,7 +224,7 @@ BOOL LLHUDNameTag::lineSegmentIntersect(const LLVector4a& start, const LLVector4
 
 void LLHUDNameTag::render()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
 	if (sDisplayText)
 	{
 		LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE);
@@ -730,7 +730,7 @@ void LLHUDNameTag::updateSize()
 
 void LLHUDNameTag::updateAll()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
 	// iterate over all text objects, calculate their restoration forces,
 	// and add them to the visible set if they are on screen and close enough
 	sVisibleTextObjects.clear();
diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp
index e2c831bb1c..b5d3dc5d30 100644
--- a/indra/newview/llviewerdisplay.cpp
+++ b/indra/newview/llviewerdisplay.cpp
@@ -1242,7 +1242,7 @@ bool setup_hud_matrices(const LLRect& screen_region)
 
 void render_ui(F32 zoom_factor, int subfield)
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_UI);
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; //LL_RECORD_BLOCK_TIME(FTM_RENDER_UI);
 
 	LLGLState::checkStates();
 	
@@ -1274,7 +1274,7 @@ void render_ui(F32 zoom_factor, int subfield)
 		// 1. Use a new scope
 		// 2. Use named zones
 		// 3. Use transient zones
-		LL_RECORD_BLOCK_TIME(FTM_RENDER_HUD);
+		LL_PROFILE_ZONE_NAMED_CATEGORY_UI("HUD"); //LL_RECORD_BLOCK_TIME(FTM_RENDER_HUD);
 		render_hud_elements();
 		render_hud_attachments();
 
@@ -1290,7 +1290,7 @@ void render_ui(F32 zoom_factor, int subfield)
 			{
 				if (!gDisconnected)
 				{
-					LL_RECORD_BLOCK_TIME(FTM_RENDER_UI_3D);
+					LL_PROFILE_ZONE_NAMED_CATEGORY_UI("UI 3D"); //LL_RECORD_BLOCK_TIME(FTM_RENDER_UI_3D);
 					render_ui_3d();
 					LLGLState::checkStates();
 				}
@@ -1299,7 +1299,7 @@ void render_ui(F32 zoom_factor, int subfield)
 					render_disconnected_background();
 				}
 
-				LL_RECORD_BLOCK_TIME(FTM_RENDER_UI_2D);
+				LL_PROFILE_ZONE_NAMED_CATEGORY_UI("UI 2D"); //LL_RECORD_BLOCK_TIME(FTM_RENDER_UI_2D);
 				render_ui_2d();
 				LLGLState::checkStates();
 			}
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index 8d749c41cc..2fc4e9d0bd 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -3333,7 +3333,7 @@ static LLTrace::BlockTimerStatHandle ftm("Update UI");
 // event processing.
 void LLViewerWindow::updateUI()
 {
-	LL_RECORD_BLOCK_TIME(ftm);
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; //LL_RECORD_BLOCK_TIME(ftm);
 
 	static std::string last_handle_msg;
 
@@ -5384,7 +5384,7 @@ void LLViewerWindow::setup3DRender()
 
 void LLViewerWindow::setup3DViewport(S32 x_offset, S32 y_offset)
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_UI
 	gGLViewport[0] = mWorldViewRectRaw.mLeft + x_offset;
 	gGLViewport[1] = mWorldViewRectRaw.mBottom + y_offset;
 	gGLViewport[2] = mWorldViewRectRaw.getWidth();
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index c7dc710dd1..a17efecf2d 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -3973,8 +3973,8 @@ void LLPipeline::postSort(LLCamera& camera)
 
 void render_hud_elements()
 {
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_UI);
-	gPipeline.disableLights();		
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; //LL_RECORD_BLOCK_TIME(FTM_RENDER_UI);
+	gPipeline.disableLights();
 	
 	LLGLDisable fog(GL_FOG);
 	LLGLSUIDefault gls_ui;
-- 
cgit v1.2.3


From b41a54e126c0aa0b45321015eca738be0f422aa2 Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Thu, 13 Jan 2022 13:02:37 -0800
Subject: SL-16606: Add profiler category VERTEX

---
 indra/llrender/llvertexbuffer.cpp | 40 +++++++++++++++++++--------------------
 1 file changed, 20 insertions(+), 20 deletions(-)

(limited to 'indra')

diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp
index 9926447ef8..6338cab96a 100644
--- a/indra/llrender/llvertexbuffer.cpp
+++ b/indra/llrender/llvertexbuffer.cpp
@@ -123,7 +123,7 @@ bool LLVertexBuffer::sPreferStreamDraw = false;
 
 U32 LLVBOPool::genBuffer()
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX
 
 	if (sNameIdx == 0)
 	{
@@ -136,7 +136,7 @@ U32 LLVBOPool::genBuffer()
 
 void LLVBOPool::deleteBuffer(U32 name)
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX
 	if (gGLManager.mInited)
 	{
 		LLVertexBuffer::unbind();
@@ -159,7 +159,7 @@ LLVBOPool::LLVBOPool(U32 vboUsage, U32 vboType)
 
 U8* LLVBOPool::allocate(U32& name, U32 size, bool for_seed)
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX
 	llassert(vbo_block_size(size) == size);
 	
 	U8* ret = NULL;
@@ -275,12 +275,12 @@ void LLVBOPool::release(U32 name, U8* buffer, U32 size)
 
 void LLVBOPool::seedPool()
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX
 	U32 dummy_name = 0;
 
 	if (mFreeList.size() < LL_VBO_POOL_SEED_COUNT)
 	{
-		LL_PROFILE_ZONE_NAMED("VBOPool Resize");
+		LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("VBOPool Resize");
 		mFreeList.resize(LL_VBO_POOL_SEED_COUNT);
 	}
 
@@ -421,7 +421,7 @@ void LLVertexBuffer::releaseVAOName(U32 name)
 //static
 void LLVertexBuffer::seedPools()
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX
 	sStreamVBOPool.seedPool();
 	sDynamicVBOPool.seedPool();
 	sDynamicCopyVBOPool.seedPool();
@@ -470,7 +470,7 @@ void LLVertexBuffer::setupClientArrays(U32 data_mask)
 //static
 void LLVertexBuffer::drawArrays(U32 mode, const std::vector<LLVector3>& pos)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX;
     gGL.begin(mode);
     for (auto& v : pos)
     {
@@ -483,7 +483,7 @@ void LLVertexBuffer::drawArrays(U32 mode, const std::vector<LLVector3>& pos)
 //static
 void LLVertexBuffer::drawElements(U32 mode, const LLVector4a* pos, const LLVector2* tc, S32 num_indices, const U16* indicesp)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX;
 	llassert(LLGLSLShader::sCurBoundShaderPtr != NULL);
 
 	gGL.syncMatrices();
@@ -699,7 +699,7 @@ void LLVertexBuffer::draw(U32 mode, U32 count, U32 indices_offset) const
 
 void LLVertexBuffer::drawArrays(U32 mode, U32 first, U32 count) const
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX;
     llassert(LLGLSLShader::sCurBoundShaderPtr != NULL);
     mMappable = false;
     gGL.syncMatrices();
@@ -1257,7 +1257,7 @@ void LLVertexBuffer::setupVertexArray()
 		return;
 	}
 
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX;
 #if GL_ARB_vertex_array_object
 	glBindVertexArray(mGLArray);
 #endif
@@ -1434,7 +1434,7 @@ bool expand_region(LLVertexBuffer::MappedRegion& region, S32 index, S32 count)
 // Map for data access
 U8* LLVertexBuffer::mapVertexBuffer(S32 type, S32 index, S32 count, bool map_range)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX;
 	bindGLBuffer(true);
 	if (mFinal)
 	{
@@ -1611,7 +1611,7 @@ U8* LLVertexBuffer::mapVertexBuffer(S32 type, S32 index, S32 count, bool map_ran
 
 U8* LLVertexBuffer::mapIndexBuffer(S32 index, S32 count, bool map_range)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX;
 	bindGLIndices(true);
 	if (mFinal)
 	{
@@ -1778,10 +1778,10 @@ void LLVertexBuffer::unmapBuffer()
 	}
 
 	bool updated_all = false;
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX;
 	if (mMappedData && mVertexLocked)
 	{
-        LL_PROFILE_ZONE_NAMED("unmapBuffer - vertex");
+        LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("unmapBuffer - vertex");
 		bindGLBuffer(true);
 		updated_all = mIndexLocked; //both vertex and index buffers done updating
 
@@ -1828,7 +1828,7 @@ void LLVertexBuffer::unmapBuffer()
 			{
 				if (!mMappedVertexRegions.empty())
 				{
-                    LL_PROFILE_ZONE_NAMED("unmapBuffer - flush vertex");
+                    LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("unmapBuffer - flush vertex");
 					for (U32 i = 0; i < mMappedVertexRegions.size(); ++i)
 					{
 						const MappedRegion& region = mMappedVertexRegions[i];
@@ -1864,7 +1864,7 @@ void LLVertexBuffer::unmapBuffer()
 	
 	if (mMappedIndexData && mIndexLocked)
 	{
-        LL_PROFILE_ZONE_NAMED("unmapBuffer - index");
+        LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("unmapBuffer - index");
 		bindGLIndices();
 		if(!mMappable)
 		{
@@ -1910,7 +1910,7 @@ void LLVertexBuffer::unmapBuffer()
 				{
 					for (U32 i = 0; i < mMappedIndexRegions.size(); ++i)
 					{
-                        LL_PROFILE_ZONE_NAMED("unmapBuffer - flush index");
+                        LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("unmapBuffer - flush index");
 						const MappedRegion& region = mMappedIndexRegions[i];
 						S32 offset = region.mIndex >= 0 ? sizeof(U16)*region.mIndex : 0;
 						S32 length = sizeof(U16)*region.mCount;
@@ -2063,7 +2063,7 @@ bool LLVertexBuffer::bindGLArray()
 	if (mGLArray && sGLRenderArray != mGLArray)
 	{
 		{
-            LL_PROFILE_ZONE_SCOPED;
+            LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX;
 #if GL_ARB_vertex_array_object
 			glBindVertexArray(mGLArray);
 #endif
@@ -2088,7 +2088,7 @@ bool LLVertexBuffer::bindGLBuffer(bool force_bind)
 
 	if (useVBOs() && (force_bind || (mGLBuffer && (mGLBuffer != sGLRenderBuffer || !sVBOActive))))
 	{
-        LL_PROFILE_ZONE_SCOPED;
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX;
 		glBindBufferARB(GL_ARRAY_BUFFER_ARB, mGLBuffer);
 		sGLRenderBuffer = mGLBuffer;
 		sBindCount++;
@@ -2119,7 +2119,7 @@ bool LLVertexBuffer::bindGLBufferFast()
 
 bool LLVertexBuffer::bindGLIndices(bool force_bind)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX;
 	bindGLArray();
 
 	bool ret = false;
-- 
cgit v1.2.3


From a71f772cc399cc516e8d4d4652ee91009b4ff95a Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Thu, 13 Jan 2022 13:03:37 -0800
Subject: SL-16606: Add profiler category VOLUME

---
 indra/llmath/llvolume.cpp    | 26 +++++++++++++-------------
 indra/newview/llvovolume.cpp | 28 ++++++++++++++--------------
 2 files changed, 27 insertions(+), 27 deletions(-)

(limited to 'indra')

diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp
index c226315e5c..e9ccde5fae 100644
--- a/indra/llmath/llvolume.cpp
+++ b/indra/llmath/llvolume.cpp
@@ -383,7 +383,7 @@ public:
 	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
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME
 
 		LLVolumeOctreeListener* node = (LLVolumeOctreeListener*) branch->getListener(0);
 
@@ -823,7 +823,7 @@ 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
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME
 
 	if ((!mDirty) && (!is_sculpted))
 	{
@@ -1305,7 +1305,7 @@ 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
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME
 
 	// Generates a circular path, starting at (1, 0, 0), counterclockwise along the xz plane.
 	static const F32 tableScale[] = { 1, 1, 1, 0.5f, 0.707107f, 0.53f, 0.525f, 0.5f };
@@ -1541,7 +1541,7 @@ 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
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME
 
 	if ((!mDirty) && (!is_sculpted))
 	{
@@ -2119,7 +2119,7 @@ LLVolume::~LLVolume()
 
 BOOL LLVolume::generate()
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME
 
 	LL_CHECK_MEMORY
 	llassert_always(mProfilep);
@@ -2379,7 +2379,7 @@ bool LLVolumeFace::VertexData::compareNormal(const LLVolumeFace::VertexData& rhs
 
 bool LLVolume::unpackVolumeFaces(std::istream& is, S32 size)
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME
 
 	//input stream is now pointing at a zlib compressed block of LLSD
 	//decompress block
@@ -2766,7 +2766,7 @@ S32	LLVolume::getNumFaces() const
 
 void LLVolume::createVolumeFaces()
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME
 
 	if (mGenerateSingleFace)
 	{
@@ -3733,7 +3733,7 @@ void LLVolume::generateSilhouetteVertices(std::vector<LLVector3> &vertices,
 										  const LLMatrix3& norm_mat_in,
 										  S32 face_mask)
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME
 
 	LLMatrix4a mat;
 	mat.loadu(mat_in);
@@ -4861,7 +4861,7 @@ void LLVolumeFace::freeData()
 
 BOOL LLVolumeFace::create(LLVolume* volume, BOOL partial_build)
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME
 
 	//tree for this face is no longer valid
 	delete mOctree;
@@ -5531,7 +5531,7 @@ bool LLVolumeFace::cacheOptimize()
 
 void LLVolumeFace::createOctree(F32 scaler, const LLVector4a& center, const LLVector4a& size)
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME
 
 	if (mOctree)
 	{
@@ -6306,7 +6306,7 @@ void CalculateTangentArray(U32 vertexCount, const LLVector4a *vertex, const LLVe
 
 void LLVolumeFace::createTangents()
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME
 
 	if (!mTangents)
 	{
@@ -6503,7 +6503,7 @@ void LLVolumeFace::fillFromLegacyData(std::vector<LLVolumeFace::VertexData>& v,
 
 BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build)
 {
-	LL_PROFILE_ZONE_SCOPED
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME
 
 	LL_CHECK_MEMORY
 	BOOL flat = mTypeMask & FLAT_MASK;
@@ -6997,7 +6997,7 @@ 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
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME
 
     //LLVector4a *tan1 = new LLVector4a[vertexCount * 2];
 	LLVector4a* tan1 = (LLVector4a*) ll_aligned_malloc_16(vertexCount*2*sizeof(LLVector4a));
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index c49ac895ca..347460ac34 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -712,7 +712,7 @@ BOOL LLVOVolume::isVisible() const
 
 void LLVOVolume::updateTextureVirtualSize(bool forced)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME;
 	// Update the pixel area of all faces
 
     if (mDrawable.isNull())
@@ -991,7 +991,7 @@ LLDrawable *LLVOVolume::createDrawable(LLPipeline *pipeline)
 
 BOOL LLVOVolume::setVolume(const LLVolumeParams &params_in, const S32 detail, bool unique_volume)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME;
 	LLVolumeParams volume_params = params_in;
 
 	S32 last_lod = mVolumep.notNull() ? LLVolumeLODGroup::getVolumeDetailFromScale(mVolumep->getDetail()) : -1;
@@ -1619,7 +1619,7 @@ BOOL LLVOVolume::setParent(LLViewerObject* parent)
 // NOTE: regenFaces() MUST be followed by genTriangles()!
 void LLVOVolume::regenFaces()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME;
 	// remove existing faces
 	BOOL count_changed = mNumFaces != getNumTEs();
 	
@@ -1918,7 +1918,7 @@ void LLVOVolume::updateRelativeXform(bool force_identity)
 
 bool LLVOVolume::lodOrSculptChanged(LLDrawable *drawable, BOOL &compiled)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME;
 	bool regen_faces = false;
 
 	LLVolume *old_volumep, *new_volumep;
@@ -1982,7 +1982,7 @@ bool LLVOVolume::lodOrSculptChanged(LLDrawable *drawable, BOOL &compiled)
 
 BOOL LLVOVolume::updateGeometry(LLDrawable *drawable)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME;
 	
 	if (mDrawable->isState(LLDrawable::REBUILD_RIGGED))
 	{
@@ -3769,7 +3769,7 @@ void LLVOVolume::afterReparent()
 //----------------------------------------------------------------------------
 void LLVOVolume::updateRiggingInfo()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME;
     if (isRiggedMesh())
     {
         const LLMeshSkinInfo* skin = getSkinInfo();
@@ -4379,7 +4379,7 @@ void LLVOVolume::updateSpatialExtents(LLVector4a& newMin, LLVector4a& newMax)
 
 F32 LLVOVolume::getBinRadius()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME;
 	F32 radius;
 	
 	F32 scale = 1.f;
@@ -4775,7 +4775,7 @@ void LLVOVolume::clearRiggedVolume()
 
 void LLVOVolume::updateRiggedVolume(bool force_update)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME;
 	//Update mRiggedVolume to match current animation frame of avatar. 
 	//Also update position/size in octree.  
 
@@ -4813,7 +4813,7 @@ void LLVOVolume::updateRiggedVolume(bool force_update)
 
 void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, const LLVolume* volume)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME;
 	bool copy = false;
 	if (volume->getNumVolumeFaces() != getNumVolumeFaces())
 	{ 
@@ -5119,7 +5119,7 @@ void LLVolumeGeometryManager::freeFaces()
 
 void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep, U32 type)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME;
 	if (   type == LLRenderPass::PASS_ALPHA 
 		&& facep->getTextureEntry()->getMaterialParams().notNull() 
 		&& !facep->getVertexBuffer()->hasDataType(LLVertexBuffer::TYPE_TANGENT)
@@ -5474,7 +5474,7 @@ static inline void add_face(T*** list, U32* count, T* face)
 
 void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME;
 	if (group->changeLOD())
 	{
 		group->mLastUpdateDistance = group->mDistance;
@@ -5952,7 +5952,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 
 void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME;
 	llassert(group);
 	if (group && group->hasState(LLSpatialGroup::MESH_DIRTY) && !group->hasState(LLSpatialGroup::GEOM_DIRTY))
 	{
@@ -6144,7 +6144,7 @@ struct CompareBatchBreakerRigged
 
 U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace** faces, U32 face_count, BOOL distance_sort, BOOL batch_textures, BOOL rigged)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME;
 
 	U32 geometryBytes = 0;
 	U32 buffer_usage = group->mBufferUsage;
@@ -6783,7 +6783,7 @@ U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace
 
 void LLGeometryManager::addGeometryCount(LLSpatialGroup* group, U32 &vertex_count, U32 &index_count)
 {	
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME;
 
 	//initialize to default usage for this partition
 	U32 usage = group->getSpatialPartition()->mBufferUsage;
-- 
cgit v1.2.3


From 8aa22b41650f13f3752643276ab1449de4fa3ab8 Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Thu, 13 Jan 2022 13:05:43 -0800
Subject: SL-16606: Add profiler category STATS

---
 indra/llcommon/lltracethreadrecorder.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'indra')

diff --git a/indra/llcommon/lltracethreadrecorder.cpp b/indra/llcommon/lltracethreadrecorder.cpp
index 7ae1e72784..090d3297a0 100644
--- a/indra/llcommon/lltracethreadrecorder.cpp
+++ b/indra/llcommon/lltracethreadrecorder.cpp
@@ -277,7 +277,7 @@ void ThreadRecorder::pushToParent()
 void ThreadRecorder::pullFromChildren()
 {
 #if LL_TRACE_ENABLED
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	if (mActiveRecordings.empty()) return;
 
 	{ LLMutexLock lock(&mChildListMutex);
-- 
cgit v1.2.3


From 84b746ad8e707d052cdb4709f8cd91642ff0e73f Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Thu, 13 Jan 2022 13:06:18 -0800
Subject: SL-16606: Add profiler category AVATAR

---
 indra/llcharacter/llkeyframemotion.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'indra')

diff --git a/indra/llcharacter/llkeyframemotion.cpp b/indra/llcharacter/llkeyframemotion.cpp
index 5a5aa2c83e..a25ff16786 100644
--- a/indra/llcharacter/llkeyframemotion.cpp
+++ b/indra/llcharacter/llkeyframemotion.cpp
@@ -677,7 +677,7 @@ BOOL LLKeyframeMotion::onActivate()
 //-----------------------------------------------------------------------------
 BOOL LLKeyframeMotion::onUpdate(F32 time, U8* joint_mask)
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
 	// llassert(time >= 0.f);		// This will fire
 	time = llmax(0.f, time);
 
-- 
cgit v1.2.3


From 8c823b75c00bd8c49568fbcd6180469a02a3a6e3 Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Thu, 13 Jan 2022 13:09:50 -0800
Subject: SL-16606: Add profiler category WIN32

---
 indra/llwindow/llwindowwin32.cpp | 130 +++++++++++++++++++--------------------
 1 file changed, 65 insertions(+), 65 deletions(-)

(limited to 'indra')

diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp
index e4d771978a..8c792daac0 100644
--- a/indra/llwindow/llwindowwin32.cpp
+++ b/indra/llwindow/llwindowwin32.cpp
@@ -1931,7 +1931,7 @@ void LLWindowWin32::hideCursor()
 
 void LLWindowWin32::showCursor()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_WIN32;
 
     ASSERT_MAIN_THREAD();
 	
@@ -2046,7 +2046,7 @@ void LLWindowWin32::initCursors()
 void LLWindowWin32::updateCursor()
 {
     ASSERT_MAIN_THREAD();
-    LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_WIN32
 	if (mNextCursor == UI_CURSOR_ARROW
 		&& mBusyCount > 0)
 	{
@@ -2076,7 +2076,7 @@ void LLWindowWin32::captureMouse()
 
 void LLWindowWin32::releaseMouse()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_WIN32;
 	ReleaseCapture();
 }
 
@@ -2090,7 +2090,7 @@ void LLWindowWin32::delayInputProcessing()
 void LLWindowWin32::gatherInput()
 {
     ASSERT_MAIN_THREAD();
-    LL_PROFILE_ZONE_SCOPED
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_WIN32
     MSG msg;
 
     {
@@ -2104,13 +2104,13 @@ void LLWindowWin32::gatherInput()
 
     if (mWindowThread->getQueue().size())
     {
-        LL_PROFILE_ZONE_NAMED("gi - PostMessage");
+        LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("gi - PostMessage");
         kickWindowThread();
     }
         
     while (mWindowThread->mMessageQueue.tryPopBack(msg))
     {
-        LL_PROFILE_ZONE_NAMED("gi - message queue");
+        LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("gi - message queue");
         if (mInputProcessingPaused)
         {
             continue;
@@ -2119,13 +2119,13 @@ void LLWindowWin32::gatherInput()
         // For async host by name support.  Really hacky.
         if (gAsyncMsgCallback && (LL_WM_HOST_RESOLVED == msg.message))
         {
-            LL_PROFILE_ZONE_NAMED("gi - callback");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("gi - callback");
             gAsyncMsgCallback(msg);
         }
     }
 
     {
-        LL_PROFILE_ZONE_NAMED("gi - PeekMessage");
+        LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("gi - PeekMessage");
         S32 msg_count = 0;
         while ((msg_count < MAX_MESSAGE_PER_UPDATE) && PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_REMOVE))
         {
@@ -2136,7 +2136,7 @@ void LLWindowWin32::gatherInput()
     }
 
     {
-        LL_PROFILE_ZONE_NAMED("gi - function queue");
+        LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("gi - function queue");
         //process any pending functions
         std::function<void()> curFunc;
         while (mFunctionQueue.tryPopBack(curFunc))
@@ -2148,14 +2148,14 @@ void LLWindowWin32::gatherInput()
     // send one and only one mouse move event per frame BEFORE handling mouse button presses
     if (mLastCursorPosition != mCursorPosition)
     {
-        LL_PROFILE_ZONE_NAMED("gi - mouse move");
+        LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("gi - mouse move");
         mCallbacks->handleMouseMove(this, mCursorPosition.convert(), mMouseMask);
     }
     
     mLastCursorPosition = mCursorPosition;
 
     {
-        LL_PROFILE_ZONE_NAMED("gi - mouse queue");
+        LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("gi - mouse queue");
         // handle mouse button presses AFTER updating mouse cursor position
         std::function<void()> curFunc;
         while (mMouseQueue.tryPopBack(curFunc))
@@ -2177,7 +2177,7 @@ static LLTrace::BlockTimerStatHandle FTM_MOUSEHANDLER("Handle Mouse");
 LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_param, LPARAM l_param)
 {
     ASSERT_WINDOW_THREAD();
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_WIN32;
 
     LL_DEBUGS("Window") << "mainWindowProc(" << std::hex << h_wnd
                         << ", " << u_msg
@@ -2226,14 +2226,14 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
 
         case WM_TIMER:
         {
-            LL_PROFILE_ZONE_NAMED("mwp - WM_TIMER");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_TIMER");
             WINDOW_IMP_POST(window_imp->mCallbacks->handleTimerEvent(window_imp));
             break;
         }
 
         case WM_DEVICECHANGE:
         {
-            LL_PROFILE_ZONE_NAMED("mwp - WM_DEVICECHANGE");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_DEVICECHANGE");
             if (debug_window_proc)
             {
                 LL_INFOS("Window") << "  WM_DEVICECHANGE: wParam=" << w_param
@@ -2250,7 +2250,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
 
         case WM_PAINT:
         {
-            LL_PROFILE_ZONE_NAMED("mwp - WM_PAINT");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_PAINT");
             GetUpdateRect(window_imp->mWindowHandle, &update_rect, FALSE);
             update_width = update_rect.right - update_rect.left + 1;
             update_height = update_rect.bottom - update_rect.top + 1;
@@ -2266,7 +2266,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
 
         case WM_SETCURSOR:
         {
-            LL_PROFILE_ZONE_NAMED("mwp - WM_SETCURSOR");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_SETCURSOR");
             // This message is sent whenever the cursor is moved in a window.
             // You need to set the appropriate cursor appearance.
 
@@ -2281,21 +2281,21 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
         }
         case WM_ENTERMENULOOP:
         {
-            LL_PROFILE_ZONE_NAMED("mwp - WM_ENTERMENULOOP");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_ENTERMENULOOP");
             WINDOW_IMP_POST(window_imp->mCallbacks->handleWindowBlock(window_imp));
             break;
         }
 
         case WM_EXITMENULOOP:
         {
-            LL_PROFILE_ZONE_NAMED("mwp - WM_EXITMENULOOP");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_EXITMENULOOP");
             WINDOW_IMP_POST(window_imp->mCallbacks->handleWindowUnblock(window_imp));
             break;
         }
 
         case WM_ACTIVATEAPP:
         {
-            LL_PROFILE_ZONE_NAMED("mwp - WM_ACTIVATEAPP");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_ACTIVATEAPP");
             window_imp->post([=]()
                 {
                     // This message should be sent whenever the app gains or loses focus.
@@ -2338,7 +2338,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
         }
         case WM_ACTIVATE:
         {
-            LL_PROFILE_ZONE_NAMED("mwp - WM_ACTIVATE");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_ACTIVATE");
             window_imp->post([=]()
                 {
                     // Can be one of WA_ACTIVE, WA_CLICKACTIVE, or WA_INACTIVE
@@ -2372,7 +2372,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
 
         case WM_SYSCOMMAND:
         {
-            LL_PROFILE_ZONE_NAMED("mwp - WM_SYSCOMMAND");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_SYSCOMMAND");
             switch (w_param)
             {
             case SC_KEYMENU:
@@ -2388,7 +2388,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
         }
         case WM_CLOSE:
         {
-            LL_PROFILE_ZONE_NAMED("mwp - WM_CLOSE");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_CLOSE");
             window_imp->post([=]()
                 {
                     // Will the app allow the window to close?
@@ -2403,7 +2403,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
         }
         case WM_DESTROY:
         {
-            LL_PROFILE_ZONE_NAMED("mwp - WM_DESTROY");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_DESTROY");
             if (window_imp->shouldPostQuit())
             {
                 PostQuitMessage(0);  // Posts WM_QUIT with an exit code of 0
@@ -2412,7 +2412,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
         }
         case WM_COMMAND:
         {
-            LL_PROFILE_ZONE_NAMED("mwp - WM_COMMAND");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_COMMAND");
             if (!HIWORD(w_param)) // this message is from a menu
             {
                 WINDOW_IMP_POST(window_imp->mCallbacks->handleMenuSelect(window_imp, LOWORD(w_param)));
@@ -2421,13 +2421,13 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
         }
         case WM_SYSKEYDOWN:
         {
-            LL_PROFILE_ZONE_NAMED("mwp - WM_SYSKEYDOWN");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_SYSKEYDOWN");
             // allow system keys, such as ALT-F4 to be processed by Windows
             eat_keystroke = FALSE;
         }
         case WM_KEYDOWN:
         {
-            LL_PROFILE_ZONE_NAMED("mwp - WM_KEYDOWN");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_KEYDOWN");
             window_imp->post([=]()
                 {
                     window_imp->mKeyCharCode = 0; // don't know until wm_char comes in next
@@ -2454,7 +2454,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
             eat_keystroke = FALSE;
         case WM_KEYUP:
         {
-            LL_PROFILE_ZONE_NAMED("mwp - WM_KEYUP");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_KEYUP");
             window_imp->post([=]()
             {
                 window_imp->mKeyScanCode = (l_param >> 16) & 0xff;
@@ -2479,7 +2479,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
         }
         case WM_IME_SETCONTEXT:
         {
-            LL_PROFILE_ZONE_NAMED("mwp - WM_IME_SETCONTEXT");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_IME_SETCONTEXT");
             if (debug_window_proc)
             {
                 LL_INFOS("Window") << "WM_IME_SETCONTEXT" << LL_ENDL;
@@ -2493,7 +2493,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
         }
         case WM_IME_STARTCOMPOSITION:
         {
-            LL_PROFILE_ZONE_NAMED("mwp - WM_IME_STARTCOMPOSITION");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_IME_STARTCOMPOSITION");
             if (debug_window_proc)
             {
                 LL_INFOS() << "WM_IME_STARTCOMPOSITION" << LL_ENDL;
@@ -2507,7 +2507,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
         }
         case WM_IME_ENDCOMPOSITION:
         {
-            LL_PROFILE_ZONE_NAMED("mwp - WM_IME_ENDCOMPOSITION");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_IME_ENDCOMPOSITION");
             if (debug_window_proc)
             {
                 LL_INFOS() << "WM_IME_ENDCOMPOSITION" << LL_ENDL;
@@ -2520,7 +2520,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
         }
         case WM_IME_COMPOSITION:
         {
-            LL_PROFILE_ZONE_NAMED("mwp - WM_IME_COMPOSITION");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_IME_COMPOSITION");
             if (debug_window_proc)
             {
                 LL_INFOS() << "WM_IME_COMPOSITION" << LL_ENDL;
@@ -2534,7 +2534,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
         }
         case WM_IME_REQUEST:
         {
-            LL_PROFILE_ZONE_NAMED("mwp - WM_IME_REQUEST");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_IME_REQUEST");
             if (debug_window_proc)
             {
                 LL_INFOS() << "WM_IME_REQUEST" << LL_ENDL;
@@ -2549,7 +2549,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
         }
         case WM_CHAR:
         {
-            LL_PROFILE_ZONE_NAMED("mwp - WM_CHAR");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_CHAR");
             window_imp->post([=]()
                 {
                     window_imp->mKeyCharCode = w_param;
@@ -2581,7 +2581,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
         }
         case WM_NCLBUTTONDOWN:
         {
-            LL_PROFILE_ZONE_NAMED("mwp - WM_NCLBUTTONDOWN");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_NCLBUTTONDOWN");
             {
                 // A click in a non-client area, e.g. title bar or window border.
                 window_imp->post([=]()
@@ -2594,7 +2594,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
         }
         case WM_LBUTTONDOWN:
         {
-            LL_PROFILE_ZONE_NAMED("mwp - WM_LBUTTONDOWN");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_LBUTTONDOWN");
             {
                 LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER);
                 window_imp->postMouseButtonEvent([=]()
@@ -2619,7 +2619,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
 
         case WM_LBUTTONDBLCLK:
         {
-            LL_PROFILE_ZONE_NAMED("mwp - WM_LBUTTONDBLCLK");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_LBUTTONDBLCLK");
             window_imp->postMouseButtonEvent([=]()
                 {
                     //RN: ignore right button double clicks for now
@@ -2640,7 +2640,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
         }
         case WM_LBUTTONUP:
         {
-            LL_PROFILE_ZONE_NAMED("mwp - WM_LBUTTONUP");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_LBUTTONUP");
             {
                 window_imp->postMouseButtonEvent([=]()
                     {
@@ -2664,7 +2664,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
         case WM_RBUTTONDBLCLK:
         case WM_RBUTTONDOWN:
         {
-            LL_PROFILE_ZONE_NAMED("mwp - WM_RBUTTONDOWN");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_RBUTTONDOWN");
             {
                 LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER);
                 window_imp->post([=]()
@@ -2687,7 +2687,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
 
         case WM_RBUTTONUP:
         {
-            LL_PROFILE_ZONE_NAMED("mwp - WM_RBUTTONUP");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_RBUTTONUP");
             {
                 LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER);
                 window_imp->postMouseButtonEvent([=]()
@@ -2702,7 +2702,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
         case WM_MBUTTONDOWN:
             //		case WM_MBUTTONDBLCLK:
         {
-            LL_PROFILE_ZONE_NAMED("mwp - WM_MBUTTONDOWN");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_MBUTTONDOWN");
             {
                 LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER);
                 window_imp->postMouseButtonEvent([=]()
@@ -2721,7 +2721,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
 
         case WM_MBUTTONUP:
         {
-            LL_PROFILE_ZONE_NAMED("mwp - WM_MBUTTONUP");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_MBUTTONUP");
             {
                 LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER);
                 window_imp->postMouseButtonEvent([=]()
@@ -2734,7 +2734,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
         break;
         case WM_XBUTTONDOWN:
         {
-            LL_PROFILE_ZONE_NAMED("mwp - WM_XBUTTONDOWN");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_XBUTTONDOWN");
             window_imp->postMouseButtonEvent([=]()
                 {
                     LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER);
@@ -2754,7 +2754,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
 
         case WM_XBUTTONUP:
         {
-            LL_PROFILE_ZONE_NAMED("mwp - WM_XBUTTONUP");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_XBUTTONUP");
             window_imp->postMouseButtonEvent([=]()
                 {
 
@@ -2770,7 +2770,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
 
         case WM_MOUSEWHEEL:
         {
-            LL_PROFILE_ZONE_NAMED("mwp - WM_MOUSEWHEEL");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_MOUSEWHEEL");
             static short z_delta = 0;
 
             RECT	client_rect;
@@ -2827,7 +2827,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
         */
         case WM_MOUSEHWHEEL:
         {
-            LL_PROFILE_ZONE_NAMED("mwp - WM_MOUSEHWHEEL");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_MOUSEHWHEEL");
             static short h_delta = 0;
 
             RECT	client_rect;
@@ -2864,12 +2864,12 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
         // Handle mouse movement within the window
         case WM_MOUSEMOVE:
         {
-            LL_PROFILE_ZONE_NAMED("mwp - WM_MOUSEMOVE");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_MOUSEMOVE");
             // DO NOT use mouse event queue for move events to ensure cursor position is updated 
             // when button events are handled
             WINDOW_IMP_POST(
                 {
-                    LL_PROFILE_ZONE_NAMED("mwp - WM_MOUSEMOVE lambda");
+                    LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_MOUSEMOVE lambda");
 
                     MASK mask = gKeyboard->currentMask(TRUE);
                     window_imp->mMouseMask = mask;
@@ -2880,7 +2880,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
 
         case WM_GETMINMAXINFO:
         {
-            LL_PROFILE_ZONE_NAMED("mwp - WM_GETMINMAXINFO");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_GETMINMAXINFO");
             LPMINMAXINFO min_max = (LPMINMAXINFO)l_param;
             min_max->ptMinTrackSize.x = window_imp->mMinWindowWidth;
             min_max->ptMinTrackSize.y = window_imp->mMinWindowHeight;
@@ -2894,7 +2894,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
         }
         case WM_SIZE:
         {
-            LL_PROFILE_ZONE_NAMED("mwp - WM_SIZE");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_SIZE");
             window_imp->updateWindowRect();
             S32 width = S32(LOWORD(l_param));
             S32 height = S32(HIWORD(l_param));
@@ -2956,7 +2956,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
 
         case WM_DPICHANGED:
         {
-            LL_PROFILE_ZONE_NAMED("mwp - WM_DPICHANGED");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_DPICHANGED");
             LPRECT lprc_new_scale;
             F32 new_scale = F32(LOWORD(w_param)) / F32(USER_DEFAULT_SCREEN_DPI);
             lprc_new_scale = (LPRECT)l_param;
@@ -2977,7 +2977,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
 
         case WM_SETFOCUS:
         {
-            LL_PROFILE_ZONE_NAMED("mwp - WM_SETFOCUS");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_SETFOCUS");
             if (debug_window_proc)
             {
                 LL_INFOS("Window") << "WINDOWPROC SetFocus" << LL_ENDL;
@@ -2988,7 +2988,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
 
         case WM_KILLFOCUS:
         {
-            LL_PROFILE_ZONE_NAMED("mwp - WM_KILLFOCUS");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_KILLFOCUS");
             if (debug_window_proc)
             {
                 LL_INFOS("Window") << "WINDOWPROC KillFocus" << LL_ENDL;
@@ -2999,7 +2999,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
 
         case WM_COPYDATA:
         {
-            LL_PROFILE_ZONE_NAMED("mwp - WM_COPYDATA");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_COPYDATA");
             {
                 // received a URL
                 PCOPYDATASTRUCT myCDS = (PCOPYDATASTRUCT)l_param;
@@ -3019,7 +3019,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
         }
         case WM_SETTINGCHANGE:
         {
-            LL_PROFILE_ZONE_NAMED("mwp - WM_SETTINGCHANGE");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_SETTINGCHANGE");
             if (w_param == SPI_SETMOUSEVANISH)
             {
                 if (!SystemParametersInfo(SPI_GETMOUSEVANISH, 0, &window_imp->mMouseVanish, 0))
@@ -3032,7 +3032,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
         
         case WM_INPUT:
         {
-            LL_PROFILE_ZONE_NAMED("MWP - WM_INPUT");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("MWP - WM_INPUT");
             
             UINT dwSize = 0;
             GetRawInputData((HRAWINPUT)l_param, RID_INPUT, NULL, &dwSize, sizeof(RAWINPUTHEADER));
@@ -3064,7 +3064,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
 
         default:
         {
-            LL_PROFILE_ZONE_NAMED("mwp - default");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - default");
             if (debug_window_proc)
             {
                 LL_INFOS("Window") << "Unhandled windows message code: 0x" << std::hex << U32(u_msg) << LL_ENDL;
@@ -3082,7 +3082,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
     // pass unhandled messages down to Windows
     LRESULT ret;
     {
-        LL_PROFILE_ZONE_NAMED("mwp - DefWindowProc");
+        LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - DefWindowProc");
         ret = DefWindowProc(h_wnd, u_msg, w_param, l_param);
     }
     return ret;
@@ -3264,7 +3264,7 @@ BOOL LLWindowWin32::copyTextToClipboard(const LLWString& wstr)
 // Constrains the mouse to the window.
 void LLWindowWin32::setMouseClipping( BOOL b )
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_WIN32;
     ASSERT_MAIN_THREAD();
 	if( b != mIsMouseClipping )
 	{
@@ -3562,7 +3562,7 @@ BOOL LLWindowWin32::resetDisplayResolution()
 
 void LLWindowWin32::swapBuffers()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_WIN32;
     ASSERT_MAIN_THREAD();
 	SwapBuffers(mhDC);
 
@@ -4565,7 +4565,7 @@ void LLWindowWin32::LLWindowWin32Thread::run()
 
     while (! getQueue().done())
     {
-        LL_PROFILE_ZONE_SCOPED;
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_WIN32;
 
         if (mWindowHandle != 0)
         {
@@ -4573,13 +4573,13 @@ void LLWindowWin32::LLWindowWin32Thread::run()
             BOOL status;
             if (mhDC == 0)
             {
-                LL_PROFILE_ZONE_NAMED("w32t - PeekMessage");
+                LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("w32t - PeekMessage");
                 logger.onChange("PeekMessage(", std::hex, mWindowHandle, ")");
                 status = PeekMessage(&msg, mWindowHandle, 0, 0, PM_REMOVE);
             }
             else
             {
-                LL_PROFILE_ZONE_NAMED("w32t - GetMessage");
+                LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("w32t - GetMessage");
                 logger.always("GetMessage(", std::hex, mWindowHandle, ")");
                 status = GetMessage(&msg, NULL, 0, 0);
             }
@@ -4595,7 +4595,7 @@ void LLWindowWin32::LLWindowWin32Thread::run()
         }
 
         {
-            LL_PROFILE_ZONE_NAMED("w32t - Function Queue");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("w32t - Function Queue");
             logger.onChange("runPending()");
             //process any pending functions
             getQueue().runPending();
@@ -4603,7 +4603,7 @@ void LLWindowWin32::LLWindowWin32Thread::run()
         
 #if 0
         {
-            LL_PROFILE_ZONE_NAMED("w32t - Sleep");
+            LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("w32t - Sleep");
             logger.always("sleep(1)");
             std::this_thread::sleep_for(std::chrono::milliseconds(1));
         }
@@ -4640,7 +4640,7 @@ void LLWindowWin32::kickWindowThread(HWND windowHandle)
 
 void LLWindowWin32::updateWindowRect()
 {
-    LL_PROFILE_ZONE_SCOPED;
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_WIN32;
     //called from window thread
     RECT rect;
     RECT client_rect;
-- 
cgit v1.2.3


From 9c7935e1a38c213a0aedac7f97a00272ca45c19e Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Thu, 13 Jan 2022 13:13:06 -0800
Subject: SL-16606: Add note about RP3

---
 indra/llcharacter/lljointsolverrp3.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'indra')

diff --git a/indra/llcharacter/lljointsolverrp3.cpp b/indra/llcharacter/lljointsolverrp3.cpp
index 69a7e3dc6e..cd25511881 100644
--- a/indra/llcharacter/lljointsolverrp3.cpp
+++ b/indra/llcharacter/lljointsolverrp3.cpp
@@ -1,6 +1,6 @@
 /** 
  * @file lljointsolverrp3.cpp
- * @brief Implementation of LLJointSolverRP3 class.
+ * @brief Implementation of Joint Solver in 3D Real Projective space (RP3). See: https://en.wikipedia.org/wiki/Real_projective_space
  *
  * $LicenseInfo:firstyear=2001&license=viewerlgpl$
  * Second Life Viewer Source Code
-- 
cgit v1.2.3


From a255c6bc727d192be75fbf9b0eb53b0d2a247280 Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Thu, 13 Jan 2022 13:16:01 -0800
Subject: SL-16606: Don't spam logging with debug joint info.

---
 indra/llcharacter/lljointsolverrp3.cpp | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

(limited to 'indra')

diff --git a/indra/llcharacter/lljointsolverrp3.cpp b/indra/llcharacter/lljointsolverrp3.cpp
index cd25511881..f3d5e2e324 100644
--- a/indra/llcharacter/lljointsolverrp3.cpp
+++ b/indra/llcharacter/lljointsolverrp3.cpp
@@ -35,6 +35,11 @@
 
 #define F_EPSILON 0.00001f
 
+#if LL_RELEASE
+    #define DEBUG_JOINT_SOLVER 0
+#else
+    #define DEBUG_JOINT_SOLVER 1
+#endif
 
 //-----------------------------------------------------------------------------
 // Constructor
@@ -150,6 +155,7 @@ void LLJointSolverRP3::solve()
 	LLVector3 cPos = mJointC->getWorldPosition();
 	LLVector3 gPos = mJointGoal->getWorldPosition();
 
+#if DEBUG_JOINT_SOLVER
 	LL_DEBUGS("JointSolver") << "LLJointSolverRP3::solve()" << LL_NEWLINE
 							<< "bPosLocal = " << mJointB->getPosition() << LL_NEWLINE
 							<< "cPosLocal = " << mJointC->getPosition() << LL_NEWLINE
@@ -159,6 +165,7 @@ void LLJointSolverRP3::solve()
 							<< "bPos : " << bPos << LL_NEWLINE
 							<< "cPos : " << cPos << LL_NEWLINE
 							<< "gPos : " << gPos << LL_ENDL;
+#endif
 
 	//-------------------------------------------------------------------------
 	// get the poleVector in world space
@@ -194,6 +201,7 @@ void LLJointSolverRP3::solve()
 	//-------------------------------------------------------------------------
 	LLVector3 abacCompOrthoVec = abVec - acVec * ((abVec * acVec)/(acVec * acVec));
 
+#if DEBUG_JOINT_SOLVER
 	LL_DEBUGS("JointSolver") << "abVec : " << abVec << LL_NEWLINE
 		<< "bcVec : " << bcVec << LL_NEWLINE
 		<< "acVec : " << acVec << LL_NEWLINE
@@ -202,6 +210,7 @@ void LLJointSolverRP3::solve()
 		<< "bcLen : " << bcLen << LL_NEWLINE
 		<< "agLen : " << agLen << LL_NEWLINE
 		<< "abacCompOrthoVec : " << abacCompOrthoVec << LL_ENDL;
+#endif
 
 	//-------------------------------------------------------------------------
 	// compute the normal of the original ABC plane (and store for later)
@@ -269,6 +278,7 @@ void LLJointSolverRP3::solve()
 
 	LLQuaternion bRot(theta - abbcAng, abbcOrthoVec);
 
+#if DEBUG_JOINT_SOLVER
 	LL_DEBUGS("JointSolver") << "abbcAng      : " << abbcAng << LL_NEWLINE
 							<< "abbcOrthoVec : " << abbcOrthoVec << LL_NEWLINE
 							<< "agLenSq      : " << agLenSq << LL_NEWLINE
@@ -280,6 +290,7 @@ void LLJointSolverRP3::solve()
 								<< abbcAng*180.0f/F_PI << " " 
 								<< (theta - abbcAng)*180.0f/F_PI 
 	<< LL_ENDL;
+#endif
 
 	//-------------------------------------------------------------------------
 	// compute rotation that rotates new A->C to A->G
@@ -293,9 +304,11 @@ void LLJointSolverRP3::solve()
 	LLQuaternion cgRot;
 	cgRot.shortestArc( acVec, agVec );
 
+#if DEBUG_JOINT_SOLVER
 	LL_DEBUGS("JointSolver") << "bcVec : " << bcVec << LL_NEWLINE
 							<< "acVec : " << acVec << LL_NEWLINE
 							<< "cgRot : " << cgRot << LL_ENDL;
+#endif
 
 	// update A->B and B->C with rotation from C to G
 	abVec = abVec * cgRot;
@@ -358,11 +371,13 @@ void LLJointSolverRP3::solve()
 	//-------------------------------------------------------------------------
 	LLQuaternion twistRot( mTwist, agVec );
 
+#if DEBUG_JOINT_SOLVER
 	LL_DEBUGS("JointSolver") << "abcNorm = " << abcNorm << LL_NEWLINE
 							<< "apgNorm = " << apgNorm << LL_NEWLINE
 							<< "pRot = " << pRot << LL_NEWLINE
 							<< "twist    : " << mTwist*180.0/F_PI << LL_NEWLINE
 							<< "twistRot : " << twistRot << LL_ENDL;
+#endif
 
 	//-------------------------------------------------------------------------
 	// compute rotation of A
-- 
cgit v1.2.3


From 1566c01ad16a973f22990653b3dab8e5bd476db8 Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Thu, 13 Jan 2022 21:09:52 -0800
Subject: SL-16607: Cleanup magic number for no child nodes

---
 indra/llmath/lloctree.h | 21 +++++++++++----------
 1 file changed, 11 insertions(+), 10 deletions(-)

(limited to 'indra')

diff --git a/indra/llmath/lloctree.h b/indra/llmath/lloctree.h
index 8c4a1304b4..80eca781a9 100644
--- a/indra/llmath/lloctree.h
+++ b/indra/llmath/lloctree.h
@@ -92,10 +92,15 @@ public:
 	typedef LLOctreeNode<T>		oct_node;
 	typedef LLOctreeListener<T>	oct_listener;
 
+    enum
+    {
+        NO_CHILD_NODES = 255 // Note: This is an U8 to match the max value in mChildMap[]
+    };
+
 	LLOctreeNode(	const LLVector4a& center, 
 					const LLVector4a& size, 
 					BaseType* parent, 
-					U8 octant = 255)
+					U8 octant = NO_CHILD_NODES)
 	:	mParent((oct_node*)parent), 
 		mOctant(octant) 
 	{ 
@@ -108,7 +113,7 @@ public:
 		mSize = size;
 
 		updateMinMax();
-		if ((mOctant == 255) && mParent)
+		if ((mOctant == NO_CHILD_NODES) && mParent)
 		{
 			mOctant = ((oct_node*) mParent)->getOctant(mCenter);
 		}
@@ -253,7 +258,7 @@ public:
 		for (U32 i = 0; i < 8; i++)
 		{
 			U8 idx = mChildMap[i];
-			if (idx != 255)
+			if (idx != NO_CHILD_NODES)
 			{
 				LLOctreeNode<T>* child = mChild[idx];
 
@@ -286,7 +291,7 @@ public:
 			// the data
 			U8 next_node = node->mChildMap[octant];
 			
-			while (next_node != 255 && node->getSize()[0] >= rad)
+			while (next_node != NO_CHILD_NODES && node->getSize()[0] >= rad)
 			{	
 				node = node->getChild(next_node);
 				octant = node->getOctant(pos);
@@ -514,9 +519,7 @@ public:
 	void clearChildren()
 	{
 		mChildCount = 0;
-
-		U32* foo = (U32*) mChildMap;
-		foo[0] = foo[1] = 0xFFFFFFFF;
+		memset(mChildMap, NO_CHILD_NODES, sizeof(mChildMap));
 	}
 
 	void validate()
@@ -607,11 +610,9 @@ public:
 		--mChildCount;
 
 		mChild[index] = mChild[mChildCount];
-		
 
 		//rebuild child map
-		U32* foo = (U32*) mChildMap;
-		foo[0] = foo[1] = 0xFFFFFFFF;
+		memset(mChildMap, NO_CHILD_NODES, sizeof(mChildMap));
 
 		for (U32 i = 0; i < mChildCount; ++i)
 		{
-- 
cgit v1.2.3


From 9b5f6c636b16e033059bb47d63a7919aeebb69ac Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Thu, 13 Jan 2022 21:10:53 -0800
Subject: SL-16607: Add Tracy capture colors for insert, remove, and balance

---
 indra/llmath/lloctree.h | 9 +++++++++
 1 file changed, 9 insertions(+)

(limited to 'indra')

diff --git a/indra/llmath/lloctree.h b/indra/llmath/lloctree.h
index 80eca781a9..7032c9651b 100644
--- a/indra/llmath/lloctree.h
+++ b/indra/llmath/lloctree.h
@@ -34,6 +34,9 @@
 
 #define OCT_ERRS LL_WARNS("OctreeErrors")
 
+#define OCTREE_DEBUG_COLOR_REMOVE   0x0000FF // r
+#define OCTREE_DEBUG_COLOR_INSERT   0x00FF00 // g
+#define OCTREE_DEBUG_COLOR_BALANCE  0xFF0000 // b
 
 extern U32 gOctreeMaxCapacity;
 extern float gOctreeMinSize;
@@ -308,6 +311,8 @@ public:
 	
 	virtual bool insert(T* data)
 	{
+        //LL_PROFILE_ZONE_NAMED_COLOR("Octree::insert()",OCTREE_DEBUG_COLOR_INSERT);
+
 		if (data == NULL || data->getBinIndex() != -1)
 		{
 			OCT_ERRS << "!!! INVALID ELEMENT ADDED TO OCTREE BRANCH !!!" << LL_ENDL;
@@ -454,6 +459,8 @@ public:
 
 	bool remove(T* data)
 	{
+        //LL_PROFILE_ZONE_NAMED_COLOR("Octree::remove()", OCTREE_DEBUG_COLOR_REMOVE);
+
 		S32 i = data->getBinIndex();
 
 		if (i >= 0 && i < mElementCount)
@@ -692,6 +699,8 @@ public:
 	
 	bool balance()
 	{	
+        //LL_PROFILE_ZONE_NAMED_COLOR("Octree::balance()",OCTREE_DEBUG_COLOR_BALANCE);
+
 		if (this->getChildCount() == 1 && 
 			!(this->mChild[0]->isLeaf()) &&
 			this->mChild[0]->getElementCount() == 0) 
-- 
cgit v1.2.3


From 1dde66ca7924358ef6c19c7d9eb8883c434882bf Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Thu, 13 Jan 2022 21:11:24 -0800
Subject: SL-16607: Cleanup whitespace

---
 indra/llmath/lloctree.h | 15 +++++++--------
 1 file changed, 7 insertions(+), 8 deletions(-)

(limited to 'indra')

diff --git a/indra/llmath/lloctree.h b/indra/llmath/lloctree.h
index 7032c9651b..2283df1e1a 100644
--- a/indra/llmath/lloctree.h
+++ b/indra/llmath/lloctree.h
@@ -126,9 +126,9 @@ public:
 		clearChildren();
 	}
 
-	virtual ~LLOctreeNode()								
+	virtual ~LLOctreeNode()
 	{ 
-		BaseType::destroyListeners(); 
+		BaseType::destroyListeners();
 		
 		for (U32 i = 0; i < mElementCount; ++i)
 		{
@@ -167,7 +167,7 @@ public:
 		return rad <= mSize[0]*2.f && isInside(pos); 
 	}
 
-	inline bool isInside(T* data) const			
+	inline bool isInside(T* data) const
 	{ 
 		return isInside(data->getPositionGroup(), data->getBinRadius());
 	}
@@ -284,7 +284,7 @@ public:
 		LLOctreeNode<T>* node = this;
 
 		if (node->isInside(pos, rad))
-		{		
+		{
 			//do a quick search by octant
 			U8 octant = node->getOctant(pos);
 			
@@ -655,7 +655,7 @@ public:
 		OCT_ERRS << "Octree failed to delete requested child." << LL_ENDL;
 	}
 
-protected:	
+protected:
 	typedef enum
 	{
 		CENTER = 0,
@@ -679,7 +679,6 @@ protected:
 	element_list mData;
 	element_iter mDataEnd;
 	U32 mElementCount;
-		
 }; 
 
 //just like a regular node, except it might expand on insert and compress on balance
@@ -688,7 +687,7 @@ class LLOctreeRoot : public LLOctreeNode<T>
 {
 public:
 	typedef LLOctreeNode<T>	BaseType;
-	typedef LLOctreeNode<T>		oct_node;
+	typedef LLOctreeNode<T>	oct_node;
 
 	LLOctreeRoot(const LLVector4a& center, 
 				 const LLVector4a& size, 
@@ -703,7 +702,7 @@ public:
 
 		if (this->getChildCount() == 1 && 
 			!(this->mChild[0]->isLeaf()) &&
-			this->mChild[0]->getElementCount() == 0) 
+			this->mChild[0]->getElementCount() == 0)
 		{ //if we have only one child and that child is an empty branch, make that child the root
 			oct_node* child = this->mChild[0];
 					
-- 
cgit v1.2.3


From 6aa4d06cb6b728beac15773e9f08a02e375893ea Mon Sep 17 00:00:00 2001
From: Runitai Linden <davep@lindenlab.com>
Date: Fri, 14 Jan 2022 17:11:27 -0600
Subject: SL-16544 Fix for small rigged meshes disappearing at short distances
 (for real this time).

---
 indra/newview/llspatialpartition.h |  1 +
 indra/newview/llvovolume.cpp       | 38 +++++++++++++++++++++++++++++---------
 indra/newview/pipeline.cpp         |  7 -------
 3 files changed, 30 insertions(+), 16 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llspatialpartition.h b/indra/newview/llspatialpartition.h
index 666c025347..afe24d7d1f 100644
--- a/indra/newview/llspatialpartition.h
+++ b/indra/newview/llspatialpartition.h
@@ -623,6 +623,7 @@ class LLVolumeGeometryManager: public LLGeometryManager
 	virtual void rebuildGeom(LLSpatialGroup* group);
 	virtual void rebuildMesh(LLSpatialGroup* group);
 	virtual void getGeometry(LLSpatialGroup* group);
+    virtual void addGeometryCount(LLSpatialGroup* group, U32& vertex_count, U32& index_count);
 	U32 genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace** faces, U32 face_count, BOOL distance_sort = FALSE, BOOL batch_textures = FALSE, BOOL rigged = FALSE);
 	void registerFace(LLSpatialGroup* group, LLFace* facep, U32 type);
 
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index c49ac895ca..b99c8e2280 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -5516,8 +5516,6 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 
 	group->clearDrawMap();
 
-	mFaceList.clear();
-
     U32 fullbright_count[2] = { 0 };
 	U32 bump_count[2] = { 0 };
 	U32 simple_count[2] = { 0 };
@@ -5693,12 +5691,12 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 					continue;
 				}
 
-				cur_total += facep->getGeomCount();
-
-				if (facep->hasGeometry() && 
+				if (facep->hasGeometry() &&
                     (rigged ||  // <-- HACK FIXME -- getPixelArea might be incorrect for rigged objects
                         facep->getPixelArea() > FORCE_CULL_AREA)) // <-- don't render tiny faces
 				{
+                    cur_total += facep->getGeomCount();
+
 					const LLTextureEntry* te = facep->getTextureEntry();
 					LLViewerTexture* tex = facep->getTexture();
 
@@ -5947,7 +5945,6 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 		group->setState(LLSpatialGroup::MESH_DIRTY | LLSpatialGroup::NEW_DRAWINFO);
 	}
 
-	mFaceList.clear();
 }
 
 void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group)
@@ -6781,6 +6778,30 @@ U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace
 	return geometryBytes;
 }
 
+void LLVolumeGeometryManager::addGeometryCount(LLSpatialGroup* group, U32& vertex_count, U32& index_count)
+{
+    //initialize to default usage for this partition
+    U32 usage = group->getSpatialPartition()->mBufferUsage;
+
+    //for each drawable
+    for (LLSpatialGroup::element_iter drawable_iter = group->getDataBegin(); drawable_iter != group->getDataEnd(); ++drawable_iter)
+    {
+        LLDrawable* drawablep = (LLDrawable*)(*drawable_iter)->getDrawable();
+
+        if (!drawablep || drawablep->isDead())
+        {
+            continue;
+        }
+
+        if (drawablep->isAnimating())
+        { //fall back to stream draw for animating verts
+            usage = GL_STREAM_DRAW_ARB;
+        }
+    }
+
+    group->mBufferUsage = usage;
+}
+
 void LLGeometryManager::addGeometryCount(LLSpatialGroup* group, U32 &vertex_count, U32 &index_count)
 {	
     LL_PROFILE_ZONE_SCOPED;
@@ -6788,11 +6809,10 @@ void LLGeometryManager::addGeometryCount(LLSpatialGroup* group, U32 &vertex_coun
 	//initialize to default usage for this partition
 	U32 usage = group->getSpatialPartition()->mBufferUsage;
 	
-	//clear off any old faces
-	mFaceList.clear();
+    //clear off any old faces
+    mFaceList.clear();
 
 	//for each drawable
-
 	for (LLSpatialGroup::element_iter drawable_iter = group->getDataBegin(); drawable_iter != group->getDataEnd(); ++drawable_iter)
 	{
 		LLDrawable* drawablep = (LLDrawable*)(*drawable_iter)->getDrawable();
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index d5f9772b85..d8315c9420 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -2500,13 +2500,6 @@ void LLPipeline::markNotCulled(LLSpatialGroup* group, LLCamera& camera)
 		group->updateDistance(camera);
 	}
 	
-	const F32 MINIMUM_PIXEL_AREA = 16.f;
-
-	if (group->mPixelArea < MINIMUM_PIXEL_AREA)
-	{
-		return;
-	}
-
 	assertInitialized();
 	
 	if (!group->getSpatialPartition()->mRenderByGroup)
-- 
cgit v1.2.3


From 50d9e332ac1eadba6f5642e655b2219c15250c15 Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Thu, 13 May 2021 02:35:45 +0300
Subject: SL-15225 llSetAgentEnvironment cloud density transition doesn't work

---
 indra/newview/llenvironment.cpp | 24 +++++++++++++++++++++++-
 1 file changed, 23 insertions(+), 1 deletion(-)

(limited to 'indra')

diff --git a/indra/newview/llenvironment.cpp b/indra/newview/llenvironment.cpp
index 0cdafcba81..42f3d15a1c 100644
--- a/indra/newview/llenvironment.cpp
+++ b/indra/newview/llenvironment.cpp
@@ -611,6 +611,7 @@ namespace
             specialSet.insert(SETTING_CLOUD_TEXTUREID);
             specialSet.insert(SETTING_MOON_TEXTUREID);
             specialSet.insert(SETTING_SUN_TEXTUREID);
+            specialSet.insert(SETTING_CLOUD_SHADOW); // due to being part of skips
         }
         return specialSet;
     }
@@ -651,6 +652,7 @@ namespace
     template<>
     void LLSettingsInjected<LLSettingsVOSky>::updateSpecial(const typename LLSettingsInjected<LLSettingsVOSky>::Injection::ptr_t &injection, typename LLSettingsBase::BlendFactor mix)
     {
+        bool is_texture = true;
         if (injection->mKeyName == SETTING_SUN_TEXTUREID)
         {
             mNextSunTextureId = injection->mValue.asUUID();
@@ -675,9 +677,29 @@ namespace
         {
             mNextHaloTextureId = injection->mValue.asUUID();
         }
+        else if (injection->mKeyName == LLSettingsSky::SETTING_CLOUD_SHADOW)
+        {
+            // Special case due to being texture dependent and part of skips
+            is_texture = false;
+            if (!injection->mBlendIn)
+                mix = 1.0 - mix;
+            stringset_t dummy;
+            LLUUID cloud_noise_id = getCloudNoiseTextureId();
+            F64 value = this->mSettings[injection->mKeyName].asReal();
+            if (this->getCloudNoiseTextureId().isNull())
+            {
+                value = 0; // there was no texture so start from zero coverage
+            }
+            // Ideally we need to check for texture in injection, but
+            // in this case user is setting value explicitly, potentially
+            // with different transitions, don't ignore it
+            F64 result = lerp(value, injection->mValue.asReal(), mix);
+            injection->mLastValue = LLSD::Real(result);
+            this->mSettings[injection->mKeyName] = injection->mLastValue;
+        }
 
         // Unfortunately I don't have a per texture blend factor.  We'll just pick the one that is furthest along.
-        if (getBlendFactor() < mix)
+        if (is_texture && getBlendFactor() < mix)
         {
             setBlendFactor(mix);
         }
-- 
cgit v1.2.3


From 1a440be5e1760ac95e9a1ef43e5c74b768726826 Mon Sep 17 00:00:00 2001
From: Runitai Linden <davep@lindenlab.com>
Date: Wed, 19 Jan 2022 10:35:58 -0600
Subject: SL-16653 Fix for some textures having incorrect texel colors after
 the first row (and add more paranoia checks on texture data).

---
 indra/llrender/llrender.cpp       |  8 ++++++++
 indra/newview/llviewertexture.cpp | 42 ++++++++++++++++++++++++++++++++++-----
 indra/newview/llviewerwindow.cpp  |  9 ---------
 3 files changed, 45 insertions(+), 14 deletions(-)

(limited to 'indra')

diff --git a/indra/llrender/llrender.cpp b/indra/llrender/llrender.cpp
index 3b46eef1b4..92d8e6193f 100644
--- a/indra/llrender/llrender.cpp
+++ b/indra/llrender/llrender.cpp
@@ -860,6 +860,14 @@ LLRender::~LLRender()
 
 void LLRender::init()
 {
+    glPixelStorei(GL_PACK_ALIGNMENT, 1);
+    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+
+    gGL.setSceneBlendType(LLRender::BT_ALPHA);
+    gGL.setAmbientLightColor(LLColor4::black);
+
+    glCullFace(GL_BACK);
+
 	if (sGLCoreProfile && !LLVertexBuffer::sUseVAO)
 	{ //bind a dummy vertex array object so we're core profile compliant
 #ifdef GL_ARB_vertex_array_object
diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp
index 06f623f1f8..5fed46f437 100644
--- a/indra/newview/llviewertexture.cpp
+++ b/indra/newview/llviewertexture.cpp
@@ -1626,10 +1626,21 @@ void LLViewerFetchedTexture::scheduleCreateTexture()
 {
     if (!mNeedsCreateTexture)
     {
-        ref();
         mNeedsCreateTexture = TRUE;
         if (preCreateTexture())
         {
+            ref();
+#if LL_IMAGEGL_THREAD_CHECK
+            //grab a copy of the raw image data to make sure it isn't modified pending texture creation
+            U8* data = mRawImage->getData();
+            U8* data_copy = nullptr;
+            S32 size = mRawImage->getDataSize();
+            if (data != nullptr && size > 0)
+            {
+                data_copy = new U8[size];
+                memcpy(data_copy, data, size);
+            }
+#endif
             mNeedsCreateTexture = TRUE;
             auto mainq = LLImageGLThread::sEnabled ? mMainQueue.lock() : nullptr;
             if (mainq)
@@ -1637,19 +1648,40 @@ void LLViewerFetchedTexture::scheduleCreateTexture()
                 mainq->postTo(
                     mImageQueue,
                     // work to be done on LLImageGL worker thread
-                    [this]()
-                    {
 #if LL_IMAGEGL_THREAD_CHECK
+                    [this, data, data_copy, size]()
+                    {
                         mGLTexturep->mActiveThread = LLThread::currentID();
+                        //verify data is unmodified
+                        llassert(data == mRawImage->getData());
+                        llassert(mRawImage->getDataSize() == size);
+                        llassert(memcmp(data, data_copy, size) == 0);
+#else
+                    [this]()
+                    {
 #endif
                         //actually create the texture on a background thread
                         createTexture();
+
+#if LL_IMAGEGL_THREAD_CHECK
+                        //verify data is unmodified
+                        llassert(data == mRawImage->getData());
+                        llassert(mRawImage->getDataSize() == size);
+                        llassert(memcmp(data, data_copy, size) == 0);
+#endif
                     },
                     // callback to be run on main thread
-                        [this]()
-                    {
 #if LL_IMAGEGL_THREAD_CHECK
+                        [this, data, data_copy, size]()
+                    {
                         mGLTexturep->mActiveThread = LLThread::currentID();
+                        llassert(data == mRawImage->getData());
+                        llassert(mRawImage->getDataSize() == size);
+                        llassert(memcmp(data, data_copy, size) == 0);
+                        delete[] data_copy;
+#else
+                        [this]()
+                        {
 #endif
                         //finalize on main thread
                         postCreateTexture();
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index 2fc4e9d0bd..b9a5e90df0 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -2058,15 +2058,6 @@ std::string LLViewerWindow::getLastSnapshotDir()
 
 void LLViewerWindow::initGLDefaults()
 {
-	gGL.setSceneBlendType(LLRender::BT_ALPHA);
-
-	glPixelStorei(GL_PACK_ALIGNMENT,1);
-	glPixelStorei(GL_UNPACK_ALIGNMENT,1);
-
-	gGL.setAmbientLightColor(LLColor4::black);
-		
-	glCullFace(GL_BACK);
-
 	// RN: Need this for translation and stretch manip.
 	gBox.prerender();
 }
-- 
cgit v1.2.3