summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/build.yaml10
-rw-r--r--autobuild.xml138
-rw-r--r--indra/cmake/Boost.cmake28
-rw-r--r--indra/cmake/Python.cmake67
-rw-r--r--indra/llcommon/CMakeLists.txt2
-rw-r--r--indra/llcommon/llapp.cpp1
-rw-r--r--indra/llcommon/llapp.h2
-rw-r--r--indra/llcommon/lldate.cpp7
-rw-r--r--indra/llcommon/llerror.cpp6
-rw-r--r--indra/llcommon/llerrorcontrol.h1
-rw-r--r--indra/llcommon/llheteromap.cpp2
-rw-r--r--indra/llcommon/llheteromap.h27
-rw-r--r--indra/llcommon/llinitparam.h129
-rw-r--r--indra/llcommon/llpounceable.h4
-rw-r--r--indra/llcommon/llprocess.cpp5
-rw-r--r--indra/llcommon/llregistry.h26
-rw-r--r--indra/llcommon/llsd.cpp162
-rw-r--r--indra/llcommon/llsd.h39
-rw-r--r--indra/llcommon/llsdjson.cpp4
-rw-r--r--indra/llcommon/llsdserialize.cpp52
-rw-r--r--indra/llcommon/llsdserialize_xml.cpp32
-rw-r--r--indra/llcommon/llsingleton.h4
-rw-r--r--indra/llcommon/llstaticstringtable.h5
-rw-r--r--indra/llcommon/llstl.h38
-rw-r--r--indra/llcommon/llthread.cpp6
-rw-r--r--indra/llcommon/lluuid.h19
-rw-r--r--indra/llcommon/llwatchdog.cpp (renamed from indra/newview/llwatchdog.cpp)36
-rw-r--r--indra/llcommon/llwatchdog.h (renamed from indra/newview/llwatchdog.h)25
-rw-r--r--indra/llcommon/workqueue.cpp7
-rw-r--r--indra/llcommon/workqueue.h6
-rw-r--r--indra/llfilesystem/lldiskcache.cpp2
-rw-r--r--indra/llimage/llimage.cpp16
-rw-r--r--indra/llinventory/llinventory.cpp18
-rw-r--r--indra/llkdu/llimagej2ckdu.cpp5
-rw-r--r--indra/llmath/llvolume.cpp31
-rw-r--r--indra/llmeshoptimizer/llmeshoptimizer.cpp1
-rw-r--r--indra/llmessage/llassetstorage.cpp3
-rw-r--r--indra/llmessage/llassetstorage.h1
-rw-r--r--indra/llmessage/llavatarnamecache.cpp18
-rw-r--r--indra/llmessage/llavatarnamecache.h10
-rw-r--r--indra/llmessage/llcachename.cpp15
-rw-r--r--indra/llmessage/llcachename.h3
-rw-r--r--indra/llmessage/llexperiencecache.cpp33
-rw-r--r--indra/llmessage/llexperiencecache.h4
-rw-r--r--indra/llphysicsextensionsos/llconvexdecompositionvhacd.cpp165
-rw-r--r--indra/llphysicsextensionsos/llconvexdecompositionvhacd.h20
-rw-r--r--indra/llprimitive/llgltfmaterial.cpp2
-rw-r--r--indra/llprimitive/llmaterialid.h30
-rw-r--r--indra/llrender/llfontfreetype.h5
-rw-r--r--indra/llrender/llgl.cpp6
-rw-r--r--indra/llrender/llgl.h4
-rw-r--r--indra/llui/llfloater.cpp2
-rw-r--r--indra/llui/llfloaterreg.cpp19
-rw-r--r--indra/llui/llfloaterreg.h13
-rw-r--r--indra/llui/llfolderviewitem.cpp13
-rw-r--r--indra/llui/llfunctorregistry.h5
-rw-r--r--indra/llui/llkeywords.h2
-rw-r--r--indra/llui/llmenugl.cpp14
-rw-r--r--indra/llui/llmenugl.h2
-rw-r--r--indra/llui/llnotifications.cpp7
-rw-r--r--indra/llui/llnotifications.h4
-rw-r--r--indra/llui/llpanel.h4
-rw-r--r--indra/llui/llradiogroup.cpp2
-rw-r--r--indra/llui/llrngwriter.cpp2
-rw-r--r--indra/llui/llscrolllistcolumn.cpp2
-rw-r--r--indra/llui/lltextbase.cpp2
-rw-r--r--indra/llui/lltooltip.cpp2
-rw-r--r--indra/llui/lltrans.h2
-rw-r--r--indra/llui/llui.cpp2
-rw-r--r--indra/llui/llui.h2
-rw-r--r--indra/llui/lluicolortable.cpp9
-rw-r--r--indra/llui/lluicolortable.h4
-rw-r--r--indra/llui/lluictrlfactory.cpp2
-rw-r--r--indra/llui/lluictrlfactory.h12
-rw-r--r--indra/llui/llxuiparser.cpp46
-rw-r--r--indra/llui/llxuiparser.h6
-rw-r--r--indra/llwindow/llwindow.h2
-rw-r--r--indra/llwindow/llwindowwin32.cpp65
-rw-r--r--indra/llwindow/llwindowwin32.h141
-rw-r--r--indra/llxml/llcontrol.cpp2
-rw-r--r--indra/llxml/llcontrol.h4
-rw-r--r--indra/newview/CMakeLists.txt2
-rw-r--r--indra/newview/VIEWER_VERSION.txt2
-rw-r--r--indra/newview/app_settings/settings.xml13
-rw-r--r--indra/newview/app_settings/shaders/class1/deferred/pbropaqueF.glsl3
-rw-r--r--indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl9
-rw-r--r--indra/newview/gltf/asset.cpp6
-rw-r--r--indra/newview/gltf/buffer_util.h44
-rw-r--r--indra/newview/gltf/llgltfloader.cpp3
-rw-r--r--indra/newview/llagent.cpp2
-rw-r--r--indra/newview/llappcorehttp.cpp2
-rw-r--r--indra/newview/llappviewer.cpp75
-rw-r--r--indra/newview/llappviewer.h2
-rw-r--r--indra/newview/llavatarlistitem.cpp2
-rw-r--r--indra/newview/llcallingcard.cpp2
-rw-r--r--indra/newview/llcapabilityprovider.h4
-rw-r--r--indra/newview/lleventpoll.cpp58
-rw-r--r--indra/newview/llexternaleditor.cpp8
-rw-r--r--indra/newview/llfavoritesbar.cpp36
-rw-r--r--indra/newview/llfilepicker_mac.mm7
-rw-r--r--indra/newview/llfloatermarketplace.cpp1
-rw-r--r--indra/newview/llgltfmateriallist.cpp2
-rw-r--r--indra/newview/llinventorylistitem.cpp2
-rw-r--r--indra/newview/llinventorymodel.cpp70
-rw-r--r--indra/newview/llinventorymodel.h8
-rw-r--r--indra/newview/llinventorypanel.cpp3
-rw-r--r--indra/newview/llinventorypanel.h2
-rw-r--r--indra/newview/lllandmarklist.cpp49
-rw-r--r--indra/newview/lllandmarklist.h1
-rw-r--r--indra/newview/llmachineid.cpp2
-rw-r--r--indra/newview/llmaterialmgr.h76
-rw-r--r--indra/newview/llmeshrepository.h2
-rw-r--r--indra/newview/llmodelpreview.cpp2
-rw-r--r--indra/newview/llmutelist.cpp4
-rw-r--r--indra/newview/lloutfitgallery.cpp19
-rw-r--r--indra/newview/lloutfitgallery.h2
-rw-r--r--indra/newview/lloutfitslist.cpp17
-rw-r--r--indra/newview/lloutfitslist.h13
-rw-r--r--indra/newview/llpanelface.cpp32
-rw-r--r--indra/newview/llpanelface.h2
-rw-r--r--indra/newview/llpanellogin.cpp10
-rw-r--r--indra/newview/llpanelobjectinventory.cpp2
-rw-r--r--indra/newview/llpanelobjectinventory.h2
-rw-r--r--indra/newview/llpanelplaceprofile.cpp4
-rw-r--r--indra/newview/llpanelplaceprofile.h2
-rw-r--r--indra/newview/llpanelsnapshotinventory.cpp6
-rw-r--r--indra/newview/llperfstats.h2
-rw-r--r--indra/newview/llscriptruntimeperms.h13
-rw-r--r--indra/newview/llselectmgr.cpp9
-rw-r--r--indra/newview/lltexturecache.cpp2
-rw-r--r--indra/newview/lltoastscriptquestion.cpp73
-rw-r--r--indra/newview/llviewerassetstorage.cpp71
-rw-r--r--indra/newview/llviewercontrol.cpp1
-rw-r--r--indra/newview/llviewermenu.cpp90
-rw-r--r--indra/newview/llviewermessage.cpp24
-rw-r--r--indra/newview/llviewerobject.cpp58
-rw-r--r--indra/newview/llviewerobject.h6
-rw-r--r--indra/newview/llviewerobjectlist.cpp2
-rw-r--r--indra/newview/llviewerobjectlist.h4
-rw-r--r--indra/newview/llviewerprecompiledheaders.h2
-rw-r--r--indra/newview/llviewerregion.cpp29
-rw-r--r--indra/newview/llviewerregion.h8
-rw-r--r--indra/newview/llviewertexture.cpp40
-rw-r--r--indra/newview/llviewerwindow.cpp6
-rw-r--r--indra/newview/llviewerwindow.h6
-rw-r--r--indra/newview/llvoicewebrtc.cpp31
-rw-r--r--indra/newview/llwearableitemslist.cpp10
-rw-r--r--indra/newview/skins/default/xui/en/menu_favorites.xml6
-rw-r--r--indra/newview/skins/default/xui/en/menu_viewer.xml12
-rw-r--r--indra/newview/skins/default/xui/en/notifications.xml21
-rw-r--r--indra/newview/skins/default/xui/en/panel_notification.xml8
-rw-r--r--indra/newview/skins/default/xui/en/panel_script_question_toast.xml6
-rw-r--r--indra/newview/skins/default/xui/en/strings.xml3
-rw-r--r--indra/newview/tests/lldateutil_test.cpp6
-rwxr-xr-xindra/newview/viewer_manifest.py5
155 files changed, 1892 insertions, 953 deletions
diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml
index 01071d1377..7279c17297 100644
--- a/.github/workflows/build.yaml
+++ b/.github/workflows/build.yaml
@@ -295,7 +295,7 @@ jobs:
echo "artifact=$RUNNER_OS$cfg_suffix" >> $GITHUB_OUTPUT
- name: Upload executable
- uses: actions/upload-artifact@v4
+ uses: actions/upload-artifact@v6
if: matrix.build_variant == 'Viewer' && steps.build.outputs.viewer_app
with:
name: "${{ steps.build.outputs.artifact }}-app"
@@ -305,14 +305,14 @@ jobs:
# The other upload of nontrivial size is the symbol file. Use a distinct
# artifact for that too.
- name: Upload symbol file
- uses: actions/upload-artifact@v4
+ uses: actions/upload-artifact@v6
if: matrix.build_variant == 'Viewer' && steps.build.outputs.symbolfile
with:
name: "${{ steps.build.outputs.artifact }}-symbols"
path: ${{ steps.build.outputs.symbolfile }}
- name: Upload metadata
- uses: actions/upload-artifact@v4
+ uses: actions/upload-artifact@v6
if: matrix.build_variant == 'Viewer'
with:
name: "${{ steps.build.outputs.artifact }}-metadata"
@@ -321,7 +321,7 @@ jobs:
${{ steps.build.outputs.metadata }}
- name: Upload physics package
- uses: actions/upload-artifact@v4
+ uses: actions/upload-artifact@v6
# should only be set for viewer-private
if: matrix.build_variant == 'Viewer' && matrix.configuration == 'Release' && steps.build.outputs.physicstpv
with:
@@ -331,7 +331,7 @@ jobs:
${{ steps.build.outputs.physicstpv }}
- name: Upload appearance utility package
- uses: actions/upload-artifact@v4
+ uses: actions/upload-artifact@v6
if: matrix.build_variant == 'Viewer' && steps.build.outputs.appearanceutility
with:
name: "${{ steps.build.outputs.artifact }}-appearanceutility"
diff --git a/autobuild.xml b/autobuild.xml
index 889fdc8567..bc6b073a99 100644
--- a/autobuild.xml
+++ b/autobuild.xml
@@ -138,11 +138,11 @@
<key>archive</key>
<map>
<key>hash</key>
- <string>a4553df5b8fde2e9cd54ebb94c6efb8eb5fe3c38</string>
+ <string>61cc299413a32350175cf7139f64388d3d096ec7</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
- <string>https://github.com/secondlife/3p-boost/releases/download/v1.86.0-be1a669/boost-1.86-darwin64-13246092114.tar.zst</string>
+ <string>https://github.com/secondlife/3p-boost/releases/download/v1.90.0-c7a9feb/boost-1.90-darwin64-20977261894.tar.zst</string>
</map>
<key>name</key>
<string>darwin64</string>
@@ -152,11 +152,11 @@
<key>archive</key>
<map>
<key>hash</key>
- <string>4a2a19dc5cb555e157ad894ba917f5a83a35b20d</string>
+ <string>6b93e323284bfab8ec20a7f3bc740c6915980bf8</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
- <string>https://github.com/secondlife/3p-boost/releases/download/v1.86.0-be1a669/boost-1.86-linux64-13246092114.tar.zst</string>
+ <string>https://github.com/secondlife/3p-boost/releases/download/v1.90.0-c7a9feb/boost-1.90-linux64-20977261894.tar.zst</string>
</map>
<key>name</key>
<string>linux64</string>
@@ -166,11 +166,11 @@
<key>archive</key>
<map>
<key>hash</key>
- <string>8a1fa9366bfe49009286e4805d7aaedb7c3df82e</string>
+ <string>c543437ca30a63dcd2538fffa89a43ef43f625fb</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
- <string>https://github.com/secondlife/3p-boost/releases/download/v1.86.0-be1a669/boost-1.86-windows64-13246092114.tar.zst</string>
+ <string>https://github.com/secondlife/3p-boost/releases/download/v1.90.0-c7a9feb/boost-1.90-windows64-20977261894.tar.zst</string>
</map>
<key>name</key>
<string>windows64</string>
@@ -183,7 +183,7 @@
<key>copyright</key>
<string>(see individual source files)</string>
<key>version</key>
- <string>1.86</string>
+ <string>1.90.0-c7a9feb</string>
<key>name</key>
<string>boost</string>
<key>description</key>
@@ -244,11 +244,11 @@
<key>archive</key>
<map>
<key>hash</key>
- <string>bf2fe4e8272e990bc8687b3b37bf4bb2b2ad6eb4</string>
+ <string>9710f82a237b95aaafbbcf708b89f6015b80d85f</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
- <string>https://github.com/secondlife/3p-colladadom/releases/download/v2.3-r10/colladadom-2.3.0-r10-darwin64-13259816660.tar.zst</string>
+ <string>https://github.com/secondlife/3p-colladadom/releases/download/v2.3-r11/colladadom-2.3.0-r11-darwin64-20980076767.tar.zst</string>
</map>
<key>name</key>
<string>darwin64</string>
@@ -258,11 +258,11 @@
<key>archive</key>
<map>
<key>hash</key>
- <string>118e509ca464182ef4b94ee8c4aa5b14a6c52a94</string>
+ <string>6a1725b1bc13634eb4dd872a4f83c3f16497475f</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
- <string>https://github.com/secondlife/3p-colladadom/releases/download/v2.3-r10/colladadom-2.3.0-r10-linux64-13259816660.tar.zst</string>
+ <string>https://github.com/secondlife/3p-colladadom/releases/download/v2.3-r11/colladadom-2.3.0-r11-linux64-20980076767.tar.zst</string>
</map>
<key>name</key>
<string>linux64</string>
@@ -272,11 +272,11 @@
<key>archive</key>
<map>
<key>hash</key>
- <string>d7aee1b2ec17bd88a2c27359281b58a11ec52d48</string>
+ <string>ba9eeb62ae3046d91f9e061db823c1863623b017</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
- <string>https://github.com/secondlife/3p-colladadom/releases/download/v2.3-r10/colladadom-2.3.0-r10-windows64-13259816660.tar.zst</string>
+ <string>https://github.com/secondlife/3p-colladadom/releases/download/v2.3-r11/colladadom-2.3.0-r11-windows64-20980076767.tar.zst</string>
</map>
<key>name</key>
<string>windows64</string>
@@ -289,7 +289,7 @@
<key>copyright</key>
<string>Copyright 2006 Sony Computer Entertainment Inc.</string>
<key>version</key>
- <string>2.3.0-r10</string>
+ <string>2.3.0-r11</string>
<key>name</key>
<string>colladadom</string>
</map>
@@ -360,11 +360,11 @@
<key>archive</key>
<map>
<key>hash</key>
- <string>e742b1e2d0a58d607b023bf55411041ac65e8a76</string>
+ <string>5eab8167cec442e8c156bb653012d7544cca6037</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
- <string>https://github.com/secondlife/3p-curl/releases/download/v7.54.1-r3/curl-7.54.1-13259824618-darwin64-13259824618.tar.zst</string>
+ <string>https://github.com/secondlife/3p-curl/releases/download/v7.54.1-r4/curl-7.54.1-20982000504-darwin64-20982000504.tar.zst</string>
</map>
<key>name</key>
<string>darwin64</string>
@@ -374,11 +374,11 @@
<key>archive</key>
<map>
<key>hash</key>
- <string>49621c70f385d37c95bcb69a9a24d86ac25f4781</string>
+ <string>3465bbe70cfba2814b1fd52094c62804f4067490</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
- <string>https://github.com/secondlife/3p-curl/releases/download/v7.54.1-r3/curl-7.54.1-13259824618-linux64-13259824618.tar.zst</string>
+ <string>https://github.com/secondlife/3p-curl/releases/download/v7.54.1-r4/curl-7.54.1-20982000504-linux64-20982000504.tar.zst</string>
</map>
<key>name</key>
<string>linux64</string>
@@ -388,11 +388,11 @@
<key>archive</key>
<map>
<key>hash</key>
- <string>2522201692116cf0adb7203e169be9126885108c</string>
+ <string>0e64e20945eeb19259abf8e78400eb492e31eda7</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
- <string>https://github.com/secondlife/3p-curl/releases/download/v7.54.1-r3/curl-7.54.1-13259824618-windows64-13259824618.tar.zst</string>
+ <string>https://github.com/secondlife/3p-curl/releases/download/v7.54.1-r4/curl-7.54.1-20982000504-windows64-20982000504.tar.zst</string>
</map>
<key>name</key>
<string>windows64</string>
@@ -405,7 +405,7 @@
<key>copyright</key>
<string>Copyright (c) 1996 - 2014, Daniel Stenberg, (daniel@haxx.se).</string>
<key>version</key>
- <string>7.54.1-13259824618</string>
+ <string>7.54.1-20982000504</string>
<key>name</key>
<string>curl</string>
<key>description</key>
@@ -606,11 +606,11 @@
<key>archive</key>
<map>
<key>hash</key>
- <string>5e6c7b9aaf73d90d7feab846a4024193c48eff6c</string>
+ <string>550a90bca35bdbbd615afb1a1c02383cb3b6edbe</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
- <string>https://github.com/secondlife/3p-freetype/releases/download/v2.13.3-r3/freetype-2.13.3-r3-darwin64-13259804885.tar.zst</string>
+ <string>https://github.com/secondlife/3p-freetype/releases/download/v2.13.3-r4/freetype-2.13.3-r4-darwin64-20935810762.tar.zst</string>
</map>
<key>name</key>
<string>darwin64</string>
@@ -620,11 +620,11 @@
<key>archive</key>
<map>
<key>hash</key>
- <string>a9a3c371958e64a49b07d7be8f59218dfd6b0352</string>
+ <string>f52b05392962cb6a8e5f534d8687faa525d4960a</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
- <string>https://github.com/secondlife/3p-freetype/releases/download/v2.13.3-r3/freetype-2.13.3-r3-linux64-13259804885.tar.zst</string>
+ <string>https://github.com/secondlife/3p-freetype/releases/download/v2.13.3-r4/freetype-2.13.3-r4-linux64-20935810762.tar.zst</string>
</map>
<key>name</key>
<string>linux64</string>
@@ -634,11 +634,11 @@
<key>archive</key>
<map>
<key>hash</key>
- <string>ad7fbc4a01607ec43d86035a49dadd43d6f2a4e5</string>
+ <string>3c30052adcbfec572562bb1e7927d7a8f4d93f3d</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
- <string>https://github.com/secondlife/3p-freetype/releases/download/v2.13.3-r3/freetype-2.13.3-r3-windows64-13259804885.tar.zst</string>
+ <string>https://github.com/secondlife/3p-freetype/releases/download/v2.13.3-r4/freetype-2.13.3-r4-windows64-20935810762.tar.zst</string>
</map>
<key>name</key>
<string>windows64</string>
@@ -651,7 +651,7 @@
<key>copyright</key>
<string>Copyright 2006, 2007, 2008, 2009, 2010 by David Turner, Robert Wilhelm, and Werner Lemberg.</string>
<key>version</key>
- <string>2.13.3-r3</string>
+ <string>2.13.3-r4</string>
<key>name</key>
<string>freetype</string>
<key>description</key>
@@ -1098,11 +1098,11 @@
<key>archive</key>
<map>
<key>hash</key>
- <string>a453355ee032f79aea4142218a957085a22c7656</string>
+ <string>6fa10d5f44601dda6efc3eda1a9dab22525e7a9a</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
- <string>https://github.com/secondlife/3p-libpng/releases/download/v1.6.44-r2/libpng-1.6.44-r2-darwin64-13246065198.tar.zst</string>
+ <string>https://github.com/secondlife/3p-libpng/releases/download/v1.6.53-eea12b7/libpng-1.6.44-dev1.geea12b7-darwin64-20934739343.tar.zst</string>
</map>
<key>name</key>
<string>darwin64</string>
@@ -1112,11 +1112,11 @@
<key>archive</key>
<map>
<key>hash</key>
- <string>75c7608646c9f5b99b1a9e3946326e2804a304d7</string>
+ <string>112b7f46f5923e6418dfa4bc13ebe2db6911c9b9</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
- <string>https://github.com/secondlife/3p-libpng/releases/download/v1.6.44-r2/libpng-1.6.44-r2-linux64-13246065198.tar.zst</string>
+ <string>https://github.com/secondlife/3p-libpng/releases/download/v1.6.53-eea12b7/libpng-1.6.44-dev1.geea12b7-linux64-20934739343.tar.zst</string>
</map>
<key>name</key>
<string>linux64</string>
@@ -1126,11 +1126,11 @@
<key>archive</key>
<map>
<key>hash</key>
- <string>09af51774c4ee7c03fe67a87dfc52e846aa625ea</string>
+ <string>2731c45f1e62e33b8612b3ee2b9c4cb39dafbfe2</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
- <string>https://github.com/secondlife/3p-libpng/releases/download/v1.6.44-r2/libpng-1.6.44-r2-windows64-13246065198.tar.zst</string>
+ <string>https://github.com/secondlife/3p-libpng/releases/download/v1.6.53-eea12b7/libpng-1.6.44-dev1.geea12b7-windows64-20934739343.tar.zst</string>
</map>
<key>name</key>
<string>windows64</string>
@@ -1143,7 +1143,7 @@
<key>copyright</key>
<string>Copyright (c) 2004, 2006-2013 Glenn Randers-Pehrson</string>
<key>version</key>
- <string>1.6.44-r2</string>
+ <string>1.6.53-eea12b7</string>
<key>name</key>
<string>libpng</string>
<key>description</key>
@@ -1158,11 +1158,11 @@
<key>archive</key>
<map>
<key>hash</key>
- <string>372c92936d940b1cfb5ba34310691d4bb435c161</string>
+ <string>c1ad7ff9ec91049c93d2dcd832f81a00f8f4b4b9</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
- <string>https://github.com/secondlife/3p-libxml2/releases/download/v2.13.5-r2/libxml2-2.13.5-r2-darwin64-13246071272.tar.zst</string>
+ <string>https://github.com/secondlife/3p-libxml2/releases/download/v2.13.9-d53cd6f/libxml2-2.13.9-d53cd6f-darwin64-20936141417.tar.zst</string>
</map>
<key>name</key>
<string>darwin64</string>
@@ -1172,11 +1172,11 @@
<key>archive</key>
<map>
<key>hash</key>
- <string>ba6fbc34112b1acab1c8615dcd13de983f3678d3</string>
+ <string>7fc2df91648661468a82754b26fd7dedfbef1d39</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
- <string>https://github.com/secondlife/3p-libxml2/releases/download/v2.13.5-r2/libxml2-2.13.5-r2-linux64-13246071272.tar.zst</string>
+ <string>https://github.com/secondlife/3p-libxml2/releases/download/v2.13.9-d53cd6f/libxml2-2.13.9-d53cd6f-linux64-20936141417.tar.zst</string>
</map>
<key>name</key>
<string>linux64</string>
@@ -1186,11 +1186,11 @@
<key>archive</key>
<map>
<key>hash</key>
- <string>71968c4b621636e8ae0c5680e631f4aa67561944</string>
+ <string>84828c26b67c33f0d3e565718943aa339582b34f</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
- <string>https://github.com/secondlife/3p-libxml2/releases/download/v2.13.5-r2/libxml2-2.13.5-r2-windows64-13246071272.tar.zst</string>
+ <string>https://github.com/secondlife/3p-libxml2/releases/download/v2.13.9-d53cd6f/libxml2-2.13.9-d53cd6f-windows64-20936141417.tar.zst</string>
</map>
<key>name</key>
<string>windows64</string>
@@ -1203,7 +1203,7 @@
<key>copyright</key>
<string>Copyright (C) 1998-2012 Daniel Veillard. All Rights Reserved.</string>
<key>version</key>
- <string>2.13.5-r2</string>
+ <string>2.13.9-d53cd6f</string>
<key>name</key>
<string>libxml2</string>
<key>description</key>
@@ -1333,11 +1333,11 @@
<key>archive</key>
<map>
<key>hash</key>
- <string>874a7d2bc843554aa4facd03b3a6d681f2b5150c</string>
+ <string>3692af717636da9c2b1e0f13eb084ce022b67f6c</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
- <string>https://github.com/secondlife/3p-meshoptimizer/releases/download/v220-r1/meshoptimizer-220.0.0-r1-darwin64-11968851109.tar.zst</string>
+ <string>https://github.com/secondlife/3p-meshoptimizer/releases/download/v1.0.1-9d6a006/meshoptimizer-1.0.1-9d6a006-darwin64-20867041007.tar.zst</string>
</map>
<key>name</key>
<string>darwin64</string>
@@ -1347,11 +1347,11 @@
<key>archive</key>
<map>
<key>hash</key>
- <string>31a537f1a3d38ef85443214315111dd56a534d9a</string>
+ <string>22ad1be39a1196a1ca3902ba936460cb69252b9c</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
- <string>https://github.com/secondlife/3p-meshoptimizer/releases/download/v220-r1/meshoptimizer-220.0.0-r1-linux64-11968851109.tar.zst</string>
+ <string>https://github.com/secondlife/3p-meshoptimizer/releases/download/v1.0.1-9d6a006/meshoptimizer-1.0.1-9d6a006-linux64-20867041007.tar.zst</string>
</map>
<key>name</key>
<string>linux64</string>
@@ -1361,11 +1361,11 @@
<key>archive</key>
<map>
<key>hash</key>
- <string>6fd727a9ccb3e7a6c6b4ffef8179e266c032eb3e</string>
+ <string>2c9769f31da5de3920d7ee400d280398c911a30f</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
- <string>https://github.com/secondlife/3p-meshoptimizer/releases/download/v220-r1/meshoptimizer-220.0.0-r1-windows64-11968851109.tar.zst</string>
+ <string>https://github.com/secondlife/3p-meshoptimizer/releases/download/v1.0.1-9d6a006/meshoptimizer-1.0.1-9d6a006-windows64-20867041007.tar.zst</string>
</map>
<key>name</key>
<string>windows64</string>
@@ -1457,11 +1457,11 @@
<key>archive</key>
<map>
<key>hash</key>
- <string>b628d088e1f368a0cd51a6b66292aaf9a025e2d4</string>
+ <string>85179317015c5c91986000d69c9f61a01af7617f</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
- <string>https://github.com/secondlife/3p-minizip-ng/releases/download/v4.0.7-r3/minizip_ng-4.0.7-r3-darwin64-13246046977.tar.zst</string>
+ <string>https://github.com/secondlife/3p-minizip-ng/releases/download/v4.0.7-r4/minizip_ng-4.0.7-r4-darwin64-20933148061.tar.zst</string>
</map>
<key>name</key>
<string>darwin64</string>
@@ -1471,11 +1471,11 @@
<key>archive</key>
<map>
<key>hash</key>
- <string>492ce9175b730d43df63821c4481685e035af623</string>
+ <string>ef1524f507f44fed6f1c1f00ae274ddb8a1ac359</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
- <string>https://github.com/secondlife/3p-minizip-ng/releases/download/v4.0.7-r3/minizip_ng-4.0.7-r3-linux64-13246046977.tar.zst</string>
+ <string>https://github.com/secondlife/3p-minizip-ng/releases/download/v4.0.7-r4/minizip_ng-4.0.7-r4-linux64-20933148061.tar.zst</string>
</map>
<key>name</key>
<string>linux64</string>
@@ -1485,11 +1485,11 @@
<key>archive</key>
<map>
<key>hash</key>
- <string>58773e707ff3490822b7b8217d7729ade2186632</string>
+ <string>90be39cf789b596377458f1ea78f415a9c281a8c</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
- <string>https://github.com/secondlife/3p-minizip-ng/releases/download/v4.0.7-r3/minizip_ng-4.0.7-r3-windows64-13246046977.tar.zst</string>
+ <string>https://github.com/secondlife/3p-minizip-ng/releases/download/v4.0.7-r4/minizip_ng-4.0.7-r4-windows64-20933148061.tar.zst</string>
</map>
<key>name</key>
<string>windows64</string>
@@ -1502,7 +1502,7 @@
<key>copyright</key>
<string>This project uses the zlib license. Copyright (C) 1995-2013 Jean-loup Gailly and Mark Adler</string>
<key>version</key>
- <string>4.0.7-r3</string>
+ <string>4.0.7-r4</string>
<key>name</key>
<string>minizip-ng</string>
<key>canonical_repo</key>
@@ -1882,11 +1882,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<key>archive</key>
<map>
<key>hash</key>
- <string>157193699127ac5056c5fc1a410f9c98d39731e2</string>
+ <string>e08f640fb423f878c288426c836189b30b0c8ad0</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
- <string>https://github.com/secondlife/3p-openssl/releases/download/v1.1.1w-r3/openssl-1.1.1w-r3-darwin64-13246054022.tar.zst</string>
+ <string>https://github.com/secondlife/3p-openssl/releases/download/v1.1.1w-r4/openssl-1.1.1w-r4-darwin64-20981673556.tar.zst</string>
</map>
<key>name</key>
<string>darwin64</string>
@@ -1896,11 +1896,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<key>archive</key>
<map>
<key>hash</key>
- <string>2e29c127dbd002d64ae55bc000f8b6ed0249fad7</string>
+ <string>d83a1e910762b792c90550ce2b8f51f9aaec7570</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
- <string>https://github.com/secondlife/3p-openssl/releases/download/v1.1.1w-r3/openssl-1.1.1w-r3-linux64-13246054022.tar.zst</string>
+ <string>https://github.com/secondlife/3p-openssl/releases/download/v1.1.1w-r4/openssl-1.1.1w-r4-linux64-20981673556.tar.zst</string>
</map>
<key>name</key>
<string>linux64</string>
@@ -1910,11 +1910,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<key>archive</key>
<map>
<key>hash</key>
- <string>ae9ced89051e03a99628c99b9ac78530fdea1e5a</string>
+ <string>eec78c22e2d1eecf375aa0c6eff08fe67d2316f4</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
- <string>https://github.com/secondlife/3p-openssl/releases/download/v1.1.1w-r3/openssl-1.1.1w-r3-windows64-13246054022.tar.zst</string>
+ <string>https://github.com/secondlife/3p-openssl/releases/download/v1.1.1w-r4/openssl-1.1.1w-r4-windows64-20981673556.tar.zst</string>
</map>
<key>name</key>
<string>windows64</string>
@@ -1927,7 +1927,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<key>copyright</key>
<string>Copyright (c) 1998-2011 The OpenSSL Project. All rights reserved; Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)</string>
<key>version</key>
- <string>1.1.1w-r3</string>
+ <string>1.1.1w-r4</string>
<key>name</key>
<string>openssl</string>
<key>description</key>
@@ -2534,11 +2534,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<key>archive</key>
<map>
<key>hash</key>
- <string>e363e3b889c52fda7601d7aeaa9832307034651e</string>
+ <string>4906257288c61b14d2e16116fc3139af35d3374f</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
- <string>https://github.com/secondlife/3p-zlib-ng/releases/download/v2.2.3-r1/zlib_ng-2.2.3-dev0.g8aa13e3.d20250206-darwin64-13183604450.tar.zst</string>
+ <string>https://github.com/secondlife/3p-zlib-ng/releases/download/v2.2.5-0d88d03/zlib_ng-2.2.5-dev0.g0d88d03.d20260112-darwin64-20930307098.tar.zst</string>
</map>
<key>name</key>
<string>darwin64</string>
@@ -2548,11 +2548,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<key>archive</key>
<map>
<key>hash</key>
- <string>3cdd52f7fb3691789d50f0b40ed6f5642321ff32</string>
+ <string>2b81a6a4ebd9ae5555d48b52eea7c2d875d68f60</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
- <string>https://github.com/secondlife/3p-zlib-ng/releases/download/v2.2.3-r1/zlib_ng-2.2.3-dev0.g8aa13e3.d20250206-linux64-13183604450.tar.zst</string>
+ <string>https://github.com/secondlife/3p-zlib-ng/releases/download/v2.2.5-0d88d03/zlib_ng-2.2.5-dev0.g0d88d03.d20260112-linux64-20930307098.tar.zst</string>
</map>
<key>name</key>
<string>linux64</string>
@@ -2562,11 +2562,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<key>archive</key>
<map>
<key>hash</key>
- <string>e802a28139328bb2421ad39e13d996d350d8106d</string>
+ <string>e2e0f964ba44fe2e6428e1e7ca262a3f80d92e65</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
- <string>https://github.com/secondlife/3p-zlib-ng/releases/download/v2.2.3-r1/zlib_ng-2.2.3-dev0.g8aa13e3.d20250206-windows64-13183604450.tar.zst</string>
+ <string>https://github.com/secondlife/3p-zlib-ng/releases/download/v2.2.5-0d88d03/zlib_ng-2.2.5-dev0.g0d88d03.d20260112-windows64-20930307098.tar.zst</string>
</map>
<key>name</key>
<string>windows64</string>
@@ -2579,7 +2579,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<key>copyright</key>
<string>Copyright (C) 1995-2013 Jean-loup Gailly and Mark Adler</string>
<key>version</key>
- <string>2.2.3-dev0.g8aa13e3.d20250206</string>
+ <string>2.2.5-0d88d03</string>
<key>name</key>
<string>zlib-ng</string>
<key>canonical_repo</key>
diff --git a/indra/cmake/Boost.cmake b/indra/cmake/Boost.cmake
index 5967a96f8a..fd3e0eccde 100644
--- a/indra/cmake/Boost.cmake
+++ b/indra/cmake/Boost.cmake
@@ -19,56 +19,50 @@ set(addrsfx "-x${ADDRESS_SIZE}")
find_library(BOOST_CONTEXT_LIBRARY
NAMES
+ libboost_context
libboost_context-mt
libboost_context-mt${addrsfx}
+ boost_context
boost_context-mt
boost_context-mt${addrsfx}
PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH)
find_library(BOOST_FIBER_LIBRARY
NAMES
+ libboost_fiber
libboost_fiber-mt
libboost_fiber-mt${addrsfx}
+ boost_fiber
boost_fiber-mt
boost_fiber-mt${addrsfx}
PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH)
find_library(BOOST_FILESYSTEM_LIBRARY
NAMES
+ libboost_filesystem
libboost_filesystem-mt
libboost_filesystem-mt${addrsfx}
+ boost_filesystem
boost_filesystem-mt
boost_filesystem-mt${addrsfx}
PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH)
find_library(BOOST_PROGRAMOPTIONS_LIBRARY
NAMES
+ libboost_program_options
libboost_program_options-mt
libboost_program_options-mt${addrsfx}
+ boost_program_options
boost_program_options-mt
boost_program_options-mt${addrsfx}
PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH)
-find_library(BOOST_REGEX_LIBRARY
- NAMES
- libboost_regex-mt
- libboost_regex-mt${addrsfx}
- boost_regex-mt
- boost_regex-mt${addrsfx}
- PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH)
-
-find_library(BOOST_SYSTEM_LIBRARY
- NAMES
- libboost_system-mt
- libboost_system-mt${addrsfx}
- boost_system-mt
- boost_system-mt${addrsfx}
- PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH)
-
find_library(BOOST_URL_LIBRARY
NAMES
+ libboost_url
libboost_url-mt
libboost_url-mt${addrsfx}
+ boost_url
boost_url-mt
boost_url-mt${addrsfx}
PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH)
@@ -78,8 +72,6 @@ target_link_libraries(ll::boost INTERFACE
${BOOST_CONTEXT_LIBRARY}
${BOOST_FILESYSTEM_LIBRARY}
${BOOST_PROGRAMOPTIONS_LIBRARY}
- ${BOOST_REGEX_LIBRARY}
- ${BOOST_SYSTEM_LIBRARY}
${BOOST_URL_LIBRARY})
if (LINUX)
diff --git a/indra/cmake/Python.cmake b/indra/cmake/Python.cmake
index 39fd21c33f..428f9e3326 100644
--- a/indra/cmake/Python.cmake
+++ b/indra/cmake/Python.cmake
@@ -1,57 +1,18 @@
-# -*- cmake -*-
+# Allow explicit Python path via environment variable
+if(DEFINED ENV{PYTHON})
+ set(Python3_ROOT_DIR "$ENV{PYTHON}")
+endif()
-set(PYTHONINTERP_FOUND)
+# On Windows, prefer registry entries to avoid Cygwin/MSYS Python
+# The registry is searched first by default, which finds native Windows Python
+# installations rather than Cygwin/MSYS Python
+if(WINDOWS)
+ set(Python3_FIND_REGISTRY FIRST CACHE STRING "Python search order")
+endif()
-if (DEFINED ENV{PYTHON})
- # Allow python executable to be explicitly set
- set(python "$ENV{PYTHON}")
- set(PYTHONINTERP_FOUND ON)
-elseif (WINDOWS)
- # On Windows, explicitly avoid Cygwin Python.
+# Find Python 3 interpreter
+find_package(Python3 REQUIRED COMPONENTS Interpreter)
- # if the user has their own version of Python installed, prefer that
- foreach(hive HKEY_CURRENT_USER HKEY_LOCAL_MACHINE)
- # prefer more recent Python versions to older ones, if multiple versions
- # are installed
- foreach(pyver 3.14 3.13 3.12 3.11 3.10 3.9 3.8 3.7)
- list(APPEND regpaths "[${hive}\\SOFTWARE\\Python\\PythonCore\\${pyver}\\InstallPath]")
- endforeach()
- endforeach()
-
- # TODO: This logic has the disadvantage that if you have multiple versions
- # of Python installed, the selected path won't necessarily be the newest -
- # e.g. this GLOB will prefer Python310 to Python311. But since pymaybe is
- # checked AFTER the registry entries, this will only surface as a problem if
- # no installed Python appears in the registry.
- file(GLOB pymaybe
- "$ENV{PROGRAMFILES}/Python*"
-## "$ENV{PROGRAMFILES(X86)}/Python*"
- # The Windows environment variable is in fact as shown above, but CMake
- # disallows querying an environment variable containing parentheses -
- # thanks, Windows. Fudge by just appending " (x86)" to $PROGRAMFILES and
- # hoping for the best.
- "$ENV{PROGRAMFILES} (x86)/Python*"
- "c:/Python*")
-
- find_program(python
- NAMES python3.exe python.exe
- NO_DEFAULT_PATH # added so that cmake does not find cygwin python
- PATHS
- ${regpaths}
- ${pymaybe}
- )
- find_package(Python3 COMPONENTS Interpreter)
-else()
- find_program(python python3)
-
- if (python)
- set(PYTHONINTERP_FOUND ON)
- endif (python)
-endif (DEFINED ENV{PYTHON})
-
-if (NOT python)
- message(FATAL_ERROR "No Python interpreter found")
-endif (NOT python)
-
-set(PYTHON_EXECUTABLE "${python}" CACHE FILEPATH "Python interpreter for builds")
+# Set legacy variable name for compatibility with existing code
+set(PYTHON_EXECUTABLE "${Python3_EXECUTABLE}" CACHE FILEPATH "Python interpreter for builds")
mark_as_advanced(PYTHON_EXECUTABLE)
diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt
index f2d19854b0..bff3c66924 100644
--- a/indra/llcommon/CMakeLists.txt
+++ b/indra/llcommon/CMakeLists.txt
@@ -100,6 +100,7 @@ set(llcommon_SOURCE_FILES
lluri.cpp
lluriparser.cpp
lluuid.cpp
+ llwatchdog.cpp
llworkerthread.cpp
hbxxh.cpp
u64.cpp
@@ -235,6 +236,7 @@ set(llcommon_HEADER_FILES
lluri.h
lluriparser.h
lluuid.h
+ llwatchdog.h
llwin32headers.h
llworkerthread.h
hbxxh.h
diff --git a/indra/llcommon/llapp.cpp b/indra/llcommon/llapp.cpp
index aa84895fb8..02d6da989a 100644
--- a/indra/llcommon/llapp.cpp
+++ b/indra/llcommon/llapp.cpp
@@ -87,6 +87,7 @@ bool LLApp::sDisableCrashlogger = false;
LLScalarCond<LLApp::EAppStatus> LLApp::sStatus{LLApp::APP_STATUS_STOPPED};
LLAppErrorHandler LLApp::sErrorHandler = NULL;
+bool gDisconnected = false;
LLApp::LLApp()
{
diff --git a/indra/llcommon/llapp.h b/indra/llcommon/llapp.h
index 57f5a112d9..ce09c566a9 100644
--- a/indra/llcommon/llapp.h
+++ b/indra/llcommon/llapp.h
@@ -50,6 +50,8 @@ void clear_signals();
#endif
+extern bool gDisconnected;
+
class LL_COMMON_API LLApp
{
public:
diff --git a/indra/llcommon/lldate.cpp b/indra/llcommon/lldate.cpp
index b4cdf3cbda..7f65c0d715 100644
--- a/indra/llcommon/lldate.cpp
+++ b/indra/llcommon/lldate.cpp
@@ -41,6 +41,9 @@
#include "llstring.h"
#include "llfasttimer.h"
+#include <boost/iostreams/device/array.hpp>
+#include <boost/iostreams/stream.hpp>
+
static const F64 LL_APR_USEC_PER_SEC = 1000000.0;
// should be APR_USEC_PER_SEC, but that relies on INT64_C which
// isn't defined in glib under our build set up for some reason
@@ -64,7 +67,7 @@ std::string LLDate::asString() const
{
std::ostringstream stream;
toStream(stream);
- return stream.str();
+ return std::move(stream).str();
}
//@ brief Converts time in seconds since EPOCH
@@ -180,7 +183,7 @@ bool LLDate::split(S32 *year, S32 *month, S32 *day, S32 *hour, S32 *min, S32 *se
bool LLDate::fromString(const std::string& iso8601_date)
{
- std::istringstream stream(iso8601_date);
+ boost::iostreams::stream<boost::iostreams::array_source> stream(iso8601_date.data(), iso8601_date.size());
return fromStream(stream);
}
diff --git a/indra/llcommon/llerror.cpp b/indra/llcommon/llerror.cpp
index 5b42c83a14..78101e21af 100644
--- a/indra/llcommon/llerror.cpp
+++ b/indra/llcommon/llerror.cpp
@@ -522,7 +522,7 @@ namespace
}
- typedef std::map<std::string, LLError::ELevel> LevelMap;
+ typedef std::unordered_map<std::string, LLError::ELevel> LevelMap;
typedef std::vector<LLError::RecorderPtr> Recorders;
typedef std::vector<LLError::CallSite*> CallSiteVector;
@@ -543,7 +543,7 @@ namespace
LevelMap mClassLevelMap;
LevelMap mFileLevelMap;
LevelMap mTagLevelMap;
- std::map<std::string, unsigned int> mUniqueLogMessages;
+ std::unordered_map<std::string, unsigned int> mUniqueLogMessages;
LLError::FatalFunction mCrashFunction;
LLError::TimeFunction mTimeFunction;
@@ -1451,7 +1451,7 @@ namespace LLError
{
std::ostringstream message_stream;
- std::map<std::string, unsigned int>::iterator messageIter = s->mUniqueLogMessages.find(message);
+ auto messageIter = s->mUniqueLogMessages.find(message);
if (messageIter != s->mUniqueLogMessages.end())
{
messageIter->second++;
diff --git a/indra/llcommon/llerrorcontrol.h b/indra/llcommon/llerrorcontrol.h
index d254fa5407..3c58d1df22 100644
--- a/indra/llcommon/llerrorcontrol.h
+++ b/indra/llcommon/llerrorcontrol.h
@@ -70,7 +70,6 @@ namespace LLError
Setting a level means log messages at that level or above.
*/
- LL_COMMON_API void setPrintLocation(bool);
LL_COMMON_API void setDefaultLevel(LLError::ELevel);
LL_COMMON_API ELevel getDefaultLevel();
LL_COMMON_API void setAlwaysFlush(bool flush);
diff --git a/indra/llcommon/llheteromap.cpp b/indra/llcommon/llheteromap.cpp
index 823bea7a3c..03dd7856b6 100644
--- a/indra/llcommon/llheteromap.cpp
+++ b/indra/llcommon/llheteromap.cpp
@@ -27,6 +27,6 @@ LLHeteroMap::~LLHeteroMap()
// pair.second is the std::pair; pair.second.first is the void*;
// pair.second.second points to the deleter function
(pair.second.second)(pair.second.first);
- pair.second.first = NULL;
+ pair.second.first = nullptr;
}
}
diff --git a/indra/llcommon/llheteromap.h b/indra/llcommon/llheteromap.h
index d8e6fefb17..211dfaae83 100644
--- a/indra/llcommon/llheteromap.h
+++ b/indra/llcommon/llheteromap.h
@@ -12,9 +12,10 @@
#if ! defined(LL_LLHETEROMAP_H)
#define LL_LLHETEROMAP_H
+#include <typeindex>
#include <typeinfo>
#include <utility> // std::pair
-#include <map>
+#include <unordered_map>
/**
* LLHeteroMap addresses an odd requirement. Usually when you want to put
@@ -43,7 +44,7 @@ public:
// Look up map entry by typeid(T). We don't simply use mMap[typeid(T)]
// because that requires default-constructing T on every lookup. For
// some kinds of T, that could be expensive.
- TypeMap::iterator found = mMap.find(&typeid(T));
+ TypeMap::iterator found = mMap.find(typeid(T));
if (found == mMap.end())
{
// Didn't find typeid(T). Create an entry. Because we're storing
@@ -52,8 +53,8 @@ public:
void* ptr = new T();
void (*dlfn)(void*) = &deleter<T>;
std::pair<TypeMap::iterator, bool> inserted =
- mMap.insert(TypeMap::value_type(&typeid(T),
- TypeMap::mapped_type(ptr, dlfn)));
+ mMap.emplace(typeid(T),
+ TypeMap::mapped_type(ptr, dlfn));
// Okay, now that we have an entry, claim we found it.
found = inserted.first;
}
@@ -71,23 +72,9 @@ private:
delete static_cast<T*>(p);
}
- // Comparing two std::type_info* values is tricky, because the standard
- // does not guarantee that there will be only one type_info instance for a
- // given type. In other words, &typeid(A) in one part of the program may
- // not always equal &typeid(A) in some other part. Use special comparator.
- struct type_info_ptr_comp
- {
- bool operator()(const std::type_info* lhs, const std::type_info* rhs) const
- {
- return lhs->before(*rhs);
- }
- };
-
- // What we actually store is a map from std::type_info (permitting lookup
+ // What we actually store is a map from std::type_index (permitting lookup
// by object type) to a void* pointer to the object PLUS its deleter.
- typedef std::map<
- const std::type_info*, std::pair<void*, void (*)(void*)>,
- type_info_ptr_comp>
+ typedef std::unordered_map<std::type_index, std::pair<void*, void (*)(void*)>>
TypeMap;
TypeMap mMap;
};
diff --git a/indra/llcommon/llinitparam.h b/indra/llcommon/llinitparam.h
index b01ea0bfb1..b220afadfc 100644
--- a/indra/llcommon/llinitparam.h
+++ b/indra/llcommon/llinitparam.h
@@ -34,7 +34,6 @@
#include <list>
#include <unordered_map>
#include <boost/function.hpp>
-#include <boost/unordered_map.hpp>
#include "llerror.h"
#include "llstl.h"
@@ -267,7 +266,7 @@ namespace LLInitParam
private:
struct Inaccessable{};
public:
- typedef std::map<std::string, T> value_name_map_t;
+ typedef std::unordered_map<std::string, T> value_name_map_t;
typedef Inaccessable name_t;
typedef TypeValues<T> type_value_t;
typedef ParamValue<typename LLTypeTags::Sorted<T>::value_t> param_value_t;
@@ -294,7 +293,7 @@ namespace LLInitParam
static std::vector<std::string>* getPossibleValues()
{
- return NULL;
+ return nullptr;
}
void assignNamedValue(const Inaccessable& name)
@@ -310,7 +309,7 @@ namespace LLInitParam
return param_value_t::getValue();
}
- static value_name_map_t* getValueNames() {return NULL;}
+ static value_name_map_t* getValueNames() { return nullptr; }
};
// helper class to implement name value lookups
@@ -321,7 +320,7 @@ namespace LLInitParam
{
typedef TypeValuesHelper<T, DERIVED_TYPE, IS_SPECIALIZED> self_t;
public:
- typedef typename std::map<std::string, T> value_name_map_t;
+ typedef typename std::unordered_map<std::string, T> value_name_map_t;
typedef std::string name_t;
typedef self_t type_value_t;
typedef ParamValue<typename LLTypeTags::Sorted<T>::value_t> param_value_t;
@@ -497,9 +496,9 @@ namespace LLInitParam
typedef bool (*parser_write_func_t)(Parser& parser, const void*, name_stack_t&);
typedef std::function<void (name_stack_t&, S32, S32, const possible_values_t*)> parser_inspect_func_t;
- typedef std::map<const std::type_info*, parser_read_func_t> parser_read_func_map_t;
- typedef std::map<const std::type_info*, parser_write_func_t> parser_write_func_map_t;
- typedef std::map<const std::type_info*, parser_inspect_func_t> parser_inspect_func_map_t;
+ typedef std::unordered_map<std::type_index, parser_read_func_t> parser_read_func_map_t;
+ typedef std::unordered_map<std::type_index, parser_write_func_t> parser_write_func_map_t;
+ typedef std::unordered_map<std::type_index, parser_inspect_func_t> parser_inspect_func_map_t;
public:
@@ -514,7 +513,7 @@ namespace LLInitParam
template <typename T> bool readValue(T& param, typename std::enable_if_t<!std::is_enum_v<T>>* dummy = 0)
{
- parser_read_func_map_t::iterator found_it = mParserReadFuncs->find(&typeid(T));
+ parser_read_func_map_t::iterator found_it = mParserReadFuncs->find(typeid(T));
if (found_it != mParserReadFuncs->end())
{
return found_it->second(*this, (void*)&param);
@@ -525,14 +524,14 @@ namespace LLInitParam
template <typename T> bool readValue(T& param, typename std::enable_if_t<std::is_enum_v<T> >* dummy = 0)
{
- parser_read_func_map_t::iterator found_it = mParserReadFuncs->find(&typeid(T));
+ parser_read_func_map_t::iterator found_it = mParserReadFuncs->find(typeid(T));
if (found_it != mParserReadFuncs->end())
{
return found_it->second(*this, (void*)&param);
}
else
{
- found_it = mParserReadFuncs->find(&typeid(S32));
+ found_it = mParserReadFuncs->find(typeid(S32));
if (found_it != mParserReadFuncs->end())
{
S32 int_value;
@@ -546,7 +545,7 @@ namespace LLInitParam
template <typename T> bool writeValue(const T& param, name_stack_t& name_stack)
{
- parser_write_func_map_t::iterator found_it = mParserWriteFuncs->find(&typeid(T));
+ parser_write_func_map_t::iterator found_it = mParserWriteFuncs->find(typeid(T));
if (found_it != mParserWriteFuncs->end())
{
return found_it->second(*this, (const void*)&param, name_stack);
@@ -557,7 +556,7 @@ namespace LLInitParam
// dispatch inspection to registered inspection functions, for each parameter in a param block
template <typename T> bool inspectValue(name_stack_t& name_stack, S32 min_count, S32 max_count, const possible_values_t* possible_values)
{
- parser_inspect_func_map_t::iterator found_it = mParserInspectFuncs->find(&typeid(T));
+ parser_inspect_func_map_t::iterator found_it = mParserInspectFuncs->find(typeid(T));
if (found_it != mParserInspectFuncs->end())
{
found_it->second(name_stack, min_count, max_count, possible_values);
@@ -574,16 +573,16 @@ namespace LLInitParam
protected:
template <typename T>
- void registerParserFuncs(parser_read_func_t read_func, parser_write_func_t write_func = NULL)
+ void registerParserFuncs(parser_read_func_t read_func, parser_write_func_t write_func = nullptr)
{
- mParserReadFuncs->insert(std::make_pair(&typeid(T), read_func));
- mParserWriteFuncs->insert(std::make_pair(&typeid(T), write_func));
+ mParserReadFuncs->emplace(typeid(T), read_func);
+ mParserWriteFuncs->emplace(typeid(T), write_func);
}
template <typename T>
void registerInspectFunc(parser_inspect_func_t inspect_func)
{
- mParserInspectFuncs->insert(std::make_pair(&typeid(T), inspect_func));
+ mParserInspectFuncs->emplace(typeid(T), inspect_func);
}
bool mParseSilently;
@@ -614,7 +613,7 @@ namespace LLInitParam
{
struct UserData
{
- virtual ~UserData() {}
+ virtual ~UserData() = default;
};
typedef bool(*merge_func_t)(Param&, const Param&, bool);
@@ -665,7 +664,7 @@ namespace LLInitParam
void aggregateBlockData(BlockDescriptor& src_block_data);
void addParam(ParamDescriptorPtr param, const char* name);
- typedef boost::unordered_map<const std::string, ParamDescriptorPtr> param_map_t;
+ typedef std::unordered_map<std::string, ParamDescriptorPtr, ll::string_hash, std::equal_to<>> param_map_t;
typedef std::vector<ParamDescriptorPtr> param_list_t;
typedef std::list<ParamDescriptorPtr> all_params_list_t;
typedef std::vector<std::pair<param_handle_t, ParamDescriptor::validation_func_t> > param_validation_list_t;
@@ -679,38 +678,26 @@ namespace LLInitParam
class BaseBlock* mCurrentBlockPtr; // pointer to block currently being constructed
};
- //TODO: implement in terms of owned_ptr
- template<typename T>
+ // TODO: implement in terms of owned_ptr
+ template<typename T>
class LazyValue
- {
- public:
- LazyValue()
- : mPtr(NULL)
- {}
+ {
+ public:
+ LazyValue() = default;
- ~LazyValue()
- {
- delete mPtr;
- }
+ ~LazyValue() { delete mPtr; }
- LazyValue(const T& value)
- {
- mPtr = new T(value);
- }
+ LazyValue(const T& value) { mPtr = new T(value); }
- LazyValue(const LazyValue& other)
- : mPtr(NULL)
- {
- *this = other;
- }
+ LazyValue(const LazyValue& other) : mPtr(nullptr) { *this = other; }
- LazyValue& operator = (const LazyValue& other)
- {
+ LazyValue& operator=(const LazyValue& other)
+ {
if (!other.mPtr)
{
delete mPtr;
- mPtr = NULL;
- }
+ mPtr = nullptr;
+ }
else
{
if (!mPtr)
@@ -721,23 +708,21 @@ namespace LLInitParam
{
*mPtr = *(other.mPtr);
}
- }
- return *this;
}
+ return *this;
+ }
bool operator==(const LazyValue& other) const
{
- if (empty() || other.empty()) return false;
+ if (empty() || other.empty())
+ return false;
return *mPtr == *other.mPtr;
}
- bool empty() const
- {
- return mPtr == NULL;
- }
+ bool empty() const { return mPtr == nullptr; }
- void set(const T& other)
- {
+ void set(const T& other)
+ {
if (!mPtr)
{
mPtr = new T(other);
@@ -748,36 +733,26 @@ namespace LLInitParam
}
}
- const T& get() const
- {
- return *ensureInstance();
- }
+ const T& get() const { return *ensureInstance(); }
- T& get()
- {
- return *ensureInstance();
- }
+ T& get() { return *ensureInstance(); }
- operator const T&() const
- {
- return get();
- }
+ operator const T&() const { return get(); }
- private:
- // lazily allocate an instance of T
- T* ensureInstance() const
+ private:
+ // lazily allocate an instance of T
+ T* ensureInstance() const
+ {
+ if (mPtr == nullptr)
{
- if (mPtr == NULL)
- {
- mPtr = new T();
- }
- return mPtr;
+ mPtr = new T();
}
+ return mPtr;
+ }
- private:
-
- mutable T* mPtr;
- };
+ private:
+ mutable T* mPtr = nullptr;
+ };
// root class of all parameter blocks
@@ -864,7 +839,7 @@ namespace LLInitParam
mParamProvided(false)
{}
- virtual ~BaseBlock() {}
+ virtual ~BaseBlock() = default;
bool submitValue(Parser::name_stack_t& name_stack, Parser& p, bool silent=false);
param_handle_t getHandleFromParam(const Param* param) const;
diff --git a/indra/llcommon/llpounceable.h b/indra/llcommon/llpounceable.h
index e86098f20b..20561b0c65 100644
--- a/indra/llcommon/llpounceable.h
+++ b/indra/llcommon/llpounceable.h
@@ -38,9 +38,9 @@
#include "llsingleton.h"
#include <boost/call_traits.hpp>
#include <boost/utility/value_init.hpp>
-#include <boost/unordered_map.hpp>
#include <boost/signals2/signal.hpp>
+#include <unordered_map>
#include <type_traits>
// Forward declare the user template, since we want to be able to point to it
@@ -86,7 +86,7 @@ class LLPounceableQueueSingleton:
// instance will call on the SAME LLPounceableQueueSingleton instance --
// given how class statics work. We must keep a separate queue for each
// LLPounceable instance. Use a hash map for that.
- typedef boost::unordered_map<owner_ptr, signal_t> map_t;
+ typedef std::unordered_map<owner_ptr, signal_t> map_t;
public:
// Disambiguate queues belonging to different LLPounceables.
diff --git a/indra/llcommon/llprocess.cpp b/indra/llcommon/llprocess.cpp
index 706d539df2..90ce71a6a5 100644
--- a/indra/llcommon/llprocess.cpp
+++ b/indra/llcommon/llprocess.cpp
@@ -657,10 +657,7 @@ LLProcess::LLProcess(const LLSDOrParams& params):
// case), e.g. by calling operator(), returns a reference to *the same
// instance* of the wrapped type that's stored in our Block subclass.
// That's important! We know 'params' persists throughout this method
- // call; but without that guarantee, we'd have to assume that converting
- // one of its members to std::string might return a different (temp)
- // instance. Capturing the c_str() from a temporary std::string is Bad Bad
- // Bad. But armed with this knowledge, when you see params.cwd().c_str(),
+ // call; but without that guarantee, when you see params.cwd().c_str(),
// grit your teeth and smile and carry on.
if (params.cwd.isProvided())
diff --git a/indra/llcommon/llregistry.h b/indra/llcommon/llregistry.h
index 35335e1213..92f8ae3245 100644
--- a/indra/llcommon/llregistry.h
+++ b/indra/llcommon/llregistry.h
@@ -32,21 +32,11 @@
#include "llsingleton.h"
#include "llstl.h"
-template <typename T>
-struct LLRegistryDefaultComparator
-{
- bool operator()(const T& lhs, const T& rhs) const
- {
- using std::less;
- return less<T>()(lhs, rhs);
- }
-};
-
-template <typename KEY, typename VALUE, typename COMPARATOR = LLRegistryDefaultComparator<KEY> >
+template <typename KEY, typename VALUE>
class LLRegistry
{
public:
- typedef LLRegistry<KEY, VALUE, COMPARATOR> registry_t;
+ typedef LLRegistry<KEY, VALUE> registry_t;
typedef const KEY& ref_const_key_t;
typedef const VALUE& ref_const_value_t;
typedef const VALUE* ptr_const_value_t;
@@ -54,9 +44,9 @@ public:
class Registrar
{
- friend class LLRegistry<KEY, VALUE, COMPARATOR>;
+ friend class LLRegistry<KEY, VALUE>;
public:
- typedef std::map<KEY, VALUE, COMPARATOR> registry_map_t;
+ typedef std::map<KEY, VALUE> registry_map_t;
bool add(ref_const_key_t key, ref_const_value_t value)
{
@@ -234,9 +224,9 @@ private:
Registrar mDefaultRegistrar;
};
-template <typename KEY, typename VALUE, typename DERIVED_TYPE, typename COMPARATOR = LLRegistryDefaultComparator<KEY> >
+template <typename KEY, typename VALUE, typename DERIVED_TYPE>
class LLRegistrySingleton
- : public LLRegistry<KEY, VALUE, COMPARATOR>,
+ : public LLRegistry<KEY, VALUE>,
public LLSingleton<DERIVED_TYPE>
{
// This LLRegistrySingleton doesn't use LLSINGLETON(LLRegistrySingleton)
@@ -244,7 +234,7 @@ class LLRegistrySingleton
// LLRegistrySingleton. So each concrete subclass needs
// LLSINGLETON(whatever) -- not this intermediate base class.
public:
- typedef LLRegistry<KEY, VALUE, COMPARATOR> registry_t;
+ typedef LLRegistry<KEY, VALUE> registry_t;
typedef const KEY& ref_const_key_t;
typedef const VALUE& ref_const_value_t;
typedef VALUE* ptr_value_t;
@@ -309,7 +299,7 @@ public:
};
// convenience functions
- typedef typename LLRegistry<KEY, VALUE, COMPARATOR>::Registrar& ref_registrar_t;
+ typedef typename LLRegistry<KEY, VALUE>::Registrar& ref_registrar_t;
static ref_registrar_t currentRegistrar()
{
return singleton_t::instance().registry_t::currentRegistrar();
diff --git a/indra/llcommon/llsd.cpp b/indra/llcommon/llsd.cpp
index ea6d6a308a..ad2ce231fa 100644
--- a/indra/llcommon/llsd.cpp
+++ b/indra/llcommon/llsd.cpp
@@ -38,6 +38,9 @@
#include <limits>
+#include <boost/iostreams/device/array.hpp>
+#include <boost/iostreams/stream.hpp>
+
// Defend against a caller forcibly passing a negative number into an unsigned
// size_t index param
inline
@@ -102,6 +105,9 @@ protected:
U32 mUseCount;
public:
+ static void destruct(Impl*& var);
+ ///< safely decrement or destroy var
+
static void reset(Impl*& var, Impl* impl);
///< safely set var to refer to the new impl (possibly shared)
@@ -165,7 +171,7 @@ public:
virtual const LLSD& ref(size_t) const { return undef(); }
virtual LLSD::map_const_iterator beginMap() const { return endMap(); }
- virtual LLSD::map_const_iterator endMap() const { static const std::map<String, LLSD> empty; return empty.end(); }
+ virtual LLSD::map_const_iterator endMap() const { static const LLSD::llsd_map_t empty; return empty.end(); }
virtual LLSD::array_const_iterator beginArray() const { return endArray(); }
virtual LLSD::array_const_iterator endArray() const { static const std::vector<LLSD> empty; return empty.end(); }
@@ -344,18 +350,7 @@ namespace
LLSD::Real ImplString::asReal() const
{
- F64 v = 0.0;
- std::istringstream i_stream(mValue);
- i_stream >> v;
-
- // we would probably like to ignore all trailing whitespace as
- // well, but for now, simply eat the next character, and make
- // sure we reached the end of the string.
- // *NOTE: gcc 2.95 does not generate an eof() event on the
- // stream operation above, so we manually get here to force it
- // across platforms.
- int c = i_stream.get();
- return ((EOF ==c) ? v : 0.0);
+ return llsd::string_to_real(mValue);
}
@@ -430,7 +425,7 @@ namespace
class ImplMap final : public LLSD::Impl
{
private:
- typedef std::map<LLSD::String, LLSD, std::less<>> DataMap;
+ using DataMap = LLSD::llsd_map_t;
DataMap mData;
@@ -456,7 +451,7 @@ namespace
<< it.second.asXMLRPCValue() << "</member>";
}
os << "</struct>";
- return os.str();
+ return std::move(os).str();
}
virtual bool has(std::string_view) const;
@@ -466,8 +461,13 @@ namespace
using LLSD::Impl::ref; // Unhiding ref(size_t)
virtual LLSD get(std::string_view) const;
virtual LLSD getKeys() const;
+ void insert(std::string&& k, const LLSD& v);
+ void insert(std::string&& k, LLSD&& v);
void insert(std::string_view k, const LLSD& v);
+ void insert(std::string_view k, LLSD&& v);
virtual void erase(const LLSD::String&);
+ LLSD& ref(std::string&&);
+ virtual const LLSD& ref(std::string&&) const;
LLSD& ref(std::string_view);
virtual const LLSD& ref(std::string_view) const;
@@ -524,18 +524,58 @@ namespace
return keys;
}
+ void ImplMap::insert(std::string&& k, const LLSD& v)
+ {
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD;
+ mData.emplace(std::move(k), v);
+ }
+
+ void ImplMap::insert(std::string&& k, LLSD&& v)
+ {
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD;
+ mData.emplace(std::move(k), std::move(v));
+ }
+
void ImplMap::insert(std::string_view k, const LLSD& v)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD;
mData.emplace(k, v);
}
+ void ImplMap::insert(std::string_view k, LLSD&& v)
+ {
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD;
+ mData.emplace(k, std::move(v));
+ }
+
void ImplMap::erase(const LLSD::String& k)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD;
mData.erase(k);
}
+ LLSD& ImplMap::ref(std::string&& k)
+ {
+ DataMap::iterator i = mData.lower_bound(k);
+ if (i == mData.end() || mData.key_comp()(k, i->first))
+ {
+ return mData.emplace_hint(i, std::make_pair(std::move(k), LLSD()))->second;
+ }
+
+ return i->second;
+ }
+
+ const LLSD& ImplMap::ref(std::string&& k) const
+ {
+ DataMap::const_iterator i = mData.lower_bound(k);
+ if (i == mData.end() || mData.key_comp()(k, i->first))
+ {
+ return undef();
+ }
+
+ return i->second;
+ }
+
LLSD& ImplMap::ref(std::string_view k)
{
DataMap::iterator i = mData.lower_bound(k);
@@ -597,7 +637,7 @@ namespace
ImplArray(const DataVector& data) : mData(data) { }
public:
- ImplArray() { }
+ ImplArray() = default;
virtual ImplArray& makeArray(Impl*&);
@@ -614,7 +654,7 @@ namespace
os << it.asXMLRPCValue();
}
os << "</data></array>";
- return os.str();
+ return std::move(os).str();
}
using LLSD::Impl::get; // Unhiding get(LLSD::String)
@@ -624,10 +664,13 @@ namespace
virtual LLSD get(size_t) const;
void set(size_t, const LLSD&);
void insert(size_t, const LLSD&);
+ void insert(size_t, LLSD&&);
LLSD& append(const LLSD&);
+ LLSD& append(LLSD&&);
virtual void erase(size_t);
LLSD& ref(size_t);
virtual const LLSD& ref(size_t) const;
+ void reserve(size_t size) { mData.reserve(size); }
LLSD::array_iterator beginArray() { return mData.begin(); }
LLSD::array_iterator endArray() { return mData.end(); }
@@ -689,12 +732,31 @@ namespace
mData.insert(mData.begin() + index, v);
}
+ void ImplArray::insert(size_t i, LLSD&& v)
+ {
+ NEGATIVE_EXIT(i);
+ DataVector::size_type index = i;
+
+ if (index >= mData.size()) // tbd - sanity check limit for index ?
+ {
+ mData.resize(index + 1);
+ }
+
+ mData.insert(mData.begin() + index, std::move(v));
+ }
+
LLSD& ImplArray::append(const LLSD& v)
{
mData.push_back(v);
return mData.back();
}
+ LLSD& ImplArray::append(LLSD&& v)
+ {
+ mData.push_back(std::move(v));
+ return mData.back();
+ }
+
void ImplArray::erase(size_t i)
{
NEGATIVE_EXIT(i);
@@ -762,6 +824,14 @@ LLSD::Impl::~Impl()
--sOutstandingCount;
}
+void LLSD::Impl::destruct(Impl*& var)
+{
+ if (var && var->mUseCount != STATIC_USAGE_COUNT && --var->mUseCount == 0)
+ {
+ delete var;
+ }
+}
+
void LLSD::Impl::reset(Impl*& var, Impl* impl)
{
if (impl && impl->mUseCount != STATIC_USAGE_COUNT)
@@ -960,7 +1030,7 @@ namespace
LLSD::LLSD() : impl(0) { ALLOC_LLSD_OBJECT; }
-LLSD::~LLSD() { FREE_LLSD_OBJECT; Impl::reset(impl, 0); }
+LLSD::~LLSD() { FREE_LLSD_OBJECT; Impl::destruct(impl); }
LLSD::LLSD(const LLSD& other) : impl(0) { ALLOC_LLSD_OBJECT; assign(other); }
void LLSD::assign(const LLSD& other) { Impl::assign(impl, other.impl); }
@@ -1036,13 +1106,31 @@ LLSD LLSD::emptyMap()
bool LLSD::has(const std::string_view k) const { return safe(impl).has(k); }
LLSD LLSD::get(const std::string_view k) const { return safe(impl).get(k); }
LLSD LLSD::getKeys() const { return safe(impl).getKeys(); }
+void LLSD::insert(std::string&& k, const LLSD& v) { makeMap(impl).insert(std::move(k), v); }
+void LLSD::insert(std::string&& k, LLSD&& v) { makeMap(impl).insert(std::move(k), std::move(v)); }
void LLSD::insert(std::string_view k, const LLSD& v) { makeMap(impl).insert(k, v); }
+void LLSD::insert(std::string_view k, LLSD&& v) { makeMap(impl).insert(k, std::move(v)); }
+LLSD& LLSD::with(std::string&& k, const LLSD& v)
+ {
+ makeMap(impl).insert(std::move(k), v);
+ return *this;
+ }
+LLSD& LLSD::with(std::string&& k, LLSD&& v)
+ {
+ makeMap(impl).insert(std::move(k), std::move(v));
+ return *this;
+ }
LLSD& LLSD::with(std::string_view k, const LLSD& v)
{
makeMap(impl).insert(k, v);
return *this;
}
+LLSD& LLSD::with(std::string_view k, LLSD&& v)
+ {
+ makeMap(impl).insert(k, std::move(v));
+ return *this;
+ }
void LLSD::erase(const String& k) { makeMap(impl).erase(k); }
LLSD& LLSD::operator[](const std::string_view k)
@@ -1050,6 +1138,13 @@ LLSD& LLSD::operator[](const std::string_view k)
LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD;
return makeMap(impl).ref(k);
}
+
+LLSD& LLSD::operator[](std::string&& k)
+{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD;
+ return makeMap(impl).ref(std::move(k));
+}
+
const LLSD& LLSD::operator[](const std::string_view k) const
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD;
@@ -1063,18 +1158,33 @@ LLSD LLSD::emptyArray()
return v;
}
+LLSD LLSD::emptyReservedArray(size_t size)
+{
+ LLSD v;
+ makeArray(v.impl).reserve(size);
+ return v;
+}
+
size_t LLSD::size() const { return safe(impl).size(); }
LLSD LLSD::get(Integer i) const { return safe(impl).get(i); }
void LLSD::set(Integer i, const LLSD& v){ makeArray(impl).set(i, v); }
+void LLSD::set(Integer i, LLSD&& v) { makeArray(impl).set(i, std::move(v)); }
void LLSD::insert(Integer i, const LLSD& v) { makeArray(impl).insert(i, v); }
+void LLSD::insert(Integer i, LLSD&& v) { makeArray(impl).insert(i, std::move(v)); }
LLSD& LLSD::with(Integer i, const LLSD& v)
{
makeArray(impl).insert(i, v);
return *this;
}
+LLSD& LLSD::with(Integer i, LLSD&& v)
+ {
+ makeArray(impl).insert(i, std::move(v));
+ return *this;
+ }
LLSD& LLSD::append(const LLSD& v) { return makeArray(impl).append(v); }
+LLSD& LLSD::append(LLSD&& v) { return makeArray(impl).append(std::move(v)); }
void LLSD::erase(Integer i) { makeArray(impl).erase(i); }
LLSD& LLSD::operator[](size_t i)
@@ -1142,6 +1252,22 @@ LLSD::reverse_array_iterator LLSD::rendArray() { return makeArray(impl)
namespace llsd
{
+LLSD::Real string_to_real(std::string_view in_string)
+{
+ LLSD::Real v = 0.0;
+ boost::iostreams::stream<boost::iostreams::array_source> i_stream(in_string.data(), in_string.size());
+ i_stream >> v;
+
+ // we would probably like to ignore all trailing whitespace as
+ // well, but for now, simply eat the next character, and make
+ // sure we reached the end of the string.
+ // *NOTE: gcc 2.95 does not generate an eof() event on the
+ // stream operation above, so we manually get here to force it
+ // across platforms.
+ int c = i_stream.get();
+ return ((EOF == c) ? v : 0.0);
+}
+
U32 allocationCount() { return LLSD::Impl::sAllocationCount; }
U32 outstandingCount() { return LLSD::Impl::sOutstandingCount; }
diff --git a/indra/llcommon/llsd.h b/indra/llcommon/llsd.h
index d2b3548831..afe35a65ba 100644
--- a/indra/llcommon/llsd.h
+++ b/indra/llcommon/llsd.h
@@ -34,6 +34,7 @@
#include "stdtypes.h"
#include "lldate.h"
+#include "llstl.h"
#include "lluri.h"
#include "lluuid.h"
@@ -321,11 +322,34 @@ public:
bool has(const std::string_view) const;
LLSD get(const std::string_view) const;
LLSD getKeys() const; // Return an LLSD array with keys as strings
+ void insert(const char* k, const LLSD& v)
+ {
+ return insert(std::string_view(k), v);
+ }
+ void insert(const char* k , LLSD&& v)
+ {
+ return insert(std::string_view(k), std::move(v));
+ }
+ void insert(std::string&&, const LLSD&);
+ void insert(std::string&&, LLSD&&);
void insert(std::string_view, const LLSD&);
+ void insert(std::string_view, LLSD&&);
void erase(const String&);
+ LLSD& with(const char* k, const LLSD& v)
+ {
+ return with(std::string_view(k), v);
+ }
+ LLSD& with(const char* k, LLSD&& v)
+ {
+ return with(std::string_view(k), std::move(v));
+ }
+ LLSD& with(std::string&&, const LLSD&);
+ LLSD& with(std::string&&, LLSD&&);
LLSD& with(std::string_view, const LLSD&);
+ LLSD& with(std::string_view, LLSD&&);
LLSD& operator[](const std::string_view);
+ LLSD& operator[](std::string&&);
LLSD& operator[](const char* c)
{
return c ? (*this)[std::string_view(c)] : *this;
@@ -339,14 +363,22 @@ public:
/** @name Array Values */
//@{
+ // Allocate an empty array
static LLSD emptyArray();
+ // Allocate an array with internal storage reserved but not initialized like a std::vector
+ static LLSD emptyReservedArray(size_t size);
+
LLSD get(Integer) const;
void set(Integer, const LLSD&);
+ void set(Integer, LLSD&&);
void insert(Integer, const LLSD&);
+ void insert(Integer, LLSD&&);
LLSD& append(const LLSD&);
+ LLSD& append(LLSD&&);
void erase(Integer);
LLSD& with(Integer, const LLSD&);
+ LLSD& with(Integer, LLSD&&);
// accept size_t so we can index relative to size()
const LLSD& operator[](size_t) const;
@@ -366,8 +398,9 @@ public:
//@{
size_t size() const;
- typedef std::map<String, LLSD>::iterator map_iterator;
- typedef std::map<String, LLSD>::const_iterator map_const_iterator;
+ using llsd_map_t = std::map<String, LLSD, std::less<>>;
+ typedef llsd_map_t::iterator map_iterator;
+ typedef llsd_map_t::const_iterator map_const_iterator;
map_iterator beginMap();
map_iterator endMap();
@@ -512,6 +545,8 @@ LL_COMMON_API std::ostream& operator<<(std::ostream& s, const LLSD& llsd);
namespace llsd
{
+ // Used by LLSD::ImplString to convert string type to real
+ LLSD::Real string_to_real(std::string_view in_string);
#ifdef LLSD_DEBUG_INFO
/** @name Unit Testing Interface */
diff --git a/indra/llcommon/llsdjson.cpp b/indra/llcommon/llsdjson.cpp
index 9abca48670..acd4bafb85 100644
--- a/indra/llcommon/llsdjson.cpp
+++ b/indra/llcommon/llsdjson.cpp
@@ -64,7 +64,7 @@ LLSD LlsdFromJson(const boost::json::value& val)
const boost::json::array& array = val.as_array();
size_t size = array.size();
// allocate elements 0 .. (size() - 1) to avoid incremental allocation
- if (! array.empty())
+ if (!array.empty())
{
result[size - 1] = LLSD();
}
@@ -78,7 +78,7 @@ LLSD LlsdFromJson(const boost::json::value& val)
result = LLSD::emptyMap();
for (const auto& element : val.as_object())
{
- result[element.key()] = LlsdFromJson(element.value());
+ result[std::string_view(element.key())] = LlsdFromJson(element.value());
}
break;
}
diff --git a/indra/llcommon/llsdserialize.cpp b/indra/llcommon/llsdserialize.cpp
index 3cc960698e..7fe1f9cdd4 100644
--- a/indra/llcommon/llsdserialize.cpp
+++ b/indra/llcommon/llsdserialize.cpp
@@ -775,7 +775,8 @@ S32 LLSDNotationParser::parseMap(std::istream& istr, LLSD& map, S32 max_depth) c
// There must be a value for every key, thus
// child_count must be greater than 0.
parse_count += count;
- map.insert(name, child);
+ map.insert(std::move(name), std::move(child)); // Move as name will be filled on next iteration
+ name.clear();
}
else
{
@@ -822,7 +823,7 @@ S32 LLSDNotationParser::parseArray(std::istream& istr, LLSD& array, S32 max_dept
else
{
parse_count += count;
- array.append(child);
+ array.append(std::move(child));
}
c = get(istr);
}
@@ -841,7 +842,7 @@ bool LLSDNotationParser::parseString(std::istream& istr, LLSD& data) const
auto count = deserialize_string(istr, value, mMaxBytesLeft);
if(PARSE_FAILURE == count) return false;
account(count);
- data = value;
+ data = std::move(value);
return true;
}
@@ -872,10 +873,10 @@ bool LLSDNotationParser::parseBinary(std::istream& istr, LLSD& data) const
if(len)
{
value.resize(len);
- account(fullread(istr, (char *)&value[0], len));
+ account(fullread(istr, (char*)value.data(), len));
}
c = get(istr); // strip off the trailing double-quote
- data = value;
+ data = std::move(value);
}
else if(0 == strncmp("b64", buf, 3))
{
@@ -885,7 +886,7 @@ bool LLSDNotationParser::parseBinary(std::istream& istr, LLSD& data) const
std::stringstream coded_stream;
get(istr, *(coded_stream.rdbuf()), '\"');
c = get(istr);
- std::string encoded(coded_stream.str());
+ std::string encoded(std::move(coded_stream).str());
S32 len = apr_base64_decode_len(encoded.c_str());
std::vector<U8> value;
if(len)
@@ -894,7 +895,7 @@ bool LLSDNotationParser::parseBinary(std::istream& istr, LLSD& data) const
len = apr_base64_decode_binary(&value[0], encoded.c_str());
value.resize(len);
}
- data = value;
+ data = std::move(value);
}
else if(0 == strncmp("b16", buf, 3))
{
@@ -925,7 +926,7 @@ bool LLSDNotationParser::parseBinary(std::istream& istr, LLSD& data) const
// copy the data out of the byte buffer
value.insert(value.end(), byte_buffer, write);
}
- data = value;
+ data = std::move(value);
}
else
{
@@ -1077,7 +1078,7 @@ S32 LLSDBinaryParser::doParse(std::istream& istr, LLSD& data, S32 max_depth) con
}
else
{
- data = value;
+ data = std::move(value);
account(cnt);
}
if(istr.fail())
@@ -1094,7 +1095,7 @@ S32 LLSDBinaryParser::doParse(std::istream& istr, LLSD& data, S32 max_depth) con
std::string value;
if(parseString(istr, value))
{
- data = value;
+ data = std::move(value);
}
else
{
@@ -1159,7 +1160,7 @@ S32 LLSDBinaryParser::doParse(std::istream& istr, LLSD& data, S32 max_depth) con
value.resize(size);
account(fullread(istr, (char*)&value[0], size));
}
- data = value;
+ data = std::move(value);
}
if(istr.fail())
{
@@ -1218,7 +1219,7 @@ S32 LLSDBinaryParser::parseMap(std::istream& istr, LLSD& map, S32 max_depth) con
// There must be a value for every key, thus child_count
// must be greater than 0.
parse_count += child_count;
- map.insert(name, child);
+ map.insert(std::move(name), std::move(child));
}
else
{
@@ -1238,13 +1239,12 @@ S32 LLSDBinaryParser::parseMap(std::istream& istr, LLSD& map, S32 max_depth) con
S32 LLSDBinaryParser::parseArray(std::istream& istr, LLSD& array, S32 max_depth) const
{
- array = LLSD::emptyArray();
U32 value_nbo = 0;
read(istr, (char*)&value_nbo, sizeof(U32)); /*Flawfinder: ignore*/
S32 size = (S32)ntohl(value_nbo);
- // *FIX: This would be a good place to reserve some space in the
- // array...
+ // Preallocate array to avoid incremental allocation
+ array = LLSD::emptyReservedArray(size);
S32 parse_count = 0;
S32 count = 0;
@@ -1260,7 +1260,7 @@ S32 LLSDBinaryParser::parseArray(std::istream& istr, LLSD& array, S32 max_depth)
if(child_count)
{
parse_count += child_count;
- array.append(child);
+ array.append(std::move(child));
}
++count;
c = istr.peek();
@@ -1279,18 +1279,15 @@ bool LLSDBinaryParser::parseString(
std::istream& istr,
std::string& value) const
{
- // *FIX: This is memory inefficient.
U32 value_nbo = 0;
read(istr, (char*)&value_nbo, sizeof(U32)); /*Flawfinder: ignore*/
S32 size = (S32)ntohl(value_nbo);
if(mCheckLimits && (size > mMaxBytesLeft)) return false;
if(size < 0) return false;
- std::vector<char> buf;
if(size)
{
- buf.resize(size);
- account(fullread(istr, &buf[0], size));
- value.assign(buf.begin(), buf.end());
+ value.resize(size);
+ account(fullread(istr, value.data(), size));
}
return true;
}
@@ -1781,7 +1778,7 @@ llssize deserialize_string_delim(
}
}
- value = write_buffer.str();
+ value = std::move(write_buffer).str();
return count;
}
@@ -1802,15 +1799,12 @@ llssize deserialize_string_raw(
{
// We probably have a valid raw string. determine
// the size, and read it.
- // *FIX: This is memory inefficient.
- auto len = strtol(buf + 1, NULL, 0);
+ auto len = strtol(buf + 1, nullptr, 0);
if((max_bytes>0)&&(len>max_bytes)) return LLSDParser::PARSE_FAILURE;
- std::vector<char> buf;
if(len)
{
- buf.resize(len);
- count += fullread(istr, (char *)&buf[0], len);
- value.assign(buf.begin(), buf.end());
+ value.resize(len);
+ count += fullread(istr, value.data(), len);
}
c = istr.get();
++count;
@@ -2166,7 +2160,7 @@ std::string zip_llsd(LLSD& data)
return std::string();
}
- std::string source = llsd_strm.str();
+ std::string source = std::move(llsd_strm).str();
U8 out[CHUNK];
diff --git a/indra/llcommon/llsdserialize_xml.cpp b/indra/llcommon/llsdserialize_xml.cpp
index 6396caf8d5..f399c51608 100644
--- a/indra/llcommon/llsdserialize_xml.cpp
+++ b/indra/llcommon/llsdserialize_xml.cpp
@@ -31,6 +31,8 @@
#include <deque>
#include "apr_base64.h"
+#include <boost/iostreams/device/array.hpp>
+#include <boost/iostreams/stream.hpp>
#include <boost/regex.hpp>
extern "C"
@@ -645,7 +647,7 @@ void LLSDXMLParser::Impl::startElementHandler(const XML_Char* name, const XML_Ch
if (mCurrentKey.empty()) { return startSkipping(); }
LLSD& map = *mStack.back();
- LLSD& newElement = map[mCurrentKey];
+ LLSD& newElement = map[std::move(mCurrentKey)];
mStack.push_back(&newElement);
mCurrentKey.clear();
@@ -709,7 +711,8 @@ void LLSDXMLParser::Impl::endElementHandler(const XML_Char* name)
return;
case ELEMENT_KEY:
- mCurrentKey = mCurrentContent;
+ mCurrentKey = std::move(mCurrentContent); // This is safe to move as we are in the end element handler
+ mCurrentContent.clear(); // Ensure mCurrentContent is empty for subsequent use
return;
default:
@@ -742,14 +745,22 @@ void LLSDXMLParser::Impl::endElementHandler(const XML_Char* name)
}
else
{
- value = LLSD(mCurrentContent).asInteger();
+ // This must treat "1.23" not as an error, but as a number, which is
+ // then truncated down to an integer. Hence, this code doesn't call
+ // std::istringstream::operator>>(int&), which would not consume the
+ // ".23" portion.
+
+ // Utilizes implementation used internally by LLSD::ImplString::asInteger
+ value = (int)llsd::string_to_real(mCurrentContent);
}
}
break;
case ELEMENT_REAL:
{
- value = LLSD(mCurrentContent).asReal();
+ // Utilizes implementation used internally by LLSD::ImplString::asReal
+ value = llsd::string_to_real(mCurrentContent);
+
// removed since this breaks when locale has decimal separator that isn't '.'
// investigated changing local to something compatible each time but deemed higher
// risk that just using LLSD.asReal() each time.
@@ -766,19 +777,19 @@ void LLSDXMLParser::Impl::endElementHandler(const XML_Char* name)
break;
case ELEMENT_STRING:
- value = mCurrentContent;
+ value = std::move(mCurrentContent); // This is safe to move as we are in the end element handler and this is cleared below
break;
case ELEMENT_UUID:
- value = LLSD(mCurrentContent).asUUID();
+ value = LLUUID(mCurrentContent);
break;
case ELEMENT_DATE:
- value = LLSD(mCurrentContent).asDate();
+ value = LLDate(mCurrentContent);
break;
case ELEMENT_URI:
- value = LLSD(mCurrentContent).asURI();
+ value = LLURI(mCurrentContent);
break;
case ELEMENT_BINARY:
@@ -787,15 +798,14 @@ void LLSDXMLParser::Impl::endElementHandler(const XML_Char* name)
// created by python and other non-linden systems - DEV-39358
// Fortunately we have very little binary passing now,
// so performance impact shold be negligible. + poppy 2009-09-04
- boost::regex r;
- r.assign("\\s");
+ static const boost::regex r("\\s");
std::string stripped = boost::regex_replace(mCurrentContent, r, "");
S32 len = apr_base64_decode_len(stripped.c_str());
std::vector<U8> data;
data.resize(len);
len = apr_base64_decode_binary(&data[0], stripped.c_str());
data.resize(len);
- value = data;
+ value = std::move(data);
break;
}
diff --git a/indra/llcommon/llsingleton.h b/indra/llcommon/llsingleton.h
index 81e69ab63c..ebef2489ce 100644
--- a/indra/llcommon/llsingleton.h
+++ b/indra/llcommon/llsingleton.h
@@ -25,10 +25,10 @@
#ifndef LLSINGLETON_H
#define LLSINGLETON_H
-#include <boost/unordered_set.hpp>
#include <initializer_list>
#include <list>
#include <typeinfo>
+#include <unordered_set>
#include <vector>
#include <mutex>
#include "lockstatic.h"
@@ -61,7 +61,7 @@ private:
static vec_t dep_sort();
// we directly depend on these other LLSingletons
- typedef boost::unordered_set<LLSingletonBase*> set_t;
+ typedef std::unordered_set<LLSingletonBase*> set_t;
set_t mDepends;
protected:
diff --git a/indra/llcommon/llstaticstringtable.h b/indra/llcommon/llstaticstringtable.h
index 66ba3487c4..edff955ee7 100644
--- a/indra/llcommon/llstaticstringtable.h
+++ b/indra/llcommon/llstaticstringtable.h
@@ -29,9 +29,10 @@
#define LL_STATIC_STRING_TABLE_H
#include "lldefs.h"
-#include <boost/unordered_map.hpp>
#include "llstl.h"
+#include <unordered_map>
+
class LLStaticHashedString
{
public:
@@ -74,7 +75,7 @@ struct LLStaticStringHasher
template< typename MappedObject >
class LL_COMMON_API LLStaticStringTable
- : public boost::unordered_map< LLStaticHashedString, MappedObject, LLStaticStringHasher >
+ : public std::unordered_map< LLStaticHashedString, MappedObject, LLStaticStringHasher >
{
};
diff --git a/indra/llcommon/llstl.h b/indra/llcommon/llstl.h
index fb387a7b52..550725cbc8 100644
--- a/indra/llcommon/llstl.h
+++ b/indra/llcommon/llstl.h
@@ -34,6 +34,7 @@
#include <vector>
#include <list>
#include <set>
+#include <typeindex>
#include <typeinfo>
#ifdef LL_LINUX
@@ -229,12 +230,10 @@ void delete_and_clear_array(T*& ptr)
template <typename T>
inline typename T::mapped_type get_ptr_in_map(const T& inmap, typename T::key_type const& key)
{
- // Typedef here avoids warnings because of new c++ naming rules.
- typedef typename T::const_iterator map_iter;
- map_iter iter = inmap.find(key);
+ auto iter = inmap.find(key);
if(iter == inmap.end())
{
- return NULL;
+ return nullptr;
}
else
{
@@ -243,8 +242,8 @@ inline typename T::mapped_type get_ptr_in_map(const T& inmap, typename T::key_ty
};
// helper function which returns true if key is in inmap.
-template <typename K, typename T>
-inline bool is_in_map(const std::map<K,T>& inmap, const K& key)
+template <typename T>
+inline bool is_in_map(const T& inmap, typename T::key_type const& key)
{
if(inmap.find(key) == inmap.end())
{
@@ -260,12 +259,10 @@ inline bool is_in_map(const std::map<K,T>& inmap, const K& key)
// To replace LLSkipMap getIfThere, use:
// get_if_there(map, key, 0)
// WARNING: Make sure default_value (generally 0) is not a valid map entry!
-template <typename K, typename T>
-inline T get_if_there(const std::map<K,T>& inmap, const K& key, T default_value)
+template <typename T>
+inline typename T::mapped_type get_if_there(const T& inmap, typename T::key_type const& key, typename T::mapped_type default_value)
{
- // Typedef here avoids warnings because of new c++ naming rules.
- typedef typename std::map<K,T>::const_iterator map_iter;
- map_iter iter = inmap.find(key);
+ auto iter = inmap.find(key);
if(iter == inmap.end())
{
return default_value;
@@ -699,5 +696,24 @@ struct ll_template_cast_impl<DEST, SOURCE> \
} \
}
+// Transparent string hashing helper for use with std::unordered_*
+// std::unordered_map<std::string, val, ll::string_hash, std::equal_to<>>
+namespace ll
+{
+ struct string_hash
+ {
+ using is_transparent = void;
+ [[nodiscard]] size_t operator()(char const* rhs) const { return std::hash<std::string_view>{}(rhs); }
+ [[nodiscard]] size_t operator()(std::string_view rhs) const { return std::hash<std::string_view>{}(rhs); }
+ [[nodiscard]] size_t operator()(const std::string& rhs) const { return std::hash<std::string>{}(rhs); }
+ };
+} // namespace ll
+
+// Specialize ostream for std::type_index to allow log output
+inline std::ostream& operator<<(std::ostream& s, std::type_index type)
+{
+ s << type.name();
+ return s;
+}
#endif // LL_LLSTL_H
diff --git a/indra/llcommon/llthread.cpp b/indra/llcommon/llthread.cpp
index e1f0d531cf..bae80a3fb9 100644
--- a/indra/llcommon/llthread.cpp
+++ b/indra/llcommon/llthread.cpp
@@ -236,7 +236,11 @@ void LLThread::tryRun()
LL::WorkQueue::ptr_t main_queue = LL::WorkQueue::getInstance("mainloop");
main_queue->post(
// Bind the current exception, rethrow it in main loop.
- [exc = std::current_exception()]() { std::rethrow_exception(exc); });
+ [exc = std::current_exception(), name = mName]()
+ {
+ LL_INFOS("THREAD") << "Rethrowing exception from thread " << name << LL_ENDL;
+ std::rethrow_exception(exc);
+ });
}
#endif // else LL_WINDOWS
}
diff --git a/indra/llcommon/lluuid.h b/indra/llcommon/lluuid.h
index e6b0eea7a1..122cf414ca 100644
--- a/indra/llcommon/lluuid.h
+++ b/indra/llcommon/lluuid.h
@@ -26,6 +26,7 @@
#ifndef LL_LLUUID_H
#define LL_LLUUID_H
+#include <functional>
#include <iostream>
#include <set>
#include <vector>
@@ -178,15 +179,27 @@ namespace std
{
inline size_t operator()(const LLUUID& id) const noexcept
{
- return (size_t)id.getDigest64();
+ size_t h = 0;
+ // Golden ratio hash with avalanche mixing
+ // Process 8 bytes at a time by manually constructing 64-bit values
+ // Shift by 31: mixes upper half into lower half for better bit distribution
+ // Shift by 47: ensures highest bits influence final hash output
+ for (int i = 0; i < UUID_BYTES; i += 8) {
+ size_t chunk = (size_t)id.mData[i] | ((size_t)id.mData[i+1] << 8) |
+ ((size_t)id.mData[i+2] << 16) | ((size_t)id.mData[i+3] << 24) |
+ ((size_t)id.mData[i+4] << 32) | ((size_t)id.mData[i+5] << 40) |
+ ((size_t)id.mData[i+6] << 48) | ((size_t)id.mData[i+7] << 56);
+ h ^= (chunk * 0x9e3779b97f4a7c15ULL) ^ (h >> 31) ^ (h >> 47);
+ }
+ return h;
}
};
}
-// For use with boost containers.
+// For use with boost::container_hash
inline size_t hash_value(const LLUUID& id) noexcept
{
- return (size_t)id.getDigest64();
+ return std::hash<LLUUID>{}(id);
}
#endif // LL_LLUUID_H
diff --git a/indra/newview/llwatchdog.cpp b/indra/llcommon/llwatchdog.cpp
index 072743505f..1bc1283d0b 100644
--- a/indra/newview/llwatchdog.cpp
+++ b/indra/llcommon/llwatchdog.cpp
@@ -24,12 +24,12 @@
* $/LicenseInfo$
*/
+// Precompiled header
+#include "linden_common.h"
-#include "llviewerprecompiledheaders.h"
#include "llwatchdog.h"
#include "llmutex.h"
#include "llthread.h"
-#include "llappviewer.h"
constexpr U32 WATCHDOG_SLEEP_TIME_USEC = 1000000U;
@@ -68,7 +68,9 @@ private:
};
// LLWatchdogEntry
-LLWatchdogEntry::LLWatchdogEntry()
+LLWatchdogEntry::LLWatchdogEntry(const std::string& thread_name)
+ : mThreadName(thread_name)
+ , mThreadID(LLThread::currentID())
{
}
@@ -90,11 +92,16 @@ void LLWatchdogEntry::stop()
LLWatchdog::getInstance()->remove(this);
}
}
+std::string LLWatchdogEntry::getThreadName() const
+{
+ return mThreadName + llformat(": %d", mThreadID);
+}
// LLWatchdogTimeout
const std::string UNINIT_STRING = "uninitialized";
-LLWatchdogTimeout::LLWatchdogTimeout() :
+LLWatchdogTimeout::LLWatchdogTimeout(const std::string& thread_name) :
+ LLWatchdogEntry(thread_name),
mTimeout(0.0f),
mPingState(UNINIT_STRING)
{
@@ -176,7 +183,7 @@ void LLWatchdog::remove(LLWatchdogEntry* e)
unlockThread();
}
-void LLWatchdog::init()
+void LLWatchdog::init(func_t set_error_state_callback)
{
if (!mSuspectsAccessMutex && !mTimer)
{
@@ -189,6 +196,7 @@ void LLWatchdog::init()
// start needs to use the mSuspectsAccessMutex
mTimer->start();
}
+ mCreateMarkerFnc = set_error_state_callback;
}
void LLWatchdog::cleanup()
@@ -242,17 +250,23 @@ void LLWatchdog::run()
{
mTimer->stop();
}
- if (LLAppViewer::instance()->logoutRequestSent())
+
+ // Sets error marker file
+ mCreateMarkerFnc();
+ // Todo1: Warn user?
+ // Todo2: We probably want to report even if 5 seconds passed, just not error 'yet'.
+ std::string last_state = (*result)->getLastState();
+ if (last_state.empty())
{
- LLAppViewer::instance()->createErrorMarker(LAST_EXEC_LOGOUT_FROZE);
+ LL_ERRS() << "Watchdog timer for thread " << (*result)->getThreadName()
+ << " expired; assuming viewer is hung and crashing" << LL_ENDL;
}
else
{
- LLAppViewer::instance()->createErrorMarker(LAST_EXEC_FROZE);
+ LL_ERRS() << "Watchdog timer for thread " << (*result)->getThreadName()
+ << " expired with state: " << last_state
+ << "; assuming viewer is hung and crashing" << LL_ENDL;
}
- // Todo1: warn user?
- // Todo2: We probably want to report even if 5 seconds passed, just not error 'yet'.
- LL_ERRS() << "Watchdog timer expired; assuming viewer is hung and crashing" << LL_ENDL;
}
}
diff --git a/indra/newview/llwatchdog.h b/indra/llcommon/llwatchdog.h
index b7dd55577e..fded881bb8 100644
--- a/indra/newview/llwatchdog.h
+++ b/indra/llcommon/llwatchdog.h
@@ -30,13 +30,17 @@
#ifndef LL_TIMER_H
#include "lltimer.h"
#endif
+#include "llmutex.h"
+#include "llsingleton.h"
+
+#include <functional>
// LLWatchdogEntry is the interface used by the tasks that
// need to be watched.
class LLWatchdogEntry
{
public:
- LLWatchdogEntry();
+ LLWatchdogEntry(const std::string &thread_name);
virtual ~LLWatchdogEntry();
// isAlive is accessed by the watchdog thread.
@@ -46,12 +50,19 @@ public:
virtual void reset() = 0;
virtual void start();
virtual void stop();
+ virtual std::string getLastState() const { return std::string(); }
+ typedef std::thread::id id_t;
+ std::string getThreadName() const;
+
+private:
+ id_t mThreadID; // ID of the thread being watched
+ std::string mThreadName;
};
class LLWatchdogTimeout : public LLWatchdogEntry
{
public:
- LLWatchdogTimeout();
+ LLWatchdogTimeout(const std::string& thread_name);
virtual ~LLWatchdogTimeout();
bool isAlive() const override;
@@ -63,6 +74,7 @@ public:
void setTimeout(F32 d);
void ping(std::string_view state);
const std::string& getState() {return mPingState; }
+ std::string getLastState() const override { return mPingState; }
private:
LLTimer mTimer;
@@ -81,10 +93,12 @@ public:
void add(LLWatchdogEntry* e);
void remove(LLWatchdogEntry* e);
- void init();
+ typedef std::function<void()> func_t;
+ void init(func_t set_error_state_callback);
void run();
void cleanup();
+
private:
void lockThread();
void unlockThread();
@@ -94,6 +108,11 @@ private:
LLMutex* mSuspectsAccessMutex;
LLWatchdogTimerThread* mTimer;
U64 mLastClockCount;
+
+ // At the moment watchdog expects app to set markers in mCreateMarkerFnc,
+ // but technically can be used to set any error states or do some cleanup
+ // or show warnings.
+ func_t mCreateMarkerFnc;
};
#endif // LL_LLTHREADWATCHDOG_H
diff --git a/indra/llcommon/workqueue.cpp b/indra/llcommon/workqueue.cpp
index 4db44ff2a6..67c23358ed 100644
--- a/indra/llcommon/workqueue.cpp
+++ b/indra/llcommon/workqueue.cpp
@@ -216,10 +216,15 @@ void LL::WorkQueueBase::callWork(const Work& work)
LL_WARNS("LLCoros") << "Capturing and rethrowing uncaught exception in WorkQueueBase "
<< getKey() << LL_ENDL;
+ std::string name = getKey();
LL::WorkQueue::ptr_t main_queue = LL::WorkQueue::getInstance("mainloop");
main_queue->post(
// Bind the current exception, rethrow it in main loop.
- [exc = std::current_exception()]() { std::rethrow_exception(exc); });
+ [exc = std::current_exception(), name]()
+ {
+ LL_INFOS("LLCoros") << "Rethrowing exception from WorkQueueBase::callWork " << name << LL_ENDL;
+ std::rethrow_exception(exc);
+ });
}
else
{
diff --git a/indra/llcommon/workqueue.h b/indra/llcommon/workqueue.h
index 735ad38a26..573203a5b3 100644
--- a/indra/llcommon/workqueue.h
+++ b/indra/llcommon/workqueue.h
@@ -530,7 +530,11 @@ namespace LL
reply,
// Bind the current exception to transport back to the
// originating WorkQueue. Once there, rethrow it.
- [exc = std::current_exception()](){ std::rethrow_exception(exc); });
+ [exc = std::current_exception()]()
+ {
+ LL_INFOS("LLCoros") << "Rethrowing exception from WorkQueueBase::postTo" << LL_ENDL;
+ std::rethrow_exception(exc);
+ });
}
},
// if caller passed a TimePoint, pass it along to post()
diff --git a/indra/llfilesystem/lldiskcache.cpp b/indra/llfilesystem/lldiskcache.cpp
index e971e324a0..9b674d5528 100644
--- a/indra/llfilesystem/lldiskcache.cpp
+++ b/indra/llfilesystem/lldiskcache.cpp
@@ -91,6 +91,8 @@ LLDiskCache::LLDiskCache(const std::string& cache_dir,
// asset will have to be re-requested.
void LLDiskCache::purge()
{
+ LL_PROFILE_ZONE_SCOPED;
+
if (mEnableCacheDebugInfo)
{
LL_INFOS() << "Total dir size before purge is " << dirFileSize(sCacheDir) << LL_ENDL;
diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp
index bea33c04ed..b4d34f536c 100644
--- a/indra/llimage/llimage.cpp
+++ b/indra/llimage/llimage.cpp
@@ -709,8 +709,20 @@ U8* LLImageBase::allocateData(S32 size)
mData = (U8*)ll_aligned_malloc_16(size);
if (!mData)
{
- LL_WARNS() << "Failed to allocate image data size [" << size << "]" << LL_ENDL;
- mBadBufferAllocation = true;
+ constexpr S32 MAX_TOLERANCE = 1024 * 1024 * 4; // 4 MB
+ if (size > MAX_TOLERANCE)
+ {
+ // If a big image failed to allocate, tollerate it for now.
+ // It's insightfull when crash logs without obvious cause are being analyzed,
+ // so a crash in a random location that normally is a mystery can get proper handling.
+ LL_WARNS() << "Failed to allocate image data size [" << size << "]" << LL_ENDL;
+ }
+ else
+ {
+ // We are too far gone if we can't allocate a small buffer.
+ LLError::LLUserWarningMsg::showOutOfMemory();
+ LL_ERRS() << "Failed to allocate image data size [" << size << "]" << LL_ENDL;
+ }
}
}
diff --git a/indra/llinventory/llinventory.cpp b/indra/llinventory/llinventory.cpp
index 3defad8f3b..f126accfb8 100644
--- a/indra/llinventory/llinventory.cpp
+++ b/indra/llinventory/llinventory.cpp
@@ -1017,10 +1017,9 @@ bool LLInventoryItem::fromLLSD(const LLSD& sd, bool is_new)
if (i->first == INV_THUMBNAIL_LABEL)
{
const LLSD &thumbnail_map = i->second;
- const std::string w = INV_ASSET_ID_LABEL;
- if (thumbnail_map.has(w))
+ if (thumbnail_map.has(INV_ASSET_ID_LABEL))
{
- mThumbnailUUID = thumbnail_map[w];
+ mThumbnailUUID = thumbnail_map[INV_ASSET_ID_LABEL];
}
/* Example:
<key> asset_id </key>
@@ -1033,7 +1032,7 @@ bool LLInventoryItem::fromLLSD(const LLSD& sd, bool is_new)
<integer> 1 </key>
*/
continue;
- }
+ }
if (i->first == INV_THUMBNAIL_ID_LABEL)
{
@@ -1044,10 +1043,9 @@ bool LLInventoryItem::fromLLSD(const LLSD& sd, bool is_new)
if (i->first == INV_FAVORITE_LABEL)
{
const LLSD& favorite_map = i->second;
- const std::string w = INV_TOGGLED_LABEL;
- if (favorite_map.has(w))
+ if (favorite_map.has(INV_TOGGLED_LABEL))
{
- mFavorite = favorite_map[w].asBoolean();
+ mFavorite = favorite_map[INV_TOGGLED_LABEL].asBoolean();
}
continue;
}
@@ -1111,7 +1109,7 @@ bool LLInventoryItem::fromLLSD(const LLSD& sd, bool is_new)
LLSD const &label = i->second;
if (label.isString())
{
- mType = LLAssetType::lookup(label.asString().c_str());
+ mType = LLAssetType::lookup(label.asStringRef().c_str());
}
else if (label.isInteger())
{
@@ -1126,7 +1124,7 @@ bool LLInventoryItem::fromLLSD(const LLSD& sd, bool is_new)
LLSD const &label = i->second;
if (label.isString())
{
- mInventoryType = LLInventoryType::lookup(label.asString().c_str());
+ mInventoryType = LLInventoryType::lookup(label.asStringRef().c_str());
}
else if (label.isInteger())
{
@@ -1290,7 +1288,7 @@ void LLInventoryCategory::packMessage(LLMessageSystem* msg) const
bool LLInventoryCategory::fromLLSD(const LLSD& sd)
{
- std::string w;
+ std::string_view w;
w = INV_FOLDER_ID_LABEL_WS;
if (sd.has(w))
diff --git a/indra/llkdu/llimagej2ckdu.cpp b/indra/llkdu/llimagej2ckdu.cpp
index 7eba9494a6..e7ac6bdb31 100644
--- a/indra/llkdu/llimagej2ckdu.cpp
+++ b/indra/llkdu/llimagej2ckdu.cpp
@@ -615,6 +615,11 @@ bool LLImageJ2CKDU::decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 deco
return false;
}
}
+ catch (std::bad_alloc&)
+ {
+ LLError::LLUserWarningMsg::showOutOfMemory();
+ LL_ERRS() << "Bad memory allocation in J2C KDU" << LL_ENDL;
+ }
catch (const KDUError& msg)
{
base.setLastError(msg.what());
diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp
index dfad66040e..082ab85e51 100644
--- a/indra/llmath/llvolume.cpp
+++ b/indra/llmath/llvolume.cpp
@@ -912,7 +912,7 @@ bool LLProfile::generate(const LLProfileParams& params, bool path_open,F32 detai
case LL_PCODE_HOLE_CIRCLE:
case LL_PCODE_HOLE_SAME:
default:
- addHole(params, true, circle_detail, 0, hollow, 1.f);
+ addHole(params, false, circle_detail, 0, hollow, 1.f);
break;
}
}
@@ -4945,9 +4945,17 @@ LLVolumeFace::LLVolumeFace(const LLVolumeFace& src)
mOctree(NULL),
mOctreeTriangles(NULL)
{
- mExtents = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*3);
- mCenter = mExtents+2;
- *this = src;
+ try
+ {
+ mExtents = (LLVector4a*)ll_aligned_malloc_16(sizeof(LLVector4a) * 3);
+ mCenter = mExtents + 2;
+ *this = src;
+ }
+ catch (std::bad_alloc&)
+ {
+ LLError::LLUserWarningMsg::showOutOfMemory();
+ LL_ERRS("LLVolume") << "Bad memory allocation in LLVolumeFace" << LL_ENDL;
+ }
}
LLVolumeFace& LLVolumeFace::operator=(const LLVolumeFace& src)
@@ -5165,7 +5173,7 @@ void LLVolumeFace::remap()
// Documentation for meshopt_generateVertexRemapMulti claims that remap should use vertice count
// but all examples use indice count. There are out of bounds crashes when using vertice count.
// To be on the safe side use bigger of the two.
- std::vector<unsigned int> remap(llmax(mNumIndices, mNumVertices));
+ std::vector<unsigned int> remap(llmax(mNumIndices, mNumVertices), 0);
S32 remap_vertices_count = static_cast<S32>(LLMeshOptimizer::generateRemapMultiU16(&remap[0],
mIndices,
mNumIndices,
@@ -5683,7 +5691,12 @@ bool LLVolumeFace::cacheOptimize(bool gen_tangents)
catch (std::bad_alloc&)
{
LLError::LLUserWarningMsg::showOutOfMemory();
- LL_ERRS("LLCoros") << "Bad memory allocation in MikktData::genTangSpace" << LL_ENDL;
+ LL_ERRS("LLVolume") << "Bad memory allocation in MikktData::genTangSpace" << LL_ENDL;
+ }
+ catch (...)
+ {
+ LL_WARNS_ONCE("LLVolume") << "Mikktspace::genTangSpace() failed" << LL_ENDL;
+ return false;
}
@@ -5705,7 +5718,7 @@ bool LLVolumeFace::cacheOptimize(bool gen_tangents)
catch (std::bad_alloc&)
{
LLError::LLUserWarningMsg::showOutOfMemory();
- LL_ERRS("LLCoros") << "Failed to allocate memory for remap: " << (S32)data.p.size() << LL_ENDL;
+ LL_ERRS("LLVOLUME") << "Failed to allocate memory for remap: " << (S32)data.p.size() << LL_ENDL;
}
U32 stream_count = data.w.empty() ? 4 : 5;
@@ -5722,7 +5735,7 @@ bool LLVolumeFace::cacheOptimize(bool gen_tangents)
catch (std::bad_alloc&)
{
LLError::LLUserWarningMsg::showOutOfMemory();
- LL_ERRS("LLCoros") << "Failed to allocate memory for VertexRemap: " << (S32)data.p.size() << LL_ENDL;
+ LL_ERRS("LLVolume") << "Failed to allocate memory for VertexRemap: " << (S32)data.p.size() << LL_ENDL;
}
}
@@ -5734,7 +5747,7 @@ bool LLVolumeFace::cacheOptimize(bool gen_tangents)
if (mNumVertices == 0)
{
LLError::LLUserWarningMsg::showOutOfMemory();
- LL_ERRS("LLCoros") << "Failed to allocate memory for resizeVertices(" << vert_count << ")" << LL_ENDL;
+ LL_ERRS("LLVolume") << "Failed to allocate memory for resizeVertices(" << vert_count << ")" << LL_ENDL;
}
if (!data.w.empty())
diff --git a/indra/llmeshoptimizer/llmeshoptimizer.cpp b/indra/llmeshoptimizer/llmeshoptimizer.cpp
index 7339454367..76d51fdad0 100644
--- a/indra/llmeshoptimizer/llmeshoptimizer.cpp
+++ b/indra/llmeshoptimizer/llmeshoptimizer.cpp
@@ -171,7 +171,6 @@ size_t LLMeshOptimizer::generateRemapMultiU32(
// but providing indices helps with removing unused vertices
U64 indeces_cmp = indices ? index_count : vertex_count;
- // meshopt_generateVertexRemapMulti will throw an assert if (indices[i] >= vertex_count)
return meshopt_generateVertexRemapMulti(&remap[0], indices, indeces_cmp, vertex_count, streams, sizeof(streams) / sizeof(streams[0]));
}
diff --git a/indra/llmessage/llassetstorage.cpp b/indra/llmessage/llassetstorage.cpp
index a8f0554a71..3ce1a911ed 100644
--- a/indra/llmessage/llassetstorage.cpp
+++ b/indra/llmessage/llassetstorage.cpp
@@ -1316,6 +1316,9 @@ const char* LLAssetStorage::getErrorString(S32 status)
case LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE:
return "Asset request: asset not found in database";
+ case LL_ERR_NO_CAP:
+ return "Asset request: region or asset capability not available";
+
case LL_ERR_EOF:
return "End of file";
diff --git a/indra/llmessage/llassetstorage.h b/indra/llmessage/llassetstorage.h
index 6d6526757d..d5daa0cb8f 100644
--- a/indra/llmessage/llassetstorage.h
+++ b/indra/llmessage/llassetstorage.h
@@ -57,6 +57,7 @@ const int LL_ERR_ASSET_REQUEST_FAILED = -1;
const int LL_ERR_ASSET_REQUEST_NONEXISTENT_FILE = -3;
const int LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE = -4;
const int LL_ERR_INSUFFICIENT_PERMISSIONS = -5;
+const int LL_ERR_NO_CAP = -6;
const int LL_ERR_PRICE_MISMATCH = -23018;
// *TODO: these typedefs are passed into the cache via a legacy C function pointer
diff --git a/indra/llmessage/llavatarnamecache.cpp b/indra/llmessage/llavatarnamecache.cpp
index ebafc53a4d..86b36315dc 100644
--- a/indra/llmessage/llavatarnamecache.cpp
+++ b/indra/llmessage/llavatarnamecache.cpp
@@ -276,7 +276,7 @@ void LLAvatarNameCache::handleAvNameCacheSuccess(const LLSD &data, const LLSD &h
// Provide some fallback for agents that return errors
void LLAvatarNameCache::handleAgentError(const LLUUID& agent_id)
{
- std::map<LLUUID,LLAvatarName>::iterator existing = mCache.find(agent_id);
+ cache_t::iterator existing = mCache.find(agent_id);
if (existing == mCache.end())
{
// there is no existing cache entry, so make a temporary name from legacy
@@ -311,7 +311,7 @@ void LLAvatarNameCache::processName(const LLUUID& agent_id, const LLAvatarName&
bool updated_account = true; // assume obsolete value for new arrivals by default
- std::map<LLUUID, LLAvatarName>::iterator it = mCache.find(agent_id);
+ cache_t::iterator it = mCache.find(agent_id);
if (it != mCache.end()
&& (*it).second.getAccountName() == av_name.getAccountName())
{
@@ -418,7 +418,7 @@ void LLAvatarNameCache::legacyNameCallback(const LLUUID& agent_id,
// Retrieve the name and set it to never (or almost never...) expire: when we are using the legacy
// protocol, we do not get an expiration date for each name and there's no reason to ask the
// data again and again so we set the expiration time to the largest value admissible.
- std::map<LLUUID,LLAvatarName>::iterator av_record = LLAvatarNameCache::getInstance()->mCache.find(agent_id);
+ cache_t::iterator av_record = LLAvatarNameCache::getInstance()->mCache.find(agent_id);
LLAvatarName& av_name = av_record->second;
av_name.setExpires(MAX_UNREFRESHED_TIME);
}
@@ -631,7 +631,7 @@ bool LLAvatarNameCache::getName(const LLUUID& agent_id, LLAvatarName *av_name)
if (mRunning)
{
// ...only do immediate lookups when cache is running
- std::map<LLUUID,LLAvatarName>::iterator it = mCache.find(agent_id);
+ cache_t::iterator it = mCache.find(agent_id);
if (it != mCache.end())
{
*av_name = it->second;
@@ -682,7 +682,7 @@ LLAvatarNameCache::callback_connection_t LLAvatarNameCache::getNameCallback(cons
if (mRunning)
{
// ...only do immediate lookups when cache is running
- std::map<LLUUID,LLAvatarName>::iterator it = mCache.find(agent_id);
+ cache_t::iterator it = mCache.find(agent_id);
if (it != mCache.end())
{
const LLAvatarName& av_name = it->second;
@@ -753,13 +753,11 @@ void LLAvatarNameCache::insert(const LLUUID& agent_id, const LLAvatarName& av_na
LLUUID LLAvatarNameCache::findIdByName(const std::string& name)
{
- std::map<LLUUID, LLAvatarName>::iterator it;
- std::map<LLUUID, LLAvatarName>::iterator end = mCache.end();
- for (it = mCache.begin(); it != end; ++it)
+ for (const auto& [id, avatar_name] : mCache)
{
- if (it->second.getUserName() == name)
+ if (avatar_name.getUserName() == name)
{
- return it->first;
+ return id;
}
}
diff --git a/indra/llmessage/llavatarnamecache.h b/indra/llmessage/llavatarnamecache.h
index 0ddaee2aa1..6743943495 100644
--- a/indra/llmessage/llavatarnamecache.h
+++ b/indra/llmessage/llavatarnamecache.h
@@ -30,8 +30,10 @@
#include "llavatarname.h" // for convenience
#include "llsingleton.h"
+#include "lluuid.h"
#include <boost/signals2.hpp>
#include <set>
+#include <unordered_map>
class LLSD;
class LLUUID;
@@ -161,23 +163,23 @@ private:
std::string mNameLookupURL;
// Accumulated agent IDs for next query against service
- typedef std::set<LLUUID> ask_queue_t;
+ using ask_queue_t = std::set<LLUUID>;
ask_queue_t mAskQueue;
// Agent IDs that have been requested, but with no reply.
// Maps agent ID to frame time request was made.
- typedef std::map<LLUUID, F64> pending_queue_t;
+ using pending_queue_t = std::unordered_map<LLUUID, F64>;
pending_queue_t mPendingQueue;
// Callbacks to fire when we received a name.
// May have multiple callbacks for a single ID, which are
// represented as multiple slots bound to the signal.
// Avoid copying signals via pointers.
- typedef std::map<LLUUID, callback_signal_t*> signal_map_t;
+ using signal_map_t = std::unordered_map<LLUUID, callback_signal_t*>;
signal_map_t mSignalMap;
// The cache at last, i.e. avatar names we know about.
- typedef std::map<LLUUID, LLAvatarName> cache_t;
+ using cache_t = std::unordered_map<LLUUID, LLAvatarName>;
cache_t mCache;
// Time when unrefreshed cached names were checked last.
diff --git a/indra/llmessage/llcachename.cpp b/indra/llmessage/llcachename.cpp
index 56dfaef873..95b7bb8c3d 100644
--- a/indra/llmessage/llcachename.cpp
+++ b/indra/llmessage/llcachename.cpp
@@ -179,12 +179,11 @@ void ReplySender::flush()
}
}
-
-typedef std::set<LLUUID> AskQueue;
-typedef std::list<PendingReply*> ReplyQueue;
-typedef std::map<LLUUID,U32> PendingQueue;
-typedef std::map<LLUUID, LLCacheNameEntry*> Cache;
-typedef std::map<std::string, LLUUID> ReverseCache;
+using AskQueue = std::set<LLUUID>;
+using ReplyQueue = std::list<PendingReply*>;
+using PendingQueue = std::unordered_map<LLUUID, U32>;
+using Cache = std::unordered_map<LLUUID, LLCacheNameEntry*>;
+using ReverseCache = std::unordered_map<std::string, LLUUID>;
class LLCacheName::Impl
{
@@ -214,7 +213,7 @@ public:
Impl(LLMessageSystem* msg);
~Impl();
- bool getName(const LLUUID& id, std::string& first, std::string& last, std::map<std::string, std::string>& default_names);
+ bool getName(const LLUUID& id, std::string& first, std::string& last, cache_map_t& default_names);
boost::signals2::connection addPending(const LLUUID& id, const LLCacheNameCallback& callback);
void addPending(const LLUUID& id, const LLHost& host);
@@ -401,7 +400,7 @@ void LLCacheName::exportFile(std::ostream& ostr)
}
-bool LLCacheName::Impl::getName(const LLUUID& id, std::string& first, std::string& last, std::map<std::string, std::string>& default_names)
+bool LLCacheName::Impl::getName(const LLUUID& id, std::string& first, std::string& last, cache_map_t &default_names)
{
if(id.isNull())
{
diff --git a/indra/llmessage/llcachename.h b/indra/llmessage/llcachename.h
index 609387b6de..a333eac0f5 100644
--- a/indra/llmessage/llcachename.h
+++ b/indra/llmessage/llcachename.h
@@ -136,7 +136,8 @@ public:
void localizeCacheName(std::string key, std::string value);
private:
- std::map<std::string, std::string> mCacheName;
+ using cache_map_t = std::unordered_map<std::string, std::string>;
+ cache_map_t mCacheName;
class Impl;
Impl& impl;
diff --git a/indra/llmessage/llexperiencecache.cpp b/indra/llmessage/llexperiencecache.cpp
index 06cb1152a3..07d11932bc 100644
--- a/indra/llmessage/llexperiencecache.cpp
+++ b/indra/llmessage/llexperiencecache.cpp
@@ -114,9 +114,7 @@ void LLExperienceCache::initSingleton()
constexpr size_t CORO_QUEUE_SIZE = 2048;
LLCoprocedureManager::instance().initializePool("ExpCache", CORO_QUEUE_SIZE);
- LLCoros::instance().launch("LLExperienceCache::idleCoro",
- boost::bind(&LLExperienceCache::idleCoro, this));
-
+ LLCoros::instance().launch("LLExperienceCache::idleCoro", LLExperienceCache::idleCoro);
}
void LLExperienceCache::cleanup()
@@ -248,6 +246,7 @@ const LLExperienceCache::cache_t& LLExperienceCache::getCached()
return mCache;
}
+// static because used by coroutine and can outlive the instance
void LLExperienceCache::requestExperiencesCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t &httpAdapter, std::string url, RequestQueue_t requests)
{
LLCore::HttpRequest::ptr_t httpRequest = std::make_shared<LLCore::HttpRequest>();
@@ -256,6 +255,13 @@ void LLExperienceCache::requestExperiencesCoro(LLCoreHttpUtil::HttpCoroutineAdap
LLSD result = httpAdapter->getAndSuspend(httpRequest, url);
+ if (sShutdown)
+ {
+ return;
+ }
+
+ LLExperienceCache* self = LLExperienceCache::getInstance();
+
LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
@@ -267,7 +273,7 @@ void LLExperienceCache::requestExperiencesCoro(LLCoreHttpUtil::HttpCoroutineAdap
// build dummy entries for the failed requests
for (RequestQueue_t::const_iterator it = requests.begin(); it != requests.end(); ++it)
{
- LLSD exp = get(*it);
+ LLSD exp = self->get(*it);
//leave the properties alone if we already have a cache entry for this xp
if (exp.isUndefined())
{
@@ -280,7 +286,7 @@ void LLExperienceCache::requestExperiencesCoro(LLCoreHttpUtil::HttpCoroutineAdap
exp["error"] = (LLSD::Integer)status.getType();
exp[QUOTA] = DEFAULT_QUOTA;
- processExperience(*it, exp);
+ self->processExperience(*it, exp);
}
return;
}
@@ -296,7 +302,7 @@ void LLExperienceCache::requestExperiencesCoro(LLCoreHttpUtil::HttpCoroutineAdap
LL_DEBUGS("ExperienceCache") << "Received result for " << public_key
<< " display '" << row[LLExperienceCache::NAME].asString() << "'" << LL_ENDL;
- processExperience(public_key, row);
+ self->processExperience(public_key, row);
}
LLSD error_ids = result["error_ids"];
@@ -312,7 +318,7 @@ void LLExperienceCache::requestExperiencesCoro(LLCoreHttpUtil::HttpCoroutineAdap
exp[MISSING] = true;
exp[QUOTA] = DEFAULT_QUOTA;
- processExperience(id, exp);
+ self->processExperience(id, exp);
LL_WARNS("ExperienceCache") << "LLExperienceResponder::result() error result for " << id << LL_ENDL;
}
@@ -363,7 +369,7 @@ void LLExperienceCache::requestExperiences()
if (mRequestQueue.empty() || (ostr.tellp() > EXP_URL_SEND_THRESHOLD))
{ // request is placed in the coprocedure pool for the ExpCache cache. Throttling is done by the pool itself.
LLCoprocedureManager::instance().enqueueCoprocedure("ExpCache", "RequestExperiences",
- boost::bind(&LLExperienceCache::requestExperiencesCoro, this, _1, ostr.str(), requests) );
+ boost::bind(&LLExperienceCache::requestExperiencesCoro, _1, ostr.str(), requests) );
ostr.str(std::string());
ostr << urlBase << "?page_size=" << PAGE_SIZE1;
@@ -395,7 +401,7 @@ void LLExperienceCache::setCapabilityQuery(LLExperienceCache::CapabilityQuery_t
mCapability = queryfn;
}
-
+// static, because coro can outlive the instance
void LLExperienceCache::idleCoro()
{
const F32 SECS_BETWEEN_REQUESTS = 0.5f;
@@ -404,14 +410,15 @@ void LLExperienceCache::idleCoro()
LL_INFOS("ExperienceCache") << "Launching Experience cache idle coro." << LL_ENDL;
do
{
- if (mEraseExpiredTimer.checkExpirationAndReset(ERASE_EXPIRED_TIMEOUT))
+ LLExperienceCache* self = LLExperienceCache::getInstance();
+ if (self->mEraseExpiredTimer.checkExpirationAndReset(ERASE_EXPIRED_TIMEOUT))
{
- eraseExpired();
+ self->eraseExpired();
}
- if (!mRequestQueue.empty())
+ if (!self->mRequestQueue.empty())
{
- requestExperiences();
+ self->requestExperiences();
}
llcoro::suspendUntilTimeout(SECS_BETWEEN_REQUESTS);
diff --git a/indra/llmessage/llexperiencecache.h b/indra/llmessage/llexperiencecache.h
index 4b344347d5..9ecdb9efca 100644
--- a/indra/llmessage/llexperiencecache.h
+++ b/indra/llmessage/llexperiencecache.h
@@ -144,9 +144,9 @@ private:
std::string mCacheFileName;
static bool sShutdown; // control for coroutines, they exist out of LLExperienceCache's scope, so they need a static control
- void idleCoro();
+ static void idleCoro();
void eraseExpired();
- void requestExperiencesCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t &, std::string, RequestQueue_t);
+ static void requestExperiencesCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t &, std::string, RequestQueue_t);
void requestExperiences();
void fetchAssociatedExperienceCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t &, LLUUID, LLUUID, std::string, ExperienceGetFn_t);
diff --git a/indra/llphysicsextensionsos/llconvexdecompositionvhacd.cpp b/indra/llphysicsextensionsos/llconvexdecompositionvhacd.cpp
index 78876f9f36..b7c4b5e591 100644
--- a/indra/llphysicsextensionsos/llconvexdecompositionvhacd.cpp
+++ b/indra/llphysicsextensionsos/llconvexdecompositionvhacd.cpp
@@ -75,10 +75,7 @@ LLCDResult LLConvexDecompositionVHACD::quitSystem()
LLConvexDecompositionVHACD::LLConvexDecompositionVHACD()
{
- //Create our vhacd instance and setup default parameters
- mVHACD = VHACD::CreateVHACD();
-
- mVHACDParameters.m_callback = &mVHACDCallback;
+ // Setup default parameters
mVHACDParameters.m_logger = &mVHACDLogger;
mDecompStages[0].mName = "Analyze";
@@ -206,27 +203,33 @@ LLConvexDecompositionVHACD::LLConvexDecompositionVHACD()
LLConvexDecompositionVHACD::~LLConvexDecompositionVHACD()
{
- mBoundDecomp = nullptr;
- mDecompData.clear();
-
- mVHACD->Release();
+ {
+ LLMutexLock lock(&mDecompDataMutex);
+ mBoundDecompID = INVALID_DECOMP_ID;
+ mDecompData.clear();
+ }
}
void LLConvexDecompositionVHACD::genDecomposition(int& decomp)
{
- int new_decomp_id = static_cast<int>(mDecompData.size()) + 1;
- mDecompData[new_decomp_id] = LLDecompData();
- decomp = new_decomp_id;
+ LLMutexLock lock(&mDecompDataMutex);
+
+ mDecompData[mNextDecompID] = std::make_shared<LLDecompData>();
+ decomp = mNextDecompID;
+
+ ++mNextDecompID; // Increment decomposition ID. Never reuse to protect downstream consumers from misuse
}
void LLConvexDecompositionVHACD::deleteDecomposition(int decomp)
{
+ LLMutexLock lock(&mDecompDataMutex);
+
auto iter = mDecompData.find(decomp);
if (iter != mDecompData.end())
{
- if (mBoundDecomp == &iter->second)
+ if (mBoundDecompID == decomp)
{
- mBoundDecomp = nullptr;
+ mBoundDecompID = INVALID_DECOMP_ID;
}
mDecompData.erase(iter);
}
@@ -234,29 +237,48 @@ void LLConvexDecompositionVHACD::deleteDecomposition(int decomp)
void LLConvexDecompositionVHACD::bindDecomposition(int decomp)
{
- auto iter = mDecompData.find(decomp);
- if (iter != mDecompData.end())
+ LLMutexLock lock(&mDecompDataMutex);
+
+ if (mDecompData.contains(decomp))
{
- mBoundDecomp = &iter->second;
+ mBoundDecompID = decomp;
}
else
{
LL_WARNS() << "Failed to bind unknown decomposition: " << decomp << LL_ENDL;
- mBoundDecomp = nullptr;
+ mBoundDecompID = INVALID_DECOMP_ID;
}
}
+LLConvexDecompositionVHACD::data_ptr_t LLConvexDecompositionVHACD::getBoundDecomp()
+{
+ data_ptr_t bound_decomp;
+ {
+ LLMutexLock lock(&mDecompDataMutex);
+ auto it = mDecompData.find(mBoundDecompID);
+ if (it != mDecompData.end())
+ {
+ bound_decomp = it->second; // Take a copy of the shared_ptr to avoid potential deletion
+ }
+ }
+ return bound_decomp;
+}
+
LLCDResult LLConvexDecompositionVHACD::setParam(const char* name, float val)
{
- if (name == std::string("Num Hulls"))
+ LLMutexLock lock(&mParamsMutex);
+
+ using namespace std::literals;
+
+ if (name == "Num Hulls"sv)
{
mVHACDParameters.m_maxConvexHulls = llclamp(ll_round(val), 1, MAX_HULLS);
}
- else if (name == std::string("Num Vertices"))
+ else if (name == "Num Vertices"sv)
{
mVHACDParameters.m_maxNumVerticesPerCH = llclamp(ll_round(val), 3, MAX_VERTICES_PER_HULL);
}
- else if (name == std::string("Error Tolerance"))
+ else if (name == "Error Tolerance"sv)
{
mVHACDParameters.m_minimumVolumePercentErrorAllowed = val;
}
@@ -270,11 +292,15 @@ LLCDResult LLConvexDecompositionVHACD::setParam(const char* name, bool val)
LLCDResult LLConvexDecompositionVHACD::setParam(const char* name, int val)
{
- if (name == std::string("Fill Mode"))
+ LLMutexLock lock(&mParamsMutex);
+
+ using namespace std::literals;
+
+ if (name == "Fill Mode"sv)
{
mVHACDParameters.m_fillMode = (VHACD::FillMode)val;
}
- else if (name == std::string("Voxel Resolution"))
+ else if (name == "Voxel Resolution"sv)
{
mVHACDParameters.m_resolution = val;
}
@@ -283,19 +309,21 @@ LLCDResult LLConvexDecompositionVHACD::setParam(const char* name, int val)
LLCDResult LLConvexDecompositionVHACD::setMeshData( const LLCDMeshData* data, bool vertex_based )
{
- if (!mBoundDecomp)
+ data_ptr_t bound_decomp = getBoundDecomp();
+ if (!bound_decomp)
{
return LLCD_NULL_PTR;
}
- return mBoundDecomp->mSourceMesh.from(data, vertex_based);
+ return bound_decomp->mSourceMesh.from(data, vertex_based);
}
LLCDResult LLConvexDecompositionVHACD::registerCallback(int stage, llcdCallbackFunc callback )
{
if (stage == 0)
{
- mVHACDCallback.setCallbackFunc(callback);
+ LLMutexLock lock(&mParamsMutex);
+ mCurrentCallbackFunc = callback;
return LLCD_OK;
}
else
@@ -306,44 +334,68 @@ LLCDResult LLConvexDecompositionVHACD::registerCallback(int stage, llcdCallbackF
LLCDResult LLConvexDecompositionVHACD::executeStage(int stage)
{
- if (!mBoundDecomp)
+ if (stage != 0)
+ {
+ return LLCD_INVALID_STAGE;
+ }
+
+ data_ptr_t bound_decomp = getBoundDecomp();
+ if (!bound_decomp)
{
return LLCD_NULL_PTR;
}
- if (stage != 0)
+ bound_decomp->mDecomposedHulls.clear();
+
+ const auto& decomp_mesh = bound_decomp->mSourceMesh;
+
+ VHACDCallback callbacks;
+ VHACD::IVHACD::Parameters current_params;
{
- return LLCD_INVALID_STAGE;
+ LLMutexLock lock(&mParamsMutex);
+
+ current_params = mVHACDParameters;
+ callbacks.setCallbackFunc(mCurrentCallbackFunc);
+ }
+ current_params.m_callback = &callbacks;
+
+ auto vhacd_impl = VHACD::CreateVHACD();
+ if (!vhacd_impl)
+ {
+ LL_WARNS() << "Failed to create VHACD instance" << LL_ENDL;
+ return LLCD_NULL_PTR;
}
- mBoundDecomp->mDecomposedHulls.clear();
- const auto& decomp_mesh = mBoundDecomp->mSourceMesh;
- if (!mVHACD->Compute((const double* const)decomp_mesh.mVertices.data(), static_cast<uint32_t>(decomp_mesh.mVertices.size()), (const uint32_t* const)decomp_mesh.mIndices.data(), static_cast<uint32_t>(decomp_mesh.mIndices.size()), mVHACDParameters))
+ if (!vhacd_impl->Compute((const double*)decomp_mesh.mVertices.data(), static_cast<uint32_t>(decomp_mesh.mVertices.size()),
+ (const uint32_t*)decomp_mesh.mIndices.data(), static_cast<uint32_t>(decomp_mesh.mIndices.size()),
+ current_params))
{
+ vhacd_impl->Release();
return LLCD_INVALID_HULL_DATA;
}
- uint32_t num_nulls = mVHACD->GetNConvexHulls();
- if (num_nulls == 0)
+ uint32_t num_convex_hulls = vhacd_impl->GetNConvexHulls();
+ if (num_convex_hulls == 0)
{
+ vhacd_impl->Release();
return LLCD_INVALID_HULL_DATA;
}
- for (uint32_t i = 0; num_nulls > i; ++i)
+ for (uint32_t i = 0; num_convex_hulls > i; ++i)
{
VHACD::IVHACD::ConvexHull ch;
- if (!mVHACD->GetConvexHull(i, ch))
+ if (!vhacd_impl->GetConvexHull(i, ch))
continue;
LLConvexMesh out_mesh;
out_mesh.setVertices(ch.m_points);
out_mesh.setIndices(ch.m_triangles);
- mBoundDecomp->mDecomposedHulls.push_back(std::move(out_mesh));
+ bound_decomp->mDecomposedHulls.push_back(std::move(out_mesh));
}
- mVHACD->Clean();
+ vhacd_impl->Release();
return LLCD_OK;
}
@@ -351,19 +403,21 @@ LLCDResult LLConvexDecompositionVHACD::executeStage(int stage)
LLCDResult LLConvexDecompositionVHACD::buildSingleHull()
{
LL_INFOS() << "Building single hull mesh" << LL_ENDL;
- if (!mBoundDecomp || mBoundDecomp->mSourceMesh.mVertices.empty())
+
+ data_ptr_t bound_decomp = getBoundDecomp();
+ if (!bound_decomp || bound_decomp->mSourceMesh.mVertices.empty())
{
return LLCD_NULL_PTR;
}
- mBoundDecomp->mSingleHullMesh.clear();
+ bound_decomp->mSingleHullMesh.clear();
VHACD::QuickHull quickhull;
- uint32_t num_tris = quickhull.ComputeConvexHull(mBoundDecomp->mSourceMesh.mVertices, MAX_VERTICES_PER_HULL);
+ uint32_t num_tris = quickhull.ComputeConvexHull(bound_decomp->mSourceMesh.mVertices, MAX_VERTICES_PER_HULL);
if (num_tris > 0)
{
- mBoundDecomp->mSingleHullMesh.setVertices(quickhull.GetVertices());
- mBoundDecomp->mSingleHullMesh.setIndices(quickhull.GetIndices());
+ bound_decomp->mSingleHullMesh.setVertices(quickhull.GetVertices());
+ bound_decomp->mSingleHullMesh.setIndices(quickhull.GetIndices());
return LLCD_OK;
}
@@ -373,29 +427,31 @@ LLCDResult LLConvexDecompositionVHACD::buildSingleHull()
int LLConvexDecompositionVHACD::getNumHullsFromStage(int stage)
{
- if (!mBoundDecomp || stage != 0)
+ data_ptr_t bound_decomp = getBoundDecomp();
+ if (!bound_decomp || stage != 0)
{
return 0;
}
- return narrow(mBoundDecomp->mDecomposedHulls.size());
+ return narrow(bound_decomp->mDecomposedHulls.size());
}
LLCDResult LLConvexDecompositionVHACD::getSingleHull( LLCDHull* hullOut )
{
memset( hullOut, 0, sizeof(LLCDHull) );
- if (!mBoundDecomp)
+ data_ptr_t bound_decomp = getBoundDecomp();
+ if (!bound_decomp)
{
return LLCD_NULL_PTR;
}
- if (mBoundDecomp->mSingleHullMesh.vertices.empty())
+ if (bound_decomp->mSingleHullMesh.vertices.empty())
{
return LLCD_INVALID_HULL_DATA;
}
- mBoundDecomp->mSingleHullMesh.to(hullOut);
+ bound_decomp->mSingleHullMesh.to(hullOut);
return LLCD_OK;
}
@@ -403,7 +459,8 @@ LLCDResult LLConvexDecompositionVHACD::getHullFromStage( int stage, int hull, LL
{
memset( hullOut, 0, sizeof(LLCDHull) );
- if (!mBoundDecomp)
+ data_ptr_t bound_decomp = getBoundDecomp();
+ if (!bound_decomp)
{
return LLCD_NULL_PTR;
}
@@ -413,19 +470,21 @@ LLCDResult LLConvexDecompositionVHACD::getHullFromStage( int stage, int hull, LL
return LLCD_INVALID_STAGE;
}
- if (mBoundDecomp->mDecomposedHulls.empty() || mBoundDecomp->mDecomposedHulls.size() <= hull)
+ if (bound_decomp->mDecomposedHulls.empty() || S32(bound_decomp->mDecomposedHulls.size()) <= hull)
{
return LLCD_REQUEST_OUT_OF_RANGE;
}
- mBoundDecomp->mDecomposedHulls[hull].to(hullOut);
+ bound_decomp->mDecomposedHulls[hull].to(hullOut);
return LLCD_OK;
}
LLCDResult LLConvexDecompositionVHACD::getMeshFromStage( int stage, int hull, LLCDMeshData* meshDataOut )
{
memset( meshDataOut, 0, sizeof(LLCDMeshData));
- if (!mBoundDecomp)
+
+ data_ptr_t bound_decomp = getBoundDecomp();
+ if (!bound_decomp)
{
return LLCD_NULL_PTR;
}
@@ -435,12 +494,12 @@ LLCDResult LLConvexDecompositionVHACD::getMeshFromStage( int stage, int hull, LL
return LLCD_INVALID_STAGE;
}
- if (mBoundDecomp->mDecomposedHulls.empty() || mBoundDecomp->mDecomposedHulls.size() <= hull)
+ if (bound_decomp->mDecomposedHulls.empty() || S32(bound_decomp->mDecomposedHulls.size()) <= hull)
{
return LLCD_REQUEST_OUT_OF_RANGE;
}
- mBoundDecomp->mDecomposedHulls[hull].to(meshDataOut);
+ bound_decomp->mDecomposedHulls[hull].to(meshDataOut);
return LLCD_OK;
}
diff --git a/indra/llphysicsextensionsos/llconvexdecompositionvhacd.h b/indra/llphysicsextensionsos/llconvexdecompositionvhacd.h
index 675356629c..27c867704e 100644
--- a/indra/llphysicsextensionsos/llconvexdecompositionvhacd.h
+++ b/indra/llphysicsextensionsos/llconvexdecompositionvhacd.h
@@ -31,6 +31,7 @@
#include "llconvexdecomposition.h"
#include "llsingleton.h"
#include "llmath.h"
+#include "llmutex.h"
#include <vector>
@@ -323,14 +324,25 @@ private:
std::vector<LLConvexMesh> mDecomposedHulls;
};
- std::unordered_map<int, LLDecompData> mDecompData;
+ using data_ptr_t = std::shared_ptr<LLDecompData>;
- LLDecompData* mBoundDecomp = nullptr;
+ data_ptr_t getBoundDecomp();
+
+ // MUST lock before accessing mDecompData mBoundDecompID or mNextDecompID
+ LLMutex mDecompDataMutex;
+
+ static constexpr int INVALID_DECOMP_ID = -1;
+
+ int mBoundDecompID = INVALID_DECOMP_ID;
+ int mNextDecompID = 0; // Only for use inside genDecomposition.
+
+ std::unordered_map<int, data_ptr_t> mDecompData;
- VHACD::IVHACD* mVHACD = nullptr;
- VHACDCallback mVHACDCallback;
VHACDLogger mVHACDLogger;
+
+ LLMutex mParamsMutex;
VHACD::IVHACD::Parameters mVHACDParameters;
+ llcdCallbackFunc mCurrentCallbackFunc;
LLConvexMesh mMeshFromHullData;
LLConvexMesh mSingleHullMeshFromMeshData;
diff --git a/indra/llprimitive/llgltfmaterial.cpp b/indra/llprimitive/llgltfmaterial.cpp
index 930222e3db..b2cd1dc597 100644
--- a/indra/llprimitive/llgltfmaterial.cpp
+++ b/indra/llprimitive/llgltfmaterial.cpp
@@ -214,7 +214,7 @@ std::string LLGLTFMaterial::asJSON(bool prettyprint) const
// to WriteGltfSceneToStream in the viewer.
gltf.WriteGltfSceneToStream(&model_out, str, prettyprint, false);
- return str.str();
+ return std::move(str).str();
}
void LLGLTFMaterial::setFromModel(const tinygltf::Model& model, S32 mat_index)
diff --git a/indra/llprimitive/llmaterialid.h b/indra/llprimitive/llmaterialid.h
index cec0965441..3ed80eaab9 100644
--- a/indra/llprimitive/llmaterialid.h
+++ b/indra/llprimitive/llmaterialid.h
@@ -63,15 +63,11 @@ public:
static const LLMaterialID null;
- // Returns a 64 bits digest of the material Id, by XORing its two 64 bits
- // long words. HB
- inline U64 getDigest64() const
- {
- U64* tmp = (U64*)mID;
- return tmp[0] ^ tmp[1];
- }
-
private:
+ // definitions follow class
+ friend std::hash<LLMaterialID>;
+ friend size_t hash_value(const LLMaterialID&) noexcept;
+
void parseFromBinary(const LLSD::Binary& pMaterialID);
int compareToOtherMaterialID(const LLMaterialID& pOtherMaterialID) const;
@@ -85,15 +81,27 @@ namespace std
{
inline size_t operator()(const LLMaterialID& id) const noexcept
{
- return (size_t)id.getDigest64();
+ size_t h = 0;
+ // Golden ratio hash with avalanche mixing
+ // Process 8 bytes at a time by manually constructing 64-bit values
+ // Shift by 31: mixes upper half into lower half for better bit distribution
+ // Shift by 47: ensures highest bits influence final hash output
+ for (int i = 0; i < MATERIAL_ID_SIZE; i += 8) {
+ size_t chunk = (size_t)id.mID[i] | ((size_t)id.mID[i + 1] << 8) |
+ ((size_t)id.mID[i+2] << 16) | ((size_t)id.mID[i+3] << 24) |
+ ((size_t)id.mID[i+4] << 32) | ((size_t)id.mID[i+5] << 40) |
+ ((size_t)id.mID[i + 6] << 48) | ((size_t)id.mID[i + 7] << 56);
+ h ^= (chunk * 0x9e3779b97f4a7c15ULL) ^ (h >> 31) ^ (h >> 47);
+ }
+ return h;
}
};
}
-// For use with boost containers.
+// For use with boost::container_hash
inline size_t hash_value(const LLMaterialID& id) noexcept
{
- return (size_t)id.getDigest64();
+ return std::hash<LLMaterialID>{}(id);
}
#endif // LL_LLMATERIALID_H
diff --git a/indra/llrender/llfontfreetype.h b/indra/llrender/llfontfreetype.h
index a9b3a944ee..f7600e40a3 100644
--- a/indra/llrender/llfontfreetype.h
+++ b/indra/llrender/llfontfreetype.h
@@ -27,13 +27,14 @@
#ifndef LL_LLFONTFREETYPE_H
#define LL_LLFONTFREETYPE_H
-#include <boost/unordered_map.hpp>
#include "llpointer.h"
#include "llstl.h"
#include "llimagegl.h"
#include "llfontbitmapcache.h"
+#include <unordered_map>
+
// Hack. FT_Face is just a typedef for a pointer to a struct,
// but there's no simple forward declarations file for FreeType,
// and the main include file is 200K.
@@ -184,7 +185,7 @@ private:
fallback_font_vector_t mFallbackFonts; // A list of fallback fonts to look for glyphs in (for Unicode chars)
// *NOTE: the same glyph can be present with multiple representations (but the pointer is always unique)
- typedef boost::unordered_multimap<llwchar, LLFontGlyphInfo*> char_glyph_info_map_t;
+ typedef std::unordered_multimap<llwchar, LLFontGlyphInfo*> char_glyph_info_map_t;
mutable char_glyph_info_map_t mCharGlyphInfoMap; // Information about glyph location in bitmap
mutable LLFontBitmapCache* mFontBitmapCachep;
diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp
index 25277f1341..5357a79bae 100644
--- a/indra/llrender/llgl.cpp
+++ b/indra/llrender/llgl.cpp
@@ -2429,7 +2429,7 @@ void clear_glerror()
//
// Static members
-boost::unordered_map<LLGLenum, LLGLboolean> LLGLState::sStateMap;
+std::unordered_map<LLGLenum, LLGLboolean> LLGLState::sStateMap;
GLboolean LLGLDepthTest::sDepthEnabled = GL_FALSE; // OpenGL default
GLenum LLGLDepthTest::sDepthFunc = GL_LESS; // OpenGL default
@@ -2471,7 +2471,7 @@ void LLGLState::resetTextureStates()
void LLGLState::dumpStates()
{
LL_INFOS("RenderState") << "GL States:" << LL_ENDL;
- for (boost::unordered_map<LLGLenum, LLGLboolean>::iterator iter = sStateMap.begin();
+ for (std::unordered_map<LLGLenum, LLGLboolean>::iterator iter = sStateMap.begin();
iter != sStateMap.end(); ++iter)
{
LL_INFOS("RenderState") << llformat(" 0x%04x : %s",(S32)iter->first,iter->second?"true":"false") << LL_ENDL;
@@ -2503,7 +2503,7 @@ void LLGLState::checkStates(GLboolean writeAlpha)
//llassert_always(colorMask[2]);
// llassert_always(colorMask[3] == writeAlpha);
- for (boost::unordered_map<LLGLenum, LLGLboolean>::iterator iter = sStateMap.begin();
+ for (std::unordered_map<LLGLenum, LLGLboolean>::iterator iter = sStateMap.begin();
iter != sStateMap.end(); ++iter)
{
LLGLenum state = iter->first;
diff --git a/indra/llrender/llgl.h b/indra/llrender/llgl.h
index dd30c82981..469802657a 100644
--- a/indra/llrender/llgl.h
+++ b/indra/llrender/llgl.h
@@ -31,7 +31,7 @@
#include <functional>
#include <string>
-#include <boost/unordered_map.hpp>
+#include <unordered_map>
#include <list>
#include "llglheaders.h"
@@ -261,7 +261,7 @@ public:
static void checkStates(GLboolean writeAlpha = GL_TRUE);
protected:
- static boost::unordered_map<LLGLenum, LLGLboolean> sStateMap;
+ static std::unordered_map<LLGLenum, LLGLboolean> sStateMap;
public:
enum { CURRENT_STATE = -2, DISABLED_STATE = 0, ENABLED_STATE = 1 };
diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp
index f609fe8105..da913ee9d6 100644
--- a/indra/llui/llfloater.cpp
+++ b/indra/llui/llfloater.cpp
@@ -239,7 +239,7 @@ void LLFloater::initClass()
}
// defaults for floater param block pulled from widgets/floater.xml
-static LLWidgetNameRegistry::StaticRegistrar sRegisterFloaterParams(&typeid(LLFloater::Params), "floater");
+static LLWidgetNameRegistry::StaticRegistrar sRegisterFloaterParams(typeid(LLFloater::Params), "floater");
LLFloater::LLFloater(const LLSD& key, const LLFloater::Params& p)
: LLPanel(), // intentionally do not pass params here, see initFromParams
diff --git a/indra/llui/llfloaterreg.cpp b/indra/llui/llfloaterreg.cpp
index a818e72f59..c18495ce71 100644
--- a/indra/llui/llfloaterreg.cpp
+++ b/indra/llui/llfloaterreg.cpp
@@ -40,9 +40,9 @@
LLFloaterReg::instance_list_t LLFloaterReg::sNullInstanceList;
LLFloaterReg::instance_map_t LLFloaterReg::sInstanceMap;
LLFloaterReg::build_map_t LLFloaterReg::sBuildMap;
-std::map<std::string, std::string, std::less<>> LLFloaterReg::sGroupMap;
+LLFloaterReg::group_map_t LLFloaterReg::sGroupMap;
bool LLFloaterReg::sBlockShowFloaters = false;
-std::set<std::string, std::less<>> LLFloaterReg::sAlwaysShowableList;
+LLFloaterReg::always_showable_t LLFloaterReg::sAlwaysShowableList;
static LLFloaterRegListener sFloaterRegListener;
@@ -96,11 +96,8 @@ LLFloater* LLFloaterReg::getLastFloaterCascading()
candidate_rect.mTop = 100000;
LLFloater* candidate_floater = NULL;
- std::map<std::string,std::string>::const_iterator it = sGroupMap.begin(), it_end = sGroupMap.end();
- for( ; it != it_end; ++it)
+ for (const auto& [floater_name, group_name] : sGroupMap)
{
- const std::string& group_name = it->second;
-
instance_list_t& instances = sInstanceMap[group_name];
for (LLFloater* inst : instances)
@@ -604,17 +601,11 @@ U32 LLFloaterReg::getVisibleFloaterInstanceCount()
{
U32 count = 0;
- std::map<std::string,std::string>::const_iterator it = sGroupMap.begin(), it_end = sGroupMap.end();
- for( ; it != it_end; ++it)
+ for (const auto& [floater_name, group_name] : sGroupMap)
{
- const std::string& group_name = it->second;
-
instance_list_t& instances = sInstanceMap[group_name];
-
- for (instance_list_t::const_iterator iter = instances.begin(); iter != instances.end(); ++iter)
+ for (LLFloater* inst : instances)
{
- LLFloater* inst = *iter;
-
if (inst->getVisible() && !inst->isMinimized())
{
count++;
diff --git a/indra/llui/llfloaterreg.h b/indra/llui/llfloaterreg.h
index 24d1476dda..71a11b6f42 100644
--- a/indra/llui/llfloaterreg.h
+++ b/indra/llui/llfloaterreg.h
@@ -29,9 +29,11 @@
/// llcommon
#include "llrect.h"
#include "llsd.h"
+#include "llstl.h"
#include <functional>
#include <list>
+#include <unordered_set>
//*******************************************************
//
@@ -51,26 +53,29 @@ public:
// 2) We can change the key of a floater without altering the list.
typedef std::list<LLFloater*> instance_list_t;
typedef const instance_list_t const_instance_list_t;
- typedef std::map<std::string, instance_list_t, std::less<>> instance_map_t;
+ typedef std::unordered_map<std::string, instance_list_t, ll::string_hash, std::equal_to<>> instance_map_t;
struct BuildData
{
LLFloaterBuildFunc mFunc;
std::string mFile;
};
- typedef std::map<std::string, BuildData, std::less<>> build_map_t;
+ typedef std::unordered_map<std::string, BuildData, ll::string_hash, std::equal_to<>> build_map_t;
private:
friend class LLFloaterRegListener;
static instance_list_t sNullInstanceList;
static instance_map_t sInstanceMap;
static build_map_t sBuildMap;
- static std::map<std::string, std::string, std::less<>> sGroupMap;
+
+ using group_map_t = std::unordered_map<std::string, std::string, ll::string_hash, std::equal_to<>>;
+ static group_map_t sGroupMap;
static bool sBlockShowFloaters;
/**
* Defines list of floater names that can be shown despite state of sBlockShowFloaters.
*/
- static std::set<std::string, std::less<>> sAlwaysShowableList;
+ using always_showable_t = std::unordered_set<std::string, ll::string_hash, std::equal_to<>>;
+ static always_showable_t sAlwaysShowableList;
public:
// Registration
diff --git a/indra/llui/llfolderviewitem.cpp b/indra/llui/llfolderviewitem.cpp
index 878f1cb856..dafbca7433 100644
--- a/indra/llui/llfolderviewitem.cpp
+++ b/indra/llui/llfolderviewitem.cpp
@@ -28,6 +28,7 @@
#include "llflashtimer.h"
#include "linden_common.h"
+#include "llapp.h"
#include "llfolderviewitem.h"
#include "llfolderview.h"
#include "llfolderviewmodel.h"
@@ -1884,6 +1885,11 @@ void LLFolderViewFolder::updateHasFavorites(bool new_childs_value)
void LLFolderViewFolder::onIdleUpdateFavorites(void* data)
{
LLFolderViewFolder* self = reinterpret_cast<LLFolderViewFolder*>(data);
+ if (gDisconnected || !self)
+ {
+ return;
+ }
+
if (self->mFavoritesDirtyFlags == FAVORITE_CLEANUP)
{
// parent or child already processed the update, clean the callback
@@ -2359,9 +2365,10 @@ bool LLFolderViewFolder::handleDoubleClick( S32 x, S32 y, MASK mask )
{
// navigating is going to destroy views and change children
// delay it untill handleDoubleClick processing is complete
- doOnIdleOneTime([this]()
- {
- getViewModelItem()->navigateToFolder(false);
+ LLPointer<LLFolderViewModelItem> view_model_item = getViewModelItem();
+ doOnIdleOneTime([view_model_item]() mutable
+ {;
+ view_model_item->navigateToFolder(false);
});
}
return true;
diff --git a/indra/llui/llfunctorregistry.h b/indra/llui/llfunctorregistry.h
index 953963b683..40a3e439a6 100644
--- a/indra/llui/llfunctorregistry.h
+++ b/indra/llui/llfunctorregistry.h
@@ -29,8 +29,9 @@
#define LL_LLFUNCTORREGISTRY_H
#include <string>
-#include <map>
+#include <unordered_map>
+#include "llstring.h"
#include "llsd.h"
#include "llsingleton.h"
@@ -56,7 +57,7 @@ class LLFunctorRegistry : public LLSingleton<LLFunctorRegistry<FUNCTOR_TYPE> >
public:
typedef FUNCTOR_TYPE ResponseFunctor;
- typedef typename std::map<std::string, FUNCTOR_TYPE> FunctorMap;
+ typedef typename std::unordered_map<std::string, FUNCTOR_TYPE, ll::string_hash, std::equal_to<>> FunctorMap;
bool registerFunctor(const std::string& name, ResponseFunctor f)
{
diff --git a/indra/llui/llkeywords.h b/indra/llui/llkeywords.h
index 5892238593..53b5435324 100644
--- a/indra/llui/llkeywords.h
+++ b/indra/llui/llkeywords.h
@@ -194,7 +194,7 @@ protected:
token_list_t mLineTokenList;
token_list_t mDelimiterTokenList;
- typedef std::map<std::string, std::string, std::less<>> element_attributes_t;
+ typedef std::unordered_map<std::string, std::string, ll::string_hash, std::equal_to<>> element_attributes_t;
typedef element_attributes_t::const_iterator attribute_iterator_t;
element_attributes_t mAttributes;
std::string getAttribute(std::string_view key);
diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp
index 2ca2454040..6ba31c251e 100644
--- a/indra/llui/llmenugl.cpp
+++ b/indra/llui/llmenugl.cpp
@@ -4404,3 +4404,17 @@ bool LLContextMenu::addChild(LLView* view, S32 tab_group)
return addContextChild(view, tab_group);
}
+void LLContextMenu::deleteAllChildren()
+{
+ mHoverItem = nullptr;
+ LLMenuGL::deleteAllChildren();
+}
+
+void LLContextMenu::removeChild(LLView* ctrl)
+{
+ if (ctrl == mHoverItem)
+ {
+ mHoverItem = nullptr;
+ }
+ LLMenuGL::removeChild(ctrl);
+}
diff --git a/indra/llui/llmenugl.h b/indra/llui/llmenugl.h
index eacf2c59d4..bca0a731fc 100644
--- a/indra/llui/llmenugl.h
+++ b/indra/llui/llmenugl.h
@@ -730,6 +730,8 @@ public:
virtual bool handleRightMouseUp ( S32 x, S32 y, MASK mask );
virtual bool addChild (LLView* view, S32 tab_group = 0);
+ /*virtual*/ void deleteAllChildren();
+ /*virtual*/ void removeChild(LLView* ctrl);
LLHandle<LLContextMenu> getHandle() { return getDerivedHandle<LLContextMenu>(); }
diff --git a/indra/llui/llnotifications.cpp b/indra/llui/llnotifications.cpp
index 0ffe6cff5e..56475a2d8d 100644
--- a/indra/llui/llnotifications.cpp
+++ b/indra/llui/llnotifications.cpp
@@ -1424,6 +1424,7 @@ LLNotificationChannelPtr LLNotifications::getChannel(const std::string& channelN
// this function is called once at construction time, after the object is constructed.
void LLNotifications::initSingleton()
{
+ LL_PROFILE_ZONE_SCOPED;
loadTemplates();
loadVisibilityRules();
createDefaultChannels();
@@ -1436,6 +1437,8 @@ void LLNotifications::cleanupSingleton()
void LLNotifications::createDefaultChannels()
{
+ LL_PROFILE_ZONE_SCOPED;
+
LL_INFOS("Notifications") << "Generating default notification channels" << LL_ENDL;
// now construct the various channels AFTER loading the notifications,
// because the history channel is going to rewrite the stored notifications file
@@ -1578,6 +1581,8 @@ void addPathIfExists(const std::string& new_path, std::vector<std::string>& path
bool LLNotifications::loadTemplates()
{
+ LL_PROFILE_ZONE_SCOPED;
+
LL_INFOS("Notifications") << "Reading notifications template" << LL_ENDL;
// Passing findSkinnedFilenames(constraint=LLDir::ALL_SKINS) makes it
// output all relevant pathnames instead of just the ones from the most
@@ -1663,6 +1668,8 @@ bool LLNotifications::loadTemplates()
bool LLNotifications::loadVisibilityRules()
{
+ LL_PROFILE_ZONE_SCOPED;
+
const std::string xml_filename = "notification_visibility.xml";
// Note that here we're looking for the "en" version, the default
// language, rather than the most localized version of this file.
diff --git a/indra/llui/llnotifications.h b/indra/llui/llnotifications.h
index c7c7435be2..ea1cb7f638 100644
--- a/indra/llui/llnotifications.h
+++ b/indra/llui/llnotifications.h
@@ -946,7 +946,7 @@ public:
typedef std::vector<std::string> TemplateNames;
TemplateNames getTemplateNames() const; // returns a list of notification names
- typedef std::map<std::string, LLNotificationTemplatePtr, std::less<>> TemplateMap;
+ typedef std::unordered_map<std::string, LLNotificationTemplatePtr, ll::string_hash, std::equal_to<>> TemplateMap;
TemplateMap::const_iterator templatesBegin() { return mTemplates.begin(); }
TemplateMap::const_iterator templatesEnd() { return mTemplates.end(); }
@@ -992,7 +992,7 @@ private:
LLNotificationMap mUniqueNotifications;
- typedef std::map<std::string, std::string, std::less<>> GlobalStringMap;
+ typedef std::unordered_map<std::string, std::string, ll::string_hash, std::equal_to<>> GlobalStringMap;
GlobalStringMap mGlobalStrings;
bool mIgnoreAllNotifications;
diff --git a/indra/llui/llpanel.h b/indra/llui/llpanel.h
index fe861dc719..a928997c7d 100644
--- a/indra/llui/llpanel.h
+++ b/indra/llui/llpanel.h
@@ -250,7 +250,7 @@ private:
LLButton* mDefaultBtn;
LLUIString mLabel;
- typedef std::map<std::string, std::string, std::less<>> ui_string_map_t;
+ typedef std::unordered_map<std::string, std::string, ll::string_hash, std::equal_to<>> ui_string_map_t;
ui_string_map_t mUIStrings;
@@ -292,7 +292,7 @@ public:
}
private:
- typedef std::map< std::string, LLPanelClassCreatorFunc, std::less<>> param_name_map_t;
+ typedef std::unordered_map<std::string, LLPanelClassCreatorFunc, ll::string_hash, std::equal_to<>> param_name_map_t;
param_name_map_t mPanelClassesNames;
};
diff --git a/indra/llui/llradiogroup.cpp b/indra/llui/llradiogroup.cpp
index 2aff434612..1dbd9f5b0c 100644
--- a/indra/llui/llradiogroup.cpp
+++ b/indra/llui/llradiogroup.cpp
@@ -67,7 +67,7 @@ protected:
LLSD mPayload; // stores data that this item represents in the radio group
};
-static LLWidgetNameRegistry::StaticRegistrar register_radio_item(&typeid(LLRadioGroup::ItemParams), "radio_item");
+static LLWidgetNameRegistry::StaticRegistrar register_radio_item(typeid(LLRadioGroup::ItemParams), "radio_item");
LLRadioGroup::Params::Params()
: allow_deselect("allow_deselect"),
diff --git a/indra/llui/llrngwriter.cpp b/indra/llui/llrngwriter.cpp
index 1b4008cff2..5b0d2315c1 100644
--- a/indra/llui/llrngwriter.cpp
+++ b/indra/llui/llrngwriter.cpp
@@ -94,7 +94,7 @@ void LLRNGWriter::addDefinition(const std::string& type_name, const LLInitParam:
block.inspectBlock(*this);
// add includes for all possible children
- const std::type_info* type = *LLWidgetTypeRegistry::instance().getValue(type_name);
+ const std::type_index& type = *LLWidgetTypeRegistry::instance().getValue(type_name);
const widget_registry_t* widget_registryp = LLChildRegistryRegistry::instance().getValue(type);
// add include declarations for all valid children
diff --git a/indra/llui/llscrolllistcolumn.cpp b/indra/llui/llscrolllistcolumn.cpp
index a4510d1fc2..b5ba466750 100644
--- a/indra/llui/llscrolllistcolumn.cpp
+++ b/indra/llui/llscrolllistcolumn.cpp
@@ -39,7 +39,7 @@
const S32 MIN_COLUMN_WIDTH = 20;
// defaults for LLScrollColumnHeader param block pulled from widgets/scroll_column_header.xml
-static LLWidgetNameRegistry::StaticRegistrar sRegisterColumnHeaderParams(&typeid(LLScrollColumnHeader::Params), "scroll_column_header");
+static LLWidgetNameRegistry::StaticRegistrar sRegisterColumnHeaderParams(typeid(LLScrollColumnHeader::Params), "scroll_column_header");
//---------------------------------------------------------------------------
// LLScrollColumnHeader
diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp
index 2079ff17fc..24ae5c09e9 100644
--- a/indra/llui/lltextbase.cpp
+++ b/indra/llui/lltextbase.cpp
@@ -129,7 +129,7 @@ struct LLTextBase::line_end_compare
//
// register LLTextBase::Params under name "textbase"
-static LLWidgetNameRegistry::StaticRegistrar sRegisterTextBaseParams(&typeid(LLTextBase::Params), "textbase");
+static LLWidgetNameRegistry::StaticRegistrar sRegisterTextBaseParams(typeid(LLTextBase::Params), "textbase");
LLTextBase::LineSpacingParams::LineSpacingParams()
: multiple("multiple", 1.f),
diff --git a/indra/llui/lltooltip.cpp b/indra/llui/lltooltip.cpp
index 74f03618cf..c5b1b5ba1d 100644
--- a/indra/llui/lltooltip.cpp
+++ b/indra/llui/lltooltip.cpp
@@ -129,7 +129,7 @@ void LLToolTipView::drawStickyRect()
}
// defaults for floater param block pulled from widgets/floater.xml
-static LLWidgetNameRegistry::StaticRegistrar sRegisterInspectorParams(&typeid(LLInspector::Params), "inspector");
+static LLWidgetNameRegistry::StaticRegistrar sRegisterInspectorParams(typeid(LLInspector::Params), "inspector");
//
// LLToolTip
diff --git a/indra/llui/lltrans.h b/indra/llui/lltrans.h
index c5d01e6f8d..4dba4c5c3e 100644
--- a/indra/llui/lltrans.h
+++ b/indra/llui/lltrans.h
@@ -125,7 +125,7 @@ public:
}
private:
- typedef std::map<std::string, LLTransTemplate, std::less<>> template_map_t;
+ typedef std::unordered_map<std::string, LLTransTemplate, ll::string_hash, std::equal_to<>> template_map_t;
static template_map_t sStringTemplates;
static template_map_t sDefaultStringTemplates;
static LLStringUtil::format_map_t sDefaultArgs;
diff --git a/indra/llui/llui.cpp b/indra/llui/llui.cpp
index 38d5720556..0056e73cce 100644
--- a/indra/llui/llui.cpp
+++ b/indra/llui/llui.cpp
@@ -65,7 +65,6 @@
// for XUIParse
#include "llquaternion.h"
-#include <boost/tokenizer.hpp>
#include <boost/algorithm/string/find_iterator.hpp>
#include <boost/algorithm/string/finder.hpp>
@@ -157,6 +156,7 @@ mWindow(NULL), // set later in startup
mRootView(NULL),
mHelpImpl(NULL)
{
+ LL_PROFILE_ZONE_SCOPED;
LLRender2D::createInstance(image_provider);
LLSpellChecker::createInstance();
diff --git a/indra/llui/llui.h b/indra/llui/llui.h
index 2ef64baaf6..091e0ab1cf 100644
--- a/indra/llui/llui.h
+++ b/indra/llui/llui.h
@@ -114,7 +114,7 @@ class LLUI : public LLSimpleton<LLUI>
{
LOG_CLASS(LLUI);
public:
- typedef std::map<std::string, LLControlGroup*, std::less<> > settings_map_t;
+ typedef std::unordered_map<std::string, LLControlGroup*, ll::string_hash, std::equal_to<>> settings_map_t;
LLUI(const settings_map_t &settings,
LLImageProviderInterface* image_provider,
diff --git a/indra/llui/lluicolortable.cpp b/indra/llui/lluicolortable.cpp
index cd062b23b8..90ba6f1ecc 100644
--- a/indra/llui/lluicolortable.cpp
+++ b/indra/llui/lluicolortable.cpp
@@ -198,8 +198,8 @@ LLUIColor LLUIColorTable::getColor(std::string_view name, const LLColor4& defaul
// update user color, loaded colors are parsed on initialization
void LLUIColorTable::setColor(std::string_view name, const LLColor4& color)
{
- auto it = mUserSetColors.lower_bound(name);
- if(it != mUserSetColors.end() && !(mUserSetColors.key_comp()(name, it->first)))
+ auto it = mUserSetColors.find(name);
+ if(it != mUserSetColors.end())
{
it->second = color;
}
@@ -330,9 +330,8 @@ void LLUIColorTable::clearTable(string_color_map_t& table)
// if the color already exists it changes the color
void LLUIColorTable::setColor(std::string_view name, const LLColor4& color, string_color_map_t& table)
{
- string_color_map_t::iterator it = table.lower_bound(name);
- if(it != table.end()
- && !(table.key_comp()(name, it->first)))
+ string_color_map_t::iterator it = table.find(name);
+ if(it != table.end())
{
it->second = color;
}
diff --git a/indra/llui/lluicolortable.h b/indra/llui/lluicolortable.h
index 0c6286e5eb..aff6f59db6 100644
--- a/indra/llui/lluicolortable.h
+++ b/indra/llui/lluicolortable.h
@@ -27,7 +27,7 @@
#ifndef LL_LLUICOLORTABLE_H_
#define LL_LLUICOLORTABLE_H_
-#include <map>
+#include <unordered_map>
#include "llinitparam.h"
#include "llsingleton.h"
@@ -42,7 +42,7 @@ class LLUIColorTable : public LLSingleton<LLUIColorTable>
LOG_CLASS(LLUIColorTable);
// consider using sorted vector, can be much faster
- typedef std::map<std::string, LLUIColor, std::less<>> string_color_map_t;
+ typedef std::unordered_map<std::string, LLUIColor, ll::string_hash, std::equal_to<>> string_color_map_t;
public:
struct ColorParams : LLInitParam::ChoiceBlock<ColorParams>
diff --git a/indra/llui/lluictrlfactory.cpp b/indra/llui/lluictrlfactory.cpp
index 9abccfd9a0..33ffc3dfc6 100644
--- a/indra/llui/lluictrlfactory.cpp
+++ b/indra/llui/lluictrlfactory.cpp
@@ -253,7 +253,7 @@ const LLInitParam::BaseBlock& get_empty_param_block()
// adds a widget and its param block to various registries
//static
-void LLUICtrlFactory::registerWidget(const std::type_info* widget_type, const std::type_info* param_block_type, const std::string& name)
+void LLUICtrlFactory::registerWidget(std::type_index widget_type, std::type_index param_block_type, const std::string& name)
{
// associate parameter block type with template .xml file
std::string* existing_name = LLWidgetNameRegistry::instance().getValue(param_block_type);
diff --git a/indra/llui/lluictrlfactory.h b/indra/llui/lluictrlfactory.h
index fc069c078f..f44b4ba4dc 100644
--- a/indra/llui/lluictrlfactory.h
+++ b/indra/llui/lluictrlfactory.h
@@ -65,7 +65,7 @@ class LLDefaultChildRegistry : public LLChildRegistry<LLDefaultChildRegistry>
// lookup widget name by type
class LLWidgetNameRegistry
-: public LLRegistrySingleton<const std::type_info*, std::string, LLWidgetNameRegistry>
+: public LLRegistrySingleton<std::type_index, std::string, LLWidgetNameRegistry>
{
LLSINGLETON_EMPTY_CTOR(LLWidgetNameRegistry);
};
@@ -74,7 +74,7 @@ class LLWidgetNameRegistry
// this is used for schema generation
//typedef const LLInitParam::BaseBlock& (*empty_param_block_func_t)();
//class LLDefaultParamBlockRegistry
-//: public LLRegistrySingleton<const std::type_info*, empty_param_block_func_t, LLDefaultParamBlockRegistry>
+//: public LLRegistrySingleton<std::type_index, empty_param_block_func_t, LLDefaultParamBlockRegistry>
//{
// LLSINGLETON(LLDefaultParamBlockRegistry);
//};
@@ -202,7 +202,7 @@ private:
static void copyName(LLXMLNodePtr src, LLXMLNodePtr dest);
// helper function for adding widget type info to various registries
- static void registerWidget(const std::type_info* widget_type, const std::type_info* param_block_type, const std::string& tag);
+ static void registerWidget(std::type_index widget_type, std::type_index param_block_type, const std::string& tag);
static void loadWidgetTemplate(const std::string& widget_tag, LLInitParam::BaseBlock& block);
@@ -290,7 +290,7 @@ template <typename PARAM_BLOCK, int DUMMY>
LLUICtrlFactory::ParamDefaults<PARAM_BLOCK, DUMMY>::ParamDefaults()
{
// look up template file for this param block...
- const std::string* param_block_tag = LLWidgetNameRegistry::instance().getValue(&typeid(PARAM_BLOCK));
+ const std::string* param_block_tag = LLWidgetNameRegistry::instance().getValue(typeid(PARAM_BLOCK));
if (param_block_tag)
{ // ...and if it exists, back fill values using the most specific template first
PARAM_BLOCK params;
@@ -314,12 +314,12 @@ LLChildRegistry<DERIVED>::Register<T>::Register(const char* tag, LLWidgetCreator
: LLChildRegistry<DERIVED>::StaticRegistrar(tag, func == nullptr ? (LLWidgetCreatorFunc)&LLUICtrlFactory::defaultBuilder<T> : func)
{
// add this widget to various registries
- LLUICtrlFactory::instance().registerWidget(&typeid(T), &typeid(typename T::Params), tag);
+ LLUICtrlFactory::instance().registerWidget(typeid(T), typeid(typename T::Params), tag);
// since registry_t depends on T, do this in line here
// TODO: uncomment this for schema generation
//typedef typename T::child_registry_t registry_t;
- //LLChildRegistryRegistry::instance().defaultRegistrar().add(&typeid(T), registry_t::instance());
+ //LLChildRegistryRegistry::instance().defaultRegistrar().add(typeid(T), registry_t::instance());
}
#endif //LLUICTRLFACTORY_H
diff --git a/indra/llui/llxuiparser.cpp b/indra/llui/llxuiparser.cpp
index 9bf2f4220c..f4ef6f79f1 100644
--- a/indra/llui/llxuiparser.cpp
+++ b/indra/llui/llxuiparser.cpp
@@ -602,7 +602,7 @@ void LLXUIXSDWriter::writeXSD(const std::string& type_name, const std::string& p
LLXSDWriter::writeXSD(type_name, root_nodep, block, "http://www.lindenlab.com/xui");
// add includes for all possible children
- const std::type_info* type = *LLWidgetTypeRegistry::instance().getValue(type_name);
+ const std::type_index& type = *LLWidgetTypeRegistry::instance().getValue(type_name);
const widget_registry_t* widget_registryp = LLChildRegistryRegistry::instance().getValue(type);
// add choices for valid children
@@ -1459,7 +1459,7 @@ void LLSimpleXUIParser::characterDataHandler(void *userData, const char *s, int
void LLSimpleXUIParser::characterData(const char *s, int len)
{
- mTextContents += std::string(s, len);
+ mTextContents.append(s, len);
}
void LLSimpleXUIParser::startElement(const char *name, const char **atts)
@@ -1480,24 +1480,24 @@ void LLSimpleXUIParser::startElement(const char *name, const char **atts)
mOutputStack.back().second++;
S32 num_tokens_pushed = 0;
- std::string child_name(name);
+ std::string_view child_name(name);
if (mOutputStack.back().second == 1)
{ // root node for this block
- mScope.push_back(child_name);
+ mScope.emplace_back(child_name);
}
else
{ // compound attribute
if (child_name.find(".") == std::string::npos)
{
- mNameStack.push_back(std::make_pair(child_name, true));
+ mNameStack.emplace_back(child_name, true);
num_tokens_pushed++;
- mScope.push_back(child_name);
+ mScope.emplace_back(child_name);
}
else
{
// parse out "dotted" name into individual tokens
- tokenizer name_tokens(child_name, sep);
+ tokenizer name_tokens(std::string(child_name), sep);
tokenizer::iterator name_token_it = name_tokens.begin();
if(name_token_it == name_tokens.end())
@@ -1603,8 +1603,8 @@ bool LLSimpleXUIParser::processText()
LLStringUtil::trim(mTextContents);
if (!mTextContents.empty())
{
- mNameStack.push_back(std::make_pair(std::string("value"), true));
- mCurAttributeValueBegin = mTextContents.c_str();
+ mNameStack.emplace_back("value", true);
+ mCurAttributeValueBegin = std::move(mTextContents);
mOutputStack.back().first->submitValue(mNameStack, *this, mParseSilently);
mNameStack.pop_back();
}
@@ -1648,12 +1648,12 @@ bool LLSimpleXUIParser::readFlag(Parser& parser, void* val_ptr)
bool LLSimpleXUIParser::readBoolValue(Parser& parser, void* val_ptr)
{
LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(parser);
- if (!strcmp(self.mCurAttributeValueBegin, "true"))
+ if (!strcmp(self.mCurAttributeValueBegin.c_str(), "true"))
{
*((bool*)val_ptr) = true;
return true;
}
- else if (!strcmp(self.mCurAttributeValueBegin, "false"))
+ else if (!strcmp(self.mCurAttributeValueBegin.c_str(), "false"))
{
*((bool*)val_ptr) = false;
return true;
@@ -1665,56 +1665,56 @@ bool LLSimpleXUIParser::readBoolValue(Parser& parser, void* val_ptr)
bool LLSimpleXUIParser::readStringValue(Parser& parser, void* val_ptr)
{
LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(parser);
- *((std::string*)val_ptr) = self.mCurAttributeValueBegin;
+ *((std::string*)val_ptr) = std::move(self.mCurAttributeValueBegin);
return true;
}
bool LLSimpleXUIParser::readU8Value(Parser& parser, void* val_ptr)
{
LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(parser);
- return parse(self.mCurAttributeValueBegin, uint_p[assign_a(*(U8*)val_ptr)]).full;
+ return parse(self.mCurAttributeValueBegin.c_str(), uint_p[assign_a(*(U8*)val_ptr)]).full;
}
bool LLSimpleXUIParser::readS8Value(Parser& parser, void* val_ptr)
{
LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(parser);
- return parse(self.mCurAttributeValueBegin, int_p[assign_a(*(S8*)val_ptr)]).full;
+ return parse(self.mCurAttributeValueBegin.c_str(), int_p[assign_a(*(S8*)val_ptr)]).full;
}
bool LLSimpleXUIParser::readU16Value(Parser& parser, void* val_ptr)
{
LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(parser);
- return parse(self.mCurAttributeValueBegin, uint_p[assign_a(*(U16*)val_ptr)]).full;
+ return parse(self.mCurAttributeValueBegin.c_str(), uint_p[assign_a(*(U16*)val_ptr)]).full;
}
bool LLSimpleXUIParser::readS16Value(Parser& parser, void* val_ptr)
{
LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(parser);
- return parse(self.mCurAttributeValueBegin, int_p[assign_a(*(S16*)val_ptr)]).full;
+ return parse(self.mCurAttributeValueBegin.c_str(), int_p[assign_a(*(S16*)val_ptr)]).full;
}
bool LLSimpleXUIParser::readU32Value(Parser& parser, void* val_ptr)
{
LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(parser);
- return parse(self.mCurAttributeValueBegin, uint_p[assign_a(*(U32*)val_ptr)]).full;
+ return parse(self.mCurAttributeValueBegin.c_str(), uint_p[assign_a(*(U32*)val_ptr)]).full;
}
bool LLSimpleXUIParser::readS32Value(Parser& parser, void* val_ptr)
{
LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(parser);
- return parse(self.mCurAttributeValueBegin, int_p[assign_a(*(S32*)val_ptr)]).full;
+ return parse(self.mCurAttributeValueBegin.c_str(), int_p[assign_a(*(S32*)val_ptr)]).full;
}
bool LLSimpleXUIParser::readF32Value(Parser& parser, void* val_ptr)
{
LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(parser);
- return parse(self.mCurAttributeValueBegin, real_p[assign_a(*(F32*)val_ptr)]).full;
+ return parse(self.mCurAttributeValueBegin.c_str(), real_p[assign_a(*(F32*)val_ptr)]).full;
}
bool LLSimpleXUIParser::readF64Value(Parser& parser, void* val_ptr)
{
LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(parser);
- return parse(self.mCurAttributeValueBegin, real_p[assign_a(*(F64*)val_ptr)]).full;
+ return parse(self.mCurAttributeValueBegin.c_str(), real_p[assign_a(*(F64*)val_ptr)]).full;
}
bool LLSimpleXUIParser::readColor4Value(Parser& parser, void* val_ptr)
@@ -1722,7 +1722,7 @@ bool LLSimpleXUIParser::readColor4Value(Parser& parser, void* val_ptr)
LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(parser);
LLColor4 value;
- if (parse(self.mCurAttributeValueBegin, real_p[assign_a(value.mV[0])] >> real_p[assign_a(value.mV[1])] >> real_p[assign_a(value.mV[2])] >> real_p[assign_a(value.mV[3])], space_p).full)
+ if (parse(self.mCurAttributeValueBegin.c_str(), real_p[assign_a(value.mV[0])] >> real_p[assign_a(value.mV[1])] >> real_p[assign_a(value.mV[2])] >> real_p[assign_a(value.mV[3])], space_p).full)
{
*(LLColor4*)(val_ptr) = value;
return true;
@@ -1736,7 +1736,7 @@ bool LLSimpleXUIParser::readUIColorValue(Parser& parser, void* val_ptr)
LLColor4 value;
LLUIColor* colorp = (LLUIColor*)val_ptr;
- if (parse(self.mCurAttributeValueBegin, real_p[assign_a(value.mV[0])] >> real_p[assign_a(value.mV[1])] >> real_p[assign_a(value.mV[2])] >> real_p[assign_a(value.mV[3])], space_p).full)
+ if (parse(self.mCurAttributeValueBegin.c_str(), real_p[assign_a(value.mV[0])] >> real_p[assign_a(value.mV[1])] >> real_p[assign_a(value.mV[2])] >> real_p[assign_a(value.mV[3])], space_p).full)
{
colorp->set(value);
return true;
@@ -1749,7 +1749,7 @@ bool LLSimpleXUIParser::readUUIDValue(Parser& parser, void* val_ptr)
LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(parser);
LLUUID temp_id;
// LLUUID::set is destructive, so use temporary value
- if (temp_id.set(std::string(self.mCurAttributeValueBegin)))
+ if (temp_id.set(self.mCurAttributeValueBegin))
{
*(LLUUID*)(val_ptr) = temp_id;
return true;
diff --git a/indra/llui/llxuiparser.h b/indra/llui/llxuiparser.h
index 2179ae54d3..3cc564772e 100644
--- a/indra/llui/llxuiparser.h
+++ b/indra/llui/llxuiparser.h
@@ -40,7 +40,7 @@ class LLView;
// lookup widget type by name
class LLWidgetTypeRegistry
-: public LLRegistrySingleton<std::string, const std::type_info*, LLWidgetTypeRegistry>
+: public LLRegistrySingleton<std::string, std::type_index, LLWidgetTypeRegistry>
{
LLSINGLETON_EMPTY_CTOR(LLWidgetTypeRegistry);
};
@@ -52,7 +52,7 @@ typedef std::function<LLView* (LLXMLNodePtr node, LLView *parent, LLXMLNodePtr o
typedef LLRegistry<std::string, LLWidgetCreatorFunc> widget_registry_t;
class LLChildRegistryRegistry
-: public LLRegistrySingleton<const std::type_info*, widget_registry_t, LLChildRegistryRegistry>
+: public LLRegistrySingleton<std::type_index, widget_registry_t, LLChildRegistryRegistry>
{
LLSINGLETON_EMPTY_CTOR(LLChildRegistryRegistry);
};
@@ -247,7 +247,7 @@ private:
S32 mCurReadDepth;
std::string mCurFileName;
std::string mTextContents;
- const char* mCurAttributeValueBegin;
+ std::string mCurAttributeValueBegin;
std::vector<S32> mTokenSizeStack;
std::vector<std::string> mScope;
std::vector<bool> mEmptyLeafNode;
diff --git a/indra/llwindow/llwindow.h b/indra/llwindow/llwindow.h
index 2d8fc80b9e..e9dfa3aba4 100644
--- a/indra/llwindow/llwindow.h
+++ b/indra/llwindow/llwindow.h
@@ -202,6 +202,8 @@ public:
};
virtual S32 getRefreshRate() { return mRefreshRate; }
+
+ virtual void initWatchdog() {} // windows runs window as a thread and it needs a watchdog
protected:
LLWindow(LLWindowCallbacks* callbacks, bool fullscreen, U32 flags);
virtual ~LLWindow();
diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp
index 45326444d5..252482a96e 100644
--- a/indra/llwindow/llwindowwin32.cpp
+++ b/indra/llwindow/llwindowwin32.cpp
@@ -49,6 +49,7 @@
#include "llthreadsafequeue.h"
#include "stringize.h"
#include "llframetimer.h"
+#include "llwatchdog.h"
// System includes
#include <commdlg.h>
@@ -365,7 +366,8 @@ static LLMonitorInfo sMonitorInfo;
// the containing class a friend.
struct LLWindowWin32::LLWindowWin32Thread : public LL::ThreadPool
{
- static const int MAX_QUEUE_SIZE = 2048;
+ static constexpr int MAX_QUEUE_SIZE = 2048;
+ static constexpr F32 WINDOW_TIMEOUT_SEC = 90.f;
LLThreadSafeQueue<MSG> mMessageQueue;
@@ -427,6 +429,50 @@ struct LLWindowWin32::LLWindowWin32Thread : public LL::ThreadPool
PostMessage(windowHandle, WM_POST_FUNCTION_, wparam, LPARAM(ptr));
}
+ // Call from main thread.
+ void initTimeout()
+ {
+ // post into thread's queue to avoid threading issues
+ post([this]()
+ {
+ if (!mWindowTimeout)
+ {
+ mWindowTimeout = std::make_unique<LLWatchdogTimeout>("mainloop");
+ // supposed to be executed within run(),
+ // so no point checking if thread is alive
+ resumeTimeout("TimeoutInit");
+ }
+ });
+ }
+private:
+ // These timeout related functions are strictly for the thread.
+ void resumeTimeout(std::string_view state)
+ {
+ if (mWindowTimeout)
+ {
+ mWindowTimeout->setTimeout(WINDOW_TIMEOUT_SEC);
+ mWindowTimeout->start(state);
+ }
+ }
+
+ void pauseTimeout()
+ {
+ if (mWindowTimeout)
+ {
+ mWindowTimeout->stop();
+ }
+ }
+
+ void pingTimeout(std::string_view state)
+ {
+ if (mWindowTimeout)
+ {
+ mWindowTimeout->setTimeout(WINDOW_TIMEOUT_SEC);
+ mWindowTimeout->ping(state);
+ }
+ }
+
+public:
using FuncType = std::function<void()>;
// call GetMessage() and pull enqueue messages for later processing
HWND mWindowHandleThrd = NULL;
@@ -437,6 +483,8 @@ struct LLWindowWin32::LLWindowWin32Thread : public LL::ThreadPool
bool mGLReady = false;
bool mGotGLBuffer = false;
LLAtomicBool mDeleteOnExit = false;
+private:
+ std::unique_ptr<LLWatchdogTimeout> mWindowTimeout;
};
@@ -4598,6 +4646,11 @@ bool LLWindowWin32::getInputDevices(U32 device_type_filter,
return false;
}
+void LLWindowWin32::initWatchdog()
+{
+ mWindowThread->initTimeout();
+}
+
F32 LLWindowWin32::getSystemUISize()
{
F32 scale_value = 1.f;
@@ -4747,6 +4800,8 @@ void LLWindowWin32::LLWindowWin32Thread::checkDXMem()
return;
}
+ pauseTimeout();
+
IDXGIFactory4* p_factory = nullptr;
HRESULT res = CreateDXGIFactory1(__uuidof(IDXGIFactory4), (void**)&p_factory);
@@ -4850,6 +4905,8 @@ void LLWindowWin32::LLWindowWin32Thread::checkDXMem()
}
mGotGLBuffer = true;
+
+ resumeTimeout("checkDXMem");
}
void LLWindowWin32::LLWindowWin32Thread::run()
@@ -4865,6 +4922,9 @@ void LLWindowWin32::LLWindowWin32Thread::run()
timeBeginPeriod(llclamp((U32) 1, tc.wPeriodMin, tc.wPeriodMax));
}
+ // Normally won't exist yet, but in case of re-init, make sure it's cleaned up
+ resumeTimeout("WindowThread");
+
while (! getQueue().done())
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_WIN32;
@@ -4874,6 +4934,7 @@ void LLWindowWin32::LLWindowWin32Thread::run()
if (mWindowHandleThrd != 0)
{
+ pingTimeout("messages");
MSG msg;
BOOL status;
if (mhDCThrd == 0)
@@ -4901,6 +4962,7 @@ void LLWindowWin32::LLWindowWin32Thread::run()
{
LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("w32t - Function Queue");
+ pingTimeout("queue");
logger.onChange("runPending()");
//process any pending functions
getQueue().runPending();
@@ -4915,6 +4977,7 @@ void LLWindowWin32::LLWindowWin32Thread::run()
#endif
}
+ pauseTimeout();
destroyWindow();
if (mDeleteOnExit)
diff --git a/indra/llwindow/llwindowwin32.h b/indra/llwindow/llwindowwin32.h
index 77217747cc..84b382f4ce 100644
--- a/indra/llwindow/llwindowwin32.h
+++ b/indra/llwindow/llwindowwin32.h
@@ -45,83 +45,82 @@ typedef void (*LLW32MsgCallback)(const MSG &msg);
class LLWindowWin32 : 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 enable_vsync, const LLCoordScreen * const posp = NULL);
- /*virtual*/ void setTitle(const std::string title);
+ void show() override;
+ void hide() override;
+ void close() override;
+ bool getVisible() override;
+ bool getMinimized() override;
+ bool getMaximized() override;
+ bool maximize() override;
+ void minimize() override;
+ void restore() override;
+ bool getFullscreen();
+ bool getPosition(LLCoordScreen *position) override;
+ bool getSize(LLCoordScreen *size) override;
+ bool getSize(LLCoordWindow *size) override;
+ bool setPosition(LLCoordScreen position) override;
+ bool setSizeImpl(LLCoordScreen size) override;
+ bool setSizeImpl(LLCoordWindow size) override;
+ bool switchContext(bool fullscreen, const LLCoordScreen &size, bool enable_vsync, const LLCoordScreen * const posp = NULL) override;
+ void setTitle(const std::string title) override;
void* createSharedContext() override;
void makeContextCurrent(void* context) override;
void destroySharedContext(void* context) override;
- /*virtual*/ void toggleVSync(bool enable_vsync);
- /*virtual*/ bool setCursorPosition(LLCoordWindow position);
- /*virtual*/ bool getCursorPosition(LLCoordWindow *position);
- /*virtual*/ bool getCursorDelta(LLCoordCommon* delta);
- /*virtual*/ bool isWrapMouse() const override { return !mAbsoluteCursorPosition; };
- /*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*/ void setFSAASamples(const U32 fsaa_samples);
- /*virtual*/ U32 getFSAASamples();
- /*virtual*/ bool restoreGamma(); // Restore original gamma table (before updating gamma)
- /*virtual*/ ESwapMethod getSwapMethod() { return mSwapMethod; }
- /*virtual*/ void gatherInput();
- /*virtual*/ void delayInputProcessing();
- /*virtual*/ void swapBuffers();
- /*virtual*/ void restoreGLContext() {};
+ void toggleVSync(bool enable_vsync) override;
+ bool setCursorPosition(LLCoordWindow position) override;
+ bool getCursorPosition(LLCoordWindow *position) override;
+ bool getCursorDelta(LLCoordCommon* delta) override;
+ bool isWrapMouse() const override { return !mAbsoluteCursorPosition; };
+ 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
+ void setFSAASamples(const U32 fsaa_samples) override;
+ U32 getFSAASamples() 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*/ bool dialogColorPicker(F32 *r, F32 *g, F32 *b );
+ bool dialogColorPicker(F32 *r, F32 *g, F32 *b ) override;
- /*virtual*/ void *getPlatformWindow();
- /*virtual*/ void bringToFront();
- /*virtual*/ void focusClient();
+ void *getPlatformWindow() override;
+ void bringToFront() override;
+ void focusClient() override;
- /*virtual*/ void allowLanguageTextInput(LLPreeditor *preeditor, bool b);
- /*virtual*/ void setLanguageTextInput( const LLCoordGL & pos );
- /*virtual*/ void updateLanguageTextInputArea();
- /*virtual*/ void interruptLanguageTextInput();
- /*virtual*/ void spawnWebBrowser(const std::string& escaped_url, bool async);
+ void allowLanguageTextInput(LLPreeditor *preeditor, bool b) override;
+ void setLanguageTextInput( const LLCoordGL & pos ) override;
+ void updateLanguageTextInputArea() override;
+ void interruptLanguageTextInput() override;
+ void spawnWebBrowser(const std::string& escaped_url, bool async) override;
- /*virtual*/ F32 getSystemUISize();
+ F32 getSystemUISize() override;
LLWindowCallbacks::DragNDropResult completeDragNDropRequest( const LLCoordGL gl_coord, const MASK mask, LLWindowCallbacks::DragNDropAction action, const std::string url );
@@ -130,14 +129,16 @@ public:
static std::vector<std::string> getDynamicFallbackFontList();
static void setDPIAwareness();
- /*virtual*/ void* getDirectInput8();
- /*virtual*/ bool getInputDevices(U32 device_type_filter,
+ void* getDirectInput8() override;
+ bool getInputDevices(U32 device_type_filter,
std::function<bool(std::string&, LLSD&, void*)> osx_callback,
void* win_callback,
- void* userdata);
+ void* userdata) override;
U32 getRawWParam() { return mRawWParam; }
+ void initWatchdog() override;
+
protected:
LLWindowWin32(LLWindowCallbacks* callbacks,
const std::string& title, const std::string& name, int x, int y, int width, int height, U32 flags,
diff --git a/indra/llxml/llcontrol.cpp b/indra/llxml/llcontrol.cpp
index 8a95ab2cc2..df6be2546d 100644
--- a/indra/llxml/llcontrol.cpp
+++ b/indra/llxml/llcontrol.cpp
@@ -761,6 +761,7 @@ void LLControlGroup::setUntypedValue(std::string_view name, const LLSD& val)
// Returns number of controls loaded, so 0 if failure
U32 LLControlGroup::loadFromFileLegacy(const std::string& filename, bool require_declaration, eControlType declare_as)
{
+ LL_PROFILE_ZONE_SCOPED;
std::string name;
LLXmlTree xml_controls;
@@ -995,6 +996,7 @@ U32 LLControlGroup::saveToFile(const std::string& filename, bool nondefault_only
U32 LLControlGroup::loadFromFile(const std::string& filename, bool set_default_values, bool save_values, bool error_when_no_comment)
{
+ LL_PROFILE_ZONE_SCOPED;
LLSD settings;
llifstream infile;
infile.open(filename.c_str());
diff --git a/indra/llxml/llcontrol.h b/indra/llxml/llcontrol.h
index c9bd0a8a32..5aa2b9715e 100644
--- a/indra/llxml/llcontrol.h
+++ b/indra/llxml/llcontrol.h
@@ -33,8 +33,10 @@
#include "llrect.h"
#include "llrefcount.h"
#include "llinstancetracker.h"
+#include "llstl.h"
#include <functional>
+#include <unordered_map>
#include <vector>
#include <boost/signals2.hpp>
@@ -165,7 +167,7 @@ class LLControlGroup : public LLInstanceTracker<LLControlGroup, std::string>
LOG_CLASS(LLControlGroup);
protected:
- typedef std::map<std::string, LLControlVariablePtr, std::less<> > ctrl_name_table_t;
+ using ctrl_name_table_t = std::unordered_map<std::string, LLControlVariablePtr, ll::string_hash, std::equal_to<>>;
ctrl_name_table_t mNameTable;
static const std::string mTypeString[TYPE_COUNT];
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index c2b1473e8f..c76145fab3 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -735,7 +735,6 @@ set(viewer_SOURCE_FILES
llvovolume.cpp
llvowater.cpp
llvowlsky.cpp
- llwatchdog.cpp
llwearableitemslist.cpp
llwearablelist.cpp
llweb.cpp
@@ -1412,7 +1411,6 @@ set(viewer_HEADER_FILES
llvovolume.h
llvowater.h
llvowlsky.h
- llwatchdog.h
llwearableitemslist.h
llwearablelist.h
llweb.h
diff --git a/indra/newview/VIEWER_VERSION.txt b/indra/newview/VIEWER_VERSION.txt
index 4703009f54..2aaedf9944 100644
--- a/indra/newview/VIEWER_VERSION.txt
+++ b/indra/newview/VIEWER_VERSION.txt
@@ -1 +1 @@
-2026.01.0
+26.1.0
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 5d82b38c2a..03b5259b75 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -9102,7 +9102,7 @@
<key>Comment</key>
<string>Show reflection probes in the transparency debug view</string>
<key>Persist</key>
- <integer>1</integer>
+ <integer>0</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
@@ -16607,5 +16607,16 @@
<key>Value</key>
<integer>2</integer>
</map>
+ <key>PurgeDiskCacheOnStartup</key>
+ <map>
+ <key>Comment</key>
+ <string>Whether or not to LRU purge the disk cache during startup on main thread</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/app_settings/shaders/class1/deferred/pbropaqueF.glsl b/indra/newview/app_settings/shaders/class1/deferred/pbropaqueF.glsl
index dd9e883fdf..abe61fe892 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/pbropaqueF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/pbropaqueF.glsl
@@ -146,6 +146,9 @@ vec3 srgb_to_linear(vec3 c);
void main()
{
vec4 basecolor = texture(diffuseMap, base_color_texcoord.xy).rgba;
+
+ basecolor.a *= vertex_color.a;
+
if (basecolor.a < minimum_alpha)
{
discard;
diff --git a/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl b/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl
index e405a9ea2d..69c9e9ff84 100644
--- a/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl
+++ b/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl
@@ -51,9 +51,7 @@ in vec3 vary_norm;
in vec4 vertex_color; //vertex color should be treated as sRGB
#endif
-#ifdef HAS_ALPHA_MASK
uniform float minimum_alpha;
-#endif
uniform mat4 proj_mat;
uniform mat4 inv_proj;
@@ -225,6 +223,13 @@ void main()
float final_alpha = diffuse_linear.a;
+#ifdef IS_AVATAR_SKIN
+ if(final_alpha < minimum_alpha)
+ {
+ discard;
+ }
+#endif
+
#ifdef USE_VERTEX_COLOR
final_alpha *= vertex_color.a;
diff --git a/indra/newview/gltf/asset.cpp b/indra/newview/gltf/asset.cpp
index 187876e3b8..c170672859 100644
--- a/indra/newview/gltf/asset.cpp
+++ b/indra/newview/gltf/asset.cpp
@@ -1027,6 +1027,12 @@ bool Image::prepImpl(Asset& asset, const LLUUID& id)
std::string dir = gDirUtilp->getDirName(asset.mFilename);
std::string img_file = dir + gDirUtilp->getDirDelimiter() + mUri;
+ if (!gDirUtilp->fileExists(img_file))
+ {
+ // URI might be escaped, unescape.
+ img_file = dir + gDirUtilp->getDirDelimiter() + LLURI::unescape(mUri);
+ }
+
LLUUID tracking_id = LLLocalBitmapMgr::getInstance()->addUnit(img_file);
if (tracking_id.notNull() && mLoadIntoTexturePipe)
{
diff --git a/indra/newview/gltf/buffer_util.h b/indra/newview/gltf/buffer_util.h
index c231443a9e..53dee98cd1 100644
--- a/indra/newview/gltf/buffer_util.h
+++ b/indra/newview/gltf/buffer_util.h
@@ -141,6 +141,42 @@ namespace LL
}
template<>
+ inline void copyScalar<U32, LLVector4a>(U32* src, LLVector4a& dst)
+ {
+ dst.set((F32)*src, 0.f, 0.f, 0.f);
+ }
+
+ template<>
+ inline void copyScalar<U16, LLVector4a>(U16* src, LLVector4a& dst)
+ {
+ dst.set((F32)*src, 0.f, 0.f, 0.f);
+ }
+
+ template<>
+ inline void copyScalar<U8, LLVector4a>(U8* src, LLVector4a& dst)
+ {
+ dst.set((F32)*src, 0.f, 0.f, 0.f);
+ }
+
+ template<>
+ inline void copyScalar<U32, LLVector2>(U32* src, LLVector2& dst)
+ {
+ dst.set((F32)*src, 0.f);
+ }
+
+ template<>
+ inline void copyScalar<U16, LLVector2>(U16* src, LLVector2& dst)
+ {
+ dst.set((F32)*src, 0.f);
+ }
+
+ template<>
+ inline void copyScalar<U8, LLVector2>(U8* src, LLVector2& dst)
+ {
+ dst.set((F32)*src, 0.f);
+ }
+
+ template<>
inline void copyVec2<F32, LLVector2>(F32* src, LLVector2& dst)
{
dst.set(src[0], src[1]);
@@ -221,6 +257,12 @@ namespace LL
}
template<>
+ inline void copyVec4<U32, LLVector4a>(U32* src, LLVector4a& dst)
+ {
+ dst.set((F32)src[0], (F32)src[1], (F32)src[2], (F32)src[3]);
+ }
+
+ template<>
inline void copyVec4<U16, LLVector4a>(U16* src, LLVector4a& dst)
{
dst.set(src[0], src[1], src[2], src[3]);
@@ -373,7 +415,7 @@ namespace LL
}
else
{
- LL_ERRS("GLTF") << "Unsupported accessor type" << LL_ENDL;
+ LL_ERRS("GLTF") << "Unsupported accessor type " << (S32)accessor.mType << LL_ENDL;
}
}
diff --git a/indra/newview/gltf/llgltfloader.cpp b/indra/newview/gltf/llgltfloader.cpp
index 1af98c3730..66aa29d86b 100644
--- a/indra/newview/gltf/llgltfloader.cpp
+++ b/indra/newview/gltf/llgltfloader.cpp
@@ -826,7 +826,8 @@ bool LLGLTFLoader::populateModelFromMesh(LLModel* pModel, const std::string& bas
LL_DEBUGS("GLTF_IMPORT") << "No normals found for primitive, using default normal." << LL_ENDL;
}
- vert.uv0 = glm::vec2(prim.mTexCoords0[i][0], -prim.mTexCoords0[i][1]);
+ // Flip texture V coordinate
+ vert.uv0 = glm::vec2(prim.mTexCoords0[i][0], 1.f - prim.mTexCoords0[i][1]);
if (skinIdx >= 0)
{
diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp
index 0d7ad0a124..60af0cad05 100644
--- a/indra/newview/llagent.cpp
+++ b/indra/newview/llagent.cpp
@@ -4850,6 +4850,8 @@ const std::string& LLAgent::getTeleportStateName() const
void LLAgent::parseTeleportMessages(const std::string& xml_filename)
{
+ LL_PROFILE_ZONE_SCOPED;
+
LLXMLNodePtr root;
bool success = LLUICtrlFactory::getLayeredXMLNode(xml_filename, root);
diff --git a/indra/newview/llappcorehttp.cpp b/indra/newview/llappcorehttp.cpp
index f3265afebd..ece18fb5cc 100644
--- a/indra/newview/llappcorehttp.cpp
+++ b/indra/newview/llappcorehttp.cpp
@@ -144,6 +144,8 @@ LLAppCoreHttp::~LLAppCoreHttp()
void LLAppCoreHttp::init()
{
+ LL_PROFILE_ZONE_SCOPED;
+
LLCoreHttpUtil::setPropertyMethods(
std::bind(&LLControlGroup::getBOOL, std::ref(gSavedSettings), std::placeholders::_1),
std::bind(&LLControlGroup::declareBOOL, std::ref(gSavedSettings), std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, LLControlVariable::PERSIST_NONDFT));
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 8bf418aa44..ab4a0fbc28 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -340,9 +340,6 @@ F32 gLogoutMaxTime = LOGOUT_REQUEST_TIME;
S32 gPendingMetricsUploads = 0;
-
-bool gDisconnected = false;
-
// Used to restore texture state after a mode switch
LLFrameTimer gRestoreGLTimer;
bool gRestoreGL = false;
@@ -735,6 +732,8 @@ public:
bool LLAppViewer::init()
{
+ LL_PROFILE_ZONE_SCOPED;
+
setupErrorHandling(mSecondInstance);
//
@@ -936,6 +935,7 @@ bool LLAppViewer::init()
// Early out from user choice.
LL_WARNS("InitInfo") << "initHardwareTest() failed." << LL_ENDL;
// quit immediately
+ LL_PROFILER_FRAME_END;
return false;
}
LL_INFOS("InitInfo") << "Hardware test initialization done." << LL_ENDL ;
@@ -954,6 +954,7 @@ bool LLAppViewer::init()
OSMessageBox(msg.c_str(), LLStringUtil::null, OSMB_OK);
LL_WARNS("InitInfo") << "Failed to init cache" << LL_ENDL;
// quit immediately
+ LL_PROFILER_FRAME_END;
return false;
}
LL_INFOS("InitInfo") << "Cache initialization is done." << LL_ENDL ;
@@ -989,6 +990,7 @@ bool LLAppViewer::init()
// Already handled with a MBVideoDrvErr
LL_WARNS("InitInfo") << "gGLManager.mHasRequirements is false." << LL_ENDL;
// quit immediately
+ LL_PROFILER_FRAME_END;
return false;
}
@@ -1002,6 +1004,7 @@ bool LLAppViewer::init()
OSMessageBox(msg.c_str(), LLStringUtil::null, OSMB_OK);
LL_WARNS("InitInfo") << "SSE2 is not supported" << LL_ENDL;
// quit immediately
+ LL_PROFILER_FRAME_END;
return false;
}
#endif
@@ -1240,7 +1243,7 @@ bool LLAppViewer::init()
/*----------------------------------------------------------------------*/
// nat 2016-06-29 moved the following here from the former mainLoop().
- mMainloopTimeout = new LLWatchdogTimeout();
+ mMainloopTimeout = new LLWatchdogTimeout("mainloop");
// Create IO Pump to use for HTTP Requests.
gServicePump = new LLPumpIO(gAPRPoolp);
@@ -1273,7 +1276,7 @@ bool LLAppViewer::init()
gDirUtilp->deleteDirAndContents(gDirUtilp->getDumpLogsDirPath());
}
#endif
-
+ LL_PROFILER_FRAME_END;
return true;
}
@@ -1430,12 +1433,14 @@ bool LLAppViewer::doFrame()
{
LL_PROFILE_ZONE_NAMED_CATEGORY_APP("df mainloop");
+ pingMainloopTimeout("df mainloop");
// canonical per-frame event
mainloop.post(newFrame);
}
{
LL_PROFILE_ZONE_NAMED_CATEGORY_APP("df suspend");
+ pingMainloopTimeout("df suspend");
// give listeners a chance to run
llcoro::suspend();
// if one of our coroutines threw an uncaught exception, rethrow it now
@@ -1471,6 +1476,7 @@ bool LLAppViewer::doFrame()
{
{
LL_PROFILE_ZONE_NAMED_CATEGORY_APP("df pauseMainloopTimeout");
+ pingMainloopTimeout("df idle"); // So that it will be aware of last state.
pauseMainloopTimeout(); // *TODO: Remove. Messages shouldn't be stalling for 20+ seconds!
}
@@ -1482,7 +1488,7 @@ bool LLAppViewer::doFrame()
{
LL_PROFILE_ZONE_NAMED_CATEGORY_APP("df resumeMainloopTimeout");
- resumeMainloopTimeout();
+ resumeMainloopTimeout("df idle");
}
}
@@ -1497,7 +1503,7 @@ bool LLAppViewer::doFrame()
}
disconnectViewer();
- resumeMainloopTimeout();
+ resumeMainloopTimeout("df snapshot n disconnect");
}
// Render scene.
@@ -2190,6 +2196,8 @@ void LLAppViewer::initGeneralThread()
bool LLAppViewer::initThreads()
{
+ LL_PROFILE_ZONE_SCOPED;
+
static const bool enable_threads = true;
LLImage::initClass(gSavedSettings.getBOOL("TextureNewByteRange"),gSavedSettings.getS32("TextureReverseByteRange"));
@@ -2300,7 +2308,22 @@ void errorHandler(const std::string& title_string, const std::string& message_st
}
if (!message_string.empty())
{
- OSMessageBox(message_string, title_string.empty() ? LLTrans::getString("MBFatalError") : title_string, OSMB_OK);
+ if (on_main_thread())
+ {
+ // Prevent watchdog from killing us while dialog is up.
+ // Can't do pauseMainloopTimeout, since this may be called
+ // from threads and we are not going to need watchdog now.
+ LLAppViewer::instance()->pauseMainloopTimeout();
+
+ // todo: might want to have non-crashing timeout for OOM cases
+ // and needs a way to pause main loop.
+ OSMessageBox(message_string, title_string.empty() ? LLTrans::getString("MBFatalError") : title_string, OSMB_OK);
+ LLAppViewer::instance()->resumeMainloopTimeout();
+ }
+ else
+ {
+ OSMessageBox(message_string, title_string.empty() ? LLTrans::getString("MBFatalError") : title_string, OSMB_OK);
+ }
}
}
@@ -3022,6 +3045,8 @@ bool LLAppViewer::initConfiguration()
// keeps growing, necessitating a method all its own.
void LLAppViewer::initStrings()
{
+ LL_PROFILE_ZONE_SCOPED;
+
std::string strings_file = "strings.xml";
std::string strings_path_full = gDirUtilp->findSkinnedFilenameBaseLang(LLDir::XUI, strings_file);
if (strings_path_full.empty() || !LLFile::isfile(strings_path_full))
@@ -3109,6 +3134,7 @@ void LLAppViewer::sendOutOfDiskSpaceNotification()
bool LLAppViewer::initWindow()
{
+ LL_PROFILE_ZONE_SCOPED;
LL_INFOS("AppInit") << "Initializing window..." << LL_ENDL;
// store setting in a global for easy access and modification
@@ -3164,7 +3190,19 @@ bool LLAppViewer::initWindow()
if (use_watchdog)
{
- LLWatchdog::getInstance()->init();
+ LLWatchdog::getInstance()->init([]()
+ {
+ LLAppViewer* app = LLAppViewer::instance();
+ if (app->logoutRequestSent())
+ {
+ app->createErrorMarker(LAST_EXEC_LOGOUT_FROZE);
+ }
+ else
+ {
+ app->createErrorMarker(LAST_EXEC_FROZE);
+ }
+ });
+ gViewerWindow->getWindow()->initWatchdog();
}
LLNotificationsUI::LLNotificationManager::getInstance();
@@ -4327,6 +4365,7 @@ U32 LLAppViewer::getObjectCacheVersion()
bool LLAppViewer::initCache()
{
+ LL_PROFILE_ZONE_SCOPED;
mPurgeCache = false;
bool read_only = mSecondInstance;
LLAppViewer::getTextureCache()->setReadOnly(read_only) ;
@@ -4420,19 +4459,22 @@ bool LLAppViewer::initCache()
if (mPurgeCache)
{
- LLSplashScreen::update(LLTrans::getString("StartupClearingCache"));
- purgeCache();
+ LLSplashScreen::update(LLTrans::getString("StartupClearingCache"));
+ purgeCache();
// clear the new C++ file system based cache
LLDiskCache::getInstance()->clearCache();
- }
- else
+ }
+ else if (gSavedSettings.getBOOL("PurgeDiskCacheOnStartup"))
{
// purge excessive files from the new file system based cache
LLDiskCache::getInstance()->purge();
}
+
+ // Start disk cache purge thread to
+ // purge excessive files from the file system based cache
+ LLAppViewer::getPurgeDiskCacheThread()->start();
}
- LLAppViewer::getPurgeDiskCacheThread()->start();
LLSplashScreen::update(LLTrans::getString("StartupInitializingTextureCache"));
@@ -4475,6 +4517,7 @@ void LLAppViewer::loadKeyBindings()
// As per GHI #4498, remove old, stale CEF cache folders from previous sessions
void LLAppViewer::purgeCefStaleCaches()
{
+ LL_PROFILE_ZONE_SCOPED;
// TODO: we really shouldn't use a hard coded name for the cache folder here...
const std::string browser_parent_cache = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "cef_cache");
if (LLFile::isdir(browser_parent_cache))
@@ -4682,6 +4725,8 @@ std::string get_name_cache_filename(const std::string &base_file, const std::str
void LLAppViewer::loadNameCache()
{
+ LL_PROFILE_ZONE_SCOPED;
+
// display names cache
std::string filename = get_name_cache_filename("avatar_name_cache", "xml");
LL_INFOS("AvNameCache") << filename << LL_ENDL;
@@ -5829,7 +5874,7 @@ void LLAppViewer::initMainloopTimeout(std::string_view state)
{
if (!mMainloopTimeout)
{
- mMainloopTimeout = new LLWatchdogTimeout();
+ mMainloopTimeout = new LLWatchdogTimeout("mainloop");
resumeMainloopTimeout(state);
}
}
diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h
index 6b0d3e0b27..e1119419af 100644
--- a/indra/newview/llappviewer.h
+++ b/indra/newview/llappviewer.h
@@ -417,8 +417,6 @@ extern S32 gPendingMetricsUploads;
extern F32 gSimLastTime;
extern F32 gSimFrames;
-extern bool gDisconnected;
-
extern LLFrameTimer gRestoreGLTimer;
extern bool gRestoreGL;
extern bool gUseWireframe;
diff --git a/indra/newview/llavatarlistitem.cpp b/indra/newview/llavatarlistitem.cpp
index 80c7f8beca..de3ce901c1 100644
--- a/indra/newview/llavatarlistitem.cpp
+++ b/indra/newview/llavatarlistitem.cpp
@@ -47,7 +47,7 @@ S32 LLAvatarListItem::sLeftPadding = 0;
S32 LLAvatarListItem::sNameRightPadding = 0;
S32 LLAvatarListItem::sChildrenWidths[LLAvatarListItem::ALIC_COUNT];
-static LLWidgetNameRegistry::StaticRegistrar sRegisterAvatarListItemParams(&typeid(LLAvatarListItem::Params), "avatar_list_item");
+static LLWidgetNameRegistry::StaticRegistrar sRegisterAvatarListItemParams(typeid(LLAvatarListItem::Params), "avatar_list_item");
LLAvatarListItem::Params::Params()
: default_style("default_style"),
diff --git a/indra/newview/llcallingcard.cpp b/indra/newview/llcallingcard.cpp
index 76e308a966..2c9d74ed97 100644
--- a/indra/newview/llcallingcard.cpp
+++ b/indra/newview/llcallingcard.cpp
@@ -680,6 +680,8 @@ void LLAvatarTracker::processChange(LLMessageSystem* msg)
LLNotifications::instance().add("RevokedModifyRights",args, payload);
}
}
+ // update modify permissions flags for affected objects
+ LLViewerObject::markObjectsForUpdate(agent_id);
(mBuddyInfo[agent_id])->setRightsFrom(new_rights);
}
}
diff --git a/indra/newview/llcapabilityprovider.h b/indra/newview/llcapabilityprovider.h
index 484bd2ef04..acc752588d 100644
--- a/indra/newview/llcapabilityprovider.h
+++ b/indra/newview/llcapabilityprovider.h
@@ -37,12 +37,12 @@
class LLCapabilityProvider
{
public:
- virtual ~LLCapabilityProvider() {}
+ virtual ~LLCapabilityProvider() = default;
/**
* Get a capability URL, given a capability name. Returns empty string if
* no such capability is defined on this provider.
*/
- virtual std::string getCapability(const std::string& name) const = 0;
+ virtual std::string getCapability(std::string_view name) const = 0;
/**
* Get host to which to send that capability request.
*/
diff --git a/indra/newview/lleventpoll.cpp b/indra/newview/lleventpoll.cpp
index de3752d879..f1b46f0533 100644
--- a/indra/newview/lleventpoll.cpp
+++ b/indra/newview/lleventpoll.cpp
@@ -56,6 +56,7 @@ namespace Details
private:
void eventPollCoro(std::string url);
+ void handleMessage(const std::string& msg_name, const LLSD& body);
void handleMessage(const LLSD &content);
bool mDone;
@@ -95,21 +96,23 @@ namespace Details
mSenderIp = sender.getIPandPort();
}
+ void LLEventPollImpl::handleMessage(const std::string &msg_name, const LLSD &body)
+ {
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_APP;
+ LLSD message;
+ message["sender"] = mSenderIp;
+ message["body"] = body;
+
+ LLMessageSystem::dispatch(msg_name, message);
+ }
+
void LLEventPollImpl::handleMessage(const LLSD& content)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_APP;
std::string msg_name = content["message"].asString();
LLSD message;
- try
- {
- message["sender"] = mSenderIp;
- message["body"] = content["body"];
- }
- catch (std::bad_alloc&)
- {
- LLError::LLUserWarningMsg::showOutOfMemory();
- LL_ERRS("LLCoros") << "Bad memory allocation on message: " << msg_name << LL_ENDL;
- }
+ message["sender"] = mSenderIp;
+ message["body"] = content["body"];
LLMessageSystem::dispatch(msg_name, message);
}
@@ -194,7 +197,7 @@ namespace Details
break;
}
- LLSD httpResults = result["http_result"];
+ LLSD &httpResults = result["http_result"];
LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
if (!status)
@@ -299,7 +302,7 @@ namespace Details
}
acknowledge = result["id"];
- LLSD events = result["events"];
+ LLSD &events = result["events"];
if (acknowledge.isUndefined())
{
@@ -310,20 +313,37 @@ namespace Details
LL_DEBUGS("LLEventPollImpl") << " <" << counter << "> " << events.size() << "events (id " << acknowledge << ")" << LL_ENDL;
- LLSD::array_const_iterator i = events.beginArray();
- LLSD::array_const_iterator end = events.endArray();
+ LLSD::array_iterator i = events.beginArray();
+ LLSD::array_iterator end = events.endArray();
for (; i != end; ++i)
{
if (i->has("message"))
{
if (main_queue)
- { // shuttle to a sensible spot in the main thread instead
+ {
+ // Shuttle copy to a sensible spot in the main thread instead
// of wherever this coroutine happens to be executing
- const LLSD& msg = *i;
- main_queue->post([this, msg]()
+
+ LL::WorkQueue::Work work;
+ {
+ // LLSD is too smart for it's own good and may act like a smart
+ // pointer for the content of (*i), so instead of passing (*i)
+ // pass a prepared name and move ownership of "body",
+ // as we are not going to need "body" anywhere else.
+ std::string msg_name = (*i)["message"].asString();
+
+ // WARNING: This is a shallow copy!
+ // If something still retains the data (like in httpAdapter?) this might still
+ // result in a crash, if it does appear to be the case, make a deep copy or
+ // convert data to string and pass that string.
+ const LLSD body = (*i)["body"];
+ (*i)["body"].clear();
+ work = [this, msg_name, body]()
{
- handleMessage(msg);
- });
+ handleMessage(msg_name, body);
+ };
+ }
+ main_queue->post(work);
}
else
{
diff --git a/indra/newview/llexternaleditor.cpp b/indra/newview/llexternaleditor.cpp
index 193a42f9f6..c3aad4ee65 100644
--- a/indra/newview/llexternaleditor.cpp
+++ b/indra/newview/llexternaleditor.cpp
@@ -46,9 +46,13 @@ LLExternalEditor::EErrorCode LLExternalEditor::setCommand(const std::string& env
{
LL_INFOS() << "Editor command is empty or not set, falling back to OS open handler" << LL_ENDL;
#if LL_WINDOWS
- static const std::string os_cmd = "%SystemRoot%\\explorer.exe \"%s\"";
+ std::string os_cmd = LLStringUtil::getenv("SystemRoot", "");
+ if (!os_cmd.empty())
+ {
+ os_cmd.append("\\explorer.exe \"%s\"");
+ }
#elif LL_DARWIN
- static const std::string os_cmd = "/usr/bin/open \"%s\"";
+ static const std::string os_cmd = "/usr/bin/open -t \"%s\"";
#elif LL_LINUX
static const std::string os_cmd = "/usr/bin/xdg-open \"%s\"";
#endif
diff --git a/indra/newview/llfavoritesbar.cpp b/indra/newview/llfavoritesbar.cpp
index 377710c170..98b3ca820b 100644
--- a/indra/newview/llfavoritesbar.cpp
+++ b/indra/newview/llfavoritesbar.cpp
@@ -1395,6 +1395,19 @@ bool LLFavoritesBarCtrl::enableSelected(const LLSD& userdata)
{
return !LLAgentPicksInfo::getInstance()->isPickLimitReached();
}
+ else if (param == "copy_slurl"
+ || param == "show_on_map")
+ {
+ LLViewerInventoryItem* item = gInventory.getItem(mSelectedItemID);
+ if (nullptr == item)
+ return false; // shouldn't happen as it is selected from existing items
+
+ const LLUUID& asset_id = item->getAssetUUID();
+
+ // Favorites are supposed to be loaded first, it should be here already
+ LLLandmark* landmark = gLandmarkList.getAsset(asset_id, NULL /*callback*/);
+ return nullptr != landmark;
+ }
return false;
}
@@ -1425,10 +1438,17 @@ void LLFavoritesBarCtrl::doToSelected(const LLSD& userdata)
LLVector3d posGlobal;
LLLandmarkActions::getLandmarkGlobalPos(mSelectedItemID, posGlobal);
+ // inventory item and asset exist, otherwise
+ // enableSelected wouldn't have let it get here,
+ // only need to check location validity
if (!posGlobal.isExactlyZero())
{
LLLandmarkActions::getSLURLfromPosGlobal(posGlobal, copy_slurl_to_clipboard_cb);
}
+ else
+ {
+ LLNotificationsUtil::add("LandmarkLocationUnknown");
+ }
}
else if (action == "show_on_map")
{
@@ -1437,10 +1457,20 @@ void LLFavoritesBarCtrl::doToSelected(const LLSD& userdata)
LLVector3d posGlobal;
LLLandmarkActions::getLandmarkGlobalPos(mSelectedItemID, posGlobal);
- if (!posGlobal.isExactlyZero() && worldmap_instance)
+ if (worldmap_instance)
{
- worldmap_instance->trackLocation(posGlobal);
- LLFloaterReg::showInstance("world_map", "center");
+ // inventory item and asset exist, otherwise
+ // enableSelected wouldn't have let it get here,
+ // only need to check location validity
+ if (!posGlobal.isExactlyZero())
+ {
+ worldmap_instance->trackLocation(posGlobal);
+ LLFloaterReg::showInstance("world_map", "center");
+ }
+ else
+ {
+ LLNotificationsUtil::add("LandmarkLocationUnknown");
+ }
}
}
else if (action == "create_pick")
diff --git a/indra/newview/llfilepicker_mac.mm b/indra/newview/llfilepicker_mac.mm
index 6921cd6101..7262d18483 100644
--- a/indra/newview/llfilepicker_mac.mm
+++ b/indra/newview/llfilepicker_mac.mm
@@ -241,8 +241,13 @@ void doSaveDialogModeless(const std::string* file,
NSURL* url = [NSURL fileURLWithPath:fileName];
[panel setNameFieldStringValue: fileName];
- [panel setDirectoryURL: url];
+ NSURL *last_url = [[NSUserDefaults standardUserDefaults] URLForKey:@"NSNavLastRootDirectory"];
+ if(!last_url)
+ {
+ NSURL *documents_url = [[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask].firstObject;
+ [panel setDirectoryURL:documents_url];
+ }
[panel beginWithCompletionHandler:^(NSModalResponse result)
{
diff --git a/indra/newview/llfloatermarketplace.cpp b/indra/newview/llfloatermarketplace.cpp
index 2a67e75fec..bb2378d864 100644
--- a/indra/newview/llfloatermarketplace.cpp
+++ b/indra/newview/llfloatermarketplace.cpp
@@ -56,6 +56,7 @@ void LLFloaterMarketplace::onOpen(const LLSD& key)
else
{
openMarketplaceURL(params.url);
+ set_current_url(params.url); // Fix looping back to previous url when using the viewer navigation bar
}
}
diff --git a/indra/newview/llgltfmateriallist.cpp b/indra/newview/llgltfmateriallist.cpp
index ac8477a615..b784419780 100644
--- a/indra/newview/llgltfmateriallist.cpp
+++ b/indra/newview/llgltfmateriallist.cpp
@@ -170,7 +170,7 @@ namespace
void LLGLTFMaterialList::applyOverrideMessage(LLMessageSystem* msg, const std::string& data_in)
{
- std::istringstream str(data_in);
+ boost::iostreams::stream<boost::iostreams::array_source> str(data_in.data(), data_in.size());
LLSD data;
diff --git a/indra/newview/llinventorylistitem.cpp b/indra/newview/llinventorylistitem.cpp
index a435a4f7c7..aa6ba6d023 100644
--- a/indra/newview/llinventorylistitem.cpp
+++ b/indra/newview/llinventorylistitem.cpp
@@ -41,7 +41,7 @@
#include "llinventorymodel.h"
#include "llviewerinventory.h"
-static LLWidgetNameRegistry::StaticRegistrar sRegisterPanelInventoryListItemBaseParams(&typeid(LLPanelInventoryListItemBase::Params), "inventory_list_item");
+static LLWidgetNameRegistry::StaticRegistrar sRegisterPanelInventoryListItemBaseParams(typeid(LLPanelInventoryListItemBase::Params), "inventory_list_item");
constexpr S32 WIDGET_SPACING = 3;
constexpr S32 FAVORITE_IMAGE_SIZE = 14;
diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp
index 01ff01e233..870f0873b9 100644
--- a/indra/newview/llinventorymodel.cpp
+++ b/indra/newview/llinventorymodel.cpp
@@ -3425,6 +3425,7 @@ bool LLInventoryModel::loadFromFile(const std::string& filename,
LLSD inventory;
if (!is_cache_obsolete)
{
+ LL_PROFILE_ZONE_NAMED("inventory load from file - llsd parse");
LLPointer<LLSDParser> parser = new LLSDBinaryParser();
if (parser->parse(file, inventory, LLSDSerialize::SIZE_UNLIMITED) == LLSDParser::PARSE_FAILURE)
@@ -3436,56 +3437,61 @@ bool LLInventoryModel::loadFromFile(const std::string& filename,
if (!is_cache_obsolete)
{
- const LLSD& llsd_cats = inventory["categories"];
- if (llsd_cats.isArray())
{
- LLSD::array_const_iterator iter = llsd_cats.beginArray();
- LLSD::array_const_iterator end = llsd_cats.endArray();
- for (; iter != end; ++iter)
+ LL_PROFILE_ZONE_NAMED("inventory load from file - categories");
+ const LLSD& llsd_cats = inventory["categories"];
+ if (llsd_cats.isArray())
{
- LLPointer<LLViewerInventoryCategory> inv_cat = new LLViewerInventoryCategory(LLUUID::null);
- if (inv_cat->importLLSDMap(*iter))
+ LLSD::array_const_iterator iter = llsd_cats.beginArray();
+ LLSD::array_const_iterator end = llsd_cats.endArray();
+ for (; iter != end; ++iter)
{
- categories.push_back(inv_cat);
+ LLPointer<LLViewerInventoryCategory> inv_cat = new LLViewerInventoryCategory(LLUUID::null);
+ if (inv_cat->importLLSDMap(*iter))
+ {
+ categories.push_back(inv_cat);
+ }
}
}
}
- const LLSD& llsd_items = inventory["items"];
- if (llsd_items.isArray())
{
- LLSD::array_const_iterator iter = llsd_items.beginArray();
- LLSD::array_const_iterator end = llsd_items.endArray();
- for (; iter != end; ++iter)
+ LL_PROFILE_ZONE_NAMED("inventory load from file - items");
+ const LLSD& llsd_items = inventory["items"];
+ if (llsd_items.isArray())
{
- LLPointer<LLViewerInventoryItem> inv_item = new LLViewerInventoryItem;
- if (inv_item->fromLLSD(*iter))
+ LLSD::array_const_iterator iter = llsd_items.beginArray();
+ LLSD::array_const_iterator end = llsd_items.endArray();
+ for (; iter != end; ++iter)
{
- if (inv_item->getUUID().isNull())
+ LLPointer<LLViewerInventoryItem> inv_item = new LLViewerInventoryItem;
+ if (inv_item->fromLLSD(*iter))
{
- LL_DEBUGS(LOG_INV) << "Ignoring inventory with null item id: "
- << inv_item->getName() << LL_ENDL;
- }
- else
- {
- if (inv_item->getType() == LLAssetType::AT_UNKNOWN)
+ if (inv_item->getUUID().isNull())
{
- cats_to_update.insert(inv_item->getParentUUID());
+ LL_DEBUGS(LOG_INV) << "Ignoring inventory with null item id: " << inv_item->getName() << LL_ENDL;
}
else
{
- items.push_back(inv_item);
+ if (inv_item->getType() == LLAssetType::AT_UNKNOWN)
+ {
+ cats_to_update.insert(inv_item->getParentUUID());
+ }
+ else
+ {
+ items.push_back(inv_item);
+ }
}
}
- }
- // TODO(brad) - figure out how to reenable this without breaking everything else
- // static constexpr U64 BATCH_SIZE = 512U;
- // if ((++lines_count % BATCH_SIZE) == 0)
- // {
- // // SL-19968 - make sure message system code gets a chance to run every so often
- // pump_idle_startup_network();
- // }
+ // TODO(brad) - figure out how to reenable this without breaking everything else
+ // static constexpr U64 BATCH_SIZE = 512U;
+ // if ((++lines_count % BATCH_SIZE) == 0)
+ // {
+ // // SL-19968 - make sure message system code gets a chance to run every so often
+ // pump_idle_startup_network();
+ // }
+ }
}
}
}
diff --git a/indra/newview/llinventorymodel.h b/indra/newview/llinventorymodel.h
index 9fbabec8f3..05ada9121a 100644
--- a/indra/newview/llinventorymodel.h
+++ b/indra/newview/llinventorymodel.h
@@ -201,13 +201,13 @@ private:
// the inventory using several different identifiers.
// mInventory member data is the 'master' list of inventory, and
// mCategoryMap and mItemMap store uuid->object mappings.
- typedef std::map<LLUUID, LLPointer<LLViewerInventoryCategory> > cat_map_t;
- typedef std::map<LLUUID, LLPointer<LLViewerInventoryItem> > item_map_t;
+ typedef std::unordered_map<LLUUID, LLPointer<LLViewerInventoryCategory> > cat_map_t;
+ typedef std::unordered_map<LLUUID, LLPointer<LLViewerInventoryItem>> item_map_t;
cat_map_t mCategoryMap;
item_map_t mItemMap;
// This last set of indices is used to map parents to children.
- typedef std::map<LLUUID, cat_array_t*> parent_cat_map_t;
- typedef std::map<LLUUID, item_array_t*> parent_item_map_t;
+ typedef std::unordered_map<LLUUID, cat_array_t*> parent_cat_map_t;
+ typedef std::unordered_map<LLUUID, item_array_t*> parent_item_map_t;
parent_cat_map_t mParentChildCategoryTree;
parent_item_map_t mParentChildItemTree;
diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp
index 8d57a4e7bb..06dd830416 100644
--- a/indra/newview/llinventorypanel.cpp
+++ b/indra/newview/llinventorypanel.cpp
@@ -2125,8 +2125,7 @@ LLFolderViewItem* LLInventoryPanel::getItemByID(const LLUUID& id)
{
LL_PROFILE_ZONE_SCOPED;
- std::map<LLUUID, LLFolderViewItem*>::iterator map_it;
- map_it = mItemMap.find(id);
+ auto map_it = mItemMap.find(id);
if (map_it != mItemMap.end())
{
return map_it->second;
diff --git a/indra/newview/llinventorypanel.h b/indra/newview/llinventorypanel.h
index dc2e304ab3..ca2d5814bc 100644
--- a/indra/newview/llinventorypanel.h
+++ b/indra/newview/llinventorypanel.h
@@ -300,7 +300,7 @@ protected:
LLPointer<LLFolderViewGroupedItemBridge> mGroupedItemBridge;
Params mParams; // stored copy of parameter block
- std::map<LLUUID, LLFolderViewItem*> mItemMap;
+ std::unordered_map<LLUUID, LLFolderViewItem*> mItemMap;
/**
* Pointer to LLInventoryFolderViewModelBuilder.
*
diff --git a/indra/newview/lllandmarklist.cpp b/indra/newview/lllandmarklist.cpp
index 3fa0ab99f3..b25a42a938 100644
--- a/indra/newview/lllandmarklist.cpp
+++ b/indra/newview/lllandmarklist.cpp
@@ -147,29 +147,66 @@ void LLLandmarkList::processGetAssetReply(
else
{
// failed to parse, shouldn't happen
+ LL_WARNS("Landmarks") << "Failed to parse landmark " << uuid << LL_ENDL;
gLandmarkList.eraseCallbacks(uuid);
}
}
else
{
// got a good status, but no file, shouldn't happen
+ LL_WARNS("Landmarks") << "Empty buffer for landmark " << uuid << LL_ENDL;
gLandmarkList.eraseCallbacks(uuid);
}
+
+ // We got this asset, remove it from retry and bad lists.
+ gLandmarkList.mRetryList.erase(uuid);
+ gLandmarkList.mBadList.erase(uuid);
}
else
{
- // SJB: No use case for a notification here. Use LL_DEBUGS() instead
- if( LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE == status )
+ if (LL_ERR_NO_CAP == status)
+ {
+ // A problem with asset cap, always allow retrying.
+ // Todo: should this reschedule?
+ gLandmarkList.mRequestedList.erase(uuid);
+ gLandmarkList.eraseCallbacks(uuid);
+ // If there was a previous request, it likely failed due to an obsolete cap
+ // so clear the retry marker to allow multiple retries.
+ gLandmarkList.mRetryList.erase(uuid);
+ return;
+ }
+ if (gLandmarkList.mBadList.find(uuid) != gLandmarkList.mBadList.end())
+ {
+ // Already on the 'bad' list, ignore
+ gLandmarkList.mRequestedList.erase(uuid);
+ gLandmarkList.eraseCallbacks(uuid);
+ return;
+ }
+ if (LL_ERR_ASSET_REQUEST_FAILED == status
+ && gLandmarkList.mRetryList.find(uuid) == gLandmarkList.mRetryList.end())
+ {
+ // There is a number of reasons why an asset request can fail,
+ // like a cap being obsolete due to user teleporting.
+ // Let viewer rerequest at least once more.
+ // Todo: should this reshchedule?
+ gLandmarkList.mRetryList.emplace(uuid);
+ gLandmarkList.mRequestedList.erase(uuid);
+ gLandmarkList.eraseCallbacks(uuid);
+ return;
+ }
+
+ if (LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE == status)
{
- LL_WARNS("Landmarks") << "Missing Landmark" << LL_ENDL;
- //LLNotificationsUtil::add("LandmarkMissing");
+ LL_WARNS("Landmarks") << "Missing Landmark " << uuid << LL_ENDL;
}
else
{
- LL_WARNS("Landmarks") << "Unable to load Landmark" << LL_ENDL;
- //LLNotificationsUtil::add("UnableToLoadLandmark");
+ LL_WARNS("Landmarks") << "Unable to load Landmark " << uuid
+ << ". asset status: " << status
+ << ". Extended status: " << (S64)ext_status << LL_ENDL;
}
+ gLandmarkList.mRetryList.erase(uuid);
gLandmarkList.mBadList.insert(uuid);
gLandmarkList.mRequestedList.erase(uuid); //mBadList effectively blocks any load, so no point keeping id in requests
gLandmarkList.eraseCallbacks(uuid);
diff --git a/indra/newview/lllandmarklist.h b/indra/newview/lllandmarklist.h
index fb8b5a1960..76b5b97211 100644
--- a/indra/newview/lllandmarklist.h
+++ b/indra/newview/lllandmarklist.h
@@ -72,6 +72,7 @@ protected:
typedef std::set<LLUUID> landmark_uuid_list_t;
landmark_uuid_list_t mBadList;
+ landmark_uuid_list_t mRetryList;
typedef std::map<LLUUID,F32> landmark_requested_list_t;
landmark_requested_list_t mRequestedList;
diff --git a/indra/newview/llmachineid.cpp b/indra/newview/llmachineid.cpp
index 51c38aba3a..0a90cf0699 100644
--- a/indra/newview/llmachineid.cpp
+++ b/indra/newview/llmachineid.cpp
@@ -398,6 +398,8 @@ bool getSerialNumber(unsigned char *unique_id, size_t len)
S32 LLMachineID::init()
{
+ LL_PROFILE_ZONE_SCOPED;
+
size_t len = sizeof(static_unique_id);
memset(static_unique_id, 0, len);
S32 ret_code = 0;
diff --git a/indra/newview/llmaterialmgr.h b/indra/newview/llmaterialmgr.h
index ac4c18d60c..5fc0b1b290 100644
--- a/indra/newview/llmaterialmgr.h
+++ b/indra/newview/llmaterialmgr.h
@@ -33,9 +33,42 @@
#include "httprequest.h"
#include "httpheaders.h"
#include "httpoptions.h"
+#include <boost/container_hash/hash.hpp>
class LLViewerRegion;
+// struct for TE-specific material ID query
+class TEMaterialPair
+{
+public:
+ U32 te;
+ LLMaterialID materialID;
+
+ bool operator==(const TEMaterialPair& b) const { return (materialID == b.materialID) && (te == b.te); }
+};
+
+inline bool operator<(const TEMaterialPair& lhs, const TEMaterialPair& rhs)
+{
+ return (lhs.te < rhs.te) ? true : (lhs.materialID < rhs.materialID);
+}
+
+// std::hash implementation for TEMaterialPair
+namespace std
+{
+ template<>
+ struct hash<TEMaterialPair>
+ {
+ inline size_t operator()(const TEMaterialPair& p) const noexcept
+ {
+ // Utilize boost::hash_combine to generate a good hash
+ size_t seed = 0;
+ boost::hash_combine(seed, p.te + 1);
+ boost::hash_combine(seed, p.materialID);
+ return seed;
+ }
+ };
+} // namespace std
+
class LLMaterialMgr : public LLSingleton<LLMaterialMgr>
{
LLSINGLETON(LLMaterialMgr);
@@ -83,29 +116,6 @@ private:
void onRegionRemoved(LLViewerRegion* regionp);
private:
- // struct for TE-specific material ID query
- class TEMaterialPair
- {
- public:
-
- U32 te;
- LLMaterialID materialID;
-
- bool operator==(const TEMaterialPair& b) const { return (materialID == b.materialID) && (te == b.te); }
- };
-
- // definitions follow class
- friend std::hash<TEMaterialPair>;
- friend size_t hash_value(const TEMaterialPair&) noexcept;
-
- friend inline bool operator<(
- const LLMaterialMgr::TEMaterialPair& lhs,
- const LLMaterialMgr::TEMaterialPair& rhs)
- {
- return (lhs.te < rhs.te) ? true :
- (lhs.materialID < rhs.materialID);
- }
-
typedef std::set<LLMaterialID> material_queue_t;
typedef std::map<LLUUID, material_queue_t> get_queue_t;
typedef std::pair<const LLUUID, LLMaterialID> pending_material_t;
@@ -113,7 +123,7 @@ private:
typedef std::map<LLMaterialID, std::unique_ptr<get_callback_t>> get_callback_map_t;
- typedef boost::unordered_map<TEMaterialPair, std::unique_ptr<get_callback_te_t>> get_callback_te_map_t;
+ typedef std::unordered_map<TEMaterialPair, std::unique_ptr<get_callback_te_t>> get_callback_te_map_t;
typedef std::set<LLUUID> getall_queue_t;
typedef std::map<LLUUID, F64> getall_pending_map_t;
typedef std::map<LLUUID, std::unique_ptr<getall_callback_t>> getall_callback_map_t;
@@ -142,23 +152,5 @@ private:
U32 getMaxEntries(const LLViewerRegion* regionp);
};
-// std::hash implementation for TEMaterialPair
-namespace std
-{
- template<> struct hash<LLMaterialMgr::TEMaterialPair>
- {
- inline size_t operator()(const LLMaterialMgr::TEMaterialPair& p) const noexcept
- {
- return size_t((p.te + 1) * p.materialID.getDigest64());
- }
- };
-}
-
-// For use with boost containers.
-inline size_t hash_value(const LLMaterialMgr::TEMaterialPair& p) noexcept
-{
- return size_t((p.te + 1) * p.materialID.getDigest64());
-}
-
#endif // LL_LLMATERIALMGR_H
diff --git a/indra/newview/llmeshrepository.h b/indra/newview/llmeshrepository.h
index 56ad8297c7..061b4b5428 100644
--- a/indra/newview/llmeshrepository.h
+++ b/indra/newview/llmeshrepository.h
@@ -442,7 +442,7 @@ public:
LLCondition* mSignal;
//map of known mesh headers
- typedef boost::unordered_map<LLUUID, LLMeshHeader> mesh_header_map; // pair is header_size and data
+ typedef std::unordered_map<LLUUID, LLMeshHeader> mesh_header_map; // pair is header_size and data
mesh_header_map mMeshHeader;
class HeaderRequest : public RequestStats
diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp
index ed5ab35439..bc9ca46672 100644
--- a/indra/newview/llmodelpreview.cpp
+++ b/indra/newview/llmodelpreview.cpp
@@ -3461,7 +3461,7 @@ bool LLModelPreview::render()
LLViewerCamera::getInstance()->setAspect(aspect);
- LLViewerCamera::getInstance()->setView(LLViewerCamera::getInstance()->getDefaultFOV() / mCameraZoom);
+ LLViewerCamera::getInstance()->setViewNoBroadcast(LLViewerCamera::getInstance()->getDefaultFOV() / mCameraZoom);
LLVector3 offset = mCameraOffset;
LLVector3 target_pos = mPreviewTarget + offset;
diff --git a/indra/newview/llmutelist.cpp b/indra/newview/llmutelist.cpp
index 35d36affa2..9035baafcd 100644
--- a/indra/newview/llmutelist.cpp
+++ b/indra/newview/llmutelist.cpp
@@ -582,6 +582,8 @@ std::vector<LLMute> LLMuteList::getMutes() const
//-----------------------------------------------------------------------------
bool LLMuteList::loadFromFile(const std::string& filename)
{
+ LL_PROFILE_ZONE_SCOPED;
+
if(!filename.size())
{
LL_WARNS() << "Mute List Filename is Empty!" << LL_ENDL;
@@ -962,6 +964,8 @@ bool LLRenderMuteList::saveToFile()
bool LLRenderMuteList::loadFromFile()
{
+ LL_PROFILE_ZONE_SCOPED;
+
std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, "render_mute_settings.txt");
LLFILE* fp = LLFile::fopen(filename, LLFILE_MODE("rb"));
if (!fp)
diff --git a/indra/newview/lloutfitgallery.cpp b/indra/newview/lloutfitgallery.cpp
index 8a070babcd..9b21a217db 100644
--- a/indra/newview/lloutfitgallery.cpp
+++ b/indra/newview/lloutfitgallery.cpp
@@ -850,7 +850,12 @@ void LLOutfitGallery::updateAddedCategory(LLUUID cat_id)
// Start observing changes in "My Outfits" category.
mCategoriesObserver->addCategory(cat_id,
- boost::bind(&LLOutfitGallery::refreshOutfit, this, cat_id), true);
+ [this, cat_id]()
+ {
+ mPendingOutfitRefreshes.insert(cat_id);
+ startIdleLoop(cat_id);
+ },
+ true);
outfit_category->fetch();
refreshOutfit(cat_id);
@@ -901,6 +906,18 @@ void LLOutfitGallery::updateChangedCategoryName(LLViewerInventoryCategory *cat,
}
}
+bool LLOutfitGallery::updateOneOutfit()
+{
+ if (mPendingOutfitRefreshes.empty())
+ return false;
+
+ auto it = mPendingOutfitRefreshes.begin();
+ LLUUID outfit_id = *it;
+ mPendingOutfitRefreshes.erase(it);
+ refreshOutfit(outfit_id);
+ return true;
+}
+
void LLOutfitGallery::onOutfitRightClick(LLUICtrl* ctrl, S32 x, S32 y, const LLUUID& cat_id)
{
if (mOutfitMenu && cat_id.notNull())
diff --git a/indra/newview/lloutfitgallery.h b/indra/newview/lloutfitgallery.h
index 5801a32a39..183b6ea9d5 100644
--- a/indra/newview/lloutfitgallery.h
+++ b/indra/newview/lloutfitgallery.h
@@ -98,6 +98,7 @@ public:
/*virtual*/ void updateAddedCategory(LLUUID cat_id);
/*virtual*/ void updateRemovedCategory(LLUUID cat_id);
/*virtual*/ void updateChangedCategoryName(LLViewerInventoryCategory *cat, std::string name);
+ /*virtual*/ bool updateOneOutfit(); // bulk processing, scheduled by observer when updates are needed
/*virtual*/ bool hasItemSelected();
/*virtual*/ bool canWearSelected();
@@ -190,6 +191,7 @@ private:
typedef item_num_map_t::value_type item_numb_map_value_t;
item_num_map_t mItemIndexMap;
std::map<S32, LLOutfitGalleryItem*> mIndexToItemMap;
+ std::set<LLUUID> mPendingOutfitRefreshes;
LLInventoryCategoriesObserver* mOutfitsObserver;
diff --git a/indra/newview/lloutfitslist.cpp b/indra/newview/lloutfitslist.cpp
index 32831fcd9b..7db79c7010 100644
--- a/indra/newview/lloutfitslist.cpp
+++ b/indra/newview/lloutfitslist.cpp
@@ -1055,6 +1055,15 @@ void LLOutfitListBase::refreshList(const LLUUID& category_id)
}
}
+void LLOutfitListBase::startIdleLoop(const LLUUID cat_id)
+{
+ if (mRefreshListState.CategoryUUID.isNull())
+ {
+ mRefreshListState.CategoryUUID = cat_id;
+ gIdleCallbacks.addFunction(onIdle, this);
+ }
+}
+
// static
void LLOutfitListBase::onIdle(void* userdata)
{
@@ -1129,6 +1138,14 @@ void LLOutfitListBase::onIdleRefreshList()
return;
}
+ // Let derived classes process their own updates.
+ while (updateOneOutfit())
+ {
+ curent_time = LLTimer::getTotalSeconds();
+ if (curent_time >= end_time)
+ return;
+ }
+
sortOutfits();
highlightBaseOutfit();
diff --git a/indra/newview/lloutfitslist.h b/indra/newview/lloutfitslist.h
index bcf7e45696..408ff07116 100644
--- a/indra/newview/lloutfitslist.h
+++ b/indra/newview/lloutfitslist.h
@@ -95,6 +95,17 @@ public:
virtual void updateAddedCategory(LLUUID cat_id) = 0;
virtual void updateRemovedCategory(LLUUID cat_id) = 0;
virtual void updateChangedCategoryName(LLViewerInventoryCategory *cat, std::string name) = 0;
+
+ /*
+ * Optional hook for derived classes to perform additional processing.
+ * This is called by the outfit list update logic after the core
+ * bookkeeping for an outfit has been handled.
+ *
+ * @return true if update processing should continue,
+ * false if no additional work is required.
+ * The base implementation returns false.
+ */
+ virtual bool updateOneOutfit() { return false; };
virtual void sortOutfits();
void removeSelected();
@@ -138,6 +149,7 @@ protected:
bool isOutfitFolder(LLViewerInventoryCategory* cat) const;
+ void startIdleLoop(const LLUUID cat_id);
static void onIdle(void* userdata);
void onIdleRefreshList();
@@ -150,6 +162,7 @@ protected:
uuid_vec_t::const_iterator RemovedIterator;
} mRefreshListState;
std::set<LLUUID> mChangedItems;
+ std::set<LLUUID> mPendingOutfitRefreshes;
bool mIsInitialized;
LLInventoryCategoriesObserver* mCategoriesObserver;
diff --git a/indra/newview/llpanelface.cpp b/indra/newview/llpanelface.cpp
index de8ab95dee..bcb51b22ca 100644
--- a/indra/newview/llpanelface.cpp
+++ b/indra/newview/llpanelface.cpp
@@ -1201,7 +1201,7 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)
// See if that's been overridden by a material setting for same...
//
- LLSelectedTEMaterial::getCurrentDiffuseAlphaMode(alpha_mode, identical_alpha_mode, mIsAlpha);
+ LLSelectedTEMaterial::getCurrentDiffuseAlphaMode(alpha_mode, identical_alpha_mode);
// it is invalid to have any alpha mode other than blend if transparency is greater than zero ...
// Want masking? Want emissive? Tough! You get BLEND!
@@ -1211,6 +1211,12 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)
alpha_mode = mIsAlpha ? alpha_mode : LLMaterial::DIFFUSE_ALPHA_MODE_NONE;
mComboAlphaMode->getSelectionInterface()->selectNthItem(alpha_mode);
+ mComboAlphaMode->setTentative(!identical_alpha_mode);
+ if (!identical_alpha_mode)
+ {
+ std::string multiple = LLTrans::getString("multiple_textures");
+ mComboAlphaMode->setLabel(multiple);
+ }
updateAlphaControls();
mExcludeWater &= (LLMaterial::DIFFUSE_ALPHA_MODE_BLEND == alpha_mode);
@@ -5484,32 +5490,40 @@ void LLPanelFace::LLSelectedTEMaterial::getMaxNormalRepeats(F32& repeats, bool&
identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &max_norm_repeats_func, repeats);
}
-void LLPanelFace::LLSelectedTEMaterial::getCurrentDiffuseAlphaMode(U8& diffuse_alpha_mode, bool& identical, bool diffuse_texture_has_alpha)
+void LLPanelFace::LLSelectedTEMaterial::getCurrentDiffuseAlphaMode(U8& diffuse_alpha_mode, bool& identical)
{
struct LLSelectedTEGetDiffuseAlphaMode : public LLSelectedTEGetFunctor<U8>
{
- LLSelectedTEGetDiffuseAlphaMode() : _isAlpha(false) {}
- LLSelectedTEGetDiffuseAlphaMode(bool diffuse_texture_has_alpha) : _isAlpha(diffuse_texture_has_alpha) {}
+ LLSelectedTEGetDiffuseAlphaMode() {}
virtual ~LLSelectedTEGetDiffuseAlphaMode() {}
U8 get(LLViewerObject* object, S32 face)
{
- U8 diffuse_mode = _isAlpha ? LLMaterial::DIFFUSE_ALPHA_MODE_BLEND : LLMaterial::DIFFUSE_ALPHA_MODE_NONE;
-
LLTextureEntry* tep = object->getTE(face);
if (tep)
{
LLMaterial* mat = tep->getMaterialParams().get();
if (mat)
{
- diffuse_mode = mat->getDiffuseAlphaMode();
+ return mat->getDiffuseAlphaMode();
+ }
+ }
+
+ bool has_alpha = false;
+ LLViewerTexture* image = object->getTEImage(face);
+ if (image)
+ {
+ LLGLenum format = image->getPrimaryFormat();
+ if (format == GL_RGBA || format == GL_ALPHA)
+ {
+ has_alpha = true;
}
}
+ U8 diffuse_mode = has_alpha ? LLMaterial::DIFFUSE_ALPHA_MODE_BLEND : LLMaterial::DIFFUSE_ALPHA_MODE_NONE;
return diffuse_mode;
}
- bool _isAlpha; // whether or not the diffuse texture selected contains alpha information
- } get_diff_mode(diffuse_texture_has_alpha);
+ } get_diff_mode;
identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &get_diff_mode, diffuse_alpha_mode);
}
diff --git a/indra/newview/llpanelface.h b/indra/newview/llpanelface.h
index 63fee6bab8..82790ac54b 100644
--- a/indra/newview/llpanelface.h
+++ b/indra/newview/llpanelface.h
@@ -652,7 +652,7 @@ public:
static void getCurrent(LLMaterialPtr& material_ptr, bool& identical_material);
static void getMaxSpecularRepeats(F32& repeats, bool& identical);
static void getMaxNormalRepeats(F32& repeats, bool& identical);
- static void getCurrentDiffuseAlphaMode(U8& diffuse_alpha_mode, bool& identical, bool diffuse_texture_has_alpha);
+ static void getCurrentDiffuseAlphaMode(U8& diffuse_alpha_mode, bool& identical);
static void selectionNormalScaleAutofit(LLPanelFace* panel_face, F32 repeats_per_meter);
static void selectionSpecularScaleAutofit(LLPanelFace* panel_face, F32 repeats_per_meter);
diff --git a/indra/newview/llpanellogin.cpp b/indra/newview/llpanellogin.cpp
index 00b592d86e..868e02f28b 100644
--- a/indra/newview/llpanellogin.cpp
+++ b/indra/newview/llpanellogin.cpp
@@ -220,6 +220,11 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect,
// STEAM-14: When user presses Enter with this field in focus, initiate login
password_edit->setCommitCallback(boost::bind(&LLPanelLogin::onClickConnect, false));
+ childSetAction("connect_btn", onClickConnect, this);
+
+ mLoginBtn = getChild<LLButton>("connect_btn");
+ setDefaultBtn(mLoginBtn);
+
// change z sort of clickable text to be behind buttons
sendChildToBack(getChildView("forgot_password_text"));
sendChildToBack(getChildView("sign_up_text"));
@@ -296,11 +301,6 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect,
onUpdateStartSLURL(start_slurl); // updates grid if needed
}
- childSetAction("connect_btn", onClickConnect, this);
-
- mLoginBtn = getChild<LLButton>("connect_btn");
- setDefaultBtn(mLoginBtn);
-
std::string channel = LLVersionInfo::instance().getChannel();
std::string version = stringize(LLVersionInfo::instance().getShortVersion(), " (",
LLVersionInfo::instance().getBuild(), ')');
diff --git a/indra/newview/llpanelobjectinventory.cpp b/indra/newview/llpanelobjectinventory.cpp
index a31a54bb67..d27ce81e4f 100644
--- a/indra/newview/llpanelobjectinventory.cpp
+++ b/indra/newview/llpanelobjectinventory.cpp
@@ -1830,7 +1830,7 @@ void LLPanelObjectInventory::onFocusReceived()
LLFolderViewItem* LLPanelObjectInventory::getItemByID( const LLUUID& id )
{
- std::map<LLUUID, LLFolderViewItem*>::iterator map_it = mItemMap.find(id);
+ auto map_it = mItemMap.find(id);
if (map_it != mItemMap.end())
{
return map_it->second;
diff --git a/indra/newview/llpanelobjectinventory.h b/indra/newview/llpanelobjectinventory.h
index 154639e4bb..13e27b489c 100644
--- a/indra/newview/llpanelobjectinventory.h
+++ b/indra/newview/llpanelobjectinventory.h
@@ -109,7 +109,7 @@ protected:
bool isSelectionRemovable();
private:
- std::map<LLUUID, LLFolderViewItem*> mItemMap;
+ std::unordered_map<LLUUID, LLFolderViewItem*> mItemMap;
LLScrollContainer* mScroller;
LLFolderView* mFolders;
diff --git a/indra/newview/llpanelplaceprofile.cpp b/indra/newview/llpanelplaceprofile.cpp
index 87f05f2028..c380b6860f 100644
--- a/indra/newview/llpanelplaceprofile.cpp
+++ b/indra/newview/llpanelplaceprofile.cpp
@@ -517,7 +517,7 @@ void LLPanelPlaceProfile::displaySelectedParcelInfo(LLParcel* parcel,
std::string parcel_owner =
LLSLURL("agent", parcel->getOwnerID(), "inspect").getSLURLString();
mParcelOwner->setText(parcel_owner);
- LLAvatarNameCache::get(region->getOwner(), boost::bind(&LLPanelPlaceInfo::onAvatarNameCache, _1, _2, mRegionOwnerText));
+ mAvatarNameCacheConnection = LLAvatarNameCache::get(region->getOwner(), boost::bind(&LLPanelPlaceInfo::onAvatarNameCache, _1, _2, mRegionOwnerText));
mRegionGroupText->setText( getString("none_text"));
}
@@ -548,7 +548,7 @@ void LLPanelPlaceProfile::displaySelectedParcelInfo(LLParcel* parcel,
const LLUUID& auth_buyer_id = parcel->getAuthorizedBuyerID();
if(auth_buyer_id.notNull())
{
- LLAvatarNameCache::get(auth_buyer_id, boost::bind(&LLPanelPlaceInfo::onAvatarNameCache, _1, _2, mSaleToText));
+ mAvatarNameCacheConnection = LLAvatarNameCache::get(auth_buyer_id, boost::bind(&LLPanelPlaceInfo::onAvatarNameCache, _1, _2, mSaleToText));
// Show sales info to a specific person or a group he belongs to.
if (auth_buyer_id != gAgent.getID() && !gAgent.isInGroup(auth_buyer_id))
diff --git a/indra/newview/llpanelplaceprofile.h b/indra/newview/llpanelplaceprofile.h
index f562be0f5d..0c161198f8 100644
--- a/indra/newview/llpanelplaceprofile.h
+++ b/indra/newview/llpanelplaceprofile.h
@@ -118,6 +118,8 @@ private:
LLTextEditor* mResaleText;
LLTextBox* mSaleToText;
LLAccordionCtrl* mAccordionCtrl;
+
+ boost::signals2::scoped_connection mAvatarNameCacheConnection;
};
#endif // LL_LLPANELPLACEPROFILE_H
diff --git a/indra/newview/llpanelsnapshotinventory.cpp b/indra/newview/llpanelsnapshotinventory.cpp
index b81b891685..7396f079b0 100644
--- a/indra/newview/llpanelsnapshotinventory.cpp
+++ b/indra/newview/llpanelsnapshotinventory.cpp
@@ -110,7 +110,11 @@ void LLPanelSnapshotInventory::updateControls(const LLSD& info)
void LLPanelSnapshotInventory::onResolutionCommit(LLUICtrl* ctrl)
{
- bool current_window_selected = (getChild<LLComboBox>(getImageSizeComboName())->getCurrentIndex() == 3);
+ LLComboBox* combo = getChild<LLComboBox>(getImageSizeComboName());
+ // Current window likely won't ever change position from being the penultimate item
+ // Custom window is last item
+ S32 curent_window_index = combo->getItemCount() - 2;
+ bool current_window_selected = (combo->getCurrentIndex() == curent_window_index);
getChild<LLSpinCtrl>(getWidthSpinnerName())->setVisible(!current_window_selected);
getChild<LLSpinCtrl>(getHeightSpinnerName())->setVisible(!current_window_selected);
}
diff --git a/indra/newview/llperfstats.h b/indra/newview/llperfstats.h
index 1a2098ec7e..38deb87237 100644
--- a/indra/newview/llperfstats.h
+++ b/indra/newview/llperfstats.h
@@ -223,7 +223,7 @@ namespace LLPerfStats
static void updateMeanFrameTime(U64 tot_frame_time_raw);
// StatsArray is a uint64_t for each possible statistic type.
using StatsArray = std::array<uint64_t, static_cast<size_t>(LLPerfStats::StatType_t::STATS_COUNT)>;
- using StatsMap = std::unordered_map<LLUUID, StatsArray, boost::hash<LLUUID>>;
+ using StatsMap = std::unordered_map<LLUUID, StatsArray>;
using StatsTypeMatrix = std::array<StatsMap, static_cast<size_t>(LLPerfStats::ObjType_t::OT_COUNT)>;
using StatsSummaryArray = std::array<StatsArray, static_cast<size_t>(LLPerfStats::ObjType_t::OT_COUNT)>;
diff --git a/indra/newview/llscriptruntimeperms.h b/indra/newview/llscriptruntimeperms.h
index 300304c21b..6350b61d08 100644
--- a/indra/newview/llscriptruntimeperms.h
+++ b/indra/newview/llscriptruntimeperms.h
@@ -24,10 +24,7 @@
* $/LicenseInfo$
*/
-#ifndef LL_LLSCRIPTRUNTIME_PERMS_H
-#define LL_LLSCRIPTRUNTIME_PERMS_H
-
-#include <boost/array.hpp>
+#pragma once
typedef struct _script_perm {
std::string question;
@@ -37,12 +34,12 @@ typedef struct _script_perm {
question(q), permbit(b), caution(c) {}
} script_perm_t;
-const U32 NUM_SCRIPT_PERMISSIONS = 18;
+const U32 NUM_SCRIPT_PERMISSIONS = 19;
const S32 SCRIPT_PERMISSION_DEBIT = 0;
const S32 SCRIPT_PERMISSION_TRIGGER_ANIMATION = 3;
const S32 SCRIPT_PERMISSION_OVERRIDE_ANIMATIONS = 14;
-static const boost::array<script_perm_t, NUM_SCRIPT_PERMISSIONS> SCRIPT_PERMISSIONS = {{
+static const std::array<script_perm_t, NUM_SCRIPT_PERMISSIONS> SCRIPT_PERMISSIONS = {{
_script_perm("ScriptTakeMoney", (0x1 << 1), true),
_script_perm("ActOnControlInputs", (0x1 << 2), false),
_script_perm("RemapControlInputs", (0x1 << 3), false),
@@ -60,7 +57,7 @@ static const boost::array<script_perm_t, NUM_SCRIPT_PERMISSIONS> SCRIPT_PERMISSI
_script_perm("OverrideYourAnimations", (0x1 << 15), false),
_script_perm("ScriptReturnObjects", (0x1 << 16), false),
_script_perm("ForceSitAvatar", (0x1 << 17), false),
- _script_perm("ChangeEnvSettings", (0x1 << 18), false)
+ _script_perm("ChangeEnvSettings", (0x1 << 18), false),
+ _script_perm("PrivilegedLandAccess",(0x1 << 19), true)
} };
-#endif // LL_LLSCRIPTRUNTIME_PERMS_H
diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp
index a624682e11..7cf626f632 100644
--- a/indra/newview/llselectmgr.cpp
+++ b/indra/newview/llselectmgr.cpp
@@ -6193,6 +6193,15 @@ void LLSelectMgr::processObjectPropertiesFamily(LLMessageSystem* msg, void** use
node->mCategory = category;
node->mName.assign(name);
node->mDescription.assign(desc);
+
+ LLViewerObject* obj = node->getObject();
+ if (obj && LLViewerObject::isObjectInPendingUpdate(owner_id, obj))
+ {
+ // current response doesn't return modify permissions flags,
+ // so we should request it separately if needed
+ obj->requestObjectUpdate();
+ }
+
}
dialog_refresh_all();
diff --git a/indra/newview/lltexturecache.cpp b/indra/newview/lltexturecache.cpp
index b0b929a3ef..00b6bc09e9 100644
--- a/indra/newview/lltexturecache.cpp
+++ b/indra/newview/lltexturecache.cpp
@@ -986,6 +986,8 @@ void LLTextureCache::setReadOnly(bool read_only)
// Returns the unused amount of max_size if any
S64 LLTextureCache::initCache(ELLPath location, S64 max_size, bool texture_cache_mismatch)
{
+ LL_PROFILE_ZONE_SCOPED;
+
llassert_always(getPending() == 0) ; //should not start accessing the texture cache before initialized.
S64 entries_size = (max_size * 36) / 100; //0.36 * max_size
diff --git a/indra/newview/lltoastscriptquestion.cpp b/indra/newview/lltoastscriptquestion.cpp
index 25dc0982b8..55e178e084 100644
--- a/indra/newview/lltoastscriptquestion.cpp
+++ b/indra/newview/lltoastscriptquestion.cpp
@@ -48,7 +48,12 @@ bool LLToastScriptQuestion::postBuild()
LLTextBox* mFooter = getChild<LLTextBox>("bottom_info_message");
mMessage->setValue(mNotification->getMessage());
- mFooter->setValue(mNotification->getFooter());
+ std::string footer = mNotification->getFooter();
+ mFooter->setValue(footer);
+ if (footer.empty())
+ {
+ mFooter->setVisible(false);
+ }
snapToMessageHeight();
@@ -78,21 +83,69 @@ void LLToastScriptQuestion::snapToMessageHeight()
if (mMessage->getVisible() && mFooter->getVisible())
{
- S32 heightDelta = 0;
- S32 maxTextHeight = (mMessage->getFont()->getLineHeight() * MAX_LINES_COUNT)
+ S32 height_delta = 0;
+ S32 max_text_height = (mMessage->getFont()->getLineHeight() * MAX_LINES_COUNT)
+ (mFooter->getFont()->getLineHeight() * MAX_LINES_COUNT);
- LLRect messageRect = mMessage->getRect();
- LLRect footerRect = mFooter->getRect();
+ LLRect message_rect = mMessage->getRect();
+
+ S32 old_message_height = message_rect.getHeight();
+ S32 new_message_height = mMessage->getTextBoundingRect().getHeight();
+ S32 new_footer_height = mFooter->getTextBoundingRect().getHeight();
+
+ constexpr S32 FOOTER_PADDING = 8; // new height should include padding for newly added footer
+ S32 required_text_height = new_message_height + new_footer_height + FOOTER_PADDING;
+ S32 new_text_height = llmin(required_text_height, max_text_height);
+
+ // Footer was invisible, so use old_message_height for old height
+ height_delta = new_text_height - old_message_height;
+
+ reshape( getRect().getWidth(), llmax(getRect().getHeight() + height_delta, MIN_PANEL_HEIGHT));
+
+ // Floater was resized, now resize and shift children
+ // Message follows top, so it's top is in a correct position, but needs to be resized down
+ S32 message_delta = new_message_height - old_message_height;
+ message_rect = mMessage->getRect(); // refresh since it might have changed after reshape
+ message_rect.mBottom = message_rect.mBottom - message_delta;
+ mMessage->setRect(message_rect);
+ mMessage->needsReflow();
+ // Button panel should stay the same size, just translate it
+ LLPanel* panel = getChild<LLPanel>("buttons_panel");
+ panel->translate(0, -message_delta);
+ // Footer should be both moved and resized
+ LLRect footer_rect = mFooter->getRect();
+ footer_rect.mTop = footer_rect.mTop - message_delta;
+ footer_rect.mBottom = footer_rect.mTop - new_footer_height;
+ mFooter->setRect(footer_rect);
+ mFooter->needsReflow();
+ }
+ else if (mMessage->getVisible())
+ {
+ S32 height_delta = 0;
+ S32 max_text_height = (mMessage->getFont()->getLineHeight() * MAX_LINES_COUNT);
+
+ LLRect message_rect = mMessage->getRect();
+
+ S32 old_message_height = message_rect.getHeight();
+ S32 new_message_height = mMessage->getTextBoundingRect().getHeight();
- S32 oldTextHeight = messageRect.getHeight() + footerRect.getHeight();
+ S32 new_text_height = llmin(new_message_height, max_text_height);
- S32 requiredTextHeight = mMessage->getTextBoundingRect().getHeight() + mFooter->getTextBoundingRect().getHeight();
- S32 newTextHeight = llmin(requiredTextHeight, maxTextHeight);
+ // Footer was invisible, so use old_message_height for old height
+ height_delta = new_text_height - old_message_height;
- heightDelta = newTextHeight - oldTextHeight - heightDelta;
+ reshape(getRect().getWidth(), llmax(getRect().getHeight() + height_delta, MIN_PANEL_HEIGHT));
- reshape( getRect().getWidth(), llmax(getRect().getHeight() + heightDelta, MIN_PANEL_HEIGHT));
+ // Floater was resized, now resize and shift children
+ // Message follows top, so it's top is in a correct position, but needs to be resized down
+ S32 message_delta = new_message_height - old_message_height;
+ message_rect = mMessage->getRect(); // refresh since it might have changed after reshape
+ message_rect.mBottom = message_rect.mBottom - message_delta;
+ mMessage->setRect(message_rect);
+ mMessage->needsReflow();
+ // Button panel should stay the same size, just translate it
+ LLPanel* panel = getChild<LLPanel>("buttons_panel");
+ panel->translate(0, -message_delta);
}
}
diff --git a/indra/newview/llviewerassetstorage.cpp b/indra/newview/llviewerassetstorage.cpp
index 867d47c893..5b580ef415 100644
--- a/indra/newview/llviewerassetstorage.cpp
+++ b/indra/newview/llviewerassetstorage.cpp
@@ -42,6 +42,7 @@
#include "llcoproceduremanager.h"
#include "lleventcoro.h"
#include "llsdutil.h"
+#include "llstartup.h"
#include "llworld.h"
///----------------------------------------------------------------------------
@@ -460,28 +461,78 @@ void LLViewerAssetStorage::assetRequestCoro(
if (!gAgent.getRegion())
{
- LL_WARNS_ONCE("ViewerAsset") << "Asset request fails: no region set" << LL_ENDL;
- result_code = LL_ERR_ASSET_REQUEST_FAILED;
- ext_status = LLExtStat::NONE;
- removeAndCallbackPendingDownloads(uuid, atype, uuid, atype, result_code, ext_status, 0);
- return;
+ if (STATE_WORLD_INIT <= LLStartUp::getStartupState())
+ {
+ // Viewer isn't ready, wait for region to become available
+ LL_INFOS_ONCE("ViewerAsset") << "Waiting for agent region to be set" << LL_ENDL;
+
+ LLEventStream region_init("waitForRegion", true);
+ std::string pump_name = region_init.getName();
+
+ boost::signals2::connection region_conn =
+ gAgent.addRegionChangedCallback([pump_name]()
+ {
+ LLEventPumps::instance().obtain(pump_name).post(LLSD());
+ });
+ F32Seconds timeout_seconds(LL_ASSET_STORAGE_TIMEOUT);
+ llcoro::suspendUntilEventOnWithTimeout(region_init, timeout_seconds, LLSDMap("timeout", LLSD::Boolean(true)));
+ gAgent.removeRegionChangedCallback(region_conn);
+ region_conn.disconnect();
+
+ if (LLApp::isExiting() || !gAssetStorage)
+ {
+ return;
+ }
+
+ // recheck region whether suspend ended on timeout or not
+ if (!gAgent.getRegion())
+ {
+ LL_WARNS_ONCE("ViewerAsset") << "Asset request fails: timeout reached while waiting for region" << LL_ENDL;
+ result_code = LL_ERR_NO_CAP;
+ ext_status = LLExtStat::NONE;
+ removeAndCallbackPendingDownloads(uuid, atype, uuid, atype, result_code, ext_status, 0);
+ return;
+ }
+ }
+ else
+ {
+ LL_WARNS_ONCE("ViewerAsset") << "Asset request fails: no region set" << LL_ENDL;
+ result_code = LL_ERR_NO_CAP;
+ ext_status = LLExtStat::NONE;
+ removeAndCallbackPendingDownloads(uuid, atype, uuid, atype, result_code, ext_status, 0);
+ return;
+ }
}
- else if (!gAgent.getRegion()->capabilitiesReceived())
+
+ if (!gAgent.getRegion()->capabilitiesReceived())
{
LL_WARNS_ONCE("ViewerAsset") << "Waiting for capabilities" << LL_ENDL;
LLEventStream capsRecv("waitForCaps", true);
- gAgent.getRegion()->setCapabilitiesReceivedCallback(
- boost::bind(&LLViewerAssetStorage::capsRecvForRegion, this, _1, capsRecv.getName()));
+ boost::signals2::connection caps_conn =
+ gAgent.getRegion()->setCapabilitiesReceivedCallback(
+ boost::bind(&LLViewerAssetStorage::capsRecvForRegion, this, _1, capsRecv.getName()));
- llcoro::suspendUntilEventOn(capsRecv);
+ F32Seconds timeout_seconds(LL_ASSET_STORAGE_TIMEOUT); // from minutes to seconds, by default 5 minutes
+ LLSD result = llcoro::suspendUntilEventOnWithTimeout(capsRecv, timeout_seconds, LLSDMap("timeout", LLSD::Boolean(true)));
+ caps_conn.disconnect();
if (LLApp::isExiting() || !gAssetStorage)
{
return;
}
+ if (result.has("timeout"))
+ {
+ // Caps failed to arrive in 5 minutes
+ LL_WARNS_ONCE("ViewerAsset") << "Asset " << uuid << " request fails : capabilities took too long to arrive" << LL_ENDL;
+ result_code = LL_ERR_NO_CAP;
+ ext_status = LLExtStat::NONE;
+ removeAndCallbackPendingDownloads(uuid, atype, uuid, atype, result_code, ext_status, 0);
+ return;
+ }
+
LL_WARNS_ONCE("ViewerAsset") << "capsRecv got event" << LL_ENDL;
LL_WARNS_ONCE("ViewerAsset") << "region " << gAgent.getRegion() << " mViewerAssetUrl " << mViewerAssetUrl << LL_ENDL;
}
@@ -492,7 +543,7 @@ void LLViewerAssetStorage::assetRequestCoro(
if (mViewerAssetUrl.empty())
{
LL_WARNS_ONCE("ViewerAsset") << "asset request fails: caps received but no viewer asset cap found" << LL_ENDL;
- result_code = LL_ERR_ASSET_REQUEST_FAILED;
+ result_code = LL_ERR_NO_CAP;
ext_status = LLExtStat::NONE;
removeAndCallbackPendingDownloads(uuid, atype, uuid, atype, result_code, ext_status, 0);
return;
diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp
index a8ed79a8cc..6d825441ca 100644
--- a/indra/newview/llviewercontrol.cpp
+++ b/indra/newview/llviewercontrol.cpp
@@ -814,6 +814,7 @@ void setting_setup_signal_listener(LLControlGroup& group, const std::string& set
void settings_setup_listeners()
{
+ LL_PROFILE_ZONE_SCOPED;
setting_setup_signal_listener(gSavedSettings, "FirstPersonAvatarVisible", handleRenderAvatarMouselookChanged);
setting_setup_signal_listener(gSavedSettings, "RenderFarClip", handleRenderFarClipChanged);
setting_setup_signal_listener(gSavedSettings, "RenderTerrainScale", handleTerrainScaleChanged);
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index f29760c824..5799e23ca5 100644
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -140,7 +140,7 @@
#include "llwindow.h"
#include "llpathfindingmanager.h"
#include "llstartup.h"
-#include "boost/unordered_map.hpp"
+#include <unordered_map>
#include <boost/regex.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/json.hpp>
@@ -153,7 +153,7 @@ using namespace LLAvatarAppearanceDefines;
typedef LLPointer<LLViewerObject> LLViewerObjectPtr;
-static boost::unordered_map<std::string, LLStringExplicit> sDefaultItemLabels;
+static std::unordered_map<std::string, LLStringExplicit> sDefaultItemLabels;
LLVOAvatar* find_avatar_from_object(LLViewerObject* object);
LLVOAvatar* find_avatar_from_object(const LLUUID& object_id);
@@ -413,7 +413,23 @@ static LLSLMMenuUpdater* gSLMMenuUpdater = NULL;
LLSLMMenuUpdater::LLSLMMenuUpdater()
{
- mMarketplaceListingsItem = gMenuHolder->getChild<LLView>("MarketplaceListings")->getHandle();
+ LLView* me_menu = gMenuHolder->findChild<LLView>("Me");
+ if (!me_menu)
+ {
+ LLError::LLUserWarningMsg::showMissingFiles();
+ LL_ERRS() << "Can't find 'Me' menu in 'menu_viewer'" << LL_ENDL;
+ return;
+ }
+
+ LLView* marketplace_listings = me_menu->findChild<LLView>("MarketplaceListings");
+ if (!marketplace_listings)
+ {
+ LLError::LLUserWarningMsg::showMissingFiles();
+ LL_ERRS() << "Can't find 'MarketplaceListings' in 'Me' menu" << LL_ENDL;
+ return;
+ }
+
+ mMarketplaceListingsItem = marketplace_listings->getHandle();
}
void LLSLMMenuUpdater::setMerchantMenu()
{
@@ -473,6 +489,8 @@ void check_merchant_status(bool force)
void init_menus()
{
+ LL_PROFILE_ZONE_SCOPED;
+
// Initialize actions
initialize_menus();
@@ -549,7 +567,29 @@ void init_menus()
color = LLUIColorTable::instance().getColor( "MenuNonProductionBgColor" );
}
- LLView* menu_bar_holder = gViewerWindow->getRootView()->getChildView("menu_bar_holder");
+ LLView* menu_stack = gViewerWindow->getMainView()->findChildView("menu_stack");
+ if (!menu_stack)
+ {
+ LLError::LLUserWarningMsg::showMissingFiles();
+ LL_ERRS() << "Can't find menu_stack in main_view" << LL_ENDL;
+ return;
+ }
+
+ LLView* status_bar_container = menu_stack->findChildView("status_bar_container");
+ if (!status_bar_container)
+ {
+ LLError::LLUserWarningMsg::showMissingFiles();
+ LL_ERRS() << "Can't find status_bar_container in main_view" << LL_ENDL;
+ return;
+ }
+
+ LLView* menu_bar_holder = status_bar_container->findChildView("menu_bar_holder");
+ if (!menu_bar_holder)
+ {
+ LLError::LLUserWarningMsg::showMissingFiles();
+ LL_ERRS() << "Can't find status_bar_container in main_view" << LL_ENDL;
+ return;
+ }
gMenuBarView = LLUICtrlFactory::getInstance()->createFromFile<LLMenuBarGL>("menu_viewer.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
gMenuBarView->setRect(LLRect(0, menu_bar_holder->getRect().mTop, 0, menu_bar_holder->getRect().mTop - MENU_BAR_HEIGHT));
@@ -563,8 +603,33 @@ void init_menus()
// *TODO:Also fix cost in llfolderview.cpp for Inventory menus
const std::string sound_upload_cost_str = std::to_string(LLAgentBenefitsMgr::current().getSoundUploadCost());
const std::string animation_upload_cost_str = std::to_string(LLAgentBenefitsMgr::current().getAnimationUploadCost());
- gMenuHolder->childSetLabelArg("Upload Sound", "[COST]", sound_upload_cost_str);
- gMenuHolder->childSetLabelArg("Upload Animation", "[COST]", animation_upload_cost_str);
+
+ LLView* main_upload_menu = gMenuHolder->findChild<LLView>("Upload");
+ if (!main_upload_menu)
+ {
+ LLError::LLUserWarningMsg::showMissingFiles();
+ LL_ERRS() << "Can't find 'Upload' menu in 'menu_viewer'" << LL_ENDL;
+ return;
+ }
+
+ LLView* upload_sound = main_upload_menu->findChild<LLView>("Upload Sound");
+ if (!upload_sound)
+ {
+ LLError::LLUserWarningMsg::showMissingFiles();
+ LL_ERRS() << "Can't find 'Upload Sound' menu item in 'Upload' menu" << LL_ENDL;
+ return;
+ }
+ upload_sound->setLabelArg("[COST]", sound_upload_cost_str);
+
+ LLView* upload_anim = main_upload_menu->findChild<LLView>("Upload Animation");
+ if (!upload_anim)
+ {
+ LLError::LLUserWarningMsg::showMissingFiles();
+ LL_ERRS() << "Can't find 'Upload Animation' menu item in 'Upload' menu" << LL_ENDL;
+ return;
+ }
+ upload_anim->setLabelArg("[COST]", animation_upload_cost_str);
+
gAttachSubMenu = gMenuBarView->findChildMenuByName("Attach Object", true);
gDetachSubMenu = gMenuBarView->findChildMenuByName("Detach Object", true);
@@ -572,13 +637,6 @@ void init_menus()
gDetachAvatarMenu = gMenuHolder->getChild<LLMenuGL>("Avatar Detach", true);
gDetachHUDAvatarMenu = gMenuHolder->getChild<LLMenuGL>("Avatar Detach HUD", true);
- // Don't display the Memory console menu if the feature is turned off
- LLMenuItemCheckGL *memoryMenu = gMenuBarView->getChild<LLMenuItemCheckGL>("Memory", true);
- if (memoryMenu)
- {
- memoryMenu->setVisible(false);
- }
-
gMenuBarView->createJumpKeys();
// Let land based option enable when parcel changes
@@ -2963,7 +3021,7 @@ void handle_object_show_original()
static void init_default_item_label(LLUICtrl* ctrl)
{
const std::string& item_name = ctrl->getName();
- boost::unordered_map<std::string, LLStringExplicit>::iterator it = sDefaultItemLabels.find(item_name);
+ std::unordered_map<std::string, LLStringExplicit>::iterator it = sDefaultItemLabels.find(item_name);
if (it == sDefaultItemLabels.end())
{
// *NOTE: This will not work for items of type LLMenuItemCheckGL because they return boolean value
@@ -2979,7 +3037,7 @@ static void init_default_item_label(LLUICtrl* ctrl)
static LLStringExplicit get_default_item_label(const std::string& item_name)
{
LLStringExplicit res("");
- boost::unordered_map<std::string, LLStringExplicit>::iterator it = sDefaultItemLabels.find(item_name);
+ std::unordered_map<std::string, LLStringExplicit>::iterator it = sDefaultItemLabels.find(item_name);
if (it != sDefaultItemLabels.end())
{
res = it->second;
@@ -9689,6 +9747,8 @@ void initialize_spellcheck_menu()
void initialize_menus()
{
+ LL_PROFILE_ZONE_SCOPED;
+
// A parameterized event handler used as ctrl-8/9/0 zoom controls below.
class LLZoomer : public view_listener_t
{
diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp
index 3a7b721f70..d1e25988cc 100644
--- a/indra/newview/llviewermessage.cpp
+++ b/indra/newview/llviewermessage.cpp
@@ -5745,28 +5745,40 @@ void process_script_question(LLMessageSystem *msg, void **user_data)
args["NAME"] = clean_owner_name;
S32 known_questions = 0;
bool has_not_only_debit = questions ^ SCRIPT_PERMISSIONS[SCRIPT_PERMISSION_DEBIT].permbit;
+ bool caution_enabled = gSavedSettings.getBOOL("PermissionsCautionEnabled");
// check the received permission flags against each permission
+ std::string warning_msg;
for (const script_perm_t& script_perm : SCRIPT_PERMISSIONS)
{
if (questions & script_perm.permbit)
{
- count++;
known_questions |= script_perm.permbit;
// check whether permission question should cause special caution dialog
caution |= (script_perm.caution);
- if (("ScriptTakeMoney" == script_perm.question) && has_not_only_debit)
+ // Cautions go into top part of the dialog, questions go into the footer
+ if (caution_enabled && script_perm.caution)
+ {
+ warning_msg += "\n" + LLTrans::getString(script_perm.question + "Caution") + "\n";
continue;
+ }
if (LLTrans::getString(script_perm.question).empty())
{
continue;
}
- script_question += " " + LLTrans::getString(script_perm.question) + "\n";
+ count++;
+ script_question += "\n " + LLTrans::getString(script_perm.question);
}
}
+ if (!warning_msg.empty())
+ {
+ LLStringUtil::format(warning_msg, args);
+ args["WARNINGS"] = warning_msg;
+ }
+
args["QUESTIONS"] = script_question;
if (known_questions != questions)
@@ -5791,12 +5803,12 @@ void process_script_question(LLMessageSystem *msg, void **user_data)
// check whether cautions are even enabled or not
const char* notification = "ScriptQuestion";
- if(caution && gSavedSettings.getBOOL("PermissionsCautionEnabled"))
+ if(caution && caution_enabled)
{
- args["FOOTERTEXT"] = (count > 1) ? LLTrans::getString("AdditionalPermissionsRequestHeader") + "\n\n" + script_question : "";
+ args["FOOTERTEXT"] = (count > 0) ? LLTrans::getString("AdditionalPermissionsRequestHeader") + "\n" + script_question : "";
notification = "ScriptQuestionCaution";
}
- else if(experienceid.notNull())
+ else if (experienceid.notNull())
{
payload["experience"]=experienceid;
LLExperienceCache::instance().get(experienceid, boost::bind(process_script_experience_details, _1, args, payload));
diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp
index 0f4cbdd25c..dfb0521167 100644
--- a/indra/newview/llviewerobject.cpp
+++ b/indra/newview/llviewerobject.cpp
@@ -130,6 +130,7 @@ F64Seconds LLViewerObject::sPhaseOutUpdateInterpolationTime(2.0); // For motio
F64Seconds LLViewerObject::sMaxRegionCrossingInterpolationTime(1.0);// For motion interpolation: don't interpolate over this time on region crossing
std::map<std::string, U32> LLViewerObject::sObjectDataMap;
+std::unordered_map<LLUUID, std::vector<LLViewerObject*>> LLViewerObject::sPendingUpdatesByOwner;
// The maximum size of an object extra parameters binary (packed) block
#define MAX_OBJECT_PARAMS_SIZE 1024
@@ -521,6 +522,8 @@ void LLViewerObject::markDead()
mReflectionProbe = nullptr;
}
+ removeObjectFromPendingUpdate(this);
+
sNumZombieObjects++;
}
}
@@ -7751,6 +7754,61 @@ bool LLViewerObject::isReachable()
return false;
}
+void LLViewerObject::markObjectsForUpdate(const LLUUID& owner_id)
+{
+ sPendingUpdatesByOwner.erase(owner_id);
+ for (S32 i = 0; i < gObjectList.getNumObjects(); ++i)
+ {
+ LLViewerObject* obj = gObjectList.getObject(i);
+ if (!obj || obj->isDead() || obj->isAvatar() || obj->permYouOwner())
+ {
+ continue;
+ }
+ sPendingUpdatesByOwner[owner_id].push_back(obj);
+ }
+}
+
+void LLViewerObject::removeObjectFromPendingUpdate(LLViewerObject* obj)
+{
+ for (auto& [owner_id, objects] : sPendingUpdatesByOwner)
+ {
+ objects.erase(std::remove(objects.begin(), objects.end(), obj), objects.end());
+ }
+}
+
+bool LLViewerObject::isObjectInPendingUpdate(const LLUUID& owner_id, LLViewerObject* obj)
+{
+ if (!obj)
+ {
+ return false;
+ }
+ auto it = sPendingUpdatesByOwner.find(owner_id);
+ if (it != sPendingUpdatesByOwner.end())
+ {
+ const auto& objects = it->second;
+ return std::find(objects.begin(), objects.end(), obj) != objects.end();
+ }
+ return false;
+}
+
+void LLViewerObject::requestObjectUpdate()
+{
+ if (LLViewerRegion* regionp = getRegion())
+ {
+ LLMessageSystem* msg = gMessageSystem;
+ msg->newMessageFast(_PREHASH_RequestMultipleObjects);
+ msg->nextBlockFast(_PREHASH_AgentData);
+ msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+ msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+ msg->nextBlockFast(_PREHASH_ObjectData);
+ msg->addU8Fast(_PREHASH_CacheMissType, 0);
+ msg->addU32Fast(_PREHASH_ID, getLocalID());
+ msg->sendReliable(regionp->getHost());
+
+ removeObjectFromPendingUpdate(this);
+ }
+}
+
class ObjectPhysicsProperties : public LLHTTPNode
{
public:
diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h
index cccf59a319..465e221ae4 100644
--- a/indra/newview/llviewerobject.h
+++ b/indra/newview/llviewerobject.h
@@ -622,6 +622,11 @@ public:
void setPhysicsDensity(F32 density);
void setPhysicsRestitution(F32 restitution);
+ static void markObjectsForUpdate(const LLUUID& owner_id);
+ static void removeObjectFromPendingUpdate(LLViewerObject* obj);
+ static bool isObjectInPendingUpdate(const LLUUID& owner_id, LLViewerObject* obj);
+ void requestObjectUpdate();
+
virtual void dump() const;
static U32 getNumZombieObjects() { return sNumZombieObjects; }
@@ -796,6 +801,7 @@ private:
std::unique_ptr<LLReflectionProbeParams> mReflectionProbeParams;
static std::map<std::string, U32> sObjectDataMap;
+ static std::unordered_map<LLUUID, std::vector<LLViewerObject*>> sPendingUpdatesByOwner;
public:
// Sent to sim in UPDATE_FLAGS, received in ObjectPhysicsProperties
U8 mPhysicsShapeType;
diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp
index 50edb408c7..34e5cc9de8 100644
--- a/indra/newview/llviewerobjectlist.cpp
+++ b/indra/newview/llviewerobjectlist.cpp
@@ -174,7 +174,7 @@ bool LLViewerObjectList::removeFromLocalIDTable(LLViewerObject* objectp)
U32 local_id = objectp->mLocalID;
U64 indexid = (((U64)objectp->mRegionIndex) << 32) | (U64)local_id;
- std::map<U64, LLUUID>::iterator iter = mIndexAndLocalIDToUUID.find(indexid);
+ auto iter = mIndexAndLocalIDToUUID.find(indexid);
if (iter == mIndexAndLocalIDToUUID.end())
{
return false;
diff --git a/indra/newview/llviewerobjectlist.h b/indra/newview/llviewerobjectlist.h
index 547ef9fb2d..adc90a0483 100644
--- a/indra/newview/llviewerobjectlist.h
+++ b/indra/newview/llviewerobjectlist.h
@@ -204,7 +204,7 @@ protected:
uuid_set_t mDeadObjects;
- std::map<LLUUID, LLPointer<LLViewerObject> > mUUIDObjectMap;
+ std::unordered_map<LLUUID, LLPointer<LLViewerObject> > mUUIDObjectMap;
//set of objects that need to update their cost
uuid_set_t mStaleObjectCost;
@@ -221,7 +221,7 @@ protected:
static U32 sSimulatorMachineIndex;
std::map<U64, U32> mIPAndPortToIndex;
- std::map<U64, LLUUID> mIndexAndLocalIDToUUID;
+ std::unordered_map<U64, LLUUID> mIndexAndLocalIDToUUID;
friend class LLViewerObject;
diff --git a/indra/newview/llviewerprecompiledheaders.h b/indra/newview/llviewerprecompiledheaders.h
index f6ee00cb25..d33d426769 100644
--- a/indra/newview/llviewerprecompiledheaders.h
+++ b/indra/newview/llviewerprecompiledheaders.h
@@ -126,8 +126,6 @@
#include "llfloater.h"
#include <boost/signals2.hpp>
-#include <boost/unordered_set.hpp>
-#include <boost/unordered_map.hpp>
#include <boost/json.hpp>
#include "glm/glm.hpp"
diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp
index cd70f8f9b9..42a587f376 100644
--- a/indra/newview/llviewerregion.cpp
+++ b/indra/newview/llviewerregion.cpp
@@ -104,7 +104,7 @@ S32 LLViewerRegion::sLastCameraUpdated = 0;
S32 LLViewerRegion::sNewObjectCreationThrottle = -1;
LLViewerRegion::vocache_entry_map_t LLViewerRegion::sRegionCacheCleanup;
-typedef std::map<std::string, std::string> CapabilityMap;
+typedef std::unordered_map<std::string, std::string, ll::string_hash, std::equal_to<>> CapabilityMap;
static void log_capabilities(const CapabilityMap &capmap);
@@ -3437,7 +3437,7 @@ void LLViewerRegion::setCapabilityDebug(const std::string& name, const std::stri
}
}
-std::string LLViewerRegion::getCapabilityDebug(const std::string& name) const
+std::string LLViewerRegion::getCapabilityDebug(std::string_view name) const
{
CapabilityMap::const_iterator iter = mImpl->mSecondCapabilitiesTracker.find(name);
if (iter == mImpl->mSecondCapabilitiesTracker.end())
@@ -3448,15 +3448,14 @@ std::string LLViewerRegion::getCapabilityDebug(const std::string& name) const
return iter->second;
}
-
-bool LLViewerRegion::isSpecialCapabilityName(const std::string &name)
+bool LLViewerRegion::isSpecialCapabilityName(std::string_view name)
{
return name == "EventQueueGet" || name == "UntrustedSimulatorMessage";
}
-std::string LLViewerRegion::getCapability(const std::string& name) const
+std::string LLViewerRegion::getCapability(std::string_view name) const
{
- if (!capabilitiesReceived() && (name!=std::string("Seed")) && (name!=std::string("ObjectMedia")))
+ if (!capabilitiesReceived() && (name != "Seed") && (name != "ObjectMedia"))
{
LL_WARNS() << "getCapability called before caps received for " << name << LL_ENDL;
}
@@ -3464,21 +3463,20 @@ std::string LLViewerRegion::getCapability(const std::string& name) const
CapabilityMap::const_iterator iter = mImpl->mCapabilities.find(name);
if(iter == mImpl->mCapabilities.end())
{
- return "";
+ return {};
}
return iter->second;
}
-bool LLViewerRegion::isCapabilityAvailable(const std::string& name) const
+bool LLViewerRegion::isCapabilityAvailable(std::string_view name) const
{
- if (!capabilitiesReceived() && (name!=std::string("Seed")) && (name!=std::string("ObjectMedia")))
+ if (!capabilitiesReceived() && (name != "Seed") && (name != "ObjectMedia"))
{
LL_WARNS() << "isCapabilityAvailable called before caps received for " << name << LL_ENDL;
}
- CapabilityMap::const_iterator iter = mImpl->mCapabilities.find(name);
- if(iter == mImpl->mCapabilities.end())
+ if (!mImpl->mCapabilities.contains(name))
{
return false;
}
@@ -3734,9 +3732,14 @@ bool LLViewerRegion::avatarHoverHeightEnabled() const
void log_capabilities(const CapabilityMap &capmap)
{
+ // Copy into sorted map for ordered output
+ using SortedCapabilityMap = std::map<std::string, std::string>;
+ SortedCapabilityMap sorted_capmap;
+ sorted_capmap.insert(capmap.begin(), capmap.end());
+
S32 count = 0;
- CapabilityMap::const_iterator iter;
- for (iter = capmap.begin(); iter != capmap.end(); ++iter, ++count)
+ SortedCapabilityMap::const_iterator iter;
+ for (iter = sorted_capmap.begin(); iter != sorted_capmap.end(); ++iter, ++count)
{
if (!iter->second.empty())
{
diff --git a/indra/newview/llviewerregion.h b/indra/newview/llviewerregion.h
index b3ec857907..974bc375b8 100644
--- a/indra/newview/llviewerregion.h
+++ b/indra/newview/llviewerregion.h
@@ -274,10 +274,10 @@ public:
S32 getNumSeedCapRetries();
void setCapability(const std::string& name, const std::string& url);
void setCapabilityDebug(const std::string& name, const std::string& url);
- bool isCapabilityAvailable(const std::string& name) const;
+ bool isCapabilityAvailable(std::string_view name) const;
// implements LLCapabilityProvider
- virtual std::string getCapability(const std::string& name) const;
- std::string getCapabilityDebug(const std::string& name) const;
+ virtual std::string getCapability(std::string_view name) const;
+ std::string getCapabilityDebug(std::string_view name) const;
// has region received its final (not seed) capability list?
@@ -287,7 +287,7 @@ public:
void setCapabilitiesError();
boost::signals2::connection setCapabilitiesReceivedCallback(const caps_received_signal_t::slot_type& cb);
- static bool isSpecialCapabilityName(const std::string &name);
+ static bool isSpecialCapabilityName(std::string_view name);
void logActiveCapabilities() const;
// Utilities to post and get via
diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp
index 1e83482752..23915d01fa 100644
--- a/indra/newview/llviewertexture.cpp
+++ b/indra/newview/llviewertexture.cpp
@@ -1488,7 +1488,9 @@ bool LLViewerFetchedTexture::preCreateTexture(S32 usename/*= 0*/)
// from local images, but this might become unsafe in case of changes to fetcher
if (mBoostLevel == BOOST_PREVIEW)
{
- mRawImage->biasedScaleToPowerOfTwo(1024);
+ // A local file with a preview flag likely means mesh's texture upload
+ // which should follow normal upload scaling rules
+ mRawImage->biasedScaleToPowerOfTwo(LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT);
}
else
{ // leave black border, do not scale image content
@@ -2574,14 +2576,31 @@ bool LLViewerFetchedTexture::doLoadedCallbacks()
S32 best_raw_discard = gl_discard; // Current GL quality level
S32 current_aux_discard = MAX_DISCARD_LEVEL + 1;
S32 best_aux_discard = MAX_DISCARD_LEVEL + 1;
+ LLImageRaw *current_raw_image = nullptr;
if (mIsRawImageValid)
{
- // If we have an existing raw image, we have a baseline for the raw and auxiliary quality levels.
+ // If we have an existing raw image, we have a baseline for the raw
+ // and auxiliary quality levels.
+ // Note: we call updateImagesCreateTextures before callbacks, which
+ // leads to destroyRawImage and deletes raw image. So this case
+ // might be rare or even never trigger as there is never a raw image,
+ // only a saved one.
current_raw_discard = mRawDiscardLevel;
best_raw_discard = llmin(best_raw_discard, mRawDiscardLevel);
best_aux_discard = llmin(best_aux_discard, mRawDiscardLevel); // We always decode the aux when we decode the base raw
current_aux_discard = llmin(current_aux_discard, best_aux_discard);
+ current_raw_image = mRawImage;
+ }
+ else if (mSavedRawImage.notNull())
+ {
+ // We have a saved raw image, we can use that as our baseline for
+ // raw and auxiliary quality levels.
+ current_raw_discard = mSavedRawDiscardLevel;
+ best_raw_discard = llmin(best_raw_discard, mSavedRawDiscardLevel);
+ best_aux_discard = llmin(best_aux_discard, mSavedRawDiscardLevel); // We always decode the aux when we decode the base raw
+ current_aux_discard = llmin(current_aux_discard, best_aux_discard);
+ current_raw_image = mSavedRawImage;
}
else
{
@@ -2646,12 +2665,17 @@ bool LLViewerFetchedTexture::doLoadedCallbacks()
if (need_readback)
{
readbackRawImage();
+ if (mIsRawImageValid)
+ {
+ current_raw_discard = mRawDiscardLevel;
+ current_raw_image = mRawImage;
+ }
}
//
// Run raw/auxiliary data callbacks
//
- if (run_raw_callbacks && mIsRawImageValid && (mRawDiscardLevel <= getMaxDiscardLevel()))
+ if (run_raw_callbacks && current_raw_image != nullptr && (current_raw_discard <= getMaxDiscardLevel()))
{
// Do callbacks which require raw image data.
//LL_INFOS() << "doLoadedCallbacks raw for " << getID() << LL_ENDL;
@@ -2662,7 +2686,7 @@ bool LLViewerFetchedTexture::doLoadedCallbacks()
{
callback_list_t::iterator curiter = iter++;
LLLoadedCallbackEntry *entryp = *curiter;
- if (entryp->mNeedsImageRaw && (entryp->mLastUsedDiscard > mRawDiscardLevel))
+ if (entryp->mNeedsImageRaw && (entryp->mLastUsedDiscard > current_raw_discard))
{
// If we've loaded all the data there is to load or we've loaded enough
// to satisfy the interested party, then this is the last time that
@@ -2673,11 +2697,11 @@ bool LLViewerFetchedTexture::doLoadedCallbacks()
{
LL_WARNS() << "Raw Image with no Aux Data for callback" << LL_ENDL;
}
- bool final = mRawDiscardLevel <= entryp->mDesiredDiscard;
+ bool final = current_raw_discard <= entryp->mDesiredDiscard;
//LL_INFOS() << "Running callback for " << getID() << LL_ENDL;
- //LL_INFOS() << mRawImage->getWidth() << "x" << mRawImage->getHeight() << LL_ENDL;
- entryp->mLastUsedDiscard = mRawDiscardLevel;
- entryp->mCallback(true, this, mRawImage, mAuxRawImage, mRawDiscardLevel, final, entryp->mUserData);
+ //LL_INFOS() << current_raw_image->getWidth() << "x" << current_raw_image->getHeight() << LL_ENDL;
+ entryp->mLastUsedDiscard = current_raw_discard;
+ entryp->mCallback(true, this, current_raw_image, mAuxRawImage, current_raw_discard, final, entryp->mUserData);
if (final)
{
iter = mLoadedCallbackList.erase(curiter);
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index a3c241456d..773ff14e90 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -2067,10 +2067,6 @@ void LLViewerWindow::initGLDefaults()
gBox.prerender();
}
-struct MainPanel : public LLPanel
-{
-};
-
void LLViewerWindow::initBase()
{
S32 height = getWindowHeightScaled();
@@ -2109,6 +2105,8 @@ void LLViewerWindow::initBase()
main_view->setShape(full_window);
getRootView()->addChild(main_view);
+ mMainView = main_view;
+
// placeholder widget that controls where "world" is rendered
mWorldViewPlaceholder = main_view->getChildView("world_view_rect")->getHandle();
mPopupView = main_view->getChild<LLPopupView>("popup_holder");
diff --git a/indra/newview/llviewerwindow.h b/indra/newview/llviewerwindow.h
index 9a0bb28f1d..105c1b8baa 100644
--- a/indra/newview/llviewerwindow.h
+++ b/indra/newview/llviewerwindow.h
@@ -144,6 +144,10 @@ private:
};
+struct MainPanel : public LLPanel
+{
+};
+
static const U32 MAX_SNAPSHOT_IMAGE_SIZE = 7680; // max snapshot image size 7680 * 7680 UHDTV2
class LLViewerWindow : public LLWindowCallbacks
@@ -248,6 +252,7 @@ public:
// ACCESSORS
//
LLRootView* getRootView() const;
+ MainPanel* getMainView() const { return mMainView; }
// 3D world area in scaled pixels (via UI scale), use for most UI computations
LLRect getWorldViewRectScaled() const;
@@ -500,6 +505,7 @@ private:
LLRect mWorldViewRectRaw; // area of screen for 3D world
LLRect mWorldViewRectScaled; // area of screen for 3D world scaled by UI size
LLRootView* mRootView; // a view of size mWindowRectRaw, containing all child views
+ MainPanel* mMainView; // a view of size mWindowRectRaw, directly containing the base elements of the ui tree
LLView* mFloaterSnapRegion = nullptr;
LLView* mNavBarContainer = nullptr;
LLPanel* mStatusBarContainer = nullptr;
diff --git a/indra/newview/llvoicewebrtc.cpp b/indra/newview/llvoicewebrtc.cpp
index d1de2f55da..481f9e3522 100644
--- a/indra/newview/llvoicewebrtc.cpp
+++ b/indra/newview/llvoicewebrtc.cpp
@@ -2496,17 +2496,18 @@ void LLVoiceWebRTCConnection::processIceUpdatesCoro(connectionPtr_t connection)
// callback from llwebrtc
void LLVoiceWebRTCConnection::OnOfferAvailable(const std::string &sdp)
{
+ connectionPtr_t connection = shared_from_this();
LL::WorkQueue::postMaybe(mMainQueue,
- [=, this] {
- if (mShutDown)
+ [=] {
+ if (connection->mShutDown)
{
return;
}
LL_DEBUGS("Voice") << "On Offer Available." << LL_ENDL;
- mChannelSDP = sdp;
- if (mVoiceConnectionState == VOICE_STATE_WAIT_FOR_SESSION_START)
+ connection->mChannelSDP = sdp;
+ if (connection->mVoiceConnectionState == VOICE_STATE_WAIT_FOR_SESSION_START)
{
- mVoiceConnectionState = VOICE_STATE_REQUEST_CONNECTION;
+ connection->mVoiceConnectionState = VOICE_STATE_REQUEST_CONNECTION;
}
});
}
@@ -2523,16 +2524,17 @@ void LLVoiceWebRTCConnection::OnOfferAvailable(const std::string &sdp)
// callback from llwebrtc
void LLVoiceWebRTCConnection::OnAudioEstablished(llwebrtc::LLWebRTCAudioInterface* audio_interface)
{
+ connectionPtr_t connection = shared_from_this();
LL::WorkQueue::postMaybe(mMainQueue,
- [=, this] {
- if (mShutDown)
+ [=] {
+ if (connection->mShutDown)
{
return;
}
LL_DEBUGS("Voice") << "On AudioEstablished." << LL_ENDL;
- mWebRTCAudioInterface = audio_interface;
- mWebRTCAudioInterface->setMute(true); // mute will be set appropriately later when we finish setting up.
- setVoiceConnectionState(VOICE_STATE_SESSION_ESTABLISHED);
+ connection->mWebRTCAudioInterface = audio_interface;
+ connection->mWebRTCAudioInterface->setMute(true); // mute will be set appropriately later when we finish setting up.
+ connection->setVoiceConnectionState(VOICE_STATE_SESSION_ESTABLISHED);
});
}
@@ -3207,17 +3209,18 @@ void LLVoiceWebRTCConnection::OnDataReceivedImpl(const std::string &data, bool b
// llwebrtc callback
void LLVoiceWebRTCConnection::OnDataChannelReady(llwebrtc::LLWebRTCDataInterface *data_interface)
{
+ connectionPtr_t connection = shared_from_this();
LL::WorkQueue::postMaybe(mMainQueue,
- [=, this] {
- if (mShutDown)
+ [=] {
+ if (connection->mShutDown)
{
return;
}
if (data_interface)
{
- mWebRTCDataInterface = data_interface;
- mWebRTCDataInterface->setDataObserver(this);
+ connection->mWebRTCDataInterface = data_interface;
+ connection->mWebRTCDataInterface->setDataObserver(connection.get());
}
});
}
diff --git a/indra/newview/llwearableitemslist.cpp b/indra/newview/llwearableitemslist.cpp
index cc593fe7b4..f639024228 100644
--- a/indra/newview/llwearableitemslist.cpp
+++ b/indra/newview/llwearableitemslist.cpp
@@ -82,7 +82,7 @@ LLPanelWearableListItem::LLPanelWearableListItem(LLViewerInventoryItem* item, co
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
-static LLWidgetNameRegistry::StaticRegistrar sRegisterPanelWearableOutfitItem(&typeid(LLPanelWearableOutfitItem::Params), "wearable_outfit_list_item");
+static LLWidgetNameRegistry::StaticRegistrar sRegisterPanelWearableOutfitItem(typeid(LLPanelWearableOutfitItem::Params), "wearable_outfit_list_item");
LLPanelWearableOutfitItem::Params::Params()
: add_btn("add_btn"),
@@ -222,7 +222,7 @@ void LLPanelWearableOutfitItem::updateItem(const std::string& name,
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
-static LLWidgetNameRegistry::StaticRegistrar sRegisterPanelClothingListItem(&typeid(LLPanelClothingListItem::Params), "clothing_list_item");
+static LLWidgetNameRegistry::StaticRegistrar sRegisterPanelClothingListItem(typeid(LLPanelClothingListItem::Params), "clothing_list_item");
LLPanelClothingListItem::Params::Params()
@@ -309,7 +309,7 @@ bool LLPanelClothingListItem::postBuild()
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
-static LLWidgetNameRegistry::StaticRegistrar sRegisterPanelBodyPartsListItem(&typeid(LLPanelBodyPartsListItem::Params), "bodyparts_list_item");
+static LLWidgetNameRegistry::StaticRegistrar sRegisterPanelBodyPartsListItem(typeid(LLPanelBodyPartsListItem::Params), "bodyparts_list_item");
LLPanelBodyPartsListItem::Params::Params()
@@ -380,7 +380,7 @@ bool LLPanelBodyPartsListItem::postBuild()
return true;
}
-static LLWidgetNameRegistry::StaticRegistrar sRegisterPanelDeletableWearableListItem(&typeid(LLPanelDeletableWearableListItem::Params), "deletable_wearable_list_item");
+static LLWidgetNameRegistry::StaticRegistrar sRegisterPanelDeletableWearableListItem(typeid(LLPanelDeletableWearableListItem::Params), "deletable_wearable_list_item");
LLPanelDeletableWearableListItem::Params::Params()
: delete_btn("delete_btn")
@@ -467,7 +467,7 @@ void LLPanelAttachmentListItem::updateItem(const std::string& name,
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
-static LLWidgetNameRegistry::StaticRegistrar sRegisterPanelDummyClothingListItem(&typeid(LLPanelDummyClothingListItem::Params), "dummy_clothing_list_item");
+static LLWidgetNameRegistry::StaticRegistrar sRegisterPanelDummyClothingListItem(typeid(LLPanelDummyClothingListItem::Params), "dummy_clothing_list_item");
LLPanelDummyClothingListItem::Params::Params()
: add_panel("add_panel"),
diff --git a/indra/newview/skins/default/xui/en/menu_favorites.xml b/indra/newview/skins/default/xui/en/menu_favorites.xml
index 6345394b46..f82f705fb7 100644
--- a/indra/newview/skins/default/xui/en/menu_favorites.xml
+++ b/indra/newview/skins/default/xui/en/menu_favorites.xml
@@ -35,6 +35,9 @@
<menu_item_call.on_click
function="Favorites.DoToSelected"
parameter="show_on_map" />
+ <menu_item_call.on_enable
+ function="Favorites.EnableSelected"
+ parameter="show_on_map" />
</menu_item_call>
<menu_item_call
label="Copy SLurl"
@@ -43,6 +46,9 @@
<menu_item_call.on_click
function="Favorites.DoToSelected"
parameter="copy_slurl" />
+ <menu_item_call.on_enable
+ function="Favorites.EnableSelected"
+ parameter="copy_slurl" />
</menu_item_call>
<menu_item_call
label="Create Pick"
diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml
index c93cb7822e..ba43e80eda 100644
--- a/indra/newview/skins/default/xui/en/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/en/menu_viewer.xml
@@ -2601,18 +2601,6 @@ function="World.EnvPreset"
parameter="fast timers" />
</menu_item_check>
<menu_item_check
- label="Memory"
- name="Memory"
- shortcut="control|shift|0"
- use_mac_ctrl="true">
- <menu_item_check.on_check
- function="Advanced.CheckConsole"
- parameter="memory view" />
- <menu_item_check.on_click
- function="Advanced.ToggleConsole"
- parameter="memory view" />
- </menu_item_check>
- <menu_item_check
label="Scene Statistics"
name="Scene Statistics">
<menu_item_check.on_check
diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index d278bac075..59deead084 100644
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -2466,6 +2466,17 @@ You already have a landmark for this location.
</notification>
<notification
+ icon="alert.tga"
+ name="LandmarkLocationUnknown"
+ type="alert">
+Viewer wasn't able to get region's location. Region might be temporarily unavailable, was removed or landmark failed to load.
+ <usetemplate
+ name="okbutton"
+ yestext="OK"/>
+ <tag>fail</tag>
+ </notification>
+
+ <notification
icon="alertmodal.tga"
name="CannotCreateLandmarkNotOwner"
type="alertmodal">
@@ -8585,10 +8596,10 @@ Scripts associated with this experience will be able to do the following on regi
priority="critical"
persist="true"
type="notify">
-Warning: The object &apos;&lt;nolink&gt;[OBJECTNAME]&lt;/nolink&gt;&apos; wants total access to your Linden Dollars account. If you allow access, it can remove funds from your account at any time, or empty your account completely, on an ongoing basis with no additional warnings.
-
-Do not allow access if you do not fully understand why it wants access to your account.
+Warning:
+[WARNINGS]
+Do not allow access if you do not fully understand why it wants access to your account.
<tag>confirm</tag>
<form name="form">
<button
@@ -8601,9 +8612,7 @@ Do not allow access if you do not fully understand why it wants access to your a
name="Deny"
text="Deny"/>
</form>
- <footer>
-[FOOTERTEXT]
- </footer>
+ <footer>[FOOTERTEXT]</footer>
</notification>
<notification
diff --git a/indra/newview/skins/default/xui/en/panel_notification.xml b/indra/newview/skins/default/xui/en/panel_notification.xml
index bfe738f472..eaf638d35f 100644
--- a/indra/newview/skins/default/xui/en/panel_notification.xml
+++ b/indra/newview/skins/default/xui/en/panel_notification.xml
@@ -49,7 +49,7 @@
embedded_items="false"
enabled="false"
follows="left|right|top|bottom"
- height="85"
+ height="85"
layout="topleft"
left="10"
mouse_opaque="false"
@@ -67,16 +67,16 @@
<panel
background_visible="false"
follows="left|right|bottom"
- height="30"
+ height="30"
width="290"
label="control_panel"
layout="topleft"
left="10"
name="control_panel"
top_pad="5">
- <!--
+ <!--
Notes:
- This panel holds buttons of notification. Change of its size can affect the layout of buttons.
+ This panel holds buttons of notification. Change of its size can affect the layout of buttons.
-->
</panel>
</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_script_question_toast.xml b/indra/newview/skins/default/xui/en/panel_script_question_toast.xml
index 1b1e31165a..9045e6a8ae 100644
--- a/indra/newview/skins/default/xui/en/panel_script_question_toast.xml
+++ b/indra/newview/skins/default/xui/en/panel_script_question_toast.xml
@@ -6,7 +6,7 @@
bg_alpha_color="PanelNotificationBackground"
bg_opaque_color="PanelNotificationBackground"
chrome="true"
- height="270"
+ height="220"
label="script_question_panel"
layout="topleft"
left="0"
@@ -39,9 +39,9 @@
width="285">
</panel>
<text
- follows="all"
+ follows="left|right|top"
font="SansSerifBold"
- height="55"
+ height="15"
layout="topleft"
mouse_opaque="false"
name="bottom_info_message"
diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml
index 8e0eea97d1..1860d38b0e 100644
--- a/indra/newview/skins/default/xui/en/strings.xml
+++ b/indra/newview/skins/default/xui/en/strings.xml
@@ -518,6 +518,8 @@ http://secondlife.com/support for help fixing this problem.
<string name="reconnect_nearby">You will now be reconnected to Nearby Voice Chat</string>
<string name="ScriptQuestionCautionChatGranted">'[OBJECTNAME]', an object owned by '[OWNERNAME]', located in [REGIONNAME] at [REGIONPOS], has been granted permission to: [PERMISSIONS].</string>
<string name="ScriptQuestionCautionChatDenied">'[OBJECTNAME]', an object owned by '[OWNERNAME]', located in [REGIONNAME] at [REGIONPOS], has been denied permission to: [PERMISSIONS].</string>
+ <string name="ScriptTakeMoneyCaution">The object &apos;&lt;nolink&gt;[OBJECTNAME]&lt;/nolink&gt;&apos; wants total access to your Linden Dollars account. If you allow access, it can remove funds from your account at any time, or empty your account completely, on an ongoing basis with no additional warnings.</string>
+ <string name="PrivilegedLandAccessCaution">The object &apos;&lt;nolink&gt;[OBJECTNAME]&lt;/nolink&gt;&apos; wants privileged access to your land. If you allow access it may sell your land with no additional warnings.</string>
<string name="AdditionalPermissionsRequestHeader">If you allow access to your account, you will also be allowing the object to:</string>
<string name="ScriptTakeMoney">Take Linden dollars (L$) from you</string>
<string name="ActOnControlInputs">Act on your control inputs</string>
@@ -535,6 +537,7 @@ http://secondlife.com/support for help fixing this problem.
<string name="ChangeYourDefaultAnimations">Change your default animations</string>
<string name="ForceSitAvatar">Force your avatar to sit</string>
<string name="ChangeEnvSettings">Change your environment settings</string>
+ <string name="PrivilegedLandAccess">Sell land on your behalf.</string>
<string name="NotConnected">Not Connected</string>
<string name="AgentNameSubst">(You)</string> <!-- Substitution for agent name -->
diff --git a/indra/newview/tests/lldateutil_test.cpp b/indra/newview/tests/lldateutil_test.cpp
index acbf019034..3e2e5e70a2 100644
--- a/indra/newview/tests/lldateutil_test.cpp
+++ b/indra/newview/tests/lldateutil_test.cpp
@@ -34,16 +34,16 @@
#include "lltrans.h"
#include "llui.h"
-#include <map>
+#include <unordered_map>
// Baked-in return values for getString()
-std::map< std::string, std::string, std::less<>> gString;
+std::unordered_map< std::string, std::string, ll::string_hash, std::equal_to<>> gString;
// Baked-in return values for getCountString()
// map of pairs of input xml_desc and integer count
typedef std::pair< std::string, int > count_string_t;
-std::map< count_string_t, std::string > gCountString;
+std::map<count_string_t, std::string> gCountString;
std::string LLTrans::getString(const std::string_view xml_desc, const LLStringUtil::format_map_t& args, bool def_string)
{
diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py
index 273ffab84f..bcabc07c5a 100755
--- a/indra/newview/viewer_manifest.py
+++ b/indra/newview/viewer_manifest.py
@@ -259,9 +259,10 @@ class ViewerManifest(LLManifest):
global CHANNEL_VENDOR_BASE
channel_type=self.channel_type()
if channel_type == 'release':
- return CHANNEL_VENDOR_BASE
+ app_suffix='Viewer'
else:
- return CHANNEL_VENDOR_BASE + ' ' + self.channel_variant()
+ app_suffix=self.channel_variant()
+ return CHANNEL_VENDOR_BASE + ' ' + app_suffix
def exec_name(self):
return "SecondLifeViewer"